diff --git a/.clang-format b/.clang-format index 153f0e4a334..74975cc3c0f 100644 --- a/.clang-format +++ b/.clang-format @@ -84,6 +84,7 @@ PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left +QualifierAlignment: Left ReflowComments: true SortIncludes: true SortUsingDeclarations: true diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 00000000000..ba2317e2b1b --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Applied clang-format to all source files +1bc2bd84600c8d2ca9253339c167401127f6a9f3 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000000..99ba77a6fee --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Report a bug that is preventing proper operation +title: '' +labels: Bugs +assignees: '' + +--- + + + +## Bug Description + + + +## Steps to Reproduce + + + +## Environment + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..40e40338b92 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Troubleshooting and User Support + url: https://openmc.discourse.group/ + about: For user support and troubleshooting, please use our Discourse forum diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 00000000000..04ecb8cf9c2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,10 @@ +--- +name: Documentation improvement +about: Found something incomplete or incorrect in our documentation? +title: '' +labels: Documentation +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000000..ddf49b89417 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest a new feature or enhancement to existing capabilities +title: '' +labels: '' +assignees: '' + +--- + +## Description + + + +## Alternatives + + + +## Compatibility + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..68a6e692a46 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,24 @@ + + +# Description + +Please include a summary of the change and which issue is fixed if applicable. Please also include relevant motivation and context. + +Fixes # (issue) + +# Checklist + +- [ ] I have performed a self-review of my own code +- [ ] I have run [clang-format](https://docs.openmc.org/en/latest/devguide/styleguide.html#automatic-formatting) (version 15) on any C++ source files (if applicable) +- [ ] I have followed the [style guidelines](https://docs.openmc.org/en/latest/devguide/styleguide.html#python) for Python source files (if applicable) +- [ ] I have made corresponding changes to the documentation (if applicable) +- [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1673af53198..d4a5bddcc39 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,119 +20,173 @@ env: COVERALLS_PARALLEL: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - jobs: main: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: matrix: - python-version: [3.8] + python-version: ["3.10"] mpi: [n, y] omp: [n, y] dagmc: [n] + ncrystal: [n] libmesh: [n] event: [n] vectfit: [n] include: - - python-version: 3.6 + - python-version: "3.8" + omp: n + mpi: n + - python-version: "3.9" omp: n mpi: n - - python-version: 3.7 + - python-version: "3.11" + omp: n + mpi: n + - python-version: "3.12" omp: n mpi: n - dagmc: y - python-version: 3.8 + python-version: "3.10" mpi: y omp: y + - ncrystal: y + python-version: "3.10" + mpi: n + omp: n - libmesh: y - python-version: 3.8 + python-version: "3.10" mpi: y omp: y - libmesh: y - python-version: 3.8 + python-version: "3.10" mpi: n omp: y - event: y - python-version: 3.8 + python-version: "3.10" omp: y mpi: n - vectfit: y - python-version: 3.8 + python-version: "3.10" omp: n mpi: y - name: 'Python ${{ matrix.python-version }} (omp=${{ matrix.omp }}, - mpi=${{ matrix.mpi }}, dagmc=${{ matrix.dagmc }}, + name: "Python ${{ matrix.python-version }} (omp=${{ matrix.omp }}, + mpi=${{ matrix.mpi }}, dagmc=${{ matrix.dagmc }}, ncrystal=${{ matrix.ncrystal }}, libmesh=${{ matrix.libmesh }}, event=${{ matrix.event }} - vectfit=${{ matrix.vectfit }})' + vectfit=${{ matrix.vectfit }})" env: MPI: ${{ matrix.mpi }} PHDF5: ${{ matrix.mpi }} OMP: ${{ matrix.omp }} DAGMC: ${{ matrix.dagmc }} + NCRYSTAL: ${{ matrix.ncrystal }} EVENT: ${{ matrix.event }} VECTFIT: ${{ matrix.vectfit }} LIBMESH: ${{ matrix.libmesh }} + NPY_DISABLE_CPU_FEATURES: "AVX512F AVX512_SKX" + OPENBLAS_NUM_THREADS: 1 + # libfabric complains about fork() as a result of using Python multiprocessing. + # We can work around it with RDMAV_FORK_SAFE=1 in libfabric < 1.13 and with + # FI_EFA_FORK_SAFE=1 in more recent versions. + RDMAV_FORK_SAFE: 1 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - - name: Environment Variables + + - name: Environment Variables run: | echo "DAGMC_ROOT=$HOME/DAGMC" echo "OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml" >> $GITHUB_ENV echo "OPENMC_ENDF_DATA=$HOME/endf-b-vii.1" >> $GITHUB_ENV - - - name: Apt dependencies + - name: Apt dependencies shell: bash run: | sudo apt -y update - sudo apt install -y libmpich-dev \ + sudo apt install -y libpng-dev \ libnetcdf-dev \ libpnetcdf-dev \ libhdf5-serial-dev \ - libhdf5-mpich-dev \ libeigen3-dev + + - name: Optional apt dependencies for MPI + shell: bash + if: ${{ matrix.mpi == 'y' }} + run: | + sudo apt install -y libhdf5-mpich-dev \ + libmpich-dev sudo update-alternatives --set mpi /usr/bin/mpicc.mpich sudo update-alternatives --set mpirun /usr/bin/mpirun.mpich sudo update-alternatives --set mpi-x86_64-linux-gnu /usr/include/x86_64-linux-gnu/mpich - - - name: install + - name: Optional apt dependencies for vectfit + shell: bash + if: ${{ matrix.vectfit == 'y' }} + run: sudo apt install -y libblas-dev liblapack-dev + + - name: install shell: bash run: | echo "$HOME/NJOY2016/build" >> $GITHUB_PATH $GITHUB_WORKSPACE/tools/ci/gha-install.sh - - - name: before + + - name: cache-xs + uses: actions/cache@v4 + with: + path: | + ~/nndc_hdf5 + ~/endf-b-vii.1 + key: ${{ runner.os }}-build-xs-cache + + - name: before shell: bash run: $GITHUB_WORKSPACE/tools/ci/gha-before-script.sh - - - name: test + + - name: test shell: bash - run: $GITHUB_WORKSPACE/tools/ci/gha-script.sh + run: | + CTEST_OUTPUT_ON_FAILURE=1 make test -C $GITHUB_WORKSPACE/build/ + $GITHUB_WORKSPACE/tools/ci/gha-script.sh - - - name: after_success + - name: Install OpenMOC for notebook testing + if: github.base_ref == 'master' + shell: bash -l {0} + run: | + cd ~ + git clone https://github.com/mit-crpg/openmoc && + cd openmoc + # OpenMOC has some custom commands that rely on setuptools/distutils + python setup.py install + # install twice to make sure openmoc.py is copied into the installation location + python setup.py install + + - name: Execute all Notebooks + if: github.base_ref == 'master' + shell: bash -l {0} + run: | + git clone https://github.com/mit-crpg/openmoc + cd openmoc + pytest -v .test + + - name: after_success shell: bash run: | - cpp-coveralls -i src -i include --exclude-pattern "/usr/*" --dump cpp_cov.json + cpp-coveralls -i src -i include -e src/external --exclude-pattern "/usr/*" --dump cpp_cov.json coveralls --merge=cpp_cov.json --service=github finish: needs: main runs-on: ubuntu-latest steps: - - name: Coveralls Finished - uses: coverallsapp/github-action@master - with: - github-token: ${{ secrets.github_token }} - parallel-finished: true + - name: Coveralls Finished + uses: coverallsapp/github-action@v2 + with: + github-token: ${{ secrets.github_token }} + parallel-finished: true diff --git a/.github/workflows/ci_openmc-notebooks.yaml b/.github/workflows/ci_openmc-notebooks.yaml new file mode 100644 index 00000000000..ef47c6a2c5f --- /dev/null +++ b/.github/workflows/ci_openmc-notebooks.yaml @@ -0,0 +1,76 @@ +name: Test Notebooks + +on: + # Allow this workflow to be run manually + workflow_dispatch: + # Run for pull requests to master branch + pull_request: + branches: + - master + +jobs: + # Set the job key + test-notebooks: + # Name the job + name: Test Jupyter Notebooks + # Set the type of machine to run on + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + + - name: Install conda environment + uses: conda-incubator/setup-miniconda@v3 + with: + activate-environment: jupyter-actions + environment-file: .github/environment.yml + python-version: 3.7 + + - name: Install OpenMC + shell: bash -l {0} + run: | + conda install -n base conda-libmamba-solver + conda config --set solver libmamba + conda activate jupyter-actions + conda install -c conda-forge openmc + + - name: Cache Cross Sections + id: xs-cache + uses: actions/cache@v3 + with: + # use this cache as long as the download script doesn't change + key: xs-cache-${{ hashfiles('.test/download-xs.sh') }} + path: ~/endfb-vii.1-hdf5/* + + - name: Download OpenMC Cross Sections + shell: bash -l {0} + if: steps.xs-cache.outputs.cache-hit != 'true' + run: | + ./.test/download-xs.sh + + - name: Set Environment Variables + shell: bash -l {0} + run: | + echo "OPENMC_CROSS_SECTIONS=$HOME/endfb-vii.1-hdf5/cross_sections.xml" >> $GITHUB_ENV + + - name: Install OpenMOC + shell: bash -l {0} + run: | + conda init bash + source ~/.bashrc + conda activate jupyter-actions + cd ~ + git clone https://github.com/mit-crpg/openmoc && + cd openmoc + # OpenMOC has some custom commands that rely on setuptools/distutils + python setup.py install + # install twice to make sure openmoc.py is copied into the installation location + python setup.py install + + - name: Execute all Notebooks + shell: bash -l {0} + run: | + conda activate jupyter-actions + pytest -v .test diff --git a/.github/workflows/dockerhub-publish-dagmc-libmesh.yml b/.github/workflows/dockerhub-publish-dagmc-libmesh.yml new file mode 100644 index 00000000000..813596953b7 --- /dev/null +++ b/.github/workflows/dockerhub-publish-dagmc-libmesh.yml @@ -0,0 +1,36 @@ +name: dockerhub-publish-latest-dagmc-libmesh + +on: + push: + branches: master + +jobs: + main: + runs-on: ubuntu-latest + steps: + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + push: true + tags: openmc/openmc:latest-dagmc-libmesh + build-args: | + build_dagmc=on + build_libmesh=on + compile_cores=2 + - + name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/dockerhub-publish-dagmc.yml b/.github/workflows/dockerhub-publish-dagmc.yml index d9622927953..6757f772713 100644 --- a/.github/workflows/dockerhub-publish-dagmc.yml +++ b/.github/workflows/dockerhub-publish-dagmc.yml @@ -10,25 +10,25 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: push: true tags: openmc/openmc:latest-dagmc build-args: | - include_dagmc=true + build_dagmc=on compile_cores=2 - name: Image digest diff --git a/.github/workflows/dockerhub-publish-dev.yml b/.github/workflows/dockerhub-publish-dev.yml index 73f62acaa2f..7a81363a78a 100644 --- a/.github/workflows/dockerhub-publish-dev.yml +++ b/.github/workflows/dockerhub-publish-dev.yml @@ -10,25 +10,26 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: push: true tags: openmc/openmc:develop build-args: | compile_cores=2 + openmc_branch=develop - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/dockerhub-publish-develop-dagmc-libmesh.yml b/.github/workflows/dockerhub-publish-develop-dagmc-libmesh.yml new file mode 100644 index 00000000000..a219f2a91d9 --- /dev/null +++ b/.github/workflows/dockerhub-publish-develop-dagmc-libmesh.yml @@ -0,0 +1,37 @@ +name: dockerhub-publish-develop-dagmc-libmesh + +on: + push: + branches: develop + +jobs: + main: + runs-on: ubuntu-latest + steps: + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + push: true + tags: openmc/openmc:develop-dagmc-libmesh + build-args: | + build_dagmc=on + build_libmesh=on + compile_cores=2 + openmc_branch=develop + - + name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/dockerhub-publish-develop-dagmc.yml b/.github/workflows/dockerhub-publish-develop-dagmc.yml index 0ded0c180e2..a901b8d3f0b 100644 --- a/.github/workflows/dockerhub-publish-develop-dagmc.yml +++ b/.github/workflows/dockerhub-publish-develop-dagmc.yml @@ -10,26 +10,27 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: push: true tags: openmc/openmc:develop-dagmc build-args: | - include_dagmc=true + build_dagmc=on compile_cores=2 + openmc_branch=develop - name: Image digest run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/dockerhub-publish-develop-libmesh.yml b/.github/workflows/dockerhub-publish-develop-libmesh.yml new file mode 100644 index 00000000000..22e9aa68fba --- /dev/null +++ b/.github/workflows/dockerhub-publish-develop-libmesh.yml @@ -0,0 +1,36 @@ +name: dockerhub-publish-develop-libmesh + +on: + push: + branches: develop + +jobs: + main: + runs-on: ubuntu-latest + steps: + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + push: true + tags: openmc/openmc:develop-libmesh + build-args: | + build_libmesh=on + compile_cores=2 + openmc_branch=develop + - + name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/dockerhub-publish-libmesh.yml b/.github/workflows/dockerhub-publish-libmesh.yml new file mode 100644 index 00000000000..843ce0f6fdb --- /dev/null +++ b/.github/workflows/dockerhub-publish-libmesh.yml @@ -0,0 +1,35 @@ +name: dockerhub-publish-latest-libmesh + +on: + push: + branches: master + +jobs: + main: + runs-on: ubuntu-latest + steps: + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + push: true + tags: openmc/openmc:latest-libmesh + build-args: | + build_libmesh=on + compile_cores=2 + - + name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/dockerhub-publish-release-dagmc-libmesh.yml b/.github/workflows/dockerhub-publish-release-dagmc-libmesh.yml new file mode 100644 index 00000000000..db62bb53e69 --- /dev/null +++ b/.github/workflows/dockerhub-publish-release-dagmc-libmesh.yml @@ -0,0 +1,39 @@ +name: dockerhub-publish-release-dagmc-libmesh + +on: + push: + tags: 'v*.*.*' + +jobs: + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + push: true + tags: openmc/openmc:${{ env.RELEASE_VERSION }}-dagmc-libmesh + build-args: | + build_dagmc=on + build_libmesh=on + compile_cores=2 + - + name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/dockerhub-publish-release-dagmc.yml b/.github/workflows/dockerhub-publish-release-dagmc.yml index 6038a9878be..de959378289 100644 --- a/.github/workflows/dockerhub-publish-release-dagmc.yml +++ b/.github/workflows/dockerhub-publish-release-dagmc.yml @@ -8,30 +8,30 @@ jobs: main: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: push: true tags: openmc/openmc:${{ env.RELEASE_VERSION }}-dagmc build-args: | - include_dagmc=true + build_dagmc=on compile_cores=2 - name: Image digest diff --git a/.github/workflows/dockerhub-publish-release-libmesh.yml b/.github/workflows/dockerhub-publish-release-libmesh.yml new file mode 100644 index 00000000000..e8ea98aebd5 --- /dev/null +++ b/.github/workflows/dockerhub-publish-release-libmesh.yml @@ -0,0 +1,38 @@ +name: dockerhub-publish-release-libmesh + +on: + push: + tags: 'v*.*.*' + +jobs: + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set env + run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Build and push + id: docker_build + uses: docker/build-push-action@v5 + with: + push: true + tags: openmc/openmc:${{ env.RELEASE_VERSION }}-libmesh + build-args: | + build_libmesh=on + compile_cores=2 + - + name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/.github/workflows/dockerhub-publish-release.yml b/.github/workflows/dockerhub-publish-release.yml index c94a50c0dac..fab030192b7 100644 --- a/.github/workflows/dockerhub-publish-release.yml +++ b/.github/workflows/dockerhub-publish-release.yml @@ -8,25 +8,25 @@ jobs: main: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Set env run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: push: true tags: openmc/openmc:${{ env.RELEASE_VERSION }} diff --git a/.github/workflows/dockerhub-publish.yml b/.github/workflows/dockerhub-publish.yml index 6bd0c4dc697..fd51a9fa733 100644 --- a/.github/workflows/dockerhub-publish.yml +++ b/.github/workflows/dockerhub-publish.yml @@ -10,20 +10,20 @@ jobs: steps: - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: push: true tags: openmc/openmc:latest diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml new file mode 100644 index 00000000000..cef14ca2c8c --- /dev/null +++ b/.github/workflows/format-check.yml @@ -0,0 +1,32 @@ +name: C++ Format Check + +on: + # allow workflow to be run manually + workflow_dispatch: + + pull_request: + branches: + - develop + - master + +jobs: + cpp-linter: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: cpp-linter/cpp-linter-action@v2 + id: linter + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + style: file + files-changed-only: true + tidy-checks: '-*' + version: '15' # clang-format version + file-annotations: true + step-summary: true + extensions: 'cpp,h' + + - name: Failure Check + if: steps.linter.outputs.checks-failed > 0 + run: echo "Some files failed the formatting check! See job summary and file annotations for more info" && exit 1 diff --git a/.gitignore b/.gitignore index 6838e756892..3b2a24a4dbc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,9 @@ # Compiled objects and modules *.a *.o -*.mod *.log *.out +*.pkl # Compiler python objects *.pyc @@ -35,9 +35,6 @@ build # build from src/utils/setup.py src/utils/build -# xml-fortran reader -src/xml-fortran/xmlreader - # Test results error file results_error.dat inputs_error.dat @@ -68,6 +65,7 @@ scripts/*.tar.* scripts/G4EMLOW*/ # Images +*.png *.ppm *.voxel *.vti @@ -79,17 +77,6 @@ scripts/G4EMLOW*/ # IPython notebook checkpoints .ipynb_checkpoints -# Jupyter notebooks -examples/jupyter/*.xml -examples/jupyter/*.png -examples/jupyter/*.xls -examples/jupyter/*.ace -examples/jupyter/*.endf -examples/jupyter/mgxs -examples/jupyter/tracks -examples/jupyter/fission-rates -examples/jupyter/plots - # Cython files *.c *.html @@ -116,3 +103,6 @@ CMakeSettings.json # Visual Studio Code configuration files .vscode/ + +# Python pickle files +*.pkl diff --git a/.gitmodules b/.gitmodules index ff91200103e..4dde5fd5ee5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,6 @@ [submodule "vendor/fmt"] path = vendor/fmt url = https://github.com/fmtlib/fmt.git +[submodule "vendor/Catch2"] + path = vendor/Catch2 + url = https://github.com/catchorg/Catch2.git diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 00000000000..98ca8b581da --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,13 @@ +version: 2 + +build: + os: "ubuntu-20.04" + tools: + python: "3.9" + +sphinx: + configuration: docs/source/conf.py + +python: + install: + - requirements: docs/requirements-rtd.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index dcd0a0bef55..1841251ff5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ -cmake_minimum_required(VERSION 3.3 FATAL_ERROR) +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(openmc C CXX) # Set version numbers set(OPENMC_VERSION_MAJOR 0) -set(OPENMC_VERSION_MINOR 12) -set(OPENMC_VERSION_RELEASE 2) +set(OPENMC_VERSION_MINOR 14) +set(OPENMC_VERSION_RELEASE 1) set(OPENMC_VERSION ${OPENMC_VERSION_MAJOR}.${OPENMC_VERSION_MINOR}.${OPENMC_VERSION_RELEASE}) configure_file(include/openmc/version.h.in "${CMAKE_BINARY_DIR}/include/openmc/version.h" @ONLY) @@ -17,68 +17,140 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) # Allow user to specify _ROOT variables -if (NOT (CMAKE_VERSION VERSION_LESS 3.12)) +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.12) cmake_policy(SET CMP0074 NEW) endif() +# Enable correct usage of CXX_EXTENSIONS +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.22) + cmake_policy(SET CMP0128 NEW) +endif() + #=============================================================================== # Command line options #=============================================================================== -option(openmp "Enable shared-memory parallelism with OpenMP" ON) -option(profile "Compile with profiling flags" OFF) -option(debug "Compile with debug flags" OFF) -option(optimize "Turn on all compiler optimization flags" OFF) -option(coverage "Compile with coverage analysis flags" OFF) -option(dagmc "Enable support for DAGMC (CAD) geometry" OFF) -option(libmesh "Enable support for libMesh unstructured mesh tallies" OFF) +option(OPENMC_USE_OPENMP "Enable shared-memory parallelism with OpenMP" ON) +option(OPENMC_BUILD_TESTS "Build tests" ON) +option(OPENMC_ENABLE_PROFILE "Compile with profiling flags" OFF) +option(OPENMC_ENABLE_COVERAGE "Compile with coverage analysis flags" OFF) +option(OPENMC_USE_DAGMC "Enable support for DAGMC (CAD) geometry" OFF) +option(OPENMC_USE_LIBMESH "Enable support for libMesh unstructured mesh tallies" OFF) +option(OPENMC_USE_MPI "Enable MPI" OFF) +option(OPENMC_USE_MCPL "Enable MCPL" OFF) +option(OPENMC_USE_NCRYSTAL "Enable support for NCrystal scattering" OFF) +option(OPENMC_USE_UWUW "Enable UWUW" OFF) + +# Warnings for deprecated options +foreach(OLD_OPT IN ITEMS "openmp" "profile" "coverage" "dagmc" "libmesh") + if(DEFINED ${OLD_OPT}) + string(TOUPPER ${OLD_OPT} OPT_UPPER) + if ("${OLD_OPT}" STREQUAL "profile" OR "${OLD_OPT}" STREQUAL "coverage") + set(NEW_OPT_PREFIX "OPENMC_ENABLE") + else() + set(NEW_OPT_PREFIX "OPENMC_USE") + endif() + message(WARNING "The OpenMC CMake option '${OLD_OPT}' has been deprecated. " + "Its value will be ignored. " + "Please use '-D${NEW_OPT_PREFIX}_${OPT_UPPER}=${${OLD_OPT}}' instead.") + unset(${OLD_OPT} CACHE) + endif() +endforeach() + +foreach(OLD_BLD in ITEMS "debug" "optimize") + if(DEFINED ${OLD_BLD}) + if("${OLD_BLD}" STREQUAL "debug") + set(BLD_VAR "Debug") + else() + set(BLD_VAR "Release") + endif() + message(WARNING "The OpenMC CMake option '${OLD_BLD}' has been deprecated. " + "Its value will be ignored. " + "OpenMC now uses the CMAKE_BUILD_TYPE variable to set the build mode. " + "Please use '-DCMAKE_BUILD_TYPE=${BLD_VAR}' instead.") + unset(${OLD_BLD} CACHE) + endif() +endforeach() + +#=============================================================================== +# Set a default build configuration if not explicitly specified +#=============================================================================== + +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "No build type selected, defaulting to RelWithDebInfo") + set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build" FORCE) +endif() + +#=============================================================================== +# OpenMP for shared-memory parallelism (and GPU support some day!) +#=============================================================================== + +if(OPENMC_USE_OPENMP) + find_package(OpenMP REQUIRED) +endif() #=============================================================================== # MPI for distributed-memory parallelism #=============================================================================== -set(MPI_ENABLED FALSE) -if(${CMAKE_CXX_COMPILER} MATCHES "(mpi[^/]*|CC)$") - message(STATUS "Detected MPI wrapper: ${CMAKE_CXX_COMPILER}") - set(MPI_ENABLED TRUE) +if(OPENMC_USE_MPI) + find_package(MPI REQUIRED) endif() #=============================================================================== -# DAGMC Geometry Support - need DAGMC/MOAB +# Helper macro for finding a dependency #=============================================================================== -if(dagmc) - find_package(DAGMC REQUIRED PATH_SUFFIXES lib/cmake) - if (${DAGMC_VERSION} VERSION_LESS 3.2.0) - message(FATAL_ERROR "Discovered DAGMC Version: ${DAGMC_VERSION}. \ - Please update DAGMC to version 3.2.0 or greater.") + +macro(find_package_write_status pkg) + find_package(${pkg} QUIET NO_SYSTEM_ENVIRONMENT_PATH) + if(${pkg}_FOUND) + message(STATUS "Found ${pkg}: ${${pkg}_DIR} (version ${${pkg}_VERSION})") + else() + message(STATUS "Did not find ${pkg}, will use submodule instead") endif() -endif() +endmacro() #=============================================================================== -# Check for submodules perhaps already on system +# NCrystal Scattering Support #=============================================================================== -# If not found, we just pull appropriate versions from github and build them. -find_package(fmt QUIET NO_SYSTEM_ENVIRONMENT_PATH) -if(fmt_FOUND) - message(STATUS "Found fmt: ${fmt_DIR} (version ${fmt_VERSION})") -else() - message(STATUS "Did not find fmt, will use submodule instead") +if(OPENMC_USE_NCRYSTAL) + find_package(NCrystal REQUIRED) + message(STATUS "Found NCrystal: ${NCrystal_DIR} (version ${NCrystal_VERSION})") endif() -find_package(pugixml QUIET NO_SYSTEM_ENVIRONMENT_PATH) -if(pugixml_FOUND) - message(STATUS "Found pugixml: ${pugixml_DIR}") -else() - message(STATUS "Did not find pugixml, will use submodule instead") + +#=============================================================================== +# DAGMC Geometry Support - need DAGMC/MOAB +#=============================================================================== + +if(OPENMC_USE_DAGMC) + find_package(DAGMC REQUIRED PATH_SUFFIXES lib/cmake) + if (${DAGMC_VERSION} VERSION_LESS 3.2.0) + message(FATAL_ERROR "Discovered DAGMC Version: ${DAGMC_VERSION}." + "Please update DAGMC to version 3.2.0 or greater.") + endif() + message(STATUS "Found DAGMC: ${DAGMC_DIR} (version ${DAGMC_VERSION})") + + # Check if UWUW is needed and available + if(OPENMC_USE_UWUW AND NOT DAGMC_BUILD_UWUW) + message(FATAL_ERROR "UWUW is enabled but DAGMC was not configured with UWUW.") + endif() endif() #=============================================================================== # libMesh Unstructured Mesh Support #=============================================================================== -if(libmesh) + +if(OPENMC_USE_LIBMESH) find_package(LIBMESH REQUIRED) endif() +#=============================================================================== +# libpng +#=============================================================================== + +find_package(PNG) + #=============================================================================== # HDF5 for binary output #=============================================================================== @@ -97,11 +169,16 @@ if(NOT DEFINED HDF5_PREFER_PARALLEL) endif() find_package(HDF5 REQUIRED COMPONENTS C HL) + +# Remove HDF5 transitive dependencies that are system libraries +list(FILTER HDF5_LIBRARIES EXCLUDE REGEX ".*lib(pthread|dl|m).*") +message(STATUS "HDF5 Libraries: ${HDF5_LIBRARIES}") + if(HDF5_IS_PARALLEL) - if(NOT MPI_ENABLED) - message(FATAL_ERROR "Parallel HDF5 was detected, but the detected compiler,\ - ${CMAKE_CXX_COMPILER}, does not support MPI. An MPI-capable compiler must \ - be used with parallel HDF5.") + if(NOT OPENMC_USE_MPI) + message(FATAL_ERROR "Parallel HDF5 was detected, but MPI was not enabled.\ + To use parallel HDF5, OpenMC needs to be built with MPI support by passing\ + -DOPENMC_USE_MPI=ON when calling cmake.") endif() message(STATUS "Using parallel HDF5") endif() @@ -109,10 +186,19 @@ endif() # Version 1.12 of HDF5 deprecates the H5Oget_info_by_idx() interface. # Thus, we give these flags to allow usage of the old interface in newer # versions of HDF5. -if(NOT (${HDF5_VERSION} VERSION_LESS 1.12.0)) +if(${HDF5_VERSION} VERSION_GREATER_EQUAL 1.12.0) list(APPEND cxxflags -DH5Oget_info_by_idx_vers=1 -DH5O_info_t_vers=1) endif() +#=============================================================================== +# MCPL +#=============================================================================== + +if (OPENMC_USE_MCPL) + find_package(MCPL REQUIRED) + message(STATUS "Found MCPL: ${MCPL_DIR} (found version \"${MCPL_VERSION}\")") +endif() + #=============================================================================== # Set compile/link flags based on which compiler is being used #=============================================================================== @@ -120,30 +206,13 @@ endif() # Skip for Visual Studio which has its own configurations through GUI if(NOT MSVC) -if(openmp) - # Requires CMake 3.1+ - find_package(OpenMP) - if(OPENMP_FOUND) - list(APPEND cxxflags ${OpenMP_CXX_FLAGS}) - list(APPEND ldflags ${OpenMP_CXX_FLAGS}) - endif() -endif() - set(CMAKE_POSITION_INDEPENDENT_CODE ON) -list(APPEND cxxflags -O2) -if(debug) - list(REMOVE_ITEM cxxflags -O2) - list(APPEND cxxflags -g -O0) -endif() -if(profile) +if(OPENMC_ENABLE_PROFILE) list(APPEND cxxflags -g -fno-omit-frame-pointer) endif() -if(optimize) - list(REMOVE_ITEM cxxflags -O2) - list(APPEND cxxflags -O3) -endif() -if(coverage) + +if(OPENMC_ENABLE_COVERAGE) list(APPEND cxxflags --coverage) list(APPEND ldflags --coverage) endif() @@ -183,6 +252,7 @@ endif() # pugixml library #=============================================================================== +find_package_write_status(pugixml) if (NOT pugixml_FOUND) add_subdirectory(vendor/pugixml) set_target_properties(pugixml PROPERTIES CXX_STANDARD 14 CXX_EXTENSIONS OFF) @@ -192,6 +262,7 @@ endif() # {fmt} library #=============================================================================== +find_package_write_status(fmt) if (NOT fmt_FOUND) set(FMT_INSTALL ON CACHE BOOL "Generate the install target.") add_subdirectory(vendor/fmt) @@ -202,25 +273,40 @@ endif() #=============================================================================== # CMake 3.13+ will complain about policy CMP0079 unless it is set explicitly -if (NOT (CMAKE_VERSION VERSION_LESS 3.13)) +if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.13) cmake_policy(SET CMP0079 NEW) endif() -add_subdirectory(vendor/xtl) -set(xtl_DIR ${CMAKE_CURRENT_BINARY_DIR}/vendor/xtl) -add_subdirectory(vendor/xtensor) +find_package_write_status(xtensor) +if (NOT xtensor_FOUND) + add_subdirectory(vendor/xtl) + set(xtl_DIR ${CMAKE_CURRENT_BINARY_DIR}/vendor/xtl) + add_subdirectory(vendor/xtensor) +endif() #=============================================================================== # GSL header-only library #=============================================================================== -set(GSL_LITE_OPT_INSTALL_COMPAT_HEADER ON CACHE BOOL - "Install MS-GSL compatibility header ") -add_subdirectory(vendor/gsl-lite) +find_package_write_status(gsl-lite) +if (NOT gsl-lite_FOUND) + add_subdirectory(vendor/gsl-lite) -# Make sure contract violations throw exceptions -target_compile_definitions(gsl-lite-v1 INTERFACE GSL_THROW_ON_CONTRACT_VIOLATION) -target_compile_definitions(gsl-lite-v1 INTERFACE gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=1) + # Make sure contract violations throw exceptions + target_compile_definitions(gsl-lite-v1 INTERFACE GSL_THROW_ON_CONTRACT_VIOLATION) + target_compile_definitions(gsl-lite-v1 INTERFACE gsl_CONFIG_ALLOWS_NONSTRICT_SPAN_COMPARISON=1) +endif() + +#=============================================================================== +# Catch2 library +#=============================================================================== + +if(OPENMC_BUILD_TESTS) + find_package_write_status(Catch2) + if (NOT Catch2_FOUND) + add_subdirectory(vendor/Catch2) + endif() +endif() #=============================================================================== # RPATH information @@ -251,18 +337,6 @@ if("${isSystemDir}" STREQUAL "-1") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") endif() -#=============================================================================== -# faddeeva library -#=============================================================================== - -add_library(faddeeva STATIC vendor/faddeeva/Faddeeva.cc) -target_include_directories(faddeeva - PUBLIC - $ - $ -) -target_compile_options(faddeeva PRIVATE ${cxxflags}) - #=============================================================================== # libopenmc #=============================================================================== @@ -271,10 +345,10 @@ list(APPEND libopenmc_SOURCES src/bank.cpp src/boundary_condition.cpp src/bremsstrahlung.cpp - src/dagmc.cpp src/cell.cpp src/cmfd_solver.cpp src/cross_sections.cpp + src/dagmc.cpp src/distribution.cpp src/distribution_angle.cpp src/distribution_energy.cpp @@ -284,18 +358,21 @@ list(APPEND libopenmc_SOURCES src/endf.cpp src/error.cpp src/event.cpp - src/initialize.cpp + src/file_utils.cpp src/finalize.cpp src/geometry.cpp src/geometry_aux.cpp src/hdf5_interface.cpp + src/initialize.cpp src/lattice.cpp src/material.cpp src/math_functions.cpp + src/mcpl_interface.cpp src/mesh.cpp src/message_passing.cpp src/mgxs.cpp src/mgxs_interface.cpp + src/ncrystal_interface.cpp src/nuclide.cpp src/output.cpp src/particle.cpp @@ -310,6 +387,9 @@ list(APPEND libopenmc_SOURCES src/progress_bar.cpp src/random_dist.cpp src/random_lcg.cpp + src/random_ray/random_ray_simulation.cpp + src/random_ray/random_ray.cpp + src/random_ray/flat_source_domain.cpp src/reaction.cpp src/reaction_product.cpp src/scattdata.cpp @@ -328,18 +408,20 @@ list(APPEND libopenmc_SOURCES src/tallies/derivative.cpp src/tallies/filter.cpp src/tallies/filter_azimuthal.cpp - src/tallies/filter_cellborn.cpp - src/tallies/filter_cellfrom.cpp src/tallies/filter_cell.cpp src/tallies/filter_cell_instance.cpp + src/tallies/filter_cellborn.cpp + src/tallies/filter_cellfrom.cpp + src/tallies/filter_collision.cpp src/tallies/filter_delayedgroup.cpp src/tallies/filter_distribcell.cpp - src/tallies/filter_energyfunc.cpp src/tallies/filter_energy.cpp - src/tallies/filter_collision.cpp + src/tallies/filter_energyfunc.cpp src/tallies/filter_legendre.cpp src/tallies/filter_material.cpp + src/tallies/filter_materialfrom.cpp src/tallies/filter_mesh.cpp + src/tallies/filter_meshborn.cpp src/tallies/filter_meshsurface.cpp src/tallies/filter_mu.cpp src/tallies/filter_particle.cpp @@ -347,20 +429,28 @@ list(APPEND libopenmc_SOURCES src/tallies/filter_sph_harm.cpp src/tallies/filter_sptl_legendre.cpp src/tallies/filter_surface.cpp + src/tallies/filter_time.cpp src/tallies/filter_universe.cpp src/tallies/filter_zernike.cpp src/tallies/tally.cpp src/tallies/tally_scoring.cpp src/tallies/trigger.cpp - src/timer.cpp src/thermal.cpp + src/timer.cpp src/track_output.cpp + src/universe.cpp src/urr.cpp src/volume_calc.cpp + src/weight_windows.cpp src/wmp.cpp src/xml_interface.cpp src/xsdata.cpp) +# Add bundled external dependencies +list(APPEND libopenmc_SOURCES + src/external/quartic_solver.cpp + src/external/Faddeeva.cc) + # For Visual Studio compilers if(MSVC) # Use static library (otherwise explicit symbol portings are needed) @@ -373,6 +463,8 @@ else() add_library(libopenmc SHARED ${libopenmc_SOURCES}) endif() +add_library(OpenMC::libopenmc ALIAS libopenmc) + # Avoid vs error lnk1149 :output filename matches input filename if(NOT MSVC) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc) @@ -389,12 +481,13 @@ target_include_directories(libopenmc target_compile_options(libopenmc PRIVATE ${cxxflags}) # Add include directory for configured version file -target_include_directories(libopenmc PRIVATE ${CMAKE_BINARY_DIR}/include) +target_include_directories(libopenmc + PUBLIC $) if (HDF5_IS_PARALLEL) target_compile_definitions(libopenmc PRIVATE -DPHDF5) endif() -if (MPI_ENABLED) +if (OPENMC_USE_MPI) target_compile_definitions(libopenmc PUBLIC -DOPENMC_MPI) endif() @@ -413,31 +506,84 @@ endif() # target_link_libraries treats any arguments starting with - but not -l as # linker flags. Thus, we can pass both linker flags and libraries together. target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARIES} - pugixml faddeeva xtensor gsl-lite-v1 fmt::fmt) + xtensor gsl::gsl-lite-v1 fmt::fmt ${CMAKE_DL_LIBS}) -if(dagmc) +if(TARGET pugixml::pugixml) + target_link_libraries(libopenmc pugixml::pugixml) +else() + target_link_libraries(libopenmc pugixml) +endif() + +if(OPENMC_USE_DAGMC) target_compile_definitions(libopenmc PRIVATE DAGMC) - target_link_libraries(libopenmc dagmc-shared uwuw-shared) + target_link_libraries(libopenmc dagmc-shared) endif() -if(libmesh) +if(OPENMC_USE_LIBMESH) target_compile_definitions(libopenmc PRIVATE LIBMESH) target_link_libraries(libopenmc PkgConfig::LIBMESH) endif() +if (PNG_FOUND) + target_compile_definitions(libopenmc PRIVATE USE_LIBPNG) + target_link_libraries(libopenmc PNG::PNG) +endif() + +if (OPENMC_USE_OPENMP) + target_link_libraries(libopenmc OpenMP::OpenMP_CXX) +endif() + +if (OPENMC_USE_MPI) + target_link_libraries(libopenmc MPI::MPI_CXX) +endif() + +if (OPENMC_BUILD_TESTS) + # Add cpp tests directory + include(CTest) + add_subdirectory(tests/cpp_unit_tests) +endif() + +if (OPENMC_USE_MCPL) + target_compile_definitions(libopenmc PUBLIC OPENMC_MCPL) + target_link_libraries(libopenmc MCPL::mcpl) +endif() + +if(OPENMC_USE_NCRYSTAL) + target_compile_definitions(libopenmc PRIVATE NCRYSTAL) + target_link_libraries(libopenmc NCrystal::NCrystal) +endif() + +if (OPENMC_USE_UWUW) + target_compile_definitions(libopenmc PRIVATE UWUW) + target_link_libraries(libopenmc uwuw-shared) +endif() + +#=============================================================================== +# Log build info that this executable can report later +#=============================================================================== +target_compile_definitions(libopenmc PRIVATE BUILD_TYPE=${CMAKE_BUILD_TYPE}) +target_compile_definitions(libopenmc PRIVATE COMPILER_ID=${CMAKE_CXX_COMPILER_ID}) +target_compile_definitions(libopenmc PRIVATE COMPILER_VERSION=${CMAKE_CXX_COMPILER_VERSION}) +if (OPENMC_ENABLE_PROFILE) + target_compile_definitions(libopenmc PRIVATE PROFILINGBUILD) +endif() +if (OPENMC_ENABLE_COVERAGE) + target_compile_definitions(libopenmc PRIVATE COVERAGEBUILD) +endif() + #=============================================================================== # openmc executable #=============================================================================== add_executable(openmc src/main.cpp) +add_executable(OpenMC::openmc ALIAS openmc) target_compile_options(openmc PRIVATE ${cxxflags}) target_include_directories(openmc PRIVATE ${CMAKE_BINARY_DIR}/include) target_link_libraries(openmc libopenmc) -# Ensure C++14 standard is used. Starting with CMake 3.8, another way this could -# be done is using the cxx_std_14 compiler feature. -set_target_properties( - openmc libopenmc faddeeva - PROPERTIES CXX_STANDARD 14 CXX_EXTENSIONS OFF) +# Ensure C++14 standard is used and turn off GNU extensions +target_compile_features(openmc PUBLIC cxx_std_14) +target_compile_features(libopenmc PUBLIC cxx_std_14) +set_target_properties(openmc libopenmc PROPERTIES CXX_EXTENSIONS OFF) #=============================================================================== # Python package @@ -457,7 +603,7 @@ configure_file(cmake/OpenMCConfig.cmake.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIR configure_file(cmake/OpenMCConfigVersion.cmake.in "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake" @ONLY) set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC) -install(TARGETS openmc libopenmc faddeeva +install(TARGETS openmc libopenmc EXPORT openmc-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} @@ -468,7 +614,6 @@ install(EXPORT openmc-targets NAMESPACE OpenMC:: DESTINATION ${INSTALL_CONFIGDIR}) -install(DIRECTORY src/relaxng DESTINATION ${CMAKE_INSTALL_DATADIR}/openmc) install(FILES "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfig.cmake" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/OpenMCConfigVersion.cmake" @@ -477,7 +622,3 @@ install(FILES man/man1/openmc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) install(FILES LICENSE DESTINATION "${CMAKE_INSTALL_DOCDIR}" RENAME copyright) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(FILES "${CMAKE_BINARY_DIR}/include/openmc/version.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openmc) - -# Copy headers for vendored dependencies (note that all except faddeeva are handled -# separately since they are managed by CMake) -install(DIRECTORY vendor/faddeeva DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/CODEOWNERS b/CODEOWNERS index a061b7b6ea7..6d452e36653 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,9 +5,9 @@ openmc/data/ @paulromano openmc/lib/ @paulromano # Depletion -openmc/deplete/ @drewejohnson -tests/regression_tests/deplete/ @drewejohnson -tests/unit_tests/test_deplete_*.py @drewejohnson +openmc/deplete/ @paulromano +tests/regression_tests/deplete/ @paulromano +tests/unit_tests/test_deplete_*.py @paulromano # MG-related functionality openmc/mgxs_library.py @nelsonag @@ -26,6 +26,12 @@ src/dagmc.cpp @pshriwise tests/regression_tests/dagmc/ @pshriwise tests/unit_tests/dagmc/ @pshriwise +# Weight windows +openmc/weight_windows.py @pshriwise +openmc/lib/weight_windows.py @pshriwise +src/weight_windows.py @pshriwise +tests/unit_tests/weightwindows/ @pshriwise + # Photon transport openmc/data/BREMX.DAT @amandalund openmc/data/compton_profiles.h5 @amandalund @@ -46,3 +52,15 @@ openmc/lib/plot.py @pshriwise # Resonance covariance openmc/data/resonance_covariance.py @icmeyer + +# Docker +Dockerfile @shimwell + +# Random ray +src/random_ray/ @jtramm + +# NCrystal interface +src/ncrystal_interface.cpp @marquezj + +# MCPL interface +src/mcpl_interface.cpp @ebknudsen diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index be506f919ae..378ca346a85 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,9 +13,8 @@ openmc@anl.gov. ## Resources - [GitHub Repository](https://github.com/openmc-dev/openmc) -- [Documentation](http://openmc.readthedocs.io/en/latest) -- [User's Mailing List](openmc-users@googlegroups.com) -- [Developer's Mailing List](openmc-dev@googlegroups.com) +- [Documentation](http://docs.openmc.org/en/latest) +- [Discussion Forum](https://openmc.discourse.group) - [Slack Community](https://openmc.slack.com/signup) (If you don't see your domain listed, contact openmc@anl.gov) @@ -37,10 +36,10 @@ development team will be happy to discuss it. All changes to OpenMC happen through pull requests. For a full overview of the process, see the developer's guide section on [Contributing to -OpenMC](http://openmc.readthedocs.io/en/latest/devguide/contributing.html). +OpenMC](https://docs.openmc.org/en/latest/devguide/contributing.html). ## Code Style Before you run off to make changes to the code, please have a look at our [style -guide](http://openmc.readthedocs.io/en/latest/devguide/styleguide.html), which +guide](https://docs.openmc.org/en/latest/devguide/styleguide.html), which is used when reviewing new contributions. diff --git a/Dockerfile b/Dockerfile index 89fec615ef7..107df4afe76 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,149 +1,239 @@ -# To build with OpenMC +# To build with OpenMC and by default this Dockerfile builds the master branch of OpenMC. # docker build -t openmc . +# To build with OpenMC develop branch +# docker build -t openmc_develop --build-arg openmc_branch=develop . + # To build with OpenMC and DAGMC enabled -# docker build -t openmc_dagmc --build-arg include_dagmc=true . +# docker build -t openmc_dagmc --build-arg build_dagmc=on --build-arg compile_cores=4 . + +# To build with OpenMC and Libmesh enabled +# docker build -t openmc_libmesh --build-arg build_libmesh=on --build-arg compile_cores=4 . -# To make use of multiple cores during the compile stages of the docker build -# docker build -t openmc_dagmc --build-arg compile_cores=8 . +# To build with both DAGMC and Libmesh enabled +# docker build -t openmc_dagmc_libmesh --build-arg build_dagmc=on --build-arg build_libmesh=on --build-arg compile_cores=4 . -FROM ubuntu:latest +# sudo docker run image_name:tag_name or ID with no tag sudo docker run ID number -# By default this Dockerfile builds OpenMC without dagmc -ARG include_dagmc=false +# global ARG as these ARGS are used in multiple stages # By default one core is used to compile ARG compile_cores=1 +# By default this Dockerfile builds OpenMC without DAGMC and LIBMESH support +ARG build_dagmc=off +ARG build_libmesh=off + +FROM debian:bookworm-slim AS dependencies + +ARG compile_cores +ARG build_dagmc +ARG build_libmesh + +# Set default value of HOME to /root +ENV HOME=/root + +# Embree variables +ENV EMBREE_TAG='v4.3.1' +ENV EMBREE_REPO='https://github.com/embree/embree' +ENV EMBREE_INSTALL_DIR=$HOME/EMBREE/ + +# MOAB variables +ENV MOAB_TAG='5.5.1' +ENV MOAB_REPO='https://bitbucket.org/fathomteam/moab/' + +# Double-Down variables +ENV DD_TAG='v1.1.0' +ENV DD_REPO='https://github.com/pshriwise/double-down' +ENV DD_INSTALL_DIR=$HOME/Double_down + +# DAGMC variables +ENV DAGMC_BRANCH='v3.2.3' +ENV DAGMC_REPO='https://github.com/svalinn/DAGMC' +ENV DAGMC_INSTALL_DIR=$HOME/DAGMC/ + +# LIBMESH variables +ENV LIBMESH_TAG='v1.7.1' +ENV LIBMESH_REPO='https://github.com/libMesh/libmesh' +ENV LIBMESH_INSTALL_DIR=$HOME/LIBMESH + +# NJOY variables +ENV NJOY_REPO='https://github.com/njoy/NJOY2016' + # Setup environment variables for Docker image -ENV CC=/usr/bin/mpicc CXX=/usr/bin/mpicxx \ - PATH=/opt/openmc/bin:/opt/NJOY2016/build:$PATH \ - LD_LIBRARY_PATH=/opt/openmc/lib:$LD_LIBRARY_PATH \ - OPENMC_CROSS_SECTIONS=/root/nndc_hdf5/cross_sections.xml \ +ENV LD_LIBRARY_PATH=${DAGMC_INSTALL_DIR}/lib:$LD_LIBRARY_PATH \ OPENMC_ENDF_DATA=/root/endf-b-vii.1 \ DEBIAN_FRONTEND=noninteractive -# Install dependencies from Debian package manager +# Install and update dependencies from Debian package manager RUN apt-get update -y && \ apt-get upgrade -y && \ apt-get install -y \ - python3-pip python-is-python3 wget git gfortran g++ cmake \ + python3-pip python-is-python3 wget git build-essential cmake \ mpich libmpich-dev libhdf5-serial-dev libhdf5-mpich-dev \ - imagemagick && \ + libpng-dev python3-venv && \ apt-get autoremove +# create virtual enviroment to avoid externally managed environment error +RUN python3 -m venv openmc_venv +ENV PATH=/openmc_venv/bin:$PATH + # Update system-provided pip -RUN pip3 install --upgrade pip +RUN pip install --upgrade pip # Clone and install NJOY2016 -RUN git clone https://github.com/njoy/NJOY2016.git /opt/NJOY2016 && \ - cd /opt/NJOY2016 && \ - mkdir build && cd build && \ - cmake -Dstatic=on .. && make 2>/dev/null && make install - -# Clone and install OpenMC without DAGMC -RUN if [ "$include_dagmc" = "false" ] ; \ - then git clone --recurse-submodules https://github.com/openmc-dev/openmc.git /opt/openmc ; \ - cd /opt/openmc ; \ - mkdir -p build ; \ - cd build ; \ - cmake -Doptimize=on \ - -DHDF5_PREFER_PARALLEL=on .. ; \ - make -j"$compile_cores" ; \ - make -j"$compile_cores" install ; \ - cd .. ; \ - pip install -e .[test] ; \ - fi - -# install addition packages required for DAGMC -RUN if [ "$include_dagmc" = "true" ] ; \ - then apt-get --yes install libeigen3-dev ; \ - apt-get --yes install libnetcdf-dev ; \ - apt-get --yes install libtbb-dev ; \ - apt-get --yes install libglfw3-dev ; \ - fi - -# Clone and install Embree -RUN if [ "$include_dagmc" = "true" ] ; \ - then git clone --single-branch --branch v3.12.2 https://github.com/embree/embree.git ; \ - cd embree ; \ - mkdir build ; \ - cd build ; \ - cmake .. -DCMAKE_INSTALL_PREFIX=.. \ - -DEMBREE_ISPC_SUPPORT=OFF ; \ - make -j"$compile_cores" ; \ - make -j"$compile_cores" install ; \ +RUN cd $HOME \ + && git clone --single-branch --depth 1 ${NJOY_REPO} \ + && cd NJOY2016 \ + && mkdir build \ + && cd build \ + && cmake -Dstatic=on .. \ + && make 2>/dev/null -j${compile_cores} install \ + && rm -rf $HOME/NJOY2016 + + +RUN if [ "$build_dagmc" = "on" ]; then \ + # Install addition packages required for DAGMC + apt-get -y install libeigen3-dev libnetcdf-dev libtbb-dev libglfw3-dev \ + && pip install --upgrade numpy "cython<3.0" \ + # Clone and install EMBREE + && mkdir -p $HOME/EMBREE && cd $HOME/EMBREE \ + && git clone --single-branch -b ${EMBREE_TAG} --depth 1 ${EMBREE_REPO} \ + && mkdir build && cd build \ + && cmake ../embree \ + -DCMAKE_INSTALL_PREFIX=${EMBREE_INSTALL_DIR} \ + -DEMBREE_MAX_ISA=NONE \ + -DEMBREE_ISA_SSE42=ON \ + -DEMBREE_ISPC_SUPPORT=OFF \ + && make 2>/dev/null -j${compile_cores} install \ + && rm -rf ${EMBREE_INSTALL_DIR}/build ${EMBREE_INSTALL_DIR}/embree ; \ + # Clone and install MOAB + mkdir -p $HOME/MOAB && cd $HOME/MOAB \ + && git clone --single-branch -b ${MOAB_TAG} --depth 1 ${MOAB_REPO} \ + && mkdir build && cd build \ + && cmake ../moab -DENABLE_HDF5=ON \ + -DENABLE_NETCDF=ON \ + -DBUILD_SHARED_LIBS=OFF \ + -DENABLE_FORTRAN=OFF \ + -DENABLE_BLASLAPACK=OFF \ + && make 2>/dev/null -j${compile_cores} install \ + && cmake ../moab \ + -DENABLE_PYMOAB=ON \ + -DBUILD_SHARED_LIBS=ON \ + && make 2>/dev/null -j${compile_cores} install \ + && cd pymoab && bash install.sh \ + && python setup.py install \ + && python -c "import pymoab" \ + && rm -rf $HOME/MOAB ; \ + # Clone and install Double-Down + mkdir -p $HOME/Double_down && cd $HOME/Double_down \ + && git clone --single-branch -b ${DD_TAG} --depth 1 ${DD_REPO} \ + && mkdir build && cd build \ + && cmake ../double-down -DCMAKE_INSTALL_PREFIX=${DD_INSTALL_DIR} \ + -DMOAB_DIR=/usr/local \ + -DEMBREE_DIR=${EMBREE_INSTALL_DIR} \ + && make 2>/dev/null -j${compile_cores} install \ + && rm -rf ${DD_INSTALL_DIR}/build ${DD_INSTALL_DIR}/double-down ; \ + # Clone and install DAGMC + mkdir -p $HOME/DAGMC && cd $HOME/DAGMC \ + && git clone --single-branch -b ${DAGMC_BRANCH} --depth 1 ${DAGMC_REPO} \ + && mkdir build && cd build \ + && cmake ../DAGMC -DBUILD_TALLY=ON \ + -DCMAKE_INSTALL_PREFIX=${DAGMC_INSTALL_DIR} \ + -DMOAB_DIR=/usr/local \ + -DDOUBLE_DOWN=ON \ + -DDOUBLE_DOWN_DIR=${DD_INSTALL_DIR} \ + -DCMAKE_PREFIX_PATH=${DD_INSTALL_DIR}/lib \ + -DBUILD_STATIC_LIBS=OFF \ + && make 2>/dev/null -j${compile_cores} install \ + && rm -rf ${DAGMC_INSTALL_DIR}/DAGMC ${DAGMC_INSTALL_DIR}/build ; \ fi -# Clone and install MOAB -RUN if [ "$include_dagmc" = "true" ] ; \ - then pip install --upgrade numpy cython ; \ - mkdir MOAB ; \ - cd MOAB ; \ - mkdir build ; \ - git clone --single-branch --branch 5.2.1 https://bitbucket.org/fathomteam/moab.git ; \ - cd build ; \ - cmake ../moab -DENABLE_HDF5=ON \ - -DENABLE_NETCDF=ON \ - -DBUILD_SHARED_LIBS=OFF \ - -DENABLE_FORTRAN=OFF \ - -DENABLE_BLASLAPACK=OFF ; \ - make -j"$compile_cores" ; \ - make -j"$compile_cores" install ; \ - rm -rf * ; \ - cmake ../moab -DBUILD_SHARED_LIBS=ON \ - -DENABLE_HDF5=ON \ - -DENABLE_PYMOAB=ON \ - -DENABLE_FORTRAN=OFF \ - -DENABLE_BLASLAPACK=OFF ; \ - make -j"$compile_cores" ; \ - make -j"$compile_cores" install ; \ - fi -# Clone and install Double-Down -RUN if [ "$include_dagmc" = "true" ] ; \ - then git clone --single-branch --branch main https://github.com/pshriwise/double-down.git ; \ - cd double-down ; \ - mkdir build ; \ - cd build ; \ - cmake .. -DCMAKE_INSTALL_PREFIX=.. \ - -DMOAB_DIR=/usr/local \ - -DEMBREE_DIR=/embree ; \ - make -j"$compile_cores" ; \ - make -j"$compile_cores" install ; \ +RUN if [ "$build_libmesh" = "on" ]; then \ + # Install addition packages required for LIBMESH + apt-get -y install m4 libnetcdf-dev libpnetcdf-dev \ + # Install LIBMESH + && mkdir -p $HOME/LIBMESH && cd $HOME/LIBMESH \ + && git clone --shallow-submodules --recurse-submodules --single-branch -b ${LIBMESH_TAG} --depth 1 ${LIBMESH_REPO} \ + && mkdir build && cd build \ + && ../libmesh/configure \ + --prefix=${LIBMESH_INSTALL_DIR} CXX=mpicxx CC=mpicc FC=mpifort F77=mpif77 \ + --enable-exodus \ + --enable-mpi \ + --enable-silent-rules \ + --enable-unique-id \ + --disable-eigen \ + --disable-fortran \ + --disable-lapack \ + --disable-examples \ + --disable-warnings \ + --disable-maintainer-mode \ + --disable-metaphysicl \ + --with-methods="opt" \ + --without-gdb-command \ + --with-cxx-std-min=2014 \ + && make 2>/dev/null -j${compile_cores} install \ + && rm -rf ${LIBMESH_INSTALL_DIR}/build ${LIBMESH_INSTALL_DIR}/libmesh ; \ fi -# Clone and install DAGMC -RUN if [ "$include_dagmc" = "true" ] ; \ - then mkdir DAGMC ; \ - cd DAGMC ; \ - git clone --single-branch --branch 3.2.0 https://github.com/svalinn/DAGMC.git ; \ - mkdir build ; \ - cd build ; \ - cmake ../DAGMC -DBUILD_TALLY=ON \ - -DCMAKE_INSTALL_PREFIX=/DAGMC/ \ - -DMOAB_DIR=/usr/local \ - -DBUILD_STATIC_LIBS=OFF \ - -DBUILD_STATIC_EXE=OFF ; \ - make -j"$compile_cores" install ; \ - rm -rf /DAGMC/DAGMC /DAGMC/build ; \ - fi - -# Clone and install OpenMC with DAGMC -RUN if [ "$include_dagmc" = "true" ] ; \ - then git clone --recurse-submodules https://github.com/openmc-dev/openmc.git /opt/openmc ; \ - cd /opt/openmc ; \ - mkdir build ; \ - cd build ; \ - cmake -Doptimize=on \ - -Ddagmc=ON \ - -DDAGMC_DIR=/DAGMC/ \ - -DHDF5_PREFER_PARALLEL=on .. ; \ - make -j"$compile_cores" ; \ - make -j"$compile_cores" install ; \ - cd .. ; \ - pip install -e .[test] ; \ - fi +FROM dependencies AS build + +ENV HOME=/root + +ARG openmc_branch=master +ENV OPENMC_REPO='https://github.com/openmc-dev/openmc' + +ARG compile_cores +ARG build_dagmc +ARG build_libmesh + +ENV DAGMC_INSTALL_DIR=$HOME/DAGMC/ +ENV LIBMESH_INSTALL_DIR=$HOME/LIBMESH + +# clone and install openmc +RUN mkdir -p ${HOME}/OpenMC && cd ${HOME}/OpenMC \ + && git clone --shallow-submodules --recurse-submodules --single-branch -b ${openmc_branch} --depth=1 ${OPENMC_REPO} \ + && mkdir build && cd build ; \ + if [ ${build_dagmc} = "on" ] && [ ${build_libmesh} = "on" ]; then \ + cmake ../openmc \ + -DCMAKE_CXX_COMPILER=mpicxx \ + -DOPENMC_USE_MPI=on \ + -DHDF5_PREFER_PARALLEL=on \ + -DOPENMC_USE_DAGMC=on \ + -DOPENMC_USE_LIBMESH=on \ + -DCMAKE_PREFIX_PATH="${DAGMC_INSTALL_DIR};${LIBMESH_INSTALL_DIR}" ; \ + fi ; \ + if [ ${build_dagmc} = "on" ] && [ ${build_libmesh} = "off" ]; then \ + cmake ../openmc \ + -DCMAKE_CXX_COMPILER=mpicxx \ + -DOPENMC_USE_MPI=on \ + -DHDF5_PREFER_PARALLEL=on \ + -DOPENMC_USE_DAGMC=ON \ + -DCMAKE_PREFIX_PATH=${DAGMC_INSTALL_DIR} ; \ + fi ; \ + if [ ${build_dagmc} = "off" ] && [ ${build_libmesh} = "on" ]; then \ + cmake ../openmc \ + -DCMAKE_CXX_COMPILER=mpicxx \ + -DOPENMC_USE_MPI=on \ + -DHDF5_PREFER_PARALLEL=on \ + -DOPENMC_USE_LIBMESH=on \ + -DCMAKE_PREFIX_PATH=${LIBMESH_INSTALL_DIR} ; \ + fi ; \ + if [ ${build_dagmc} = "off" ] && [ ${build_libmesh} = "off" ]; then \ + cmake ../openmc \ + -DCMAKE_CXX_COMPILER=mpicxx \ + -DOPENMC_USE_MPI=on \ + -DHDF5_PREFER_PARALLEL=on ; \ + fi ; \ + make 2>/dev/null -j${compile_cores} install \ + && cd ../openmc && pip install .[test,depletion-mpi] \ + && python -c "import openmc" + +FROM build AS release + +ENV HOME=/root +ENV OPENMC_CROSS_SECTIONS=/root/nndc_hdf5/cross_sections.xml # Download cross sections (NNDC and WMP) and ENDF data needed by test suite -RUN /opt/openmc/tools/ci/download-xs.sh +RUN ${HOME}/OpenMC/openmc/tools/ci/download-xs.sh diff --git a/LICENSE b/LICENSE index 848a2384501..1f9198c1e3b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Copyright (c) 2011-2021 Massachusetts Institute of Technology and OpenMC contributors +Copyright (c) 2011-2024 Massachusetts Institute of Technology, UChicago Argonne +LLC, and OpenMC contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/MANIFEST.in b/MANIFEST.in index 795bfcf2367..afd016cb021 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -8,7 +8,6 @@ include schemas.xml include pyproject.toml include pytest.ini include docs/source/_templates/layout.html -include docs/sphinxext/LICENSE global-include *.cmake global-include *.cmake.in global-include *.rst @@ -20,25 +19,22 @@ recursive-include docs *.svg recursive-include docs *.tex recursive-include docs *.txt recursive-include docs Makefile -recursive-include examples *.h5 -recursive-include examples *.ipynb -recursive-include examples *.png +recursive-include examples *.cpp recursive-include examples *.py recursive-include examples *.xml recursive-include include *.h +recursive-include include *.h.in +recursive-include include *.hh recursive-include man *.1 -recursive-inlcude openmc *.pyx +recursive-include openmc *.pyx recursive-include openmc *.c -recursive-include src *.c recursive-include src *.cc recursive-include src *.cpp -recursive-include src *.h -recursive-include src *.hpp recursive-include src *.rnc recursive-include src *.rng recursive-include tests *.dat recursive-include tests *.h5 -recursive-inlcude tests *.h5m +recursive-include tests *.h5m recursive-include tests *.py recursive-include tests *.xml recursive-include vendor CMakeLists.txt diff --git a/README.md b/README.md index ebd7b050aed..6539ec3c7c5 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,11 @@ # OpenMC Monte Carlo Particle Transport Code -[![License](https://img.shields.io/github/license/openmc-dev/openmc.svg)](http://openmc.readthedocs.io/en/latest/license.html) -[![GitHub Actions build status (Linux)](https://github.com/openmc-dev/openmc/workflows/CI/badge.svg?branch=develop)](https://github.com/openmc-dev/openmc/actions?query=workflow%3ACI) +[![License](https://img.shields.io/badge/license-MIT-green)](https://docs.openmc.org/en/latest/license.html) +[![GitHub Actions build status (Linux)](https://github.com/openmc-dev/openmc/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/openmc-dev/openmc/actions/workflows/ci.yml) [![Code Coverage](https://coveralls.io/repos/github/openmc-dev/openmc/badge.svg?branch=develop)](https://coveralls.io/github/openmc-dev/openmc?branch=develop) [![dockerhub-publish-develop-dagmc](https://github.com/openmc-dev/openmc/workflows/dockerhub-publish-develop-dagmc/badge.svg)](https://github.com/openmc-dev/openmc/actions?query=workflow%3Adockerhub-publish-develop-dagmc) [![dockerhub-publish-develop](https://github.com/openmc-dev/openmc/workflows/dockerhub-publish-develop/badge.svg)](https://github.com/openmc-dev/openmc/actions?query=workflow%3Adockerhub-publish-develop) +[![conda-pacakge](https://anaconda.org/conda-forge/openmc/badges/version.svg)](https://anaconda.org/conda-forge/openmc) The OpenMC project aims to provide a fully-featured Monte Carlo particle transport code based on modern methods. It is a constructive solid geometry, @@ -12,14 +13,15 @@ continuous-energy transport code that uses HDF5 format cross sections. The project started under the Computational Reactor Physics Group at MIT. Complete documentation on the usage of OpenMC is hosted on Read the Docs (both -for the [latest release](http://openmc.readthedocs.io/en/stable/) and -[developmental](http://openmc.readthedocs.io/en/latest/) version). If you are -interested in the project, or would like to help and contribute, please get in touch on the OpenMC [discussion forum](https://openmc.discourse.group/). +for the [latest release](https://docs.openmc.org/en/stable/) and +[developmental](https://docs.openmc.org/en/latest/) version). If you are +interested in the project, or would like to help and contribute, please get in +touch on the OpenMC [discussion forum](https://openmc.discourse.group/). ## Installation Detailed [installation -instructions](http://openmc.readthedocs.io/en/stable/usersguide/install.html) +instructions](https://docs.openmc.org/en/stable/usersguide/install.html) can be found in the User's Guide. ## Citing @@ -35,22 +37,23 @@ citing the following publication: ## Troubleshooting If you run into problems compiling, installing, or running OpenMC, first check -the [Troubleshooting section](http://openmc.readthedocs.io/en/stable/usersguide/troubleshoot.html) in -the User's Guide. If you are not able to find a solution to your problem there, +the [Troubleshooting +section](https://docs.openmc.org/en/stable/usersguide/troubleshoot.html) in the +User's Guide. If you are not able to find a solution to your problem there, please post to the [discussion forum](https://openmc.discourse.group/). ## Reporting Bugs OpenMC is hosted on GitHub and all bugs are reported and tracked through the -[Issues](https://github.com/openmc-dev/openmc/issues) feature on GitHub. However, -GitHub Issues should not be used for common troubleshooting purposes. If you are -having trouble installing the code or getting your model to run properly, you -should first send a message to the User's Group mailing list. If it turns out -your issue really is a bug in the code, an issue will then be created on -GitHub. If you want to request that a feature be added to the code, you may -create an Issue on github. +[Issues](https://github.com/openmc-dev/openmc/issues) feature on GitHub. +However, GitHub Issues should not be used for common troubleshooting purposes. +If you are having trouble installing the code or getting your model to run +properly, you should first send a message to the [discussion +forum](https://openmc.discourse.group/). If it turns out your issue really is a +bug in the code, an issue will then be created on GitHub. If you want to request +that a feature be added to the code, you may create an Issue on github. ## License OpenMC is distributed under the MIT/X -[license](http://openmc.readthedocs.io/en/stable/license.html). +[license](https://docs.openmc.org/en/stable/license.html). diff --git a/cmake/Modules/FindLIBMESH.cmake b/cmake/Modules/FindLIBMESH.cmake index 82d806343aa..df5b5b9d863 100644 --- a/cmake/Modules/FindLIBMESH.cmake +++ b/cmake/Modules/FindLIBMESH.cmake @@ -17,5 +17,5 @@ endif() include(FindPkgConfig) set(ENV{PKG_CONFIG_PATH} "$ENV{PKG_CONFIG_PATH}:${LIBMESH_PC}") set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH True) -pkg_check_modules(LIBMESH REQUIRED ${LIBMESH_PC_FILE}>=1.6.0 IMPORTED_TARGET) -pkg_get_variable(LIBMESH_PREFIX ${LIBMESH_PC_FILE} prefix) \ No newline at end of file +pkg_check_modules(LIBMESH REQUIRED ${LIBMESH_PC_FILE}>=1.7.0 IMPORTED_TARGET) +pkg_get_variable(LIBMESH_PREFIX ${LIBMESH_PC_FILE} prefix) diff --git a/cmake/OpenMCConfig.cmake.in b/cmake/OpenMCConfig.cmake.in index e23ec26a625..44a5e0d5a3f 100644 --- a/cmake/OpenMCConfig.cmake.in +++ b/cmake/OpenMCConfig.cmake.in @@ -5,17 +5,40 @@ find_package(gsl-lite REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../gsl-lite) find_package(pugixml REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../pugixml) find_package(xtl REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtl) find_package(xtensor REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtensor) -if(@DAGMC_FOUND@) +if(@OPENMC_USE_DAGMC@) find_package(DAGMC REQUIRED HINTS @DAGMC_DIR@) endif() -if(@LIBMESH_FOUND@) +if(@OPENMC_USE_NCRYSTAL@) + find_package(NCrystal REQUIRED) + message(STATUS "Found NCrystal: ${NCrystal_DIR} (version ${NCrystal_VERSION})") +endif() + +if(@OPENMC_USE_LIBMESH@) include(FindPkgConfig) list(APPEND CMAKE_PREFIX_PATH @LIBMESH_PREFIX@) set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH True) - pkg_check_modules(LIBMESH REQUIRED @LIBMESH_PC_FILE@>=1.6.0 IMPORTED_TARGET) + pkg_check_modules(LIBMESH REQUIRED @LIBMESH_PC_FILE@>=1.7.0 IMPORTED_TARGET) endif() +find_package(PNG) + if(NOT TARGET OpenMC::libopenmc) include("${OpenMC_CMAKE_DIR}/OpenMCTargets.cmake") endif() + +if(@OPENMC_USE_MPI@) + find_package(MPI REQUIRED) +endif() + +if(@OPENMC_USE_OPENMP@) + find_package(OpenMP REQUIRED) +endif() + +if(@OPENMC_USE_MCPL@) + find_package(MCPL REQUIRED) +endif() + +if(@OPENMC_USE_UWUW@) + find_package(UWUW REQUIRED) +endif() diff --git a/docs/requirements-rtd.txt b/docs/requirements-rtd.txt index fd76dfffb9d..df033351705 100644 --- a/docs/requirements-rtd.txt +++ b/docs/requirements-rtd.txt @@ -1,11 +1,13 @@ +sphinx==5.0.2 +sphinx_rtd_theme==1.0.0 sphinx-numfig jupyter sphinxcontrib-katex sphinxcontrib-svg2pdfconverter -nbsphinx numpy scipy h5py pandas uncertainties matplotlib +lxml diff --git a/docs/source/_images/2x2_fsrs.jpeg b/docs/source/_images/2x2_fsrs.jpeg new file mode 100644 index 00000000000..1c8e474d0e8 Binary files /dev/null and b/docs/source/_images/2x2_fsrs.jpeg differ diff --git a/docs/source/_images/2x2_materials.jpeg b/docs/source/_images/2x2_materials.jpeg new file mode 100644 index 00000000000..b76607eca66 Binary files /dev/null and b/docs/source/_images/2x2_materials.jpeg differ diff --git a/docs/source/_images/hexlat_anim.gif b/docs/source/_images/hexlat_anim.gif new file mode 100644 index 00000000000..fceedc01047 Binary files /dev/null and b/docs/source/_images/hexlat_anim.gif differ diff --git a/docs/source/capi/index.rst b/docs/source/capi/index.rst index eb6493e0e92..d9ac0d1e019 100644 --- a/docs/source/capi/index.rst +++ b/docs/source/capi/index.rst @@ -355,7 +355,7 @@ Functions Get density of a material. :param int32_t index: Index in the materials array - :param double* denity: Pointer to a density + :param double* density: Pointer to a density :return: Return status (negative if an error occurs) :rtype: int @@ -420,6 +420,16 @@ Functions :return: Return status (negative if an error occurred) :rtype: int +.. c:function:: int openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh) + + Get the mesh for a mesh filter + + :param int32_t index: Index in the filters array + :param index_mesh: Index in the meshes array + :type index_mesh: int32_t* + :return: Return status (negative if an error occurred) + :rtype: int + .. c:function:: int openmc_mesh_filter_set_mesh(int32_t index, int32_t index_mesh) Set the mesh for a mesh filter @@ -429,6 +439,98 @@ Functions :return: Return status (negative if an error occurred) :rtype: int +.. c:function:: int openmc_mesh_filter_get_translation(int32_t index, double translation[3]) + + Get the 3-D translation coordinates for a mesh filter + + :param int32_t index: Index in the filters array + :param double[3] translation: 3-D translation coordinates + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_mesh_filter_set_translation(int32_t index, double translation[3]) + + Set the 3-D translation coordinates for a mesh filter + + :param int32_t index: Index in the filters array + :param double[3] translation: 3-D translation coordinates + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_meshborn_filter_get_mesh(int32_t index, int32_t* index_mesh) + + Get the mesh for a meshborn filter + + :param int32_t index: Index in the filters array + :param index_mesh: Index in the meshes array + :type index_mesh: int32_t* + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_meshborn_filter_set_mesh(int32_t index, int32_t index_mesh) + + Set the mesh for a meshborn filter + + :param int32_t index: Index in the filters array + :param int32_t index_mesh: Index in the meshes array + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_meshborn_filter_get_translation(int32_t index, double translation[3]) + + Get the 3-D translation coordinates for a meshborn filter + + :param int32_t index: Index in the filters array + :param double[3] translation: 3-D translation coordinates + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_meshborn_filter_set_translation(int32_t index, double translation[3]) + + Set the 3-D translation coordinates for a meshborn filter + + :param int32_t index: Index in the filters array + :param double[3] translation: 3-D translation coordinates + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_meshsurface_filter_get_mesh(int32_t index, int32_t* index_mesh) + + Get the mesh for a mesh surface filter + + :param int32_t index: Index in the filters array + :param index_mesh: Index in the meshes array + :type index_mesh: int32_t* + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh) + + Set the mesh for a mesh surface filter + + :param int32_t index: Index in the filters array + :param int32_t index_mesh: Index in the meshes array + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_meshsurface_filter_get_translation(int32_t index, double translation[3]) + + Get the 3-D translation coordinates for a mesh surface filter + + :param int32_t index: Index in the filters array + :param double[3] translation: 3-D translation coordinates + :return: Return status (negative if an error occurred) + :rtype: int + +.. c:function:: int openmc_meshsurface_filter_set_translation(int32_t index, double translation[3]) + + Set the 3-D translation coordinates for a mesh surface filter + + :param int32_t index: Index in the filters array + :param double[3] translation: 3-D translation coordinates + :return: Return status (negative if an error occurred) + :rtype: int + .. c:function:: int openmc_next_batch() Simulate next batch of particles. Must be called after openmc_simulation_init(). @@ -460,6 +562,13 @@ Functions :return: Return status (negative if an error occurs) :rtype: int +.. c:function:: int openmc_remove_tally(int32_t index); + + Given an index of a tally, remove it from the tallies array + :param int index: Index in tallies array + :return: Return status (negative if an error occurs) + :rtype: int + .. c:function:: int openmc_run() Run a simulation diff --git a/docs/source/conf.py b/docs/source/conf.py index 55cfef35218..53d529f3dc0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -44,7 +44,6 @@ 'sphinx.ext.viewcode', 'sphinxcontrib.katex', 'sphinx_numfig', - 'nbsphinx' ] if not on_rtd: extensions.append('sphinxcontrib.rsvgconverter') @@ -63,16 +62,16 @@ # General information about the project. project = 'OpenMC' -copyright = '2011-2021, Massachusetts Institute of Technology and OpenMC contributors' +copyright = '2011-2024, Massachusetts Institute of Technology, UChicago Argonne LLC, and OpenMC contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = "0.12" +version = "0.14" # The full version, including alpha/beta/rc tags. -release = "0.12.2" +release = "0.14.1-dev" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -121,10 +120,9 @@ # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages -if not on_rtd: - import sphinx_rtd_theme - html_theme = 'sphinx_rtd_theme' - html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] +import sphinx_rtd_theme +html_theme = 'sphinx_rtd_theme' +html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] html_logo = '_images/openmc_logo.png' @@ -138,7 +136,7 @@ # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -#html_favicon = None +html_favicon = 'favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -216,6 +214,7 @@ def setup(app): \setcounter{tocdepth}{2} \numberwithin{equation}{section} \DeclareUnicodeCharacter{03B1}{$\alpha$} +\DeclareUnicodeCharacter{03C0}{$\pi$} """, 'printindex': r"" } @@ -247,7 +246,7 @@ def setup(app): intersphinx_mapping = { 'python': ('https://docs.python.org/3', None), 'numpy': ('https://numpy.org/doc/stable/', None), - 'scipy': ('https://docs.scipy.org/doc/scipy/reference', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/', None), 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), - 'matplotlib': ('https://matplotlib.org/', None) + 'matplotlib': ('https://matplotlib.org/stable/', None) } diff --git a/docs/source/devguide/docbuild.rst b/docs/source/devguide/docbuild.rst index 38ef628df56..389a423f3a2 100644 --- a/docs/source/devguide/docbuild.rst +++ b/docs/source/devguide/docbuild.rst @@ -5,21 +5,14 @@ Building Sphinx Documentation ============================= In order to build the documentation in the ``docs`` directory, you will need to -have the `Sphinx `_ third-party Python -package. The easiest way to install Sphinx is via pip: +have the several third-party Python packages installed, including `Sphinx +`_. To install the necessary +prerequisites, provide the optional "docs" dependencies when installing OpenMC's +Python API. That is, from the root directory of the OpenMC repository: .. code-block:: sh - pip install sphinx - -Additionally, you will need several Sphinx extensions that can be installed -directly with pip: - -.. code-block:: sh - - pip install sphinx-numfig - pip install sphinxcontrib-katex - pip install sphinxcontrib-svg2pdfconverter + python -m pip install .[docs] ----------------------------------- Building Documentation as a Webpage diff --git a/docs/source/devguide/styleguide.rst b/docs/source/devguide/styleguide.rst index bfe2ac35f82..3c71d14ad92 100644 --- a/docs/source/devguide/styleguide.rst +++ b/docs/source/devguide/styleguide.rst @@ -12,18 +12,26 @@ adding new code in OpenMC. C++ --- -.. important:: To ensure consistent styling with little effort, this project - uses `clang-format `_. The - repository contains a ``.clang-format`` file that can be used to - automatically apply the style rules that are described below. The easiest - way to use clang-format is through a plugin/extension for your editor/IDE - that automatically runs clang-format using the ``.clang-format`` file - whenever a file is saved. - -Indentation ------------ - -Use two spaces per indentation level. +.. _styleguide_formatting: + +Automatic Formatting +-------------------- + +To ensure consistent styling with little effort, this project uses `clang-format +`_. The repository contains a +``.clang-format`` file that can be used to automatically apply a consistent +format. The easiest way to use clang-format is to run +``tools/dev/install-commit-hooks.sh`` to install a post-commit hook that gets +executed each time a commit is made. Note that this script requires that you +already have clang-format installed. In addition, you may want to configure your +editor/IDE to automatically runs clang-format using the ``.clang-format`` file +whenever a file is saved. For example, `Visual Studio Code +`_ includes +support for running clang-format. + +.. note:: + OpenMC's CI uses `clang-format` version 15. A different version of `clang-format` + may produce different line changes and as a result fail the CI test. Miscellaneous ------------- @@ -123,94 +131,6 @@ Variables declared constexpr or const that have static storage duration (exist for the duration of the program) should be upper-case with underscores, e.g., ``SQRT_PI``. -Use C++-style declarator layout (see `NL.18 -`_): -pointer and reference operators in declarations should be placed adject to the -base type rather than the variable name. Avoid declaring multiple names in a -single declaration to avoid confusion: - -.. code-block:: C++ - - T* p; // good - T& p; // good - T *p; // bad - T* p, q; // misleading - -Curly braces ------------- - -For a class declaration, the opening brace should be on the same line that -lists the name of the class. - -.. code-block:: C++ - - class Matrix { - ... - }; - -For a function definition, the opening and closing braces should each be on -their own lines. This helps distinguish function code from the argument list. -If the entire function fits on one or two lines, then the braces can be on the -same line. e.g.: - -.. code-block:: C++ - - return_type function(type1 arg1, type2 arg2) - { - content(); - } - - return_type - function_with_many_args(type1 arg1, type2 arg2, type3 arg3, - type4 arg4) - { - content(); - } - - int return_one() {return 1;} - - int return_one() - {return 1;} - -For a conditional, the opening brace should be on the same line as the end of -the conditional statement. If there is a following ``else if`` or ``else`` -statement, the closing brace should be on the same line as that following -statement. Otherwise, the closing brace should be on its own line. A one-line -conditional can have the closing brace on the same line or it can omit the -braces entirely e.g.: - -.. code-block:: C++ - - if (condition) { - content(); - } - - if (condition1) { - content(); - } else if (condition 2) { - more_content(); - } else { - further_content(); - } - - if (condition) {content()}; - - if (condition) content(); - -For loops similarly have an opening brace on the same line as the statement and -a closing brace on its own line. One-line loops may have the closing brace on -the same line or omit the braces entirely. - -.. code-block:: C++ - - for (int i = 0; i < 5; i++) { - content(); - } - - for (int i = 0; i < 5; i++) {content();} - - for (int i = 0; i < 5; i++) content(); - Documentation ------------- @@ -226,7 +146,7 @@ Style for Python code should follow PEP8_. Docstrings for functions and methods should follow numpydoc_ style. -Python code should work with Python 3.4+. +Python code should work with Python 3.8+. Use of third-party Python packages should be limited to numpy_, scipy_, matplotlib_, pandas_, and h5py_. Use of other third-party packages must be diff --git a/docs/source/devguide/tests.rst b/docs/source/devguide/tests.rst index d5571306241..d8fc53b3ad0 100644 --- a/docs/source/devguide/tests.rst +++ b/docs/source/devguide/tests.rst @@ -23,17 +23,17 @@ Prerequisites OpenMC in development/editable mode. With setuptools, this is accomplished by running:: - python setup.py develop - - or using pip (recommended):: - - pip install -e .[test] + python -m pip install -e .[test] - The test suite requires a specific set of cross section data in order for tests to pass. A download URL for the data that OpenMC expects can be found - within ``tools/ci/download-xs.sh``. + within ``tools/ci/download-xs.sh``. Once the tarball is downloaded and + unpacked, set the :envvar:`OPENMC_CROSS_SECTIONS` environment variable to the + path of the ``cross_sections.xml`` file within the unpacked data. - In addition to the HDF5 data, some tests rely on ENDF files. A download URL - for those can also be found in ``tools/ci/download-xs.sh``. + for those can also be found in ``tools/ci/download-xs.sh``. Once the tarball + is downloaded and unpacked, set the :envvar:`OPENMC_ENDF_DATA` environment + variable to the top-level directory of the unpacked tarball. - Some tests require `NJOY `_ to preprocess cross section data. The test suite assumes that you have an ``njoy`` executable available on your :envvar:`PATH`. @@ -41,7 +41,7 @@ Prerequisites Running Tests ------------- -To execute the test suite, go to the ``tests/`` directory and run:: +To execute the Python test suite, go to the ``tests/`` directory and run:: pytest @@ -51,6 +51,39 @@ installed and run:: pytest --cov=../openmc --cov-report=html +To execute the C++ test suite, go to your build directory and run:: + + ctest + +If you want to view testing output on failure run:: + + ctest --output-on-failure + +Possible Reasons for Test Failures +---------------------------------- + +You may find that when you run the test suite, not everything passes. First, +make sure you have satisfied all the prerequisites above. After you have done +that, consider the following: + +- When building OpenMC, make sure you run CMake with + ``-DCMAKE_BUILD_TYPE=Debug``. Building with a release build will result in + some test failures due to differences in which compiler optimizations are + used. +- Because tallies involve the sum of many floating point numbers, the + non-associativity of floating point numbers can result in different answers + especially when the number of threads is high (different order of operations). + Thus, if you are running on a CPU with many cores, you may need to limit the + number of OpenMP threads used. It is recommended to set the + :envvar:`OMP_NUM_THREADS` environment variable to 2. +- Recent versions of NumPy use instruction dispatch that may generate different + results depending the particular ISA that you are running on. To avoid issues, + you may need to disable AVX512 instructions. This can be done by setting the + :envvar:`NPY_DISABLE_CPU_FEATURES` environment variable to "AVX512F + AVX512_SKX". When NumPy/SciPy are built against OpenBLAS, you may also need to + limit the number of threads that OpenBLAS uses internally; this can be done by + setting the :envvar:`OPENBLAS_NUM_THREADS` environment variable to 1. + Generating XML Inputs --------------------- @@ -62,6 +95,23 @@ run:: pytest --build-inputs +Adding C++ Unit Tests +--------------------- + +The C++ test suite uses Catch2 integrated with CTest. Each header file should +have a corresponding test file in ``tests/cpp_unit_tests/``. If the test file +does not exist run:: + + touch test_.cpp + +The file must be added to the CMake build system in +``tests/cpp_unit_tests/CMakeLists.txt``. ``test_`` should +be added to ``TEST_NAMES``. + +To add a test case to ``test_.cpp`` ensure +``catch2/catch_test_macros.hpp`` is included. A unit test can then be added +using the ``TEST_CASE`` macro and the ``REQUIRE`` assertion from Catch2. + Adding Tests to the Regression Suite ------------------------------------ @@ -84,6 +134,12 @@ following files to your new test directory: compiler options during openmc configuration and build (e.g., no MPI, no debug/optimization). +For tests using the Python API, both the **inputs_true.dat** and +**results_true.dat** files can be generated automatically in the correct format +via:: + + pytest --update + In addition to this description, please see the various types of tests that are already included in the test suite to see how to create them. If all is implemented correctly, the new test will automatically be discovered by pytest. diff --git a/docs/source/devguide/user-input.rst b/docs/source/devguide/user-input.rst index 0bde0fb0581..a26f98b1979 100644 --- a/docs/source/devguide/user-input.rst +++ b/docs/source/devguide/user-input.rst @@ -49,14 +49,6 @@ following steps should be followed to make changes to user input: written out to the statepoint or summary files and that the :class:`openmc.StatePoint` and :class:`openmc.Summary` classes read them in. -7. Finally, a set of `RELAX NG`_ schemas exists that enables validation of input - files. You should modify the RELAX NG schema for the file you changed. The - easiest way to do this is to change the `compact syntax`_ file - (e.g. ``src/relaxng/geometry.rnc``) and then convert it to regular XML syntax - using trang_:: - - trang geometry.rnc geometry.rng - For most user input additions and changes, it is simple enough to follow a "monkey see, monkey do" approach. When in doubt, contact your nearest OpenMC developer or send a message to the `developers mailing list`_. @@ -65,7 +57,4 @@ developer or send a message to the `developers mailing list`_. .. _property attribute: https://docs.python.org/3.6/library/functions.html#property .. _XML Schema Part 2: http://www.w3.org/TR/xmlschema-2/ .. _boolean: http://www.w3.org/TR/xmlschema-2/#boolean -.. _RELAX NG: https://relaxng.org/ -.. _compact syntax: https://relaxng.org/compact-tutorial-20030326.html -.. _trang: https://relaxng.org/jclark/trang.html .. _developers mailing list: https://groups.google.com/forum/?fromgroups=#!forum/openmc-dev diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index 3d8d2e82732..d6a3c6ba4f4 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -4,7 +4,7 @@ Development Workflow ==================== -Anyone wishing to make contributions to OpenMC should be fully acquianted and +Anyone wishing to make contributions to OpenMC should be fully acquainted and comfortable working with git_ and GitHub_. We assume here that you have git installed on your system, have a GitHub account, and have setup SSH keys to be able to create/push to repositories on GitHub. @@ -67,6 +67,12 @@ features and bug fixes. The general steps for contributing are as follows: cd openmc git checkout -b newbranch develop +3. Run ``tools/dev/install-commit-hooks.sh`` to install a post-commit hook that + runs clang-format on C++ files to apply :ref:`automatic code formatting + ` (requires that clang-format already be installed). + In addition, you may want to configure your text editor to automatically run + clang-format when saving C++ files. + 3. Make your changes on the new branch that you intend to have included in *develop*. If you have made other changes that should not be merged back, ensure that those changes are made on a different branch. @@ -75,7 +81,7 @@ features and bug fixes. The general steps for contributing are as follows: openmc-dev/openmc as the target. At a minimum, you should describe what the changes you've made are and why - you are making them. If the changes are related to an oustanding issue, make + you are making them. If the changes are related to an outstanding issue, make sure it is cross-referenced. 5. A committer will review your pull request based on the criteria @@ -110,11 +116,11 @@ pip_. From the root directory of the OpenMC repository, run: .. code-block:: sh - pip install -e .[test] + python -m pip install -e .[test] This installs the OpenMC Python package in `"editable" mode -`_ so -that 1) it can be imported from a Python interpreter and 2) any changes made are +`_ so that 1) +it can be imported from a Python interpreter and 2) any changes made are immediately reflected in the installed version (that is, you don't need to keep reinstalling it). While the same effect can be achieved using the :envvar:`PYTHONPATH` environment variable, this is generally discouraged as it diff --git a/docs/source/examples/cad-based-geometry.ipynb b/docs/source/examples/cad-based-geometry.ipynb deleted file mode 120000 index ee3727e6725..00000000000 --- a/docs/source/examples/cad-based-geometry.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/cad-based-geometry.ipynb \ No newline at end of file diff --git a/docs/source/examples/candu.ipynb b/docs/source/examples/candu.ipynb deleted file mode 120000 index 480d99fb164..00000000000 --- a/docs/source/examples/candu.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/candu.ipynb \ No newline at end of file diff --git a/docs/source/examples/capi.ipynb b/docs/source/examples/capi.ipynb deleted file mode 120000 index f69a37093c2..00000000000 --- a/docs/source/examples/capi.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/capi.ipynb \ No newline at end of file diff --git a/docs/source/examples/expansion-filters.ipynb b/docs/source/examples/expansion-filters.ipynb deleted file mode 120000 index e7573413595..00000000000 --- a/docs/source/examples/expansion-filters.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/expansion-filters.ipynb \ No newline at end of file diff --git a/docs/source/examples/hexagonal-lattice.ipynb b/docs/source/examples/hexagonal-lattice.ipynb deleted file mode 120000 index e2b63d24373..00000000000 --- a/docs/source/examples/hexagonal-lattice.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/hexagonal-lattice.ipynb \ No newline at end of file diff --git a/docs/source/examples/index.rst b/docs/source/examples/index.rst deleted file mode 100644 index 38bc51e2686..00000000000 --- a/docs/source/examples/index.rst +++ /dev/null @@ -1,73 +0,0 @@ -.. _examples: - -======== -Examples -======== - -The following series of `Jupyter `_ Notebooks provide -examples for how to use various features of OpenMC by leveraging the -:ref:`pythonapi`. - -------------- -General Usage -------------- - -.. toctree:: - :maxdepth: 1 - - pincell - post-processing - pandas-dataframes - tally-arithmetic - capi - expansion-filters - search - nuclear-data - nuclear-data-resonance-covariance - pincell_depletion - --------- -Geometry --------- - -.. toctree:: - :maxdepth: 1 - - hexagonal-lattice - triso - candu - cad-based-geometry - ------------------------------------ -Multigroup Cross Section Generation ------------------------------------ - -.. toctree:: - :maxdepth: 1 - - mgxs-part-i - mgxs-part-ii - mgxs-part-iii - mdgxs-part-i - mdgxs-part-ii - ---------------- -Multigroup Mode ---------------- - -.. toctree:: - :maxdepth: 1 - - mg-mode-part-i - mg-mode-part-ii - mg-mode-part-iii - ------------------ -Unstructured Mesh ------------------ - -.. toctree:: - :maxdepth: 1 - - unstructured-mesh-part-i - unstructured-mesh-part-ii diff --git a/docs/source/examples/mdgxs-part-i.ipynb b/docs/source/examples/mdgxs-part-i.ipynb deleted file mode 120000 index 01eb1172d46..00000000000 --- a/docs/source/examples/mdgxs-part-i.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/mdgxs-part-i.ipynb \ No newline at end of file diff --git a/docs/source/examples/mdgxs-part-ii.ipynb b/docs/source/examples/mdgxs-part-ii.ipynb deleted file mode 120000 index 2d9d339074b..00000000000 --- a/docs/source/examples/mdgxs-part-ii.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/mdgxs-part-ii.ipynb \ No newline at end of file diff --git a/docs/source/examples/mg-mode-part-i.ipynb b/docs/source/examples/mg-mode-part-i.ipynb deleted file mode 120000 index d1577f70007..00000000000 --- a/docs/source/examples/mg-mode-part-i.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/mg-mode-part-i.ipynb \ No newline at end of file diff --git a/docs/source/examples/mg-mode-part-ii.ipynb b/docs/source/examples/mg-mode-part-ii.ipynb deleted file mode 120000 index a093063761a..00000000000 --- a/docs/source/examples/mg-mode-part-ii.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/mg-mode-part-ii.ipynb \ No newline at end of file diff --git a/docs/source/examples/mg-mode-part-iii.ipynb b/docs/source/examples/mg-mode-part-iii.ipynb deleted file mode 120000 index 6fa0d180e44..00000000000 --- a/docs/source/examples/mg-mode-part-iii.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/mg-mode-part-iii.ipynb \ No newline at end of file diff --git a/docs/source/examples/mgxs-part-i.ipynb b/docs/source/examples/mgxs-part-i.ipynb deleted file mode 120000 index a04b1da8952..00000000000 --- a/docs/source/examples/mgxs-part-i.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/mgxs-part-i.ipynb \ No newline at end of file diff --git a/docs/source/examples/mgxs-part-ii.ipynb b/docs/source/examples/mgxs-part-ii.ipynb deleted file mode 120000 index dd8af3c4382..00000000000 --- a/docs/source/examples/mgxs-part-ii.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/mgxs-part-ii.ipynb \ No newline at end of file diff --git a/docs/source/examples/mgxs-part-iii.ipynb b/docs/source/examples/mgxs-part-iii.ipynb deleted file mode 120000 index d6acc76bafd..00000000000 --- a/docs/source/examples/mgxs-part-iii.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/mgxs-part-iii.ipynb \ No newline at end of file diff --git a/docs/source/examples/nuclear-data-resonance-covariance.ipynb b/docs/source/examples/nuclear-data-resonance-covariance.ipynb deleted file mode 120000 index 0ab0dd62b59..00000000000 --- a/docs/source/examples/nuclear-data-resonance-covariance.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/nuclear-data-resonance-covariance.ipynb \ No newline at end of file diff --git a/docs/source/examples/nuclear-data.ipynb b/docs/source/examples/nuclear-data.ipynb deleted file mode 120000 index 59721abdc9d..00000000000 --- a/docs/source/examples/nuclear-data.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/nuclear-data.ipynb \ No newline at end of file diff --git a/docs/source/examples/pandas-dataframes.ipynb b/docs/source/examples/pandas-dataframes.ipynb deleted file mode 120000 index f41f570beb8..00000000000 --- a/docs/source/examples/pandas-dataframes.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/pandas-dataframes.ipynb \ No newline at end of file diff --git a/docs/source/examples/pincell.ipynb b/docs/source/examples/pincell.ipynb deleted file mode 120000 index edbbb8de24b..00000000000 --- a/docs/source/examples/pincell.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/pincell.ipynb \ No newline at end of file diff --git a/docs/source/examples/pincell_depletion.ipynb b/docs/source/examples/pincell_depletion.ipynb deleted file mode 120000 index 1f25930fcbe..00000000000 --- a/docs/source/examples/pincell_depletion.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/pincell_depletion.ipynb \ No newline at end of file diff --git a/docs/source/examples/post-processing.ipynb b/docs/source/examples/post-processing.ipynb deleted file mode 120000 index 1f3f4cd7130..00000000000 --- a/docs/source/examples/post-processing.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/post-processing.ipynb \ No newline at end of file diff --git a/docs/source/examples/search.ipynb b/docs/source/examples/search.ipynb deleted file mode 120000 index fbfb67bc606..00000000000 --- a/docs/source/examples/search.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/search.ipynb \ No newline at end of file diff --git a/docs/source/examples/tally-arithmetic.ipynb b/docs/source/examples/tally-arithmetic.ipynb deleted file mode 120000 index 7ffe194626d..00000000000 --- a/docs/source/examples/tally-arithmetic.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/tally-arithmetic.ipynb \ No newline at end of file diff --git a/docs/source/examples/triso.ipynb b/docs/source/examples/triso.ipynb deleted file mode 120000 index 0e51d8add9a..00000000000 --- a/docs/source/examples/triso.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/triso.ipynb \ No newline at end of file diff --git a/docs/source/examples/unstructured-mesh-part-i.ipynb b/docs/source/examples/unstructured-mesh-part-i.ipynb deleted file mode 120000 index b1358788bab..00000000000 --- a/docs/source/examples/unstructured-mesh-part-i.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/unstructured-mesh-part-i.ipynb \ No newline at end of file diff --git a/docs/source/examples/unstructured-mesh-part-ii.ipynb b/docs/source/examples/unstructured-mesh-part-ii.ipynb deleted file mode 120000 index 9074811b705..00000000000 --- a/docs/source/examples/unstructured-mesh-part-ii.ipynb +++ /dev/null @@ -1 +0,0 @@ -../../../examples/jupyter/unstructured-mesh-part-ii.ipynb \ No newline at end of file diff --git a/docs/source/favicon.ico b/docs/source/favicon.ico new file mode 100644 index 00000000000..85649d92dba Binary files /dev/null and b/docs/source/favicon.ico differ diff --git a/docs/source/index.rst b/docs/source/index.rst index 3b2f5b05334..a01055374b0 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -36,7 +36,7 @@ Forum `_. :maxdepth: 1 quickinstall - examples/index + Examples releasenotes/index methods/index usersguide/index diff --git a/docs/source/io_formats/depletion_results.rst b/docs/source/io_formats/depletion_results.rst index 172c17ae636..7035fc9c9ee 100644 --- a/docs/source/io_formats/depletion_results.rst +++ b/docs/source/io_formats/depletion_results.rst @@ -47,10 +47,3 @@ The current version of the depletion results file format is 1.1. **/reactions//** :Attributes: - **index** (*int*) -- Index user in results for this reaction - -.. note:: - - The reaction rates for some isotopes not originally present may - be non-zero, but should be negligible compared to other atoms. - This can be controlled by changing the - :class:`openmc.deplete.Operator` ``dilute_initial`` attribute. diff --git a/docs/source/io_formats/geometry.rst b/docs/source/io_formats/geometry.rst index af229bcfff3..ac48e48d2d1 100644 --- a/docs/source/io_formats/geometry.rst +++ b/docs/source/io_formats/geometry.rst @@ -19,14 +19,14 @@ Each ```` element can have the following attributes or sub-elements: :name: An optional string name to identify the surface in summary output - files. This string is limited to 52 characters for formatting purposes. + files. *Default*: "" :type: The type of the surfaces. This can be "x-plane", "y-plane", "z-plane", "plane", "x-cylinder", "y-cylinder", "z-cylinder", "sphere", "x-cone", - "y-cone", "z-cone", or "quadric". + "y-cone", "z-cone", "quadric", "x-torus", "y-torus", or "z-torus". *Default*: None @@ -48,7 +48,7 @@ Each ```` element can have the following attributes or sub-elements: :periodic_surface_id: If a periodic boundary condition is applied, this attribute identifies the - ``id`` of the corresponding periodic sufrace. + ``id`` of the corresponding periodic surface. The following quadratic surfaces can be modeled: @@ -122,7 +122,6 @@ Each ```` element can have the following attributes or sub-elements: :name: An optional string name to identify the cell in summary output files. - This string is limmited to 52 characters for formatting purposes. *Default*: "" @@ -235,7 +234,7 @@ the following attributes or sub-elements: :name: An optional string name to identify the lattice in summary output - files. This string is limited to 52 characters for formatting purposes. + files. *Default*: "" @@ -301,7 +300,7 @@ the following attributes or sub-elements: :name: An optional string name to identify the hex_lattice in summary output - files. This string is limited to 52 characters for formatting purposes. + files. *Default*: "" @@ -370,3 +369,51 @@ Here is an example of a properly defined 2d hexagonal lattice: 202 + + +.. _dagmc_element: + +---------------------------- +```` Element +---------------------------- + +Each ```` element can have the following attributes or sub-elements: + + :id: + A unique integer used to identify the universe. + + *Default*: None + + :name: + An optional string name to identify the surface in summary output + files. + + *Default*: None + + :auto_geom_ids: + Boolean value indicating whether the existing geometry IDs will be used or appended + to the existing ID space of natively defined OpenMC geometry entities. + + *Default*: false + + :auto_mat_ids: + Boolean value indicating whether the existing material IDs will be used or appended + to the existing ID space of natively defined OpenMC materials. + + *Default*: false + + :filename: + A required string indicating the file to be loaded representing the DAGMC universe. + + *Default*: None + + + .. note:: A geometry.xml file containing only a DAGMC model for a file named `dagmc.h5m` (no CSG) + looks as follows + + .. code-block:: xml + + + + + diff --git a/docs/source/io_formats/index.rst b/docs/source/io_formats/index.rst index 7ae22c0a33f..4bbaa961a68 100644 --- a/docs/source/io_formats/index.rst +++ b/docs/source/io_formats/index.rst @@ -45,8 +45,10 @@ Output Files statepoint source summary + properties depletion_results particle_restart track voxel volume + weight_windows diff --git a/docs/source/io_formats/materials.rst b/docs/source/io_formats/materials.rst index ac2cfe271e1..92b0165a43c 100644 --- a/docs/source/io_formats/materials.rst +++ b/docs/source/io_formats/materials.rst @@ -31,7 +31,7 @@ Each ``material`` element can have the following attributes or sub-elements: :name: An optional string name to identify the material in summary output - files. This string is limited to 52 characters for formatting purposes. + files. *Default*: "" diff --git a/docs/source/io_formats/nuclear_data.rst b/docs/source/io_formats/nuclear_data.rst index ef61604cb44..8174108e1ae 100644 --- a/docs/source/io_formats/nuclear_data.rst +++ b/docs/source/io_formats/nuclear_data.rst @@ -339,6 +339,16 @@ Incoherent elastic scattering [eV\ :math:`^{-1}`]. :Attributes: - **type** (*char[]*) -- 'IncoherentElastic' +Sum of functions +---------------- + +:Object type: Group +:Attributes: - **type** (*char[]*) -- "Sum" + - **n** (*int*) -- Number of functions +:Datasets: + - ***func_** (:ref:`function <1d_functions>`) -- Dataset for the + i-th function (indexing starts at 1) + .. _angle_energy: -------------------------- @@ -501,6 +511,19 @@ equiprobable bins. - **skewed** (*int8_t*) -- Whether discrete angles are equi-probable (0) or have a skewed distribution (1). +Mixed Elastic +------------- + +This angle-energy distribution is used when an evaluation specifies both +coherent and incoherent elastic thermal neutron scattering. + +:Object type: Group +:Attributes: - **type** (*char[]*) -- "mixed_elastic" +:Groups: - **coherent** -- Distribution for coherent elastic scattering. The + format is given in :ref:`angle_energy`. + - **incoherent** -- Distribution for incoherent elastic scattering. + The format is given in :ref:`angle_energy`. + .. _energy_distribution: -------------------- diff --git a/docs/source/io_formats/particle_restart.rst b/docs/source/io_formats/particle_restart.rst index 6ebf7e7baa6..2734f0470ef 100644 --- a/docs/source/io_formats/particle_restart.rst +++ b/docs/source/io_formats/particle_restart.rst @@ -26,9 +26,12 @@ The current version of the particle restart file format is 2.0. - **run_mode** (*char[]*) -- Run mode used, either 'fixed source', 'eigenvalue', or 'particle restart'. - **id** (*int8_t*) -- Unique identifier of the particle. + - **type** (*int*) -- Particle type (0=neutron, 1=photon, 2=electron, + 3=positron) - **weight** (*double*) -- Weight of the particle. - **energy** (*double*) -- Energy of the particle in eV for continuous-energy mode, or the energy group of the particle for multi-group mode. - **xyz** (*double[3]*) -- Position of the particle. - **uvw** (*double[3]*) -- Direction of the particle. + - **time** (*double*) -- Time of the particle in [s]. diff --git a/docs/source/io_formats/plots.rst b/docs/source/io_formats/plots.rst index 966d2b80239..e6b75eafcb6 100644 --- a/docs/source/io_formats/plots.rst +++ b/docs/source/io_formats/plots.rst @@ -10,9 +10,9 @@ of the plots.xml is simply ```` and any number output plots can be defined with ```` sub-elements. Two plot types are currently implemented in openMC: -* ``slice`` 2D pixel plot along one of the major axes. Produces a PPM image +* ``slice`` 2D pixel plot along one of the major axes. Produces a PNG image file. -* ``voxel`` 3D voxel data dump. Produces a binary file containing voxel xyz +* ``voxel`` 3D voxel data dump. Produces an HDF5 file containing voxel xyz position and cell or material id. @@ -68,20 +68,14 @@ sub-elements: :type: Keyword for type of plot to be produced. Currently only "slice" and "voxel" plots are implemented. The "slice" plot type creates 2D pixel maps saved in - the PPM file format. PPM files can be displayed in most viewers (e.g. the - default Gnome viewer, IrfanView, etc.). The "voxel" plot type produces a - binary datafile containing voxel grid positioning and the cell or material - (specified by the ``color`` tag) at the center of each voxel. These - datafiles can be processed into VTK files using the :ref:`scripts_voxel` - script provided with OpenMC, and subsequently viewed with a 3D viewer such - as VISIT or Paraview. See the :ref:`io_voxel` for information about the - datafile structure. - - .. note:: Since the PPM format is saved without any kind of compression, - the resulting file sizes can be quite large. Saving the image in - the PNG format can often times reduce the file size by orders of - magnitude without any loss of image quality. Likewise, - high-resolution voxel files produced by OpenMC can be quite large, + the PNG file format. The "voxel" plot type produces a binary datafile + containing voxel grid positioning and the cell or material (specified by the + ``color`` tag) at the center of each voxel. Voxel plot files can be + processed into VTK files using the :ref:`scripts_voxel` script provided with + OpenMC and subsequently viewed with a 3D viewer such as VISIT or Paraview. + See the :ref:`io_voxel` for information about the datafile structure. + + .. note:: High-resolution voxel files produced by OpenMC can be quite large, but the equivalent VTK files will be significantly smaller. *Default*: "slice" @@ -94,11 +88,6 @@ attribute or sub-element: directions for "slice" and "voxel" plots, respectively. Should be two or three integers separated by spaces. - .. warning:: The ``pixels`` input determines the output file size. For the - PPM format, 10 million pixels will result in a file just under - 30 MB in size. A 10 million voxel binary file will be around - 40 MB. - .. warning:: If the aspect ratio defined in ``pixels`` does not match the aspect ratio defined in ``width`` the plot may appear stretched or squeezed. diff --git a/docs/source/io_formats/properties.rst b/docs/source/io_formats/properties.rst new file mode 100644 index 00000000000..5030e78f35d --- /dev/null +++ b/docs/source/io_formats/properties.rst @@ -0,0 +1,36 @@ +.. _io_properties: + +====================== +Properties File Format +====================== + +The current version of the properties file format is 1.0. + +**/** + +:Attributes: - **filetype** (*char[]*) -- String indicating the type of file. + - **version** (*int[2]*) -- Major and minor version of the + statepoint file format. + - **openmc_version** (*int[3]*) -- Major, minor, and release + version number for OpenMC. + - **git_sha1** (*char[40]*) -- Git commit SHA-1 hash. + - **date_and_time** (*char[]*) -- Date and time the summary was + written. + - **path** (*char[]*) -- Path to directory containing input files. + +**/geometry/** + +:Attributes: - **n_cells** (*int*) -- Number of cells in the problem. + +**/geometry/cells/cell /** + +:Datasets: - **temperature** (*double[]*) -- Temperature of the cell in [K]. + +**/materials/** + +:Attributes: - **n_materials** (*int*) -- Number of materials in the problem. + +**/materials/material /** + +:Attributes: - **atom_density** (*double*) -- Total density in [atom/b-cm]. + - **mass_density** (*double*) -- Total density in [g/cm^3]. diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index 53376b04c77..ae3266dabed 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -32,6 +32,17 @@ standard deviation. *Default*: false +------------------------------------- +```` Element +------------------------------------- + +The ```` element indicates whether delayed neutrons +are created in fission. If this element is set to "true", delayed neutrons +will be created in fission events; otherwise only prompt neutrons will be +created. + + *Default*: true + ------------------------------------- ```` Element ------------------------------------- @@ -49,13 +60,15 @@ fission. ```` Element -------------------- -The ```` element indicates two kinds of cutoffs. The first is the weight -cutoff used below which particles undergo Russian roulette. Surviving particles -are assigned a user-determined weight. Note that weight cutoffs and Russian -rouletting are not turned on by default. The second is the energy cutoff which -is used to kill particles under certain energy. The energy cutoff should not be -used unless you know particles under the energy are of no importance to results -you care. This element has the following attributes/sub-elements: +The ```` element indicates three kinds of cutoffs. The first is the +weight cutoff used below which particles undergo Russian roulette. Surviving +particles are assigned a user-determined weight. Note that weight cutoffs and +Russian rouletting are not turned on by default. The second is the energy cutoff +which is used to kill particles under certain energy. The energy cutoff should +not be used unless you know particles under the energy are of no importance to +results you care. The third is the time cutoff used to kill particles whose time +exceeds a specific cutoff. Particles will be killed exactly at the specified +time. :weight: The weight below which particles undergo Russian roulette. @@ -88,13 +101,25 @@ you care. This element has the following attributes/sub-elements: *Default*: 0.0 --------------------------------- -```` Element --------------------------------- + :time_neutron + The time above which neutrons will be killed. + + *Default*: Infinity + + :time_photon + The time above which photons will be killed. + + *Default*: Infinity + + :time_electron + The time above which electrons will be killed. -When the DAGMC mode is enabled, the OpenMC geometry will be read from the file -``dagmc.h5m``. If a :ref:`geometry.xml ` file is present with -``dagmc`` set to ``true``, it will be ignored. + *Default*: Infinity + + :time_positron + The time above which positorns will be killed. + + *Default*: Infinity ---------------------------- ```` @@ -227,9 +252,9 @@ to false. *Default*: true ----------------------------------------- +------------------------------------- ```` Element ----------------------------------------- +------------------------------------- This element indicates the number of neutrons to run in flight concurrently when using event-based parallelism. A higher value uses more memory, but @@ -237,9 +262,17 @@ may be more efficient computationally. *Default*: 100000 ---------------------------- +--------------------------------- +```` Element +--------------------------------- + +This element indicates the maximum number of events a particle can undergo. + + *Default*: 1000000 + +----------------------- ```` Element ---------------------------- +----------------------- The ```` element allows the user to set a maximum scattering order to apply to every nuclide/material in the problem. That is, if the data @@ -251,6 +284,23 @@ then, OpenMC will only use up to the :math:`P_1` data. .. note:: This element is not used in the continuous-energy :ref:`energy_mode`. +------------------------ +```` Element +------------------------ + +The ```` element indicates the number of times a particle can split during a history. + + *Default*: 1000 + +-------------------------------------- +```` Element +-------------------------------------- + +This ```` element indicates the maximum number of +particle restart files (per MPI process) to write for lost particles. + + *Default*: None + .. _mesh_element: ------------------ @@ -342,6 +392,15 @@ either "false" or "true". *Default*: false +----------------------- +```` Element +----------------------- + +The ```` element is used to set the seed for the pseudorandom number +generator during generation of colors in plots. + + *Default*: 1 + --------------------- ```` Element --------------------- @@ -354,6 +413,32 @@ or sub-elements and can be set to either "false" or "true". .. note:: This element is not used in the multi-group :ref:`energy_mode`. +------------------------ +```` Element +------------------------ + +The ```` element enables random ray mode and contains a number of +settings relevant to the solver. Tips for selecting these parameters can be +found in the :ref:`random ray user guide `. + + :distance_inactive: + The inactive ray length (dead zone length) in [cm]. + + *Default*: None + + :distance_active: + The active ray length in [cm]. + + *Default*: None + + :source: + Specifies the starting ray distribution, and follows the format for + :ref:`source_element`. It must be uniform in space and angle and cover the + full domain. It does not represent a physical neutron or photon source -- it + is only used to sample integrating ray starting locations and directions. + + *Default*: None + ---------------------------------- ```` Element ---------------------------------- @@ -429,6 +514,8 @@ pseudo-random number generator. *Default*: 1 +.. _source_element: + -------------------- ```` Element -------------------- @@ -446,24 +533,29 @@ attributes/sub-elements: *Default*: 1.0 + :type: + Indicator of source type. One of ``independent``, ``file``, ``compiled``, or + ``mesh``. The type of the source will be determined by this attribute if it + is present. + :particle: The source particle type, either ``neutron`` or ``photon``. *Default*: neutron :file: - If this attribute is given, it indicates that the source is to be read from - a binary source file whose path is given by the value of this element. Note, - the number of source sites needs to be the same as the number of particles - simulated in a fission source generation. + If this attribute is given, it indicates that the source type is ``file``, + meaning particles are to be read from a binary source file whose path is + given by the value of this element. *Default*: None :library: - If this attribute is given, it indicates that the source is to be - instantiated from an externally compiled source function. This source can be - as complex as is required to define the source for your problem. The library - has a few basic requirements: + If this attribute is given, it indicates that the source type is + ``compiled``, meaning that particles are instantiated from an externally + compiled source function. This source can be completely customized as needed + to define the source for your problem. The library has a few basic + requirements: * It must contain a class that inherits from ``openmc::Source``; * The class must implement a function called ``sample()``; @@ -471,16 +563,15 @@ attributes/sub-elements: as a unique pointer. This function can be used to pass parameters through to the source from the XML, if needed. - More documentation on how to build sources can be found in :ref:`custom_source`. - - *Default*: None + More documentation on how to build sources can be found in + :ref:`compiled_source`. :parameters: - If this attribute is given, it provides the parameters to pass through to the - class generated using the ``library`` parameter . More documentation on how to - build parametrized sources can be found in :ref:`parameterized_custom_source`. - - *Default*: None + If this attribute is given, it indicated that the source type is + ``compiled``. Its value provides the parameters to pass through to the class + generated using the ``library`` parameter. More documentation on how to + build parametrized sources can be found in + :ref:`parameterized_compiled_source`. :space: An element specifying the spatial distribution of source sites. This element @@ -498,9 +589,13 @@ attributes/sub-elements: independent distributions of r-, phi-, and z-coordinates where phi is the azimuthal angle and the origin for the cylindrical coordinate system is specified by origin. A "spherical" spatial distribution specifies - independent distributions of r-, theta-, and phi-coordinates where theta - is the angle with respect to the z-axis, phi is the azimuthal angle, and - the sphere is centered on the coordinate (x0,y0,z0). + independent distributions of r-, cos_theta-, and phi-coordinates where + cos_theta is the cosine of the angle with respect to the z-axis, phi is + the azimuthal angle, and the sphere is centered on the coordinate + (x0,y0,z0). A "mesh" spatial distribution samples source sites from a mesh element + based on the relative strengths provided in the node. Source locations + within an element are sampled isotropically. If no strengths are provided, + the space within the mesh is uniformly sampled. *Default*: None @@ -614,6 +709,47 @@ attributes/sub-elements: *Default*: false + :mesh: + For mesh sources, this indicates the ID of the corresponding mesh. + + :source: + For mesh sources, this sub-element specifies the source for an individual + mesh element and follows the format for :ref:`source_element`. The number of + ```` sub-elements should correspond to the number of mesh elements. + + :constraints: + This sub-element indicates the presence of constraints on sampled source + sites (see :ref:`usersguide_source_constraints` for details). It may have + the following sub-elements: + + :domain_ids: + The unique IDs of domains for which source sites must be within. + + *Default*: None + + :domain_type: + The type of each domain for source rejection ("cell", "material", or + "universe"). + + *Default*: None + + :fissionable: + A boolean indicating whether source sites must be sampled within a + material that is fissionable in order to be accepted. + + :time_bounds: + A pair of times in [s] indicating the lower and upper bound for a time + interval that source particles must be within. + + :energy_bounds: + A pair of energies in [eV] indicating the lower and upper bound for an + energy interval that source particles must be within. + + :rejection_strategy: + Either "resample", indicating that source sites should be resampled when + one is rejected, or "kill", indicating that a rejected source site is + assigned zero weight. + .. _univariate: Univariate Probability Distributions @@ -627,16 +763,17 @@ variable and whose sub-elements/attributes are as follows: :type: The type of the distribution. Valid options are "uniform", "discrete", - "tabular", "maxwell", and "watt". The "uniform" option produces variates - sampled from a uniform distribution over a finite interval. The "discrete" - option produces random variates that can assume a finite number of values - (i.e., a distribution characterized by a probability mass function). The - "tabular" option produces random variates sampled from a tabulated + "tabular", "maxwell", "watt", and "mixture". The "uniform" option produces + variates sampled from a uniform distribution over a finite interval. The + "discrete" option produces random variates that can assume a finite number + of values (i.e., a distribution characterized by a probability mass function). + The "tabular" option produces random variates sampled from a tabulated distribution where the density function is either a histogram or linearly-interpolated between tabulated points. The "watt" option produces random variates is sampled from a Watt fission spectrum (only used for energies). The "maxwell" option produce variates sampled from a Maxwell - fission spectrum (only used for energies). + fission spectrum (only used for energies). The "mixture" option produces samples + from univariate sub-distributions with given probabilities. *Default*: None @@ -645,6 +782,11 @@ variable and whose sub-elements/attributes are as follows: numbers :math:`a` and :math:`b` that define the interval :math:`[a,b]` over which random variates are sampled. + For a "powerlaw" distribution, ``parameters`` should be given as three real + numbers :math:`a` and :math:`b` that define the interval :math:`[a,b]` over + which random variates are sampled and :math:`n` that defines the exponent of + the probability distribution :math:`p(x)=c x^n` + For a "discrete" or "tabular" distribution, ``parameters`` provides the :math:`(x,p)` pairs defining the discrete/tabular distribution. All :math:`x` points are given first followed by corresponding :math:`p` points. @@ -659,12 +801,22 @@ variable and whose sub-elements/attributes are as follows: .. note:: The above format should be used even when using the multi-group :ref:`energy_mode`. + :interpolation: For a "tabular" distribution, ``interpolation`` can be set to "histogram" or "linear-linear" thereby specifying how tabular points are to be interpolated. *Default*: histogram +:pair: + For a "mixture" distribution, this element provides a distribution and its corresponding probability. + + :probability: + An attribute or ``pair`` that provides the probability of a univariate distribution within a "mixture" distribution. + + :dist: + This sub-element of a ``pair`` element provides information on the corresponding univariate distribution. + ------------------------- ```` Element ------------------------- @@ -723,27 +875,34 @@ attributes/sub-elements: *Default*: false ---------------------------- -```` Element ---------------------------- + :mcpl: + If this element is set to "true", the source point file containing the + source bank will be written as an MCPL_ file name ``source.mcpl`` instead of + an HDF5 file. This option is only applicable if the ```` element + is set to true. -The ```` element specifies a surface source file for OpenMC to -read source bank for initializing histories. -This element has the following attributes/sub-elements: + *Default*: false + +------------------------------ +```` Element +------------------------------ + +The ```` element specifies a surface source file for OpenMC to +read source bank for initializing histories. This element has the following +attributes/sub-elements: :path: Absolute or relative path to a surface source file to read in source bank. *Default*: ``surface_source.h5`` in current working directory ----------------------------- -```` Element ----------------------------- +------------------------------- +```` Element +------------------------------- -The ```` element triggers OpenMC to bank particles crossing +The ```` element triggers OpenMC to bank particles crossing certain surfaces and write out the source bank in a separate file called -``surface_source.h5``. -This element has the following attributes/sub-elements: +``surface_source.h5``. This element has the following attributes/sub-elements: :surface_ids: A list of integers separated by spaces indicating the unique IDs of surfaces @@ -759,6 +918,16 @@ This element has the following attributes/sub-elements: *Default*: None + :mcpl: + An optional boolean which indicates if the banked particles should be + written to a file in the MCPL_-format instead of the native HDF5-based + format. If activated the output file name is changed to + ``surface_source.mcpl``. + + *Default*: false + + .. _MCPL: https://mctools.github.io/mcpl/mcpl.pdf + ------------------------------ ```` Element ------------------------------ @@ -824,7 +993,9 @@ cell, the nearest temperature at which cross sections are given is to be applied, within a given tolerance (see :ref:`temperature_tolerance`). A value of "interpolation" indicates that cross sections are to be linear-linear interpolated between temperatures at which nuclear data are present (see -:ref:`temperature_treatment`). +:ref:`temperature_treatment`). With the "interpolation" method, temperatures +outside of the bounds of the nuclear data may be accepted, provided they still +fall within the tolerance (see :ref:`temperature_tolerance`). *Default*: "nearest" @@ -863,7 +1034,12 @@ The ```` element specifies a tolerance in Kelvin that is to be applied when the "nearest" temperature method is used. For example, if a cell temperature is 340 K and the tolerance is 15 K, then the closest temperature in the range of 325 K to 355 K will be used to evaluate cross -sections. +sections. If the ```` is "interpolation", the tolerance +specified applies to cell temperatures outside of the data bounds. For example, +if a cell is specified at 695K, a tolerance of 15K and data is only available +at 700K and 1000K, the cell's cross sections will be evaluated at 700K, since +the desired temperature of 695K is within the tolerance of the actual data +despite not being bounded on both sides. *Default*: 10 K @@ -978,8 +1154,14 @@ The ```` element indicates that a stochastic volume calculation should be run at the beginning of the simulation. This element has the following sub-elements/attributes: - :cells: - The unique IDs of cells for which the volume should be estimated. + :domain_type: + The type of each domain for the volume calculation ("cell", "material", or + "universe"). + + *Default*: None + + :domain_ids: + The unique IDs of domains for which the volume should be estimated. *Default*: None @@ -989,13 +1171,185 @@ sub-elements/attributes: *Default*: None :lower_left: - The lower-left Cartesian coordinates of a bounding box that is used to - sample points within. + The lower-left Cartesian coordinates of a bounding box that is used to + sample points within. - *Default*: None + *Default*: None :upper_right: - The upper-right Cartesian coordinates of a bounding box that is used to - sample points within. + The upper-right Cartesian coordinates of a bounding box that is used to + sample points within. + + *Default*: None + + :threshold: + Presence of a ```` sub-element indicates that the volume + calculation will be halted based on a threshold on the error. It has the + following sub-elements/attributes: + + :type: + The type of the trigger. Accepted options are "variance", "std_dev", + and "rel_err". + + :variance: + Variance of the mean, :math:`\sigma^2` + + :std_dev: + Standard deviation of the mean, :math:`\sigma` + + :rel_err: + Relative error of the mean, :math:`\frac{\sigma}{\mu}` + + *Default*: None + + :threshold: + The trigger's convergence criterion for the given type. + + *Default*: None + +---------------------------- +```` Element +---------------------------- + +The ```` element specifies all necessary parameters for +mesh-based weight windows. This element has the following +sub-elements/attributes: + + :id: + A unique integer that is used to identify the weight windows + + :mesh: + ID of a mesh that is to be used for weight windows + + *Default*: None + + :particle_type: + The particle that the weight windows will apply to (e.g., 'neutron') + + *Default*: 'neutron' + + :energy_bins: + Monotonically increasing list of bounding energies in [eV] to be used for + weight windows + + *Default*: None + + :lower_ww_bounds: + Lower weight window bound for each (energy bin, mesh bin) combination. + + *Default*: None + + :upper_ww_bounds: + Upper weight window bound for each (energy bin, mesh bin) combination. + + *Default*: None + + :survival: + The ratio of survival weight and lower weight window bound. + + *Default*: 3.0 + + :max_lower_bound_ratio: + Maximum allowed ratio of a particle's weight to the weight window's lower + bound. A factor will be applied to raise the weight window to be lower than + the particle's weight by a factor of max_lower_bound_ratio during transport + if exceeded. + + :max_split: + Maximum allowable number of particles when splitting + + *Default*: 10 + + :weight_cutoff: + Threshold below which particles will be terminated + + *Default*: :math:`10^{-38}` + +-------------------------------------- +```` Element +-------------------------------------- + +The ```` element provides information for creating a set of +mesh-based weight windows. + + :mesh: + ID of a mesh that is to be used for the weight windows spatial bins + + *Default*: None + + :energy_bounds: + The weight window energy bounds. If not present, the max/min energy of the + cross section data is applied as a single energy bin. + + *Default*: None + + :particle_type: + The particle that the weight windows will apply to (e.g., 'neutron') + + *Default*: neutron + + :max_realizations: + The number of tally realizations after which the weight windows will stop updating. + + *Default*: 1 + + :update_interval: + The number of tally realizations between weight window updates. + + *Default*: 1 + + :on_the_fly: + Controls whether or not the tally results are reset after a weight window update. + + *Default*: true + + :method: + Method used to update weight window values (currently only 'magic' is supported) + + *Default*: magic + + :update_parameters: + Method-specific update parameters used when generating/updating weight windows. + + For MAGIC: + + :value: + The type of tally value to use when creating weight windows (one of 'mean' or 'rel_err') + + *Default*: 'mean' + + :threshold: + The relative error threshold above which tally results will be ignored. + + *Default*: 1.0 + + :ratio: + The ratio of the lower to upper weight window bounds. + + *Default*: 5.0 + +--------------------------------------- +```` Element +--------------------------------------- + +The ```` element indicates the checkpoints for weight +window split/roulette (surface, collision or both). This element has the +following sub-elements/attributes: + + :surface: + If set to "true", weight window checks will be performed at surface + crossings. + + *Default*: False + + :collision: + If set to "true", weight window checks will be performed at collisions. + + *Default*: True + +-------------------------------------- +```` Element +-------------------------------------- - *Default*: None + The ``weight_windows_file`` element has no attributes and contains the path to + a weight windows HDF5 file to load during simulation initialization. diff --git a/docs/source/io_formats/source.rst b/docs/source/io_formats/source.rst index 86ae8a1e5e6..4ce2229ed8f 100644 --- a/docs/source/io_formats/source.rst +++ b/docs/source/io_formats/source.rst @@ -20,7 +20,7 @@ following the same format. - **source_bank** (Compound type) -- Source bank information for each particle. The compound type has fields ``r``, ``u``, ``E``, - ``wgt``, ``delayed_group``, ``surf_id`` and ``particle``, - which represent the position, direction, energy, weight, + ``time``, ``wgt``, ``delayed_group``, ``surf_id`` and ``particle``, + which represent the position, direction, energy, time, weight, delayed group, surface ID, and particle type (0=neutron, 1=photon, 2=electron, 3=positron), respectively. diff --git a/docs/source/io_formats/statepoint.rst b/docs/source/io_formats/statepoint.rst index 46725fa8b9d..f61e967ca8a 100644 --- a/docs/source/io_formats/statepoint.rst +++ b/docs/source/io_formats/statepoint.rst @@ -4,7 +4,7 @@ State Point File Format ======================= -The current version of the statepoint file format is 17.0. +The current version of the statepoint file format is 18.1. **/** @@ -52,11 +52,11 @@ The current version of the statepoint file format is 17.0. sum-of-squares for each global tally. - **source_bank** (Compound type) -- Source bank information for each particle. The compound type has fields ``r``, ``u``, ``E``, - ``wgt``, ``delayed_group``, ``surf_id``, and ``particle``, which - represent the position, direction, energy, weight, delayed group, - surface ID, and particle type (0=neutron, 1=photon, 2=electron, - 3=positron), respectively. - Only present when `run_mode` is 'eigenvalue'. + ``time``, ``wgt``, ``delayed_group``, ``surf_id``, and + ``particle``, which represent the position, direction, energy, + time, weight, delayed group, surface ID, and particle type + (0=neutron, 1=photon, 2=electron, 3=positron), respectively. Only + present when `run_mode` is 'eigenvalue'. **/tallies/** @@ -68,20 +68,41 @@ The current version of the statepoint file format is 17.0. :Attributes: - **n_meshes** (*int*) -- Number of meshes in the problem. - **ids** (*int[]*) -- User-defined unique ID of each mesh. +.. _mesh-spec-hdf5: + **/tallies/meshes/mesh /** :Datasets: - **type** (*char[]*) -- Type of mesh. - **dimension** (*int*) -- Number of mesh cells in each dimension. - - **lower_left** (*double[]*) -- Coordinates of lower-left corner of - mesh. - - **upper_right** (*double[]*) -- Coordinates of upper-right corner - of mesh. - - **width** (*double[]*) -- Width of each mesh cell in each - dimension. + - **Regular Mesh Only:** + - **lower_left** (*double[]*) -- Coordinates of lower-left corner of + mesh. + - **upper_right** (*double[]*) -- Coordinates of upper-right corner + of mesh. + - **width** (*double[]*) -- Width of each mesh cell in each + dimension. + - **Rectilinear Mesh Only:** + - **x_grid** (*double[]*) -- Mesh divisions along the x-axis. + - **y_grid** (*double[]*) -- Mesh divisions along the y-axis. + - **z_grid** (*double[]*) -- Mesh divisions along the z-axis. + - **Cylindrical & Spherical Mesh Only:** + - **r_grid** (*double[]*) -- The mesh divisions along the r-axis. + - **phi_grid** (*double[]*) -- The mesh divisions along the phi-axis. + - **origin** (*double[]*) -- The origin in cartesian coordinates. + - **Spherical Mesh Only:** + - **theta_grid** (*double[]*) -- The mesh divisions along the theta-axis. - **Unstructured Mesh Only:** + - **filename** (*char[]*) -- Name of the mesh file. + - **library** (*char[]*) -- Mesh library used to represent the + mesh ("moab" or "libmesh"). + - **length_multiplier** (*double*) Scaling factor applied to the mesh. + - **options** (*char[]*) -- Special options that control spatial + search data structures used. - **volumes** (*double[]*) -- Volume of each mesh cell. - - **centroids** (*double[]*) -- Location of the mesh cell - centroids. + - **vertices** (*double[]*) -- x, y, z values of the mesh vertices. + - **connectivity** (*int[]*) -- Connectivity array for the mesh + cells. + - **element_types** (*int[]*) -- Mesh element types. **/tallies/filters/** @@ -103,6 +124,10 @@ The current version of the statepoint file format is 17.0. - **y** (*double[]*) -- Interpolant values for energyfunction interpolation. Only used for 'energyfunction' filters. + :Attributes: + - **interpolation** (*int*) -- Interpolation type. Only used for + 'energyfunction' filters. + **/tallies/derivatives/derivative /** :Datasets: - **independent variable** (*char[]*) -- Independent variable of @@ -118,6 +143,8 @@ The current version of the statepoint file format is 17.0. - **internal** (*int*) -- Flag indicating the presence of tally data (0) or absence of tally data (1). All user defined tallies will have a value of 0 unless otherwise instructed. + - **multiply_density** (*int*) -- Flag indicating whether reaction + rates should be multiplied by atom density (1) or not (0). :Datasets: - **n_realizations** (*int*) -- Number of realizations. - **n_filters** (*int*) -- Number of filters used. @@ -149,7 +176,7 @@ All values are given in seconds and are measured on the master process. finalization. - **transport** (*double*) -- Time spent transporting particles. - **inactive batches** (*double*) -- Time spent in the inactive - batches (including non-transport activities like communcating + batches (including non-transport activities like communicating sites). - **active batches** (*double*) -- Time spent in the active batches (including non-transport activities like communicating sites). diff --git a/docs/source/io_formats/summary.rst b/docs/source/io_formats/summary.rst index cf0eca4aae0..7d3ab94d9f4 100644 --- a/docs/source/io_formats/summary.rst +++ b/docs/source/io_formats/summary.rst @@ -24,8 +24,6 @@ The current version of the summary file format is 6.0. - **n_universes** (*int*) -- Number of unique universes in the problem. - **n_lattices** (*int*) -- Number of lattices in the problem. - - **dagmc** (*int*) -- Indicates that a DAGMC geometry was used - if present. **/geometry/cells/cell /** @@ -49,25 +47,45 @@ The current version of the summary file format is 6.0. - **lattice** (*int*) -- Unique ID of the lattice which fills the cell. Only present if fill_type is set to 'lattice'. - **region** (*char[]*) -- Region specification for the cell. + - **geom_type** (*char[]*) -- Type of geometry used to create the cell. + Either 'csg' or 'dagmc'. **/geometry/surfaces/surface /** :Datasets: - **name** (*char[]*) -- Name of the surface. - **type** (*char[]*) -- Type of the surface. Can be 'x-plane', 'y-plane', 'z-plane', 'plane', 'x-cylinder', 'y-cylinder', - 'z-cylinder', 'sphere', 'x-cone', 'y-cone', 'z-cone', or 'quadric'. + 'z-cylinder', 'sphere', 'x-cone', 'y-cone', 'z-cone', 'quadric', + 'x-torus', 'y-torus', or 'z-torus'. - **coefficients** (*double[]*) -- Array of coefficients that define the surface. See :ref:`surface_element` for what coefficients are defined for each surface type. - - **boundary_condition** (*char[]*) -- Boundary condition applied to - the surface. Can be 'transmission', 'vacuum', 'reflective', or - 'periodic'. + - **boundary_type** (*char[]*) -- Boundary condition applied to + the surface. Can be 'transmission', 'vacuum', 'reflective', + 'periodic', or 'white'. + - **albedo** (*double*) -- Boundary albedo as a positive multiplier + of particle weight. If absent, it is assumed to be 1.0. + - **geom_type** (*char[]*) -- Type of geometry used to create the cell. + Either 'csg' or 'dagmc'. + **/geometry/universes/universe /** :Datasets: - **cells** (*int[]*) -- Array of unique IDs of cells that appear in the universe. + - **geom_type** (*char[]*) -- Type of geometry used to create the cell. + Either 'csg' or 'dagmc'. + - **filename** (*char[]*) -- Name of the DAGMC file representing this universe. + Only present for DAGMC Universes. +:Attributes: + - **auto_geom_ids** (*int*) -- ``1`` if geometry IDs of the DAGMC + model will be appended to the ID space of the natively defined + CSG geometry, ``0`` if the existing DAGMC IDs will be used. + - **auto_mat_ids** (*int*) -- ``1`` if UWUW material IDs of the DAGMC + model will be appended to the ID space of the natively defined + OpenMC materials, ``0`` if the existing UWUW IDs will be used. + **/geometry/lattices/lattice /** @@ -119,8 +137,8 @@ The current version of the summary file format is 6.0. :Attributes: - **volume** (*double[]*) -- Volume of this material [cm^3]. Only present if ``volume`` supplied - **temperature** (*double[]*) -- Temperature of this material [K]. - Only present in ``temperature`` supplied - - **depletable** (*int[]*) -- ``1`` if the material can be depleted, + Only present if ``temperature`` is supplied + - **depletable** (*int*) -- ``1`` if the material can be depleted, ``0`` otherwise. Always present **/nuclides/** diff --git a/docs/source/io_formats/tallies.rst b/docs/source/io_formats/tallies.rst index 8c1ad91b58b..78101ab668d 100644 --- a/docs/source/io_formats/tallies.rst +++ b/docs/source/io_formats/tallies.rst @@ -31,7 +31,7 @@ The ```` element accepts the following sub-elements: :name: An optional string name to identify the tally in summary output - files. This string is limited to 52 characters for formatting purposes. + files. *Default*: "" @@ -40,15 +40,15 @@ The ```` element accepts the following sub-elements: :nuclides: If specified, the scores listed will be for particular nuclides, not the - summation of reactions from all nuclides. The format for nuclides should be - [Atomic symbol]-[Mass number], e.g. "U-235". The reaction rate for all + summation of reactions from all nuclides. Nuclides are expressed using the + GNDS naming convention, e.g. "U235" or "Am242_m1". The reaction rate for all nuclides can be obtained with "total". For example, to obtain the reaction - rates for U-235, Pu-239, and all nuclides in a material, this element should + rates for U235, Pu239, and all nuclides in a material, this element should be: .. code-block:: xml - U-235 Pu-239 total + U235 Pu239 total *Default*: total @@ -69,6 +69,12 @@ The ```` element accepts the following sub-elements: list of valid scores can be found in the :ref:`user's guide `. + :multiply_density: + A boolean that indicates whether reaction rate scores should be computed by + multiplying by the atom density of a nuclide present in a material. + + *Default*: true + :trigger: Precision trigger applied to all filter bins and nuclides for this tally. It must specify the trigger's type, threshold and scores to which it will @@ -94,6 +100,18 @@ The ```` element accepts the following sub-elements: *Default*: None + :ignore_zeros: + Whether to allow zero tally bins to be ignored when assessing the + convergece of the precision trigger. If True, only nonzero tally scores + will be compared to the trigger's threshold. + + .. note:: The ``ignore_zeros`` option can cause the tally trigger to fire + prematurely if there are no hits in any bins at the first + evalulation. It is the user's responsibility to specify enough + particles per batch to get a nonzero score in at least one bin. + + *Default*: False + :scores: The score(s) in this tally to which the trigger should be applied. @@ -312,12 +330,16 @@ element with the tag name ````. This element has the following attributes/sub-elements: :type: - The type of mesh. This can be either "regular", "rectilinear", or - "unstructured". + The type of mesh. This can be either "regular", "rectilinear", + "cylindrical", "spherical", or "unstructured". :dimension: The number of mesh cells in each direction. (For regular mesh only.) + :length_multiplier: + A multiplicative factor to apply to the mesh coordinates in all directions. + (For unstructured mesh only.) + :lower_left: The lower-left corner of the structured mesh. If only two coordinates are given, it is assumed that the mesh is an x-y mesh. (For regular mesh only.) @@ -336,12 +358,28 @@ attributes/sub-elements: The mesh divisions along the y-axis. (For rectilinear mesh only.) :z_grid: - The mesh divisions along the z-axis. (For rectilinear mesh only.) + The mesh divisions along the z-axis. (For rectilinear and cylindrical meshes only.) + + :r_grid: + The mesh divisions along the r-axis. (For cylindrical and spherical meshes only.) + + :phi_grid: + The mesh divisions along the phi-axis. (For cylindrical and spherical meshes only.) + + :theta_grid: + The mesh divisions along the theta-axis. (For spherical mesh only.) + + :origin: + The origin in cartesian coordinates. (For cylindrical and spherical meshes only.) :library: The mesh library used to represent an unstructured mesh. This can be either "moab" or "libmesh". (For unstructured mesh only.) + :options: + Special options that control spatial search data structures used. (For + unstructured mesh using MOAB only) + :filename: The name of the mesh file to be loaded at runtime. (For unstructured mesh only.) diff --git a/docs/source/io_formats/track.rst b/docs/source/io_formats/track.rst index c617cd73e39..a97d75e58e6 100644 --- a/docs/source/io_formats/track.rst +++ b/docs/source/io_formats/track.rst @@ -4,18 +4,34 @@ Track File Format ================= -The current revision of the particle track file format is 2.0. +The current revision of the particle track file format is 3.0. **/** :Attributes: - **filetype** (*char[]*) -- String indicating the type of file. - **version** (*int[2]*) -- Major and minor version of the track file format. - - **n_particles** (*int*) -- Number of particles for which tracks - are recorded. - - **n_coords** (*int[]*) -- Number of coordinates for each - particle. :Datasets: - - **coordinates_** (*double[][3]*) -- (x,y,z) coordinates for the - *i*-th particle. + - **track___

** (Compound type) -- Particle track information + for source particle in batch *b*, generation *g*, and particle + number *p*. particle. The compound type has fields ``r``, ``u``, + ``E``, ``time``, ``wgt``, ``cell_id``, ``cell_instance``, and + ``material_id``, which represent the position (each coordinate in + [cm]), direction, energy in [eV], time in [s], weight, cell ID, + cell instance, and material ID, respectively. When the particle is + present in a cell with no material assigned, the material ID is + given as -1. Note that this array contains information for one or + more primary/secondary particles originating. The starting index + for each primary/secondary particle is given by the ``offsets`` + attribute. + + :Attributes: - **n_particles** (*int*) -- Number of + primary/secondary particles for the source history. + - **offsets** (*int[]*) Offset (starting index) into + the array for each primary/secondary particle. The + last offset should match the total size of the + array. + - **particles** (*int[]*) -- Particle type for each + primary/secondary particle (0=neutron, 1=photon, + 2=electron, 3=positron). diff --git a/docs/source/io_formats/weight_windows.rst b/docs/source/io_formats/weight_windows.rst new file mode 100644 index 00000000000..302e893187a --- /dev/null +++ b/docs/source/io_formats/weight_windows.rst @@ -0,0 +1,39 @@ +.. _io_weight_windows: + +==================== +Weight Window Format +==================== + +The current revision of the weight window file format is 1.0. + +**/** + +:Attributes: - **filetype** (*char[]*) -- String indicating the type of file. + - **version** (*int[2]*) -- Major and minor version of the weight + window file format. + +**/weight_windows/** + +:Attributes: - **n_weight_windows** (*int*) -- Number of weight window objects in the file. + - **ids** (*int[]*) -- Unique IDs of weight window objects in the file. + +**/weight_windows/weight_windows_/** + +:Datasets: - **mesh** (*int*) -- ID of the mesh associated with the weight window object. + - **particle_type** (*char[]*) -- Particle type to which the weight windows apply. + - **energy_bounds** (*double[]*) -- Energy bounds of the weight windows in [eV] + - **lower_ww_bounds** (*double[]*) -- Weight window lower bounds. + - **upper_ww_bounds** (*double[]*) -- Weight window upper bounds. + - **survival_ratio** (*double*) -- Weight window survival ratio. + - **max_lower_bound_ratio** (*double*) -- Maximum particle weight to lower weight window bound ratio. + - **max_split** (*int*) -- Maximum number of splits per weight window check. + - **weight_cutoff** (*double*) -- Particle weight cutoff. + +**/meshes/** + +:Attributes: - **n_meshes** (*int*) -- Number of meshes in the file. + - **ids** (*int[]*) -- User-defined unique ID of each mesh. + +**/meshes/mesh /** + +Please see the section on **/tallies/meshes/** in the :doc:`statepoint`. diff --git a/docs/source/license.rst b/docs/source/license.rst index 40ab106adaa..23315e8fe0b 100644 --- a/docs/source/license.rst +++ b/docs/source/license.rst @@ -4,7 +4,8 @@ License Agreement ================= -Copyright © 2011-2021 Massachusetts Institute of Technology and OpenMC contributors +Copyright © 2011-2024 Massachusetts Institute of Technology, UChicago Argonne +LLC, and OpenMC contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/docs/source/methods/cmfd.rst b/docs/source/methods/cmfd.rst index 344a4cc1a66..66d545ac18b 100644 --- a/docs/source/methods/cmfd.rst +++ b/docs/source/methods/cmfd.rst @@ -266,11 +266,11 @@ and eq. :eq:`eq_cell_bound` can be written in this generic form, The parameter :math:`\widetilde{D}_{l,m,n}^{u,g}` represents the linear coupling term between current and flux. These current relationships can be -sustituted into eq. :eq:`eq_neut_bal` to produce a linear system of multigroup +substituted into eq. :eq:`eq_neut_bal` to produce a linear system of multigroup diffusion equations for each spatial cell and energy group. However, a solution to these equations is not consistent with a higher order transport solution unless equivalence factors are present. This is because both the diffusion -approximation, governed by Fick's Law, and spatial trunction error will produce +approximation, governed by Fick's Law, and spatial truncation error will produce differences. Therefore, a nonlinear parameter, :math:`\widehat{D}_{l,m,n}^{u,g}`, is added to eqs. :eq:`eq_cell_cell` and :eq:`eq_cell_bound`. These equations are, respectively, diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index c6d1f44f44b..2cafa869162 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -9,7 +9,7 @@ Continuous-Energy Data ---------------------- In OpenMC, the data governing the interaction of neutrons with various nuclei -for continous-energy problems are represented using an HDF5 format that can be +for continuous-energy problems are represented using an HDF5 format that can be produced by converting files in the ACE format, which is used by MCNP_ and Serpent_. ACE-format data can be generated with the NJOY_ nuclear data processing system, which converts raw `ENDF/B data`_ into linearly-interpolable @@ -178,6 +178,27 @@ been selected. There are three methods available: section data is loaded for a single temperature and is used in the unresolved resonance and fast energy ranges. +------------------ +NCrystal materials +------------------ + +As an alternative of the standard thermal scattering treatment using +:math:`S(\alpha,\beta)` tables, OpenMC allows to create materials using +NCrystal_. In addition to the regular thermal elastic, and thermal inelastic +processes, NCrystal allows the generation of models for materials that cannot +currently included in ACE files such as oriented single crystals (see the +`NCrystal paper`_), and further extend the physics `using plugins`_. Thermal +scattering kernels are generated on the fly from dynamic and structural data, or +loaded from :math:`S(\alpha,\beta)` tables converted from ENDF6 evaluations. +These kernels are sampled in a direct way using a fast `rejection algorithm`_ +that does not require previous processing. A `large library`_ of materials is +already included in the NCrystal distribution, and new materials can be easily +defined from scratch in the `NCMAT format`_ or `combining existing files`_. + +The compositions of the materials defined in NCrystal are passed on to OpenMC +all other reactions except for thermal neutron scattering are handled by +continuous energy ACE libraries. + ---------------- Multi-Group Data ---------------- @@ -187,9 +208,10 @@ are represented using a multi-group library format specific to the OpenMC code. The format is described in the :ref:`mgxs_lib_spec`. The data itself can be prepared via traditional paths or directly from a continuous-energy OpenMC calculation by use of the Python API as is shown in an `example notebook -<../examples/mg-mode-part-i.ipynb>`_. This multi-group library consists of -meta-data (such as the energy group structure) and multiple `xsdata` objects -which contains the required microscopic or macroscopic multi-group data. +`_. +This multi-group library consists of meta-data (such as the energy group +structure) and multiple `xsdata` objects which contains the required microscopic +or macroscopic multi-group data. At a minimum, the library must contain the absorption cross section (:math:`\sigma_{a,g}`) and a scattering matrix. If the problem is an eigenvalue @@ -275,6 +297,13 @@ or even isotropic scattering. .. _MCNP: https://mcnp.lanl.gov .. _Serpent: http://montecarlo.vtt.fi .. _NJOY: https://www.njoy21.io/NJOY21/ -.. _ENDF/B data: https://www.nndc.bnl.gov/endf/b8.0/ +.. _ENDF/B data: https://www.nndc.bnl.gov/endf-b8.0/ .. _Leppanen: https://doi.org/10.1016/j.anucene.2009.03.019 .. _algorithms: http://ab-initio.mit.edu/wiki/index.php/Faddeeva_Package +.. _NCrystal: https://github.com/mctools/ncrystal +.. _NCrystal paper: https://doi.org/10.1016/j.cpc.2019.07.015 +.. _using plugins: https://doi.org/10.1016/j.cpc.2021.108082 +.. _rejection algorithm: https://doi.org/10.1016/j.jcp.2018.11.043 +.. _large library: https://github.com/mctools/ncrystal/wiki/Data-library +.. _NCMAT format: https://github.com/mctools/ncrystal/wiki/NCMAT-format +.. _combining existing files: https://github.com/mctools/ncrystal/wiki/Announcement-Release3.0.0#2-multiphase-materials diff --git a/docs/source/methods/depletion.rst b/docs/source/methods/depletion.rst index dce1f2503ef..87a9976dd0a 100644 --- a/docs/source/methods/depletion.rst +++ b/docs/source/methods/depletion.rst @@ -103,16 +103,17 @@ integrate over the entire timestep. Our aim here is not to exhaustively describe all integration methods but rather to give a few examples that elucidate the main considerations one must take into account when choosing a method. Generally, there is a tradeoff between the -accuracy of the method and its computational expense. The expense is driven -almost entirely by the time to compute a transport solution, i.e., to evaluate -:math:`\mathbf{A}` for a given :math:`\mathbf{n}`. Thus, the cost of a method -scales with the number of :math:`\mathbf{A}` evaluations that are performed per -timestep. On the other hand, methods that require more evaluations generally -achieve higher accuracy. The predictor method only requires one evaluation and -its error converges as :math:`\mathcal{O}(h)`. The CE/CM method requires two -evaluations and is thus twice as expensive as the predictor method, but achieves -an error of :math:`\mathcal{O}(h^2)`. An exhaustive description of time -integration methods and their merits can be found in the `thesis of Colin Josey +accuracy of the method and its computational expense. In the case of +transport-coupled depletion, the expense is driven almost entirely by the time +to compute a transport solution, i.e., to evaluate :math:`\mathbf{A}` for a +given :math:`\mathbf{n}`. Thus, the cost of a method scales with the number of +:math:`\mathbf{A}` evaluations that are performed per timestep. On the other +hand, methods that require more evaluations generally achieve higher accuracy. +The predictor method only requires one evaluation and its error converges as +:math:`\mathcal{O}(h)`. The CE/CM method requires two evaluations and is thus +twice as expensive as the predictor method, but achieves an error of +:math:`\mathcal{O}(h^2)`. An exhaustive description of time integration methods +and their merits can be found in the `thesis of Colin Josey `_. OpenMC does not rely on a single time integration method but rather has several @@ -169,12 +170,14 @@ Data Considerations In principle, solving Eq. :eq:`depletion-matrix` using CRAM is fairly simple: just construct the burnup matrix at various times and solve a set of sparse -linear systems. However, constructing the burnup matrix itself involves not only -solving the transport equation to estimate transmutation reaction rates but also -a series of choices about what data to include. In OpenMC, the burnup matrix is -constructed based on data inside of a *depletion chain* file, which includes -fundamental data gathered from ENDF incident neutron, decay, and fission product -yield sublibraries. For each nuclide, this file includes: +linear systems. However, constructing the burnup matrix itself involves not +only solving the transport equation to estimate transmutation reaction rates +(in the case of transport-coupled depletion) or to obtain microscopic cross +sections (in the case of transport-independent depletion), but also a series of +choices about what data to include. In OpenMC, the burnup matrix is constructed +based on data inside of a *depletion chain* file, which includes fundamental +data gathered from ENDF incident neutron, decay, and fission product yield +sublibraries. For each nuclide, this file includes: - What transmutation reactions are possible, their Q values, and their products; - If a nuclide is not stable, what decay modes are possible, their branching @@ -185,9 +188,12 @@ yield sublibraries. For each nuclide, this file includes: Transmutation Reactions ----------------------- -OpenMC will setup tallies in a problem based on what transmutation reactions are -available in a depletion chain file, so any arbitrary number of transmutation -reactions can be tracked. The pregenerated chain files that are available on +In transport-coupled depletion, OpenMC will setup tallies in a problem based on +what transmutation reactions are available in a depletion chain file, so any +arbitrary number of transmutation reactions can be tracked. In +transport-independent depletion, OpenMC will calculate reaction rates for every +reaction that is present in both the available cross sections and the depletion +chain file. The pregenerated chain files that are available on https://openmc.org include the following transmutation reactions: fission, (n,\ :math:`\gamma`\ ), (n,2n), (n,3n), (n,4n), (n,p), and (n,\ :math:`\alpha`\ ). @@ -202,11 +208,12 @@ accurately model the branching of the capture reaction in Am241. This is complicated by the fact that the branching ratio may depend on the incident neutron energy causing capture. -OpenMC does not currently allow energy-dependent capture branching ratios. -However, the depletion chain file does allow a transmutation reaction to be -listed multiple times with different branching ratios resulting in different -products. Spectrum-averaged capture branching ratios have been computed in LWR -and SFR spectra and are available at https://openmc.org/depletion-chains. +OpenMC's transport solver does not currently allow energy-dependent capture +branching ratios. However, the depletion chain file does allow a transmutation +reaction to be listed multiple times with different branching ratios resulting +in different products. Spectrum-averaged capture branching ratios have been +computed in LWR and SFR spectra and are available at +https://openmc.org/depletion-chains. Fission Product Yields ---------------------- @@ -217,26 +224,31 @@ energies. It is an open question as to what the best way to handle this energy dependence is. OpenMC includes three methods for treating the energy dependence of FPY: -1. Use FPY data corresponding to a specified energy. +1. Use FPY data corresponding to a specified energy. This is used by default in + both transport-coupled and transport-independent depletion. 2. Tally fission rates above and below a specified cutoff energy. Assume that all fissions below the cutoff energy correspond to thermal FPY data and all - fission above the cutoff energy correspond to fast FPY data. + fission above the cutoff energy correspond to fast FPY data. Only applicable + to transport-coupled depletion. 3. Compute the average energy at which fission events occur and use an effective FPY by linearly interpolating between FPY provided at neighboring energies. + Only applicable to transport-coupled depletion. -The method can be selected through the ``fission_yield_mode`` argument to the -:class:`openmc.deplete.Operator` constructor. +The method for transport-coupled depletion can be selected through the +``fission_yield_mode`` argument to the :class:`openmc.deplete.CoupledOperator` +constructor. Power Normalization ------------------- -The reaction rates provided OpenMC are given in units of reactions per source -particle. For depletion, it is necessary to compute an absolute reaction rate in -reactions per second. To do so, the reaction rates are normalized based on a -specified power. A complete description of how this normalization can be -performed is described in :ref:`usersguide_tally_normalization`. Here, we simply -note that the main depletion class, :class:`openmc.deplete.Operator`, allows the -user to choose one of two methods for estimating the heating rate, including: +In transport-coupled depletion, the reaction rates provided OpenMC are given in +units of reactions per source particle. For depletion, it is necessary to +compute an absolute reaction rate in reactions per second. To do so, the +reaction rates are normalized based on a specified power. A complete +description of how this normalization can be performed is described in +:ref:`usersguide_tally_normalization`. Here, we simply note that the main +depletion class, :class:`openmc.deplete.CoupledOperator`, allows the user to +choose one of two methods for estimating the heating rate, including: 1. Using fixed Q values from a depletion chain file (useful for comparisons to other codes that use fixed Q values), or @@ -244,4 +256,86 @@ user to choose one of two methods for estimating the heating rate, including: energy-dependent estimate of the true heating rate. The method for normalization can be chosen through the ``normalization_mode`` -argument to the :class:`openmc.deplete.Operator` class. +argument to the :class:`openmc.deplete.CoupledOperator` class. + +-------------- +Transfer Rates +-------------- + +OpenMC allows continuous removal or feed of nuclides by adding an +extra transfer rate term to the depletion matrix. An application of this feature +is the chemical processing of Molten Salt Reactors (MSRs), where one can +model the removal of fission products or feeding fresh fuel into the system. + +A transfer rate as defined here is the rate at which nuclides are +continuously removed/fed from/to a material. + +.. note:: + + A transfer rate can be positive or negative, indicating removal or feed + respectively. + +Mathematically, it can be thought of as an additional term :math:`\mathbf{T}` +in the depletion equation that is proportional to the nuclide density, which can be written as: + +.. math:: + + \begin{aligned}\frac{dN_i(t)}{dt} = &\underbrace{\sum\limits_j f_{j\rightarrow i} + \int_0^\infty dE \; \sigma_j (E,t) \phi(E,t) N_j(t) - \int_0^\infty dE \; \sigma_i(E,t) + \phi(E,t) N_i(t)}_\textbf{R} \\ + &+ \underbrace{\sum_j \left [ \lambda_{j\rightarrow i} N_j(t) - \lambda_{i\rightarrow j} N_i(t) \right ]}_\textbf{D} \\ + &- \underbrace{t_i N_i(t)}_\textbf{T} \end{aligned} + +where the reaction term :math:`\mathbf{R}`, the decay term :math:`\mathbf{D}` +and the new transfer term :math:`\mathbf{T}` have been grouped together so that +:math:`\mathbf{A} = \mathbf{R}+\mathbf{D}-\mathbf{T}`. +The transfer rate coefficient :math:`t_i` defines the continuous transfer of the +nuclide :math:`i`, which behaves similar to radioactive decay. +:math:`t_i` can also be defined as the reciprocal of a cycle time +:math:`T_{cyc}`, intended as the time needed to process the whole inventory. + +Note that this formulation assumes homogeneous distribution of nuclide +:math:`i` throughout the material. + +A more rigorous description of removal rate and its implementation can be found +in the paper by `Hombourger +`_. + +The resulting burnup matrix can be solved with the same integration algorithms +that are used in the absence of the transfer term. + +.. note:: + + If no ``destination_material`` is specified, nuclides that are removed + or fed will not be tracked afterwards. + +Coupling materials +------------------ + +To keep track of removed nuclides or to feed nuclides from one depletable material +to another, the respective depletion equations have to be coupled. This can be +achieved by defining one block matrix, with diagonal blocks corresponding to +depletion matrices :math:`\mathbf{A_{ii}}`, where the index :math:`i` indicates +the depletable material id, and off-diagonal blocks corresponding to inter-material +coupling matrices :math:`\mathbf{T_{ij}}`, positioned so that that the indices :math:`i` and +:math:`j` indicate the nuclides receiving and losing materials, respectively. +The nuclide vectors are assembled together in one single vector and the resulting +system is solved with the same integration algorithms seen before. + +As an example, consider the case of two depletable materials and one +transfer defined from material 1 to material 2. The final system will look like: + +.. math:: + + \begin{aligned}\frac{d}{dt}\begin{pmatrix}\vec{N_1}\\ \vec{N_2}\end{pmatrix} &= + \begin{pmatrix}\mathbf{A_{11}} & \mathbf{0}\\ \mathbf{T_{21}} & \mathbf{A_{22 }} + \end{pmatrix} \begin{pmatrix}\vec{N_1}\\ \vec{N_2}\end{pmatrix} \end{aligned} + +where: + +:math:`\mathbf{A_{11}} = \mathbf{R_{11}}+\mathbf{D_{11}}-\mathbf{T_{21}}`, and + +:math:`\mathbf{A_{22}} = \mathbf{R_{22}}+\mathbf{D_{22}}`. + +Note that mass conservation is guaranteed by transferring the number +of atoms directly. diff --git a/docs/source/methods/energy_deposition.rst b/docs/source/methods/energy_deposition.rst index fbcccc26b20..4675aee3fb2 100644 --- a/docs/source/methods/energy_deposition.rst +++ b/docs/source/methods/energy_deposition.rst @@ -7,7 +7,7 @@ Heating and Energy Deposition As particles traverse a problem, some portion of their energy is deposited at collision sites. This energy is deposited when charged particles, including electrons and recoil nuclei, undergo electromagnetic interactions with -surrounding electons and ions. The information describing how much energy +surrounding electrons and ions. The information describing how much energy is deposited for a specific reaction is referred to as "heating numbers" and can be computed using a program like NJOY with the ``heatr`` module. diff --git a/docs/source/methods/geometry.rst b/docs/source/methods/geometry.rst index 04e3456c4db..b282ffdee37 100644 --- a/docs/source/methods/geometry.rst +++ b/docs/source/methods/geometry.rst @@ -118,7 +118,19 @@ to fully define the surface. +----------------------+------------+------------------------------+-------------------------+ | General quadric | quadric | :math:`Ax^2 + By^2 + Cz^2 + | :math:`A \; B \; C \; D | | surface | | Dxy + Eyz + Fxz + Gx + Hy + | \; E \; F \; G \; H \; | - | | | Jz + K` | J \; K` | + | | | Jz + K = 0` | J \; K` | + +----------------------+------------+------------------------------+-------------------------+ + | Torus parallel to the| x-torus | :math:`(x-x_0)^2/B^2+\frac{( | :math:`x_0 \; y_0 \; | + | :math:`x`-axis | | \sqrt{(y-y_0)^2+(z-z_0)^2} - | z_0 \; A \; B \; C` | + | | | A)^2}{C^2} - 1 = 0` | | + +----------------------+------------+------------------------------+-------------------------+ + | Torus parallel to the| y-torus | :math:`(y-y_0)^2/B^2+\frac{( | :math:`x_0 \; y_0 \; | + | :math:`y`-axis | | \sqrt{(x-x_0)^2+(z-z_0)^2} - | z_0 \; A \; B \; C` | + | | | A)^2}{C^2} - 1 = 0` | | + +----------------------+------------+------------------------------+-------------------------+ + | Torus parallel to the| z-torus | :math:`(z-z_0)^2/B^2+\frac{( | :math:`x_0 \; y_0 \; | + | :math:`z`-axis | | \sqrt{(x-x_0)^2+(y-y_0)^2} - | z_0 \; A \; B \; C` | + | | | A)^2}{C^2} - 1 = 0` | | +----------------------+------------+------------------------------+-------------------------+ .. _universes: @@ -437,6 +449,72 @@ Defining the terms we then have the simple quadratic equation :math:`ad^2 + 2kd + c = 0` which can be solved as described in :ref:`cylinder_distance`. +Torus Parallel to an Axis +------------------------- + +The equation for a torus parallel to, for example, the x-axis is + +.. math:: + :label: dist-xtorus-sqrt + + \frac{(x-x_0)^2}{B^2} + \frac{(\sqrt{(y-y_0)^2 + (z-z_0)^2} - A)^2}{C^2} - + 1 = 0. + +First, it needs to be cast into a polynomial form. Rearranging terms, + +.. math:: + :label: dist-xtorus-1 + + (D\bar{x}^2 + \bar{y}^2 + \bar{z}^2 + A^2 - C^2)^2 = 4A^2(\bar{y}^2 + + \bar{z}^2) + +where :math:`D = (C/B)^2`, :math:`\bar{x} = x - x_0`, :math:`\bar{y} = y - y_0`, +and :math:`\bar{z} = z - z_0`. To find the distance to the surface, we thus need +to solve + +.. math:: + :label: dist-xtorus-2 + + (D(\bar{x} + du)^2 + (\bar{y} + dv)^2 + (\bar{z} + dw)^2 + A^2 - C^2)^2 = + 4A^2((\bar{y} + dv)^2 + (\bar{z} + dw)^2). + +Expanding and collecting like powers of :math:`d` yields + +.. math:: + :label: dist-xtorus-3 + + (c_2d^2 + c_1d + c_0)^2 = c_2'd^2 + c_1'd + c_0' + +where + +.. math:: + :label: dist-xtorus-4 + + \begin{aligned} + c_2 &= Du^2 + v^2 + w^2 \\ + c_1 &= 2(Du\bar{x} + v\bar{y} + w\bar{z}) \\ + c_0 &= D\bar{x}^2 + \bar{y}^2 + \bar{z}^2 + A^2 - C^2 \\ + c_2' &= 4A^2 (v^2 + w^2) \\ + c_1' &= 8A^2 (v\bar{y} + w\bar{z}) \\ + c_0' &= 4A^2(\bar{y}^2 + \bar{z}^2). + \end{aligned} + +Expanding the left-hand side and collecting like powers of :math:`d` on one +side, we obtain + +.. math:: + :label: dist-xtorus-5 + + (c_2^2)d^4 + (2c_1c_2)d^3 + (c_1^2 + 2c_0c_2 - c_2')d^2 + (2c_0c_1 - c_1')d + + (c_0^2 - c_0') = 0. + +The above equation is a fourth-order (quartic) polynomial equation. Although +there is an analytical solution to the general quartic equation, it can be +subject to roundoff errors when evaluated numerically. OpenMC uses an external +`quartic equation solver `_ developed by +Orellana and De Michele that is based on the decomposition of the quartic +polynomial into two quadratics. + .. _find-cell: ---------------------------- @@ -637,16 +715,20 @@ unsuccessful, then a search is done over every cell in the base universe. Building Neighbor Lists ----------------------- -After the geometry has been loaded and stored in memory from an input file, -OpenMC builds a list for each surface containing any cells that are bounded by -that surface in order to speed up processing of surface crossings. The algorithm -to build these lists is as follows. First, we loop over all cells in the -geometry and count up how many times each surface appears in a specification as -bounding a negative half-space and bounding a positive half-space. Two arrays -are then allocated for each surface, one that lists each cell that contains the -negative half-space of the surface and one that lists each cell that contains -the positive half-space of the surface. Another loop is performed over all cells -and the neighbor lists are populated for each surface. +Neighbor lists are data structures that are used to accelerate geometry searches +when a particle crosses a boundary. Namely, they are used to constrain the +number of cells that must be searched in order to determine which cell a +particle is crossing into. Earlier versions of OpenMC relied on "surface-based" +neighbor lists, where the cells that are adjacent to each surface are stored in +lists, one for each side of a surface. As of version 0.11, OpenMC switched to +using "cell-based" neighbor lists. For each cell, a list of the adjacent cells +is stored and then used to limit future searches. Unlike surface-based neighbor +lists, cell-based neighbor lists cannot be computed prior to transport. Thus, +cell-based neighbor lists in OpenMC grow dynamically as particles are +transported through the geometry and cross surfaces. Special care must be taken +to ensure that these dynamic neighbor lists are populated in a threadsafe +manner. Full details of the implementation in OpenMC can be found in a paper by +`Harper et al `_. .. _reflection: @@ -895,6 +977,27 @@ Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0`. Thus, the gradient to the surface is \nabla f = \left ( \begin{array}{c} 2Ax + Dy + Fz + G \\ 2By + Dx + Ez + H \\ 2Cz + Ey + Fx + J \end{array} \right ). +Torus Parallel to an Axis +------------------------- + +A torus parallel to, for example, the x-axis has the form + +.. math:: + :label: reflection-torus-1 + + f(x,y,z) = \frac{(x-x_0)^2}{B^2} + \frac{(\sqrt{(y-y_0)^2 + (z-z_0)^2} - + A)^2}{C^2} - 1. + +The gradient to the surface is therefore + +.. math:: + :label: reflection-torus-grad + + \nabla f = \left ( \begin{array}{c} 2\bar{x}/B^2 \\ 2\bar{y}(g - A)/(C^2g) + \\ 2\bar{z}(g - A)/(C^2g) \end{array} \right ) + +where :math:`g = \sqrt{\bar{y}^2 + \bar{z}^2}` and, as always, :math:`\bar{x} = +x - x_0`, :math:`\bar{y} = y - y_0`, and :math:`\bar{z} = z - z_0`. .. _white: diff --git a/docs/source/methods/index.rst b/docs/source/methods/index.rst index 59892ac273f..08aa7d05341 100644 --- a/docs/source/methods/index.rst +++ b/docs/source/methods/index.rst @@ -20,3 +20,4 @@ Theory and Methodology energy_deposition parallelization cmfd + random_ray \ No newline at end of file diff --git a/docs/source/methods/introduction.rst b/docs/source/methods/introduction.rst index 924d4858ded..eacdd70f520 100644 --- a/docs/source/methods/introduction.rst +++ b/docs/source/methods/introduction.rst @@ -45,7 +45,7 @@ following steps: - Initialize the pseudorandom number generator. - - Read the contiuous-energy or multi-group cross section data specified in + - Read the continuous-energy or multi-group cross section data specified in the problem. - If using a special energy grid treatment such as a union energy grid or diff --git a/docs/source/methods/neutron_physics.rst b/docs/source/methods/neutron_physics.rst index 774575b46e1..70ace4a3532 100644 --- a/docs/source/methods/neutron_physics.rst +++ b/docs/source/methods/neutron_physics.rst @@ -91,7 +91,7 @@ inelastic scattering reactions. The specific multi-group scattering implementation is discussed in the :ref:`multi-group-scatter` section. Elastic scattering refers to the process by which a neutron scatters off a -nucleus and does not leave it in an excited. It is referred to as "elastic" +nucleus and does not leave it in an excited state. It is referred to as "elastic" because in the center-of-mass system, the neutron does not actually lose energy. However, in lab coordinates, the neutron does indeed lose energy. Elastic scattering can be treated exactly in a Monte Carlo code thanks @@ -182,7 +182,7 @@ Inelastic Scattering -------------------- Note that the multi-group mode makes no distinction between elastic or -inelastic scattering reactions. The spceific multi-group scattering +inelastic scattering reactions. The specific multi-group scattering implementation is discussed in the :ref:`multi-group-scatter` section. The major algorithms for inelastic scattering were described in previous @@ -359,7 +359,7 @@ secondary energy and angle sampling. For a reaction with secondary products, it is necessary to determine the outgoing angle and energy of the products. For any reaction other than elastic and level inelastic scattering, the outgoing energy must be determined based on -tabulated or parameterized data. The `ENDF-6 Format `_ specifies a +tabulated or parameterized data. The `ENDF-6 Format`_ specifies a variety of ways that the secondary energy distribution can be represented. ENDF File 5 contains uncorrelated energy distribution whereas ENDF File 6 contains correlated energy-angle distributions. The ACE format specifies its own @@ -1403,7 +1403,7 @@ given analytically by .. math:: :label: coherent-elastic-angle - \mu = 1 - \frac{E_i}{E} + \mu = 1 - \frac{2E_i}{E} where :math:`E_i` is the energy of the Bragg edge that scattered the neutron. @@ -1416,8 +1416,7 @@ For incoherent elastic scattering, OpenMC has two methods for calculating the cosine of the angle of scattering. The first method uses the Debye-Waller integral, :math:`W'`, and the characteristic bound cross section as given directly in an ENDF-6 formatted file. In this case, the cosine of the angle of -scattering can be sampled by inverting equation 7.4 from the `ENDF-6 Format -Manual `_: +scattering can be sampled by inverting equation 7.4 from the `ENDF-6 Format`_: .. math:: :label: incoherent-elastic-mu-exact @@ -1627,6 +1626,8 @@ cross sections. Variance Reduction Techniques ----------------------------- +.. _survival_biasing: + Survival Biasing ---------------- @@ -1677,6 +1678,47 @@ default, the cutoff weight in OpenMC is :math:`w_c = 0.25` and the survival weight is :math:`w_s = 1.0`. These parameters vary from one Monte Carlo code to another. +Weight Windows +-------------- + +In fixed source problems, it can often be difficult to obtain sufficiently low +variance on tallies in regions that are far from the source. The `weight window +method `_ was developed to increase the +population of particles in important spatial regions and energy ranges by +controlling particle weights. Each spatial region and particle energy range is +assigned upper and lower weight bounds, :math:`w_u` and :math:`w_\ell`, +respectively. When a particle is in a given spatial region / energy range, its +weight, :math:`w`, is compared to the lower and upper bounds. If the weight of +the particle is above the upper weight bound, the particle is split into +:math:`N` particles, where + +.. math:: + :label: ww-split + + N = \min(N_{max}, \lceil w/w_u \rceil) + +and :math:`N_{max}` is a user-defined maximum number of splits. To ensure a +fair game, each of the :math:`N` particles is assigned a weight :math:`w/N`. If +the weight is below :math:`w_\ell`, it is Russian rouletted as described in +:ref:`survival_biasing` with a survival weight :math:`w_s` that is set equal to + +.. math:: + :label: ww-survival-weight + + w_s = \min(N_{max} w, f_s w_l) + +where :math:`f_s` is a user-defined survival weight ratio greater than one. + +On top of the standard weight window method described above, OpenMC implements +two additional checks intended to mitigate problems with long histories. First, +particles with a weight that falls below some very small cutoff (defaults to +:math:`10^{-38}`) are killed with no Russian rouletting. Additionally, the total +number of splits experienced by a particle is tracked and if it reaches some +maximum value, it is prohibited from splitting further. + +At present, OpenMC allows weight windows to be defined on all supported mesh +types. + .. only:: html .. rubric:: References @@ -1709,7 +1751,7 @@ another. .. _PREPRO: https://www-nds.iaea.org/ndspub/endf/prepro/ -.. _endf102: https://www.oecd-nea.org/dbdata/data/manual-endf/endf102.pdf +.. _ENDF-6 Format: https://www.oecd-nea.org/dbdata/data/manual-endf/endf102.pdf .. _Monte Carlo Sampler: https://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-09721-MS diff --git a/docs/source/methods/parallelization.rst b/docs/source/methods/parallelization.rst index 29748807ab3..d9fc15c9fab 100644 --- a/docs/source/methods/parallelization.rst +++ b/docs/source/methods/parallelization.rst @@ -293,7 +293,7 @@ Cost of Nearest Neighbor Algorithm ---------------------------------- With the communication cost of the traditional fission bank algorithm -quantified, we now proceed to discuss the communicatin cost of the proposed +quantified, we now proceed to discuss the communication cost of the proposed algorithm. Comparing the cost of communication of this algorithm with the traditional algorithm is not trivial due to fact that the cost will be a function of how many fission sites are sampled on each node. If each node @@ -398,7 +398,7 @@ equation :eq:`k-to-source`, we can relate the stochastic eigenvalue to the integral of the noise component of the source distribution as .. math:: - :label: noise-integeral + :label: noise-integral N\hat{k} = Nk + \sqrt{N} \int \hat{\epsilon}(\mathbf{r}) \: d\mathbf{r}. diff --git a/docs/source/methods/random_ray.rst b/docs/source/methods/random_ray.rst new file mode 100644 index 00000000000..aa436784766 --- /dev/null +++ b/docs/source/methods/random_ray.rst @@ -0,0 +1,804 @@ +.. _methods_random_ray: + +========== +Random Ray +========== + +.. _methods_random_ray_intro: + +------------------- +What is Random Ray? +------------------- + +`Random ray `_ is a stochastic transport method, closely related to +the deterministic Method of Characteristics (MOC) [Askew-1972]_. Rather than +each ray representing a single neutron as in Monte Carlo, it represents a +characteristic line through the simulation geometry upon which the transport +equation can be written as an ordinary differential equation that can be solved +analytically (although with discretization required in energy, making it a +multigroup method). The behavior of the governing transport equation can be +approximated by solving along many characteristic tracks (rays) through the +system. Unlike particles in Monte Carlo, rays in random ray or MOC are not +affected by the material characteristics of the simulated problem---rays are +selected so as to explore the full simulation problem with a statistically equal +distribution in space and angle. + +.. raw:: html + + + +The above animation is an example of the random ray integration process at work, +showing a series of random rays being sampled and transported through the +geometry. In the following sections, we will discuss how the random ray solver +works. + +---------------------------------------------- +Why is a Random Ray Solver Included in OpenMC? +---------------------------------------------- + +* One area that Monte Carlo struggles with is maintaining numerical efficiency + in regions of low physical particle flux. Random ray, on the other hand, has + approximately even variance throughout the entire global simulation domain, + such that areas with low neutron flux are no less well known that areas of + high neutron flux. Absent weight windows in MC, random ray can be several + orders of magnitude faster than multigroup Monte Carlo in classes of problems + where areas with low physical neutron flux need to be resolved. While MC + uncertainty can be greatly improved with variance reduction techniques, they + add some user complexity, and weight windows can often be expensive to + generate via MC transport alone (e.g., via the `MAGIC method + `_). The random ray solver + may be used in future versions of OpenMC as a fast way to generate weight + windows for subsequent usage by the MC solver in OpenMC. + +* In practical implementation terms, random ray is mechanically very similar to + how Monte Carlo works, in terms of the process of ray tracing on constructive + solid geometry (CSG) and handling stochastic convergence, etc. In the original + 1972 paper by Askew that introduces MOC (which random ray is a variant of), he + stated: + + .. epigraph:: + + "One of the features of the method proposed [MoC] is that ... the + tracking process needed to perform this operation is common to the + proposed method ... and to Monte Carlo methods. Thus a single tracking + routine capable of recognizing a geometric arrangement could be utilized + to service all types of solution, choice being made depending which was + more appropriate to the problem size and required accuracy." + + -- Askew [Askew-1972]_ + + This prediction holds up---the additional requirements needed in OpenMC to + handle random ray transport turned out to be fairly small. + +* It amortizes the code complexity in OpenMC for representing multigroup cross + sections. There is a significant amount of interface code, documentation, and + complexity in allowing OpenMC to generate and use multigroup XS data in its + MGMC mode. Random ray allows the same multigroup data to be used, making full + reuse of these existing capabilities. + +------------------------------- +Random Ray Numerical Derivation +------------------------------- + +In this section, we will derive the numerical basis for the random ray solver +mode in OpenMC. The derivation of random ray is also discussed in several papers +(`1 `_, `2 `_, `3 `_), and some of those +derivations are reproduced here verbatim. Several extensions are also made to +add clarity, particularly on the topic of OpenMC's treatment of cell volumes in +the random ray solver. + +~~~~~~~~~~~~~~~~~~~~~~~~~ +Method of Characteristics +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Boltzmann neutron transport equation is a partial differential equation +(PDE) that describes the angular flux within a system. It is a balance equation, +with the streaming and absorption terms typically appearing on the left hand +side, which are balanced by the scattering source and fission source terms on +the right hand side. + +.. math:: + :label: transport + + \begin{align*} + \mathbf{\Omega} \cdot \mathbf{\nabla} \psi(\mathbf{r},\mathbf{\Omega},E) & + \Sigma_t(\mathbf{r},E) \psi(\mathbf{r},\mathbf{\Omega},E) = \\ + & \int_0^\infty d E^\prime \int_{4\pi} d \Omega^{\prime} \Sigma_s(\mathbf{r},\mathbf{\Omega}^\prime \rightarrow \mathbf{\Omega}, E^\prime \rightarrow E) \psi(\mathbf{r},\mathbf{\Omega}^\prime, E^\prime) \\ + & + \frac{\chi(\mathbf{r}, E)}{4\pi k_{eff}} \int_0^\infty dE^\prime \nu \Sigma_f(\mathbf{r},E^\prime) \int_{4\pi}d \Omega^\prime \psi(\mathbf{r},\mathbf{\Omega}^\prime,E^\prime) + \end{align*} + +In Equation :eq:`transport`, :math:`\psi` is the angular neutron flux. This +parameter represents the total distance traveled by all neutrons in a particular +direction inside of a control volume per second, and is often given in units of +:math:`1/(\text{cm}^{2} \text{s})`. As OpenMC does not support time dependence +in the random ray solver mode, we consider the steady state equation, where the +units of flux become :math:`1/\text{cm}^{2}`. The angular direction unit vector, +:math:`\mathbf{\Omega}`, represents the direction of travel for the neutron. The +spatial position vector, :math:`\mathbf{r}`, represents the location within the +simulation. The neutron energy, :math:`E`, or speed in continuous space, is +often given in units of electron volts. The total macroscopic neutron cross +section is :math:`\Sigma_t`. This value represents the total probability of +interaction between a neutron traveling at a certain speed (i.e., neutron energy +:math:`E`) and a target nucleus (i.e., the material through which the neutron is +traveling) per unit path length, typically given in units of +:math:`1/\text{cm}`. Macroscopic cross section data is a combination of +empirical data and quantum mechanical modeling employed in order to generate an +evaluation represented either in pointwise form or resonance parameters for each +target isotope of interest in a material, as well as the density of the +material, and is provided as input to a simulation. The scattering neutron cross +section, :math:`\Sigma_s`, is similar to the total cross section but only +measures scattering interactions between the neutron and the target nucleus, and +depends on the change in angle and energy the neutron experiences as a result of +the interaction. Several additional reactions like (n,2n) and (n,3n) are +included in the scattering transfer cross section. The fission neutron cross +section, :math:`\Sigma_f`, is also similar to the total cross section but only +measures the fission interaction between a neutron and a target nucleus. The +energy spectrum for neutrons born from fission, :math:`\chi`, represents a known +distribution of outgoing neutron energies based on the material that fissioned, +which is taken as input data to a computation. The average number of neutrons +born per fission is :math:`\nu`. The eigenvalue of the equation, +:math:`k_{eff}`, represents the effective neutron multiplication factor. If the +right hand side of Equation :eq:`transport` is condensed into a single term, +represented by the total neutron source term :math:`Q(\mathbf{r}, \mathbf{\Omega},E)`, +the form given in Equation :eq:`transport_simple` is reached. + +.. math:: + :label: transport_simple + + \overbrace{\mathbf{\Omega} \cdot \mathbf{\nabla} \psi(\mathbf{r},\mathbf{\Omega},E)}^{\text{streaming term}} + \overbrace{\Sigma_t(\mathbf{r},E) \psi(\mathbf{r},\mathbf{\Omega},E)}^{\text{absorption term}} = \overbrace{Q(\mathbf{r}, \mathbf{\Omega},E)}^{\text{total neutron source term}} + +Fundamentally, MOC works by solving Equation :eq:`transport_simple` along a +single characteristic line, thus altering the full spatial and angular scope of +the transport equation into something that holds true only for a particular +linear path (or track) through the reactor. These tracks are linear for neutral +particles that are not subject to field effects. With our transport equation in +hand, we will now derive the solution along a track. To accomplish this, we +parameterize :math:`\mathbf{r}` with respect to some reference location +:math:`\mathbf{r}_0` such that :math:`\mathbf{r} = \mathbf{r}_0 + s\mathbf{\Omega}`. In this +manner, Equation :eq:`transport_simple` can be rewritten for a specific segment +length :math:`s` at a specific angle :math:`\mathbf{\Omega}` through a constant +cross section region of the reactor geometry as in Equation :eq:`char_long`. + +.. math:: + :label: char_long + + \mathbf{\Omega} \cdot \mathbf{\nabla} \psi(\mathbf{r}_0 + s\mathbf{\Omega},\mathbf{\Omega},E) + \Sigma_t(\mathbf{r}_0 + s\mathbf{\Omega},E) \psi(\mathbf{r}_0 + s\mathbf{\Omega},\mathbf{\Omega},E) = Q(\mathbf{r}_0 + s\mathbf{\Omega}, \mathbf{\Omega},E) + +As this equation holds along a one dimensional path, we can assume the +dependence of :math:`s` on :math:`\mathbf{r}_0` and :math:`\mathbf{\Omega}` such that +:math:`\mathbf{r}_0 + s\mathbf{\Omega}` simplifies to :math:`s`. When the differential +operator is also applied to the angular flux :math:`\psi`, we arrive at the +characteristic form of the Boltzmann Neutron Transport Equation given in +Equation :eq:`char`. + +.. math:: + :label: char + + \frac{d}{ds} \psi(s,\mathbf{\Omega},E) + \Sigma_t(s,E) \psi(s,\mathbf{\Omega},E) = Q(s, \mathbf{\Omega},E) + +An analytical solution to this characteristic equation can be achieved with the +use of an integrating factor: + +.. math:: + :label: int_factor + + e^{ \int_0^s ds' \Sigma_t (s', E)} + +to arrive at the final form of the characteristic equation shown in Equation +:eq:`full_char`. + +.. math:: + :label: full_char + + \psi(s,\mathbf{\Omega},E) = \psi(\mathbf{r}_0,\mathbf{\Omega},E) e^{-\int_0^s ds^\prime \Sigma_t(s^\prime,E)} + \int_0^s ds^{\prime\prime} Q(s^{\prime\prime},\mathbf{\Omega}, E) e^{-\int_{s^{\prime\prime}}^s ds^\prime \Sigma_t(s^\prime,E)} + +With this characteristic form of the transport equation, we now have an +analytical solution along a linear path through any constant cross section +region of a system. While the solution only holds along a linear track, no +discretizations have yet been made. + +Similar to many other solution approaches to the Boltzmann neutron transport +equation, the MOC approach also uses a "multigroup" approximation in order to +discretize the continuous energy spectrum of neutrons traveling through the +system into fixed set of energy groups :math:`G`, where each group :math:`g \in +G` has its own specific cross section parameters. This makes the difficult +non-linear continuous energy dependence much more manageable as group wise cross +section data can be precomputed and fed into a simulation as input data. The +computation of multigroup cross section data is not a trivial task and can +introduce errors in the simulation. However, this is an active field of research +common to all multigroup methods, and there are numerous generation methods +available that are capable of reducing the biases introduced by the multigroup +approximation. Commonly used methods include the subgroup self-shielding method +and use of fast (unconverged) Monte Carlo simulations to produce cross section +estimates. It is important to note that Monte Carlo methods are capable of +treating the energy variable of the neutron continuously, meaning that they do +not need to make this approximation and are therefore not subject to any +multigroup errors. + +Following the multigroup discretization, another assumption made is that a large +and complex problem can be broken up into small constant cross section regions, +and that these regions have group dependent, flat, isotropic sources (fission +and scattering), :math:`Q_g`. Anisotropic as well as higher order sources are +also possible with MOC-based methods but are not used yet in OpenMC for +simplicity. With these key assumptions, the multigroup MOC form of the neutron +transport equation can be written as in Equation :eq:`moc_final`. + +.. math:: + :label: moc_final + + \psi_g(s, \mathbf{\Omega}) = \psi_g(\mathbf{r_0}, \mathbf{\Omega}) e^{-\int_0^s ds^\prime \Sigma_{t_g}(s^\prime)} + \int_0^s ds^{\prime\prime} Q_g(s^{\prime\prime},\mathbf{\Omega}) e^{-\int_{s^{\prime\prime}}^s ds^\prime \Sigma_{t_g}(s^\prime)} + +The CSG definition of the system is used to create spatially defined source +regions (each region being denoted as :math:`i`). These neutron source regions +are often approximated as being constant +(flat) in source intensity but can also be defined using a higher order source +(linear, quadratic, etc.) that allows for fewer source regions to be required to +achieve a specified solution fidelity. In OpenMC, the approximation of a +spatially constant isotropic fission and scattering source :math:`Q_{i,g}` in +cell :math:`i` leads +to simple exponential attenuation along an individual characteristic of length +:math:`s` given by Equation :eq:`fsr_attenuation`. + +.. math:: + :label: fsr_attenuation + + \psi_g(s) = \psi_g(0) e^{-\Sigma_{t,i,g} s} + \frac{Q_{i,g}}{\Sigma_{t,i,g}} \left( 1 - e^{-\Sigma_{t,i,g} s} \right) + +For convenience, we can also write this equation in terms of the incoming and +outgoing angular flux (:math:`\psi_g^{in}` and :math:`\psi_g^{out}`), and +consider a specific tracklength for a particular ray :math:`r` crossing cell +:math:`i` as :math:`\ell_r`, as in: + +.. math:: + :label: fsr_attenuation_in_out + + \psi_g^{out} = \psi_g^{in} e^{-\Sigma_{t,i,g} \ell_r} + \frac{Q_{i,g}}{\Sigma_{t,i,g}} \left( 1 - e^{-\Sigma_{t,i,g} \ell_r} \right) . + +We can then define the average angular flux of a single ray passing through the +cell as: + +.. math:: + :label: average + + \overline{\psi}_{r,i,g} = \frac{1}{\ell_r} \int_0^{\ell_r} \psi_{g}(s)ds . + +We can then substitute in Equation :eq:`fsr_attenuation` and solve, resulting +in: + +.. math:: + :label: average_solved + + \overline{\psi}_{r,i,g} = \frac{Q_{i,g}}{\Sigma_{t,i,g}} - \frac{\psi_{r,g}^{out} - \psi_{r,g}^{in}}{\ell_r \Sigma_{t,i,g}} . + +By rearranging Equation :eq:`fsr_attenuation_in_out`, we can then define +:math:`\Delta \psi_{r,g}` as the change in angular flux for ray :math:`r` +passing through region :math:`i` as: + +.. math:: + :label: delta_psi + + \Delta \psi_{r,g} = \psi_{r,g}^{in} - \psi_{r,g}^{out} = \left(\psi_{r,g}^{in} - \frac{Q_{i,g}}{\Sigma_{t,i,g}} \right) \left( 1 - e^{-\Sigma_{t,i,g} \ell_r} \right) . + +Equation :eq:`delta_psi` is a useful expression as it is easily computed with +the known inputs for a ray crossing through the region. + +By substituting :eq:`delta_psi` into :eq:`average_solved`, we can arrive at a +final expression for the average angular flux for a ray crossing a region as: + +.. math:: + :label: average_psi_final + + \overline{\psi}_{r,i,g} = \frac{Q_{i,g}}{\Sigma_{t,i,g}} + \frac{\Delta \psi_{r,g}}{\ell_r \Sigma_{t,i,g}} + +~~~~~~~~~~~ +Random Rays +~~~~~~~~~~~ + +In the previous subsection, the governing characteristic equation along a 1D +line through the system was written, such that an analytical solution for the +ODE can be computed. If enough characteristic tracks (ODEs) are solved, then the +behavior of the governing PDE can be numerically approximated. In traditional +deterministic MOC, the selection of tracks is chosen deterministically, where +azimuthal and polar quadratures are defined along with even track spacing in +three dimensions. This is the point at which random ray diverges from +deterministic MOC numerically. In the random ray method, rays are randomly +sampled from a uniform distribution in space and angle and tracked along a +predefined distance through the geometry before terminating. **Importantly, +different rays are sampled each power iteration, leading to a fully stochastic +convergence process.** This results in a need to utilize both inactive and +active batches as in the Monte Carlo method. + +While Monte Carlo implicitly converges the scattering source fully within each +iteration, random ray (and MOC) solvers are not typically written to fully +converge the scattering source within a single iteration. Rather, both the +fission and scattering sources are updated each power iteration, thus requiring +enough outer iterations to reach a stationary distribution in both the fission +source and scattering source. So, even in a low dominance ratio problem like a +2D pincell, several hundred inactive batches may still be required with random +ray to allow the scattering source to fully develop, as neutrons undergoing +hundreds of scatters may constitute a non-trivial contribution to the fission +source. We note that use of a two-level second iteration scheme is sometimes +used by some MOC or random ray solvers so as to fully converge the scattering +source with many inner iterations before updating the fission source in the +outer iteration. It is typically more efficient to use the single level +iteration scheme, as there is little reason to spend so much work converging the +scattering source if the fission source is not yet converged. + +Overall, the difference in how random ray and Monte Carlo converge the +scattering source means that in practice, random ray typically requires more +inactive iterations than are required in Monte Carlo. While a Monte Carlo +simulation may need 100 inactive iterations to reach a stationary source +distribution for many problems, a random ray solve will likely require 1,000 +iterations or more. Source convergence metrics (e.g., Shannon entropy) are thus +recommended when performing random ray simulations to ascertain when the source +has fully developed. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Converting Angular Flux to Scalar Flux +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Thus far in our derivation, we have been able to write analytical equations that +solve for the change in angular flux of a ray crossing a flat source region +(Equation :eq:`delta_psi`) as well as the ray's average angular flux through +that region (Equation :eq:`average_psi_final`). To determine the source for the +next power iteration, we need to assemble our estimates of angular fluxes from +all the sampled rays into scalar fluxes within each FSR. + +We can define the scalar flux in region :math:`i` as: + +.. math:: + :label: integral + + \phi_i = \frac{\int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r}}{\int_{V_i} d\mathbf{r}} . + +The integral in the numerator: + +.. math:: + :label: numerator + + \int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r} . + +is not known analytically, but with random ray, we are going the numerically +approximate it by discretizing over a finite number of tracks (with a finite +number of locations and angles) crossing the domain. We can then use the +characteristic method to determine the total angular flux along that line. + +Conceptually, this can be thought of as taking a volume-weighted sum of angular +fluxes for all :math:`N_i` rays that happen to pass through cell :math:`i` that +iteration. When written in discretized form (with the discretization happening +in terms of individual ray segments :math:`r` that pass through region +:math:`i`), we arrive at: + +.. math:: + :label: discretized + + \phi_{i,g} = \frac{\int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r}}{\int_{V_i} d\mathbf{r}} = \overline{\overline{\psi}}_{i,g} \approx \frac{\sum\limits_{r=1}^{N_i} \ell_r w_r \overline{\psi}_{r,i,g}}{\sum\limits_{r=1}^{N_i} \ell_r w_r} . + +Here we introduce the term :math:`w_r`, which represents the "weight" of the ray +(its 2D area), such that the volume that a ray is responsible for can be +determined by multiplying its length :math:`\ell` by its weight :math:`w`. As +the scalar flux vector is a shape function only, we are actually free to +multiply all ray weights :math:`w` by any constant such that the overall shape +is still maintained, even if the magnitude of the shape function changes. Thus, +we can simply set :math:`w_r` to be unity for all rays, such that: + +.. math:: + :label: weights + + \text{Volume of cell } i = V_i \approx \sum\limits_{r=1}^{N_i} \ell_r w_r = \sum\limits_{r=1}^{N_i} \ell_r . + +We can then rewrite our discretized equation as: + +.. math:: + :label: discretized_2 + + \phi_{i,g} \approx \frac{\sum\limits_{r=1}^{N_i} \ell_r w_r \overline{\psi}_{r,i,g}}{\sum\limits_{r=1}^{N_i} \ell_r w_r} = \frac{\sum\limits_{r=1}^{N_i} \ell_r \overline{\psi}_{r,i,g}}{\sum\limits_{r=1}^{N_i} \ell_r} . + +Thus, the scalar flux can be inferred if we know the volume weighted sum of the +average angular fluxes that pass through the cell. Substituting +:eq:`average_psi_final` into :eq:`discretized_2`, we arrive at: + +.. math:: + :label: scalar_full + + \phi_{i,g} = \frac{\int_{V_i} \int_{4\pi} \psi(r, \Omega) d\Omega d\mathbf{r}}{\int_{V_i} d\mathbf{r}} = \overline{\overline{\psi}}_{i,g} = \frac{\sum\limits_{r=1}^{N_i} \ell_r \overline{\psi}_{r,i,g}}{\sum\limits_{r=1}^{N_i} \ell_r} = \frac{\sum\limits_{r=1}^{N_i} \ell_r \frac{Q_{i,g}}{\Sigma_{t,i,g}} + \frac{\Delta \psi_{r,g}}{\ell_r \Sigma_{t,i,g}}}{\sum\limits_{r=1}^{N_i} \ell_r}, + +which when partially simplified becomes: + +.. math:: + :label: scalar_four_vols + + \phi = \frac{Q_{i,g} \sum\limits_{r=1}^{N_i} \ell_r}{\Sigma_{t,i,g} \sum\limits_{r=1}^{N_i} \ell_r} + \frac{\sum\limits_{r=1}^{N_i} \ell_r \frac{\Delta \psi_i}{\ell_r}}{\Sigma_{t,i,g} \sum\limits_{r=1}^{N_i} \ell_r} . + +Note that there are now four (seemingly identical) volume terms in this equation. + +~~~~~~~~~~~~~~ +Volume Dilemma +~~~~~~~~~~~~~~ + +At first glance, Equation :eq:`scalar_four_vols` appears ripe for cancellation +of terms. Mathematically, such cancellation allows us to arrive at the following +"naive" estimator for the scalar flux: + +.. math:: + :label: phi_naive + + \phi_{i,g}^{naive} = \frac{Q_{i,g} }{\Sigma_{t,i,g}} + \frac{\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}}{\Sigma_{t,i,g} \sum\limits_{r=1}^{N_i} \ell_r} . + +This derivation appears mathematically sound at first glance but unfortunately +raises a serious issue as discussed in more depth by `Tramm et al. +`_ and `Cosgrove and Tramm `_. Namely, the second +term: + +.. math:: + :label: ratio_estimator + + \frac{\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}}{\Sigma_{t,i,g} \sum\limits_{r=1}^{N_i} \ell_r} + +features stochastic variables (the sums over random ray lengths and angular +fluxes) in both the numerator and denominator, making it a stochastic ratio +estimator, which is inherently biased. In practice, usage of the naive estimator +does result in a biased, but "consistent" estimator (i.e., it is biased, but +the bias tends towards zero as the sample size increases). Experimentally, the +right answer can be obtained with this estimator, though a very fine ray density +is required to eliminate the bias. + +How might we solve the biased ratio estimator problem? While there is no obvious +way to alter the numerator term (which arises from the characteristic +integration approach itself), there is potentially more flexibility in how we +treat the stochastic term in the denominator, :math:`\sum\limits_{r=1}^{N_i} +\ell_r` . From Equation :eq:`weights` we know that this term can be directly +inferred from the volume of the problem, which does not actually change between +iterations. Thus, an alternative treatment for this "volume" term in the +denominator is to replace the actual stochastically sampled total track length +with the expected value of the total track length. For instance, if the true +volume of the FSR is known (as is the total volume of the full simulation domain +and the total tracklength used for integration that iteration), then we know the +true expected value of the tracklength in that FSR. That is, if a FSR accounts +for 2% of the overall volume of a simulation domain, then we know that the +expected value of tracklength in that FSR will be 2% of the total tracklength +for all rays that iteration. This is a key insight, as it allows us to the +replace the actual tracklength that was accumulated inside that FSR each +iteration with the expected value. + +If we know the analytical volumes, then those can be used to directly compute +the expected value of the tracklength in each cell. However, as the analytical +volumes are not typically known in OpenMC due to the usage of user-defined +constructive solid geometry, we need to source this quantity from elsewhere. An +obvious choice is to simply accumulate the total tracklength through each FSR +across all iterations (batches) and to use that sum to compute the expected +average length per iteration, as: + +.. math:: + :label: sim_estimator + + \sum\limits^{}_{i} \ell_i \approx \frac{\sum\limits^{B}_{b}\sum\limits^{N_i}_{r} \ell_{b,r} }{B} + +where :math:`b` is a single batch in :math:`B` total batches simulated so far. + +In this manner, the expected value of the tracklength will become more refined +as iterations continue, until after many iterations the variance of the +denominator term becomes trivial compared to the numerator term, essentially +eliminating the presence of the stochastic ratio estimator. A "simulation +averaged" estimator is therefore: + +.. math:: + :label: phi_sim + + \phi_{i,g}^{simulation} = \frac{Q_{i,g} }{\Sigma_{t,i,g}} + \frac{\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}}{\Sigma_{t,i,g} \frac{\sum\limits^{B}_{b}\sum\limits^{N_i}_{r} \ell_{b,r} }{B}} + +In practical terms, the "simulation averaged" estimator is virtually +indistinguishable numerically from use of the true analytical volume to estimate +this term. Note also that the term "simulation averaged" refers only to the +volume/length treatment, the scalar flux estimate itself is computed fully again +each iteration. + +There are some drawbacks to this method. Recall, this denominator volume term +originally stemmed from taking a volume weighted integral of the angular flux, +in which case the denominator served as a normalization term for the numerator +integral in Equation :eq:`integral`. Essentially, we have now used a different +term for the volume in the numerator as compared to the normalizing volume in +the denominator. The inevitable mismatch (due to noise) between these two +quantities results in a significant increase in variance. Notably, the same +problem occurs if using a tracklength estimate based on the analytical volume, +as again the numerator integral and the normalizing denominator integral no +longer match on a per-iteration basis. + +In practice, the simulation averaged method does completely remove the bias, +though at the cost of a notable increase in variance. Empirical testing reveals +that on most problems, the simulation averaged estimator does win out overall in +numerical performance, as a much coarser quadrature can be used resulting in +faster runtimes overall. Thus, OpenMC uses the simulation averaged estimator in +its random ray mode. + +~~~~~~~~~~~~~~~ +Power Iteration +~~~~~~~~~~~~~~~ + +Given a starting source term, we now have a way of computing an estimate of the +scalar flux in each cell by way of transporting rays randomly through the +domain, recording the change in angular flux for the rays into each cell as they +make their traversals, and summing these contributions up as in Equation +:eq:`phi_sim`. How then do we turn this into an iterative process such that we +improve the estimate of the source and scalar flux over many iterations, given +that our initial starting source will just be a guess? + +The source :math:`Q^{n}` for iteration :math:`n` can be inferred +from the scalar flux from the previous iteration :math:`n-1` as: + +.. math:: + :label: source_update + + Q^{n}(i, g) = \frac{\chi}{k^{n-1}_{eff}} \nu \Sigma_f(i, g) \phi^{n-1}(g) + \sum\limits^{G}_{g'} \Sigma_{s}(i,g,g') \phi^{n-1}(g') + +where :math:`Q^{n}(i, g)` is the total source (fission + scattering) in region +:math:`i` and energy group :math:`g`. Notably, the in-scattering source in group +:math:`g` must be computed by summing over the contributions from all groups +:math:`g' \in G`. + +In a similar manner, the eigenvalue for iteration :math:`n` can be computed as: + +.. math:: + :label: eigenvalue_update + + k^{n}_{eff} = k^{n-1}_{eff} \frac{F^n}{F^{n-1}}, + +where the total spatial- and energy-integrated fission rate :math:`F^n` in +iteration :math:`n` can be computed as: + +.. math:: + :label: fission_source + + F^n = \sum\limits^{M}_{i} \left( V_i \sum\limits^{G}_{g} \nu \Sigma_f(i, g) \phi^{n}(g) \right) + +where :math:`M` is the total number of FSRs in the simulation. Similarly, the +total spatial- and energy-integrated fission rate :math:`F^{n-1}` in iteration +:math:`n-1` can be computed as: + +.. math:: + :label: fission_source_prev + + F^{n-1} = \sum\limits^{M}_{i} \left( V_i \sum\limits^{G}_{g} \nu \Sigma_f(i, g) \phi^{n-1}(g) \right) + +Notably, the volume term :math:`V_i` appears in the eigenvalue update equation. +The same logic applies to the treatment of this term as was discussed earlier. +In OpenMC, we use the "simulation averaged" volume derived from summing over all +ray tracklength contributions to a FSR over all iterations and dividing by the +total integration tracklength to date. Thus, Equation :eq:`fission_source` +becomes: + +.. math:: + :label: fission_source_volumed + + F^n = \sum\limits^{M}_{i} \left( \frac{\sum\limits^{B}_{b}\sum\limits^{N_i}_{r} \ell_{b,r} }{B} \sum\limits^{G}_{g} \nu \Sigma_f(i, g) \phi^{n}(g) \right) + +and a similar substitution can be made to update Equation +:eq:`fission_source_prev` . In OpenMC, the most up-to-date version of the volume +estimate is used, such that the total fission source from the previous iteration +(:math:`n-1`) is also recomputed each iteration. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Ray Starting Conditions and Inactive Length +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Another key area of divergence between deterministic MOC and random ray is the +starting conditions for rays. In deterministic MOC, the angular flux spectrum +for rays are stored at any reflective or periodic boundaries so as to provide a +starting condition for the next iteration. As there are many tracks, storage of +angular fluxes can become costly in terms of memory consumption unless there are +only vacuum boundaries present. + +In random ray, as the starting locations of rays are sampled anew each +iteration, the initial angular flux spectrum for the ray is unknown. While a +guess can be made by taking the isotropic source from the FSR the ray was +sampled in, direct usage of this quantity would result in significant bias and +error being imparted on the simulation. + +Thus, an `on-the-fly approximation method `_ was developed (known +as the "dead zone"), where the first several mean free paths of a ray are +considered to be "inactive" or "read only". In this sense, the angular flux is +solved for using the MOC equation, but the ray does not "tally" any scalar flux +back to the FSRs that it travels through. After several mean free paths have +been traversed, the ray's angular flux spectrum typically becomes dominated by +the accumulated source terms from the cells it has traveled through, while the +(incorrect) starting conditions have been attenuated away. In the animation in +the :ref:`introductory section on this page `, the +yellow portion of the ray lengths is the dead zone. As can be seen in this +animation, the tallied :math:`\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}` term +that is plotted is not affected by the ray when the ray is within its inactive +length. Only when the ray enters its active mode does the ray contribute to the +:math:`\sum\limits_{r=1}^{N_i} \Delta \psi_{r,g}` sum for the iteration. + +~~~~~~~~~~~~~~~~~~~~~ +Ray Ending Conditions +~~~~~~~~~~~~~~~~~~~~~ + +To ensure that a uniform density of rays is integrated in space and angle +throughout the simulation domain, after exiting the initial inactive "dead zone" +portion of the ray, the rays are run for a user-specified distance. Typically, a +choice of at least several times the length of the inactive "dead zone" is made +so as to amortize the cost of the dead zone. For example, if a dead zone of 30 +cm is selected, then an active length of 300 cm might be selected so that the +cost of the dead zone is at most 10% of the overall runtime. + +-------------------- +Simplified Algorithm +-------------------- + +A simplified set of functions that execute a single random ray power iteration +are given below. Not all global variables are defined in this illustrative +example, but the high level components of the algorithm are shown. A number of +significant simplifications are made for clarity---for example, no inactive +"dead zone" length is shown, geometry operations are abstracted, no parallelism +(or thread safety) is expressed, a naive exponential treatment is used, and rays +are not halted at their exact termination distances, among other subtleties. +Nonetheless, the below algorithms may be useful for gaining intuition on the +basic components of the random ray process. Rather than expressing the algorithm +in abstract pseudocode, C++ is used to make the control flow easier to +understand. + +The first block below shows the logic for a single power iteration (batch): + +.. code-block:: C++ + + double power_iteration(double k_eff) { + + // Update source term (scattering + fission) + update_neutron_source(k_eff); + + // Reset scalar fluxes to zero + fill(global::scalar_flux_new, 0.0f); + + // Transport sweep over all random rays for the iteration + for (int i = 0; i < nrays; i++) { + RandomRay ray; + initialize_ray(ray); + transport_single_ray(ray); + } + + // Normalize scalar flux and update volumes + normalize_scalar_flux_and_volumes(); + + // Add source to scalar flux, compute number of FSR hits + add_source_to_scalar_flux(); + + // Compute k-eff using updated scalar flux + k_eff = compute_k_eff(k_eff); + + // Set phi_old = phi_new + global::scalar_flux_old.swap(global::scalar_flux_new); + + return k_eff; + } + +The second function shows the logic for transporting a single ray within the +transport loop: + +.. code-block:: C++ + + void transport_single_ray(RandomRay& ray) { + + // Reset distance to zero + double distance = 0.0; + + // Continue transport of ray until active length is reached + while (distance < user_setting::active_length) { + // Ray trace to find distance to next surface (i.e., segment length) + double s = distance_to_nearest_boundary(ray); + + // Attenuate flux (and accumulate source/attenuate) on segment + attenuate_flux(ray, s); + + // Advance particle to next surface + ray.location = ray.location + s * ray.direction; + + // Move ray across the surface + cross_surface(ray); + + // Add segment length "s" to total distance traveled + distance += s; + } + } + +The final function below shows the logic for solving for the characteristic MOC +equation (and accumulating the scalar flux contribution of the ray into the +scalar flux value for the FSR). + +.. code-block:: C++ + + void attenuate_flux(RandomRay& ray, double s) { + + // Determine which flat source region (FSR) the ray is currently in + int fsr = get_fsr_id(ray.location); + + // Determine material type + int material = get_material_type(fsr); + + // MOC incoming flux attenuation + source contribution/attenuation equation + for (int e = 0; e < global::n_energy_groups; e++) { + float sigma_t = global::macro_xs[material].total; + float tau = sigma_t * s; + float delta_psi = (ray.angular_flux[e] - global::source[fsr][e] / sigma_t) * (1 - exp(-tau)); + ray.angular_flux_[e] -= delta_psi; + global::scalar_flux_new[fsr][e] += delta_psi; + } + + // Record total tracklength in this FSR (to compute volume) + global::volume[fsr] += s; + } + +------------------------ +How are Tallies Handled? +------------------------ + +Most tallies, filters, and scores that you would expect to work with a +multigroup solver like random ray should work. For example, you can define 3D +mesh tallies with energy filters and flux, fission, and nu-fission scores, etc. +There are some restrictions though. For starters, it is assumed that all filter +mesh boundaries will conform to physical surface boundaries (or lattice +boundaries) in the simulation geometry. It is acceptable for multiple cells +(FSRs) to be contained within a filter mesh cell (e.g., pincell-level or +assembly-level tallies should work), but it is currently left as undefined +behavior if a single simulation cell is able to score to multiple filter mesh +cells. In the future, the capability to fully support mesh tallies may be added +to OpenMC, but for now this restriction needs to be respected. + +--------------------------- +Fundamental Sources of Bias +--------------------------- + +Compared to continuous energy Monte Carlo simulations, the known sources of bias +in random ray particle transport are: + + - **Multigroup Energy Discretization:** The multigroup treatment of flux and + cross sections incurs a significant bias, as a reaction rate (:math:`R_g = + V \phi_g \Sigma_g`) for an energy group :math:`g` can only be conserved + for a given choice of multigroup cross section :math:`\Sigma_g` if the + flux (:math:`\phi_g`) is known a priori. If the flux was already known, + then there would be no point to the simulation, resulting in a fundamental + need for approximating this quantity. There are numerous methods for + generating relatively accurate multigroup cross section libraries that can + each be applied to a narrow design area reliably, although there are + always limitations and/or complexities that arise with a multigroup energy + treatment. This is by far the most significant source of simulation bias + between Monte Carlo and random ray for most problems. While the other + areas typically have solutions that are highly effective at mitigating + bias, error stemming from multigroup energy discretization is much harder + to remedy. + - **Flat Source Approximation:**. In OpenMC, a "flat" (0th order) source + approximation is made, wherein the scattering and fission sources within a + cell are assumed to be spatially uniform. As the source in reality is a + continuous function, this leads to bias, although the bias can be reduced + to acceptable levels if the flat source regions are sufficiently small. + The bias can also be mitigated by assuming a higher-order source (e.g., + linear or quadratic), although OpenMC does not yet have this capability. + In practical terms, this source of bias can become very large if cells are + large (with dimensions beyond that of a typical particle mean free path), + but the subdivision of cells can often reduce this bias to trivial levels. + - **Anisotropic Source Approximation:** In OpenMC, the source is not only + assumed to be flat but also isotropic, leading to bias. It is possible for + MOC (and likely random ray) to treat anisotropy explicitly, but this is + not currently supported in OpenMC. This source of bias is not significant + for some problems, but becomes more problematic for others. Even in the + absence of explicit treatment of anistropy, use of transport-corrected + multigroup cross sections can often mitigate this bias, particularly for + light water reactor simulation problems. + - **Angular Flux Initial Conditions:** Each time a ray is sampled, its + starting angular flux is unknown, so a guess must be made (typically the + source term for the cell it starts in). Usage of an adequate inactive ray + length (dead zone) mitigates this error. As the starting guess is + attenuated at a rate of :math:`\exp(-\Sigma_t \ell)`, this bias can driven + below machine precision in a low cost manner on many problems. + +.. _Tramm-2017a: https://doi.org/10.1016/j.jcp.2017.04.038 +.. _Tramm-2017b: https://doi.org/10.1016/j.anucene.2017.10.015 +.. _Tramm-2018: https://dspace.mit.edu/handle/1721.1/119038 +.. _Tramm-2020: https://doi.org/10.1051/EPJCONF/202124703021 +.. _Cosgrove-2023: https://doi.org/10.1080/00295639.2023.2270618 + +.. only:: html + + .. rubric:: References + +.. [Askew-1972] Askew, “A Characteristics Formulation of the Neutron Transport + Equation in Complicated Geometries.” Technical Report AAEW-M 1108, UK Atomic + Energy Establishment (1972). diff --git a/docs/source/methods/tallies.rst b/docs/source/methods/tallies.rst index dc3a63decfc..d833c157d5d 100644 --- a/docs/source/methods/tallies.rst +++ b/docs/source/methods/tallies.rst @@ -179,12 +179,12 @@ n(\mathbf{r}, \mathbf{\hat{\Omega}}, E, t)` and :math:`d\ell = v \, dt` where Equation :eq:`track-length-integral` indicates that we can use the length of a particle's trajectory as an estimate for the flux, i.e. the track-length -estimator of the flux would be +estimator of the volume-integrated flux would be .. math:: :label: track-length-flux - \phi = \frac{1}{W} \sum_{i \in T} w_i \ell_i + V \phi = \frac{1}{W} \sum_{i \in T} w_i \ell_i where :math:`T` is the set of all the particle's trajectories within the desired volume and :math:`\ell_i` is the length of the :math:`i`-th trajectory. In the @@ -510,6 +510,6 @@ improve the estimate of the percentile. .. _Cauchy distribution: https://en.wikipedia.org/wiki/Cauchy_distribution -.. _unpublished rational approximation: https://web.archive.org/web/20150926021742/http://home.online.no/~pjacklam/notes/invnorm/ +.. _unpublished rational approximation: https://stackedboxes.org/2017/05/01/acklams-normal-quantile-function/ .. _MC21: http://www.osti.gov/bridge/servlets/purl/903083-HT5p1o/903083.pdf diff --git a/docs/source/publications.rst b/docs/source/publications.rst index b4f4e6aeb05..88d0a97b977 100644 --- a/docs/source/publications.rst +++ b/docs/source/publications.rst @@ -497,7 +497,7 @@ Parallelism Int. Conf. M&C+SNA+MC*, Nashville, Tennessee, Apr. 19--23 (2015). - Hajime Fujita, Nan Dun, Aiman Fang, Zachary A. Rubinstein, Ziming Zheng, Kamil - Iskra, Jeff Hammonds, Anshu Dubey, Pavan Balaji, and Andrew A. Chien, "Using + Iskra, Jeff Hammond, Anshu Dubey, Pavan Balaji, and Andrew A. Chien, "Using Global View Resilience (GVR) to add Resilience to Exascale Applications," *Proc. Supercomputing*, New Orleans, Louisiana, Nov. 16--21, 2014. diff --git a/docs/source/pythonapi/base.rst b/docs/source/pythonapi/base.rst index 342b4c1a64f..5ae9f20edf4 100644 --- a/docs/source/pythonapi/base.rst +++ b/docs/source/pythonapi/base.rst @@ -21,19 +21,23 @@ Simulation Settings :nosignatures: :template: myclass.rst - openmc.Source + openmc.SourceBase + openmc.IndependentSource + openmc.FileSource + openmc.CompiledSource + openmc.MeshSource openmc.SourceParticle openmc.VolumeCalculation openmc.Settings -The following function can be used for generating a source file: - .. autosummary:: :toctree: generated :nosignatures: :template: myfunction.rst + openmc.read_source_file openmc.write_source_file + openmc.wwinp_to_wws Material Specification ---------------------- @@ -43,9 +47,6 @@ Material Specification :nosignatures: :template: myclass.rst - openmc.Nuclide - openmc.Element - openmc.Macroscopic openmc.Material openmc.Materials @@ -80,12 +81,17 @@ Building geometry openmc.YCone openmc.ZCone openmc.Quadric + openmc.XTorus + openmc.YTorus + openmc.ZTorus openmc.Halfspace openmc.Intersection openmc.Union openmc.Complement + openmc.BoundingBox openmc.Cell openmc.Universe + openmc.DAGMCUniverse openmc.RectLattice openmc.HexLattice openmc.Geometry @@ -114,13 +120,15 @@ Constructing Tallies openmc.Filter openmc.UniverseFilter openmc.MaterialFilter + openmc.MaterialFromFilter openmc.CellFilter openmc.CellFromFilter - openmc.CellbornFilter + openmc.CellBornFilter openmc.CellInstanceFilter openmc.CollisionFilter openmc.SurfaceFilter openmc.MeshFilter + openmc.MeshBornFilter openmc.MeshSurfaceFilter openmc.EnergyFilter openmc.EnergyoutFilter @@ -133,11 +141,14 @@ Constructing Tallies openmc.LegendreFilter openmc.SpatialLegendreFilter openmc.SphericalHarmonicsFilter + openmc.TimeFilter openmc.ZernikeFilter openmc.ZernikeRadialFilter openmc.ParticleFilter openmc.RegularMesh openmc.RectilinearMesh + openmc.CylindricalMesh + openmc.SphericalMesh openmc.UnstructuredMesh openmc.Trigger openmc.TallyDerivative @@ -153,6 +164,7 @@ Geometry Plotting :template: myclass.rst openmc.Plot + openmc.ProjectionPlot openmc.Plots Running OpenMC @@ -178,8 +190,18 @@ Post-processing :template: myclass.rst openmc.Particle + openmc.ParticleTrack openmc.StatePoint openmc.Summary + openmc.Track + openmc.Tracks + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myfunction.rst + + openmc.voxel_to_vtk The following classes and functions are used for functional expansion reconstruction. @@ -212,6 +234,19 @@ Various classes may be created when performing tally slicing and/or arithmetic: openmc.arithmetic.AggregateNuclide openmc.arithmetic.AggregateFilter +Variance Reduction +------------------ + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myclass + + openmc.WeightWindows + openmc.WeightWindowGenerator + openmc.hdf5_to_wws + + Coarse Mesh Finite Difference Acceleration ------------------------------------------ diff --git a/docs/source/pythonapi/capi.rst b/docs/source/pythonapi/capi.rst index 44094ffd410..995ad97fa74 100644 --- a/docs/source/pythonapi/capi.rst +++ b/docs/source/pythonapi/capi.rst @@ -13,23 +13,37 @@ Functions :template: myfunction.rst calculate_volumes + current_batch + export_properties + export_weight_windows finalize find_cell find_material + global_bounding_box + global_tallies hard_reset + id_map + import_properties + import_weight_windows init + is_statepoint_batch iter_batches keff load_nuclide + master next_batch num_realizations plot_geometry + property_map reset + reset_timers run run_in_memory - simulation_init + sample_external_source simulation_finalize + simulation_init source_bank + statepoint_load statepoint_write Classes @@ -40,12 +54,86 @@ Classes :nosignatures: :template: myclass.rst + AzimuthalFilter Cell + CellFilter + CellInstanceFilter + CellbornFilter + CellfromFilter + CollisionFilter + CylindricalMesh + DelayedGroupFilter + DistribcellFilter EnergyFilter - MaterialFilter + EnergyFunctionFilter + EnergyoutFilter + Filter + LegendreFilter Material + MaterialFilter + MaterialFromFilter + Mesh MeshFilter + MeshBornFilter MeshSurfaceFilter + MuFilter Nuclide + ParticleFilter + PolarFilter + RectilinearMesh RegularMesh + SpatialLegendreFilter + SphericalHarmonicsFilter + SphericalMesh + SurfaceFilter Tally + UniverseFilter + UnstructuredMesh + WeightWindows + ZernikeFilter + ZernikeRadialFilter + +Data +---- + +.. data:: cells + + Mapping of cell ID to :class:`openmc.lib.Cell` instances. + + :type: dict + +.. data:: filters + + Mapping of filter ID to :class:`openmc.lib.Filter` instances. + + :type: dict + +.. data:: materials + + Mapping of material ID to :class:`openmc.lib.Material` instances. + + :type: dict + +.. data:: meshes + + Mapping of mesh ID to :class:`openmc.lib.Mesh` instances. + + :type: dict + +.. data:: nuclides + + Mapping of nuclide name to :class:`openmc.lib.Nuclide` instances. + + :type: dict + +.. data:: tallies + + Mapping of tally ID to :class:`openmc.lib.Tally` instances. + + :type: dict + +.. data:: weight_windows + + Mapping of weight window ID to :class:`openmc.lib.WeightWindows` instances. + + :type: dict diff --git a/docs/source/pythonapi/data.rst b/docs/source/pythonapi/data.rst index 95fdfeca9f7..1eaf90c9724 100644 --- a/docs/source/pythonapi/data.rst +++ b/docs/source/pythonapi/data.rst @@ -61,9 +61,15 @@ Core Functions atomic_mass atomic_weight + combine_distributions + decay_constant + decay_energy + decay_photon_energy dose_coefficients - gnd_name + gnds_name + half_life isotopes + kalbach_slope linearize thin water_density @@ -114,6 +120,7 @@ Angle-Energy Distributions IncoherentElasticAE IncoherentElasticAEDiscrete IncoherentInelasticAEDiscrete + MixedElasticAE Resonance Data -------------- diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index d4a0f128fe8..8731a9a1383 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -15,16 +15,18 @@ are: 1) A transport operator 2) A time-integration scheme -The former is responsible for executing a transport code, like OpenMC, -and retaining important information required for depletion. The most common examples -are reaction rates and power normalization data. The latter is responsible for -projecting reaction rates and compositions forward in calendar time across -some step size :math:`\Delta t`, and obtaining new compositions given a power -or power density. The :class:`Operator` is provided to handle communicating with -OpenMC. Several classes are provided that implement different time-integration -algorithms for depletion calculations, which are described in detail in Colin -Josey's thesis, `Development and analysis of high order neutron -transport-depletion coupling algorithms `_. +The former is responsible for calculating and retaining important information +required for depletion. The most common examples are reaction rates and power +normalization data. The latter is responsible for projecting reaction rates and +compositions forward in calendar time across some step size :math:`\Delta t`, +and obtaining new compositions given a power or power density. The +:class:`CoupledOperator` class is provided to obtain reaction rates via tallies +through OpenMC's transport solver, and the :class:`IndependentOperator` class is +provided to obtain reaction rates from cross-section data. Several classes are +provided that implement different time-integration algorithms for depletion +calculations, which are described in detail in Colin Josey's thesis, +`Development and analysis of high order neutron transport-depletion coupling +algorithms `_. .. autosummary:: :toctree: generated @@ -40,18 +42,30 @@ transport-depletion coupling algorithms `_. SICELIIntegrator SILEQIIntegrator -Each of these classes expects a "transport operator" to be passed. An operator -specific to OpenMC is available using the following class: +Each of these classes expects a "transport operator" to be passed. OpenMC +provides the following transport operator classes: .. autosummary:: :toctree: generated :nosignatures: :template: mycallable.rst - Operator + CoupledOperator + IndependentOperator -The :class:`Operator` must also have some knowledge of how nuclides transmute -and decay. This is handled by the :class:`Chain`. +The :class:`CoupledOperator` and :class:`IndependentOperator` classes must also +have some knowledge of how nuclides transmute and decay. This is handled by the +:class:`Chain` class. + +The :class:`IndependentOperator` class requires a set of fluxes and microscopic +cross sections. The following function can be used to generate this information: + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myfunction.rst + + get_microxs_and_flux Minimal Example --------------- @@ -64,11 +78,12 @@ A minimal example for performing depletion would be: >>> import openmc.deplete >>> geometry = openmc.Geometry.from_xml() >>> settings = openmc.Settings.from_xml() + >>> model = openmc.model.Model(geometry, settings) # Representation of a depletion chain >>> chain_file = "chain_casl.xml" - >>> operator = openmc.deplete.Operator( - ... geometry, settings, chain_file) + >>> operator = openmc.deplete.CoupledOperator( + ... model, chain_file) # Set up 5 time steps of one day each >>> dt = [24 * 60 * 60] * 5 @@ -131,10 +146,11 @@ data, such as number densities and reaction rates for each material. :template: myclass.rst AtomNumber + MicroXS OperatorResult ReactionRates Results - ResultsList + StepResult The following class and functions are used to solve the depletion equations, with :func:`cram.CRAM48` being the default. @@ -166,7 +182,13 @@ with :func:`cram.CRAM48` being the default. :type: bool -The following classes are used to help the :class:`openmc.deplete.Operator` +.. data:: pool.NUM_PROCESSES + + Number of worker processes used for depletion calculations, which rely on the + :class:`multiprocessing.pool.Pool` class. If set to ``None`` (default), the + number returned by :func:`os.cpu_count` is used. + +The following classes are used to help the :class:`openmc.deplete.CoupledOperator` compute quantities like effective fission yields, reaction rates, and total system energy. @@ -183,14 +205,55 @@ total system energy. helpers.FissionYieldCutoffHelper helpers.FluxCollapseHelper +The :class:`openmc.deplete.IndependentOperator` uses inner classes subclassed +from those listed above to perform similar calculations. + +The following classes are used to define transfer rates to model continuous +removal or feed of nuclides during depletion. + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myclass.rst + + transfer_rates.TransferRates + +Intermediate Classes +-------------------- + +Specific implementations of abstract base classes may utilize some of +the same methods and data structures. These methods and data are stored +in intermediate classes. + +Methods common to tally-based implementation of :class:`FissionYieldHelper` +are stored in :class:`helpers.TalliedFissionYieldHelper` + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myclass.rst + + helpers.TalliedFissionYieldHelper + +Methods common to OpenMC-specific implementations of :class:`TransportOperator` +are stored in :class:`openmc_operator.OpenMCOperator` + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: mycallable.rst + + openmc_operator.OpenMCOperator + + Abstract Base Classes --------------------- A good starting point for extending capabilities in :mod:`openmc.deplete` is to examine the following abstract base classes. Custom classes can inherit from :class:`abc.TransportOperator` to implement alternative -schemes for collecting reaction rates and other data from a transport code -prior to depleting materials +schemes for collecting reaction rates and other data prior to depleting +materials .. autosummary:: :toctree: generated @@ -200,7 +263,9 @@ prior to depleting materials abc.TransportOperator The following classes are abstract classes used to pass information from -OpenMC simulations back on to the :class:`abc.TransportOperator` +transport simulations (in the case of transport-coupled depletion) or to +simply calculate these quantities directly (in the case of +transport-independent depletion) back on to the :class:`abc.TransportOperator` .. autosummary:: :toctree: generated @@ -210,7 +275,6 @@ OpenMC simulations back on to the :class:`abc.TransportOperator` abc.NormalizationHelper abc.FissionYieldHelper abc.ReactionRateHelper - abc.TalliedFissionYieldHelper Custom integrators or depletion solvers can be developed by subclassing from the following abstract base classes: diff --git a/docs/source/pythonapi/index.rst b/docs/source/pythonapi/index.rst index 0656e6c8090..6f832a935ec 100644 --- a/docs/source/pythonapi/index.rst +++ b/docs/source/pythonapi/index.rst @@ -6,11 +6,11 @@ Python API OpenMC includes a rich Python API that enables programmatic pre- and post-processing. The easiest way to begin using the API is to take a look at the -:ref:`examples`. This assumes that you are already familiar with Python and -common third-party packages such as `NumPy `_. If you have -never used Python before, the prospect of learning a new code *and* a -programming language might sound daunting. However, you should keep in mind that -there are many substantial benefits to using the Python API, including: +examples_. This assumes that you are already familiar with Python and common +third-party packages such as `NumPy `_. If you have never +used Python before, the prospect of learning a new code *and* a programming +language might sound daunting. However, you should keep in mind that there are +many substantial benefits to using the Python API, including: - The ability to define dimensions using variables. - Availability of standard-library modules for working with files. @@ -50,3 +50,5 @@ or class. data capi openmoc + +.. _examples: https://github.com/openmc-dev/openmc/wiki/Example-Jupyter-Notebooks diff --git a/docs/source/pythonapi/mgxs.rst b/docs/source/pythonapi/mgxs.rst index bf5a845992d..392914b367d 100644 --- a/docs/source/pythonapi/mgxs.rst +++ b/docs/source/pythonapi/mgxs.rst @@ -41,6 +41,7 @@ Multi-group Cross Sections openmc.mgxs.KappaFissionXS openmc.mgxs.MultiplicityMatrixXS openmc.mgxs.NuFissionMatrixXS + openmc.mgxs.ReducedAbsorptionXS openmc.mgxs.ScatterXS openmc.mgxs.ScatterMatrixXS openmc.mgxs.ScatterProbabilityMatrix diff --git a/docs/source/pythonapi/model.rst b/docs/source/pythonapi/model.rst index a6c89be7cda..99459f64d09 100644 --- a/docs/source/pythonapi/model.rst +++ b/docs/source/pythonapi/model.rst @@ -11,9 +11,6 @@ Convenience Functions :template: myfunction.rst openmc.model.borated_water - openmc.model.cylinder_from_points - openmc.model.hexagonal_prism - openmc.model.rectangular_prism openmc.model.subdivide openmc.model.pin @@ -25,7 +22,13 @@ Composite Surfaces :nosignatures: :template: myclass.rst + openmc.model.CruciformPrism + openmc.model.CylinderSector + openmc.model.HexagonalPrism + openmc.model.IsogonalOctagon + openmc.model.Polygon openmc.model.RectangularParallelepiped + openmc.model.RectangularPrism openmc.model.RightCircularCylinder openmc.model.XConeOneSided openmc.model.YConeOneSided diff --git a/docs/source/pythonapi/stats.rst b/docs/source/pythonapi/stats.rst index d14aff5589f..ffb4fcda2ba 100644 --- a/docs/source/pythonapi/stats.rst +++ b/docs/source/pythonapi/stats.rst @@ -15,13 +15,20 @@ Univariate Probability Distributions openmc.stats.Univariate openmc.stats.Discrete openmc.stats.Uniform + openmc.stats.PowerLaw openmc.stats.Maxwell openmc.stats.Watt openmc.stats.Tabular openmc.stats.Legendre openmc.stats.Mixture openmc.stats.Normal - openmc.stats.Muir + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myfunction.rst + + openmc.stats.muir Angular Distributions --------------------- @@ -50,3 +57,11 @@ Spatial Distributions openmc.stats.SphericalIndependent openmc.stats.Box openmc.stats.Point + openmc.stats.MeshSpatial + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myfunction.rst + + openmc.stats.spherical_uniform diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index e416b3efd9a..7f222f77cb8 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -8,39 +8,56 @@ This quick install guide outlines the basic steps needed to install OpenMC on your computer. For more detailed instructions on configuring and installing OpenMC, see :ref:`usersguide_install` in the User's Manual. ----------------------------------------- -Installing on Linux/Mac with conda-forge ----------------------------------------- +-------------------------------------------------- +Installing on Linux/Mac with Mamba and conda-forge +-------------------------------------------------- `Conda `_ is an open source package management -system and environment management system for installing multiple versions of -software packages and their dependencies and switching easily between them. If -you have `conda` installed on your system, OpenMC can be installed via the -`conda-forge` channel. First, add the `conda-forge` channel with: +system and environments management system for installing multiple versions of +software packages and their dependencies and switching easily between them. +`Mamba `_ is a cross-platform package +manager and is compatible with `conda` packages. +OpenMC can be installed in a `conda` environment with `mamba`. +First, `conda` should be installed with one of the following installers: +`Miniconda `_, +`Anaconda `_, or `Miniforge `_. +Once you have `conda` installed on your system, OpenMC can be installed via the +`conda-forge` channel with `mamba`. + +First, add the `conda-forge` channel with: .. code-block:: sh conda config --add channels conda-forge -To list the versions of OpenMC that are available on the `conda-forge` channel, -in your terminal window or an Anaconda Prompt run: +Then create and activate a new conda enviroment called `openmc-env` in +which to install OpenMC. .. code-block:: sh - conda search openmc + conda create -n openmc-env + conda activate openmc-env -OpenMC can then be installed with: +Then install `mamba`, which will be used to install OpenMC. .. code-block:: sh - conda create -n openmc-env openmc + conda install mamba -This will install OpenMC in a conda environment called `openmc-env`. To activate -the environment, run: +To list the versions of OpenMC that are available on the `conda-forge` channel, +in your terminal window or an Anaconda Prompt run: .. code-block:: sh - conda activate openmc-env + mamba search openmc + +OpenMC can then be installed with: + +.. code-block:: sh + + mamba install openmc + +You are now in a conda environment called `openmc-env` that has OpenMC installed. ------------------------------------------- Installing on Linux/Mac/Windows with Docker @@ -90,31 +107,54 @@ can be used to access the installed packages. .. _Spack: https://spack.readthedocs.io/en/latest/ .. _setup guide: https://spack.readthedocs.io/en/latest/getting_started.html --------------------------------- -Installing from Source on Ubuntu +------------------------------- +Manually Installing from Source +------------------------------- + +Obtaining prerequisites on Ubuntu +--------------------------------- + +When building OpenMC from source, all :ref:`prerequisites ` can +be installed using the package manager: + +.. code-block:: sh + + sudo apt install g++ cmake libhdf5-dev libpng-dev + +After the packages have been installed, follow the instructions to build from +source below. + +Obtaining prerequisites on macOS -------------------------------- -To build OpenMC from source, several :ref:`prerequisites ` are -needed. If you are using Ubuntu or higher, all prerequisites can be installed -directly from the package manager: +For an OpenMC build with multithreading enabled, a package manager like +`Homebrew `_ should first be installed. Then, the following +packages should be installed, for example in Homebrew via: .. code-block:: sh - sudo apt install g++ cmake libhdf5-dev + brew install llvm cmake xtensor hdf5 python libomp libpng -After the packages have been installed, follow the instructions below for -building and installing OpenMC from source. +The compiler provided by the above LLVM package should be used in place of the +one provisioned by XCode, which does not support the multithreading library used +by OpenMC. Consequently, the C++ compiler should explicitly be set before +proceeding: -------------------------------------------- -Installing from Source on Linux or Mac OS X -------------------------------------------- +.. code-block:: sh + + export CXX=/opt/homebrew/opt/llvm/bin/clang++ + +After the packages have been installed, follow the instructions to build from +source below. + +Building Source on Linux or macOS +--------------------------------- All OpenMC source code is hosted on `GitHub `_. If you have `git -`_, the `gcc `_ compiler suite, -`CMake `_, and `HDF5 -`_ installed, you can download and -install OpenMC be entering the following commands in a terminal: +`_, a modern C++ compiler, `CMake `_, +and `HDF5 `_ installed, you can +download and install OpenMC by entering the following commands in a terminal: .. code-block:: sh @@ -134,14 +174,14 @@ should specify an installation directory where you have write access, e.g. cmake -DCMAKE_INSTALL_PREFIX=$HOME/.local .. The :mod:`openmc` Python package must be installed separately. The easiest way -to install it is using `pip `_, which is -included by default in Python 3.4+. From the root directory of the OpenMC -distribution/repository, run: +to install it is using `pip `_. +From the root directory of the OpenMC repository, run: .. code-block:: sh - pip install . + python -m pip install . -If you want to build a parallel version of OpenMC (using OpenMP or MPI), -directions can be found in the :ref:`detailed installation instructions +By default, OpenMC will be built with multithreading support. To build +distributed-memory parallel versions of OpenMC using MPI or to configure other +options, directions can be found in the :ref:`detailed installation instructions `. diff --git a/docs/source/releasenotes/0.13.0.rst b/docs/source/releasenotes/0.13.0.rst new file mode 100644 index 00000000000..8a35b81acf8 --- /dev/null +++ b/docs/source/releasenotes/0.13.0.rst @@ -0,0 +1,100 @@ +==================== +What's New in 0.13.0 +==================== + +.. currentmodule:: openmc + +------- +Summary +------- + +This release of OpenMC includes several noteworthy and unique features. Most +importantly, mesh-based weight windows have been added and work with all +supported mesh types (regular, rectilinear, cylindrical, spherical, and +unstructured). Other additions include torus surfaces, an ability to place +CAD-based geometries in universes, a feature to export/import physical +properties, and a filter for particle time. + +There is one breaking changing in the Python API. The +:class:`openmc.deplete.Operator` class used to accept :class:`~openmc.Geometry` +and :class:`~openmc.Settings` objects as its first two arguments; users now need +to pass a :class:`~openmc.model.Model` class instead. + +The minimum supported Python version is now 3.6. + +------------ +New Features +------------ + +- Variance reduction using mesh-based weight windows is now possible with the + :class:`~openmc.WeightWindows` class. +- Users can now model axis-aligned tori using the :class:`~openmc.XTorus`, + :class:`~openmc.YTorus`, and :class:`~openmc.ZTorus` classes. +- DAGMC CAD-based geometries can now be placed in a universe using + :class:`~openmc.DAGMCUniverse`, allowing users to combine CSG and CAD-based + geometry in a single model. +- The C/C++ API has two new functions ``openmc_properties_export`` and + ``openmc_properties_import`` with corresponding Python API bindings, + :func:`~openmc.lib.export_properties` and + :func:`~openmc.lib.import_properties`. These functions allow physical + properties (temperatures, densities, material compositions) to be written to + an HDF5 file and re-used for subsequent simulations. +- A new :class:`~openmc.stats.PowerLaw` univariate distribution +- The capabilities of the :class:`~openmc.Model` class have been substantially + expanded (e.g., the :meth:`~openmc.model.Model.deplete`, + :meth:`~openmc.model.Model.plot_geometry`, and + :meth:`~openmc.model.Model.rotate_cells` methods). +- A new :class:`~openmc.TimeFilter` class that allows tallies to be filtered + by the particle's time, which is now tracked. +- The :class:`~openmc.Source` class now allows you to specify a time + distribution. +- The new :class:`~openmc.CylindricalMesh` and :class:`~openmc.SphericalMesh` + can be used for mesh tallies over cylidrical and spherical meshes, + respectively. +- Geometry plotting, which used to produce the files in the unusual .ppm format, + now produces .png files by default. + +--------- +Bug Fixes +--------- + +- `Fix for shared fission bank memory errors `_ +- `Make sure properties export only happens from root process `_ +- `Fix pathlib use error in openmc-ace-to-hdf5 `_ +- `Fix DAGMC and libMesh variable in CMake config `_ +- `Fix bug associated with volume calc in MG mode `_ +- `Add missing Settings.write_initial_source property `_ +- `Bug fixes for specifying Materials.cross_sections `_ +- `Removing Legendre filter in diffusion coefficient results `_ +- `Ensure particles lost during event_calculate_xs are terminated `_ +- `Fixed parsing of xsdir entries with a continuation line `_ +- `openmc.RegularMesh attribute consistency `_ +- `Ensure secondary particles below energy cutoff are not created `_ +- `Allow compilation with g++ 11 `_ +- `Depletion-related bug fixes `_ +- `Miscellaneous bug fixes `_ +- `Fixes for various bugs `_ +- `Reset triggers in openmc_reset `_ + +------------ +Contributors +------------ + +- `Hunter Belanger `_ +- `Helen Brooks `_ +- `Andrew Davis `_ +- `Valerio Giusti `_ +- `Jeff Hammond `_ +- `Yuan Hu `_ +- `Andrew Johnson `_ +- `Miriam Kreher `_ +- `Amanda Lund `_ +- `Adam Nelson `_ +- `April Novak `_ +- `Ariful Islam Pranto `_ +- `Gavin Ridley `_ +- `Paul Romano `_ +- `Olaf Schumann `_ +- `Jonathan Shimwell `_ +- `Patrick Shriwise `_ +- `John Tramm `_ diff --git a/docs/source/releasenotes/0.13.1.rst b/docs/source/releasenotes/0.13.1.rst new file mode 100644 index 00000000000..70c8609ac32 --- /dev/null +++ b/docs/source/releasenotes/0.13.1.rst @@ -0,0 +1,182 @@ +==================== +What's New in 0.13.1 +==================== + +.. currentmodule:: openmc + +------- +Summary +------- + +This release of OpenMC includes many bug fixes as well as improvements in +geometry modeling, mesh functionality, source specification, depletion +capabilities, and other general enhancements. The depletion module features a +new transport operator, :class:`openmc.deplete.IndependentOperator`, that allows +a depletion calculation to be performed using arbitrary one-group cross sections +(e.g., generated by an external solver) along with a +:class:`openmc.deplete.MicroXS` class for managing one-group cross sections. The +track file generation capability has been significantly overhauled and a new +:class:`openmc.Tracks` class was introduced to allow access to information in +track files from the Python API. Support has been added for new ENDF thermal +scattering evaluations that use mixed coherent/incoherent elastic scattering. + +------------------------------------ +Compatibility Notes and Deprecations +------------------------------------ + +- The ``openmc.deplete.Operator`` class has been renamed + :class:`openmc.deplete.CoupledOperator`. +- The ``openmc.deplete.ResultsList`` class has been renamed to + :class:`openmc.deplete.Results` and no longer requires you to call the + ``from_hdf5()`` method in order to create it; instead, you can directly + instantiate it. +- A few methods that represent k-effective have been renamed for the sake of + consistency: + + - ``openmc.StatePoint.k_combined`` is now :attr:`openmc.StatePoint.keff` + - ``openmc.deplete.ResultsList.get_eigenvalue`` is now + :meth:`openmc.deplete.Results.get_keff` + +- The :class:`openmc.stats.SphericalIndependent` class, which used to + accept a distribution for ``theta`` now accepts a distribution for ``cos_theta`` + instead in order to more easily handle the common case of specifying a uniform + spatial distribution over a sphere (also see the new + :func:`openmc.stats.spherical_uniform` function). + +- If you are building OpenMC from source, note that several of our CMake options + have been changed: + + ========== ====================== + Old option New option + ========== ====================== + debug --- + optimize --- + profile OPENMC_ENABLE_PROFILE + coverage OPENMC_ENABLE_COVERAGE + openmp OPENMC_USE_OPENMP + --- OPENMC_USE_MPI + dagmc OPENMC_USE_DAGMC + libmesh OPENMC_USE_LIBMESH + ========== ====================== + + The ``debug`` and ``optimize`` options have been removed; instead, use the + standard `CMAKE_BUILD_TYPE + `_ + variable. + +------------ +New Features +------------ + +- Two new composite surfaces: :class:`openmc.model.IsogonalOctagon` and + :class:`openmc.model.CylinderSector`. +- The :class:`~openmc.DAGMCUniverse` class now has a + :attr:`~openmc.DAGMCUniverse.bounding_box` attribute and a + :meth:`~openmc.DAGMCUniverse.bounding_region` method. +- When translating a :class:`~openmc.Region` using the + :meth:`~openmc.Region.translate` method, there is now an ``inplace`` argument. +- The :class:`~openmc.Material` class has several new methods and attributes: + + - The :meth:`~openmc.Material.add_components` methods allows you to add + multiple nuclides/elements to a material with a single call by passing a + dictionary. + - The :meth:`~openmc.Material.get_activity` method returns the activity of a + material in Bq, Bq/g, or Bq/cm³. + - The :meth:`~openmc.Material.remove_element` method removes an element from a + material + - The :meth:`~openmc.Material.get_nuclide_atoms` method gives the number of + atoms of each nuclide in a material + +- All mesh classes now have a ``volumes`` property that provides the volume of + each mesh element as well as ``write_data_to_vtk`` methods. +- Support for externally managed MOAB meshes or libMesh meshes. +- Multiple discrete distributions can be merged with the new + :meth:`~openmc.stats.Discrete.merge` method. +- The :func:`openmc.stats.spherical_uniform` function creates a uniform + distribution over a sphere using the + :class:`~openmc.stats.SphericalIndependent` class. +- Univariate distributions in the :mod:`openmc.stats` module now have + ``sample()`` methods. +- An ``openmc_sample_external_source`` function has been added to the C API with + a corresponding Python binding :func:`openmc.lib.sample_external_source`. +- The track file generation capability has been completely overhauled. Track + files now include much more information, and a new :class:`~openmc.Tracks` + class allows access to track file information from the Python API and has a + :meth:`~openmc.Tracks.write_to_vtk` method for writing a VTK file. Multiple + tracks are now written to a single file (one per MPI rank). +- A new :func:`openmc.wwinp_to_wws` function that converts weight windows from a + ``wwinp`` file to a list of :class:`~openmc.WeightWindows` objects. +- The new :meth:`openmc.EnergyFilter.from_group_structure` method provides a + way of creating an energy filter with a group structure identified by name. +- The :class:`openmc.data.Decay` class now has a + :attr:`~openmc.data.Decay.sources` property that provides radioactive decay + source distributions. +- A :class:`openmc.mgxs.ReducedAbsorptionXS` class produces a multigroup cross + section representing "reduced" absorption (absorption less neutron production + from (n,xn) reactions). +- Added support in the Python API and HDF5 nuclear data format for new ENDF + thermal neutron scattering evaluations with mixed coherent elastic and + incoherent elastic. +- CMake now relies on ``find_package(MPI)`` for a more standard means of + identifying an MPI compiler configuration. + +--------- +Bug Fixes +--------- + +- `Fix bug when a rotation matrix is passed to Halfspace.rotate `_ +- `Fix bug for spherical mesh string repr `_ +- `Fix package_data specification to include pyx files `_ +- `Allow meshes with same ID to appear in multiple files `_ +- `Fix overwritten variable in get_libraries_from_xsdata `_ +- `Write output files to correct directory `_ +- `Allow CMake to properly find third-party packages `_ +- `Fix Region.from_expression when ")(" appears in specification `_ +- `Move lost particle reset from finalize() to reset() `_ +- `Minor typo fixes in test_lattice.py `_ +- `Fix color assignment in Universe.plot `_ +- `Several depletion-related fixes `_ +- `Allow control of C++ standard used by compiler `_ +- `Fix IO format documentation for surface source read/write `_ +- `Make sure basis gets set in Plot.from_geometry `_ +- `Improve robustness of torus distance calculation `_ +- `Allow use of redundant fission when adjusting KERMA in from_njoy `_ +- `Disable GNU extensions for CMake target `_ +- `Two from_xml fixes `_ +- `Fix for rare infinite loop when finding cell `_ +- `Allow photon heating to be tallied by nuclide `_ +- `Use UTF-8 encoding when reading dose coefficients `_ +- `Fix a corner case in Region.from_expression `_ +- `Fix bug in spherical and cylindrical meshes `_ +- `Ensure weight window bounds are flattened when writing to XML `_ +- `Fix for std::cout sync bug in output.cpp `_ +- `Allow compiling against fmt v9 `_ +- `Fix TimeFilter for small time intervals `_ + +------------ +Contributors +------------ + +- `David Andrs `_ +- `Hunter Belanger `_ +- `Helen Brooks `_ +- `Rémi Delaporte-Mathurin `_ +- `Joffrey Dorville `_ +- `Christopher Fichtlscherer `_ +- `Lewis Gross `_ +- `Andrew Johnson `_ +- `Kalin Kiesling `_ +- `Amanda Lund `_ +- `Richard Morrison `_ +- `Patrick Myers `_ +- `Adam Nelson `_ +- `April Novak `_ +- `Ethan Peterson `_ +- `Gavin Ridley `_ +- `Paul Romano `_ +- `Jonathan Shimwell `_ +- `Patrick Shriwise `_ +- `Amelia Trainer `_ +- `John Tramm `_ +- `Bob Urberger `_ +- `Olek Yardas `_ diff --git a/docs/source/releasenotes/0.13.2.rst b/docs/source/releasenotes/0.13.2.rst new file mode 100644 index 00000000000..b0c9b0691e5 --- /dev/null +++ b/docs/source/releasenotes/0.13.2.rst @@ -0,0 +1,99 @@ +==================== +What's New in 0.13.2 +==================== + +.. currentmodule:: openmc + +------- +Summary +------- + +This release of OpenMC includes several bug fixes, performance improvements for +complex geometries and depletion simulations, and other general enhancements. +Notably, a capability has been added to compute the photon spectra from decay of +unstable nuclides. Alongside that, a new :data:`openmc.config` configuration +variable has been introduced that allows easier configuration of data sources. +Additionally, users can now perform cell or material rejection when sampling +external source distributions. + +------------------------------------ +Compatibility Notes and Deprecations +------------------------------------ + +- If you are building against libMesh for unstructured mesh tally support, + version 1.6 or higher is now required. +- The ``openmc.stats.Muir`` class has been replaced by a + :func:`openmc.stats.muir` function that returns an instance of + :class:`openmc.stats.Normal`. + +------------ +New Features +------------ + +- The :meth:`openmc.Material.get_nuclide_atom_densities` method now takes an + optional ``nuclide`` argument. +- Functions/methods in the :mod:`openmc.deplete` module now accept times in + Julian years (``'a'``). +- The :meth:`openmc.Universe.plot` method now allows a pre-existing axes object + to be passed in. +- Performance optimization for geometries with many complex regions. +- Performance optimization for depletion by avoiding deepcopies and caching + reaction rates. +- The :class:`openmc.RegularMesh` class now has a + :meth:`~openmc.RegularMesh.from_domain` classmethod. +- The :class:`openmc.CylindricalMesh` class now has a + :meth:`~openmc.CylindricalMesh.from_domain` classmethod. +- Improved method to condense diffusion coefficients from the :mod:`openmc.mgxs` + module. +- A new :data:`openmc.config` configuration variable has been introduced that + allows data sources to be specified at runtime or via environment variables. +- The :class:`openmc.EnergyFunctionFilter` class now supports multiple + interpolation schemes, not just linear-linear interpolation. +- The :class:`openmc.DAGMCUniverse` class now has ``material_names``, + ``n_cells``, and ``n_surfaces`` attributes. +- A new :func:`openmc.data.decay_photon_energy` function has been added that + returns the energy spectrum of photons emitted from the decay of an unstable + nuclide. +- The :class:`openmc.Material` class also has a new + :attr:`~openmc.Material.decay_photon_energy` attribute that gives the decay + photon energy spectrum from the material based on its constituent nuclides. +- The :class:`openmc.deplete.StepResult` now has a + :meth:`~openmc.deplete.StepResult.get_material` method. +- The :class:`openmc.Source` class now takes a ``domains`` argument that + specifies a list of cells, materials, or universes that is used to reject + source sites (i.e., if the sampled sites are not within the specified domain, + they are rejected). + +--------- +Bug Fixes +--------- + +- `Delay call to Tally::set_strides `_ +- `Fix reading reference direction from XML for angular distributions `_ +- `Fix erroneous behavior in Material.add_components `_ +- `Fix reading thermal elastic data from ACE `_ +- `Fix reading source file with time attribute `_ +- `Fix conversion of multiple thermal scattering data files from ACE `_ +- `Fix reading values from wwinp file `_ +- `Handle possibility of .ppm file in Universe.plot `_ +- `Update volume calc types to mitigate overflow issues `_ + +------------ +Contributors +------------ + +- `Lewis Gross `_ +- `Andrew Johnson `_ +- `Miriam Kreher `_ +- `James Logan `_ +- `Jose Ignacio Marquez Damien `_ +- `Josh May `_ +- `Patrick Myers `_ +- `Adam Nelson `_ +- `April Novak `_ +- `Ethan Peterson `_ +- `Gavin Ridley `_ +- `Paul Romano `_ +- `Patrick Shriwise `_ +- `Jonathan Shimwell `_ +- `Olek Yardas `_ diff --git a/docs/source/releasenotes/0.13.3.rst b/docs/source/releasenotes/0.13.3.rst new file mode 100644 index 00000000000..c2debbcb31b --- /dev/null +++ b/docs/source/releasenotes/0.13.3.rst @@ -0,0 +1,134 @@ +==================== +What's New in 0.13.3 +==================== + +.. currentmodule:: openmc + +------- +Summary +------- + +This release of OpenMC includes many bug fixes, performance improvements, and +several notable new features. Some of the highlights include support for MCPL +source files, NCrystal thermal scattering materials, and a new +:class:`openmc.stats.MeshSpatial` class that allows a source distribution to be +specified over a mesh. Additionally, OpenMC now allows you to export your model +as a single XML file rather than separate XML files for geometry, materials, +settings, and tallies. + +------------------------------------ +Compatibility Notes and Deprecations +------------------------------------ + +- Atomic mass data used in :func:`openmc.data.atomic_mass` has been updated to + AME 2020, which results in slightly different masses. + +------------ +New Features +------------ + +- Support was added for `MCPL `_ files to be + used as external sources. Additionally, source points and surfaces sources can + be written as MCPL files instead of HDF5 files. (`#2116 + `_) +- Support was added for `NCrystal `_ + thermal scattering materials. (`#2222 + `_) +- The :class:`~openmc.CylindricalMesh` and :class:`~openmc.SphericalMesh` + classes now have an ``origin`` attribute that changes the center of the mesh. + (`#2256 `_) +- A new :class:`openmc.model.Polygon` class allows defining generalized 2D + polygons. (`#2266 `_) +- A new :func:`openmc.data.decay_energy` function and + :meth:`openmc.Material.get_decay_heat` method enable determination of decay + heat from a single nuclide or material. (`#2287 + `_) +- Full models can now be written as a single XML file rather than separate + geometry, materials, settings, and tallies XML files. (`#2291 + `_) +- Discrete distributions are now sampled using alias sampling, which is O(1) in + time. (`#2329 `_) +- The new :class:`openmc.stats.MeshSpatial` allows a spatial source distribution + to be specified with source strengths for each mesh element. (`#2334 + `_) +- The new :meth:`openmc.Geometry.get_surfaces_by_name` method returns a list of + matching surfaces in a geometry. (`#2347 + `_) +- A new :attr:`openmc.Settings.create_delayed_neutrons` attribute controls + whether delayed neutrons are created during a simulation. (`#2348 + `_) +- The :meth:`openmc.deplete.Results.export_to_materials` method now takes a + ``path`` argument. (`#2364 `_) +- A new :meth:`openmc.EnergyFilter.get_tabular` method allows one to create a + tabular distribution based on tally results using an energy filter. (`#2371 + `_) +- Several methods in the :class:`openmc.Material` class that require a volume to + be set (e.g., :meth:`~openmc.Material.get_mass`) now accept a ``volume`` + argument. (`#2412 `_) + +--------- +Bug Fixes +--------- + +- Fix for finding redundant surfaces (`#2263 `_) +- Adds tolerance for temperatures slightly out of bounds (`#2265 `_) +- Fix getter/setter for weight window bounds (`#2275 `_) +- Make sure Chain.reduce preserves decay source (`#2283 `_) +- Fix array shape for weight window bounds (`#2284 `_) +- Fix for non-zero CDF start points in TSL data (`#2290 `_) +- Fix a case where inelastic scattering yield is zero (`#2295 `_) +- Prevent Compton profile out-of-bounds memory access (`#2297 `_) +- Produce light particles from decay (`#2301 `_) +- Fix zero runtime attributes in depletion statepoints (`#2302 `_) +- Fix bug in openmc.Universe.get_nuclide_densities (`#2310 `_) +- Only show print output from depletion on rank 0 (`#2311 `_) +- Fix photon transport with no atomic relaxation data (`#2312 `_) +- Fix for precedence in region expressions (`#2318 `_) +- Allow source particles with energy below cutoff (`#2319 `_) +- Fix IncidentNeutron.from_njoy for high temperatures (`#2320 `_) +- Add capability to unset cell temperatures (`#2323 `_) +- Fix in plot_xs when S(a,b) tables are present (`#2335 `_) +- Various fixes for tally triggers (`#2344 `_) +- Raise error when mesh is flat (`#2363 `_) +- Don't call normalize inside Tabular.mean (`#2375 `_) +- Avoid out-of-bounds access in inelastic scatter sampling (`#2378 `_) +- Use correct direction for anisotropic fission (`#2381 `_) +- Fix several thermal scattering nuclide assignments (`#2382 `_) +- Fix _materials_by_id attribute in Model (`#2385 `_) +- Updates to batch checks for simulation restarts (`#2390 `_) +- write_data_to_vtk volume normalization correction (`#2397 `_) +- Enable generation of JEFF 3.3 depletion chain (`#2410 `_) +- Fix spherical to Cartesian coordinate conversion (`#2417 `_) +- Handle zero photon cross sections in IncidentPhoton.from_ace (`#2433 `_) +- Fix hybrid depletion when nuclides are not present (`#2436 `_) +- Fix bug in cylindrical and spherical meshes (`#2439 `_) +- Improvements to mesh radial boundary coincidence (`#2443 `_) + +------------ +Contributors +------------ + +- `Hunter Belanger `_ +- `Rémi Delaporte-Mathurin `_ +- `Christopher Fichtlscherer `_ +- `Valerio Giusti `_ +- `Chris Keckler `_ +- `Kalin Kiesling `_ +- `Thomas Kittelmann `_ +- `Erik Knudsen `_ +- `Colin Larmier `_ +- `Amanda Lund `_ +- `Jose Ignacio Marquez Damien `_ +- `Josh May `_ +- `Patrick Myers `_ +- `Baptiste Mouginot `_ +- `April Novak `_ +- `Matthew Nyberg `_ +- `Ethan Peterson `_ +- `Gavin Ridley `_ +- `Paul Romano `_ +- `Patrick Shriwise `_ +- `Jonathan Shimwell `_ +- `Paul Wilson `_ +- `Olek Yardas `_ +- `Jiankai Yu `_ diff --git a/docs/source/releasenotes/0.14.0.rst b/docs/source/releasenotes/0.14.0.rst new file mode 100644 index 00000000000..445edfa077a --- /dev/null +++ b/docs/source/releasenotes/0.14.0.rst @@ -0,0 +1,284 @@ +==================== +What's New in 0.14.0 +==================== + +.. currentmodule:: openmc + +------- +Summary +------- + +This release of OpenMC includes many bug fixes, performance improvements, and +several notable new features. Some of the highlights include projection plots, +pulse height tallies for photons, weight window generation, and an ability to +specify continuous removal or feed of nuclides/elements during depletion. +Additionally, one of the longstanding annoyances of depletion calculations, +namely the need to include initial "dilute" nuclides, has been eliminated. There +are also a wide array of general improvements in the Python API. + +------------------------------------ +Compatibility Notes and Deprecations +------------------------------------ + +- The :class:`openmc.deplete.MicroXS` has been completely redesigned and + improved. See further comments below under "New Features". (`#2572 + `_, `#2579 + `_, `#2595 + `_, `#2700 + `_) +- The ``rectangular_prism`` function has been replaced by the + :class:`openmc.model.RectangularPrism` class and the ``hexagonal_prism`` + function has been replaced by the :class:`openmc.model.HexagonalPrism` class. + Note that whereas the ``rectangular_prism`` and ``hexagonal_prism`` functions + returned a region representing the interior of the prism, the new + :class:`~openmc.model.RectangularPrism` and + :class:`~openmc.model.HexagonalPrism` classes return composite surfaces, so + you need to use the unary ``-`` or ``+`` operators to obtain a region that can + be assigned to a cell. (`#2739 + `_) +- The ``Source`` class has been refactored and split up into three separate + classes: :class:`~openmc.IndependentSource`, :class:`~openmc.FileSource`, and + :class:`~openmc.CompiledSource`. (`#2524 + `_) +- The ``vertices`` and ``centroids`` attributes on mesh classes now always + return Cartesian coordinates and the shape of the returned arrays has changed + to allow `ijk` indexing using a tuple (i.e., `xyz = vertices[i, j, k]`). + (`#2711 `_) +- The :attr:`openmc.Material.decay_photon_energy` attribute has been replaced by + the :meth:`openmc.Material.get_decay_photon_energy` method. (`#2715 + `_) + +------------ +New Features +------------ + +- A new :class:`openmc.ProjectionPlot` class enables the generation of orthographic or + perspective projection plots. (`#1926 + `_) +- The :class:`openmc.model.RightCircularCylinder` class now supports optional + filleted edges. (`#2309 `_) +- Continuous removal or feed of nuclides/elements between materials can now be + modeled during depletion via the + :meth:`openmc.deplete.abc.Integrator.add_transfer_rate` method. (`#2358 + `_, `#2564 + `_, `#2626 + `_) +- The MAGIC method for global weight window generation has been implemented as + part of the C++ API. (`#2359 + `_) +- A new capability for pulse height tallies (currently limited to photons) has + been added and can be used via the "pulse-height" tally score. (`#2452 + `_) +- A :class:`openmc.model.CruciformPrism` class has been added that provides a + generalized cruciform prism composite surface. (`#2457 + `_) +- Type hints have been added in various places throughout the Python API. + (`#2462 `_, `#2467 + `_, `#2468 + `_, `#2470 + `_, `#2471 + `_, `#2601 + `_) +- Voxel plots can now be generated through the :meth:`openmc.Plot.to_vtk` + method. (`#2464 `_) +- The :class:`openmc.mgxs.EnergyGroups` class now allows you to alternatively + pass a string of the group structure name (e.g., "CCFE-709") instead of the + energy group boundaries. (`#2466 + `_) +- Several enhancements have been made to the :meth:`openmc.Universe.plot` method + (addition of axis labels with units, ability to show legend and/or outlines, automatic + determination of origin/width, ability to pass total number of pixels). + (`#2472 `_, `#2482 + `_, `#2483 + `_, `#2492 + `_, `#2513 + `_, `#2575 + `_) +- Functionality in the Python dealing with bounding boxes now relies on a new + :class:`openmc.BoundingBox` class. (`#2475 + `_) +- Users now have more flexibility in specifying nuclides and reactions in the + :func:`openmc.plot_xs` function. (`#2478 + `_) +- The import time of the :mod:`openmc` Python module has been improved by + deferring the import of matplotlib. (`#2488 + `_) +- Mesh clases in the Python API now support a ``bounding_box`` property. (`#2507 + `_, `#2620 + `_, `#2621 + `_) +- The ``Source`` class has been refactored and split up into three separate + classes: :class:`~openmc.IndependentSource`, :class:`~openmc.FileSource`, and + :class:`~openmc.CompiledSource`. (`#2524 + `_) +- Support was added for curvilinear elements when exporting cylindrical and + spherical meshes to VTK. (`#2533 + `_) +- The :class:`openmc.Tally` class now has a + :attr:`~openmc.Tally.multiply_density` attribute that indicates whether + reaction rate tallies should include the number density of the nuclide of + interest. (`#2539 `_) +- The :func:`~openmc.wwinp_to_wws` function now supports ``wwinp`` files with + cylindrical or spherical meshes. (`#2556 + `_) +- Depletion no longer relies on adding initial "dilute" nuclides to each + depletable material in order to compute reaction rates. (`#2559 + `_, `#2568 + `_) +- The :class:`openmc.deplete.Results` class now has + :meth:`~openmc.deplete.Results.get_mass` (`#2565 + `_), + :meth:`~openmc.deplete.Results.get_activity` (`#2617 + `_), and + :meth:`~openmc.deplete.Results.get_decay_heat` (`#2625 + `_) methods. +- The :meth:`openmc.deplete.StepResult.save` method now supports a ``path`` + argument. (`#2567 `_) +- The :class:`openmc.deplete.MicroXS` has been completely redesigned and + improved. First, it no longer relies on the :mod:`openmc.mgxs` module, no + longer subclasses :class:`pandas.DataFrame`, and doesn't require adding + initial "dilute" nuclides into material compositions. It now enables users to + specify an energy group structure to collect multigroup cross sections, + specify nuclides/reactions, and works with mesh domains in addition to the + existing domains. A new :func:`openmc.deplete.get_microxs_and_flux` function + was added that improves the workflow for calculating microscopic cross + sections along with fluxes. Altogether, these changes make it straightforward + to switch between coupled and independent operators for depletion/activation + calculations. (`#2572 `_, + `#2579 `_, `#2595 + `_, `#2700 + `_) +- The :class:`openmc.Geometry` class now has ``merge_surfaces`` and + ``surface_precision`` arguments. (`#2602 + `_) +- Several predefined energy group structures have been added ("MPACT-51", + "MPACT-60", "MPACT-69", "SCALE-252"). (`#2614 + `_) +- When running a depletion calculation, you are now allowed to include nuclides + in the initial material compositions that do not have neutron cross sections + (decay-only nuclides). (`#2616 + `_) +- The :class:`~openmc.CylindricalMesh` and :class:`~openmc.SphericalMesh` + classes can now be fully formed using the constructor. (`#2619 + `_) +- A time cutoff can now be specified in the :attr:`openmc.Settings.cutoff` + attribute. (`#2631 `_) +- The :meth:`openmc.Material.add_element` method now supports a + ``cross_sections`` argument that allows a cross section data source to be + specified. (`#2633 `_) +- The :class:`~openmc.Cell` class now has a :meth:`~openmc.Cell.plot` method. + (`#2648 `_) +- The :class:`~openmc.Geometry` class now has a :meth:`~openmc.Geometry.plot` + method. (`#2661 `_) +- When weight window checks are performed can now be explicitly specified with + the :attr:`openmc.Settings.weight_window_checkpoints` attribute. (`#2670 + `_) +- The :class:`~openmc.Settings` class now has a + :attr:`~openmc.Settings.max_write_lost_particles` attribute that can limit the + number of lost particle files written. (`#2688 + `_) +- The :class:`~openmc.deplete.CoupledOperator` class now has a + ``diff_volume_method`` argument that specifies how the volume of new materials + should be determined. (`#2691 + `_) +- The :meth:`openmc.DAGMCUniverse.bounding_region` method now has a + ``padding_distance`` argument. (`#2701 + `_) +- A new :meth:`openmc.Material.get_decay_photon_energy` method replaces the + :attr:`decay_photon_energy` attribute and includes an ability to eliminate + low-importance points. This is facilitated by a new + :meth:`openmc.stats.Discrete.clip` method. (`#2715 + `_) +- The :meth:`openmc.model.Model.differentiate_depletable_mats` method allows + depletable materials to be differentiated independent of the depletion + calculation itself. (`#2718 + `_) +- Albedos can now be specified on surface boundary conditions. (`#2724 + `_) + +--------- +Bug Fixes +--------- + +- Enable use of NCrystal materials in plot_xs (`#2435 `_) +- Avoid segfault from extern "C" std::string (`#2455 `_) +- Fix several issues with the Model class (`#2465 `_) +- Provide alternative batch estimation message (`#2479 `_) +- Correct index check for remove_tally (`#2494 `_) +- Support for NCrystal material in from_xml_element (`#2496 `_) +- Fix compilation with gcc 5 (`#2498 `_) +- Fixed in the Tally::add_filter method (`#2501 `_) +- Fix meaning of "masking" for plots (`#2510 `_) +- Fix description of statepoint.batches in Settings class (`#2514 `_) +- Reorder list initialization of Plot constructor (`#2519 `_) +- Added mkdir to cwd argument in Model.run (`#2523 `_) +- Fix export of spherical coordinates in SphericalMesh (`#2538 `_) +- Add virtual destructor on PlottableInterface (`#2541 `_) +- Ensure parent directory is created during depletion (`#2543 `_) +- Fix potential out-of-bounds access in TimeFilter (`#2532 `_) +- Remove use of sscanf for reading surface coefficients (`#2574 `_) +- Fix torus intersection bug (`#2589 `_) +- Multigroup per-thread cache fixes (`#2591 `_) +- Bank surface source particles in all active cycles (`#2592 `_) +- Fix for muir standard deviation (`#2598 `_) +- Check for zero fission cross section (`#2600 `_) +- XML read fixes in Plot classes (`#2623 `_) +- Added infinity check in VolumeCalculation (`#2634 `_) +- Fix sampling issue in Mixture distributions (`#2658 `_) +- Prevent segfault in distance to boundary calculation (`#2659 `_) +- Several CylindricalMesh fixes (`#2676 + `_, `#2680 + `_, `#2684 + `_, `#2710 + `_) +- Add type checks on Intersection, Union, Complement (`#2685 `_) +- Fixed typo in CF4Integrator docstring (`#2704 `_) +- Ensure property setters are used in CylindricalMesh and SphericalMesh (`#2709 `_) +- Fix sample_external_source bug (`#2713 `_) +- Fix localization issue affecting openmc-plotter (`#2723 `_) +- Correct openmc.lib wrapper for evaluate_legendre (`#2729 `_) +- Bug fix in Region.from_expression during tokenization (`#2733 `_) +- Fix bug in temperature interpolation (`#2734 `_) +- Check for invalid domain IDs in volume calculations (`#2742 `_) +- Skip boundary condition check for volume calculations (`#2743 `_) +- Fix loop over coordinates for source domain rejection (`#2751 `_) + +------------ +Contributors +------------ + +- `April Novak `_ +- `Baptiste Mouginot `_ +- `Ben Collins `_ +- `Chritopher Billingham `_ +- `Christopher Fichtlscherer `_ +- `Christina Cai `_ +- `Lorenzo Chierici `_ +- `Huw Rhys Jones `_ +- `Emilio Castro `_ +- `Erik Knudsen `_ +- `Ethan Peterson `_ +- `Egor Afanasenko `_ +- `Paul Wilson `_ +- `Gavin Ridley `_ +- `Hunter Belanger `_ +- `Jack Fletcher `_ +- `John Vincent Cauilan `_ +- `Josh May `_ +- `John Tramm `_ +- `Kevin McLaughlin `_ +- `Yue Jin `_ +- `Lewis Gross `_ +- `Luke Labrie-Cleary `_ +- `Patrick Myers `_ +- `Nicola Rizzi `_ +- `Yuvraj Jain `_ +- `Paul Romano `_ +- `Patrick Shriwise `_ +- `Rosie Barker `_ +- `Jonathan Shimwell `_ +- `John Tchakerian `_ +- `Travis Labossiere-Hickman `_ +- `Xinyan Wang `_ +- `Olek Yardas `_ +- `Zoe Prieto `_ diff --git a/docs/source/releasenotes/index.rst b/docs/source/releasenotes/index.rst index f3c02f0396c..6923101cc43 100644 --- a/docs/source/releasenotes/index.rst +++ b/docs/source/releasenotes/index.rst @@ -7,6 +7,11 @@ Release Notes .. toctree:: :maxdepth: 1 + 0.14.0 + 0.13.3 + 0.13.2 + 0.13.1 + 0.13.0 0.12.2 0.12.1 0.12.0 diff --git a/docs/source/usersguide/basics.rst b/docs/source/usersguide/basics.rst index 250255f45a3..60b599588eb 100644 --- a/docs/source/usersguide/basics.rst +++ b/docs/source/usersguide/basics.rst @@ -75,10 +75,7 @@ person. The nested tags *firstname*, *lastname*, *age*, and *occupation* indicate characteristics about the person being described. In much the same way, OpenMC input uses XML tags to describe the geometry, the -materials, and settings for a Monte Carlo simulation. Note that because the XML -files have a well-defined structure, they can be validated using the -:ref:`scripts_validate` script or using :ref:`Emacs nXML mode -`. +materials, and settings for a Monte Carlo simulation. Creating Input Files -------------------- @@ -86,12 +83,12 @@ Creating Input Files .. currentmodule:: openmc The most rudimentary option for creating input files is to simply write them -from scratch using the :ref:`XML format specifications -`. This approach will feel familiar to users of other -Monte Carlo codes such as MCNP and Serpent, with the added bonus that the XML -formats feel much more "readable". Alternatively, input files can be generated -using OpenMC's :ref:`Python API `, which is introduced in the -following section. +from scratch using the :ref:`XML format specifications `. +This approach will feel familiar to users of other Monte Carlo codes such as +MCNP and Serpent, with the added bonus that the XML formats feel much more +"readable". However, it is strongly recommended to generate input files using +OpenMC's :ref:`Python API `, which is introduced in the following +section. ---------- Python API @@ -181,14 +178,3 @@ energy electronvolt eV time second s ======= ============ ====== ------------------------------------- -ERSN-OpenMC Graphical User Interface ------------------------------------- - -A third-party Java-based user-friendly graphical user interface for creating XML -input files called ERSN-OpenMC_ is developed and maintained by members of the -Radiation and Nuclear Systems Group at the Faculty of Sciences Tetouan, Morocco. -The GUI also allows one to automatically download prerequisites for installing and -running OpenMC. - -.. _ERSN-OpenMC: https://github.com/EL-Bakkali-Jaafar/ERSN-OpenMC diff --git a/docs/source/usersguide/cross_sections.rst b/docs/source/usersguide/data.rst similarity index 62% rename from docs/source/usersguide/cross_sections.rst rename to docs/source/usersguide/data.rst index 58bf1a2933e..6af2973388b 100644 --- a/docs/source/usersguide/cross_sections.rst +++ b/docs/source/usersguide/data.rst @@ -1,55 +1,73 @@ -.. _usersguide_cross_sections: - -=========================== -Cross Section Configuration -=========================== - -In order to run a simulation with OpenMC, you will need cross section data for -each nuclide or material in your problem. OpenMC can be run in continuous-energy -or multi-group mode. - -In continuous-energy mode, OpenMC uses a native `HDF5 -`_ format (see :ref:`io_nuclear_data`) to -store all nuclear data. Pregenerated HDF5 libraries can be found at -https://openmc.org; unless you have specific data needs, it is highly -recommended to use one of the pregenerated libraries. Alternatively, if you have -ACE format data that was produced with NJOY_, such as that distributed with -MCNP_ or Serpent_, it can be converted to the HDF5 format using the :ref:`using -the Python API `. Several sources provide openly available -ACE data including the `ENDF/B`_, JEFF_, and TENDL_ libraries as well as the -`LANL Nuclear Data Team `_. In addition to -tabulated cross sections in the HDF5 files, OpenMC relies on :ref:`windowed -multipole ` data to perform on-the-fly Doppler broadening. - -In multi-group mode, OpenMC utilizes an HDF5-based library format which can be -used to describe nuclide- or material-specific quantities. +.. _usersguide_data: + +================== +Data Configuration +================== + +OpenMC relies on a variety of physical data in order to carry out transport +simulations, depletion simulations, and other common tasks. As a user, you are +responsible for specifying one or more of the following: + +- **Cross sections (XML)** -- A :ref:`cross sections XML ` + file (commonly named ``cross_sections.xml``) contains a listing of other data + files, in particular neutron cross sections, photon cross sections, and + windowed multipole data. Each of those files, in turn, uses a `HDF5 + `_ format (see :ref:`io_nuclear_data`). In + order to run transport simulations with continuous-energy cross sections, you + need to specify this file. + +- **Depletion chain (XML)** -- A :ref:`depletion chain XML ` + file contains decay data, fission product yields, and information on what + neutron reactions can result in transmutation. This file is needed for + depletion/activation calculations as well as some basic functions in the + :mod:`openmc.data` module. + +- **Multigroup cross sections (HDF5)** -- OpenMC can also perform transport + simulations using multigroup data. In this case, multigroup cross sections are + stored in a single :ref:`HDF5 file `. Thus, in order to run a + multigroup transport simulation, this file needs to be specified. + +Each of the above files can specified in several ways. In the Python API, a +:ref:`runtime configuration variable ` +:data:`openmc.config` can be used to specify any of the above and is initialized +using a set of environment variables. + +.. _usersguide_data_runtime: --------------------- -Environment Variables +Runtime Configuration --------------------- -When :ref:`scripts_openmc` is run, it will look for several environment -variables that indicate where cross sections can be found. While the location of -cross sections can also be indicated through the -:attr:`openmc.Materials.cross_sections` attribute (or in the :ref:`materials.xml -` file), if you always use the same set of cross section data, it -is often easier to just set an environment variable that will be picked up by -default every time OpenMC is run. The following environment variables are used: - -:envvar:`OPENMC_CROSS_SECTIONS` - Indicates the path to the :ref:`cross_sections.xml ` - summary file that is used to locate HDF5 format cross section libraries if the - user has not specified :attr:`openmc.Materials.cross_sections` (equivalently, - the :ref:`cross_sections` in :ref:`materials.xml `). - -:envvar:`OPENMC_MG_CROSS_SECTIONS` +Data sources for OpenMC can be specified at runtime in Python using the +:data:`openmc.config` variable. This variable acts like a dictionary and stores +key-values pairs, where the values are file paths (strings or path-like objects) +and the key can be one of the following: + +``"cross_sections"`` + Indicates the path to the :ref:`cross sections XML ` file + that lists HDF5 format neutron cross sections, photon cross sections, and + windowed multipole data. At startup, this is initialized with the value of the + :envvar:`OPENMC_CROSS_SECTIONS` environment variable. Note that the + :attr:`openmc.Materials.cross_sections` attribute will override this, if + specified. + +``"chain_file"`` + Indicates the path to the :ref:`depletion chain XML ` file + that contains decay data, fission product yields, and what neutron reactions + may result in transmutation of a target nuclide. At startup, this is + initialized with the value of the :envvar:`OPENMC_CHAIN_FILE` environment + variable. + +``"mg_cross_sections"`` Indicates the path to an :ref:`HDF5 file ` that contains - multi-group cross sections if the user has not specified - :attr:`openmc.Materials.cross_sections` (equivalently, the - :ref:`cross_sections` in :ref:`materials.xml `). + multigroup cross sections. At startup, this is initialized with the value of + the :envvar:`OPENMC_MG_CROSS_SECTIONS` environment variable. Note that the + :attr:`openmc.Materials.cross_sections` attribute will override this if + specified. -To set these environment variables persistently, export them from your shell -profile (``.profile`` or ``.bashrc`` in bash_). +If you want to persistently set the environment variables used to initialized +the configuration, export them from your shell profile (``.profile`` or +``.bashrc`` in bash_). .. _bash: http://www.linuxfromscratch.org/blfs/view/6.3/postlfs/profile.html @@ -61,12 +79,13 @@ Using Pregenerated Libraries ---------------------------- Various evaluated nuclear data libraries have been processed into the HDF5 -format required by OpenMC and can be found at https://openmc.org. You -can find both libraries generated by the OpenMC development team as well as -libraries based on ACE files distributed elsewhere. To use these libraries, -download the archive file, unpack it, and then set your -:envvar:`OPENMC_CROSS_SECTIONS` environment variable to the absolute path of -the ``cross_sections.xml`` file contained in the unpacked directory. +format required by OpenMC and can be found at https://openmc.org. Unless you +have specific data needs, it is highly recommended to use one of the +pregenerated libraries. You can find both libraries generated by the OpenMC +development team as well as libraries based on ACE files distributed elsewhere. +To use these libraries, download the archive file, unpack it, and then specify +the path of the ``cross_sections.xml`` file contained in the unpacked directory +as described in :ref:`usersguide_data_runtime`. .. _create_xs_library: @@ -75,6 +94,12 @@ Manually Creating a Library from ACE files .. currentmodule:: openmc.data +If you have ACE format data that was produced with NJOY_, such as that +distributed with MCNP_ or Serpent_, it can be converted to the HDF5 format using +the using the Python API. Several sources provide openly available ACE data +including the `ENDF/B`_, JEFF_, and TENDL_ libraries as well as the `LANL +Nuclear Data Team `_. + The :mod:`openmc.data` module in the Python API enables users to directly convert ACE data to OpenMC's HDF5 format and create a corresponding :ref:`cross_sections.xml ` file. For those who prefer to use @@ -124,7 +149,7 @@ OpenMC. .. hint:: The :class:`IncidentNeutron` class allows you to view/modify cross sections, secondary angle/energy distributions, probability tables, etc. For a more thorough overview of the capabilities of this class, - see the `example notebook <../examples/nuclear-data.ipynb>`__. + see the `example notebook `_. Manually Creating a Library from ENDF files ------------------------------------------- @@ -224,6 +249,19 @@ relaxation sublibrary files are required: Once the HDF5 files have been generated, a library can be created using the :class:`DataLibrary` class as described in :ref:`create_xs_library`. +----------- +Chain Files +----------- + +Pregenerated depletion chain XML files can be found at https://openmc.org. +Additionally, depletion chains can be generated using the +:class:`openmc.deplete.Chain` class. In particular, the +:meth:`~openmc.deplete.Chain.from_endf` method allows a chain to be generated +starting from a set of ENDF incident neutron, decay, and fission product yield +sublibrary files. Once you've downloaded or generated a depletion chain XML +file, make sure to specify its path as described in +:ref:`usersguide_data_runtime`. + ----------------------- Windowed Multipole Data ----------------------- @@ -241,25 +279,25 @@ The `official ENDF/B-VII.1 HDF5 library multipole library, so if you are using this library, the windowed multipole data will already be available to you. --------------------------- -Multi-Group Cross Sections --------------------------- +.. _create_mgxs: -Multi-group cross section libraries are generally tailored to the specific -calculation to be performed. Therefore, at this point in time, OpenMC is not -distributed with any pre-existing multi-group cross section libraries. -However, if obtained or generated their own library, the user -should set the :envvar:`OPENMC_MG_CROSS_SECTIONS` environment variable -to the absolute path of the file library expected to used most frequently. +------------------------- +Multigroup Cross Sections +------------------------- -For an example of how to create a multi-group library, see the `example notebook +Multigroup cross section libraries are generally tailored to the specific +calculation to be performed. Therefore, at this point in time, OpenMC is not +distributed with any pre-existing multigroup cross section libraries. However, +if a multigroup library file is downloaded or generated, the path to the file +needs to be specified as described in :ref:`usersguide_data_runtime`. For an +example of how to create a multigroup library, see the `example notebook <../examples/mg-mode-part-i.ipynb>`__. .. _NJOY: http://www.njoy21.io/ .. _NNDC: https://www.nndc.bnl.gov/endf .. _MCNP: https://mcnp.lanl.gov .. _Serpent: http://montecarlo.vtt.fi -.. _ENDF/B: https://www.nndc.bnl.gov/endf/b7.1/acefiles.html +.. _ENDF/B: https://www.nndc.bnl.gov/endf-b7.1/acefiles.html .. _JEFF: https://www.oecd-nea.org/dbdata/jeff/jeff33/ .. _TENDL: https://tendl.web.psi.ch/tendl_2017/tendl2017.html .. _Seltzer and Berger: https://doi.org/10.1016/0092-640X(86)90014-8 diff --git a/docs/source/usersguide/depletion.rst b/docs/source/usersguide/depletion.rst index 6fa2b89c932..261900ce61a 100644 --- a/docs/source/usersguide/depletion.rst +++ b/docs/source/usersguide/depletion.rst @@ -4,63 +4,74 @@ Depletion and Transmutation =========================== -OpenMC supports coupled depletion, or burnup, calculations through the -:mod:`openmc.deplete` Python module. OpenMC solves the transport equation to -obtain transmutation reaction rates, and then the reaction rates are used to -solve a set of transmutation equations that determine the evolution of nuclide -densities within a material. The nuclide densities predicted as some future time -are then used to determine updated reaction rates, and the process is repeated -for as many timesteps as are requested. - -The depletion module is designed such that the flux/reaction rate solution (the +OpenMC supports transport-coupled and transport-independent depletion, or +burnup, calculations through the :mod:`openmc.deplete` Python module. OpenMC +uses transmutation reaction rates to solve a set of transmutation equations +that determine the evolution of nuclide densities within a material. The +nuclide densities predicted at some future time are then used to determine +updated reaction rates, and the process is repeated for as many timesteps as +are requested. + +The depletion module is designed such that the reaction rate solution (the transport "operator") is completely isolated from the solution of the -transmutation equations and the method used for advancing time. At present, the -:mod:`openmc.deplete` module offers a single transport operator, -:class:`openmc.deplete.Operator` (which uses the OpenMC transport solver), but -in principle additional operator classes based on other transport codes could be -implemented and no changes to the depletion solver itself would be needed. The -operator class requires a :class:`openmc.Geometry` instance and a -:class:`openmc.Settings` instance:: - - geom = openmc.Geometry() - settings = openmc.Settings() - ... - - op = openmc.deplete.Operator(geom, settings) - -Any material that contains a fissionable nuclide is depleted by default, but -this can behavior can be changed with the :attr:`Material.depletable` attribute. - -.. important:: The volume must be specified for each material that is depleted by - setting the :attr:`Material.volume` attribute. This is necessary - in order to calculate the proper normalization of tally results - based on the source rate. +transmutation equations and the method used for advancing time. :mod:`openmc.deplete` supports multiple time-integration methods for determining material compositions over time. Each method appears as a different class. For example, :class:`openmc.deplete.CECMIntegrator` runs a depletion calculation using the CE/CM algorithm (deplete over a timestep using the middle-of-step -reaction rates). An instance of :class:`openmc.deplete.Operator` is passed to -one of these functions along with the timesteps and power level:: +reaction rates). An instance of :class:`~openmc.deplete.abc.TransportOperator` +is passed to one of these Integrator classes along with the timesteps and power +level:: power = 1200.0e6 # watts timesteps = [10.0, 10.0, 10.0] # days openmc.deplete.CECMIntegrator(op, timesteps, power, timestep_units='d').integrate() -The coupled transport-depletion problem is executed, and once it is done a +The depletion problem is executed, and once it is done a ``depletion_results.h5`` file is written. The results can be analyzed using the -:class:`openmc.deplete.ResultsList` class. This class has methods that allow for +:class:`openmc.deplete.Results` class. This class has methods that allow for easy retrieval of k-effective, nuclide concentrations, and reaction rates over time:: - results = openmc.deplete.ResultsList.from_hdf5("depletion_results.h5") - time, keff = results.get_eigenvalue() + results = openmc.deplete.Results("depletion_results.h5") + time, keff = results.get_keff() + +Note that the coupling between the reaction rate solver and the transmutation +solver happens in-memory rather than by reading/writing files on disk. OpenMC +has two categories of transport operators for obtaining transmutation reaction +rates. + +.. _coupled-depletion: + +Transport-coupled depletion +=========================== + +This category of operator solves the transport equation to obtain transmutation +reaction rates. At present, the :mod:`openmc.deplete` module offers a single +transport-coupled operator, :class:`openmc.deplete.CoupledOperator` (which uses +the OpenMC transport solver), but in principle additional transport-coupled +operator classes based on other transport codes could be implemented and no +changes to the depletion solver itself would be needed. The +:class:`openmc.deplete.CoupledOperator` class requires a :class:`~openmc.Model` +instance containing material, geometry, and settings information:: + + model = openmc.Model() + ... + + op = openmc.deplete.CoupledOperator(model) + +Any material that contains a fissionable nuclide is depleted by default, but +this can behavior can be changed with the :attr:`Material.depletable` attribute. -Note that the coupling between the transport solver and the transmutation solver -happens in-memory rather than by reading/writing files on disk. +.. important:: + + The volume must be specified for each material that is depleted by setting + the :attr:`Material.volume` attribute. This is necessary in order to + calculate the proper normalization of tally results based on the source rate. Fixed-Source Transmutation -========================== +-------------------------- When the ``power`` or ``power_density`` argument is used for one of the Integrator classes, it is assumed that OpenMC is running in k-eigenvalue mode, @@ -77,11 +88,11 @@ using the :attr:`Material.depletable` attribute:: mat = openmc.Material() mat.depletable = True -When constructing the :class:`~openmc.deplete.Operator`, you should indicate -that normalization of tally results will be done based on the source rate rather -than a power or power density:: +When constructing the :class:`~openmc.deplete.CoupledOperator`, you should +indicate that normalization of tally results will be done based on the source +rate rather than a power or power density:: - op = openmc.deplete.Operator(geometry, settings, normalization_mode='source-rate') + op = openmc.deplete.CoupledOperator(model, normalization_mode='source-rate') Finally, when creating a depletion integrator, use the ``source_rates`` argument:: @@ -92,19 +103,22 @@ timestep in the calculation. A zero source rate for a given timestep will result in a decay-only step, where all reaction rates are zero. Caveats -======= +------- + +.. _energy-deposition: Energy Deposition ------------------ +~~~~~~~~~~~~~~~~~ The default energy deposition mode, ``"fission-q"``, instructs the -:class:`openmc.deplete.Operator` to normalize reaction rates using the product -of fission reaction rates and fission Q values taken from the depletion chain. -This approach does not consider indirect contributions to energy deposition, -such as neutron heating and energy from secondary photons. In doing this, the -energy deposited during a transport calculation will be lower than expected. -This causes the reaction rates to be over-adjusted to hit the user-specific -power, or power density, leading to an over-depletion of burnable materials. +:class:`~openmc.deplete.CoupledOperator` to normalize reaction rates using the +product of fission reaction rates and fission Q values taken from the depletion +chain. This approach does not consider indirect contributions to energy +deposition, such as neutron heating and energy from secondary photons. In doing +this, the energy deposited during a transport calculation will be lower than +expected. This causes the reaction rates to be over-adjusted to hit the +user-specific power, or power density, leading to an over-depletion of burnable +materials. There are some remedies. First, the fission Q values can be directly set in a variety of ways. This requires knowing what the total fission energy release @@ -113,29 +127,32 @@ should be, including indirect components. Some examples are provided below:: # use a dictionary of fission_q values fission_q = {"U235": 202e+6} # energy in eV + # create a Model object + model = openmc.Model(geometry, settings) + # create a modified chain and write it to a new file chain = openmc.deplete.Chain.from_xml("chain.xml", fission_q) chain.export_to_xml("chain_mod_q.xml") - op = openmc.deplete.Operator(geometry, setting, "chain_mod_q.xml") + op = openmc.deplete.CoupledOperator(model, "chain_mod_q.xml") # alternatively, pass the modified fission Q directly to the operator - op = openmc.deplete.Operator(geometry, setting, "chain.xml", + op = openmc.deplete.CoupledOperator(model, "chain.xml", fission_q=fission_q) A more complete way to model the energy deposition is to use the modified -heating reactions described in :ref:`methods_heating`. These values can be used +heating reactions described in :ref:`methods_heating`. These values can be used to normalize reaction rates instead of using the fission reaction rates with:: - op = openmc.deplete.Operator(geometry, settings, "chain.xml", + op = openmc.deplete.CoupledOperator(model, "chain.xml", normalization_mode="energy-deposition") These modified heating libraries can be generated by running the latest version -of :meth:`openmc.data.IncidentNeutron.from_njoy`, and will eventually be bundled +of :meth:`openmc.data.IncidentNeutron.from_njoy()`, and will eventually be bundled into the distributed libraries. Local Spectra and Repeated Materials ------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is not uncommon to explicitly create a single burnable material across many locations. From a pure transport perspective, there is nothing wrong with @@ -160,7 +177,7 @@ the next transport step. This can be countered by instructing the operator to treat repeated instances of the same material as a unique material definition with:: - op = openmc.deplete.Operator(geometry, settings, chain_file, + op = openmc.deplete.CoupledOperator(model, chain_file, diff_burnable_mats=True) For our example problem, this would deplete fuel on the outer region of the @@ -177,3 +194,258 @@ across all material instances. This will increase the total memory usage and run time due to an increased number of tallies and material definitions. +Transport-independent depletion +=============================== + +This category of operator uses multigroup microscopic cross sections along with +multigroup flux spectra to obtain transmutation reaction rates. The cross +sections are pre-calculated, so there is no need for direct coupling between a +transport-independent operator and a transport solver. The :mod:`openmc.deplete` +module offers a single transport-independent operator, +:class:`~openmc.deplete.IndependentOperator`, and only one operator is needed +since, in theory, any transport code could calculate the multigroup microscopic +cross sections. The :class:`~openmc.deplete.IndependentOperator` class has two +constructors. The default constructor requires a :class:`openmc.Materials` +instance, a list of multigroup flux arrays, and a list of +:class:`~openmc.deplete.MicroXS` instances containing multigroup microscopic +cross sections in units of barns. This might look like the following:: + + materials = openmc.Materials([m1, m2, m3]) + ... + + # Assign fluxes (generated from any code) + flux_m1 = numpy.array([...]) + flux_m2 = numpy.array([...]) + flux_m3 = numpy.array([...]) + fluxes = [flux_m1, flux_m2, flux_m3] + + # Assign microscopic cross sections + micro_m1 = openmc.deplete.MicroXS.from_csv('xs_m1.csv') + micro_m2 = openmc.deplete.MicroXS.from_csv('xs_m2.csv') + micro_m3 = openmc.deplete.MicroXS.from_csv('xs_m3.csv') + micros = [micro_m1, micro_m2, micro_m3] + + # Create operator + op = openmc.deplete.IndependentOperator(materials, fluxes, micros) + +For more details on the :class:`~openmc.deplete.MicroXS` class, including how to +use OpenMC's transport solver to generate microscopic cross sections and fluxes +for use with :class:`~openmc.deplete.IndependentOperator`, see :ref:`micros`. + +.. note:: + + The same statements from :ref:`coupled-depletion` about which materials are + depleted and the requirement for depletable materials to have a specified + volume also apply here. + +An alternate constructor, +:meth:`~openmc.deplete.IndependentOperator.from_nuclides`, accepts a volume and +dictionary of nuclide concentrations in place of the :class:`openmc.Materials` +instance. Note that while the normal constructor allows multiple materials to be +depleted with a single operator, the +:meth:`~openmc.deplete.IndependentOperator.from_nuclides` classmethod only works +for a single material:: + + nuclides = {'U234': 8.92e18, + 'U235': 9.98e20, + 'U238': 2.22e22, + 'U236': 4.57e18, + 'O16': 4.64e22, + 'O17': 1.76e19} + volume = 0.5 + op = openmc.deplete.IndependentOperator.from_nuclides(volume, + nuclides, + flux, + micro_xs, + chain_file, + nuc_units='atom/cm3') + +A user can then define an integrator class as they would for a coupled +transport-depletion calculation and follow the same steps from there. + +.. note:: + + Ideally, multigroup cross section data should be available for every reaction + in the depletion chain. If cross section data is not present for a nuclide in + the depletion chain with at least one reaction, that reaction will not be + simulated. + +.. _micros: + +Loading and Generating Microscopic Cross Sections +------------------------------------------------- + +As mentioned above, any transport code could be used to calculate multigroup +microscopic cross sections and fluxes. The :mod:`openmc.deplete` module provides +the :class:`~openmc.deplete.MicroXS` class, which can either be instantiated +from pre-calculated cross sections in a ``.csv`` file or from data arrays +directly:: + + micro_xs = MicroXS.from_csv(micro_xs_path) + + nuclides = ['U234', 'U235', 'U238'] + reactions = ['fission', '(n,gamma)'] + data = np.array([[0.1, 0.2], + [0.3, 0.4], + [0.01, 0.5]]) + micro_xs = MicroXS(data, nuclides, reactions) + +.. important:: + + The cross section values are assumed to be in units of barns. Make sure your + cross sections are in the correct units before passing to a + :class:`~openmc.deplete.IndependentOperator` object. + +Additionally, a convenience function, +:func:`~openmc.deplete.get_microxs_and_flux`, can provide the needed fluxes and +cross sections using OpenMC's transport solver:: + + model = openmc.Model() + ... + + fluxes, micros = openmc.deplete.get_microxs_and_flux(model, materials) + +If you are running :func:`~openmc.deplete.get_microxs_and_flux` on a cluster +where temporary files are created on a local filesystem that is not shared +across nodes, you'll need to set an environment variable pointing to a local +directoy so that each MPI process knows where to store output files used to +calculate the microscopic cross sections. In order of priority, they are +:envvar:`TMPDIR`. :envvar:`TEMP`, and :envvar:`TMP`. Users interested in further +details can read the documentation for the `tempfile +`_ module. + +Caveats +------- + +Reaction Rate Normalization +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`~openmc.deplete.IndependentOperator` class supports two methods for +normalizing reaction rates: + +.. important:: + + Make sure you set the correct parameter in the :class:`openmc.abc.Integrator` + class. Use the ``source_rates`` parameter when + ``normalization_mode == source-rate``, and use ``power`` or ``power_density`` + when ``normalization_mode == fission-q``. + +1. ``source-rate`` normalization, which assumes the ``source_rate`` provided by + the time integrator is a flux, and obtains the reaction rates by multiplying + the cross sections by the ``source-rate``. +2. ``fission-q`` normalization, which uses the ``power`` or ``power_density`` + provided by the time integrator to obtain normalized reaction rates by + computing a normalization factor as the ratio of the user-specified power to + the "observed" power based on fission reaction rates. The equation for the + normalization factor is + + .. math:: + :label: fission-q + + f = \frac{P}{\sum\limits_m \sum\limits_i \left(Q_i N_{i,m} \sum\limits_g + \sigma^f_{i,g,m} \phi_{g,m} \right)} + + where :math:`P` is the power, :math:`Q_i` is the fission Q value for nuclide + :math:`i`, :math:`\sigma_{i,g,m}^f` is the microscopic fission cross section + for nuclide :math:`i` in energy group :math:`g` for material :math:`m`, + :math:`\phi_{g,m}` is the neutron flux in group :math:`g` for material + :math:`m`, and :math:`N_{i,m}` is the number of atoms of nuclide :math:`i` + for material :math:`m`. Reaction rates are then multiplied by :math:`f` so + that the total fission power matches :math:`P`. This equation makes the same + assumptions and issues as discussed in :ref:`energy-deposition`. + Unfortunately, the proposed solution in that section does not apply here + since we are decoupled from transport code. However, there is a method to + converge to a more accurate value for flux by using substeps during time + integration. `This paper `_ + provides a good discussion of this method. + +.. warning:: + + The accuracy of results when using ``fission-q`` is entirely dependent on + your depletion chain. Make sure it has sufficient data to resolve the + dynamics of your particular scenario. + +Multiple Materials +~~~~~~~~~~~~~~~~~~ + +A transport-independent depletion simulation using ``source-rate`` normalization +will calculate reaction rates for each material independently. This can be +useful for running many different cases of a particular scenario. A +transport-independent depletion simulation using ``fission-q`` normalization +will sum the fission energy values across all materials into :math:`Q_i` in +Equation :math:numref:`fission-q`, and Equation :math:numref:`fission-q` +provides the normalization factor applied to reaction rates in each material. +This can be useful for running a scenario with multiple depletable materials +that are part of the same reactor. This behavior may change in the future. + +Time integration +~~~~~~~~~~~~~~~~ + +The values of the microscopic cross sections passed to +:class:`openmc.deplete.IndependentOperator` are fixed for the entire depletion +simulation. This implicit assumption may produce inaccurate results for certain +scenarios. + +Transfer Rates +============== + +Transfer rates define removal or feed of nuclides to or from one or more +depletable materials. This can be useful to model continuous fuel reprocessing, +online fission products separation, etc. + +Transfer rates are defined by calling the +:meth:`~openmc.deplete.abc.Integrator.add_transfer_rate()` method directly from +one of the Integrator classes:: + + ... + integrator = openmc.deplete.PredictorIntegrator(op, time_steps, power) + integrator.add_transfer_rate(...) + +Defining transfer rates +----------------------- + +The :meth:`~openmc.deplete.abc.Integrator.add_transfer_rate()` method requires a +:class:`~openmc.Material` instance (alternatively, a material id or +the name) as the depletable material from which nuclides are processed, +a list of elements that share the same transfer rate, and a transfer rate itself. + +.. caution:: + + Make sure you set the transfer rate value with the right sign. + A positive transfer rate assumes removal, while a negative one assumes feed. + +The ``transfer_rate_units`` argument specifies the units for the transfer rate. +The default is `1/s`, but '1/min', '1/h', '1/d' and '1/a' are also valid +options. + +For example, to define continuous removal of xenon from one material with a +removal rate value of 0.1 s\ :sup:`-1` (or a cycle time of 10 s), you'd use:: + + mat1 = openmc.Material(material_id=1, name='fuel') + + ... + + integrator = openmc.deplete.PredictorIntegrator(op, time_steps, power) + # by openmc.Material object + integrator.add_transfer_rate(mat1, ['Xe'], 0.1) + # or by material id + integrator.add_transfer_rate(1, ['Xe'], 0.1) + # or by material name + integrator.add_transfer_rate('fuel', ['Xe'], 0.1) + +Note that in this case the xenon isotopes that are removed will not be tracked. + +Defining a destination material +------------------------------- + +To transfer elements from one depletable material to another, the +``destination_material`` parameter needs to be passed to the +:meth:`~openmc.deplete.abc.Integrator.add_transfer_rate()` method. For example, +to transfer xenon from one material to another, you'd use:: + + ... + mat2 = openmc.Material(name='storage') + + ... + + integrator.add_transfer_rate(mat1, ['Xe'], 0.1, destination_material=mat2) diff --git a/docs/source/usersguide/geometry.rst b/docs/source/usersguide/geometry.rst index c8e5fd99f3b..3a3d02231ad 100644 --- a/docs/source/usersguide/geometry.rst +++ b/docs/source/usersguide/geometry.rst @@ -78,10 +78,23 @@ classes are listed in the following table. | Cone parallel to the | :math:`(x-x_0)^2 + (y-y_0)^2 | :class:`openmc.ZCone` | | :math:`z`-axis | - R^2(z-z_0)^2 = 0` | | +----------------------+------------------------------+---------------------------+ - | General quadric | :math:`Ax^2 + By^2 + Cz^2 + | :class:`openmc.Quadric` | + | General quadric | :math:`Ax^2 + By^2 + Cz^2 + | :class:`openmc.Quadric` | | surface | Dxy + Eyz + Fxz + Gx + Hy + | | | | Jz + K = 0` | | +----------------------+------------------------------+---------------------------+ + | Torus parallel to the| :math:`(x-x_0)^2/B^2+\frac{( | :class:`openmc.XTorus` | + | :math:`x`-axis | \sqrt{(y-y_0)^2+(z-z_0)^2} - | | + | | A)^2}{C^2} - 1 = 0` | | + +----------------------+------------------------------+---------------------------+ + | Torus parallel to the| :math:`(y-y_0)^2/B^2+\frac{( | :class:`openmc.YTorus` | + | :math:`y`-axis | \sqrt{(x-x_0)^2+(z-z_0)^2} - | | + | | A)^2}{C^2} - 1 = 0` | | + +----------------------+------------------------------+---------------------------+ + | Torus parallel to the| :math:`(z-z_0)^2/B^2+\frac{( | :class:`openmc.ZTorus` | + | :math:`z`-axis | \sqrt{(x-x_0)^2+(y-y_0)^2} - | | + | | A)^2}{C^2} - 1 = 0` | | + +----------------------+------------------------------+---------------------------+ + Each surface is characterized by several parameters. As one example, the parameters for a sphere are the :math:`x,y,z` coordinates of the center of the @@ -134,12 +147,13 @@ For many regions, a bounding-box can be determined automatically:: While a bounding box can be determined for regions involving half-spaces of spheres, cylinders, and axis-aligned planes, it generally cannot be determined if the region involves cones, non-axis-aligned planes, or other exotic -second-order surfaces. For example, the :func:`openmc.model.hexagonal_prism` -function returns the interior region of a hexagonal prism; because it is bounded -by a :class:`openmc.Plane`, trying to get its bounding box won't work:: +second-order surfaces. For example, the :class:`openmc.model.HexagonalPrism` +class returns a hexagonal prism surface; because it utilizes a +:class:`openmc.Plane`, trying to get the bounding box of its interior won't +work:: - >>> hex = openmc.model.hexagonal_prism() - >>> hex.bounding_box + >>> hex = openmc.model.HexagonalPrism() + >>> (-hex).bounding_box (array([-0.8660254, -inf, -inf]), array([ 0.8660254, inf, inf])) @@ -159,13 +173,17 @@ surface. To specify a vacuum boundary condition, simply change the outer_surface = openmc.Sphere(r=100.0) outer_surface.boundary_type = 'vacuum' -Reflective and periodic boundary conditions can be set with the strings -'reflective' and 'periodic'. Vacuum and reflective boundary conditions can be -applied to any type of surface. Periodic boundary conditions can be applied to -pairs of planar surfaces. If there are only two periodic surfaces they will be -matched automatically. Otherwise it is necessary to specify pairs explicitly -using the :attr:`Surface.periodic_surface` attribute as in the following -example:: +Reflective, periodic, and white boundary conditions can be set with the +strings 'reflective', 'periodic', and 'white' respectively. +Vacuum, reflective and white boundary conditions can be applied to any +type of surface. The 'white' boundary condition supports diffuse particle +reflection in contrast to specular reflection provided by the 'reflective' +boundary condition. + +Periodic boundary conditions can be applied to pairs of planar surfaces. +If there are only two periodic surfaces they will be matched automatically. +Otherwise it is necessary to specify pairs explicitly using the +:attr:`Surface.periodic_surface` attribute as in the following example:: p1 = openmc.Plane(a=0.3, b=5.0, d=1.0, boundary_type='periodic') p2 = openmc.Plane(a=0.3, b=5.0, d=-1.0, boundary_type='periodic') @@ -183,6 +201,20 @@ lies in the first quadrant of the Cartesian grid. If the geometry instead lies in the fourth quadrant, the :class:`YPlane` must be replaced by a :class:`Plane` with the normal vector pointing in the :math:`-y` direction. +Additionally, 'reflective', 'periodic', and 'white' boundary conditions have +an albedo parameter that can be used to modify the importance of particles +that encounter the boundary. The albedo value specifies the ratio between +the particle's importance after interaction with the boundary to its initial +importance. The following example creates a reflective planar surface which +reduces the reflected particles' importance by 33.3%:: + + x1 = openmc.XPlane(1.0, boundary_type='reflective', albedo=0.667) + + # This is equivalent + x1 = openmc.XPlane(1.0) + x1.boundary_type = 'reflective' + x1.albedo = 0.667 + .. _usersguide_cells: ----- @@ -397,7 +429,7 @@ code would work:: hexlat.universes = [outer_ring, middle_ring, inner_ring] If you need to create a hexagonal boundary (composed of six planar surfaces) for -a hexagonal lattice, :func:`openmc.model.hexagonal_prism` can be used. +a hexagonal lattice, :class:`openmc.model.HexagonalPrism` can be used. .. _usersguide_geom_export: @@ -433,30 +465,64 @@ will handle creating the unverse:: Using CAD-based Geometry -------------------------- -OpenMC relies on the Direct Accelerated Geometry Monte Carlo toolkit (`DAGMC -`_) to represent CAD-based geometry in a -surface mesh format. A DAGMC run can be enabled in OpenMC by setting the -``dagmc`` property to ``True`` in the model Settings either via the Python -:class:`openmc.settings` Python class:: - - settings = openmc.Settings() - settings.dagmc = True - -or in the :ref:`settings.xml ` file:: - - true - -With ``dagmc`` set to true, OpenMC will load the DAGMC model (from a local file -named ``dagmc.h5m``) when initializing a simulation. If a `geometry.xml -<../io_formats/geometry.html>`_ is present as well, it will be ignored. - - **Note:** DAGMC geometries used in OpenMC are currently required to be clean, - meaning that all surfaces have been `imprinted and merged - `_ - successfully and that the model is `watertight - `_. Future - implementations of DAGMC geometry will support small volume overlaps and - un-merged surfaces. +Defining Geometry +----------------- + +OpenMC relies on the `Direct Accelerated Geometry Monte Carlo`_ (DAGMC) +to represent CAD-based geometry in a surface mesh format. DAGMC geometries are +applied as universes in the OpenMC geometry file. A geometry represented +entirely by a DAGMC geometry will contain only the DAGMC universe. Using a +:class:`openmc.DAGMCUniverse` looks like the following:: + + dag_univ = openmc.DAGMCUniverse(filename='dagmc.h5m') + geometry = openmc.Geometry(dag_univ) + geometry.export_to_xml() + +The resulting ``geometry.xml`` file will be: + +.. code-block:: xml + + + + + + +DAGMC universes can also be used to fill CSG cells or lattice cells in a geometry:: + + cell.fill = dagmc_univ + +It is important in these cases to understand the DAGMC model's position +with respect to the CSG geometry. DAGMC geometries can be plotted with +OpenMC to verify that the model matches one's expectations. + +**Note:** DAGMC geometries used in OpenMC are currently required to be clean, +meaning that all surfaces have been `imprinted and merged +`_ successfully +and that the model is `watertight +`_. +Future implementations of DAGMC geometry will support small volume overlaps and +un-merged surfaces. + +Cell, Surface, and Material IDs +------------------------------- + +By default, DAGMC applies cell and surface IDs defined by the CAD engine that +the model originated in. If these IDs overlap with IDs in the CSG ID space, +this will result in an error. However, the ``auto_ids`` property of a DAGMC +universe can be set to set DAGMC cell and surface IDs by appending to the +existing CSG cell ID space in the OpenMC model. + +Similar options exist for the material IDs of DAGMC models. If DAGMC material +assignments are based on natively defined OpenMC materials, no further work is +required. If DAGMC materials are assigned using the `University of Wisconsin +Unified Workflow`_ (UWUW), however, material IDs in the UWUW material library +may overlap with those used in the CSG geometry. In this case, overlaps in the +UWUW and OpenMC material ID space will cause an error. To automatically resolve +these ID overlaps, ``auto_ids`` can be set to ``True`` to append the UWUW +material IDs to the OpenMC material ID space. + +.. _Direct Accelerated Geometry Monte Carlo: https://svalinn.github.io/DAGMC/ +.. _University of Wisconsin Unified Workflow: https://svalinn.github.io/DAGMC/usersguide/uw2.html ------------------------- Calculating Atoms Content diff --git a/docs/source/usersguide/index.rst b/docs/source/usersguide/index.rst index fab353c773d..03a77e87063 100644 --- a/docs/source/usersguide/index.rst +++ b/docs/source/usersguide/index.rst @@ -13,7 +13,7 @@ essential aspects of using OpenMC to perform simulations. beginners install - cross_sections + data basics materials geometry @@ -25,4 +25,6 @@ essential aspects of using OpenMC to perform simulations. processing parallel volume + random_ray troubleshoot + \ No newline at end of file diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 695240406ac..130e96c0ae6 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -8,39 +8,56 @@ Installation and Configuration .. _install_conda: ----------------------------------------- -Installing on Linux/Mac with conda-forge ----------------------------------------- - -Conda_ is an open source package management system and environment management -system for installing multiple versions of software packages and their -dependencies and switching easily between them. If you have `conda` installed on -your system, OpenMC can be installed via the `conda-forge` channel. First, add -the `conda-forge` channel with: +-------------------------------------------------- +Installing on Linux/Mac with Mamba and conda-forge +-------------------------------------------------- + +`Conda `_ is an open source package management +systems and environments management system for installing multiple versions of +software packages and their dependencies and switching easily between them. +`Mamba `_ is a cross-platform package +manager and is compatible with `conda` packages. +OpenMC can be installed in a `conda` environment with `mamba`. +First, `conda` should be installed with one of the following installers: +`Miniconda `_, +`Anaconda `_, or `Miniforge `_. +Once you have `conda` installed on your system, OpenMC can be installed via the +`conda-forge` channel with `mamba`. + +First, add the `conda-forge` channel with: .. code-block:: sh conda config --add channels conda-forge -To list the versions of OpenMC that are available on the `conda-forge` channel, -in your terminal window or an Anaconda Prompt run: +Then create and activate a new conda enviroment called `openmc-env` in +which to install OpenMC. .. code-block:: sh - conda search openmc + conda create -n openmc-env + conda activate openmc-env -OpenMC can then be installed with: +Then install `mamba`, which will be used to install OpenMC. .. code-block:: sh - conda create -n openmc-env openmc + conda install mamba -This will install OpenMC in a conda environment called `openmc-env`. To activate -the environment, run: +To list the versions of OpenMC that are available on the `conda-forge` channel, +in your terminal window or an Anaconda Prompt run: .. code-block:: sh - conda activate openmc-env + mamba search openmc + +OpenMC can then be installed with: + +.. code-block:: sh + + mamba install openmc + +You are now in a conda environment called `openmc-env` that has OpenMC installed. ------------------------------------------- Installing on Linux/Mac/Windows with Docker @@ -88,9 +105,9 @@ other information use: .. note:: - It should be noted that by default OpenMC builds with ``-O2 -g`` flags which - are equivalent to a CMake build type of `RelwithDebInfo`. In addition, MPI - is OFF while OpenMP is ON. + It should be noted that by default OpenMC is built with + `-DCMAKE_BUILD_TYPE=RelwithDebInfo`. In addition, MPI is OFF while OpenMP is + ON. It is recommended to install OpenMC with the Python API. Information about this Spack recipe can be found with the following command: @@ -116,17 +133,18 @@ following command: configured defaults unless otherwise specfied in the specification on the command line. In the above example, assuming the default options weren't changed in Spack's package configuration, py-openmc will link against a - non-optimized non-MPI openmc. Even if an optimized openmc was built - separately, it will rebuild openmc with optimization OFF. Thus, if you are - trying to link against dependencies that were configured different than - defaults, ``^openmc[variants]`` will have to be present in the command. + non-MPI non-release build of openmc. Even if a release build of openmc was + built separately, it will rebuild openmc with the default build type. Thus, + if you are trying to link against dependencies that were configured + different than defaults, ``^openmc[variants]`` will have to be present in + the command. -For a more performant build of OpenMC with optimization turned ON and MPI -provided by OpenMPI, the following command can be used: +For a release build of OpenMC with MPI support on (provided by OpenMPI), the +following command can be used: .. code-block:: sh - spack install py-openmc+mpi ^openmc+optimize ^openmpi + spack install py-openmc +mpi ^openmpi ^openmc build_type=Release .. note:: @@ -146,7 +164,7 @@ This can be observed using Spack's ``spec`` tool: .. code-block:: - spack spec py-openmc+mpi ^openmc+optimize + spack spec py-openmc +mpi ^openmc build_type=Release Once installed, environment/lmod modules can be generated or Spack's ``load`` feature can be used to access the installed packages. @@ -203,7 +221,7 @@ Prerequisites respectively. To link against a parallel HDF5 library, make sure to set the HDF5_PREFER_PARALLEL CMake option, e.g.:: - CXX=mpicxx.mpich cmake -DHDF5_PREFER_PARALLEL=on .. + cmake -DHDF5_PREFER_PARALLEL=on -DOPENMC_USE_MPI=on .. Note that the exact package names may vary depending on your particular distribution and version. @@ -219,6 +237,15 @@ Prerequisites .. admonition:: Optional :class: note + * libpng_ official reference PNG library + + OpenMC's built-in plotting capabilities use the libpng library to produce + compressed PNG files. In the absence of this library, OpenMC will fallback + to writing PPM files, which are uncompressed and only supported by select + image viewers. libpng can be installed on Ddebian derivates with:: + + sudo apt install libpng-dev + * An MPI implementation for distributed-memory parallel runs To compile with support for parallel runs on a distributed-memory @@ -243,7 +270,28 @@ Prerequisites In addition to turning this option on, the path to the DAGMC installation should be specified as part of the ``CMAKE_PREFIX_PATH`` variable:: - cmake -Ddagmc=on -DCMAKE_PREFIX_PATH=/path/to/dagmc/installation + cmake -DOPENMC_USE_DAGMC=on -DCMAKE_PREFIX_PATH=/path/to/dagmc/installation .. + + * MCPL_ library for reading and writing .mcpl files + + This option allows OpenMC to read and write MCPL (Monte Carlo Particle + Lists) files instead of .h5 files for sources (external source + distribution, k-eigenvalue source distribution, and surface sources). To + turn this option on in the CMake configuration step, add the following + option:: + + cmake -DOPENMC_USE_MCPL=on .. + + * NCrystal_ library for defining materials with enhanced thermal neutron transport + + Adding this option allows the creation of materials from NCrystal, which + replaces the scattering kernel treatment of ACE files with a modular, + on-the-fly approach. To use it `install + `_ and `initialize + `_ + NCrystal and turn on the option in the CMake configuration step:: + + cmake -DOPENMC_USE_NCRYSTAL=on .. * libMesh_ mesh library framework for numerical simulations of partial differential equations @@ -252,9 +300,9 @@ Prerequisites be used, but the implementation is currently restricted to collision estimators. In addition to turning this option on, the path to the libMesh installation should be specified as part of the ``CMAKE_PREFIX_PATH`` - variable.:: + variable:: - CXX=mpicxx cmake -Dlibmesh=on -DCMAKE_PREFIX_PATH=/path/to/libmesh/installation + cmake -DOPENMC_USE_LIBMESH=on -DOPENMC_USE_MPI=on -DCMAKE_PREFIX_PATH=/path/to/libmesh/installation .. Note that libMesh is most commonly compiled with MPI support. If that is the case, then OpenMC should be compiled with MPI support as well. @@ -265,7 +313,11 @@ Prerequisites .. _MPICH: https://www.mpich.org .. _HDF5: https://www.hdfgroup.org/solutions/hdf5/ .. _DAGMC: https://svalinn.github.io/DAGMC/index.html +.. _MOAB: https://bitbucket.org/fathomteam/moab .. _libMesh: https://libmesh.github.io/ +.. _libpng: http://www.libpng.org/pub/png/libpng.html +.. _MCPL: https://github.com/mctools/mcpl +.. _NCrystal: https://github.com/mctools/ncrystal Obtaining the Source -------------------- @@ -320,63 +372,73 @@ CMakeLists.txt Options The following options are available in the CMakeLists.txt file: -debug - Enables debugging when compiling. The flags added are dependent on which - compiler is used. - -profile - Enables profiling using the GNU profiler, gprof. +OPENMC_ENABLE_COVERAGE + Compile and link code instrumented for coverage analysis. This is typically + used in conjunction with gcov_. (Default: off) -optimize - Enables high-optimization using compiler-dependent flags. For gcc and - Intel C++, this compiles with -O3. +OPENMC_ENABLE_PROFILE + Enables profiling using the GNU profiler, gprof. (Default: off) -openmp +OPENMC_USE_OPENMP Enables shared-memory parallelism using the OpenMP API. The C++ compiler being used must support OpenMP. (Default: on) -dagmc +OPENMC_USE_DAGMC Enables use of CAD-based DAGMC_ geometries and MOAB_ unstructured mesh tallies. Please see the note about DAGMC in the optional dependencies list for more information on this feature. The installation directory for DAGMC should also be defined as `DAGMC_ROOT` in the CMake configuration command. (Default: off) -libmesh +OPENMC_USE_MCPL + Turns on support for reading MCPL_ source files and writing MCPL source points + and surface sources. (Default: off) + +OPENMC_USE_NCRYSTAL + Turns on support for NCrystal materials. NCrystal must be `installed + `_ and `initialized + `_. + (Default: off) + +OPENMC_USE_LIBMESH Enables the use of unstructured mesh tallies with libMesh_. (Default: off) -coverage - Compile and link code instrumented for coverage analysis. This is typically - used in conjunction with gcov_. +OPENMC_USE_MPI + Turns on compiling with MPI (Default: off). For further information on MPI + options, please see the `FindMPI.cmake documentation + `_. -To set any of these options (e.g. turning on debug mode), the following form +To set any of these options (e.g., turning on profiling), the following form should be used: .. code-block:: sh - cmake -Ddebug=on /path/to/openmc + cmake -DOPENMC_ENABLE_PROFILE=on /path/to/openmc .. _gcov: https://gcc.gnu.org/onlinedocs/gcc/Gcov.html .. _usersguide_compile_mpi: -Compiling with MPI -++++++++++++++++++ +Specifying the Build Type ++++++++++++++++++++++++++ -To compile with MPI, set the :envvar:`CXX` environment variable to the path to -the MPI C++ wrapper. For example, in a bash shell: +OpenMC can be configured for debug, release, or release with debug info by setting +the `CMAKE_BUILD_TYPE` option. -.. code-block:: sh +Debug + Enable debug compiler flags with no optimization `-O0 -g`. - export CXX=mpicxx - cmake /path/to/openmc +Release + Disable debug and enable optimization `-O3 -DNDEBUG`. + +RelWithDebInfo + (Default if no type is specified.) Enable optimization and debug `-O2 -g`. -Note that in many shells, environment variables can be set for a single command, -i.e. +Example of configuring for Debug mode: .. code-block:: sh - CXX=mpicxx cmake /path/to/openmc + cmake -DCMAKE_BUILD_TYPE=Debug /path/to/openmc Selecting HDF5 Installation +++++++++++++++++++++++++++ @@ -402,11 +464,11 @@ can typically be set for a single command, i.e. .. _compile_linux: -Compiling on Linux and Mac OS X -------------------------------- +Compiling on Linux and macOS +---------------------------- -To compile OpenMC on Linux or Max OS X, run the following commands from within -the root directory of the source code: +To compile OpenMC on Linux or macOS, run the following commands from within the +root directory of the source code: .. code-block:: sh @@ -426,13 +488,13 @@ OpenMC locally by specifying an install prefix when running cmake: The ``CMAKE_INSTALL_PREFIX`` variable can be changed to any path for which you have write-access. -Compiling on Windows 10 ------------------------ +Compiling on Windows +-------------------- -Recent versions of Windows 10 include a subsystem for Linux that allows one to -run Bash within Ubuntu running in Windows. First, follow the installation guide -`here `_ to get Bash -on Ubuntu on Windows setup. Once you are within bash, obtain the necessary +Recent versions of Windows include a subsystem for Linux that allows one to run +Bash within Ubuntu running in Windows. First, follow the installation guide +`here `_ to get Bash on +Ubuntu on Windows set up. Once you are within bash, obtain the necessary :ref:`prerequisites ` via ``apt``. Finally, follow the :ref:`instructions for compiling on linux `. @@ -460,18 +522,12 @@ distribution/repository, run: .. code-block:: sh - pip install . + python -m pip install . pip will first check that all :ref:`required third-party packages ` have been installed, and if they are not present, they will be installed by downloading the appropriate packages from the Python -Package Index (`PyPI `_). However, do note that since pip -runs the ``setup.py`` script which requires NumPy, you will have to first -install NumPy: - -.. code-block:: sh - - pip install numpy +Package Index (`PyPI `_). Installing in "Development" Mode -------------------------------- @@ -484,7 +540,7 @@ to install the Python package in :ref:`"editable" mode `. Prerequisites ------------- -The Python API works with Python 3.5+. In addition to Python itself, the API +The Python API works with Python 3.8+. In addition to Python itself, the API relies on a number of third-party packages. All prerequisites can be installed using Conda_ (recommended), pip_, or through the package manager in most Linux distributions. @@ -501,8 +557,9 @@ distributions. are used for several optional features in the API. `pandas `_ - Pandas is used to generate tally DataFrames as demonstrated in - an `example notebook <../examples/pandas-dataframes.ipynb>`_. + Pandas is used to generate tally DataFrames as demonstrated in an `example + notebook + `_. `h5py `_ h5py provides Python bindings to the HDF5 library. Since OpenMC outputs @@ -517,8 +574,7 @@ distributions. Uncertainties are used for decay data in the :mod:`openmc.data` module. `lxml `_ - lxml is used for the :ref:`scripts_validate` script and various other - parts of the Python API. + lxml is used for various parts of the Python API. .. admonition:: Optional :class: note @@ -552,41 +608,15 @@ for OpenMC. Thus, the install process would proceed as follows: make install cd .. - MPICC= pip install mpi4py - HDF5_DIR= pip install --no-binary=h5py h5py + MPICC= python -m pip install mpi4py + HDF5_DIR= python -m pip install --no-binary=h5py h5py If you are using parallel HDF5, you'll also need to make sure the right MPI wrapper is used when installing h5py: .. code-block:: sh - CC= HDF5_MPI=ON HDF5_DIR= pip install --no-binary=h5py h5py - -.. _usersguide_nxml: - ------------------------------------------------------ -Configuring Input Validation with GNU Emacs nXML mode ------------------------------------------------------ - -The `GNU Emacs`_ text editor has a built-in mode that extends functionality for -editing XML files. One of the features in nXML mode is the ability to perform -real-time `validation`_ of XML files against a `RELAX NG`_ schema. The OpenMC -source contains RELAX NG schemas for each type of user input file. In order for -nXML mode to know about these schemas, you need to tell emacs where to find a -"locating files" description. Adding the following lines to your ``~/.emacs`` -file will enable real-time validation of XML input files: - -.. code-block:: common-lisp - - (require 'rng-loc) - (add-to-list 'rng-schema-locating-files "~/openmc/schemas.xml") - -Make sure to replace the last string on the second line with the path to the -schemas.xml file in your own OpenMC source directory. + CC= HDF5_MPI=ON HDF5_DIR= python -m pip install --no-binary=h5py h5py -.. _GNU Emacs: http://www.gnu.org/software/emacs/ -.. _validation: https://en.wikipedia.org/wiki/XML_validation -.. _RELAX NG: https://relaxng.org/ -.. _ctest: https://cmake.org/cmake/help/latest/manual/ctest.1.html .. _Conda: https://conda.io/en/latest/ .. _pip: https://pip.pypa.io/en/stable/ diff --git a/docs/source/usersguide/materials.rst b/docs/source/usersguide/materials.rst index 8b43f1a2ac6..83af5580574 100644 --- a/docs/source/usersguide/materials.rst +++ b/docs/source/usersguide/materials.rst @@ -101,6 +101,42 @@ you would need to add hydrogen and oxygen to a material and then assign the .. _usersguide_naming: +------------------------- +Adding NCrystal materials +------------------------- + +Additional support for thermal scattering can be added by using NCrystal_. The +:meth:`Material.from_ncrystal` class method generates a :class:`openmc.Material` +object from an `NCrystal configuration string +`_. +Temperature, material composition, and density are passed from the configuration +string and the `NCMAT file +`_ that define the +material, e.g.:: + + mat = openmc.Material.from_ncrystal('Al_sg225.ncmat;temp=300K') + +defines a material containing polycrystalline alumnium, + +:: + + mat = openmc.Material.from_ncrystal("""Ge_sg227.ncmat;dcutoff=0.5;mos=40arcsec; + dir1=@crys_hkl:5,1,1@lab:0,0,1; + dir2=@crys_hkl:0,-1,1@lab:0,1,0""") + +defines an oriented germanium single crystal with 40 arcsec mosaicity. + +NCrystal only handles low energy neutron interactions. Other interactions are +provided by standard ACE files. NCrystal_ comes with a `predefined library +`_ but more materials can +be added by creating NCMAT files or on-the-fly in the configuration string. + +.. warning:: Currently, NCrystal_ materials cannot be modified after they are created. + Density, temperature and composition should be defined in the + configuration string or the NCMAT file. + +.. _NCrystal: https://github.com/mctools/ncrystal + ------------------ Naming Conventions ------------------ @@ -222,3 +258,4 @@ been generated, you can tell OpenMC to use this file either by setting materials.cross_sections = '/path/to/cross_sections.xml' .. _MCNP: https://mcnp.lanl.gov/ + diff --git a/docs/source/usersguide/plots.rst b/docs/source/usersguide/plots.rst index 109a8b54922..2d588519c55 100644 --- a/docs/source/usersguide/plots.rst +++ b/docs/source/usersguide/plots.rst @@ -80,26 +80,13 @@ assign them to a :class:`openmc.Plots` collection and export it to XML:: plots += [plot2, plot3] plots.export_to_xml() -To actually generate the plots, run the :func:`openmc.plot_geometry` -function. Alternatively, run the :ref:`scripts_openmc` executable with the -``--plot`` command-line flag. When that has finished, you will have one or more -``.ppm`` files, i.e., `portable pixmap -`_ files. On some Linux -distributions, these ``.ppm`` files are natively viewable. If you find that -you're unable to open them on your system (or you don't like the fact that they -are not compressed), you may want to consider converting them to another format. -This is easily accomplished with the ``convert`` command available on most Linux -distributions as part of the `ImageMagick -`_ package. (On Debian -derivatives: ``sudo apt install imagemagick``). Images are then converted like: - -.. code-block:: sh - - convert myplot.ppm myplot.png - -Alternatively, if you're working within a `Jupyter `_ -Notebook or QtConsole, you can use the :func:`openmc.plot_inline` to run OpenMC -in plotting mode and display the resulting plot within the notebook. +To actually generate the plots, run the :func:`openmc.plot_geometry` function. +Alternatively, run the :ref:`scripts_openmc` executable with the ``--plot`` +command-line flag. When that has finished, you will have one or more ``.png`` +files. Alternatively, if you're working within a `Jupyter +`_ Notebook or QtConsole, you can use the +:func:`openmc.plot_inline` to run OpenMC in plotting mode and display the +resulting plot within the notebook. .. _usersguide_voxel: @@ -134,3 +121,91 @@ will depend on the 3D viewer, but should be straightforward. program (Visit, ParaView, etc.) if the number of voxels is large (>10 million or so). Thus if you want an accurate picture that renders smoothly, consider using only one voxel in a certain direction. + +---------------- +Projection Plots +---------------- + +.. only:: html + + .. image:: ../_images/hexlat_anim.gif + :width: 200px + +The :class:`openmc.ProjectionPlot` class presents an alternative method of +producing 3D visualizations of OpenMC geometries. It was developed to overcome +the primary shortcoming of voxel plots, that an enormous number of voxels must +be employed to capture detailed geometric features. Projection plots perform +volume rendering on material or cell volumes, with colors specified in the same +manner as slice plots. This is done using the native ray tracing capabilities +within OpenMC, so any geometry in which particles successfully run without +overlaps or leaks will work with projection plots. + +One drawback of projection plots is that particle tracks cannot be overlaid on +them at present. Moreover, checking for overlap regions is not currently +possible with projection plots. The image heading this section can be created by +adding the following code to the hexagonal lattice example packaged with OpenMC, +before exporting to plots.xml. + +:: + + r = 5 + import numpy as np + for i in range(100): + phi = 2 * np.pi * i/100 + thisp = openmc.ProjectionPlot(plot_id = 4 + i) + thisp.filename = 'frame%s'%(str(i).zfill(3)) + thisp.look_at = [0, 0, 0] + thisp.camera_position = [r * np.cos(phi), r * np.sin(phi), 6 * np.sin(phi)] + thisp.pixels = [200, 200] + thisp.color_by = 'material' + thisp.colorize(geometry) + thisp.set_transparent(geometry) + thisp.xs[fuel] = 1.0 + thisp.xs[iron] = 1.0 + thisp.wireframe_domains = [fuel] + thisp.wireframe_thickness = 2 + + plot_file.append(thisp) + +This generates a sequence of png files which can be joined to form a gif. Each +image specifies a different camera position using some simple periodic functions +to create a perfectly looped gif. :attr:`ProjectionPlot.look_at` defines where +the camera's centerline should point at. :attr:`ProjectionPlot.camera_position` +similarly defines where the camera is situated in the universe level we seek to +plot. The other settings resemble those employed by :class:`openmc.Plot`, with +the exception of the :class:`ProjectionPlot.set_transparent` method and +:attr:`ProjectionPlot.xs` dictionary. These are used to control volume rendering +of material volumes. "xs" here stands for cross section, and it defines material +opacities in units of inverse centimeters. Setting this value to a large number +would make a material or cell opaque, and setting it to zero makes a material +transparent. Thus, the :class:`ProjectionPlot.set_transparent` can be used to +make all materials in the geometry transparent. From there, individual material +or cell opacities can be tuned to produce the desired result. + +Two camera projections are available when using these plots, perspective and +orthographic. The default, perspective projection, is a cone of rays passing +through each pixel which radiate from the camera position and span the field of +view in the x and y positions. The horizontal field of view can be set with the +:attr: `ProjectionPlot.horizontal_field_of_view` attribute, which is to be +specified in units of degrees. The field of view only influences behavior in +perspective projection mode. + +In the orthographic projection, rays follow the same angle but originate from +different points. The horizontal width of this plane of ray starting points may +be set with the :attr: `ProjectionPlot.orthographic_width` element. If this +element is nonzero, the orthographic projection is employed. Left to its default +value of zero, the perspective projection is employed. + +Lastly, projection plots come packaged with wireframe generation that can target +either all surface/cell/material boundaries in the geometry, or only wireframing +around specific regions. In the above example, we have set only the fuel region +from the hexagonal lattice example to have a wireframe drawn around it. This is +accomplished by setting the :attr: `ProjectionPlot.wireframe_domains`, which may +be set to either material IDs or cell IDs. The +:attr:`ProjectionPlot.wireframe_thickness` attribute sets the wireframe +thickness in units of pixels. + +.. note:: When setting specific material or cell regions to have wireframes + drawn around them, the plot must be colored by materials if wireframing + around specific materials and similarly colored by cell instance if + wireframing around specific cells. diff --git a/docs/source/usersguide/processing.rst b/docs/source/usersguide/processing.rst index e61ba33bf15..3103b7b7cf4 100644 --- a/docs/source/usersguide/processing.rst +++ b/docs/source/usersguide/processing.rst @@ -34,30 +34,20 @@ as requested; it is used in many of the provided plotting utilities, OpenMC's regression test suite, and can be used in user-created scripts to carry out manipulations of the data. -An `example notebook <../examples/post-processing.ipynb>`_ demonstrates how to -extract data from a statepoint using the Python API. +An `example notebook`_ demonstrates how to extract data from a statepoint using +the Python API. Plotting in 2D -------------- -The `notebook example <../examples/post-processing.ipynb>`_ also demonstrates -how to plot a structured mesh tally in two dimensions using the Python API. One -can also use the :ref:`scripts_plot` script which provides an interactive GUI to -explore and plot structured mesh tallies for any scores and filter bins. +The `example notebook`_ also demonstrates how to plot a structured mesh tally in +two dimensions using the Python API. One can also use the :ref:`scripts_plot` +script which provides an interactive GUI to explore and plot structured mesh +tallies for any scores and filter bins. .. image:: ../_images/plotmeshtally.png :width: 400px -Getting Data into MATLAB ------------------------- - -There is currently no front-end utility to dump tally data to MATLAB files, but -the process is straightforward. First extract the data using the Python API via -``openmc.statepoint`` and then use the `Scipy MATLAB IO routines -`_ to save to a MAT -file. Note that all arrays that are accessible in a statepoint are already in -NumPy arrays that can be reshaped and dumped to MATLAB in one step. - .. _usersguide_track: ---------------------------- @@ -101,5 +91,6 @@ For eigenvalue problems, OpenMC will store information on the fission source sites in the statepoint file by default. For each source site, the weight, position, sampled direction, and sampled energy are stored. To extract this data from a statepoint file, the ``openmc.statepoint`` module can be used. An -`example notebook <../examples/post-processing.ipynb>`_ demontrates how to -analyze and plot source information. +`example notebook`_ demontrates how to analyze and plot source information. + +.. _example notebook: https://nbviewer.jupyter.org/github/openmc-dev/openmc-notebooks/blob/main/post-processing.ipynb diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst new file mode 100644 index 00000000000..dad86c826e0 --- /dev/null +++ b/docs/source/usersguide/random_ray.rst @@ -0,0 +1,480 @@ +.. _random_ray: + +================= +Random Ray Solver +================= + +In general, the random ray solver mode uses most of the same settings and +:ref:`run strategies ` as the standard Monte Carlo solver +mode. For instance, random ray solves are also split up into :ref:`inactive and +active batches `. However, there are a couple of settings +that are unique to the random ray solver and a few areas that the random ray +run strategy differs, both of which will be described in this section. + +------------------------ +Enabling Random Ray Mode +------------------------ + +To utilize the random ray solver, the :attr:`~openmc.Settings.random_ray` +dictionary must be present in the :class:`openmc.Settings` Python class. There +are a number of additional settings that must be specified within this +dictionary that will be discussed below. Additionally, the "multi-group" energy +mode must be specified. + +------- +Batches +------- + +In Monte Carlo simulations, inactive batches are used to let the fission source +develop into a stationary distribution before active batches are performed that +actually accumulate statistics. While this is true of random ray as well, in the +random ray mode the inactive batches are also used to let the scattering source +develop. Monte Carlo fully represents the scattering source within each +iteration (by its nature of fully simulating particles from birth to death +through any number of physical scattering events), whereas the scattering source +in random ray can only represent as many scattering events as batches have been +completed. For example, by iteration 10 in random ray, the scattering source +only captures the behavior of neutrons through their 10th scattering event. +Thus, while inactive batches are only required in an eigenvalue solve in Monte +Carlo, **inactive batches are required for both eigenvalue and fixed source +solves in random ray mode** due to this additional need to converge the +scattering source. + +The additional burden of converging the scattering source generally results in a +higher requirement for the number of inactive batches---often by an order of +magnitude or more. For instance, it may be reasonable to only use 50 inactive +batches for a light water reactor simulation with Monte Carlo, but random ray +might require 500 or more inactive batches. Similar to Monte Carlo, +:ref:`Shannon entropy ` can be used to gauge whether the +combined scattering and fission source has fully developed. + +Similar to Monte Carlo, active batches are used in the random ray solver mode to +accumulate and converge statistics on unknown quantities (i.e., the random ray +sources, scalar fluxes, as well as any user-specified tallies). + +The batch parameters are set in the same manner as with the regular Monte Carlo +solver:: + + settings = openmc.Settings() + settings.energy_mode = "multi-group" + settings.batches = 1200 + settings.inactive = 600 + +------------------------------- +Inactive Ray Length (Dead Zone) +------------------------------- + +A major issue with random ray is that the starting angular flux distribution for +each sampled ray is unknown. Thus, an on-the-fly method is used to build a high +quality approximation of the angular flux of the ray each iteration. This is +accomplished by running the ray through an inactive length (also known as a dead +zone length), where the ray is moved through the geometry and its angular flux +is solved for via the normal :ref:`MOC ` equation, but +no information is written back to the system. Thus, the ray is run in a "read +only" mode for the set inactive length. This parameter can be adjusted, in units +of cm, as:: + + settings.random_ray['distance_inactive'] = 40.0 + +After several mean free paths are traversed, the angular flux spectrum of the +ray becomes dominated by the in-scattering and fission source components that it +picked up when travelling through the geometry, while its original (incorrect) +starting angular flux is attenuated toward zero. Thus, longer selections of +inactive ray length will asymptotically approach the true angular flux. + +In practice, 10 mean free paths are sufficient (with light water reactors often +requiring only about 10--50 cm of inactive ray length for the error to become +undetectable). However, we caution that certain models with large quantities of +void regions (even if just limited to a few streaming channels) may require +significantly longer inactive ray lengths to ensure that the angular flux is +accurate before the conclusion of the inactive ray length. Additionally, +problems where a sensitive estimate of the uncollided flux is required (e.g., +the detector response to fast neutrons is required, and the detected is located +far away from the source in a moderator region) may require the user to specify +an inactive length that is derived from the pyhsical geometry of the simulation +problem rather than its material properties. For instance, consider a detector +placed 30 cm outside of a reactor core, with a moderator region separating the +detector from the core. In this case, rays sampled in the moderator region and +heading toward the detector will begin life with a highly scattered thermal +spectrum and will have an inaccurate fast spectrum. If the dead zone length is +only 20 cm, we might imagine such rays writing to the detector tally within +their active lengths, despite their innaccurate estimate of the uncollided fast +angular flux. Thus, an inactive length of 100--200 cm would ensure that any such +rays would still be within their inactive regions, and only rays that have +actually traversed through the core (and thus have an accurate representation of +the core's emitted fast flux) will score to the detector region while in their +active phase. + + +------------------------------------ +Active Ray Length and Number of Rays +------------------------------------ + +Once the inactive length of the ray has completed, the active region of the ray +begins. The ray is now run in regular mode, where changes in angular flux as it +traverses through each flat source region are written back to the system, so as +to contribute to the estimate for the iteration scalar flux (which is used to +compute the source for the next iteration). The active ray length can be +adjusted, in units of [cm], as:: + + settings.random_ray['distance_active'] = 400.0 + +Assuming that a sufficient inactive ray length is used so that the starting +angular flux is highly accurate, any selection of active length greater than +zero is theoretically acceptable. However, in order to adequately sample the +full integration domain, a selection of a very short track length would require +a very high number of rays to be selected. Due to the static costs per ray of +computing the starting angular flux in the dead zone, typically very short ray +lengths are undesireable. Thus, to amortize the per-ray cost of the inactive +region of the ray, it is desirable to select a very long inactive ray length. +For example, if the inactive length is set to 20 cm, a 200 cm active ray length +ensures that only about 10% of the overall simulation runtime is spent in the +inactive ray phase integration, making the dead zone a relatively inexpensive +way of estimating the angular flux. + +Thus, to fully amortize the cost of the dead zone integration, one might ask why +not simply run a single ray per iteration with an extremely long active length? +While this is also theoretically possible, this results in two issues. The first +problem is that each ray only represents a single angular sample. As we want to +sample the angular phase space of the simulation with similar fidelity to the +spatial phase space, we naturally want a lot of angles. This means in practice, +we want to balance the need to amortize the cost of the inactive region of the +ray with the need to sample lots of angles. The second problem is that +parallelism in OpenMC is expressed in terms of rays, with each being processed +by an independent MPI rank and/or OpenMP thread, thus we want to ensure each +thread has many rays to process. + +In practical terms, the best strategy is typically to set an active ray length +that is about 10 times that of the inactive ray length. This is often the right +balance between ensuring not too much time is spent in the dead zone, while +still adequately sampling the angular phase space. However, as discussed in the +previous section, some types of simulation may demand that additional thought be +applied to this parameter. For instance, in the same example where we have a +detector region far outside a reactor core, we want to make sure that there is +enough active ray length that rays exiting the core can reach the detector +region. For example, if the detector were to be 30 cm outside of the core, then +we would need to ensure that at least a few hundred cm of active length were +used so as to ensure even rays with indirect angles will be able to reach the +target region. + +The number of rays each iteration can be set by reusing the normal Monte Carlo +particle count selection parameter, as:: + + settings.particles = 2000 + +----------- +Ray Density +----------- + +In the preceding sections, it was argued that for most use cases, the inactive +length for a ray can be determined by taking a multiple of the mean free path +for the limiting energy group. The active ray length could then be set by taking +a multiple of the inactive length. With these parameters set, how many rays per +iteration should be run? + +There are three basic settings that control the density of the stochastic +quadrature being used to integrate the domain each iteration. These three +variables are: + +- The number of rays (in OpenMC settings parlance, "particles") +- The inactive distance per ray +- The active distance per ray + +While the inactive and active ray lengths can usually be chosen by simply +examining the geometry, tallies, and cross section data, one has much more +flexibility in the choice of the number of rays to run. Consider a few +scenarios: + +- If a choice of zero rays is made, then no information is gained by the system + after each batch. +- If a choice of rays close to zero is made, then some information is gained + after each batch, but many source regions may not have been visited that + iteration, which is not ideal numerically and can result in instability. + Empirically, we have found that the simulation can remain stable and produce + accurate results even when on average 20% or more of the cells have zero rays + passing through them each iteration. However, besides the cost of transporting + rays, a new neutron source must be computed based on the scalar flux at each + iteration. This cost is dictated only by the number of source regions and + energy groups---it is independent of the number of rays. Thus, in practical + terms, if too few rays are run, then the simulation runtime becomes dominated + by the fixed cost of source updates, making it inefficient overall given that + a huge number of active batches will likely be required to converge statistics + to acceptable levels. Additionally, if many cells are missed each iteration, + then the fission and scattering sources may not develop very quickly, + resulting in a need for far more inactive batches than might otherwise be + required. +- If a choice of running a very large number of rays is made such that you + guarantee that all cells are hit each iteration, this avoids any issues with + numerical instability. As even more rays are run, this reduces the number of + active batches that must be used to converge statistics and therefore + minimizes the fixed per-iteration source update costs. While this seems + advantageous, it has the same practical downside as with Monte Carlo---namely, + that the inactive batches tend to be overly well integrated, resulting in a + lot of wasted time. This issue is actually much more serious than in Monte + Carlo (where typically only tens of inactive batches are needed), as random + ray often requires hundreds or even thousands of inactive batches. Thus, + minimizing the cost of the source updates in the active phase needs to be + balanced against the increased cost of the inactive phase of the simulation. +- If a choice of rays is made such that relatively few (e.g., around 0.1%) of + cells are missed each iteration, the cost of the inactive batches of the + simulation is minimized. In this "goldilocks" regime, there is very little + chance of numerical instability, and enough information is gained by each cell + to progress the fission and scattering sources forward at their maximum rate. + However, the inactive batches can proceed with minimal cost. While this will + result in the active phase of the simulation requiring more batches (and + correspondingly higher source update costs), the added cost is typically far + less than the savings by making the inactive phase much cheaper. + +To help you set this parameter, OpenMC will report the average flat source +region miss rate at the end of the simulation. Additionally, OpenMC will alert +you if very high miss rates are detected, indicating that more rays and/or a +longer active ray length might improve numerical performance. Thus, a "guess and +check" approach to this parameter is recommended, where a very low guess is +made, a few iterations are performed, and then the simulation is restarted with +a larger value until the "low ray density" messages go away. + +.. note:: + In summary, the user should select an inactive length corresponding to many + times the mean free path of a particle, generally O(10--100) cm, to ensure accuracy of + the starting angular flux. The active length should be 10× the inactive + length to amortize its cost. The number of rays should be enough so that + nearly all :ref:`FSRs ` are hit at least once each power iteration (the hit fraction + is reported by OpenMC for empirical user adjustment). + +.. warning:: + For simulations where long range uncollided flux estimates need to be + accurately resolved (e.g., shielding, detector response, and problems with + significant void areas), make sure that selections for inactive and active + ray lengths are sufficiently long to allow for transport to occur between + source and target regions of interest. + +---------- +Ray Source +---------- + +Random ray requires that the ray source be uniform in space and isotropic in +angle. To facilitate sampling, the user must specify a single random ray source +for sampling rays in both eigenvalue and fixed source solver modes. The random +ray integration source should be of type :class:`openmc.IndependentSource`, and +is specified as part of the :attr:`openmc.Settings.random_ray` dictionary. Note +that the source must not be limited to only fissionable regions. Additionally, +the source box must cover the entire simulation domain. In the case of a +simulation domain that is not box shaped, a box source should still be used to +bound the domain but with the source limited to rejection sampling the actual +simulation universe (which can be specified via the ``domains`` field of the +:class:`openmc.IndependentSource` Python class). Similar to Monte Carlo sources, +for two-dimensional problems (e.g., a 2D pincell) it is desirable to make the +source bounded near the origin of the infinite dimension. An example of an +acceptable ray source for a two-dimensional 2x2 lattice would look like: + +:: + + pitch = 1.26 + lower_left = (-pitch, -pitch, -pitch) + upper_right = ( pitch, pitch, pitch) + uniform_dist = openmc.stats.Box(lower_left, upper_right) + settings.random_ray['ray_source'] = openmc.IndependentSource(space=uniform_dist) + +.. note:: + The random ray source is not related to the underlying particle flux or + source distribution of the simulation problem. It is akin to the selection + of an integration quadrature. Thus, in fixed source mode, the ray source + still needs to be provided and still needs to be uniform in space and angle + throughout the simulation domain. In fixed source mode, the user will + provide physical particle fixed sources in addition to the random ray + source. + +.. _subdivision_fsr: + +---------------------------------- +Subdivision of Flat Source Regions +---------------------------------- + +While the scattering and fission sources in Monte Carlo +are treated continuously, they are assumed to be invariant (flat) within a +MOC or random ray flat source region (FSR). This introduces bias into the +simulation, which can be remedied by reducing the physical size of the FSR +to dimensions below that of typical mean free paths of particles. + +In OpenMC, this subdivision currently must be done manually. The level of +subdivision needed will be dependent on the fidelity the user requires. For +typical light water reactor analysis, consider the following example subdivision +of a two-dimensional 2x2 reflective pincell lattice: + +.. figure:: ../_images/2x2_materials.jpeg + :class: with-border + :width: 400 + + Material definition for an asymmetrical 2x2 lattice (1.26 cm pitch) + +.. figure:: ../_images/2x2_fsrs.jpeg + :class: with-border + :width: 400 + + FSR decomposition for an asymmetrical 2x2 lattice (1.26 cm pitch) + +In the future, automated subdivision of FSRs via mesh overlay may be supported. + +------- +Tallies +------- + +Most tallies, filters, and scores that you would expect to work with a +multigroup solver like random ray are supported. For example, you can define 3D +mesh tallies with energy filters and flux, fission, and nu-fission scores, etc. +There are some restrictions though. For starters, it is assumed that all filter +mesh boundaries will conform to physical surface boundaries (or lattice +boundaries) in the simulation geometry. It is acceptable for multiple cells +(FSRs) to be contained within a mesh element (e.g., pincell-level or +assembly-level tallies should work), but it is currently left as undefined +behavior if a single simulation cell is contained in multiple mesh elements. + +Supported scores: + - flux + - total + - fission + - nu-fission + - events + +Supported Estimators: + - tracklength + +Supported Filters: + - cell + - cell instance + - distribcell + - energy + - material + - mesh + - universe + +Note that there is no difference between the analog, tracklength, and collision +estimators in random ray mode as individual particles are not being simulated. +Tracklength-style tally estimation is inherent to the random ray method. + +-------- +Plotting +-------- + +Visualization of geometry is handled in the same way as normal with OpenMC (see +:ref:`plotting guide ` for more details). That is, ``openmc +--plot`` is handled without any modifications, as the random ray solver uses the +same geometry definition as in Monte Carlo. + +In addition to OpenMC's standard geometry plotting mode, the random ray solver +also features an additional method of data visualization. If a ``plots.xml`` +file is present, any voxel plots that are defined will be output at the end of a +random ray simulation. Rather than being stored in HDF5 file format, the random +ray plotting will generate ``.vtk`` files that can be directly read and plotted +with `Paraview `_. + +In fixed source Monte Carlo (MC) simulations, by default the only thing global +tally provided is the leakage fraction. In a k-eigenvalue MC simulation, by +default global tallies are collected for the eigenvalue and leakage fraction. +Spatial flux information must be manually requested, and often fine-grained +spatial meshes are considered costly/unnecessary, so it is impractical in MC +mode to plot spatial flux or power info by default. Conversely, in random ray, +the solver functions by estimating the multigroup source and flux spectrums in +every fine-grained FSR each iteration. Thus, for random ray, in both fixed +source and eigenvalue simulations, the simulation always finishes with a well +converged flux estimate for all areas. As such, it is much more common in random +ray, MOC, and other deterministic codes to provide spatial flux information by +default. In the future, all FSR data will be made available in the statepoint +file, which facilitates plotting and manipulation through the Python API; at +present, statepoint support is not available. + +Only voxel plots will be used to generate output; other plot types present in +the ``plots.xml`` file will be ignored. The following fields will be written to +the VTK structured grid file: + + - material + - FSR index + - flux spectrum (for each energy group) + - total fission source (integrated across all energy groups) + +------------------------------------------ +Inputting Multigroup Cross Sections (MGXS) +------------------------------------------ + +Multigroup cross sections for use with OpenMC's random ray solver are input the +same way as with OpenMC's traditional multigroup Monte Carlo mode. There is more +information on generating multigroup cross sections via OpenMC in the +:ref:`multigroup materials ` user guide. You may also wish to +use an existing multigroup library. An example of using OpenMC's Python +interface to generate a correctly formatted ``mgxs.h5`` input file is given +in the `OpenMC Jupyter notebook collection +`_. + +.. note:: + Currently only isotropic and isothermal multigroup cross sections are + supported in random ray mode. To represent multiple material temperatures, + separate materials can be defined each with a separate multigroup dataset + corresponding to a given temperature. + +--------------------------------------- +Putting it All Together: Example Inputs +--------------------------------------- + +An example of a settings definition for random ray is given below:: + + # Geometry and MGXS material definition of 2x2 lattice (not shown) + pitch = 1.26 + group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] + ... + + # Instantiate a settings object for a random ray solve + settings = openmc.Settings() + settings.energy_mode = "multi-group" + settings.batches = 1200 + settings.inactive = 600 + settings.particles = 2000 + + settings.random_ray['distance_inactive'] = 40.0 + settings.random_ray['distance_active'] = 400.0 + + # Create an initial uniform spatial source distribution for sampling rays + lower_left = (-pitch, -pitch, -pitch) + upper_right = ( pitch, pitch, pitch) + uniform_dist = openmc.stats.Box(lower_left, upper_right) + settings.random_ray['ray_source'] = openmc.IndependentSource(space=uniform_dist) + + settings.export_to_xml() + + # Define tallies + + # Create a mesh filter + mesh = openmc.RegularMesh() + mesh.dimension = (2, 2) + mesh.lower_left = (-pitch/2, -pitch/2) + mesh.upper_right = (pitch/2, pitch/2) + mesh_filter = openmc.MeshFilter(mesh) + + # Create a multigroup energy filter + energy_filter = openmc.EnergyFilter(group_edges) + + # Create tally using our two filters and add scores + tally = openmc.Tally() + tally.filters = [mesh_filter, energy_filter] + tally.scores = ['flux', 'fission', 'nu-fission'] + + # Instantiate a Tallies collection and export to XML + tallies = openmc.Tallies([tally]) + tallies.export_to_xml() + + # Create voxel plot + plot = openmc.Plot() + plot.origin = [0, 0, 0] + plot.width = [2*pitch, 2*pitch, 1] + plot.pixels = [1000, 1000, 1] + plot.type = 'voxel' + + # Instantiate a Plots collection and export to XML + plots = openmc.Plots([plot]) + plots.export_to_xml() + +All other inputs (e.g., geometry, materials) will be unchanged from a typical +Monte Carlo run (see the :ref:`geometry ` and +:ref:`multigroup materials ` user guides for more information). + +There is also a complete example of a pincell available in the +``openmc/examples/pincell_random_ray`` folder. diff --git a/docs/source/usersguide/scripts.rst b/docs/source/usersguide/scripts.rst index 963e91cf2d8..78ee6f77581 100644 --- a/docs/source/usersguide/scripts.rst +++ b/docs/source/usersguide/scripts.rst @@ -47,7 +47,7 @@ flags: -r, --restart file Restart a previous run from a state point or a particle restart file -s, --threads N Run with *N* OpenMP threads --t, --track Write tracks for all particles +-t, --track Write tracks for all particles (up to max_tracks) -v, --version Show version information -h, --help Show help message @@ -112,6 +112,19 @@ otherwise. tallies. The path to the statepoint file can be provided as an optional arugment (if omitted, a file dialog will be presented). +.. _scripts_track_combine: + +------------------------ +``openmc-track-combine`` +------------------------ + +This script combines multiple HDF5 :ref:`particle track files +` into a single HDF5 particle track file. The filenames of the +particle track files should be given as posititional arguments. The output +filename can also be changed with the ``-o`` flag: + +-o OUT, --out OUT Output HDF5 particle track file + .. _scripts_track: ----------------------- @@ -144,9 +157,9 @@ geometry.xml added. Any 'surfaces' attributes/elements on a cell will be renamed 'region'. materials.xml - Nuclide names will be changed from ACE aliases (e.g., Am-242m) to HDF5/GND + Nuclide names will be changed from ACE aliases (e.g., Am-242m) to HDF5/GNDS names (e.g., Am242_m1). Thermal scattering table names will be changed from - ACE aliases (e.g., HH2O) to HDF5/GND names (e.g., c_H_in_H2O). + ACE aliases (e.g., HH2O) to HDF5/GNDS names (e.g., c_H_in_H2O). ---------------------- ``openmc-update-mgxs`` @@ -158,34 +171,6 @@ the latest HDF5-based format. -i IN, --input IN Input XML file -o OUT, --output OUT Output file in HDF5 format -.. _scripts_validate: - ------------------------ -``openmc-validate-xml`` ------------------------ - -Input files can be checked before executing OpenMC using the -``openmc-validate-xml`` script which is installed alongside the Python API. Two -command line arguments can be set when running ``openmc-validate-xml``: - --i, --input-path Location of OpenMC input files. --r, --relaxng-path Location of OpenMC RelaxNG files - -If the RelaxNG path is not set, the script will search for these files because -it expects that the user is either running the script located in the install -directory ``bin`` folder or in ``src/utils``. Once executed, it will match -OpenMC XML files with their RelaxNG schema and check if they are valid. Below -is a table of the messages that will be printed after each file is checked. - -======================== =================================== -Message Description -======================== =================================== -[XML ERROR] Cannot parse XML file. -[NO RELAXNG FOUND] No RelaxNG file found for XML file. -[NOT VALID] XML file does not match RelaxNG. -[VALID] XML file matches RelaxNG. -======================== =================================== - .. _scripts_voxel: --------------------------- diff --git a/docs/source/usersguide/settings.rst b/docs/source/usersguide/settings.rst index 95b7fdf453c..eb02f654c30 100644 --- a/docs/source/usersguide/settings.rst +++ b/docs/source/usersguide/settings.rst @@ -169,15 +169,19 @@ External Source Distributions External source distributions can be specified through the :attr:`Settings.source` attribute. If you have a single external source, you can -create an instance of :class:`openmc.Source` and use it to set the -:attr:`Settings.source` attribute. If you have multiple external sources with -varying source strengths, :attr:`Settings.source` should be set to a list of -:class:`openmc.Source` objects. - -The :class:`openmc.Source` class has three main attributes that one can set: -:attr:`Source.space`, which defines the spatial distribution, -:attr:`Source.angle`, which defines the angular distribution, and -:attr:`Source.energy`, which defines the energy distribution. +create an instance of any of the subclasses of :class:`openmc.SourceBase` +(:class:`openmc.IndependentSource`, :class:`openmc.FileSource`, +:class:`openmc.CompiledSource`) and use it to set the :attr:`Settings.source` +attribute. If you have multiple external sources with varying source strengths, +:attr:`Settings.source` should be set to a list of :class:`openmc.SourceBase` +objects. + +The :class:`openmc.IndependentSource` class is the primary class for defining +source distributions and has four main attributes that one can set: +:attr:`IndependentSource.space`, which defines the spatial distribution, +:attr:`IndependentSource.angle`, which defines the angular distribution, +:attr:`IndependentSource.energy`, which defines the energy distribution, and +:attr:`IndependentSource.time`, which defines the time distribution. The spatial distribution can be set equal to a sub-class of :class:`openmc.stats.Spatial`; common choices are :class:`openmc.stats.Point` or @@ -186,7 +190,9 @@ The spatial distribution can be set equal to a sub-class of :class:`openmc.stats.CartesianIndependent`. To independently specify distributions using spherical or cylindrical coordinates, you can use :class:`openmc.stats.SphericalIndependent` or -:class:`openmc.stats.CylindricalIndependent`, respectively. +:class:`openmc.stats.CylindricalIndependent`, respectively. Meshes can also be +used to represent spatial distributions with :class:`openmc.stats.MeshSpatial` +by specifying a mesh and source strengths for each mesh element. The angular distribution can be set equal to a sub-class of :class:`openmc.stats.UnitSphere` such as :class:`openmc.stats.Isotropic`, @@ -210,36 +216,45 @@ distribution. This could be a probability mass function specified, a Watt fission spectrum with :math:`a` = 0.988 MeV and :math:`b` = 2.249 MeV :sup:`-1` is used. +The time distribution can be set equal to any univariate probability +distribution. This could be a probability mass function +(:class:`openmc.stats.Discrete`), a uniform distribution +(:class:`openmc.stats.Uniform`), or a tabular distribution +(:class:`openmc.stats.Tabular`). By default, if no time distribution is +specified, particles are started at :math:`t=0`. + As an example, to create an isotropic, 10 MeV monoenergetic source uniformly -distributed over a cube centered at the origin with an edge length of 10 cm, one +distributed over a cube centered at the origin with an edge length of 10 cm, and +emitting a pulse of particles from 0 to 10 µs, one would run:: - source = openmc.Source() + source = openmc.IndependentSource() source.space = openmc.stats.Box((-5, -5, -5), (5, 5, 5)) source.angle = openmc.stats.Isotropic() source.energy = openmc.stats.Discrete([10.0e6], [1.0]) + source.time = openmc.stats.Uniform(0, 1e-6) settings.source = source -The :class:`openmc.Source` class also has a :attr:`Source.strength` attribute -that indicates the relative strength of a source distribution if multiple are -used. For example, to create two sources, one that should be sampled 70% of the -time and another that should be sampled 30% of the time:: +All subclasses of :class:`openmc.SourceBase` have a :attr:`SourceBase.strength` +attribute that indicates the relative strength of a source distribution if +multiple are used. For example, to create two sources, one that should be +sampled 70% of the time and another that should be sampled 30% of the time:: - src1 = openmc.Source() + src1 = openmc.IndependentSource() src1.strength = 0.7 ... - src2 = openmc.Source() + src2 = openmc.IndependentSource() src2.strength = 0.3 ... settings.source = [src1, src2] -Finally, the :attr:`Source.particle` attribute can be used to indicate the -source should be composed of particles other than neutrons. For example, the -following would generate a photon source:: +Finally, the :attr:`IndependentSource.particle` attribute can be used to +indicate the source should be composed of particles other than neutrons. For +example, the following would generate a photon source:: - source = openmc.Source() + source = openmc.IndependentSource() source.particle = 'photon' ... @@ -251,10 +266,10 @@ For a full list of all classes related to statistical distributions, see File-based Sources ------------------ -OpenMC can use a pregenerated HDF5 source file by specifying the ``filename`` -argument to :class:`openmc.Source`:: +OpenMC can use a pregenerated HDF5 source file through the +:class:`openmc.FileSource` class:: - settings.source = openmc.Source(filename='source.h5') + settings.source = openmc.FileSource('source.h5') Statepoint and source files are generated automatically when a simulation is run and can be used as the starting source in a new simulation. Alternatively, a @@ -274,10 +289,10 @@ attribute:: In this example, at most 10,000 source particles are stored when particles cross surfaces with IDs of 1, 2, or 3. -.. _custom_source: +.. _compiled_source: -Custom Sources --------------- +Compiled Sources +---------------- It is often the case that one may wish to simulate a complex source distribution that is not possible to represent with the classes described above. For these @@ -293,7 +308,7 @@ below. #include "openmc/source.h" #include "openmc/particle.h" - class CustomSource : public openmc::Source + class CompiledSource : public openmc::Source { openmc::SourceSite sample(uint64_t* seed) const { @@ -315,9 +330,9 @@ below. } }; - extern "C" std::unique_ptr openmc_create_source(std::string parameters) + extern "C" std::unique_ptr openmc_create_source(std::string parameters) { - return std::make_unique(); + return std::make_unique(); } The above source creates monodirectional 14.08 MeV neutrons that are distributed @@ -344,19 +359,21 @@ OpenMC shared library. This can be done by writing a CMakeLists.txt file: target_link_libraries(source OpenMC::libopenmc) After running ``cmake`` and ``make``, you will have a libsource.so (or .dylib) -file in your build directory. Setting the :attr:`openmc.Source.library` -attribute to the path of this shared library will indicate that it should be -used for sampling source particles at runtime. +file in your build directory. You can then use this as an external source during +an OpenMC run by passing the path of the shared library to the +:class:`openmc.CompiledSource` class, which is then set as the +:attr:`Settings.source` attribute:: + + settings.source = openmc.CompiledSource('libsource.so') -.. _parameterized_custom_source: +.. _parameterized_compiled_source: -Custom Parameterized Sources ----------------------------- +Parameterized Compiled Sources +------------------------------ -Some custom sources may have values (parameters) that can be changed between -runs. This is supported by using the ``openmc_create_source()`` function to -pass parameters defined in the :attr:`openmc.Source.parameters` attribute to -the source class when it is created: +Some compiled sources may have values (parameters) that can be changed between +runs. This is supported by using the ``openmc_create_source()`` function to pass +parameters to the source class when it is created: .. code-block:: c++ @@ -365,9 +382,9 @@ the source class when it is created: #include "openmc/source.h" #include "openmc/particle.h" - class CustomSource : public openmc::Source { + class CompiledSource : public openmc::Source { public: - CustomSource(double energy) : energy_{energy} { } + CompiledSource(double energy) : energy_{energy} { } // Samples from an instance of this class. openmc::SourceSite sample(uint64_t* seed) const @@ -392,13 +409,64 @@ the source class when it is created: double energy_; }; - extern "C" std::unique_ptr openmc_create_source(std::string parameter) { + extern "C" std::unique_ptr openmc_create_source(std::string parameter) { double energy = std::stod(parameter); - return std::make_unique(energy); + return std::make_unique(energy); } -As with the basic custom source functionality, the custom source library -location must be provided in the :attr:`openmc.Source.library` attribute. +When creating an instance of the :class:`openmc.CompiledSource` class, you will +need to pass both the path of the shared library as well as the parameters as a +string, which gets passed down to the ``openmc_create_source()`` function:: + + settings.source = openmc.CompiledSource('libsource.so', '3.5e6') + +.. _usersguide_source_constraints: + +Source Constraints +------------------ + +All source classes in OpenMC have the ability to apply a set of "constraints" +that limit which sampled source sites are actually used for transport. The most +common use case is to sample source sites over some simple spatial distribution +(e.g., uniform over a box) and then only accept those that appear in a given +cell or material. This can be done with a domain constraint, which can be +specified as follows:: + + source_cell = openmc.Cell(...) + ... + + spatial_dist = openmc.stats.Box((-10., -10., -10.), (10., 10., 10.)) + source = openmc.IndependentSource( + space=spatial_dist, + constraints={'domains': [source_cell]} + ) + +For k-eigenvalue problems, a convenient constraint is available that limits +source sites to those sampled in a fissionable material:: + + source = openmc.IndependentSource( + space=spatial_dist, constraints={'fissionable': True} + ) + +Constraints can also be placed on a range of energies or times:: + + # Only use source sites between 500 keV and 1 MeV and with times under 1 sec + source = openmc.FileSource( + 'source.h5', + constraints={'energy_bounds': [500.0e3, 1.0e6], 'time_bounds': [0.0, 1.0]} + ) + +Normally, when a source site is rejected, a new one will be resampled until one +is found that meets the constraints. However, the rejection strategy can be +changed so that a rejected site will just not be simulated by specifying:: + + source = openmc.IndependentSource( + space=spatial_dist, + constraints={'domains': [cell], 'rejection_strategy': 'kill'} + ) + +In this case, the actual number of particles simulated may be less than what you +specified in :attr:`Settings.particles`. .. _usersguide_entropy: @@ -464,7 +532,6 @@ selected:: Some features related to photon transport are not currently implemented, including: - * Tallying photon energy deposition. * Generating a photon source from a neutron calculation that can be used for a later fixed source photon calculation. * Photoneutron reactions. @@ -504,4 +571,142 @@ As an example, to write a statepoint file every five batches:: settings.batches = n settings.statepoint = {'batches': range(5, n + 5, 5)} -.. _NIST ESTAR database: https://physics.nist.gov/PhysRefData/Star/Text/ESTAR.html +Particle Track Files +-------------------- + +OpenMC can generate a particle track file that contains track information +(position, direction, energy, time, weight, cell ID, and material ID) for each +state along a particle's history. There are two ways to indicate which particles +and/or how many particles should have their tracks written. First, you can +identify specific source particles by their batch, generation, and particle ID +numbers:: + + settings.tracks = [ + (1, 1, 50), + (2, 1, 30), + (5, 1, 75) + ] + +In this example, track information would be written for the 50th particle in the +1st generation of batch 1, the 30th particle in the first generation of batch 2, +and the 75th particle in the 1st generation of batch 5. Unless you are using +more than one generation per batch (see :ref:`usersguide_particles`), the +generation number should be 1. Alternatively, you can run OpenMC in a mode where +track information is written for *all* particles, up to a user-specified limit:: + + openmc.run(tracks=True) + +In this case, you can control the maximum number of source particles for which +tracks will be written as follows:: + + settings.max_tracks = 1000 + +Particle track information is written to the ``tracks.h5`` file, which can be +analyzed using the :class:`~openmc.Tracks` class:: + + >>> tracks = openmc.Tracks('tracks.h5') + >>> tracks + [, + , + ] + +Each :class:`~openmc.Track` object stores a list of track information for every +primary/secondary particle. In the above example, the first source particle +produced 150 secondary particles for a total of 151 particles. Information for +each primary/secondary particle can be accessed using the +:attr:`~openmc.Track.particle_tracks` attribute:: + + >>> first_track = tracks[0] + >>> first_track.particle_tracks + [, + , + , + , + , + ... + , + ] + >>> photon = first_track.particle_tracks[1] + +The :class:`~openmc.ParticleTrack` class is a named tuple indicating the +particle type and then a NumPy array of the "states". The states array is a +compound type with a field for each physical quantity (position, direction, +energy, time, weight, cell ID, and material ID). For example, to get the +position for the above particle track:: + + >>> photon.states['r'] + array([(-11.92987939, -12.28467295, 0.67837495), + (-11.95213726, -12.2682 , 0.68783964), + (-12.2682 , -12.03428339, 0.82223855), + (-12.5913778 , -11.79510096, 0.95966298), + (-12.6622572 , -11.74264344, 0.98980293), + (-12.6907775 , -11.7215357 , 1.00193058)], + dtype=[('x', '>> tracks.filter(particle='photon') + [, + , + ] + +The :meth:`openmc.Tracks.filter` method returns a new :class:`~openmc.Tracks` +instance, whereas the :meth:`openmc.Track.filter` method returns a new +:class:`~openmc.Track` instance. + +.. note:: If you are using an MPI-enabled install of OpenMC and run a simulation + with more than one process, a separate track file will be written for + each MPI process with the filename ``tracks_p#.h5`` where # is the + rank of the corresponding process. Multiple track files can be + combined with the :ref:`scripts_track_combine` script: + + .. code-block:: sh + + openmc-track-combine tracks_p*.h5 --out tracks.h5 + +----------------------- +Restarting a Simulation +----------------------- + +OpenMC can be run in a mode where it reads in a statepoint file and continues a +simulation from the ending point of the statepoint file. A restart simulation +can be performed by passing the path to the statepoint file to the OpenMC +executable: + +.. code-block:: sh + + openmc -r statepoint.100.h5 + +From the Python API, the `restart_file` argument provides the same behavior: + +.. code-block:: python + + openmc.run(restart_file='statepoint.100.h5') + +or if using the :class:`~openmc.Model` class: + +.. code-block:: python + + model.run(restart_file='statepoint.100.h5') + +The restart simulation will execute until the number of batches specified in the +:class:`~openmc.Settings` object on a model (or in the :ref:`settings XML file +`) is satisfied. Note that if the number of batches in the +statepoint file is the same as that specified in the settings object (i.e., if +the inputs were not modified before the restart run), no particles will be +transported and OpenMC will exit immediately. + +.. note:: A statepoint file must match the input model to be successfully used in a restart simulation. diff --git a/docs/source/usersguide/tallies.rst b/docs/source/usersguide/tallies.rst index da2c5f26d54..02328af58ca 100644 --- a/docs/source/usersguide/tallies.rst +++ b/docs/source/usersguide/tallies.rst @@ -269,9 +269,8 @@ The following tables show all valid scores: |heating |Total nuclear heating in units of eV per source | | |particle. For neutrons, this corresponds to MT=301 | | |produced by NJOY's HEATR module while for photons, | - | |this is tallied from either direct photon energy | - | |deposition (analog estimator) or pre-generated | - | |photon heating number. See :ref:`methods_heating` | + | |this is tallied from direct photon energy | + | |deposition. See :ref:`methods_heating`. | +----------------------+---------------------------------------------------+ |heating-local |Total nuclear heating in units of eV per source | | |particle assuming energy from secondary photons is | @@ -318,6 +317,11 @@ The following tables show all valid scores: | |particle. This corresponds to MT=444 produced by | | |NJOY's HEATR module. | +----------------------+---------------------------------------------------+ + |pulse-height |The energy deposited by an entire photon's history | + | |(including its progeny). Units are eV per source | + | |particle. Note that this score can only be combined| + | |with a cell filter and an energy filter. | + +----------------------+---------------------------------------------------+ .. _usersguide_tally_normalization: @@ -333,7 +337,7 @@ it is usually straightforward to convert units if the source rate is known. For example, if the system being modeled includes a source that is emitting 10\ :sup:`4` neutrons per second, the tally results just need to be multipled by 10\ :sup:`4`. This can either be done manually or using the -:attr:`openmc.Source.strength` attribute. +:attr:`openmc.SourceBase.strength` attribute. For a :math:`k`\ -eigenvalue calculation, normalizing tally results is not as simple because the source rate is not actually known. Instead, we typically know diff --git a/docs/source/usersguide/troubleshoot.rst b/docs/source/usersguide/troubleshoot.rst index 7fb5723d932..f86ed727405 100644 --- a/docs/source/usersguide/troubleshoot.rst +++ b/docs/source/usersguide/troubleshoot.rst @@ -15,18 +15,20 @@ error you are receiving is among the following options. Problems with Simulations ------------------------- -Segmentation Fault -****************** +RuntimeError: OpenMC aborted unexpectedly. +****************************************** -A segmentation fault occurs when the program tries to access a variable in -memory that was outside the memory allocated for the program. The best way to -debug a segmentation fault is to re-compile OpenMC with debug options turned -on. Create a new build directory and type the following commands: +This error usually indicates that OpenMC experienced a segmentation fault. A +segmentation fault occurs when the program tries to access a variable in memory +that was outside the memory allocated for the program. The best way to debug a +segmentation fault is to :ref:`compile OpenMC from source ` with +debug options turned on. Create a new build directory and type the following +commands: .. code-block:: sh mkdir build-debug && cd build-debug - cmake -Ddebug=on /path/to/openmc + cmake -DCMAKE_BUILD_TYPE=Debug /path/to/openmc make Now when you re-run your problem, it should report exactly where the program @@ -34,6 +36,28 @@ failed. If after reading the debug output, you are still unsure why the program failed, post a message on the `OpenMC Discourse Forum `_. +.. _troubleshoot_lost_particles: + +WARNING: After particle __ crossed surface __ it could not be located in any cell and it did not leak. +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +During a simulation, particles can become "lost" if they reach a surface and +there is no cell defined on the other side of the surface. It is important to +ensure that 1) proper boundary conditions have been applied to the outer +surfaces of your model and 2) all space in your model is filled with a cell, +even regions that are void and have no material assigned to them. + +Please see the instructions in :ref:`troubleshoot_geometry` on how to resolve +issues with lost particles. + +ERROR: Maximum number of lost particles has been reached. +********************************************************* + +See the above description regarding :ref:`lost particles +`. When too many particles are lost, the simulation +will abort altogether. Again, please see the instructions in +:ref:`troubleshoot_geometry` on how to resolve issues with lost particles. + ERROR: No cross_sections.xml file was specified in settings.xml or in the OPENMC_CROSS_SECTIONS environment variable. ********************************************************************************************************************* @@ -45,25 +69,53 @@ with the :envvar:`OPENMC_CROSS_SECTIONS` environment variable. It is recommended to add a line in your ``.profile`` or ``.bash_profile`` setting the :envvar:`OPENMC_CROSS_SECTIONS` environment variable. +RuntimeError: Failed to open HDF5 file with mode 'w': summary.h5 +**************************************************************** + +This often occurs when working with the Python API and executing multiple OpenMC +runs in a script. If an :class:`openmc.StatePoint` is open in the Python interpreter, +the file handle of the statepoint file as well as the linked `summary.h5` file will +be unavailable for writing, causing this error to appear. To avoid this situation, +it is recommended that data be extracted from statepoint files in a context manager: + +.. code-block:: python + + with openmc.StatePoint('statepoint.10.h5') as sp: + k_eff = sp.keff + +or that the :meth:`StatePoint.close` method is called before executing a subsequent +OpenMC run. + +.. _troubleshoot_geometry: + Geometry Debugging ****************** -Overlapping Cells -^^^^^^^^^^^^^^^^^ +To identify issues in your geometry, it is highly recommended to use the `OpenMC +Plot Explorer `_ GUI application. This +application enables you to interactively explore a model, identify regions that +may be missing a cell definition, and identify overlapping cells. + +If you are having issues with lost particles, the following procedure may be +helpful. If OpenMC reports, for example, that a particle reaching surface 50 +could not be located, look at your geometry.xml to see which cells have a region +definition that includes surface 50, e.g.: + +.. code-block:: xml + + -For fast run times, normal simulations do not check if the geometry is -incorrectly defined to have overlapping cells. This can lead to incorrect -results that may or may not be obvious when there are errors in the geometry -input file. The built-in 2D and 3D plotters will check for cell overlaps at -the center of every pixel or voxel position they process, however this might -not be a sufficient check to ensure correctly defined geometry. For instance, -if an overlap is of small aspect ratio, the plotting resolution might not be -high enough to produce any pixels in the overlapping area. +This may indicate that you need to define a cell on the other side of cell 10. +At this point, using the OpenMC Plot Explorer to locate cell 10 may provide a +visual clue as to whether there is a missing or overlapping cell near cell 10. +Working with the unique integer IDs of cells may be cumbersome; if you provide +names to your cells, these names will show up in the Plot Explorer, which will +aid geometry debugging. -To reliably validate a geometry input, it is best to run the problem in +Another method to check for overlapping cells in a geometry is to run the problem in geometry debugging mode with the ``-g``, ``-geometry-debug``, or ``--geometry-debug`` command-line options. This will enable checks for -overlapping cells at every move of esch simulated particle. Depending on the +overlapping cells at every move of each simulated particle. Depending on the complexity of the geometry input file, this could add considerable overhead to the run (these runs can still be done in parallel). As a result, for this run mode the user will probably want to run fewer particles than a normal @@ -75,31 +127,15 @@ output after a geometry debug run to see how many checks were performed in each cell, and then adjust the number of starting particles or starting source distributions accordingly to achieve good coverage. -ERROR: After particle __ crossed surface __ it could not be located in any cell and it did not leak. -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -This error can arise either if a problem is specified with no boundary -conditions or if there is an error in the geometry itself. First check to ensure -that all of the outer surfaces of your geometry have been given vacuum or -reflective boundary conditions. If proper boundary conditions have been applied -and you still receive this error, it means that a surface/cell/lattice in your -geometry has been specified incorrectly or is missing. - -The best way to debug this error is to turn on a trace for the particle getting -lost. After the error message, the code will display what batch, generation, and -particle number caused the error. In your settings.xml, add a :ref:`trace` -followed by the batch, generation, and particle number. This will give you -detailed output every time that particle enters a cell, crosses a boundary, or -has a collision. For example, if you received this error at cycle 5, generation -1, particle 4032, you would enter: - -.. code-block:: xml +Depletion +********* - 5 1 4032 +If you are running a depletion simulation and are experiencing random hangs or +crashes, you may need to set:: -For large runs it is often advantageous to run only the offending particle by -using particle restart mode with the ``-r`` command-line option in conjunction -with the particle restart files that are created when particles are lost with -this error. + openmc.deplete.pool.USE_MULTIPROCESSING = False -.. _mailing list: https://groups.google.com/forum/?fromgroups=#!forum/openmc-users +in your Python file before making any calls to the integrator. This can be +caused by an MPI implementation that is not compatible with forking (e.g., see +the `OpenMPI FAQ entry about forking +`_). diff --git a/examples/assembly/assembly.py b/examples/assembly/assembly.py index 31984543a63..d94cb69bfc4 100644 --- a/examples/assembly/assembly.py +++ b/examples/assembly/assembly.py @@ -99,11 +99,11 @@ def assembly_model(): assembly.universes[gt_pos[:, 0], gt_pos[:, 1]] = guide_tube_pin() # Create outer boundary of the geometry to surround the lattice - outer_boundary = openmc.model.rectangular_prism( + outer_boundary = openmc.model.RectangularPrism( pitch, pitch, boundary_type='reflective') # Create a cell filled with the lattice - main_cell = openmc.Cell(fill=assembly, region=outer_boundary) + main_cell = openmc.Cell(fill=assembly, region=-outer_boundary) # Finally, create geometry by providing a list of cells that fill the root # universe @@ -112,11 +112,10 @@ def assembly_model(): model.settings.batches = 150 model.settings.inactive = 50 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Box( - (-pitch/2, -pitch/2, -1), - (pitch/2, pitch/2, 1), - only_fissionable=True - )) + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Box((-pitch/2, -pitch/2, -1), (pitch/2, pitch/2, 1)), + constraints={'fissionable': True} + ) # NOTE: We never actually created a Materials object. When you export/run # using the Model object, if no materials were assigned it will look through @@ -131,6 +130,8 @@ def assembly_model(): parser.add_argument('--generate', action='store_true') parser.add_argument('--run', action='store_true') args = parser.parse_args() + if not args.generate and not args.run: + parser.print_help() if args.generate or args.run: model = assembly_model() diff --git a/examples/custom_source/CMakeLists.txt b/examples/custom_source/CMakeLists.txt index 9498176944a..21463ed51ed 100644 --- a/examples/custom_source/CMakeLists.txt +++ b/examples/custom_source/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3 FATAL_ERROR) +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(openmc_sources CXX) add_library(source SHARED source_ring.cpp) find_package(OpenMC REQUIRED) diff --git a/examples/custom_source/build_xml.py b/examples/custom_source/build_xml.py index a0817d4223f..ff6dae2bb65 100644 --- a/examples/custom_source/build_xml.py +++ b/examples/custom_source/build_xml.py @@ -8,8 +8,8 @@ mats.export_to_xml() # Create a 5 cm x 5 cm box filled with iron -box = openmc.model.rectangular_prism(10.0, 10.0, boundary_type='vacuum') -cell = openmc.Cell(fill=iron, region=box) +box = openmc.model.RectangularPrism(10.0, 10.0, boundary_type='vacuum') +cell = openmc.Cell(fill=iron, region=-box) geometry = openmc.Geometry([cell]) geometry.export_to_xml() @@ -18,7 +18,7 @@ settings.run_mode = 'fixed source' settings.batches = 10 settings.particles = 1000 -source = openmc.Source() +source = openmc.CompiledSource() source.library = 'build/libsource.so' settings.source = source settings.export_to_xml() diff --git a/examples/custom_source/source_ring.cpp b/examples/custom_source/source_ring.cpp index 4b90f801aaf..b87afbd1760 100644 --- a/examples/custom_source/source_ring.cpp +++ b/examples/custom_source/source_ring.cpp @@ -10,9 +10,8 @@ class RingSource : public openmc::Source openmc::SourceSite sample(uint64_t* seed) const { openmc::SourceSite particle; - // wgt + // particle type particle.particle = openmc::ParticleType::neutron; - particle.wgt = 1.0; // position double angle = 2.0 * M_PI * openmc::prn(seed); double radius = 3.0; @@ -22,7 +21,6 @@ class RingSource : public openmc::Source // angle particle.u = {1.0, 0.0, 0.0}; particle.E = 14.08e6; - particle.delayed_group = 0; return particle; } }; diff --git a/examples/jezebel/jezebel.py b/examples/jezebel/jezebel.py index 5114ac714d6..83b47a5e94f 100644 --- a/examples/jezebel/jezebel.py +++ b/examples/jezebel/jezebel.py @@ -29,5 +29,5 @@ # Get the resulting k-effective value n = settings.batches with openmc.StatePoint(f'statepoint.{n}.h5') as sp: - keff = sp.k_combined + keff = sp.keff print(f'Final k-effective = {keff}') diff --git a/examples/jupyter/c5g7.h5 b/examples/jupyter/c5g7.h5 deleted file mode 100644 index b3dea952b16..00000000000 Binary files a/examples/jupyter/c5g7.h5 and /dev/null differ diff --git a/examples/jupyter/cad-based-geometry.ipynb b/examples/jupyter/cad-based-geometry.ipynb deleted file mode 100644 index 9fa56f6fbdf..00000000000 --- a/examples/jupyter/cad-based-geometry.ipynb +++ /dev/null @@ -1,758 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using CAD-Based Geometries\n", - "In this notebook we'll be exploring how to use CAD-based geometries in OpenMC via the [DagMC](https://svalinn.github.io/DAGMC/index.html) toolkit. The models we'll be using in this notebook have already been created using [Trelis](https://coreform.com/products/trelisnew/) and faceted into a surface mesh represented as `.h5m` files in the [Mesh Oriented DatABase](https://sigma.mcs.anl.gov/moab-library/) format. We'll be retrieving these files using the function below.\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import urllib.request\n", - "\n", - "fuel_pin_url = 'https://tinyurl.com/y3ugwz6w' # 1.2 MB\n", - "teapot_url = 'https://tinyurl.com/y4mcmc3u' # 29 MB\n", - "\n", - "def download(url):\n", - " \"\"\"\n", - " Helper function for retrieving dagmc models\n", - " \"\"\"\n", - " u = urllib.request.urlopen(url)\n", - " \n", - " if u.status != 200:\n", - " raise RuntimeError(\"Failed to download file.\")\n", - " \n", - " # save file as dagmc.h5m\n", - " with open(\"dagmc.h5m\", 'wb') as f:\n", - " f.write(u.read())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This notebook is intended to demonstrate how DagMC problems are run in OpenMC. For more information on how DagMC models are created, please refer to the [DagMC User's Guide](https://svalinn.github.io/DAGMC/usersguide/index.html).\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "from IPython.display import Image\n", - "import openmc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To start, we'll be using a simple U235 fuel pin surrounded by a water moderator, so let's create those materials." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - " # materials\n", - "u235 = openmc.Material(name=\"fuel\")\n", - "u235.add_nuclide('U235', 1.0, 'ao')\n", - "u235.set_density('g/cc', 11)\n", - "u235.id = 40\n", - "\n", - "water = openmc.Material(name=\"water\")\n", - "water.add_nuclide('H1', 2.0, 'ao')\n", - "water.add_nuclide('O16', 1.0, 'ao')\n", - "water.set_density('g/cc', 1.0)\n", - "water.add_s_alpha_beta('c_H_in_H2O')\n", - "water.id = 41\n", - "\n", - "mats = openmc.Materials([u235, water])\n", - "mats.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's get our DAGMC geometry. We'll be using prefabricated models in this notebook. For information on how to create your own DAGMC models, you can refer to the instructions [here](https://svalinn.github.io/DAGMC/usersguide/trelis_workflow.html)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's download the DAGMC model. These models come in the form of triangle surface meshes stored using the the Mesh Oriented datABase ([MOAB](https://sigma.mcs.anl.gov/moab-library/)) in an HDF5 file with the extension `.h5m`. An example of a coarse triangle mesh looks like:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": { - "image/png": { - "width": 350 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "Image(\"./images/cylinder_mesh.png\", width=350)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we'll need to grab some pre-made DagMC models." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "download(fuel_pin_url)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC expects that the model has the name \"dagmc.h5m\" so we'll name the file that and indicate to OpenMC that a DAGMC geometry is being used by setting the `settings.dagmc` attribute to `True`." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "settings = openmc.Settings()\n", - "settings.dagmc = True\n", - "settings.batches = 10\n", - "settings.inactive = 2\n", - "settings.particles = 5000\n", - "settings.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Unlike conventional geometries in OpenMC, we really have no way of knowing what our model looks like at this point. Thankfully DagMC geometries can be plotted just like any other OpenMC geometry to give us an idea of what we're now working with.\n", - "\n", - "Note that material assignments have already been applied to this model. Materials can be assigned either using ids or names of materials in the `materials.xml` file. It is recommended that material names are used for assignment for readability." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQAgMAAAD90d5fAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACVBMVEX///8AAP///wCN6GYzAAAAAWJLR0QAiAUdSAAAAAd0SU1FB+MGEgg2EcTrSQcAAAWvSURBVHja7Z3NddswEISjA0pgPyqBB9MHlsB+UgIPUpV5tmPiRwSwfxg6CPacvC87M4D0InL3169Ro0aNGjVq1KhRP7Buy2fdGyKm5ai3Rgi3RDU3bqNZM8tJIRjWlOkcYqpYhmFKcUu2ZivGbSnU3QiyFMuGMZUhJrbclkpZCFZjWAjm6pAZ0Ii+FUIj6laqrlt4P9EgqhgTG9G1QnJE6wqVoQkYuRFNK3SGvBVGI/JWJg5EmGJyfr/q3l4tqV48hsx6ZiOyVli2S63nMiR6ZdR6fpaVXmdqvT+P+m2h19kh2Z5BPU7+wF2v1jMpvV5TlXFCYer1qtb2CnlVjKeXIzBOKDy9UrXW52ntKr3y2Y0rTbJGrS0HSQXj6JWotT6zlQjG0aua3myO6YwkwFsJkgh2F1ry/ixW7D3dlIneSNoK3RROI2krMku2GiRuhWqKYzWStEI1ZWI1krRCNYV8Rk7PisCSlQKJjj3NFMdtJG6FZkpoCcH21HqaKUzbX6xnW0JjxHpRTAktIdmeWk8xZeKrFetFMYVve2o9zxKyWrFedVOcRK1Yr7opk0itSK+6KZNIrUivOkSmVqwXx3cOIzqPNeedUK1Ir5rzk1CtSK+aKZNUrVCvGkQY4I8KQkz2nWlJZErZ+cB3piWRKTMVwmWEppQh3ne2JaEpZecVlkSmECFsSyJTiOHiM0JTSvHyvgssCU0pOe99F1gSmvJGgggsCU0pQXSWhKZQICJLQlMo4RJZEpqSj5ezg8wEyCaDPAgQHy4ZI3A+Hy+t7yTntZaEpjQLFyVeHrJJIY8qxIdLygicn2sQse+B8znIZAl5q0FWOWSvQfS+h843C1c9Xh4iZwTxOodYhKsaLwjEIlzVeB2QTQN5/ACISbiCeF0GOY6JKlxBvO4lyKqD7CWIs4bMJcimgzxKEJsEVzJ8QHQMH6/LIEYJDjJ8EcTqmBQPChayaSGPPMTqLBZP4wHRMnyGL4KYncXSafyGqI+JPygXQcyOSXBQ+oXYHfjCkcdC9Ax/UC6BGN4q+XvlG2JwFv1pvARieKvk75VvyGoB2buHGF5d+cvL8FYJ7pXuIRYMf680vB9zN2R/EJOry19eF0BMb/rcXd8fZLWB7AOih5h+MOY+GqGQzQbyGJAB6RGytIEspxAbRuaL14AMyIAMyIAMyIAMyIBgvtxNbSC9fuEekP8cstpA9usgrg1kHhA9pJ//F24K6edXh/5+CWoKgfwE2OEvphDIagHZMxDTj8bzD8YeIU0fKTG9689vejCk6QNL/Tzf1c8zd/08B4mBGN4ruVsFDGn6ULLhvZK7VdCQTcsoPPIOeXi/n3cd+nn/pKN3gg7IpmMUX6GyOo3Fl8EOyKqD7CUI5AU9yKuG/byZ2dHbsgdk1UD2MuQ4KP/8u9iQV9chL+FDxglgBiMckJYjHiziVQkXaOwGZIAIZBQKZKgLZjzNkeGWg3Z8vDYZgzIyyGlN2QkQyBgnyEAqzGgtH69NwqANCZt0puwkiNOZ4i2ZCxDICDrIMD3MWEDvfMMBh975hqMaAwjbFPLQScj4TMggUMxI0wDCNIUxnDVwnmlKYMlcgUAG5kJG/2KGGAeQduOYnUwv3mBpyIhsyLBvzNhyJ9ErVKtuCWiUPGQoPma8v+PrFf4NiiWglQuQ5RGYNRiRKa0WekBWk0CWrGDWxThOK3EjVEtAK3wgy4gwa5Vc8u/LCqZZEAVZdYVZ2pXq1WT9GGSRGmQlHGa5HWRNH2ThIGZ1ImQJJGadpeNCBGphVoxilqVC1r5CFthiVvFClgpj1iNDFj1jVlZDlm9D1ohjFqJDVrtjltRTWlE3QmlFz6h7fzeA1GKsiy9RMBtGWTATsT6qkLDZilGwxciQIsWUkTPflnFOsWacKGas1VclGZtbMOJmmrTxt27GJ3DUqFGjRo0aNWqUZf0BnVivRTb4g0AAAAAldEVYdGRhdGU6Y3JlYXRlADIwMTktMDYtMThUMDg6NTQ6MTctMDU6MDB3TrB6AAAAJXRFWHRkYXRlOm1vZGlmeQAyMDE5LTA2LTE4VDA4OjU0OjE3LTA1OjAwBhMIxgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "p = openmc.Plot()\n", - "p.width = (25.0, 25.0)\n", - "p.pixels = (400, 400)\n", - "p.color_by = 'material'\n", - "p.colors = {u235: 'yellow', water: 'blue'}\n", - "openmc.plot_inline(p)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've had a chance to examine the model a bit, we can finish applying our settings and add a source." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "settings.source = openmc.Source(space=openmc.stats.Box([-4., -4., -4.],\n", - " [ 4., 4., 4.]))\n", - "settings.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Tallies work in the same way when using DAGMC geometries too. We'll add a tally on the fuel cell here." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "tally = openmc.Tally()\n", - "tally.scores = ['total']\n", - "tally.filters = [openmc.CellFilter(1)]\n", - "tallies = openmc.Tallies([tally])\n", - "tallies.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Note:** Applying tally filters in DagMC models requires prior knowledge of the model. Here, we know that the fuel cell's volume ID in the CAD sofware is 1. To identify cells without use of CAD software, load them into the [OpenMC plotter](https://github.com/openmc-dev/plotter) where cell, material, and volume IDs can be identified for native both OpenMC and DagMC geometries." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we're ready to run the simulation just like any other OpenMC run." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | 2c0b16e73d5d81a2f849f4e2bfae5eb5319f2417\n", - " Date/Time | 2019-06-18 08:54:17\n", - " OpenMP Threads | 2\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading DAGMC geometry...\n", - "Loading file dagmc.h5m\n", - "Initializing the GeomQueryTool...\n", - "Using faceting tolerance: 0.0001\n", - "Building OBB Tree...\n", - " Reading U235 from /home/shriwise/opt/openmc/xs/nndc_hdf5/U235.h5\n", - " Reading H1 from /home/shriwise/opt/openmc/xs/nndc_hdf5/H1.h5\n", - " Reading O16 from /home/shriwise/opt/openmc/xs/nndc_hdf5/O16.h5\n", - " Reading c_H_in_H2O from /home/shriwise/opt/openmc/xs/nndc_hdf5/c_H_in_H2O.h5\n", - " Maximum neutron transport energy: 20000000.000000 eV for U235\n", - " Reading tallies XML file...\n", - " Writing summary.h5 file...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 1.15789\n", - " 2/1 1.05169\n", - " 3/1 1.00736\n", - " 4/1 0.97863 0.99300 +/- 0.01436\n", - " 5/1 0.95316 0.97972 +/- 0.01566\n", - " 6/1 0.95079 0.97248 +/- 0.01322\n", - " 7/1 0.96879 0.97175 +/- 0.01027\n", - " 8/1 0.94253 0.96688 +/- 0.00970\n", - " 9/1 0.97406 0.96790 +/- 0.00826\n", - " 10/1 0.97362 0.96862 +/- 0.00719\n", - " Creating state point statepoint.10.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 2.4575e-01 seconds\n", - " Reading cross sections = 1.3129e-01 seconds\n", - " Total time in simulation = 1.6897e+00 seconds\n", - " Time in transport only = 1.6829e+00 seconds\n", - " Time in inactive batches = 3.1605e-01 seconds\n", - " Time in active batches = 1.3737e+00 seconds\n", - " Time synchronizing fission bank = 2.8739e-03 seconds\n", - " Sampling source sites = 2.5550e-03 seconds\n", - " SEND/RECV source sites = 2.8512e-04 seconds\n", - " Time accumulating tallies = 7.8450e-06 seconds\n", - " Total time for finalization = 1.7404e-04 seconds\n", - " Total time elapsed = 1.9588e+00 seconds\n", - " Calculation Rate (inactive) = 31640.8 particles/second\n", - " Calculation Rate (active) = 29119.1 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 0.97020 +/- 0.00750\n", - " k-effective (Track-length) = 0.96862 +/- 0.00719\n", - " k-effective (Absorption) = 0.95742 +/- 0.00791\n", - " Combined k-effective = 0.96203 +/- 0.00898\n", - " Leakage Fraction = 0.57677 +/- 0.00317\n", - "\n" - ] - } - ], - "source": [ - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## More Complicated Geometry" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Neat! But this pincell is something we could've done with CSG. Let's take a look at something more complex. We'll download a pre-built model of the [Utah teapot](https://en.wikipedia.org/wiki/Utah_teapot) and use it here." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "download(teapot_url)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/jpeg": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": { - "image/jpeg": { - "width": 600 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "Image(\"./images/teapot.jpg\", width=600)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our teapot is made out of iron, so we'll want to create that material and make sure it is in our `materials.xml` file." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "iron = openmc.Material(name=\"iron\")\n", - "iron.add_nuclide(\"Fe54\", 0.0564555822608)\n", - "iron.add_nuclide(\"Fe56\", 0.919015287728)\n", - "iron.add_nuclide(\"Fe57\", 0.0216036861685)\n", - "iron.add_nuclide(\"Fe58\", 0.00292544384231)\n", - "iron.set_density(\"g/cm3\", 7.874)\n", - "mats = openmc.Materials([iron, water])\n", - "mats.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To make sure we've updated the file correctly, let's make a plot of the teapot." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "p = openmc.Plot()\n", - "p.basis = 'xz'\n", - "p.origin = (0.0, 0.0, 0.0)\n", - "p.width = (30.0, 20.0)\n", - "p.pixels = (450, 300)\n", - "p.color_by = 'material'\n", - "p.colors = {iron: 'gray', water: 'blue'}\n", - "openmc.plot_inline(p)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here we start to see some of the advantages CAD geometries provide. This particular file was pulled from the [GrabCAD](https://grabcad.com/library) and pushed through the DAGMC workflow without modification (other than the addition of material assignments). It would take a considerable amount of time to create a model like this using CSG!" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "p.width = (18.0, 6.0)\n", - "p.basis = 'xz'\n", - "p.origin = (10.0, 0.0, 5.0)\n", - "p.pixels = (600, 200)\n", - "p.color_by = 'material'\n", - "openmc.plot_inline(p)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's brew some tea! ... using a very hot neutron source. We'll use some well-placed point sources distributed throughout the model." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "settings = openmc.Settings()\n", - "settings.dagmc = True\n", - "settings.batches = 10\n", - "settings.particles = 5000\n", - "settings.run_mode = \"fixed source\"\n", - "\n", - "src_locations = ((-4.0, 0.0, -2.0),\n", - " ( 4.0, 0.0, -2.0),\n", - " ( 4.0, 0.0, -6.0),\n", - " (-4.0, 0.0, -6.0),\n", - " (10.0, 0.0, -4.0),\n", - " (-8.0, 0.0, -4.0))\n", - "\n", - "# we'll use the same energy for each source\n", - "src_e = openmc.stats.Discrete(x=[12.0,], p=[1.0,])\n", - "\n", - "# create source for each location\n", - "sources = []\n", - "for loc in src_locations:\n", - " src_pnt = openmc.stats.Point(xyz=loc)\n", - " src = openmc.Source(space=src_pnt, energy=src_e)\n", - " sources.append(src)\n", - "\n", - "src_str = 1.0 / len(sources)\n", - "for source in sources:\n", - " source.strength = src_str\n", - "\n", - "settings.source = sources\n", - "settings.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "...and setup a couple mesh tallies. One for the kettle, and one for the water inside." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "mesh = openmc.RegularMesh()\n", - "mesh.dimension = (120, 1, 40)\n", - "mesh.lower_left = (-20.0, 0.0, -10.0)\n", - "mesh.upper_right = (20.0, 1.0, 4.0)\n", - "\n", - "mesh_filter = openmc.MeshFilter(mesh)\n", - "\n", - "pot_filter = openmc.CellFilter([1])\n", - "pot_tally = openmc.Tally()\n", - "pot_tally.filters = [mesh_filter, pot_filter]\n", - "pot_tally.scores = ['flux']\n", - "\n", - "water_filter = openmc.CellFilter([5])\n", - "water_tally = openmc.Tally()\n", - "water_tally.filters = [mesh_filter, water_filter]\n", - "water_tally.scores = ['flux']\n", - "\n", - "\n", - "tallies = openmc.Tallies([pot_tally, water_tally])\n", - "tallies.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | 2c0b16e73d5d81a2f849f4e2bfae5eb5319f2417\n", - " Date/Time | 2019-06-18 08:54:35\n", - " OpenMP Threads | 2\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading DAGMC geometry...\n", - "Loading file dagmc.h5m\n", - "Initializing the GeomQueryTool...\n", - "Using faceting tolerance: 0.001\n", - "Building OBB Tree...\n", - " Reading Fe54 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Fe54.h5\n", - " Reading Fe56 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Fe56.h5\n", - " Reading Fe57 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Fe57.h5\n", - " Reading Fe58 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Fe58.h5\n", - " Reading H1 from /home/shriwise/opt/openmc/xs/nndc_hdf5/H1.h5\n", - " Reading O16 from /home/shriwise/opt/openmc/xs/nndc_hdf5/O16.h5\n", - " Reading c_H_in_H2O from /home/shriwise/opt/openmc/xs/nndc_hdf5/c_H_in_H2O.h5\n", - " Maximum neutron transport energy: 20000000.000000 eV for Fe58\n", - " Reading tallies XML file...\n", - " Writing summary.h5 file...\n", - " Initializing source particles...\n", - "\n", - " ===============> FIXED SOURCE TRANSPORT SIMULATION <===============\n", - "\n", - " Simulating batch 1\n", - " Simulating batch 2\n", - " Simulating batch 3\n", - " Simulating batch 4\n", - " Simulating batch 5\n", - " Simulating batch 6\n", - " Simulating batch 7\n", - " Simulating batch 8\n", - " Simulating batch 9\n", - " Simulating batch 10\n", - " Creating state point statepoint.10.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 4.9659e+00 seconds\n", - " Reading cross sections = 6.3783e-01 seconds\n", - " Total time in simulation = 1.5112e+01 seconds\n", - " Time in transport only = 1.4102e+01 seconds\n", - " Time in active batches = 1.5112e+01 seconds\n", - " Time accumulating tallies = 2.8790e-04 seconds\n", - " Total time for finalization = 3.2375e-02 seconds\n", - " Total time elapsed = 2.0224e+01 seconds\n", - " Calculation Rate (active) = 3308.59 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " Leakage Fraction = 0.62594 +/- 0.00117\n", - "\n" - ] - } - ], - "source": [ - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that the performance is significantly lower than our pincell model due to the increased complexity of the model, but it allows us to examine tally results like these:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "sp = openmc.StatePoint(\"statepoint.10.h5\")\n", - "\n", - "water_tally = sp.get_tally(scores=['flux'], id=water_tally.id)\n", - "water_flux = water_tally.mean\n", - "water_flux.shape = (40, 120)\n", - "water_flux = water_flux[::-1, :]\n", - "\n", - "pot_tally = sp.get_tally(scores=['flux'], id=pot_tally.id)\n", - "pot_flux = pot_tally.mean\n", - "pot_flux.shape = (40, 120)\n", - "pot_flux = pot_flux[::-1, :]\n", - "\n", - "del sp" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "

" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "from matplotlib import pyplot as plt\n", - "fig = plt.figure(figsize=(18, 16))\n", - "\n", - "sub_plot1 = plt.subplot(121, title=\"Kettle Flux\")\n", - "sub_plot1.imshow(pot_flux)\n", - "\n", - "sub_plot2 = plt.subplot(122, title=\"Water Flux\")\n", - "sub_plot2.imshow(water_flux)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/jupyter/candu.ipynb b/examples/jupyter/candu.ipynb deleted file mode 100644 index eaf1e36d217..00000000000 --- a/examples/jupyter/candu.ipynb +++ /dev/null @@ -1,1116 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Modeling a CANDU Bundle\n", - "In this example, we will create a typical CANDU bundle with rings of fuel pins. At present, OpenMC does not have a specialized lattice for this type of fuel arrangement, so we must resort to manual creation of the array of fuel pins." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "from math import pi, sin, cos\n", - "import numpy as np\n", - "import openmc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's begin by creating the materials that will be used in our model." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "fuel = openmc.Material(name='fuel')\n", - "fuel.add_element('U', 1.0)\n", - "fuel.add_element('O', 2.0)\n", - "fuel.set_density('g/cm3', 10.0)\n", - "\n", - "clad = openmc.Material(name='zircaloy')\n", - "clad.add_element('Zr', 1.0)\n", - "clad.set_density('g/cm3', 6.0)\n", - "\n", - "heavy_water = openmc.Material(name='heavy water')\n", - "heavy_water.add_nuclide('H2', 2.0)\n", - "heavy_water.add_nuclide('O16', 1.0)\n", - "heavy_water.add_s_alpha_beta('c_D_in_D2O')\n", - "heavy_water.set_density('g/cm3', 1.1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our materials created, we'll now define key dimensions in our model. These dimensions are taken from the example in section 11.1.3 of the [Serpent manual](http://montecarlo.vtt.fi/download/Serpent_manual.pdf)." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Outer radius of fuel and clad\n", - "r_fuel = 0.6122\n", - "r_clad = 0.6540\n", - "\n", - "# Pressure tube and calendria radii\n", - "pressure_tube_ir = 5.16890\n", - "pressure_tube_or = 5.60320\n", - "calendria_ir = 6.44780\n", - "calendria_or = 6.58750\n", - "\n", - "# Radius to center of each ring of fuel pins\n", - "ring_radii = np.array([0.0, 1.4885, 2.8755, 4.3305])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To begin creating the bundle, we'll first create annular regions completely filled with heavy water and add in the fuel pins later. The radii that we've specified above correspond to the center of each ring. We actually need to create cylindrical surfaces at radii that are half-way between the centers." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# These are the surfaces that will divide each of the rings\n", - "radial_surf = [openmc.ZCylinder(r=r) for r in\n", - " (ring_radii[:-1] + ring_radii[1:])/2]\n", - "\n", - "water_cells = []\n", - "for i in range(ring_radii.size):\n", - " # Create annular region\n", - " if i == 0:\n", - " water_region = -radial_surf[i]\n", - " elif i == ring_radii.size - 1:\n", - " water_region = +radial_surf[i-1]\n", - " else:\n", - " water_region = +radial_surf[i-1] & -radial_surf[i]\n", - " \n", - " water_cells.append(openmc.Cell(fill=heavy_water, region=water_region))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's see what our geometry looks like so far. In order to plot the geometry, we create a universe that contains the annular water cells and then use the `Universe.plot()` method. While we're at it, we'll set some keyword arguments that can be reused for later plots." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plot_args = {'width': (2*calendria_or, 2*calendria_or)}\n", - "bundle_universe = openmc.Universe(cells=water_cells)\n", - "bundle_universe.plot(**plot_args)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we need to create a universe that contains a fuel pin. Note that we don't actually need to put water outside of the cladding in this universe because it will be truncated by a higher universe." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "surf_fuel = openmc.ZCylinder(r=r_fuel)\n", - "\n", - "fuel_cell = openmc.Cell(fill=fuel, region=-surf_fuel)\n", - "clad_cell = openmc.Cell(fill=clad, region=+surf_fuel)\n", - "\n", - "pin_universe = openmc.Universe(cells=(fuel_cell, clad_cell))" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "pin_universe.plot(**plot_args)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The code below works through each ring to create a cell containing the fuel pin universe. As each fuel pin is created, we modify the region of the water cell to include everything outside the fuel pin." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "num_pins = [1, 6, 12, 18]\n", - "angles = [0, 0, 15, 0]\n", - "\n", - "for i, (r, n, a) in enumerate(zip(ring_radii, num_pins, angles)):\n", - " for j in range(n):\n", - " # Determine location of center of pin\n", - " theta = (a + j/n*360.) * pi/180.\n", - " x = r*cos(theta)\n", - " y = r*sin(theta)\n", - " \n", - " pin_boundary = openmc.ZCylinder(x0=x, y0=y, r=r_clad)\n", - " water_cells[i].region &= +pin_boundary\n", - " \n", - " # Create each fuel pin -- note that we explicitly assign an ID so \n", - " # that we can identify the pin later when looking at tallies\n", - " pin = openmc.Cell(fill=pin_universe, region=-pin_boundary)\n", - " pin.translation = (x, y, 0)\n", - " pin.id = (i + 1)*100 + j\n", - " bundle_universe.add_cell(pin)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "bundle_universe.plot(**plot_args)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looking pretty good! Finally, we create cells for the pressure tube and calendria and then put our bundle in the middle of the pressure tube." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "pt_inner = openmc.ZCylinder(r=pressure_tube_ir)\n", - "pt_outer = openmc.ZCylinder(r=pressure_tube_or)\n", - "calendria_inner = openmc.ZCylinder(r=calendria_ir)\n", - "calendria_outer = openmc.ZCylinder(r=calendria_or, boundary_type='vacuum')\n", - "\n", - "bundle = openmc.Cell(fill=bundle_universe, region=-pt_inner)\n", - "pressure_tube = openmc.Cell(fill=clad, region=+pt_inner & -pt_outer)\n", - "v1 = openmc.Cell(region=+pt_outer & -calendria_inner)\n", - "calendria = openmc.Cell(fill=clad, region=+calendria_inner & -calendria_outer)\n", - "\n", - "root_universe = openmc.Universe(cells=[bundle, pressure_tube, v1, calendria])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's look at the final product. We'll export our geometry and materials and then use `plot_inline()` to get a nice-looking plot." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "geometry = openmc.Geometry(root_universe)\n", - "geometry.export_to_xml()\n", - "\n", - "materials = openmc.Materials(geometry.get_all_materials().values())\n", - "materials.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot = openmc.Plot.from_geometry(geometry)\n", - "plot.color_by = 'material'\n", - "plot.colors = {\n", - " fuel: 'black',\n", - " clad: 'silver',\n", - " heavy_water: 'blue'\n", - "}\n", - "plot.to_ipython_image()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Interpreting Results\n", - "\n", - "One of the difficulties of a geometry like this is identifying tally results when there was no lattice involved. To address this, we specifically gave an ID to each fuel pin of the form 100\\*ring + azimuthal position. Consequently, we can use a distribcell tally and then look at our `DataFrame` which will show these cell IDs." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "settings = openmc.Settings()\n", - "settings.particles = 1000\n", - "settings.batches = 20\n", - "settings.inactive = 10\n", - "settings.source = openmc.Source(space=openmc.stats.Point())\n", - "settings.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "fuel_tally = openmc.Tally()\n", - "fuel_tally.filters = [openmc.DistribcellFilter(fuel_cell)]\n", - "fuel_tally.scores = ['flux']\n", - "\n", - "tallies = openmc.Tallies([fuel_tally])\n", - "tallies.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "openmc.run(output=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The return code of `0` indicates that OpenMC ran successfully. Now let's load the statepoint into a `openmc.StatePoint` object and use the `Tally.get_pandas_dataframe(...)` method to see our results." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "sp = openmc.StatePoint('statepoint.{}.h5'.format(settings.batches))" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
level 1level 2level 3distribcellnuclidescoremeanstd. dev.
univcellunivcellunivcell
idididididid
03441100250totalflux0.2078050.007037
13441200251totalflux0.1971970.005272
23441201252totalflux0.1903100.007816
33441202253totalflux0.1947360.006469
43441203254totalflux0.1910970.006431
53441204255totalflux0.1899100.004891
63441205256totalflux0.1822030.003851
73441300257totalflux0.1659220.005815
83441301258totalflux0.1689330.008300
93441302259totalflux0.1595870.003085
1034413032510totalflux0.1591580.005910
1134413042511totalflux0.1485370.005308
1234413052512totalflux0.1509450.006654
1334413062513totalflux0.1542370.003665
1434413072514totalflux0.1658880.004733
1534413082515totalflux0.1567770.006540
1634413092516totalflux0.1652770.005935
1734413102517totalflux0.1565280.005732
1834413112518totalflux0.1596100.004584
1934414002519totalflux0.0965970.004466
2034414012520totalflux0.1182140.005451
2134414022521totalflux0.1061670.004722
2234414032522totalflux0.1108140.004208
2334414042523totalflux0.1123190.005079
2434414052524totalflux0.1102320.004153
2534414062525totalflux0.0999670.005085
2634414072526totalflux0.0954440.003615
2734414082527totalflux0.0926200.003997
2834414092528totalflux0.0955170.004022
2934414102529totalflux0.1137370.009530
3034414112530totalflux0.1083680.007241
3134414122531totalflux0.1069900.005716
3234414132532totalflux0.1120500.005002
3334414142533totalflux0.1150540.006239
3434414152534totalflux0.1143940.004919
3534414162535totalflux0.1143520.005322
3634414172536totalflux0.1108900.005051
\n", - "
" - ], - "text/plain": [ - " level 1 level 2 level 3 distribcell nuclide score mean \\\n", - " univ cell univ cell univ cell \n", - " id id id id id id \n", - "0 3 44 1 100 2 5 0 total flux 2.08e-01 \n", - "1 3 44 1 200 2 5 1 total flux 1.97e-01 \n", - "2 3 44 1 201 2 5 2 total flux 1.90e-01 \n", - "3 3 44 1 202 2 5 3 total flux 1.95e-01 \n", - "4 3 44 1 203 2 5 4 total flux 1.91e-01 \n", - "5 3 44 1 204 2 5 5 total flux 1.90e-01 \n", - "6 3 44 1 205 2 5 6 total flux 1.82e-01 \n", - "7 3 44 1 300 2 5 7 total flux 1.66e-01 \n", - "8 3 44 1 301 2 5 8 total flux 1.69e-01 \n", - "9 3 44 1 302 2 5 9 total flux 1.60e-01 \n", - "10 3 44 1 303 2 5 10 total flux 1.59e-01 \n", - "11 3 44 1 304 2 5 11 total flux 1.49e-01 \n", - "12 3 44 1 305 2 5 12 total flux 1.51e-01 \n", - "13 3 44 1 306 2 5 13 total flux 1.54e-01 \n", - "14 3 44 1 307 2 5 14 total flux 1.66e-01 \n", - "15 3 44 1 308 2 5 15 total flux 1.57e-01 \n", - "16 3 44 1 309 2 5 16 total flux 1.65e-01 \n", - "17 3 44 1 310 2 5 17 total flux 1.57e-01 \n", - "18 3 44 1 311 2 5 18 total flux 1.60e-01 \n", - "19 3 44 1 400 2 5 19 total flux 9.66e-02 \n", - "20 3 44 1 401 2 5 20 total flux 1.18e-01 \n", - "21 3 44 1 402 2 5 21 total flux 1.06e-01 \n", - "22 3 44 1 403 2 5 22 total flux 1.11e-01 \n", - "23 3 44 1 404 2 5 23 total flux 1.12e-01 \n", - "24 3 44 1 405 2 5 24 total flux 1.10e-01 \n", - "25 3 44 1 406 2 5 25 total flux 1.00e-01 \n", - "26 3 44 1 407 2 5 26 total flux 9.54e-02 \n", - "27 3 44 1 408 2 5 27 total flux 9.26e-02 \n", - "28 3 44 1 409 2 5 28 total flux 9.55e-02 \n", - "29 3 44 1 410 2 5 29 total flux 1.14e-01 \n", - "30 3 44 1 411 2 5 30 total flux 1.08e-01 \n", - "31 3 44 1 412 2 5 31 total flux 1.07e-01 \n", - "32 3 44 1 413 2 5 32 total flux 1.12e-01 \n", - "33 3 44 1 414 2 5 33 total flux 1.15e-01 \n", - "34 3 44 1 415 2 5 34 total flux 1.14e-01 \n", - "35 3 44 1 416 2 5 35 total flux 1.14e-01 \n", - "36 3 44 1 417 2 5 36 total flux 1.11e-01 \n", - "\n", - " std. dev. \n", - " \n", - " \n", - "0 7.04e-03 \n", - "1 5.27e-03 \n", - "2 7.82e-03 \n", - "3 6.47e-03 \n", - "4 6.43e-03 \n", - "5 4.89e-03 \n", - "6 3.85e-03 \n", - "7 5.82e-03 \n", - "8 8.30e-03 \n", - "9 3.09e-03 \n", - "10 5.91e-03 \n", - "11 5.31e-03 \n", - "12 6.65e-03 \n", - "13 3.67e-03 \n", - "14 4.73e-03 \n", - "15 6.54e-03 \n", - "16 5.94e-03 \n", - "17 5.73e-03 \n", - "18 4.58e-03 \n", - "19 4.47e-03 \n", - "20 5.45e-03 \n", - "21 4.72e-03 \n", - "22 4.21e-03 \n", - "23 5.08e-03 \n", - "24 4.15e-03 \n", - "25 5.08e-03 \n", - "26 3.62e-03 \n", - "27 4.00e-03 \n", - "28 4.02e-03 \n", - "29 9.53e-03 \n", - "30 7.24e-03 \n", - "31 5.72e-03 \n", - "32 5.00e-03 \n", - "33 6.24e-03 \n", - "34 4.92e-03 \n", - "35 5.32e-03 \n", - "36 5.05e-03 " - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "output_tally = sp.get_tally()\n", - "output_tally.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see that in the 'level 2' column, the 'cell id' tells us how each row corresponds to a ring and azimuthal position." - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/jupyter/capi.ipynb b/examples/jupyter/capi.ipynb deleted file mode 100644 index e696d6b01ec..00000000000 --- a/examples/jupyter/capi.ipynb +++ /dev/null @@ -1,475 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using the C/C++ API\n", - "This notebook shows how to use the OpenMC C/C++ API through the openmc.lib module. This module is particularly useful for multiphysics coupling because it allows you to update the density of materials and the temperatures of cells in memory, without stopping the simulation.\n", - "\n", - "Warning: these bindings are still somewhat experimental and may be subject to change in future versions of OpenMC." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import openmc\n", - "import openmc.lib" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Generate Input Files\n", - "\n", - "Let's start by creating a fuel rod geometry. We will make 10 zones in the z-direction which will allow us to make changes to each zone. Changes in temperature have to be made on the cell, so will make 10 cells in the axial direction. Changes in density have to be made on the material, so we will make 10 water materials. " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Materials: we will make a fuel, helium, zircaloy, and 10 water materials. " - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "material_list = []" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "uo2 = openmc.Material(material_id=1, name='UO2 fuel at 2.4% wt enrichment')\n", - "uo2.set_density('g/cm3', 10.29769)\n", - "uo2.add_element('U', 1., enrichment=2.4)\n", - "uo2.add_element('O', 2.)\n", - "material_list.append(uo2)\n", - "\n", - "helium = openmc.Material(material_id=2, name='Helium for gap')\n", - "helium.set_density('g/cm3', 0.001598)\n", - "helium.add_element('He', 2.4044e-4)\n", - "material_list.append(helium)\n", - "\n", - "zircaloy = openmc.Material(material_id=3, name='Zircaloy 4')\n", - "zircaloy.set_density('g/cm3', 6.55)\n", - "zircaloy.add_element('Sn', 0.014, 'wo')\n", - "zircaloy.add_element('Fe', 0.00165, 'wo')\n", - "zircaloy.add_element('Cr', 0.001, 'wo')\n", - "zircaloy.add_element('Zr', 0.98335, 'wo')\n", - "material_list.append(zircaloy)\n", - "\n", - "for i in range(4, 14):\n", - " water = openmc.Material(material_id=i)\n", - " water.set_density('g/cm3', 0.7)\n", - " water.add_element('H', 2.0)\n", - " water.add_element('O', 1.0)\n", - " water.add_s_alpha_beta('c_H_in_H2O')\n", - " material_list.append(water)\n", - " \n", - "materials_file = openmc.Materials(material_list)\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Cells: we will make a fuel cylinder, a gap cylinder, a cladding cylinder, and a water exterior. Each one will be broken into 10 cells which are the 10 axial zones. The z_list is the list of axial positions that delimit those 10 zones. To keep track of all the cells, we will create lists: fuel_list, gap_list, clad_list, and water_list. " - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "pitch = 1.25984\n", - "fuel_or = openmc.ZCylinder(r=0.39218)\n", - "clad_ir = openmc.ZCylinder(r=0.40005)\n", - "clad_or = openmc.ZCylinder(r=0.4572)\n", - "left = openmc.XPlane(x0=-pitch/2)\n", - "right = openmc.XPlane(x0=pitch/2)\n", - "back = openmc.YPlane(y0=-pitch/2)\n", - "front = openmc.YPlane(y0=pitch/2)\n", - "z = [0., 30., 60., 90., 120., 150., 180., 210., 240., 270., 300.]\n", - "z_list = [openmc.ZPlane(z0=z_i) for z_i in z]" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "left.boundary_type = 'reflective'\n", - "right.boundary_type = 'reflective'\n", - "front.boundary_type = 'reflective'\n", - "back.boundary_type = 'reflective'\n", - "z_list[0].boundary_type = 'vacuum'\n", - "z_list[-1].boundary_type = 'vacuum'" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "fuel_list = []\n", - "gap_list = []\n", - "clad_list = []\n", - "water_list = []\n", - "for i in range(1, 11):\n", - " fuel_list.append(openmc.Cell(cell_id=i))\n", - " gap_list.append(openmc.Cell(cell_id=i+10))\n", - " clad_list.append(openmc.Cell(cell_id=i+20))\n", - " water_list.append(openmc.Cell(cell_id=i+30))\n", - " \n", - "for j, fuels in enumerate(fuel_list):\n", - " fuels.region = -fuel_or & +z_list[j] & -z_list[j+1]\n", - " fuels.fill = uo2\n", - " fuels.temperature = 800.\n", - "\n", - "for j, gaps in enumerate(gap_list):\n", - " gaps.region = +fuel_or & -clad_ir & +z_list[j] & -z_list[j+1]\n", - " gaps.fill = helium\n", - " gaps.temperature = 700.\n", - "\n", - "for j, clads in enumerate(clad_list):\n", - " clads.region = +clad_ir & -clad_or & +z_list[j] & -z_list[j+1]\n", - " clads.fill = zircaloy\n", - " clads.temperature = 600.\n", - "\n", - "for j, waters in enumerate(water_list):\n", - " waters.region = +clad_or & +left & -right & +back & -front & +z_list[j] & -z_list[j+1]\n", - " waters.fill = material_list[j+3]\n", - " waters.temperature = 500." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "root = openmc.Universe(name='root universe')\n", - "root.add_cells(fuel_list)\n", - "root.add_cells(gap_list)\n", - "root.add_cells(clad_list)\n", - "root.add_cells(water_list)\n", - "geometry_file = openmc.Geometry(root)\n", - "geometry_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you are coupling this externally to a heat transfer solver, you will want to know the heat deposited by each fuel cell. So let's create a cell filter for the recoverable fission heat. " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "cell_filter = openmc.CellFilter(fuel_list)\n", - "t = openmc.Tally(tally_id=1)\n", - "t.filters.append(cell_filter)\n", - "t.scores = ['fission-q-recoverable']\n", - "tallies = openmc.Tallies([t])\n", - "tallies.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's plot our geometry to make sure it looks like we expect. Since we made new water materials in each axial cell, and we have centered the plot at 150, we should see one color for the water material in the bottom half and a different color for the water material in the top half. " - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAFcAAAD4CAYAAACZgnpXAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAAAIMElEQVR4nO3df6jddR3H8ecrh2K41JhL04071CxHueqiEAXSDzWhppU0CwwR1h8O+sNKK1iL9I8U8x8zmBVCxMQ/KsvKoKAWodSdqXOOxXQ2N3/MZURKaXPv/jhf19nd/XE85/u63nPu6wGX7fv9nvO9H54cvjuHe9/7qqoIjze83gsYZYlrlLhGiWuUuEaLXu8FACxZsqTGxsamPf78gV2HbR+7859sP/noVr73O555mX+fcfxh+968aMWMz9myZcv+qjpptnPPi7hjY2NMTExMe3zTvs8etv2uS+7l3V9a1sr3vuumJ3n4pxcdtu/ypT+a8TmS/tbLuXNZMEpco8Q1SlyjxDVKXKPENUpco8Q1SlyjxDVKXKPENUpco8Q1SlyjxDWaNa6kH0jaJ+mRrn0bJO2V9GDzdfGk5yyX9IKkLzoWPSx6eeXeAVw0xf5bqmpV8/XLSce+Dfxq0MUNu1l/hlZVmyWN9XpCSZcAu4AX+1/WaBjkmrtO0sPNZeNEAEnHAdcC35jtyZLWSpqQNPHcc88NsIz5q9+43wVOB1YBTwM3N/s30LlcvDDbCapqY1WNV9X4SSfN+lPqodTXj9ar6tlX/y7pduCeZvM84FOSbgROAA5K+k9V3TroQodRX3ElnVJVTzeblwKPAFTVB7oeswF4YaGGhR7iStoEnA8skbQH+DpwvqRVQAFPAJ/3LXF49fJu4fIpdn+/h+dt6GdBoySf0IwS1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXqNXxVEkfkbRF0tbmzw86Fz/ftT2euh/4WFW9E/gc8MN2ljmcWh1Praq/dG1uA46VdExVvdTn+oZaq+Opk3wSeGChhoX2x1MBkLQS+BYzzKdl9ncaVfVsVb1SVQeB24FzXz0m6TTgJ8AVVfXYDOcY+dnfvuJKOqVr89B4qqQTgF8A11XVHwde3ZBrezx1HXAGsF7S+mbfBVW1r91lD4dWx1Or6nrg+kEXNSryCc0ocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXqPVb00r6iqSdknZIutC18GHQ6uyvpLOBNcDK5jm3STqqrcUOm1njVtVm4Pkez7cauLOqXqqqXcBOugYAF5q+7kHZWCfpCmACuKaq/gGcCtzf9Zg9zb4jSFoLrAVYvnz5jN9o1aYbD9s+yL19L7qX8/OFds5rmf3tRcZTpzHD7O9eYFnXQ09r9i1Irc7+Aj8D1kg6RtIK4EzgT4MtcXi1OvtbVdsk3QU8ChwArq6qVywrHwKt35q2qm4AbhhkUaMin9CMEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S1yhxjRLXKHGNEtcocY0S16inuFONqHYdu0ZSSVrSbB8v6eeSHpK0TdKVbS96WPT6yr2DKUZUJS0DLgB2d+2+Gni0qs6hM6hys6SjB1vmcOop7gwjqrcAX6Yz1XPo4cBiSQKOa553YMB1DqW+x1MlrQb2VtVDnY6H3EpnHu0pYDHw6WYYcMHpd8jvjcBXgfVTHL4QeBB4K53x1VslvWmKc+TWtNM4HVgBPCTpCTpjqA9IOhm4EvhxdewEdgFvn3yChTD729dloaq2Aktf3W4Cj1fVfkm7gQ8Bf5D0FuAs4PEW1jp0en0rtgm4DzhL0h5JV83w8G8C75O0FfgtcG1V7R98qcOnp1fuNCOq3cfHuv7+FJ23ZwtePqEZJa5R4holrlHiGiWuUeIaJa5R4holrlHiGiWuUeIaJa5R4holrlHiGiWuUeIaJa5R4holrlHiGiWuUeIaJa5R4holrlHiGiWuUeIaJa5R4holrlHiGvV1a9quY4fN/Tb7zm9uV7tN0u/bXvAw6fvWtFPN/Uo6AbgN+HhVrQQua2WVQ2qQW9NONff7GToDfrub5+5rY5HDqt/x1ENzv5MOvQ04UdLvJG1pbl073TlGfjz1NU9Qds39TjVrtgh4L50JymOB+yTdX1V/nfzAqtoIbAQYHx+vycdHQT/jqd1zv/D/ud9z6dxE+e9V9SLwoqTNwDnAEXEXgtd8WaiqrVW1tKrGmsnJPcB7quoZ4G7g/ZIWNa/w84Dtra54iPTyVqznud+q2g7cCzxM536/36uqI97CLRT93pq2+/jYpO2bgJsGW9ZoyCc0o8Q1SlyjxDVKXKPENUpco8Q1SlyjxDVKXKPENUpco8Q1SlyjxDVS1ev/s0FJ/wJ2GE69BHD8D6hnVdXi2R7U93+r3bIdVTXe9kklTbjO28vjclkwSlyj+RJ34yied178gzaq5ssrdyQlrtG8iSvpsuYXpg9KGvjtk6SLJO2QtFPSdS2tcdpfBJ/KvIkLPAJ8Atg86IkkHQV8B/gocDZwuaSzBz0v0/wi+HTmTdyq2l5VbX1KOxfYWVWPV9XLwJ3A6kFPOsMvgk9p3sRt2anAk13be5p9c2pOP/5K+g1w8hSHvlZVd8/lWubCnMatqg/P0bfaCyzr2j6t2TenRvWy8GfgTEkrmrsIrqFzj7a5VVXz4gu4lM618SXgWeDXA57vYjrjAo/Ruey0scZNwNPAf5u1XjXT4/Px12hULwvzQuIaJa5R4holrlHiGiWu0f8AXl9L6QNoVkwAAAAASUVORK5CYII=\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "root.plot(basis='yz', width=[2, 10], color_by='material', origin=[0., 0., 150.], pixels=[400, 400])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Settings: everything will be standard except for the temperature settings. Since we will be working with specified temperatures, you will need temperature dependent data. I typically use the endf data found here: https://openmc.org/official-data-libraries/\n", - "Make sure your cross sections environment variable is pointing to temperature-dependent data before using the following settings." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "lower_left = [-0.62992, -pitch/2, 0]\n", - "upper_right = [+0.62992, +pitch/2, +300]\n", - "uniform_dist = openmc.stats.Box(lower_left, upper_right, only_fissionable=True)\n", - "\n", - "settings_file = openmc.Settings()\n", - "settings_file.batches = 100\n", - "settings_file.inactive = 10\n", - "settings_file.particles = 10000\n", - "settings_file.temperature = {'multipole': True, 'method': 'interpolation', 'range': [290, 2500]}\n", - "settings_file.source = openmc.source.Source(space=uniform_dist)\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To run a regular simulation, just use openmc.run(). \n", - "However, we want to run a simulation that we can stop in the middle and update the material and cell properties. So we will use openmc.lib." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "openmc.lib.init()\n", - "openmc.lib.simulation_init()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are 10 inactive batches, so we need to run next_batch() at least 10 times before the tally is activated. " - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "for _ in range(14):\n", - " openmc.lib.next_batch()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's take a look at the tally. There are 10 entries, one for each cell in the fuel." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[ 4178272.4202991 ]\n", - " [ 9595363.82759911]\n", - " [12307462.30060902]\n", - " [11772927.66594472]\n", - " [11892601.29001472]\n", - " [12203397.88895767]\n", - " [12851791.20965905]\n", - " [11760027.45873386]\n", - " [ 9293110.94735569]\n", - " [ 4511597.61592287]]\n" - ] - } - ], - "source": [ - "t = openmc.lib.tallies[1]\n", - "print(t.mean)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let's make some changes to the temperatures. For this, we need to identify each cell by its id. We can use get_temperature() to compare the temperatures of the cells before and after the change. " - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "fuel temperature is: \n", - "800.0\n", - "gap temperature is: \n", - "700.0\n", - "clad temperature is: \n", - "600.0\n", - "water temperature is: \n", - "500.00000000000006\n" - ] - } - ], - "source": [ - "print(\"fuel temperature is: \")\n", - "print(openmc.lib.cells[5].get_temperature())\n", - "print(\"gap temperature is: \")\n", - "print(openmc.lib.cells[15].get_temperature())\n", - "print(\"clad temperature is: \")\n", - "print(openmc.lib.cells[25].get_temperature())\n", - "print(\"water temperature is: \")\n", - "print(openmc.lib.cells[35].get_temperature())" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "for i in range(1, 11):\n", - " temp = 900.0\n", - " openmc.lib.cells[i].set_temperature(temp)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "fuel temperature is: \n", - "899.9999999999999\n" - ] - } - ], - "source": [ - "print(\"fuel temperature is: \")\n", - "print(openmc.lib.cells[5].get_temperature())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's make a similar change for the water density. Again, we need to identify each material by its id." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "for i in range(4, 14):\n", - " density = 0.65\n", - " openmc.lib.materials[i].set_density(density, units='g/cm3')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The new batches we run will use the new material and cell properties." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "for _ in range(14):\n", - " openmc.lib.next_batch()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When you're ready to end the simulation, use the following:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "openmc.lib.simulation_finalize()\n", - "openmc.lib.finalize()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/jupyter/chain_simple.xml b/examples/jupyter/chain_simple.xml deleted file mode 120000 index 96f6fa8818e..00000000000 --- a/examples/jupyter/chain_simple.xml +++ /dev/null @@ -1 +0,0 @@ -../../tests/chain_simple.xml \ No newline at end of file diff --git a/examples/jupyter/expansion-filters.ipynb b/examples/jupyter/expansion-filters.ipynb deleted file mode 100644 index 3b0413a0582..00000000000 --- a/examples/jupyter/expansion-filters.ipynb +++ /dev/null @@ -1,1548 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Functional Expansions\n", - "OpenMC's general tally system accommodates a wide range of tally *filters*. While most filters are meant to identify regions of phase space that contribute to a tally, there are a special set of functional expansion filters that will multiply the tally by a set of orthogonal functions, e.g. Legendre polynomials, so that continuous functions of space or angle can be reconstructed from the tallied moments.\n", - "\n", - "In this example, we will determine the spatial dependence of the flux along the $z$ axis by making a Legendre polynomial expansion. Let us represent the flux along the z axis, $\\phi(z)$, by the function\n", - "\n", - "$$ \\phi(z') = \\sum\\limits_{n=0}^N a_n P_n(z') $$\n", - "\n", - "where $z'$ is the position normalized to the range [-1, 1]. Since $P_n(z')$ are known functions, our only task is to determine the expansion coefficients, $a_n$. By the orthogonality properties of the Legendre polynomials, one can deduce that the coefficients, $a_n$, are given by\n", - "\n", - "$$ a_n = \\frac{2n + 1}{2} \\int_{-1}^1 dz' P_n(z') \\phi(z').$$\n", - "\n", - "Thus, the problem reduces to finding the integral of the flux times each Legendre polynomial -- a problem which can be solved by using a Monte Carlo tally. By using a Legendre polynomial filter, we obtain stochastic estimates of these integrals for each polynomial order." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import openmc\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To begin, let us first create a simple model. The model will be a slab of fuel material with reflective boundaries conditions in the x- and y-directions and vacuum boundaries in the z-direction. However, to make the distribution slightly more interesting, we'll put some B4C in the middle of the slab." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Define fuel and B4C materials\n", - "fuel = openmc.Material()\n", - "fuel.add_element('U', 1.0, enrichment=4.5)\n", - "fuel.add_nuclide('O16', 2.0)\n", - "fuel.set_density('g/cm3', 10.0)\n", - "\n", - "b4c = openmc.Material()\n", - "b4c.add_element('B', 4.0)\n", - "b4c.add_element('C', 1.0)\n", - "b4c.set_density('g/cm3', 2.5)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Define surfaces used to construct regions\n", - "zmin, zmax = -10., 10.\n", - "box = openmc.model.rectangular_prism(10., 10., boundary_type='reflective')\n", - "bottom = openmc.ZPlane(z0=zmin, boundary_type='vacuum')\n", - "boron_lower = openmc.ZPlane(z0=-0.5)\n", - "boron_upper = openmc.ZPlane(z0=0.5)\n", - "top = openmc.ZPlane(z0=zmax, boundary_type='vacuum')\n", - "\n", - "# Create three cells and add them to geometry\n", - "fuel1 = openmc.Cell(fill=fuel, region=box & +bottom & -boron_lower)\n", - "absorber = openmc.Cell(fill=b4c, region=box & +boron_lower & -boron_upper)\n", - "fuel2 = openmc.Cell(fill=fuel, region=box & +boron_upper & -top)\n", - "geom = openmc.Geometry([fuel1, absorber, fuel2])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For the starting source, we'll use a uniform distribution over the entire box geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "settings = openmc.Settings()\n", - "spatial_dist = openmc.stats.Box(*geom.bounding_box)\n", - "settings.source = openmc.Source(space=spatial_dist)\n", - "settings.batches = 210\n", - "settings.inactive = 10\n", - "settings.particles = 1000" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Defining the tally is relatively straightforward. One simply needs to list 'flux' as a score and then add an expansion filter. For this case, we will want to use the `SpatialLegendreFilter` class which multiplies tally scores by Legendre polynomials evaluated on normalized spatial positions along an axis." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a flux tally\n", - "flux_tally = openmc.Tally()\n", - "flux_tally.scores = ['flux']\n", - "\n", - "# Create a Legendre polynomial expansion filter and add to tally\n", - "order = 8\n", - "expand_filter = openmc.SpatialLegendreFilter(order, 'z', zmin, zmax)\n", - "flux_tally.filters.append(expand_filter)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The last thing we need to do is create a `Tallies` collection and export the entire model, which we'll do using the `Model` convenience class." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "tallies = openmc.Tallies([flux_tally])\n", - "model = openmc.model.Model(geometry=geom, settings=settings, tallies=tallies)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Running a simulation is now as simple as calling the `run()` method of `Model`." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "sp_file = model.run(output=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that the run is finished, we need to load the results from the statepoint file." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "with openmc.StatePoint(sp_file) as sp:\n", - " df = sp.tallies[flux_tally.id].get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We've used the `get_pandas_dataframe()` method that returns tally data as a Pandas dataframe. Let's see what the raw data looks like." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
spatiallegendrenuclidescoremeanstd. dev.
0P0totalflux36.5236010.081540
1P1totalflux-0.0028300.041466
2P2totalflux-4.4119230.027161
3P3totalflux0.0043160.020245
4P4totalflux-0.2772810.014558
5P5totalflux0.0106040.011350
6P6totalflux0.1092120.010280
7P7totalflux-0.0027050.009100
8P8totalflux-0.0884690.007889
\n", - "
" - ], - "text/plain": [ - " spatiallegendre nuclide score mean std. dev.\n", - "0 P0 total flux 3.65e+01 8.15e-02\n", - "1 P1 total flux -2.83e-03 4.15e-02\n", - "2 P2 total flux -4.41e+00 2.72e-02\n", - "3 P3 total flux 4.32e-03 2.02e-02\n", - "4 P4 total flux -2.77e-01 1.46e-02\n", - "5 P5 total flux 1.06e-02 1.13e-02\n", - "6 P6 total flux 1.09e-01 1.03e-02\n", - "7 P7 total flux -2.71e-03 9.10e-03\n", - "8 P8 total flux -8.85e-02 7.89e-03" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since the expansion coefficients are given as\n", - "\n", - "$$ a_n = \\frac{2n + 1}{2} \\int_{-1}^1 dz' P_n(z') \\phi(z')$$\n", - "\n", - "we just need to multiply the Legendre moments by $(2n + 1)/2$." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "n = np.arange(order + 1)\n", - "a_n = (2*n + 1)/2 * df['mean']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To plot the flux distribution, we can use the `numpy.polynomial.Legendre` class which represents a truncated Legendre polynomial series. Since we really want to plot $\\phi(z)$ and not $\\phi(z')$ we first need to perform a change of variables. Since\n", - "\n", - "$$ \\lvert \\phi(z) dz \\rvert = \\lvert \\phi(z') dz' \\rvert $$\n", - "\n", - "and, for this case, $z = 10z'$, it follows that\n", - "\n", - "$$ \\phi(z) = \\frac{\\phi(z')}{10} = \\sum_{n=0}^N \\frac{a_n}{10} P_n(z'). $$" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "phi = np.polynomial.Legendre(a_n/10, domain=(zmin, zmax))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's plot it and see how our flux looks!" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Flux [n/src]')" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "z = np.linspace(zmin, zmax, 1000)\n", - "plt.plot(z, phi(z))\n", - "plt.xlabel('Z position [cm]')\n", - "plt.ylabel('Flux [n/src]')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As you might expect, we get a rough cosine shape but with a flux depression in the middle due to the boron slab that we introduced. To get a more accurate distribution, we'd likely need to use a higher order expansion.\n", - "\n", - "One more thing we can do is confirm that integrating the distribution gives us the same value as the first moment (since $P_0(z') = 1$). This can easily be done by numerically integrating using the trapezoidal rule:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "36.523562389125146" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.trapz(phi(z), z)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In addition to being able to tally Legendre moments, there are also functional expansion filters available for spherical harmonics (`SphericalHarmonicsFilter`) and Zernike polynomials over a unit disk (`ZernikeFilter`). A separate `LegendreFilter` class can also be used for determining Legendre scattering moments (i.e., an expansion of the scattering cosine, $\\mu$)." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Zernike polynomials\n", - "\n", - "Now let's look at an example of functional expansion tallies using Zernike polynomials as the basis functions.\n", - "\n", - "In this example, we will determine the spatial dependence of the flux along the radial direction $r'$ and $/$ or azimuthal angle $\\theta$ by making a Zernike polynomial expansion. Let us represent the flux along the radial and azimuthal direction, $\\phi(r', \\theta)$, by the function\n", - "\n", - "$$ \\phi(r', \\theta) = \\sum\\limits_{n=0}^N \\sum\\limits_{m=-n}^n a_n^m Z_n^m(r', \n", - "\\theta) $$\n", - "\n", - "where $r'$ is the position normalized to the range [0, r] (r is the radius of cylindrical geometry), and the azimuthal lies within the range [0, $ 2\\pi$]. \n", - "\n", - "Since $Z_n^m(r', \\theta)$ are known functions, we need to determine the expansion coefficients, $a_n^m$. By the orthogonality properties of the Zernike polynomials, one can deduce that the coefficients, $a_n^m$, are given by\n", - "\n", - "$$ a_n^m = k_n^m \\int_{0}^r dr' \\int_{0}^{2\\pi} d\\theta Z_n^m(r',\\theta) \\phi(r', \\theta).$$\n", - "$$ k_n^m = \\frac{2n + 2}{\\pi}, m \\ne 0. $$\n", - "$$ k_n^m = \\frac{n+1}{\\pi}, m = 0.$$\n", - "\n", - "Similarly, the problem reduces to finding the integral of the flux times each Zernike polynomial." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To begin with, let us first create a simple model. The model will be a pin-cell fuel material with vacuum boundary condition in both radial direction and axial direction." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "# Define fuel \n", - "fuel = openmc.Material()\n", - "fuel.add_element('U', 1.0, enrichment=5.0)\n", - "fuel.add_nuclide('O16', 2.0)\n", - "fuel.set_density('g/cm3', 10.0)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Define surfaces used to construct regions\n", - "zmin, zmax, radius = -1., 1., 0.5 \n", - "pin = openmc.ZCylinder(x0=0.0, y0=0.0, r=radius, boundary_type='vacuum')\n", - "bottom = openmc.ZPlane(z0=zmin, boundary_type='vacuum')\n", - "top = openmc.ZPlane(z0=zmax, boundary_type='vacuum')\n", - "\n", - "# Create three cells and add them to geometry\n", - "fuel = openmc.Cell(fill=fuel, region= -pin & +bottom & -top)\n", - "geom = openmc.Geometry([fuel])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For the starting source, we'll use a uniform distribution over the entire box geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "settings = openmc.Settings()\n", - "spatial_dist = openmc.stats.Box(*geom.bounding_box)\n", - "settings.source = openmc.Source(space=spatial_dist)\n", - "settings.batches = 100\n", - "settings.inactive = 20\n", - "settings.particles = 100000" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Defining the tally is relatively straightforward. One simply needs to list 'flux' as a score and then add an expansion filter. For this case, we will want to use the `SpatialLegendreFilter`, `ZernikeFilter`, `ZernikeRadialFilter` classes which multiplies tally scores by Legendre, azimuthal Zernike and radial-only Zernike polynomials evaluated on normalized spatial positions along radial and axial directions." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a flux tally\n", - "flux_tally_legendre = openmc.Tally()\n", - "flux_tally_legendre.scores = ['flux']\n", - "\n", - "# Create a Legendre polynomial expansion filter and add to tally\n", - "order = 10\n", - "cell_filter = openmc.CellFilter(fuel)\n", - "legendre_filter = openmc.SpatialLegendreFilter(order, 'z', zmin, zmax)\n", - "flux_tally_legendre.filters = [cell_filter, legendre_filter]\n", - "\n", - "# Create a Zernike azimuthal polynomial expansion filter and add to tally \n", - "flux_tally_zernike = openmc.Tally()\n", - "flux_tally_zernike.scores = ['flux']\n", - "zernike_filter = openmc.ZernikeFilter(order=order, x=0.0, y=0.0, r=radius)\n", - "flux_tally_zernike.filters = [cell_filter, zernike_filter]\n", - "\n", - "# Create a Zernike radial polynomial expansion filter and add to tally \n", - "flux_tally_zernike1d = openmc.Tally()\n", - "flux_tally_zernike1d.scores = ['flux']\n", - "zernike1d_filter = openmc.ZernikeRadialFilter(order=order, x=0.0, y=0.0, r=radius)\n", - "flux_tally_zernike1d.filters = [cell_filter, zernike1d_filter]\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The last thing we need to do is create a `Tallies` collection and export the entire model, which we'll do using the `Model` convenience class." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "tallies = openmc.Tallies([flux_tally_legendre, flux_tally_zernike, flux_tally_zernike1d])\n", - "model = openmc.model.Model(geometry=geom, settings=settings, tallies=tallies)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Running a simulation is now as simple as calling the `run()` method of `Model`." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "sp_file = model.run(output=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that the run is finished, we need to load the results from the statepoint file." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "with openmc.StatePoint(sp_file) as sp:\n", - " df1 = sp.tallies[flux_tally_legendre.id].get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We've used the `get_pandas_dataframe()` method that returns tally data as a Pandas dataframe. Let's see what the raw data looks like." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellspatiallegendrenuclidescoremeanstd. dev.
04P0totalflux0.5434250.000599
14P1totalflux0.0006350.000523
24P2totalflux-0.0559890.000342
34P3totalflux-0.0000530.000284
44P4totalflux-0.0007490.000230
54P5totalflux0.0001110.000149
64P6totalflux-0.0006920.000177
74P7totalflux-0.0000640.000152
84P8totalflux-0.0001390.000142
94P9totalflux0.0002010.000119
104P10totalflux-0.0000510.000112
\n", - "
" - ], - "text/plain": [ - " cell spatiallegendre nuclide score mean std. dev.\n", - "0 4 P0 total flux 5.43e-01 5.99e-04\n", - "1 4 P1 total flux 6.35e-04 5.23e-04\n", - "2 4 P2 total flux -5.60e-02 3.42e-04\n", - "3 4 P3 total flux -5.27e-05 2.84e-04\n", - "4 4 P4 total flux -7.49e-04 2.30e-04\n", - "5 4 P5 total flux 1.11e-04 1.49e-04\n", - "6 4 P6 total flux -6.92e-04 1.77e-04\n", - "7 4 P7 total flux -6.41e-05 1.52e-04\n", - "8 4 P8 total flux -1.39e-04 1.42e-04\n", - "9 4 P9 total flux 2.01e-04 1.19e-04\n", - "10 4 P10 total flux -5.05e-05 1.12e-04" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df1" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since the scaling factors for expansion coefficients will be provided by the Python API, thus, we do not need to multiply the moments by scaling factors." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "a_n = df1['mean']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Loading the coefficients is realized via calling the OpenMC Python API as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "phi = openmc.legendre_from_expcoef(a_n, domain=(zmin, zmax))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's plot it and see how our flux looks!" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Flux [n/src]')" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEICAYAAABF82P+AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3deXhU5dnH8e+dHUhCgLAlkIQlIFsIEBDBXVRwAUWrUHFv3du6tWr1tdZqrdW2rq1Sa9XWDXEpIAoCCiKiBGQPSwgIIUDCmrAkZLnfP+bQjmFCJjCTk2Tuz3XNxczZ5peTYe6c85znOaKqGGOMMdWFuR3AGGNMw2QFwhhjjE9WIIwxxvhkBcIYY4xPViCMMcb4ZAXCGGOMT0EtECIyUkTWikiuiNzvY/4tIrJCRJaKyHwR6e1MTxORQ870pSLyUjBzGmOMOZoEqx+EiIQD64BzgXxgETBeVVd7LROvqsXO89HAbao6UkTSgGmq2tff90tMTNS0tLTA/QDGGBMCFi9evFNV2/qaFxHE9x0C5KpqHoCIvAOMAf5bII4UB0cL4LirVVpaGtnZ2ce7ujHGhCQR+b6mecE8xZQMbPF6ne9M+wERuV1ENgB/BH7uNauLiHwnInNF5LQg5jTGGONDMAuE+Jh21BGCqr6oqt2A+4CHnMnbgBRVHQDcDbwlIvFHvYHITSKSLSLZRUVFAYxujDEmmAUiH+js9boTUHCM5d8BLgFQ1TJV3eU8XwxsAHpUX0FVJ6pqlqpmtW3r8xSaMcaY4xTMArEISBeRLiISBYwDpngvICLpXi8vBNY709s6jdyISFcgHcgLYlZjjDHVBK2RWlUrROQOYAYQDryqqqtE5FEgW1WnAHeIyAigHNgDXOusfjrwqIhUAJXALaq6O1hZjTHGHC1ol7nWt6ysLLWrmIwxpm5EZLGqZvmaZz2pjTHG+BTMfhDGhBxVZd+hcgpLyihyHiVlFZSVV1JaXsnhSiUqXIiOCCcqIozY6AjaxkX/99GmRRQivi4ANKb+WYEw5jgVl5azfMs+lm/dS27hfjYUHSCvcD8lZRXHvc3Y6Ai6tW1Bt3ax9Ggfx4DOCWR0SqBZVHgAkxvjHysQxvhp94HDfLm+iAW5u1iyeQ+5Rfs50oTXIT6Gbu1acOnAZFJaN6d9fMx/jwriYiKIiQwnJiKcyHChvFI5XFlFWXklJaUVFO33HGnsKC5l084D5Bbt56vcnXywZCsAEWFCn6R4Tu7ahrNPaseg1FZEhtvZYRN81khtTA1UlZxtJXy6chtz1xWxfOs+VKFls0gGpiQwIKUVA1I8f+G3bBYZ8PfffeAw323eQ/b3e1i8aQ/fbdlDeaUSHxPB6T3acmG/jpzdqx3REXZ0YY7fsRqprUAYU826HSVMXVbAx8u3kbfzAGECA1JacXp6W07vkUhGpwTCw+q/nWB/WQXz1xcxZ00hc9YUsnP/YeJjIrgwI4nLBiYzKLWVtV+YOrMCYUwtDpRVMHVZAW9/u5ll+fsIEzilWxsu7JfE+X3a0yY22u2IP1BRWcVXG3bx4ZJ8ZqzawaHySnp1jOf64WmM7p9ETKQdVRj/WIEwpgZrthfz+oLvmbJ0KwcOV9KjfSzjBqcwOjOJxAZWFGpyoKyCKcsKeO2rTazdUULrFlFMGJrKjcO70LJ54E99mabFCoQxXlSVrzfs4uV5ecxdV0RMZBgXZSQxfkgKA1MSGu1pGlXl67xdvDp/E7NydhAXHcH1w9O48dSuVihMjaxAGANUVSmfrtrOX7/IZeXWYhJjo7huWBoThqaS0DzK7XgBlbOtmOdmr+eTlduJi47g5jO68pPTutqpJ3MUKxAmpKkqc9YU8qeZ61i9rZiuiS346elduXRAcpP/wlyzvZg/z1zHzNU7SGoZw32jTmJ0/6RGe5RkAs8KhAlZX+Xu5KkZa1m6ZS+pbZpz14geXNw/yZWrkNz09YZdPPbxalYVFJPZOYHHL+1Ln6SWbscyDYAVCBNy8or28/jHOcxeU0hyQjN+fk53xg7sFNIdzKqqlPeX5PPkp2vYc7Ccn5zahTtH9LBe2iHuWAXCelKbJmXfoXKem72e1xdsIiYynAdGncR1w9OsMxkQFib8KKsz5/ZuzxPT1/DyvDymr9zG45f04/QedsMtczQ7gjBNgqrywZKtPD49hz0HD3NlVmfuOa8nbeMax6WqbliYt4tff7CCvJ0HmDA0hQcv6G1HEyHIjiBMk7Zp5wEe/GgFX+XuYmBKAm/cMIS+yXZ+vTZDu7Zh+i9O408z1/L3LzeyIHcXz4zLJKNTgtvRTANhRxCm0SqvrGLivDyem72eqPAw7ht1Ej8ekkJYiDVAB8KC3J3c894yikrKuHNEOree2T3kGvJDlR1BmCZn/Y4S7pq0lJVbixnVtwOPjO5D+/gYt2M1WsO6J/LpL07nof+s5OmZ6/hm426eHTeA1i2aVv8QUzehe0mHaZSqqpR/zN/Ihc/Pp2BvKS9NGMjfJgyy4hAALZtH8ty4TJ4Y249vNu7mwue+ZMnmPW7HMi6yAmEajYK9h5jwj2/43bTVnNY9kU/vPI2RfTu6HatJERHGD0nhg1uHEREuXPHS1/zzq400lVPRpm6sQJhGYeaq7Yx8Zh5Lt+zlD2P78cq1WbSLs6OGYOmb3JJpd5zGmT3b8dupq7nv/eUcrqhyO5apZ9YGYRq08soqnvxkDa/M30hGp5Y8P34AqW1auB0rJLRsHsnEqwfxl1nreH5OLpt2HeSlCYOsXSKE2BGEabC27j3EFS9/zSvzN3LdsDTeu+UUKw71LCxMuOe8njw7LpOlW/Yy5sX5rNtR4nYsU0+sQJgGae66Ii587kvW79jPiz8eyCOj+1hvaBeNyUxm0s2nUFpexdi/LuDL9UVuRzL1wAqEaVBUlVe+zOP6f35Lh/gYpv7sVC7MsIbohiCzcwJT7hhOp1bNuOG1Rfxn6Va3I5kgswJhGoyyikp+OXk5j32cw8i+HfjgtmF0SbRTSg1Jx5bNePfmUxiY0opfvLOUV77MczuSCSIrEKZBKCwpZfzEhUxenM+dI9J5YfxAmkfZNRQNUctmkbx+wxAu6NeBxz7O4fGPV1NVZZfBNkX2P9C4bs32Yq7/5yL2Hiznb1cNZFQ/O6XU0MVEhvP8+IEkxq7i719uZOf+wzx1eQYRITycelNkBcK4asGGndz8xmJaREcw+dZT7CY2jUh4mPDb0X1oFxfN0zPXUVpeybPjBhAVYUWiqbDfpHHN1GUFXPfqIjq0jOGD24ZZcWiERIQ7zk7n/y7qzScrt3Pbm4spLa90O5YJECsQxhWvfJnHz97+jszOCUy+ZRhJCc3cjmROwI2nduF3l/RlVk4hP30jm0OHrUg0BVYgTL1SVX4/PYfHPs7hgn4deOPGIbRsHul2LBMAVw9N5Y+XZTA/dyfXv/YtB8oq3I5kTpAVCFNvqqqUhz5aycR5eVxzSirPjx9ITKR1fmtKrhjcmWeuzGTRpj3c+PoiO5Jo5KxAmHpRWaX8cvJy3vxmM7ec0Y3fju5jN6RposZkJvPnK/rzzcbd3PSvbGuTaMSsQJigK6+s4hfvfMf7S/K5a0QP7hvZExErDk3ZmMxk/nhZBl+u38ltby6xkWAbKSsQJqjKKiq57c0lTFu+jV9fcBK/GJFuxSFE/CirM7+/tB9z1hTys7eXUF5pRaKxCWqBEJGRIrJWRHJF5H4f828RkRUislRE5otIb695DzjrrRWR84OZ0wRHeWUVt7/5HZ+t3sGjY/pw0+nd3I5k6tmPT07hkYt7M2PVDu6etIxK63HdqASto5yIhAMvAucC+cAiEZmiqqu9FntLVV9ylh8N/BkY6RSKcUAfIAmYJSI9VNVOZjYSFZVV3PnOUmbleIrDNaekuR3JuOS64V04XFnF76evITY6gt9f2teOIhuJYPakHgLkqmoegIi8A4wB/lsgVLXYa/kWwJE/L8YA76hqGbBRRHKd7X0dxLwmQKqqlF9NXs7HK7bx4AW9rDgYbjq9G/sOlfPi5xtIjI3invN6uh3J+CGYBSIZ2OL1Oh84ufpCInI7cDcQBZztte7Causm+1j3JuAmgJSUlICENidGVXnwoxV88N1W7jm3Bz89vavbkUwDce95Pdm1/zDPz8mlTYsorhvexe1IphbBbIPwdQx51AlIVX1RVbsB9wEP1XHdiaqapapZbdu2PaGw5sSpKr+dupq3v93C7Wd142fnpLsdyTQgIsJjl/Tl/D7teWTqarufRCMQzAKRD3T2et0JKDjG8u8AlxznuqYBePHzXF5bsIkbhnfhXjuFYHyICA/j2XEDOLlLa+6ZtIy56+zOdA1ZMAvEIiBdRLqISBSeRucp3guIiPefmBcC653nU4BxIhItIl2AdODbIGY1J2jSoi08PXMdlw5I5qELe1kjpKlRTGQ4f782i/T2cdz678Us27LX7UimBkErEKpaAdwBzABygEmqukpEHnWuWAK4Q0RWichSPO0Q1zrrrgIm4WnQ/hS43a5garhm5+zggQ9XcFp6Ik9elkGY9ZA2tYiPieT1GwbTJjaKG19fxJbdB92OZHwQ1aZxXXJWVpZmZ2e7HSPkLP5+D1e9spAe7eN4+6dDaRFttxgx/sstLGHsXxfQPj6GybcOo2UzG7ixvonIYlXN8jXPelKb45ZbuJ8bX19E+/gYXr1usBUHU2fd28Xx0tWD2LTrALe9udiG5GhgrECY47L7wGFueG0R4SK8ccMQEmOj3Y5kGqlh3RJ5YmwGX+Xu4sEPV9BUzmo0BfYnn6mzsopKbvnXYrYXl/L2T4eS2qaF25FMI3f5oE5s3n2Q52avJy2xBbef1d3tSAYrEKaOVJUHP1zJt5t28+y4TAaltnI7kmki7hqRzuZdB3hqxlo6t27O6P5JbkcKeXaKydTJy/PymLw4n5+fk86YzKM6txtz3ESEJy/PYEhaa3753jJW5O9zO1LIswJh/DZj1Xae/HQNF2V05K4R1kvaBF50RDh/nTCQxNhobvpXNoUlpW5HCmlWIIxf1mwv5s53lpLRKYGnf9TfOsKZoEmMjWbiNYPYe7CcW/61mLIK6wLlFisQplb7DpVz878WExsTwcSrB9l9pE3Q9UlqydM/6s+SzXv5v49W2pVNLrECYY6pqkq5692lbN1ziL9dNZD28TFuRzIh4sKMjvzs7O5Mys7ntQWb3I4TkqxAmGN6bs565qwp5OGLe5OV1trtOCbE3DWiB+f2bs9jH+fwVe5Ot+OEHCsQpkazc3bwzKz1XDawE1cPTXU7jglBYWHCX67MpFvbFtz25hIbs6meWYEwPm3aeYA7311Kn6R4HrdbRBoXxUZH8PdrsqhS5dY3F1Nabo3W9cUKhDlKaXklt765hPAw4aUJ1iht3JfapgV/viKTlVuL+e3UVW7HCRlWIMxRHv84h5xtxfz5iv50bt3c7TjGAHBu7/bcdmY33v52C5Oyt9S+gjlhViDMD0xfsY1/Lfyem07vytkntXc7jjE/cPe5PRjWrQ3/99FKVhVYT+tgswJh/mvzroPcN3k5mZ0T7JahpkGKCA/jufEDaNU8ilv/vYR9h8rdjtSkWYEwAByuqOJnby8BgefHDyAqwj4apmFKjI3mxasGUrD3EPdMWkpVlXWiCxb7FjAAPPnpGpbl7+OpyzOs3cE0eINSW/HQhb2YlVPIS/M2uB2nybICYZids4N/zN/ItaekMrJvR7fjGOOXa4elcWFGR/40cx2Lv9/jdpwmyQpEiCsqKeNXk5fTq2M8D1zQy+04xvhNRHhibD86tozh529/x76D1h4RaFYgQpiqcv/7yykpq+DZcZnW38E0OvExkTw/fgA7iku5/4PlNqhfgFmBCGFvfbuZ2WsKuW/kSfRoH+d2HGOOy4CUVvzy/J58snI7b36z2e04TYoViBCVV7Sfx6blMLx7G64fluZ2HGNOyE9P68rpPdry6LTV5GwrdjtOk2EFIgSVV1Zx16RlRIYLT/+oP2FhNs6SadzCwoQ/X9Gfls0i+dnb33HwcIXbkZoEKxAh6IU5uSzbspffj+1Hx5bN3I5jTEAkxkbzlysy2VC0n0em2HhNgWAFIsQs3bKXFz7P5dIByVyUkeR2HGMC6tT0RG47sxuTsvP5ZMU2t+M0elYgQkhpeSX3vreMdnHRPDK6j9txjAmKO0f0IKNTSx74cAWFxaVux2nUrECEkGdnrye3cD9PjO1Hy2aRbscxJigiw8P4y5WZlJZX8svJdunribACESKW5+9l4rw8fjSoE2f2bOd2HGOCqlvbWH59QS/mrivi3wu/dztOo2UFIgSUVVTyy/eWkxgbxUMX9XY7jjH14uqhqZzeoy2PT89hQ9F+t+M0ShHHmikiU/zYxm5VvS4wcUwwvDAnl7U7Snj1uiw7tWRChojw1OUZnP/MPO56dynv3zqMyHD7m7gujlkggF7AT44xX4AXAxfHBNrKrfv46xcbGDsw2W4AZEJO+/gYnri0H7e+uYTnZ6/nbrvPSZ3UViAeVNW5x1pARH4bwDwmgA5XVHHve8to3SKKh+3UkglRo/p1ZOzAZF74PJezTmrHgJRWbkdqNI55vKWqk2rbgD/LGHe8NHcDa7aX8PtL+5HQPMrtOMa45pHRfWgfH8OvJi+ntLzS7TiNhl8n5ETkMxFJ8HrdSkRmBC+WOVEbivbzwpxcLsroyLm97dSSCW3xMZE8MbYf6wv389zs9W7HaTT8bbFJVNW9R16o6h6g1mslRWSkiKwVkVwRud/H/LtFZLWILBeR2SKS6jWvUkSWOg9/GsuNQ1V58MMVxESG8fDFdmrJGIAze7bjR4M68fK8PFbk73M7TqPgb4GoEpGUIy+cL/Jj9j4RkXA8DdijgN7AeBGp/m31HZClqhnAZOCPXvMOqWqm8xjtZ04DTF6cz8K83dw/qhft4mLcjmNMg/HQRb1JjI3i3veWcbiiyu04DZ6/BeJBYL6I/EtE/gXMAx6oZZ0hQK6q5qnqYeAdYIz3Aqr6uaoedF4uBDr5H934smt/GY9PzyErtRXjBnd2O44xDUrLZp5TTWt3lPDCHDvVVJtaC4SICLAKGAi8C0wCBqlqbW0QycAWr9f5zrSa3Ah84vU6RkSyRWShiFxSW07j8fjHORwoq+CJsf1sGG9jfDj7pPaMHZDMX7/YwKoCO9V0LLUWCPUMZPKRqu5U1WmqOlVVd/qxbV/fTj5PS4nIBCALeMprcoqqZgE/Bp4RkW4+1rvJKSLZRUVFfkRq2uav38kH323lljO6kW53iDOmRg9f3JtWLaK4973llFfaqaaa+HuKaaGIDK7jtvMB73McnYCC6guJyAg8p7BGq2rZkemqWuD8mwd8AQyovq6qTlTVLFXNatu2bR3jNS2l5ZU8+NEKuiS24Pazursdx5gGLaF5FI9f0pecbcW88uVGt+M0WP4WiLOAr0Vkg3PF0QoRWV7LOouAdBHpIiJRwDjgB1cjicgA4GU8xaHQa3orEYl2nicCw4HVfmYNSS/MyeX7XQd5/JK+xESGux3HmAbvvD4dOL9Pe56dvY7Nuw7WvkII8rdAjAK6AWcDFwMXOf/WSFUrgDuAGUAOMElVV4nIoyJy5Kqkp4BY4L1ql7P2ArJFZBnwOfAHVbUCUYPcwhJenucZTmNY90S34xjTaPx2dF8iwsJ46D8rbVhwH2obasN7uXxVLRORM4EM4I3aVlLV6cD0atMe9no+oob1FgD9/MwW0lSV30xZRbPIcB68oJfbcYxpVDq0jOGX5/fkN1NWMWVZAWMyj3UdTejx9wjifaBSRLoD/wC6AG8FLZXx2/QV2/kqdxf3nt+TNrHRbscxptGZMDSV/p0T+N201ew9eNjtOA2K3x3lnFNGY4FnVPUuoGPwYhl/HCir4LGPV9O7YzxXnZxa+wrGmKOEhwm/v7Qvew6W84dP1rgdp0Hxt0CUi8h44BpgmjPNbizgshc+z2XbvlJ+d0kfwq3PgzHHrU9SS248tQvvLNrCtxt3ux2nwfC3QFwPnAI8rqobRaQL8O/gxTK12VC0n1e+zOOygZ0YlNra7TjGNHp3jkgnOaEZv/5whQ3D4ThmgRCRiSJyKbBFVX+uqm8DqOpGVf1DvSQ0R1FVHpmyipjIcO4fdZLbcYxpEppHRfDomD7kFu7ntQXWNwJqP4J4FegPTHdGW71PRPrXQy5zDJ+u3M6X63dyz7k9aBtnDdPGBMo5vdpzzknteHbWenYUl7odx3W13TBooao+oqqnAVcAm4F7nD4Lr4rIFfWS0vzXwcMV/G7aak7qEMeEodYwbUygPXxxb8orlSem57gdxXV+38FbVXep6tuqeo2qZuIZyjs9eNGML3/7YgMF+0r53SV9ibAbsBsTcKltWnDzGV35aGkB3+TtcjuOq/zqKOcMe3EZkOa9jqo+GpxYxpf8PQeZOC+PMZlJDE6zhmljguW2M7vzwZKt/GbKKqb97NSQ/WPM35/6P3ju5VABHPB6mHr05KdrEYH7RlrDtDHB1CwqnIcu7MWa7SW8+c1mt+O4xt+hNjqp6sigJjHHlL1pN1OXFfCLc9JJSmjmdhxjmryRfTswvHsb/jRzLRdldAzJkQr8PYJYICI2NpJLqqqUR6etpkN8DDef0dXtOMaEBBHhkYv7cPBwJU/PXOt2HFf4WyBOBRaLyNo6DPdtAuTD77ayPH8f943qSfMofw/6jDEnKr19HFefksq7i7awdnuJ23HqXV2G+04HzsPP4b5NYBwoq+CPM9bQv3MCY/rbSJPG1LdfnJNObHQEj4fgZa9+FQhV/d7XI9jhDLw8dwM7ist4+KLedo9pY1yQ0DyKn5+Tzrx1RXyxtrD2FZqQ2obaWFLbBvxZxhyfrXsP8fK8PEb3T2JQaiu34xgTsq45JY20Ns35/fQcKkLoHta1HUH0ctocanqsAOwWZkHy5CdrPJe12nhLxrgqKiKM+0edxLod+3k3e4vbcepNbS2e/nwzVQYiiPmhxd/vYcqyAn5+jmeESWOMu87v04Ehaa35y2frGN0/ibiYpn/Hg9rGYvLZ9lDtkV9fYUOFqmccmLZx0dx8ul3WakxDICI8dFEvdu4/zN++2OB2nHoRmv3HG7jPVu8g+/s93DWiBy2i7bJWYxqKjE4JXDogmVfmb6Rg7yG34wSdFYgGpqKyij98uoZubVtwRVYnt+MYY6q59/yeoPDsrPVuRwk6vwqEiPT2Me3MgKcxvJu9hbyiA9w38qSQHSDMmIYsOaEZE4am8t7iLeQW7nc7TlD5+w00yblZkIhIMxF5HngimMFC0YGyCp6ZtZ6s1Fac27u923GMMTW4/axuNIsM58+fNe0hOPwtECcDnYEFwCKgABgerFCh6pUvN1JUUsYDF/RCxDrFGdNQtYmN5iendWX6iu0sz9/rdpyg8bdAlAOHgGZADLBRVUOnt0g9KCopY+K8DYzs08E6xRnTCPzktC60ah7JUzOa7lGEvwViEZ4CMRjPwH3jRWRy0FKFoOdmr6e0oopfjezpdhRjjB/iYiK5/azufLl+Jws27HQ7TlD4WyBuVNWHVbVcVber6hg8NxEyAZBXtJ+3v93M+CGd6do21u04xhg/TRiaSlLLGP746VpU1e04AedvgSgUkRTvBzA3mMFCydMz1xIVEcYvzunhdhRjTB3ERIZz54geLN2yl89W73A7TsD5WyA+BqY5/84G8oBPghUqlKzcuo/pK7bzk9O60jYu9O5YZUxjN3ZgMl0SW/DMrPVN7ijC3+G++6lqhvNvOjAEmB/caKHh6Zlradkskp+c1sXtKMaY4xARHsYdZ3Vn9bbiJncUcVw9sVR1CZ4Ga3MCsjft5ou1RdxyRjfiQ2DgL2OaqjGZSaS1ac6zs5vWUYRfA/2IyN1eL8OAgUBRUBKFCFXlqRlrSYyN5tphqW7HMcacgIjwMO44O51731vGrJzCJtPR1d8jiDivRzSetogxwQoVCubn7uSbjbu546xudp9pY5qASzKTSG3TnGdmrWsyRxF+fTOp6m+DHSSUqCpPz1hLckIzxp+c4nYcY0wAHGmL+OXk5czOKWREEziKOGaBEJGpQI2lUFVHBzxRCJiVU8iy/H08eVk/oiPC3Y5jjAmQSwck88LnuTwzex3n9GrX6IfMqe0I4ul6SRFCqqqUP81cS1qb5lw20IbzNqYpiQgP4/azuvOrycuZs6aQc3o17qOI2togNqrq3JoetW1cREaKyFoRyRWR+33Mv1tEVjv3t54tIqle864VkfXO49rj+NkapGkrtrFmewl3ndvDhvM2pgm6dEAyKa2b89yc3EbfFlHbN9RHR56IyPt12bCIhAMvAqOA3njGb6p+X4nvgCxVzQAmA3901m0N/AbPKLJDgN+ISKMfwa6ySnl21jp6to/j4owkt+MYY4IgMjyMm8/oyrIte/k6b5fbcU5IbQXC+wRaXW+OPATIVdU8VT0MvEO1K59U9XNVPei8XAgcOedyPvCZqu5W1T3AZ8DIOr5/gzN9xTY2FB3g5+ekExbWuM9NGmNqdtnATiTGRjf6e1fXViC0huf+SAa2eL3Od6bV5Eb+N3yHX+uKyE0iki0i2UVFDbtbRlWV8vyc9aS3i2VU3w5uxzHGBFFMZDg3ntqFL9fvZOXWfW7HOW61FYj+IlIsIiVAhvO8WERKRKS4lnV9/Ynss8iIyAQgC3iqLuuq6kRVzVLVrLZt29YSx10zVm1n3Y793HF2dzt6MCYEXDU0hbjoiEZ9FHHMAqGq4aoar6pxqhrhPD/yOr6WbefjuQvdEZ3w3InuB0RkBPAgMFpVy+qybmNRVaU8O3s9XRNbcJG1PRgTEuJjIrn6lFSmr9zGxp0H3I5zXIJ5Gc0iIF1EuohIFDAOmOK9gIgMAF7GUxwKvWbNAM4TkVZO4/R5zrRG6bOcHazZXsIdZ3cn3I4ejAkZ1w/vQmR4GBPnNc6jiKAVCFWtAO7A88WeA0xS1VUi8qiIHOlg9xQQC7wnIktFZIqz7m7gd3iKzCLgUWdao6OqPDd7PaltmjO6vx09GBNK2sZFc0VWJ95fvJUdxaVux6mzoA4CpKrTgenVpj3s9XzEMdZ9FXg1eOnqx5CAn00AABMDSURBVJw1hawqKOaPl2dYvwdjQtBNp3XjrW828+r8jTxwQS+349SJfWMFkary3JxcOrduxqUDjnUBlzGmqUpp05wL+nXkrW83c6Cswu04dWIFIoi+3rCLZVv2cssZ3Yi0owdjQtaNp3ahpLSC97K31L5wA2LfWkH00rw8EmOjbcwlY0LcgJRWDExJ4NWvNlFZ1XiG37ACESSrCvYxb10R1w9PIybSRmw1JtTdeGpXNu8+yKycxnNbUisQQfLy3DxioyOYMNTuFmeMgfP7tCc5oRn/mL/R7Sh+swIRBFt2H+TjFdv48ckptGxm95o2xniGAr9+eBrfbtzNivzGMfyGFYggeOXLPMIEbhjexe0oxpgG5IrBnWkRFc4/5ue5HcUvViACbNf+Mt7N3sIlmcl0aBnjdhxjTAMSHxPJFYM7M235Nrbva/gd56xABNgbX39PaXkVN59R19HRjTGh4PphXahU5Y2vN7kdpVZWIAKotLySN77exIhe7eneLs7tOMaYBiilTXNG9GrPu4u2UFZR6XacY7ICEUAffbeVPQfL+clp1vZgjKnZNaeksuvAYT5Zsd3tKMdkBSJAVJV/frWJXh3jOblLa7fjGGMasOHdEumS2KLBn2ayAhEgX2/YxdodJVw/PA0RG9LbGFOzsDBhwtBUlmze26DvOGcFIkBe/WoTbVpE2ZDexhi/XD6wEzGRYfx74fduR6mRFYgA+H7XAWav2cGPT06xYTWMMX5p2TySSzKT+WjpVvYdLHc7jk9WIALg9QXfEy5iw2oYY+rk6lNSKS2vYvKSfLej+GQF4gTtL/MM4XthRkfax1vHOGOM//oktWRgSgL/Xvg9VQ1wlFcrECfow++2UlJWwXXD0tyOYoxphK45JY2NOw/w1Yadbkc5ihWIE6CqvPXNZnp3jCezc4LbcYwxjdCofh1o3SKKNxdudjvKUaxAnIClW/aSs62Yq4am2KWtxpjjEh0RzmUDk5mVs4OikjK34/yAFYgT8NY3m2kRFc6YTLvftDHm+F05OIWKKuWDBtZYbQXiOO07VM7U5QWMzkwmNjrC7TjGmEase7tYBqe14t1FW1BtOI3VViCO04dL8iktr+Kqk1PcjmKMaQKuHJxC3s4DfLtxt9tR/ssKxHFQVd76djP9O7Wkb3JLt+MYY5qAC/p1IC46gncXbXE7yn9ZgTgOi7/fw7od+/mxHT0YYwKkeVQEYwYk8fGKbew71DB6VluBOA6TF+fTPCqcizJs3CVjTOCMG5xCWUUV/1m61e0ogBWIOjt0uJJpy7cxqm9HWljjtDEmgPomt6RPUjxvf9swGqutQNTRzNXb2V9WweWDOrkdxRjTBI0b3JmcbcWs3FrsdhQrEHU1eXE+yQnN7KZAxpigGDMgmeiIMN7Ndr9ntRWIOijYe4j5uTu5bFAnwsKs57QxJvDiYyI5v08Hpi3f5vo9q61A1MGH321FFS4baD2njTHBM3ZgMnsPlvP5mkJXc1iB8JOq8v7ifIaktSa1TQu34xhjmrBTuyfSNi6a95e4ezWTFQg/rdxaTN7OA4y1owdjTJBFhIdx6YBkPl9TyO4Dh13LYQXCT1OXFxAZLozs28HtKMaYEDB2YDIVVcrUZQWuZbAC4YeqKmXasgJOT29LQvMot+MYY0LASR3i6d0x3tURXoNaIERkpIisFZFcEbnfx/zTRWSJiFSIyOXV5lWKyFLnMSWYOWuzZPMeCvaVclH/jm7GMMaEmLEDk1mWv4/cwhJX3j9oBUJEwoEXgVFAb2C8iPSutthm4DrgLR+bOKSqmc5jdLBy+mPqsgKiI8IY0au9mzGMMSFmdGYS4WHiWmN1MI8ghgC5qpqnqoeBd4Ax3guo6iZVXQ5UBTHHCamsUj5esZ2zT2pHXEyk23GMMSGkXVwMp6cn8tF3W6msqv+hN4JZIJIB73Fr851p/ooRkWwRWSgilwQ2mv++ydvFzv1lXNzfBuYzxtS/sQM7sW1fKV9v2FXv7x3MAuGrq3FdSmCKqmYBPwaeEZFuR72ByE1OEckuKio63pzHNHV5AS2iwjmrZ7ugbN8YY47l3N7tiYuOcGWE12AWiHygs9frToDf12upaoHzbx7wBTDAxzITVTVLVbPatm17Yml9qKxSZqzawTm92tMsKjzg2zfGmNrERIZzXp8OfLpqe70PvRHMArEISBeRLiISBYwD/LoaSURaiUi08zwRGA6sDlrSGmRv2s3uA4c5v4/1fTDGuOfi/h0pKa1g7trgnCmpSdAKhKpWAHcAM4AcYJKqrhKRR0VkNICIDBaRfOBHwMsisspZvReQLSLLgM+BP6hqvReImat3EBUexhk9A390Yowx/hrePZHWLaKYUs+d5oJ6xxtVnQ5MrzbtYa/ni/Cceqq+3gKgXzCz1UZVmbl6O8O7tyHWbgxkjHFRZHgYo/p24IMlWzl4uILmUfXznWQ9qWuwZnsJW3Yf4jw7vWSMaQBG90/iUHkln63eUW/vaQWiBjNX7UAE6xxnjGkQBqe1pkN8DFOXbau397QCUYOZq7czKKUVbeOi3Y5ijDGEhQkXZXRk7rpC9h0sr5/3rJd3aWTy9xxkVUEx5/WxowdjTMNxcf8kyiuVGau218v7WYHw4XPnUrJz7PSSMaYByejUktQ2zZm6vH6uZrIC4cPctYV0bt2Mrol25zhjTMMhIlyckcRXuTspKikL+vtZgaimrKKSBRt2cWaPdoj4Gi3EGGPcMzoziSqFT1YGv7HaCkQ1izbu4eDhSs60znHGmAaoR/s4ureL5ZMVwW+HsAJRzRdrC4kKD+OUbm3cjmKMMT5d0LcD32z0jDQdTFYgqvliXREnd21dbz0VjTGmrkb27UiVevprBZMVCC/5ew6SW7ifM3rY6SVjTMPVq2McaW2aB70dwgqEly+cy1vPtHs/GGMaMBFhZN+OfL1hF3sPHg7a+1iB8DJvXRGdWjWjW1u7vNUY07Bd0K8DFVUa1LGZrEA4KquUhXm7OLV7ol3eaoxp8PoltyQ5oRmfrAze1UxWIByrC4opLq2wq5eMMY2CiDCqbwfmr99JcWlwxmayAuFYsGEngBUIY0yjMapfRw5XVjEnpzAo27cC4ViwYRfd28XSLi7G7SjGGOOXAZ0TaB8fzfQVwbmayS72Bw5XVLFo024uH3TUze2MMabBCgsTrh6ayqHyyqBs3woEsDx/LwcPVzLMTi8ZYxqZO85OD9q27RQT8PWGXYjAyV2sQBhjzBFWIPC0P/TuGE+rFlFuRzHGmAYj5AtEaXklizfvsdNLxhhTTcgXiOLSckb26cBZJ9nwGsYY4y3kG6nbxcXw3PgBbscwxpgGJ+SPIIwxxvhmBcIYY4xPViCMMcb4ZAXCGGOMT1YgjDHG+GQFwhhjjE9WIIwxxvhkBcIYY4xPoqpuZwgIESkCvj+BTSQCOwMUJ5AsV91YrrqxXHXTFHOlqmpbXzOaTIE4USKSrapZbueoznLVjeWqG8tVN6GWy04xGWOM8ckKhDHGGJ+sQPzPRLcD1MBy1Y3lqhvLVTchlcvaIIwxxvhkRxDGGGN8CqkCISI/EpFVIlIlIjW2+IvISBFZKyK5InK/1/QuIvKNiKwXkXdFJCD3KBWR1iLymbPdz0SklY9lzhKRpV6PUhG5xJn3mohs9JqXWV+5nOUqvd57itd0N/dXpoh87fy+l4vIlV7zAra/avqseM2Pdn72XGdfpHnNe8CZvlZEzj/eDMeZ624RWe3sm9kikuo1z+fvsx6zXSciRV4ZfuI171rn975eRK6tx0x/8cqzTkT2es0L2v4SkVdFpFBEVtYwX0TkOSf3chEZ6DXvxPeVqobMA+gF9AS+ALJqWCYc2AB0BaKAZUBvZ94kYJzz/CXg1gDl+iNwv/P8fuDJWpZvDewGmjuvXwMuD8L+8isXsL+G6a7tL6AHkO48TwK2AQmB3F/H+qx4LXMb8JLzfBzwrvO8t7N8NNDF2U54gPaPP7nO8vr83Hok17F+n/WY7TrgBR/rtgbynH9bOc9b1Uemasv/DHi1nvbX6cBAYGUN8y8APgEEGAp8E8h9FVJHEKqao6pra1lsCJCrqnmqehh4BxgjIgKcDUx2lnsduCRA0cY42/N3u5cDn6jqwQC9f03qmuu/3N5fqrpOVdc7zwuAQsBnZ6AT4POzcoysk4FznH0zBnhHVctUdSOQ62yvXnKp6uden5+FQKcAvfcJZzuG84HPVHW3qu4BPgNGupBpPPB2AN63Vqo6D88fgzUZA7yhHguBBBHpSID2VUgVCD8lA1u8Xuc709oAe1W1otr0QGivqtsAnH9ru0H2OI7+gD7uHGL+RUSi6zlXjIhki8jCI6e9aED7S0SG4PnLcIPX5EDsr5o+Kz6XcfbFPjz7xp91j1ddt30jnr9Cj/D1+wwUf7Nd5vx+JotI5zquG6xMOKfiugBzvCYHc3/VpqbsAdlXTe6e1CIyC+jgY9aDqvoffzbhY5oeY/oJ5/J3G852OgL9gBlekx8AtuP5EpwI3Ac8Wo+5UlS1QES6AnNEZAVQ7GM5t/bXv4BrVbXKmXzc+6v65n1Mq/4zBuXzVAu/ty0iE4As4AyvyUf9PlV1g6/1g5RtKvC2qpaJyC14jsDO9nPdYGU6YhwwWVUrvaYFc3/VJqifryZXIFR1xAluIh/o7PW6E1CAZ5yTBBGJcP4SPDL9hHOJyA4R6aiq25wvtMJjbOoK4ENVLffa9jbnaZmI/BO4tz5zOadwUNU8EfkCGAC8j8v7S0TigY+Bh5zD7yPbPu79VU1NnxVfy+SLSATQEs8pA3/WPV5+bVtERuApuGeoatmR6TX8PgP1hVdrNlXd5fXy78CTXuueWW3dL+ojk5dxwO3eE4K8v2pTU/aA7Cs7xXS0RUC6eK7AicLzgZiinpafz/Gc/we4FvDniMQfU5zt+bPdo85/Ol+SR877XwL4vOIhGLlEpNWRUzQikggMB1a7vb+c392HeM7PvldtXqD2l8/PyjGyXg7McfbNFGCceK5y6gKkA98eZ4465xKRAcDLwGhVLfSa7vP3GaBc/mbr6PVyNJDjPJ8BnOdkbAWcxw+PpIOWycnVE0+D79de04K9v2ozBbjGuZppKLDP+QMoMPsqWK3vDfEBXIqnspYBO4AZzvQkYLrXchcA6/D8FfCg1/SueP4T5wLvAdEBytUGmA2sd/5t7UzPAl7xWi4N2AqEVVt/DrACzxfdv4HY+soFDHPee5nz740NYX8BE4ByYKnXIzPQ+8vXZwXP6arRzvMY52fPdfZFV691H3TWWwuMCvBnvbZcs5z/A0f2zZTafp/1mO0JYJWT4XPgJK91b3D2ZS5wfX1lcl4/Avyh2npB3V94/hjc5nyW8/G0F90C3OLMF+BFJ/cKvK7ODMS+sp7UxhhjfLJTTMYYY3yyAmGMMcYnKxDGGGN8sgJhjDHGJysQxhhjfLICYZoUEblUfjjq7VLxjN47Kkjvd4uIXOM8v05EkrzmvSIivQPwHo+IyFYROZ7e3tW3dZp4RnENVF8Z04TZZa6mSRORm4CrgLP0f0NtBOu9vgDuVdXsAG/3ETwjhj4doO2lAdNUtW8gtmeaLjuCME2WiPQAHgaurl4cRCRNRNaIyOteg8I1d+adIyLficgK8YzHf6Sn7B/kf/dQeNqZ9oiI3Csil+PpqPemc9TSTES+EOe+IyIy3tneShF50ivHfhF5XESWiWewt/Z+/FyxIvJPZ3vLReQyr209KSKLRWSWiAxxMuSJyOjA7FUTSqxAmCZJRCKBt/D8Rb+5hsV6AhNVNQPP4IK3iUgMnvtFXKmq/fCMV3ariLTG0xO/j7P8Y94bUtXJQDZwlapmquohryxJeMYTOhvIBAbL/0b9bAEsVNX+wDzgp378eP+HZ0iFfk6WIyOLtgC+UNVBQImT8Vwn9wmfnjKhxwqEaap+B6xS1XeOscwWVf3Kef5v4FQ8RWOjqq5zpr+O56YtxUAp8IqIjAXqci+OwXi+uIvUM3Dhm842AQ4D05zni/EMp1KbEXiGVwBAPeP9H9nWp87zFcBc9QzquMLP7RrzA1YgTJMjImcClwF31LJo9Qa4moZJxvliH4JnlNpL+N8XsV+RjjGvXP/XEFiJfyMsC76HbvbeVhWeMcdwTq81uZGbTfBZgTBNijNy5T+Ba1S1pJbFU0TkFOf5eGA+sAZIE5HuzvSrgbkiEgu0VNXpwJ14ThVVVwLE+Zj+DXCGiCSKSLjzXnPr8nNVMxOv4ic13CvcmBNlBcI0NbfgucPc36pd6nqlj2VzgGtFZDmee/f+TVVLgeuB98Rz46MqPPfTjgOmOcvOBe7ysb3XgJeONFIfmaie4ZcfwDMy6TJgifp386qaPAa0chq8l+G5v7QxAWeXuZqQ1Jgu9bTLXI1b7AjCmIZvP3BToDrK4bml584TTmWaPDuCMMYY45MdQRhjjPHJCoQxxhifrEAYY4zxyQqEMcYYn6xAGGOM8ckKhDHGGJ/+Hzmumjbu2pG1AAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "z = np.linspace(zmin, zmax, 1000)\n", - "plt.plot(z, phi(z))\n", - "plt.xlabel('Z position [cm]')\n", - "plt.ylabel('Flux [n/src]')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A rough cosine shape is obtained. \n", - "One can also numerically integrate the function using the trapezoidal rule." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.543424143829605" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.trapz(phi(z), z)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following cases show how to reconstruct the flux distribution Zernike polynomials tallied results." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "with openmc.StatePoint(sp_file) as sp:\n", - " df2 = sp.tallies[flux_tally_zernike.id].get_pandas_dataframe()" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellzernikenuclidescoremeanstd. dev.
04Z0,0totalflux0.5434250.000599
14Z1,-1totalflux-0.0002360.000398
24Z1,1totalflux0.0001260.000325
34Z2,-2totalflux-0.0001040.000206
44Z2,0totalflux-0.0642910.000404
.....................
614Z10,2totalflux-0.0001300.000099
624Z10,4totalflux-0.0000570.000092
634Z10,6totalflux-0.0000480.000109
644Z10,8totalflux-0.0000560.000092
654Z10,10totalflux-0.0000460.000098
\n", - "

66 rows × 6 columns

\n", - "
" - ], - "text/plain": [ - " cell zernike nuclide score mean std. dev.\n", - "0 4 Z0,0 total flux 5.43e-01 5.99e-04\n", - "1 4 Z1,-1 total flux -2.36e-04 3.98e-04\n", - "2 4 Z1,1 total flux 1.26e-04 3.25e-04\n", - "3 4 Z2,-2 total flux -1.04e-04 2.06e-04\n", - "4 4 Z2,0 total flux -6.43e-02 4.04e-04\n", - ".. ... ... ... ... ... ...\n", - "61 4 Z10,2 total flux -1.30e-04 9.86e-05\n", - "62 4 Z10,4 total flux -5.70e-05 9.21e-05\n", - "63 4 Z10,6 total flux -4.79e-05 1.09e-04\n", - "64 4 Z10,8 total flux -5.59e-05 9.23e-05\n", - "65 4 Z10,10 total flux -4.58e-05 9.76e-05\n", - "\n", - "[66 rows x 6 columns]" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's plot the flux in radial direction with specific azimuthal angle ($\\theta = 0.0$)." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Flux')" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "z_n = df2['mean'] \n", - "zz = openmc.Zernike(z_n, radius)\n", - "rr = np.linspace(0, radius, 100)\n", - "plt.plot(rr, zz(rr, 0.0)) \n", - "plt.xlabel('Radial position [cm]')\n", - "plt.ylabel('Flux')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A polar figure with all azimuthal can be plotted like this:" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "z_n = df2['mean']\n", - "zz = openmc.Zernike(z_n, radius=radius) \n", - "#\n", - "# Using linspace so that the endpoint of 360 is included...\n", - "azimuths = np.radians(np.linspace(0, 360, 50))\n", - "zeniths = np.linspace(0, radius, 100)\n", - "r, theta = np.meshgrid(zeniths, azimuths)\n", - "values = zz(zeniths, azimuths)\n", - "fig, ax = plt.subplots(subplot_kw=dict(projection='polar'))\n", - "ax.contourf(theta, r, values, cmap='jet')\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Sometimes, we just need the radial-only Zernike polynomial tallied flux distribution. \n", - "Let us extract the tallied coefficients first." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "with openmc.StatePoint(sp_file) as sp:\n", - " df3 = sp.tallies[flux_tally_zernike1d.id].get_pandas_dataframe()" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellzernikeradialnuclidescoremeanstd. dev.
04Z0,0totalflux0.5434250.000599
14Z2,0totalflux-0.0642910.000404
24Z4,0totalflux-0.0006010.000223
34Z6,0totalflux-0.0004540.000227
44Z8,0totalflux-0.0000110.000166
54Z10,0totalflux-0.0001020.000161
\n", - "
" - ], - "text/plain": [ - " cell zernikeradial nuclide score mean std. dev.\n", - "0 4 Z0,0 total flux 5.43e-01 5.99e-04\n", - "1 4 Z2,0 total flux -6.43e-02 4.04e-04\n", - "2 4 Z4,0 total flux -6.01e-04 2.23e-04\n", - "3 4 Z6,0 total flux -4.54e-04 2.27e-04\n", - "4 4 Z8,0 total flux -1.15e-05 1.66e-04\n", - "5 4 Z10,0 total flux -1.02e-04 1.61e-04" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A plot along with r-axis is also done." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Flux')" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "z_n = df3['mean'] \n", - "zz = openmc.ZernikeRadial(z_n, radius=radius)\n", - "rr = np.linspace(0, radius, 50)\n", - "plt.plot(rr, zz(rr)) \n", - "plt.xlabel('Radial position [cm]')\n", - "plt.ylabel('Flux')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Similarly, we can also re-construct the polar figure based on radial-only Zernike polinomial coefficients. " - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "z_n = df3['mean'] \n", - "zz = openmc.ZernikeRadial(z_n, radius=radius)\n", - "azimuths = np.radians(np.linspace(0, 360, 50))\n", - "zeniths = np.linspace(0, radius, 100)\n", - "r, theta = np.meshgrid(zeniths, azimuths)\n", - "values = [[i for i in zz(zeniths)] for j in range(len(azimuths))]\n", - "fig, ax = plt.subplots(subplot_kw=dict(projection='polar'), figsize=(6,6))\n", - "ax.contourf(theta, r, values, cmap='jet')\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Based on Legendre polynomial coefficients and the azimuthal or radial-only Zernike coefficient, it's possible to reconstruct the flux both on radial and axial directions. " - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Reconstruct 3-D flux based on radial only Zernike and Legendre polynomials\n", - "z_n = df3['mean'] \n", - "zz = openmc.ZernikeRadial(z_n, radius=radius)\n", - "azimuths = np.radians(np.linspace(0, 360, 100)) # azimuthal mesh \n", - "zeniths = np.linspace(0, radius, 100) # radial mesh \n", - "zmin, zmax = -1.0, 1.0 \n", - "z = np.linspace(zmin, zmax, 100) # axial mesh \n", - "# \n", - "# flux = np.matmul(np.matrix(phi(z)).transpose(), np.matrix(zz(zeniths))) \n", - "# flux = np.array(flux) # change np.matrix to np.array\n", - "# np.matrix is not recommended for use anymore\n", - "flux = np.array([phi(z)]).T @ np.array([zz(zeniths)])\n", - "#\n", - "plt.figure(figsize=(5,10))\n", - "plt.title('Flux distribution')\n", - "plt.xlabel('Radial Position [cm]')\n", - "plt.ylabel('Axial Height [cm]')\n", - "plt.pcolor(zeniths, z, flux, cmap='jet')\n", - "plt.colorbar()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "One can also reconstruct the 3D flux distribution based on Legendre and Zernike polynomial tallied coefficients." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "# Define needed function first \n", - "def cart2pol(x, y):\n", - " rho = np.sqrt(x**2 + y**2)\n", - " phi = np.arctan2(y, x)\n", - " return(rho, phi)\n", - "\n", - "# Reconstruct 3-D flux based on azimuthal Zernike and Legendre polynomials\n", - "z_n = df2['mean']\n", - "zz = openmc.Zernike(z_n, radius=radius) \n", - "#\n", - "xstep = 2.0*radius/20\n", - "hstep = (zmax - zmin)/20\n", - "x = np.linspace(-radius, radius, 50)\n", - "x = np.array(x)\n", - "[X,Y] = np.meshgrid(x,x)\n", - "h = np.linspace(zmin, zmax, 50)\n", - "h = np.array(h)\n", - "[r, theta] = cart2pol(X,Y)\n", - "flux3d = np.zeros((len(x), len(x), len(h)))\n", - "flux3d.fill(np.nan)\n", - "#\n", - "for i in range(len(x)):\n", - " for j in range(len(x)):\n", - " if r[i][j]<=radius:\n", - " for k in range(len(h)):\n", - " flux3d[i][j][k] = phi(h[k]) * zz(r[i][j], theta[i][j])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us print out with VTK format." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "# You'll need to install pyevtk as a prerequisite\n", - "from pyevtk.hl import gridToVTK\n", - "import numpy as np\n", - "#\n", - "# Dimensions\n", - "nx, ny, nz = len(x), len(x), len(h)\n", - "lx, ly, lz = 2.0*radius, 2.0*radius, (zmax-zmin)\n", - "dx, dy, dz = lx/nx, ly/ny, lz/nz\n", - "#\n", - "ncells = nx * ny * nz\n", - "npoints = (nx + 1) * (ny + 1) * (nz + 1)\n", - "#\n", - "# Coordinates\n", - "x = np.arange(0, lx + 0.1*dx, dx, dtype='float64')\n", - "y = np.arange(0, ly + 0.1*dy, dy, dtype='float64')\n", - "z = np.arange(0, lz + 0.1*dz, dz, dtype='float64')\n", - "# Print out \n", - "path = gridToVTK(\"./rectilinear\", x, y, z, cellData = {\"flux3d\" : flux3d})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use VisIt or ParaView to plot it as you want. Then, the plot can be loaded and shown as follows." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "f1 = plt.imread('./images/flux3d.png')\n", - "plt.imshow(f1, cmap='jet')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/jupyter/hexagonal-lattice.ipynb b/examples/jupyter/hexagonal-lattice.ipynb deleted file mode 100644 index 07c3ab8344c..00000000000 --- a/examples/jupyter/hexagonal-lattice.ipynb +++ /dev/null @@ -1,411 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Modeling Hexagonal Lattices\n", - "In this example, we will create a hexagonal lattice and show how the orientation can be changed via the cell rotation property. Let's first just set up some materials and universes that we will use to fill the lattice." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import openmc" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "fuel = openmc.Material(name='fuel')\n", - "fuel.add_nuclide('U235', 1.0)\n", - "fuel.set_density('g/cm3', 10.0)\n", - "\n", - "fuel2 = openmc.Material(name='fuel2')\n", - "fuel2.add_nuclide('U238', 1.0)\n", - "fuel2.set_density('g/cm3', 10.0)\n", - "\n", - "water = openmc.Material(name='water')\n", - "water.add_nuclide('H1', 2.0)\n", - "water.add_nuclide('O16', 1.0)\n", - "water.set_density('g/cm3', 1.0)\n", - "\n", - "materials = openmc.Materials((fuel, fuel2, water))\n", - "materials.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our three materials, we will set up two universes that represent pin-cells: one with a small pin and one with a big pin. Since we will be using these universes in a lattice, it's always a good idea to have an \"outer\" universe as well that is applied outside the defined lattice." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "r_pin = openmc.ZCylinder(r=0.25)\n", - "fuel_cell = openmc.Cell(fill=fuel, region=-r_pin)\n", - "water_cell = openmc.Cell(fill=water, region=+r_pin)\n", - "pin_universe = openmc.Universe(cells=(fuel_cell, water_cell))\n", - "\n", - "r_big_pin = openmc.ZCylinder(r=0.5)\n", - "fuel2_cell = openmc.Cell(fill=fuel2, region=-r_big_pin)\n", - "water2_cell = openmc.Cell(fill=water, region=+r_big_pin)\n", - "big_pin_universe = openmc.Universe(cells=(fuel2_cell, water2_cell))\n", - "\n", - "all_water_cell = openmc.Cell(fill=water)\n", - "outer_universe = openmc.Universe(cells=(all_water_cell,))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's create a hexagonal lattice using the `HexLattice` class:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "lattice = openmc.HexLattice()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We need to set the `center` of the lattice, the `pitch`, an `outer` universe (which is applied to all lattice elements outside of those that are defined), and a list of `universes`. Let's start with the easy ones first. Note that for a 2D lattice, we only need to specify a single number for the pitch." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "lattice.center = (0., 0.)\n", - "lattice.pitch = (1.25,)\n", - "lattice.outer = outer_universe" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we need to set the `universes` property on our lattice. It needs to be set to a list of lists of Universes, where each list of Universes corresponds to a ring of the lattice. The rings are ordered from outermost to innermost, and within each ring the indexing starts at the \"top\". To help visualize the proper indices, we can use the `show_indices()` helper method." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " (0, 0)\n", - " (0,17) (0, 1)\n", - " (0,16) (1, 0) (0, 2)\n", - "(0,15) (1,11) (1, 1) (0, 3)\n", - " (1,10) (2, 0) (1, 2)\n", - "(0,14) (2, 5) (2, 1) (0, 4)\n", - " (1, 9) (3, 0) (1, 3)\n", - "(0,13) (2, 4) (2, 2) (0, 5)\n", - " (1, 8) (2, 3) (1, 4)\n", - "(0,12) (1, 7) (1, 5) (0, 6)\n", - " (0,11) (1, 6) (0, 7)\n", - " (0,10) (0, 8)\n", - " (0, 9)\n" - ] - } - ], - "source": [ - "print(lattice.show_indices(num_rings=4))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's set up a lattice where the first element in each ring is the big pin universe and all other elements are regular pin universes. \n", - "\n", - "From the diagram above, we see that the outer ring has 18 elements, the first ring has 12, and the second ring has 6 elements. The innermost ring of any hexagonal lattice will have only a single element. \n", - "\n", - "We build these rings through 'list concatenation' as follows: " - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "outer_ring = [big_pin_universe] + [pin_universe]*17 # Adds up to 18\n", - "\n", - "ring_1 = [big_pin_universe] + [pin_universe]*11 # Adds up to 12\n", - "\n", - "ring_2 = [big_pin_universe] + [pin_universe]*5 # Adds up to 6\n", - "\n", - "inner_ring = [big_pin_universe]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now assign the rings (and the universes they contain) to our lattice. " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "HexLattice\n", - "\tID =\t4\n", - "\tName =\t\n", - "\tOrientation =\ty\n", - "\t# Rings =\t4\n", - "\t# Axial =\tNone\n", - "\tCenter =\t(0.0, 0.0)\n", - "\tPitch =\t(1.25,)\n", - "\tOuter =\t3\n", - "\tUniverses \n", - " 2\n", - " 1 1\n", - " 1 2 1\n", - "1 1 1 1\n", - " 1 2 1\n", - "1 1 1 1\n", - " 1 2 1\n", - "1 1 1 1\n", - " 1 1 1\n", - "1 1 1 1\n", - " 1 1 1\n", - " 1 1\n", - " 1\n" - ] - } - ], - "source": [ - "lattice.universes = [outer_ring, \n", - " ring_1, \n", - " ring_2,\n", - " inner_ring]\n", - "print(lattice)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's put our lattice inside a circular cell that will serve as the top-level cell for our geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "outer_surface = openmc.ZCylinder(r=5.0, boundary_type='vacuum')\n", - "main_cell = openmc.Cell(fill=lattice, region=-outer_surface)\n", - "geometry = openmc.Geometry([main_cell])\n", - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's create a plot to see what our geometry looks like." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot = openmc.Plot.from_geometry(geometry)\n", - "plot.color_by = 'material'\n", - "plot.colors = colors = {\n", - " water: 'blue',\n", - " fuel: 'olive',\n", - " fuel2: 'yellow'\n", - "}\n", - "plot.to_ipython_image()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "At this point, if we wanted to simulate the model, we would need to create an instance of `openmc.Settings`, export it to XML, and run." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Lattice orientation\n", - "\n", - "Now let's say we want our hexagonal lattice orientated such that two sides of the lattice are parallel to the x-axis. This can be achieved by two means: either we can rotate the cell that contains the lattice, or we can can change the `HexLattice.orientation` attribute. By default, the `orientation` is set to \"y\", indicating that two sides of the lattice are parallel to the y-axis, but we can also change it to \"x\" to make them parallel to the x-axis." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Change the orientation of the lattice and re-export the geometry\n", - "lattice.orientation = 'x'\n", - "geometry.export_to_xml()\n", - "\n", - "# Run OpenMC in plotting mode\n", - "plot.to_ipython_image()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When we change the orientation to 'x', you can see that the first universe in each ring starts to the right along the x-axis. As before, the universes are defined in a clockwise fashion around each ring. To see the proper indices for a hexagonal lattice in this orientation, we can again call `show_indices` but pass an extra orientation argument:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " (0,12) (0,13) (0,14) (0,15)\n", - "\n", - " (0,11) (1, 8) (1, 9) (1,10) (0,16)\n", - "\n", - " (0,10) (1, 7) (2, 4) (2, 5) (1,11) (0,17)\n", - "\n", - "(0, 9) (1, 6) (2, 3) (3, 0) (2, 0) (1, 0) (0, 0)\n", - "\n", - " (0, 8) (1, 5) (2, 2) (2, 1) (1, 1) (0, 1)\n", - "\n", - " (0, 7) (1, 4) (1, 3) (1, 2) (0, 2)\n", - "\n", - " (0, 6) (0, 5) (0, 4) (0, 3)\n" - ] - } - ], - "source": [ - "print(lattice.show_indices(4, orientation='x'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Hexagonal prisms\n", - "\n", - "OpenMC also contains a convenience function that can create a hexagonal prism representing the interior region of six surfaces defining a hexagon. This can be useful as a bounding surface of a hexagonal lattice. For example, if we wanted the outer boundary of our geometry to be hexagonal, we could change the `region` of the main cell:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQBAMAAABykSv/AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAElBMVEX///+TUVD//wCAgAA4vPIAAP/pte6jAAAAAWJLR0QAiAUdSAAAAAd0SU1FB+QIHAkpLvz/+XkAAAiBSURBVHja7Z3rddw6DISNDkR3ICkVrCpwjtNB3H8rNznxPkQBu3xgCAqX83fOMfkJszJFUtTb29DQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQULlCA7XgoBYgk5OCNCmJFxBqAzINkFS14WiQLS8g1ApkclIQeEm8gFA7kGmApKgdBzhbXkAoaut9mflOaBhTu4K8LwvfLx2jGcjfxtl+KRk4jihZyz8du6VkTI1AlkXol5aBA+Ebj/ulZzQpyLIIzSsaqJI8grzvWp8hBgxE5HhoXtHAZUvmuDWvaOBA6AnHd/OKBjBbd5CFk7IBBHnO8bd5RQOYLXrBoSpkSdyAvEoWBASRLS8gZAOiny0WZNs2viO1BhAkMCDbJvSr2sD9cycGZNuEftUbuIEjA7J+t36Je6Vg4ECCFYh2thiQbROSomDAQMgORDdb4Qiy3lqPkqJhBFRJvICQJYhmttyABEsQzWx5ASEOpNXtVzNbwRZEryQ8yBrFYVE0MCBkDaKVLQGkzTBeEyQIIE0erDSzJYI0eNTVBCEZBKaoSZ1sBXsQnZJ4AaEeQDSy5QbEggOSregvvrcBmdVByITjQFKfLSMO/Y0pVhwxiW6yWnIoP12RHYfuFIQlh+b0FplyKE6dPoC8W4DMWiDGHHobU6w5Hkl0kmXFobQuSvYcOrsgzIP1V3N9tqgvkPKSuAGxv2ftQMqzxYKsF6FBlFEPQgzIys7dQo07SGm2OBBp8hZo1IMw45NVmE5HGtWjFG7AKK3UII3qgSMDclvsi68j0qgGCf2BlGWLAbmt9cWBQBq1INQjSEm23ICEHkEKskV9guSXxA1I6BMkP1ssyHpt4xK1jjTqQKhXkNxsBRbEeqxVUBIBZOWvYqvRbz4ICSC2zyMF2RJBFqFxoFEFEkSQ9opA8rLlBYR6BsnJVugZJKckXkDiZJlOxtdsTKGuOCq2oXXGUb4zsKMfyD/NZSDUG0fpCLg/jsKHkg45iqYgdsmy7v9d+dmiLjkKtnN0ypH/cmKHP5B/mvNAqFeO3LWrfjky10U75sjaBXFLlnWfeaVnyw1Ip7feGORltugsIK9K4gaE+6++bvxWCwsj+X8iA7IKc7QmRioIMSDSrLmJkTpwZECu6xWHy2VipIIwI9/rcgXi3eJ8I3EETGcCmf4PIOEIst7+1mXfho0R0rLlBYTOBTL5BwnnAglJBTkDyJQD0u/tVwYJZwMJWSDX8l7iRkyMFBDiQXod/crZCgLIyl8s6+cRuSQSCPDUkHwjAYREkD+X5bKwam9EnZzyQDpSAkg4I0hwDELnBJleFuRdr/EfP/WMj5clARbk81PReAUCvGd9fgr9KjNeZIugHGy/So3nIGAOpl/lxtNswX7o19Z/6hkfT0AIzRH3q8rYkUxiQTAc+35VGh9iScA/kEPoaw0JhJAcX38U9aveELJFOI6vbz32S8PgQfAcj/3SMdhswX7ov+6t/77+fJWMDwaEGnDc+qVmfByzBbvxfu30cNdRMT4OJWlSkO/r+KlnHEBgyfqKJFzeUuOQLTcgqHvWr7j133xOSo34vkUcyCrsqEg1fjBX8XaBlYw7yCSCrMIMZrJhAcKMe1dhcjzd+MHE4ZoULeNhDCyBSMsV6YYBCHkAmd5Qp4YYgAQUyBcj4ZdbZjyABNgZFa1BJj8gwQdI8APiJlpuQNzcfv38Q3QzRHEzaPQzjKcjyDkfrDiQUz7qupl88DMd5AbEzZSpn0lsWLZ+Ha4idlnBzUKPn6U3wpPce4VcDH0AOffytJsNA362cBCe5KeesePYb6pxs83Jz8YzApMoGvueTs9Bzrs50812WT8bmAlYEkXFvTwky88mfz8gwPsWDmTKAznXq0luXhbz8/oeCSDSBHy3L1S6ecXVz0vHdDaQKQdkvf2tqO42RhKIm6MS/Bxe4QbEzQEvfkDoCNLv7Xf6P4C4OSjMz9FtDEivo9/nIG6ON/Rz4CQxID0pNVl+QNwck+vn4GI3IG4O9/Zz3Dr1S3LnSEiWn08S+PlIBHVKkvoowoJ0RBKyQdx82sbPx4aoP5I9R2Ky/HyQy88n0qgzkqg7ycnqbRdEKAZx82FHPyDUM0hGsvx8jtYPCIkg/Mwm0ohAspLl5yPabj5r7udD88SCXJcrKt5Gzjf2IJnJEh5KOgDJ5eBBtpuEOCCMShDqEyQ7WX5AUMdzVILkc6BOtagDKSiIH5C3HkFKOEDnjOQb1SDUH0hRskDnjOQb1SCY4znyjbkyWfzalXAV2zyPFBYEc85IvlEPwq+LrlzbSGOuTVYvC7wKINQXSHGy/ID0sQtirk5WJxtTFArSxe6t+pvvY7bswqVwz9qBWJHUj0/ibNmQ1A8YjyAmP5OgBYI6ZySfoy5ZxhtTgl5BhDfh2nNUgxhuTJl3Tddy2G3n2HPUg5ARScRRnSyrddGIo74gVkcoBH0QsiCJ21RIlh8Qk2wBkuUIhOxBVJL1bGfgJuzBqDYQBTE5ZwQDQgKINJ3e6rANLZDrQsYl7pWCgQExOGcEkiyLc0ZAIGQLopYsg+M5MAVxBEKWIIrJ8gPS/HgOULIcgdARpIvDNqpK0hhEl4MDWaM4LIoGDoSsQJST1fqcERwIezyH0CvVByttDn5ddIM/6qoXpPECLxCk7fEcuGQ5AiELEECy/IC8zJaqgUvWy/uWsoEryItzRmZlAwjydGPKrG7AksXuMT80rmjgQEgkmSEGKllPtnOADBQIO70VN65poDikjSkhBIgBK4iwvhCC0K9aAwfCbkyZj91SMnAc3HYOpldaBhCEDs2zvdIxJiDIW2goJIcfEGrHMQ2QJLUDwXL4AaFWHBMYpFlJ0Bx+QKgNxzRAktUGBM/hB4RacEwNQJqUpAXH0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0JBb/Qdzkh5bG3T0BgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMC0wOC0yOFQwODo0MTo0NiswMTowMPgs44sAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjAtMDgtMjhUMDg6NDE6NDYrMDE6MDCJcVs3AAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "main_cell.region = openmc.model.hexagonal_prism(\n", - " edge_length=4*lattice.pitch[0],\n", - " orientation='x',\n", - " boundary_type='vacuum'\n", - ")\n", - "geometry.export_to_xml()\n", - "\n", - "# Run OpenMC in plotting mode\n", - "plot.color_by = 'cell'\n", - "plot.to_ipython_image()" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/images/cylinder_mesh.png b/examples/jupyter/images/cylinder_mesh.png deleted file mode 100644 index cd9638060d1..00000000000 Binary files a/examples/jupyter/images/cylinder_mesh.png and /dev/null differ diff --git a/examples/jupyter/images/flux3d.png b/examples/jupyter/images/flux3d.png deleted file mode 100644 index 4f706f9a230..00000000000 Binary files a/examples/jupyter/images/flux3d.png and /dev/null differ diff --git a/examples/jupyter/images/manifold-cad.png b/examples/jupyter/images/manifold-cad.png deleted file mode 100644 index 81d8aabecac..00000000000 Binary files a/examples/jupyter/images/manifold-cad.png and /dev/null differ diff --git a/examples/jupyter/images/manifold_flux.png b/examples/jupyter/images/manifold_flux.png deleted file mode 100644 index 6462928a8ca..00000000000 Binary files a/examples/jupyter/images/manifold_flux.png and /dev/null differ diff --git a/examples/jupyter/images/manifold_pnt_cld.png b/examples/jupyter/images/manifold_pnt_cld.png deleted file mode 100644 index 94f0a7a0471..00000000000 Binary files a/examples/jupyter/images/manifold_pnt_cld.png and /dev/null differ diff --git a/examples/jupyter/images/mdgxs.png b/examples/jupyter/images/mdgxs.png deleted file mode 100644 index b93d0f04230..00000000000 Binary files a/examples/jupyter/images/mdgxs.png and /dev/null differ diff --git a/examples/jupyter/images/mgxs.png b/examples/jupyter/images/mgxs.png deleted file mode 100644 index 3946a5b3c6d..00000000000 Binary files a/examples/jupyter/images/mgxs.png and /dev/null differ diff --git a/examples/jupyter/images/pin_mesh.png b/examples/jupyter/images/pin_mesh.png deleted file mode 100644 index 2179da9c211..00000000000 Binary files a/examples/jupyter/images/pin_mesh.png and /dev/null differ diff --git a/examples/jupyter/images/teapot.jpg b/examples/jupyter/images/teapot.jpg deleted file mode 100644 index 382e8838f78..00000000000 Binary files a/examples/jupyter/images/teapot.jpg and /dev/null differ diff --git a/examples/jupyter/images/umesh_flux.png b/examples/jupyter/images/umesh_flux.png deleted file mode 100644 index 5d31e1cda2e..00000000000 Binary files a/examples/jupyter/images/umesh_flux.png and /dev/null differ diff --git a/examples/jupyter/images/umesh_heating.png b/examples/jupyter/images/umesh_heating.png deleted file mode 100644 index 984d1e34af0..00000000000 Binary files a/examples/jupyter/images/umesh_heating.png and /dev/null differ diff --git a/examples/jupyter/images/umesh_w_assembly.png b/examples/jupyter/images/umesh_w_assembly.png deleted file mode 100644 index 61e3ac5874a..00000000000 Binary files a/examples/jupyter/images/umesh_w_assembly.png and /dev/null differ diff --git a/examples/jupyter/mdgxs-part-i.ipynb b/examples/jupyter/mdgxs-part-i.ipynb deleted file mode 100644 index ea1dd7bcdfa..00000000000 --- a/examples/jupyter/mdgxs-part-i.ipynb +++ /dev/null @@ -1,1495 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multigroup (Delayed) Cross Section Generation Part I: Introduction\n", - "This IPython Notebook introduces the use of the `openmc.mgxs` module to calculate multi-energy-group and multi-delayed-group cross sections for an infinite homogeneous medium. In particular, this Notebook introduces the the following features:\n", - "\n", - "* Creation of multi-delayed-group cross sections for an **infinite homogeneous medium**\n", - "* Calculation of delayed neutron precursor concentrations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Introduction to Multi-Delayed-Group Cross Sections (MDGXS)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Many Monte Carlo particle transport codes, including OpenMC, use continuous-energy nuclear cross section data. However, most deterministic neutron transport codes use *multi-group cross sections* defined over discretized energy bins or *energy groups*. Furthermore, kinetics calculations typically separate out parameters that involve delayed neutrons into prompt and delayed components and further subdivide delayed components by delayed groups. An example is the energy spectrum for prompt and delayed neutrons for U-235 and Pu-239 computed for a light water reactor spectrum." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": { - "image/png": { - "width": 350 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "Image(filename='images/mdgxs.png', width=350)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A variety of tools employing different methodologies have been developed over the years to compute multi-group cross sections for certain applications, including NJOY (LANL), MC$^2$-3 (ANL), and Serpent (VTT). The `openmc.mgxs` Python module is designed to leverage OpenMC's tally system to calculate multi-group cross sections with arbitrary energy discretizations and different delayed group models (e.g. 6, 7, or 8 delayed group models) for fine-mesh heterogeneous deterministic neutron transport applications.\n", - "\n", - "Before proceeding to illustrate how one may use the `openmc.mgxs` module, it is worthwhile to define the general equations used to calculate multi-energy-group and multi-delayed-group cross sections. This is only intended as a brief overview of the methodology used by `openmc.mgxs` - we refer the interested reader to the large body of literature on the subject for a more comprehensive understanding of this complex topic." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Introductory Notation\n", - "The continuous real-valued microscopic cross section may be denoted $\\sigma_{n,x}(\\mathbf{r}, E)$ for position vector $\\mathbf{r}$, energy $E$, nuclide $n$ and interaction type $x$. Similarly, the scalar neutron flux may be denoted by $\\Phi(\\mathbf{r},E)$ for position $\\mathbf{r}$ and energy $E$. **Note**: Although nuclear cross sections are dependent on the temperature $T$ of the interacting medium, the temperature variable is neglected here for brevity." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Spatial and Energy Discretization\n", - "The energy domain for critical systems such as thermal reactors spans more than 10 orders of magnitude of neutron energies from 10$^{-5}$ - 10$^7$ eV. The multi-group approximation discretization divides this energy range into one or more energy groups. In particular, for $G$ total groups, we denote an energy group index $g$ such that $g \\in \\{1, 2, ..., G\\}$. The energy group indices are defined such that the smaller group the higher the energy, and vice versa. The integration over neutron energies across a discrete energy group is commonly referred to as **energy condensation**.\n", - "\n", - "The delayed neutrons created from fissions are created from > 30 delayed neutron precursors. Modeling each of the delayed neutron precursors is possible, but this approach has not recieved much attention due to large uncertainties in certain precursors. Therefore, the delayed neutrons are often combined into \"delayed groups\" that have a set time constant, $\\lambda_d$. Some cross section libraries use the same group time constants for all nuclides (e.g. JEFF 3.1) while other libraries use different time constants for all nuclides (e.g. ENDF/B-VII.1). Multi-delayed-group cross sections can either be created with the entire delayed group set, a subset of delayed groups, or integrated over all delayed groups.\n", - "\n", - "Multi-group cross sections are computed for discretized spatial zones in the geometry of interest. The spatial zones may be defined on a structured and regular fuel assembly or pin cell mesh, an arbitrary unstructured mesh or the constructive solid geometry used by OpenMC. For a geometry with $K$ distinct spatial zones, we designate each spatial zone an index $k$ such that $k \\in \\{1, 2, ..., K\\}$. The volume of each spatial zone is denoted by $V_{k}$. The integration over discrete spatial zones is commonly referred to as **spatial homogenization**." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### General Scalar-Flux Weighted MDGXS\n", - "The multi-group cross sections computed by `openmc.mgxs` are defined as a *scalar flux-weighted average* of the microscopic cross sections across each discrete energy group. This formulation is employed in order to preserve the reaction rates within each energy group and spatial zone. In particular, spatial homogenization and energy condensation are used to compute the general multi-group cross section. For instance, the delayed-nu-fission multi-energy-group and multi-delayed-group cross section, $\\nu_d \\sigma_{f,x,k,g}$, can be computed as follows:\n", - "\n", - "$$\\nu_d \\sigma_{n,x,k,g} = \\frac{\\int_{E_{g}}^{E_{g-1}}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r} \\nu_d \\sigma_{f,x}(\\mathbf{r},E')\\Phi(\\mathbf{r},E')}{\\int_{E_{g}}^{E_{g-1}}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r}\\Phi(\\mathbf{r},E')}$$\n", - "\n", - "This scalar flux-weighted average microscopic cross section is computed by `openmc.mgxs` for only the delayed-nu-fission and delayed neutron fraction reaction type at the moment. These double integrals are stochastically computed with OpenMC's tally system - in particular, [filters](../usersguide/tallies.rst#filters) on the energy range and spatial zone (material, cell, universe, or mesh) define the bounds of integration for both numerator and denominator." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Multi-Group Prompt and Delayed Fission Spectrum\n", - "The energy spectrum of neutrons emitted from fission is denoted by $\\chi_{n}(\\mathbf{r},E' \\rightarrow E'')$ for incoming and outgoing energies $E'$ and $E''$, respectively. Unlike the multi-group cross sections $\\sigma_{n,x,k,g}$ considered up to this point, the fission spectrum is a probability distribution and must sum to unity. The outgoing energy is typically much less dependent on the incoming energy for fission than for scattering interactions. As a result, it is common practice to integrate over the incoming neutron energy when computing the multi-group fission spectrum. The fission spectrum may be simplified as $\\chi_{n}(\\mathbf{r},E)$ with outgoing energy $E$.\n", - "\n", - "Computing the cumulative energy spectrum of emitted neutrons, $\\chi_{n}(\\mathbf{r},E)$, has been presented in the `mgxs-part-i.ipynb` notebook. Here, we will present the energy spectrum of prompt and delayed emission neutrons, $\\chi_{n,p}(\\mathbf{r},E)$ and $\\chi_{n,d}(\\mathbf{r},E)$, respectively. Unlike the multi-group cross sections defined up to this point, the multi-group fission spectrum is weighted by the fission production rate rather than the scalar flux. This formulation is intended to preserve the total fission production rate in the multi-group deterministic calculation. In order to mathematically define the multi-group fission spectrum, we denote the microscopic fission cross section as $\\sigma_{n,f}(\\mathbf{r},E)$ and the average number of neutrons emitted from fission interactions with nuclide $n$ as $\\nu_{n,p}(\\mathbf{r},E)$ and $\\nu_{n,d}(\\mathbf{r},E)$ for prompt and delayed neutrons, respectively. The multi-group fission spectrum $\\chi_{n,k,g,d}$ is then the probability of fission neutrons emitted into energy group $g$ and delayed group $d$. There are not prompt groups, so inserting $p$ in place of $d$ just denotes all prompt neutrons. \n", - "\n", - "Similar to before, spatial homogenization and energy condensation are used to find the multi-energy-group and multi-delayed-group fission spectrum $\\chi_{n,k,g,d}$ as follows:\n", - "\n", - "$$\\chi_{n,k,g',d} = \\frac{\\int_{E_{g'}}^{E_{g'-1}}\\mathrm{d}E''\\int_{0}^{\\infty}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r}\\chi_{n,d}(\\mathbf{r},E'\\rightarrow E'')\\nu_{n,d}(\\mathbf{r},E')\\sigma_{n,f}(\\mathbf{r},E')\\Phi(\\mathbf{r},E')}{\\int_{0}^{\\infty}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r}\\nu_{n,d}(\\mathbf{r},E')\\sigma_{n,f}(\\mathbf{r},E')\\Phi(\\mathbf{r},E')}$$\n", - "\n", - "The fission production-weighted multi-energy-group and multi-delayed-group fission spectrum for delayed neutrons is computed using OpenMC tallies with energy in, energy out, and delayed group filters. Alternatively, the delayed group filter can be omitted to compute the fission spectrum integrated over all delayed groups.\n", - "\n", - "This concludes our brief overview on the methodology to compute multi-energy-group and multi-delayed-group cross sections. The following sections detail more concretely how users may employ the `openmc.mgxs` module to power simulation workflows requiring multi-group cross sections for downstream deterministic calculations." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "import openmc\n", - "import openmc.mgxs as mgxs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we need to define materials that will be used in the problem. Let's create a material for the homogeneous medium." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Material and register the Nuclides\n", - "inf_medium = openmc.Material(name='moderator')\n", - "inf_medium.set_density('g/cc', 5.)\n", - "inf_medium.add_nuclide('H1', 0.03)\n", - "inf_medium.add_nuclide('O16', 0.015)\n", - "inf_medium.add_nuclide('U235', 0.0001)\n", - "inf_medium.add_nuclide('U238', 0.007)\n", - "inf_medium.add_nuclide('Pu239', 0.00003)\n", - "inf_medium.add_nuclide('Zr90', 0.002)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our material, we can now create a `Materials` object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Materials collection and export to XML\n", - "materials_file = openmc.Materials([inf_medium])\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. This problem will be a simple square cell with reflective boundary conditions to simulate an infinite homogeneous medium. The first step is to create the outer bounding surfaces of the problem." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate boundary Planes\n", - "min_x = openmc.XPlane(boundary_type='reflective', x0=-0.63)\n", - "max_x = openmc.XPlane(boundary_type='reflective', x0=0.63)\n", - "min_y = openmc.YPlane(boundary_type='reflective', y0=-0.63)\n", - "max_y = openmc.YPlane(boundary_type='reflective', y0=0.63)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now create a cell that is defined by intersections of half-spaces created by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Cell\n", - "cell = openmc.Cell(cell_id=1, name='cell')\n", - "\n", - "# Register bounding Surfaces with the Cell\n", - "cell.region = +min_x & -max_x & +min_y & -max_y\n", - "\n", - "# Fill the Cell with the Material\n", - "cell.fill = inf_medium" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now must create a geometry and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and set root Universe\n", - "openmc_geometry = openmc.Geometry([cell])\n", - "\n", - "# Export to \"geometry.xml\"\n", - "openmc_geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we must define simulation parameters. In this case, we will use 10 inactive batches and 40 active batches each with 2500 particles." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "batches = 50\n", - "inactive = 10\n", - "particles = 5000\n", - "\n", - "# Instantiate a Settings object\n", - "settings_file = openmc.Settings()\n", - "settings_file.batches = batches\n", - "settings_file.inactive = inactive\n", - "settings_file.particles = particles\n", - "settings_file.output = {'tallies': True}\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-0.63, -0.63, -0.63, 0.63, 0.63, 0.63]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings_file.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we are ready to generate multi-group cross sections! First, let's define a 100-energy-group structure and 1-energy-group structure using the built-in `EnergyGroups` class. We will also create a 6-delayed-group list." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a 100-group EnergyGroups object\n", - "energy_groups = mgxs.EnergyGroups()\n", - "energy_groups.group_edges = np.logspace(-3, 7.3, 101)\n", - "\n", - "# Instantiate a 1-group EnergyGroups object\n", - "one_group = mgxs.EnergyGroups()\n", - "one_group.group_edges = np.array([energy_groups.group_edges[0], energy_groups.group_edges[-1]])\n", - "\n", - "delayed_groups = list(range(1,7))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now use the `EnergyGroups` object and delayed group list, along with our previously created materials and geometry, to instantiate some `MGXS` objects from the `openmc.mgxs` module. In particular, the following are subclasses of the generic and abstract `MGXS` class:\n", - "\n", - "* `TotalXS`\n", - "* `TransportXS`\n", - "* `AbsorptionXS`\n", - "* `CaptureXS`\n", - "* `FissionXS`\n", - "* `NuFissionMatrixXS`\n", - "* `KappaFissionXS`\n", - "* `ScatterXS`\n", - "* `ScatterMatrixXS`\n", - "* `Chi`\n", - "* `InverseVelocity`\n", - "\n", - "A separate abstract `MDGXS` class is used for cross-sections and parameters that involve delayed neutrons. The subclasses of `MDGXS` include:\n", - "\n", - "* `DelayedNuFissionXS`\n", - "* `ChiDelayed`\n", - "* `Beta`\n", - "* `DecayRate`\n", - "\n", - "These classes provide us with an interface to generate the tally inputs as well as perform post-processing of OpenMC's tally data to compute the respective multi-group cross sections. \n", - "\n", - "In this case, let's create the multi-group chi-prompt, chi-delayed, and prompt-nu-fission cross sections with our 100-energy-group structure and multi-group delayed-nu-fission and beta cross sections with our 100-energy-group and 6-delayed-group structures. \n", - "\n", - "The prompt chi and nu-fission data can actually be gathered using the `Chi` and `FissionXS` classes, respectively, by passing in a value of `True` for the optional `prompt` parameter upon initialization." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a few different sections\n", - "chi_prompt = mgxs.Chi(domain=cell, groups=energy_groups, by_nuclide=True, prompt=True)\n", - "prompt_nu_fission = mgxs.FissionXS(domain=cell, groups=energy_groups, by_nuclide=True, nu=True, prompt=True)\n", - "chi_delayed = mgxs.ChiDelayed(domain=cell, energy_groups=energy_groups, by_nuclide=True)\n", - "delayed_nu_fission = mgxs.DelayedNuFissionXS(domain=cell, energy_groups=energy_groups, delayed_groups=delayed_groups, by_nuclide=True)\n", - "beta = mgxs.Beta(domain=cell, energy_groups=energy_groups, delayed_groups=delayed_groups, by_nuclide=True)\n", - "decay_rate = mgxs.DecayRate(domain=cell, energy_groups=one_group, delayed_groups=delayed_groups, by_nuclide=True)\n", - "\n", - "chi_prompt.nuclides = ['U235', 'Pu239']\n", - "prompt_nu_fission.nuclides = ['U235', 'Pu239']\n", - "chi_delayed.nuclides = ['U235', 'Pu239']\n", - "delayed_nu_fission.nuclides = ['U235', 'Pu239']\n", - "beta.nuclides = ['U235', 'Pu239']\n", - "decay_rate.nuclides = ['U235', 'Pu239']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Each multi-group cross section object stores its tallies in a Python dictionary called `tallies`. We can inspect the tallies in the dictionary for our `Decay Rate` object as follows. " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "OrderedDict([('delayed-nu-fission', Tally\n", - " \tID =\t1\n", - " \tName =\t\n", - " \tFilters =\tCellFilter, DelayedGroupFilter, EnergyFilter\n", - " \tNuclides =\tU235 Pu239 \n", - " \tScores =\t['delayed-nu-fission']\n", - " \tEstimator =\ttracklength), ('decay-rate', Tally\n", - " \tID =\t2\n", - " \tName =\t\n", - " \tFilters =\tCellFilter, DelayedGroupFilter, EnergyFilter\n", - " \tNuclides =\tU235 Pu239 \n", - " \tScores =\t['decay-rate']\n", - " \tEstimator =\ttracklength)])" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "decay_rate.tallies" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `Beta` object includes tracklength tallies for the 'nu-fission' and 'delayed-nu-fission' scores in the 100-energy-group and 6-delayed-group structure in cell 1. Now that each `MGXS` and `MDGXS` object contains the tallies that it needs, we must add these tallies to a `Tallies` object to generate the \"tallies.xml\" input file for OpenMC." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=4.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=6.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=5.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=8.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=14.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Instantiate an empty Tallies object\n", - "tallies_file = openmc.Tallies()\n", - "\n", - "# Add chi-prompt tallies to the tallies file\n", - "tallies_file += chi_prompt.tallies.values()\n", - "\n", - "# Add prompt-nu-fission tallies to the tallies file\n", - "tallies_file += prompt_nu_fission.tallies.values()\n", - "\n", - "# Add chi-delayed tallies to the tallies file\n", - "tallies_file += chi_delayed.tallies.values()\n", - "\n", - "# Add delayed-nu-fission tallies to the tallies file\n", - "tallies_file += delayed_nu_fission.tallies.values()\n", - "\n", - "# Add beta tallies to the tallies file\n", - "tallies_file += beta.tallies.values()\n", - "\n", - "# Add decay rate tallies to the tallies file\n", - "tallies_file += decay_rate.tallies.values()\n", - "\n", - "# Export to \"tallies.xml\"\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we a have a complete set of inputs, so we can go ahead and run our simulation." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | 61c911cffdae2406f9f4bc667a9a6954748bb70c\n", - " Date/Time | 2019-07-19 06:56:34\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading H1 from /opt/data/hdf5/nndc_hdf5_v15/H1.h5\n", - " Reading O16 from /opt/data/hdf5/nndc_hdf5_v15/O16.h5\n", - " Reading U235 from /opt/data/hdf5/nndc_hdf5_v15/U235.h5\n", - " Reading U238 from /opt/data/hdf5/nndc_hdf5_v15/U238.h5\n", - " Reading Pu239 from /opt/data/hdf5/nndc_hdf5_v15/Pu239.h5\n", - " Reading Zr90 from /opt/data/hdf5/nndc_hdf5_v15/Zr90.h5\n", - " Maximum neutron transport energy: 20000000.000000 eV for H1\n", - " Reading tallies XML file...\n", - " Writing summary.h5 file...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 1.21670\n", - " 2/1 1.24155\n", - " 3/1 1.21924\n", - " 4/1 1.22486\n", - " 5/1 1.21719\n", - " 6/1 1.24330\n", - " 7/1 1.22322\n", - " 8/1 1.24133\n", - " 9/1 1.21840\n", - " 10/1 1.25141\n", - " 11/1 1.21217\n", - " 12/1 1.25625 1.23421 +/- 0.02204\n", - " 13/1 1.22056 1.22966 +/- 0.01351\n", - " 14/1 1.21757 1.22664 +/- 0.01002\n", - " 15/1 1.24571 1.23045 +/- 0.00865\n", - " 16/1 1.26489 1.23619 +/- 0.00910\n", - " 17/1 1.22323 1.23434 +/- 0.00791\n", - " 18/1 1.26108 1.23768 +/- 0.00762\n", - " 19/1 1.23145 1.23699 +/- 0.00676\n", - " 20/1 1.23548 1.23684 +/- 0.00605\n", - " 21/1 1.20446 1.23390 +/- 0.00621\n", - " 22/1 1.20533 1.23152 +/- 0.00615\n", - " 23/1 1.22520 1.23103 +/- 0.00568\n", - " 24/1 1.18367 1.22765 +/- 0.00625\n", - " 25/1 1.23614 1.22821 +/- 0.00585\n", - " 26/1 1.23746 1.22879 +/- 0.00550\n", - " 27/1 1.23626 1.22923 +/- 0.00518\n", - " 28/1 1.21334 1.22835 +/- 0.00497\n", - " 29/1 1.25169 1.22958 +/- 0.00486\n", - " 30/1 1.25579 1.23089 +/- 0.00479\n", - " 31/1 1.23828 1.23124 +/- 0.00457\n", - " 32/1 1.26911 1.23296 +/- 0.00468\n", - " 33/1 1.20090 1.23157 +/- 0.00469\n", - " 34/1 1.28606 1.23384 +/- 0.00503\n", - " 35/1 1.23129 1.23374 +/- 0.00483\n", - " 36/1 1.22535 1.23341 +/- 0.00465\n", - " 37/1 1.20367 1.23231 +/- 0.00461\n", - " 38/1 1.22886 1.23219 +/- 0.00444\n", - " 39/1 1.24056 1.23248 +/- 0.00429\n", - " 40/1 1.25038 1.23307 +/- 0.00419\n", - " 41/1 1.21504 1.23249 +/- 0.00410\n", - " 42/1 1.20762 1.23171 +/- 0.00404\n", - " 43/1 1.20597 1.23093 +/- 0.00399\n", - " 44/1 1.24424 1.23133 +/- 0.00389\n", - " 45/1 1.24767 1.23179 +/- 0.00381\n", - " 46/1 1.22998 1.23174 +/- 0.00370\n", - " 47/1 1.26195 1.23256 +/- 0.00369\n", - " 48/1 1.23146 1.23253 +/- 0.00359\n", - " 49/1 1.22059 1.23222 +/- 0.00351\n", - " 50/1 1.24724 1.23260 +/- 0.00345\n", - " Creating state point statepoint.50.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 4.7388e-01 seconds\n", - " Reading cross sections = 4.4709e-01 seconds\n", - " Total time in simulation = 3.9290e+01 seconds\n", - " Time in transport only = 3.9005e+01 seconds\n", - " Time in inactive batches = 1.4079e+00 seconds\n", - " Time in active batches = 3.7882e+01 seconds\n", - " Time synchronizing fission bank = 1.8814e-02 seconds\n", - " Sampling source sites = 1.6376e-02 seconds\n", - " SEND/RECV source sites = 2.3626e-03 seconds\n", - " Time accumulating tallies = 8.3299e-04 seconds\n", - " Total time for finalization = 1.1533e-02 seconds\n", - " Total time elapsed = 3.9783e+01 seconds\n", - " Calculation Rate (inactive) = 35514.2 particles/second\n", - " Calculation Rate (active) = 5279.54 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.23256 +/- 0.00308\n", - " k-effective (Track-length) = 1.23260 +/- 0.00345\n", - " k-effective (Absorption) = 1.23111 +/- 0.00186\n", - " Combined k-effective = 1.23135 +/- 0.00184\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Run OpenMC\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our simulation ran successfully and created statepoint and summary output files. We begin our analysis by instantiating a `StatePoint` object. " - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the last statepoint file\n", - "sp = openmc.StatePoint('statepoint.50.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In addition to the statepoint file, our simulation also created a summary file which encapsulates information about the materials and geometry. By default, a `Summary` object is automatically linked when a `StatePoint` is loaded. This is necessary for the `openmc.mgxs` module to properly process the tally data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The statepoint is now ready to be analyzed by our multi-group cross sections. We simply have to load the tallies from the `StatePoint` into each object as follows and our `MGXS` objects will compute the cross sections for us under-the-hood." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the tallies from the statepoint into each MGXS object\n", - "chi_prompt.load_from_statepoint(sp)\n", - "prompt_nu_fission.load_from_statepoint(sp)\n", - "chi_delayed.load_from_statepoint(sp)\n", - "delayed_nu_fission.load_from_statepoint(sp)\n", - "beta.load_from_statepoint(sp)\n", - "decay_rate.load_from_statepoint(sp)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Voila! Our multi-group cross sections are now ready to rock 'n roll!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Extracting and Storing MGXS Data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's first inspect our delayed-nu-fission section by printing it to the screen after condensing the cross section down to one group." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[5.14223507e-06, 1.16426087e-06]],\n", - "\n", - " [[2.65426350e-05, 7.58220468e-06]],\n", - "\n", - " [[2.53399053e-05, 5.73796202e-06]],\n", - "\n", - " [[5.68141581e-05, 1.04757933e-05]],\n", - "\n", - " [[2.32930026e-05, 5.45658817e-06]],\n", - "\n", - " [[9.75735783e-06, 1.65150949e-06]]])" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "delayed_nu_fission.get_condensed_xs(one_group).get_xs()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since the `openmc.mgxs` module uses [tally arithmetic](tally-arithmetic.ipynb) under-the-hood, the cross section is stored as a \"derived\" `Tally` object. This means that it can be queried and manipulated using all of the same methods supported for the `Tally` class in the OpenMC Python API. For example, we can construct a [Pandas](https://pandas.pydata.org/) `DataFrame` of the multi-group cross section data." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
celldelayedgroupgroup innuclidemeanstd. dev.
198111U2359.345817e-086.616216e-08
199111Pu2391.574816e-081.114955e-08
398121U2354.824023e-073.415087e-07
399121Pu2391.025593e-077.261101e-08
598131U2354.605432e-073.260339e-07
599131Pu2397.761348e-085.494962e-08
798141U2351.032576e-067.309948e-07
799141Pu2391.416989e-071.003215e-07
998151U2354.233415e-072.996976e-07
999151Pu2397.380753e-085.225504e-08
\n", - "
" - ], - "text/plain": [ - " cell delayedgroup group in nuclide mean std. dev.\n", - "198 1 1 1 U235 9.345817e-08 6.616216e-08\n", - "199 1 1 1 Pu239 1.574816e-08 1.114955e-08\n", - "398 1 2 1 U235 4.824023e-07 3.415087e-07\n", - "399 1 2 1 Pu239 1.025593e-07 7.261101e-08\n", - "598 1 3 1 U235 4.605432e-07 3.260339e-07\n", - "599 1 3 1 Pu239 7.761348e-08 5.494962e-08\n", - "798 1 4 1 U235 1.032576e-06 7.309948e-07\n", - "799 1 4 1 Pu239 1.416989e-07 1.003215e-07\n", - "998 1 5 1 U235 4.233415e-07 2.996976e-07\n", - "999 1 5 1 Pu239 7.380753e-08 5.225504e-08" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = delayed_nu_fission.get_pandas_dataframe()\n", - "df.head(10)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
celldelayedgroupgroup innuclidemeanstd. dev.
0111U2350.0133360.000061
1111Pu2390.0132710.000053
2121U2350.0327390.000149
3121Pu2390.0308810.000123
4131U2350.1207800.000549
5131Pu2390.1133700.000451
6141U2350.3027800.001378
7141Pu2390.2925000.001163
8151U2350.8494900.003865
9151Pu2390.8574900.003411
10161U2352.8530000.012980
11161Pu2392.7297000.010858
\n", - "
" - ], - "text/plain": [ - " cell delayedgroup group in nuclide mean std. dev.\n", - "0 1 1 1 U235 0.013336 0.000061\n", - "1 1 1 1 Pu239 0.013271 0.000053\n", - "2 1 2 1 U235 0.032739 0.000149\n", - "3 1 2 1 Pu239 0.030881 0.000123\n", - "4 1 3 1 U235 0.120780 0.000549\n", - "5 1 3 1 Pu239 0.113370 0.000451\n", - "6 1 4 1 U235 0.302780 0.001378\n", - "7 1 4 1 Pu239 0.292500 0.001163\n", - "8 1 5 1 U235 0.849490 0.003865\n", - "9 1 5 1 Pu239 0.857490 0.003411\n", - "10 1 6 1 U235 2.853000 0.012980\n", - "11 1 6 1 Pu239 2.729700 0.010858" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = decay_rate.get_pandas_dataframe()\n", - "df.head(12)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Each multi-group cross section object can be easily exported to a variety of file formats, including CSV, Excel, and LaTeX for storage or data processing." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "beta.export_xs_data(filename='beta', format='excel')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following code snippet shows how to export the chi-prompt and chi-delayed `MGXS` to the same HDF5 binary data store." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "chi_prompt.build_hdf5_store(filename='mdgxs', append=True)\n", - "chi_delayed.build_hdf5_store(filename='mdgxs', append=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Using Tally Arithmetic to Compute the Delayed Neutron Precursor Concentrations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, we illustrate how one can leverage OpenMC's [tally arithmetic](tally-arithmetic.ipynb) data processing feature with `MGXS` objects. The `openmc.mgxs` module uses tally arithmetic to compute multi-group cross sections with automated uncertainty propagation. Each `MGXS` object includes an `xs_tally` attribute which is a \"derived\" `Tally` based on the tallies needed to compute the cross section type of interest. These derived tallies can be used in subsequent tally arithmetic operations. For example, we can use tally artithmetic to compute the delayed neutron precursor concentrations using the `Beta`, `DelayedNuFissionXS`, and `DecayRate` objects. The delayed neutron precursor concentrations are modeled using the following equations:\n", - "\n", - "$$\\frac{\\partial}{\\partial t} C_{k,d} (t) = \\int_{0}^{\\infty}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r} \\beta_{k,d} (t) \\nu_d \\sigma_{f,x}(\\mathbf{r},E',t)\\Phi(\\mathbf{r},E',t) - \\lambda_{d} C_{k,d} (t) $$\n", - "\n", - "$$C_{k,d} (t=0) = \\frac{1}{\\lambda_{d}} \\int_{0}^{\\infty}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r} \\beta_{k,d} (t=0) \\nu_d \\sigma_{f,x}(\\mathbf{r},E',t=0)\\Phi(\\mathbf{r},E',t=0) $$\n", - "\n", - "First, let's investigate the decay rates for U235 and Pu235. The fraction of the delayed neutron precursors remaining as a function of time after fission for each delayed group and fissioning isotope have been plotted below." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Get the decay rate data\n", - "dr_tally = decay_rate.xs_tally\n", - "dr_u235 = dr_tally.get_values(nuclides=['U235']).flatten()\n", - "dr_pu239 = dr_tally.get_values(nuclides=['Pu239']).flatten()\n", - "\n", - "# Compute the exponential decay of the precursors\n", - "time = np.logspace(-3,3)\n", - "dr_u235_points = np.exp(-np.outer(dr_u235, time))\n", - "dr_pu239_points = np.exp(-np.outer(dr_pu239, time))\n", - "\n", - "# Create a plot of the fraction of the precursors remaining as a f(time)\n", - "colors = ['b', 'g', 'r', 'c', 'm', 'k']\n", - "legend = []\n", - "fig = plt.figure(figsize=(8,6))\n", - "for g,c in enumerate(colors):\n", - " plt.semilogx(time, dr_u235_points [g,:], color=c, linestyle='--', linewidth=3)\n", - " plt.semilogx(time, dr_pu239_points[g,:], color=c, linestyle=':' , linewidth=3)\n", - " legend.append('U-235 $t_{1/2}$ = ' + '{0:1.2f} seconds'.format(np.log(2) / dr_u235[g]))\n", - " legend.append('Pu-239 $t_{1/2}$ = ' + '{0:1.2f} seconds'.format(np.log(2) / dr_pu239[g]))\n", - "\n", - "plt.title('Delayed Neutron Precursor Decay Rates')\n", - "plt.xlabel('Time (s)')\n", - "plt.ylabel('Fraction Remaining')\n", - "plt.legend(legend, loc=1, bbox_to_anchor=(1.55, 0.95))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's compute the initial concentration of the delayed neutron precursors:" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
celldelayedgroupnuclidescoremeanstd. dev.
011U235(((delayed-nu-fission / nu-fission) * (delayed...8.779139e-084.658590e-10
111Pu239(((delayed-nu-fission / nu-fission) * (delayed...7.149814e-093.559010e-11
212U235(((delayed-nu-fission / nu-fission) * (delayed...9.527880e-075.055905e-09
312Pu239(((delayed-nu-fission / nu-fission) * (delayed...1.303159e-076.486820e-10
413U235(((delayed-nu-fission / nu-fission) * (delayed...2.353903e-071.249083e-09
513Pu239(((delayed-nu-fission / nu-fission) * (delayed...2.032895e-081.011928e-10
614U235(((delayed-nu-fission / nu-fission) * (delayed...4.720191e-072.504737e-09
714Pu239(((delayed-nu-fission / nu-fission) * (delayed...2.626309e-081.307315e-10
815U235(((delayed-nu-fission / nu-fission) * (delayed...2.827915e-081.500614e-10
915Pu239(((delayed-nu-fission / nu-fission) * (delayed...2.430587e-091.209889e-11
1016U235(((delayed-nu-fission / nu-fission) * (delayed...1.477530e-097.840413e-12
1116Pu239(((delayed-nu-fission / nu-fission) * (delayed...6.994312e-113.481605e-13
\n", - "
" - ], - "text/plain": [ - " cell delayedgroup nuclide \\\n", - "0 1 1 U235 \n", - "1 1 1 Pu239 \n", - "2 1 2 U235 \n", - "3 1 2 Pu239 \n", - "4 1 3 U235 \n", - "5 1 3 Pu239 \n", - "6 1 4 U235 \n", - "7 1 4 Pu239 \n", - "8 1 5 U235 \n", - "9 1 5 Pu239 \n", - "10 1 6 U235 \n", - "11 1 6 Pu239 \n", - "\n", - " score mean std. dev. \n", - "0 (((delayed-nu-fission / nu-fission) * (delayed... 8.78e-08 4.66e-10 \n", - "1 (((delayed-nu-fission / nu-fission) * (delayed... 7.15e-09 3.56e-11 \n", - "2 (((delayed-nu-fission / nu-fission) * (delayed... 9.53e-07 5.06e-09 \n", - "3 (((delayed-nu-fission / nu-fission) * (delayed... 1.30e-07 6.49e-10 \n", - "4 (((delayed-nu-fission / nu-fission) * (delayed... 2.35e-07 1.25e-09 \n", - "5 (((delayed-nu-fission / nu-fission) * (delayed... 2.03e-08 1.01e-10 \n", - "6 (((delayed-nu-fission / nu-fission) * (delayed... 4.72e-07 2.50e-09 \n", - "7 (((delayed-nu-fission / nu-fission) * (delayed... 2.63e-08 1.31e-10 \n", - "8 (((delayed-nu-fission / nu-fission) * (delayed... 2.83e-08 1.50e-10 \n", - "9 (((delayed-nu-fission / nu-fission) * (delayed... 2.43e-09 1.21e-11 \n", - "10 (((delayed-nu-fission / nu-fission) * (delayed... 1.48e-09 7.84e-12 \n", - "11 (((delayed-nu-fission / nu-fission) * (delayed... 6.99e-11 3.48e-13 " - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Use tally arithmetic to compute the precursor concentrations\n", - "precursor_conc = beta.get_condensed_xs(one_group).xs_tally.summation(filter_type=openmc.EnergyFilter, remove_filter=True) * \\\n", - " delayed_nu_fission.get_condensed_xs(one_group).xs_tally.summation(filter_type=openmc.EnergyFilter, remove_filter=True) / \\\n", - " decay_rate.xs_tally.summation(filter_type=openmc.EnergyFilter, remove_filter=True)\n", - "\n", - "# Get the Pandas DataFrames for inspection\n", - "precursor_conc.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can plot the delayed neutron fractions for each nuclide." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Beta (U-235) : 0.006504 +/- 0.000007\n", - "Beta (Pu-239): 0.002245 +/- 0.000002\n" - ] - }, - { - "data": { - "text/plain": [ - "(0, 7)" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "energy_filter = [f for f in beta.xs_tally.filters if type(f) is openmc.EnergyFilter]\n", - "beta_integrated = beta.get_condensed_xs(one_group).xs_tally.summation(filter_type=openmc.EnergyFilter, remove_filter=True)\n", - "beta_u235 = beta_integrated.get_values(nuclides=['U235'])\n", - "beta_pu239 = beta_integrated.get_values(nuclides=['Pu239'])\n", - "\n", - "# Reshape the betas\n", - "beta_u235.shape = (beta_u235.shape[0])\n", - "beta_pu239.shape = (beta_pu239.shape[0])\n", - "\n", - "df = beta_integrated.summation(filter_type=openmc.DelayedGroupFilter, remove_filter=True).get_pandas_dataframe()\n", - "print('Beta (U-235) : {:.6f} +/- {:.6f}'.format(df[df['nuclide'] == 'U235']['mean'][0], df[df['nuclide'] == 'U235']['std. dev.'][0]))\n", - "print('Beta (Pu-239): {:.6f} +/- {:.6f}'.format(df[df['nuclide'] == 'Pu239']['mean'][1], df[df['nuclide'] == 'Pu239']['std. dev.'][1]))\n", - "\n", - "beta_u235 = np.append(beta_u235[0], beta_u235)\n", - "beta_pu239 = np.append(beta_pu239[0], beta_pu239)\n", - "\n", - "# Create a step plot for the MGXS\n", - "plt.plot(np.arange(0.5, 7.5, 1), beta_u235, drawstyle='steps', color='b', linewidth=3)\n", - "plt.plot(np.arange(0.5, 7.5, 1), beta_pu239, drawstyle='steps', color='g', linewidth=3)\n", - "\n", - "plt.title('Delayed Neutron Fraction (beta)')\n", - "plt.xlabel('Delayed Group')\n", - "plt.ylabel('Beta(fraction total neutrons)')\n", - "plt.legend(['U-235', 'Pu-239'])\n", - "plt.xlim([0,7])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also plot the energy spectrum for fission emission of prompt and delayed neutrons." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1000.0, 20000000.0)" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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Hox/75XHAyeJyE9xXCB3FJE6VZ3uLaSq5UA5QGFhYYMNI7t376ampoavv07k/dlIVzp37szBBx/MPvvsk2pRDKNNk0xlsRLoLyL9cJTEOByX1glR1YnBcxGZjBPqcHrsGtGpqakhNzeXvLw8JBQ4zsgUVJUtW7ZQU1NDv379Ui2OYbRpkjYN5Uaqmgo8hxPU5ClVXSMiN4jIGAAROU5EanBiO88WkTUtKcPXX39N9+7dTVFkKCJC9+7dbWRoGGlAUvdZqOpSHBfX3rTrPecrqR9oJ1obj+LEkW4SpigyG/v+Wp7yqnIuW3JZ6DqnYw6BkQFKTyhNoVRGupOuBu6soLq6mkGDBtVLCwQCzJo1q0HZjRs3csopp3DMMccwcOBA7rrrrlDeb37zG4YMGUJ+fj6nn346tbVOkLWKigr2228/8vPzyc/P54Ybbkgo06OPPsrUqXH3N/oq01zy8vL49NNPk3qPtkDZq2Xk3pKLzJSoR96deVR/Vh23jbpddQSWB1pFXiNzMWWRJnTo0IGysjLWrl3La6+9xn333cfatc7+xV/84he89dZbrFq1itGjR9dTCieddBKrVq1i1apVXH/99bGaN7KUwPIAdbvqYuZv37WdsU+NpejRorjtxGvDMMCURdrQq1cvhg0bBkBubi5HH300mzY5i8e6desWKvfll182emrmkUceYcCAAQwfPpxXXnkllP7JJ58wduxYjjvuOI477rh6eUEWL17MiBEjOPbYY/n+97/PRx99xN69e+nfvz/B5cp79+7liCOO4JNPPonZ5pYtWzj99NMZOHAgl1xyCebtuGVI9JDfumMr67esp3hAcSitpKAEnaHoDPsODP+0KWURCICIv6OkpGH9kpL6ZQKB5MhZXV3Nm2++yYgRI0Jp1113HYcccghz586tN7JYsWIFQ4cO5ayzzmLNmobrAzZv3syMGTN45ZVXePnll0OjFYArr7ySn//856xcuZKnn36aSy65pEH9E088kddee40333yTcePGcdttt9GuXTsuuOAC5s6dC8Df//53hg4dSo8ePWK2OXPmTE488UTWrFnDD3/4Q/773/+2WH8ZDkEFEHlsv3a72SOMZmPBj5JIrBFAvJFBXV0dY8eO5c4776w3orjpppu46aabuOWWW7j33nuZOXMmw4YNY8OGDeTk5LB06VLOOecc3n23fvC6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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "chi_d_u235 = np.squeeze(chi_delayed.get_xs(nuclides=['U235'], order_groups='decreasing'))\n", - "chi_d_pu239 = np.squeeze(chi_delayed.get_xs(nuclides=['Pu239'], order_groups='decreasing'))\n", - "chi_p_u235 = np.squeeze(chi_prompt.get_xs(nuclides=['U235'], order_groups='decreasing'))\n", - "chi_p_pu239 = np.squeeze(chi_prompt.get_xs(nuclides=['Pu239'], order_groups='decreasing'))\n", - "\n", - "chi_d_u235 = np.append(chi_d_u235 , chi_d_u235[0])\n", - "chi_d_pu239 = np.append(chi_d_pu239, chi_d_pu239[0])\n", - "chi_p_u235 = np.append(chi_p_u235 , chi_p_u235[0])\n", - "chi_p_pu239 = np.append(chi_p_pu239, chi_p_pu239[0])\n", - "\n", - "# Create a step plot for the MGXS\n", - "plt.semilogx(energy_groups.group_edges, chi_d_u235 , drawstyle='steps', color='b', linestyle='--', linewidth=3)\n", - "plt.semilogx(energy_groups.group_edges, chi_d_pu239, drawstyle='steps', color='g', linestyle='--', linewidth=3)\n", - "plt.semilogx(energy_groups.group_edges, chi_p_u235 , drawstyle='steps', color='b', linestyle=':', linewidth=3)\n", - "plt.semilogx(energy_groups.group_edges, chi_p_pu239, drawstyle='steps', color='g', linestyle=':', linewidth=3)\n", - "\n", - "plt.title('Energy Spectrum for Fission Neutrons')\n", - "plt.xlabel('Energy (eV)')\n", - "plt.ylabel('Fraction on emitted neutrons')\n", - "plt.legend(['U-235 delayed', 'Pu-239 delayed', 'U-235 prompt', 'Pu-239 prompt'],loc=2)\n", - "plt.xlim(1.0e3, 20.0e6)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/mdgxs-part-ii.ipynb b/examples/jupyter/mdgxs-part-ii.ipynb deleted file mode 100644 index 1c996c82a21..00000000000 --- a/examples/jupyter/mdgxs-part-ii.ipynb +++ /dev/null @@ -1,1179 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multigroup (Delayed) Cross Section Generation Part II: Advanced Features\n", - "This IPython Notebook illustrates the use of the **`openmc.mgxs.Library`** class. The `Library` class is designed to automate the calculation of multi-group cross sections for use cases with one or more domains, cross section types, and/or nuclides. In particular, this Notebook illustrates the following features:\n", - "\n", - "* Calculation of multi-energy-group and multi-delayed-group cross sections for a **fuel assembly**\n", - "* Automated creation, manipulation and storage of `MGXS` with **`openmc.mgxs.Library`**\n", - "* Steady-state pin-by-pin **delayed neutron fractions (beta)** for each delayed group.\n", - "* Generation of surface currents on the interfaces and surfaces of a Mesh." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import math\n", - "\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "import openmc\n", - "import openmc.mgxs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we need to define materials that will be used in the problem: fuel, water, and cladding." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# 1.6 enriched fuel\n", - "fuel = openmc.Material(name='1.6% Fuel')\n", - "fuel.set_density('g/cm3', 10.31341)\n", - "fuel.add_nuclide('U235', 3.7503e-4)\n", - "fuel.add_nuclide('U238', 2.2625e-2)\n", - "fuel.add_nuclide('O16', 4.6007e-2)\n", - "\n", - "# borated water\n", - "water = openmc.Material(name='Borated Water')\n", - "water.set_density('g/cm3', 0.740582)\n", - "water.add_nuclide('H1', 4.9457e-2)\n", - "water.add_nuclide('O16', 2.4732e-2)\n", - "water.add_nuclide('B10', 8.0042e-6)\n", - "\n", - "# zircaloy\n", - "zircaloy = openmc.Material(name='Zircaloy')\n", - "zircaloy.set_density('g/cm3', 6.55)\n", - "zircaloy.add_nuclide('Zr90', 7.2758e-3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our three materials, we can now create a `Materials` object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a materials collection and export to XML\n", - "materials = openmc.Materials((fuel, water, zircaloy))\n", - "materials.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. This problem will be a square array of fuel pins and control rod guide tubes for which we can use OpenMC's lattice/universe feature. The basic universe will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces for fuel and clad, as well as the outer bounding surfaces of the problem." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Create cylinders for the fuel and clad\n", - "fuel_outer_radius = openmc.ZCylinder(r=0.39218)\n", - "clad_outer_radius = openmc.ZCylinder(r=0.45720)\n", - "\n", - "# Create boundary planes to surround the geometry\n", - "min_x = openmc.XPlane(x0=-10.71, boundary_type='reflective')\n", - "max_x = openmc.XPlane(x0=+10.71, boundary_type='reflective')\n", - "min_y = openmc.YPlane(y0=-10.71, boundary_type='reflective')\n", - "max_y = openmc.YPlane(y0=+10.71, boundary_type='reflective')\n", - "min_z = openmc.ZPlane(z0=-10., boundary_type='reflective')\n", - "max_z = openmc.ZPlane(z0=+10., boundary_type='reflective')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now construct a fuel pin cell from cells that are defined by intersections of half-spaces created by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a Universe to encapsulate a fuel pin\n", - "fuel_pin_universe = openmc.Universe(name='1.6% Fuel Pin')\n", - "\n", - "# Create fuel Cell\n", - "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", - "fuel_cell.fill = fuel\n", - "fuel_cell.region = -fuel_outer_radius\n", - "fuel_pin_universe.add_cell(fuel_cell)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='1.6% Clad')\n", - "clad_cell.fill = zircaloy\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "fuel_pin_universe.add_cell(clad_cell)\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", - "moderator_cell.fill = water\n", - "moderator_cell.region = +clad_outer_radius\n", - "fuel_pin_universe.add_cell(moderator_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Likewise, we can construct a control rod guide tube with the same surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a Universe to encapsulate a control rod guide tube\n", - "guide_tube_universe = openmc.Universe(name='Guide Tube')\n", - "\n", - "# Create guide tube Cell\n", - "guide_tube_cell = openmc.Cell(name='Guide Tube Water')\n", - "guide_tube_cell.fill = water\n", - "guide_tube_cell.region = -fuel_outer_radius\n", - "guide_tube_universe.add_cell(guide_tube_cell)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='Guide Clad')\n", - "clad_cell.fill = zircaloy\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "guide_tube_universe.add_cell(clad_cell)\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='Guide Tube Moderator')\n", - "moderator_cell.fill = water\n", - "moderator_cell.region = +clad_outer_radius\n", - "guide_tube_universe.add_cell(moderator_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Using the pin cell universe, we can construct a 17x17 rectangular lattice with a 1.26 cm pitch." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create fuel assembly Lattice\n", - "assembly = openmc.RectLattice(name='1.6% Fuel Assembly')\n", - "assembly.pitch = (1.26, 1.26)\n", - "assembly.lower_left = [-1.26 * 17. / 2.0] * 2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we create a NumPy array of fuel pin and guide tube universes for the lattice." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Create array indices for guide tube locations in lattice\n", - "template_x = np.array([5, 8, 11, 3, 13, 2, 5, 8, 11, 14, 2, 5, 8,\n", - " 11, 14, 2, 5, 8, 11, 14, 3, 13, 5, 8, 11])\n", - "template_y = np.array([2, 2, 2, 3, 3, 5, 5, 5, 5, 5, 8, 8, 8, 8,\n", - " 8, 11, 11, 11, 11, 11, 13, 13, 14, 14, 14])\n", - "\n", - "# Create universes array with the fuel pin and guide tube universes\n", - "universes = np.tile(fuel_pin_universe, (17,17))\n", - "universes[template_x, template_y] = guide_tube_universe\n", - "\n", - "# Store the array of universes in the lattice\n", - "assembly.universes = universes" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC requires that there is a \"root\" universe. Let us create a root cell that is filled by the pin cell universe and then assign it to the root universe." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Create root Cell\n", - "root_cell = openmc.Cell(name='root cell', fill=assembly)\n", - "\n", - "# Add boundary planes\n", - "root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z\n", - "\n", - "# Create root Universe\n", - "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", - "root_universe.add_cell(root_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now must create a geometry that is assigned a root universe and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and export to XML\n", - "geometry = openmc.Geometry(root_universe)\n", - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the geometry and materials finished, we now just need to define simulation parameters. In this case, we will use 10 inactive batches and 40 active batches each with 2500 particles." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "batches = 50\n", - "inactive = 10\n", - "particles = 2500\n", - "\n", - "# Instantiate a Settings object\n", - "settings = openmc.Settings()\n", - "settings.batches = batches\n", - "settings.inactive = inactive\n", - "settings.particles = particles\n", - "settings.output = {'tallies': False}\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-10.71, -10.71, -10, 10.71, 10.71, 10.]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us also create a plot to verify that our fuel assembly geometry was created successfully." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Plot our geometry\n", - "plot = openmc.Plot.from_geometry(geometry)\n", - "plot.pixels = (250, 250)\n", - "plot.color_by = 'material'\n", - "openmc.plot_inline(plot)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As we can see from the plot, we have a nice array of fuel and guide tube pin cells with fuel, cladding, and water!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create an MGXS Library" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we are ready to generate multi-group cross sections! First, let's define a 20-energy-group and 1-energy-group." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a 20-group EnergyGroups object\n", - "energy_groups = openmc.mgxs.EnergyGroups()\n", - "energy_groups.group_edges = np.logspace(-3, 7.3, 21)\n", - "\n", - "# Instantiate a 1-group EnergyGroups object\n", - "one_group = openmc.mgxs.EnergyGroups()\n", - "one_group.group_edges = np.array([energy_groups.group_edges[0], energy_groups.group_edges[-1]])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will instantiate an `openmc.mgxs.Library` for the energy and delayed groups with our the fuel assembly geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=1.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=5.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=6.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=17.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=23.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Instantiate a tally mesh \n", - "mesh = openmc.RegularMesh(mesh_id=1)\n", - "mesh.dimension = [17, 17, 1]\n", - "mesh.lower_left = [-10.71, -10.71, -10000.]\n", - "mesh.width = [1.26, 1.26, 20000.]\n", - "\n", - "# Initialize an 20-energy-group and 6-delayed-group MGXS Library\n", - "mgxs_lib = openmc.mgxs.Library(geometry)\n", - "mgxs_lib.energy_groups = energy_groups\n", - "mgxs_lib.num_delayed_groups = 6\n", - "\n", - "# Specify multi-group cross section types to compute\n", - "mgxs_lib.mgxs_types = ['total', 'transport', 'nu-scatter matrix', 'kappa-fission', 'inverse-velocity', 'chi-prompt',\n", - " 'prompt-nu-fission', 'chi-delayed', 'delayed-nu-fission', 'beta']\n", - "\n", - "# Specify a \"mesh\" domain type for the cross section tally filters\n", - "mgxs_lib.domain_type = 'mesh'\n", - "\n", - "# Specify the mesh domain over which to compute multi-group cross sections\n", - "mgxs_lib.domains = [mesh]\n", - "\n", - "# Construct all tallies needed for the multi-group cross section library\n", - "mgxs_lib.build_library()\n", - "\n", - "# Create a \"tallies.xml\" file for the MGXS Library\n", - "tallies_file = openmc.Tallies()\n", - "mgxs_lib.add_to_tallies_file(tallies_file, merge=True)\n", - "\n", - "# Instantiate a current tally\n", - "mesh_filter = openmc.MeshSurfaceFilter(mesh)\n", - "current_tally = openmc.Tally(name='current tally')\n", - "current_tally.scores = ['current']\n", - "current_tally.filters = [mesh_filter]\n", - "\n", - "# Add current tally to the tallies file\n", - "tallies_file.append(current_tally)\n", - "\n", - "# Export to \"tallies.xml\"\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we can run OpenMC to generate the cross sections." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | 61c911cffdae2406f9f4bc667a9a6954748bb70c\n", - " Date/Time | 2019-07-18 22:07:58\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading U235 from /opt/data/hdf5/nndc_hdf5_v15/U235.h5\n", - " Reading U238 from /opt/data/hdf5/nndc_hdf5_v15/U238.h5\n", - " Reading O16 from /opt/data/hdf5/nndc_hdf5_v15/O16.h5\n", - " Reading H1 from /opt/data/hdf5/nndc_hdf5_v15/H1.h5\n", - " Reading B10 from /opt/data/hdf5/nndc_hdf5_v15/B10.h5\n", - " Reading Zr90 from /opt/data/hdf5/nndc_hdf5_v15/Zr90.h5\n", - " Maximum neutron transport energy: 20000000.000000 eV for U235\n", - " Reading tallies XML file...\n", - " Writing summary.h5 file...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 1.03852\n", - " 2/1 0.99743\n", - " 3/1 1.02987\n", - " 4/1 1.04397\n", - " 5/1 1.06262\n", - " 6/1 1.06657\n", - " 7/1 0.98574\n", - " 8/1 1.04364\n", - " 9/1 1.01253\n", - " 10/1 1.02094\n", - " 11/1 0.99586\n", - " 12/1 1.00508 1.00047 +/- 0.00461\n", - " 13/1 1.05292 1.01795 +/- 0.01769\n", - " 14/1 1.04732 1.02530 +/- 0.01450\n", - " 15/1 1.04886 1.03001 +/- 0.01218\n", - " 16/1 1.00948 1.02659 +/- 0.01052\n", - " 17/1 1.02644 1.02657 +/- 0.00889\n", - " 18/1 1.03080 1.02710 +/- 0.00772\n", - " 19/1 1.00018 1.02411 +/- 0.00743\n", - " 20/1 1.05668 1.02736 +/- 0.00740\n", - " 21/1 1.01160 1.02593 +/- 0.00685\n", - " 22/1 1.04334 1.02738 +/- 0.00642\n", - " 23/1 1.03105 1.02766 +/- 0.00591\n", - " 24/1 1.01174 1.02653 +/- 0.00559\n", - " 25/1 0.99844 1.02465 +/- 0.00553\n", - " 26/1 1.02241 1.02451 +/- 0.00517\n", - " 27/1 1.02904 1.02478 +/- 0.00487\n", - " 28/1 1.02132 1.02459 +/- 0.00459\n", - " 29/1 1.01384 1.02402 +/- 0.00438\n", - " 30/1 1.03891 1.02477 +/- 0.00422\n", - " 31/1 1.04092 1.02553 +/- 0.00409\n", - " 32/1 1.00058 1.02440 +/- 0.00406\n", - " 33/1 0.99940 1.02331 +/- 0.00403\n", - " 34/1 0.98362 1.02166 +/- 0.00420\n", - " 35/1 1.05358 1.02294 +/- 0.00422\n", - " 36/1 0.99923 1.02202 +/- 0.00416\n", - " 37/1 1.08491 1.02435 +/- 0.00463\n", - " 38/1 1.01838 1.02414 +/- 0.00447\n", - " 39/1 0.98567 1.02281 +/- 0.00451\n", - " 40/1 1.05047 1.02374 +/- 0.00445\n", - " 41/1 1.01993 1.02361 +/- 0.00431\n", - " 42/1 1.01223 1.02326 +/- 0.00419\n", - " 43/1 1.06259 1.02445 +/- 0.00423\n", - " 44/1 1.01993 1.02432 +/- 0.00411\n", - " 45/1 0.99233 1.02340 +/- 0.00409\n", - " 46/1 0.98532 1.02234 +/- 0.00411\n", - " 47/1 1.02513 1.02242 +/- 0.00400\n", - " 48/1 1.01637 1.02226 +/- 0.00390\n", - " 49/1 1.03215 1.02251 +/- 0.00381\n", - " 50/1 1.01826 1.02241 +/- 0.00371\n", - " Creating state point statepoint.50.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 4.2397e-01 seconds\n", - " Reading cross sections = 4.0321e-01 seconds\n", - " Total time in simulation = 2.0407e+01 seconds\n", - " Time in transport only = 2.0154e+01 seconds\n", - " Time in inactive batches = 1.0937e+00 seconds\n", - " Time in active batches = 1.9314e+01 seconds\n", - " Time synchronizing fission bank = 7.8056e-03 seconds\n", - " Sampling source sites = 6.7223e-03 seconds\n", - " SEND/RECV source sites = 9.5783e-04 seconds\n", - " Time accumulating tallies = 9.2006e-02 seconds\n", - " Total time for finalization = 1.0890e-02 seconds\n", - " Total time elapsed = 2.0869e+01 seconds\n", - " Calculation Rate (inactive) = 22858.4 particles/second\n", - " Calculation Rate (active) = 5177.70 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.02207 +/- 0.00343\n", - " k-effective (Track-length) = 1.02241 +/- 0.00371\n", - " k-effective (Absorption) = 1.02408 +/- 0.00356\n", - " Combined k-effective = 1.02306 +/- 0.00307\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Run OpenMC\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our simulation ran successfully and created statepoint and summary output files. We begin our analysis by instantiating a `StatePoint` object. " - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the last statepoint file\n", - "sp = openmc.StatePoint('statepoint.50.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The statepoint is now ready to be analyzed by the `Library`. We simply have to load the tallies from the statepoint into the `Library` and our `MGXS` objects will compute the cross sections for us under-the-hood." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# Initialize MGXS Library with OpenMC statepoint data\n", - "mgxs_lib.load_from_statepoint(sp)\n", - "\n", - "# Extrack the current tally separately\n", - "current_tally = sp.get_tally(name='current tally')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Using Tally Arithmetic to Compute the Delayed Neutron Precursor Concentrations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, we illustrate how one can leverage OpenMC's [tally arithmetic](tally-arithmetic.ipynb) data processing feature with `MGXS` objects. The `openmc.mgxs` module uses tally arithmetic to compute multi-group cross sections with automated uncertainty propagation. Each `MGXS` object includes an `xs_tally` attribute which is a \"derived\" `Tally` based on the tallies needed to compute the cross section type of interest. These derived tallies can be used in subsequent tally arithmetic operations. For example, we can use tally artithmetic to compute the delayed neutron precursor concentrations using the `Beta` and `DelayedNuFissionXS` objects. The delayed neutron precursor concentrations are modeled using the following equations:\n", - "\n", - "$$\\frac{\\partial}{\\partial t} C_{k,d} (t) = \\int_{0}^{\\infty}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r} \\beta_{k,d} (t) \\nu_d \\sigma_{f,x}(\\mathbf{r},E',t)\\Phi(\\mathbf{r},E',t) - \\lambda_{d} C_{k,d} (t) $$\n", - "\n", - "$$C_{k,d} (t=0) = \\frac{1}{\\lambda_{d}} \\int_{0}^{\\infty}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r} \\beta_{k,d} (t=0) \\nu_d \\sigma_{f,x}(\\mathbf{r},E',t=0)\\Phi(\\mathbf{r},E',t=0) $$" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
mesh 1delayedgroupnuclidescoremeanstd. dev.
xyz
01111total(((delayed-nu-fission / nu-fission) * (delayed...0.0000992.275247e-05
11112total(((delayed-nu-fission / nu-fission) * (delayed...0.0012602.852271e-04
21113total(((delayed-nu-fission / nu-fission) * (delayed...0.0008001.795615e-04
31114total(((delayed-nu-fission / nu-fission) * (delayed...0.0006301.397151e-04
41115total(((delayed-nu-fission / nu-fission) * (delayed...0.0000234.861639e-06
51116total(((delayed-nu-fission / nu-fission) * (delayed...0.0000023.879558e-07
62111total(((delayed-nu-fission / nu-fission) * (delayed...0.0000912.062544e-05
72112total(((delayed-nu-fission / nu-fission) * (delayed...0.0011622.584797e-04
82113total(((delayed-nu-fission / nu-fission) * (delayed...0.0007371.626991e-04
92114total(((delayed-nu-fission / nu-fission) * (delayed...0.0005811.265708e-04
\n", - "
" - ], - "text/plain": [ - " mesh 1 delayedgroup nuclide \\\n", - " x y z \n", - "0 1 1 1 1 total \n", - "1 1 1 1 2 total \n", - "2 1 1 1 3 total \n", - "3 1 1 1 4 total \n", - "4 1 1 1 5 total \n", - "5 1 1 1 6 total \n", - "6 2 1 1 1 total \n", - "7 2 1 1 2 total \n", - "8 2 1 1 3 total \n", - "9 2 1 1 4 total \n", - "\n", - " score mean std. dev. \n", - " \n", - "0 (((delayed-nu-fission / nu-fission) * (delayed... 0.000099 2.275247e-05 \n", - "1 (((delayed-nu-fission / nu-fission) * (delayed... 0.001260 2.852271e-04 \n", - "2 (((delayed-nu-fission / nu-fission) * (delayed... 0.000800 1.795615e-04 \n", - "3 (((delayed-nu-fission / nu-fission) * (delayed... 0.000630 1.397151e-04 \n", - "4 (((delayed-nu-fission / nu-fission) * (delayed... 0.000023 4.861639e-06 \n", - "5 (((delayed-nu-fission / nu-fission) * (delayed... 0.000002 3.879558e-07 \n", - "6 (((delayed-nu-fission / nu-fission) * (delayed... 0.000091 2.062544e-05 \n", - "7 (((delayed-nu-fission / nu-fission) * (delayed... 0.001162 2.584797e-04 \n", - "8 (((delayed-nu-fission / nu-fission) * (delayed... 0.000737 1.626991e-04 \n", - "9 (((delayed-nu-fission / nu-fission) * (delayed... 0.000581 1.265708e-04 " - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Set the time constants for the delayed precursors (in seconds^-1)\n", - "precursor_halflife = np.array([55.6, 24.5, 16.3, 2.37, 0.424, 0.195])\n", - "precursor_lambda = math.log(2.0) / precursor_halflife\n", - "\n", - "beta = mgxs_lib.get_mgxs(mesh, 'beta')\n", - "\n", - "# Create a tally object with only the delayed group filter for the time constants\n", - "beta_filters = [f for f in beta.xs_tally.filters if type(f) is not openmc.DelayedGroupFilter]\n", - "lambda_tally = beta.xs_tally.summation(nuclides=beta.xs_tally.nuclides)\n", - "for f in beta_filters:\n", - " lambda_tally = lambda_tally.summation(filter_type=type(f), remove_filter=True) * 0. + 1.\n", - "\n", - "# Set the mean of the lambda tally and reshape to account for nuclides and scores\n", - "lambda_tally._mean = precursor_lambda\n", - "lambda_tally._mean.shape = lambda_tally.std_dev.shape\n", - "\n", - "# Set a total nuclide and lambda score\n", - "lambda_tally.nuclides = [openmc.Nuclide(name='total')]\n", - "lambda_tally.scores = ['lambda']\n", - "\n", - "delayed_nu_fission = mgxs_lib.get_mgxs(mesh, 'delayed-nu-fission')\n", - "\n", - "# Use tally arithmetic to compute the precursor concentrations\n", - "precursor_conc = beta.xs_tally.summation(filter_type=openmc.EnergyFilter, remove_filter=True) * \\\n", - " delayed_nu_fission.xs_tally.summation(filter_type=openmc.EnergyFilter, remove_filter=True) / lambda_tally\n", - " \n", - "# The difference is a derived tally which can generate Pandas DataFrames for inspection\n", - "precursor_conc.get_pandas_dataframe().head(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Another useful feature of the Python API is the ability to extract the surface currents for the interfaces and surfaces of a mesh. We can inspect the currents for the mesh by getting the pandas dataframe." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
mesh 1nuclidescoremeanstd. dev.
xyzsurf
0111x-min outtotalcurrent0.000000.000000
1111x-min intotalcurrent0.000000.000000
2111x-max outtotalcurrent0.032450.000677
3111x-max intotalcurrent0.031800.000659
4111y-min outtotalcurrent0.000000.000000
5111y-min intotalcurrent0.000000.000000
6111y-max outtotalcurrent0.030720.000677
7111y-max intotalcurrent0.031040.000652
8111z-min outtotalcurrent0.000000.000000
9111z-min intotalcurrent0.000000.000000
\n", - "
" - ], - "text/plain": [ - " mesh 1 nuclide score mean std. dev.\n", - " x y z surf \n", - "0 1 1 1 x-min out total current 0.00000 0.000000\n", - "1 1 1 1 x-min in total current 0.00000 0.000000\n", - "2 1 1 1 x-max out total current 0.03245 0.000677\n", - "3 1 1 1 x-max in total current 0.03180 0.000659\n", - "4 1 1 1 y-min out total current 0.00000 0.000000\n", - "5 1 1 1 y-min in total current 0.00000 0.000000\n", - "6 1 1 1 y-max out total current 0.03072 0.000677\n", - "7 1 1 1 y-max in total current 0.03104 0.000652\n", - "8 1 1 1 z-min out total current 0.00000 0.000000\n", - "9 1 1 1 z-min in total current 0.00000 0.000000" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "current_tally.get_pandas_dataframe().head(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cross Section Visualizations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In addition to inspecting the data in the tallies by getting the pandas dataframe, we can also plot the tally data on the domain mesh. Below is the delayed neutron fraction tallied in each mesh cell for each delayed group." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0.5, 1.0, 'Beta - delayed group 6')" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Extract the energy-condensed delayed neutron fraction tally\n", - "beta_by_group = beta.get_condensed_xs(one_group).xs_tally.summation(filter_type='energy', remove_filter=True)\n", - "beta_by_group.mean.shape = (17, 17, 6)\n", - "beta_by_group.mean[beta_by_group.mean == 0] = np.nan\n", - "\n", - "# Plot the betas\n", - "plt.figure(figsize=(18,9))\n", - "fig = plt.subplot(231)\n", - "plt.imshow(beta_by_group.mean[:,:,0], interpolation='none', cmap='jet')\n", - "plt.colorbar()\n", - "plt.title('Beta - delayed group 1')\n", - "\n", - "fig = plt.subplot(232)\n", - "plt.imshow(beta_by_group.mean[:,:,1], interpolation='none', cmap='jet')\n", - "plt.colorbar()\n", - "plt.title('Beta - delayed group 2')\n", - "\n", - "fig = plt.subplot(233)\n", - "plt.imshow(beta_by_group.mean[:,:,2], interpolation='none', cmap='jet')\n", - "plt.colorbar()\n", - "plt.title('Beta - delayed group 3')\n", - "\n", - "fig = plt.subplot(234)\n", - "plt.imshow(beta_by_group.mean[:,:,3], interpolation='none', cmap='jet')\n", - "plt.colorbar()\n", - "plt.title('Beta - delayed group 4')\n", - "\n", - "fig = plt.subplot(235)\n", - "plt.imshow(beta_by_group.mean[:,:,4], interpolation='none', cmap='jet')\n", - "plt.colorbar()\n", - "plt.title('Beta - delayed group 5')\n", - "\n", - "fig = plt.subplot(236)\n", - "plt.imshow(beta_by_group.mean[:,:,5], interpolation='none', cmap='jet')\n", - "plt.colorbar()\n", - "plt.title('Beta - delayed group 6')" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/mg-mode-part-i.ipynb b/examples/jupyter/mg-mode-part-i.ipynb deleted file mode 100644 index c393ecc417c..00000000000 --- a/examples/jupyter/mg-mode-part-i.ipynb +++ /dev/null @@ -1,702 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multigroup Mode Part I: Introduction\n", - "This Notebook illustrates the usage of OpenMC's multi-group calculational mode with the Python API. This example notebook creates and executes the 2-D [C5G7](https://www.oecd-nea.org/jcms/pl_17882) benchmark model using the `openmc.MGXSLibrary` class to create the supporting data library on the fly." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate MGXS Library" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "import os\n", - "\n", - "import matplotlib.pyplot as plt\n", - "import matplotlib.colors as colors\n", - "import numpy as np\n", - "\n", - "import openmc\n", - "\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now create the multi-group library using data directly from Appendix A of the [C5G7](https://www.oecd-nea.org/jcms/pl_17882) benchmark documentation. All of the data below will be created at 294K, consistent with the benchmark.\n", - "\n", - "This notebook will first begin by setting the group structure and building the groupwise data for UO2. As you can see, the cross sections are input in the order of increasing groups (or decreasing energy).\n", - "\n", - "*Note*: The C5G7 benchmark uses transport-corrected cross sections. So the total cross section we input here will technically be the transport cross section." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# Create a 7-group structure with arbitrary boundaries (the specific boundaries are unimportant)\n", - "groups = openmc.mgxs.EnergyGroups(np.logspace(-5, 7, 8))\n", - "\n", - "uo2_xsdata = openmc.XSdata('uo2', groups)\n", - "uo2_xsdata.order = 0\n", - "\n", - "# When setting the data let the object know you are setting the data for a temperature of 294K.\n", - "uo2_xsdata.set_total([1.77949E-1, 3.29805E-1, 4.80388E-1, 5.54367E-1,\n", - " 3.11801E-1, 3.95168E-1, 5.64406E-1], temperature=294.)\n", - "\n", - "uo2_xsdata.set_absorption([8.0248E-03, 3.7174E-3, 2.6769E-2, 9.6236E-2,\n", - " 3.0020E-02, 1.1126E-1, 2.8278E-1], temperature=294.)\n", - "uo2_xsdata.set_fission([7.21206E-3, 8.19301E-4, 6.45320E-3, 1.85648E-2,\n", - " 1.78084E-2, 8.30348E-2, 2.16004E-1], temperature=294.)\n", - "\n", - "uo2_xsdata.set_nu_fission([2.005998E-2, 2.027303E-3, 1.570599E-2, 4.518301E-2,\n", - " 4.334208E-2, 2.020901E-1, 5.257105E-1], temperature=294.)\n", - "\n", - "uo2_xsdata.set_chi([5.87910E-1, 4.11760E-1, 3.39060E-4, 1.17610E-7,\n", - " 0.00000E-0, 0.00000E-0, 0.00000E-0], temperature=294.)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now add the scattering matrix data. \n", - "\n", - "*Note*: Most users familiar with deterministic transport libraries are already familiar with the idea of entering one scattering matrix for every order (i.e. scattering order as the outer dimension). However, the shape of OpenMC's scattering matrix entry is instead [Incoming groups, Outgoing Groups, Scattering Order] to best enable other scattering representations. We will follow the more familiar approach in this notebook, and then use numpy's `numpy.rollaxis` function to change the ordering to what we need (scattering order on the inner dimension)." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# The scattering matrix is ordered with incoming groups as rows and outgoing groups as columns\n", - "# (i.e., below the diagonal is up-scattering).\n", - "scatter_matrix = \\\n", - " [[[1.27537E-1, 4.23780E-2, 9.43740E-6, 5.51630E-9, 0.00000E-0, 0.00000E-0, 0.00000E-0],\n", - " [0.00000E-0, 3.24456E-1, 1.63140E-3, 3.14270E-9, 0.00000E-0, 0.00000E-0, 0.00000E-0],\n", - " [0.00000E-0, 0.00000E-0, 4.50940E-1, 2.67920E-3, 0.00000E-0, 0.00000E-0, 0.00000E-0],\n", - " [0.00000E-0, 0.00000E-0, 0.00000E-0, 4.52565E-1, 5.56640E-3, 0.00000E-0, 0.00000E-0],\n", - " [0.00000E-0, 0.00000E-0, 0.00000E-0, 1.25250E-4, 2.71401E-1, 1.02550E-2, 1.00210E-8],\n", - " [0.00000E-0, 0.00000E-0, 0.00000E-0, 0.00000E-0, 1.29680E-3, 2.65802E-1, 1.68090E-2],\n", - " [0.00000E-0, 0.00000E-0, 0.00000E-0, 0.00000E-0, 0.00000E-0, 8.54580E-3, 2.73080E-1]]]\n", - "scatter_matrix = np.array(scatter_matrix)\n", - "scatter_matrix = np.rollaxis(scatter_matrix, 0, 3)\n", - "uo2_xsdata.set_scatter_matrix(scatter_matrix, temperature=294.)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that the UO2 data has been created, we can move on to the remaining materials using the same process.\n", - "\n", - "However, we will actually skip repeating the above for now. Our simulation will instead use the `c5g7.h5` file that has already been created using exactly the same logic as above, but for the remaining materials in the benchmark problem.\n", - "\n", - "For now we will show how you would use the `uo2_xsdata` information to create an `openmc.MGXSLibrary` object and write to disk." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# Initialize the library\n", - "mg_cross_sections_file = openmc.MGXSLibrary(groups)\n", - "\n", - "# Add the UO2 data to it\n", - "mg_cross_sections_file.add_xsdata(uo2_xsdata)\n", - "\n", - "# And write to disk\n", - "mg_cross_sections_file.export_to_hdf5('mgxs.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate 2-D C5G7 Problem Input Files" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To build the actual 2-D model, we will first begin by creating the `materials.xml` file.\n", - "\n", - "First we need to define materials that will be used in the problem. In other notebooks, either nuclides or elements were added to materials at the equivalent stage. We can do that in multi-group mode as well. However, multi-group cross-sections are sometimes provided as macroscopic cross-sections; the C5G7 benchmark data are macroscopic. In this case, we can instead use the `Material.add_macroscopic` method to specify a macroscopic object. Unlike for nuclides and elements, we do not need provide information on atom/weight percents as no number densities are needed.\n", - "\n", - "When assigning macroscopic objects to a material, the density can still be scaled by setting the density to a value that is not 1.0. This would be useful, for example, when slightly perturbing the density of water due to a small change in temperature (while of course ignoring any resultant spectral shift). The density of a macroscopic dataset is set to 1.0 in the `openmc.Material` object by default when a macroscopic dataset is used; so we will show its use the first time and then afterwards it will not be required.\n", - "\n", - "Aside from these differences, the following code is very similar to similar code in other OpenMC example Notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# For every cross section data set in the library, assign an openmc.Macroscopic object to a material\n", - "materials = {}\n", - "for xs in ['uo2', 'mox43', 'mox7', 'mox87', 'fiss_chamber', 'guide_tube', 'water']:\n", - " materials[xs] = openmc.Material(name=xs)\n", - " materials[xs].set_density('macro', 1.)\n", - " materials[xs].add_macroscopic(xs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can go ahead and produce a `materials.xml` file for use by OpenMC" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# Instantiate a Materials collection, register all Materials, and export to XML\n", - "materials_file = openmc.Materials(materials.values())\n", - "\n", - "# Set the location of the cross sections file to our pre-written set\n", - "materials_file.cross_sections = 'c5g7.h5'\n", - "\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our next step will be to create the geometry information needed for our assembly and to write that to the `geometry.xml` file.\n", - "\n", - "We will begin by defining the surfaces, cells, and universes needed for each of the individual fuel pins, guide tubes, and fission chambers." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create the surface used for each pin\n", - "pin_surf = openmc.ZCylinder(x0=0, y0=0, R=0.54, name='pin_surf')\n", - "\n", - "# Create the cells which will be used to represent each pin type.\n", - "cells = {}\n", - "universes = {}\n", - "for material in materials.values():\n", - " # Create the cell for the material inside the cladding\n", - " cells[material.name] = openmc.Cell(name=material.name)\n", - " # Assign the half-spaces to the cell\n", - " cells[material.name].region = -pin_surf\n", - " # Register the material with this cell\n", - " cells[material.name].fill = material\n", - " \n", - " # Repeat the above for the material outside the cladding (i.e., the moderator)\n", - " cell_name = material.name + '_moderator'\n", - " cells[cell_name] = openmc.Cell(name=cell_name)\n", - " cells[cell_name].region = +pin_surf\n", - " cells[cell_name].fill = materials['water']\n", - " \n", - " # Finally add the two cells we just made to a Universe object\n", - " universes[material.name] = openmc.Universe(name=material.name)\n", - " universes[material.name].add_cells([cells[material.name], cells[cell_name]])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "The next step is to take our universes (representing the different pin types) and lay them out in a lattice to represent the assembly types" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "lattices = {}\n", - "\n", - "# Instantiate the UO2 Lattice\n", - "lattices['UO2 Assembly'] = openmc.RectLattice(name='UO2 Assembly')\n", - "lattices['UO2 Assembly'].dimension = [17, 17]\n", - "lattices['UO2 Assembly'].lower_left = [-10.71, -10.71]\n", - "lattices['UO2 Assembly'].pitch = [1.26, 1.26]\n", - "u = universes['uo2']\n", - "g = universes['guide_tube']\n", - "f = universes['fiss_chamber']\n", - "lattices['UO2 Assembly'].universes = \\\n", - " [[u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u],\n", - " [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u],\n", - " [u, u, u, u, u, g, u, u, g, u, u, g, u, u, u, u, u],\n", - " [u, u, u, g, u, u, u, u, u, u, u, u, u, g, u, u, u],\n", - " [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u],\n", - " [u, u, g, u, u, g, u, u, g, u, u, g, u, u, g, u, u],\n", - " [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u],\n", - " [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u],\n", - " [u, u, g, u, u, g, u, u, f, u, u, g, u, u, g, u, u],\n", - " [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u],\n", - " [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u],\n", - " [u, u, g, u, u, g, u, u, g, u, u, g, u, u, g, u, u],\n", - " [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u],\n", - " [u, u, u, g, u, u, u, u, u, u, u, u, u, g, u, u, u],\n", - " [u, u, u, u, u, g, u, u, g, u, u, g, u, u, u, u, u],\n", - " [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u],\n", - " [u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u, u]]\n", - " \n", - "# Create a containing cell and universe\n", - "cells['UO2 Assembly'] = openmc.Cell(name='UO2 Assembly')\n", - "cells['UO2 Assembly'].fill = lattices['UO2 Assembly']\n", - "universes['UO2 Assembly'] = openmc.Universe(name='UO2 Assembly')\n", - "universes['UO2 Assembly'].add_cell(cells['UO2 Assembly'])\n", - "\n", - "# Instantiate the MOX Lattice\n", - "lattices['MOX Assembly'] = openmc.RectLattice(name='MOX Assembly')\n", - "lattices['MOX Assembly'].dimension = [17, 17]\n", - "lattices['MOX Assembly'].lower_left = [-10.71, -10.71]\n", - "lattices['MOX Assembly'].pitch = [1.26, 1.26]\n", - "m = universes['mox43']\n", - "n = universes['mox7']\n", - "o = universes['mox87']\n", - "g = universes['guide_tube']\n", - "f = universes['fiss_chamber']\n", - "lattices['MOX Assembly'].universes = \\\n", - " [[m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m],\n", - " [m, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, m],\n", - " [m, n, n, n, n, g, n, n, g, n, n, g, n, n, n, n, m],\n", - " [m, n, n, g, n, o, o, o, o, o, o, o, n, g, n, n, m],\n", - " [m, n, n, n, o, o, o, o, o, o, o, o, o, n, n, n, m],\n", - " [m, n, g, o, o, g, o, o, g, o, o, g, o, o, g, n, m],\n", - " [m, n, n, o, o, o, o, o, o, o, o, o, o, o, n, n, m],\n", - " [m, n, n, o, o, o, o, o, o, o, o, o, o, o, n, n, m],\n", - " [m, n, g, o, o, g, o, o, f, o, o, g, o, o, g, n, m],\n", - " [m, n, n, o, o, o, o, o, o, o, o, o, o, o, n, n, m],\n", - " [m, n, n, o, o, o, o, o, o, o, o, o, o, o, n, n, m],\n", - " [m, n, g, o, o, g, o, o, g, o, o, g, o, o, g, n, m],\n", - " [m, n, n, n, o, o, o, o, o, o, o, o, o, n, n, n, m],\n", - " [m, n, n, g, n, o, o, o, o, o, o, o, n, g, n, n, m],\n", - " [m, n, n, n, n, g, n, n, g, n, n, g, n, n, n, n, m],\n", - " [m, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, m],\n", - " [m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m, m]]\n", - " \n", - "# Create a containing cell and universe\n", - "cells['MOX Assembly'] = openmc.Cell(name='MOX Assembly')\n", - "cells['MOX Assembly'].fill = lattices['MOX Assembly']\n", - "universes['MOX Assembly'] = openmc.Universe(name='MOX Assembly')\n", - "universes['MOX Assembly'].add_cell(cells['MOX Assembly'])\n", - " \n", - "# Instantiate the reflector Lattice\n", - "lattices['Reflector Assembly'] = openmc.RectLattice(name='Reflector Assembly')\n", - "lattices['Reflector Assembly'].dimension = [1,1]\n", - "lattices['Reflector Assembly'].lower_left = [-10.71, -10.71]\n", - "lattices['Reflector Assembly'].pitch = [21.42, 21.42]\n", - "lattices['Reflector Assembly'].universes = [[universes['water']]]\n", - "\n", - "# Create a containing cell and universe\n", - "cells['Reflector Assembly'] = openmc.Cell(name='Reflector Assembly')\n", - "cells['Reflector Assembly'].fill = lattices['Reflector Assembly']\n", - "universes['Reflector Assembly'] = openmc.Universe(name='Reflector Assembly')\n", - "universes['Reflector Assembly'].add_cell(cells['Reflector Assembly'])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "Let's now create the core layout in a 3x3 lattice where each lattice position is one of the assemblies we just defined.\n", - "\n", - "After that we can create the final cell to contain the entire core." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "lattices['Core'] = openmc.RectLattice(name='3x3 core lattice')\n", - "lattices['Core'].dimension= [3, 3]\n", - "lattices['Core'].lower_left = [-32.13, -32.13]\n", - "lattices['Core'].pitch = [21.42, 21.42]\n", - "r = universes['Reflector Assembly']\n", - "u = universes['UO2 Assembly']\n", - "m = universes['MOX Assembly']\n", - "lattices['Core'].universes = [[u, m, r],\n", - " [m, u, r],\n", - " [r, r, r]]\n", - "\n", - "# Create boundary planes to surround the geometry\n", - "min_x = openmc.XPlane(x0=-32.13, boundary_type='reflective')\n", - "max_x = openmc.XPlane(x0=+32.13, boundary_type='vacuum')\n", - "min_y = openmc.YPlane(y0=-32.13, boundary_type='vacuum')\n", - "max_y = openmc.YPlane(y0=+32.13, boundary_type='reflective')\n", - "\n", - "# Create root Cell\n", - "root_cell = openmc.Cell(name='root cell')\n", - "root_cell.fill = lattices['Core']\n", - "\n", - "# Add boundary planes\n", - "root_cell.region = +min_x & -max_x & +min_y & -max_y\n", - "\n", - "# Create root Universe\n", - "root_universe = openmc.Universe(name='root universe', universe_id=0)\n", - "root_universe.add_cell(root_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before we commit to the geometry, we should view it using the Python API's plotting capability" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "root_universe.plot(origin=(0., 0., 0.), width=(3 * 21.42, 3 * 21.42), pixels=(500, 500),\n", - " color_by='material')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OK, it looks pretty good, let's go ahead and write the file" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and set root Universe\n", - "geometry = openmc.Geometry(root_universe)\n", - "\n", - "# Export to \"geometry.xml\"\n", - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now create the tally file information. The tallies will be set up to give us the pin powers in this notebook. We will do this with a mesh filter, with one mesh cell per pin." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "tallies_file = openmc.Tallies()\n", - "\n", - "# Instantiate a tally Mesh\n", - "mesh = openmc.RegularMesh()\n", - "mesh.dimension = [17 * 2, 17 * 2]\n", - "mesh.lower_left = [-32.13, -10.71]\n", - "mesh.upper_right = [+10.71, +32.13]\n", - "\n", - "# Instantiate tally Filter\n", - "mesh_filter = openmc.MeshFilter(mesh)\n", - "\n", - "# Instantiate the Tally\n", - "tally = openmc.Tally(name='mesh tally')\n", - "tally.filters = [mesh_filter]\n", - "tally.scores = ['fission']\n", - "\n", - "# Add tally to collection\n", - "tallies_file.append(tally)\n", - "\n", - "# Export all tallies to a \"tallies.xml\" file\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the geometry and materials finished, we now just need to define simulation parameters for the `settings.xml` file. Note the use of the `energy_mode` attribute of our `settings_file` object. This is used to tell OpenMC that we intend to run in multi-group mode instead of the default continuous-energy mode. If we didn't specify this but our cross sections file was not a continuous-energy data set, then OpenMC would complain.\n", - "\n", - "This will be a relatively coarse calculation with only 500,000 active histories. A benchmark-fidelity run would of course require many more!" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "batches = 150\n", - "inactive = 50\n", - "particles = 5000\n", - "\n", - "# Instantiate a Settings object\n", - "settings_file = openmc.Settings()\n", - "settings_file.batches = batches\n", - "settings_file.inactive = inactive\n", - "settings_file.particles = particles\n", - "\n", - "# Tell OpenMC this is a multi-group problem\n", - "settings_file.energy_mode = 'multi-group'\n", - "\n", - "# Set the verbosity to 6 so we dont see output for every batch\n", - "settings_file.verbosity = 6\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-32.13, -10.71, -1e50, 10.71, 32.13, 1e50]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings_file.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Tell OpenMC we want to run in eigenvalue mode\n", - "settings_file.run_mode = 'eigenvalue'\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's go ahead and execute the simulation! You'll notice that the output for multi-group mode is exactly the same as for continuous-energy. The differences are all under the hood." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2017 Massachusetts Institute of Technology\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.8.0\n", - " Git SHA1 | 966169de084fcfda3a5aaca3edc0065c8caf6bbc\n", - " Date/Time | 2017-03-09 08:18:02\n", - " OpenMP Threads | 8\n", - "\n", - " Reading settings XML file...\n", - " Reading geometry XML file...\n", - " Reading materials XML file...\n", - " Reading cross sections HDF5 file...\n", - " Reading tallies XML file...\n", - " Loading cross section data...\n", - " Loading uo2 data...\n", - " Loading mox43 data...\n", - " Loading mox7 data...\n", - " Loading mox87 data...\n", - " Loading fiss_chamber data...\n", - " Loading guide_tube data...\n", - " Loading water data...\n", - " Building neighboring cells lists for each surface...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Creating state point statepoint.150.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 1.3630E-01 seconds\n", - " Reading cross sections = 3.0827E-02 seconds\n", - " Total time in simulation = 8.9648E+00 seconds\n", - " Time in transport only = 8.2752E+00 seconds\n", - " Time in inactive batches = 2.4798E+00 seconds\n", - " Time in active batches = 6.4849E+00 seconds\n", - " Time synchronizing fission bank = 1.4553E-02 seconds\n", - " Sampling source sites = 1.0318E-02 seconds\n", - " SEND/RECV source sites = 4.0840E-03 seconds\n", - " Time accumulating tallies = 4.2427E-04 seconds\n", - " Total time for finalization = 1.7081E-02 seconds\n", - " Total time elapsed = 9.1340E+00 seconds\n", - " Calculation Rate (inactive) = 1.00813E+05 neutrons/second\n", - " Calculation Rate (active) = 77101.8 neutrons/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.18880 +/- 0.00179\n", - " k-effective (Track-length) = 1.18853 +/- 0.00244\n", - " k-effective (Absorption) = 1.18601 +/- 0.00111\n", - " Combined k-effective = 1.18628 +/- 0.00111\n", - " Leakage Fraction = 0.00175 +/- 0.00006\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Run OpenMC\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Results Visualization\n", - "\n", - "Now that we have run the simulation, let's look at the fission rate and flux tallies that we tallied." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Load the last statepoint file and keff value\n", - "sp = openmc.StatePoint('statepoint.' + str(batches) + '.h5')\n", - "\n", - "# Get the OpenMC pin power tally data\n", - "mesh_tally = sp.get_tally(name='mesh tally')\n", - "fission_rates = mesh_tally.get_values(scores=['fission'])\n", - "\n", - "# Reshape array to 2D for plotting\n", - "fission_rates.shape = mesh.dimension\n", - "\n", - "# Normalize to the average pin power\n", - "fission_rates /= np.mean(fission_rates[fission_rates > 0.])\n", - "\n", - "# Force zeros to be NaNs so their values are not included when matplotlib calculates\n", - "# the color scale\n", - "fission_rates[fission_rates == 0.] = np.nan\n", - "\n", - "# Plot the pin powers and the fluxes\n", - "plt.figure()\n", - "plt.imshow(fission_rates, interpolation='none', cmap='jet', origin='lower')\n", - "plt.colorbar()\n", - "plt.title('Pin Powers')\n", - "plt.show()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There we have it! We have just successfully run the C5G7 benchmark model!" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/jupyter/mg-mode-part-ii.ipynb b/examples/jupyter/mg-mode-part-ii.ipynb deleted file mode 100644 index ef9e00017be..00000000000 --- a/examples/jupyter/mg-mode-part-ii.ipynb +++ /dev/null @@ -1,1540 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multigroup Mode Part II: MGXS Library Generation with OpenMC\n", - "The previous Notebook in this series used multi-group mode to perform a calculation with previously defined cross sections. However, in many circumstances the multi-group data is not given and one must instead generate the cross sections for the specific application (or at least verify the use of cross sections from another application). \n", - "\n", - "This Notebook illustrates the use of the openmc.mgxs.Library class specifically for the calculation of MGXS to be used in OpenMC's multi-group mode. This example notebook is therefore very similar to the MGXS Part III notebook, except OpenMC is used as the multi-group solver instead of OpenMOC.\n", - "\n", - "During this process, this notebook will illustrate the following features:\n", - "\n", - " - Calculation of multi-group cross sections for a fuel assembly\n", - " - Automated creation and storage of MGXS with openmc.mgxs.Library\n", - " - Steady-state pin-by-pin fission rates comparison between continuous-energy and multi-group OpenMC.\n", - " - Modification of the scattering data in the library to show the flexibility of the multi-group solver\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import os\n", - "\n", - "import openmc\n", - "\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will begin by creating three materials for the fuel, water, and cladding of the fuel pins." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# 1.6% enriched fuel\n", - "fuel = openmc.Material(name='1.6% Fuel')\n", - "fuel.set_density('g/cm3', 10.31341)\n", - "fuel.add_element('U', 1., enrichment=1.6)\n", - "fuel.add_element('O', 2.)\n", - "\n", - "# zircaloy\n", - "zircaloy = openmc.Material(name='Zircaloy')\n", - "zircaloy.set_density('g/cm3', 6.55)\n", - "zircaloy.add_element('Zr', 1.)\n", - "\n", - "# borated water\n", - "water = openmc.Material(name='Borated Water')\n", - "water.set_density('g/cm3', 0.740582)\n", - "water.add_element('H', 4.9457e-2)\n", - "water.add_element('O', 2.4732e-2)\n", - "water.add_element('B', 8.0042e-6)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our three materials, we can now create a Materials object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Materials object\n", - "materials_file = openmc.Materials((fuel, zircaloy, water))\n", - "\n", - "# Export to \"materials.xml\"\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. This problem will be a square array of fuel pins and control rod guide tubes for which we can use OpenMC's lattice/universe feature. The basic universe will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces for fuel and clad, as well as the outer bounding surfaces of the problem." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Create cylinders for the fuel and clad\n", - "# The x0 and y0 parameters (0. and 0.) are the default values for an\n", - "# openmc.ZCylinder object. We could therefore leave them out to no effect\n", - "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, R=0.39218)\n", - "clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, R=0.45720)\n", - "\n", - "# Create boundary planes to surround the geometry\n", - "min_x = openmc.XPlane(x0=-10.71, boundary_type='reflective')\n", - "max_x = openmc.XPlane(x0=+10.71, boundary_type='reflective')\n", - "min_y = openmc.YPlane(y0=-10.71, boundary_type='reflective')\n", - "max_y = openmc.YPlane(y0=+10.71, boundary_type='reflective')\n", - "min_z = openmc.ZPlane(z0=-10., boundary_type='reflective')\n", - "max_z = openmc.ZPlane(z0=+10., boundary_type='reflective')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now construct a fuel pin cell from cells that are defined by intersections of half-spaces created by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a Universe to encapsulate a fuel pin\n", - "fuel_pin_universe = openmc.Universe(name='1.6% Fuel Pin')\n", - "\n", - "# Create fuel Cell\n", - "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", - "fuel_cell.fill = fuel\n", - "fuel_cell.region = -fuel_outer_radius\n", - "fuel_pin_universe.add_cell(fuel_cell)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='1.6% Clad')\n", - "clad_cell.fill = zircaloy\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "fuel_pin_universe.add_cell(clad_cell)\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", - "moderator_cell.fill = water\n", - "moderator_cell.region = +clad_outer_radius\n", - "fuel_pin_universe.add_cell(moderator_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Likewise, we can construct a control rod guide tube with the same surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a Universe to encapsulate a control rod guide tube\n", - "guide_tube_universe = openmc.Universe(name='Guide Tube')\n", - "\n", - "# Create guide tube Cell\n", - "guide_tube_cell = openmc.Cell(name='Guide Tube Water')\n", - "guide_tube_cell.fill = water\n", - "guide_tube_cell.region = -fuel_outer_radius\n", - "guide_tube_universe.add_cell(guide_tube_cell)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='Guide Clad')\n", - "clad_cell.fill = zircaloy\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "guide_tube_universe.add_cell(clad_cell)\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='Guide Tube Moderator')\n", - "moderator_cell.fill = water\n", - "moderator_cell.region = +clad_outer_radius\n", - "guide_tube_universe.add_cell(moderator_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Using the pin cell universe, we can construct a 17x17 rectangular lattice with a 1.26 cm pitch." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create fuel assembly Lattice\n", - "assembly = openmc.RectLattice(name='1.6% Fuel Assembly')\n", - "assembly.pitch = (1.26, 1.26)\n", - "assembly.lower_left = [-1.26 * 17. / 2.0] * 2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we create a NumPy array of fuel pin and guide tube universes for the lattice." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Create array indices for guide tube locations in lattice\n", - "template_x = np.array([5, 8, 11, 3, 13, 2, 5, 8, 11, 14, 2, 5, 8,\n", - " 11, 14, 2, 5, 8, 11, 14, 3, 13, 5, 8, 11])\n", - "template_y = np.array([2, 2, 2, 3, 3, 5, 5, 5, 5, 5, 8, 8, 8, 8,\n", - " 8, 11, 11, 11, 11, 11, 13, 13, 14, 14, 14])\n", - "\n", - "# Initialize an empty 17x17 array of the lattice universes\n", - "universes = np.empty((17, 17), dtype=openmc.Universe)\n", - "\n", - "# Fill the array with the fuel pin and guide tube universes\n", - "universes[:, :] = fuel_pin_universe\n", - "universes[template_x, template_y] = guide_tube_universe\n", - "\n", - "# Store the array of universes in the lattice\n", - "assembly.universes = universes" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC requires that there is a \"root\" universe. Let us create a root cell that is filled by the pin cell universe and then assign it to the root universe." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Create root Cell\n", - "root_cell = openmc.Cell(name='root cell')\n", - "root_cell.fill = assembly\n", - "\n", - "# Add boundary planes\n", - "root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z\n", - "\n", - "# Create root Universe\n", - "root_universe = openmc.Universe(name='root universe', universe_id=0)\n", - "root_universe.add_cell(root_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before proceeding lets check the geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "root_universe.plot(origin=(0., 0., 0.), width=(21.42, 21.42), pixels=(500, 500), color_by='material')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looks good!\n", - "\n", - "We now must create a geometry that is assigned a root universe and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and set root universe\n", - "geometry = openmc.Geometry(root_universe)\n", - "\n", - "# Export to \"geometry.xml\"\n", - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the geometry and materials finished, we now just need to define simulation parameters." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "batches = 600\n", - "inactive = 50\n", - "particles = 3000\n", - "\n", - "# Instantiate a Settings object\n", - "settings_file = openmc.Settings()\n", - "settings_file.batches = batches\n", - "settings_file.inactive = inactive\n", - "settings_file.particles = particles\n", - "settings_file.output = {'tallies': False}\n", - "settings_file.run_mode = 'eigenvalue'\n", - "settings_file.verbosity = 4\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-10.71, -10.71, -10, 10.71, 10.71, 10.]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings_file.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create an MGXS Library\n", - "\n", - "Now we are ready to generate multi-group cross sections! First, let's define a 2-group structure using the built-in EnergyGroups class." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a 2-group EnergyGroups object\n", - "groups = openmc.mgxs.EnergyGroups([0., 0.625, 20.0e6])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will instantiate an openmc.mgxs.Library for the energy groups with our the fuel assembly geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "# Initialize a 2-group MGXS Library for OpenMC\n", - "mgxs_lib = openmc.mgxs.Library(geometry)\n", - "mgxs_lib.energy_groups = groups" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we must specify to the Library which types of cross sections to compute. OpenMC's multi-group mode can accept isotropic flux-weighted cross sections or angle-dependent cross sections, as well as supporting anisotropic scattering represented by either Legendre polynomials, histogram, or tabular angular distributions. We will create the following multi-group cross sections needed to run an OpenMC simulation to verify the accuracy of our cross sections: \"total\", \"absorption\", \"nu-fission\", '\"fission\", \"nu-scatter matrix\", \"multiplicity matrix\", and \"chi\".\n", - "\n", - "The \"multiplicity matrix\" type is a relatively rare cross section type. This data is needed to provide OpenMC's multi-group mode with additional information needed to accurately treat scattering multiplication (i.e., (n,xn) reactions)), including how this multiplication varies depending on both incoming and outgoing neutron energies." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Specify multi-group cross section types to compute\n", - "mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission',\n", - " 'nu-scatter matrix', 'multiplicity matrix', 'chi']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we must specify the type of domain over which we would like the `Library` to compute multi-group cross sections. The domain type corresponds to the type of tally filter to be used in the tallies created to compute multi-group cross sections. At the present time, the `Library` supports \"material\", \"cell\", \"universe\", and \"mesh\" domain types. In this simple example, we wish to compute multi-group cross sections only for each material and therefore will use a \"material\" domain type.\n", - "\n", - "**NOTE:** By default, the `Library` class will instantiate `MGXS` objects for each and every domain (material, cell, universe, or mesh) in the geometry of interest. However, one may specify a subset of these domains to the `Library.domains` property." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "# Specify a \"cell\" domain type for the cross section tally filters\n", - "mgxs_lib.domain_type = \"material\"\n", - "\n", - "# Specify the cell domains over which to compute multi-group cross sections\n", - "mgxs_lib.domains = geometry.get_all_materials().values()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will instruct the library to not compute cross sections on a nuclide-by-nuclide basis, and instead to focus on generating material-specific macroscopic cross sections.\n", - "\n", - "**NOTE:** The default value of the `by_nuclide` parameter is `False`, so the following step is not necessary but is included for illustrative purposes." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# Do not compute cross sections on a nuclide-by-nuclide basis\n", - "mgxs_lib.by_nuclide = False" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we will set the scattering order that we wish to use. For this problem we will use P3 scattering. A warning is expected telling us that the default behavior (a P0 correction on the scattering data) is over-ridden by our choice of using a Legendre expansion to treat anisotropic scattering." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/nelsonag/git/openmc/openmc/mgxs/library.py:412: RuntimeWarning: The P0 correction will be ignored since the scattering order 0 is greater than zero\n", - " warn(msg, RuntimeWarning)\n" - ] - } - ], - "source": [ - "# Set the Legendre order to 3 for P3 scattering\n", - "mgxs_lib.legendre_order = 3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that the `Library` has been setup let's verify that it contains the types of cross sections which meet the needs of OpenMC's multi-group solver. Note that this step is done automatically when writing the Multi-Group Library file later in the process (as part of `mgxs_lib.write_mg_library()`), but it is a good practice to also run this before spending all the time running OpenMC to generate the cross sections.\n", - "\n", - "If no error is raised, then we have a good set of data." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "# Check the library - if no errors are raised, then the library is satisfactory.\n", - "mgxs_lib.check_library_for_openmc_mgxs()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Great, now we can use the `Library` to construct the tallies needed to compute all of the requested multi-group cross sections in each domain." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "# Construct all tallies needed for the multi-group cross section library\n", - "mgxs_lib.build_library()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The tallies can now be exported to a \"tallies.xml\" input file for OpenMC.\n", - "\n", - "**NOTE:** At this point the `Library` has constructed nearly 100 distinct Tally objects. The overhead to tally in OpenMC scales as O(N) for N tallies, which can become a bottleneck for large tally datasets. To compensate for this, the Python API's `Tally`, `Filter` and `Tallies` classes allow for the smart merging of tallies when possible. The `Library` class supports this runtime optimization with the use of the optional `merge` parameter (`False` by default) for the `Library.add_to_tallies_file(...)` method, as shown below." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a \"tallies.xml\" file for the MGXS Library\n", - "tallies_file = openmc.Tallies()\n", - "mgxs_lib.add_to_tallies_file(tallies_file, merge=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In addition, we instantiate a fission rate mesh tally that we will eventually use to compare with the corresponding multi-group results." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=66.\n", - " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", - " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=11.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Instantiate a tally Mesh\n", - "mesh = openmc.RegularMesh()\n", - "mesh.dimension = [17, 17]\n", - "mesh.lower_left = [-10.71, -10.71]\n", - "mesh.upper_right = [+10.71, +10.71]\n", - "\n", - "# Instantiate tally Filter\n", - "mesh_filter = openmc.MeshFilter(mesh)\n", - "\n", - "# Instantiate the Tally\n", - "tally = openmc.Tally(name='mesh tally')\n", - "tally.filters = [mesh_filter]\n", - "tally.scores = ['fission']\n", - "\n", - "# Add tally to collection\n", - "tallies_file.append(tally, merge=True)\n", - "\n", - "# Export all tallies to a \"tallies.xml\" file\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "Time to run the calculation and get our results!" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-22 15:02:43\n", - " OpenMP Threads | 8\n", - "\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.16513 +/- 0.00090\n", - " k-effective (Track-length) = 1.16337 +/- 0.00104\n", - " k-effective (Absorption) = 1.16479 +/- 0.00080\n", - " Combined k-effective = 1.16460 +/- 0.00068\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Run OpenMC\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To make sure the results we need are available after running the multi-group calculation, we will now rename the statepoint and summary files." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "# Move the statepoint File\n", - "ce_spfile = './statepoint_ce.h5'\n", - "os.rename('statepoint.' + str(batches) + '.h5', ce_spfile)\n", - "# Move the Summary file\n", - "ce_sumfile = './summary_ce.h5'\n", - "os.rename('summary.h5', ce_sumfile)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing\n", - "\n", - "Our simulation ran successfully and created statepoint and summary output files. Let's begin by loading the StatePoint file." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the statepoint file\n", - "sp = openmc.StatePoint(ce_spfile, autolink=False)\n", - "\n", - "# Load the summary file in its new location\n", - "su = openmc.Summary(ce_sumfile)\n", - "sp.link_with_summary(su)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The statepoint is now ready to be analyzed by the `Library`. We simply have to load the tallies from the statepoint into the `Library` and our `MGXS` objects will compute the cross sections for us under-the-hood." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "# Initialize MGXS Library with OpenMC statepoint data\n", - "mgxs_lib.load_from_statepoint(sp)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The next step will be to prepare the input for OpenMC to use our newly created multi-group data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Multi-Group OpenMC Calculation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now use the `Library` to produce a multi-group cross section data set for use by the OpenMC multi-group solver. \n", - "Note that since this simulation included so few histories, it is reasonable to expect some data has not had any scores, and thus we could see division by zero errors. This will show up as a runtime warning in the following step. The `Library` class is designed to gracefully handle these scenarios." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a MGXS File which can then be written to disk\n", - "mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=['fuel', 'zircaloy', 'water'])\n", - "\n", - "# Write the file to disk using the default filename of \"mgxs.h5\"\n", - "mgxs_file.export_to_hdf5()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC's multi-group mode uses the same input files as does the continuous-energy mode (materials, geometry, settings, plots, and tallies file). Differences would include the use of a flag to tell the code to use multi-group transport, a location of the multi-group library file, and any changes needed in the materials.xml and geometry.xml files to re-define materials as necessary. The materials and geometry file changes could be necessary if materials or their nuclide/element/macroscopic constituents need to be renamed.\n", - "\n", - "In this example we have created macroscopic cross sections (by material), and thus we will need to change the material definitions accordingly.\n", - "\n", - "First we will create the new materials.xml file." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Material instance already exists with id=1.\n", - " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Material instance already exists with id=2.\n", - " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Material instance already exists with id=3.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Re-define our materials to use the multi-group macroscopic data\n", - "# instead of the continuous-energy data.\n", - "\n", - "# 1.6% enriched fuel UO2\n", - "fuel_mg = openmc.Material(name='UO2', material_id=1)\n", - "fuel_mg.add_macroscopic('fuel')\n", - "\n", - "# cladding\n", - "zircaloy_mg = openmc.Material(name='Clad', material_id=2)\n", - "zircaloy_mg.add_macroscopic('zircaloy')\n", - "\n", - "# moderator\n", - "water_mg = openmc.Material(name='Water', material_id=3)\n", - "water_mg.add_macroscopic('water')\n", - "\n", - "# Finally, instantiate our Materials object\n", - "materials_file = openmc.Materials((fuel_mg, zircaloy_mg, water_mg))\n", - "\n", - "# Set the location of the cross sections file\n", - "materials_file.cross_sections = 'mgxs.h5'\n", - "\n", - "# Export to \"materials.xml\"\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "No geometry file neeeds to be written as the continuous-energy file is correctly defined for the multi-group case as well." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we can make the changes we need to the simulation parameters.\n", - "These changes are limited to telling OpenMC to run a multi-group vice contrinuous-energy calculation." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "# Set the energy mode\n", - "settings_file.energy_mode = 'multi-group'\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Lets clear the tallies file so it doesn't include tallies for re-generating a multi-group library, but then put back in a tally for the fission mesh." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a \"tallies.xml\" file for the MGXS Library\n", - "tallies_file = openmc.Tallies()\n", - "\n", - "# Add fission and flux mesh to tally for plotting using the same mesh we've already defined\n", - "mesh_tally = openmc.Tally(name='mesh tally')\n", - "mesh_tally.filters = [openmc.MeshFilter(mesh)]\n", - "mesh_tally.scores = ['fission']\n", - "tallies_file.append(mesh_tally)\n", - "\n", - "# Export to \"tallies.xml\"\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "Before running the calculation let's visually compare a subset of the newly-generated multi-group cross section data to the continuous-energy data. We will do this using the cross section plotting functionality built-in to the OpenMC Python API." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAY4AAAEaCAYAAAAG87ApAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xd4VHXWwPHvSQ+BhI70Ik1ERIkIir2hglhYV117Qdey7rq66uq+rmtdd13dVdTVVXHVxd4Qe6OJShNEBAQE6Z1AQkLaef+4d8IkmUzuTKZlcj7PMw+Ze+/ce24yzJlfF1XFGGOM8Sol3gEYY4xpXCxxGGOMCYklDmOMMSGxxGGMMSYkljiMMcaExBKHMcaYkFjiMCYGROSPIvKfKJ37bhHZIiIbonF+Y2qyxGFiSkTOE5HZIlIoIutF5H0RGRHHeLqIyOvuB2+BiCwUkYsbeM6jRWSN/zZVvVdVL29QsIGv1Q34PTBAVfeJwPl6iIiKSFqN7RNE5G6/511E5EUR2SoiRSLyjYiM8tvfXkQmisg69/c6Q0QObWh8JjFY4jAxIyI3AA8D9wIdgG7AY8CYOo5PC7Q9wp4HVgPdgTbABcDGGFw3UroBW1V1U6gvDPf3KyKtgelAKbA/0BZ4CPifiIx1D2sOzAKGAK2B54DJItI8nGuaBKOq9rBH1B9AHlAI/CLIMX8GXgNeAHYClwOZOMlmnft4GMh0j28LvAvsALYB04AUd9/NwFpgF7AEOK6OaxYCg4PENAz40r3GfOBov32tgWfduLYDbwE5QDFQ6Z67EOjk3tsLfq89DfjePe8XwH5++1YCNwILgALgZSArQGzH17jWBI/nvtk99x4grcY5ewAaYPsE4G7357uAhb7ftd8xNwOrAKnjd7kTGBLv96I9Gv6wEoeJleFAFvBmPceNwUkeLYEXgdtwPrwHAwcCQ4Hb3WN/D6wB2uGUYP4IqIj0A64FDlHVFsBJOB+YgXwFjBeRc9xqnyoi0hmYDNyNkyRuBF4XkXbuIc8DzXC+dbcHHlLVIuBkYJ2qNncf62qcty8wEfitG/t7wCQRyfA77GxgJNATGARcXDNwVf2kxrUu9njuc4FTgZaqWl7H7yWYE4DXVbWyxvZXcEpAfWu+QEQGAxnAsjCuZxKMJQ4TK22ALR4+qGaq6luqWqmqxcCvgL+o6iZV3QzciVOdBFAGdAS6q2qZqk5TVQUqcEoqA0QkXVVXquryOq73C5ySyp+An0TkWxE5xN13PvCeqr7nxvMxMBs4RUQ64nxoX6Wq293rT/H4u/glMFlVP1bVMuDvQDZwmN8x/1LVdaq6DZiEkzgjee7V7u83HG2B9QG2r/fbX0VEcnGS7J2qWhDmNU0CscRhYmUr0NZDvfrqGs874VR/+KxytwH8Decb7EciskJEbgFQ1WU437j/DGwSkZdEpBMBuB/6t6jq/jillm+Bt0REcNo9fiEiO3wPYAROsuoKbFPV7V5uPtg9ud/cVwOd/Y7x7yG1G6fNIFLnrvk79udL7Ok1tqfjJGqALTi/g5o6+u0HQESycRLfV6p6X33Bm8bBEoeJlZk4deqn13Nczema1+F8gPt0c7ehqrtU9feq2gunXv8GETnO3fc/VR3hvlaBv9YXoKpuwfmG3gmnamo18LyqtvR75Kjq/e6+1iLS0sM91FTtntwk1RWnTaahvJw7WHzrcRJEjxrbe7I3IX0CnCkiNT8/zsb5vSx1r52J0+6zBrgylJswic0Sh4kJt4ri/3DaE04XkWYiki4iJ4vIA0FeOhG4XUTaiUhb9xwvAIjIKBHp7X44FuBUUVWKSD8ROdb94CphbwNyLSLyVxEZKCJpItIC+DWwTFW3utcZLSIniUiqiGS5XW27qOp64H3gMRFp5d7Lke5pNwJtRCSvjnt6BThVRI4TkXSctpo9OI3wDdWgc6tqBfA6cI+ItHHv61xgAM79gtODKg94WkT2cX8v5+K0R92kqupe+zWc3/1FAdpDTCNmicPEjKo+CNyA07i9Gefb6bU430rrcjdOu8IC4DtgrrsNoA/Ot99CnBLNY6r6OU77xv04VSYbcBqub63j/M1wGux3ACtwvq2f5sa7Gqex/o9+8d7E3v83F+B8O18MbMKpHkNVF+MkvBVuFVe1ajJVXYLTfvKIG+NoYLSqlgb5PXgSoXNfjdNLbQHOfV0LnKqqG91rbMWpsssCFuFUQ94AXKCqL7vnOAwYBZwI7HDH7RSKyBENvEWTAMRpSzTGGGO8sRKHMcaYkFjiMMYYExJLHMYYY0JiicMYY0xIkipxiMhoEXlSREbHOxZjjElWSdmrqm3bttqjR494h2GMMY3GnDlztqhqu/qPhFhMWx1zPXr0YPbs2fEOwxhjGg0RWVX/UY6kqqoyxhgTfZY4jDHGhCSpEoevcbygwGZuNsaYaEmqxKGqk1R1XF5eXXPLGWOMaaikShzGGGOizxKHMcaYkFjiMCYBlVVUsnTjrniHYUxAljiMSUD3v7+YEx+ays9bd8c7FGNqSarEYb2qTLKYvcpZynxr0Z44R2JMbUmVOKxXlTHGRF9SJQ5jjDHRZ4nDmASWfFOQmmRgicMYY0xILHEYEye7S8vpcctk/jNtRbxDMSYkljiMiZNtRaUAPDP9pzhHYkxoLHEYY4wJSVIlDhvHYYwx0ZdUicPGcZjGREQA6zllGp+kShzGxMuKzYW8MXdNSK+RKMViTLQl5ZrjxsTayIenUVpRyZkHdwn5tWpFDtPIWInDmAgoraiM6PmsNGISmSUOYyJIrfhgmgBLHMZEUCh5QzwUKywPmURkicOYCArnc14j0K9q+eZCetwy2RZ/MjFRZ+O4iPzLw+t3qurtEYzHmEbNqary1kIhEWzJeP+79QC8/e1abjqpf8TOa0wgwXpVjQH+r57X3wJY4jDGZTVLpikIljgeUtXngr1YRFpFOB5jGrVEbZO49n9zGTO4MycM6BDvUEwSqLONQ1Ufru/FXo5pKBE5XUSeEpGXReTEaF/PmFgLlGy8NJx7PRfAuwvWc8V/Z4d3UmNqqHcAoIj0BK4Devgfr6qnhXtREXkGGAVsUtWBfttHAv8EUoH/qOr9qvoW8JZbuvk78FG41zUm2kJp6A43ORgTb15Gjr8FPA1MAiI1ymkC8CjwX98GEUkFxgMnAGuAWSLyjqoucg+53d1vTMIKp6oq1JeUV1SyraiU9rlZtfZZMjKx4CVxlKiqlx5WnqnqVBHpUWPzUGCZqq4AEJGXgDEi8gNwP/C+qs6t65wiMg4YB9CtW7dIhmtMVIT7Gf+Xdxfx35mrWPDnE8nNSo9oTMZ44WUcxz9F5A4RGS4iB/seUYilM7Da7/kad9t1wPHAWBG5qq4Xq+qTqpqvqvnt2rWLQnjG1C8WjeMfL9oIQGFJeVyub4yXEscBwAXAseytqlL3edS5pR1PJR4RGQ2M7t27d3SDMqYO4Qzmsw9709h4SRy/AHqpammUY1kLdPV73sXd5pmqTgIm5efnXxHJwIyJrshlDmvjMLHgpapqIdAy2oEAs4A+ItJTRDKAc4B3YnBdYyImvNJDsE/70E5opRcTC15KHC2BxSIyC9jj29jA7rgTgaOBtiKyBrhDVZ8WkWuBD3G64z6jqt+HeF6rqjJxFcrndiQ/48WKGiaGvCSOOyJ9UVU9t47t7wHvNeC8VlVl4iq8adUbnkJsOncTS14Sx8/AelUtARCRbMDmLTAmgJBKHEEODrf8YAUPEwte2jhepfrAvwp3W8IRkdEi8mRBQUG8QzFNVKS/+Ac6X7BrWMHDxIKXxJHm36PK/TkjeiGFT1Unqeq4vLy8eIdiTL0isQ6Hj7VxmFjykjg2i0hVQ7iIjAG2RC8kYxqxcKYcCfE1gXKEtXGYWPLSxvFr4AURedR9vgZnQGDCsV5VJt5CKUUEbeMIUoKwHGHirc4ShzvFiKjqMlUdBgwABqjqYaq6PHYhemdVVSbe4vWhblVVJpaCVVVdCMwRkZdE5GKguaoWxiYsYxqnSHfGDbTPcoSJtzqrqlT11wAi0h84GZggInnA58AHwAxVrYhJlMY0EqG0NQQ7MuhY8oA9raz+ysROvY3jqrpYVR9S1ZE4ExtOx5m/6utoBxcq645rGqNIfuiv2FzEwrX2/jfR5aVXVRVVLXZHd9+qqvlRiils1sZh4i20AYDhJYxAVVW+No4Pvt/AqEemh3VeY7wKKXH4WVT/IcY0PfEeAGhMLNTZxiEiN9S1C2genXCMadwi1R3XmEQWrMRxL9AKaFHj0bye18WNtXGYuIvBmuMNUbin9qqBxoQq2ADAucBbqjqn5g4RuTx6IYXPZsc18RapJOBrxwjWDhJOt9xj/v4Fs247PsyojHEESxyXAFvr2JdwDePGNDXhVHVt3rWn/oOMqUewcRxLguzbGJ1wjGncQvkwtzYO01gFm3Lkz/W92MsxxjQl4cx4GyiBiIcVOWwEuYmXYFVVl4vIziD7BWdd8D9HNCJjGrFYliKsxGLiJVjieAqnF1UwT0Uwlgaz2XFNvIW25rh98pvGKVgbx52xDCQSrFeVibdwRoMHe03Q+awiVFV117uLaNs8k18fvW9kTmiSnpf1OIwxHsWycTxSVVVPT/8JwBKH8SwhB/IZY4xJXJY4jImgkEocwXZWDQBsSDTR8fPW3dz//mKbyr0Jq7eqSkTaAVcAPfyPV9VLoxeWMY1TZThtHAG2JXJP23HPz2bxhl2MHdKZ3u3r6z9jkpGXNo63gWnAJ4At3GRMELGYVj3eyioq4x2CiTMviaOZqt4c9UgiqLDEJnIz8RGLZGAD/0y8eWnjeFdETol6JBHgmx33p61FTPzm53iHY5qg0MZxeDkmvK66sdBIC0wmArwkjutxkkeJiOxyH8FGlMeNbwXAFplp3PrGd9z//mIqK+3dbWInrA/TEF/jK3DEq6pLrMjT5HlZc7yFqqaoapb7cwtVzY1FcOHq3jaH8w7txhNTlnPdxHmUlFnTjImNUD7M4/WNfebyuia9NsYbT91xReQ0Efm7+xgV7aAaSoB7Th/IH0/pz+Tv1nPeU1+xtdCmkzbRF+n1OKJRH3XuU18xY9kWT8eWV1TyxJTlAb98WVm+6ao3cYjI/TjVVYvcx/Uicl+0A2soEWHckfvy+K8O5vt1OznjsS9Ztqkw3mGZJBdOKSLUl/iqihpSYtm4s8TTcW/MW8v97y/m4U9+3Hv98C9rkoSXEscpwAmq+oyqPgOMBE6NbliRc/IBHXlp3DB2l5Zz1uNf8tUKK6ab6Alt4sLE/87uK2kU+S05+2M9X8AKisu4//3F1m03iXkdOd7S7+e8aAQSTQd1a8WbVx9OuxaZXPD017wxd028QzJJKlLtFl7W42iISMQZ6Bwbd5Zw7N+/4Ikpy5k0f13DL2ISkpfEcR8wT0QmiMhzwBzgnuiGFXldWzfj9asOI797a254ZT4Pfby00Q7AMokrlJHjif72m/jNz/zf298D3ktS5z75FVuLSgEotx6NSctLr6qJwDDgDeB1YLiqvhztwKIhr1k6z106lLFDuvDPT3/k96/MZ0+59bgykRNWG0eY06o35Py/f3U+PW+dHPR1D35U5+rRAPzl3e+57/0fqm1bs73Y78LeYzSNS50jx0Wkv6ouFpGD3U2++p1OItJJVedGP7zIy0hL4W9jB9G9dTMe/Hgpa3cU8+8LhtCyWUa8QzNNjKcBgIGWlY3QBIgNff2MZVuZsWwrP24s5JmLD6GsopLySmvXaAqCTTlyAzAOeDDAPgWOjUpEMSAiXHdcH7q1acZNry7gzMe/5NmLD6F7m5x4h2YauVhUP8Vj/J3vvjbvqt2t/bPFmwAY8H8fYLVTTUOwFQDHuT+erKrV+u6JSFZUo6p+rV7AbUCeqo6N5LnHDO5Mx7xsxj0/mzMe+5KnLsxnSPdWkbyEaWJC6VXlJcnEd3nZ2hlqa1Hd46HKKqrHunxzIaXllWSk2eoNycbLX/RLj9s8E5FnRGSTiCyssX2kiCwRkWUicguAqq5Q1csacr1ghvZszRu/PozcrDTOfeorJi9YH61LmSYgnG/cAadV91Adlehrlv976gpuf+s7Hvn0R5ZvtjFUyaTOxCEi+4jIECBbRA4SkYPdx9FAswZedwLOeBD/66UC44GTgQHAuSIyoIHX8aRXu+a8cfXhDOqcxzX/m8vjXyy3HlcmLCFNORLmB3+oXXVDfSurKv+ZtoItfrMthPu/4ZXZa3jw46Uc9+CUMM9gElGwNo6TgIuBLjjtHL53607gjw25qKpOFZEeNTYPBZap6goAEXkJGIMzWj3qWudk8MLlh3LTawv46weL+XlbEX8ZM5D0VCtmG+8i/XUj2Pmi9d1m+eZC7p78Q8B90R5fYhqHYG0czwHPichZqvp6DGLpDKz2e74GOFRE2uCMGzlIRG5V1YDTnYjIOJzGfLp16xZWAFnpqfzzl4Pp1jqb8Z8vZ832Ysb/6mBys9LDOp9pesLrjlt7296qqto7q/aFfilPwhl/8cJXq6IQiUlUXr5ODxGRqpHjItJKRO6OYkzVqOpWVb1KVfetK2m4xz2pqvmqmt+uXbuwr5eSItx0Un8eOGsQM5dv5RePz2TtjuL6X2gMkZ8dN1EqTH2xfv1T4Cl7bn9rYcDtJjl5SRwnq+oO3xNV3Y4zf1WkrQW6+j3v4m7zzLeQU0FBQYODOfuQrky4ZCjrdhRz+vgZfLem4ec0yS+85TjCSw+RaIdbvKH20jp1VUfNWbW9aiR5OOz/UPLwkjhSRSTT90REsoHMIMeHaxbQR0R6ikgGcA7wTign8C3klJcXmem0RvRpy+tXH0ZGagpn/3smHy/aGJHzmuQVyme5p2MDVWN5v0S9Rj48zdNxIoHHcIRi9KPTG/R6kzi8JI4XgU9F5DIRuQz4GHiuIRcVkYnATKCfiKwRkctUtRy4FvgQ+AF4RVVD+noTyRKHT98OLXjzmsPo26E5456fzbMzforYuU3yCadXVaBv+L5tkVg6NjLTlkTgJCZpBOtVBYCq/lVE5gPHu5vuUtUPG3JRVT23ju3vAe814LyTgEn5+flXhHuOQNq3yOKlccO5/qV53DlpEau27uZPowaQmmI9TEx1IU2qHuaHcSTW4wh+/tC2h2JnSRl7yipp1yIalRYmVupNHK4fgHJV/UREmolIC1XdFc3AEk12RiqPnz+E+977gf9M/4k123fz8DkH0TzT66/QNAWhzI7rRSJ907/y+TkNPscRf/2cguIyVt7faJb0MQF4WQHwCuA14N/ups7AW9EMKlzRqKryl5oi3D5qAHeN2Z/Pl2xm7ONfsmb77qhcyzRSkVqPw9NEhsqPG3fFaIbnyNxYQXFZRM5j4stLG8c1wOE4A/9Q1R+B9tEMKlyRbhyvywXDe/DsxYewdkcxYx6dweyV26J6PdN4xKSqyv13a2EpJzw0lT++sTCiEx9aBaypj5fEsUdVS31PRCSNxOleHjdH9m3Hm1cfTousNM576mtem2OrCpoQe1V5+G8U7IhdJc5yrrNWbgs+p5XHoK6bOI/HvlgWcN/slds9ncM0DV4SxxQR+SPOnFUnAK8Ck6IbVniiXVVVU+/2zXnrmsPJ79GKG1+dz33v/0CFzSvdpEV8dtwoL/Lkb9L8dTzwQeDFm+pbZ9w0LV4Sxy3AZuA74EqcXk+3RzOocMWqqspfy2YZPHfpUM4f1o1/T1nBlc/PpnBPecyubxJLTL431KhLSvRZcgN5auqKeIdgGsDL0rGVqvoU8CucOaPeVps6tpr01BTuPv0A/uI2mp/12Jes3maN5k1RaOM4wjvGlzf8rxWPxZ0a4p73fmDhWhtJ3lgFm1b9CRHZ3/05D/gW+C8wT0QCjsNo6i4c3oMJlxzC+gJnmpJZ1mje5ITWOO6hjSPoehwOQSLabTdWSWhrUWn9B5mEFKzEcYTfyO1LgKWqegAwBPhD1CMLQ6zbOAI5ok873rrmcHKz0znvqa94dfbq+l9kkkdIjeORumTjrACorFRKymLRldhEWrDE4f914ATcsRuquiGqETVAPNo4AunVrjlvXX04h/Zsw02vLeDe96zRvKkIp3E8+Dd8b+cLdo5Efefd8sYC+v/pg6rnyzYV2rioRiJY4tghIqNE5CCccRwfQFV33OxYBNeY5TVL59lLDuHC4d15cuoKxv13NrtKbPBTsqusDP01gdfjqHtakb379s51FdkFlmJTV7VxZ/VJE4//xxRG/PXzmFzbNEywxHElzqSDzwK/9StpHAdMjnZgySA9NYW/jBnIXWP254ulmxn7+ExrNE9yoX27D3fp2Jpn0TpLHIV7ytlQUBLWdYypS7AVAJdSY11wd/uHODPYJhwRGQ2M7t27d7xDqeaC4T3o2bY5V784hzHjZ/DE+UMY2rN1vMMyURCvhZzqKiOc9sh0Vmwp8hqSMZ4k1YLaidLGEciIPm1565rDaZmdzq/+8xWvWKN5UgqpV5X7b9D2iaAjwvf+XNc5wkka8e7aW2TjoBJeUiWORNerXXPedBvN//DaAu6ZvMgazZNMxNYc9+0LkIoCrTmeEu9P+wja/46ErNAwfixxxFhes3QmXHIIFw3vzlPTfuKK/85mpzWaJ41IV1U1Fdb217h4mVb9ehHJFcfTIjJXRE6MRXDJKi01hTvHDOTu0wcydelmTntkesC1n03jE4sBgFWrA1arqmrcJY4jHrDeVI2JlxLHpaq6EzgRaAVcANwf1aiaiPOHdWfiuGEUlVZwxvgveWve2niHZBootNlxHYE+8wNVRwUTybTxxZLNETxb/WwGo8bHS+LwvSdPAZ53R5Mn5NebRBg5HqpDerRm8nUjOKBzHr99+VvueHshpeVhDAYwCSHSs+N6vVYkCxzvLlgXuZM1wMK1BSxYsyPeYZgAvCSOOSLyEU7i+FBEWgAJ+cmWyL2qgmmfm8WLVxzK5SN68tzMVZzz5Ezre99IRapxfO++uhvHq20L/bJhxRMNyzcHnrJ91CPTOe3RGQBs2llCpXUkSRheEsdlOFOrH6Kqu4F0nLmrTASlp6Zw+6gBPHreQSzesItRj0xj5vKt8Q7LhCiUNccbOsdUsrRxnDH+y1rbPli4d2aj9QXFDL33Ux7+ZCkA81fv4DcT51kiiSMviWM4sERVd4jI+ThrcTSeuqBGZtSgTrxz7eHkZadz/tNf8+TU5VYHnKyCzFXl614bLBH572nEeYPC0trjNq56YU7Vz5vcqUm+WOq0vYx7fjbvzF/Hpl17ar3OxIaXxPE4sFtEDgR+DyzHmV7dREnv9i14+9oRnLR/B+59bzFXvzjX5rlqJMJpHA8kNcXJBOUVXic5jFzmiPXXlHC/F63dsdt6I8aJl8RR7i7cNAZ4VFXHAy2iG5ZpnpnG+PMO5vZT9+OjRRsZM34GP27cFe+wTD1CGdAZ7AMzzU0cXs6nmqC9VSJkR3HgL01nPT6TkQ9Pi3E0Brwljl0icitON9zJIpKC085hokxEuPyIXrx4+aHsLC5nzPgZCdPjxQQWqZkAUnwljgDnqzk7rrMtIpd1zhW5U0XERc98A8DGnSVs2mmdRhKBl8TxS2APzniODUAX4G9RjcpUM6xXGyb/ZgT7dczl2v/N48/vfM+eclsAJxGVhTCverDG8VSpu8RR84NdhAhPq56YNu7cw9B7P601HbuJPS9rjm8AXgTyRGQUUKKq1sYRYx1ys5h4xTAuPbwnE75cyRnjv6yzG6OJH69tEhC8qio11Kqq5M8bJoF4mXLkbOAb4BfA2cDXIjI22oGFozEOAAxFRloK/zd6AE9flM/6gmJGPzKdV2evtl5XCaSsIpQSR91SgpQ4ql7vtyslgonD3k+mPl6qqm7DGcNxkapeCAwF/hTdsMLTWAcAhuq4/Trw/vVHMqhLHje9toDrX/rWel0liEBtEuHwJYLAbRzOv9VGjkewqmr+msb1xeulb36OdwhNjpfEkaKqm/yeb/X4OhNF++Rl8eLlw7jxxL5M/m49p/xrGvN+3h7vsJq80HpVqftv7X17q6rCn6Thxa9Xhf3axuSWN76LdwhNjpcE8IGIfCgiF4vIxTjLxr4X3bCMF6kpwrXH9uGVK4dRWQljn5jJPz5aYnNdxZh/1U44VVUVAacVqbtXVSA12ziWbSrktjcXeo7FmFB4aRy/Cfg3MMh9PKmqN0c7MOPdkO6tef+3R3D64M7867NlnPHYDJbamI+Y8S9lhNI47sscwUopXts4ag4AtC8PJpqCJg4RSRWRz1X1DVW9wX28GavgjHe5Wek8ePaBPHH+EDYUlDDqkek8OXW5rTAYA/6lgnC64wb+G9W9r6qNwz9x1HFuY6IhaOJQ1QqgUkSSu7U5iYwcuA8f/u5IjurbjnvfW8y5T37Fz1ttdbVo8q+eqgilxBGEL/8EHsdRuyHcuuOaWPLSxlEIfOeu/vcv3yPagZnwtW2eyZMXDOHvvziQH9bv5MSHp/Dk1OWUh1D/bryrVlUVoSlHfCWGYOcLNslhUxgQ6K+gjmlJTHR4SRxv4HS/nQrM8XuYBCYijB3ShQ9/dyQjerfl3vcWc/pjM1i4tnF1tWwMyirCbBwPkjgqg7R/7K2q2rsvpYkXOU79l81ZFUtpde0QkXZAO1V9rsb2/YFNgV9lEk2nltk8dWE+7y/cwB3vfM+Y8TO4bERPfnd8X7IzUuMdXlIo92vXCGnkeLB9Wvvcpm5rthfHO4QmJViJ4xGgbYDtrYF/RiccEw0iwikHdOST3x3F2fldeHLqCk58eApTl8Z2belk5Z8sQmkcD7rWhrsvWCIKmniscdxEUbDE0VtVp9bcqKrTcLrlxoSI5IjIcyLylIj8KlbXTUZ5zdK578xBvDxuGOmpKVz4zDdc+fxsVm+zxvOG8G+H2BNCN9hgU3v49gTqVlurB5VaVZWJrWCJI9iaGw2aVl1EnhGRTSKysMb2kSKyRESWicgt7uYzgddU9QrgtIZc1zgO7dWG968/gptO6sfUpVs47h9T+MdHS9gdYCU2Uz//TgfFpd5nLQ7WHOJLKsVlQc5XbRxH9V1NrXHcxFawxLFMRE6puVFETgZWNPC6E4CRNc6bCowHTgYGAOcOOiC8AAAgAElEQVSKyACcadxXu4fZXOIRkpmWyjXH9OazG4/i5IH78K/PlnHcg1N4Z/46m+QuRP4ljlCSb7CqKt8pgyUOX3VUoMKGVVWZaAqWOH4LPCwiE0TkOvfxHE77xvUNuahbBbatxuahwDJVXaGqpcBLOKsOrsFJHkHjFZFxIjJbRGZv3mx19151zMvmn+ccxKtXDadVswx+M3Eep4+fwZfLtsQ7tEbDvx0ilBKHl/XEA56vRqawPJ9YXvrmZ/Lv/pjKJB58W+cHsar+CBwATAF6uI8pwCBVXRqFWDqzt2QBTsLojNMd+CwReRyYFCTeJ1U1X1Xz27VrF4XwktshPVoz6boR/G3sIDbv2sN5//maC5/5xrrveuBrEM9KT2F3hBKHb9/XP9X8fgWpbt7wr+qy5JE4/u/t79lSWMqGJF6tsM7uuACqugd4Nkax1BVDEXCJl2NFZDQwunfv3tENKkmlpgi/yO/K6AM78fzMVYz/YhmjHpnOaQd24rfH96FXu+bxDjEh+cZa5Galh5Q4gg75CJII0lOd73ul7iqQIsF7WJnYSkkBKmDH7jI6tcyOdzhRkUjTo68Fuvo97+Ju86yprMcRbVnpqVxxZC+m3HQM1xyzLx8t2sDx/5jCbybOs8kTA/AN+svNTg/emF1DZZBZdf331WxzykhLcV+zd1p2a5dKHL4vEjuTeI2cREocs4A+ItJTRDKAc4B34hxTk5aXnc5NJ/Vn2h+O5Yoje/HJDxs58aGpXPX8HKvC8uNr42iRlcbu0nJ27C71tC58ZbVG9erH+ueBml18q0ocNoVMQqpKHEk8DYqXpWNzRCTF73mKiDRryEVFZCIwE+gnImtE5DJVLQeuBT4EfgBeUdXvQzxvUi8dGy/tWmRy68n7MePmY/nNsb2ZsXwLox6ZzgVPf83nizcldSOgF75SRpucTErKKnno46VM+HIlb8x1CszFpRXc8voCCnZX/yD545t7FyAq2lO9N5Z/r6iaDeTpbiOHTZ2emHz/HXaWJG/3di8ljk8B/0TRDPikIRdV1XNVtaOqpqtqF1V92t3+nqr2VdV9VfWeMM5rVVVR1CongxtO7Mf0m4/lDyP78ePGQi6ZMIvjH5rC81+tarLjQHwf7G2bZwBQuMd5XuImlJdn/cxLs1bz8KfV+5T459uavzv/fTWrvzLSnKli/Ku3atZU2XT68dekSxxAlqoW+p64PzeoxBEtVuKIjbzsdK4+ujfTbj6Gf54zmOaZafzprYUMv+8z7pm8iGWbCus/SRLxVTO1znESh6+KyvfZ7fvX/8O9ZpuEL9ns3e+/r3pS8ZU4fIlj7Y5ivl9X/T0fSrdgEzklfkm+qbdxFInIwb4nIjIESMgZxazEEVvpqSmMGdyZt685nNeuGs7hvdvw7IyVHP+PKZz9xExen7OmSXyAVVVVNc8E9rZJBKvCq1lC2FXjQ8Y/sZz4UPWZfzKqelXtLXE8Ne2ngDGZ2NrhVx25szh5S+BBu+O6fgu8KiLrcKbJ2Qf4ZVSjaqgtP8Kzp8Y7iiZDgHz3Udqrki2Fe9i0aQ8lb1ewcJLQNieTti0yaJ6ZFtupMA4YC/meenI3SLFbzdSuRab73PnQ9q0l/u3qHUD1ZFBznfELnv6Glffvfc8q0LJZerUPIp80XxtHkAkQk7l+PZFt311a9XMyrxFSb+JQ1Vki0h/o525aoqrJ+xsxDZKRmkKnvGw65mWxq6ScTbv2sKmwhI27SshMS6FNTiZtmmfQLCM1uklkg9vwHIPEsbu0grQUoWsrp8/+Rnfgl6+d4Z3564Dq7RbBBv8BfLa47pULfL2q3v627t7qf/twcf2Bm4jbXuSfOEqDHFn/OVq5VZ+JKNh6HMeq6mcicmaNXX1FBFV9I8qxhazaAMBLJsc7nCZNgFz30b6kjI++38g789cxY9kWKjYrvds3Z+T++3BM//YM7tqS1JQIJ5EYljiL9pTTLCOVzu5grw0FTuKoWVXl31Mq1GU2vvlpGxO/+Zk3563lqL7OzAjBBhuu3paQtclJb7tbQmzXIpMtheEljoPu+higWgk00QQrcRwFfAaMDrBPcaYCSSiqOgmYlJ+ff0W8YzF75WalM3ZIF8YO6cLWwj28v3ADk+av47EvlvHo58tonZPBUX3bcXS/duT3aE2nvCykEU0Tvm13Ga1zMmjbPJOMtBR2uY3ZC9YW8Od39vYor6/Eoap13vfZ/55Z9fOXy20esUS1aZfzpaH/Pi1YubUo6LF/+3Axa7YX889zDopFaBFVZ+JQ1Tvcf6Nf1jdNRpvmmZw/rDvnD+vOjt2lTP1xC58v3sQXSzbx5jyn6mWf3CyGdG9F/31a0K1NM9rkZJKaImzfXcq6HcXsKimnQ24WIwfuU9WTKZ62F5XSOieDlBRhv465zHfbND5etLHaccHaOMCp0hozuHO1bRMuOYSLn51VbZuz9oZ1t63pqakr6Nwqm84ts+ncKps2ORkx/wKycece0lOFPu1bMGfV9qDHjv98OQAPnT2YlEiXuKOs3jYOEWkD3AGMwHm3Tgf+oqpboxxbyGyuqsalZbMMTjuwE6cd2ImKSuWH9TuZs2p71WPyd+uDvv6udxdx4fDujDuyV1WPplj6cvkW5q7azpbCPXRx2zcO7tayKnHUVK07rl9VVd8OzVm6sbBqOhf/HlZH92tf6zyhrGvelNzz3g/Vnmelp9CppZNIurgJpWvrZvRok0OPtjnkZTdoWaGA1hcU0yE3i3YtMtldWsHu0nKaZQT/mN1aVFrVsaKx8NKr6iVgKnCW+/xXwMvA8dEKKlxWVdV4paYIAzvnMbBzHhcd1gNweiet3r6bHbvLKK+oJK9ZOp1bZpOblc7STbv495QVPDVtBc9/tYrzhnbjtMGdGNgpr95vb1sL97ByaxFDurcOKUbf+IzMtFSWbNjFeU99DTgfUIft66yyfFTfdjw7Y2XA11fWUeK4/6xBnPnYl7w5dy2/O74vB/z5o2qv+79RA/jLu4v8zhNS2E3G/DtOZO32YtbuKGbN9t1VP6/dUcyidTvZWlS9zaFVs3S6t8mhR5tm9GibQ78OLdivYy7dWjcLuwSwYnMRPdvm0MYdDLplVynd2tT+mPUvfa4vKOb1uWu4//3FLL37ZM/X+mTRRgZ1yaN9blZYsTaEl8TRUVXv8nt+t4gkdndckxSyM1Lp2yHwQpT998nloV8O5ppj9uXhT35kwpcr+c/0n8jLTmdw15b8ZXsRWWmpLF66mbzsdHKz0qhU+H5dAXe9u4gthaU8/MvBnH5Q9aqh4tIKdhSX0jGv9qymJz88jfTUFD783ZE8M33vuImSskr6dHBmDj6qbzsuPbwnz8z4qdbrK9Xponns37/g7tMHVm0f3KUlAOsKSuh92/u1XnfpiJ4sWr+T1+asqdpWV1fdpiwvO5287HQGdMoNuN/3RWTlliJWbi1i5dbdrNpaxKyV23l7/rqqEmFORir9O+YyoGMuB3ZtyUHdWtKrbU691V7lFZUs31zI2fld6dbaGSP909YiurWpPV7af4zHuh0lPDnVWRtvW1H9Dep7yis48M6PKCmrpFfbHD678eh6XxNpUt+smiLyD+Ab4BV301hgqKreGOXYwpafn6+zZ8+OdxgmhnbsLuWTHzYxZ9U25v28gzu3/4H9WMUi7V7r2Kz01KrlXnu0ySEnM420FCE1RVi+uZCtRaXkd29FWorT7bWotJwNBSVsLtwDwMHdWjF/zY5q03oM7tqSLHcqEHASxA8bdla7bk5GKjmZaWzatYfs9NSqQXrDerbh+3UFVY3q/ob1bFP181c/7a0dTk9JqVoHJJADOufxXRObiNL/dxWqStWqqqWi0gp27ylnd2lFVcmwWUYqbXIyaJGVTvPMtIBrvO/aU8b363bSu31z8rLSmfPzdrq3bhbwS0hxWTnz1zh/n+5tmrFuRwllFZUc2KUl89fsCHo//u+Dht63P7n0vTmqmu/lWC8ljitwBgG+4D5PwRlNfiWgqho4vRsTQy2bZVT13AKonHUlZfNfZv+ySsorlfJKRYDMtBSaZ6VRXFrBDxt2sWxz4OlRvl29g+z0VFJEKKgxqnvuz9UbPQWqJQ2A3Ow0WudkVPsGWVRaQZHbhbbmyO4+HVrUOm9NQ3u05puVzsJOZZWV5Hdvxew6GmBzMtIY2CmPheuaVvIIV4oIzTPTaJ659yNRUYrLKthZXM7mXSWs3l4MFCNATmYaLbLSqhJJaoqwbkcxItAyO520lBTSUqTq711Tmd/gzdLyyqoRTY1ljrF6SxyNiV/j+BU//vhjvMMxCa6sopIlG3axdOMudpWUU7innEx3rYu5P29na2EpRaXl5HdvTfPMNH7aUsSnizdSUrb3m/7Fh/XgtlP3qxqUV9P0H7fwwIeLWbCm7g9wX3/9MeNn1GpYr9mX/7cvzeOtb9dV7VNVet76Xp3n7HFL8PFMr/96OGc9PrPatnvPOKDazL2NRbTHPWwvKmXWym3MXrWd2Su38d3agmoJAOC2U/bjiiN7AXDNi3P5ZuU2vr71uFptJu8uWMe1/5sHwKhBHZm7ajvrCkp4edwwfvnkV4Cz7kqgNg//v2lairDs3lMicn8iEtESByJyGnCk+/QLVX033OCiyRrHTSjSU1OqGuS9KiguY9POElrnZNCyWUa9AxdH9GnLiD4jKKuoZPH6XYx+dHq1/cfvt7fX1H8vHcqBd35U8xTVjDty36rEAdRb737ryf257/3ao8gP7dmavh1aMLhrq2rbD+7WktY5ke9tlAxa5WRw4v77cOL++wDOhIbfrS3g+7UFFJVWcFC3llWdJACOH9Ceyd+t56sVWzmsd9tq59rqDg7s26E56wtKqv6Ou/1KoqXllUHH9kCt5edjxst6HPcD1wOL3Mf1InJftAMzJhHlZafTp0ML2jTPDGm0e3pqCgd0yeOb246rtv3yI3pVO/fwXsHrq3u1y6m17blLh1b9fNi+bfjNsXu7o1951L4Bz3PfmQdw1+kDq93DD38ZyctXDic1JZHWd0tcWempHNKjNRcf3pNrjuldLWkAnDywI+1aZPLAh0tqdaFeu6OYjLQUBnTMZUNBCb5fec1JQb1WCKlq1eDDWPDyDjkFOEFVn1HVZ4CRQOKOhTcmgbVvkcWP95zM4K4taZGVVqsH0MPnDK76eZ8A3Syz0lNrbRvWa2+34od/OZgbTuxX6xh/X9x4dMD147MzUklPderma4rGmIdkl5Weyh2jB/Dt6h3c/NqCasljxeYierbJoXOrbDbsLKlKEDWnkak5UHR5jTa5sgpl6cZdvPD1zwy951MW1+iQES2eqqqAlsA292ebs9yYBkhPTeGtaw4PuK+DX7K4+pjApYWaMv0a5usbf5CWIvRoW7vU4i9QSWrckb3424dLPMVj9ho1qBM/bS7iwY+XsnJrEX89axA92+Yw9+ftHNmnLR3zsqmo1KqJMYtrLOj17eodHNLD+WKwZvtujntwSq1r+E+7/9PmIvrvE/3+Sl5KHPcB80Rkgog8B8wBQl6dzxjjjW8MQKDSBcDfxg7i5pH9A+5LDVDpfe7QrgCcdmAnvrjp6HqvH6jEEc3lgY/tX3t0fDK57rg+/POcwazYUsRJD0/l1H9NZ1tRKSMHdqTfPs44JV8je80FvS71m27m5627q+3rmBf7gX8+XqZVnygiXwCHuJtuVtUNUY0qTDbliEkGH/z2CJ6fuYozawxO9PlFftc6XxuoxOErkRzYtSVdWtW/eGeg6S+i2Uv0iD5tg04j78Xx+3WIUDTRMWZwZw7v3ZYJM1YyY/kWrjlmX07avwOVCh1yM9m40xkjtHZH9eRQWsf0Mqce0BEEJi+oPi3PlKWbWVdQwmUjekbnRlxeGsfPAHar6juq+g5QIiKnRzWqMNkKgCYZNMtI48qj9iWtji6+wQSqZspMd85T4nFVwD4dWvDaVcOrbatUZWDn6FSB1NfJoFc9VWsAT5x/cL3HxFvb5pnceFI/3rz6cG46qT8izqDTv541iGG9WpOblVar23Zd85IN7tqSEwIky5dmreYuv+lposXLO/MOVa26G1XdgTPpoTEmwQSqqvINTtwTwnKy+T1ac5VfjyxV5YGzDmx4gAGcHaQEBfDZjUez8M6Tgry+S1hJNlEc3a89L40bzu9P7FcrcfiX9PwLfV1aZbNvgA4OseLltx3oGK+N6saYGDjzYKdaKyu99n/X7AwncZSUB/72un+nXC4aXntqlltO7s/tp+4HQGZ6KgM65fLSuGGRCrlKVnpq1ezCPtP+cEy15/4jumt6YGx0ElqsnTu0G0N7Vp94MzcrrWpCRP8OVt3aNKNFVvw+hr0kjtki8g8R2dd9PITTQG6MSRAPnDWIhXeeFHCwWLbbyF5zjIDP5N8cwZ1jBgbcd+HwHtx0Uj8uP8KpM4/4So2u6TcfW+1519bN2L9TLn077P1W/fdfHMjAzrlx/cCMpoy0FJ6/bCiH9947lmdnSTl//2gJlZXKDL8FvPp1aEH73LqnYv/HR0v4zcR5VTM6R5qXv8B1wJ9wplIH+Bi4JirRGGPCkpaaQvM6qmt806iU1lHiCCYjLYVrjtnb2WS/jrXbOYLNmVWXq47al4sO687iDbtq7fvuzycCTkLz55uL7IWvVnH7WwtDul5jkZmWyouXD2PN9t0UFJcxYcZKxn++nDmrtvPVim1Vx6WlppCWmsIzF+fz8aJNTPzm52rn+ddnywA4cf8OjBrUKeC11u0opqC4jLQU4eMfNgY8pi5eelUVAbcAiEgqkONuM8Y0An3cqekP7t6ywefyrzJ69LyD2Cc3i3x3nMEFT3/NtB8DL2vbf58W3DF6fzq1zGJXSXnVNC+BZo5tkRV8sKFvBckthXs8N/g3Nl1aNaNLK7hpZD9enbOGr1Zs48yDOjO0Z2tOHdSx6rhj+3fgsH3bsmj9zoALiF37v3moOglkT3klg9y1XgZ1yQs6f1p9vPSq+p+I5IpIDvAdsEhEbgr7isaYmBrSvRVTbzqm3kZor0470PkGe0y/9lVJA+D5yw4lt0Y10v7uyPhzh3Zj+L5t6N4mJ6S5wYJp2zzTU/fixqx9i71jNY7o25ZzhnarlViz0lN5+5rD6+xZdt3EefS7/YOqpAFUSxo5Gancd+YBIcXlpapqgKruFJFfAe/jlD7mAH8L6UoxYOM4jAks0GJC4Xpg7CB+d0JfcgI0WE+6bgRXvziX79ft5JMbjmTmim386a2FdG1du2RR03OXDqWlTW1SJ9/A0LqMHNiRpy/K57Lngq9FdEy/dvTt0ILfHt+3quMEwHkhxOIlcaSLSDpwOvCoqpaJSELOxW6z4xoTfVnpqfSsY2xF9zY5vHvdCDbt2kOH3Cz2bdecgZ1yOahbq4DH+zuqb7tIh5pUunooXR23XwfOO7Qb//v6Zx4YO4g/vLag1jHPXjI0wCtD4yVx/BtYCcwHpopIdyA2M2kZYxodEamac0tEPCUNU7czDurMm/PWBhzRH8idp+3PzSP7k5edTnmFctx+7WnZLJ2Sskp2FkdmueGwFnISkTRVrb3OZYKwpWONMcmipKyCnSVl1do7oiGUhZy8NI7nueM4ZruPB4H65wAwxhjTYFnpqVFPGqHyMgDwGWAXcLb72Ak8G82gjDHGJC4vbRz7qupZfs/vFJFvoxWQMcaYxOalxFEsIiN8T0TkcKA4eiEZY4xJZF5KHFcB/xUR36id7cBF0QvJGGNMIguaOEQkBeinqgeKSC6AqlpXXGOMacKCVlWpaiXwB/fnnZY0jDHGeGnj+EREbhSRriLS2veIemQuEeklIk+LyGuxuqYxxpi6eUkcv8SZRn0qzhxVcwBPo+tE5BkR2SQiC2tsHykiS0RkmYjcEuwcqrpCVS/zcj1jjDHR52Va9Yasej4BeBT4r2+DOzX7eOAEYA0wS0TeAVKB+2q8/lJVbdgq9sYYYyLKy8jxa0Skpd/zViJytZeTq+pUYFuNzUOBZW5JohR4CRijqt+p6qgaD89JQ0TG+Ua3b9682evLjDHGhMhLVdUVqlq1QoiqbgcaMvtsZ2C13/M17raARKSNiDwBHCQit9Z1nKo+qar5qprfrp3NsmmMMdHiZRxHqoiIurMhulVNGdENay9V3YozlsQYY0wC8FLi+AB4WUSOE5HjgInutnCtBfyXIuvibmswERktIk8WFIS/JKIxxpjgvCSOm4HPgV+7j09xx3aEaRbQR0R6ikgGcA7wTgPOV0VVJ6nquLy8yCxNaYwxpjYvvaoqgcfdR0hEZCJwNNBWRNYAd6jq0yJyLfAhTk+qZ1T1+1DPXcf1bOlYY4yJsnoXchKRPjjdZAcAVZPCq2qv6IYWPlvIyRhjQhPRhZxw1t54HCgHjsEZk/FC+OEZY4xpzLwkjmxV/RSndLJKVf8MnBrdsMJjjePGGBN9XhLHHneW3B9F5FoROQNoHuW4wmKN48YYE31eEsf1QDPgN8AQ4AJsPQ5jjGmyvPSqmuX+WAhcEt1wGsZ6VRljTPTVmTjciQfrpKqnRT6chlHVScCk/Pz8hkyJYowxJohgJY7hOHNKTQS+BiQmERljjElowRLHPjhTn58LnAdMBiZGarCeMcaYxqnOxnFVrVDVD1T1ImAYsAz4wh31nZCsO64xxkRf0F5VIpIpImfiDPi7BvgX8GYsAguHdcc1xpjoC9Y4/l9gIPAecKeqLqzrWGOMMU1HsDaO84EinHEcvxGpahsXQFU1N8qxGWOMSUB1Jg5V9TI4MKHYOA5jjIm+RpccgrE2DmOMib6kShzGGGOizxKHMcaYkFjiMMYYExJLHMYYY0KSVInDRo4bY0z0JVXisF5VxhgTfUmVOIwxxkSfJQ5jjDEhscRhjDEmJJY4jDHGhMQShzHGmJBY4jDGGBOSpEocNo7DGGOiL6kSh43jMMaY6EuqxGGMMSb6LHEYY4wJiSUOY4wxIbHEYYwxJiSWOIwxxoTEEocxxpiQWOIwxhgTEkscxhhjQiKqGu8YIk5EdgFL4h1HFLQFtsQ7iChJ1nuz+2p8kvXe6ruv7qrazsuJ0iITT8JZoqr58Q4i0kRkdjLeFyTvvdl9NT7Jem+RvC+rqjLGGBMSSxzGGGNCkqyJ48l4BxAlyXpfkLz3ZvfV+CTrvUXsvpKycdwYY0z0JGuJwxhjTJRY4jDGGBMSSxzGGGNC0qQSh4gcLSLTROQJETk63vFEkojs597XayLy63jHEyki0ktEnhaR1+IdSyQk2/34JOv7D5L3c0NEjnDv6T8i8mUor200iUNEnhGRTSKysMb2kSKyRESWicgt9ZxGgUIgC1gTrVhDFYl7U9UfVPUq4Gzg8GjG61WE7muFql4W3UgbJpT7bAz34xPifSXc+y+YEN+bCfm5EUiIf7Np7t/sXeC5kC6kqo3iARwJHAws9NuWCiwHegEZwHxgAHCA+8vwf7QHUtzXdQBejPc9RfLe3NecBrwPnBfve4rkfbmvey3e9xOJ+2wM9xPufSXa+y9S95aonxuR+Ju5+18BWoRynUYz5YiqThWRHjU2DwWWqeoKABF5CRijqvcBo4KcbjuQGY04wxGpe1PVd4B3RGQy8L/oRexNhP9mCSuU+wQWxTa68IV6X4n2/gsmxPem72+WUJ8bgYT6NxORbkCBqu4K5TqNJnHUoTOw2u/5GuDQug4WkTOBk4CWwKPRDa3BQr23o4Ezcd7Y70U1soYJ9b7aAPcAB4nIrW6CaQwC3mcjvh+fuu7raBrH+y+Yuu6tMX1uBBLs/9xlwLOhnrCxJ46QqOobwBvxjiMaVPUL4Is4hxFxqroVuCrecURKst2PT7K+/yDpPzfuCOd1jaZxvA5rga5+z7u425JBst5bst5XTcl6n8l6X5C89xbx+2rsiWMW0EdEeopIBnAO8E6cY4qUZL23ZL2vmpL1PpP1viB57y3y9xXvXgAh9BaYCKwHynDq6C5zt58CLMXpNXBbvOO0e0v++2oq95ms95XM9xar+7JJDo0xxoSksVdVGWOMiTFLHMYYY0JiicMYY0xILHEYY4wJiSUOY4wxIbHEYYwxJiSWOEyTJiIVIvKt36O+qfljQkRWish3IpIf5JiLRGRijW1tRWSziGSKyIsisk1ExkY/YtOUNKm5qowJoFhVB0fyhCKSpqrlETjVMaq6Jcj+N4EHRaSZqu52t40FJqnqHuBXIjIhAnEYU42VOIwJwP3Gf6eIzHW/+fd3t+e4i+V8IyLzRGSMu/1iEXlHRD4DPhWRFBF5TEQWi8jHIvKeiIwVkWNF5C2/65wgIm96iGeIiEwRkTki8qGIdFTVncAUYLTfoefgjB42JmoscZimLrtGVdUv/fZtUdWDgceBG91ttwGfqepQ4BjgbyKS4+47GBirqkfhTDHeA2choAuA4e4xnwP9RaSd+/wS4JlgAYpIOvCIe+4h7vH3uLsn4iQLRKQT0Bf4LMTfgTEhsaoq09QFq6ryTaU9BycRAJwInCYivkSSBXRzf/5YVbe5P48AXlXVSmCDiHwOoKoqIs8D54vIszgJ5cJ6YuwHDAQ+FhFwVnRb7+6bDDwmIrk4y7a+rqoV9d20MQ1hicOYuu1x/61g7/8VAc5S1SX+B4rIoUCRx/M+C0wCSnCSS33tIQJ8r6rDa+5Q1WIR+QA4A6fkcYPHGIwJm1VVGROaD4HrxP3qLyIH1XHcDOAst62jA3C0b4eqrgPWAbfjbfW1JUA7ERnuXjNdRPb32z8RJ2F0AGaGdjvGhM4Sh2nqarZx3F/P8XcB6cACEfnefR7I6zjTWi8CXgDmAgV++18EVqvqD/UFqKqlOL2l/ioi84FvgcP8DvkY6AS8rDbdtYkBm1bdmCgRkeaqWuiuM/4NcLiqbnD3PQrMU9Wn63jtSiC/nu64XmKYALyrqq815DzG+LMShzHR866IfAtMA+7ySxpzgNtAOk8AAABOSURBVEE4JZG6bMbp1lvnAMD6iMiLwFE4bSnGRIyVOIwxxoTEShzGGGNCYonDGGNMSCxxGGOMCYklDmOMMSGxxGGMMSYkljiMMcaE5P8BEDhmqGftacMAAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# First lets plot the fuel data\n", - "# We will first add the continuous-energy data\n", - "fig = openmc.plot_xs(fuel, ['total'])\n", - "\n", - "# We will now add in the corresponding multi-group data and show the result\n", - "openmc.plot_xs(fuel_mg, ['total'], plot_CE=False, mg_cross_sections='mgxs.h5', axis=fig.axes[0])\n", - "fig.axes[0].legend().set_visible(False)\n", - "plt.show()\n", - "plt.close()\n", - "\n", - "# Then repeat for the zircaloy data\n", - "fig = openmc.plot_xs(zircaloy, ['total'])\n", - "openmc.plot_xs(zircaloy_mg, ['total'], plot_CE=False, mg_cross_sections='mgxs.h5', axis=fig.axes[0])\n", - "fig.axes[0].legend().set_visible(False)\n", - "plt.show()\n", - "plt.close()\n", - "\n", - "# And finally repeat for the water data\n", - "fig = openmc.plot_xs(water, ['total'])\n", - "openmc.plot_xs(water_mg, ['total'], plot_CE=False, mg_cross_sections='mgxs.h5', axis=fig.axes[0])\n", - "fig.axes[0].legend().set_visible(False)\n", - "plt.show()\n", - "plt.close()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "At this point, the problem is set up and we can run the multi-group calculation." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-22 15:04:03\n", - " OpenMP Threads | 8\n", - "\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.16541 +/- 0.00086\n", - " k-effective (Track-length) = 1.16590 +/- 0.00096\n", - " k-effective (Absorption) = 1.16469 +/- 0.00046\n", - " Combined k-effective = 1.16480 +/- 0.00045\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Run the Multi-Group OpenMC Simulation\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Results Comparison\n", - "Now we can compare the multi-group and continuous-energy results.\n", - "\n", - "We will begin by loading the multi-group statepoint file we just finished writing and extracting the calculated keff." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [], - "source": [ - "# Move the StatePoint File\n", - "mg_spfile = './statepoint_mg.h5'\n", - "os.rename('statepoint.' + str(batches) + '.h5', mg_spfile)\n", - "# Move the Summary file\n", - "mg_sumfile = './summary_mg.h5'\n", - "os.rename('summary.h5', mg_sumfile)\n", - "\n", - "# Rename and then load the last statepoint file and keff value\n", - "mgsp = openmc.StatePoint(mg_spfile, autolink=False)\n", - "\n", - "# Load the summary file in its new location\n", - "mgsu = openmc.Summary(mg_sumfile)\n", - "mgsp.link_with_summary(mgsu)\n", - "\n", - "# Get keff\n", - "mg_keff = mgsp.k_combined" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we can load the continuous-energy eigenvalue for comparison." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "ce_keff = sp.k_combined" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Lets compare the two eigenvalues, including their bias" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Continuous-Energy keff = 1.164600+/-0.000677\n", - "Multi-Group keff = 1.164805+/-0.000448\n", - "bias [pcm]: -20.4\n" - ] - } - ], - "source": [ - "bias = 1.0E5 * (ce_keff - mg_keff)\n", - "\n", - "print('Continuous-Energy keff = {0:1.6f}'.format(ce_keff))\n", - "print('Multi-Group keff = {0:1.6f}'.format(mg_keff))\n", - "print('bias [pcm]: {0:1.1f}'.format(bias.nominal_value))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This shows a small but nontrivial pcm bias between the two methods. Some degree of mismatch is expected simply to the very few histories being used in these example problems. An additional mismatch is always inherent in the practical application of multi-group theory due to the high degree of approximations inherent in that method." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Pin Power Visualizations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next we will visualize the pin power results obtained from both the Continuous-Energy and Multi-Group OpenMC calculations.\n", - "\n", - "First, we extract volume-integrated fission rates from the Multi-Group calculation's mesh fission rate tally for each pin cell in the fuel assembly." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "# Get the OpenMC fission rate mesh tally data\n", - "mg_mesh_tally = mgsp.get_tally(name='mesh tally')\n", - "mg_fission_rates = mg_mesh_tally.get_values(scores=['fission'])\n", - "\n", - "# Reshape array to 2D for plotting\n", - "mg_fission_rates.shape = (17,17)\n", - "\n", - "# Normalize to the average pin power\n", - "mg_fission_rates /= np.mean(mg_fission_rates[mg_fission_rates > 0.])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now do the same for the Continuous-Energy results." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "# Get the OpenMC fission rate mesh tally data\n", - "ce_mesh_tally = sp.get_tally(name='mesh tally')\n", - "ce_fission_rates = ce_mesh_tally.get_values(scores=['fission'])\n", - "\n", - "# Reshape array to 2D for plotting\n", - "ce_fission_rates.shape = (17,17)\n", - "\n", - "# Normalize to the average pin power\n", - "ce_fission_rates /= np.mean(ce_fission_rates[ce_fission_rates > 0.])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can easily use Matplotlib to visualize the two fission rates side-by-side." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAADHCAYAAAAeaDj1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAIABJREFUeJztnXm8VWX1/99LZB4EZBIF0USTLCivU1LihEoqaupXE9PUkH7RV79l5ldLycoG9VsYFpEppqllhmJagloOFSYSCE5BCjLIoCgzKLh+f+x95XA45zwP95x777l3f96v133dc/b+7Getvffa6+xpPY+5O0IIIbLDTo3tgBBCiIZFiV8IITKGEr8QQmQMJX4hhMgYSvxCCJExlPiFECJjNKnEb2YvmNmQxvYjy5jZn8zsvDKWH29m36qkT1nDzNzM9ikxv9keJ4q/CuHuZf0BnwOmA2uBN4A/AYMr0O5E4LvlttOYf+k6vJtum9q/WY3tV4TfY4D38vy+vLH92gGf3wH+Dhy2A8v/Fbionn2cn8ZDt7zp/wIc6BfZjgP75MTYDh0nQCvgauAVYB2wOD1uhzb2fiywLxV/9fBX1hm/mX0V+AlwHdAT6Av8DBheTrvNjB+5e4ecv4GVNmBmO1e6TeC3eX7/qB5sVJrfunsHoBvwF+DeRvanEK8BZ9d+MbOPAu0a2Iffkxyjnwe6AHsBY4HPFBLXU3yFUPzVJ2X8wu1C8ut2RglNa5IfhiXp30+A1um8IcAi4GvAcpKrhS+k80aS/HrWni0/mE6fDxyT8wv7O+DXwBrgBaAmx/YHZ0Xp94nknBkBXwTmASuByUDvdHq/dNmdC/0aA/sATwCrgDdJdnax9d/GZt68WjvnAa+nbV2VM38n4ArgP8Bb6bp2zVv2wnTZJ9PpnwcWpPpv1W4voBewHtg1p/1PACuAlkXOXu4MnZkU2xaAAT9O9+tqYDZwwI7sh5x9OAqYS3IWdTNgJc647sz5PiBdvnv6vQvwx3Sd304/75HO+x6wBdhIEm/j0ukfBqamvr0CnJnT/jDgRZLYWwxcFnHMzAe+CTybM+0G4CpyzvjJO/sDzgeezo9tIo6TAj4cA2yoXfeAr98Angc2ATsD+6e+vUNyvJ1cKC5K+PzfwKtprFwP7BSzLxV/lYm/3L9yzvgPA9oAk0porgIOBQYBA4GDSQK/ll4kPyC7kySxm82si7tPAH7D1rPlk4q0fzJwD9CZZKeNi3HczI4Cvg+cCexGkizviVkW+A4whWRH7gH8NHK5YgwG9gOOBq42s/3T6V8BTgGOAHqTBMvNecseQXIwHmdmA0iuts4hWafa7Yq7LyU5YM7MWfZc4B53f68M34tti6HAp4F9Uz/OJPkx2obI/XAicBDwsVR3XMgpM2tF8iP4Fsl2g+SH9DZgT5Ir0w2k8eLuVwFPAaPTeBttZu1JDrq7gB7AWcDP0u0M8CvgYnfvCBwAPB7yK2Ua0MnM9jezFmm7d0Yuuw07cJzkcgzwjLsvitCeTXIV0JkkmT5Isr97kMTnb8xsvx1w+VSghuSkYzhwwQ4sWwjF347H3wfO1JVdgTfdfXMJzTnAte6+3N1XAN8mSTi1vJfOf8/dHyb5tduRQHra3R929y3AHSQ/LjGcA9zq7jPcfRPwv8BhZtYvYtn3SHZeb3ff6O5PB/SXmdk7OX+3583/trtvcPdZwKycdRhFcgWwKPVxDHB63mX3GHdf5+4bgNNJzviedvd3Se7h5nbEdDswAiBNOGeTbLNinJnnd+8d2BbvAR1JzljM3V9y9zcKLB+zH37g7u+4++skl8+DQj6THFRfBE6vjU93f8vd73P39e6+huQs64gSbZ0IzHf329x9s7v/C7gPOCNnHQeYWSd3f9vdZ5RoK587SBLDscBLJGdsDUU3YGntFzPrmu7fVWa2MU97k7svTOPrUKADyf54190fJzlrPZt4fujuK9N9+ZPAsoq/+ou/shL/W0C3wP2/3iS/orUsSKd90EbeD8d6kuCKZWnO5/VAm8j7kdv45e5rSdZn94hlLyc5+/ln+vbEBQBmdqWZrU3/xufob3D3zjl/+W8k5K9D7frvCUyqDXySBLGF5FlKLQvz1umD7+6+nm3Pch4gCZS9SBLOKnf/Z4n1/F2e30tit0WaFMaRXKEsN7MJZtapwPIx+6HY9inqM8k2mgMcWDvDzNqZ2S/MbIGZrQaeBDqnP4KF2BM4JDf5kCSKXun8z5Jcbi8wsyfM7LASfuVzB8lLEeeT3KqsN3Jicq2Z9SXZvrvVzk8TcWeSbdU6b/Ht4svd38+ZtoC4Y6ZQe/m5IB/FX/3FX1mJ/x8k9/5OKaFZQrICtfRNp8VQbreh69n2oVmvnM/b+JVeVu1Kcua1Lp1ccFl3X+ruX3T33sDFJJdf+7j7db71QdSoMn2H5CA5IS/427h77tlh7jZ6g+Ryt3ad2qbrVOv3RpLnBCNIrrpKne1HUWxbpPNucvcDSe517gt8vUATpfZDOX69SXL/e4yZ1Sa5r5FcTR7i7p1IbgVAkjhg+3hbCDyRt/07uPuXUhvPuvtwksvw+0m2bax/C0ge8g4D/lBAso7isbtdcwFbuQ9IXwceAw4ysz1KLVeg7SVAHzPLzRl92bqvYnzuk7dsbC4o7Jzir07xB2UkfndfRXI74WYzOyX9RWtpZieYWe0T+LuBb5pZdzPrlupj72cuA/auq3/ATOBzZtbCzI5n28uqu4EvmNkgM2tN8lbSM+4+35NbUouBEemyFwAfql3QzM7IOWjeJtlhuWdBlWI88D0z2zO1293MSr0t9XvgJDP7ZHqPcQxbg6qWX5OcZZ5MBRJ/sW1hZgeZ2SFm1pIkIWyk8DYquh/K9c3dXwEeITkrhOTSfwPwjpl1Ba7JWyQ/3v4I7Gtm56Zx3TJdr/3NrJWZnWNmu3jyjGR1kfUrxYXAUe6+rsC8mcBp6TG1T6otxg4dJ+4+heSWxf3pPmqV7qdDA4s+Q3IydXm6LYYAJ7H1nniMz183sy5m1ge4BPhtrN+FUPzVPf7Kep3T3W8EvkrywHYFya/UaJJfIIDvkrzj/zzJk/UZ6bQYfkVya+IdM7s/qN6eS0gCs/YS6YM23P1Rkrde7iM5U/4QycOTWr5IcobwFvARkndyazkIeMbM1pI8UL7E3V8t4cfleZfbb0b6PzZtf4qZrSF5KHhIMbG7v0DywO2edJ3WkrzVsClH8zeSAJmRnnWWS7Ft0Qn4JcnBWPuW0fUFfA7th3K5HhhpZj1I7im3JXn7Yxrw5zztWJJnKG+b2U3pfdihqT9LSC75f8jW2yHnAvPTy/ZRJDEWjbv/x92nF5n9Y5I3dZaRPJv5TYmm6nKcnEqSWO4kOT5eI/G/6INLT54bnQScQLINfwZ83t1f3gGfHwCeI/mReCj1vRwUf3WMP3PXQCzNETPrQHJQ93f313KmPw7c5e63NJpzInOYmZPE4rzG9kU0sS4bRGnM7KT0Urs9yfvhs0nex66dfxDJq3RlXWILIZo2SvzNi+FsLZbrD5zl6SWdJa+RPgpcml5GCiEyim71CCFExtAZvxBCZAwlfiGEyBiN0eteELP2nnS/UYqY11YLFevl0TOiUDi/nrEA7buHb5vvFOHzmlW7hI21DEtYH6HZEKFpH6F5J0ITc0fxnQhRy/zShAIEex+aj/ubEQ1VFmvVzWnbr7Qo5ulLqwhNRD1tmy7hIOnA2qBmNR2DmlbhncIWihWxbuXdiJW3iOPMPXzOaxZuZ/PrEclhRVgSR6necQAW4v5WVFyXlfjTwqixQAvgFnf/Qd781iRFQweSvEv7X3HFEV1IXkkvRUzWOiYsOXdwWFN0yIutfOzicB9JbSOy8eMPnRg2VqqOs5aZEZo5EZqaCE3M2+OhmAW4P6K/uJ4Rv3qLQj8gBwWbqJfYbtsPPlns1f2UvwZdy6nPLkFEtcxe/xXu3uVTPBXUPBpxnPWOKNJdE/EDsnBLn6CmVYtNQc2GTeGesNu2Dh+vS78SUTsX1XVkDNv1M5fH0dEt1flWT9rHxM0kBR0DgLNta89xtVwIvO3u+5AUePywrvaEaCgU26K5U849/oOBee7+alrVdw/bD8AynKSKD5IuBY42swa/xBZiB1Fsi2ZNOYl/d7btbW8R299Z/ECT9sK5ipyOw3Ixs5FmNt3Mpm/tJ02IRqFisb1NXL9bsZu9QpRF1bzV4+4T3L3G3WvinigKUf1sE9etuje2O0IA5SX+xWzbzeoebN+d6QcaS/rJ34XwEwohGhvFtmjWlJP4nwX6m9leaTfAZ5H0kJfLZJIxZSEZIepxV6mwqH4U26JZU+fXOd19s5mNJulzugXJEGYvmNm1wHR3n0zS7eodZlY7mHFkl6e92NqNdRFOj3iO1i/C1OlhycGHPBHU/KjgOA/b8h2uDmoO+MyzQc3tH+Sb4lx74LeCmi0Ru/8qvhfUHH7M34Ka95dG3L6bGfGqZlSn1rMD80u/ClxvsW2Ej7hSA/ulDPzHtKBmH8KdYH6La4OajhGFBe0iXlPel1cibIVrBma3+GhQc9Oq0KvgsGF5wUeN2/BA/6FBzW0/PT/czrSI0Slj4np+yOf4dF7We/yejJP7cN60q3M+b2TrGJFCNBkU26I5UzUPd4UQQjQMSvxCCJExlPiFECJjKPELIUTGUOIXQoiMocQvhBAZQ4lfCCEyRlUOxJIQKNDaGNHEpWHRg7t/Jqg58eVwX/t8OFy0+cjCiKKzmPXqH7Z1PeF+y/s/vihs66iwrS0R67WgJtxPzd7TXgtq3r8iohDsnY+Vnv/XtuE26oGW+2yi54NzS2oWPdY/2M7n+XVQ89V7fx7UrP9CUEK7teH9/+PrIuK6b1jCiIjC50lhW0ee+pdwO7uEbQ3/UdjWsIunBDWt7j817M/GiAFdRgT8CdUt5qAzfiGEyBhK/EIIkTGU+IUQImMo8QshRMZQ4hdCiIxRzmDrfczsL2b2opm9YGaXFNAMMbNVZjYz/Qv3SyxEI6PYFs2dcl7n3Ax8zd1nmFlH4Dkzm+ruL+bpnnL3E8uwI0RDo9gWzZo6n/G7+xvuPiP9vAZ4ie0HpBaiyaHYFs2dihRwmVk/4OPAMwVmH2Zms4AlwGXu/kKRNkYCIwFo1xeGlba507h1Qb/m9twnqNmbN4IabowoUOkRoRkVlmzsHda0GRu21T+w/QCmHTUwqDn04xHr9eWwZM+a5UHN2J4XBTVfGXxL2Fi/wPz88/YSlBvbuXHdom945445+htBTUxxFmeEC5QWnxkRR0dH7P8zwxIOiNAcGmErYjCr4/8WHjEv6pgODyxHy8vD29m/E7b10Rv+GdTMOfGg0oLXg018QNkPd82sA3AfcKm7r86bPQPY090HAj8F7i/WjrtPcPcad6+hdbjKU4j6phKxnRvXO3XvWr8OCxFJWYnfzFqSHBi/cfc/5M9399Xuvjb9/DDQ0sy6lWNTiIZAsS2aM+W81WMkA06/5O7/V0TTK9VhZgen9t6qq00hGgLFtmjulHOP/3DgXGC2mc1Mp11J2h2Tu48HTge+ZGabgQ3AWe4e0ROTEI2KYls0a+qc+N39aQJdaLr7OGBcXW0I0RgotkVzR5W7QgiRMZT4hRAiYyjxCyFExqjOEbi6AYFant49lwSb2fvupWFb/xdRyHFUWMKqCM0jYUmbiAGmCNeuwcqw5NAps8KiiIGBmBihuSq8nUdHjCD06IVHBzUPPBeo8mkRtlMfvO87sWZTx5Ka01v/PtzQHRHGIrb3SxHN7Bwx+Nxe+0c0NChCE67xi9KsPLxNUNP16oih7o4IS26y8Hb+7/HhdvbjlaBmwFWlKw+nTop/qUxn/EIIkTGU+IUQImMo8QshRMZQ4hdCiIyhxC+EEBlDiV8IITKGEr8QQmQMJX4hhMgYVVnA1abTOvY57tmSmgc4OdzQ2RGdJd4bUcD1cFjC7Ahbt0TYGhtha1qErcExo4ZVxtb6DmFb7WKKfHqEbe3F98PthGqg3o7wpR7oZKs5tnXpKr6PzHk13NDk8HZaFlFYFLNL9orocPSZCFuHzIkw9mpEXI8K2+o6KqI467HKHEMXxRRcXhy29fvJEaN0nVx6lK4NhAvXaqnECFzzzWy2mc00s+kF5puZ3WRm88zseTP7RLk2hahvFNeiOVOpM/4j3f3NIvNOAPqnf4cAP0//C1HtKK5Fs6Qh7vEPB37tCdOAzma2WwPYFaI+UVyLJkslEr8DU8zsOTMbWWD+7sDCnO+L0mlCVDOKa9FsqcStnsHuvtjMegBTzexld39yRxtJD66RAC379qqAW0KURcXjul3fXSvtoxB1ouwzfndfnP5fDkwCDs6TLAb65HzfI52W384Ed69x95oW3TuX65YQZVEfcd26e+kumYVoKMpK/GbW3sw61n4GhgL5L25NBj6fvgVxKLDK3d8ox64Q9YniWjR3yr3V0xOYZMl7vDsDd7n7n81sFIC7jyd5C34YMA9YD3yhTJtC1DeKa9GsKSvxu/urwMAC08fnfHbgyzvS7sZ32zFnQekhe07c86FgOy9eVqGCqbkRmtFhW7eOC4wMBVzQ4+6wrZjirFFhCb0jNPtGFGddHdFOeNUhYn8tvCFi+Kn5gfmbSs+ur7h2jC2B4b8eP+CwYDtHjQ1vp543hP3pGTGa1ZiI4qwxHw63s81NsWKcFrY16w/9g5qBS8IHbFTR4R+CEtrFDGP2hbCtu28bHtT02eZdgu15nfcinElQlw1CCJExlPiFECJjKPELIUTGUOIXQoiMocQvhBAZQ4lfCCEyhhK/EEJkDCV+IYTIGFU5AtfOrd6jy56lq9/P57ZwQ6eGJbP6RBSELIuo4HotLLng5YjirI+HJRwaoVkVoSldI5fwywhNoCAK4N4+JwY1Z5z1x6DmNfqFjd0QGIHpxYjRl+qBdqxnEDNLao5a+I9wQxEjp607LXxO1/4b7wc1Y2JGGDg6QrMuQrNLWDJwbMSxGLF9Nm8Oa1YODY9o9e+h+wU1g9bNCmpmRhz4f3rmtNKCddcF26hFZ/xCCJExlPiFECJjKPELIUTGUOIXQoiMocQvhBAZo86J38z2M7OZOX+rzezSPM0QM1uVo4npwFeIRkWxLZo7dX6d091fIX0h0MxakAw7N6mA9Cl3D7/LJ0SVoNgWzZ1K3eo5GviPuy+oUHtCVAuKbdHsqFQB11lAseqkw8xsFrAEuMzdXygkMrORwEgA67MHG9a1LWmwT/vSo9EAcHi4UGdgxMhZUTwUURQUY2tyhK3XI2x9PMLW/hG2joqwdXfY1hlDwsVZ/DVs63o+GdSctfs9Jee/3TJ+pCLKjO3cuO7QtzPLQtVFwyI8mh3eTgsiRs4acHiErWlhW1MjbMWE2h4etvVahK29IsZF67QxbOu9zmFbh94QLs7iorCtHz4etvWzQ/5fyfnr20ZUpaWUfcZvZq2Ak4F7C8yeAezp7gOBnwL3F2vH3Se4e42711i3Xct1S4iyqURs58Z12+7t689ZIXaAStzqOQGY4e7L8me4+2p3X5t+fhhoaWbdKmBTiIZAsS2aJZVI/GdT5FLYzHqZJddmZnZwau+tCtgUoiFQbItmSVn3+M2sPXAscHHOtFEA7j4eOB34kpltBjYAZ7lH3MgTopFRbIvmTFmJ393XAbvmTRuf83kcMK4cG0I0Bopt0ZxR5a4QQmQMJX4hhMgYSvxCCJExqnIELjOnxc5bSmq2xLh+c7goYsW4DkHNGsKavW8M23pi3MFBzRE1/wxq5kYUsfR/ICiB2RGaayMKwa6MaOeMCM3CsK1WfT4R1Kx4rG9pwZpWEc5UnjZsYj/+XVKzYnY41rp/LqI46+mwP7MOjxh97rKwrWOnhW1FxdpVEcVZMT0ixdQx7R+21fLFiHZejtBcF7Z1/pU/C2oO5LmS85/baX2EMwk64xdCiIyhxC+EEBlDiV8IITKGEr8QQmQMJX4hhMgYSvxCCJExlPiFECJjKPELIUTGqMoCro62hqNbP1pSsx+vhBvqGpZ0XrU27M/OYQ0rw5Ij5oaLs1acHy7g6f9whD+bwhLahCVznwhr+g8Na8ZdeWFQM/q6XwU1D155crido39Ucv5vOy4NtlEfdGQNn+LJkpol7BZsp/u/5oaNRUgGvh4hihkR7tMRmpiRxZ6J0GyM0KyL0MQcHzHFWb0rozmcvwc1b1F6uIcWlC56zSXqjN/MbjWz5WY2J2daVzObamZz0/9diix7XqqZa2bnRXsmRD2juBZZJfZWz0Tg+LxpVwCPuXt/4LH0+zaYWVfgGuAQ4GDgmmIHkhCNwEQU1yKDRCV+d3+S7W9mDAduTz/fDpxSYNHjgKnuvtLd3wamsv2BJkSjoLgWWaWch7s93f2N9PNSoGcBze7Awpzvi9JpQlQrimvR7KnIWz3pkHNlDTtnZiPNbLqZTd+0YnUl3BKiLCod12+viH/4JkR9Uk7iX2ZmuwGk/5cX0CwG+uR83yOdth3uPsHda9y9pnX3TmW4JURZ1Ftcd+neouLOClEXykn8k4HatxnOAwr1AP8IMNTMuqQPv4am04SoVhTXotkT+zrn3cA/gP3MbJGZXQj8ADjWzOYCx6TfMbMaM7sFwN1XAt8Bnk3/rk2nCdHoKK5FVrHkNmZ10a5mf993+m0lNdPWHRZsp037iHW7JmKEqZgRhh6JsDUxwlb7CFtnhG2tbhO21Smi8IrJYVt3RowINiKm0GVx2NatfC6oufCRu0oLvlKD/3t6xM6oLLvW9PNh068qqbnjMyPDDT0UEWvHRaze/mEJPwnb8l3DtixmlLavRazXyRXabRFxzeAIW6MibI2I2IYrI47X1oXuOm5l/aeOZcuMmVEbSF02CCFExlDiF0KIjKHEL4QQGUOJXwghMoYSvxBCZAwlfiGEyBhK/EIIkTGU+IUQImNU5QhcGxa1Z9bXDy2pueT6nwTb+cXnImoZXo9waK8ITUSxx8YKFfW3uTFsa/3GXYKaTlNWhY1FbMMRj4Wb8TPCmvWbwn3ZXNU6YtSoeYH5MaM41QPraM8zHFxSc+dDnw22MyJinzw3JezPgT3CGvaNKM46LaKdwRGaSWFbCyZ3D2p6r1oR1LS8NCI3nBqWsCRC842wrfE/DI/lM4AXS86fs9OGCGcSdMYvhBAZQ4lfCCEyhhK/EEJkDCV+IYTIGEr8QgiRMYKJ38xuNbPlZjYnZ9r1ZvaymT1vZpPMrHORZeeb2Wwzm2lm0yvpuBDlotgWWSXmjH8icHzetKnAAe7+MeDfwP+WWP5Idx/k7jV1c1GIemMiim2RQYKJ392fBFbmTZvi7pvTr9NIxhwVokmh2BZZpRIFXBcAvy0yz4EpZubAL9x9QrFGzGwkkAw/1KEvrC1t9Nerzg06dvpdvw9qjuWpoGZMxAhT4fILWN2+f1Czho5BzeCVM4KaXk9EFGf1DUuIqJfi6rDE3gqPQtT+mfB2Xrpx77CxewLz3w43kVJ2bG8T1237MvekgSUNbnkwYkD2Q8KSA+8Kb++fR8T1qK5hWzFDPm08IKxp872w5t1TWwc1LUsPVJUQU0y5a4Tm6fB2foDjgppL3ropqHnv/k6lBW+Gc0ctZSV+M7sK2Az8pohksLsvNrMewFQzezk9y9qO9MCZAGA9aqpvPEiRKSoV29vEdWfFtagO6vxWj5mdD5wInONFBu5198Xp/+XAJAjUqwtRBSi2RXOnTonfzI4HLgdOdvf1RTTtzaxj7WdgKDCnkFaIakGxLbJAzOucdwP/APYzs0VmdiEwDuhIcok708zGp9reZvZwumhP4GkzmwX8E3jI3f9cL2shRB1QbIusErzH7+5nF5j8qyLaJcCw9POrQOknWUI0IoptkVVUuSuEEBlDiV8IITKGEr8QQmSMqhyBiw3Ay6UlG28JV5acNuoPQc2aiFF/xgwLSuChiFe0r40odYkp/v9ehK0nImz9K8LWsxG2bomwNTas+Z9Lrgu38+2whG6B+Y0V9W2BQCHT+UcWqxfbyry/fCio+c7M8Pb+0lFBCTxWmbhuMyrC1uSwrf4fj4i18RG2XqrMeq2LGDXu663DBZfvDQkUZwEMCcwv+A5aYXTGL4QQGUOJXwghMoYSvxBCZAwlfiGEyBhK/EIIkTGU+IUQImMo8QshRMZQ4hdCiIxhRbobb1TMDnD4XWnRoQPCDW0MSz7xr6eDmiP5a1Dz3XXfCmomtR8e1CynZ1BzDI8GNT/giqBmC+Hik4v5RVBzB+HR0H518+ighjfDEiZGaOaHRN/G/bWYgaMqirWucXoHxmWfHzHk2aXhkdxiCgGfOufAoGbw2HDx0auX9Apq/s7hQc2Iv90X1Hz/8EuDmou4Jahptylc7XRD68uCmjGLIyoK728T1kQcHjAmMH8C7kui4jqmW+ZbzWy5mc3JmTbGzBan3dbONLOCta1mdryZvWJm88wsnImEaEAU2yKrxNzqmQgcX2D6j919UPr3cP5MM2sB3AycAAwAzjaziNN0IRqMiSi2RQYJJv50HNGVdWj7YGCeu7/q7u+SDIEdvtchRAOh2BZZpZyHu6PN7Pn0crlLgfm7Awtzvi9KpxXEzEaa2XQzm163Y1GIilGx2N4mrresqA9fhdhh6pr4fw58CBgEvAHcWK4j7j7B3WvcvQbCPW8KUU9UNLa3iesW3SvhnxBlU6fE7+7L3H2Lu78P/JLk0jefxUCfnO97pNOEqFoU2yIL1Cnxm9luOV9PBeYUkD0L9DezvcysFXAWMLku9oRoKBTbIgsEh6Qws7tJhgDoZmaLgGuAIWY2CHBgPnBxqu0N3OLuw9x9s5mNBh4BWgC3uvsL9bIWQtQBxbbIKlVawNXH4X8CqnMiWlodlpwSUQzz3bDkxI/cG9T88b4zgppen301qFm+LFzk1bvnkqCmH/ODmqcfODaoiagng5kRmrUx7SyLEIWKoC7C/eWGL+Cy3g4jA6qvhhsaFDFa0w1hyYijfxnUxBRDzadfULOMHkHNBtoFNX/nk0HNd/lmUHNNxFBur7BfUDOMh4KaccdeHtQwLSwhVCe3sAbfOL0yBVxCCCGaF0r8QgiRMZT4hRAiYyjxCyFExlDiF0KIjKGAbNW4AAAC40lEQVTEL4QQGUOJXwghMoYSvxBCZIwqLeCyFcCCnEndiBufqZqQz/VPXf3d090bvMe0AnEN2dnmjUlWfI6O66pM/PmY2fSk186mg3yuf5qav4VoauvQ1PwF+VwI3eoRQoiMocQvhBAZo6kk/gmN7UAdkM/1T1PztxBNbR2amr8gn7ejSdzjF0IIUTmayhm/EEKIClH1id/MjjezV8xsnpld0dj+hDCz+WY228xmJgPHVx/pIOLLzWxOzrSuZjbVzOam/wsNMt5oFPF5jJktTrf1TDMb1pg+7ghNLa5BsV1fNEZsV3XiN7MWwM3ACcAA4GwzG9C4XkVxpLsPquJXyCYCx+dNuwJ4zN37A4+l36uJiWzvM8CP0209yN0fbmCf6kQTjmtQbNcHE2ng2K7qxE8y0PU8d3/V3d8F7gGGN7JPTR53fxJYmTd5OHB7+vl24JQGdSpAEZ+bKorrekKxHUe1J/7dgYU53xel06oZB6aY2XNmFhpnr5ro6e5vpJ+XAuHxHauD0Wb2fHq5XFWX8CVoinENiu2Gpt5iu9oTf1NksLt/guQy/stm9unGdmhH8eRVr6bwutfPgQ8Bg4A3gBsb151mj2K74ajX2K72xL8Y6JPzfY90WtXi7ovT/8uBSSSX9U2BZWa2G0D6f3kj+xPE3Ze5+xZ3fx/4JU1nWze5uAbFdkNS37Fd7Yn/WaC/me1lZq2As4DJjexTUcysvZl1rP0MDAXmlF6qapgMnJd+Pg94oBF9iaL2YE45laazrZtUXINiu6Gp79jeuZKNVRp332xmo4FHgBbAre7+QiO7VYqewCQzg2Tb3uXuf25cl7bHzO4GhgDdzGwRcA3wA+B3ZnYhSQ+SZzaeh9tTxOchZjaI5NJ9PnBxozm4AzTBuAbFdr3RGLGtyl0hhMgY1X6rRwghRIVR4hdCiIyhxC+EEBlDiV8IITKGEr8QQmQMJX4hhMgYSvxCCJExlPiFECJj/H9ylB0qVZDZzAAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Force zeros to be NaNs so their values are not included when matplotlib calculates\n", - "# the color scale\n", - "ce_fission_rates[ce_fission_rates == 0.] = np.nan\n", - "mg_fission_rates[mg_fission_rates == 0.] = np.nan\n", - "\n", - "# Plot the CE fission rates in the left subplot\n", - "fig = plt.subplot(121)\n", - "plt.imshow(ce_fission_rates, interpolation='none', cmap='jet')\n", - "plt.title('Continuous-Energy Fission Rates')\n", - "\n", - "# Plot the MG fission rates in the right subplot\n", - "fig2 = plt.subplot(122)\n", - "plt.imshow(mg_fission_rates, interpolation='none', cmap='jet')\n", - "plt.title('Multi-Group Fission Rates')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "These figures really indicate that more histories are probably necessary when trying to achieve a fully converged solution, but hey, this is good enough for our example!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Scattering Anisotropy Treatments\n", - "\n", - "We will next show how we can work with the scattering angular distributions. OpenMC's MG solver has the capability to use group-to-group angular distributions which are represented as any of the following: a truncated Legendre series of up to the 10th order, a histogram distribution, and a tabular distribution. Any combination of these representations can be used by OpenMC during the transport process, so long as all constituents of a given material use the same representation. This means it is possible to have water represented by a tabular distribution and fuel represented by a Legendre if so desired.\n", - "\n", - "*Note*: To have the highest runtime performance OpenMC natively converts Legendre series to a tabular distribution before the transport begins. This default functionality can be turned off with the `tabular_legendre` element of the `settings.xml` file (or for the Python API, the `openmc.Settings.tabular_legendre` attribute).\n", - "\n", - "This section will examine the following:\n", - "- Re-run the MG-mode calculation with P0 scattering everywhere using the `openmc.Settings.max_order` attribute\n", - "- Re-run the problem with only the water represented with P3 scattering and P0 scattering for the remaining materials using the Python API's ability to convert between formats." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "### Global P0 Scattering\n", - "First we begin by re-running with P0 scattering (i.e., isotropic) everywhere. If a global maximum order is requested, the most effective way to do this is to use the `max_order` attribute of our `openmc.Settings` object." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "# Set the maximum scattering order to 0 (i.e., isotropic scattering)\n", - "settings_file.max_order = 0\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can re-run OpenMC to obtain our results" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-22 15:04:39\n", - " OpenMP Threads | 8\n", - "\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.16379 +/- 0.00090\n", - " k-effective (Track-length) = 1.16469 +/- 0.00101\n", - " k-effective (Absorption) = 1.16315 +/- 0.00052\n", - " Combined k-effective = 1.16335 +/- 0.00050\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Run the Multi-Group OpenMC Simulation\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And then get the eigenvalue differences from the Continuous-Energy and P3 MG solution" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "P3 bias [pcm]: -20.4\n", - "P0 bias [pcm]: 125.1\n" - ] - } - ], - "source": [ - "# Move the statepoint File\n", - "mgp0_spfile = './statepoint_mg_p0.h5'\n", - "os.rename('statepoint.' + str(batches) + '.h5', mgp0_spfile)\n", - "# Move the Summary file\n", - "mgp0_sumfile = './summary_mg_p0.h5'\n", - "os.rename('summary.h5', mgp0_sumfile)\n", - "\n", - "# Load the last statepoint file and keff value\n", - "mgsp_p0 = openmc.StatePoint(mgp0_spfile, autolink=False)\n", - "\n", - "# Get keff\n", - "mg_p0_keff = mgsp_p0.k_combined\n", - "\n", - "bias_p0 = 1.0E5 * (ce_keff - mg_p0_keff)\n", - "\n", - "print('P3 bias [pcm]: {0:1.1f}'.format(bias.nominal_value))\n", - "print('P0 bias [pcm]: {0:1.1f}'.format(bias_p0.nominal_value))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Mixed Scattering Representations\n", - "OpenMC's Multi-Group mode also includes a feature where not every data in the library is required to have the same scattering treatment. For example, we could represent the water with P3 scattering, and the fuel and cladding with P0 scattering. This series will show how this can be done.\n", - "\n", - "First we will convert the data to P0 scattering, unless its water, then we will leave that as P3 data." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [], - "source": [ - "# Convert the zircaloy and fuel data to P0 scattering\n", - "for i, xsdata in enumerate(mgxs_file.xsdatas):\n", - " if xsdata.name != 'water':\n", - " mgxs_file.xsdatas[i] = xsdata.convert_scatter_format('legendre', 0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also use whatever scattering format that we want for the materials in the library. As an example, we will take this P0 data and convert zircaloy to a histogram anisotropic scattering format and the fuel to a tabular anisotropic scattering format" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [], - "source": [ - "# Convert the formats as discussed\n", - "for i, xsdata in enumerate(mgxs_file.xsdatas):\n", - " if xsdata.name == 'zircaloy':\n", - " mgxs_file.xsdatas[i] = xsdata.convert_scatter_format('histogram', 2)\n", - " elif xsdata.name == 'fuel':\n", - " mgxs_file.xsdatas[i] = xsdata.convert_scatter_format('tabular', 2)\n", - " \n", - "mgxs_file.export_to_hdf5('mgxs.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally we will re-set our `max_order` parameter of our `openmc.Settings` object to our maximum order so that OpenMC will use whatever scattering data is available in the library.\n", - "\n", - "After we do this we can re-run the simulation." - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-22 15:05:16\n", - " OpenMP Threads | 8\n", - "\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.16471 +/- 0.00093\n", - " k-effective (Track-length) = 1.16412 +/- 0.00106\n", - " k-effective (Absorption) = 1.16449 +/- 0.00050\n", - " Combined k-effective = 1.16441 +/- 0.00049\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "settings_file.max_order = None\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()\n", - "\n", - "# Run the Multi-Group OpenMC Simulation\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For a final step we can again obtain the eigenvalue differences from this case and compare with the same from the P3 MG solution" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "P3 bias [pcm]: -20.4\n", - "Mixed Scattering bias [pcm]: 19.5\n" - ] - } - ], - "source": [ - "# Load the last statepoint file and keff value\n", - "mgsp_mixed = openmc.StatePoint('./statepoint.' + str(batches) + '.h5')\n", - "\n", - "mg_mixed_keff = mgsp_mixed.k_combined\n", - "bias_mixed = 1.0E5 * (ce_keff - mg_mixed_keff)\n", - "\n", - "print('P3 bias [pcm]: {0:1.1f}'.format(bias.nominal_value))\n", - "print('Mixed Scattering bias [pcm]: {0:1.1f}'.format(bias_mixed.nominal_value))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "Our tests in this section showed the flexibility of data formatting within OpenMC's multi-group mode: every material can be represented with its own format with the approximations that make the most sense. Now, as you'll see above, the runtimes from our P3, P0, and mixed cases are not significantly different and therefore this might not be a useful strategy for multi-group Monte Carlo. However, this capability provides a useful benchmark for the accuracy hit one may expect due to these scattering approximations before implementing this generality in a deterministic solver where the runtime savings are more significant.\n", - "\n", - "**NOTE**: The biases obtained above with P3, P0, and mixed representations do not necessarily reflect the inherent accuracies of the options. These cases were *not* run with a sufficient number of histories to truly differentiate methods improvement from statistical noise." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/mg-mode-part-iii.ipynb b/examples/jupyter/mg-mode-part-iii.ipynb deleted file mode 100644 index ea1e773f8df..00000000000 --- a/examples/jupyter/mg-mode-part-iii.ipynb +++ /dev/null @@ -1,1426 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multigroup Mode Part III: Advanced Feature Showcase\n", - "This Notebook illustrates the use of the the more advanced features of OpenMC's multi-group mode and the openmc.mgxs.Library class. During this process, this notebook will illustrate the following features:\n", - "\n", - " - Calculation of multi-group cross sections for a simplified BWR 8x8 assembly with isotropic and angle-dependent MGXS.\n", - " - Automated creation and storage of MGXS with openmc.mgxs.Library\n", - " - Fission rate comparison between continuous-energy and the two multi-group OpenMC cases.\n", - "\n", - "To avoid focusing on unimportant details, the BWR assembly in this notebook is greatly simplified. The descriptions which follow will point out some areas of simplification." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import openmc\n", - "\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will be running a rodded 8x8 assembly with Gadolinia fuel pins. Let's start by creating the materials that we will use later.\n", - "\n", - "Material Definition Simplifications:\n", - "\n", - "- This model will be run at room temperature so the NNDC ENDF-B/VII.1 data set can be used but the water density will be representative of a module with around 20% voiding. This water density will be non-physically used in all regions of the problem.\n", - "- Steel is composed of more than just iron, but we will only treat it as such here." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "materials = {}\n", - "\n", - "# Fuel\n", - "materials['Fuel'] = openmc.Material(name='Fuel')\n", - "materials['Fuel'].set_density('g/cm3', 10.32)\n", - "materials['Fuel'].add_element('O', 2)\n", - "materials['Fuel'].add_element('U', 1, enrichment=3.)\n", - "\n", - "# Gadolinia bearing fuel\n", - "materials['Gad'] = openmc.Material(name='Gad')\n", - "materials['Gad'].set_density('g/cm3', 10.23)\n", - "materials['Gad'].add_element('O', 2)\n", - "materials['Gad'].add_element('U', 1, enrichment=3.)\n", - "materials['Gad'].add_element('Gd', .02)\n", - "\n", - "# Zircaloy\n", - "materials['Zirc2'] = openmc.Material(name='Zirc2')\n", - "materials['Zirc2'].set_density('g/cm3', 6.55)\n", - "materials['Zirc2'].add_element('Zr', 1)\n", - "\n", - "# Boiling Water\n", - "materials['Water'] = openmc.Material(name='Water')\n", - "materials['Water'].set_density('g/cm3', 0.6)\n", - "materials['Water'].add_element('H', 2)\n", - "materials['Water'].add_element('O', 1)\n", - "\n", - "# Boron Carbide for the Control Rods\n", - "materials['B4C'] = openmc.Material(name='B4C')\n", - "materials['B4C'].set_density('g/cm3', 0.7 * 2.52)\n", - "materials['B4C'].add_element('B', 4)\n", - "materials['B4C'].add_element('C', 1)\n", - "\n", - "# Steel \n", - "materials['Steel'] = openmc.Material(name='Steel')\n", - "materials['Steel'].set_density('g/cm3', 7.75)\n", - "materials['Steel'].add_element('Fe', 1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now create a Materials object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Materials object\n", - "materials_file = openmc.Materials(materials.values())\n", - "\n", - "# Export to \"materials.xml\"\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. The first step is to define some constants which will be used to set our dimensions and then we can start creating the surfaces and regions for the problem, the 8x8 lattice, the rods and the control blade.\n", - "\n", - "Before proceeding let's discuss some simplifications made to the problem geometry:\n", - "- To enable the use of an equal-width mesh for running the multi-group calculations, the intra-assembly gap was increased to the same size as the pitch of the 8x8 fuel lattice\n", - "- The can is neglected\n", - "- The pin-in-water geometry for the control blade is ignored and instead the blade is a solid block of B4C\n", - "- Rounded corners are ignored\n", - "- There is no cladding for the water rod" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Set constants for the problem and assembly dimensions\n", - "fuel_rad = 0.53213\n", - "clad_rad = 0.61341\n", - "Np = 8\n", - "pin_pitch = 1.6256\n", - "length = float(Np + 2) * pin_pitch\n", - "assembly_width = length - 2. * pin_pitch\n", - "rod_thick = 0.47752 / 2. + 0.14224\n", - "rod_span = 7. * pin_pitch\n", - "\n", - "surfaces = {}\n", - "\n", - "# Create boundary planes to surround the geometry\n", - "surfaces['Global x-'] = openmc.XPlane(0., boundary_type='reflective')\n", - "surfaces['Global x+'] = openmc.XPlane(length, boundary_type='reflective')\n", - "surfaces['Global y-'] = openmc.YPlane(0., boundary_type='reflective')\n", - "surfaces['Global y+'] = openmc.YPlane(length, boundary_type='reflective')\n", - "\n", - "# Create cylinders for the fuel and clad\n", - "surfaces['Fuel Radius'] = openmc.ZCylinder(r=fuel_rad)\n", - "surfaces['Clad Radius'] = openmc.ZCylinder(r=clad_rad)\n", - "\n", - "surfaces['Assembly x-'] = openmc.XPlane(pin_pitch)\n", - "surfaces['Assembly x+'] = openmc.XPlane(length - pin_pitch)\n", - "surfaces['Assembly y-'] = openmc.YPlane(pin_pitch)\n", - "surfaces['Assembly y+'] = openmc.YPlane(length - pin_pitch)\n", - "\n", - "# Set surfaces for the control blades\n", - "surfaces['Top Blade y-'] = openmc.YPlane(length - rod_thick)\n", - "surfaces['Top Blade x-'] = openmc.XPlane(pin_pitch)\n", - "surfaces['Top Blade x+'] = openmc.XPlane(rod_span)\n", - "surfaces['Left Blade x+'] = openmc.XPlane(rod_thick)\n", - "surfaces['Left Blade y-'] = openmc.YPlane(length - rod_span)\n", - "surfaces['Left Blade y+'] = openmc.YPlane(9. * pin_pitch)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now construct regions with these surfaces before we use those to create cells" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Set regions for geometry building\n", - "regions = {}\n", - "regions['Global'] = \\\n", - " (+surfaces['Global x-'] & -surfaces['Global x+'] &\n", - " +surfaces['Global y-'] & -surfaces['Global y+'])\n", - "regions['Assembly'] = \\\n", - " (+surfaces['Assembly x-'] & -surfaces['Assembly x+'] &\n", - " +surfaces['Assembly y-'] & -surfaces['Assembly y+'])\n", - "regions['Fuel'] = -surfaces['Fuel Radius']\n", - "regions['Clad'] = +surfaces['Fuel Radius'] & -surfaces['Clad Radius']\n", - "regions['Water'] = +surfaces['Clad Radius']\n", - "regions['Top Blade'] = \\\n", - " (+surfaces['Top Blade y-'] & -surfaces['Global y+']) & \\\n", - " (+surfaces['Top Blade x-'] & -surfaces['Top Blade x+'])\n", - "regions['Top Steel'] = \\\n", - " (+surfaces['Global x-'] & -surfaces['Top Blade x-']) & \\\n", - " (+surfaces['Top Blade y-'] & -surfaces['Global y+'])\n", - "regions['Left Blade'] = \\\n", - " (+surfaces['Left Blade y-'] & -surfaces['Left Blade y+']) & \\\n", - " (+surfaces['Global x-'] & -surfaces['Left Blade x+'])\n", - "regions['Left Steel'] = \\\n", - " (+surfaces['Left Blade y+'] & -surfaces['Top Blade y-']) & \\\n", - " (+surfaces['Global x-'] & -surfaces['Left Blade x+'])\n", - "regions['Corner Blade'] = \\\n", - " regions['Left Steel'] | regions['Top Steel']\n", - "regions['Water Fill'] = \\\n", - " regions['Global'] & ~regions['Assembly'] & \\\n", - " ~regions['Top Blade'] & ~regions['Left Blade'] &\\\n", - " ~regions['Corner Blade']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will begin building the 8x8 assembly. To do that we will have to build the cells and universe for each pin type (fuel, gadolinia-fuel, and water)." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "universes = {}\n", - "cells = {}\n", - "\n", - "for name, mat, in zip(['Fuel Pin', 'Gd Pin'],\n", - " [materials['Fuel'], materials['Gad']]):\n", - " universes[name] = openmc.Universe(name=name)\n", - " cells[name] = openmc.Cell(name=name)\n", - " cells[name].fill = mat\n", - " cells[name].region = regions['Fuel']\n", - " universes[name].add_cell(cells[name])\n", - " \n", - " cells[name + ' Clad'] = openmc.Cell(name=name + ' Clad')\n", - " cells[name + ' Clad'].fill = materials['Zirc2']\n", - " cells[name + ' Clad'].region = regions['Clad']\n", - " universes[name].add_cell(cells[name + ' Clad'])\n", - " \n", - " cells[name + ' Water'] = openmc.Cell(name=name + ' Water')\n", - " cells[name + ' Water'].fill = materials['Water']\n", - " cells[name + ' Water'].region = regions['Water']\n", - " universes[name].add_cell(cells[name + ' Water'])\n", - "\n", - "universes['Hole'] = openmc.Universe(name='Hole')\n", - "cells['Hole'] = openmc.Cell(name='Hole')\n", - "cells['Hole'].fill = materials['Water']\n", - "universes['Hole'].add_cell(cells['Hole'])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's use this pin information to create our 8x8 assembly." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create fuel assembly Lattice\n", - "universes['Assembly'] = openmc.RectLattice(name='Assembly')\n", - "universes['Assembly'].pitch = (pin_pitch, pin_pitch)\n", - "universes['Assembly'].lower_left = [pin_pitch, pin_pitch]\n", - "\n", - "f = universes['Fuel Pin']\n", - "g = universes['Gd Pin']\n", - "h = universes['Hole']\n", - "\n", - "lattices = [[f, f, f, f, f, f, f, f],\n", - " [f, f, f, f, f, f, f, f],\n", - " [f, f, f, g, f, g, f, f],\n", - " [f, f, g, h, h, f, g, f],\n", - " [f, f, f, h, h, f, f, f],\n", - " [f, f, g, f, f, f, g, f],\n", - " [f, f, f, g, f, g, f, f],\n", - " [f, f, f, f, f, f, f, f]]\n", - "\n", - "# Store the array of lattice universes\n", - "universes['Assembly'].universes = lattices\n", - "\n", - "cells['Assembly'] = openmc.Cell(name='Assembly')\n", - "cells['Assembly'].fill = universes['Assembly']\n", - "cells['Assembly'].region = regions['Assembly']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "So far we have the rods and water within the assembly , but we still need the control blade and the water which fills the rest of the space. We will create those cells now" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# The top portion of the blade, poisoned with B4C\n", - "cells['Top Blade'] = openmc.Cell(name='Top Blade')\n", - "cells['Top Blade'].fill = materials['B4C']\n", - "cells['Top Blade'].region = regions['Top Blade']\n", - "\n", - "# The left portion of the blade, poisoned with B4C\n", - "cells['Left Blade'] = openmc.Cell(name='Left Blade')\n", - "cells['Left Blade'].fill = materials['B4C']\n", - "cells['Left Blade'].region = regions['Left Blade']\n", - "\n", - "# The top-left corner portion of the blade, with no poison\n", - "cells['Corner Blade'] = openmc.Cell(name='Corner Blade')\n", - "cells['Corner Blade'].fill = materials['Steel']\n", - "cells['Corner Blade'].region = regions['Corner Blade']\n", - "\n", - "# Water surrounding all other cells and our assembly\n", - "cells['Water Fill'] = openmc.Cell(name='Water Fill')\n", - "cells['Water Fill'].fill = materials['Water']\n", - "cells['Water Fill'].region = regions['Water Fill']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC requires that there is a \"root\" universe. Let us create our root universe and fill it with the cells just defined." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Create root Universe\n", - "universes['Root'] = openmc.Universe(name='root universe', universe_id=0)\n", - "universes['Root'].add_cells([cells['Assembly'], cells['Top Blade'],\n", - " cells['Corner Blade'], cells['Left Blade'],\n", - " cells['Water Fill']])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "What do you do after you create your model? Check it! We will use the plotting capabilities of the Python API to do this for us.\n", - "\n", - "When doing so, we will coloring by material with fuel being red, gadolinia-fuel as yellow, zirc cladding as a light grey, water as blue, B4C as black and steel as a darker gray." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "universes['Root'].plot(origin=(length / 2., length / 2., 0.),\n", - " pixels=(500, 500), width=(length, length),\n", - " color_by='material',\n", - " colors={materials['Fuel']: (1., 0., 0.),\n", - " materials['Gad']: (1., 1., 0.),\n", - " materials['Zirc2']: (0.5, 0.5, 0.5),\n", - " materials['Water']: (0.0, 0.0, 1.0),\n", - " materials['B4C']: (0.0, 0.0, 0.0),\n", - " materials['Steel']: (0.4, 0.4, 0.4)})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looks pretty good to us!\n", - "\n", - "We now must create a geometry that is assigned a root universe and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and set root universe\n", - "geometry = openmc.Geometry(universes['Root'])\n", - "\n", - "# Export to \"geometry.xml\"\n", - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the geometry and materials finished, we now just need to define simulation parameters, including how to run the model and what we want to learn from the model (i.e., define the tallies). We will start with our simulation parameters in the next block.\n", - "\n", - "This will include setting the run strategy, telling OpenMC not to bother creating a `tallies.out` file, and limiting the verbosity of our output to just the header and results to not clog up our notebook with results from each batch." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "batches = 1000\n", - "inactive = 20\n", - "particles = 1000\n", - "\n", - "# Instantiate a Settings object\n", - "settings_file = openmc.Settings()\n", - "settings_file.batches = batches\n", - "settings_file.inactive = inactive\n", - "settings_file.particles = particles\n", - "settings_file.output = {'tallies': False}\n", - "settings_file.verbosity = 4\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [pin_pitch, pin_pitch, 10, length - pin_pitch, length - pin_pitch, 10]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings_file.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create an MGXS Library\n", - "\n", - "Now we are ready to generate multi-group cross sections! First, let's define a 2-group structure using the built-in EnergyGroups class." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a 2-group EnergyGroups object\n", - "groups = openmc.mgxs.EnergyGroups()\n", - "groups.group_edges = np.array([0., 0.625, 20.0e6])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will instantiate an openmc.mgxs.Library for the energy groups with our the problem geometry. This library will use the default setting of isotropically-weighting the multi-group cross sections." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "# Initialize a 2-group Isotropic MGXS Library for OpenMC\n", - "iso_mgxs_lib = openmc.mgxs.Library(geometry)\n", - "iso_mgxs_lib.energy_groups = groups" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we must specify to the Library which types of cross sections to compute. OpenMC's multi-group mode can accept isotropic flux-weighted cross sections or angle-dependent cross sections, as well as supporting anisotropic scattering represented by either Legendre polynomials, histogram, or tabular angular distributions. \n", - "\n", - "Just like before, we will create the following multi-group cross sections needed to run an OpenMC simulation to verify the accuracy of our cross sections: \"total\", \"absorption\", \"nu-fission\", '\"fission\", \"nu-scatter matrix\", \"multiplicity matrix\", and \"chi\".\n", - "\"multiplicity matrix\" is needed to provide OpenMC's multi-group mode with additional information needed to accurately treat scattering multiplication (i.e., (n,xn) reactions)) explicitly." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Specify multi-group cross section types to compute\n", - "iso_mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission',\n", - " 'nu-scatter matrix', 'multiplicity matrix', 'chi']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we must specify the type of domain over which we would like the `Library` to compute multi-group cross sections. The domain type corresponds to the type of tally filter to be used in the tallies created to compute multi-group cross sections. At the present time, the `Library` supports \"material\" \"cell\", \"universe\", and \"mesh\" domain types. \n", - "\n", - "For the sake of example we will use a mesh to gather our cross sections. This mesh will be set up so there is one mesh bin for every pin cell." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a tally Mesh\n", - "mesh = openmc.RegularMesh()\n", - "mesh.dimension = [10, 10]\n", - "mesh.lower_left = [0., 0.]\n", - "mesh.upper_right = [length, length]\n", - "\n", - "# Specify a \"mesh\" domain type for the cross section tally filters\n", - "iso_mgxs_lib.domain_type = \"mesh\"\n", - "\n", - "# Specify the mesh over which to compute multi-group cross sections\n", - "iso_mgxs_lib.domains = [mesh]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we will set the scattering treatment that we wish to use.\n", - "\n", - "In the [mg-mode-part-ii](mg-mode-part-ii.html) notebook, the cross sections were generated with a typical P3 scattering expansion in mind. Now, however, we will use a more advanced technique: OpenMC will directly provide us a histogram of the change-in-angle (i.e., $\\mu$) distribution.\n", - "\n", - "Where as in the [mg-mode-part-ii](mg-mode-part-ii.html) notebook, all that was required was to set the `legendre_order` attribute of `mgxs_lib`, here we have only slightly more work: we have to tell the Library that we want to use a histogram distribution (as it is not the default), and then tell it the number of bins.\n", - "\n", - "For this problem we will use 11 bins." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# Set the scattering format to histogram and then define the number of bins\n", - "\n", - "# Avoid a warning that corrections don't make sense with histogram data\n", - "iso_mgxs_lib.correction = None\n", - "# Set the histogram data\n", - "iso_mgxs_lib.scatter_format = 'histogram'\n", - "iso_mgxs_lib.histogram_bins = 11" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Ok, we made our isotropic library with histogram-scattering!\n", - "\n", - "Now why don't we go ahead and create a library to do the same, but with angle-dependent MGXS. That is, we will avoid making the isotropic flux weighting approximation and instead just store a cross section for every polar and azimuthal angle pair.\n", - "\n", - "To do this with the Python API and OpenMC, all we have to do is set the number of polar and azimuthal bins. Here we only need to set the number of bins, the API will convert all of angular space into equal-width bins for us.\n", - "\n", - "Since this problem is symmetric in the z-direction, we only need to concern ourselves with the azimuthal variation here. We will use eight angles.\n", - "\n", - "Ok, we will repeat all the above steps for a new library object, but will also set the number of azimuthal bins at the end." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "# Let's repeat all of the above for an angular MGXS library so we can gather\n", - "# that in the same continuous-energy calculation\n", - "angle_mgxs_lib = openmc.mgxs.Library(geometry)\n", - "angle_mgxs_lib.energy_groups = groups\n", - "angle_mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission',\n", - " 'nu-scatter matrix', 'multiplicity matrix', 'chi']\n", - "\n", - "angle_mgxs_lib.domain_type = \"mesh\"\n", - "angle_mgxs_lib.domains = [mesh]\n", - "angle_mgxs_lib.correction = None\n", - "angle_mgxs_lib.scatter_format = 'histogram'\n", - "angle_mgxs_lib.histogram_bins = 11\n", - "\n", - "# Set the angular bins to 8\n", - "angle_mgxs_lib.num_azimuthal = 8" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that our libraries have been setup, let's make sure they contain the types of cross sections which meet the needs of OpenMC's multi-group solver. Note that this step is done automatically when writing the Multi-Group Library file later in the process (as part of the `mgxs_lib.write_mg_library()`), but it is a good practice to also run this before spending all the time running OpenMC to generate the cross sections." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "# Check the libraries - if no errors are raised, then the library is satisfactory.\n", - "iso_mgxs_lib.check_library_for_openmc_mgxs()\n", - "angle_mgxs_lib.check_library_for_openmc_mgxs()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Lastly, we use our two `Library` objects to construct the tallies needed to compute all of the requested multi-group cross sections in each domain.\n", - "\n", - "We expect a warning here telling us that the default Legendre order is not meaningful since we are using histogram scattering." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mgxs/mgxs.py:4144: UserWarning: The legendre order will be ignored since the scatter format is set to histogram\n", - " warnings.warn(msg)\n" - ] - } - ], - "source": [ - "# Construct all tallies needed for the multi-group cross section library\n", - "iso_mgxs_lib.build_library()\n", - "angle_mgxs_lib.build_library()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The tallies within the libraries can now be exported to a \"tallies.xml\" input file for OpenMC." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a \"tallies.xml\" file for the MGXS Library\n", - "tallies_file = openmc.Tallies()\n", - "iso_mgxs_lib.add_to_tallies_file(tallies_file, merge=True)\n", - "angle_mgxs_lib.add_to_tallies_file(tallies_file, merge=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In addition, we instantiate a fission rate mesh tally for eventual comparison of results." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=1.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=11.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=21.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=22.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=12.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=18.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Instantiate tally Filter\n", - "mesh_filter = openmc.MeshFilter(mesh)\n", - "\n", - "# Instantiate the Tally\n", - "tally = openmc.Tally(name='mesh tally')\n", - "tally.filters = [mesh_filter]\n", - "tally.scores = ['fission']\n", - "\n", - "# Add tally to collection\n", - "tallies_file.append(tally, merge=True)\n", - "\n", - "# Export all tallies to a \"tallies.xml\" file\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "Time to run the calculation and get our results!" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | ed7123f4e7ce7b097c4b2bfb0ef5283eaa8afaea\n", - " Date/Time | 2019-10-04 10:54:35\n", - " OpenMP Threads | 4\n", - "\n", - " Minimum neutron data temperature: 294.000000 K\n", - " Maximum neutron data temperature: 294.000000 K\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 0.83866 +/- 0.00102\n", - " k-effective (Track-length) = 0.83799 +/- 0.00118\n", - " k-effective (Absorption) = 0.83968 +/- 0.00103\n", - " Combined k-effective = 0.83900 +/- 0.00085\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Run OpenMC\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To make the files available and not be over-written when running the multi-group calculation, we will now rename the statepoint and summary files." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "# Move the StatePoint File\n", - "ce_spfile = './statepoint_ce.h5'\n", - "os.rename('statepoint.' + str(batches) + '.h5', ce_spfile)\n", - "# Move the Summary file\n", - "ce_sumfile = './summary_ce.h5'\n", - "os.rename('summary.h5', ce_sumfile)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing\n", - "\n", - "Our simulation ran successfully and created statepoint and summary output files. Let's begin by loading the StatePoint file, but not automatically linking the summary file." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the statepoint file, but not the summary file, as it is a different filename than expected.\n", - "sp = openmc.StatePoint(ce_spfile, autolink=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In addition to the statepoint file, our simulation also created a summary file which encapsulates information about the materials and geometry. This is necessary for the `openmc.Library` to properly process the tally data. We first create a `Summary` object and link it with the statepoint. Normally this would not need to be performed, but since we have renamed our summary file to avoid conflicts with the Multi-Group calculation's summary file, we will load this in explicitly." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "su = openmc.Summary(ce_sumfile)\n", - "sp.link_with_summary(su)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The statepoint is now ready to be analyzed. To create our libraries we simply have to load the tallies from the statepoint into each `Library` and our `MGXS` objects will compute the cross sections for us under-the-hood." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "# Initialize MGXS Library with OpenMC statepoint data\n", - "iso_mgxs_lib.load_from_statepoint(sp)\n", - "angle_mgxs_lib.load_from_statepoint(sp)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The next step will be to prepare the input for OpenMC to use our newly created multi-group data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Isotropic Multi-Group OpenMC Calculation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will now use the `Library` to produce the isotropic multi-group cross section data set for use by the OpenMC multi-group solver. \n", - "\n", - "If the model to be run in multi-group mode is the same as the continuous-energy mode, the `openmc.mgxs.Library` class has the ability to directly create the multi-group geometry, materials, and multi-group library for us. \n", - "Note that this feature is only useful if the MG model is intended to replicate the CE geometry - it is not useful if the CE library is not the same geometry (like it would be for generating MGXS from a generic spectral region).\n", - "\n", - "This method creates and assigns the materials automatically, including creating a geometry which is equivalent to our mesh cells for which the cross sections were derived." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Allow the API to create our Library, materials, and geometry file\n", - "iso_mgxs_file, materials_file, geometry_file = iso_mgxs_lib.create_mg_mode()\n", - "\n", - "# Tell the materials file what we want to call the multi-group library\n", - "materials_file.cross_sections = 'mgxs.h5'\n", - "\n", - "# Write our newly-created files to disk\n", - "iso_mgxs_file.export_to_hdf5('mgxs.h5')\n", - "materials_file.export_to_xml()\n", - "geometry_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we can make the changes we need to the settings file.\n", - "These changes are limited to telling OpenMC to run a multi-group calculation and provide the location of our multi-group cross section file." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "# Set the energy mode\n", - "settings_file.energy_mode = 'multi-group'\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's clear up the tallies file so it doesn't include all the extra tallies for re-generating a multi-group library" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a \"tallies.xml\" file for the MGXS Library\n", - "tallies_file = openmc.Tallies()\n", - "\n", - "# Add our fission rate mesh tally\n", - "tallies_file.append(tally)\n", - "\n", - "# Export to \"tallies.xml\"\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before running the calculation let's look at our meshed model. It might not be interesting, but let's take a look anyways." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "geometry_file.root_universe.plot(origin=(length / 2., length / 2., 0.),\n", - " pixels=(300, 300), width=(length, length),\n", - " color_by='material')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "So, we see a 10x10 grid with a different color for every material, sounds good!\n", - "\n", - "At this point, the problem is set up and we can run the multi-group calculation." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | ed7123f4e7ce7b097c4b2bfb0ef5283eaa8afaea\n", - " Date/Time | 2019-10-04 10:56:58\n", - " OpenMP Threads | 4\n", - "\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 0.82471 +/- 0.00104\n", - " k-effective (Track-length) = 0.82466 +/- 0.00103\n", - " k-effective (Absorption) = 0.82482 +/- 0.00075\n", - " Combined k-effective = 0.82477 +/- 0.00068\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Execute the Isotropic MG OpenMC Run\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before we go the angle-dependent case, let's save the StatePoint and Summary files so they don't get over-written" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [], - "source": [ - "# Move the StatePoint File\n", - "iso_mg_spfile = './statepoint_mg_iso.h5'\n", - "os.rename('statepoint.' + str(batches) + '.h5', iso_mg_spfile)\n", - "# Move the Summary file\n", - "iso_mg_sumfile = './summary_mg_iso.h5'\n", - "os.rename('summary.h5', iso_mg_sumfile)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Angle-Dependent Multi-Group OpenMC Calculation\n", - "\n", - "Let's now run the calculation with the angle-dependent multi-group cross sections. This process will be the exact same as above, except this time we will use the angle-dependent Library as our starting point.\n", - "\n", - "We do not need to re-write the materials, geometry, or tallies file to disk since they are the same as for the isotropic case." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Let's repeat for the angle-dependent case\n", - "angle_mgxs_lib.load_from_statepoint(sp)\n", - "angle_mgxs_file, materials_file, geometry_file = angle_mgxs_lib.create_mg_mode()\n", - "angle_mgxs_file.export_to_hdf5()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "At this point, the problem is set up and we can run the multi-group calculation." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | ed7123f4e7ce7b097c4b2bfb0ef5283eaa8afaea\n", - " Date/Time | 2019-10-04 10:57:24\n", - " OpenMP Threads | 4\n", - "\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 0.83564 +/- 0.00103\n", - " k-effective (Track-length) = 0.83572 +/- 0.00104\n", - " k-effective (Absorption) = 0.83478 +/- 0.00073\n", - " Combined k-effective = 0.83504 +/- 0.00066\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Execute the angle-dependent OpenMC Run\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Results Comparison\n", - "In this section we will compare the eigenvalues and fission rate distributions of the continuous-energy, isotropic multi-group and angle-dependent multi-group cases.\n", - "\n", - "We will begin by loading the multi-group statepoint files, first the isotropic, then angle-dependent. The angle-dependent was not renamed, so we can autolink its summary." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the isotropic statepoint file\n", - "iso_mgsp = openmc.StatePoint(iso_mg_spfile, autolink=False)\n", - "iso_mgsum = openmc.Summary(iso_mg_sumfile)\n", - "iso_mgsp.link_with_summary(iso_mgsum)\n", - "\n", - "# Load the angle-dependent statepoint file\n", - "angle_mgsp = openmc.StatePoint('statepoint.' + str(batches) + '.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Eigenvalue Comparison\n", - "Next, we can load the eigenvalues for comparison and do that comparison" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "ce_keff = sp.k_combined\n", - "iso_mg_keff = iso_mgsp.k_combined\n", - "angle_mg_keff = angle_mgsp.k_combined\n", - "\n", - "# Find eigenvalue bias\n", - "iso_bias = 1.0e5 * (ce_keff - iso_mg_keff)\n", - "angle_bias = 1.0e5 * (ce_keff - angle_mg_keff)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's compare the eigenvalues in units of pcm" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Isotropic to CE Bias [pcm]: 1423.5\n", - "Angle to CE Bias [pcm]: 396.6\n" - ] - } - ], - "source": [ - "print('Isotropic to CE Bias [pcm]: {0:1.1f}'.format(iso_bias.nominal_value))\n", - "print('Angle to CE Bias [pcm]: {0:1.1f}'.format(angle_bias.nominal_value))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see a large reduction in error by switching to the usage of angle-dependent multi-group cross sections! \n", - "\n", - "Of course, this rodded and partially voided BWR problem was chosen specifically to exacerbate the angular variation of the reaction rates (and thus cross sections). Such improvements should not be expected in every case, especially if localized absorbers are not present.\n", - "\n", - "It is important to note that both eigenvalues can be improved by the application of finer geometric or energetic discretizations, but this shows that the angle discretization may be a factor for consideration.\n", - "\n", - "### Fission Rate Distribution Comparison\n", - "Next we will visualize the mesh tally results obtained from our three cases.\n", - "\n", - "This will be performed by first obtaining the one-group fission rate tally information from our state point files. After we have this information we will re-shape the data to match the original mesh laydown. We will then normalize, and finally create side-by-side plots of all." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "sp_files = [sp, iso_mgsp, angle_mgsp]\n", - "titles = ['Continuous-Energy', 'Isotropic Multi-Group',\n", - " 'Angle-Dependent Multi-Group']\n", - "fiss_rates = []\n", - "fig = plt.figure(figsize=(12, 6))\n", - "for i, (case, title) in enumerate(zip(sp_files, titles)):\n", - " # Get our mesh tally information\n", - " mesh_tally = case.get_tally(name='mesh tally')\n", - " fiss_rates.append(mesh_tally.get_values(scores=['fission']))\n", - " \n", - " # Reshape the array\n", - " fiss_rates[-1].shape = mesh.dimension\n", - " \n", - " # Normalize the fission rates\n", - " fiss_rates[-1] /= np.mean(fiss_rates[-1][fiss_rates[-1] > 0.])\n", - " \n", - " # Set 0s to NaNs so they show as white\n", - " fiss_rates[-1][fiss_rates[-1] == 0.] = np.nan\n", - "\n", - " fig = plt.subplot(1, len(titles), i + 1)\n", - " # Plot only the fueled regions\n", - " plt.imshow(fiss_rates[-1][1:-1, 1:-1], cmap='jet', origin='lower',\n", - " vmin=0.4, vmax=4.)\n", - " plt.title(title + '\\nFission Rates')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "With this colormap, dark blue is the lowest power and dark red is the highest power.\n", - "\n", - "We see general agreement between the fission rate distributions, but it looks like there may be less of a gradient near the rods in the continuous-energy and angle-dependent MGXS cases than in the isotropic MGXS case. \n", - "\n", - "To better see the differences, let's plot ratios of the fission powers for our two multi-group cases compared to the continuous-energy case t" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAt0AAAFfCAYAAACSp3C8AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3debgkZXn///eHYd+XGRUYFg1uqBHNCBr9KmJUcAN3UEFcQowSNYlRUSP5kuCSn78QEaOZICKKoEFRoigaBVEjChhcEBFEkGGRddh37u8fVWem+zBzTh/oPnWW9+u66pruWu+umXn67qfueipVhSRJkqTRWaPrACRJkqS5zqRbkiRJGjGTbkmSJGnETLolSZKkETPpliRJkkbMpFuSJEkaMZNu9UmybZKbkyzo6Pj/kORzEyx/dZJvTWdMkgaXZP8kP+g6jumQ5LQkb+w6jqlIcnGSP5tg+TeSvHY6Y5LmC5PuaTRZYzfgPkbayFfV76tqw6q6Z4px7Z+kkhw2bv6e7fyjpxpLku3bbdfsie/YqnrOJNstSfK1JNcnWZ7kV0kOTbLZVGOQ5rK2Pbk+yTpdxwKQZNck97Y//G9OsizJF5M8qevYRmmQHyrt31Ulefy4+Se283e9H8e9TydHVe1RVZ+ZYJskOTDJz5PcmuTKNra9p3p8ab4x6Z5jehPUDvwWeMW4GF4L/Ga6Akjyp8BpwA+BR1XVpsDuwN3A41ezTZfnTOpEku2B/wMU8KJOg+l3eVVtCGwEPBn4NfD9JM/qNqwZ4TfAfmNvkmwBPAW4ehpjOBx4O/C3wBbA1sD7aNrZ+2iTdHMNCZPuziTZIcn3ktyQ5JokX+hZ9qdJzmyXndkmkiQ5lOZL8oi2F+iIdn4leUuSC4ALJtpHu+y0JB9M8pMkNyb5apLN22V9vctJNk/y6SSXtz1iX5ngY10J/AJ47ti2wJ8CJ/Uce9cky8adi9VdATi9/XN5+3mfMkCP0D8Dn66qD1bVH2BF7/3BVXVae7z9k/wwyWFJrgX+IckaSd6X5JIkVyU5Jskmg8Tc9hadkOQLSW5K8tPxvVHSDLQfcAZwNM2P4xWSHJ3k40m+3v6b/nGSP+pZ/pwk57fty7+1bdkqr8AleVSSbye5rt3mFYMEV41lVfV+4Ejgw4Pss439k+3ym9rYtpvCthN97mcn+XX7uY8AMu6zvj7JeW1becq441aSNyW5IM0VuI+3CemjgU8CT2nbueUTnJZjgVdmZfnfPsCJwJ3jPsM/9by/T/vVzt8deE+7v5uT/Kydv9qrqUkeAbwZ2Luqvl1Vt1XVPVX1g6rav2e909JcXfwhcCvwsCRbJTmpPe8XJvnzQWNu29uD0ly1vL79Tlp3gvMkzUgm3d35R+BbwGbAYuBjsCJR/TpNb8IWwL8AX0+yRVW9F/g+cGBbAnJgz/72AnYBdpxoHz3r7we8HtiSphf48NXE+VlgfeAxwIOAw1az3phjWNkTszfwVeCOSbZZnae3f27aft4fTbRykg1oen2+NMC+dwEuAh4MHArs307PBB4GbAgcMYVY9wT+E9gc+DzwlSRrTWF7abrtR5PEHQs8N8mDxy3fG/i/NG3UhTT/T0iyEDgBOIimfTmf5sf1fbT/J79N83/iQe0+/y3JjlOM9cvAE5NsMOA+X03Txi4Ezmk/46DxTPS5v0zTq7uQ5sreU3s+6540SexLgEU0bfVx4z7HC4AnAX8MvAJ4blWdB7wJ+FHbzm06wXm4HPgVMFZitx9NmztlVfVN4APAF9rjDtJRsBtwaVWdNcC6+wIH0FyxuAQ4HlgGbAW8DPhAkt2mEPKraTp0/gh4BM3fgzSrmHR35y5gO2Crqrq9qsZ6b58PXFBVn62qu6vqOJrLqy+cZH8frKrrquq2Affx2ar6ZVXdAvw9TVlI382TSbYE9gDeVFXXV9VdVfW9SeI4Edi17SW+318I99NmNP+mrxybkeSf216lW5L0NtKXV9XH2vNzG02D/i9VdVFV3UyTUOydwUtPzq6qE6rqLpofOevSXBqXZpwkT6Npf75YVWfTJJCvGrfaiVX1k6q6myZp3amd/zzg3Kr6crvscHr+z43zAuDiqvp0+3/tf2l+FL98iiFfTtOrvOmA+/x6VZ1eVXcA76XpRd5mwG0n+9xj/8//ddznfhNNO3xeu+0HgJ16e7uBD1XV8qr6PXBqz76n4hhgvySPoumQmLAzYsgWMu7vOk3d/fIkt4/7rEdX1bntuXgIzQ+Ud7Xfd+fQXL3Yj8EdUVWXVtV1ND+E9nlgH0Wafibd3XknzZfIT5Kcm+T17fytaHoFel1CUzc3kUt7Xg+yj0vHLVuLpkHttQ1wXVVdP8mxV2gT2K/T9EJsUVU/HHTbqUrynqy84eqTwPXAvTS992PxvLPtOToR6E2gL+3f233O2SXt+uN7/1Znxf6q6l5W9uhIM9FrgW9V1TXt+88zrsSE/uTqVpqrP9D8u+799140/95XZTtglzYpW96WTrwaeEhWjpR0c5KbJ4l3a5ra8+UT7bNn/d74bgaua+MeZNupfO7edmQ74KM9+72Opo3vbXdXt++p+DJNj/OBNFciR6b9bhr7O/o/wLX0tK8AVbWY5rtjHfrLbcZ/J11XVTf1zBvke63X+O8s21fNOt5A1pGquhL4c1jR6/TfSU6n6dHZbtzq2wLfHNt0dbvseT3ZPqBJqHuX3QVcM27+pcDmSTatqonqDMc7BvguzSXa8W6hKVcBoO1dX7Sa/azuszYLqz5A05u0QpIf01zePXWSGMfve/w525am7OYPNI37ZDFv07N8DZqSocsniUGadknWoyltWJBkLAlcB9g0yeOr6meT7OIKmn/fY/tL7/txLgW+V1XPXs3yQZPOFwM/rapbkky2T+j//7ghTdnX5QPEM5Erxu033Le9PLSqjr0f+56wretbserWJN8A/pKm1GK8vjaW/h8UUzpuVT2m932Sq2juKVoyQInJ+O+kzZNs1JN4bwtcNoWYx39n2b5q1rGnuyNJXp5k7IvqepoG6l7gZOARSV6VZM0krwR2BL7WrvsHmprjiUy2D4DXJNkxyfrAIcAJ44cJrKorgG/Q1DxulmStJE9nct8Dnk1bpz7Ob4B1kzy/rXl+H80X/qpcTXNOJvu8vd4JvD7Ju5M8CKA9zw+dZLvjgL9O8tD2S3qs1vHuAWP+kyQvactR3k5Tx37GFOKWpstewD00bcJO7fRomhrkQS73fx14XJK92n/vb2H1id3XaNqifdv2Y60kT0pz8+CE0tg6ycHAG2nqpQfd5/OSPC3J2jS13WdU1aUPJJ72cz+m5//5W8d97k8CByV5TBv/JkkGLaP5A7C4jXcQ7wGeUVUXr2LZOTSff/MkD6FpjyY67vYZcHSRqjof+Hfg+DQ3la7XdkKssqa/Z7tLgf8BPphk3SR/DLwBGBuucJCY35JkcZp7lt4LfGEV60gzmkl3d54E/Li9rHoS8La2nvhamrrDv6W5lPdO4AU9l4E/CrwszR3cq7z5cYB9QHNZ8miay53r0nyBrMq+NL3gvwauYuIGfOz4VVXfaWvvxi+7gebu9yNpejluYTWXpqvqVpravR+2l2wnrZFua+N3o7kJ8zftZd5v0gwjuKofAWOOojknpwO/A24H/moKMX8VeCXND6h9gZe0dZ/STPNamhF+fl9VV45NNDcOv3qy+xjaduTlNCMFXUuTvJ/FKm6Ybns1n0Nzc+LlNO3Nh1n9D22Ardp28WbgTOBxwK5V9a0p7PPzwME0JR5/ArzmAcQz/nN/qP3cD6cZmnRs+Yntvo5PciPwS5p7YgbxXeBc4Mok10y2clVd3nMf0HifBX4GXExzs/5Eyel/tn9em+SnA8b6Fpo6/n+hOb/LaH7YvBL4/QTb7QNsT3PeTwQOrqr/nkLMn2+XXURzD8I/rWIdaUZLU5am+STJacDnqurIrmOZC5L8A7BDVb2m61ik6db2ki4DXl1Vk5V1TUc8RwPLqsrRLeaIJBcDb+xJ0qVZyZ5uSdKUJHlukk3TPMnyPTQ30FlOJUkTMOmWJE3VU2gu8V9DMxTpXu3IRZKk1bC8RJIkSRoxe7olSZKkETPp7kjPgyEWTL72avdxc5KpDKc3byXZPklNNjLDBNu/J4k3nkoPgO3e9LLdk2YWk+4RS3JxktvS8+S1JFu1w3VtOH5s7Klot79omPHCfWK+MsnR7djVg2z7gBr5SfZ9WppHDd+c5JokX07zqPphH2fXJH1DAlbVB6rqjcM+ljQX2e4NNS7bPWmOMOmeHi9svyjGptnwJK0XVtWGNA/OeAJwUMfxjDmwjWsHmqfZfaTjeCStmu3e8NjuSXOASXdHxveMJNk/yUVJbkryuySvbufvkOR7SW5oezm+0LOPSrJD+3qTJMckuTrJJUneN/aUsXbfP0jykfahOr9LMtBDG9qHZpxC8yU0dtznJ/nfJDcmubQdp3rM6e2fy9uemae027w+yXnt8U9Jsl07P0kOS3JVu79fJHnsAHEtB74yLq410jyJ8rdJrk3yxTRPL7uPJK9r47mpPe9/0c7fgOYpnFv19tAl+Yckn2vX+UaSA8ft72dJXtK+flSSbye5Lsn5SV4x2eeR5gPbPds9aT4z6Z4B2gbvcGCPqtqI5pG657SL/5HmKVybAYtZ/VMVPwZsQvPI9GfQPM75dT3LdwHOBxbSPEnuU0kyQGyLaZ6qdmHP7Fva/W8KPB/4yyR7tcvGHhO/adu79aMke9KM5fsSYBHN46aPa9d7TrvNI9r4X0HztLfJ4tqi3V9vXH9F84jrZwBb0Twd8uOr2cVVNE/t3JjmPB2W5IlVdUv7eS+foIfuOJqnq43FsiOwHfD19u/y2zRPT3sQzZPv/q1dR1LLds92T5p3qspphBPNY21vBpa301fa+dsDBawJbNAueymw3rjtjwGWAotXse+iudy4ALgT2LFn2V8Ap7Wv9wcu7Fm2frvtQyaJ+aZ2ve/QfJms7jP+K3DY+M/Vs/wbwBt63q8B3ErTYO8G/AZ4MrDGJOfytHa7G9pjnANs27P8POBZPe+3pHmE/Zqrimvcvr8CvK19vSvNE+16l/8DzVM8ATai+QLern1/KHBU+/qVwPfHbfvvNI887vzfo5PTdEy2e7Z7tntOTved7OmeHntV1abttNf4hdX0MrwSeBNwRZKvJ3lUu/idNE97+0mSc5O8fhX7XwisBVzSM+8SYOue91f2HO/W9uVENwntVU3v067Ao9pjAJBklySntpd0b2jjXrjq3QDNl8xHkyxPshy4rv1MW1fVd4EjaHpmrkqyNMnGE+zrrVW1CfDHrOwF6z3OiT3HOQ+4B3jw+J0k2SPJGe2l0OXA8yb5DCtU1U3A12l6c6Dp/Tm2J4ZdxmJo9/1q4CGD7FuaQ2z3bPds96QeJt0zRFWdUlXPpuml+DXwH+38K6vqz6tqK5penH8bq2fscQ1Nz8Z2PfO2BS4bQlzfA46m/8adzwMnAdu0XwSfpPkygaZXZbxLgb/o+QLetKrWq6r/aY9xeFX9CbAjzeXWvxsgrl8A/wR8vOdy8aU0l6p7j7NuVfWdhzSPrv5S+5keXFWbAidP8hnGOw7Yp63dXBc4tSeG742LYcOq+ssB9inNK7Z7tnvSfGLSPQMkeXCSPdu6uDtoLnHe2y57eVtfCE2tXo0tG1PN8FtfBA5NslF7s87fAJ8bUoj/Cjw7yePb9xsB11XV7Ul2Bl7Vs+7VbXy94+h+EjgoyWPaz7RJkpe3r5/U9iCtRXPp8vbxn28Cn6HpzXlRz3EO7blZaVFbVzne2sA6bax3p7m56jk9y/8AbJFkkwmOfTLNl/0hwBeqaizmrwGPSLJvkrXa6UlJHj3gZ5LmBds92z1pvjHpnhnWoPmyuJzmEuQzgLEegicBP05yM00vy9tq1WPU/hVN430R8AOaXpmjhhFcVV1NU2P5/nbWm4FDktzUzvtiz7q30tT6/bC9zPjkqjoR+DBwfJIbgV/S3LQDzQ09/0HzxXoJzc1E/9+Acd0JfBT4+3bWR2nO0bfa2M6guZFq/HY3AW9t476e5svzpJ7lv6bp0bmo/QxbrWIfdwBfBv6M5lz37vs5NJdgL6e5vP1hmi87SSvZ7tnuSfNKqga5oiRJkiTNLkmOohm156qqus/QnO29JJ8Gngi8t6o+0rNsd5oftguAI6vqQ+38hwLHA1sAZwP7tj+IJ2RPtyRJkuaqo4HdJ1h+Hc1VoL6HTiVZQHOz8x40917s0zMM5odpRi/agebK0RsGCcSkW5IkSXNSVZ1Ok1ivbvlVVXUmzY3ZvXamGXb0orYX+3hgz/Ym5t2AE9r1PkMzVv6k1pxq8JIkSZq7dk/qmq6DGNDZcC7NzchjllbV0iHsemuakXnGLKO5X2ILYHlV3d0zf2sGYNItSZKkFa4Bzuo6iAEFbq+qJV3HMQiTbt1HO2LAH69mtABJmnNs96Rx1pglFcj3Djra5pRdBmzT835xO+9aYNMka7a93WPzJzVLzujsluTiJH/2ALZPkrcm+WWSW5IsS/KfSR43hNhOS/LG3nntQw1mzRdP+xluT3Jzz/RfXcclzWe2e6Nlu6eRW2ON2TGNzpnAw5M8NMnaNENinlTNsH+nAi9r13st8NVBdmhP9+zwUeD5wJ8DP6QZuubF7bxfdBjXTHJgVR05ygP0/KqVNHq2e5Oz3dNoJLOnp3sSSY4DdgUWJlkGHAysBVBVn0zyEJpqmo2Be5O8Hdixqm5MciBwCk37c1RVndvu9l00Y/D/E/C/wKcGCqaqnEY4AZ+ledLYbTRPXHtnO/9FNMX/y4HTgEevZvuHA/cAO09wjE1oHuJwNc2DFt4HrNEu25/moREfoRnW5nc0jwyG5mEO99DcgHAzcEQ7v4Ad2tdH0wyZ83XgJuDHwB+1y7Zv112zJ5bTgDe2r9doY7kEuKqNcZN22a7AsnGf42Lgz9rXO7f/CW6keVLav0zw+VcccxXLdqW5yeFv2xiuAF7Xs3yd9tz8vj3OJ4H1xm37LpqHPXy2nf/Odj+XA28cO180D/T4A7CgZ/8vAX7W9b9DJ6fpnGz3bPds92b39CdJ1dprz4oJOKvr8zXoNDd+xsxgVbUvTcP2wmouX/5zkkfQPPnr7cAimkfr/ld7+WK8Z9E00j+Z4DAfo/kCehjNU932A17Xs3wX4HxgIfDPwKeSpKreC3yfprdkw6o6cDX73xv4v8BmwIU0X1qD2L+dntnGtiFwxIDbfhT4aFVtDPwRPU9/ux8eQnN+tqYZS/PjSTZrl30IeASwE80XyNasfALd2Lab0zz6+IB2oPy/oXki2w40X1AAVDPk0LX0P1p5X5ovXWnesN2z3cN2b/brumyk+/KSoZtd0c4drwS+XlXfrqq7aHoc1gP+dBXrbkHTu7BK7eDtewMHVdVNVXUx8P/TNHpjLqmq/6iqe2jGk9wSePAU4j2xqn5SzSXGY2ka6kG8mqan5qKquhk4CNg7ySBlTXcBOyRZWFU3V9UZk6x/ePvo4rHpH8ft65CququqTqbp3XpkO9bmAcBfV9V11TzK+AM053PMvcDBVXVHVd0GvAL4dFWdW82jn/9hXByfAV4DkGRz4Ln0PC5Zmsds9yZnu6eZYay8ZDZMs8jsinbu2Irm0iMAVXUvzViQqxrn8VqaL4vVWUhTm3RJz7xLxu3ryp5j3dq+3HAK8V7Z8/rWKWzb9znb12sy2BffG2h6Yn6d5MwkLwBI8smem4be07P+W6tq057p73uWXVv9NYljn2ERsD5w9tiXFvDNdv6Yq6uqd/zPregft7P3NcDngBcm2YDmi+r7VbXa5EGaR2z3Jme7p5mj62TapFv3U417fznNZTuguUufZliaVQ058x1gcZLVjUF5DU2PxnY987Zdzb4GiW0qbmn/XL9n3kN6Xvd9zjauu2nq/27p3a7tuVrR6FfVBVW1D/AgmsetnpBkg6p6U3tJeMOq+sADiB2ac3cb8JieL61Nqqr3y3X8+bmCZnigMb3DCVFVlwE/oqlp3JemtlWaj2z3VsZlu6fZp+tk2qRb99MfaGr7xnwReH6SZyVZi+ZmlzuA/xm/YVVdAPwbcFySXZOsnWTdJHsneXd76fSLwKFJNkqyHU3t3efuZ2wDq6qrab7kXpNkQZLX09QhjjkO+Ot2uJ0NaS5hfqHtffkNsG6S57fn4H00N/cAkOQ1SRa1vWHL29lDHYyz3fd/AIcleVB73K2TPHeCzb4IvC7Jo5OsD/z9KtY5huamo8cBXx5mzNIsYrtnu6fZyvKSkZhd0c5eHwTe117Ke0dVnU9T//Yxml6HF9LccHTnarZ/K82NOB+naYh/SzN01tiYrH9F04NyEc0d+58Hjhowto8CL0tyfZLDp/zJmuG8/o7mcvBj6P8CPYqmx+N0mtEDbm9jpapuAN4MHEnzBXYLzR3zY3YHzk3zwIqPAnu3tYWrc8S48WrPHjD+d9HcJHVGkhuB/wYeubqVq+obwOE0Y3ReCIzVXN7Rs9qJND1dJ/Zc1pbmG9s92z1JPVL1QK6ySfNbkkcDvwTW6a2fTPJb4C+q6r87C06SRsB2b+5bsuaaddYmm3QdxkBy3XVnl4+Bl+amJC+mGe5sfZq6y/8a98XzUpqayO92E6EkDZft3jwzhx6OM5OYdEtT9xc0D8+4B/gezeVioHk0M7AjsG9bOylJc4Ht3nxj0j10Jt3SFFXV7hMs23UaQ5GkaWG7Nw+ZdA+dSbckSZJWsrxkJEy6JUmS1M+ke+hGknQnCwu2H8WuB7b++pOvM2obb9x1BI2Z8P9mzRnw824mnIctNpsh5Y7Ll0++zghdfPXVXHPTTek0iCFbuO66tf1GG3UbxFprdXt8aHrIZoINNug6ApgJo4OtvXbXEcDdd0++zjxw8ZVXcs0NN8yQ/yDqwohSoe2Bs0az6wE99rGdHh6A3XbrOoLGTPjuWbRo8nVGbSb8ENv3ZRMNuTuNvvSlTg+/5P3v7/T4o7D9Rhtx1kte0m0QW23V7fFhZvy6BXjyk7uOYGYkm4sXT77OqF11VdcRzAhL3vzmyVeaKSwvGYkZ0P8oSZKkGcWke+hMuiVJktTPpHvoTLolSZK0kuUlI2HSLUmSpH4m3UPnGZUkSZJGzJ5uSZIkrWR5yUiYdEuSJKmfSffQmXRLkiSpn0n30Jl0S5IkaSXLS0bCpFuSJEn9TLqHzqRbkiRJK9nTPRKTntEkj0xyTs90Y5K3T0dwktQF2z1J0rBN2tNdVecDOwEkWQBcBpw44rgkqTO2e5LmPXu6h26q5SXPAn5bVZeMIhhJmoFs9yTNPybdQzfVM7o3cNwoApGkGcp2T9L8MlbTPRumST9KjkpyVZJfrmZ5khye5MIkP0/yxHb+M8eVGd6eZK922dFJftezbKdBTuvAPd1J1gZeBBy0muUHAAc077YddLeSNGNNpd3bdsMNpzEySRqxudPTfTRwBHDMapbvATy8nXYBPgHsUlWnsrLMcHPgQuBbPdv9XVWdMJVAplJesgfw06r6w6oWVtVSYGkT3JKaShCSNEMN3O4tWbTIdk/S3DCHRi+pqtOTbD/BKnsCx1RVAWck2TTJllV1Rc86LwO+UVW3PpBYpnJG98FLrJLmF9s9SZrbtgYu7Xm/rJ3Xa1Vlhoe25SiHJVlnkAMNlHQn2QB4NvDlQdaXpNnOdk/SvNZ1rfbgNd0Lk5zVMx0wzNOQZEvgccApPbMPAh4FPAnYHHjXIPsaqLykqm4BtphamJI0e9nuSZrXZk95yTVVteQBbH8ZsE3P+8XtvDGvAE6sqrvGZvSUntyR5NPAOwY5kE+klCRJ0kpzqKZ7ACcBByY5nuZGyhvG1XPvw7ib6cdqvpME2AtY5cgo45l0S5Ikqd8cSbqTHAfsSlOGsgw4GFgLoKo+CZwMPI9mdJJbgdf1bLs9TS/498bt9tgki4AA5wBvGiQWk25JkiStNId6uqtqn0mWF/CW1Sy7mPveVElV7XZ/YjHpliRJUr85knTPJJ5RSZIkacTs6ZYkSVI/e7qHzqRbkiRJK82hmu6ZxKRbkiRJ/Uy6h86kW5IkSSvZ0z0SJt2SJEnqZ9I9dCNJujfbDJ773FHseXBPf3q3xwdYvLjrCBqPeETXEcDaa3cdAWy8cdcRAD/4QdcRNJ761G6Pv8EG3R5/FJLu/6E/7WndHh/gYQ/rOoLGhht2HcHMaHRuv73rCOBBD+o6gsadd3Z7/HXW6fb46pw93ZIkSVrJ8pKRMOmWJElSP5PuoTPpliRJUj+T7qEz6ZYkSdJKlpeMhEm3JEmS+pl0D51JtyRJklayp3skPKOSJEnSiNnTLUmSpH72dA+dSbckSZL6mXQPnUm3JEmSVrKmeyRMuiVJktTPpHvoTLolSZK0kj3dI+EZlSRJkkZsoJ7uJJsCRwKPBQp4fVX9aJSBSVKXbPckzWv2dA/doOUlHwW+WVUvS7I2sP4IY5KkmcB2T9L8ZdI9dJMm3Uk2AZ4O7A9QVXcCd442LEnqju2epHnNmu6RGKSn+6HA1cCnkzweOBt4W1XdMtLIJKk7tnuS5jeT7qEb5IyuCTwR+ERVPQG4BXj3+JWSHJDkrCRn3XHH1UMOU5Km1ZTbvatvu226Y5Sk0Rjr6Z4N0ywySLTLgGVV9eP2/Qk0X0Z9qmppVS2pqiXrrLNomDFK0nSbcru3aL31pjVASRqprpPp+Zh0V9WVwKVJHtnOehbwq5FGJUkdst2TJA3boKOX/BVwbHsH/0XA60YXkiTNCLZ7kuavWdaLPBsMlHRX1TnAkhHHIkkzhu2epHlrDo1ekuQo4AXAVVX12FUsD80Qsc8DbgX2r6qftsvuAX7Rrvr7qnpRO/+hwPHAFjQ32u/bjnI1oblxRiVJkjQ8XddqD6+m+2hg9wmW7wE8vJ0OAD7Rs+y2qtqpnV7UM//DwGFVtQNwPfCGgU7pICtJkiRpnphDo5dU1enAdROssidwTDXOADZNsuXqT00C7EZzgz3AZ4C9Bjmtg9Z0S5Ikab6YI+UlA9gauLTn/bJ23hXAuknOAu4GPlRVX6EpKVleVXePW39SJt2SJEnqN3uS7oVtYjxmaVUtHWnjb2sAAB0wSURBVNK+t6uqy5I8DPhukl8AN9zfnZl0S5Ikaba6pqoeyE3vlwHb9Lxf3M6jqsb+vCjJacATgC/RlKCs2fZ2r1h/MrPmZ4wkSZKmwRyq6R7AScB+aTwZuKGqrkiyWZJ1mtORhcBTgV9VVQGnAi9rt38t8NVBDmRPtyRJkvrNnvKSCSU5DtiVpgxlGXAwsBZAVX0SOJlmuMALaYYMHHsmw6OBf09yL00n9Yeqauwhae8Cjk/yT8D/Ap8aJBaTbkmSJK00h8bprqp9JllewFtWMf9/gMetZpuLgJ2nGotJtyRJkvrNkaR7JjHpliRJUj+T7qHzjEqSJEkjNpKe7jXWgPXWG8WeB7fppt0eH+Cii7qOoPHCDU/tOgS+cfszuw6BPS4f6D6Hkbpn/4GeFDtyC26+38OMDseac/Ai27rrwiMe0W0Mu+3W7fGB//paug4BgBeu+Y2uQ+BHm+7RdQg85fb/6ToEvr9m9+0/wA47dHv8u7J2twFMxRyq6Z5J5uA3nyRJkh4Qk+6hM+mWJEnSSvZ0j4RJtyRJkvqZdA+dSbckSZL6mXQPnUm3JEmSVrK8ZCQ8o5IkSdKI2dMtSZKkfvZ0D51JtyRJklayvGQkTLolSZLUz6R76Ey6JUmS1M+ke+hMuiVJkrSS5SUj4RmVJEmSRmygnu4kFwM3AfcAd1fVklEGJUlds92TNK/Z0z10UykveWZVXTOySCRp5rHdkzT/WF4yEtZ0S5IkqZ9J99ANmnQX8K0kBfx7VS0dYUySNBPY7kman+zpHolBk+6nVdVlSR4EfDvJr6vq9N4VkhwAHACwwQbbDjlMSZp2U2r3tt1ssy5ilKTRMOkeuoHOaFVd1v55FXAisPMq1llaVUuqasm66y4abpSSNM2m2u4t2nDD6Q5RkkZnjTVmxzSLTBptkg2SbDT2GngO8MtRByZJXbHdkyQN2yDlJQ8GTkwytv7nq+qbI41Kkrpluydp/rKmeyQmTbqr6iLg8dMQiyTNCLZ7kuY9k+6hc8hASZIkrWRP90iYdEuSJKmfSffQmXRLkiSpn0n30HlGJUmSpBEz6ZYkSdJKYzXds2Ga9KPkqCRXJVnlsK9pHJ7kwiQ/T/LEdv5OSX6U5Nx2/it7tjk6ye+SnNNOOw1yWi0vkSRJUr+5U15yNHAEcMxqlu8BPLyddgE+0f55K7BfVV2QZCvg7CSnVNXydru/q6oTphKISbckSZJWmkOjl1TV6Um2n2CVPYFjqqqAM5JsmmTLqvpNzz4uT3IVsAhYvrodTWZunFFJkiQNT9dlI9P3GPitgUt73i9r562QZGdgbeC3PbMPbctODkuyziAHsqdbkiRJ/WZPT/fCJGf1vF9aVUuHtfMkWwKfBV5bVfe2sw8CrqRJxJcC7wIOmWxfJt2SJElaaXaVl1xTVUsewPaXAdv0vF/cziPJxsDXgfdW1RljK1TVFe3LO5J8GnjHIAeaNWdUkiRJGrKTgP3aUUyeDNxQVVckWRs4kabeu++Gybb3myQB9gJWOTLKeCPp6V6wADbZZBR7HtyaM6AP/23PGujvYPQe+8yuI2CPrgMAzj//DV2HwCP3fVXXITQ+9rFuj1/V7fFH4Y474MILu43h17/u9vjAC+/8VdchNF740q4j4CldBwB8+tPdt/+vW/S1rkMA4K6FL+j0+DMhL5mS2dPTPaEkxwG70pShLAMOBtYCqKpPAicDzwMupBmx5HXtpq8Ang5skWT/dt7+VXUOcGySRUCAc4A3DRLLbPsnIEmSpFGaXeUlE6qqfSZZXsBbVjH/c8DnVrPNbvcnFpNuSZIk9ZsjSfdMYtItSZKkfibdQ2fSLUmSpJXmUHnJTOIZlSRJkkbMnm5JkiT1s6d76Ey6JUmStJLlJSNh0i1JkqR+Jt1DZ9ItSZKkfibdQ2fSLUmSpJUsLxkJk25JkiT1M+keOs+oJEmSNGID93QnWQCcBVxWVS8YXUiSNDPY7kmalywvGYmplJe8DTgP2HhEsUjSTGO7J2l+MukeuoHOaJLFwPOBI0cbjiTNDLZ7kua1NdaYHdMsMmhP978C7wQ2GmEskjST2O5Jmp8sLxmJSZPuJC8Arqqqs5PsOsF6BwAHAGy00bZDC1CSptv9afe23cjcXNIcYtI9dIOc0acCL0pyMXA8sFuSz41fqaqWVtWSqlqy3nqLhhymJE2rKbd7i9Zbb7pjlCTNIpMm3VV1UFUtrqrtgb2B71bVa0YemSR1xHZP0rw2Vl4yG6ZZxIfjSJIkqd8sS2hngykl3VV1GnDaSCKRpBnIdk/SvGTSPXT2dEuSJGklRy8ZCZNuSZIk9TPpHjqTbkmSJK1kT/dIeEYlSZKkEbOnW5IkSf3s6R46k25JkiStZHnJSJh0S5IkqZ9J99CZdEuSJKmfSffQmXRLkiRpJctLRsIzKkmSpDkpyVFJrkryy9UsT5LDk1yY5OdJntiz7LVJLmin1/bM/5Mkv2i3OTxJBonFpFuSJEn91lhjdkyTOxrYfYLlewAPb6cDgE8AJNkcOBjYBdgZODjJZu02nwD+vGe7ifa/wkjKS+69F269dRR7HtyyZd0eH+Cztz+26xAA2HdmhNG5R257W9chcMkHP991CABstXG3x68Fc7Cy7cEPhne8o9MQrl1/m06PD/D72x/ddQgAPKHrAGaIbbftOgI47Ocv6DoEAHbr+L/H7bd3e/wpmUPlJVV1epLtJ1hlT+CYqirgjCSbJtkS2BX4dlVdB5Dk28DuSU4DNq6qM9r5xwB7Ad+YLJY5+M0nSZKkB2SOJN0D2Bq4tOf9snbeRPOXrWL+pEy6JUmS1KcYqEx5JliY5Kye90uramln0UzApFuSJEl97r236wgGdk1VLXkA218G9BYfLW7nXUZTYtI7/7R2/uJVrD+peXPtQJIkSZOrapLu2TANwUnAfu0oJk8GbqiqK4BTgOck2ay9gfI5wCntshuTPLkdtWQ/4KuDHMiebkmSJM1JSY6j6bFemGQZzYgkawFU1SeBk4HnARcCtwKva5ddl+QfgTPbXR0ydlMl8GaaUVHWo7mBctKbKMGkW5IkSePMovKSCVXVPpMsL+Atq1l2FHDUKuafBUx5bDiTbkmSJK0wVl6i4TLpliRJUh+T7uEz6ZYkSVIfk+7hM+mWJEnSCpaXjIZDBkqSJEkjZk+3JEmS+tjTPXyTJt1J1gVOB9Zp1z+hqg4edWCS1BXbPUnzmeUlozFIT/cdwG5VdXOStYAfJPlGVZ0x4tgkqSu2e5LmNZPu4Zs06W4HDb+5fbtWO9Uog5KkLtnuSZrP7OkejYFqupMsAM4GdgA+XlU/HmlUktQx2z1J85lJ9/ANlHRX1T3ATkk2BU5M8tiq+mXvOkkOAA4A2HDDbYceqCRNp6m2e9tuvXUHUUrSaJh0D9+UhgysquXAqcDuq1i2tKqWVNWSddddNKz4JKlTg7Z7izbffPqDkyTNGpMm3UkWtT09JFkPeDbw61EHJkldsd2TNJ+N1XTPhmk2GaS8ZEvgM2194xrAF6vqa6MNS5I6ZbsnaV6bbQntbDDI6CU/B54wDbFI0oxguydpPnP0ktHwiZSSJEnqY9I9fCbdkiRJ6mPSPXxTGr1EkiRJ0tTZ0y1JkqQVrOkeDZNuSZIk9THpHj6TbkmSJK1gT/domHRLkiSpj0n38Jl0S5IkqY9J9/CZdEuSJGkFy0tGwyEDJUmSpBGzp1uSJEl97OkevpEk3euvDzvtNIo9D+7JT+72+ABP+No/dh0CAD/60d93HQJPeexNXYcAt9/edQRs98YXdR1C48gjOz187rqz0+OPRAJrr911FJ17wq+P6zoEAD7z8326DoEHPajrCODGG7uOAP76YV/tOgQArl28Z6fHX2utTg8/JZaXjIY93ZIkSepj0j18Jt2SJEnqY9I9fN5IKUmSpBXGyktmwzSIJLsnOT/JhUnevYrl2yX5TpKfJzktyeJ2/jOTnNMz3Z5kr3bZ0Ul+17Ns0sJqe7olSZI0JyVZAHwceDawDDgzyUlV9aue1T4CHFNVn0myG/BBYN+qOhXYqd3P5sCFwLd6tvu7qjph0FhMuiVJktRnDpWX7AxcWFUXASQ5HtgT6E26dwT+pn19KvCVVeznZcA3qurW+xuI5SWSJElaYZaVlyxMclbPdMC4j7M1cGnP+2XtvF4/A17Svn4xsFGSLcatszcwfnimQ9uSlMOSrDPZebWnW5IkSX1mUU/3NVW15AHu4x3AEUn2B04HLgPuGVuYZEvgccApPdscBFwJrA0sBd4FHDLRQUy6JUmS1GcWJd2TuQzYpuf94nbeClV1OW1Pd5INgZdW1fKeVV4BnFhVd/Vsc0X78o4kn6ZJ3Cdk0i1JkqQV5tjDcc4EHp7koTTJ9t7Aq3pXSLIQuK6q7qXpwT5q3D72aef3brNlVV2RJMBewC8nC8SkW5IkSX3mStJdVXcnOZCmNGQBcFRVnZvkEOCsqjoJ2BX4YJKiKS95y9j2Sban6Sn/3rhdH5tkERDgHOBNk8Vi0i1JkqQ5q6pOBk4eN+/9Pa9PAFY59F9VXcx9b7ykqnabahwm3ZIkSVphjpWXzBiTJt1JtgGOAR4MFLC0qj466sAkqSu2e5LmO5Pu4Rukp/tu4G+r6qdJNgLOTvLtcU/ykaS5xHZP0rxm0j18kybd7ZAoV7Svb0pyHk1ti18+kuYk2z1J85nlJaMxpZru9g7OJwA/HkUwkjTT2O5Jmo9Muodv4MfAt4OFfwl4e1XduIrlB4w9gvPmm68eZoyS1ImptHtXX3fd9AcoSZo1BurpTrIWzRfPsVX15VWtU1VLaR6DyXbbLamhRShJHZhqu7fk8Y+33ZM0J1heMhqDjF4S4FPAeVX1L6MPSZK6Zbsnab4z6R6+QXq6nwrsC/wiyTntvPe0A41L0lxkuydpXjPpHr5BRi/5Ac0jLiVpXrDdkzSfWV4yGj6RUpIkSX1MuofPpFuSJEkr2NM9GgMPGShJkiTp/rGnW5IkSX3s6R4+k25JkiStYHnJaJh0S5IkqY9J9/CZdEuSJKmPSffwmXRLkiRpBctLRsPRSyRJkqQRs6dbkiRJfezpHj6TbkmSJK1geclomHRLkiSpj0n38I0k6V60+T385atuGMWuB1Ybb9Lp8QHY6X1dRwDAU/bbt+sQ4Oiju44Anve8riOAE07oOoLGmWd2e/zbbuv2+KOwYAFsvHGnIWw8A7pRLn3aPl2HAMBrT/ts1yHwnzd33/a+co3/7DoEvrPhy7sOAYCdug5gljHpHr4Z0ERLkiRpprC8ZDRMuiVJktTHpHv4HDJQkiRJGjF7uiVJkrSC5SWjYdItSZKkPibdw2d5iSRJkvrce+/smAaRZPck5ye5MMm7V7F8uyTfSfLzJKclWdyz7J4k57TTST3zH5rkx+0+v5Bk7cniMOmWJEnSCmPlJbNhmkySBcDHgT2AHYF9kuw4brWPAMdU1R8DhwAf7Fl2W1Xt1E4v6pn/YeCwqtoBuB54w2SxmHRLkiSpT9fJ9BB7uncGLqyqi6rqTuB4YM9x6+wIfLd9feoqlvdJEmA3YOzhG58B9posEJNuSZIkzVVbA5f2vF/Wzuv1M+Al7esXAxsl2aJ9v26Ss5KckWQssd4CWF5Vd0+wz/vwRkpJkiStMMtGL1mY5Kye90uraukU9/EO4Igk+wOnA5cB97TLtquqy5I8DPhukl8A9+ux6ybdkiRJ6jOLku5rqmrJBMsvA7bpeb+4nbdCVV1O29OdZEPgpVW1vF12WfvnRUlOA54AfAnYNMmabW/3ffa5KpaXSJIkqU/XtdpDrOk+E3h4O9rI2sDewEm9KyRZmGQsJz4IOKqdv1mSdcbWAZ4K/Kqqiqb2+2XtNq8FvjpZIJMm3UmOSnJVkl8O9NEkaZaz3ZM0n82l0UvanugDgVOA84AvVtW5SQ5JMjYaya7A+Ul+AzwYOLSd/2jgrCQ/o0myP1RVv2qXvQv4myQX0tR4f2qyWAYpLzkaOAI4ZoB1JWkuOBrbPUnz2CwqL5lUVZ0MnDxu3vt7Xp/AypFIetf5H+Bxq9nnRTQjowxs0qS7qk5Psv1UdipJs5ntnqT5bJbdSDlrDK2mO8kB7ZAqZ1197bXD2q0kzVh97d4113QdjiRpBhta0l1VS6tqSVUtWbTFFpNvIEmzXF+7t3Bh1+FI0tB0Xas9xBspZwyHDJQkSVKf2ZbQzgYm3ZIkSVrBmu7RGGTIwOOAHwGPTLIsyRtGH5Ykdcd2T9J813XZyLwsL6mqfaYjEEmaKWz3JM1n9nSPhk+klCRJkkbMmm5JkiT1sad7+Ey6JUmS1Meke/hMuiVJkrSCNd2jYdItSZKkPibdw2fSLUmSpBXs6R4Nk25JkiT1MekePocMlCRJkkbMnm5JkiT1sad7+Ey6JUmStII13aNh0i1JkqQ+Jt3DN5qk+6674PLLR7LrQaXTo7fWX7/rCBpvfWvXEcBFF3UdARx+eNcRwAUXdB1B4/rruz3+3Xd3e/xRuPdeuPXWTkNYa9O1Oz0+wDYPmhl/tze8aN+uQ+Dpt3cdAVxw48u7DoFn7VBdh9Do+P/nmmvMnizWnu7RsKdbkiRJfUy6h8/RSyRJkqQRs6dbkiRJfezpHj6TbkmSJK1gTfdomHRLkiSpj0n38Jl0S5IkaQV7ukfDpFuSJEl9TLqHz6RbkiRJK9jTPRoOGShJkiSNmD3dkiRJ6mNP9/DZ0y1JkqQ+9947O6ZBJNk9yflJLkzy7lUs3y7Jd5L8PMlpSRa383dK8qMk57bLXtmzzdFJfpfknHbaabI47OmWJEnSCnOppjvJAuDjwLOBZcCZSU6qql/1rPYR4Jiq+kyS3YAPAvsCtwL7VdUFSbYCzk5ySlUtb7f7u6o6YdBYBurpnuwXgiTNNbZ7kuazrnuwh9jTvTNwYVVdVFV3AscDe45bZ0fgu+3rU8eWV9VvquqC9vXlwFXAovt7TidNunt+IezRBrVPkh3v7wElaaaz3ZM0n431dM+GaQBbA5f2vF/Wzuv1M+Al7esXAxsl2aJ3hSQ7A2sDv+2ZfWhbdnJYknUmC2SQnu5BfiFI0lxiuydpXus6mZ5C0r0wyVk90wH34+O+A3hGkv8FngFcBtwztjDJlsBngddV1ViqfxDwKOBJwObAuyY7yCA13av6hbDL+JXaD3kAwLZbbjnAbiVpxpp6u7d48fREJknqdU1VLZlg+WXANj3vF7fzVmhLR14CkGRD4KVjddtJNga+Dry3qs7o2eaK9uUdST5Nk7hPaGijl1TV0qpaUlVLFm2++bB2K0kzVl+7t8UWk28gSbNE1z3YQywvORN4eJKHJlkb2Bs4qXeFJAuTjOXEBwFHtfPXBk6kucnyhHHbbNn+GWAv4JeTBTJIT/ekvxAkaY6x3ZM0b82l0Uuq6u4kBwKnAAuAo6rq3CSHAGdV1UnArsAHkxRwOvCWdvNXAE8Htkiyfztv/6o6Bzg2ySIgwDnAmyaLZZCke8UvBJovnb2BVw30SSVpdrLdkzSvzZWkG6CqTgZOHjfv/T2vTwDuM/RfVX0O+Nxq9rnbVOOYNOle3S+EqR5IkmYL2z1J89lc6umeSQZ6OM6qfiFI0lxmuydpPjPpHj4fAy9JkiSNmI+BlyRJUh97uofPpFuSJEkrWNM9GibdkiRJ6mPSPXwm3ZIkSVrBnu7RMOmWJElSH5Pu4TPpliRJUh+T7uFzyEBJkiRpxOzpliRJ0grWdI+GSbckSZL6mHQPn0m3JEmSVrCnezRSVcPfaXI1cMkD2MVC4JohhWMMD9xMiMMY5lYM21XVomEEM1PY7g3VTIjDGIxh2DHMmnZvnXWW1FZbndV1GAO5+OKcXVVLuo5jECPp6X6g/6iSnNX1CTSGmRWHMRjDTGe7N7fiMAZjmGkxTDd7uofP0UskSZKkEbOmW5IkSStY0z0aMzXpXtp1ABhDr5kQhzE0jGHumgnndSbEADMjDmNoGENjJsQwrUy6h28kN1JKkiRpdlprrSW1cOHsuJHyyivn+Y2UkiRJmr3s6R6+GXcjZZLdk5yf5MIk7+7g+EcluSrJL6f72D0xbJPk1CS/SnJukrd1EMO6SX6S5GdtDP93umPoiWVBkv9N8rWOjn9xkl8kOSdJZz/9k2ya5IQkv05yXpKnTPPxH9meg7HpxiRvn84Y5irbPdu9VcTSabvXxtB522e71517750d02wyo8pLkiwAfgM8G1gGnAnsU1W/msYYng7cDBxTVY+druOOi2FLYMuq+mmSjYCzgb2m+TwE2KCqbk6yFvAD4G1VdcZ0xdATy98AS4CNq+oFHRz/YmBJVXU6TmySzwDfr6ojk6wNrF9VyzuKZQFwGbBLVT2QsannPdu9FTHY7vXH0mm718ZwMR23fbZ73VhzzSW1ySazo7zkuutmT3nJTOvp3hm4sKouqqo7geOBPaczgKo6HbhuOo+5ihiuqKqftq9vAs4Dtp7mGKqqbm7frtVO0/4LLcli4PnAkdN97JkkySbA04FPAVTVnV198bSeBfx2rn/xTBPbPWz3etnuNWz3NNfMtKR7a+DSnvfLmOZGd6ZJsj3wBODHHRx7QZJzgKuAb1fVtMcA/CvwTqDLi0gFfCvJ2UkO6CiGhwJXA59uLzkfmWSDjmIB2Bs4rsPjzyW2e+PY7s2Idg+6b/ts9zrUddnIXCwvmWlJt3ok2RD4EvD2qrpxuo9fVfdU1U7AYmDnJNN62TnJC4Crqurs6TzuKjytqp4I7AG8pb0UP93WBJ4IfKKqngDcAkx77S9Ae4n3RcB/dnF8zW22ezOm3YPu2z7bvY6MjdM9G6bZZKYl3ZcB2/S8X9zOm3faesIvAcdW1Ze7jKW9nHcqsPs0H/qpwIvausLjgd2SfG6aY6CqLmv/vAo4kaYcYLotA5b19LqdQPNl1IU9gJ9W1R86Ov5cY7vXst0DZki7BzOi7bPd61DXybRJ9+idCTw8yUPbX5V7Ayd1HNO0a2/m+RRwXlX9S0cxLEqyaft6PZqbvH49nTFU1UFVtbiqtqf5t/DdqnrNdMaQZIP2pi7ay5rPAaZ9hIequhK4NMkj21nPAqbtBrNx9mEeXWKdBrZ72O6NmQntHsyMts92r1tdJ9NzMemeUeN0V9XdSQ4ETgEWAEdV1bnTGUOS44BdgYVJlgEHV9WnpjMGmp6OfYFftLWFAO+pqpOnMYYtgc+0d2uvAXyxqjobuqpDDwZObPIB1gQ+X1Xf7CiWvwKObROzi4DXTXcA7Zfvs4G/mO5jz1W2eyvY7s0sM6Xts93rgI+BH40ZNWSgJEmSurXGGktqnXVmx5CBt9/ukIGSJEmapbouGxlmeUkmeQBZku2SfCfJz5Oc1g7bObbstUkuaKfX9sz/kzQPj7owyeFtidyETLolSZK0wlwavaQtF/s4zc2wOwL7JNlx3GofoXk42B8DhwAfbLfdHDgY2IXmRuKDk2zWbvMJ4M+Bh7fTpDddm3RLkiSpT9fJ9BB7ugd5ANmOwHfb16f2LH8uzXj911XV9cC3gd3bJ+huXFVnVFOnfQyw12SBzKgbKSVJktS9OXQj5aoeQLbLuHV+BrwE+CjwYmCjJFusZtut22nZKuZPyKRbkiRJPc4+BbKw6ygGtG6S3rs+l1bV0inu4x3AEUn2B06neVbCPUOKbwWTbkmSJK1QVdP9UKhRmvQBZFV1OU1P99hTcV9aVcuTXEYznGrvtqe12y8eN3/Sh5pZ0y1JkqS5atIHkCVZmGQsJz4IOKp9fQrwnCSbtTdQPgc4paquAG5M8uR21JL9gK9OFohJtyRJkuakqrobGHsA2Xk0D706N8khSV7UrrYrcH6S39A8GOrQdtvrgH+kSdzPBA5p5wG8GTgSuBD4LfCNyWLx4TiSJEnSiNnTLUmSJI2YSbckSZI0YibdkiRJ0oiZdEuSJEkjZtItSZIkjZhJtyRJkjRiJt2SJEnSiJl0S5IkSSP2/wBF08dc0eG+NAAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Calculate and plot the ratios of MG to CE for each of the 2 MG cases\n", - "ratios = []\n", - "fig, axes = plt.subplots(figsize=(12, 6), nrows=1, ncols=2)\n", - "for i, (case, title, axis) in enumerate(zip(sp_files[1:], titles[1:], axes.flat)):\n", - " # Get our ratio relative to the CE (in fiss_ratios[0])\n", - " ratios.append(np.divide(fiss_rates[i + 1], fiss_rates[0]))\n", - " \n", - " # Plot only the fueled regions\n", - " im = axis.imshow(ratios[-1][1:-1, 1:-1], cmap='bwr', origin='lower',\n", - " vmin = 0.9, vmax = 1.1)\n", - " axis.set_title(title + '\\nFission Rates Relative\\nto Continuous-Energy')\n", - " \n", - "# Add a color bar\n", - "fig.subplots_adjust(right=0.8)\n", - "cbar_ax = fig.add_axes([0.85, 0.15, 0.05, 0.7])\n", - "fig.colorbar(im, cax=cbar_ax)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With this ratio its clear that the errors are significantly worse in the isotropic case. These errors are conveniently located right where the most anisotropy is espected: by the control blades and by the Gd-bearing pins!" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/mgxs-part-i.ipynb b/examples/jupyter/mgxs-part-i.ipynb deleted file mode 100644 index 3d5711adc16..00000000000 --- a/examples/jupyter/mgxs-part-i.ipynb +++ /dev/null @@ -1,1139 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multigroup Cross Section Generation Part I: Introduction\n", - "This IPython Notebook introduces the use of the `openmc.mgxs` module to calculate multi-group cross sections for an infinite homogeneous medium. In particular, this Notebook introduces the the following features:\n", - "\n", - "* **General equations** for scalar-flux averaged multi-group cross sections\n", - "* Creation of multi-group cross sections for an **infinite homogeneous medium**\n", - "* Use of **tally arithmetic** to manipulate multi-group cross sections" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Introduction to Multi-Group Cross Sections (MGXS)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Many Monte Carlo particle transport codes, including OpenMC, use continuous-energy nuclear cross section data. However, most deterministic neutron transport codes use *multi-group cross sections* defined over discretized energy bins or *energy groups*. An example of U-235's continuous-energy fission cross section along with a 16-group cross section computed for a light water reactor spectrum is displayed below." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\ncdttt+F//ud/nOZ5//33YTab8cYbb+Dxxx9HTEwMWrZsiW+++QaAfReJ3r17o2XLlrj99tthtVox\nbdo0dO/eHQCglEKvXr0wevRol9e32Wxo1aoV5s6d6/PyerIMM2bMwPXr15GVleXy+PXr11fOQ0QU\nLLhlmohIg7KyMpSVlTlNM5lMLluId+7ciX/84x/4/e9/j7CwMKxcuRLjx4/Hl19+WTnIPXbsGIYO\nHYpu3brhv//7v9G+fXvs3r0bjz32GPLy8rBkyRKn51y8eDGGDh2KNWvWwGw2o127dlizZg3+7d/+\nDf/yL/+CVatWobCwEBkZGbh+/TpMJlNl37x587BgwQJ8/fXX6NmzZ+Vzbty4EcXFxT4Ppj1dhvvu\nuw9du3bFa6+95vRa5eXl2LRpE+Lj42vcfYaIyDCKiIj8Zv369cpkMtV4a9asmdO8JpNJdejQQdls\ntspply5dUk2aNFHPP/985bT7779fdenSRRUXFzs9ft68eSokJEQVFhYqpZR67733lMlkUiNGjHCa\nr7y8XLVv317Fx8c7TT937pxq3ry56t69e+W0oqIiFRERodLT053mve2229R9991X67KfPn1amUwm\n9frrr7vcV9cyXLlypXJaRkaGMplM6tChQ5XTduzYoUwmk3r11VdrfO27775bxcXF1dpHRKQDd/Mg\nItJg06ZN+Mc//uF0O3DggMt899xzD8LCwip/jo6ORnR0NM6dOwcAuHbtGv73f/8X48ePR8uWLSu3\neJeVlWHMmDG4du0aPv74Y6fn/NWvfuX085dffolLly5h4sSJTtM7d+6MhIQEp2kWiwXTpk3Dhg0b\ncPXqVQDA3//+dxw/ftznrdLeLkNaWhrMZjNee+21ymnr169HeHg4HnroIZ8aiIh04WCaiEiD2NhY\n3HHHHU63QYMGuczXpk0bl2ktWrTAjz/+CADIz89HeXk5Vq9ejebNmzvdkpKSYDKZkJeX5/T4Dh06\nOP2cn58PALjllltcXis6Otpl2rx581BUVFS53/KLL76ILl264MEHH/Rw6Z15sgyORsA+yB85ciT+\n/Oc/o7S0FHl5edixYwdSUlKcfvEgIgoG3GeaiCiIRUVFoUmTJpg6dSoeffTRGufp1q2b08+OfaAd\nHAP277//3uWxNU3r2bMnxowZg5deegmjR49GTk4Oli9f7vK8OpdhxowZ2LNnD7Kzs3HhwgWUlZVh\n+vTpPr0+EZFOHEwTEQWx0NBQ3HPPPcjNzUVcXByaNWvm9XP07dsX7du3x1/+8hcsWLCgcvq5c+ew\nf/9+dOrUyeUx8+fPx/33349//dd/RfPmzTFr1qyALsO4cePQpk0bvPbaa7h48SL69OnjsksKEVEw\n4GCaiEiDI0eO4MaNGy7Te/bsibZt29b6WFXtWlqrVq3CsGHDMHz4cMyePRtdu3ZFcXExvv76a+zY\nsQN///vfa30+k8mEjIwMPPLII0hJSUFaWhoKCwuxfPlydOzYEWaz6x5/o0aNQmxsLN5//31MmTKl\nzua6eLsMzZo1w69//WusWrUKALBixYp6vT4RkS4cTBMR+ZFjV4i0tLQa71u7dm2duytU350iNjYW\nubm5WL58OX73u9/hhx9+QGRkJHr37o2xY8fW+liHWbNmwWQyYeXKlZgwYQK6d++O3/72t8jOzsb5\n8+drfMzEiRORkZFRr3NL+7IMDjNmzMCqVavQtGlTTJ06td4NREQ68HLiRESNVGFhIXr37o0JEybg\nT3/6k8v9d955J5o1a+ZythB3HJcTX7duHaZMmYKmTfVvr1FKoby8HPfddx8KCgpw5MgR7a9JRFQV\nz+ZBRNQIXLp0CfPmzcP27dvxf//3f9i4cSPuuecelJSUYP78+ZXzFRcXY//+/XjyySdx6NAhPPnk\nk16/1owZM9C8eXNs377dn4tQo/Hjx6N58+b48MMPfT5AkoioPrhlmoioESgsLMTUqVPx6aefoqCg\nAKGhoYiPj0dGRgYGDx5cOd/777+Pe++9F23btsXcuXNdrq5Ym9LSUqctw7feeisiIyP9uhzVnTp1\nCoWFhQCAkJAQxMbGan09IqLqOJgmIiIiIvIRd/MgIiIiIvIRB9NERERERD7iYJqIiIiIyEccTBMR\nERER+YiDaSIiIiIiH3EwTURERETkIw6miYiIiIh8xME0EREREZGPOJgmIiIiIvLR/wcwWUbzha5y\njwAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "execution_count": 1, - "metadata": { - "image/png": { - "width": 350 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "Image(filename='images/mgxs.png', width=350)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A variety of tools employing different methodologies have been developed over the years to compute multi-group cross sections for certain applications, including NJOY (LANL), MC$^2$-3 (ANL), and Serpent (VTT). The `openmc.mgxs` Python module is designed to leverage OpenMC's tally system to calculate multi-group cross sections with arbitrary energy discretizations for fine-mesh heterogeneous deterministic neutron transport applications.\n", - "\n", - "Before proceeding to illustrate how one may use the `openmc.mgxs` module, it is worthwhile to define the general equations used to calculate multi-group cross sections. This is only intended as a brief overview of the methodology used by `openmc.mgxs` - we refer the interested reader to the large body of literature on the subject for a more comprehensive understanding of this complex topic." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Introductory Notation\n", - "The continuous real-valued microscopic cross section may be denoted $\\sigma_{n,x}(\\mathbf{r}, E)$ for position vector $\\mathbf{r}$, energy $E$, nuclide $n$ and interaction type $x$. Similarly, the scalar neutron flux may be denoted by $\\Phi(\\mathbf{r},E)$ for position $\\mathbf{r}$ and energy $E$. **Note**: Although nuclear cross sections are dependent on the temperature $T$ of the interacting medium, the temperature variable is neglected here for brevity." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Spatial and Energy Discretization\n", - "The energy domain for critical systems such as thermal reactors spans more than 10 orders of magnitude of neutron energies from 10$^{-5}$ - 10$^7$ eV. The multi-group approximation discretization divides this energy range into one or more energy groups. In particular, for $G$ total groups, we denote an energy group index $g$ such that $g \\in \\{1, 2, ..., G\\}$. The energy group indices are defined such that the smaller group the higher the energy, and vice versa. The integration over neutron energies across a discrete energy group is commonly referred to as **energy condensation**.\n", - "\n", - "Multi-group cross sections are computed for discretized spatial zones in the geometry of interest. The spatial zones may be defined on a structured and regular fuel assembly or pin cell mesh, an arbitrary unstructured mesh or the constructive solid geometry used by OpenMC. For a geometry with $K$ distinct spatial zones, we designate each spatial zone an index $k$ such that $k \\in \\{1, 2, ..., K\\}$. The volume of each spatial zone is denoted by $V_{k}$. The integration over discrete spatial zones is commonly referred to as **spatial homogenization**." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### General Scalar-Flux Weighted MGXS\n", - "The multi-group cross sections computed by `openmc.mgxs` are defined as a *scalar flux-weighted average* of the microscopic cross sections across each discrete energy group. This formulation is employed in order to preserve the reaction rates within each energy group and spatial zone. In particular, spatial homogenization and energy condensation are used to compute the general multi-group cross section $\\sigma_{n,x,k,g}$ as follows:\n", - "\n", - "$$\\sigma_{n,x,k,g} = \\frac{\\int_{E_{g}}^{E_{g-1}}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r}\\sigma_{n,x}(\\mathbf{r},E')\\Phi(\\mathbf{r},E')}{\\int_{E_{g}}^{E_{g-1}}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r}\\Phi(\\mathbf{r},E')}$$\n", - "\n", - "This scalar flux-weighted average microscopic cross section is computed by `openmc.mgxs` for most multi-group cross sections, including total, absorption, and fission reaction types. These double integrals are stochastically computed with OpenMC's tally system - in particular, [filters](../usersguide/tallies.rst#filters) on the energy range and spatial zone (material, cell or universe) define the bounds of integration for both numerator and denominator." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Multi-Group Scattering Matrices\n", - "The general multi-group cross section $\\sigma_{n,x,k,g}$ is a vector of $G$ values for each energy group $g$. The equation presented above only discretizes the energy of the incoming neutron and neglects the outgoing energy of the neutron (if any). Hence, this formulation must be extended to account for the outgoing energy of neutrons in the discretized scattering matrix cross section used by deterministic neutron transport codes. \n", - "\n", - "We denote the incoming and outgoing neutron energy groups as $g$ and $g'$ for the microscopic scattering matrix cross section $\\sigma_{n,s}(\\mathbf{r},E)$. As before, spatial homogenization and energy condensation are used to find the multi-group scattering matrix cross section $\\sigma_{n,s,k,g \\to g'}$ as follows:\n", - "\n", - "$$\\sigma_{n,s,k,g\\rightarrow g'} = \\frac{\\int_{E_{g'}}^{E_{g'-1}}\\mathrm{d}E''\\int_{E_{g}}^{E_{g-1}}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r}\\sigma_{n,s}(\\mathbf{r},E'\\rightarrow E'')\\Phi(\\mathbf{r},E')}{\\int_{E_{g}}^{E_{g-1}}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r}\\Phi(\\mathbf{r},E')}$$\n", - "\n", - "This scalar flux-weighted multi-group microscopic scattering matrix is computed using OpenMC tallies with both energy in and energy out filters." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Multi-Group Fission Spectrum\n", - "The energy spectrum of neutrons emitted from fission is denoted by $\\chi_{n}(\\mathbf{r},E' \\rightarrow E'')$ for incoming and outgoing energies $E'$ and $E''$, respectively. Unlike the multi-group cross sections $\\sigma_{n,x,k,g}$ considered up to this point, the fission spectrum is a probability distribution and must sum to unity. The outgoing energy is typically much less dependent on the incoming energy for fission than for scattering interactions. As a result, it is common practice to integrate over the incoming neutron energy when computing the multi-group fission spectrum. The fission spectrum may be simplified as $\\chi_{n}(\\mathbf{r},E)$ with outgoing energy $E$.\n", - "\n", - "Unlike the multi-group cross sections defined up to this point, the multi-group fission spectrum is weighted by the fission production rate rather than the scalar flux. This formulation is intended to preserve the total fission production rate in the multi-group deterministic calculation. In order to mathematically define the multi-group fission spectrum, we denote the microscopic fission cross section as $\\sigma_{n,f}(\\mathbf{r},E)$ and the average number of neutrons emitted from fission interactions with nuclide $n$ as $\\nu_{n}(\\mathbf{r},E)$. The multi-group fission spectrum $\\chi_{n,k,g}$ is then the probability of fission neutrons emitted into energy group $g$. \n", - "\n", - "Similar to before, spatial homogenization and energy condensation are used to find the multi-group fission spectrum $\\chi_{n,k,g}$ as follows:\n", - "\n", - "$$\\chi_{n,k,g'} = \\frac{\\int_{E_{g'}}^{E_{g'-1}}\\mathrm{d}E''\\int_{0}^{\\infty}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r}\\chi_{n}(\\mathbf{r},E'\\rightarrow E'')\\nu_{n}(\\mathbf{r},E')\\sigma_{n,f}(\\mathbf{r},E')\\Phi(\\mathbf{r},E')}{\\int_{0}^{\\infty}\\mathrm{d}E'\\int_{\\mathbf{r} \\in V_{k}}\\mathrm{d}\\mathbf{r}\\nu_{n}(\\mathbf{r},E')\\sigma_{n,f}(\\mathbf{r},E')\\Phi(\\mathbf{r},E')}$$\n", - "\n", - "The fission production-weighted multi-group fission spectrum is computed using OpenMC tallies with both energy in and energy out filters.\n", - "\n", - "This concludes our brief overview on the methodology to compute multi-group cross sections. The following sections detail more concretely how users may employ the `openmc.mgxs` module to power simulation workflows requiring multi-group cross sections for downstream deterministic calculations." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "import openmc\n", - "import openmc.mgxs as mgxs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We being by creating a material for the homogeneous medium." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# Instantiate a Material and register the Nuclides\n", - "inf_medium = openmc.Material(name='moderator')\n", - "inf_medium.set_density('g/cc', 5.)\n", - "inf_medium.add_nuclide('H1', 0.028999667)\n", - "inf_medium.add_nuclide('O16', 0.01450188)\n", - "inf_medium.add_nuclide('U235', 0.000114142)\n", - "inf_medium.add_nuclide('U238', 0.006886019)\n", - "inf_medium.add_nuclide('Zr90', 0.002116053)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our material, we can now create a `Materials` object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# Instantiate a Materials collection and export to XML\n", - "materials_file = openmc.Materials([inf_medium])\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. This problem will be a simple square cell with reflective boundary conditions to simulate an infinite homogeneous medium. The first step is to create the outer bounding surfaces of the problem." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# Instantiate boundary Planes\n", - "min_x = openmc.XPlane(boundary_type='reflective', x0=-0.63)\n", - "max_x = openmc.XPlane(boundary_type='reflective', x0=0.63)\n", - "min_y = openmc.YPlane(boundary_type='reflective', y0=-0.63)\n", - "max_y = openmc.YPlane(boundary_type='reflective', y0=0.63)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now create a cell that is defined by intersections of half-spaces created by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Cell\n", - "cell = openmc.Cell(cell_id=1, name='cell')\n", - "\n", - "# Register bounding Surfaces with the Cell\n", - "cell.region = +min_x & -max_x & +min_y & -max_y\n", - "\n", - "# Fill the Cell with the Material\n", - "cell.fill = inf_medium" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC requires that there is a \"root\" universe. Let us create a root universe and add our square cell to it." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# Create root universe\n", - "root_universe = openmc.Universe(name='root universe', cells=[cell])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now must create a geometry that is assigned a root universe and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and set root Universe\n", - "openmc_geometry = openmc.Geometry(root_universe)\n", - "\n", - "# Export to \"geometry.xml\"\n", - "openmc_geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we must define simulation parameters. In this case, we will use 10 inactive batches and 40 active batches each with 2500 particles." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "batches = 50\n", - "inactive = 10\n", - "particles = 2500\n", - "\n", - "# Instantiate a Settings object\n", - "settings_file = openmc.Settings()\n", - "settings_file.batches = batches\n", - "settings_file.inactive = inactive\n", - "settings_file.particles = particles\n", - "settings_file.output = {'tallies': True}\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-0.63, -0.63, -0.63, 0.63, 0.63, 0.63]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings_file.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we are ready to generate multi-group cross sections! First, let's define a 2-group structure using the built-in `EnergyGroups` class." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a 2-group EnergyGroups object\n", - "groups = mgxs.EnergyGroups()\n", - "groups.group_edges = np.array([0., 0.625, 20.0e6])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now use the `EnergyGroups` object, along with our previously created materials and geometry, to instantiate some `MGXS` objects from the `openmc.mgxs` module. In particular, the following are subclasses of the generic and abstract `MGXS` class:\n", - "\n", - "* `TotalXS`\n", - "* `TransportXS`\n", - "* `AbsorptionXS`\n", - "* `CaptureXS`\n", - "* `FissionXS`\n", - "* `KappaFissionXS`\n", - "* `ScatterXS`\n", - "* `ScatterMatrixXS`\n", - "* `Chi`\n", - "* `ChiPrompt`\n", - "* `InverseVelocity`\n", - "* `PromptNuFissionXS`\n", - "\n", - "Of course, we are aware that the fission cross section (`FissionXS`) can sometimes be paired with the fission neutron multiplication to become $\\nu\\sigma_f$. This can be accomodated in to the `FissionXS` class by setting the `nu` parameter to `True` as shown below.\n", - "\n", - "Additionally, scattering reactions (like (n,2n)) can also be defined to take in to account the neutron multiplication to become $\\nu\\sigma_s$. This can be accomodated in the the transport (`TransportXS`), scattering (`ScatterXS`), and scattering-matrix (`ScatterMatrixXS`) cross sections types by setting the `nu` parameter to `True` as shown below.\n", - "\n", - "These classes provide us with an interface to generate the tally inputs as well as perform post-processing of OpenMC's tally data to compute the respective multi-group cross sections. In this case, let's create the multi-group total, absorption and scattering cross sections with our 2-group structure." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a few different sections\n", - "total = mgxs.TotalXS(domain=cell, groups=groups)\n", - "absorption = mgxs.AbsorptionXS(domain=cell, groups=groups)\n", - "scattering = mgxs.ScatterXS(domain=cell, groups=groups)\n", - "\n", - "# Note that if we wanted to incorporate neutron multiplication in the\n", - "# scattering cross section we would write the previous line as:\n", - "# scattering = mgxs.ScatterXS(domain=cell, groups=groups, nu=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Each multi-group cross section object stores its tallies in a Python dictionary called `tallies`. We can inspect the tallies in the dictionary for our `Absorption` object as follows. " - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "OrderedDict([('flux', Tally\n", - " \tID =\t1\n", - " \tName =\t\n", - " \tFilters =\tCellFilter, EnergyFilter\n", - " \tNuclides =\ttotal \n", - " \tScores =\t['flux']\n", - " \tEstimator =\ttracklength), ('absorption', Tally\n", - " \tID =\t2\n", - " \tName =\t\n", - " \tFilters =\tCellFilter, EnergyFilter\n", - " \tNuclides =\ttotal \n", - " \tScores =\t['absorption']\n", - " \tEstimator =\ttracklength)])" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "absorption.tallies" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `Absorption` object includes tracklength tallies for the 'absorption' and 'flux' scores in the 2-group structure in cell 1. Now that each `MGXS` object contains the tallies that it needs, we must add these tallies to a `Tallies` object to generate the \"tallies.xml\" input file for OpenMC." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another CellFilter instance already exists with id=3.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:61: IDWarning: Another EnergyFilter instance already exists with id=4.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Instantiate an empty Tallies object\n", - "tallies_file = openmc.Tallies()\n", - "\n", - "# Add total tallies to the tallies file\n", - "tallies_file += total.tallies.values()\n", - "\n", - "# Add absorption tallies to the tallies file\n", - "tallies_file += absorption.tallies.values()\n", - "\n", - "# Add scattering tallies to the tallies file\n", - "tallies_file += scattering.tallies.values()\n", - "\n", - "# Export to \"tallies.xml\"\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we a have a complete set of inputs, so we can go ahead and run our simulation." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2017 Massachusetts Institute of Technology\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.9.0\n", - " Git SHA1 | 9b7cebf7bc34d60e0f1750c3d6cb103df11e8dc4\n", - " Date/Time | 2017-12-04 20:56:46\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Building neighboring cells lists for each surface...\n", - " Reading H1 from /home/romano/openmc/scripts/nndc_hdf5/H1.h5\n", - " Reading O16 from /home/romano/openmc/scripts/nndc_hdf5/O16.h5\n", - " Reading U235 from /home/romano/openmc/scripts/nndc_hdf5/U235.h5\n", - " Reading U238 from /home/romano/openmc/scripts/nndc_hdf5/U238.h5\n", - " Reading Zr90 from /home/romano/openmc/scripts/nndc_hdf5/Zr90.h5\n", - " Maximum neutron transport energy: 2.00000E+07 eV for H1\n", - " Reading tallies XML file...\n", - " Writing summary.h5 file...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k \n", - " ========= ======== ==================== \n", - " 1/1 1.11184 \n", - " 2/1 1.15820 \n", - " 3/1 1.18468 \n", - " 4/1 1.17492 \n", - " 5/1 1.19645 \n", - " 6/1 1.18436 \n", - " 7/1 1.14070 \n", - " 8/1 1.15150 \n", - " 9/1 1.19202 \n", - " 10/1 1.17677 \n", - " 11/1 1.20272 \n", - " 12/1 1.21366 1.20819 +/- 0.00547\n", - " 13/1 1.15906 1.19181 +/- 0.01668\n", - " 14/1 1.14687 1.18058 +/- 0.01629\n", - " 15/1 1.14570 1.17360 +/- 0.01442\n", - " 16/1 1.13480 1.16713 +/- 0.01343\n", - " 17/1 1.17680 1.16852 +/- 0.01144\n", - " 18/1 1.16866 1.16853 +/- 0.00990\n", - " 19/1 1.19253 1.17120 +/- 0.00913\n", - " 20/1 1.18124 1.17220 +/- 0.00823\n", - " 21/1 1.19206 1.17401 +/- 0.00766\n", - " 22/1 1.17681 1.17424 +/- 0.00700\n", - " 23/1 1.17634 1.17440 +/- 0.00644\n", - " 24/1 1.13659 1.17170 +/- 0.00654\n", - " 25/1 1.17144 1.17169 +/- 0.00609\n", - " 26/1 1.20649 1.17386 +/- 0.00610\n", - " 27/1 1.11238 1.17024 +/- 0.00678\n", - " 28/1 1.18911 1.17129 +/- 0.00647\n", - " 29/1 1.14681 1.17000 +/- 0.00626\n", - " 30/1 1.12152 1.16758 +/- 0.00641\n", - " 31/1 1.12729 1.16566 +/- 0.00639\n", - " 32/1 1.15399 1.16513 +/- 0.00612\n", - " 33/1 1.13547 1.16384 +/- 0.00599\n", - " 34/1 1.17723 1.16440 +/- 0.00576\n", - " 35/1 1.09296 1.16154 +/- 0.00622\n", - " 36/1 1.19621 1.16287 +/- 0.00612\n", - " 37/1 1.12560 1.16149 +/- 0.00605\n", - " 38/1 1.17872 1.16211 +/- 0.00586\n", - " 39/1 1.17721 1.16263 +/- 0.00568\n", - " 40/1 1.13724 1.16178 +/- 0.00555\n", - " 41/1 1.18526 1.16254 +/- 0.00542\n", - " 42/1 1.13779 1.16177 +/- 0.00531\n", - " 43/1 1.15066 1.16143 +/- 0.00516\n", - " 44/1 1.12174 1.16026 +/- 0.00514\n", - " 45/1 1.17478 1.16068 +/- 0.00501\n", - " 46/1 1.14146 1.16014 +/- 0.00489\n", - " 47/1 1.20464 1.16135 +/- 0.00491\n", - " 48/1 1.15119 1.16108 +/- 0.00479\n", - " 49/1 1.17938 1.16155 +/- 0.00468\n", - " 50/1 1.15798 1.16146 +/- 0.00457\n", - " Creating state point statepoint.50.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 4.0504E-01 seconds\n", - " Reading cross sections = 3.6457E-01 seconds\n", - " Total time in simulation = 6.3478E+00 seconds\n", - " Time in transport only = 6.0079E+00 seconds\n", - " Time in inactive batches = 8.1713E-01 seconds\n", - " Time in active batches = 5.5307E+00 seconds\n", - " Time synchronizing fission bank = 5.4640E-03 seconds\n", - " Sampling source sites = 4.0981E-03 seconds\n", - " SEND/RECV source sites = 1.2606E-03 seconds\n", - " Time accumulating tallies = 1.2030E-04 seconds\n", - " Total time for finalization = 9.6554E-04 seconds\n", - " Total time elapsed = 6.7713E+00 seconds\n", - " Calculation Rate (inactive) = 30594.8 neutrons/second\n", - " Calculation Rate (active) = 18080.8 neutrons/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.15984 +/- 0.00411\n", - " k-effective (Track-length) = 1.16146 +/- 0.00457\n", - " k-effective (Absorption) = 1.16177 +/- 0.00380\n", - " Combined k-effective = 1.16105 +/- 0.00364\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "0" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Run OpenMC\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our simulation ran successfully and created statepoint and summary output files. We begin our analysis by instantiating a `StatePoint` object. " - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the last statepoint file\n", - "sp = openmc.StatePoint('statepoint.50.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In addition to the statepoint file, our simulation also created a summary file which encapsulates information about the materials and geometry. By default, a `Summary` object is automatically linked when a `StatePoint` is loaded. This is necessary for the `openmc.mgxs` module to properly process the tally data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The statepoint is now ready to be analyzed by our multi-group cross sections. We simply have to load the tallies from the `StatePoint` into each object as follows and our `MGXS` objects will compute the cross sections for us under-the-hood." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the tallies from the statepoint into each MGXS object\n", - "total.load_from_statepoint(sp)\n", - "absorption.load_from_statepoint(sp)\n", - "scattering.load_from_statepoint(sp)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Voila! Our multi-group cross sections are now ready to rock 'n roll!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Extracting and Storing MGXS Data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's first inspect our total cross section by printing it to the screen." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Multi-Group XS\n", - "\tReaction Type =\ttotal\n", - "\tDomain Type =\tcell\n", - "\tDomain ID =\t1\n", - "\tCross Sections [cm^-1]:\n", - " Group 1 [0.625 - 20000000.0eV]:\t6.81e-01 +/- 2.69e-01%\n", - " Group 2 [0.0 - 0.625 eV]:\t1.40e+00 +/- 5.93e-01%\n", - "\n", - "\n", - "\n" - ] - } - ], - "source": [ - "total.print_xs()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Since the `openmc.mgxs` module uses [tally arithmetic](../examples/tally-arithmetic.rst) under-the-hood, the cross section is stored as a \"derived\" `Tally` object. This means that it can be queried and manipulated using all of the same methods supported for the `Tally` class in the OpenMC Python API. For example, we can construct a [Pandas](https://pandas.pydata.org/) `DataFrame` of the multi-group cross section data." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellgroup innuclidemeanstd. dev.
111total0.6677870.001802
012total1.2920130.007642
\n", - "
" - ], - "text/plain": [ - " cell group in nuclide mean std. dev.\n", - "1 1 1 total 0.667787 0.001802\n", - "0 1 2 total 1.292013 0.007642" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = scattering.get_pandas_dataframe()\n", - "df.head(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Each multi-group cross section object can be easily exported to a variety of file formats, including CSV, Excel, and LaTeX for storage or data processing." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "absorption.export_xs_data(filename='absorption-xs', format='excel')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The following code snippet shows how to export all three `MGXS` to the same HDF5 binary data store." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "total.build_hdf5_store(filename='mgxs', append=True)\n", - "absorption.build_hdf5_store(filename='mgxs', append=True)\n", - "scattering.build_hdf5_store(filename='mgxs', append=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Comparing MGXS with Tally Arithmetic" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, we illustrate how one can leverage OpenMC's [tally arithmetic](../examples/tally-arithmetic.rst) data processing feature with `MGXS` objects. The `openmc.mgxs` module uses tally arithmetic to compute multi-group cross sections with automated uncertainty propagation. Each `MGXS` object includes an `xs_tally` attribute which is a \"derived\" `Tally` based on the tallies needed to compute the cross section type of interest. These derived tallies can be used in subsequent tally arithmetic operations. For example, we can use tally artithmetic to confirm that the `TotalXS` is equal to the sum of the `AbsorptionXS` and `ScatterXS` objects." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01total(((total / flux) - (absorption / flux)) - (sca...-1.110223e-150.011292
110.6252.000000e+07total(((total / flux) - (absorption / flux)) - (sca...7.771561e-160.002570
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 1 0.00e+00 6.25e-01 total \n", - "1 1 6.25e-01 2.00e+07 total \n", - "\n", - " score mean std. dev. \n", - "0 (((total / flux) - (absorption / flux)) - (sca... -1.11e-15 1.13e-02 \n", - "1 (((total / flux) - (absorption / flux)) - (sca... 7.77e-16 2.57e-03 " - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Use tally arithmetic to compute the difference between the total, absorption and scattering\n", - "difference = total.xs_tally - absorption.xs_tally - scattering.xs_tally\n", - "\n", - "# The difference is a derived tally which can generate Pandas DataFrames for inspection\n", - "difference.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Similarly, we can use tally arithmetic to compute the ratio of `AbsorptionXS` and `ScatterXS` to the `TotalXS`." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01total((absorption / flux) / (total / flux))0.0761150.000649
110.6252.000000e+07total((absorption / flux) / (total / flux))0.0192630.000095
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 1 0.00e+00 6.25e-01 total \n", - "1 1 6.25e-01 2.00e+07 total \n", - "\n", - " score mean std. dev. \n", - "0 ((absorption / flux) / (total / flux)) 7.61e-02 6.49e-04 \n", - "1 ((absorption / flux) / (total / flux)) 1.93e-02 9.46e-05 " - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Use tally arithmetic to compute the absorption-to-total MGXS ratio\n", - "absorption_to_total = absorption.xs_tally / total.xs_tally\n", - "\n", - "# The absorption-to-total ratio is a derived tally which can generate Pandas DataFrames for inspection\n", - "absorption_to_total.get_pandas_dataframe()" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01total((scatter / flux) / (total / flux))0.9238850.007736
110.6252.000000e+07total((scatter / flux) / (total / flux))0.9807370.003737
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 1 0.00e+00 6.25e-01 total \n", - "1 1 6.25e-01 2.00e+07 total \n", - "\n", - " score mean std. dev. \n", - "0 ((scatter / flux) / (total / flux)) 9.24e-01 7.74e-03 \n", - "1 ((scatter / flux) / (total / flux)) 9.81e-01 3.74e-03 " - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Use tally arithmetic to compute the scattering-to-total MGXS ratio\n", - "scattering_to_total = scattering.xs_tally / total.xs_tally\n", - "\n", - "# The scattering-to-total ratio is a derived tally which can generate Pandas DataFrames for inspection\n", - "scattering_to_total.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Lastly, we sum the derived scatter-to-total and absorption-to-total ratios to confirm that they sum to unity." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01total(((absorption / flux) / (total / flux)) + ((sc...1.00.007763
110.6252.000000e+07total(((absorption / flux) / (total / flux)) + ((sc...1.00.003739
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 1 0.00e+00 6.25e-01 total \n", - "1 1 6.25e-01 2.00e+07 total \n", - "\n", - " score mean std. dev. \n", - "0 (((absorption / flux) / (total / flux)) + ((sc... 1.00e+00 7.76e-03 \n", - "1 (((absorption / flux) / (total / flux)) + ((sc... 1.00e+00 3.74e-03 " - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Use tally arithmetic to ensure that the absorption- and scattering-to-total MGXS ratios sum to unity\n", - "sum_ratio = absorption_to_total + scattering_to_total\n", - "\n", - "# The sum ratio is a derived tally which can generate Pandas DataFrames for inspection\n", - "sum_ratio.get_pandas_dataframe()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/mgxs-part-ii.ipynb b/examples/jupyter/mgxs-part-ii.ipynb deleted file mode 100644 index 495f0121100..00000000000 --- a/examples/jupyter/mgxs-part-ii.ipynb +++ /dev/null @@ -1,2745 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multigroup Cross Section Generation Part II: Advanced Features\n", - "This IPython Notebook illustrates the use of the `openmc.mgxs` module to calculate multi-group cross sections for a heterogeneous fuel pin cell geometry. In particular, this Notebook illustrates the following features:\n", - "\n", - "* Creation of multi-group cross sections on a **heterogeneous geometry**\n", - "* Calculation of cross sections on a **nuclide-by-nuclide basis**\n", - "* The use of **[tally precision triggers](../io_formats/settings.rst#trigger-element)** with multi-group cross sections\n", - "* Built-in features for **energy condensation** in downstream data processing\n", - "* The use of the **`openmc.data`** module to plot continuous-energy vs. multi-group cross sections\n", - "* **Validation** of multi-group cross sections with **[OpenMOC](https://mit-crpg.github.io/OpenMOC/)**\n", - "\n", - "**Note:** This Notebook was created using [OpenMOC](https://mit-crpg.github.io/OpenMOC/) to verify the multi-group cross-sections generated by OpenMC. You must install [OpenMOC](https://mit-crpg.github.io/OpenMOC/) on your system in order to run this Notebook in its entirety. In addition, this Notebook illustrates the use of [Pandas](https://pandas.pydata.org/) `DataFrames` to containerize multi-group cross section data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "plt.style.use('seaborn-dark')\n", - "\n", - "import openmoc\n", - "\n", - "import openmc\n", - "import openmc.mgxs as mgxs\n", - "import openmc.data\n", - "from openmc.openmoc_compatible import get_openmoc_geometry\n", - "\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we need to define materials that will be used in the problem. We'll create three distinct materials for water, clad and fuel." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# 1.6% enriched fuel\n", - "fuel = openmc.Material(name='1.6% Fuel')\n", - "fuel.set_density('g/cm3', 10.31341)\n", - "fuel.add_nuclide('U235', 3.7503e-4)\n", - "fuel.add_nuclide('U238', 2.2625e-2)\n", - "fuel.add_nuclide('O16', 4.6007e-2)\n", - "\n", - "# borated water\n", - "water = openmc.Material(name='Borated Water')\n", - "water.set_density('g/cm3', 0.740582)\n", - "water.add_nuclide('H1', 4.9457e-2)\n", - "water.add_nuclide('O16', 2.4732e-2)\n", - "\n", - "# zircaloy\n", - "zircaloy = openmc.Material(name='Zircaloy')\n", - "zircaloy.set_density('g/cm3', 6.55)\n", - "zircaloy.add_nuclide('Zr90', 7.2758e-3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our materials, we can now create a `Materials` object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Materials collection\n", - "materials_file = openmc.Materials([fuel, water, zircaloy])\n", - "\n", - "# Export to \"materials.xml\"\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. Our problem will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces -- in this case two cylinders and six reflective planes." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Create cylinders for the fuel and clad\n", - "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.39218)\n", - "clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.45720)\n", - "\n", - "# Create box to surround the geometry\n", - "box = openmc.model.rectangular_prism(1.26, 1.26, boundary_type='reflective')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now create cells that are defined by intersections of half-spaces created by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a Universe to encapsulate a fuel pin\n", - "pin_cell_universe = openmc.Universe(name='1.6% Fuel Pin')\n", - "\n", - "# Create fuel Cell\n", - "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", - "fuel_cell.fill = fuel\n", - "fuel_cell.region = -fuel_outer_radius\n", - "pin_cell_universe.add_cell(fuel_cell)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='1.6% Clad')\n", - "clad_cell.fill = zircaloy\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "pin_cell_universe.add_cell(clad_cell)\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", - "moderator_cell.fill = water\n", - "moderator_cell.region = +clad_outer_radius & box\n", - "pin_cell_universe.add_cell(moderator_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now must create a geometry with the pin cell universe and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and set root Universe\n", - "openmc_geometry = openmc.Geometry(pin_cell_universe)\n", - "\n", - "# Export to \"geometry.xml\"\n", - "openmc_geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we must define simulation parameters. In this case, we will use 10 inactive batches and 40 active batches each with 10,000 particles." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "batches = 50\n", - "inactive = 10\n", - "particles = 10000\n", - "\n", - "# Instantiate a Settings object\n", - "settings_file = openmc.Settings()\n", - "settings_file.batches = batches\n", - "settings_file.inactive = inactive\n", - "settings_file.particles = particles\n", - "settings_file.output = {'tallies': True}\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-0.63, -0.63, -0.63, 0.63, 0.63, 0.63]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings_file.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Activate tally precision triggers\n", - "settings_file.trigger_active = True\n", - "settings_file.trigger_max_batches = settings_file.batches * 4\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we are finally ready to make use of the `openmc.mgxs` module to generate multi-group cross sections! First, let's define \"coarse\" 2-group and \"fine\" 8-group structures using the built-in `EnergyGroups` class." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a \"coarse\" 2-group EnergyGroups object\n", - "coarse_groups = mgxs.EnergyGroups([0., 0.625, 20.0e6])\n", - "\n", - "# Instantiate a \"fine\" 8-group EnergyGroups object\n", - "fine_groups = mgxs.EnergyGroups([0., 0.058, 0.14, 0.28,\n", - " 0.625, 4.0, 5.53e3, 821.0e3, 20.0e6])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we will instantiate a variety of `MGXS` objects needed to run an OpenMOC simulation to verify the accuracy of our cross sections. In particular, we define transport, fission, nu-fission, nu-scatter and chi cross sections for each of the three cells in the fuel pin with the 8-group structure as our energy groups." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Extract all Cells filled by Materials\n", - "openmc_cells = openmc_geometry.get_all_material_cells().values()\n", - "\n", - "# Create dictionary to store multi-group cross sections for all cells\n", - "xs_library = {}\n", - "\n", - "# Instantiate 8-group cross sections for each cell\n", - "for cell in openmc_cells:\n", - " xs_library[cell.id] = {}\n", - " xs_library[cell.id]['transport'] = mgxs.TransportXS(groups=fine_groups)\n", - " xs_library[cell.id]['fission'] = mgxs.FissionXS(groups=fine_groups)\n", - " xs_library[cell.id]['nu-fission'] = mgxs.FissionXS(groups=fine_groups, nu=True)\n", - " xs_library[cell.id]['nu-scatter'] = mgxs.ScatterMatrixXS(groups=fine_groups, nu=True)\n", - " xs_library[cell.id]['chi'] = mgxs.Chi(groups=fine_groups)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we showcase the use of OpenMC's [tally precision trigger](../io_formats/settings.rst#trigger-element) feature in conjunction with the `openmc.mgxs` module. In particular, we will assign a tally trigger of 1E-2 on the standard deviation for each of the tallies used to compute multi-group cross sections." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a tally trigger for +/- 0.01 on each tally used to compute the multi-group cross sections\n", - "tally_trigger = openmc.Trigger('std_dev', 1e-2)\n", - "\n", - "# Add the tally trigger to each of the multi-group cross section tallies\n", - "for cell in openmc_cells:\n", - " for mgxs_type in xs_library[cell.id]:\n", - " xs_library[cell.id][mgxs_type].tally_trigger = tally_trigger" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we must loop over all cells to set the cross section domains to the various cells - fuel, clad and moderator - included in the geometry. In addition, we will set each cross section to tally cross sections on a per-nuclide basis through the use of the `MGXS` class' boolean `by_nuclide` instance attribute. " - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=53.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=21.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=3.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=4.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=41.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=15.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Instantiate an empty Tallies object\n", - "tallies_file = openmc.Tallies()\n", - "\n", - "# Iterate over all cells and cross section types\n", - "for cell in openmc_cells:\n", - " for rxn_type in xs_library[cell.id]:\n", - "\n", - " # Set the cross sections domain to the cell\n", - " xs_library[cell.id][rxn_type].domain = cell\n", - " \n", - " # Tally cross sections by nuclide\n", - " xs_library[cell.id][rxn_type].by_nuclide = True\n", - " \n", - " # Add OpenMC tallies to the tallies file for XML generation\n", - " for tally in xs_library[cell.id][rxn_type].tallies.values():\n", - " tallies_file.append(tally, merge=True)\n", - "\n", - "# Export to \"tallies.xml\"\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we a have a complete set of inputs, so we can go ahead and run our simulation." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | 61c911cffdae2406f9f4bc667a9a6954748bb70c\n", - " Date/Time | 2019-07-19 07:08:16\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading U235 from /opt/data/hdf5/nndc_hdf5_v15/U235.h5\n", - " Reading U238 from /opt/data/hdf5/nndc_hdf5_v15/U238.h5\n", - " Reading O16 from /opt/data/hdf5/nndc_hdf5_v15/O16.h5\n", - " Reading H1 from /opt/data/hdf5/nndc_hdf5_v15/H1.h5\n", - " Reading Zr90 from /opt/data/hdf5/nndc_hdf5_v15/Zr90.h5\n", - " Maximum neutron transport energy: 20000000.000000 eV for U235\n", - " Reading tallies XML file...\n", - " Writing summary.h5 file...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 1.20332\n", - " 2/1 1.22209\n", - " 3/1 1.24322\n", - " 4/1 1.21622\n", - " 5/1 1.25850\n", - " 6/1 1.22581\n", - " 7/1 1.21118\n", - " 8/1 1.23377\n", - " 9/1 1.24254\n", - " 10/1 1.21241\n", - " 11/1 1.21042\n", - " 12/1 1.23539 1.22290 +/- 0.01249\n", - " 13/1 1.22436 1.22339 +/- 0.00723\n", - " 14/1 1.22888 1.22476 +/- 0.00529\n", - " 15/1 1.22553 1.22491 +/- 0.00410\n", - " 16/1 1.24194 1.22775 +/- 0.00439\n", - " 17/1 1.24755 1.23058 +/- 0.00466\n", - " 18/1 1.21117 1.22815 +/- 0.00471\n", - " 19/1 1.22530 1.22784 +/- 0.00417\n", - " 20/1 1.20762 1.22582 +/- 0.00424\n", - " 21/1 1.20377 1.22381 +/- 0.00433\n", - " 22/1 1.24305 1.22541 +/- 0.00426\n", - " 23/1 1.22434 1.22533 +/- 0.00392\n", - " 24/1 1.22937 1.22562 +/- 0.00364\n", - " 25/1 1.22458 1.22555 +/- 0.00339\n", - " 26/1 1.18978 1.22332 +/- 0.00388\n", - " 27/1 1.20582 1.22229 +/- 0.00379\n", - " 28/1 1.22719 1.22256 +/- 0.00358\n", - " 29/1 1.21307 1.22206 +/- 0.00343\n", - " 30/1 1.20915 1.22141 +/- 0.00331\n", - " 31/1 1.22799 1.22173 +/- 0.00317\n", - " 32/1 1.21251 1.22131 +/- 0.00305\n", - " 33/1 1.20540 1.22062 +/- 0.00299\n", - " 34/1 1.20052 1.21978 +/- 0.00299\n", - " 35/1 1.24552 1.22081 +/- 0.00304\n", - " 36/1 1.21685 1.22066 +/- 0.00293\n", - " 37/1 1.22395 1.22078 +/- 0.00282\n", - " 38/1 1.22379 1.22089 +/- 0.00272\n", - " 39/1 1.20951 1.22049 +/- 0.00265\n", - " 40/1 1.25199 1.22154 +/- 0.00277\n", - " 41/1 1.23243 1.22190 +/- 0.00270\n", - " 42/1 1.20973 1.22152 +/- 0.00264\n", - " 43/1 1.24682 1.22228 +/- 0.00268\n", - " 44/1 1.20694 1.22183 +/- 0.00263\n", - " 45/1 1.22196 1.22183 +/- 0.00256\n", - " 46/1 1.20687 1.22142 +/- 0.00252\n", - " 47/1 1.22023 1.22139 +/- 0.00245\n", - " 48/1 1.22204 1.22140 +/- 0.00239\n", - " 49/1 1.22077 1.22139 +/- 0.00232\n", - " 50/1 1.23166 1.22164 +/- 0.00228\n", - " Triggers unsatisfied, max unc./thresh. is 1.17623 for flux in tally 53\n", - " The estimated number of batches is 66\n", - " Creating state point statepoint.050.h5...\n", - " 51/1 1.20071 1.22113 +/- 0.00228\n", - " Triggers unsatisfied, max unc./thresh. is 1.26577 for flux in tally 53\n", - " The estimated number of batches is 76\n", - " 52/1 1.21423 1.22097 +/- 0.00223\n", - " Triggers unsatisfied, max unc./thresh. is 1.24 for flux in tally 53\n", - " The estimated number of batches is 75\n", - " 53/1 1.25595 1.22178 +/- 0.00233\n", - " Triggers unsatisfied, max unc./thresh. is 1.2112 for flux in tally 53\n", - " The estimated number of batches is 74\n", - " 54/1 1.21806 1.22170 +/- 0.00227\n", - " Triggers unsatisfied, max unc./thresh. is 1.18484 for flux in tally 53\n", - " The estimated number of batches is 72\n", - " 55/1 1.22911 1.22186 +/- 0.00223\n", - " Triggers unsatisfied, max unc./thresh. is 1.1596 for flux in tally 53\n", - " The estimated number of batches is 71\n", - " 56/1 1.23054 1.22205 +/- 0.00219\n", - " Triggers unsatisfied, max unc./thresh. is 1.13453 for flux in tally 53\n", - " The estimated number of batches is 70\n", - " 57/1 1.19384 1.22145 +/- 0.00222\n", - " Triggers unsatisfied, max unc./thresh. is 1.11914 for flux in tally 53\n", - " The estimated number of batches is 69\n", - " 58/1 1.20625 1.22114 +/- 0.00220\n", - " Triggers unsatisfied, max unc./thresh. is 1.11471 for flux in tally 53\n", - " The estimated number of batches is 70\n", - " 59/1 1.21977 1.22111 +/- 0.00216\n", - " Triggers unsatisfied, max unc./thresh. is 1.10334 for flux in tally 53\n", - " The estimated number of batches is 70\n", - " 60/1 1.20813 1.22085 +/- 0.00213\n", - " Triggers unsatisfied, max unc./thresh. is 1.09813 for flux in tally 53\n", - " The estimated number of batches is 71\n", - " 61/1 1.22077 1.22085 +/- 0.00209\n", - " Triggers unsatisfied, max unc./thresh. is 1.10221 for flux in tally 53\n", - " The estimated number of batches is 72\n", - " 62/1 1.21956 1.22082 +/- 0.00205\n", - " Triggers unsatisfied, max unc./thresh. is 1.11395 for flux in tally 53\n", - " The estimated number of batches is 75\n", - " 63/1 1.22360 1.22087 +/- 0.00201\n", - " Triggers unsatisfied, max unc./thresh. is 1.09283 for flux in tally 53\n", - " The estimated number of batches is 74\n", - " 64/1 1.23955 1.22122 +/- 0.00200\n", - " Triggers unsatisfied, max unc./thresh. is 1.07416 for flux in tally 53\n", - " The estimated number of batches is 73\n", - " 65/1 1.21143 1.22104 +/- 0.00197\n", - " Triggers unsatisfied, max unc./thresh. is 1.06461 for flux in tally 53\n", - " The estimated number of batches is 73\n", - " 66/1 1.21791 1.22099 +/- 0.00194\n", - " Triggers unsatisfied, max unc./thresh. is 1.13207 for flux in tally 53\n", - " The estimated number of batches is 82\n", - " 67/1 1.24897 1.22148 +/- 0.00196\n", - " Triggers unsatisfied, max unc./thresh. is 1.11277 for flux in tally 53\n", - " The estimated number of batches is 81\n", - " 68/1 1.22221 1.22149 +/- 0.00193\n", - " Triggers unsatisfied, max unc./thresh. is 1.09514 for flux in tally 53\n", - " The estimated number of batches is 80\n", - " 69/1 1.25627 1.22208 +/- 0.00199\n", - " Triggers unsatisfied, max unc./thresh. is 1.07653 for flux in tally 53\n", - " The estimated number of batches is 79\n", - " 70/1 1.21493 1.22196 +/- 0.00196\n", - " Triggers unsatisfied, max unc./thresh. is 1.12831 for flux in tally 53\n", - " The estimated number of batches is 87\n", - " 71/1 1.23406 1.22216 +/- 0.00193\n", - " Triggers unsatisfied, max unc./thresh. is 1.11005 for flux in tally 53\n", - " The estimated number of batches is 86\n", - " 72/1 1.23842 1.22242 +/- 0.00192\n", - " Triggers unsatisfied, max unc./thresh. is 1.09352 for flux in tally 53\n", - " The estimated number of batches is 85\n", - " 73/1 1.24542 1.22279 +/- 0.00193\n", - " Triggers unsatisfied, max unc./thresh. is 1.08766 for flux in tally 53\n", - " The estimated number of batches is 85\n", - " 74/1 1.21314 1.22263 +/- 0.00190\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Triggers unsatisfied, max unc./thresh. is 1.07419 for flux in tally 53\n", - " The estimated number of batches is 84\n", - " 75/1 1.26484 1.22328 +/- 0.00198\n", - " Triggers unsatisfied, max unc./thresh. is 1.06788 for flux in tally 53\n", - " The estimated number of batches is 85\n", - " 76/1 1.22243 1.22327 +/- 0.00195\n", - " Triggers unsatisfied, max unc./thresh. is 1.05164 for flux in tally 53\n", - " The estimated number of batches is 83\n", - " 77/1 1.21865 1.22320 +/- 0.00192\n", - " Triggers unsatisfied, max unc./thresh. is 1.04022 for flux in tally 53\n", - " The estimated number of batches is 83\n", - " 78/1 1.23500 1.22338 +/- 0.00190\n", - " Triggers unsatisfied, max unc./thresh. is 1.0275 for flux in tally 53\n", - " The estimated number of batches is 82\n", - " 79/1 1.22125 1.22334 +/- 0.00187\n", - " Triggers unsatisfied, max unc./thresh. is 1.0283 for flux in tally 53\n", - " The estimated number of batches is 83\n", - " 80/1 1.23793 1.22355 +/- 0.00186\n", - " Triggers unsatisfied, max unc./thresh. is 1.01363 for flux in tally 53\n", - " The estimated number of batches is 82\n", - " 81/1 1.24238 1.22382 +/- 0.00185\n", - " Triggers unsatisfied, max unc./thresh. is 1.01172 for flux in tally 53\n", - " The estimated number of batches is 83\n", - " 82/1 1.23493 1.22397 +/- 0.00183\n", - " Triggers satisfied for batch 82\n", - " Creating state point statepoint.082.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 9.5644e-01 seconds\n", - " Reading cross sections = 9.0579e-01 seconds\n", - " Total time in simulation = 9.9887e+01 seconds\n", - " Time in transport only = 9.9333e+01 seconds\n", - " Time in inactive batches = 5.4841e+00 seconds\n", - " Time in active batches = 9.4403e+01 seconds\n", - " Time synchronizing fission bank = 7.3998e-02 seconds\n", - " Sampling source sites = 5.9021e-02 seconds\n", - " SEND/RECV source sites = 1.4787e-02 seconds\n", - " Time accumulating tallies = 1.2234e-03 seconds\n", - " Total time for finalization = 2.8416e-02 seconds\n", - " Total time elapsed = 1.0094e+02 seconds\n", - " Calculation Rate (inactive) = 18234.5 particles/second\n", - " Calculation Rate (active) = 7626.89 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.22348 +/- 0.00169\n", - " k-effective (Track-length) = 1.22397 +/- 0.00183\n", - " k-effective (Absorption) = 1.22467 +/- 0.00117\n", - " Combined k-effective = 1.22448 +/- 0.00108\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Run OpenMC\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our simulation ran successfully and created statepoint and summary output files. We begin our analysis by instantiating a `StatePoint` object. " - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the last statepoint file\n", - "sp = openmc.StatePoint('statepoint.082.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The statepoint is now ready to be analyzed by our multi-group cross sections. We simply have to load the tallies from the `StatePoint` into each object as follows and our `MGXS` objects will compute the cross sections for us under-the-hood." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "# Iterate over all cells and cross section types\n", - "for cell in openmc_cells:\n", - " for rxn_type in xs_library[cell.id]:\n", - " xs_library[cell.id][rxn_type].load_from_statepoint(sp)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "That's it! Our multi-group cross sections are now ready for the big spotlight. This time we have cross sections in three distinct spatial zones - fuel, clad and moderator - on a per-nuclide basis." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Extracting and Storing MGXS Data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's first inspect one of our cross sections by printing it to the screen as a microscopic cross section in units of barns." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Multi-Group XS\n", - "\tReaction Type =\tnu-fission\n", - "\tDomain Type =\tcell\n", - "\tDomain ID =\t1\n", - "\tNuclide =\tU235\n", - "\tCross Sections [barns]:\n", - " Group 1 [821000.0 - 20000000.0eV]:\t3.30e+00 +/- 2.14e-01%\n", - " Group 2 [5530.0 - 821000.0 eV]:\t3.96e+00 +/- 1.33e-01%\n", - " Group 3 [4.0 - 5530.0 eV]:\t5.50e+01 +/- 2.29e-01%\n", - " Group 4 [0.625 - 4.0 eV]:\t8.85e+01 +/- 3.10e-01%\n", - " Group 5 [0.28 - 0.625 eV]:\t2.90e+02 +/- 3.94e-01%\n", - " Group 6 [0.14 - 0.28 eV]:\t4.49e+02 +/- 4.12e-01%\n", - " Group 7 [0.058 - 0.14 eV]:\t6.87e+02 +/- 3.01e-01%\n", - " Group 8 [0.0 - 0.058 eV]:\t1.44e+03 +/- 2.79e-01%\n", - "\n", - "\tNuclide =\tU238\n", - "\tCross Sections [barns]:\n", - " Group 1 [821000.0 - 20000000.0eV]:\t1.06e+00 +/- 2.53e-01%\n", - " Group 2 [5530.0 - 821000.0 eV]:\t1.21e-03 +/- 2.60e-01%\n", - " Group 3 [4.0 - 5530.0 eV]:\t5.73e-04 +/- 2.93e+00%\n", - " Group 4 [0.625 - 4.0 eV]:\t6.54e-06 +/- 2.72e-01%\n", - " Group 5 [0.28 - 0.625 eV]:\t1.07e-05 +/- 3.83e-01%\n", - " Group 6 [0.14 - 0.28 eV]:\t1.55e-05 +/- 4.13e-01%\n", - " Group 7 [0.058 - 0.14 eV]:\t2.30e-05 +/- 3.01e-01%\n", - " Group 8 [0.0 - 0.058 eV]:\t4.24e-05 +/- 2.79e-01%\n", - "\n", - "\n", - "\n" - ] - } - ], - "source": [ - "nufission = xs_library[fuel_cell.id]['nu-fission']\n", - "nufission.print_xs(xs_type='micro', nuclides=['U235', 'U238'])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our multi-group cross sections are capable of summing across all nuclides to provide us with macroscopic cross sections as well." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Multi-Group XS\n", - "\tReaction Type =\tnu-fission\n", - "\tDomain Type =\tcell\n", - "\tDomain ID =\t1\n", - "\tCross Sections [cm^-1]:\n", - " Group 1 [821000.0 - 20000000.0eV]:\t2.52e-02 +/- 2.41e-01%\n", - " Group 2 [5530.0 - 821000.0 eV]:\t1.51e-03 +/- 1.31e-01%\n", - " Group 3 [4.0 - 5530.0 eV]:\t2.07e-02 +/- 2.29e-01%\n", - " Group 4 [0.625 - 4.0 eV]:\t3.32e-02 +/- 3.10e-01%\n", - " Group 5 [0.28 - 0.625 eV]:\t1.09e-01 +/- 3.94e-01%\n", - " Group 6 [0.14 - 0.28 eV]:\t1.69e-01 +/- 4.12e-01%\n", - " Group 7 [0.058 - 0.14 eV]:\t2.58e-01 +/- 3.01e-01%\n", - " Group 8 [0.0 - 0.058 eV]:\t5.40e-01 +/- 2.79e-01%\n", - "\n", - "\n", - "\n" - ] - } - ], - "source": [ - "nufission = xs_library[fuel_cell.id]['nu-fission']\n", - "nufission.print_xs(xs_type='macro', nuclides='sum')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Although a printed report is nice, it is not scalable or flexible. Let's extract the microscopic cross section data for the moderator as a [Pandas](https://pandas.pydata.org/) `DataFrame` ." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellgroup ingroup outnuclidemeanstd. dev.
126311H10.2339910.003752
127311O161.5692880.006360
124312H11.5872790.003098
125312O160.2855990.001422
122313H10.0104820.000220
123313O160.0000000.000000
120314H10.0000090.000006
121314O160.0000000.000000
118315H10.0000050.000005
119315O160.0000000.000000
\n", - "
" - ], - "text/plain": [ - " cell group in group out nuclide mean std. dev.\n", - "126 3 1 1 H1 0.233991 0.003752\n", - "127 3 1 1 O16 1.569288 0.006360\n", - "124 3 1 2 H1 1.587279 0.003098\n", - "125 3 1 2 O16 0.285599 0.001422\n", - "122 3 1 3 H1 0.010482 0.000220\n", - "123 3 1 3 O16 0.000000 0.000000\n", - "120 3 1 4 H1 0.000009 0.000006\n", - "121 3 1 4 O16 0.000000 0.000000\n", - "118 3 1 5 H1 0.000005 0.000005\n", - "119 3 1 5 O16 0.000000 0.000000" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "nuscatter = xs_library[moderator_cell.id]['nu-scatter']\n", - "df = nuscatter.get_pandas_dataframe(xs_type='micro')\n", - "df.head(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we illustate how one can easily take multi-group cross sections and condense them down to a coarser energy group structure. The `MGXS` class includes a `get_condensed_xs(...)` method which takes an `EnergyGroups` parameter with a coarse(r) group structure and returns a new `MGXS` condensed to the coarse groups. We illustrate this process below using the 2-group structure created earlier." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "# Extract the 8-group transport cross section for the fuel\n", - "fine_xs = xs_library[fuel_cell.id]['transport']\n", - "\n", - "# Condense to the 2-group structure\n", - "condensed_xs = fine_xs.get_condensed_xs(coarse_groups)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Group condensation is as simple as that! We now have a new coarse 2-group `TransportXS` in addition to our original 8-group `TransportXS`. Let's inspect the 2-group `TransportXS` by printing it to the screen and extracting a Pandas `DataFrame` as we have already learned how to do." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Multi-Group XS\n", - "\tReaction Type =\ttransport\n", - "\tDomain Type =\tcell\n", - "\tDomain ID =\t1\n", - "\tNuclide =\tU235\n", - "\tCross Sections [cm^-1]:\n", - " Group 1 [0.625 - 20000000.0eV]:\t7.79e-03 +/- 2.12e-01%\n", - " Group 2 [0.0 - 0.625 eV]:\t1.82e-01 +/- 1.92e-01%\n", - "\n", - "\tNuclide =\tU238\n", - "\tCross Sections [cm^-1]:\n", - " Group 1 [0.625 - 20000000.0eV]:\t2.17e-01 +/- 1.12e-01%\n", - " Group 2 [0.0 - 0.625 eV]:\t2.53e-01 +/- 1.89e-01%\n", - "\n", - "\tNuclide =\tO16\n", - "\tCross Sections [cm^-1]:\n", - " Group 1 [0.625 - 20000000.0eV]:\t1.45e-01 +/- 1.12e-01%\n", - " Group 2 [0.0 - 0.625 eV]:\t1.74e-01 +/- 2.03e-01%\n", - "\n", - "\n", - "\n" - ] - } - ], - "source": [ - "condensed_xs.print_xs()" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellgroup innuclidemeanstd. dev.
311U23520.7630620.044093
411U2389.5790860.010757
511O163.1572740.003531
012U235485.3490360.930937
112U23811.1991670.021167
212O163.7883830.007676
\n", - "
" - ], - "text/plain": [ - " cell group in nuclide mean std. dev.\n", - "3 1 1 U235 20.763062 0.044093\n", - "4 1 1 U238 9.579086 0.010757\n", - "5 1 1 O16 3.157274 0.003531\n", - "0 1 2 U235 485.349036 0.930937\n", - "1 1 2 U238 11.199167 0.021167\n", - "2 1 2 O16 3.788383 0.007676" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = condensed_xs.get_pandas_dataframe(xs_type='micro')\n", - "df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Verification with OpenMOC" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let's verify our cross sections using OpenMOC. First, we construct an equivalent OpenMOC geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "# Create an OpenMOC Geometry from the OpenMC Geometry\n", - "openmoc_geometry = get_openmoc_geometry(sp.summary.geometry)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we we can inject the multi-group cross sections into the equivalent fuel pin cell OpenMOC geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "# Get all OpenMOC cells in the gometry\n", - "openmoc_cells = openmoc_geometry.getRootUniverse().getAllCells()\n", - "\n", - "# Inject multi-group cross sections into OpenMOC Materials\n", - "for cell_id, cell in openmoc_cells.items():\n", - " \n", - " # Ignore the root cell\n", - " if cell.getName() == 'root cell':\n", - " continue\n", - " \n", - " # Get a reference to the Material filling this Cell\n", - " openmoc_material = cell.getFillMaterial()\n", - " \n", - " # Set the number of energy groups for the Material\n", - " openmoc_material.setNumEnergyGroups(fine_groups.num_groups)\n", - " \n", - " # Extract the appropriate cross section objects for this cell\n", - " transport = xs_library[cell_id]['transport']\n", - " nufission = xs_library[cell_id]['nu-fission']\n", - " nuscatter = xs_library[cell_id]['nu-scatter']\n", - " chi = xs_library[cell_id]['chi']\n", - " \n", - " # Inject NumPy arrays of cross section data into the Material\n", - " # NOTE: Sum across nuclides to get macro cross sections needed by OpenMOC\n", - " openmoc_material.setSigmaT(transport.get_xs(nuclides='sum').flatten())\n", - " openmoc_material.setNuSigmaF(nufission.get_xs(nuclides='sum').flatten())\n", - " openmoc_material.setSigmaS(nuscatter.get_xs(nuclides='sum').flatten())\n", - " openmoc_material.setChi(chi.get_xs(nuclides='sum').flatten())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are now ready to run OpenMOC to verify our cross-sections from OpenMC." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ NORMAL ] Initializing a default angular quadrature...\n", - "[ NORMAL ] Initializing 2D tracks...\n", - "[ NORMAL ] Initializing 2D tracks reflections...\n", - "[ NORMAL ] Initializing 2D tracks array...\n", - "[ NORMAL ] Ray tracing for 2D track segmentation...\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 0.09 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 10.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 19.94 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 29.87 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 39.80 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 49.72 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 59.65 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 69.58 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 79.50 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 89.43 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 100.00 %\n", - "[ NORMAL ] Initializing FSR lookup vectors\n", - "[ NORMAL ] Total number of FSRs 3\n", - "[ RESULT ] Total Track Generation & Segmentation Time...........2.5566E-02 sec\n", - "[ NORMAL ] Initializing MOC eigenvalue solver...\n", - "[ NORMAL ] Initializing solver arrays...\n", - "[ NORMAL ] Centering segments around FSR centroid...\n", - "[ NORMAL ] Max boundary angular flux storage per domain = 0.42 MB\n", - "[ NORMAL ] Max scalar flux storage per domain = 0.00 MB\n", - "[ NORMAL ] Max source storage per domain = 0.00 MB\n", - "[ NORMAL ] Number of azimuthal angles = 128\n", - "[ NORMAL ] Azimuthal ray spacing = 0.100000\n", - "[ NORMAL ] Number of polar angles = 6\n", - "[ NORMAL ] Source type = Flat\n", - "[ NORMAL ] MOC transport undamped\n", - "[ NORMAL ] CMFD acceleration: OFF\n", - "[ NORMAL ] Using 1 threads\n", - "[ NORMAL ] Computing the eigenvalue...\n", - "[ NORMAL ] Iteration 0: k_eff = 0.423133 res = 5.671E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... -57686 D.R. = 0.00\n", - "[ NORMAL ] Iteration 1: k_eff = 0.475953 res = 2.442E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 5282 D.R. = 4.31\n", - "[ NORMAL ] Iteration 2: k_eff = 0.491468 res = 4.764E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1551 D.R. = 1.95\n", - "[ NORMAL ] Iteration 3: k_eff = 0.487446 res = 2.253E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -402 D.R. = 0.47\n", - "[ NORMAL ] Iteration 4: k_eff = 0.483930 res = 6.957E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... -351 D.R. = 0.31\n", - "[ NORMAL ] Iteration 5: k_eff = 0.477280 res = 3.902E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -665 D.R. = 5.61\n", - "[ NORMAL ] Iteration 6: k_eff = 0.468938 res = 3.161E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -834 D.R. = 0.81\n", - "[ NORMAL ] Iteration 7: k_eff = 0.460319 res = 2.480E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -861 D.R. = 0.78\n", - "[ NORMAL ] Iteration 8: k_eff = 0.450591 res = 9.377E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... -972 D.R. = 0.38\n", - "[ NORMAL ] Iteration 9: k_eff = 0.441377 res = 3.085E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -921 D.R. = 3.29\n", - "[ NORMAL ] Iteration 10: k_eff = 0.431990 res = 1.028E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -938 D.R. = 0.33\n", - "[ NORMAL ] Iteration 11: k_eff = 0.422932 res = 1.180E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -905 D.R. = 1.15\n", - "[ NORMAL ] Iteration 12: k_eff = 0.414487 res = 1.633E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -844 D.R. = 1.38\n", - "[ NORMAL ] Iteration 13: k_eff = 0.406708 res = 1.754E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -777 D.R. = 1.07\n", - "[ NORMAL ] Iteration 14: k_eff = 0.399378 res = 5.021E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -732 D.R. = 2.86\n", - "[ NORMAL ] Iteration 15: k_eff = 0.393067 res = 9.074E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... -631 D.R. = 0.18\n", - "[ NORMAL ] Iteration 16: k_eff = 0.387427 res = 4.840E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... -564 D.R. = 0.53\n", - "[ NORMAL ] Iteration 17: k_eff = 0.382668 res = 2.299E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -475 D.R. = 4.75\n", - "[ NORMAL ] Iteration 18: k_eff = 0.378741 res = 1.573E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -392 D.R. = 0.68\n", - "[ NORMAL ] Iteration 19: k_eff = 0.375642 res = 7.017E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -309 D.R. = 4.46\n", - "[ NORMAL ] Iteration 20: k_eff = 0.373489 res = 4.053E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -215 D.R. = 0.58\n", - "[ NORMAL ] Iteration 21: k_eff = 0.372357 res = 4.235E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -113 D.R. = 1.04\n", - "[ NORMAL ] Iteration 22: k_eff = 0.371974 res = 6.352E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -38 D.R. = 1.50\n", - "[ NORMAL ] Iteration 23: k_eff = 0.372581 res = 3.267E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 60 D.R. = 0.51\n", - "[ NORMAL ] Iteration 24: k_eff = 0.374056 res = 1.573E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 147 D.R. = 0.48\n", - "[ NORMAL ] Iteration 25: k_eff = 0.376384 res = 3.630E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 232 D.R. = 2.31\n", - "[ NORMAL ] Iteration 26: k_eff = 0.379563 res = 2.420E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 317 D.R. = 0.07\n", - "[ NORMAL ] Iteration 27: k_eff = 0.383583 res = 3.146E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 401 D.R. = 13.00\n", - "[ NORMAL ] Iteration 28: k_eff = 0.388380 res = 1.089E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 479 D.R. = 0.35\n", - "[ NORMAL ] Iteration 29: k_eff = 0.393938 res = 6.049E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 555 D.R. = 5.56\n", - "[ NORMAL ] Iteration 30: k_eff = 0.400234 res = 3.267E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 629 D.R. = 0.54\n", - "[ NORMAL ] Iteration 31: k_eff = 0.407235 res = 2.420E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 700 D.R. = 0.74\n", - "[ NORMAL ] Iteration 32: k_eff = 0.414884 res = 1.815E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 764 D.R. = 0.75\n", - "[ NORMAL ] Iteration 33: k_eff = 0.423172 res = 7.259E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 828 D.R. = 0.40\n", - "[ NORMAL ] Iteration 34: k_eff = 0.432051 res = 6.049E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 887 D.R. = 8.33\n", - "[ NORMAL ] Iteration 35: k_eff = 0.441471 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 942 D.R. = 0.96\n", - "[ NORMAL ] Iteration 36: k_eff = 0.451430 res = 2.662E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 995 D.R. = 0.46\n", - "[ NORMAL ] Iteration 37: k_eff = 0.461853 res = 8.227E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1042 D.R. = 3.09\n", - "[ NORMAL ] Iteration 38: k_eff = 0.472730 res = 5.928E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1087 D.R. = 0.72\n", - "[ NORMAL ] Iteration 39: k_eff = 0.484006 res = 2.299E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1127 D.R. = 0.39\n", - "[ NORMAL ] Iteration 40: k_eff = 0.495653 res = 2.299E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1164 D.R. = 1.00\n", - "[ NORMAL ] Iteration 41: k_eff = 0.507634 res = 7.017E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1198 D.R. = 3.05\n", - "[ NORMAL ] Iteration 42: k_eff = 0.519914 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1227 D.R. = 0.28\n", - "[ NORMAL ] Iteration 43: k_eff = 0.532458 res = 1.089E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1254 D.R. = 0.56\n", - "[ NORMAL ] Iteration 44: k_eff = 0.545234 res = 6.291E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1277 D.R. = 5.78\n", - "[ NORMAL ] Iteration 45: k_eff = 0.558210 res = 3.509E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1297 D.R. = 0.56\n", - "[ NORMAL ] Iteration 46: k_eff = 0.571353 res = 3.025E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1314 D.R. = 0.86\n", - "[ NORMAL ] Iteration 47: k_eff = 0.584635 res = 7.259E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 1328 D.R. = 0.24\n", - "[ NORMAL ] Iteration 48: k_eff = 0.598027 res = 4.961E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1339 D.R. = 6.83\n", - "[ NORMAL ] Iteration 49: k_eff = 0.611500 res = 9.014E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1347 D.R. = 1.82\n", - "[ NORMAL ] Iteration 50: k_eff = 0.625029 res = 5.203E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1352 D.R. = 0.58\n", - "[ NORMAL ] Iteration 51: k_eff = 0.638590 res = 1.512E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1356 D.R. = 0.29\n", - "[ NORMAL ] Iteration 52: k_eff = 0.652158 res = 2.359E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1356 D.R. = 1.56\n", - "[ NORMAL ] Iteration 53: k_eff = 0.665710 res = 4.598E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1355 D.R. = 1.95\n", - "[ NORMAL ] Iteration 54: k_eff = 0.679228 res = 2.783E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1351 D.R. = 0.61\n", - "[ NORMAL ] Iteration 55: k_eff = 0.692689 res = 2.117E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1346 D.R. = 0.76\n", - "[ NORMAL ] Iteration 56: k_eff = 0.706075 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1338 D.R. = 0.91\n", - "[ NORMAL ] Iteration 57: k_eff = 0.719370 res = 5.505E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1329 D.R. = 2.84\n", - "[ NORMAL ] Iteration 58: k_eff = 0.732556 res = 2.238E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1318 D.R. = 0.41\n", - "[ NORMAL ] Iteration 59: k_eff = 0.745619 res = 7.864E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 1306 D.R. = 0.35\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ NORMAL ] Iteration 60: k_eff = 0.758546 res = 4.477E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1292 D.R. = 5.69\n", - "[ NORMAL ] Iteration 61: k_eff = 0.771323 res = 4.658E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1277 D.R. = 1.04\n", - "[ NORMAL ] Iteration 62: k_eff = 0.783939 res = 9.679E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 1261 D.R. = 0.21\n", - "[ NORMAL ] Iteration 63: k_eff = 0.796383 res = 4.235E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 1244 D.R. = 0.44\n", - "[ NORMAL ] Iteration 64: k_eff = 0.808646 res = 9.074E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 1226 D.R. = 2.14\n", - "[ NORMAL ] Iteration 65: k_eff = 0.820719 res = 6.412E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1207 D.R. = 7.07\n", - "[ NORMAL ] Iteration 66: k_eff = 0.832594 res = 2.420E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 1187 D.R. = 0.04\n", - "[ NORMAL ] Iteration 67: k_eff = 0.844264 res = 2.299E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1167 D.R. = 9.50\n", - "[ NORMAL ] Iteration 68: k_eff = 0.855724 res = 5.928E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1146 D.R. = 2.58\n", - "[ NORMAL ] Iteration 69: k_eff = 0.866968 res = 6.049E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1124 D.R. = 1.02\n", - "[ NORMAL ] Iteration 70: k_eff = 0.877992 res = 2.722E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1102 D.R. = 0.45\n", - "[ NORMAL ] Iteration 71: k_eff = 0.888792 res = 1.633E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1079 D.R. = 0.60\n", - "[ NORMAL ] Iteration 72: k_eff = 0.899364 res = 2.117E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1057 D.R. = 1.30\n", - "[ NORMAL ] Iteration 73: k_eff = 0.909708 res = 3.327E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1034 D.R. = 1.57\n", - "[ NORMAL ] Iteration 74: k_eff = 0.919819 res = 4.477E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1011 D.R. = 1.35\n", - "[ NORMAL ] Iteration 75: k_eff = 0.929699 res = 3.569E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 987 D.R. = 0.80\n", - "[ NORMAL ] Iteration 76: k_eff = 0.939346 res = 4.840E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 964 D.R. = 0.14\n", - "[ NORMAL ] Iteration 77: k_eff = 0.948758 res = 4.840E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 941 D.R. = 1.00\n", - "[ NORMAL ] Iteration 78: k_eff = 0.957938 res = 6.049E-10 delta-k (pcm) =\n", - "[ NORMAL ] ... 917 D.R. = 0.12\n", - "[ NORMAL ] Iteration 79: k_eff = 0.966885 res = 2.057E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 894 D.R. = 34.00\n", - "[ NORMAL ] Iteration 80: k_eff = 0.975601 res = 4.235E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 871 D.R. = 2.06\n", - "[ NORMAL ] Iteration 81: k_eff = 0.984087 res = 5.868E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 848 D.R. = 1.39\n", - "[ NORMAL ] Iteration 82: k_eff = 0.992344 res = 7.259E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 825 D.R. = 0.12\n", - "[ NORMAL ] Iteration 83: k_eff = 1.000375 res = 1.512E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 803 D.R. = 2.08\n", - "[ NORMAL ] Iteration 84: k_eff = 1.008182 res = 7.864E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 780 D.R. = 0.52\n", - "[ NORMAL ] Iteration 85: k_eff = 1.015768 res = 7.259E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 758 D.R. = 0.92\n", - "[ NORMAL ] Iteration 86: k_eff = 1.023136 res = 3.025E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 736 D.R. = 0.42\n", - "[ NORMAL ] Iteration 87: k_eff = 1.030288 res = 1.210E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 715 D.R. = 4.00\n", - "[ NORMAL ] Iteration 88: k_eff = 1.037228 res = 3.690E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 693 D.R. = 3.05\n", - "[ NORMAL ] Iteration 89: k_eff = 1.043960 res = 5.203E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 673 D.R. = 1.41\n", - "[ NORMAL ] Iteration 90: k_eff = 1.050486 res = 6.231E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 652 D.R. = 1.20\n", - "[ NORMAL ] Iteration 91: k_eff = 1.056812 res = 6.775E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 632 D.R. = 1.09\n", - "[ NORMAL ] Iteration 92: k_eff = 1.062939 res = 2.964E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 612 D.R. = 0.44\n", - "[ NORMAL ] Iteration 93: k_eff = 1.068872 res = 5.505E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 593 D.R. = 1.86\n", - "[ NORMAL ] Iteration 94: k_eff = 1.074616 res = 4.235E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 574 D.R. = 0.08\n", - "[ NORMAL ] Iteration 95: k_eff = 1.080173 res = 2.541E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 555 D.R. = 6.00\n", - "[ NORMAL ] Iteration 96: k_eff = 1.085550 res = 1.996E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 537 D.R. = 0.79\n", - "[ NORMAL ] Iteration 97: k_eff = 1.090748 res = 3.388E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 519 D.R. = 1.70\n", - "[ NORMAL ] Iteration 98: k_eff = 1.095774 res = 3.085E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 502 D.R. = 0.91\n", - "[ NORMAL ] Iteration 99: k_eff = 1.100629 res = 3.267E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 485 D.R. = 1.06\n", - "[ NORMAL ] Iteration 100: k_eff = 1.105320 res = 3.025E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 469 D.R. = 0.09\n", - "[ NORMAL ] Iteration 101: k_eff = 1.109851 res = 6.654E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 453 D.R. = 2.20\n", - "[ NORMAL ] Iteration 102: k_eff = 1.114224 res = 3.569E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 437 D.R. = 5.36\n", - "[ NORMAL ] Iteration 103: k_eff = 1.118444 res = 5.203E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 421 D.R. = 1.46\n", - "[ NORMAL ] Iteration 104: k_eff = 1.122516 res = 1.452E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 407 D.R. = 0.28\n", - "[ NORMAL ] Iteration 105: k_eff = 1.126445 res = 5.445E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 392 D.R. = 0.38\n", - "[ NORMAL ] Iteration 106: k_eff = 1.130232 res = 2.783E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 378 D.R. = 5.11\n", - "[ NORMAL ] Iteration 107: k_eff = 1.133884 res = 1.996E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 365 D.R. = 0.72\n", - "[ NORMAL ] Iteration 108: k_eff = 1.137403 res = 4.235E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 351 D.R. = 2.12\n", - "[ NORMAL ] Iteration 109: k_eff = 1.140793 res = 3.751E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 339 D.R. = 0.89\n", - "[ NORMAL ] Iteration 110: k_eff = 1.144059 res = 4.174E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 326 D.R. = 1.11\n", - "[ NORMAL ] Iteration 111: k_eff = 1.147203 res = 4.416E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 314 D.R. = 1.06\n", - "[ NORMAL ] Iteration 112: k_eff = 1.150231 res = 3.025E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 302 D.R. = 0.68\n", - "[ NORMAL ] Iteration 113: k_eff = 1.153146 res = 5.384E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 291 D.R. = 1.78\n", - "[ NORMAL ] Iteration 114: k_eff = 1.155950 res = 3.569E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 280 D.R. = 0.66\n", - "[ NORMAL ] Iteration 115: k_eff = 1.158649 res = 5.142E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 269 D.R. = 1.44\n", - "[ NORMAL ] Iteration 116: k_eff = 1.161244 res = 2.843E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 259 D.R. = 0.55\n", - "[ NORMAL ] Iteration 117: k_eff = 1.163739 res = 3.267E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 249 D.R. = 1.15\n", - "[ NORMAL ] Iteration 118: k_eff = 1.166139 res = 5.505E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 239 D.R. = 1.69\n", - "[ NORMAL ] Iteration 119: k_eff = 1.168445 res = 4.719E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 230 D.R. = 0.86\n", - "[ NORMAL ] Iteration 120: k_eff = 1.170662 res = 6.170E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 221 D.R. = 1.31\n", - "[ NORMAL ] Iteration 121: k_eff = 1.172791 res = 5.384E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 212 D.R. = 0.87\n", - "[ NORMAL ] Iteration 122: k_eff = 1.174837 res = 1.331E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 204 D.R. = 0.25\n", - "[ NORMAL ] Iteration 123: k_eff = 1.176801 res = 1.391E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 196 D.R. = 1.05\n", - "[ NORMAL ] Iteration 124: k_eff = 1.178688 res = 1.089E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 188 D.R. = 0.78\n", - "[ NORMAL ] Iteration 125: k_eff = 1.180500 res = 3.448E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 181 D.R. = 3.17\n", - "[ NORMAL ] Iteration 126: k_eff = 1.182238 res = 1.041E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 173 D.R. = 3.02\n", - "[ NORMAL ] Iteration 127: k_eff = 1.183907 res = 3.690E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 166 D.R. = 0.35\n", - "[ NORMAL ] Iteration 128: k_eff = 1.185508 res = 2.722E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 160 D.R. = 0.74\n", - "[ NORMAL ] Iteration 129: k_eff = 1.187044 res = 9.074E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 153 D.R. = 0.33\n", - "[ NORMAL ] Iteration 130: k_eff = 1.188518 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 147 D.R. = 3.20\n", - "[ NORMAL ] Iteration 131: k_eff = 1.189930 res = 2.783E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 141 D.R. = 0.96\n", - "[ NORMAL ] Iteration 132: k_eff = 1.191285 res = 2.541E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 135 D.R. = 0.91\n", - "[ NORMAL ] Iteration 133: k_eff = 1.192584 res = 4.537E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 129 D.R. = 1.79\n", - "[ NORMAL ] Iteration 134: k_eff = 1.193829 res = 5.505E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 124 D.R. = 1.21\n", - "[ NORMAL ] Iteration 135: k_eff = 1.195022 res = 6.412E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 119 D.R. = 1.16\n", - "[ NORMAL ] Iteration 136: k_eff = 1.196166 res = 6.049E-10 delta-k (pcm)\n", - "[ NORMAL ] ... = 114 D.R. = 0.01\n", - "[ NORMAL ] Iteration 137: k_eff = 1.197262 res = 4.416E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 109 D.R. = 73.00\n", - "[ NORMAL ] Iteration 138: k_eff = 1.198311 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 104 D.R. = 0.88\n", - "[ NORMAL ] Iteration 139: k_eff = 1.199316 res = 2.420E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 100 D.R. = 0.06\n", - "[ NORMAL ] Iteration 140: k_eff = 1.200279 res = 4.053E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 96 D.R. = 16.75\n", - "[ NORMAL ] Iteration 141: k_eff = 1.201201 res = 1.028E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 92 D.R. = 0.25\n", - "[ NORMAL ] Iteration 142: k_eff = 1.202083 res = 3.509E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 88 D.R. = 3.41\n", - "[ NORMAL ] Iteration 143: k_eff = 1.202927 res = 1.815E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 84 D.R. = 0.52\n", - "[ NORMAL ] Iteration 144: k_eff = 1.203736 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 80 D.R. = 1.07\n", - "[ NORMAL ] Iteration 145: k_eff = 1.204510 res = 6.836E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 77 D.R. = 3.53\n", - "[ NORMAL ] Iteration 146: k_eff = 1.205251 res = 5.324E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 74 D.R. = 0.78\n", - "[ NORMAL ] Iteration 147: k_eff = 1.205959 res = 2.299E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 70 D.R. = 0.43\n", - "[ NORMAL ] Iteration 148: k_eff = 1.206637 res = 1.815E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 67 D.R. = 0.79\n", - "[ NORMAL ] Iteration 149: k_eff = 1.207285 res = 8.469E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 64 D.R. = 0.47\n", - "[ NORMAL ] Iteration 150: k_eff = 1.207905 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 61 D.R. = 2.29\n", - "[ NORMAL ] Iteration 151: k_eff = 1.208498 res = 9.074E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 59 D.R. = 0.47\n", - "[ NORMAL ] Iteration 152: k_eff = 1.209065 res = 2.178E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 56 D.R. = 2.40\n", - "[ NORMAL ] Iteration 153: k_eff = 1.209607 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 54 D.R. = 3.11\n", - "[ NORMAL ] Iteration 154: k_eff = 1.210125 res = 9.074E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 51 D.R. = 1.34\n", - "[ NORMAL ] Iteration 155: k_eff = 1.210621 res = 5.445E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 49 D.R. = 0.06\n", - "[ NORMAL ] Iteration 156: k_eff = 1.211094 res = 6.049E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 47 D.R. = 1.11\n", - "[ NORMAL ] Iteration 157: k_eff = 1.211546 res = 6.049E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 45 D.R. = 1.00\n", - "[ NORMAL ] Iteration 158: k_eff = 1.211978 res = 4.658E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 43 D.R. = 7.70\n", - "[ NORMAL ] Iteration 159: k_eff = 1.212391 res = 1.815E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 41 D.R. = 0.04\n", - "[ NORMAL ] Iteration 160: k_eff = 1.212786 res = 1.210E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 39 D.R. = 6.67\n", - "[ NORMAL ] Iteration 161: k_eff = 1.213162 res = 6.049E-10 delta-k (pcm)\n", - "[ NORMAL ] ... = 37 D.R. = 0.05\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ NORMAL ] Iteration 162: k_eff = 1.213522 res = 1.996E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 35 D.R. = 33.00\n", - "[ NORMAL ] Iteration 163: k_eff = 1.213866 res = 4.658E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 34 D.R. = 2.33\n", - "[ NORMAL ] Iteration 164: k_eff = 1.214194 res = 1.996E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 32 D.R. = 0.43\n", - "[ NORMAL ] Iteration 165: k_eff = 1.214507 res = 1.210E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 31 D.R. = 0.06\n", - "[ NORMAL ] Iteration 166: k_eff = 1.214806 res = 1.875E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 29 D.R. = 15.50\n", - "[ NORMAL ] Iteration 167: k_eff = 1.215092 res = 4.961E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 28 D.R. = 2.65\n", - "[ NORMAL ] Iteration 168: k_eff = 1.215365 res = 6.049E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 27 D.R. = 1.22\n", - "[ NORMAL ] Iteration 169: k_eff = 1.215625 res = 2.964E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 26 D.R. = 0.49\n", - "[ NORMAL ] Iteration 170: k_eff = 1.215874 res = 5.505E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 24 D.R. = 1.86\n", - "[ NORMAL ] Iteration 171: k_eff = 1.216110 res = 2.117E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 23 D.R. = 0.38\n", - "[ NORMAL ] Iteration 172: k_eff = 1.216337 res = 4.174E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 22 D.R. = 1.97\n", - "[ NORMAL ] Iteration 173: k_eff = 1.216552 res = 3.509E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 21 D.R. = 0.84\n", - "[ NORMAL ] Iteration 174: k_eff = 1.216759 res = 2.722E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 20 D.R. = 0.78\n", - "[ NORMAL ] Iteration 175: k_eff = 1.216954 res = 2.601E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 19 D.R. = 0.96\n", - "[ NORMAL ] Iteration 176: k_eff = 1.217142 res = 4.295E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 18 D.R. = 1.65\n", - "[ NORMAL ] Iteration 177: k_eff = 1.217320 res = 4.598E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 17 D.R. = 1.07\n", - "[ NORMAL ] Iteration 178: k_eff = 1.217491 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 17 D.R. = 1.26\n", - "[ NORMAL ] Iteration 179: k_eff = 1.217654 res = 2.480E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 16 D.R. = 0.43\n", - "[ NORMAL ] Iteration 180: k_eff = 1.217809 res = 6.049E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 15 D.R. = 0.24\n", - "[ NORMAL ] Iteration 181: k_eff = 1.217956 res = 6.412E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 14 D.R. = 10.60\n", - "[ NORMAL ] Iteration 182: k_eff = 1.218098 res = 7.138E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 14 D.R. = 1.11\n", - "[ NORMAL ] Iteration 183: k_eff = 1.218232 res = 1.633E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 13 D.R. = 0.23\n", - "[ NORMAL ] Iteration 184: k_eff = 1.218360 res = 2.541E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 12 D.R. = 1.56\n", - "[ NORMAL ] Iteration 185: k_eff = 1.218482 res = 1.028E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 12 D.R. = 0.40\n", - "[ NORMAL ] Iteration 186: k_eff = 1.218599 res = 7.864E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 11 D.R. = 0.76\n", - "[ NORMAL ] Iteration 187: k_eff = 1.218709 res = 4.053E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 11 D.R. = 5.15\n", - "[ NORMAL ] Iteration 188: k_eff = 1.218815 res = 2.299E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 10 D.R. = 0.57\n", - "[ NORMAL ] Iteration 189: k_eff = 1.218916 res = 5.445E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 10 D.R. = 2.37\n", - "[ NORMAL ] Iteration 190: k_eff = 1.219011 res = 3.327E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 9 D.R. = 0.61\n", - "[ NORMAL ] Iteration 191: k_eff = 1.219103 res = 4.840E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 9 D.R. = 0.15\n", - "[ NORMAL ] Iteration 192: k_eff = 1.219190 res = 1.210E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 8 D.R. = 2.50\n", - "[ NORMAL ] Iteration 193: k_eff = 1.219273 res = 1.573E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 8 D.R. = 1.30\n", - "[ NORMAL ] Iteration 194: k_eff = 1.219352 res = 1.331E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 7 D.R. = 0.85\n", - "[ NORMAL ] Iteration 195: k_eff = 1.219428 res = 2.783E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 7 D.R. = 2.09\n", - "[ NORMAL ] Iteration 196: k_eff = 1.219499 res = 2.722E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 7 D.R. = 0.98\n", - "[ NORMAL ] Iteration 197: k_eff = 1.219567 res = 2.057E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 0.76\n", - "[ NORMAL ] Iteration 198: k_eff = 1.219633 res = 1.331E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 0.65\n", - "[ NORMAL ] Iteration 199: k_eff = 1.219695 res = 3.932E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 2.95\n", - "[ NORMAL ] Iteration 200: k_eff = 1.219753 res = 1.996E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 0.51\n", - "[ NORMAL ] Iteration 201: k_eff = 1.219810 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 2.42\n", - "[ NORMAL ] Iteration 202: k_eff = 1.219863 res = 1.270E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 0.26\n", - "[ NORMAL ] Iteration 203: k_eff = 1.219914 res = 2.662E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 2.10\n", - "[ NORMAL ] Iteration 204: k_eff = 1.219962 res = 5.445E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.20\n", - "[ NORMAL ] Iteration 205: k_eff = 1.220009 res = 3.327E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 6.11\n", - "[ NORMAL ] Iteration 206: k_eff = 1.220052 res = 4.658E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 1.40\n", - "[ NORMAL ] Iteration 207: k_eff = 1.220094 res = 3.025E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.65\n", - "[ NORMAL ] Iteration 208: k_eff = 1.220134 res = 2.117E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.70\n", - "[ NORMAL ] Iteration 209: k_eff = 1.220172 res = 1.875E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.89\n", - "[ NORMAL ] Iteration 210: k_eff = 1.220208 res = 1.028E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.55\n", - "[ NORMAL ] Iteration 211: k_eff = 1.220243 res = 5.263E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 5.12\n", - "[ NORMAL ] Iteration 212: k_eff = 1.220275 res = 2.480E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.47\n", - "[ NORMAL ] Iteration 213: k_eff = 1.220306 res = 4.598E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 1.85\n", - "[ NORMAL ] Iteration 214: k_eff = 1.220336 res = 3.630E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.08\n", - "[ NORMAL ] Iteration 215: k_eff = 1.220364 res = 1.391E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 3.83\n", - "[ NORMAL ] Iteration 216: k_eff = 1.220391 res = 6.049E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 4.35\n", - "[ NORMAL ] Iteration 217: k_eff = 1.220416 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.32\n", - "[ NORMAL ] Iteration 218: k_eff = 1.220441 res = 6.049E-10 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.03\n", - "[ NORMAL ] Iteration 219: k_eff = 1.220464 res = 1.270E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 21.00\n", - "[ NORMAL ] Iteration 220: k_eff = 1.220486 res = 1.452E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 1.14\n", - "[ NORMAL ] Iteration 221: k_eff = 1.220507 res = 2.299E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 1.58\n", - "[ NORMAL ] Iteration 222: k_eff = 1.220527 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.42\n", - "[ NORMAL ] Iteration 223: k_eff = 1.220545 res = 7.078E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 7.31\n", - "[ NORMAL ] Iteration 224: k_eff = 1.220563 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.14\n", - "[ NORMAL ] Iteration 225: k_eff = 1.220580 res = 3.146E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 3.25\n", - "[ NORMAL ] Iteration 226: k_eff = 1.220596 res = 1.633E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.52\n", - "[ NORMAL ] Iteration 227: k_eff = 1.220612 res = 3.569E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 2.19\n", - "[ NORMAL ] Iteration 228: k_eff = 1.220627 res = 2.722E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.76\n", - "[ NORMAL ] Iteration 229: k_eff = 1.220641 res = 1.875E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.69\n", - "[ NORMAL ] Iteration 230: k_eff = 1.220655 res = 3.448E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 1.84\n", - "[ NORMAL ] Iteration 231: k_eff = 1.220667 res = 8.046E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 2.33\n", - "[ NORMAL ] Iteration 232: k_eff = 1.220679 res = 3.751E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.47\n", - "[ NORMAL ] Iteration 233: k_eff = 1.220690 res = 5.686E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 1.52\n", - "[ NORMAL ] Iteration 234: k_eff = 1.220701 res = 1.270E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.22\n", - "[ NORMAL ] Iteration 235: k_eff = 1.220711 res = 6.715E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 0 D.R. = 5.29\n" - ] - } - ], - "source": [ - "# Generate tracks for OpenMOC\n", - "track_generator = openmoc.TrackGenerator(openmoc_geometry, num_azim=128, azim_spacing=0.1)\n", - "track_generator.generateTracks()\n", - "\n", - "# Run OpenMOC\n", - "solver = openmoc.CPUSolver(track_generator)\n", - "solver.computeEigenvalue()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We report the eigenvalues computed by OpenMC and OpenMOC here together to summarize our results." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "openmc keff = 1.224484\n", - "openmoc keff = 1.220711\n", - "bias [pcm]: -377.3\n" - ] - } - ], - "source": [ - "# Print report of keff and bias with OpenMC\n", - "openmoc_keff = solver.getKeff()\n", - "openmc_keff = sp.k_combined.n\n", - "bias = (openmoc_keff - openmc_keff) * 1e5\n", - "\n", - "print('openmc keff = {0:1.6f}'.format(openmc_keff))\n", - "print('openmoc keff = {0:1.6f}'.format(openmoc_keff))\n", - "print('bias [pcm]: {0:1.1f}'.format(bias))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As a sanity check, let's run a simulation with the coarse 2-group cross sections to ensure that they also produce a reasonable result." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "openmoc_geometry = get_openmoc_geometry(sp.summary.geometry)\n", - "openmoc_cells = openmoc_geometry.getRootUniverse().getAllCells()\n", - "\n", - "# Inject multi-group cross sections into OpenMOC Materials\n", - "for cell_id, cell in openmoc_cells.items():\n", - " \n", - " # Ignore the root cell\n", - " if cell.getName() == 'root cell':\n", - " continue\n", - " \n", - " openmoc_material = cell.getFillMaterial()\n", - " openmoc_material.setNumEnergyGroups(coarse_groups.num_groups)\n", - " \n", - " # Extract the appropriate cross section objects for this cell\n", - " transport = xs_library[cell_id]['transport']\n", - " nufission = xs_library[cell_id]['nu-fission']\n", - " nuscatter = xs_library[cell_id]['nu-scatter']\n", - " chi = xs_library[cell_id]['chi']\n", - " \n", - " # Perform group condensation\n", - " transport = transport.get_condensed_xs(coarse_groups)\n", - " nufission = nufission.get_condensed_xs(coarse_groups)\n", - " nuscatter = nuscatter.get_condensed_xs(coarse_groups)\n", - " chi = chi.get_condensed_xs(coarse_groups)\n", - " \n", - " # Inject NumPy arrays of cross section data into the Material\n", - " openmoc_material.setSigmaT(transport.get_xs(nuclides='sum').flatten())\n", - " openmoc_material.setNuSigmaF(nufission.get_xs(nuclides='sum').flatten())\n", - " openmoc_material.setSigmaS(nuscatter.get_xs(nuclides='sum').flatten())\n", - " openmoc_material.setChi(chi.get_xs(nuclides='sum').flatten())" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ NORMAL ] Initializing a default angular quadrature...\n", - "[ NORMAL ] Initializing 2D tracks...\n", - "[ NORMAL ] Initializing 2D tracks reflections...\n", - "[ NORMAL ] Initializing 2D tracks array...\n", - "[ NORMAL ] Ray tracing for 2D track segmentation...\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 0.09 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 10.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 19.94 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 29.87 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 39.80 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 49.72 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 59.65 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 69.58 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 79.50 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 89.43 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 100.00 %\n", - "[ NORMAL ] Initializing FSR lookup vectors\n", - "[ NORMAL ] Total number of FSRs 3\n", - "[ RESULT ] Total Track Generation & Segmentation Time...........3.9517E-02 sec\n", - "[ NORMAL ] Initializing MOC eigenvalue solver...\n", - "[ NORMAL ] Initializing solver arrays...\n", - "[ NORMAL ] Centering segments around FSR centroid...\n", - "[ NORMAL ] Max boundary angular flux storage per domain = 0.10 MB\n", - "[ NORMAL ] Max scalar flux storage per domain = 0.00 MB\n", - "[ NORMAL ] Max source storage per domain = 0.00 MB\n", - "[ NORMAL ] Number of azimuthal angles = 128\n", - "[ NORMAL ] Azimuthal ray spacing = 0.100000\n", - "[ NORMAL ] Number of polar angles = 6\n", - "[ NORMAL ] Source type = Flat\n", - "[ NORMAL ] MOC transport undamped\n", - "[ NORMAL ] CMFD acceleration: OFF\n", - "[ NORMAL ] Using 1 threads\n", - "[ NORMAL ] Computing the eigenvalue...\n", - "[ NORMAL ] Iteration 0: k_eff = 0.366880 res = 4.840E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -63312 D.R. = 0.00\n", - "[ NORMAL ] Iteration 1: k_eff = 0.391184 res = 9.679E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 2430 D.R. = 0.20\n", - "[ NORMAL ] Iteration 2: k_eff = 0.392990 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 180 D.R. = 6.00\n", - "[ NORMAL ] Iteration 3: k_eff = 0.381099 res = 9.195E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -1189 D.R. = 1.58\n", - "[ NORMAL ] Iteration 4: k_eff = 0.375018 res = 0.000E+00 delta-k (pcm) =\n", - "[ NORMAL ] ... -608 D.R. = 0.00\n", - "[ NORMAL ] Iteration 5: k_eff = 0.369593 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -542 D.R. = inf\n", - "[ NORMAL ] Iteration 6: k_eff = 0.365543 res = 1.065E-07 delta-k (pcm) =\n", - "[ NORMAL ] ... -405 D.R. = 5.50\n", - "[ NORMAL ] Iteration 7: k_eff = 0.363054 res = 1.065E-07 delta-k (pcm) =\n", - "[ NORMAL ] ... -248 D.R. = 1.00\n", - "[ NORMAL ] Iteration 8: k_eff = 0.361473 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -158 D.R. = 0.18\n", - "[ NORMAL ] Iteration 9: k_eff = 0.361280 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... -19 D.R. = 3.00\n", - "[ NORMAL ] Iteration 10: k_eff = 0.362003 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 72 D.R. = 0.33\n", - "[ NORMAL ] Iteration 11: k_eff = 0.363718 res = 4.840E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 171 D.R. = 2.50\n", - "[ NORMAL ] Iteration 12: k_eff = 0.366338 res = 1.258E-07 delta-k (pcm) =\n", - "[ NORMAL ] ... 262 D.R. = 2.60\n", - "[ NORMAL ] Iteration 13: k_eff = 0.369804 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 346 D.R. = 0.77\n", - "[ NORMAL ] Iteration 14: k_eff = 0.373989 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 418 D.R. = 0.40\n", - "[ NORMAL ] Iteration 15: k_eff = 0.378923 res = 0.000E+00 delta-k (pcm) =\n", - "[ NORMAL ] ... 493 D.R. = 0.00\n", - "[ NORMAL ] Iteration 16: k_eff = 0.384479 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 555 D.R. = inf\n", - "[ NORMAL ] Iteration 17: k_eff = 0.390637 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 615 D.R. = 1.00\n", - "[ NORMAL ] Iteration 18: k_eff = 0.397338 res = 0.000E+00 delta-k (pcm) =\n", - "[ NORMAL ] ... 670 D.R. = 0.00\n", - "[ NORMAL ] Iteration 19: k_eff = 0.404533 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 719 D.R. = inf\n", - "[ NORMAL ] Iteration 20: k_eff = 0.412184 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 765 D.R. = 1.67\n", - "[ NORMAL ] Iteration 21: k_eff = 0.420253 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 806 D.R. = 0.80\n", - "[ NORMAL ] Iteration 22: k_eff = 0.428686 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 843 D.R. = 0.75\n", - "[ NORMAL ] Iteration 23: k_eff = 0.437462 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 877 D.R. = 1.67\n", - "[ NORMAL ] Iteration 24: k_eff = 0.446538 res = 1.161E-07 delta-k (pcm) =\n", - "[ NORMAL ] ... 907 D.R. = 1.20\n", - "[ NORMAL ] Iteration 25: k_eff = 0.455883 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 934 D.R. = 0.17\n", - "[ NORMAL ] Iteration 26: k_eff = 0.465469 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 958 D.R. = 1.00\n", - "[ NORMAL ] Iteration 27: k_eff = 0.475265 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 979 D.R. = 2.00\n", - "[ NORMAL ] Iteration 28: k_eff = 0.485246 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 998 D.R. = 1.00\n", - "[ NORMAL ] Iteration 29: k_eff = 0.495385 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1013 D.R. = 0.50\n", - "[ NORMAL ] Iteration 30: k_eff = 0.505661 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1027 D.R. = 4.00\n", - "[ NORMAL ] Iteration 31: k_eff = 0.516051 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1038 D.R. = 1.25\n", - "[ NORMAL ] Iteration 32: k_eff = 0.526534 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1048 D.R. = 1.00\n", - "[ NORMAL ] Iteration 33: k_eff = 0.537092 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1055 D.R. = 1.00\n", - "[ NORMAL ] Iteration 34: k_eff = 0.547706 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1061 D.R. = 0.60\n", - "[ NORMAL ] Iteration 35: k_eff = 0.558361 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1065 D.R. = 0.33\n", - "[ NORMAL ] Iteration 36: k_eff = 0.569040 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1067 D.R. = 3.00\n", - "[ NORMAL ] Iteration 37: k_eff = 0.579730 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1068 D.R. = 1.67\n", - "[ NORMAL ] Iteration 38: k_eff = 0.590416 res = 0.000E+00 delta-k (pcm) =\n", - "[ NORMAL ] ... 1068 D.R. = 0.00\n", - "[ NORMAL ] Iteration 39: k_eff = 0.601087 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1067 D.R. = inf\n", - "[ NORMAL ] Iteration 40: k_eff = 0.611731 res = 1.549E-07 delta-k (pcm) =\n", - "[ NORMAL ] ... 1064 D.R. = 1.60\n", - "[ NORMAL ] Iteration 41: k_eff = 0.622338 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1060 D.R. = 0.50\n", - "[ NORMAL ] Iteration 42: k_eff = 0.632897 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1055 D.R. = 1.00\n", - "[ NORMAL ] Iteration 43: k_eff = 0.643400 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1050 D.R. = 0.75\n", - "[ NORMAL ] Iteration 44: k_eff = 0.653837 res = 0.000E+00 delta-k (pcm) =\n", - "[ NORMAL ] ... 1043 D.R. = 0.00\n", - "[ NORMAL ] Iteration 45: k_eff = 0.664203 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1036 D.R. = inf\n", - "[ NORMAL ] Iteration 46: k_eff = 0.674488 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1028 D.R. = 1.25\n", - "[ NORMAL ] Iteration 47: k_eff = 0.684688 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1020 D.R. = 1.00\n", - "[ NORMAL ] Iteration 48: k_eff = 0.694796 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1010 D.R. = 0.40\n", - "[ NORMAL ] Iteration 49: k_eff = 0.704807 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 1001 D.R. = 1.00\n", - "[ NORMAL ] Iteration 50: k_eff = 0.714715 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 990 D.R. = 0.50\n", - "[ NORMAL ] Iteration 51: k_eff = 0.724517 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 980 D.R. = 1.00\n", - "[ NORMAL ] Iteration 52: k_eff = 0.734209 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 969 D.R. = 1.00\n", - "[ NORMAL ] Iteration 53: k_eff = 0.743787 res = 0.000E+00 delta-k (pcm) =\n", - "[ NORMAL ] ... 957 D.R. = 0.00\n", - "[ NORMAL ] Iteration 54: k_eff = 0.753247 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 946 D.R. = inf\n", - "[ NORMAL ] Iteration 55: k_eff = 0.762588 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 934 D.R. = 1.50\n", - "[ NORMAL ] Iteration 56: k_eff = 0.771806 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 921 D.R. = 0.33\n", - "[ NORMAL ] Iteration 57: k_eff = 0.780901 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 909 D.R. = 2.00\n", - "[ NORMAL ] Iteration 58: k_eff = 0.789868 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 896 D.R. = 0.50\n", - "[ NORMAL ] Iteration 59: k_eff = 0.798708 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 884 D.R. = 1.00\n", - "[ NORMAL ] Iteration 60: k_eff = 0.807419 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 871 D.R. = 4.00\n", - "[ NORMAL ] Iteration 61: k_eff = 0.816000 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 858 D.R. = 0.50\n", - "[ NORMAL ] Iteration 62: k_eff = 0.824450 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 844 D.R. = 1.00\n", - "[ NORMAL ] Iteration 63: k_eff = 0.832768 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 831 D.R. = 2.00\n", - "[ NORMAL ] Iteration 64: k_eff = 0.840954 res = 1.742E-07 delta-k (pcm) =\n", - "[ NORMAL ] ... 818 D.R. = 2.25\n", - "[ NORMAL ] Iteration 65: k_eff = 0.849008 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 805 D.R. = 0.44\n", - "[ NORMAL ] Iteration 66: k_eff = 0.856930 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 792 D.R. = 0.50\n", - "[ NORMAL ] Iteration 67: k_eff = 0.864720 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 778 D.R. = 1.00\n", - "[ NORMAL ] Iteration 68: k_eff = 0.872378 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 765 D.R. = 1.00\n", - "[ NORMAL ] Iteration 69: k_eff = 0.879905 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 752 D.R. = 0.50\n", - "[ NORMAL ] Iteration 70: k_eff = 0.887301 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 739 D.R. = 2.00\n", - "[ NORMAL ] Iteration 71: k_eff = 0.894566 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 726 D.R. = 1.50\n", - "[ NORMAL ] Iteration 72: k_eff = 0.901702 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 713 D.R. = 0.33\n", - "[ NORMAL ] Iteration 73: k_eff = 0.908710 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 700 D.R. = 2.00\n", - "[ NORMAL ] Iteration 74: k_eff = 0.915590 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 687 D.R. = 1.50\n", - "[ NORMAL ] Iteration 75: k_eff = 0.922342 res = 0.000E+00 delta-k (pcm) =\n", - "[ NORMAL ] ... 675 D.R. = 0.00\n", - "[ NORMAL ] Iteration 76: k_eff = 0.928971 res = 1.161E-07 delta-k (pcm) =\n", - "[ NORMAL ] ... 662 D.R. = inf\n", - "[ NORMAL ] Iteration 77: k_eff = 0.935474 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 650 D.R. = 0.17\n", - "[ NORMAL ] Iteration 78: k_eff = 0.941853 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 637 D.R. = 1.00\n", - "[ NORMAL ] Iteration 79: k_eff = 0.948112 res = 9.679E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 625 D.R. = 5.00\n", - "[ NORMAL ] Iteration 80: k_eff = 0.954249 res = 1.065E-07 delta-k (pcm) =\n", - "[ NORMAL ] ... 613 D.R. = 1.10\n", - "[ NORMAL ] Iteration 81: k_eff = 0.960267 res = 9.679E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 601 D.R. = 0.09\n", - "[ NORMAL ] Iteration 82: k_eff = 0.966168 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 590 D.R. = 8.00\n", - "[ NORMAL ] Iteration 83: k_eff = 0.971953 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 578 D.R. = 0.75\n", - "[ NORMAL ] Iteration 84: k_eff = 0.977623 res = 1.936E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 566 D.R. = 0.33\n", - "[ NORMAL ] Iteration 85: k_eff = 0.983179 res = 2.904E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 555 D.R. = 1.50\n", - "[ NORMAL ] Iteration 86: k_eff = 0.988624 res = 0.000E+00 delta-k (pcm) =\n", - "[ NORMAL ] ... 544 D.R. = 0.00\n", - "[ NORMAL ] Iteration 87: k_eff = 0.993958 res = 6.775E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 533 D.R. = inf\n", - "[ NORMAL ] Iteration 88: k_eff = 0.999184 res = 9.679E-09 delta-k (pcm) =\n", - "[ NORMAL ] ... 522 D.R. = 0.14\n", - "[ NORMAL ] Iteration 89: k_eff = 1.004304 res = 4.840E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 511 D.R. = 5.00\n", - "[ NORMAL ] Iteration 90: k_eff = 1.009318 res = 3.872E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 501 D.R. = 0.80\n", - "[ NORMAL ] Iteration 91: k_eff = 1.014228 res = 4.840E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 491 D.R. = 1.25\n", - "[ NORMAL ] Iteration 92: k_eff = 1.019037 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 480 D.R. = 1.20\n", - "[ NORMAL ] Iteration 93: k_eff = 1.023744 res = 2.904E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 470 D.R. = 0.50\n", - "[ NORMAL ] Iteration 94: k_eff = 1.028353 res = 6.775E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 460 D.R. = 2.33\n", - "[ NORMAL ] Iteration 95: k_eff = 1.032865 res = 7.743E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 451 D.R. = 1.14\n", - "[ NORMAL ] Iteration 96: k_eff = 1.037281 res = 1.355E-07 delta-k (pcm) =\n", - "[ NORMAL ] ... 441 D.R. = 1.75\n", - "[ NORMAL ] Iteration 97: k_eff = 1.041604 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 432 D.R. = 0.43\n", - "[ NORMAL ] Iteration 98: k_eff = 1.045834 res = 4.840E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 422 D.R. = 0.83\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ NORMAL ] Iteration 99: k_eff = 1.049974 res = 5.807E-08 delta-k (pcm) =\n", - "[ NORMAL ] ... 413 D.R. = 1.20\n", - "[ NORMAL ] Iteration 100: k_eff = 1.054024 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 405 D.R. = 1.00\n", - "[ NORMAL ] Iteration 101: k_eff = 1.057987 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 396 D.R. = 0.83\n", - "[ NORMAL ] Iteration 102: k_eff = 1.061864 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 387 D.R. = 0.20\n", - "[ NORMAL ] Iteration 103: k_eff = 1.065657 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 379 D.R. = 3.00\n", - "[ NORMAL ] Iteration 104: k_eff = 1.069367 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 370 D.R. = 1.33\n", - "[ NORMAL ] Iteration 105: k_eff = 1.072996 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 362 D.R. = 1.00\n", - "[ NORMAL ] Iteration 106: k_eff = 1.076545 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 354 D.R. = 0.50\n", - "[ NORMAL ] Iteration 107: k_eff = 1.080016 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 347 D.R. = 3.50\n", - "[ NORMAL ] Iteration 108: k_eff = 1.083411 res = 1.161E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 339 D.R. = 1.71\n", - "[ NORMAL ] Iteration 109: k_eff = 1.086731 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 331 D.R. = 0.50\n", - "[ NORMAL ] Iteration 110: k_eff = 1.089976 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 324 D.R. = 0.33\n", - "[ NORMAL ] Iteration 111: k_eff = 1.093150 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 317 D.R. = 4.00\n", - "[ NORMAL ] Iteration 112: k_eff = 1.096253 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 310 D.R. = 1.00\n", - "[ NORMAL ] Iteration 113: k_eff = 1.099286 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 303 D.R. = 0.50\n", - "[ NORMAL ] Iteration 114: k_eff = 1.102251 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 296 D.R. = 1.25\n", - "[ NORMAL ] Iteration 115: k_eff = 1.105150 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 289 D.R. = 0.20\n", - "[ NORMAL ] Iteration 116: k_eff = 1.107983 res = 1.452E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 283 D.R. = 15.00\n", - "[ NORMAL ] Iteration 117: k_eff = 1.110753 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 276 D.R. = 0.33\n", - "[ NORMAL ] Iteration 118: k_eff = 1.113459 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 270 D.R. = 1.80\n", - "[ NORMAL ] Iteration 119: k_eff = 1.116105 res = 1.065E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 264 D.R. = 1.22\n", - "[ NORMAL ] Iteration 120: k_eff = 1.118690 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 258 D.R. = 0.36\n", - "[ NORMAL ] Iteration 121: k_eff = 1.121216 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 252 D.R. = 0.25\n", - "[ NORMAL ] Iteration 122: k_eff = 1.123685 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 246 D.R. = 1.00\n", - "[ NORMAL ] Iteration 123: k_eff = 1.126097 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 241 D.R. = 4.00\n", - "[ NORMAL ] Iteration 124: k_eff = 1.128454 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 235 D.R. = 0.00\n", - "[ NORMAL ] Iteration 125: k_eff = 1.130758 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 230 D.R. = inf\n", - "[ NORMAL ] Iteration 126: k_eff = 1.133008 res = 1.065E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 224 D.R. = 5.50\n", - "[ NORMAL ] Iteration 127: k_eff = 1.135207 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 219 D.R. = 0.45\n", - "[ NORMAL ] Iteration 128: k_eff = 1.137354 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 214 D.R. = 0.40\n", - "[ NORMAL ] Iteration 129: k_eff = 1.139453 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 209 D.R. = 0.00\n", - "[ NORMAL ] Iteration 130: k_eff = 1.141503 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 204 D.R. = inf\n", - "[ NORMAL ] Iteration 131: k_eff = 1.143505 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 200 D.R. = 1.50\n", - "[ NORMAL ] Iteration 132: k_eff = 1.145461 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 195 D.R. = 2.00\n", - "[ NORMAL ] Iteration 133: k_eff = 1.147372 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 191 D.R. = 1.50\n", - "[ NORMAL ] Iteration 134: k_eff = 1.149238 res = 1.065E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 186 D.R. = 1.22\n", - "[ NORMAL ] Iteration 135: k_eff = 1.151061 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 182 D.R. = 0.18\n", - "[ NORMAL ] Iteration 136: k_eff = 1.152842 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 178 D.R. = 1.00\n", - "[ NORMAL ] Iteration 137: k_eff = 1.154581 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 173 D.R. = 2.00\n", - "[ NORMAL ] Iteration 138: k_eff = 1.156279 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 169 D.R. = 2.50\n", - "[ NORMAL ] Iteration 139: k_eff = 1.157938 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 165 D.R. = 0.80\n", - "[ NORMAL ] Iteration 140: k_eff = 1.159557 res = 1.161E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 161 D.R. = 1.50\n", - "[ NORMAL ] Iteration 141: k_eff = 1.161139 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 158 D.R. = 0.33\n", - "[ NORMAL ] Iteration 142: k_eff = 1.162684 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 154 D.R. = 1.00\n", - "[ NORMAL ] Iteration 143: k_eff = 1.164193 res = 1.065E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 150 D.R. = 2.75\n", - "[ NORMAL ] Iteration 144: k_eff = 1.165666 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 147 D.R. = 0.09\n", - "[ NORMAL ] Iteration 145: k_eff = 1.167105 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 143 D.R. = 2.00\n", - "[ NORMAL ] Iteration 146: k_eff = 1.168509 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 140 D.R. = 4.00\n", - "[ NORMAL ] Iteration 147: k_eff = 1.169881 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 137 D.R. = 1.25\n", - "[ NORMAL ] Iteration 148: k_eff = 1.171220 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 133 D.R. = 0.10\n", - "[ NORMAL ] Iteration 149: k_eff = 1.172528 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 130 D.R. = 6.00\n", - "[ NORMAL ] Iteration 150: k_eff = 1.173804 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 127 D.R. = 1.67\n", - "[ NORMAL ] Iteration 151: k_eff = 1.175051 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 124 D.R. = 0.80\n", - "[ NORMAL ] Iteration 152: k_eff = 1.176268 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 121 D.R. = 1.00\n", - "[ NORMAL ] Iteration 153: k_eff = 1.177456 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 118 D.R. = 1.00\n", - "[ NORMAL ] Iteration 154: k_eff = 1.178616 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 115 D.R. = 0.63\n", - "[ NORMAL ] Iteration 155: k_eff = 1.179749 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 113 D.R. = 1.20\n", - "[ NORMAL ] Iteration 156: k_eff = 1.180855 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 110 D.R. = 0.83\n", - "[ NORMAL ] Iteration 157: k_eff = 1.181935 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 107 D.R. = 0.20\n", - "[ NORMAL ] Iteration 158: k_eff = 1.182988 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 105 D.R. = 3.00\n", - "[ NORMAL ] Iteration 159: k_eff = 1.184017 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 102 D.R. = 0.67\n", - "[ NORMAL ] Iteration 160: k_eff = 1.185021 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 100 D.R. = 1.50\n", - "[ NORMAL ] Iteration 161: k_eff = 1.186002 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 98 D.R. = 0.67\n", - "[ NORMAL ] Iteration 162: k_eff = 1.186959 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 95 D.R. = 2.50\n", - "[ NORMAL ] Iteration 163: k_eff = 1.187893 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 93 D.R. = 1.40\n", - "[ NORMAL ] Iteration 164: k_eff = 1.188805 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 91 D.R. = 1.29\n", - "[ NORMAL ] Iteration 165: k_eff = 1.189695 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 89 D.R. = 0.22\n", - "[ NORMAL ] Iteration 166: k_eff = 1.190564 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 86 D.R. = 2.00\n", - "[ NORMAL ] Iteration 167: k_eff = 1.191413 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 84 D.R. = 2.00\n", - "[ NORMAL ] Iteration 168: k_eff = 1.192241 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 82 D.R. = 0.00\n", - "[ NORMAL ] Iteration 169: k_eff = 1.193049 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 80 D.R. = inf\n", - "[ NORMAL ] Iteration 170: k_eff = 1.193838 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 78 D.R. = 4.50\n", - "[ NORMAL ] Iteration 171: k_eff = 1.194607 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 76 D.R. = 0.56\n", - "[ NORMAL ] Iteration 172: k_eff = 1.195359 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 75 D.R. = 1.20\n", - "[ NORMAL ] Iteration 173: k_eff = 1.196092 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 73 D.R. = 0.67\n", - "[ NORMAL ] Iteration 174: k_eff = 1.196808 res = 1.355E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 71 D.R. = 3.50\n", - "[ NORMAL ] Iteration 175: k_eff = 1.197507 res = 1.161E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 69 D.R. = 0.86\n", - "[ NORMAL ] Iteration 176: k_eff = 1.198190 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 68 D.R. = 0.33\n", - "[ NORMAL ] Iteration 177: k_eff = 1.198855 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 66 D.R. = 0.75\n", - "[ NORMAL ] Iteration 178: k_eff = 1.199505 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 64 D.R. = 0.67\n", - "[ NORMAL ] Iteration 179: k_eff = 1.200139 res = 1.258E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 63 D.R. = 6.50\n", - "[ NORMAL ] Iteration 180: k_eff = 1.200757 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 61 D.R. = 0.62\n", - "[ NORMAL ] Iteration 181: k_eff = 1.201361 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 60 D.R. = 0.25\n", - "[ NORMAL ] Iteration 182: k_eff = 1.201951 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 58 D.R. = 1.50\n", - "[ NORMAL ] Iteration 183: k_eff = 1.202526 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 57 D.R. = 0.33\n", - "[ NORMAL ] Iteration 184: k_eff = 1.203088 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 56 D.R. = 5.00\n", - "[ NORMAL ] Iteration 185: k_eff = 1.203636 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 54 D.R. = 0.00\n", - "[ NORMAL ] Iteration 186: k_eff = 1.204171 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 53 D.R. = inf\n", - "[ NORMAL ] Iteration 187: k_eff = 1.204692 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 52 D.R. = 2.33\n", - "[ NORMAL ] Iteration 188: k_eff = 1.205202 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 50 D.R. = 0.57\n", - "[ NORMAL ] Iteration 189: k_eff = 1.205698 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 49 D.R. = 0.50\n", - "[ NORMAL ] Iteration 190: k_eff = 1.206183 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 48 D.R. = 0.50\n", - "[ NORMAL ] Iteration 191: k_eff = 1.206656 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 47 D.R. = 6.00\n", - "[ NORMAL ] Iteration 192: k_eff = 1.207118 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 46 D.R. = 0.00\n", - "[ NORMAL ] Iteration 193: k_eff = 1.207570 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 45 D.R. = inf\n", - "[ NORMAL ] Iteration 194: k_eff = 1.208010 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 44 D.R. = 0.33\n", - "[ NORMAL ] Iteration 195: k_eff = 1.208439 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 42 D.R. = 1.33\n", - "[ NORMAL ] Iteration 196: k_eff = 1.208858 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 41 D.R. = 0.50\n", - "[ NORMAL ] Iteration 197: k_eff = 1.209267 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 40 D.R. = 1.50\n", - "[ NORMAL ] Iteration 198: k_eff = 1.209665 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 39 D.R. = 1.33\n", - "[ NORMAL ] Iteration 199: k_eff = 1.210055 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 38 D.R. = 1.50\n", - "[ NORMAL ] Iteration 200: k_eff = 1.210435 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 37 D.R. = 0.17\n", - "[ NORMAL ] Iteration 201: k_eff = 1.210805 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 37 D.R. = 9.00\n", - "[ NORMAL ] Iteration 202: k_eff = 1.211167 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 36 D.R. = 0.11\n", - "[ NORMAL ] Iteration 203: k_eff = 1.211520 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 35 D.R. = 5.00\n", - "[ NORMAL ] Iteration 204: k_eff = 1.211864 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 34 D.R. = 0.60\n", - "[ NORMAL ] Iteration 205: k_eff = 1.212200 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 33 D.R. = 0.67\n", - "[ NORMAL ] Iteration 206: k_eff = 1.212528 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 32 D.R. = 2.50\n", - "[ NORMAL ] Iteration 207: k_eff = 1.212848 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 32 D.R. = 1.60\n", - "[ NORMAL ] Iteration 208: k_eff = 1.213160 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 31 D.R. = 0.25\n", - "[ NORMAL ] Iteration 209: k_eff = 1.213466 res = 1.065E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 30 D.R. = 5.50\n", - "[ NORMAL ] Iteration 210: k_eff = 1.213763 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 29 D.R. = 0.55\n", - "[ NORMAL ] Iteration 211: k_eff = 1.214053 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 29 D.R. = 1.67\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ NORMAL ] Iteration 212: k_eff = 1.214337 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 28 D.R. = 0.30\n", - "[ NORMAL ] Iteration 213: k_eff = 1.214614 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 27 D.R. = 2.33\n", - "[ NORMAL ] Iteration 214: k_eff = 1.214883 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 26 D.R. = 1.29\n", - "[ NORMAL ] Iteration 215: k_eff = 1.215145 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 26 D.R. = 0.56\n", - "[ NORMAL ] Iteration 216: k_eff = 1.215402 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 25 D.R. = 0.40\n", - "[ NORMAL ] Iteration 217: k_eff = 1.215653 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 25 D.R. = 3.00\n", - "[ NORMAL ] Iteration 218: k_eff = 1.215897 res = 1.258E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 24 D.R. = 2.17\n", - "[ NORMAL ] Iteration 219: k_eff = 1.216136 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 23 D.R. = 0.77\n", - "[ NORMAL ] Iteration 220: k_eff = 1.216368 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 23 D.R. = 0.80\n", - "[ NORMAL ] Iteration 221: k_eff = 1.216595 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 22 D.R. = 0.25\n", - "[ NORMAL ] Iteration 222: k_eff = 1.216817 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 22 D.R. = 3.00\n", - "[ NORMAL ] Iteration 223: k_eff = 1.217033 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 21 D.R. = 0.33\n", - "[ NORMAL ] Iteration 224: k_eff = 1.217244 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 21 D.R. = 4.00\n", - "[ NORMAL ] Iteration 225: k_eff = 1.217450 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 20 D.R. = 0.75\n", - "[ NORMAL ] Iteration 226: k_eff = 1.217651 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 20 D.R. = 0.17\n", - "[ NORMAL ] Iteration 227: k_eff = 1.217847 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 19 D.R. = 4.00\n", - "[ NORMAL ] Iteration 228: k_eff = 1.218039 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 19 D.R. = 2.50\n", - "[ NORMAL ] Iteration 229: k_eff = 1.218225 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 18 D.R. = 0.20\n", - "[ NORMAL ] Iteration 230: k_eff = 1.218407 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 18 D.R. = 2.50\n", - "[ NORMAL ] Iteration 231: k_eff = 1.218585 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 17 D.R. = 1.00\n", - "[ NORMAL ] Iteration 232: k_eff = 1.218758 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 17 D.R. = 1.40\n", - "[ NORMAL ] Iteration 233: k_eff = 1.218927 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 16 D.R. = 0.71\n", - "[ NORMAL ] Iteration 234: k_eff = 1.219092 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 16 D.R. = 1.00\n", - "[ NORMAL ] Iteration 235: k_eff = 1.219253 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 16 D.R. = 1.40\n", - "[ NORMAL ] Iteration 236: k_eff = 1.219410 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 15 D.R. = 0.57\n", - "[ NORMAL ] Iteration 237: k_eff = 1.219563 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 15 D.R. = 0.50\n", - "[ NORMAL ] Iteration 238: k_eff = 1.219712 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 14 D.R. = 0.00\n", - "[ NORMAL ] Iteration 239: k_eff = 1.219858 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 14 D.R. = -nan\n", - "[ NORMAL ] Iteration 240: k_eff = 1.220000 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 14 D.R. = inf\n", - "[ NORMAL ] Iteration 241: k_eff = 1.220139 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 13 D.R. = 1.13\n", - "[ NORMAL ] Iteration 242: k_eff = 1.220274 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 13 D.R. = 1.11\n", - "[ NORMAL ] Iteration 243: k_eff = 1.220407 res = 1.065E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 13 D.R. = 1.10\n", - "[ NORMAL ] Iteration 244: k_eff = 1.220536 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 12 D.R. = 0.64\n", - "[ NORMAL ] Iteration 245: k_eff = 1.220662 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 12 D.R. = 0.43\n", - "[ NORMAL ] Iteration 246: k_eff = 1.220784 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 12 D.R. = 0.67\n", - "[ NORMAL ] Iteration 247: k_eff = 1.220904 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 11 D.R. = 1.00\n", - "[ NORMAL ] Iteration 248: k_eff = 1.221021 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 11 D.R. = 3.50\n", - "[ NORMAL ] Iteration 249: k_eff = 1.221135 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 11 D.R. = 1.43\n", - "[ NORMAL ] Iteration 250: k_eff = 1.221246 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 11 D.R. = 0.80\n", - "[ NORMAL ] Iteration 251: k_eff = 1.221355 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 10 D.R. = 0.87\n", - "[ NORMAL ] Iteration 252: k_eff = 1.221461 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 10 D.R. = 0.43\n", - "[ NORMAL ] Iteration 253: k_eff = 1.221564 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 10 D.R. = 1.67\n", - "[ NORMAL ] Iteration 254: k_eff = 1.221665 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 10 D.R. = 0.40\n", - "[ NORMAL ] Iteration 255: k_eff = 1.221763 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 9 D.R. = 0.00\n", - "[ NORMAL ] Iteration 256: k_eff = 1.221859 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 9 D.R. = inf\n", - "[ NORMAL ] Iteration 257: k_eff = 1.221953 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 9 D.R. = 1.00\n", - "[ NORMAL ] Iteration 258: k_eff = 1.222044 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 9 D.R. = 0.40\n", - "[ NORMAL ] Iteration 259: k_eff = 1.222133 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 8 D.R. = 1.50\n", - "[ NORMAL ] Iteration 260: k_eff = 1.222220 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 8 D.R. = 0.00\n", - "[ NORMAL ] Iteration 261: k_eff = 1.222305 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 8 D.R. = inf\n", - "[ NORMAL ] Iteration 262: k_eff = 1.222387 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 8 D.R. = 1.17\n", - "[ NORMAL ] Iteration 263: k_eff = 1.222468 res = 1.839E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 8 D.R. = 2.71\n", - "[ NORMAL ] Iteration 264: k_eff = 1.222547 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 7 D.R. = 0.16\n", - "[ NORMAL ] Iteration 265: k_eff = 1.222624 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 7 D.R. = 1.00\n", - "[ NORMAL ] Iteration 266: k_eff = 1.222699 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 7 D.R. = 0.33\n", - "[ NORMAL ] Iteration 267: k_eff = 1.222772 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 7 D.R. = 6.00\n", - "[ NORMAL ] Iteration 268: k_eff = 1.222844 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 7 D.R. = 1.17\n", - "[ NORMAL ] Iteration 269: k_eff = 1.222913 res = 1.452E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 2.14\n", - "[ NORMAL ] Iteration 270: k_eff = 1.222981 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 0.40\n", - "[ NORMAL ] Iteration 271: k_eff = 1.223048 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 0.17\n", - "[ NORMAL ] Iteration 272: k_eff = 1.223113 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 3.00\n", - "[ NORMAL ] Iteration 273: k_eff = 1.223176 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 1.33\n", - "[ NORMAL ] Iteration 274: k_eff = 1.223238 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 1.00\n", - "[ NORMAL ] Iteration 275: k_eff = 1.223298 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 1.00\n", - "[ NORMAL ] Iteration 276: k_eff = 1.223357 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 1.00\n", - "[ NORMAL ] Iteration 277: k_eff = 1.223414 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 0.50\n", - "[ NORMAL ] Iteration 278: k_eff = 1.223470 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 1.50\n", - "[ NORMAL ] Iteration 279: k_eff = 1.223524 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 1.67\n", - "[ NORMAL ] Iteration 280: k_eff = 1.223577 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 0.20\n", - "[ NORMAL ] Iteration 281: k_eff = 1.223629 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 5.00\n", - "[ NORMAL ] Iteration 282: k_eff = 1.223680 res = 1.258E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 2.60\n", - "[ NORMAL ] Iteration 283: k_eff = 1.223729 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.77\n", - "[ NORMAL ] Iteration 284: k_eff = 1.223777 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.70\n", - "[ NORMAL ] Iteration 285: k_eff = 1.223824 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 1.00\n", - "[ NORMAL ] Iteration 286: k_eff = 1.223870 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 1.00\n", - "[ NORMAL ] Iteration 287: k_eff = 1.223915 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.29\n", - "[ NORMAL ] Iteration 288: k_eff = 1.223959 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.00\n", - "[ NORMAL ] Iteration 289: k_eff = 1.224001 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = inf\n", - "[ NORMAL ] Iteration 290: k_eff = 1.224043 res = 1.355E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 2.80\n", - "[ NORMAL ] Iteration 291: k_eff = 1.224083 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.57\n", - "[ NORMAL ] Iteration 292: k_eff = 1.224123 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.37\n", - "[ NORMAL ] Iteration 293: k_eff = 1.224161 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 1.33\n", - "[ NORMAL ] Iteration 294: k_eff = 1.224199 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 2.00\n", - "[ NORMAL ] Iteration 295: k_eff = 1.224235 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.50\n", - "[ NORMAL ] Iteration 296: k_eff = 1.224271 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 1.75\n", - "[ NORMAL ] Iteration 297: k_eff = 1.224306 res = 1.161E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 1.71\n", - "[ NORMAL ] Iteration 298: k_eff = 1.224340 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.08\n", - "[ NORMAL ] Iteration 299: k_eff = 1.224373 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 2.00\n", - "[ NORMAL ] Iteration 300: k_eff = 1.224406 res = 1.065E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 5.50\n", - "[ NORMAL ] Iteration 301: k_eff = 1.224438 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.82\n", - "[ NORMAL ] Iteration 302: k_eff = 1.224468 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.78\n", - "[ NORMAL ] Iteration 303: k_eff = 1.224498 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.71\n", - "[ NORMAL ] Iteration 304: k_eff = 1.224528 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.40\n", - "[ NORMAL ] Iteration 305: k_eff = 1.224557 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 3.00\n", - "[ NORMAL ] Iteration 306: k_eff = 1.224585 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.83\n", - "[ NORMAL ] Iteration 307: k_eff = 1.224612 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.20\n", - "[ NORMAL ] Iteration 308: k_eff = 1.224639 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 3.00\n", - "[ NORMAL ] Iteration 309: k_eff = 1.224665 res = 9.679E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 3.33\n", - "[ NORMAL ] Iteration 310: k_eff = 1.224691 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.80\n", - "[ NORMAL ] Iteration 311: k_eff = 1.224716 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.50\n", - "[ NORMAL ] Iteration 312: k_eff = 1.224740 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.75\n", - "[ NORMAL ] Iteration 313: k_eff = 1.224764 res = 1.161E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 4.00\n", - "[ NORMAL ] Iteration 314: k_eff = 1.224786 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.17\n", - "[ NORMAL ] Iteration 315: k_eff = 1.224809 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 1.50\n", - "[ NORMAL ] Iteration 316: k_eff = 1.224831 res = 1.065E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 3.67\n", - "[ NORMAL ] Iteration 317: k_eff = 1.224852 res = 1.161E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 1.09\n", - "[ NORMAL ] Iteration 318: k_eff = 1.224873 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.00\n", - "[ NORMAL ] Iteration 319: k_eff = 1.224893 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = inf\n", - "[ NORMAL ] Iteration 320: k_eff = 1.224913 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.63\n", - "[ NORMAL ] Iteration 321: k_eff = 1.224932 res = 6.775E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 1.40\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ NORMAL ] Iteration 322: k_eff = 1.224951 res = 8.711E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 1.29\n", - "[ NORMAL ] Iteration 323: k_eff = 1.224969 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.11\n", - "[ NORMAL ] Iteration 324: k_eff = 1.224987 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 8.00\n", - "[ NORMAL ] Iteration 325: k_eff = 1.225005 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.25\n", - "[ NORMAL ] Iteration 326: k_eff = 1.225022 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.50\n", - "[ NORMAL ] Iteration 327: k_eff = 1.225039 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 2.00\n", - "[ NORMAL ] Iteration 328: k_eff = 1.225055 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 3.00\n", - "[ NORMAL ] Iteration 329: k_eff = 1.225071 res = 1.065E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 1.83\n", - "[ NORMAL ] Iteration 330: k_eff = 1.225086 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.27\n", - "[ NORMAL ] Iteration 331: k_eff = 1.225102 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 1.00\n", - "[ NORMAL ] Iteration 332: k_eff = 1.225116 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 1.00\n", - "[ NORMAL ] Iteration 333: k_eff = 1.225131 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 2.00\n", - "[ NORMAL ] Iteration 334: k_eff = 1.225145 res = 4.840E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.83\n", - "[ NORMAL ] Iteration 335: k_eff = 1.225159 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.20\n", - "[ NORMAL ] Iteration 336: k_eff = 1.225172 res = 5.807E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 6.00\n", - "[ NORMAL ] Iteration 337: k_eff = 1.225185 res = 1.355E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 2.33\n", - "[ NORMAL ] Iteration 338: k_eff = 1.225198 res = 1.258E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.93\n", - "[ NORMAL ] Iteration 339: k_eff = 1.225210 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.00\n", - "[ NORMAL ] Iteration 340: k_eff = 1.225222 res = 9.679E-09 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = inf\n", - "[ NORMAL ] Iteration 341: k_eff = 1.225233 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 4.00\n", - "[ NORMAL ] Iteration 342: k_eff = 1.225245 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.50\n", - "[ NORMAL ] Iteration 343: k_eff = 1.225256 res = 0.000E+00 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.00\n", - "[ NORMAL ] Iteration 344: k_eff = 1.225267 res = 7.743E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = inf\n", - "[ NORMAL ] Iteration 345: k_eff = 1.225278 res = 2.904E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.38\n", - "[ NORMAL ] Iteration 346: k_eff = 1.225288 res = 3.872E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 1.33\n", - "[ NORMAL ] Iteration 347: k_eff = 1.225298 res = 1.936E-08 delta-k (pcm)\n", - "[ NORMAL ] ... = 0 D.R. = 0.50\n" - ] - } - ], - "source": [ - "# Generate tracks for OpenMOC\n", - "track_generator = openmoc.TrackGenerator(openmoc_geometry, num_azim=128, azim_spacing=0.1)\n", - "track_generator.generateTracks()\n", - "\n", - "# Run OpenMOC\n", - "solver = openmoc.CPUSolver(track_generator)\n", - "solver.computeEigenvalue()" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "openmc keff = 1.224484\n", - "openmoc keff = 1.225298\n", - "bias [pcm]: 81.4\n" - ] - } - ], - "source": [ - "# Print report of keff and bias with OpenMC\n", - "openmoc_keff = solver.getKeff()\n", - "openmc_keff = sp.k_combined.n\n", - "bias = (openmoc_keff - openmc_keff) * 1e5\n", - "\n", - "print('openmc keff = {0:1.6f}'.format(openmc_keff))\n", - "print('openmoc keff = {0:1.6f}'.format(openmoc_keff))\n", - "print('bias [pcm]: {0:1.1f}'.format(bias))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There is a non-trivial bias in both the 2-group and 8-group cases. In the case of a pin cell, one can show that these biases do not converge to <100 pcm with more particle histories. For heterogeneous geometries, additional measures must be taken to address the following three sources of bias:\n", - "\n", - "* Appropriate transport-corrected cross sections\n", - "* Spatial discretization of OpenMOC's mesh\n", - "* Constant-in-angle multi-group cross sections" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "## Visualizing MGXS Data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "It is often insightful to generate visual depictions of multi-group cross sections. There are many different types of plots which may be useful for multi-group cross section visualization, only a few of which will be shown here for enrichment and inspiration.\n", - "\n", - "One particularly useful visualization is a comparison of the continuous-energy and multi-group cross sections for a particular nuclide and reaction type. We illustrate one option for generating such plots with the use of the `openmc.plotter` module to plot continuous-energy cross sections from the openly available cross section library distributed by NNDC.\n", - "\n", - "The MGXS data can also be plotted using the openmc.plot_xs command, however we will do this manually here to show how the openmc.Mgxs.get_xs method can be used to obtain data." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(1e-05, 20000000.0)" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Create a figure of the U-235 continuous-energy fission cross section \n", - "fig = openmc.plot_xs('U235', ['fission'])\n", - "\n", - "# Get the axis to use for plotting the MGXS\n", - "ax = fig.gca()\n", - "\n", - "# Extract energy group bounds and MGXS values to plot\n", - "fission = xs_library[fuel_cell.id]['fission']\n", - "energy_groups = fission.energy_groups\n", - "x = energy_groups.group_edges\n", - "y = fission.get_xs(nuclides=['U235'], order_groups='decreasing', xs_type='micro')\n", - "y = np.squeeze(y)\n", - "\n", - "# Fix low energy bound\n", - "x[0] = 1.e-5\n", - "\n", - "# Extend the mgxs values array for matplotlib's step plot\n", - "y = np.insert(y, 0, y[0])\n", - "\n", - "# Create a step plot for the MGXS\n", - "ax.plot(x, y, drawstyle='steps', color='r', linewidth=3)\n", - "\n", - "ax.set_title('U-235 Fission Cross Section')\n", - "ax.legend(['Continuous', 'Multi-Group'])\n", - "ax.set_xlim((x.min(), x.max()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Another useful type of illustration is scattering matrix sparsity structures. First, we extract Pandas `DataFrames` for the H-1 and O-16 scattering matrices." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "# Construct a Pandas DataFrame for the microscopic nu-scattering matrix\n", - "nuscatter = xs_library[moderator_cell.id]['nu-scatter']\n", - "df = nuscatter.get_pandas_dataframe(xs_type='micro')\n", - "\n", - "# Slice DataFrame in two for each nuclide's mean values\n", - "h1 = df[df['nuclide'] == 'H1']['mean']\n", - "o16 = df[df['nuclide'] == 'O16']['mean']\n", - "\n", - "# Cast DataFrames as NumPy arrays\n", - "h1 = h1.values\n", - "o16 = o16.values\n", - "\n", - "# Reshape arrays to 2D matrix for plotting\n", - "h1.shape = (fine_groups.num_groups, fine_groups.num_groups)\n", - "o16.shape = (fine_groups.num_groups, fine_groups.num_groups)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Matplotlib's `imshow` routine can be used to plot the matrices to illustrate their sparsity structures." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Create plot of the H-1 scattering matrix\n", - "fig = plt.subplot(121)\n", - "fig.imshow(h1, interpolation='nearest', cmap='jet')\n", - "plt.title('H-1 Scattering Matrix')\n", - "plt.xlabel('Group Out')\n", - "plt.ylabel('Group In')\n", - "\n", - "# Create plot of the O-16 scattering matrix\n", - "fig2 = plt.subplot(122)\n", - "fig2.imshow(o16, interpolation='nearest', cmap='jet')\n", - "plt.title('O-16 Scattering Matrix')\n", - "plt.xlabel('Group Out')\n", - "plt.ylabel('Group In')\n", - "\n", - "# Show the plot on screen\n", - "plt.show()" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/mgxs-part-iii.ipynb b/examples/jupyter/mgxs-part-iii.ipynb deleted file mode 100644 index d75255d73b7..00000000000 --- a/examples/jupyter/mgxs-part-iii.ipynb +++ /dev/null @@ -1,1668 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multigroup Cross Section Generation Part III: Libraries\n", - "This IPython Notebook illustrates the use of the **`openmc.mgxs.Library`** class. The `Library` class is designed to automate the calculation of multi-group cross sections for use cases with one or more domains, cross section types, and/or nuclides. In particular, this Notebook illustrates the following features:\n", - "\n", - "* Calculation of multi-group cross sections for a **fuel assembly**\n", - "* Automated creation, manipulation and storage of `MGXS` with **`openmc.mgxs.Library`**\n", - "* **Validation** of multi-group cross sections with **[OpenMOC](https://mit-crpg.github.io/OpenMOC/)**\n", - "* Steady-state pin-by-pin **fission rates comparison** between OpenMC and [OpenMOC](https://mit-crpg.github.io/OpenMOC/)\n", - "\n", - "**Note:** This Notebook was created using [OpenMOC](https://mit-crpg.github.io/OpenMOC/) to verify the multi-group cross-sections generated by OpenMC. You must install [OpenMOC](https://mit-crpg.github.io/OpenMOC/) on your system to run this Notebook in its entirety. In addition, this Notebook illustrates the use of [Pandas](https://pandas.pydata.org/) `DataFrames` to containerize multi-group cross section data." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import math\n", - "import pickle\n", - "\n", - "from IPython.display import Image\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "import openmc\n", - "import openmc.mgxs\n", - "from openmc.openmoc_compatible import get_openmoc_geometry\n", - "import openmoc\n", - "import openmoc.process\n", - "from openmoc.materialize import load_openmc_mgxs_lib\n", - "\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we need to define materials that will be used in the problem. We'll create three materials for the fuel, water, and cladding of the fuel pins." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# 1.6 enriched fuel\n", - "fuel = openmc.Material(name='1.6% Fuel')\n", - "fuel.set_density('g/cm3', 10.31341)\n", - "fuel.add_nuclide('U235', 3.7503e-4)\n", - "fuel.add_nuclide('U238', 2.2625e-2)\n", - "fuel.add_nuclide('O16', 4.6007e-2)\n", - "\n", - "# borated water\n", - "water = openmc.Material(name='Borated Water')\n", - "water.set_density('g/cm3', 0.740582)\n", - "water.add_nuclide('H1', 4.9457e-2)\n", - "water.add_nuclide('O16', 2.4732e-2)\n", - "water.add_nuclide('B10', 8.0042e-6)\n", - "\n", - "# zircaloy\n", - "zircaloy = openmc.Material(name='Zircaloy')\n", - "zircaloy.set_density('g/cm3', 6.55)\n", - "zircaloy.add_nuclide('Zr90', 7.2758e-3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our three materials, we can now create a `Materials` object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Materials object\n", - "materials_file = openmc.Materials([fuel, water, zircaloy])\n", - "\n", - "# Export to \"materials.xml\"\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. This problem will be a square array of fuel pins and control rod guide tubes for which we can use OpenMC's lattice/universe feature. The basic universe will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces for fuel and clad, as well as the outer bounding surfaces of the problem." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Create cylinders for the fuel and clad\n", - "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.39218)\n", - "clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.45720)\n", - "\n", - "# Create boundary planes to surround the geometry\n", - "min_x = openmc.XPlane(x0=-10.71, boundary_type='reflective')\n", - "max_x = openmc.XPlane(x0=+10.71, boundary_type='reflective')\n", - "min_y = openmc.YPlane(y0=-10.71, boundary_type='reflective')\n", - "max_y = openmc.YPlane(y0=+10.71, boundary_type='reflective')\n", - "min_z = openmc.ZPlane(z0=-10., boundary_type='reflective')\n", - "max_z = openmc.ZPlane(z0=+10., boundary_type='reflective')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now construct a fuel pin cell from cells that are defined by intersections of half-spaces created by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a Universe to encapsulate a fuel pin\n", - "fuel_pin_universe = openmc.Universe(name='1.6% Fuel Pin')\n", - "\n", - "# Create fuel Cell\n", - "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", - "fuel_cell.fill = fuel\n", - "fuel_cell.region = -fuel_outer_radius\n", - "fuel_pin_universe.add_cell(fuel_cell)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='1.6% Clad')\n", - "clad_cell.fill = zircaloy\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "fuel_pin_universe.add_cell(clad_cell)\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", - "moderator_cell.fill = water\n", - "moderator_cell.region = +clad_outer_radius\n", - "fuel_pin_universe.add_cell(moderator_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Likewise, we can construct a control rod guide tube with the same surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a Universe to encapsulate a control rod guide tube\n", - "guide_tube_universe = openmc.Universe(name='Guide Tube')\n", - "\n", - "# Create guide tube Cell\n", - "guide_tube_cell = openmc.Cell(name='Guide Tube Water')\n", - "guide_tube_cell.fill = water\n", - "guide_tube_cell.region = -fuel_outer_radius\n", - "guide_tube_universe.add_cell(guide_tube_cell)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='Guide Clad')\n", - "clad_cell.fill = zircaloy\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "guide_tube_universe.add_cell(clad_cell)\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='Guide Tube Moderator')\n", - "moderator_cell.fill = water\n", - "moderator_cell.region = +clad_outer_radius\n", - "guide_tube_universe.add_cell(moderator_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Using the pin cell universe, we can construct a 17x17 rectangular lattice with a 1.26 cm pitch." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create fuel assembly Lattice\n", - "assembly = openmc.RectLattice(name='1.6% Fuel Assembly')\n", - "assembly.pitch = (1.26, 1.26)\n", - "assembly.lower_left = [-1.26 * 17. / 2.0] * 2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we create a NumPy array of fuel pin and guide tube universes for the lattice." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Create array indices for guide tube locations in lattice\n", - "template_x = np.array([5, 8, 11, 3, 13, 2, 5, 8, 11, 14, 2, 5, 8,\n", - " 11, 14, 2, 5, 8, 11, 14, 3, 13, 5, 8, 11])\n", - "template_y = np.array([2, 2, 2, 3, 3, 5, 5, 5, 5, 5, 8, 8, 8, 8,\n", - " 8, 11, 11, 11, 11, 11, 13, 13, 14, 14, 14])\n", - "\n", - "# Initialize an empty 17x17 array of the lattice universes\n", - "universes = np.empty((17, 17), dtype=openmc.Universe)\n", - "\n", - "# Fill the array with the fuel pin and guide tube universes\n", - "universes[:,:] = fuel_pin_universe\n", - "universes[template_x, template_y] = guide_tube_universe\n", - "\n", - "# Store the array of universes in the lattice\n", - "assembly.universes = universes" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC requires that there is a \"root\" universe. Let us create a root cell that is filled by the assembly and then assign it to the root universe." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# Create root Cell\n", - "root_cell = openmc.Cell(name='root cell')\n", - "root_cell.fill = assembly\n", - "\n", - "# Add boundary planes\n", - "root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z\n", - "\n", - "# Create root Universe\n", - "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", - "root_universe.add_cell(root_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now must create a geometry that is assigned a root universe and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and set root Universe\n", - "geometry = openmc.Geometry(root_universe)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Export to \"geometry.xml\"\n", - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the geometry and materials finished, we now just need to define simulation parameters. In this case, we will use 10 inactive batches and 40 active batches each with 2500 particles." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "batches = 50\n", - "inactive = 10\n", - "particles = 10000\n", - "\n", - "# Instantiate a Settings object\n", - "settings_file = openmc.Settings()\n", - "settings_file.batches = batches\n", - "settings_file.inactive = inactive\n", - "settings_file.particles = particles\n", - "settings_file.output = {'tallies': False}\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-10.71, -10.71, -10, 10.71, 10.71, 10.]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings_file.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us also create a plot to verify that our fuel assembly geometry was created successfully." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Instantiate a Plot\n", - "plot = openmc.Plot.from_geometry(geometry)\n", - "plot.pixels = (250, 250)\n", - "plot.color_by = 'material'\n", - "plot.to_ipython_image()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As we can see from the plot, we have a nice array of fuel and guide tube pin cells with fuel, cladding, and water!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create an MGXS Library" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we are ready to generate multi-group cross sections! First, let's define a 2-group structure using the built-in `EnergyGroups` class." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a 2-group EnergyGroups object\n", - "groups = openmc.mgxs.EnergyGroups()\n", - "groups.group_edges = np.array([0., 0.625, 20.0e6])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we will instantiate an `openmc.mgxs.Library` for the energy groups with the fuel assembly geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Initialize a 2-group MGXS Library for OpenMOC\n", - "mgxs_lib = openmc.mgxs.Library(geometry)\n", - "mgxs_lib.energy_groups = groups" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we must specify to the `Library` which types of cross sections to compute. In particular, the following are the multi-group cross section `MGXS` subclasses that are mapped to string codes accepted by the `Library` class:\n", - "\n", - "* `TotalXS` (`\"total\"`)\n", - "* `TransportXS` (`\"transport\"` or `\"nu-transport` with `nu` set to `True`)\n", - "* `AbsorptionXS` (`\"absorption\"`)\n", - "* `CaptureXS` (`\"capture\"`)\n", - "* `FissionXS` (`\"fission\"` or `\"nu-fission\"` with `nu` set to `True`)\n", - "* `KappaFissionXS` (`\"kappa-fission\"`)\n", - "* `ScatterXS` (`\"scatter\"` or `\"nu-scatter\"` with `nu` set to `True`)\n", - "* `ScatterMatrixXS` (`\"scatter matrix\"` or `\"nu-scatter matrix\"` with `nu` set to `True`)\n", - "* `Chi` (`\"chi\"`)\n", - "* `ChiPrompt` (`\"chi prompt\"`)\n", - "* `InverseVelocity` (`\"inverse-velocity\"`)\n", - "* `PromptNuFissionXS` (`\"prompt-nu-fission\"`)\n", - "* `DelayedNuFissionXS` (`\"delayed-nu-fission\"`)\n", - "* `ChiDelayed` (`\"chi-delayed\"`)\n", - "* `Beta` (`\"beta\"`)\n", - "\n", - "In this case, let's create the multi-group cross sections needed to run an OpenMOC simulation to verify the accuracy of our cross sections. In particular, we will define `\"nu-transport\"`, `\"nu-fission\"`, `'\"fission\"`, `\"nu-scatter matrix\"` and `\"chi\"` cross sections for our `Library`.\n", - "\n", - "**Note**: A variety of different approximate transport-corrected total multi-group cross sections (and corresponding scattering matrices) can be found in the literature. At the present time, the `openmc.mgxs` module only supports the `\"P0\"` transport correction. This correction can be turned on and off through the boolean `Library.correction` property which may take values of `\"P0\"` (default) or `None`." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "# Specify multi-group cross section types to compute\n", - "mgxs_lib.mgxs_types = ['nu-transport', 'nu-fission', 'fission', 'nu-scatter matrix', 'chi']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we must specify the type of domain over which we would like the `Library` to compute multi-group cross sections. The domain type corresponds to the type of tally filter to be used in the tallies created to compute multi-group cross sections. At the present time, the `Library` supports `\"material\"`, `\"cell\"`, `\"universe\"`, and `\"mesh\"` domain types. We will use a `\"cell\"` domain type here to compute cross sections in each of the cells in the fuel assembly geometry.\n", - "\n", - "**Note:** By default, the `Library` class will instantiate `MGXS` objects for each and every domain (material, cell or universe) in the geometry of interest. However, one may specify a subset of these domains to the `Library.domains` property. In our case, we wish to compute multi-group cross sections in each and every cell since they will be needed in our downstream OpenMOC calculation on the identical combinatorial geometry mesh." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# Specify a \"cell\" domain type for the cross section tally filters\n", - "mgxs_lib.domain_type = 'cell'\n", - "\n", - "# Specify the cell domains over which to compute multi-group cross sections\n", - "mgxs_lib.domains = geometry.get_all_material_cells().values()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can easily instruct the `Library` to compute multi-group cross sections on a nuclide-by-nuclide basis with the boolean `Library.by_nuclide` property. By default, `by_nuclide` is set to `False`, but we will set it to `True` here." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "# Compute cross sections on a nuclide-by-nuclide basis\n", - "mgxs_lib.by_nuclide = True" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Lastly, we use the `Library` to construct the tallies needed to compute all of the requested multi-group cross sections in each domain and nuclide." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "# Construct all tallies needed for the multi-group cross section library\n", - "mgxs_lib.build_library()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The tallies can now be export to a \"tallies.xml\" input file for OpenMC. \n", - "\n", - "**NOTE**: At this point the `Library` has constructed nearly 100 distinct `Tally` objects. The overhead to tally in OpenMC scales as $O(N)$ for $N$ tallies, which can become a bottleneck for large tally datasets. To compensate for this, the Python API's `Tally`, `Filter` and `Tallies` classes allow for the smart *merging* of tallies when possible. The `Library` class supports this runtime optimization with the use of the optional `merge` paramter (`False` by default) for the `Library.add_to_tallies_file(...)` method, as shown below." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a \"tallies.xml\" file for the MGXS Library\n", - "tallies_file = openmc.Tallies()\n", - "mgxs_lib.add_to_tallies_file(tallies_file, merge=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In addition, we instantiate a fission rate mesh tally to compare with OpenMOC." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a tally Mesh\n", - "mesh = openmc.RegularMesh(mesh_id=1)\n", - "mesh.dimension = [17, 17]\n", - "mesh.lower_left = [-10.71, -10.71]\n", - "mesh.upper_right = [+10.71, +10.71]\n", - "\n", - "# Instantiate tally Filter\n", - "mesh_filter = openmc.MeshFilter(mesh)\n", - "\n", - "# Instantiate the Tally\n", - "tally = openmc.Tally(name='mesh tally')\n", - "tally.filters = [mesh_filter]\n", - "tally.scores = ['fission', 'nu-fission']\n", - "\n", - "# Add tally to collection\n", - "tallies_file.append(tally)" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=126.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=21.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=3.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=4.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=96.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=15.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=114.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Export all tallies to a \"tallies.xml\" file\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | 61c911cffdae2406f9f4bc667a9a6954748bb70c\n", - " Date/Time | 2019-07-19 07:12:55\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading U235 from /opt/data/hdf5/nndc_hdf5_v15/U235.h5\n", - " Reading U238 from /opt/data/hdf5/nndc_hdf5_v15/U238.h5\n", - " Reading O16 from /opt/data/hdf5/nndc_hdf5_v15/O16.h5\n", - " Reading H1 from /opt/data/hdf5/nndc_hdf5_v15/H1.h5\n", - " Reading B10 from /opt/data/hdf5/nndc_hdf5_v15/B10.h5\n", - " Reading Zr90 from /opt/data/hdf5/nndc_hdf5_v15/Zr90.h5\n", - " Maximum neutron transport energy: 20000000.000000 eV for U235\n", - " Reading tallies XML file...\n", - " Writing summary.h5 file...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 1.03784\n", - " 2/1 1.02297\n", - " 3/1 1.02244\n", - " 4/1 1.02344\n", - " 5/1 1.02057\n", - " 6/1 1.04077\n", - " 7/1 1.00775\n", - " 8/1 1.03892\n", - " 9/1 1.01606\n", - " 10/1 1.02209\n", - " 11/1 1.03259\n", - " 12/1 1.03331 1.03295 +/- 0.00036\n", - " 13/1 1.02027 1.02872 +/- 0.00423\n", - " 14/1 1.03901 1.03130 +/- 0.00395\n", - " 15/1 1.02000 1.02904 +/- 0.00380\n", - " 16/1 1.04469 1.03164 +/- 0.00405\n", - " 17/1 1.01862 1.02978 +/- 0.00390\n", - " 18/1 1.03265 1.03014 +/- 0.00340\n", - " 19/1 1.00489 1.02734 +/- 0.00410\n", - " 20/1 1.04533 1.02914 +/- 0.00409\n", - " 21/1 1.01534 1.02788 +/- 0.00390\n", - " 22/1 1.02204 1.02739 +/- 0.00360\n", - " 23/1 1.02181 1.02696 +/- 0.00334\n", - " 24/1 0.99207 1.02447 +/- 0.00397\n", - " 25/1 1.03041 1.02487 +/- 0.00372\n", - " 26/1 1.03652 1.02560 +/- 0.00355\n", - " 27/1 1.03793 1.02632 +/- 0.00341\n", - " 28/1 1.02099 1.02603 +/- 0.00323\n", - " 29/1 1.01953 1.02568 +/- 0.00308\n", - " 30/1 1.01690 1.02525 +/- 0.00295\n", - " 31/1 1.01938 1.02497 +/- 0.00282\n", - " 32/1 1.01800 1.02465 +/- 0.00271\n", - " 33/1 1.01598 1.02427 +/- 0.00262\n", - " 34/1 1.01735 1.02398 +/- 0.00252\n", - " 35/1 1.01080 1.02346 +/- 0.00247\n", - " 36/1 1.01267 1.02304 +/- 0.00241\n", - " 37/1 1.01907 1.02289 +/- 0.00233\n", - " 38/1 1.02333 1.02291 +/- 0.00224\n", - " 39/1 1.01516 1.02264 +/- 0.00218\n", - " 40/1 1.02797 1.02282 +/- 0.00211\n", - " 41/1 1.03949 1.02336 +/- 0.00211\n", - " 42/1 1.01456 1.02308 +/- 0.00207\n", - " 43/1 1.02376 1.02310 +/- 0.00200\n", - " 44/1 1.01917 1.02299 +/- 0.00195\n", - " 45/1 1.01631 1.02280 +/- 0.00190\n", - " 46/1 1.02381 1.02282 +/- 0.00185\n", - " 47/1 1.04002 1.02329 +/- 0.00185\n", - " 48/1 1.01059 1.02296 +/- 0.00184\n", - " 49/1 1.02647 1.02305 +/- 0.00179\n", - " 50/1 1.02451 1.02308 +/- 0.00175\n", - " Creating state point statepoint.50.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 5.7635e-01 seconds\n", - " Reading cross sections = 5.4002e-01 seconds\n", - " Total time in simulation = 7.0174e+01 seconds\n", - " Time in transport only = 6.9687e+01 seconds\n", - " Time in inactive batches = 7.1832e+00 seconds\n", - " Time in active batches = 6.2991e+01 seconds\n", - " Time synchronizing fission bank = 3.9991e-02 seconds\n", - " Sampling source sites = 3.4633e-02 seconds\n", - " SEND/RECV source sites = 5.2616e-03 seconds\n", - " Time accumulating tallies = 4.9801e-04 seconds\n", - " Total time for finalization = 1.3501e-05 seconds\n", - " Total time elapsed = 7.0791e+01 seconds\n", - " Calculation Rate (inactive) = 13921.3 particles/second\n", - " Calculation Rate (active) = 6350.11 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.02434 +/- 0.00173\n", - " k-effective (Track-length) = 1.02308 +/- 0.00175\n", - " k-effective (Absorption) = 1.02494 +/- 0.00175\n", - " Combined k-effective = 1.02408 +/- 0.00144\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Run OpenMC\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our simulation ran successfully and created statepoint and summary output files. We begin our analysis by instantiating a `StatePoint` object. " - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the last statepoint file\n", - "sp = openmc.StatePoint('statepoint.50.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The statepoint is now ready to be analyzed by the `Library`. We simply have to load the tallies from the statepoint into the `Library` and our `MGXS` objects will compute the cross sections for us under-the-hood." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "# Initialize MGXS Library with OpenMC statepoint data\n", - "mgxs_lib.load_from_statepoint(sp)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Voila! Our multi-group cross sections are now ready to rock 'n roll!" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Extracting and Storing MGXS Data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `Library` supports a rich API to automate a variety of tasks, including multi-group cross section data retrieval and storage. We will highlight a few of these features here. First, the `Library.get_mgxs(...)` method allows one to extract an `MGXS` object from the `Library` for a particular domain and cross section type. The following cell illustrates how one may extract the `NuFissionXS` object for the fuel cell.\n", - "\n", - "**Note:** The `MGXS.get_mgxs(...)` method will accept either the domain *or* the integer domain ID of interest." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "# Retrieve the NuFissionXS object for the fuel cell from the library\n", - "fuel_mgxs = mgxs_lib.get_mgxs(fuel_cell, 'nu-fission')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `NuFissionXS` object supports all of the methods described previously in the `openmc.mgxs` tutorials, such as [Pandas](https://pandas.pydata.org/) `DataFrames`:\n", - "Note that since so few histories were simulated, we should expect a few division-by-error errors as some tallies have not yet scored any results." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellgroup innuclidemeanstd. dev.
311U2358.089079e-031.461462e-05
411U2387.358661e-032.302063e-05
511O160.000000e+000.000000e+00
012U2353.617174e-019.467633e-04
112U2386.744743e-071.750450e-09
212O160.000000e+000.000000e+00
\n", - "
" - ], - "text/plain": [ - " cell group in nuclide mean std. dev.\n", - "3 1 1 U235 8.089079e-03 1.461462e-05\n", - "4 1 1 U238 7.358661e-03 2.302063e-05\n", - "5 1 1 O16 0.000000e+00 0.000000e+00\n", - "0 1 2 U235 3.617174e-01 9.467633e-04\n", - "1 1 2 U238 6.744743e-07 1.750450e-09\n", - "2 1 2 O16 0.000000e+00 0.000000e+00" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = fuel_mgxs.get_pandas_dataframe()\n", - "df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Similarly, we can use the `MGXS.print_xs(...)` method to view a string representation of the multi-group cross section data." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Multi-Group XS\n", - "\tReaction Type =\tnu-fission\n", - "\tDomain Type =\tcell\n", - "\tDomain ID =\t1\n", - "\tNuclide =\tU235\n", - "\tCross Sections [cm^-1]:\n", - " Group 1 [0.625 - 20000000.0eV]:\t8.09e-03 +/- 1.81e-01%\n", - " Group 2 [0.0 - 0.625 eV]:\t3.62e-01 +/- 2.62e-01%\n", - "\n", - "\tNuclide =\tU238\n", - "\tCross Sections [cm^-1]:\n", - " Group 1 [0.625 - 20000000.0eV]:\t7.36e-03 +/- 3.13e-01%\n", - " Group 2 [0.0 - 0.625 eV]:\t6.74e-07 +/- 2.60e-01%\n", - "\n", - "\tNuclide =\tO16\n", - "\tCross Sections [cm^-1]:\n", - " Group 1 [0.625 - 20000000.0eV]:\t0.00e+00 +/- 0.00e+00%\n", - " Group 2 [0.0 - 0.625 eV]:\t0.00e+00 +/- 0.00e+00%\n", - "\n", - "\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/tallies.py:1269: RuntimeWarning: invalid value encountered in true_divide\n", - " data = self.std_dev[indices] / self.mean[indices]\n" - ] - } - ], - "source": [ - "fuel_mgxs.print_xs()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "One can export the entire `Library` to HDF5 with the `Library.build_hdf5_store(...)` method as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "# Store the cross section data in an \"mgxs/mgxs.h5\" HDF5 binary file\n", - "mgxs_lib.build_hdf5_store(filename='mgxs.h5', directory='mgxs')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The HDF5 store will contain the numerical multi-group cross section data indexed by domain, nuclide and cross section type. Some data workflows may be optimized by storing and retrieving binary representations of the `MGXS` objects in the `Library`. This feature is supported through the `Library.dump_to_file(...)` and `Library.load_from_file(...)` routines which use Python's [`pickle`](https://docs.python.org/3/library/pickle.html) module. This is illustrated as follows." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "# Store a Library and its MGXS objects in a pickled binary file \"mgxs/mgxs.pkl\"\n", - "mgxs_lib.dump_to_file(filename='mgxs', directory='mgxs')" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a new MGXS Library from the pickled binary file \"mgxs/mgxs.pkl\"\n", - "mgxs_lib = openmc.mgxs.Library.load_from_file(filename='mgxs', directory='mgxs')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `Library` class may be used to leverage the energy condensation features supported by the `MGXS` class. In particular, one can use the `Library.get_condensed_library(...)` with a coarse group structure which is a subset of the original \"fine\" group structure as shown below." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a 1-group structure\n", - "coarse_groups = openmc.mgxs.EnergyGroups(group_edges=[0., 20.0e6])\n", - "\n", - "# Create a new MGXS Library on the coarse 1-group structure\n", - "coarse_mgxs_lib = mgxs_lib.get_condensed_library(coarse_groups)" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellgroup innuclidemeanstd. dev.
011U2350.0745560.000144
111U2380.0059760.000019
211O160.0000000.000000
\n", - "
" - ], - "text/plain": [ - " cell group in nuclide mean std. dev.\n", - "0 1 1 U235 0.074556 0.000144\n", - "1 1 1 U238 0.005976 0.000019\n", - "2 1 1 O16 0.000000 0.000000" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Retrieve the NuFissionXS object for the fuel cell from the 1-group library\n", - "coarse_fuel_mgxs = coarse_mgxs_lib.get_mgxs(fuel_cell, 'nu-fission')\n", - "\n", - "# Show the Pandas DataFrame for the 1-group MGXS\n", - "coarse_fuel_mgxs.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Verification with OpenMOC" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Of course it is always a good idea to verify that one's cross sections are accurate. We can easily do so here with the deterministic transport code [OpenMOC](https://mit-crpg.github.io/OpenMOC/). We first construct an equivalent OpenMOC geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "# Create an OpenMOC Geometry from the OpenMC Geometry\n", - "openmoc_geometry = get_openmoc_geometry(mgxs_lib.geometry)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we can inject the multi-group cross sections into the equivalent fuel assembly OpenMOC geometry. The `openmoc.materialize` module supports the loading of `Library` objects from OpenMC as illustrated below." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "# Load the library into the OpenMOC geometry\n", - "materials = load_openmc_mgxs_lib(mgxs_lib, openmoc_geometry)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We are now ready to run OpenMOC to verify our cross-sections from OpenMC." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ NORMAL ] Initializing a default angular quadrature...\n", - "[ NORMAL ] Initializing 2D tracks...\n", - "[ NORMAL ] Initializing 2D tracks reflections...\n", - "[ NORMAL ] Initializing 2D tracks array...\n", - "[ NORMAL ] Ray tracing for 2D track segmentation...\n", - "[ WARNING ] The Geometry was set with non-infinite z-boundaries and supplied\n", - "[ WARNING ] ... to a 2D TrackGenerator. The min-z boundary was set to -10.00 \n", - "[ WARNING ] ... and the max-z boundary was set to 10.00. Z-boundaries are \n", - "[ WARNING ] ... assumed to be infinite in 2D TrackGenerators.\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 0.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 10.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 20.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 30.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 40.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 50.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 60.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 70.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 80.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 90.02 %\n", - "[ NORMAL ] Progress Segmenting 2D tracks: 100.00 %\n", - "[ NORMAL ] Initializing FSR lookup vectors\n", - "[ NORMAL ] Total number of FSRs 867\n", - "[ RESULT ] Total Track Generation & Segmentation Time...........4.2139E-01 sec\n", - "[ NORMAL ] Initializing MOC eigenvalue solver...\n", - "[ NORMAL ] Initializing solver arrays...\n", - "[ NORMAL ] Centering segments around FSR centroid...\n", - "[ NORMAL ] Max boundary angular flux storage per domain = 0.42 MB\n", - "[ NORMAL ] Max scalar flux storage per domain = 0.01 MB\n", - "[ NORMAL ] Max source storage per domain = 0.01 MB\n", - "[ NORMAL ] Number of azimuthal angles = 32\n", - "[ NORMAL ] Azimuthal ray spacing = 0.100000\n", - "[ NORMAL ] Number of polar angles = 6\n", - "[ NORMAL ] Source type = Flat\n", - "[ NORMAL ] MOC transport undamped\n", - "[ NORMAL ] CMFD acceleration: OFF\n", - "[ NORMAL ] Using 1 threads\n", - "[ NORMAL ] Computing the eigenvalue...\n", - "[ NORMAL ] Iteration 0: k_eff = 0.823216 res = 9.828E-02 delta-k (pcm) =\n", - "[ NORMAL ] ... -17678 D.R. = 0.10\n", - "[ NORMAL ] Iteration 1: k_eff = 0.779788 res = 4.642E-02 delta-k (pcm) =\n", - "[ NORMAL ] ... -4342 D.R. = 0.47\n", - "[ NORMAL ] Iteration 2: k_eff = 0.738779 res = 9.633E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... -4100 D.R. = 0.21\n", - "[ NORMAL ] Iteration 3: k_eff = 0.710046 res = 8.556E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... -2873 D.R. = 0.89\n", - "[ NORMAL ] Iteration 4: k_eff = 0.688781 res = 5.190E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... -2126 D.R. = 0.61\n", - "[ NORMAL ] Iteration 5: k_eff = 0.674128 res = 3.585E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... -1465 D.R. = 0.69\n", - "[ NORMAL ] Iteration 6: k_eff = 0.664928 res = 2.516E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... -919 D.R. = 0.70\n", - "[ NORMAL ] Iteration 7: k_eff = 0.660304 res = 1.866E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... -462 D.R. = 0.74\n", - "[ NORMAL ] Iteration 8: k_eff = 0.659481 res = 1.471E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... -82 D.R. = 0.79\n", - "[ NORMAL ] Iteration 9: k_eff = 0.661799 res = 1.248E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... 231 D.R. = 0.85\n", - "[ NORMAL ] Iteration 10: k_eff = 0.666690 res = 1.123E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... 489 D.R. = 0.90\n", - "[ NORMAL ] Iteration 11: k_eff = 0.673664 res = 1.049E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... 697 D.R. = 0.93\n", - "[ NORMAL ] Iteration 12: k_eff = 0.682301 res = 1.001E-03 delta-k (pcm) =\n", - "[ NORMAL ] ... 863 D.R. = 0.95\n", - "[ NORMAL ] Iteration 13: k_eff = 0.692239 res = 9.638E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 993 D.R. = 0.96\n", - "[ NORMAL ] Iteration 14: k_eff = 0.703171 res = 9.329E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1093 D.R. = 0.97\n", - "[ NORMAL ] Iteration 15: k_eff = 0.714835 res = 9.055E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1166 D.R. = 0.97\n", - "[ NORMAL ] Iteration 16: k_eff = 0.727008 res = 8.803E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1217 D.R. = 0.97\n", - "[ NORMAL ] Iteration 17: k_eff = 0.739503 res = 8.566E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1249 D.R. = 0.97\n", - "[ NORMAL ] Iteration 18: k_eff = 0.752162 res = 8.335E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1265 D.R. = 0.97\n", - "[ NORMAL ] Iteration 19: k_eff = 0.764855 res = 8.108E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1269 D.R. = 0.97\n", - "[ NORMAL ] Iteration 20: k_eff = 0.777472 res = 7.879E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1261 D.R. = 0.97\n", - "[ NORMAL ] Iteration 21: k_eff = 0.789924 res = 7.647E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1245 D.R. = 0.97\n", - "[ NORMAL ] Iteration 22: k_eff = 0.802140 res = 7.410E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1221 D.R. = 0.97\n", - "[ NORMAL ] Iteration 23: k_eff = 0.814061 res = 7.168E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1192 D.R. = 0.97\n", - "[ NORMAL ] Iteration 24: k_eff = 0.825643 res = 6.922E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1158 D.R. = 0.97\n", - "[ NORMAL ] Iteration 25: k_eff = 0.836850 res = 6.672E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1120 D.R. = 0.96\n", - "[ NORMAL ] Iteration 26: k_eff = 0.847658 res = 6.419E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1080 D.R. = 0.96\n", - "[ NORMAL ] Iteration 27: k_eff = 0.858047 res = 6.165E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 1038 D.R. = 0.96\n", - "[ NORMAL ] Iteration 28: k_eff = 0.868008 res = 5.911E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 996 D.R. = 0.96\n", - "[ NORMAL ] Iteration 29: k_eff = 0.877535 res = 5.658E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 952 D.R. = 0.96\n", - "[ NORMAL ] Iteration 30: k_eff = 0.886625 res = 5.409E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 909 D.R. = 0.96\n", - "[ NORMAL ] Iteration 31: k_eff = 0.895281 res = 5.163E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 865 D.R. = 0.95\n", - "[ NORMAL ] Iteration 32: k_eff = 0.903509 res = 4.921E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 822 D.R. = 0.95\n", - "[ NORMAL ] Iteration 33: k_eff = 0.911317 res = 4.685E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 780 D.R. = 0.95\n", - "[ NORMAL ] Iteration 34: k_eff = 0.918715 res = 4.456E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 739 D.R. = 0.95\n", - "[ NORMAL ] Iteration 35: k_eff = 0.925715 res = 4.232E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 699 D.R. = 0.95\n", - "[ NORMAL ] Iteration 36: k_eff = 0.932329 res = 4.016E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 661 D.R. = 0.95\n", - "[ NORMAL ] Iteration 37: k_eff = 0.938571 res = 3.807E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 624 D.R. = 0.95\n", - "[ NORMAL ] Iteration 38: k_eff = 0.944455 res = 3.606E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 588 D.R. = 0.95\n", - "[ NORMAL ] Iteration 39: k_eff = 0.949996 res = 3.413E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 554 D.R. = 0.95\n", - "[ NORMAL ] Iteration 40: k_eff = 0.955210 res = 3.227E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 521 D.R. = 0.95\n", - "[ NORMAL ] Iteration 41: k_eff = 0.960110 res = 3.049E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 490 D.R. = 0.94\n", - "[ NORMAL ] Iteration 42: k_eff = 0.964713 res = 2.880E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 460 D.R. = 0.94\n", - "[ NORMAL ] Iteration 43: k_eff = 0.969032 res = 2.717E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 431 D.R. = 0.94\n", - "[ NORMAL ] Iteration 44: k_eff = 0.973082 res = 2.562E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 405 D.R. = 0.94\n", - "[ NORMAL ] Iteration 45: k_eff = 0.976877 res = 2.414E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 379 D.R. = 0.94\n", - "[ NORMAL ] Iteration 46: k_eff = 0.980431 res = 2.274E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 355 D.R. = 0.94\n", - "[ NORMAL ] Iteration 47: k_eff = 0.983757 res = 2.140E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 332 D.R. = 0.94\n", - "[ NORMAL ] Iteration 48: k_eff = 0.986869 res = 2.014E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 311 D.R. = 0.94\n", - "[ NORMAL ] Iteration 49: k_eff = 0.989777 res = 1.894E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 290 D.R. = 0.94\n", - "[ NORMAL ] Iteration 50: k_eff = 0.992495 res = 1.780E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 271 D.R. = 0.94\n", - "[ NORMAL ] Iteration 51: k_eff = 0.995033 res = 1.672E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 253 D.R. = 0.94\n", - "[ NORMAL ] Iteration 52: k_eff = 0.997402 res = 1.569E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 236 D.R. = 0.94\n", - "[ NORMAL ] Iteration 53: k_eff = 0.999613 res = 1.473E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 221 D.R. = 0.94\n", - "[ NORMAL ] Iteration 54: k_eff = 1.001675 res = 1.382E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 206 D.R. = 0.94\n", - "[ NORMAL ] Iteration 55: k_eff = 1.003597 res = 1.296E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 192 D.R. = 0.94\n", - "[ NORMAL ] Iteration 56: k_eff = 1.005388 res = 1.215E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 179 D.R. = 0.94\n", - "[ NORMAL ] Iteration 57: k_eff = 1.007057 res = 1.138E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 166 D.R. = 0.94\n", - "[ NORMAL ] Iteration 58: k_eff = 1.008612 res = 1.066E-04 delta-k (pcm) =\n", - "[ NORMAL ] ... 155 D.R. = 0.94\n", - "[ NORMAL ] Iteration 59: k_eff = 1.010059 res = 9.980E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 144 D.R. = 0.94\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ NORMAL ] Iteration 60: k_eff = 1.011406 res = 9.342E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 134 D.R. = 0.94\n", - "[ NORMAL ] Iteration 61: k_eff = 1.012659 res = 8.740E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 125 D.R. = 0.94\n", - "[ NORMAL ] Iteration 62: k_eff = 1.013825 res = 8.175E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 116 D.R. = 0.94\n", - "[ NORMAL ] Iteration 63: k_eff = 1.014909 res = 7.642E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 108 D.R. = 0.93\n", - "[ NORMAL ] Iteration 64: k_eff = 1.015917 res = 7.142E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 100 D.R. = 0.93\n", - "[ NORMAL ] Iteration 65: k_eff = 1.016853 res = 6.675E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 93 D.R. = 0.93\n", - "[ NORMAL ] Iteration 66: k_eff = 1.017724 res = 6.235E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 87 D.R. = 0.93\n", - "[ NORMAL ] Iteration 67: k_eff = 1.018533 res = 5.822E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 80 D.R. = 0.93\n", - "[ NORMAL ] Iteration 68: k_eff = 1.019284 res = 5.436E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 75 D.R. = 0.93\n", - "[ NORMAL ] Iteration 69: k_eff = 1.019982 res = 5.074E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 69 D.R. = 0.93\n", - "[ NORMAL ] Iteration 70: k_eff = 1.020630 res = 4.734E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 64 D.R. = 0.93\n", - "[ NORMAL ] Iteration 71: k_eff = 1.021232 res = 4.417E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 60 D.R. = 0.93\n", - "[ NORMAL ] Iteration 72: k_eff = 1.021790 res = 4.119E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 55 D.R. = 0.93\n", - "[ NORMAL ] Iteration 73: k_eff = 1.022308 res = 3.841E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 51 D.R. = 0.93\n", - "[ NORMAL ] Iteration 74: k_eff = 1.022789 res = 3.579E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 48 D.R. = 0.93\n", - "[ NORMAL ] Iteration 75: k_eff = 1.023235 res = 3.336E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 44 D.R. = 0.93\n", - "[ NORMAL ] Iteration 76: k_eff = 1.023648 res = 3.107E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 41 D.R. = 0.93\n", - "[ NORMAL ] Iteration 77: k_eff = 1.024032 res = 2.897E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 38 D.R. = 0.93\n", - "[ NORMAL ] Iteration 78: k_eff = 1.024388 res = 2.696E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 35 D.R. = 0.93\n", - "[ NORMAL ] Iteration 79: k_eff = 1.024718 res = 2.510E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 32 D.R. = 0.93\n", - "[ NORMAL ] Iteration 80: k_eff = 1.025024 res = 2.338E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 30 D.R. = 0.93\n", - "[ NORMAL ] Iteration 81: k_eff = 1.025307 res = 2.175E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 28 D.R. = 0.93\n", - "[ NORMAL ] Iteration 82: k_eff = 1.025570 res = 2.025E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 26 D.R. = 0.93\n", - "[ NORMAL ] Iteration 83: k_eff = 1.025814 res = 1.886E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 24 D.R. = 0.93\n", - "[ NORMAL ] Iteration 84: k_eff = 1.026039 res = 1.752E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 22 D.R. = 0.93\n", - "[ NORMAL ] Iteration 85: k_eff = 1.026249 res = 1.628E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 20 D.R. = 0.93\n", - "[ NORMAL ] Iteration 86: k_eff = 1.026442 res = 1.517E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 19 D.R. = 0.93\n", - "[ NORMAL ] Iteration 87: k_eff = 1.026622 res = 1.408E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 17 D.R. = 0.93\n", - "[ NORMAL ] Iteration 88: k_eff = 1.026788 res = 1.308E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 16 D.R. = 0.93\n", - "[ NORMAL ] Iteration 89: k_eff = 1.026942 res = 1.218E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 15 D.R. = 0.93\n", - "[ NORMAL ] Iteration 90: k_eff = 1.027085 res = 1.132E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 14 D.R. = 0.93\n", - "[ NORMAL ] Iteration 91: k_eff = 1.027217 res = 1.049E-05 delta-k (pcm) =\n", - "[ NORMAL ] ... 13 D.R. = 0.93\n", - "[ NORMAL ] Iteration 92: k_eff = 1.027339 res = 9.760E-06 delta-k (pcm) =\n", - "[ NORMAL ] ... 12 D.R. = 0.93\n", - "[ NORMAL ] Iteration 93: k_eff = 1.027453 res = 9.076E-06 delta-k (pcm) =\n", - "[ NORMAL ] ... 11 D.R. = 0.93\n", - "[ NORMAL ] Iteration 94: k_eff = 1.027557 res = 8.434E-06 delta-k (pcm) =\n", - "[ NORMAL ] ... 10 D.R. = 0.93\n", - "[ NORMAL ] Iteration 95: k_eff = 1.027655 res = 7.827E-06 delta-k (pcm) =\n", - "[ NORMAL ] ... 9 D.R. = 0.93\n", - "[ NORMAL ] Iteration 96: k_eff = 1.027744 res = 7.266E-06 delta-k (pcm) =\n", - "[ NORMAL ] ... 8 D.R. = 0.93\n", - "[ NORMAL ] Iteration 97: k_eff = 1.027828 res = 6.737E-06 delta-k (pcm) =\n", - "[ NORMAL ] ... 8 D.R. = 0.93\n", - "[ NORMAL ] Iteration 98: k_eff = 1.027905 res = 6.255E-06 delta-k (pcm) =\n", - "[ NORMAL ] ... 7 D.R. = 0.93\n", - "[ NORMAL ] Iteration 99: k_eff = 1.027976 res = 5.803E-06 delta-k (pcm) =\n", - "[ NORMAL ] ... 7 D.R. = 0.93\n", - "[ NORMAL ] Iteration 100: k_eff = 1.028042 res = 5.383E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 0.93\n", - "[ NORMAL ] Iteration 101: k_eff = 1.028103 res = 5.017E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 6 D.R. = 0.93\n", - "[ NORMAL ] Iteration 102: k_eff = 1.028160 res = 4.618E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 0.92\n", - "[ NORMAL ] Iteration 103: k_eff = 1.028212 res = 4.306E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 5 D.R. = 0.93\n", - "[ NORMAL ] Iteration 104: k_eff = 1.028260 res = 3.999E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.93\n", - "[ NORMAL ] Iteration 105: k_eff = 1.028305 res = 3.706E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.93\n", - "[ NORMAL ] Iteration 106: k_eff = 1.028347 res = 3.429E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 4 D.R. = 0.93\n", - "[ NORMAL ] Iteration 107: k_eff = 1.028385 res = 3.213E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.94\n", - "[ NORMAL ] Iteration 108: k_eff = 1.028420 res = 2.943E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.92\n", - "[ NORMAL ] Iteration 109: k_eff = 1.028453 res = 2.740E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.93\n", - "[ NORMAL ] Iteration 110: k_eff = 1.028484 res = 2.531E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 3 D.R. = 0.92\n", - "[ NORMAL ] Iteration 111: k_eff = 1.028512 res = 2.369E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.94\n", - "[ NORMAL ] Iteration 112: k_eff = 1.028538 res = 2.186E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.92\n", - "[ NORMAL ] Iteration 113: k_eff = 1.028562 res = 2.026E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.93\n", - "[ NORMAL ] Iteration 114: k_eff = 1.028584 res = 1.858E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.92\n", - "[ NORMAL ] Iteration 115: k_eff = 1.028604 res = 1.760E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 2 D.R. = 0.95\n", - "[ NORMAL ] Iteration 116: k_eff = 1.028623 res = 1.612E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.92\n", - "[ NORMAL ] Iteration 117: k_eff = 1.028641 res = 1.496E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.93\n", - "[ NORMAL ] Iteration 118: k_eff = 1.028657 res = 1.382E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.92\n", - "[ NORMAL ] Iteration 119: k_eff = 1.028672 res = 1.293E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.94\n", - "[ NORMAL ] Iteration 120: k_eff = 1.028686 res = 1.191E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.92\n", - "[ NORMAL ] Iteration 121: k_eff = 1.028699 res = 1.112E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.93\n", - "[ NORMAL ] Iteration 122: k_eff = 1.028711 res = 1.005E-06 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.90\n", - "[ NORMAL ] Iteration 123: k_eff = 1.028722 res = 9.443E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.94\n", - "[ NORMAL ] Iteration 124: k_eff = 1.028732 res = 8.583E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 1 D.R. = 0.91\n", - "[ NORMAL ] Iteration 125: k_eff = 1.028742 res = 8.028E-07 delta-k (pcm)\n", - "[ NORMAL ] ... = 0 D.R. = 0.94\n" - ] - } - ], - "source": [ - "# Generate tracks for OpenMOC\n", - "track_generator = openmoc.TrackGenerator(openmoc_geometry, num_azim=32, azim_spacing=0.1)\n", - "track_generator.generateTracks()\n", - "\n", - "# Run OpenMOC\n", - "solver = openmoc.CPUSolver(track_generator)\n", - "solver.computeEigenvalue()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We report the eigenvalues computed by OpenMC and OpenMOC here together to summarize our results." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "openmc keff = 1.024078\n", - "openmoc keff = 1.028742\n", - "bias [pcm]: 466.4\n" - ] - } - ], - "source": [ - "# Print report of keff and bias with OpenMC\n", - "openmoc_keff = solver.getKeff()\n", - "openmc_keff = sp.k_combined.nominal_value\n", - "bias = (openmoc_keff - openmc_keff) * 1e5\n", - "\n", - "print('openmc keff = {0:1.6f}'.format(openmc_keff))\n", - "print('openmoc keff = {0:1.6f}'.format(openmoc_keff))\n", - "print('bias [pcm]: {0:1.1f}'.format(bias))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There is a non-trivial bias between the eigenvalues computed by OpenMC and OpenMOC. One can show that these biases do not converge to <100 pcm with more particle histories. For heterogeneous geometries, additional measures must be taken to address the following three sources of bias:\n", - "\n", - "* Appropriate transport-corrected cross sections\n", - "* Spatial discretization of OpenMOC's mesh\n", - "* Constant-in-angle multi-group cross sections" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Flux and Pin Power Visualizations" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will conclude this tutorial by illustrating how to visualize the fission rates computed by OpenMOC and OpenMC. First, we extract volume-integrated fission rates from OpenMC's mesh fission rate tally for each pin cell in the fuel assembly." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [], - "source": [ - "# Get the OpenMC fission rate mesh tally data\n", - "mesh_tally = sp.get_tally(name='mesh tally')\n", - "openmc_fission_rates = mesh_tally.get_values(scores=['nu-fission'])\n", - "\n", - "# Reshape array to 2D for plotting\n", - "openmc_fission_rates.shape = (17,17)\n", - "\n", - "# Normalize to the average pin power\n", - "openmc_fission_rates /= np.mean(openmc_fission_rates[openmc_fission_rates > 0.])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we extract OpenMOC's volume-averaged fission rates into a 2D 17x17 NumPy array." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "# Create OpenMOC Mesh on which to tally fission rates\n", - "openmoc_mesh = openmoc.process.Mesh()\n", - "openmoc_mesh.dimension = np.array(mesh.dimension)\n", - "openmoc_mesh.lower_left = np.array(mesh.lower_left)\n", - "openmoc_mesh.upper_right = np.array(mesh.upper_right)\n", - "openmoc_mesh.width = openmoc_mesh.upper_right - openmoc_mesh.lower_left\n", - "openmoc_mesh.width /= openmoc_mesh.dimension\n", - "\n", - "# Tally OpenMOC fission rates on the Mesh\n", - "openmoc_fission_rates = openmoc_mesh.tally_fission_rates(solver)\n", - "openmoc_fission_rates = np.squeeze(openmoc_fission_rates)\n", - "openmoc_fission_rates = np.fliplr(openmoc_fission_rates)\n", - "\n", - "# Normalize to the average pin fission rate\n", - "openmoc_fission_rates /= np.mean(openmoc_fission_rates[openmoc_fission_rates > 0.])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can easily use Matplotlib to visualize the fission rates from OpenMC and OpenMOC side-by-side." - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0.5, 1.0, 'OpenMOC Fission Rates')" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Ignore zero fission rates in guide tubes with Matplotlib color scheme\n", - "openmc_fission_rates[openmc_fission_rates == 0] = np.nan\n", - "openmoc_fission_rates[openmoc_fission_rates == 0] = np.nan\n", - "\n", - "# Plot OpenMC's fission rates in the left subplot\n", - "fig = plt.subplot(121)\n", - "plt.imshow(openmc_fission_rates, interpolation='none', cmap='jet')\n", - "plt.title('OpenMC Fission Rates')\n", - "\n", - "# Plot OpenMOC's fission rates in the right subplot\n", - "fig2 = plt.subplot(122)\n", - "plt.imshow(openmoc_fission_rates, interpolation='none', cmap='jet')\n", - "plt.title('OpenMOC Fission Rates')" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/nuclear-data-resonance-covariance.ipynb b/examples/jupyter/nuclear-data-resonance-covariance.ipynb deleted file mode 100644 index 8fe85161d26..00000000000 --- a/examples/jupyter/nuclear-data-resonance-covariance.ipynb +++ /dev/null @@ -1,963 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Nuclear Data: Resonance Covariance\n", - "In this notebook we will explore features of the Python API that allow us to import and manipulate resonance covariance data. A full description of the ENDF-VI and ENDF-VII formats can be found in the [ENDF102 manual](https://www.oecd-nea.org/dbdata/data/manual-endf/endf102.pdf)." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import os\n", - "from pprint import pprint\n", - "import shutil\n", - "import subprocess\n", - "import urllib.request\n", - "\n", - "import h5py\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "import openmc.data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### ENDF: Resonance Covariance Data\n", - "\n", - "Let's download the ENDF/B-VII.1 evaluation for $^{157}$Gd and load it in:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Download ENDF file\n", - "url = 'https://t2.lanl.gov/nis/data/data/ENDFB-VII.1-neutron/Gd/157'\n", - "filename, headers = urllib.request.urlretrieve(url, 'gd157.endf')\n", - "\n", - "# Load into memory\n", - "gd157_endf = openmc.data.IncidentNeutron.from_endf(filename, covariance=True)\n", - "gd157_endf" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can access the parameters contained within File 32 in a similar manner to the File 2 parameters from before. " - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energyJneutronWidthcaptureWidthfissionWidthAfissionWidthBL
00.03142.00.0004740.10720.00.00
12.82502.00.0003450.09700.00.00
216.24001.00.0004000.09100.00.00
316.77002.00.0128000.08050.00.00
420.56002.00.0113600.08800.00.00
\n", - "
" - ], - "text/plain": [ - " energy J neutronWidth captureWidth fissionWidthA fissionWidthB L\n", - "0 0.0314 2.0 0.000474 0.1072 0.0 0.0 0\n", - "1 2.8250 2.0 0.000345 0.0970 0.0 0.0 0\n", - "2 16.2400 1.0 0.000400 0.0910 0.0 0.0 0\n", - "3 16.7700 2.0 0.012800 0.0805 0.0 0.0 0\n", - "4 20.5600 2.0 0.011360 0.0880 0.0 0.0 0" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gd157_endf.resonance_covariance.ranges[0].parameters[:5]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The newly created object will contain multiple resonance regions within `gd157_endf.resonance_covariance.ranges`. We can access the full covariance matrix from File 32 for a given range by:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "covariance = gd157_endf.resonance_covariance.ranges[0].covariance" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This covariance matrix currently only stores the upper triangular portion as covariance matrices are symmetric. Plotting the covariance matrix:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.imshow(covariance, cmap='seismic',vmin=-0.008, vmax=0.008)\n", - "plt.colorbar()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The correlation matrix can be constructed using the covariance matrix and also give some insight into the relations among the parameters." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "corr = np.zeros([len(covariance),len(covariance)])\n", - "for i in range(len(covariance)):\n", - " for j in range(len(covariance)):\n", - " corr[i, j]=covariance[i, j]/covariance[i, i]**(0.5)/covariance[j, j]**(0.5)\n", - "plt.imshow(corr, cmap='seismic',vmin=-1.0, vmax=1.0)\n", - "plt.colorbar()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Sampling and Reconstruction" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The covariance module also has the ability to sample a new set of parameters using the covariance matrix. Currently the sampling uses numpy.multivariate_normal(). Because parameters are assumed to have a multivariate normal distribution this method doesn't not currently guarantee that sampled parameters will be positive." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/data/resonance_covariance.py:233: UserWarning: Sampling routine does not guarantee positive values for parameters. This can lead to undefined behavior in the reconstruction routine.\n", - " warnings.warn(warn_str)\n" - ] - }, - { - "data": { - "text/plain": [ - "openmc.data.resonance.ReichMoore" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rm_resonance = gd157_endf.resonances.ranges[0]\n", - "n_samples = 5\n", - "samples = gd157_endf.resonance_covariance.ranges[0].sample(n_samples)\n", - "type(samples[0])\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The sampling routine requires the incorporation of the `openmc.data.ResonanceRange` for the same resonance range object. This allows each sample itself to be its own `openmc.data.ResonanceRange` with a new set of parameters. Looking at some of the sampled parameters below:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sample 1\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energyLJneutronWidthcaptureWidthfissionWidthAfissionWidthB
00.03067902.00.0004730.1085760.00.0
12.82384302.00.0003510.0864180.00.0
216.28114701.00.0004580.1068250.00.0
316.77176002.00.0135980.0728370.00.0
420.56154502.00.0111640.0866160.00.0
\n", - "
" - ], - "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.030679 0 2.0 0.000473 0.108576 0.0 0.0\n", - "1 2.823843 0 2.0 0.000351 0.086418 0.0 0.0\n", - "2 16.281147 0 1.0 0.000458 0.106825 0.0 0.0\n", - "3 16.771760 0 2.0 0.013598 0.072837 0.0 0.0\n", - "4 20.561545 0 2.0 0.011164 0.086616 0.0 0.0" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "print('Sample 1')\n", - "samples[0].parameters[:5]" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sample 2\n" - ] - }, - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energyLJneutronWidthcaptureWidthfissionWidthAfissionWidthB
00.03285802.00.0004790.1052080.00.0
12.82385902.00.0003610.0937480.00.0
216.20306901.00.0002640.0152330.00.0
316.76505502.00.0136480.0761190.00.0
420.55767902.00.0111400.0975480.00.0
\n", - "
" - ], - "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.032858 0 2.0 0.000479 0.105208 0.0 0.0\n", - "1 2.823859 0 2.0 0.000361 0.093748 0.0 0.0\n", - "2 16.203069 0 1.0 0.000264 0.015233 0.0 0.0\n", - "3 16.765055 0 2.0 0.013648 0.076119 0.0 0.0\n", - "4 20.557679 0 2.0 0.011140 0.097548 0.0 0.0" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "print('Sample 2')\n", - "samples[1].parameters[:5]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can reconstruct the cross section from the sampled parameters using the reconstruct method of `openmc.data.ResonanceRange`. For more on reconstruction see the Nuclear Data example notebook. " - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[,\n", - " ]" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gd157_endf.resonances.ranges" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Cross section (b)')" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "energy_range = [rm_resonance.energy_min, rm_resonance.energy_max]\n", - "energies = np.logspace(np.log10(energy_range[0]),\n", - " np.log10(energy_range[1]), 10000)\n", - "for sample in samples:\n", - " xs = sample.reconstruct(energies)\n", - " elastic_xs = xs[2]\n", - " plt.loglog(energies, elastic_xs)\n", - "plt.xlabel('Energy (eV)')\n", - "plt.ylabel('Cross section (b)')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Subset Selection" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Another capability of the covariance module is selecting a subset of the resonance parameters and the corresponding subset of the covariance matrix. We can do this by specifying the value we want to discriminate and the bounds within one energy region. Selecting only resonances with J=2:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energyLJneutronWidthcaptureWidthfissionWidthAfissionWidthB
00.031402.00.0004740.10720.00.0
12.825002.00.0003450.09700.00.0
316.770002.00.0128000.08050.00.0
420.560002.00.0113600.08800.00.0
521.650002.00.0003760.11400.00.0
\n", - "
" - ], - "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.0314 0 2.0 0.000474 0.1072 0.0 0.0\n", - "1 2.8250 0 2.0 0.000345 0.0970 0.0 0.0\n", - "3 16.7700 0 2.0 0.012800 0.0805 0.0 0.0\n", - "4 20.5600 0 2.0 0.011360 0.0880 0.0 0.0\n", - "5 21.6500 0 2.0 0.000376 0.1140 0.0 0.0" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "lower_bound = 2; # inclusive\n", - "upper_bound = 2; # inclusive\n", - "rm_res_cov_sub = gd157_endf.resonance_covariance.ranges[0].subset('J',[lower_bound,upper_bound])\n", - "rm_res_cov_sub.file2res.parameters[:5]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The subset method will also store the corresponding subset of the covariance matrix" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(180, 180)" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "rm_res_cov_sub.covariance\n", - "gd157_endf.resonance_covariance.ranges[0].covariance.shape\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Checking the size of the new covariance matrix to be sure it was sampled properly: " - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Number of parameters\n", - "Original: 60\n", - "Subet: 36\n", - "Covariance Size\n", - "Original: (180, 180)\n", - "Subset: (108, 108)\n" - ] - } - ], - "source": [ - "old_n_parameters = gd157_endf.resonance_covariance.ranges[0].parameters.shape[0]\n", - "old_shape = gd157_endf.resonance_covariance.ranges[0].covariance.shape\n", - "new_n_parameters = rm_res_cov_sub.file2res.parameters.shape[0]\n", - "new_shape = rm_res_cov_sub.covariance.shape\n", - "print('Number of parameters\\nOriginal: '+str(old_n_parameters)+'\\nSubet: '+str(new_n_parameters)+'\\nCovariance Size\\nOriginal: '+str(old_shape)+'\\nSubset: '+str(new_shape))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And finally, we can sample from the subset as well" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energyLJneutronWidthcaptureWidthfissionWidthAfissionWidthB
00.03048802.00.0004730.1089460.00.0
12.82594402.00.0003280.0983280.00.0
216.77388602.00.0129840.0767790.00.0
320.56573702.00.0116280.0889580.00.0
421.64646902.00.0003890.1278330.00.0
\n", - "
" - ], - "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.030488 0 2.0 0.000473 0.108946 0.0 0.0\n", - "1 2.825944 0 2.0 0.000328 0.098328 0.0 0.0\n", - "2 16.773886 0 2.0 0.012984 0.076779 0.0 0.0\n", - "3 20.565737 0 2.0 0.011628 0.088958 0.0 0.0\n", - "4 21.646469 0 2.0 0.000389 0.127833 0.0 0.0" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "samples_sub = rm_res_cov_sub.sample(n_samples)\n", - "samples_sub[0].parameters[:5]" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/jupyter/nuclear-data.ipynb b/examples/jupyter/nuclear-data.ipynb deleted file mode 100644 index 6a8aeb90c92..00000000000 --- a/examples/jupyter/nuclear-data.ipynb +++ /dev/null @@ -1,1504 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Nuclear Data\n", - "In this notebook, we will go through the salient features of the `openmc.data` package in the Python API. This package enables inspection, analysis, and conversion of nuclear data from ACE files. Most importantly, the package provides a mean to generate HDF5 nuclear data libraries that are used by the transport solver." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import os\n", - "from pprint import pprint\n", - "import shutil\n", - "import subprocess\n", - "import urllib.request\n", - "\n", - "import h5py\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import matplotlib.cm\n", - "from matplotlib.patches import Rectangle\n", - "\n", - "import openmc.data" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Physical Data\n", - "\n", - "Some very helpful physical data is available as part of `openmc.data`: atomic masses, natural abundances, and atomic weights." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "53.939608306" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "openmc.data.atomic_mass('Fe54')" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.00015574" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "openmc.data.NATURAL_ABUNDANCE['H2']" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "12.011115164864455" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "openmc.data.atomic_weight('C')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## The IncidentNeutron class\n", - "\n", - "The most useful class within the `openmc.data` API is `IncidentNeutron`, which stores to continuous-energy incident neutron data. This class has factory methods `from_ace`, `from_endf`, and `from_hdf5` which take a data file on disk and parse it into a hierarchy of classes in memory. To demonstrate this feature, we will download an ACE file (which can be produced with [NJOY 2016](https://github.com/njoy/NJOY2016)) and then load it in using the `IncidentNeutron.from_ace` method. " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "url = 'https://anl.box.com/shared/static/kxm7s57z3xgfbeq29h54n7q6js8rd11c.ace'\n", - "filename, headers = urllib.request.urlretrieve(url, 'gd157.ace')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Load ACE data into object\n", - "gd157 = openmc.data.IncidentNeutron.from_ace('gd157.ace')\n", - "gd157" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Cross sections" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "From Python, it's easy to explore (and modify) the nuclear data. Let's start off by reading the total cross section. Reactions are indexed using their \"MT\" number -- a unique identifier for each reaction defined by the ENDF-6 format. The MT number for the total cross section is 1." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "total = gd157[1]\n", - "total" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Cross sections for each reaction can be stored at multiple temperatures. To see what temperatures are available, we can look at the reaction's `xs` attribute." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'294K': }" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "total.xs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To find the cross section at a particular energy, 1 eV for example, simply get the cross section at the appropriate temperature and then call it as a function. Note that our nuclear data uses eV as the unit of energy." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "142.64747" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "total.xs['294K'](1.0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `xs` attribute can also be called on an array of energies." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([142.64747 , 38.6541761 , 175.40019642])" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "total.xs['294K']([1.0, 2.0, 3.0])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A quick way to plot cross sections is to use the `energy` attribute of `IncidentNeutron`. This gives an array of all the energy values used in cross section interpolation for each temperature present." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'294K': array([1.0000e-05, 1.0325e-05, 1.0650e-05, ..., 1.9500e+07, 1.9900e+07,\n", - " 2.0000e+07])}" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gd157.energy" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Cross section (b)')" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYgAAAEOCAYAAACTqoDjAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3Xl8VPXV+PHPySSTnbAlYQl72AVRoiBugKBYBK27VWtbqo+22kWfWvuzrXZ7amtrrRW1VJG6FGvddxRZFRBBrewQ9p2EJZB9O78/ZoJDmGQmk5nczOS8X695JXPn3jvnG8icfHdRVYwxxpj64pwOwBhjTOtkCcIYY4xfliCMMcb4ZQnCGGOMX5YgjDHG+GUJwhhjjF+WIIwxxvhlCcIYY4xfliCMMcb4ZQnCGGOMX/FOBxAKEZkCTElPT795wIABTodjjDFRZeXKlYWqmhnoPInmtZjy8vJ0xYoVTodhjDFRRURWqmpeoPOsickYY4xfliCMMcb4ZQnCGGOMX62mk1pEzgWuxxPTEFUd43BIxhjTpkW0BiEiM0XkgIisrnd8kohsEJF8EbkHQFUXq+qtwFvAPyMZlzHGmMAi3cQ0C5jke0BEXMB04GJgCHCdiAzxOeUbwL8iHJcxxpgAIpogVHURcKje4TOBfFXdoqqVwAvApQAi0hMoUtVjkYzrwLFyPly3P5JvYYwxUc+JTuruwE6f57u8xwCmAU83drGI3CIiK0RkRUFBQUgBPLl4K9P+uYLvP/8ZB46Wh3QPY4yJda2mkxpAVe8L4pwZIrIXmOJ2u0eG8j7/e+FAMpIT+OuHm1i0qYB7Lh7EdWf0JC5OQrmdMcbEJCdqELuBHj7Pc7zHgqaqb6rqLRkZGSEF4I6P4/vjcpnzo/MY1j2De19dzdV/X8rG/RFt2TLGmKjiRIL4FOgvIn1ExA1cC7zRlBuIyBQRmVFUVNSsQPp0TuX5747iT1edyuaCYiY/spiH3t9AeVVNs+5rjDGxINLDXGcDS4GBIrJLRKapajVwOzAHWAe8qKprmnLf5tYg6sXIlSNzmHvn+UwZ3o1H5uXztb8uZunmg82+tzHGRLOoXKyvbjXX3Nzcmzdt2hTWey/eVMC9r65mx6FSrhqZw//72mA6pLrD+h7GGOOkYBfri8oEUSdSq7mWVdbwyLxNzFi0hfbJCfxyyhCmntoNEevENsZEv5hezTVcfRANSXa7+OmkQbx1xzn06JjCD1/4gm/OXM6Og6UReT9jjGmNrAYRQE2t8tyy7Tw4ZwPVtbX8aMIApp3ThwRXVOZWY4yJ7RpES3LFCTeN6c0Hd57Hef0zeeDd9Ux99GP+u/OI06EZY0xERWWCiHQTkz9dM5KZ8c08nrhhJIdKKrjssY+5/401FFdUt1gMxhjTkqyJKQTHyqt4cM4Gnl22nS7tkvj1pacwcUh2i8dhjDGhsCamCEpPSuDXl57Cy7eNoV1SAjc/s4Jbn13JflvXyRgTQ6IyQTjRxOTP6T078NYPzuHuSQOZv+EAE/68kGeXbae2NnprZcYYU8eamMJkW2EJ9762io/zD3J6z/b8/vLhDOyS7nRYxhhzEmtiamG9O6fy3LRRPHT1qWwtLGHyI4t5cM56W9fJGBO1ojJBtJYmpvpEhMtPz+HDu8YydUQ3ps/fzKSHF7Ekv9Dp0IwxpsmsiSmCPs4v5N5XV7HtYClXnJ7DvZMH09HWdTLGOMyamFqBs3M7896PzuP74/rx+he7ueDPC3jls11Ec1I2xrQdliAiLCnBxU8uGsRbPziH3p1TufPF/3LjU8vZfrDE6dCMMaZRliBayKAu7Xj51jH85tKhfLHzCBf+ZRHT5+dTVVPrdGjGGOOXJYgWFBcn3HhWb+beeT7jBmbx4JwNTPnbR3y247DToRljzEmiMkG01lFMweqSkcQTN45kxo0jOVJaxRWPL+GXr6/mWHmV06EZY8xxNorJYcfKq/jz+xv559JtZKcncf/UoUw6pYvTYRljYpiNYooS6UkJ3D91KK/cNob2KQnc+txKbnlmBXuLypwOzRjTxlmCaCVO69mBN+84h59OGsTCjQVMfGgR/1yyjRpb18kY4xBLEK1IgiuO28b24/0fn8dpPdtz3xtruOLxJazbe9Tp0IwxbVCrSRAiEicivxORv4nITU7H46RenVJ55jtn8vA1I9hxqJQpf/uIP7xn6zoZY1pWRBOEiMwUkQMisrre8UkiskFE8kXkHu/hS4EcoArYFcm4ooGIcNlp3fnwzvO57LTuPL5gMxf+ZRHzNxxwOjRjTBsR6RrELGCS7wERcQHTgYuBIcB1IjIEGAgsUdU7gdsiHFfU6JDq5k9Xncq/bh5FvEv49tOfcuuzK9lzxDqxjTGRFdEEoaqLgEP1Dp8J5KvqFlWtBF7AU3vYBdTNGLO2lHrG9OvMuz88l59c5N2c6KGFzFi02WZiG2Mixok+iO7ATp/nu7zHXgEuEpG/AYsaulhEbhGRFSKyoqCgILKRtjKJ8S6+Py6XuXeez1l9O/F/76xn8iOLWb61fg42xpjmazWd1KpaqqrTVPUOVZ3eyHkzVDVPVfMyMzNbMsRWo0fHFJ761hn845t5lFTUcPXfl3LXi//lYHGF06EZY2KIEwliN9DD53mO91jQon2pjXCZOCSbD+48j9vGepYTH//nhTz/ie2JbYwJDycSxKdAfxHpIyJu4FrgDQfiiAkp7nh+OmkQ7/7wXAZ3TefeV1fz9ceXsHp3206expjmi/Qw19nAUmCgiOwSkWmqWg3cDswB1gEvquqaptxXVd9U1VsyMjLCH3SU6p+dzuybR/PwNSPYfbiMqY9+xH2vr+ZIaaXToRljolRULtYnIlOAKbm5uTdv2rTJ6XBanaKyKv78/gaeW7adjOQE7rxwINed0YN4V6vpcjLGOCjYxfqiMkHUiYXVXCNp3d6j/OrNNSzbcohBXdL55SVDGJPb2emwjDEOi+nVXK2TOjiDu7Zj9s2jeeKG0ymuqOYbT37Crc+uZMfBUqdDM8ZEAatBtBHlVTU89dFWps/Pp7pWufncPnxvbC6pifFOh2aMaWExXYMwTZeU4JlkN++usVwyrCvT52/m/AcX8MzSbVRW22xsY8zJorIGYZ3Uzff5jsM88O56Ptl6iJ4dU7jrwgFMGd6NuDhxOjRjTIRZJ7UJSFVZsLGAP763gXV7jzK0WzvunjSI8/p3RsQShTGxypqYTEAiwriBWbx9xzk8fM0IjpZXcdPM5Vz996Us2lhANP/xYIxpvqisQVgTU2RUVtcye/kOHl+wmX1Hyzm1R3vuGJfLBYOzrEZhTAyxJiYTsorqGl75bDePLchn56EyBndtx+3jcpl0Shdc1kdhTNSzBGGarbqmljf+u4dH5+ezpaCE3p1SuOW8flx+eneSElxOh2eMCZElCBM2NbXK+2v28fjCzXy5q4jM9ES+c3Yfrh/dk3ZJCU6HZ4xpophOENYH4QxVZenmgzy+cDOLNxWSnhjP9aN78Z1zepOVnuR0eMaYIMV0gqhjNQjnrN5dxOMLN/Puqr3Eu+K44vQc/ue8vvTunOp0aMaYACxBmBaxrbCEGYu38NKKXVTX1nLdmT356cWDrOnJmFbMEoRpUQeOlfPY/M08s3QbmemJPHLtaYzq28npsIwxfthEOdOistKTuH/qUF793tmkuuO5/slPeHbZdqfDMsY0Q1QmCFvuu/U6tUd7Xrv9bM4fkMkvXlvN3xdudjokY0yIojJB2JajrVu7pAT+fuNILhneld+/u56XV+5yOiRjTAhsMwATEfGuOP5yzQgOFlfys1dX0S8rjRE92jsdljGmCaKyBmGiQ4IrjseuP53MtER+/O8vKKuscTokY0wTWIIwEdUh1c2DVw5na2EJf3p/g9PhGGOawBKEibgxuZ35xqiezFqyjfwDxU6HY4wJUsAEISJnich0EflSRApEZIeIvCMi3xeRsPUSi8hYEVksIk+IyNhw3de0DndNHEBKgosH3l3vdCjGmCA1miBE5F3gu8AcYBLQFRgC/BxIAl4XkamNXD9TRA6IyOp6xyeJyAYRyReRe7yHFSj23teGvcSYTmmJ3DauH3PX7efTbYecDscYE4RGZ1KLSGdVLWz0Bo2cIyLn4fnQf0ZVT/EecwEbgYl4EsGnwHXAelWtFZFs4CFVvT5Q8DaTOrqUVdZw9h/mMaJHe2Z+6wynwzGmzQrLTGrfD34R6SIiU72T1Lr4O8fP9YuA+n8ungnkq+oWVa0EXgAuVdVa7+uHgcRAgZvok+x28e0xvZm3/gDr9x11OhxjTABBdVKLyHeB5cDlwJXAMhH5Tojv2R3Y6fN8F9BdRC4Xkb8DzwKPNhLLLSKyQkRWFBQUhBiCccqNZ/Uixe1ixsItTodijAkg2IlyPwFOU9WDACLSCVgCzAxXIKr6CvBKEOfNEJG9wBS32z0yXO9vWkb7FDdX5/XgX5/s4OeXDKFjqtvpkIwxDQh2mOtB4JjP82PeY6HYDfTweZ7jPRY0W2ojun1jVE8qa2ptCQ5jWrlGaxAicqf323zgExF5Hc9oo0uBL0N8z0+B/iLSB09iuBb4RlNu4LOjXIghGCcNyE4nr1cHZi/fwXfP7YOIOB2SMcaPQDWIdO9jM/AanuQA8DqwNdDNRWQ2sBQYKCK7RGSaqlYDt+MZOrsOeFFV1zQlaKtBRL9vjOrJlsISlm4JtSJqjIm0qNwwyPakjn7lVTWc8bu5TBySzUNXj3A6HGPalLAMcxWRf4jIKQ28lioi3xGRgPMVws1qENEvKcHF107pypzV+2wRP2NaqUBNTNOBX4rIOhH5j4g85p0dvRjPKKZ04KWIR1mPbRgUGy49rRsllTXMXbff6VCMMX402kmtql8AV4tIGpCHZ6mNMmCdqjq2NKeqvgm8mZeXd7NTMZjmG9WnE9ntEnn9iz1MObWb0+EYY+oJah6EqhYDCyIbSvBsFFNscMUJU0/txqwl2zhSWkn7FJsTYUxrEpXLfVsfROy4dER3qmqUt1ftdToUY0w9UZkgTOwY2q0dfTun8t7qfU6HYoypJyoThHVSxw4R4aJTurB080GOlFY6HY4xxkewi/UN8A55fV9E5tU9Ih1cQ6yJKbZMGtqF6lpl7roDTodijPER7GJ9/wGeAP4B2KB1E1bDczLolpHEe6v3cuXIHKfDMcZ4BZsgqlX18YhGYtqsumam5z/ZQXFFNWmJwf63NMZEUrB9EG+KyPdEpKuIdKx7RDSyRlgfROyZNLQLldW1LNhgzUzGtBbBJoib8OwJsQRY6X04tten9UHEnrzeHemc5uZdG81kTKsR7ES5PpEOxLRtrjhh4pAuvP7FbsqrakhKcDkdkjFtXrCjmBJE5Aci8pL3cbuIJEQ6ONO2XDQ0m9LKGpZutiXAjWkNgm1iehwYCTzmfYz0HjMmbEb37USK28UHtnifMa1CsMNFzlDVU32ezxOR/0YiINN2JSW4OK9/Jh+u249edortNGeMw4KtQdSISL+6JyLSFwfnQ9gopth1weAs9h+tYPXuo06HYkybF2yC+AkwX0QWiMhCYB5wV+TCapyNYopd4wdlIYLtEWFMKxDsKKYPRaQ/MNB7aIOqVkQuLNNWdUpL5PSeHZi7bj8/njjA6XCMadMCbTk63vv1cmAykOt9TPYeMybsJgzOZs2eo+wtKnM6FGPatEBNTOd7v07x87gkgnGZNmzC4CwAW7zPGIcF2nL0Pu+3v1bVrb6viUjYJ8+JSCqwELhfVd8K9/1NdMjNSqNXpxQ+XLefG0f3cjocY9qsYDupX/Zz7KVAF4nITBE5ICKr6x2fJCIbRCRfRO7xeemnwItBxmRilIhwwaBsluQfpKSi2ulwjGmzAvVBDBKRK4AMEbnc5/EtICmI+88CJtW7pwuYDlwMDAGuE5EhIjIRWAtYu4JhwpAsKmtqWbyp0OlQjGmzAo1iGoinr6E9nn6HOseAmwPdXFUXiUjveofPBPJVdQuAiLwAXAqkAal4kkaZiLyjqrVBlMHEoDN6dyQ9KZ656/Yz6ZQuTodjTJsUqA/ideB1ETlLVZeG6T27Azt9nu8CRqnq7QDe2klhQ8lBRG4BbgHo2bNnmEIyrU2CK45xA7OYv/4ANbWKK85mVRvT0oLtg7hVRNrXPRGRDiIyMxIBqeqsxjqoVXWGquapal5mZmYkQjCtxAWDszhYUskXOw87HYoxbVKwCWK4qh6pe6Kqh4HTQnzP3UAPn+c53mNBs6U22oaxA7OIjxM+WGvdUsY4IdgEESciHeqeeHeTC3VfyE+B/iLSR0TcwLXAGyHey8SwjOQEzujdkQ9t2Q1jHBFsgvgzsFREfiMiv8Gzs9wfA10kIrOBpcBAEdklItNUtRq4HZgDrANeVNU1TQna1mJqOy4YnMWmA8XsOFjqdChNdqS0ko9sFJaJYkElCFV9Brgc2O99XK6qzwZx3XWq2lVVE1Q1R1Wf8h5/R1UHqGo/Vf1dU4O2Jqa2Y+KQbCA6F+/79qxPueGpTyirdGzhY2OaJdgaBEBHoERVHwUKIjGTOlhWg2g7enVKJTcrLSoTxKb9xQBU1dpobROdgt1y9D48s5x/5j2UADwXqaCCiMdqEG3IBYOzWL71EEfLq5wOxZg2JdgaxNeBqUAJgKruAdIjFVQgVoNoWyYOzqa6Vlm4ocDpUJqkbuaGqqNhGBOyYBNEpaoqoHB8UT1jWsRpPTvQMdUdfc1M3gxRW2sZwkSnYBPEiyLyd6C9iNwMzAX+EbmwGmdNTG2LK04YOzCTBRsKqK6Jvvb8rQdLOP/B+Rw4Vu50KMY0SbCjmP6EZ/XWl/Gsz/RLVf1bJAMLEI81MbUxEwdnU1RWxYrt0Ter+qmPtrL9YClvf7nX6VCMaZJgO6lTgXmq+hM8NYdkEUmIaGTG+Dh3QCZuV1x0TprztjCFoy+itlZ568s91mxlWkSwTUyLgEQR6Q68B9yIZylvR1gTU9uTlhjP6H6donKXOfVmiHB8pL/w6U5u/9fnPL98RxjuZkzjgk0QoqqleCbLPa6qVwFDIxdW46yJqW2aMDiLrYUlbC4odjqU4NTLCBqGKkRdP0bBsYpm38uYQIJOECJyFnA98Lb3mCsyIRnj3/hBnr2qo7KZyZgoFGyC+CGeSXKvquoaEekLzI9cWMacLKdDCoO7tmNulK3uWldxqA1Qg3jo/Q2s3m3Npqb1CHYU0yJVnaqqf/A+36KqP4hsaA2zPoi2a8LgLFZsP8ThkkqnQwmaBtlJ/ci8fC7520eRD8iYIDVlLaZWw/og2q4LBmdTq7BgY/TUIgLVHODE/one97zN859sj2RIxgQlKhOEabuGd88gMz0xKpqZtN7XpvjHoi0Bbm7DXE3kWYIwUSUuTrhgUBYLNxZQWR0ds6qPNzEFcY4xrUmwE+X+KCLtRCRBRD4UkQIRuSHSwRnjzwWDsymuqGb51kNOhxKkIJqYmnyFMZEXbA3iQlU9ClwCbANygZ9EKqhArJO6bTsntzOJ8XFRs3hfbRhnUhvTkoJNEHX7T08G/qOqjn4yWyd125bsdnFObmfmrtsflslnkVIXWzAx1j9HGjjPmJYUbIJ4S0TWAyOBD0UkE7ClKY1jLhicza7DZWzcH95Z1b96cw1jfv9hWO/5VWd18MnM35kHjpXz8NxNANSosvtI2cnXqbbqpGmiS7DzIO4BxgB5qlqFZ+OgSyMZmDGNuWCwZ1Z1uJuZnv54G3uKwvu3TzCf18F8pL/jsxrs9PmbOfuBeezzxrp6dxHXzlhKn5+9w23PfRZipMacKNhO6quAKlWtEZGf49lutFtEIzOmEdntkhiekxEV/RDBzYMIfJ/731x70rHCYs+aTPe+uoplWzyd9u+t2de0AI1pQLBNTL9Q1WMicg4wAXgKeDxyYRkT2AWDsvli55GILFxXE8bltIOZST1vffMSnTUqmUgINkHUeL9OBmao6tuAO5yBiMhgEXlCRF4SkdvCeW8TmyYMyUIV5q8P/6S56trmz7EItu+hsLiCW+s1C9VPJsfKqxp/L8sQJgKCTRC7vVuOXgO8IyKJwVwrIjNF5ICIrK53fJKIbBCRfBG5B0BV16nqrcDVwNlNK4Zpi4Z0bUe3jKSINDNV14S/BtGQYCb8Pb5gc+PvYXUIEwHBJoirgTnARap6BOhIcPMgZgGTfA+IiAuYDlwMDAGuE5Eh3tem4llO/J0g4zJtmIgwfnAWizcVUl5VE/iCJmjJBOGP1BvnWhPgJlaDMJEQ7CimUmAzcJGI3A5kqer7QVy3CKg/3fVMIN+7Imwl8ALeEVGq+oaqXoxn3wljApowOJuyqhqWbj4Y1vtWhaGJqU5tE+ZD1GnqB77tQGoiIdhRTD8EngeyvI/nROSOEN+zO7DT5/kuoLuIjBWRR7xNWQ3WIETkFhFZISIrCgoKQgzBxIrRfTuR4naFvZkpHJ3U9T/kI/lXvs19MJEQH/gUAKYBo1S1BEBE/gAsBf4WrkBUdQGwIIjzZojIXmCK2+0eGa73N9EpKcHFuf078+G6A/z2MkXqt82EqKomfDWIQB/dYQrZmLALestRvhrJhPf7UP9b7wZ6+DzP8R4Lmi21YXxNGJzNvqPlrNlzNGz3DG8fRNP7D/YWlbF+X3DlOVJayfp9x0IJzZhGBZsgngY+EZH7ReR+YBmeuRCh+BToLyJ9RMQNXAu80ZQb2GJ9xtf4QVnECbwfxgli4RjmWieU1qqqGmXSw4s5WFzBoo2NN6V+tuNwiJEZ07hgO6kfAr6Np8P5EPBtVX040HUiMhtPU9RAEdklItNUtRq4Hc+oqHXAi6q6JtQCGNMpLZG83h2ZsyZ8/RDVYez1Pd5JHcK1Nzy1nG/OXE5NGGs0xgQrYB+Ed1jqGlUdBDRpkRdVva6B4+/QjKGsqvom8GZeXt7Nod7DxJaLhnbhN2+tZVthCb07pzb7fuFoYqo/NyGUfuTNBZ7FCAMNczUmEgLWIFS1BtggIj1bIB5jQnLhkGwA5oSpmSmsndTez/ZaVXrf8zbT5+ef8HpjndRx3tcONLCcSEV1DfuPhn+pEWMg+D6IDsAa725yb9Q9IhlYY6wPwtTXo2MKQ7u1C2OCCH8ndV2/xsNzNwZ9bZw3e7zts5Krr9ue+4yfvbKqmREa41+ww1x/EdEomsiamIw/Fw3twkMfbOTA0XKy2iU1617VYaxBNKc7Iy7AGNiGahbGhEOjNQgRyRWRs1V1oe8DzzDXXS0Tot+4rAZhTnLR0C4AvL+2+Z3VVWGcKNecvgibI2GcFKiJ6WHA32DsIu9rjrB5EMafAdlp9O6UEnKC8J09Hc4axFd9EE2/NlANwphICpQgslX1pAZO77HeEYnImBCJCBcN7cLSzYUcDbA8tj++HdPh7KSuSwxf1SiCFxdifpj50daAS4QbE0igBNG+kdeSwxlIU1gTk2nIhUO7UFWjIe0RcWKCCH8ndV1TU1PWTQq1BvHrt9Yy7P6A62ka06hACWKFiJzUESwi3wVWRiakwKyJyTTktB7tyUpPDGk0k29SCO9M6sarDo3li3CtLWVMKAKNYvoR8KqIXM9XCSEPz25yX49kYMaEIi5OmDgkm1c/3015VQ1JCa6gr60Ocw2i7g619fJD/Ts39k6hNjEZEw6N1iBUdb+qjgF+BWzzPn6lqmepqu2Mblqli4Z2obSyho82FTbpusoI9UFovf0gmjKKqbmd1KWV1c263rRtQc2DUNX5wPwIxxI0EZkCTMnNzXU6FNMKje7bifSkeOas2ccE7wzrYJzQxBSBHeUaSgyN9Uk0twZRXF5NijvY6U7GnCjYmdStivVBmMa44+MYPyiLuev2N2m4anXERjE1vlhfJPsgbAUn0xxRmSCMCeSioV04XFrFp9uCXwrbt4kpLKu51pv/YOvtmWhjCcLEpPMHZJIYH8d7q/2vYeRPRbVPDaI6nDvKnTjMtSlsEJNxkiUIE5NSE+MZNzCLd1fvC3p/6YoqnwQRzv0gvLdtuA+i4WstQRgnWYIwMWvy8K4cOFbBim2Hgjq/ovqrXXXDu9RGgC1HI9hTYM1apjmiMkHYTGoTjPGDskhKiOPtVcE1M/k2MYV3R7m6r/7v2WgNIuSt341pvqhMEDaKyQQjNTGe8YOyeGdVcM1MvgmiMgx9EHU1g7rd4J5Zur3Z9ww1BmNCEZUJwphgTR7WjcLiCpZvDdzMVFHl08QUzqU2AiSnxl61PgjjJEsQJqaNG5RJcoKLt1ftCXhuXQ1CJLwT5QI1VzVl8T5jWpIlCBPTUtzxjB+cxXur9wXseK5LEGmJ8WFdzTVQDWLj/mMNvmYVCOOkVpUgROQyEfmHiPxbRC50Oh4TGy4Z1pXC4sqAzUzl3iam9MT4EybNhaquYlDTSA1hX1E5tz73WbPfK1AMxoQi4glCRGaKyAERWV3v+CQR2SAi+SJyD4CqvqaqNwO3AtdEOjbTNowdmEWK28VbAUYz1dUg2iUnUFZZ0+i5TdFYB/mRsspGr7Xlvo2TWqIGMQuY5HtARFzAdOBiYAhwnYgM8Tnl597XjWm2ZLeLCwZnB2xmKqusJikhjhS363htIhyCnajnj6UH46SIJwhVXQTUr9ufCeSr6hZVrQReAC4Vjz8A76pq5Ordps25ZHhXDpVU8lF+w0uAF1dUk56UQIo7nrJwJojmtPNYhjAOcqoPojuw0+f5Lu+xO4AJwJUicqu/C0XkFhFZISIrCgoKIh+piQljB2bSPiWBVz7b3eA5x8qrSU+MJynBRWkYm5ic7AewLgjTHK1qoXhVfQR4JMA5M0RkLzDF7XaPbJnITLRLjHcxZXg3Xlyxk2PlVaQnJZx0TnFFNWlJ8SSHqYkpmA/nQDOlrQJhnORUDWI30MPneY73WFBsJrUJxeWnd6eiupZ3V/nfDLG4vJq0xHhSElxh7aQ2Jlo5lSA+BfqLSB8RcQPXAm8Ee7GtxWRCMaJHe/p2TuXlz3b5fb24wpMgkt2usPRBhGMCnI1iMk5qiWGus4GlwEAR2SUi01S1GrgdmAOsA15U1TXB3tNqECYUIsLlp3fnk62H2Hmo9KTXj5Z5mp6SwlSDCCY9RHqtJJulbZqjJUYxXaeqXVXxumiwAAAUpElEQVQ1QVVzVPUp7/F3VHWAqvZT1d815Z5WgzChuuy07gC8+vmJLZqqSmFJJZ3T3aS4XVTW1IZ1ye9QWf3BOKlVzaQOltUgTKhyOqRwTm5nXli+44QEcLS8msrqWjLTEklOcAFQ3owVXVW1Vcxifv2LPQGX+jCmIVGZIKwGYZrjxrN6saeonLnrDhw/VnCsAoDM9ESS3Z4EUVpRHfJ7NGdynK/mdkE8OGcDU6d/xMeNzP8wpiFRmSCsBmGa44JBWXTLSOLZZduOH9tXVA5AVnoS7ZI9Q2CPlleF/B7BbjgUeJhr8zLEhMHZHC6p4vonP+GGJz/hi51HmnU/07ZEZYKwGoRpjnhXHNeP7sXH+QdZt/coAJsLigHol5lKe2+COFIaeoJoLTWISad04cO7zufnkwezdu9RLpv+Mbc8s4IN+xpeQdaYOlGZIKwGYZrrhlG9SE+K56EPNgKQf6CY9MR4MtMTaZ/S/AQRzi1LmyspwcV3z+3LorvH8eMJA1iy+SCT/rqIO//9BTsOnjyay5g6UZkgjGmujJQEbjm3Lx+s3c+S/EKWbz3EsJwMRIT2yW4AjpQ5X4NoLt8KSFpiPD+c0J/Fd4/jlnP78vaqvYz/8wJ+/toq9h8tdyxG03pFZYKwJiYTDtPO7UPfzFRunLmcDfuPcfEpXQBP8gAoakaCCOeWpc3hL011SHXzs68NZtHd47j2zB68sHwn5/1xPve/seZ4X4wxEKUJwpqYTDikuOP5xzfzGNmrA5OHdeXqMzyrv6QnxiMCRaWN79XQmPD1QURuJkR2uyR+e9kw5t01limnduPZZds574/zuffVVew6bE1PppUt1mdMS+uXmcaL/3PWCcfi4oSM5AQON6cPIoxbljZHMOmlZ6cU/nTVqfzwgv48tmAzL67Yyb8/3cnlp3fne2Nz6d05NeJxmtYpKmsQxkRaVnpis9rlq4KchR2ogtCSM6l7dEzh95cPY9Hd47hhdC9e/2IP4/+8gB//+4tG9802sSsqE4T1QZhI65qRzN5mtMdXBDkLO1ACcGKtvq4Zydw/dSiLfzqOaef04b3V+7jwL4u4aeZyFm8qsPWd2pCoTBDWB2EirVv7JPYWlYV8fd1+Eu2SGm/Fbc2LtWalJ3Hv5CF8fM94/vfCAazde5Qbn1rOpIcX8+KnO8O6LatpnaIyQRgTaV0zkiksrgz5Q7C8ylODyGqX1Oh5gf4Ybw1/rHdMdXP7+P589NNx/OmqUxGBu1/+knP+MI+H5248vkyJiT2WIIzxo2uG54M91Gam8mpPYslMS2z0vECf/83ND+GsoSTGu7hyZA7v/vBc/vXdUQzPac/Dczdx9gPz+PG/v+CzHYet+SnG2CgmY/zol5UGeGZY9wlhFE+FtwaR3S5AgojCz1MRYUxuZ8bkdmZzQTHPLt3OSyt38ernuxmQncbVeT24/PQcOqa6nQ7VNJPVIIzxY0B2OgAb9h0N6foKbw2ifUrjH5KBNgxq7X+R98tM4/6pQ1n2/y7ggcuHkeKO57dvr2PU/83l+89/xqKNBbbceBSLyhqEiEwBpuTm5jodiolRaYnx5HRIZsP+4pCur+u7yPXWREb16cgnWw81+T6tPD8cl5YYz7Vn9uTaM3uyYd8x/v3pTl75fBdvr9pLt4wkLjm1G5OHdWW4dzkTEx2iMkGo6pvAm3l5eTc7HYuJXYO7tmPVrtCWx64b5nrR0C50THUzflAWg37x3knnBUoAtdGSIXwM7JLOL6cM4acXD+SDtft5eeUunv54KzMWbSGnQzKTh3dl8rCuDOtuyaK1i8oEYUxLGNWnIx+s3c/eojK6ZiQ36dq6Pa1T3C6+Nqwr4FnC41i9TYgCjmJq0ruezMnWncR4F5cM78Ylw7tRVFrF+2v38faqvTy1eCt/X7iFHh2TmTzMU7M4pXs7SxatkCUIYxpwVr9OACzJP8gVI3OadO3R8ipccUKKd3c6gBpvNvD9HAzUB9HcGkRr2FcbPAsgXpXXg6vyenCktJL31+zn7VV7eXLxFp5YuJlenVK4YFA25w/MZFSfjiQluALf1EScJQhjGjC4Szs6pyXywdr9TU4Qx8qrSU+KP+GvYnd8HKWVNSfUGiI9D6KqFXYQt09xc/UZPbj6jB4cLqnk/bX7eGfVPp77ZDszP95KUkIcZ/XtxNiBWZw/INPWgnJQq0kQItIXuBfIUNUrnY7HmLg4YcqpXXl+2Q6KyqrI8O40F4yjZVW0Szrx/DN6e5qsXHHBN6U0dxTTpKFdmnV9pHVIdXPNGT255oyelFXWsGzLQRZuLGDBhgPM37AGgF6dUhjTrzNj+nVidN9OZKY3PnTYhE9EE4SIzAQuAQ6o6ik+xycBfwVcwJOq+oCqbgGmichLkYzJmKa4/LQcnv54Gy+t3MW0c/oEfd3R8mraJZ/46/V/Xx/G5zuOnLCQX+BO6iaFe5LOadEzFyHZ7WLcoCzGDcoChrKtsISFGwtYtLGAt/67h9nLdwAwIDuNMf06c9HQLsebAU1kRHoexCxgku8BEXEB04GLgSHAdSIyJMJxGBOSYTkZnNmnI08u3kJlkAvwgf8aRGZ6Ilfl5VBa+VVHdaA+iOb2IURzx2/vzqncNKY3T33rDD7/5URe+/7Z3D1pINntknjh0x3cNHO50yHGvIgmCFVdBNQf/H0mkK+qW1S1EngBuDSScRjTHLePy2VvUTmzlmwN+ppDJZV08DNJLi0xnqoaPT5PItDGQqW2IB4A8a44RvRoz/fG5vLstFHccl4/KltJB3wsc2ImdXdgp8/zXUB3EekkIk8Ap4nIzxq6WERuEZEVIrKioKAg0rEaw3kDMpkwOJu/fLCJHQcD77SmquwtKj++npOvLt7F+/Yc8awUG2iUUmll4wnivAGZAeOJZbsOl7b62ebRrNUstaGqB1X1VlXtp6q/b+S8Gaqap6p5mZlt+5fDtJxfXTqUeJdw2/MrA67werSsmrKqGrr4SRA9OqYAsP2QJ9EE+iPYX7PWtd6tUQGe+c6ZgUKPSemJnv6dc/4wn1N/9T5XPbGEe17+kn8s2sK89fvZc6TMEkcYODGKaTfQw+d5jvdY0GypDdPSurdP5q/XjuA7s1Zwx+zPeez600lw+f/7aqd3P+du7U+eXDeoazpxAp9vP8y4gVknNDF986xePLN0e1CxACS4PP0LaYnxFNebgAdww+iegQsWpb59dm+G5WSwuaCYNXuOkr+/mA/W7ueFkq8aJzqluhnaPYMRORmM6NmefplpdGuf3OC/mzmZEwniU6C/iPTBkxiuBb7hQBzGNMn4Qdn8aupQ7ntjDbc9t5KHrz2NtMSTf4XW7fUs8DewS/pJr7VLSmB4Tns+WHeAH08ccEIT048mDDieIM7J7cxH+YV+40jxvuf1o3oBcHZuJ+as2Q/AH68YzvjBWTy/bAe3je3XjNK2bvGuOEb39Qx79XWktJL8A56ksXp3Eat2F/Ho/ILjo8HixJO4e3ZMoWfHFHp0TCGnQzLpSfEkJbhITnCR4o4nOcFFQrzgEiEuzufr8e/B7YqL6kEAwYj0MNfZwFigs4jsAu5T1adE5HZgDp5hrjNVdU1T7mtrMRmn3DSmN3EC97+5lsumf8zD14zglO4n7my4cvth0hLj6d3J/wSvK0fm8PPXVrNsy6ETEoTvrOsnbhzJKffN8Xt9WqLnvBJvreHha05jc0HxCXH8cEL/0AoY5dqnuMnr3ZG83h2PHyupqGbt3qNsKyxh56FSth8qZcehUuau209hcWXI7+V2xdEpzU2nNDfdMpLpn53GwC7tGNWnI9kBNoqKFhFNEKp6XQPH3wHeCfW+1sRknHTjWb3pl5nGD174gqmPfsQNo3vxP+f3o3v7ZI6VV/Hemn2MG5TV4IS4K07P4bH5+fzqzTXcOXHA8eNuVxx/uupUCosrSEuMJys9kQP1dmvrl5l6fPhsUVkV4Jk/UD9Jma+kJsZzRu+OnOGTNOqUVFSz50gZJZU1lFXWUF5VQ1lVDaWVNVTV1FJTq9SqUlOrPt97BhccK6/mYHEFhcUVbCksYd76A1R7qyp9M1MZ068TY/p1ZnTfTlG7N4ZEc0dOXl6erlixwukwTBtVVFbFg3PWM3u5p937lO4ZHC2rYvvBEl753tmM6NG+wWs/WLufm59ZQee0RAqLPUlg2wOTTzjn+//6jLe/3Hv8eWJ8HMvvncCeI2Vc/NfF/GB8LndeODACJTOhqKyuZeP+YyzdfJAlmwtZvvUQJZU1iMDoPp24fnRPLhrapVX0gYjISlXNC3heNCYInxrEzZs2bXI6HNPG7T5SxgvLd7B86yFE4Lvn9GXCkOyA1/36zbXM/Ngzt+L3lw/jujNP7FR+dtl2fvHa6uPPe3RMZvHd4wFYvbuIQV3SiW8FHzbGv6qaWlbtLmLhhgJe/mwXuw6X0b19Mt8fl8uVI3Nwxzv3bxfTCaKO1SBMNKuqqeXul77kaFkVT96Ud1KHZ2FxBXm/nYs7Po7K6loS4+PY8NuLHYrWNEdNrTJv/QEenZ/Pf3ceoXv7ZG48qxfjB2XRLzOtwebIyupa9hwpY4e33+RYeTVdMhLp2TGVU3MyQv4DwRKEMTHg4/xCstITmfiXRVxxeg5/vvpUp0MyzaCqLNxYwGMLNrPcu8NgitvFkK7t6JTmJjHeRWllNYdKKtl/tIK9RWUNrsd1/5QhfOvs4NcH8xXTCcKamExbs2RzIUO6tgu4x7WJHtsKS/hsx2G+3FXE2j1HKSqroqK6hhR3PB1T3WSmJ9LDOxy37pGeFM++o+Ws33uMvN4dQh4tFdMJoo7VIIwxpumCTRDWw2WMMcavqEwQIjJFRGYUFRU5HYoxxsSsqEwQqvqmqt6SkWGTg4wxJlKiMkEYY4yJPEsQxhhj/IrKBGF9EMYYE3lRmSCsD8IYYyIvKhOEMcaYyIvqiXIiUgAE3oLLOZ0B/7u+RI9YKAPERjlioQwQG+WI9jL0UtWAezZHdYJo7URkRTCzFVuzWCgDxEY5YqEMEBvliIUyBMOamIwxxvhlCcIYY4xfliAia4bTAYRBLJQBYqMcsVAGiI1yxEIZArI+CGOMMX5ZDcIYY4xfliCMMcb4ZQnCGGOMX5YgHCQiqSKyQkQucTqWUIjIZSLyDxH5t4hc6HQ8TeH92f/TG//1TscTimj++dcXA78LcSLyOxH5m4jc5HQ84WIJIgQiMlNEDojI6nrHJ4nIBhHJF5F7grjVT4EXIxNl48JRBlV9TVVvBm4FrolkvMFoYpkuB17yxj+1xYNtQFPK0Np+/r5C+P/l2O9CQ5pYhkuBHKAK2NXSsUaKJYjQzAIm+R4QERcwHbgYGAJcJyJDRGSYiLxV75ElIhOBtcCBlg7eaxbNLIPPpT/3Xue0WQRZJjy/zDu9p9W0YIyBzCL4MtRpLT9/X7MI/v+X078LDZlF8P8WA4ElqnoncFsLxxkx8U4HEI1UdZGI9K53+EwgX1W3AIjIC8Clqvp74KRqs4iMBVLx/CcrE5F3VLU2knH7ClMZBHgAeFdVP4tsxIE1pUx4/srLAb6gFf2h1JQyiMg6WtHP31cT/y3ScPB3oSFNLMNOoNJ7Tmv6g6NZLEGET3e++osUPB9Aoxo6WVXvBRCRbwGFreEXgiaWAbgDmABkiEiuqj4RyeBC1FCZHgEeFZHJwJtOBNYEDZUhGn7+vvyWQ1Vvh1b3u9CQhv4t/gr8TUTOBRY5EVgkWIJwmKrOcjqGUKnqI3g+aKOOqpYA33Y6juaI5p+/P1H+u1AKTHM6jnBrNVXrGLAb6OHzPMd7LJrEQhnqi4UyxUIZIDbKEQtlCJoliPD5FOgvIn1ExA1cC7zhcExNFQtlqC8WyhQLZYDYKEcslCFoliBCICKzgaXAQBHZJSLTVLUauB2YA6wDXlTVNU7G2ZhYKEN9sVCmWCgDxEY5YqEMzWWL9RljjPHLahDGGGP8sgRhjDHGL0sQxhhj/LIEYYwxxi9LEMYYY/yyBGGMMcYvSxCmTRCRGhH5wucRzHLsLUJEXhKRvo28fp+I/L7esRHexfoQkbki0iHScZq2xxKEaSvKVHWEz+OB5t5QRJq9lpmIDAVcdauDNmA2J+/3cK33OMCzwPeaG4sx9VmCMG2aiGwTkV+JyGciskpEBnmPp3o3jFkuIp+LyKXe498SkTdEZB7woXh2EntMRNaLyAci8o6IXCki40XkNZ/3mSgir/oJ4XrgdZ/zLhSRpd54/iMiaaq6ETgsIr4r617NVwniDeC68P5kjLEEYdqO5HpNTL5/kReq6unA48D/eo/dC8xT1TOBccCDIpLqfe104EpVPR/PznS98exlcCNwlvec+cAgEcn0Pv82MNNPXGcDKwFEpDOezX8meONZAdzpPW82nloDIjIaOKSqmwBU9TCQKCKdQvi5GNMgW+7btBVlqjqigdde8X5diecDH+BCYKqI1CWMJKCn9/sPVPWQ9/tzgP949zDYJyLzAVRVReRZ4AYReRpP4vimn/fuChR4vx+NJ9F87NmLCTeetYAA/g0sEZG7OLF5qc4BoBtwsIEyGtNkliCMgQrv1xq++p0Q4ApV3eB7oreZpyTI+z6NZzOicjxJpNrPOWV4kk/de36gqic1F6nqThHZCpwPXMFXNZU6Sd57GRM21sRkjH9zgDu826oiIqc1cN7HwBXevohsYGzdC6q6B9iDp9no6QauXwfker9fBpwtIrne90wVkQE+584G/gJsUdVddQe9MXYBtjWlgMYEYgnCtBX1+yACjWL6DZAAfCkia7zP/XkZz7aTa4HngM+AIp/Xnwd2quq6Bq5/G29SUdUC4FvAbBH5Ek/z0iCfc/8DDOXk5qWRwLIGaijGhMyW+zammbwjjYq9ncTLgbNVdZ/3tUeBz1X1qQauTcbToX22qoa02b2I/BV4Q1U/DK0ExvhnfRDGNN9bItIeT6fyb3ySw0o8/RV3NXShqpaJyH1Ad2BHiO+/2pKDiQSrQRhjjPHL+iCMMcb4ZQnCGGOMX5YgjDHG+GUJwhhjjF+WIIwxxvhlCcIYY4xf/x9XQMerjNRhWgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "energies = gd157.energy['294K']\n", - "total_xs = total.xs['294K'](energies)\n", - "plt.loglog(energies, total_xs)\n", - "plt.xlabel('Energy (eV)')\n", - "plt.ylabel('Cross section (b)')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Reaction Data\n", - "\n", - "Most of the interesting data for an `IncidentNeutron` instance is contained within the `reactions` attribute, which is a dictionary mapping MT values to `Reaction` objects." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ]\n" - ] - } - ], - "source": [ - "pprint(list(gd157.reactions.values())[:10])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's suppose we want to look more closely at the (n,2n) reaction. This reaction has an energy threshold" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Threshold = 6400881.0 eV\n" - ] - } - ], - "source": [ - "n2n = gd157[16]\n", - "print('Threshold = {} eV'.format(n2n.xs['294K'].x[0]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The (n,2n) cross section, like all basic cross sections, is represented by the `Tabulated1D` class. The energy and cross section values in the table can be directly accessed with the `x` and `y` attributes. Using the `x` and `y` has the nice benefit of automatically acounting for reaction thresholds." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'294K': }" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "n2n.xs" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(6400881.0, 20000000.0)" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "xs = n2n.xs['294K']\n", - "plt.plot(xs.x, xs.y)\n", - "plt.xlabel('Energy (eV)')\n", - "plt.ylabel('Cross section (b)')\n", - "plt.xlim((xs.x[0], xs.x[-1]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To get information on the energy and angle distribution of the neutrons emitted in the reaction, we need to look at the `products` attribute." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[,\n", - " ]" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "n2n.products" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "neutron = n2n.products[0]\n", - "neutron.distribution" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that the neutrons emitted have a correlated angle-energy distribution. Let's look at the `energy_out` attribute to see what the outgoing energy distributions are." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ,\n", - " ]" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dist = neutron.distribution[0]\n", - "dist.energy_out" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here we see we have a tabulated outgoing energy distribution for each incoming energy. Note that the same probability distribution classes that we could use to create a source definition are also used within the `openmc.data` package. Let's plot every fifth distribution to get an idea of what they look like." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "for e_in, e_out_dist in zip(dist.energy[::5], dist.energy_out[::5]):\n", - " plt.semilogy(e_out_dist.x, e_out_dist.p, label='E={:.2f} MeV'.format(e_in/1e6))\n", - "plt.ylim(top=1e-6)\n", - "plt.legend()\n", - "plt.xlabel('Outgoing energy (eV)')\n", - "plt.ylabel('Probability/eV')\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Unresolved resonance probability tables\n", - "\n", - "We can also look at unresolved resonance probability tables which are stored in a `ProbabilityTables` object. In the following example, we'll create a plot showing what the total cross section probability tables look like as a function of incoming energy." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Cross section(b)')" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZQAAAEQCAYAAACX5IJuAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzsnXeYVNX9/99netnZ2Q7sshRZWDoqKwiKGCxgwQqWoCaCEgtGk2iM35hfYotRjCRqLESNGitqxIYoVlRUmiIISBPYZZftdXZ26vn9MTuzt5y7c6cXzut59mHnzJ17zwyz530/9RBKKTgcDofDiRVNqifA4XA4nOyACwqHw+Fw4gIXFA6Hw+HEBS4oHA6Hw4kLXFA4HA6HExe4oHA4HA4nLnBB4XA4HE5c4ILC4XA4nLiQEYJCCLESQjYSQs5O9Vw4HA6HwyYlgkIIeZoQ0kAI2SYZn0MI+ZEQsocQ8gfBU7cCWJHcWXI4HA4nEkgqWq8QQk4C0AXgOUrp+N4xLYBdAE4DUANgA4BLAZQBKARgAtBEKX0n6RPmcDgcTlh0qbgopXQtIWSYZHgKgD2U0n0AQAh5GcC5AHIAWAGMBeAkhKyilPqTOF0Oh8PhqCAlgqJAGYBqweMaAFMppUsAgBDySwQsFKaYEEIWA1gMAFardfLo0aMTO1sOh8PJIjZt2tREKS2O5RzpJCj9Qil9JszzywEsB4Cqqiq6cePGZEyLw+FwsgJCyIFYz5FOWV6HAJQLHg/uHVMNIWQuIWR5e3t7XCfG4XA4nPCkk6BsADCSEDKcEGIAcAmAtyI5AaX0bUrpYrvdnpAJcjgcDkeZVKUNvwTgKwCVhJAaQsgiSqkXwBIA7wPYAWAFpfSHCM/LLRQOh8NJESlJG040PIYSOz09PTAajSCEpHoqHA4nCRBCNlFKq2I5Rzq5vGKGWyjxobOzE2azGXfccUeqp8LhcDKIrBIUHkOJD0FB/ve//53imXA4nEwiqwSFEx/0ej0AwO12p3gmHA4nk8gqQeEur/gQjKt5PJ4Uz4TD4WQSWSUo3OUVH/z+QDMCHpDncDiRkFWCwokPPp8v1VPgcDgZCBcUjoyghcLhcDiRkFWCwmMo8aE/C2XNmjU8WM/hcJhklaDwGEp8ULJQtm7ditNPPx2/+c1vkjwjDoeTCWSVoHDig5KF0tzcDADYtm0b83kOh3NkwwWFI0PJQtFqtQB40J7D4bDJKkHhMZT4oCQY2SYo8+fP56nRHE4cySpB4TGU+KBUh6LRaETPZzqvvfZaqqfA4WQVWSUonPgQzgLhd/UcDocFFxSODCULJBu3OuBwOPGDCwpHBrdQOBxONGSVoPCgfHxIZYyEUoqJEyfihRdeSNkcOBxOdGSVoPCgfHxIZRYXpRRbt27FZZddlrI5cDic6MgqQeHEByULJRmWi1Kc5rPPPsP69esTfn0OhxM9ulRPgJN+KFkoyWhrryRaJ598MgCeGMDhpDPcQuHISEcLhcPhpD9cUDgywlkoiYQLCoeTuXBB4chQEo6g0KTC5cXhcNIfLigcGeFcXokUFG6hcDiZS1YJCq9DiQ+pdHlxC4XDyVyySlB4HUp8COfySiTcQuFwMpesEpRU4nA4smZrXG6hcDicaOCCEieqqqowf/78VE8jLmRzDGXr1q0ghGDDhg3M571eL1wuV0LnwOFkK1xQ4oDL5cLOnTvx1ltvpXoqcSGb04bfeecdAMDrr7/OfP6kk06CyWRSda7PPvsM69atCz2eP38+FixYEPskOZwMhVfKx4GGhoZUTyGupDKGkkjRam5uxsGDBwGwhcvj8eCrr75SfT5p9X5ww65wjS1v+OWr6GjrCT3OzTPh4Weyw7rlHNlwQYkDDocj1VOIK6lsvZJIC2XYsGHo6uoCwBauU045JSHXvX7R62hv7xMQrVd8baG4cDiZDBeUONDd3R363e/3h7bKzVRS0XqluroaOTk5Cb1GUEwAtnB9/vnnCbmuUEw4nGwms1e+NEEoKD09mb94pCKGMmTIEFRUVCTMQqmpqUnIeVXB9yPjHCGkvaAQQsYQQh4nhLxGCLk21fNhIXR5OZ3OFM4kPqSq9UpLS0tCBKWhoQHl5eWisWTWu3h1Gnj1fT+yK2u44nCyg5S4vAghTwM4G0ADpXS8YHwOgH8C0AJ4klL6N0rpDgDXEEI0AJ4D8Fgq5twfQgslGwQlHdvXx0JLS4tsTCgolNKkbmvcY9WLHutdPlw2TxzIt9tN+NdTFyZtThxOPEiVhfIMgDnCAUKIFsC/AJwBYCyASwkhY3ufOwfAuwBWJXea6sg2Qcm29vXhxCLR78uv7//PjDU7HnfhZCIpsVAopWsJIcMkw1MA7KGU7gMAQsjLAM4FsJ1S+haAtwgh7wJ4MZlzVYPQ5SUUl0wl2yrlWYIitVASyf7RhaLHw35oEs8FDFHhXjBOBpJOWV5lAKoFj2sATCWEnAzgAgBG9GOhEEIWA1gMBAK8ySRbLRTpQhwUmkQuwKmwUJLdP8ynJdD6+q7pMWqTen0OJ1Gkk6AwoZR+CuBTFcctB7AcAKqqqpK6QmSboGRbDIWVxp1MC0VKzcgC0eOhO5tlxxicXlx+wfOycXueCY88PS9hc+NwYiGdsrwOARCm4gzuHVNNqtrXHylZXjyGkjyUZtzOiyA5aUw6CcoGACMJIcMJIQYAlwCIqDlWqtrXCy2UbI6hcJdXgPb29rh2R/Dq5PPzK02Zpxhz0phUpQ2/BOBkAEWEkBoAf6aUPkUIWQLgfQTShp+mlP4Q4XnnAphbUVER7yn3S7a5vFJpoai9xurVq1FZWYnhw4fHfM1IBSUvLw8FBQXhD1TJwXHFsrFyhhuMw0l3UpXldanC+CrEkBpMKX0bwNtVVVVXR3uOaHA4HDAajXC5XFkhKJnQbfiMM86ATqeDx+MRjTc2NqKwsFAUN0lElhertiUZmBwe/PxicaKj3W7CY8svSMl8OBwhaR+UzwS6u7tRWFiI2trarBCUTLBQgMDeJUIOHz6MQYMG4U9/+hPuvPPOfl/70EMPRXXNaDAb/XC6Eudd7mzq5gF8TlqQTjGUmElVUN7pdKKwsDD0e6ajFCtJ9y2A6+vrAQBvvvlm0q6phgtnN+Kyc+pDP2rwadmxEp9OE2jlIvjhAXxOupBVFkqqXF5OpxN5eXmh3zOdTLFQpATdXJGeI9lpw2ajD05X/7UntSPymeNHbW2UjTELI6E0yOEkjqwSlFThdDqRn58Pk8mUVYIiXWiVxgHg4osvxoIFC3DOOefEdO1YFnclQQl3zmSnDf98rjjgvvztQTGdz8sLIzlpQlYJSiqzvEpLS2E2m7NCUIKuLamLS2nhpZRixYoVWLFiRcx3+7G8Phh8F86zvb0d4b4P4a759ddf4/XXX8fSpUujnlt/GPQ+uD3qRMGrI9B51X1GWo9f1HSSN5zkJJqsEpRUurzMZnPWCEpwQZYKiFIMJZ4uo3hYC36/H2eccQZuueUWOByOsOcMN/9p06YBQMIE5eQT5G6sDz4ewDy2ZkKRbOyoTewtqKUeL95wkpNosioonyqyTVDCWShKrrB4EA8LpbW1FatXr8a8efNUtYlRuuaOHTtEn0GyYy1qYRVGApDvu8JjKpwEk1UWSqpcXtkqKFKhULJc0kVQggRjKWr3OWHNf/v27Rg3bhz+9Kc/ieaWzH1T1HJwkrwwEgCGfSu3fDicRJJVgpJKl5fFYsmaoHywvkNqoUQaW4mGeJxLGJyP1kI5dCjQRu6uu+7q97hEYTD44HbHN9hOCTD/8ldk43a7CU8+cm5cr8U5MskqQUkFlFL09PRklYUSFJRMtVBYwflIrxmuuj7RnDaziTn+3ifs2AoLWQBfQVx5bIUTL7igxEhPT+CPMSgobW1tKZ5R7AgLG4VunuACrWS5xIN4LNq1tbUAAvOK1kJxuVxxmdvhw4fh9/mh0SY/XHlwjDiAP+yHJmYYRef2ydq5ALylCydysioon4pK+aBFko0WCiC+yw8XW4kHqQh8s+Z/9tlny8YinVuwFcxvjr4CzYfiE88wG6IXb42fgrB+FI7nlgsnUrLKQklFDCXYaTibBUWr1YZ+F/4rPCZexFNQ1J4r3scFCbaCAYB7zvodmrsDNSFv7adw+qL7zK6cLRemJ1cXq6pjke4UGQ7io7yOhRMRWSUoqSAbLRShC8vn80Gv1wNQdnkdKYKyZcsWPPXUU1HNxScQkMtHDhQ9938b6qI6Z5ATjmfHWz6SxFuU2rkM2852hfE6Fk6kcEGJkWwUlFS6vFKxe6JaQTnzzDPR3Bz/fUpydARdKqvfE4HXwLZujE6vbIxbLJz+4IISI9kuKEJrJFEWSrz2d5cG4INJBeFQO/9YxaS9vRt2u0U2fusx8ur3OzfHHnMxGXzoUZF6rOQKU2w62Qu3WDhSuKDECEtQ0rUATi1KFkqiYijxEhS16b9qXpcIrrvqMbzw6u+Sci0AuGyOWJSefZVdAFk/lL1l9tCdzaJqe41UdPyU78PCEcGzvGIkuLe41WqF2WwGwE45zSSkMRTp7/G2UISvV7O4Kx0jHVcr7IkSFOm1D9Wot3AsCbjVMxljFH7JY74PC0dKVlkoqcjy6uzsBADYbLaQoDidTphMpmRNIe4It9VNRwslEkGJ9PrpwpKx7O/Pq/uid6meexZb0F59Te5yA+SuMKolIlHR+tPvc+OklqwSlFSgJCj5+eyMmkxg9erVod/VxFBiLWxMlKAA6lxeqUgEyARqRhaIHg/dKRYkvrEXRwoXlBhREpRsIRlZXkIhUHOuTHF5JQKTlqAngloSNRiNfrhU7Hnv0xCRVeLXZ5XHnBMHwgoKIWQwgEsAzABQCsAJYBuAdwG8Ryk9om/vurq6AAA5OTlZLyiJcnllawwlEZw/XB5Av++7djjkGb6qOe+cFub4K6+KXWHS4H3pT5nfZogTX/oVFELIfwCUAXgHwH0AGgCYAIwCMAfAHwkhf6CUrk30RNOVzs5OmM1m6HS6rBCU4OJaXl6O6upqZjwl1WnDkbi8Ir1+JnLTBPaf8Yt7PMzxROMnwCWXviQbt9tNeOLx81MwI06yCGeh/J1Suo0xvg3A/wghBgBD4j+tzKGzsxM2mw0AskJQggKSk5Mjegwkx+XFWtzVBtujtVCyNYZi0gI9MYS3DEY/3P24whS3I+ZdjY9Y+hUUoZj0isdoBGJxP1JK3ZRSN4A9iZ2ielKxwZZQUCyWQNFasL9XJhIUEKvVCgBwu92h5xJloYRzeUUrKEB61aG0bm7C/0z/xpW+25NyvYtH5IgeP7GjK6LXnzS7VfT4q7dyRQKzb0IJ83UVW9hbEgNyy0Xn9YvykXn1fWajKihPCDkLwOMA9iKQwzGcEPIrSul7iZxcpKQqbTgoKLm5uaGxTEWNoCTbQpGeP9PThp31XTAPyAl/YJyxaAm6YwjozzyvQ/T4jffZe7OEq7CXHSyAWzGZjdosr78D+BmldA8AEEJGoDcon6iJZQpdXV0h91BQUDo6Ovp7SVojdXklw0JJlMsLSC8LJcjbox4WPZ679zoYiqwJv+7iUYXM8Yd2sptLRovbzF5WWL3BONmFWkHpDIpJL/sAZO5teBzp7OxEcXGgpUU2CEpQQFgWSlBIHA4Hpk+fjjvvvBN//etfsXTp0piuycokU3oeSP86lN27d2PJkiW44447VB2/dba8g/G4b66M65wSQcTbFFOqGF8RImxACXA3WCYRLssruF3bRkLIKgArEDBS5wPYkOC5ZQQtLS2orKwEgJDrK5MFRY3LCwC++uorXHrppWhqakJjY2yNDBNpoUR6/Xjwu9/9Dh988AFmzJgR9Tncjd0wFMsbSSYCi1aD7ij2Z1HapvjbfQZoGcF6DUVAVASocY9xN1jmEM5CmSv4vR7AzN7fGxFIHz7iaWlpQUFBoKJYq9XCarVmraBIXV06nU52TDREEkPpr4OwGjFS+7p4EEuD0HVV8qaLAHBq9Q1Rn1OJq0YPZI7/eXN0+7TUVhQwx0dtOiwbk7rHuFssswmX5ZX+djeDpqb4+oSV8Hq9aGtrQ2Fhn2/abrdntKD05/ISdiEG+gQl1maYkVgokQpKpNdPd9yNDhiKEx9vAQCrjsARx31a1OwYybRYeCuXjCGcy+t2AP+ilLYqPD8LgIVS+k4iJhct1dXVOHDgAIYOHZrQ67S1BSqFgxYKEIijZLKg9GehCGtSAIS2Bo7WQvH5fKCUhk0blsZY4m2hxDuG8vbbbwMA1q1bF9fzAsDX056RjR33zcXQ5Jnjfq3fj80TPX5wRyucMdS1HGLsGDlov7gzuI/RzkXr8cviKgCPraQj4VxeWwG8QwjpAbAZfa6ukQCOBvAhgL8mdIZRsmjRIqxZsyah+5IEN1wSWijZLChSCyX42UqFRi3HH388Nm7ciMOH+1wh8bZQUunyWrVqlfg6sgbw8aH7168wx/Of/1Vcr7NwtPhvadlW9vsxGnxwqQzWS/uDsVBsk89jK2lHOJfXmwDeJISMBHACgEEAOgA8D2AxpTQtS8IHDx6Mjz76CE888QSuueaahF2npSXQAymbLRShWEiFI7gQR2uhbNy4UXQeIHyWV3/WRLoJSrZj1YHZQ+zMmewkjQ/fyYPHLbZA6oeJ+4OV72L3FVOCZ4SlF6rShimluwHsTvBcmBBCzgNwFoBcAE9RSj8I95ri4mKMGjUKN998M2bPno3hw4cnZG5BQZFaKMI77kyjvzoUqaAEg/SxBuUjqZSP1OWlhmwVFFeDA8aSxMVbbhjHPveDWx3M8arT5M0k170nro3xagl0kjhLJIWS3GpJLWor5UcBuBnAMOFrKKWzorkoIeRpAGcDaKCUjheMzwHwTwBaAE9SSv9GKV0JYCUhJB/AAwDCCgoAPPXUUxg/fjwWLlyIjz76CBpN/FttB4P/2WShBN1awTYy/QlK8NhoXV5BIsnyStcYSqyimgg+HPuM6PHZ26+BKYECEw3S1vnVlfLiy+Hb2Uk2Ok929mDLZNQWNr6KQOuVJwHEtptSgGcAPALgueAAIUQL4F8ATgNQA2ADIeQtSun23kNu731eFUOGDMGyZctw1VVX4dFHH8WSJUviMG0xdXWBtMpBgwaFxux2O1pbmTkMGUF/giKNoQQfJzptWK2FwhKGZLi8du3aFapFSmdWT3qCOX5ewx+SPJM+zjpb7OJa8Sa7PxgLluUiDJlev+h1tLf3cDdYElF72+6llD5GKV1PKd0U/In2or3t7qXO0ikA9lBK9/U2nXwZwLkkwH0I7L2yOZLrLFy4EHPmzMGtt96KXbt2RTtdRQ4dOoS8vLzQ4gsARUVF6OzsTMs7VjUErQ0lC8VgMIQeJ8vlpdZCiZZYz7dly5Y4zSQ1OA9H1jQykWj18psCr5bt8KJaAr/kx6fpOzbo/uJusOSh1kJ5mxByHYA3AISKDiilkUXQ+qcMQLXgcQ2AqQBuAHAqADshpIJS+jjrxYSQxQAWAwHrpHcMTz75JCZOnIgFCxZg3bp10Ov1cZtwbW0tSktLRWNFRYFNiZqammTPZQLhXF5WqzU0liyXVywxFB6UD8/LZf9gjl/pujmq81m1gIPhx1BT1zLiaLm7eBfYPchGbJMH/z16DeZfHsh6M6qYKye+qBWUX/T+e4tgjAI4Kr7TkUMpfQjAQyqOWw5gOQBUVVWFvrVlZWVYvnw55s2bh7/85S+455574jY3lqAE+3pluqAYjUZotVpR0aLX64XFYgm59BLh8lKT5ZVuMZQHHnggptenK92HHbAMjDzmctMoG3OcGuXnenBrdNX4igh8XkGXWAIrBzgS1GZ5JSZNSswhAOWCx4N7x1SjtB/KhRdeiEWLFuHee+/F7NmzcdJJJ8U8WSDg8po1S5yXILRQMpGgSAR3oBRuFubxeJCfny87NplZXulYh7J+/XpVx2WaHfTK0MdEj8/Y/3OYBianv5gamBt8CRpQUi1R/MyXLHwN7W1yV5g9z4RHnp4X55keOajN8tIDuBZAcCX+FMATlNJ47jG6AcBIQshwBITkEgA/j+QE/e2H8o9//AOfffYZLrvsMnz//ffIy8tjnEE9fr8fdXV1ooA8kPmCEnRf6XQ6WCwW0WZhQZdXkHjFUBKZ5RXp9ROJRgOYzRr4/RQaga/f66HQ6dP/Nvq9YS+KHl9w6KqYG1iq2aPFYPDD7ZaHe/cfIw/gH7WpAVLpFrrBgpgc7KWLJTIc9ah1eT0GQA/g0d7Hl/eOXRXNRQkhLwE4GUARIaQGwJ8ppU8RQpYAeB+BtOGnKaU/RHhexR0bc3Jy8OKLL2L69Om45ppr8NJLL8VURV9TUwOv1yurccl0QQlaHXq9XiYoQZdXkOBCH2sMJZF1KOkYQ3F2i11su3fIF7GSQTr445FPmUA2z2Q3sPzZ9+qLia8dJW7Hcn1TFzok9yezTm1mvva9T9gbfAXx6wk0HnUt8znxQa2gHEcpnSR4/DEhJOrUFkrppQrjqwCsYj2n8rz97th43HHH4Y477sAf//hHnH766Vi4cGG0l8KePYHtYaTiFSxyjLWle6oQurxYFkpwzxchyS5sVCJdenkpEYlsVYw1MMf37vBAK8l68vsD1k828MBJ8vf9ty3sGxZWixdhYWTLKYHvqv3jTvAOk8lBraD4CCEjKKV7AYAQchTiU48SV9TsKX/rrbfik08+wfXXX4/Jkydj0qRJisf2h5Kg6HQ65OfnZ6yFInR5Wa1WmaCUlMjdDPEUFDVBeSXLMlpLI2mCEgdDqK5G/llXjI9/Y8hM4MyT5H9jK53Fod/tCHxWejfjO0V692eRQDWEN6KMAbX3NbcA+IQQ8ikh5DMAHwP4XeKmFR2U0rcppYvtdrviMVqtFi+88AIKCgowb948tLe3Kx7bH7t27YLRaERZWZnsueLiYtTX10d13lSjZKH4/X74/f6EC4p0zxUg8S4vacFm4kiua02r9nYxzbFo4/+5deWb0VEg/1GC17KoQ22W10e9DSKD5cA/Ukpj2wQjhZSUlGDFihWYOXMmFi5ciNdeey3ieMp3332H8ePHh1q4CykrK8OhQxElqKUN0hhK0HUXHLfb7bjttttw7733hl4TzxgKS1BisVDUCEqyilCrqQN7fR0YSK3QJMGvP2aieIHcuTU5i6Kz3gHzAHmKsLPBAXMUrV+uHkPBEuMndsjvh4WtXHRaP7w+jap9WDjxIdx+KLMopR8LtgIOUkEIAaX0fwmcW8SocXkFOeGEE3Dffffh5ptvxv33349bb71V9XUopdi8eTPmzWOnF5aXl+OTTz5Rfb50QslCCdajGI1GnHzyySJBiWeWlxoLRakvW7SCEqsgRsLtPethgx7jaAHGowDjUID8LNv89OXh/1Z9bLTFk0qccXpfAL+797/18x/lGZ32Jnaj9P4aUQpdYdwFxiachTITAffWXMZzFEBaCUq4oLyU3/72t9i4cSNuu+02VFZW4rzzzlN1nQMHDqC1tRXHHnss8/nBgwejtrYWPp+PacGkM0HhMBgMIkHp6Qnc3ZrNZlm3gUS7vBKdNpxMQbneOA6bXU3YhhZ8jYBbtNyXg3GkAONJAUYhDwaS3O+MRouUZZS5mxwwFPVZLf52JzR2dTEhixboVjFvndEPr0t8E6JktUi3JA4i3ZqYu8DYhNsP5c+9v95JKf1J+FxvvUhGQwjB008/jZ9++gkLFizAF198gWOOOSbs67744gsAwJQpU5jPl5eXw+fzob6+PuOq5Z1OJ3Q6ncxCCQqKyWSSCUqiXF6UUvRawqExr9cb2npYSiZYKCfqBmGyewD8lKIaXfgBLfgBLfiQVmM1PQgdNKhEHs78aQBOKCzGaFtuwt1jw0ewLaQDP/XAm+CP5ruznhU9LimX/3/lrriE+dpfjZVX5C/b2ikbG326vJ3L+q/YKcdDt7CTaaSWi18D/Pzivrocu92Ex5ZLHTlHHmrDdq8DkN6OvwZgcnynk3zMZjNWrlyJKVOmYO7cufjyyy/Dbh38wQcfoKioCEcffTTz+cGDBwMIbEWciYJiNgfuEIWCEqyYZwlKPC0U4eLu9Xqh1+tlzxuN7C5NmSAoQTSEYChsGAobztYMg4v68CPa8ANtwQ+0GUt378DS3TtQaDBgekExTigM/CSTo6tyRI83f9MFYUKcRkvh96VXOq5FR9DdWz2vpneYFGb1Pfqvuge4xRIkXAxlNIBxCDRmFMpvLpB+jt9IYihCBg4ciHfeeQczZ87EKaecgrVr1yoKgcvlwrvvvos5c+Yo+vLLywMdZGpqajB16tSI5pJqWIJCKU2oy0tolQgzrjweD/R6vUgUPB5PRru8lDASLSaiEBNJIYCRGHGCButaGvFlc+Dn7cOBJI8yWDG2N/ZSiTwYk+geKy0XC/lRY9hisn9PfK/rb3NCk6fODXbd2L5CSb0mMN8/fFOHLkkin9ngg5OxTXH1mCLmeUdtkmyaJ2jxAgDER3m6McJbKJUIbISVB3EcpROAqjhFMok0hiJk4sSJeO+993Daaadh1qxZWL16NYYNGyY7buXKlWhpacEvfvEL+Ul6CQrKgQMHIp1GyhEKitVqhd/vh9Pp7NflFU9BES7ubrcbFotF0YKRkkkWSjgGmEw4v7Qc55eWw08pfuzqwLrmJryzqw6f4hDWoBo6EFRQO3bsGYATi4oxzp5491gqcF67kjlueVVdRf7/HSNf5t4sZhce/3PlIOa4T0+g9fR9lzR+QE0a+JFmuajdU34apfSrJM0pZRx//PF47733MHfuXEybNg0rV64UWRherxd33303RowYgVNPPVXxPPn5+cjPz0/IHiyJRigowX5n7e3t/bq8Yl2QhVaJ1EIBxKLgdrvjXoeSjoIiREMIxtjsGGOzo3L3QLipD7vRHoq/LN35I5biRxQYDJhWWIjpRUWYVlSIgdQWU3uhIxGTwYcehuVSN71A9HjwJ02iwkil7LAj7eNXG0O5hhCyg1LaBgC92/H+nVIafe+SNOXEE0/El19+iTPPPBPTp0/HTTfdhF//+tfIycnBjTfeiG3btuF///tfv1sKE0JQWVmZ8YIS7Czc1taWUJcXS0SEv0stlCNNUKQYiBb+9PGyAAAgAElEQVTjet1eADD2Zxqsa2nCF02N+LKxCe8GdxI1mnF8flHvT/LiL3oD4GF8JTQaIJ5NCXrqHTAx6l3UYNQALsZczp/VwDz+zS/ErjCnTdwixuzwKNorwuB9kGwN4qsVlIlBMQEASmkrISR8OlSSiTaGImXs2LHYsmULbrnlFjz44IN48MEHg+fHnXfeifPPPz/sOSorK7FmzZqY5pEKWBZKa2uryOUlzbJKpqBEaqGoIdWCQoi8LUsww00Npm4LZpmGYNbgIaBlFAd6HFjf3oiNjiZ83HQYbxwO7FtXprVigr4AE/UFGKfPR66G3S8sVo47MYc5fnCv/HP2eil0ur736fcF0pjV8MZgeb3LJQ3XQVcQXmTmDGFvtPfvnezvgl7nh8cruIk0ABB87SMtnsxWV5haQdEQQvIppa0AQAgpiOC1SSOWGIoUu92O5cuX49Zbb8WqVavQ3d2N008/XVVaMRAQlGeffRadnZ2w2dgbDqUjLEFpa2sLubxSYaFIn890C0UqILl58hVUb2RXh4erGSGEYJg5B8PMObjcPAx+Cuzs6sA3rY348GA9Pu2pxeqegMAM0eZgnD4fUw1FONpcgHxd8vc4/Gm3uOGGTi8PvheXqS+SqV/0n9DvA574FcwDc+BpdkJfGFu/s+nHtIoe7yoT5yTVbJY3TQWAoTvZnZIBueWSDVaLWlH4O4CvCCGv9j6eDyB+Wx+mMSNGjMANN9wQ8esqKwNdanbt2oXJkzMnu9rpdKKgIOBKEbq8ggWPiY6hsARFGrSPt6C43W7U1cV550AFdDqC4gHSz0/9ne3gIeoX/YAoAZNMNkwqsmF89SB49X78RDuwk7Zhh78VH/fU4r3agMAMNeRgkrkAR1sCP/lgWxrJp7/6dWVeLg1sbTx4qPwzm/rjL5mvMWsBZxyLPJWaULJwNDjwi/P+G3qcm2fCw8/Mj99kkoDaXl7PEUI2AghuT3gBpXR74qaV+YwfPx4A8P3332eUoHR2diInJ7CQCC2U4KJvs9niLihKWV4sCyVRLq8rr7wyqtdmGjqiwUiSh5HIw1ztMHipHz0DXdjibMZ3zhZ82FmLt9oPAgCGHrKiyl6EqtxCVOUWQrpcuHoojKbER531Jra1lgh+Wcl2l937bbfoca4Bon1bTEY/elzyuKozh30DYOl0ySRS+riDsdnXDb98VTaeTsITiduqAICDUvofQkgxIWS4tHqe00dFRQVyc3OxcePGjFqs2tvbEezWLIyhBBfr3NxcWQwlGF8BIvP9B1GyUIKutERbKB6PR/QejiR0RIMJtnxMsOXjMgBe6seeng5862jG965WvN90CK/XB9LfS3UWTDAVYIIpH+OM+ah+T8v8v54+K10sG2X8rU5o8tW7waw6wCGoZXlstlh4nq1kV9ivXGaGhhFbYf2FyOwwRt4PS2RYY6lC7RbAfwZQhUBdyn8Q2L3xeQAnJG5qkROvoHw80Gg0mDx5MjZu3JjqqUSEUFCMRiPMZjNaW1uh0WhE8ROdThcSAuGC7/f7I+5fFi5tOBYLJZ26DWcCOqLBaHMeRpvzcKVZAx+l2OPswKbOJmz1NOPrlnq831UDAMiFARXUjgoEfobCBj1J3k5fOh0g3XlArdXUee0K5njhCnb4dcn46OJLdcPZW2lUbKnvrWXpQ6mPWCah9h2cD+AYAJsBgFJaSwhJu0hzPIPy8WDy5Ml4+OGH4Xa7YTAkJqMmnrhcLrjdbgj3kykpKUF9fT2sVqtot0a9Xs/cRySahphSwQiSrBhKsBsAR46WEFRa7Ki02FEw4Cj4KcXurk5sbm3Fqm2N2IN2bEagSFAHDYZTG2buLsaxeQU4xp6PfEPfQqzVU/g8YRb7CMIlYybK3VPr1jhCv+v0gNcD+HxUtsulEu6mbhiKLOEPVInB4IObUdfSXiSfu71J7FbzE+CiBS+LxtJ9KzW1guKmlFJCCAUAQkh0yd9HGMcddxxcLhe2bNmC4447LtXTCUtwszGhoJSVlaG2thYDBgyQCUow80sIq1twOIRuLqHrKR5ZXmoQ7krJ6R8NIai05aLSlovSHwK1Le3UhT1ox260Yw/a8Uz1Xjx5MNB/ZajRikk5BZiUU4DZE20YYbOK3GQfvyGuTdHr4xeTmTIj4Hr7+lOH7LnRx7Atjk0nPM8+1zeXgtj7hMbV1A2jQHhMhKKHyud+ygy2K2zTyxZQt/h4Weoxw53I1Ns0Kp5UKygrCCFPAMgjhFwNYCEA9ZseHKGcfPLJAIAPP/wwowRFKBylpaXYtm0bTCaTTFBYRCMoQsEQilQws0x4zkS4vBwO+YLDUY+dGDEZJZiMwG6eI482YbujDd87WrClqxWftR3GW83VuOsAUGDUo6ooD5OL8nBsUR6sJXZYNezvUhCfNwG7T2oR0Sbm/tufEz3+4i2x1fHzbT9nvu7/dbInbj9ZfvF93xWKHg/Z2SzTCr+O4VL0U1x+wfOw55nwyNPsPZqShdosrwcIIacB6EAgjvL/KKWZV7WXZEpKSjBp0iSsWbMGt912W6qnExaWhVJaWooPPvgAubm5KCzs+8JbrVY0N8tz7KPZn10oKEILJWg5CJ93uVyK1zhSBSXduv6aNFocayvEsbbA98VPKQ70dKHa1oj1jW3Y2NiKDw4F3GQEwBB9DkYb7RhjysN0WxEqLDboBLGY+gP9C040FI1jf167tsTX9WnSUvSo/L/R6vzwCYonqQbQRtAtOR2KJdUG5a0APqaUriGEVAKoJIToKaWZ1bMiBZx22ml46KGH0N3dDYslfr7ZRKAkKB0dHdi9ezfOOeec0PigQYNw8OBB2TmiCXALXyN0PwUXeqGF4nA4EiIo6fZ/43ZRGIzqFqIh49m7D9buNsJg6DuHUusTpcw8+bjY4aK2lYqGEAw323BShQkLKgKNU1tdbnzX3I7V37VjR087vupuwPtdh/CPpoAgjbHaMTYnD2Otdowy2zHUlAOtZI6EUFCJm4kVqI8ErS5gEUVKT6MTpmJ5hOOsoeyd0h9vMaJd8qcydHyX6PFerbzz8YgtDbKKfL8+eYkQ4VBrSK4FMKO3h9dqABsBXAxgQaImli3Mnj0bDzzwAD744APVO0Kmio6OwEZEQkEZNWoUgEDq8KBBfZ1YBw4cyDwHK64SDqGgdHV1wWQyoaenJyQoQgslUkFRQ3d3d6g7QCrw+yk0GvHCuO5D9t3m4KEG2bFKfP2J+P9iWAV7x4nAxyv/7Exm8UJltIo/95KBkSWaeFwU+l6RzDca8LPSYhQfCLjJKKWo83ajxtCJbd1t2N7VhtfrD+CF3rYAZo0Woyy5GGPNwxirHWMseZhUZoU01j5xcl/Kst9HodESEA1AVRrOIxQsl3AtYd6bzt68tmLjOfDnyr9bj8+S38Bculocy2MF9OuHyrPGiqs7oPVTUJWJB4lEraAQSmk3IWQRgMcopfcTQr5L5MSyhZkzZ6K4uBgvvfRS2gtKS0sLgL4KeQCYNGlS6HdhO3+ldjLRCEowVgIEBCU/Px91dXVMC6Wrq0sxThOLhRKsuUk0peUGuFziOTUcVm/ot7emaK/eSCAUYASoN38OSIXLlkvg9wVaxpTqrRisycHxOYOAHMBHKQ66u1Ct7cTO7nbscLRhZeNBvFzfKzI7tBhjy8X4XDvG2+0Yn2tHCc0NuctamwIqklcgX+a8PYAugh2dWmvFB/v9blXCPvjut9hPPH6TbEhaLHn6LLlL+cuVNnh6xELfVJY+CbeqBYUQMg0Bi2RR71jabZaeTnUoQfR6PebPn4///Oc/ad/Xq6Eh0Gm1pKQkNCYUkWOP7du0M9gJQEo8LJSSkhLU1dXJYiharRZdXV1xdXnpdLp+rR5O5OTmsRfa2hr52PAx4sXxpx19/19aQjDcaMNYsx2zbYFdUH2U4qCrCzud7Tioace2jna8dqgazx3cDyDgLgtYMnYM09pQYcqFnZplG5Ht+4y9fOUP8EJNKU1Tg9gvZrNrVVuOAOCsd8As6ZS87BTxnB77gcIhib8cf658i+MvX7OBegjC5DYkBbWCciOA2wC8QSn9gRByFIBPEjet6Ei3OpQgl112GR599FG8+OKL+NWvfpXq6SjS0NAAm80mcv9oNBo899xzWL9+PaqqqkLj1113HTweD1566SVs397XhSceFsqQIUNgNptlFordbo97DCU3N5cLSgahJQTDTTYMN9lQNGgwCAmIzE+OLmzraMe3De3Y4WjH243V6O51lxEAg7QWDNfZMExnwzC9DQZXIQYazLLYkYfRPiV4kv4aQHS2sy1Hr1sHHcMz+PKQx2Rj5xxcCPPAPpH57VB5y5mlB7SybY3tk2MIGsUZtVleaxGIowQf7wPw60RNKts4/vjjceyxx+Khhx7C4sWL03bTo4aGBpF1EuTyyy/H5ZdfLhqz2Wy4/fbbsXr1atF4rBaKy+WCwWCAxWKRxVDsdnvEFkq4NGa73Y6WlpaMrpb3uAN7kCQa6ofo7j2aNjvhYLXy7+9YICAyFTk2VOTYcKplCIBAZlkT6cbOrg5srG3FPlcn9ro78aWjPvCibwGbVo9RllwcZbFhhDnwM8FsRaHBIHtf0rep1wNqWtjt+17pP0YuAm8NeVr0+LK9l0AnaQ/z+0ny2OXC2ja0uwB78ptFy8j8Wv8MgBCCm266CVdccQXefPPNtI2lNDQ0oLg4so2YpH29YrVQAMBgMMBqtSpaKEoiwRoPZ3mUlJTgp59+QlMTuwAtE9i1gb2SEOIULc4+L4VWp14ApMkC0rt3t9uHWJs2SrPZWK383T2RX0NDCMrNVpSbrRjv6vtOO3we/OTuQq22C7u7O7Db2YFVTTVwBFO7dgD5ej0qcmwYmWNDRU4OKnJsqLRbUag3hYSm6gRxv7L1n3chkhIsU64GPR39fzerl8jjL0e9+1vZ2CNnpM8NKheUJHHppZfinnvuwR//+EfMnTs34vYkyaChoUEUM1FDUFByc3PR0dERs4UCyAVFaKE0NDQoikQ0ghIUUGFNzZQpU7B+/Xr1byABaLVgLlCRWAUWq/g7Vr2fncI6cgw7w621WXwXXThI3XeWlc4LAGaz3J303TrxbX7FmAgi5cy6cfmYML3ZqtVjvDkfJ+T3peRSStHo6cE+ZxcOuLqw19mJfd2deLu2Fp2+vvnlGXUYk5+DynwrBnnyUGHNxVGWHJQYTagYzf4MpRuIBbnoUfne9f+94lDYbDRPkwN6aduWLieQYwYcToDdOixpcEFJEjqdDvfccw/mzZuHp556CosXL071lGQcPnwYU6dOjeg1wSSDoqIidHR0RNXGhGWh5Ofno7U1sKlRUHAGDBiAnTt3ikRCuMCqEZSjjz4a333Xl6AYdPEFCyrPOecc3HfffRgzZkzE70MtUkuBJR5KC9TBn1xIViv3aCksZ7sPD+yJ702UySZffbva+iLTQffcoHL5dX0esbgNhRVD7VZ4PX0uX0opmjwu7O3uRGt+M3a2OLCz1YE39zWg1XUodJxZo0Wp3oIhRisGG6woN1pDv9fv9DFvACa7c6ExiOdlsYgf+/0BMRTy7elPyM414QzBl+eeS2XPJxO1hY33A7gbgBOBOpSJAH5DKWU3vuEwueCCCzBz5kz8/ve/x1lnnYWysrJUTymE0+lEQ0MDhg4dGtHrghbN6NGjsW/fvpAIRALLQikqKsKBA4G26UHBKS8vR1NTk6yZpNEYcPkoNasUMm3aNOzbty9UcyN18Wm1WhQVyQvK4kVnhw+11eL3Wzku3Vv+JQ5pcSSrJiep8xHVchAM0JkxwGxGaaU1VIdCKcXmTVrsd3dhv7MLB5wO7GjqwC5HB9Z21MMnEHwLdBhAzRgAS++PGQNhQeNGIM8iTsvSGwLxsCAuh0b2WVDqlQuUTgN4/YAh9faB2hmcTin9PSHkfAD7AVyAQJCeC0oEEELw5JNPYuLEiVi4cCFWrVqVNq6v4OIdqctr+PDhodcRQqKKRUgtFKPRCKvVik2bNgHosx5KS0vh8/lE7qmenp6QoKixUDQajagPmbRAU6PRiFrMRIqwrb8UY4Jauyu5VWJ9vdS9pjYoz7qzBtiV9SUDxYtqZ7vc6rDmKGVeyetdhO+FaCion4QKHMWw2xordSZurTOKAvNNu9zIgRXjYcV4ABcVBOboo37U+5w45O1Gra8bNR4H6nzd2Odtxzf++pDU3PkvoMRswAi7BUNzzRhmM6NkWA6GWCwYYrWgxGRE3T75Z+H1UPj9YgvVOG0I+/NJAWoFJXjcWQBepZS2p2umUrpTUVGBZcuW4ZprrsFf/vIX3HXXXameEgBg//79ABCxhbJgwQJs3LgRN954I1asWBGVoEgtFKPRiKKiIjQ1NYFSCpfLBaPRiAEDBgAA6uvrQ8c6nc5QZb8aQdFqtSJBKS0tlT0fy3f73HPPxeuvv8587tr8sVGftz+k+7IHybFpRK40pQyqn3azq/IDi33fCzwu8c2Pq4e9k2JPJzuzqahEvty0t0af8po/WP7//eXqvvPNujDw/7hzvfh9AEBhMXvpq6thu+tGjteJPjvpZ2nJCX42WtigRwUCjVSdTh+8vWEYN/XhsM+JQ14HjKO6sK+zG3vbu/H5oRa84nCJZmjUaDBQb0apwYJSgwVlBisGGcwYW2pFudmCHF3fd9jX7YPWooXP6WftyZVU1ArKO4SQnQi4vK4lhBQDSEonst6alz8CsFNKU9tKM04sXrwY33zzDe6++26MGjVKlpKbCqK1UAoLC/Hcc4FOrEVFRWhsbIz42kHB8Pv98Hg8sNlsKCoqgsvlgsPhgMvlgslkCrmnamtrQ68VNpNkCYp0TKvVijLTioqKYDAYQqIW642SsD2NFDftnQuBaH2jfgqSADfPqLFiV9reXew/WWnwPe2QfF5BWO1QhPEorxvQGcBsvcK2WpQtFKkVx8pGYzF+CgRZbDoANgA2tNXrQXIJ0Ov1dvt92LK/A9VOJw57u1HncaLe50StuxvfO1rh8Pf+HwX+TJGn16PcbMVgswXD/mDC7NIBOCa/AEPOVzWthKG2DuUPvXGUdkqpjxDiAHButBclhDwN4GwADZTS8YLxOQD+iUAV/pOU0r/11rwsIoS8Fu310g1CCB599FHs378fV155JaxWKy644IKUzmnPnj0wGAz9LojhKC0tRXV1dcSv6+7uhslkglarRUtLC3JyckJup6amppBba/DgQLX07t27Q68VZpWptVCEY0ajEYMGDQoJqobhqxkyZAizESaLkSNHKj7nIX7odARWSfaV2wNIV8yCQvafJju+kJwgvdIiLEf9LlnSBAVbrnyhzslln8vRJD926Ii+O/d93wf+nwuL5cc11LJFtL6WXVyi04lTs6WxHouVgPoZ7WbWekIWipBhFTrJ3i9azJ1jAvxGAIE2QDU7jNAbAt/Hdo8b1c5ufLK5FU3oQYPficYuJzZ3tuKD+h6sO9yK548+iTn3ZKI2KD8fwOpeMbkdwLEIBOkPR3ndZwA8AiC0yQAhRAvgXwBOA1ADYAMh5C1K6XbmGTIck8mEN998E6effjrmz5+PJ554AldddVXK5rN161aMHTs2ppjOqFGj8PLLL0dc8NbV1QWLxRJazG02W8gVVVNTE7JQgvGaH374IfTaaARl7ty5eOKJQLaMwWBAWVmZTFBOPvlkfPrppwAi66CsFH8Zqs/BKTmlzOdiRSnFWLqwK7m8lLoGG4xicQ32xup7Hfv/2GJnF2S0N8h7g+zfJ3bXjZ5ghl7WPVe9QAm/e1odhc9L4HFT6A3qXh/c5VGK9LOTxnpGjmcvpSWD2TVCX34oT68fdZ4NWkPfe//uuTa4RUalHlMNJaLAPQA8bt6KNpcbdTUesBsiJQ+1Lq8/UUpfJYScCOBUAEsBPAYgshzTXiilawkhwyTDUwDs6bVIQAh5GQErKCsFBQgsnGvWrMG8efNw9dVXY+/evbjrrrtkxYLJYOvWrTjllFNiOkdlZSXa2tpQX1+v2I2YhcPhgNlsDu3QmJOTExKP/fv3o6enByaTCWazGWVlZdizZ0/otcGW+wA7y0sqKH6/H8uWLcOrr76KlpaWQFNCQRwlKCgvvPACVq5ciWXLluGWW25R3TLHZDLhmmuuweOPPy4af6p8hqrX98FeRFnum9ET2K33cwrEB0rrUoKwrAJAXWv6SPB6/NBJxEIqhju3yhfan81lZ8Gxgv8ed19cZ1RV4Pvw/svyNzJSod7lOEnBYui8kjBVa4sXfsG8KShIBEF+1k1A+/dO0Y3YKefrZe+vp0src/M99m7gX2mwPhWoXbmCb/0sAMsppe8SQu6O81zKAAj9JTUAphJCCgHcA+AYQshtlNJ7WS8mhCwGsBgIuCgyhZycHLz99tu4/vrr8be//Q1fffUVXnzxRVmwOJE0NDSgtrYWEyZMiOk8xx9/PABg7dq1uOiii/o9VtpBeODAgejsDDS+Ky4uDsVyfvrpJ1F7+VGjRuHQob4agGBDS+k5lca8Xi/MZjNWrlyJ3/3udxg9erTosw7+QZeWluK6667DddddBwCorq7G3XfLv/IWiwUWiyWUjGAymfDII49g0aJFol06Ozv65iHd54SVxWTJBViuLCVXmBqUXFZq9zWRipnS3iPSbLAg276Ti8VRo8RisXuH+sLYrmZWN8S+CQZjLCwRVrai2ULu8fhFltOwCoNoUzO9wY/eHdJFHNrJ7gFWNsQoFxrqE1tBLVroJFsitzdqZPN2u/3o8nuxtaEVE+vqUFxcnJKbUkC9oBzq3QL4NAD3EUKMQHISCiilzQCuUXHccgDLAaCqqir1Uh0Ber0ey5cvx4knnohrr70W48aNw9KlS7Fw4UKmTz/efPHFFwCAE044IabzVFVVITc3F++//35YQZF2GDabzSgvL8eBAwdQVlYGk8mEQYMGYd++fWhvbw9lck2ZMgWffNLXlzScoEh3YwxaQTNmzAhVwwvrgQwGdobSXXfdhdtuuw1Wq7hK+fHHH8ezzz6Ljz76CABCsaCqqipRtb8Q6QKn0VD4Zf539sLGWgi9HipbeAB5IPmwQnxg2s/YFk7TYfEqPGCw+BqFA9iWg8/LzjpjoaZ3l6uHwmhSt/gL3XRtdQF3U36+/H0H3EbyC+uN7PEtn4oLdmdfJHZluRzsv9Mep595PlZ2W8UxWqEeYs82ucrb8+WuxmFDdNiy34FbnF/jltJSaDQaDBo0COXl5Rg8eDBKS0tRXFyMoqKi0L/Bn8LCwriKj9ozXQRgDoAHKKVthJBBAG6J2ywCHAJQLng8uHdMNenYvj4SrrjiCkydOhWLFy/G1Vdfjf/+979YtmyZqG18Ili7di1MJpOom3A06HQ6nH/++VixYgWWLVsm2oNeilBQenp6YLFYcPvtt8NisYSq9SdMmIAtW7aAUhqyOoNWEBCIh9TV1YUeswQlWMAYxMPo6Ce0UMaOVU7tZe3qaLVa8eSTT4ZcdDk5fS6TUaNG4dtvvwUgLpgrGSC+sy6tkM+7p1ML1kLEWghra9h39aWDDcxzSFGuJxEHnqVZVcr1L2wxNBgBt0RrSsok7ev3yF+3bg07Oy3gCpO+P+H5AvNgFUsqzV0p3qLRQuziklhhSqKu01N4PQzXJUNIbSP00Aqu7f/MBY3k/6W12St7L38/pRKXVA5El8cHz7zrUFdXh+rqalRXV2Pr1q14//33Q9Y/i/z8/LgV86rN8uomhOwFMJsQMhvA55TSD+Iygz42ABhJCBmOgJBcAuDnkZwgXdvXR0JlZSU++eQT/Oc//8Hvf/97TJ48GfPnz8ddd92FysrKuF+PUoo33ngDp5xyiuLdeSQsWbIEzz77LO6//36miyiINNBtNpsxffp0TJ8+PTQ2efJkLF26FMXFxSF33KxZswAE3GL5+fnYuXOn4jkBcYwFCC8oN9xwQ39vT4bJZMKwYcPw9NNPY+HChaIsr+uvvx5XXXUV/lkktvykfnVW+qui752xRa3eKPfxA+o79wZKGlh30T7JcWIhbDzMTlaYOZodlJ9xptxF1SnZQ4olOqwxgC2EQrdeoG08jWgDs5oDbEujVBJcp34isjJZ1gQATJ3NHv/2U/nS27JV/Lm1tajrNllkNeCMYcWATgP7tdcyj3G73WhubkZjYyOamprQ1NQk+12YPRktarO8bgRwNYDgPpfPE0KWU0ofjuaihJCXAJwMoIgQUgPgz5TSpwghSwC8j0Da8NOU0h/6OQ3rvBltoQTRaDRYtGgR5s2bh7///e948MEH8frrr+Pcc8/FTTfdhBkzZsStbfi6detw8ODBfhf/SKiqqsLll1+O+++/H3PnzlXsDSZd/AsKCpjn8nq9qKurC/Xcys3NxYYNG2C323HbbbeJ+nL19PSECiKDtLa2QqPR4NFHH8U111zDDNwLXV7hstyqqqqwceNG1NXV4d5778Vpp50GALjyyitx+eWXi9wHCxcuxKxZs7D9BPEfeXOTeA75xfJMoOZ6diffinHyP1lrvmwIAHBot/jY5sbY6k3UtkWhlB03YI5Lqt1nnS9/f0oNE91OQPoZNdb3vceCAawYS3To84zwtAlUzWYEOvseGwrNcDfLLUWf1QitQ66G2gIDfC0SQbYZgM6+MWOxGa5G8TmNRWa4msRj2nFFMLjd8JiU+9cHSwL6Kwt45ZVXFJ9Ti1qX1yIAUymlDgAghNwH4CsAUQkKpZTZwYxSugrAqmjO2fv6jLdQhNjtdtx5551YsmQJli1bhuXLl+ONN97A0UcfjauuugoXX3xxzKbq0qVLkZ+fH9eW+suWLcOXX36Jc889F59//jmzNkMqKKx026A1AgBHHXVU6Pega27atGl4/fXXceDAAQwdOhROp1O2N3xzczPMZnO/1ld5eZ+nNZxQf/jhh+ju7sbAgQPxz3/+U/Sc1BdNCMHw4cPxo14Dn0fQ0FJSyMNsciIAABe6SURBVMiyRpQsFFZmk1KMQe7WUWg3otDWXmoNSVNlFdOQFTTZ0yN/wpwT31QyfaEJnuaAi4zkmkA7emAsNsHVKHabscYAwFBkhrtJLgwzPxSX3XXYxFlip+gHMOezu2MPc3w0Q+s0kl0lzzHIMyWlxwDA1w19bt8TmVdLHqq3AEZfphd6f+e9V5JESUkJ7r33XvzpT3/CCy+8gEceeQRLlizBTTfdhDlz5uCiiy7CnDlzIt7L5J133sGbb76JO+64I65bExcWFuKdd97BSSedhBNOOAHvvvuuKOMJgKwrMUtQ8vLycNlll+Gll14SiUuQs88+GzfffDNWrlyJG2+8ET09PTCbzXj//ffxxRdf4K677kJNTQ2MRmNIUKR9wwB2bEQJu90eShBQy/CR4tXj26/F772pTu7aqFVoAWLPt8rG1r/H7vBstrAsErkCHK5mt1AZMUYswvt3ic/H2qs9QAyWUI4J6JIs9DYT0MmIo0ju6AFg2uYFod81vbuUn0Xln6WOsG8wdBqFu/y2/jtAdLh9yDXIF/tuL4FFJ/9su9xAjqH/sR6fHyat+O6hy+NHjiT12ukhMOspnIxYTbIh4bZIBQBCyG8B/ALAG71D5wF4hlL6jwTOLWIELq+r4+EPTGe+//57vPDCC3jhhRdw6NAhEEIwZcoUzJkzB9OnT8eUKVOQl5en+Pp3330Xl1xyCY466iisX78+1GAxnuzatQunn3466urqsGzZMlx77bUhC+CLL77AjBl9tRnPPPMMfvGLX8jO4fF4cPjwYZEVEYRSiqlTp6KjowPbt2/HhRdeiH379mHLli2oq6sLxUYGDRqETZs2obS0FB999BFTnILzUvP3ECl75l8KX2vfor99L+Bq7HscCJ6LURKUCccyBOULdsDVbFGXIThkgh3eVvld+aCh4gXyUJMOnpa+hT233Axfq1ygJ52tARxykWtpt4N2iI/X5BsAwZj9pV/KXkcUEkq7ve2yMbOu78YoKCjeCASl22NArlG+MLuaGmET6OdhsxEWgVV381fs741eyx53Mqw1KacOlQvz9y3yue0/3GctvXJu9B03CCGbKKUxZeaoDco/SAj5FH0W1ZWU0m9juXAiyDaXV39MnDgREydOxL333ovNmzdj1apVePfdd3HnnXeGgpWjR4/G6NGjMWzYMJSUlECj0aC2thaffvoptmzZggkTJuC9995LiJgAgSynTZs24YorrsD111+PVatW4dFHH8WQIUPQ0tIiOnb8eHaNr16vZ4oJ0LcT5oIFC7By5Uo4HI6QtVFSUgKtVgufzxdqr9KfWJx00klYu3at4vOxUPHiFaLHlTqxu+SrGY/C0yRegI1FFria5Iuy1m6Gr128+BuKTXCrcN8YikxwN8mPm/4Fu2hz78//DX9b3/HT1i8SPd/jUxAyPdsNm+eVb23gp+oCz2rp8lDk9GZbBX93eCiskgws4XFCfv0RO+U5P18sQGVWqVXHtg48bgK9Qd1Nis8FaAV/it1OAotZRZaeGyAGAGmwi3VYC6W3JcoPlNLRyZlS7FRVVdGNGzemehopob29HRs2bMDXX3+N9evXY+/evdi/f3/IxWSxWDBp0iRcdtllWLRoUcLERIjf78fDDz+M//u//4NGo8Ff//pXOBwO3HbbbXjuuefw/fff4/77748q0cDr9WLSpElwu90wGAwYMWIE3norsHXq4MGDcejQIYwaNQo//vhjv+epra1FbW1tzKnTTDzviR9LBMXHcBEF766lsKqxW9zs7HqLTuyaU1q8LURu9QBAu0+cgmXSit2iSoJiUxAUhwpB6fFpRHf+AODwEObi3+hsh1USi7hzc99nG+xiYmXcNjcrlMq0trL/HvLzxS8ok3xke5o00DGEY/vH8mQTADhqarvs+IOrxSeljASIo89oh17iof3hmb64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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "fig = plt.figure()\n", - "ax = fig.add_subplot(111)\n", - "cm = matplotlib.cm.Spectral_r\n", - "\n", - "# Determine size of probability tables\n", - "urr = gd157.urr['294K']\n", - "n_energy = urr.table.shape[0]\n", - "n_band = urr.table.shape[2]\n", - "\n", - "for i in range(n_energy):\n", - " # Get bounds on energy\n", - " if i > 0:\n", - " e_left = urr.energy[i] - 0.5*(urr.energy[i] - urr.energy[i-1])\n", - " else:\n", - " e_left = urr.energy[i] - 0.5*(urr.energy[i+1] - urr.energy[i])\n", - "\n", - " if i < n_energy - 1:\n", - " e_right = urr.energy[i] + 0.5*(urr.energy[i+1] - urr.energy[i])\n", - " else:\n", - " e_right = urr.energy[i] + 0.5*(urr.energy[i] - urr.energy[i-1])\n", - " \n", - " for j in range(n_band):\n", - " # Determine maximum probability for a single band\n", - " max_prob = np.diff(urr.table[i,0,:]).max()\n", - " \n", - " # Determine bottom of band\n", - " if j > 0:\n", - " xs_bottom = urr.table[i,1,j] - 0.5*(urr.table[i,1,j] - urr.table[i,1,j-1])\n", - " value = (urr.table[i,0,j] - urr.table[i,0,j-1])/max_prob\n", - " else:\n", - " xs_bottom = urr.table[i,1,j] - 0.5*(urr.table[i,1,j+1] - urr.table[i,1,j])\n", - " value = urr.table[i,0,j]/max_prob\n", - "\n", - " # Determine top of band\n", - " if j < n_band - 1:\n", - " xs_top = urr.table[i,1,j] + 0.5*(urr.table[i,1,j+1] - urr.table[i,1,j])\n", - " else:\n", - " xs_top = urr.table[i,1,j] + 0.5*(urr.table[i,1,j] - urr.table[i,1,j-1])\n", - " \n", - " # Draw rectangle with appropriate color\n", - " ax.add_patch(Rectangle((e_left, xs_bottom), e_right - e_left, xs_top - xs_bottom,\n", - " color=cm(value)))\n", - "\n", - "# Overlay total cross section\n", - "ax.plot(gd157.energy['294K'], total.xs['294K'](gd157.energy['294K']), 'k')\n", - "\n", - "# Make plot pretty and labeled\n", - "ax.set_xlim(1.0, 1.0e5)\n", - "ax.set_ylim(1e-1, 1e4)\n", - "ax.set_xscale('log')\n", - "ax.set_yscale('log')\n", - "ax.set_xlabel('Energy (eV)')\n", - "ax.set_ylabel('Cross section(b)')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exporting HDF5 data\n", - "\n", - "If you have an instance `IncidentNeutron` that was created from ACE or HDF5 data, you can easily write it to disk using the `export_to_hdf5()` method. This can be used to convert ACE to HDF5 or to take an existing data set and actually modify cross sections." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "gd157.export_to_hdf5('gd157.h5', 'w')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With few exceptions, the HDF5 file encodes the same data as the ACE file." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gd157_reconstructed = openmc.data.IncidentNeutron.from_hdf5('gd157.h5')\n", - "np.all(gd157[16].xs['294K'].y == gd157_reconstructed[16].xs['294K'].y)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And one of the best parts of using HDF5 is that it is a widely used format with lots of third-party support. You can use `h5py`, for example, to inspect the data." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "reaction_002, (n,elastic)\n", - "reaction_016, (n,2n)\n", - "reaction_017, (n,3n)\n", - "reaction_022, (n,na)\n", - "reaction_024, (n,2na)\n", - "reaction_028, (n,np)\n", - "reaction_041, (n,2np)\n", - "reaction_051, (n,n1)\n", - "reaction_052, (n,n2)\n", - "reaction_053, (n,n3)\n" - ] - } - ], - "source": [ - "h5file = h5py.File('gd157.h5', 'r')\n", - "main_group = h5file['Gd157/reactions']\n", - "for name, obj in sorted(list(main_group.items()))[:10]:\n", - " if 'reaction_' in name:\n", - " print('{}, {}'.format(name, obj.attrs['label'].decode()))" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[,\n", - " ,\n", - " ]\n" - ] - } - ], - "source": [ - "n2n_group = main_group['reaction_016']\n", - "pprint(list(n2n_group.values()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "So we see that the hierarchy of data within the HDF5 mirrors the hierarchy of Python objects that we manipulated before." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.000000e+00, 3.026796e-13, 1.291101e-02, 6.511110e-02,\n", - " 3.926270e-01, 5.752268e-01, 6.969600e-01, 7.399378e-01,\n", - " 9.635450e-01, 1.142130e+00, 1.308020e+00, 1.463500e+00,\n", - " 1.557600e+00, 1.640550e+00, 1.688960e+00, 1.711400e+00,\n", - " 1.739450e+00, 1.782070e+00, 1.816650e+00, 1.845280e+00,\n", - " 1.865409e+00, 1.867240e+00, 1.881558e+00, 1.881560e+00,\n", - " 1.881800e+00, 1.894470e+00, 1.869570e+00, 1.821200e+00,\n", - " 1.716000e+00, 1.600540e+00, 1.431620e+00, 1.283460e+00,\n", - " 1.101660e+00, 1.065300e+00, 9.307300e-01, 8.029800e-01,\n", - " 7.777400e-01])" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "n2n_group['294K/xs'][()]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Working with ENDF files\n", - "\n", - "In addition to being able to load ACE and HDF5 data, we can also load ENDF data directly into an `IncidentNeutron` instance using the `from_endf()` factory method. Let's download the ENDF/B-VII.1 evaluation for $^{157}$Gd and load it in:" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Download ENDF file\n", - "url = 'https://t2.lanl.gov/nis/data/data/ENDFB-VII.1-neutron/Gd/157'\n", - "filename, headers = urllib.request.urlretrieve(url, 'gd157.endf')\n", - "\n", - "# Load into memory\n", - "gd157_endf = openmc.data.IncidentNeutron.from_endf(filename)\n", - "gd157_endf" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Just as before, we can get a reaction by indexing the object directly:" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "elastic = gd157_endf[2]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However, if we look at the cross section now, we see that it isn't represented as tabulated data anymore." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'0K': }" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "elastic.xs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you had [Cython](https://cython.org/) installed when you built/installed OpenMC, you should be able to evaluate resonant cross sections from ENDF data directly, i.e., OpenMC will reconstruct resonances behind the scenes for you." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "998.7871174521487" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "elastic.xs['0K'](0.0253)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When data is loaded from an ENDF file, there is also a special `resonances` attribute that contains resolved and unresolved resonance region data (from MF=2 in an ENDF file)." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[,\n", - " ]" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gd157_endf.resonances.ranges" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that $^{157}$Gd has a resolved resonance region represented in the Reich-Moore format as well as an unresolved resonance region. We can look at the min/max energy of each region by doing the following:" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[(1e-05, 306.6), (306.6, 54881.1)]" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[(r.energy_min, r.energy_max) for r in gd157_endf.resonances.ranges]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With knowledge of the energy bounds, let's create an array of energies over the entire resolved resonance range and plot the elastic scattering cross section." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Text(0, 0.5, 'Cross section (b)')" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Create log-spaced array of energies\n", - "resolved = gd157_endf.resonances.resolved\n", - "energies = np.logspace(np.log10(resolved.energy_min),\n", - " np.log10(resolved.energy_max), 1000)\n", - "\n", - "# Evaluate elastic scattering xs at energies\n", - "xs = elastic.xs['0K'](energies)\n", - "\n", - "# Plot cross section vs energies\n", - "plt.loglog(energies, xs)\n", - "plt.xlabel('Energy (eV)')\n", - "plt.ylabel('Cross section (b)')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Resonance ranges also have a useful `parameters` attribute that shows the energies and widths for resonances." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energyLJneutronWidthcaptureWidthfissionWidthAfissionWidthB
00.031402.00.0004740.10720.00.0
12.825002.00.0003450.09700.00.0
216.240001.00.0004000.09100.00.0
316.770002.00.0128000.08050.00.0
420.560002.00.0113600.08800.00.0
521.650002.00.0003760.11400.00.0
623.330001.00.0008130.12100.00.0
725.400002.00.0018400.08500.00.0
840.170001.00.0013070.11000.00.0
944.220002.00.0089600.09600.00.0
\n", - "
" - ], - "text/plain": [ - " energy L J neutronWidth captureWidth fissionWidthA fissionWidthB\n", - "0 0.0314 0 2.0 0.000474 0.1072 0.0 0.0\n", - "1 2.8250 0 2.0 0.000345 0.0970 0.0 0.0\n", - "2 16.2400 0 1.0 0.000400 0.0910 0.0 0.0\n", - "3 16.7700 0 2.0 0.012800 0.0805 0.0 0.0\n", - "4 20.5600 0 2.0 0.011360 0.0880 0.0 0.0\n", - "5 21.6500 0 2.0 0.000376 0.1140 0.0 0.0\n", - "6 23.3300 0 1.0 0.000813 0.1210 0.0 0.0\n", - "7 25.4000 0 2.0 0.001840 0.0850 0.0 0.0\n", - "8 40.1700 0 1.0 0.001307 0.1100 0.0 0.0\n", - "9 44.2200 0 2.0 0.008960 0.0960 0.0 0.0" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "resolved.parameters.head(10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Heavy-nuclide resonance scattering\n", - "\n", - "OpenMC has two methods for accounting for resonance upscattering in heavy nuclides, DBRC and RVS. These methods rely on 0 K elastic scattering data being present. If you have an existing ACE/HDF5 dataset and you need to add 0 K elastic scattering data to it, this can be done using the `IncidentNeutron.add_elastic_0K_from_endf()` method. Let's do this with our original `gd157` object that we instantiated from an ACE file." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "gd157.add_elastic_0K_from_endf('gd157.endf')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's check to make sure that we have both the room temperature elastic scattering cross section as well as a 0K cross section." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'294K': ,\n", - " '0K': }" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "gd157[2].xs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generating data from NJOY\n", - "\n", - "To run OpenMC in continuous-energy mode, you generally need to have ACE files already available that can be converted to OpenMC's native HDF5 format. If you don't already have suitable ACE files or need to generate new data, both the `IncidentNeutron` and `ThermalScattering` classes include `from_njoy()` methods that will run [NJOY](https://www.njoy21.io/) to generate ACE files and then read those files to create OpenMC class instances. The `from_njoy()` methods take as input the name of an ENDF file on disk. By default, it is assumed that you have an executable named `njoy` available on your path. This can be configured with the optional `njoy_exec` argument. Additionally, if you want to show the progress of NJOY as it is running, you can pass `stdout=True`.\n", - "\n", - "Let's use `IncidentNeutron.from_njoy()` to run NJOY to create data for $^2$H using an ENDF file. We'll specify that we want data specifically at 300, 400, and 500 K." - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " njoy 2016.49 25Jan19 07/19/19 06:12:49\n", - " *****************************************************************************\n", - "\n", - " reconr... 0.0s\n", - "\n", - " broadr... 0.1s\n", - " 300.0 deg 0.1s\n", - " 400.0 deg 0.2s\n", - " 500.0 deg 0.3s\n", - "\n", - " heatr... 0.3s\n", - "\n", - " gaspr... 0.6s\n", - "\n", - " purr... 0.7s\n", - "\n", - " mat = 128 0.7s\n", - "\n", - " ---message from purr---mat 128 has no resonance parameters\n", - " copy as is to nout\n", - "\n", - " acer... 0.7s\n", - "\n", - " acer... 1.0s\n", - "\n", - " acer... 1.1s\n", - " 1.2s\n", - " *****************************************************************************\n" - ] - } - ], - "source": [ - "# Download ENDF file\n", - "url = 'https://t2.lanl.gov/nis/data/data/ENDFB-VII.1-neutron/H/2'\n", - "filename, headers = urllib.request.urlretrieve(url, 'h2.endf')\n", - "\n", - "# Run NJOY to create deuterium data\n", - "h2 = openmc.data.IncidentNeutron.from_njoy('h2.endf', temperatures=[300., 400., 500.], stdout=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can use our `h2` object just as we did before." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'300K': ,\n", - " '400K': ,\n", - " '500K': ,\n", - " '0K': }" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "h2[2].xs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that 0 K elastic scattering data is automatically added when using `from_njoy()` so that resonance elastic scattering treatments can be used." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Windowed multipole\n", - "\n", - "OpenMC can also be used with an experimental format called windowed multipole. Windowed multipole allows for analytic on-the-fly Doppler broadening of the resolved resonance range. Windowed multipole data can be downloaded with the `openmc-get-multipole-data` script. This data can be used in the transport solver, but it can also be used directly in the Python API." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "url = 'https://github.com/mit-crpg/WMP_Library/releases/download/v1.1/092238.h5'\n", - "filename, headers = urllib.request.urlretrieve(url, '092238.h5')" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "u238_multipole = openmc.data.WindowedMultipole.from_hdf5('092238.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `WindowedMultipole` object can be called with energy and temperature values. Calling the object gives a tuple of 3 cross sections: elastic scattering, radiative capture, and fission." - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(array(9.13284265), array(0.50530278), array(2.9316765e-06))" - ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "u238_multipole(1.0, 294)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "An array can be passed for the energy argument." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "E = np.linspace(5, 25, 1000)\n", - "plt.semilogy(E, u238_multipole(E, 293.606)[1])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The real advantage to multipole is that it can be used to generate cross sections at any temperature. For example, this plot shows the Doppler broadening of the 6.67 eV resonance between 0 K and 900 K." - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAD8CAYAAAB5Pm/hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3Xd8VFXawPHfSScdUijpEAi99yqggisoCiqoqNgLdld513V3XevqrrpWRFexsCCChSYISJXeSwgQCJBQUgjpPXPeP27iAlImyZ2ZzOT5fj7+kZs7T54ryTNnnnvuOUprjRBCCNfl5ugEhBBC2JYUeiGEcHFS6IUQwsVJoRdCCBcnhV4IIVycFHohhHBxUuiFEMLFSaEXQggXJ4VeCCFcnIejEwAIDQ3VsbGxjk5DCCGcytatW7O01mGXO69eFPrY2Fi2bNni6DSEEMKpKKWOWnOetG6EEMLFObTQK6VGK6Wm5ebmOjINIYRwaQ4t9Frr+Vrr+4OCghyZhhBCuDRp3QghhIuTQi+EEC5OCr0QQrg4KfRCCOHipNALYWcWi+b77WnsTpPZZsI+pNALYWezNqfy5Dc7uenjdWQXljk6HdEASKEXws6+25YGQEm5hWWJ6Q7ORjQEUuiFsKOsglK2HjvDE1e2JiK4ET9LoRd2IE/GCmFHu9Jy0Br6twplYHwoW45mo7V2dFrCxcmTsULY0Z7jeSgF7VsE0jkqiJyictLOFDs6LeHipHUjhB3tPp5LXKgf/t4edI4IBmBnWo6DsxKuTgq9EHa093guHVsYn2DbNPPHTcGBU/kOzkq4Oin0QthJTlEZJ3JLaN8iEABvD3eim/hyKLPQwZkJVyeFXgg7qS7o8WH+vx2LD/cnOaPAUSmJBkIKvRB2kpJlFPqWYX6/HWsV5k9KViGVFpl5I2xHCr0QdnI4swAPN0VUE9/fjrUK96es0kJqdpEDMxOuTgq9EHaSklVIdBNfPN3/92fXqqqNcyhT2jfCdqTQC2EnhzMLz2nbwP/69VLohS1JoRfCDiwWTcrpQuJCzy30Qb6ehPp7yw1ZYVNS6IWwg+M5xZRVWGh51oybai3D/H67USuELUihF8IODlcV8vNH9AAtQ/04LHPphQ1JoRfCDlKqevDn9+irj50uLCO3qNzeaYkGwiaFXinlp5TaopQaZYv4Qjibw1mFBHh7EObv/bvvxYX6V50jfXphG1YVeqXUZ0qpDKXUnvOOj1RK7VdKJSulppz1reeA2WYmKoQzS8kqJC7MD6XU775XPcqXPr2wFWtH9NOBkWcfUEq5Ax8A1wDtgQlKqfZKqauARCDDxDyFcGqHM38/46ZaVGNf3N2U9OmFzXhYc5LWerVSKva8w72BZK31YQCl1CzgesAf8MMo/sVKqUVaa4tpGQvhZErKKzmRW0xcaOQFv+/l4UZ0E18Z0QubsarQX0QEkHrW12lAH631ZACl1F1A1sWKvFLqfuB+gOjo6DqkIUT9dvR0EVpzwamV1eJC/eShKWEzNpt1o7WerrVecInvT9Na99Ra9wwLC7NVGkI4XErVTdaWF2ndVH/vyOlCLLK4mbCBuhT640DUWV9HVh0TQpyleg597CUKfVyYHyXlFk7mldgrLdGA1KXQbwZaK6XilFJewHhgXk0CyObgoiFIySwkPMAbf++Ld0pbVk2xTJEbssIGrJ1eORNYDyQopdKUUvdorSuAycASYB8wW2u9tyY/XDYHFw3B4ayLz7ipVj3FUubSC1uwdtbNhIscXwQsMjUjIVxMSlYhIzo0veQ54QHe+Hm5yxRLYRMOXQJBWjfC1eUUlZFdWPZba+ZilFLEhfn91s8XwkwOLfTSuhGuLuUSi5mdr2Wo/28zdIQwkyxqJoQN/VboL7CY2fniQv1IO1NMSXmlrdMSDYy0boSwoZSsQtzdFFGNfS97bsswP7SGY7J/rDCZtG6EsKHDmYVENm6El8fl/9Sq+/iH5QlZYTJp3QhhQ8kZBbQOv/SN2GqxocaoX27ICrNJoRfCRsorLRzOKiA+PMCq8wN8PAkP8JYplsJ00qMXwkaOni6kvFLTpql1I3owbsjKKpbCbNKjF8JGDqQbvfY2Ta0b0YOxwqX06IXZpHUjhI0cSM9HKWh1ieWJzxcf7s+ZonIy80ttmJloaKTQC2EjBzMKiGrsSyMvd6tf066ZMfrffyrfVmmJBkgKvRA2cjA9v0b9eYCEqkKfdCrPFimJBkpuxgphA+WVFlKyCmldg/48QIi/N2EB3iTJiF6YSG7GCmEDR7JqPuOmWttmATKiF6aqy56xQoiL2Fc1Ik8I8YT9iyF1I5zYBjmpUJABlaXg7gU+wdAkDsLbQexAiB1E22YBfLn+KBWVFjzcpbsq6k4KvRBm05rc/at4z+tL2n29C8oKwM0DwttD8y7g3xQ8vKGyDIpOQ3YKbJ8Bm6aBcufusIGkWrpxJLMf8c2CHX01wgVIoRfCTMnL4JdXmHhiG3nuAahON0H76yC6H3g2uvjrKsvhxHZIWkjo9plM9VpF4Vffw5XPQufx4C5/qqL25HOhEGbISoavx8LXY9FFp3lN3cfrbefC6Heg1bBLF3kAd0+I6g1XvUjl43t4qPwpCvCBHx+BaVfAsQ12uQzhmmTWjRB1YbHAhqkwdSCkboarXyHjjjV8XDyUNpHhtQrp4+3FwZAr+HP4B3DTF1B8Bj4bAQufgfJiky9ANAQy60aI2irKhv/eBIufg7jB8MhG6D+ZxAzjqdb2LWr/e92ueSCJJ/OhwxiYvAn6PgybP4FpQyFjn1lXIBoIad0IURvpe+GToXB4FVz7Ftz6DQQ2ByDxpDE1sl3zms2hP1vniCCO5xSTVVAKXn4w8jW4/TsozoZPrzRm8ghhJSn0QtTUoRXw6VVGG+WuhdDrHlDqt2/vPZFLTIgvAT6etf4RnSONTwO7085qa8YPh/tXQkg8zBwP694DrWv9M0TDIYVeiJrYNx/+ezM0jjGKbnSf352yMzWXjnVo2wB0iAhCKdiZlnPuNwJbwKSfoN1o+PnPsPzvUuzFZUmhF8Jau76F2XcYc+HvWmgU3fNk5pdyPKeYbtF1m//u7+1BfJg/u9IuMFHBy9e4SdvjLlj7Fiz+Pyn24pJkcq4Q1khaCN8/ADEDjH68l98FT9uRaozAu0bV/UGnzpHBrDqQidYadVZrCAA3Nxj1Dnj4wMaPjGMjXzunhSRENZleKcTlHFoB394FEd1hwqyLFnmAHaln8HBTdIyo+0yyzpFBZBWUcjK35MInKAUjX4c+DxnFfs0/6/wzhWuS6ZVCXMqp3TDrNghtA7d9C96XXqRsR2oObZsH4ONp/Rr0F1N9Q3bX+X36sykFI16FzrfALy/Dls/q/HOF65EevRAXk58O/x0PjYLh9rnQqPElT6+0aHam5prStgFjLr2Hm2Lnhfr0Z3Nzg+s/gNYjYOHTkLzclJ8vXIcUeiEupLwYZt1qzFufMBMCml32JYcyCygoraBr1KXfEKzl4+lO+xaBbD925vInu3vCuM8grB3MmWQsySBEFSn0QpxPa5j/BBzfCjd+YsyyscKOY0aLpa4zbs7WM6YJ24/lUFZhufzJ3v7Gm5KbhzHPvvgSLR/RoEihF+J8276AXbPgiv+DdqOsf9mxMwT6eBAXcvGbtTXVK7YxpRUW9pywcsJC4xi4+Ss4k2LMEpJplwIp9EKc69RuWPQstBwKg5+p0Us3pmTTK7YJbm7mTXHsGdsEgM0p2da/KHYAjHgNDiyG9e+blotwXlLohahWkgez7wTfJkbLxs36mTMZeSWkZBXSt2WIqSmFBXgTF+rH5iNW9OnP1vs+4+nZZX8zVtUUDZoUeiGqLZ5itDzG/gf8w2r00g1VI+4+LZuYnlbPmMZsOZqNxVKDNoxScN37xtO7c+42ljoWDZYUeiEAkhbBjhkw8Cmj9VFDGw+fxt/bg/bNA01PrVdcE3KKyjmUWVCzFzYKhnHTIf8ELPqj6XkJ5yGFXojC0zD/cWjaCYY8V6sQG1Oy6Rnb2Cabefeq6tNvOlKDPn21yB4w+FnY/S0kzjM5M+EsZAkE0bBpDQufNFobN0wFD68ah8gqKCU5o4A+ceb256vFhvjSLNCHdYdO1y7AoKegeVdY8CQUZJqbnHAKsgSCaNj2zIXEH2Hon6BZx1qF2HjYdv15AKUUA+JDWZecVbM+fTV3T+NNrDTPeFOTKZcNjrRuRMNVfMa4AduiOwx4vNZh1iZn4u/tQScTFjK7mIGtQzhTVP7b7lU1Ft7OeDPbN994cxMNihR60XAtexGKTsPod2o0lfJsWmtWH8hiQHwInjboz1cbEB8KwJqDWbUP0v8x401t8RSZhdPASKEXDVPqJtj6ubHEr5VLHFzIocwCjucUM7hNzaZj1lR4gA8JTQP4NbkOhd7N3XhTKzptvMmJBkMKvWh4KsuNWTaBkUY7ow5WHTAK7+DWti30AANbh7LpSDYl5ZW1D9K8i/HmtvVzOLbRvOREvSaFXjQ86z+AjET4wxuXXV/+clYfyKRlmB9RTXxNSu7iBrYOpazCwqaaLIdwIUP/ZLzJLXjCeNMTLk8KvWhY8k7Cqjcg4Q/Q9to6hSopr2TD4dMMsXHbplrfuBB8PN34JSmjboG8/Y03uYxE2PChOcmJek0KvWhYlr8IlnJjV6Y62nD4NKUVFpv356s18nJnYHwoSxPT0XWdItn2WmOjklVvGhusCJcmhV40HGlbYedM6PswNImrc7gle9Px83Knn8kLmV3Kle2acjynmP3p+XUPNuJVqCiBX/5e91iiXpNCLxoGrY1phX7hMOjpOoezWDRLE9O5IiHclP1hrTWsXTgAyxJNGIWHxkPfB2H7DDi+re7xRL0lhV40DHvmQtomGP4C+NR94bHtqWfIKijl6g5NTUjOeuEBPnSJCmbpvjr26asN/iP4hRpvgvLErMuSQi9cX1kRLP0rNOsMXW8zJeTPe9PxdFcMbRtuSryauKpdODtTc8jIL6l7MJ8gGPYCpG6UJ2ZdmBR64fo2fQx5aTDytVo/AXs2rTVL9p6iX6tQAn08TUiwZq5sb3yKWJZo0qi+2+3Gm+DSvxqboguXY3qhV0q1U0pNVUrNUUo9ZHZ8IWqk+AysfduYYRI70JSQBzMKOHK6iBF2bttUS2gaQGyIL4t2nzQnoJs7jHjFeDPc9Ik5MUW9YlWhV0p9ppTKUErtOe/4SKXUfqVUslJqCoDWep/W+kHgZqDmOzgIYaa1bxtbBA7/i2khF+w6iVJwVTvHFHqlFKO7tGDdoSwy80vNCRo3GOKvhDX/knVwXJC1I/rpwMizDyil3IEPgGuA9sAEpVT7qu9dBywEFpmWqRA1lXscNn4MnW+u9RLE59NaM2/Hcfq3CiE80MeUmLUxqnMLLBoW7zFpVA9w5d+gJBfWvmNeTFEvWFXotdargfOfu+4NJGutD2uty4BZwPVV58/TWl8DmHPnS4jaWPU6WCrrvJ7N2Xam5XLkdBHXd4kwLWZtJDQLoE1Tf+bvNLHQN+tkvClunGq8SQqXUZcefQSQetbXaUCEUuoKpdS7SqmPucSIXil1v1Jqi1JqS2am7HojTJZ5ALZ/Db3ugcaxpoX9YftxvDzcGNmpmWkxa2tU5xZsPprNyVwTb6AOfR60BVa+Zl5M4XCm34zVWq/UWj+mtX5Aa/3BJc6bprXuqbXuGRZmn0fIRQPyy0vg6QuDnjEtZEWlhQW7TjIsIdwhs23ON6pzc2MnxF0mjuobx0Cv+4yN0jOSzIsrHKouhf44EHXW15FVx6wme8YKmzixA/bNg36Twd+8QcS6Q6fJKihlTLcWpsWsi5Zh/nSODGLO1rS6r31ztkFPg5c/LJelEVxFXQr9ZqC1UipOKeUFjAdqtM287BkrbGLVG8aDQP0eNjXsnK1pBPp4cEWC/R+SupibekaRdCqfvSdqucXghfiFGLtR7V8Ix7eaF1c4jLXTK2cC64EEpVSaUuoerXUFMBlYAuwDZmut99ouVSGscHKXUaD6PmwUe5OcKSxj8Z5T3NAtwq5r21zOdZ1b4OXhxrdbUi9/ck30eQAaNYYV0qt3BdbOupmgtW6utfbUWkdqrf9TdXyR1rqN1rqV1vqVmv5wad0I061+E7wDjUJlou+3H6es0sL43tGmxq2rIF9PRnZoxg87TtRt56nz+QQaG6YnLzW2XRROzaFLIEjrRpgqPdHozVePRk2itWbW5mN0iQqmXfO6L4hmtpt6RpJbXM6yfSavK9/rPvANhRU1HsOJekbWuhGuY/Wbxk3Evub25ren5nAgvYDxvaIuf7ID9G8VSkRwI2ZtMrl94+0PA5+EwyvhyK/mxhZ2JYVeuIbM/bD3e+h9H/g2MTX0fzcew9fLndFd6sdsm/O5uykm9I5ibXIWyRkF5gbveTf4N4UVr8oyxk7MoYVeevTCNKv/CZ6NjCmVJsoqKGXejhOM7R6Jv7eHqbHNNL53NF7ubny1/oi5gb18jemWR9dCympzYwu7kR69cH5ZybBnjvEUrF+oqaFnbDhGWaWFuwbEmhrXbKH+3ozq3Jw5W9PILyk3N3j3OyEwwujVy6jeKUnrRji/Nf8Cdy9j7reJSisq+WrDUYYmhNEqzN/U2LZwZ/9YCssq+W6byevUePoYo/rUjXBoubmxhV1IoRfOLfsw7Pqmqpds7oNMC3aeJKuglEkD6r6RuD10iQqmS1QwX6w/gsVi8si720QIijLm1cuo3ulIj144tzVvgZuH6aN5rTWfr0shPtyfQa3NbQfZ0qT+sRzOLGTFfpN2n6rm4WWM6o9vgWQZ1Tsb6dEL53XmKOycCT3uhMDmpob+Nfk0e47ncfeAOJRSpsa2pWs7NyciuBFTVx0yP3jX2yAoGlbKDBxnI60b4bzWvg3KDQY8YXro91ccpGmgN2N7OHbd+ZrydHfjvkFxbD5yhs1Hzt9Coo48vGDw08b6N8nLzI0tbEoKvXBOuWnGevPdbocgc4vxliPZbDiczf2DW+HtUX/WtbHWLb2iaeLnxdSVNhjVd7kVgqNlXr2TkUIvnNPadwBtPLlpsvdXJNPEz4sJvevnk7CX08jLnbv6x7I8KYOkUyauaglVvfpn4MQ2OLjU3NjCZuRmrHA+eSdg2xfQtWp0aaI9x3NZuT+TewbG4etVfx+Qupw7+sXg6+XO+78kmx+8+v+79OqdhtyMFc7n138be8EOfMr00G8vPUCgjwcT+8WYHtuegn29mDQglgW7TrLvpMmjendPGPxHOLEdDv5sbmxhE9K6Ec4l/xRsnQ5dxkMTc+e3bz6SzfKkDB66Ir5ebBVYV/cPakWAjwdvLT1gfvAuEyA4xthbVkb19Z4UeuFc1r0HlWXGnG4Taa35x09JhAd4c1f/WFNjO0qQryf3D2rJ0sR0dqTmmBv87FH9gSXmxhamk0IvnEdBJmz+D3S6GUJamRr6l6QMthw9w+NXtqaRl/PNtLmYSQPjaOLnxb9+3m9+8C7joXGsjOqdgNyMFc5j/XtQUQKDnzE1bKVF88bi/cSG+HJzT+ecaXMx/t4ePDSkFWsOZrH+0Glzg1eP6k/ugAOLzY0tTCU3Y4VzKDwNmz6FjmMhtLWpoeduTWN/ej5PX52Ap7vrfcid2C+GiOBGvLwwkUqz18DpPB4ax8movp5zvd9q4Zo2fADlRaaP5vNKynljSRLdo4MZ1dncZRTqCx9Pd567pi17T+Qxd2uaucHdPapG9Tth/0/mxhamkUIv6r+ibNg4DdpfD+HtTA397rKDnC4s48XrOjrVmjY1Nbpzc7pHB/PGkv0UlFaYG7zzLTKqr+ek0Iv6b8NHUJZvjBxNlJyRz/R1R7ilZxSdIl27faiU4oVR7ckqKOXDFSY/ROXuAUOehVO7YP8ic2MLU0ihF/Vb8RnYOBXajYZmHU0Lq7XmxfmJNPJy55kRCabFrc+6RTfmhm4RfLo2hZSsQnODd7oZmrSUUX09JYVe1G8bPoLSPBjynKlh5+08wZqDWTx5ZRtC/b1NjV2fTbmmLd7ubrzwwx60mQXZ3QMGPwundkPSQvPiClNIoRf1V3EObJgKbUdBs06mhT1TWMbf5yfSJTKIO13k4ShrNQ304dmRCaxNzuLHHSfMDd7pJmjSCla+DhaLubFFncg8elF/bZwKpbmmj+ZfXriP3OJyXh/bGXc3170BezG39omhS1QwLy1IJKeozLzA1b369N2wX0b19YnMoxf1U3EOrP/QGM0372xa2LUHs5i7LY0HhrSkXfNA0+I6E3c3xas3dCSnuJx/LE4yN3jHcRASL6P6ekZaN6J+2vhx1Wj+WdNCFpZW8Kfvd9My1I9Hh5n70JWz6dAiiHsGxjFzUyrrkrPMC1zdq0/fA0kLzIsr6kQKvah/SnKNB6QSroXmXUwL+/LCRFLPFPH62M74eLrOeja19eSVbWgZ6scf5+wir6TcvMCdZFRf30ihF/XPxo+NYn+Feb35pYnpzNyUygODW9E7rolpcZ1ZIy93/nlzF07mFvPygkTzAru5G/dVMvZC0nzz4opak0Iv6pfiM7D+fUj4g2mj+cz8UqbM3UX75oE8dVUbU2K6iu7RjXnoilbM3pLGssR08wJ3HAshrWVUX09IoRf1y6/vQkkeDH3elHBaa6bM3UV+aQXvjO+Kl4f8yp/vseGtadssgCnf7eZ0Qak5QX8b1SfCvnnmxBS1Jr/1ov7IP2VMqew0zrSnYP+zNoXlSRlMGdmWNk0DTInparw93Hn7lq7klZTz1OydWMxa4bLjjRDaBlb9Q0b1DiaFXtQfq980do8a+idTwm09eobXf0ri6vZNmTQg1pSYrqpd80D+Mqo9qw5kMm3NYXOCnjOq/9GcmKJWpNCL+iE7xdgLtvsdxpopdQ1XWMbk/26jebAPb97UxaVXpjTLbX2iubZTc95csp+tR7PNCdrhBghNgJUyqnckeTJW1A8rXwM3T2MOdh1ZLJonv9nB6YIyPry1B0GNnH+jb3tQSvHa2E60CPbhsZk7zHlq1s3deBYicx8k/lD3eKJW5MlY4Xjpe2HXbOhzPwTWffOPfy8/yKoDmfxldHuXX37YbIE+nrw/oTsZ+SU8PmuHOTtSdbgBwtoaM3AqTV4LX1hFWjfC8Zb+FbwDYcATdQ61YNcJ/r38IGO7R3Jbn2gTkmt4ukQF87frOrDqQCb/NGNTcTd3GPZnyNoP27+sezxRY1LohWMlL4PkpTDkj+BbtweZdqfl8sy3O+kR05hXb3TtHaNs7bY+MUzoHc1HKw+xYJcJq1y2HQUxA+CXV4zps8KupNALx6msgCXPG9vQ9b6/TqEy8kq478sthPh5M/X2Hnh7yBIHdfXidR3oGdOYP367i8QTdSzOSsGIV6AoC9a+ZU6CwmpS6IXjbP0cMpPg6pfAo/abfxSXVXLfV1vJLS7nkzt6EhbQcDYSsSUvDzc+vL07QY08ue/LLWTkl9QtYItu0GWCsSrpmaPmJCmsIoVeOEZxDqx4FWIHGR/ra6mi0sKjM7exKy2Hd8Z3pX2Lhrn0sK2EB/jwyR09yS4s4+7pmyms68biw14A5QbLXzQnQWEVKfTCMVa9YaxrM+JV42N9LWit+fMPe1i2L4O/X9eBER2amZykAOgUGcQHt3Uj8UQej87cTkVlHebDB0XAgMdgz1w4tsG8JMUlSaEX9ndyl7HUQY8767SpyNvLDjJrcyqTh8YzsV+sefmJ3xnWtikvjenIL0kZ/HXe3rrtNzvgcQiMhIVPy3RLO5FCL+zLYoEFT0KjxnDl32od5qsNR3l3+UFu7hnJ01fLipT2cFufGB4c0ooZG4/xwYrk2gfy8oNrXjc2J9k0zbwExUVJoRf2tW06HN9itGwaNa5ViG+3pPLCD3sY3jacV2/oJNMo7ejZEQnc0C2Cf/58gC/WHal9oLajoPXVsOIVyDN5k3LxO1Lohf0UZMCyvxk3YDvfXKsQP+44zrNzdzGodSgf3NYdD3f5FbYnNzfFm+M6c3X7pvx13l7mbE2rXSCl4Jo3wFIBS8xZxE5cnPyVCPtZPAXKiuDat2p1A3bR7pM8NXsnfeNCmDaxp2wH6CAe7m68d2s3BrUO5dk5O/lp98naBWoSB4Oegb3fw8Gl5iYpziGFXtjH3h+MmRZDnoWwmvfUl+w9xWMzt9M9OphP7+xJIy8p8o7k7eHOxxN70C26MY/N2s4vSbXcnWrAY8Y6OPMfN7aPFDZhk0KvlBqjlPpEKfWNUupqW/wM4UQKMmHhU8YDMwOfrPHLf9xxnIdnbKNTZBCf3dULP28PGyQpasrXy4PP7upF22aBPPDVVn7ee6rmQTy8YcyHxqYz0sKxGasLvVLqM6VUhlJqz3nHRyql9iulkpVSUwC01j9ore8DHgRuMTdl4VS0hgVPQGkBjJkK7jVbMnjWpmM88c0OesY05qt7+hDgI0sO1ydBjTz5+t4+dGgRxMMztrGoNm2ciB7GlMvtX0sLx0ZqMqKfDow8+4BSyh34ALgGaA9MUEq1P+uUP1d9XzRUO2dC0gJj9cLwtjV66adrDjPlu90MaRPG9Em98ZeRfL0U1MiTr+7pTZeoYB6duZ0fdxyveZArphgtnHmPGU9NC1NZXei11quB87ed6Q0ka60Pa63LgFnA9crwD+AnrfU289IVTiVzv/FQTOwg6PeI1S/TWvPvZQd5eeE+runYjGkTpSdf3wX4ePLl3b3pEdOYJ7/ZUfPZONUtnIJ04zmLujyQJX6nrj36CCD1rK/Tqo49ClwJjFNKPXihFyql7ldKbVFKbcnMzKxjGqLeKS+Gb+8CT1+48RNjTXIrVFRa+NP3e3h72QHGdo/kvQnd8PKQOQPOwM/bg+mTetG/VSjPfLuTaasP1SxARA8Y9jzs/Q62f2WbJBsom/wFaa3f1Vr30Fo/qLWeepFzpmmte2qte4aFhdkiDeFIi6cYm0Lf+LHVu0YVllZw35dbmLnpGI8MbcWb4zrLPHkn4+vlwX/u6sm1nZrz6qIkXlmYiKUmu1QNeBLihsCiZyEjyXaJNjB1/Ss6DkSd9XVk1THRkG370tjoe+BTEH+lVS/JyC/hlmnrWX0wi1dv6MQfR7TFzU2eeHWwGgScAAAWv0lEQVRG3h7uvDuhG3f0i+GTNSk8/e1Oyq1dCM3NDW6cZiyTMGcSlBXaNtkGoq6FfjPQWikVp5TyAsYD86x9sWwO7oKOrocFT0GrYTD0eatecjA9nxs+WMfhzEI+vaMnt8oWgE7P3U3x4nUdeObqNny//Th3T99MXkm5dS8OaGZ8EszYBz9Oln69CWoyvXImsB5IUEqlKaXu0VpXAJOBJcA+YLbWeq+1MWVzcBeTcwy+uR0ax8C4z8D98rNkliWmc8OH6yirtPDN/f0Y2jbcDokKe1BKMXlYa/4xthPrDp1m3EfrSM0usu7F8VfC8L8Y/fpf/23bRBsAVaflRk3Ss2dPvWXLFkenIeqiOAemXws5qXDfcghtfcnTtda8/0syby07QKeIID6e2IPmQY3slKywt1+Ts3jo6614uLsxbWIPesZasT+w1kb7Zu8PcNscaG1dG7AhUUpt1Vr3vNx5Dr3TJa0bF1FeDLNuNaZT3vT5ZYt8YWkFD8/Yxr+WHmBM1whmP9BPiryLGxAfyvePDCCokSe3frKR77ZZMf1SKbj+A2ja0Sj4p/Zc/jXighxa6KV14wIqK2DOPXB0HdwwFeKHX/L0o6cLGfvROpbsPcWfr23HWzd3kcXJGohWYf58/3B/esQ05qnZO3lt0b7L71bl5Qe3zgIvf5gxzvjEKGpM5q6J2rNYjMWo9i+Ea/4BncZd8vRFu08y6t21nMgpZvqk3tw7qKWsJd/ABPt68cXdvbmtTzQfrz7MHZ9tIqug9NIvCoqE2+cYK59+PRaKzn9uU1yOtG5E7VgsMP8x2PE1DHkO+jxw0VNLKyr56497eHjGNlqG+7PwsUEMbiPPTjRUXh5uvHJDJ94c15mtR88w+r21bD925tIvatoBxs+AMykwc4KxdpKwmrRuRM1ZKmHeZOPpxcHPwhX/d9FTj54uZNxH6/li/VHuHRjHtw/0I6qJrx2TFfXVTT2jmPtQfzzcFbd8vIEZG49eei/auEHGU9Zpm+G/t8gc+xqQ1o2omcpy+OEh2DHDKPDDnr/oJiILdp1g1LtrOXq6kGkTe/DnUe1lOQNxjo4RQcyfPJD+8SE8//0envhmB/mXmm/fYYzxQNWxdVXF3srpmg2c/NUJ65UWwMzxsOsbYzXKK6Zc8LTc4nKe/GYHk/+7nVZVrZqrOzSzc7LCWQT7evHZnb14+qo2LNh1kmvfXcuO1EusYNlpHNzwMRz9FWbeIm0cKzh0Hr1SajQwOj4+/r6DBw86LA9hhYIMmHETnNoNo96GHnde8LR1h7J4ZvZO0vNLeWxYax4Z2krWqxFW23Ikm8dn7SA9r4RnRiRw/6CWF18KY+c3xqfL5l2MefZ+IfZNth6wdh69PDAlLi9zP/z3ZqPY3zQd2oz43Skl5ZX8c8l+Pl2bQstQP96+pStdooLtn6twerlF5fzf97tYtPsUA+NDeevmLoQH+lz45P0/GaukBkXBxO8hOOrC57koKfTCHEmL4Lv7wdMHJnwDkT1+d8qO1ByenbOTA+kFTOwbw5/+0E7Wjxd1orVm1uZUXpy/Fx9Pd166viOju7S48MlH1xv9ei8/uO1baNbRvsk6kFM8GSvqMYsFVr0BsyZASCu4f+XvinxRWQUvLUjkxg9/Ja+4gs8n9eKlMR2lyIs6U0oxoXc0Cx4dRGyIH4/O3M4jM7aRXVj2+5Nj+sGkRYCG/1wN+xbYPd/6Tkb04veKzxirBiYtgM7jYfQ74HnuEgVrD2bxf9/vIjW7mNv6RPPcNW0JlP1chQ1UVFr4ePVh3ll2gKBGnrx6Q6cL39zPO2ksxXFiGwx7AQY9fdEZYa7CKVo3cjO2Hjq2AebeC/kn4aqXoO9D5/yx5BaV8/LCRL7dmkZcqB+v3diJvi0b3k0wYX/7Tubx9OydJJ7M48ZuEbwwqj2N/bzOPam8GOY9Cru/hY5jYfS74O3vmITtwCkKfTUZ0dcDlkpY+zaseNW4oTX2s3NaNRaL5rvtx3n9p32cKSrn/sEteXx4a1mnRthVWYWF91ck8+GKZAIbefKXUe25vmuLc5fS0BrWvgW/vAwh8XDTF9C0veOStiEp9MJ6Ocfgh4fhyBpjFDTqbfD539PKiSfy+MuPe9hy9AzdooN56fqOdIyQp5mF4ySdymPK3N3sSM1hUOtQXhnTieiQ8564PrzK+HRamg/X/hO63e6YZG1ICr24PK1h6+fw8wvG1yNfN/4YqkZHucXlvL30AF+uP0KwrxdTrmnLuO6RssWfqBcqLZoZG4/yxuL9VFgsPD68DfcOisPz7Oc28tPhu3shZbVxv+kPb5wziHF2UujFpeUcM3qZh1camzFf/z4EG1v4WSyaudvS+MfiJLILy7i9bwxPX5VAkK/cbBX1z8ncYv42by9L9qbTtlkAf7uuw7n3jSyVsPpNWPUPCIyAMR9C3GDHJWwiKfTiwiyVsOUzWPYiaAtc/RL0vPu3Ufy6Q1m8snAfe0/k0T06mL9Lm0Y4iSV7T/H3+YkczylmdJcW/OkPbc/d0CZ1M3z/AGQfgr6PwPAXfjebzNk4RaGXWTd2dnwbLHwKTmw3RvHXvQuNYwFIzijg9Z/2sWxfBhHBjXh2ZAKjO7eQNo1wKsVllUxddYipqw7hphSTh8Vz76A4vD2qJg2UFcLSv8LmTyA0wfgkG9XbsUnXgVMU+moyorex4hxjBsLmT8E/HEa8atx0VYrTBaX8e/lBZmw8hq+nOw8PjWfSgFiZTSOcWmp2Ea8s3MfivaeICfHlhWvbM7xd+P9m5yQvh3mPQd5x6HWPsRG5E/bupdAL4+nW3bONm61FWdDrXmPVSZ8gCkor+HxtCtNWH6aovJJbe0fzxJWtCfH3dnTWQphmzcFMXpyfSHJGAf1ahvCnP7SjU2RVQS8tMAZAG6dCQDP4wz+h3SjHJlxDUugbuqPrYMmfjDZNi+4w6i1o0Y2S8kq+3nCUD1ceIruwjCvbNWXKNQnEhwc4OmMhbKK80sLMTcd4Z9lBsgvLuL5rC565OuF/G+CkbTV2S0vfA21HGZ94G8c4NmkrSaFvqLJTYOlfYN88CGgBV/4VOt1MuYbZW1J5b3kyp/JKGBgfytNXt6FbdGNHZyyEXeSXlDN11SE+XZOC1nBn/xgmD21tzCarLIf17xvrO2kLDHgCBjwOXvV7NzQp9A1NcQ6s+Sds/BjcPIxf1P6TqXBvxLydJ3hn2UGOZRfRPTqYZ0Yk0L9VqKMzFsIhTuYW89bPB5izLY1AH08evqIVd/SLNRbjy00zBkp75hpLH1/9ErQfU2/XzJFC31CUFhg9xnXvQkkedL0Vhr1AmW9Tvt+exocrD3H0dBHtmwfyzIg2DE0IP/dxcSEaqH0n83j9pyRWHcgkLMCbh69oxYTe0cZEhCO/wk/PQfpuiB0EI1+DZp0cnfLvOEWhl+mVdVBeYsyHX/sWFGZCm5Ew9HlKQjswe0sqU1ce4kRuCZ0igpg8LJ6r2jWVqZJCXMDmI9n86+f9bDicTfMgHyYPi+emHlF4uWnYOt24YVt8BjrfDEOfr1f9e6co9NVkRF8DleXGxtyr3jCmhsUNhmF/oahpN/678Rgfrz5MZn4pPWIa8+iweIa0CZMRvBBWWJecxb+WHmDr0TNENm7EY8Nbc2O3CDzK8uDXd2DDR0b/vtd9MPgZ8G3i6JSl0LucilLYOdNYYfLMEYjsBcNe4HR4X77acJQv1h3hTFE5/VuFMHlYPP1ahkiBF6KGtNasOpDJW0sPsCstl5gQXx4c0oobu0fgXXgKVr5mDLS8/GHgE9DnIYfesJVC7yrKimDbF/Dru5B/wpgqOeQ5DjUewH9+PcLcrWmUVlgY1jacR4a2okeM40cZQjg7rTXL9mXw/i8H2ZmWS7NAH+4b3JIJvaPwzTkIy/8O+xeBX7hR8HtMckjBl0Lv7EryjMe0139oPOwUMxA96Gk2u3Vh2poUliel4+nuxtjuEdwzME7mwQthA1pr1iZn8f4vyWxMyaaJnxd3D4hlYr9YgjK3Gvs3pKwC/6bGTLeek+y6fo4UemeVnw6bphlFviQX4q+iYsCTLM6P45M1KexMzaGxrycT+8YwsV8sYQHyJKsQ9rDlSDYfrEhmxf5MArw9uL1fDJP6xxKevRVWvW4shezfFAY+CT3uskvBl0LvbE7tgQ0fGlugVZZDu1Fk93iUr482YcbGo6TnlRIb4ss9g1oyrnukbMAthIPsOZ7LhyuT+WnPKTzcFNd1ieDeQXG0K91t9PCPrAH/ZtDvEaPg+wTaLBcp9M5Aa2NxpfXvGevCe/qiu97G3ujb+GQvLNp9kvJKzeA2YdzZL4YrEsJxlymSQtQLR7IK+fzXFGZvSaO4vJKB8aHcOyiOIV77UavfNFo63kHQ+17o86CxoKDJpNDXZ2VFxsh9w4eQmQQBzSnveR8LPUbw6bYz7DmeR4CPBzf1iOL2vtG0DHPdzY2FcHY5RWXM2HiML9YdISO/lNbh/tw7KI4x4Rl4b3wXEueBuxd0uw36PwpNWpr2s6XQ10dZycZDTju+NvrvzTpxssO9/Ce7G3N2ppNTVE5C0wDu6B/DmK4R+Hl7ODpjIYSVyioszN95gk/WHCbpVD4hfl7c0iuKOxMqaLp7mjE92lJhLKnQ/1GI6F7nnymFvr6orIADi4214A+vADcPKhJGsyboOt49FM721Fw83RVXd2jGxL4x9IlrIvPfhXBiWmvWHTrN578e4ZekdACubNeUe7r60vvULNSWz6AsH6L7Q7+HIeEP4Fa7e25OUehdegmE/HTY9qWx+XbecXRgJKdaj+ezokHMTCyloLSC+HB/xveK4sbukTTx83J0xkIIk6WdKWLGxmN8szmV7MIyWob5cXfPEMapFfhs/QRyj8HI16HvQ7WK7xSFvprLjOgrKyB5GWz/yhjFWyooj72CNcFj+NeROPaeKsTH041RnVswvlcUPWIay+hdiAagpLySRbtP8uX6o+xIzcHXy50buzblgfAkorqPqPVyCtYWemkCmyEr2ei775gJBafQfmEcib+DT4uHMPugF+WVmo4R7rw8piPXdW1BoI+nozMWQtiRj6c7N3aP5MbukexOy+XL9Uf4dtsJvq4I5GWPfG7va9sn2mVEX1tlhZD4I2z7Co6tQyt3ciOHssB9OG8fieV0iSYswJsxXVtwQ7dI2rew3VxaIYTzySkqY+6244zs2IyI4No9XCUjeluwWODoWtj1Dez9EcryKQ9uxcbYybyV3p1tB33w8XRjRIdm3Ng9kgGtQvBwd3N01kKIeijY14t7BsbZ5WdJobfGqT1Gcd8zF/KOY/H0Izl0OF8UD2TGqQhUuqJfyxDeHB7BNZ2a4y/TIoUQ9YhUpIvJTYPdc2DXbMjYi3bz4HhIf+YE38HH6W0ozvemXfNA/jiiOWO6RdT6o5cQQtiaFPqzFZ6GpPlGgT+yFtBkBXdhQfBk3kvvyOnUQOLD/XlgeHNGdW5BfLg8sSqEqP+k0FcX970/GKvP6Ury/WJYFjSR9zK7c/hUOLEhvky4ogWjujQnoWmATIkUQjiVhlnoL1Dc83yj+cVvHJ+e6cqe09FEBPsyaqAxcu8YESjFXQjhtBpOoS/MgqQF5xT3nEZRLPUZy+c5XUksiaF1eAAjBjfjtQ7NpLgLIVyGaxf604eM7b6SFqFTN6C0hWyfKH7yvJEZ+d1ILImhS2Qwo/o0470OzWglq0QKIVyQaxV6iwVObIf9CyFpEWTuA+CETzyL1Fi+K+nG/rJYeseGcPOQplzdoRktZLaMEMLFOX+hryiFlDVGW2b/T1BwCotyJ8mrE99V3sHiih7k6OYMbhPKpIRwhrdrKguICSEaFNMLvVKqJfA8EKS1Hmd2/HNs/Bi9/CVUWT5lbo3Y6NaNuWU3ssLSlSZ+TRnWJ5w32obTM7YJXh7yhKoQomGyqtArpT4DRgEZWuuOZx0fCfwbcAc+1Vq/rrU+DNyjlJpji4TPtjzDj5yy3iwo685GOtI1rhnD2obzWNtw2ZVJCCGqWDuinw68D3xZfUAp5Q58AFwFpAGblVLztNaJZid5MZZWV7GuuBPj2obz7zahsiqkEEJcgFWFXmu9WikVe97h3kBy1QgepdQs4HrAboX+qvZNuap9U3v9OCGEcEp1aVxHAKlnfZ0GRCilQpRSU4FuSqn/u9iLlVL3K6W2KKW2ZGZm1iENIYQQl2L6zVit9WngQSvOmwZMA2M9erPzEEIIYajLiP44EHXW15FVx6ymlBqtlJqWm5tbhzSEEEJcSl0K/WagtVIqTinlBYwH5tUkgNZ6vtb6/qCgoDqkIYQQ4lKsKvRKqZnAeiBBKZWmlLpHa10BTAaWAPuA2VrrvbZLVQghRG1YO+tmwkWOLwIWmZqREEIIUzn0cVHp0QshhO05tNBLj14IIWxPae34mY1KqUzgqKPzqIVQIMvRSdhZQ7vmhna9INfsTGK01mGXO6leFHpnpZTaorXu6eg87KmhXXNDu16Qa3ZFsqSjEEK4OCn0Qgjh4qTQ1800RyfgAA3tmhva9YJcs8uRHr0QQrg4GdELIYSLk0J/GUqpYKXUHKVUklJqn1Kq33nfv00ptUsptVsptU4p1cVRuZrlctd81nm9lFIVSinbbhlpB9Zcs1LqCqXUDqXUXqXUKkfkaSYrfreDlFLzlVI7q655kqNyNYNSKqHq36/6vzyl1BPnnaOUUu8qpZKr/q67OypfMzn/5uC2929gsdZ6XNXibb7nfT8FGKK1PqOUugaj19fH3kma7HLXXL3D2D+An+2dnI1c8pqVUsHAh8BIrfUxpVS4I5I02eX+nR8BErXWo5VSYcB+pdQMrXWZ3TM1gdZ6P9AVfvv9PQ58f95p1wCtq/7rA3yE8/89S6G/FKVUEDAYuAug6hf8nF9yrfW6s77cgLFcs9Oy5pqrPArMBXrZLTkbsfKabwW+01ofqzonw545ms3Ka9ZAgFJKAf5ANlBhxzRtaThwSGt9/oOa1wNfauPm5YaqTz3NtdYn7Z+ieaR1c2lxQCbwuVJqu1LqU6WU3yXOvwf4yT6p2cxlr1kpFQHcgDHacQXW/Du3ARorpVYqpbYqpe6wf5qmsuaa3wfaASeA3cDjWmuLnfO0lfHAzAscv+DOeXbJyIak0F+aB9Ad+Ehr3Q0oBKZc6ESl1FCMQv+c/dKzCWuu+R3gORf6o7fmmj2AHsC1wAjgBaVUG7tmaS5rrnkEsANogdHyeF8pFWjXLG2gqk11HfCto3OxFyn0l5YGpGmtN1Z9PQfjj+McSqnOwKfA9VVbKToza665JzBLKXUEGAd8qJQaY78UTWfNNacBS7TWhVrrLGA14Mw33q255kkY7SqttU7GuB/V1o452so1wDatdfoFvlfnnfPqIyn0l6C1PgWkKqUSqg4NBxLPPkcpFQ18B0zUWh+wc4qms+aatdZxWutYrXUsRoF4WGv9g30zNY811wz8CAxUSnkopXwxbtDts2OaprLymo9VHUcp1RRIAA7bLUnbmcCF2zZg7JJ3R9Xsm75ArrP350EemLospVRXjNG6F8Yv+STgFgCt9VSl1KfAWP63+maFsy+OdLlrPu/c6cACrfUcO6dpKmuuWSn1x6rjFuBTrfU7jsnWHFb8brcApgPNAQW8rrX+2jHZmqPqPsQxoKXWOrfq2IPw2zUrjHsTI4EiYJLWeouj8jWLFHohhHBx0roRQggXJ4VeCCFcnBR6IYRwcVLohRDCxUmhF0IIFyeFXgghXJwUeiGEcHFS6IUQwsX9P7RsSiDTnd/NAAAAAElFTkSuQmCC\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "E = np.linspace(6.1, 7.1, 1000)\n", - "plt.semilogy(E, u238_multipole(E, 0)[1])\n", - "plt.semilogy(E, u238_multipole(E, 900)[1])" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/pandas-dataframes.ipynb b/examples/jupyter/pandas-dataframes.ipynb deleted file mode 100644 index f5e5142b51c..00000000000 --- a/examples/jupyter/pandas-dataframes.ipynb +++ /dev/null @@ -1,2696 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Pandas Dataframes\n", - "This notebook demonstrates how systematic analysis of tally scores is possible using Pandas dataframes. A dataframe can be automatically generated using the `Tally.get_pandas_dataframe(...)` method. Furthermore, by linking the tally data in a statepoint file with geometry and material information from a summary file, the dataframe can be shown with user-supplied labels." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import glob\n", - "from IPython.display import Image\n", - "import matplotlib.pyplot as plt\n", - "import scipy.stats\n", - "import numpy as np\n", - "import pandas as pd\n", - "import openmc\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we need to define materials that will be used in the problem. We will create three materials for the fuel, water, and cladding of the fuel pin." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# 1.6 enriched fuel\n", - "fuel = openmc.Material(name='1.6% Fuel')\n", - "fuel.set_density('g/cm3', 10.31341)\n", - "fuel.add_nuclide('U235', 3.7503e-4)\n", - "fuel.add_nuclide('U238', 2.2625e-2)\n", - "fuel.add_nuclide('O16', 4.6007e-2)\n", - "\n", - "# borated water\n", - "water = openmc.Material(name='Borated Water')\n", - "water.set_density('g/cm3', 0.740582)\n", - "water.add_nuclide('H1', 4.9457e-2)\n", - "water.add_nuclide('O16', 2.4732e-2)\n", - "water.add_nuclide('B10', 8.0042e-6)\n", - "\n", - "# zircaloy\n", - "zircaloy = openmc.Material(name='Zircaloy')\n", - "zircaloy.set_density('g/cm3', 6.55)\n", - "zircaloy.add_nuclide('Zr90', 7.2758e-3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our three materials, we can now create a materials file object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Materials collection\n", - "materials = openmc.Materials([fuel, water, zircaloy])\n", - "\n", - "# Export to \"materials.xml\"\n", - "materials.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. This problem will be a square array of fuel pins for which we can use OpenMC's lattice/universe feature. The basic universe will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces for fuel and clad, as well as the outer bounding surfaces of the problem." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Create cylinders for the fuel and clad\n", - "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.39218)\n", - "clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.45720)\n", - "\n", - "# Create boundary planes to surround the geometry\n", - "# Use both reflective and vacuum boundaries to make life interesting\n", - "min_x = openmc.XPlane(x0=-10.71, boundary_type='reflective')\n", - "max_x = openmc.XPlane(x0=+10.71, boundary_type='vacuum')\n", - "min_y = openmc.YPlane(y0=-10.71, boundary_type='vacuum')\n", - "max_y = openmc.YPlane(y0=+10.71, boundary_type='reflective')\n", - "min_z = openmc.ZPlane(z0=-10.71, boundary_type='reflective')\n", - "max_z = openmc.ZPlane(z0=+10.71, boundary_type='reflective')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now construct a fuel pin cell from cells that are defined by intersections of half-spaces created by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Create fuel Cell\n", - "fuel_cell = openmc.Cell(name='1.6% Fuel', fill=fuel,\n", - " region=-fuel_outer_radius)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='1.6% Clad', fill=zircaloy)\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='1.6% Moderator', fill=water,\n", - " region=+clad_outer_radius)\n", - "\n", - "# Create a Universe to encapsulate a fuel pin\n", - "pin_cell_universe = openmc.Universe(name='1.6% Fuel Pin', cells=[\n", - " fuel_cell, clad_cell, moderator_cell\n", - "])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Using the pin cell universe, we can construct a 17x17 rectangular lattice with a 1.26 cm pitch." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Create fuel assembly Lattice\n", - "assembly = openmc.RectLattice(name='1.6% Fuel - 0BA')\n", - "assembly.pitch = (1.26, 1.26)\n", - "assembly.lower_left = [-1.26 * 17. / 2.0] * 2\n", - "assembly.universes = [[pin_cell_universe] * 17] * 17" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC requires that there is a \"root\" universe. Let us create a root cell that is filled by the pin cell universe and then assign it to the root universe." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create root Cell\n", - "root_cell = openmc.Cell(name='root cell', fill=assembly)\n", - "\n", - "# Add boundary planes\n", - "root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z\n", - "\n", - "# Create root Universe\n", - "root_universe = openmc.Universe(name='root universe')\n", - "root_universe.add_cell(root_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now must create a geometry that is assigned a root universe and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and export to \"geometry.xml\"\n", - "geometry = openmc.Geometry(root_universe)\n", - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the geometry and materials finished, we now just need to define simulation parameters. In this case, we will use 5 inactive batches and 15 minimum active batches each with 2500 particles. We also tell OpenMC to turn tally triggers on, which means it will keep running until some criterion on the uncertainty of tallies is reached." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "min_batches = 20\n", - "max_batches = 200\n", - "inactive = 5\n", - "particles = 2500\n", - "\n", - "# Instantiate a Settings object\n", - "settings = openmc.Settings()\n", - "settings.batches = min_batches\n", - "settings.inactive = inactive\n", - "settings.particles = particles\n", - "settings.output = {'tallies': False}\n", - "settings.trigger_active = True\n", - "settings.trigger_max_batches = max_batches\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-10.71, -10.71, -10, 10.71, 10.71, 10.]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us also create a plot file that we can use to verify that our pin cell geometry was created successfully." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEVyEhLpgJFNv8T///98iBL0AAAAAWJLR0QDEQxM8gAAAAd0SU1FB+QIDwgKFMc0xewAAAOeSURBVGje7ZtLkqowFIZPrAsDRz247YAluIosgYEO2h20q3AJDFyAA6wSVnkDCAnkBAK/lH0bTpVVX1mCmsfJRx5E7w6hXn/U64PFWKNkkaIriXNMQWajpNDAO9HJQqJzRmGeUpRLHkVeYOJAEnkut+qT5zxpI/EYtZE26qJI3Uy9x2NY4sOBFDafvNWYD2NSo/H9t6FbJRY+qv///E0GbnowNZGqgkxpX1xf4XkYLzWq+rureyRVpfGYUuBEok/VxI6SxJHFQ4MBi2sEsSoIKktqAlJREUVNhZmscTeMzWVN+4l084h082h6atHApG4/DTrar9AtVdiN1my/Rv9huxLXafJ5+u/G/lIOH1b/3fb9aWdRUKv/GiU9BlUi1vVfYlwm7V5s6j8u2p9UnfHZpsbjGnVOO07CcvxsMm2m06uB93rQbGHajJ++Sb+LW91/s6FBp4sh038njX8hcn3WP/7zP7o9/hf/P9ROEfb7R2ZiVI2fRZletfQkXiieSLSrRCq4u7Dwr28XriGkNt02/rWRLKylN8xaeHKjNJH6pJdHT/+Vbun9f/z3zHbamf13PyS9nP/uLOnlsczKGeO/h0m4RimycrT/fsZt//WQXg55/zWa0oWR3tV/u/7L5S/Wf6389Rr/9ZBeHrXIHliMtfSyuMZOldZX5bS7eBQKheSSXt6fLBWmjrR5Se/qvz7+6y4023/9pJfB0nTpW0uvNyar/5YhZJOpOmj7b2AjRanW29TDf3MD1T08pdelwqv/9viDS3pn89+0i6b/Zl2s/Nfwt9H+++6+8xOi678WPkuKR2IqbVB6o37/3Tv89zLWf33aL9p/5vHf/vzxSv8lxH9v1E7abWSk99pFznRH4eKj8Jevp5McWKxMl8HSX4alt0+Fnf7r4W9bdvwc478v8NeX++/I34+WH1p/cPtZeqD5C82fYP5Gxw90/Pot/jvVX1B/gv1t6YE+P4DPL+jz0+/x32nPz+jzOzp/AM9fCInNnyw90Pk7cP4Qnb9E509f56/T5o/R+Wt0/hydv4fXD5Ye6PoVuH6Grt/N47/+65ezzB+NWL9F14/R9Wt0/Rxev196oPtHwP0r8/iv//6d1X+x/WPw/jUhsf1zSw90/+YZ2z+K7l9d/RfbP43u34b3jy890PMLJ+z8xGv8d/r5kdV/sfNL6Pkp+PzW0gM9PwieX0TPT87rv5P2D/4M//U8v4ueH4bPL6Pnp98b/wAXomzv5H3x5AAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMC0wOC0xNVQwNzoxMDoyMCswMTowML6m1KIAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjAtMDgtMTVUMDc6MTA6MjArMDE6MDDP+2weAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Instantiate a Plot\n", - "plot = openmc.Plot(plot_id=1)\n", - "plot.filename = 'materials-xy'\n", - "plot.origin = [0, 0, 0]\n", - "plot.width = [21.5, 21.5]\n", - "plot.pixels = [250, 250]\n", - "plot.color_by = 'material'\n", - "\n", - "# Show plot\n", - "openmc.plot_inline(plot)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As we can see from the plot, we have a nice array of pin cells with fuel, cladding, and water! Before we run our simulation, we need to tell the code what we want to tally. The following code shows how to create a variety of tallies." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate an empty Tallies object\n", - "tallies = openmc.Tallies()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Instantiate a fission rate mesh Tally" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a tally Mesh\n", - "mesh = openmc.RegularMesh(mesh_id=1)\n", - "mesh.dimension = [17, 17]\n", - "mesh.lower_left = [-10.71, -10.71]\n", - "mesh.width = [1.26, 1.26]\n", - "\n", - "# Instantiate tally Filter\n", - "mesh_filter = openmc.MeshFilter(mesh)\n", - "\n", - "# Instantiate energy Filter\n", - "energy_filter = openmc.EnergyFilter([0, 0.625, 20.0e6])\n", - "\n", - "# Instantiate the Tally\n", - "tally = openmc.Tally(name='mesh tally')\n", - "tally.filters = [mesh_filter, energy_filter]\n", - "tally.scores = ['fission', 'nu-fission']\n", - "\n", - "# Add mesh and Tally to Tallies\n", - "tallies.append(tally)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Instantiate a cell Tally with nuclides" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate tally Filter\n", - "cell_filter = openmc.CellFilter(fuel_cell)\n", - "\n", - "# Instantiate the tally\n", - "tally = openmc.Tally(name='cell tally')\n", - "tally.filters = [cell_filter]\n", - "tally.scores = ['scatter']\n", - "tally.nuclides = ['U235', 'U238']\n", - "\n", - "# Add mesh and tally to Tallies\n", - "tallies.append(tally)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create a \"distribcell\" Tally. The distribcell filter allows us to tally multiple repeated instances of the same cell throughout the geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate tally Filter\n", - "distribcell_filter = openmc.DistribcellFilter(moderator_cell)\n", - "\n", - "# Instantiate tally Trigger for kicks\n", - "trigger = openmc.Trigger(trigger_type='std_dev', threshold=5e-5)\n", - "trigger.scores = ['absorption']\n", - "\n", - "# Instantiate the Tally\n", - "tally = openmc.Tally(name='distribcell tally')\n", - "tally.filters = [distribcell_filter]\n", - "tally.scores = ['absorption', 'scatter']\n", - "tally.triggers = [trigger]\n", - "\n", - "# Add mesh and tally to Tallies\n", - "tallies.append(tally)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Export to \"tallies.xml\"\n", - "tallies.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we a have a complete set of inputs, so we can go ahead and run our simulation." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2020 MIT and OpenMC contributors\n", - " License | https://docs.openmc.org/en/latest/license.html\n", - " Version | 0.12.0\n", - " Git SHA1 | 3d90a9f857ec72eae897e054d4225180f1fa4d93\n", - " Date/Time | 2020-08-15 07:10:20\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading U235 from /home/master/data/nuclear/endfb71_hdf5/U235.h5\n", - " Reading U238 from /home/master/data/nuclear/endfb71_hdf5/U238.h5\n", - " Reading O16 from /home/master/data/nuclear/endfb71_hdf5/O16.h5\n", - " Reading H1 from /home/master/data/nuclear/endfb71_hdf5/H1.h5\n", - " Reading B10 from /home/master/data/nuclear/endfb71_hdf5/B10.h5\n", - " Reading Zr90 from /home/master/data/nuclear/endfb71_hdf5/Zr90.h5\n", - " Minimum neutron data temperature: 294.000000 K\n", - " Maximum neutron data temperature: 294.000000 K\n", - " Reading tallies XML file...\n", - " Preparing distributed cell instances...\n", - " Writing summary.h5 file...\n", - " Maximum neutron transport energy: 20000000.000000 eV for U235\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 0.53544\n", - " 2/1 0.62631\n", - " 3/1 0.63917\n", - " 4/1 0.67203\n", - " 5/1 0.69300\n", - " 6/1 0.64862\n", - " 7/1 0.63937 0.64399 +/- 0.00463\n", - " 8/1 0.67696 0.65498 +/- 0.01131\n", - " 9/1 0.63216 0.64928 +/- 0.00982\n", - " 10/1 0.70996 0.66141 +/- 0.01433\n", - " 11/1 0.69761 0.66745 +/- 0.01316\n", - " 12/1 0.68662 0.67019 +/- 0.01146\n", - " 13/1 0.64374 0.66688 +/- 0.01046\n", - " 14/1 0.69121 0.66958 +/- 0.00961\n", - " 15/1 0.72125 0.67475 +/- 0.01003\n", - " 16/1 0.72706 0.67950 +/- 0.01024\n", - " 17/1 0.69623 0.68090 +/- 0.00945\n", - " 18/1 0.70953 0.68310 +/- 0.00897\n", - " 19/1 0.69026 0.68361 +/- 0.00832\n", - " 20/1 0.68633 0.68379 +/- 0.00775\n", - " Triggers unsatisfied, max unc./thresh. is 75.24758750489383 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 84938 --- greater than max batches\n", - " Creating state point statepoint.020.h5...\n", - " 21/1 0.68310 0.68375 +/- 0.00725\n", - " Triggers unsatisfied, max unc./thresh. is 71.20148627325992 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 81120 --- greater than max batches\n", - " 22/1 0.68679 0.68393 +/- 0.00681\n", - " Triggers unsatisfied, max unc./thresh. is 66.94650483064697 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 76197 --- greater than max batches\n", - " 23/1 0.67440 0.68340 +/- 0.00644\n", - " Triggers unsatisfied, max unc./thresh. is 63.553590826021285 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 72709 --- greater than max batches\n", - " 24/1 0.67483 0.68295 +/- 0.00611\n", - " Triggers unsatisfied, max unc./thresh. is 60.37873858685279 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 69272 --- greater than max batches\n", - " 25/1 0.71558 0.68458 +/- 0.00602\n", - " Triggers unsatisfied, max unc./thresh. is 60.34535216026281 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 72837 --- greater than max batches\n", - " 26/1 0.71853 0.68620 +/- 0.00595\n", - " Triggers unsatisfied, max unc./thresh. is 59.60875760463032 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 74623 --- greater than max batches\n", - " 27/1 0.67455 0.68567 +/- 0.00570\n", - " Triggers unsatisfied, max unc./thresh. is 57.228951643423976 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 72059 --- greater than max batches\n", - " 28/1 0.69435 0.68605 +/- 0.00546\n", - " Triggers unsatisfied, max unc./thresh. is 56.194065573871285 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 72634 --- greater than max batches\n", - " 29/1 0.67706 0.68567 +/- 0.00524\n", - " Triggers unsatisfied, max unc./thresh. is 53.86022066923874 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 69628 --- greater than max batches\n", - " 30/1 0.69294 0.68596 +/- 0.00504\n", - " Triggers unsatisfied, max unc./thresh. is 51.73413206858763 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66916 --- greater than max batches\n", - " 31/1 0.69108 0.68616 +/- 0.00484\n", - " Triggers unsatisfied, max unc./thresh. is 49.71174462484801 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64258 --- greater than max batches\n", - " 32/1 0.68089 0.68596 +/- 0.00466\n", - " Triggers unsatisfied, max unc./thresh. is 50.80993117627794 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 69710 --- greater than max batches\n", - " 33/1 0.67698 0.68564 +/- 0.00450\n", - " Triggers unsatisfied, max unc./thresh. is 50.46659333785448 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 71318 --- greater than max batches\n", - " 34/1 0.68167 0.68551 +/- 0.00435\n", - " Triggers unsatisfied, max unc./thresh. is 48.852656603250665 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 69216 --- greater than max batches\n", - " 35/1 0.67760 0.68524 +/- 0.00421\n", - " Triggers unsatisfied, max unc./thresh. is 48.5685583427197 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 70773 --- greater than max batches\n", - " 36/1 0.67628 0.68495 +/- 0.00408\n", - " Triggers unsatisfied, max unc./thresh. is 47.77661998216646 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 70766 --- greater than max batches\n", - " 37/1 0.66736 0.68440 +/- 0.00399\n", - " Triggers unsatisfied, max unc./thresh. is 46.57810773879176 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 69430 --- greater than max batches\n", - " 38/1 0.71026 0.68519 +/- 0.00395\n", - " Triggers unsatisfied, max unc./thresh. is 45.876107560616674 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 69458 --- greater than max batches\n", - " 39/1 0.67674 0.68494 +/- 0.00384\n", - " Triggers unsatisfied, max unc./thresh. is 45.30341918376721 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 69787 --- greater than max batches\n", - " 40/1 0.69360 0.68519 +/- 0.00373\n", - " Triggers unsatisfied, max unc./thresh. is 44.018056562863386 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 67821 --- greater than max batches\n", - " 41/1 0.70987 0.68587 +/- 0.00369\n", - " Triggers unsatisfied, max unc./thresh. is 42.781078099052785 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 65893 --- greater than max batches\n", - " 42/1 0.68780 0.68592 +/- 0.00359\n", - " Triggers unsatisfied, max unc./thresh. is 41.60877069209228 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64063 --- greater than max batches\n", - " 43/1 0.69223 0.68609 +/- 0.00350\n", - " Triggers unsatisfied, max unc./thresh. is 42.44932759168626 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 68479 --- greater than max batches\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 44/1 0.69561 0.68633 +/- 0.00342\n", - " Triggers unsatisfied, max unc./thresh. is 41.34743776753899 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66680 --- greater than max batches\n", - " 45/1 0.67503 0.68605 +/- 0.00334\n", - " Triggers unsatisfied, max unc./thresh. is 40.97332186124358 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 67158 --- greater than max batches\n", - " 46/1 0.67290 0.68573 +/- 0.00328\n", - " Triggers unsatisfied, max unc./thresh. is 40.24678448931756 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66417 --- greater than max batches\n", - " 47/1 0.67355 0.68544 +/- 0.00321\n", - " Triggers unsatisfied, max unc./thresh. is 40.42620640829592 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 68645 --- greater than max batches\n", - " 48/1 0.71383 0.68610 +/- 0.00320\n", - " Triggers unsatisfied, max unc./thresh. is 39.90662320308606 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 68485 --- greater than max batches\n", - " 49/1 0.68389 0.68605 +/- 0.00313\n", - " Triggers unsatisfied, max unc./thresh. is 39.075369568753906 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 67188 --- greater than max batches\n", - " 50/1 0.73148 0.68706 +/- 0.00322\n", - " Triggers unsatisfied, max unc./thresh. is 38.57054567218653 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66951 --- greater than max batches\n", - " 51/1 0.69796 0.68730 +/- 0.00316\n", - " Triggers unsatisfied, max unc./thresh. is 38.21572703507316 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 67186 --- greater than max batches\n", - " 52/1 0.70691 0.68771 +/- 0.00312\n", - " Triggers unsatisfied, max unc./thresh. is 37.50971908717773 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66134 --- greater than max batches\n", - " 53/1 0.69104 0.68778 +/- 0.00306\n", - " Triggers unsatisfied, max unc./thresh. is 36.824732312223716 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 65096 --- greater than max batches\n", - " 54/1 0.74368 0.68892 +/- 0.00320\n", - " Triggers unsatisfied, max unc./thresh. is 36.20814737643575 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64246 --- greater than max batches\n", - " 55/1 0.67371 0.68862 +/- 0.00315\n", - " Triggers unsatisfied, max unc./thresh. is 35.48607231512293 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62969 --- greater than max batches\n", - " 56/1 0.67846 0.68842 +/- 0.00310\n", - " Triggers unsatisfied, max unc./thresh. is 35.34421893287461 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63715 --- greater than max batches\n", - " 57/1 0.66351 0.68794 +/- 0.00307\n", - " Triggers unsatisfied, max unc./thresh. is 34.67062652878957 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62512 --- greater than max batches\n", - " 58/1 0.67049 0.68761 +/- 0.00303\n", - " Triggers unsatisfied, max unc./thresh. is 34.22135922543247 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62074 --- greater than max batches\n", - " 59/1 0.66967 0.68728 +/- 0.00299\n", - " Triggers unsatisfied, max unc./thresh. is 33.66881484408945 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 61219 --- greater than max batches\n", - " 60/1 0.70271 0.68756 +/- 0.00295\n", - " Triggers unsatisfied, max unc./thresh. is 33.19914799505717 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60626 --- greater than max batches\n", - " 61/1 0.70035 0.68779 +/- 0.00291\n", - " Triggers unsatisfied, max unc./thresh. is 32.65594936729897 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59725 --- greater than max batches\n", - " 62/1 0.66274 0.68735 +/- 0.00289\n", - " Triggers unsatisfied, max unc./thresh. is 32.15622046485561 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 58945 --- greater than max batches\n", - " 63/1 0.68607 0.68733 +/- 0.00284\n", - " Triggers unsatisfied, max unc./thresh. is 31.601225649282494 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57926 --- greater than max batches\n", - " 64/1 0.66518 0.68695 +/- 0.00282\n", - " Triggers unsatisfied, max unc./thresh. is 31.12129365572805 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57149 --- greater than max batches\n", - " 65/1 0.65999 0.68650 +/- 0.00281\n", - " Triggers unsatisfied, max unc./thresh. is 30.641988019531464 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56341 --- greater than max batches\n", - " 66/1 0.67843 0.68637 +/- 0.00276\n", - " Triggers unsatisfied, max unc./thresh. is 30.320463443580458 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56085 --- greater than max batches\n", - " 67/1 0.69295 0.68648 +/- 0.00272\n", - " Triggers unsatisfied, max unc./thresh. is 30.06051080038397 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56031 --- greater than max batches\n", - " 68/1 0.69158 0.68656 +/- 0.00268\n", - " Triggers unsatisfied, max unc./thresh. is 29.7400907913873 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 55727 --- greater than max batches\n", - " 69/1 0.69825 0.68674 +/- 0.00264\n", - " Triggers unsatisfied, max unc./thresh. is 29.278619659445805 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 54869 --- greater than max batches\n", - " 70/1 0.73637 0.68750 +/- 0.00271\n", - " Triggers unsatisfied, max unc./thresh. is 28.945044018568716 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 54464 --- greater than max batches\n", - " 71/1 0.64301 0.68683 +/- 0.00275\n", - " Triggers unsatisfied, max unc./thresh. is 28.73677928804667 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 54508 --- greater than max batches\n", - " 72/1 0.71506 0.68725 +/- 0.00274\n", - " Triggers unsatisfied, max unc./thresh. is 29.20796537704291 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57164 --- greater than max batches\n", - " 73/1 0.69203 0.68732 +/- 0.00270\n", - " Triggers unsatisfied, max unc./thresh. is 29.56297016014581 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59435 --- greater than max batches\n", - " 74/1 0.69208 0.68739 +/- 0.00267\n", - " Triggers unsatisfied, max unc./thresh. is 29.545241442413783 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60237 --- greater than max batches\n", - " 75/1 0.65717 0.68696 +/- 0.00266\n", - " Triggers unsatisfied, max unc./thresh. is 29.284013224166248 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60034 --- greater than max batches\n", - " 76/1 0.70992 0.68728 +/- 0.00265\n", - " Triggers unsatisfied, max unc./thresh. is 29.00034584995327 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59718 --- greater than max batches\n", - " 77/1 0.65590 0.68685 +/- 0.00264\n", - " Triggers unsatisfied, max unc./thresh. is 28.867967845905174 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60007 --- greater than max batches\n", - " 78/1 0.64439 0.68626 +/- 0.00267\n", - " Triggers unsatisfied, max unc./thresh. is 29.016012595317935 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 61466 --- greater than max batches\n", - " 79/1 0.66295 0.68595 +/- 0.00265\n", - " Triggers unsatisfied, max unc./thresh. is 28.626245464278142 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60646 --- greater than max batches\n", - " 80/1 0.66672 0.68569 +/- 0.00263\n", - " Triggers unsatisfied, max unc./thresh. is 28.24218910063624 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59827 --- greater than max batches\n", - " 81/1 0.69110 0.68576 +/- 0.00260\n", - " Triggers unsatisfied, max unc./thresh. is 27.917349908027763 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59238 --- greater than max batches\n", - " 82/1 0.67481 0.68562 +/- 0.00257\n", - " Triggers unsatisfied, max unc./thresh. is 28.01946018168837 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60457 --- greater than max batches\n", - " 83/1 0.72216 0.68609 +/- 0.00258\n", - " Triggers unsatisfied, max unc./thresh. is 27.931394620754766 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60858 --- greater than max batches\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 84/1 0.68429 0.68607 +/- 0.00254\n", - " Triggers unsatisfied, max unc./thresh. is 27.713137470531738 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60679 --- greater than max batches\n", - " 85/1 0.65458 0.68567 +/- 0.00254\n", - " Triggers unsatisfied, max unc./thresh. is 27.364539968246927 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59911 --- greater than max batches\n", - " 86/1 0.69966 0.68585 +/- 0.00252\n", - " Triggers unsatisfied, max unc./thresh. is 27.178113974435043 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59836 --- greater than max batches\n", - " 87/1 0.64776 0.68538 +/- 0.00253\n", - " Triggers unsatisfied, max unc./thresh. is 26.941566345072534 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59525 --- greater than max batches\n", - " 88/1 0.62737 0.68468 +/- 0.00259\n", - " Triggers unsatisfied, max unc./thresh. is 26.73959660667411 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59351 --- greater than max batches\n", - " 89/1 0.69779 0.68484 +/- 0.00257\n", - " Triggers unsatisfied, max unc./thresh. is 26.490234865810894 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 58951 --- greater than max batches\n", - " 90/1 0.67312 0.68470 +/- 0.00254\n", - " Triggers unsatisfied, max unc./thresh. is 26.24036001465229 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 58533 --- greater than max batches\n", - " 91/1 0.69289 0.68480 +/- 0.00251\n", - " Triggers unsatisfied, max unc./thresh. is 25.936795778335345 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57859 --- greater than max batches\n", - " 92/1 0.69884 0.68496 +/- 0.00249\n", - " Triggers unsatisfied, max unc./thresh. is 25.695465963215582 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57448 --- greater than max batches\n", - " 93/1 0.71351 0.68528 +/- 0.00248\n", - " Triggers unsatisfied, max unc./thresh. is 25.49001212499821 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57183 --- greater than max batches\n", - " 94/1 0.65602 0.68495 +/- 0.00248\n", - " Triggers unsatisfied, max unc./thresh. is 25.350859463183905 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57203 --- greater than max batches\n", - " 95/1 0.72223 0.68537 +/- 0.00248\n", - " Triggers unsatisfied, max unc./thresh. is 25.157803279393637 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56968 --- greater than max batches\n", - " 96/1 0.67930 0.68530 +/- 0.00246\n", - " Triggers unsatisfied, max unc./thresh. is 24.92205849077747 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56526 --- greater than max batches\n", - " 97/1 0.66201 0.68505 +/- 0.00244\n", - " Triggers unsatisfied, max unc./thresh. is 24.653967027285237 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 55925 --- greater than max batches\n", - " 98/1 0.71110 0.68533 +/- 0.00243\n", - " Triggers unsatisfied, max unc./thresh. is 24.566957281211884 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56134 --- greater than max batches\n", - " 99/1 0.69409 0.68542 +/- 0.00241\n", - " Triggers unsatisfied, max unc./thresh. is 24.581943149247135 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56807 --- greater than max batches\n", - " 100/1 0.71197 0.68570 +/- 0.00240\n", - " Triggers unsatisfied, max unc./thresh. is 24.444112571967217 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56769 --- greater than max batches\n", - " 101/1 0.71713 0.68603 +/- 0.00240\n", - " Triggers unsatisfied, max unc./thresh. is 24.18957776896016 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56179 --- greater than max batches\n", - " 102/1 0.68143 0.68598 +/- 0.00237\n", - " Triggers unsatisfied, max unc./thresh. is 23.97797098066553 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 55775 --- greater than max batches\n", - " 103/1 0.69936 0.68612 +/- 0.00235\n", - " Triggers unsatisfied, max unc./thresh. is 24.253000406602812 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57650 --- greater than max batches\n", - " 104/1 0.65247 0.68578 +/- 0.00235\n", - " Triggers unsatisfied, max unc./thresh. is 24.593482483379837 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59885 --- greater than max batches\n", - " 105/1 0.66517 0.68557 +/- 0.00234\n", - " Triggers unsatisfied, max unc./thresh. is 24.37904760701804 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59439 --- greater than max batches\n", - " 106/1 0.67814 0.68550 +/- 0.00232\n", - " Triggers unsatisfied, max unc./thresh. is 24.142311084988883 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 58873 --- greater than max batches\n", - " 107/1 0.67788 0.68542 +/- 0.00229\n", - " Triggers unsatisfied, max unc./thresh. is 23.935477435724106 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 58442 --- greater than max batches\n", - " 108/1 0.68016 0.68537 +/- 0.00227\n", - " Triggers unsatisfied, max unc./thresh. is 24.532504688648594 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 61995 --- greater than max batches\n", - " 109/1 0.66963 0.68522 +/- 0.00226\n", - " Triggers unsatisfied, max unc./thresh. is 24.354532539671386 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 61692 --- greater than max batches\n", - " 110/1 0.67556 0.68513 +/- 0.00224\n", - " Triggers unsatisfied, max unc./thresh. is 24.16165322902175 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 61303 --- greater than max batches\n", - " 111/1 0.68273 0.68511 +/- 0.00222\n", - " Triggers unsatisfied, max unc./thresh. is 24.00069508298176 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 61065 --- greater than max batches\n", - " 112/1 0.69505 0.68520 +/- 0.00220\n", - " Triggers unsatisfied, max unc./thresh. is 23.791656279909404 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60572 --- greater than max batches\n", - " 113/1 0.69385 0.68528 +/- 0.00218\n", - " Triggers unsatisfied, max unc./thresh. is 23.667941020219764 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60504 --- greater than max batches\n", - " 114/1 0.65352 0.68499 +/- 0.00218\n", - " Triggers unsatisfied, max unc./thresh. is 23.469658485546123 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 60045 --- greater than max batches\n", - " 115/1 0.68339 0.68497 +/- 0.00216\n", - " Triggers unsatisfied, max unc./thresh. is 23.259123161328624 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59514 --- greater than max batches\n", - " 116/1 0.65854 0.68474 +/- 0.00215\n", - " Triggers unsatisfied, max unc./thresh. is 23.06250977653337 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59044 --- greater than max batches\n", - " 117/1 0.66907 0.68460 +/- 0.00214\n", - " Triggers unsatisfied, max unc./thresh. is 22.874382198219536 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 58608 --- greater than max batches\n", - " 118/1 0.68165 0.68457 +/- 0.00212\n", - " Triggers unsatisfied, max unc./thresh. is 22.709602691165983 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 58283 --- greater than max batches\n", - " 119/1 0.70967 0.68479 +/- 0.00211\n", - " Triggers unsatisfied, max unc./thresh. is 22.509869996658225 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57769 --- greater than max batches\n", - " 120/1 0.65543 0.68453 +/- 0.00211\n", - " Triggers unsatisfied, max unc./thresh. is 22.422104322874098 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57822 --- greater than max batches\n", - " 121/1 0.67305 0.68444 +/- 0.00209\n", - " Triggers unsatisfied, max unc./thresh. is 22.32834321567902 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57838 --- greater than max batches\n", - " 122/1 0.68206 0.68441 +/- 0.00207\n", - " Triggers unsatisfied, max unc./thresh. is 22.155196965032374 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57435 --- greater than max batches\n", - " 123/1 0.71125 0.68464 +/- 0.00207\n", - " Triggers unsatisfied, max unc./thresh. is 21.96683678913398 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56945 --- greater than max batches\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 124/1 0.65918 0.68443 +/- 0.00206\n", - " Triggers unsatisfied, max unc./thresh. is 21.78216358933223 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56467 --- greater than max batches\n", - " 125/1 0.68122 0.68440 +/- 0.00205\n", - " Triggers unsatisfied, max unc./thresh. is 21.681928420505304 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56418 --- greater than max batches\n", - " 126/1 0.66900 0.68427 +/- 0.00203\n", - " Triggers unsatisfied, max unc./thresh. is 21.60631058168512 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56492 --- greater than max batches\n", - " 127/1 0.66742 0.68414 +/- 0.00202\n", - " Triggers unsatisfied, max unc./thresh. is 21.468291123480988 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56234 --- greater than max batches\n", - " 128/1 0.66971 0.68402 +/- 0.00201\n", - " Triggers unsatisfied, max unc./thresh. is 21.313238544974386 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 55879 --- greater than max batches\n", - " 129/1 0.68183 0.68400 +/- 0.00199\n", - " Triggers unsatisfied, max unc./thresh. is 21.314008888585132 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56337 --- greater than max batches\n", - " 130/1 0.68403 0.68400 +/- 0.00197\n", - " Triggers unsatisfied, max unc./thresh. is 21.159444482258046 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 55971 --- greater than max batches\n", - " 131/1 0.69137 0.68406 +/- 0.00196\n", - " Triggers unsatisfied, max unc./thresh. is 21.24931160989673 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56899 --- greater than max batches\n", - " 132/1 0.67481 0.68399 +/- 0.00195\n", - " Triggers unsatisfied, max unc./thresh. is 21.164512281281944 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56893 --- greater than max batches\n", - " 133/1 0.70390 0.68414 +/- 0.00194\n", - " Triggers unsatisfied, max unc./thresh. is 21.084176856795946 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 56907 --- greater than max batches\n", - " 134/1 0.67961 0.68411 +/- 0.00192\n", - " Triggers unsatisfied, max unc./thresh. is 21.48684646255342 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59563 --- greater than max batches\n", - " 135/1 0.65362 0.68387 +/- 0.00192\n", - " Triggers unsatisfied, max unc./thresh. is 21.41235779526348 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59609 --- greater than max batches\n", - " 136/1 0.63946 0.68353 +/- 0.00194\n", - " Triggers unsatisfied, max unc./thresh. is 21.30299014546295 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59456 --- greater than max batches\n", - " 137/1 0.64818 0.68327 +/- 0.00194\n", - " Triggers unsatisfied, max unc./thresh. is 21.159761745415484 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 59107 --- greater than max batches\n", - " 138/1 0.68975 0.68331 +/- 0.00193\n", - " Triggers unsatisfied, max unc./thresh. is 21.000094566393475 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 58659 --- greater than max batches\n", - " 139/1 0.67280 0.68324 +/- 0.00191\n", - " Triggers unsatisfied, max unc./thresh. is 20.853656171297644 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 58279 --- greater than max batches\n", - " 140/1 0.66857 0.68313 +/- 0.00190\n", - " Triggers unsatisfied, max unc./thresh. is 20.709591767033707 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57905 --- greater than max batches\n", - " 141/1 0.68175 0.68312 +/- 0.00189\n", - " Triggers unsatisfied, max unc./thresh. is 20.560813068689416 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57499 --- greater than max batches\n", - " 142/1 0.72210 0.68340 +/- 0.00190\n", - " Triggers unsatisfied, max unc./thresh. is 20.54814917791921 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57851 --- greater than max batches\n", - " 143/1 0.67361 0.68333 +/- 0.00188\n", - " Triggers unsatisfied, max unc./thresh. is 20.4177880049802 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 57536 --- greater than max batches\n", - " 144/1 0.65862 0.68315 +/- 0.00188\n", - " Triggers unsatisfied, max unc./thresh. is 21.229890183572195 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62654 --- greater than max batches\n", - " 145/1 0.69713 0.68325 +/- 0.00187\n", - " Triggers unsatisfied, max unc./thresh. is 21.34513800240435 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63792 --- greater than max batches\n", - " 146/1 0.72980 0.68358 +/- 0.00188\n", - " Triggers unsatisfied, max unc./thresh. is 21.60165210412777 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 65801 --- greater than max batches\n", - " 147/1 0.70004 0.68370 +/- 0.00187\n", - " Triggers unsatisfied, max unc./thresh. is 21.596734424310384 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66237 --- greater than max batches\n", - " 148/1 0.68882 0.68374 +/- 0.00186\n", - " Triggers unsatisfied, max unc./thresh. is 21.447240534346236 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 65783 --- greater than max batches\n", - " 149/1 0.70401 0.68388 +/- 0.00185\n", - " Triggers unsatisfied, max unc./thresh. is 21.424993974056104 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66106 --- greater than max batches\n", - " 150/1 0.72110 0.68413 +/- 0.00186\n", - " Triggers unsatisfied, max unc./thresh. is 21.27792348945665 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 65654 --- greater than max batches\n", - " 151/1 0.65918 0.68396 +/- 0.00185\n", - " Triggers unsatisfied, max unc./thresh. is 21.378637401006184 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66734 --- greater than max batches\n", - " 152/1 0.67751 0.68392 +/- 0.00184\n", - " Triggers unsatisfied, max unc./thresh. is 21.25974745003047 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66446 --- greater than max batches\n", - " 153/1 0.69302 0.68398 +/- 0.00183\n", - " Triggers unsatisfied, max unc./thresh. is 21.16055371271148 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 66275 --- greater than max batches\n", - " 154/1 0.67102 0.68389 +/- 0.00182\n", - " Triggers unsatisfied, max unc./thresh. is 21.0227808264386 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 65857 --- greater than max batches\n", - " 155/1 0.64427 0.68363 +/- 0.00183\n", - " Triggers unsatisfied, max unc./thresh. is 20.882547322553506 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 65418 --- greater than max batches\n", - " 156/1 0.68488 0.68364 +/- 0.00181\n", - " Triggers unsatisfied, max unc./thresh. is 20.797424126850476 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 65318 --- greater than max batches\n", - " 157/1 0.67337 0.68357 +/- 0.00180\n", - " Triggers unsatisfied, max unc./thresh. is 20.67015745584828 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64948 --- greater than max batches\n", - " 158/1 0.66662 0.68346 +/- 0.00180\n", - " Triggers unsatisfied, max unc./thresh. is 20.568519956722266 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64734 --- greater than max batches\n", - " 159/1 0.62697 0.68309 +/- 0.00182\n", - " Triggers unsatisfied, max unc./thresh. is 20.47085213159483 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64540 --- greater than max batches\n", - " 160/1 0.68300 0.68309 +/- 0.00181\n", - " Triggers unsatisfied, max unc./thresh. is 20.34586209866351 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64168 --- greater than max batches\n", - " 161/1 0.68918 0.68313 +/- 0.00180\n", - " Triggers unsatisfied, max unc./thresh. is 20.23505377614212 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63881 --- greater than max batches\n", - " 162/1 0.70939 0.68330 +/- 0.00179\n", - " Triggers unsatisfied, max unc./thresh. is 20.21114215977674 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64138 --- greater than max batches\n", - " 163/1 0.69681 0.68338 +/- 0.00179\n", - " Triggers unsatisfied, max unc./thresh. is 20.163170350438893 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64241 --- greater than max batches\n", - " 164/1 0.66454 0.68326 +/- 0.00178\n", - " Triggers unsatisfied, max unc./thresh. is 20.109882525638955 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64306 --- greater than max batches\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 165/1 0.68804 0.68329 +/- 0.00177\n", - " Triggers unsatisfied, max unc./thresh. is 20.033653897136055 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 64221 --- greater than max batches\n", - " 166/1 0.66078 0.68315 +/- 0.00176\n", - " Triggers unsatisfied, max unc./thresh. is 19.916131324861123 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63867 --- greater than max batches\n", - " 167/1 0.65762 0.68300 +/- 0.00176\n", - " Triggers unsatisfied, max unc./thresh. is 19.85097950868946 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63843 --- greater than max batches\n", - " 168/1 0.69267 0.68306 +/- 0.00175\n", - " Triggers unsatisfied, max unc./thresh. is 19.729436003984436 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63453 --- greater than max batches\n", - " 169/1 0.67859 0.68303 +/- 0.00174\n", - " Triggers unsatisfied, max unc./thresh. is 19.61178427698242 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63084 --- greater than max batches\n", - " 170/1 0.66545 0.68292 +/- 0.00173\n", - " Triggers unsatisfied, max unc./thresh. is 19.495197332905757 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62716 --- greater than max batches\n", - " 171/1 0.66716 0.68283 +/- 0.00172\n", - " Triggers unsatisfied, max unc./thresh. is 19.47044861415963 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62936 --- greater than max batches\n", - " 172/1 0.70008 0.68293 +/- 0.00172\n", - " Triggers unsatisfied, max unc./thresh. is 19.382801191970024 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62746 --- greater than max batches\n", - " 173/1 0.69417 0.68300 +/- 0.00171\n", - " Triggers unsatisfied, max unc./thresh. is 19.270038663528165 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62390 --- greater than max batches\n", - " 174/1 0.66458 0.68289 +/- 0.00170\n", - " Triggers unsatisfied, max unc./thresh. is 19.281533726364312 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62836 --- greater than max batches\n", - " 175/1 0.65867 0.68275 +/- 0.00170\n", - " Triggers unsatisfied, max unc./thresh. is 19.234847030404104 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62902 --- greater than max batches\n", - " 176/1 0.69631 0.68283 +/- 0.00169\n", - " Triggers unsatisfied, max unc./thresh. is 19.13381099709457 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62609 --- greater than max batches\n", - " 177/1 0.71142 0.68299 +/- 0.00169\n", - " Triggers unsatisfied, max unc./thresh. is 19.022563643493143 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62245 --- greater than max batches\n", - " 178/1 0.68640 0.68301 +/- 0.00168\n", - " Triggers unsatisfied, max unc./thresh. is 19.03176453708651 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62667 --- greater than max batches\n", - " 179/1 0.70448 0.68313 +/- 0.00167\n", - " Triggers unsatisfied, max unc./thresh. is 19.088395456136563 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63405 --- greater than max batches\n", - " 180/1 0.70538 0.68326 +/- 0.00167\n", - " Triggers unsatisfied, max unc./thresh. is 18.98864751831452 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63105 --- greater than max batches\n", - " 181/1 0.65591 0.68311 +/- 0.00166\n", - " Triggers unsatisfied, max unc./thresh. is 18.911017891051518 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62948 --- greater than max batches\n", - " 182/1 0.72818 0.68336 +/- 0.00167\n", - " Triggers unsatisfied, max unc./thresh. is 18.808510226366458 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62621 --- greater than max batches\n", - " 183/1 0.67896 0.68334 +/- 0.00167\n", - " Triggers unsatisfied, max unc./thresh. is 18.825142861337717 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63086 --- greater than max batches\n", - " 184/1 0.65442 0.68317 +/- 0.00166\n", - " Triggers unsatisfied, max unc./thresh. is 18.79514029258707 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63239 --- greater than max batches\n", - " 185/1 0.68885 0.68321 +/- 0.00165\n", - " Triggers unsatisfied, max unc./thresh. is 18.76276176864163 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63373 --- greater than max batches\n", - " 186/1 0.68893 0.68324 +/- 0.00165\n", - " Triggers unsatisfied, max unc./thresh. is 18.690155368597363 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63233 --- greater than max batches\n", - " 187/1 0.68918 0.68327 +/- 0.00164\n", - " Triggers unsatisfied, max unc./thresh. is 18.590144288270153 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62904 --- greater than max batches\n", - " 188/1 0.69854 0.68335 +/- 0.00163\n", - " Triggers unsatisfied, max unc./thresh. is 18.61460656150607 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63416 --- greater than max batches\n", - " 189/1 0.66324 0.68324 +/- 0.00162\n", - " Triggers unsatisfied, max unc./thresh. is 18.518608099237504 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 63106 --- greater than max batches\n", - " 190/1 0.69450 0.68331 +/- 0.00162\n", - " Triggers unsatisfied, max unc./thresh. is 18.425351661292233 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62812 --- greater than max batches\n", - " 191/1 0.68953 0.68334 +/- 0.00161\n", - " Triggers unsatisfied, max unc./thresh. is 18.328779429843646 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62491 --- greater than max batches\n", - " 192/1 0.66621 0.68325 +/- 0.00160\n", - " Triggers unsatisfied, max unc./thresh. is 18.28094973389564 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62500 --- greater than max batches\n", - " 193/1 0.71102 0.68339 +/- 0.00160\n", - " Triggers unsatisfied, max unc./thresh. is 18.19949730061142 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62275 --- greater than max batches\n", - " 194/1 0.65341 0.68324 +/- 0.00160\n", - " Triggers unsatisfied, max unc./thresh. is 18.159054737369345 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62328 --- greater than max batches\n", - " 195/1 0.70061 0.68333 +/- 0.00159\n", - " Triggers unsatisfied, max unc./thresh. is 18.082465954324594 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62131 --- greater than max batches\n", - " 196/1 0.69339 0.68338 +/- 0.00159\n", - " Triggers unsatisfied, max unc./thresh. is 18.043133483791827 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62186 --- greater than max batches\n", - " 197/1 0.64411 0.68318 +/- 0.00159\n", - " Triggers unsatisfied, max unc./thresh. is 18.019303623546417 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62347 --- greater than max batches\n", - " 198/1 0.66626 0.68309 +/- 0.00159\n", - " Triggers unsatisfied, max unc./thresh. is 17.968092739058083 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62316 --- greater than max batches\n", - " 199/1 0.67839 0.68306 +/- 0.00158\n", - " Triggers unsatisfied, max unc./thresh. is 17.91968515142146 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 62302 --- greater than max batches\n", - " 200/1 0.66459 0.68297 +/- 0.00157\n", - " Triggers unsatisfied, max unc./thresh. is 17.82970764669685 for absorption in\n", - " tally 3\n", - " WARNING: The estimated number of batches is 61996 --- greater than max batches\n", - " Creating state point statepoint.200.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 2.9309e-01 seconds\n", - " Reading cross sections = 2.8108e-01 seconds\n", - " Total time in simulation = 1.1321e+01 seconds\n", - " Time in transport only = 1.1242e+01 seconds\n", - " Time in inactive batches = 1.6721e-01 seconds\n", - " Time in active batches = 1.1153e+01 seconds\n", - " Time synchronizing fission bank = 2.2958e-02 seconds\n", - " Sampling source sites = 1.8701e-02 seconds\n", - " SEND/RECV source sites = 3.9403e-03 seconds\n", - " Time accumulating tallies = 9.9349e-04 seconds\n", - " Total time for finalization = 5.2200e-07 seconds\n", - " Total time elapsed = 1.1620e+01 seconds\n", - " Calculation Rate (inactive) = 74758.2 particles/second\n", - " Calculation Rate (active) = 43708.5 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 0.68198 +/- 0.00141\n", - " k-effective (Track-length) = 0.68297 +/- 0.00157\n", - " k-effective (Absorption) = 0.68161 +/- 0.00145\n", - " Combined k-effective = 0.68209 +/- 0.00118\n", - " Leakage Fraction = 0.34033 +/- 0.00074\n", - "\n" - ] - } - ], - "source": [ - "# Remove old HDF5 (summary, statepoint) files\n", - "!rm statepoint.*\n", - "\n", - "# Run OpenMC!\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# We do not know how many batches were needed to satisfy the \n", - "# tally trigger(s), so find the statepoint file(s)\n", - "statepoints = glob.glob('statepoint.*.h5')\n", - "\n", - "# Load the last statepoint file\n", - "sp = openmc.StatePoint(statepoints[-1])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Analyze the mesh fission rate tally**" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tally\n", - "\tID =\t1\n", - "\tName =\tmesh tally\n", - "\tFilters =\tMeshFilter, EnergyFilter\n", - "\tNuclides =\ttotal\n", - "\tScores =\t['fission', 'nu-fission']\n", - "\tEstimator =\ttracklength\n" - ] - } - ], - "source": [ - "# Find the mesh tally with the StatePoint API\n", - "tally = sp.get_tally(name='mesh tally')\n", - "\n", - "# Print a little info about the mesh tally to the screen\n", - "print(tally)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use the new Tally data retrieval API with pure NumPy" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[[0.04508259]]\n", - "\n", - " [[0.0221707 ]]\n", - "\n", - " [[0.10763375]]\n", - "\n", - " [[0.05107401]]]\n" - ] - } - ], - "source": [ - "# Get the relative error for the thermal fission reaction \n", - "# rates in the four corner pins \n", - "data = tally.get_values(scores=['fission'],\n", - " filters=[openmc.MeshFilter, openmc.EnergyFilter], \\\n", - " filter_bins=[((1,1),(1,17), (17,1), (17,17)), \\\n", - " ((0., 0.625),)], value='rel_err')\n", - "print(data)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
mesh 1energy low [eV]energy high [eV]scoremeanstd. dev.
xyz
01110.00e+006.25e-01fission2.27e-041.02e-05
11110.00e+006.25e-01nu-fission5.54e-042.50e-05
21116.25e-012.00e+07fission7.19e-051.82e-06
31116.25e-012.00e+07nu-fission1.89e-044.69e-06
42110.00e+006.25e-01fission2.35e-049.82e-06
52110.00e+006.25e-01nu-fission5.71e-042.39e-05
62116.25e-012.00e+07fission6.88e-051.61e-06
72116.25e-012.00e+07nu-fission1.81e-044.15e-06
83110.00e+006.25e-01fission2.31e-041.13e-05
93110.00e+006.25e-01nu-fission5.63e-042.76e-05
103116.25e-012.00e+07fission6.95e-051.76e-06
113116.25e-012.00e+07nu-fission1.83e-044.53e-06
124110.00e+006.25e-01fission2.07e-049.85e-06
134110.00e+006.25e-01nu-fission5.04e-042.40e-05
144116.25e-012.00e+07fission6.48e-051.45e-06
154116.25e-012.00e+07nu-fission1.71e-043.81e-06
165110.00e+006.25e-01fission2.20e-041.07e-05
175110.00e+006.25e-01nu-fission5.37e-042.60e-05
185116.25e-012.00e+07fission6.76e-051.78e-06
195116.25e-012.00e+07nu-fission1.78e-044.63e-06
\n", - "
" - ], - "text/plain": [ - " mesh 1 energy low [eV] energy high [eV] score mean \\\n", - " x y z \n", - "0 1 1 1 0.00e+00 6.25e-01 fission 2.27e-04 \n", - "1 1 1 1 0.00e+00 6.25e-01 nu-fission 5.54e-04 \n", - "2 1 1 1 6.25e-01 2.00e+07 fission 7.19e-05 \n", - "3 1 1 1 6.25e-01 2.00e+07 nu-fission 1.89e-04 \n", - "4 2 1 1 0.00e+00 6.25e-01 fission 2.35e-04 \n", - "5 2 1 1 0.00e+00 6.25e-01 nu-fission 5.71e-04 \n", - "6 2 1 1 6.25e-01 2.00e+07 fission 6.88e-05 \n", - "7 2 1 1 6.25e-01 2.00e+07 nu-fission 1.81e-04 \n", - "8 3 1 1 0.00e+00 6.25e-01 fission 2.31e-04 \n", - "9 3 1 1 0.00e+00 6.25e-01 nu-fission 5.63e-04 \n", - "10 3 1 1 6.25e-01 2.00e+07 fission 6.95e-05 \n", - "11 3 1 1 6.25e-01 2.00e+07 nu-fission 1.83e-04 \n", - "12 4 1 1 0.00e+00 6.25e-01 fission 2.07e-04 \n", - "13 4 1 1 0.00e+00 6.25e-01 nu-fission 5.04e-04 \n", - "14 4 1 1 6.25e-01 2.00e+07 fission 6.48e-05 \n", - "15 4 1 1 6.25e-01 2.00e+07 nu-fission 1.71e-04 \n", - "16 5 1 1 0.00e+00 6.25e-01 fission 2.20e-04 \n", - "17 5 1 1 0.00e+00 6.25e-01 nu-fission 5.37e-04 \n", - "18 5 1 1 6.25e-01 2.00e+07 fission 6.76e-05 \n", - "19 5 1 1 6.25e-01 2.00e+07 nu-fission 1.78e-04 \n", - "\n", - " std. dev. \n", - " \n", - "0 1.02e-05 \n", - "1 2.50e-05 \n", - "2 1.82e-06 \n", - "3 4.69e-06 \n", - "4 9.82e-06 \n", - "5 2.39e-05 \n", - "6 1.61e-06 \n", - "7 4.15e-06 \n", - "8 1.13e-05 \n", - "9 2.76e-05 \n", - "10 1.76e-06 \n", - "11 4.53e-06 \n", - "12 9.85e-06 \n", - "13 2.40e-05 \n", - "14 1.45e-06 \n", - "15 3.81e-06 \n", - "16 1.07e-05 \n", - "17 2.60e-05 \n", - "18 1.78e-06 \n", - "19 4.63e-06 " - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get a pandas dataframe for the mesh tally data\n", - "df = tally.get_pandas_dataframe(nuclides=False)\n", - "\n", - "# Set the Pandas float display settings\n", - "pd.options.display.float_format = '{:.2e}'.format\n", - "\n", - "# Print the first twenty rows in the dataframe\n", - "df.head(20)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Create a boxplot to view the distribution of\n", - "# fission and nu-fission rates in the pins\n", - "bp = df.boxplot(column='mean', by='score')" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Extract thermal nu-fission rates from pandas\n", - "fiss = df[df['score'] == 'nu-fission']\n", - "fiss = fiss[fiss['energy low [eV]'] == 0.0]\n", - "\n", - "# Extract mean and reshape as 2D NumPy arrays\n", - "mean = fiss['mean'].values.reshape((17,17))\n", - "\n", - "plt.imshow(mean, interpolation='nearest')\n", - "plt.title('fission rate')\n", - "plt.xlabel('x')\n", - "plt.ylabel('y')\n", - "plt.colorbar()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Analyze the cell+nuclides scatter-y2 rate tally**" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tally\n", - "\tID =\t2\n", - "\tName =\tcell tally\n", - "\tFilters =\tCellFilter\n", - "\tNuclides =\tU235 U238\n", - "\tScores =\t['scatter']\n", - "\tEstimator =\ttracklength\n" - ] - } - ], - "source": [ - "# Find the cell Tally with the StatePoint API\n", - "tally = sp.get_tally(name='cell tally')\n", - "\n", - "# Print a little info about the cell tally to the screen\n", - "print(tally)" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellnuclidescoremeanstd. dev.
01U235scatter3.81e-024.13e-05
11U238scatter2.34e+002.41e-03
\n", - "
" - ], - "text/plain": [ - " cell nuclide score mean std. dev.\n", - "0 1 U235 scatter 3.81e-02 4.13e-05\n", - "1 1 U238 scatter 2.34e+00 2.41e-03" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get a pandas dataframe for the cell tally data\n", - "df = tally.get_pandas_dataframe()\n", - "\n", - "# Print the first twenty rows in the dataframe\n", - "df.head(20)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use the new Tally data retrieval API with pure NumPy" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[[2.41367509e-03]\n", - " [4.12533801e-05]]]\n" - ] - } - ], - "source": [ - "# Get the standard deviations the total scattering rate\n", - "data = tally.get_values(scores=['scatter'], \n", - " nuclides=['U238', 'U235'], value='std_dev')\n", - "print(data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "**Analyze the distribcell tally**" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tally\n", - "\tID =\t3\n", - "\tName =\tdistribcell tally\n", - "\tFilters =\tDistribcellFilter\n", - "\tNuclides =\ttotal\n", - "\tScores =\t['absorption', 'scatter']\n", - "\tEstimator =\ttracklength\n" - ] - } - ], - "source": [ - "# Find the distribcell Tally with the StatePoint API\n", - "tally = sp.get_tally(name='distribcell tally')\n", - "\n", - "# Print a little info about the distribcell tally to the screen\n", - "print(tally)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Use the new Tally data retrieval API with pure NumPy" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[[0.0131914 ]]\n", - "\n", - " [[0.01252949]]\n", - "\n", - " [[0.01241481]]\n", - "\n", - " [[0.01194961]]\n", - "\n", - " [[0.01186091]]\n", - "\n", - " [[0.0127257 ]]\n", - "\n", - " [[0.01358576]]\n", - "\n", - " [[0.0130368 ]]\n", - "\n", - " [[0.014031 ]]\n", - "\n", - " [[0.0141883 ]]]\n" - ] - } - ], - "source": [ - "# Get the relative error for the scattering reaction rates in\n", - "# the first 10 distribcell instances \n", - "data = tally.get_values(scores=['scatter'], filters=[openmc.DistribcellFilter],\n", - " filter_bins=[tuple(range(10))], value='rel_err')\n", - "print(data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Print the distribcell tally dataframe" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
level 1level 2level 3distribcellscoremeanstd. dev.
univcelllatunivcell
idididxyidid
55834271613279absorption7.11e-041.10e-05
55934271613279scatter8.91e-026.60e-04
56034281613280absorption6.75e-041.02e-05
56134281613280scatter8.35e-026.11e-04
56234291613281absorption6.10e-041.02e-05
56334291613281scatter7.75e-026.10e-04
564342101613282absorption5.67e-049.88e-06
565342101613282scatter7.11e-025.99e-04
566342111613283absorption5.06e-049.35e-06
567342111613283scatter6.39e-025.53e-04
568342121613284absorption4.35e-048.22e-06
569342121613284scatter5.62e-025.18e-04
570342131613285absorption3.73e-047.90e-06
571342131613285scatter4.76e-024.92e-04
572342141613286absorption2.98e-047.30e-06
573342141613286scatter3.82e-024.17e-04
574342151613287absorption2.05e-045.96e-06
575342151613287scatter2.86e-023.72e-04
576342161613288absorption1.22e-044.12e-06
577342161613288scatter1.82e-022.59e-04
\n", - "
" - ], - "text/plain": [ - " level 1 level 2 level 3 distribcell score \\\n", - " univ cell lat univ cell \n", - " id id id x y id id \n", - "558 3 4 2 7 16 1 3 279 absorption \n", - "559 3 4 2 7 16 1 3 279 scatter \n", - "560 3 4 2 8 16 1 3 280 absorption \n", - "561 3 4 2 8 16 1 3 280 scatter \n", - "562 3 4 2 9 16 1 3 281 absorption \n", - "563 3 4 2 9 16 1 3 281 scatter \n", - "564 3 4 2 10 16 1 3 282 absorption \n", - "565 3 4 2 10 16 1 3 282 scatter \n", - "566 3 4 2 11 16 1 3 283 absorption \n", - "567 3 4 2 11 16 1 3 283 scatter \n", - "568 3 4 2 12 16 1 3 284 absorption \n", - "569 3 4 2 12 16 1 3 284 scatter \n", - "570 3 4 2 13 16 1 3 285 absorption \n", - "571 3 4 2 13 16 1 3 285 scatter \n", - "572 3 4 2 14 16 1 3 286 absorption \n", - "573 3 4 2 14 16 1 3 286 scatter \n", - "574 3 4 2 15 16 1 3 287 absorption \n", - "575 3 4 2 15 16 1 3 287 scatter \n", - "576 3 4 2 16 16 1 3 288 absorption \n", - "577 3 4 2 16 16 1 3 288 scatter \n", - "\n", - " mean std. dev. \n", - " \n", - " \n", - "558 7.11e-04 1.10e-05 \n", - "559 8.91e-02 6.60e-04 \n", - "560 6.75e-04 1.02e-05 \n", - "561 8.35e-02 6.11e-04 \n", - "562 6.10e-04 1.02e-05 \n", - "563 7.75e-02 6.10e-04 \n", - "564 5.67e-04 9.88e-06 \n", - "565 7.11e-02 5.99e-04 \n", - "566 5.06e-04 9.35e-06 \n", - "567 6.39e-02 5.53e-04 \n", - "568 4.35e-04 8.22e-06 \n", - "569 5.62e-02 5.18e-04 \n", - "570 3.73e-04 7.90e-06 \n", - "571 4.76e-02 4.92e-04 \n", - "572 2.98e-04 7.30e-06 \n", - "573 3.82e-02 4.17e-04 \n", - "574 2.05e-04 5.96e-06 \n", - "575 2.86e-02 3.72e-04 \n", - "576 1.22e-04 4.12e-06 \n", - "577 1.82e-02 2.59e-04 " - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get a pandas dataframe for the distribcell tally data\n", - "df = tally.get_pandas_dataframe(nuclides=False)\n", - "\n", - "# Print the last twenty rows in the dataframe\n", - "df.tail(20)" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
meanstd. dev.
count2.89e+022.89e+02
mean4.19e-046.86e-06
std2.41e-042.51e-06
min1.68e-051.07e-06
25%2.06e-045.09e-06
50%3.98e-046.90e-06
75%6.17e-048.44e-06
max8.70e-041.52e-05
\n", - "
" - ], - "text/plain": [ - " mean std. dev.\n", - " \n", - " \n", - "count 2.89e+02 2.89e+02\n", - "mean 4.19e-04 6.86e-06\n", - "std 2.41e-04 2.51e-06\n", - "min 1.68e-05 1.07e-06\n", - "25% 2.06e-04 5.09e-06\n", - "50% 3.98e-04 6.90e-06\n", - "75% 6.17e-04 8.44e-06\n", - "max 8.70e-04 1.52e-05" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Show summary statistics for absorption distribcell tally data\n", - "absorption = df[df['score'] == 'absorption']\n", - "absorption[['mean', 'std. dev.']].dropna().describe()\n", - "\n", - "# Note that the maximum standard deviation does indeed\n", - "# meet the 5e-5 threshold set by the tally trigger" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perform a statistical test comparing the tally sample distributions for two categories of fuel pins." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mann-Whitney Test p-value: 0.47449458604689265\n" - ] - } - ], - "source": [ - "# Extract tally data from pins in the pins divided along y=-x diagonal \n", - "multi_index = ('level 2', 'lat',)\n", - "lower = df[df[multi_index + ('x',)] + df[multi_index + ('y',)] < 16]\n", - "upper = df[df[multi_index + ('x',)] + df[multi_index + ('y',)] > 16]\n", - "lower = lower[lower['score'] == 'absorption']\n", - "upper = upper[upper['score'] == 'absorption']\n", - "\n", - "# Perform non-parametric Mann-Whitney U Test to see if the \n", - "# absorption rates (may) come from same sampling distribution\n", - "u, p = scipy.stats.mannwhitneyu(lower['mean'], upper['mean'])\n", - "print('Mann-Whitney Test p-value: {0}'.format(p))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that the symmetry implied by the y=-x diagonal ensures that the two sampling distributions are identical. Indeed, as illustrated by the test above, for any reasonable significance level (*e.g.*, $\\alpha$=0.05) one would **not reject** the null hypothesis that the two sampling distributions are identical.\n", - "\n", - "Next, perform the same test but with two groupings of pins which are not symmetrically identical to one another." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mann-Whitney Test p-value: 2.499381683224802e-42\n" - ] - } - ], - "source": [ - "# Extract tally data from pins in the pins divided along y=x diagonal\n", - "multi_index = ('level 2', 'lat',)\n", - "lower = df[df[multi_index + ('x',)] > df[multi_index + ('y',)]]\n", - "upper = df[df[multi_index + ('x',)] < df[multi_index + ('y',)]]\n", - "lower = lower[lower['score'] == 'absorption']\n", - "upper = upper[upper['score'] == 'absorption']\n", - "\n", - "# Perform non-parametric Mann-Whitney U Test to see if the \n", - "# absorption rates (may) come from same sampling distribution\n", - "u, p = scipy.stats.mannwhitneyu(lower['mean'], upper['mean'])\n", - "print('Mann-Whitney Test p-value: {0}'.format(p))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that the asymmetry implied by the y=x diagonal ensures that the two sampling distributions are *not* identical. Indeed, as illustrated by the test above, for any reasonable significance level (*e.g.*, $\\alpha$=0.05) one would **reject** the null hypothesis that the two sampling distributions are identical." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - ":4: SettingWithCopyWarning: \n", - "A value is trying to be set on a copy of a slice from a DataFrame.\n", - "Try using .loc[row_indexer,col_indexer] = value instead\n", - "\n", - "See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n", - " scatter['rel. err.'] = scatter['std. dev.'] / scatter['mean']\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Extract the scatter tally data from pandas\n", - "scatter = df[df['score'] == 'scatter']\n", - "\n", - "scatter['rel. err.'] = scatter['std. dev.'] / scatter['mean']\n", - "\n", - "# Show a scatter plot of the mean vs. the std. dev.\n", - "scatter.plot(kind='scatter', x='mean', y='rel. err.', title='Scattering Rates')" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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3bs333zzDQBffPEF3bt3p2vXrtx88807H1I0bdo0TjjhBM4//3zat28PwOmnn07nzp057LDDGDVq1M5Y6tevz5/+9Cc6d+5Mnz59mDVrFj179qRNmzaMH1/2y7Y6gxARKWTLli106tRp5/yPP/7Iqaee+otyd9xxB1999RW1atXip59+omHDhlx++eXUr19/50OFTjnlFC6++GKGDBnC6NGjufrqq3nllVe45ppruOaaaxg8eDAjR4782XZnzZrFwoULad26NQCjR4+mUaNGbNmyha5du3LWWWfRuHFjNm3aRM+ePfn73//OGWecwZ///GfefPNNFi1axJAhQ5LGXBI6gxARKaROnTrMmzdv5+vWW29NWq5Dhw5ccMEFPPXUU2RmJv++PWPGDM4//3wALrroIt5///2dy8855xyAnet36Nat287kAMGZSseOHenevTvLly/n888/ByA7O5t+/foB0L59e44//niysrJo3749y5YtK/0BCClBiIiU0oQJE7jiiiuYM2cOnTt3Jj8/f5d1gjsAilevXr2d09OmTWPq1KnMmDGD+fPnc/jhh7N161YgeG7Fju1lZGRQq1atndOpxLIrShAiIqWQSCRYvnw5J5xwAnfeeSc//fQTGzdupEGDBmzYsGFnuR49evDMM88AwcOEjjnmGAC6d+/Oiy++CLBzfTLr1q1jjz32oG7duixevJiZM2em8V39nK5BiEillkq31CjE43EuvPBC1q1bh7tz3XXX0bBhQ0455RTOPvtsXn31VR544AFGjBjBpZdeyl133UXTpk157LHHALjvvvu48MILueeeexg4cCC777570v3069ePkSNH0qFDBw4++GC6d+9eYe/RCj8uryrr0qWL5+TkRB2GlEBRfdwr6z8FSb9PP/2UQw45JOow0m7z5s3UqVMHM+OZZ55h3LhxvPpqsoElyk+yY2tmc9w96SPxdAYhIhKBOXPmcOWVV+LuNGzYkNGjR0cd0i8oQYiIRODYY49l/vz5UYdRLF2kFpFKpzo1fVcWpTmmShAiUqnUrl2bNWvWKEmUI3dnzZo11K5du0T11MQkIpVKy5Ytyc3NRQ8AK1+1a9emZcuWJaqjBCEilUpWVtbP7iKW6ChBSJWibrEiFUfXIEREJKm0nUGY2WjgZGCVu7cLlz0LHBwWaQj85O6dktRdBmwA4kB+UTdx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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Plot a histogram and kernel density estimate for the scattering rates\n", - "scatter['mean'].plot(kind='hist', bins=25)\n", - "scatter['mean'].plot(kind='kde')\n", - "plt.title('Scattering Rates')\n", - "plt.xlabel('Mean')\n", - "plt.legend(['KDE', 'Histogram'])" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/pincell.ipynb b/examples/jupyter/pincell.ipynb deleted file mode 100644 index dd0cf131368..00000000000 --- a/examples/jupyter/pincell.ipynb +++ /dev/null @@ -1,1583 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Modeling a Pin-Cell\n", - "This notebook is intended to demonstrate the basic features of the Python API for constructing input files and running OpenMC. In it, we will show how to create a basic reflective pin-cell model that is equivalent to modeling an infinite array of fuel pins. If you have never used OpenMC, this can serve as a good starting point to learn the Python API. We highly recommend having a copy of the [Python API reference documentation](https://docs.openmc.org/en/stable/pythonapi/index.html) open in another browser tab that you can refer to." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import openmc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Defining Materials\n", - "\n", - "Materials in OpenMC are defined as a set of nuclides with specified atom/weight fractions. To begin, we will create a material by making an instance of the `Material` class. In OpenMC, many objects, including materials, are identified by a \"unique ID\" that is simply just a positive integer. These IDs are used when exporting XML files that the solver reads in. They also appear in the output and can be used for identification. Since an integer ID is not very useful by itself, you can also give a material a `name` as well." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Material\n", - "\tID =\t1\n", - "\tName =\tuo2\n", - "\tTemperature =\tNone\n", - "\tDensity =\tNone [sum]\n", - "\tS(a,b) Tables \n", - "\tNuclides \n", - "\n" - ] - } - ], - "source": [ - "uo2 = openmc.Material(1, \"uo2\")\n", - "print(uo2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "On the XML side, you have no choice but to supply an ID. However, in the Python API, if you don't give an ID, one will be automatically generated for you:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Material\n", - "\tID =\t2\n", - "\tName =\t\n", - "\tTemperature =\tNone\n", - "\tDensity =\tNone [sum]\n", - "\tS(a,b) Tables \n", - "\tNuclides \n", - "\n" - ] - } - ], - "source": [ - "mat = openmc.Material()\n", - "print(mat)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that an ID of 2 was automatically assigned. Let's now move on to adding nuclides to our `uo2` material. The `Material` object has a method `add_nuclide()` whose first argument is the name of the nuclide and second argument is the atom or weight fraction." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Help on method add_nuclide in module openmc.material:\n", - "\n", - "add_nuclide(nuclide, percent, percent_type='ao') method of openmc.material.Material instance\n", - " Add a nuclide to the material\n", - " \n", - " Parameters\n", - " ----------\n", - " nuclide : str\n", - " Nuclide to add, e.g., 'Mo95'\n", - " percent : float\n", - " Atom or weight percent\n", - " percent_type : {'ao', 'wo'}\n", - " 'ao' for atom percent and 'wo' for weight percent\n", - "\n" - ] - } - ], - "source": [ - "help(uo2.add_nuclide)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that by default it assumes we want an atom fraction." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Add nuclides to uo2\n", - "uo2.add_nuclide('U235', 0.03)\n", - "uo2.add_nuclide('U238', 0.97)\n", - "uo2.add_nuclide('O16', 2.0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we need to assign a total density to the material. We'll use the `set_density` for this." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "uo2.set_density('g/cm3', 10.0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You may sometimes be given a material specification where all the nuclide densities are in units of atom/b-cm. In this case, you just want the density to be the sum of the constituents. In that case, you can simply run `mat.set_density('sum')`.\n", - "\n", - "With UO2 finished, let's now create materials for the clad and coolant. Note the use of `add_element()` for zirconium." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "zirconium = openmc.Material(name=\"zirconium\")\n", - "zirconium.add_element('Zr', 1.0)\n", - "zirconium.set_density('g/cm3', 6.6)\n", - "\n", - "water = openmc.Material(name=\"h2o\")\n", - "water.add_nuclide('H1', 2.0)\n", - "water.add_nuclide('O16', 1.0)\n", - "water.set_density('g/cm3', 1.0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "An astute observer might now point out that this water material we just created will only use free-atom cross sections. We need to tell it to use an $S(\\alpha,\\beta)$ table so that the bound atom cross section is used at thermal energies. To do this, there's an `add_s_alpha_beta()` method. Note the use of the GND-style name \"c_H_in_H2O\"." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "water.add_s_alpha_beta('c_H_in_H2O')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When we go to run the transport solver in OpenMC, it is going to look for a `materials.xml` file. Thus far, we have only created objects in memory. To actually create a `materials.xml` file, we need to instantiate a `Materials` collection and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "materials = openmc.Materials([uo2, zirconium, water])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that `Materials` is actually a subclass of Python's built-in `list`, so we can use methods like `append()`, `insert()`, `pop()`, etc." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "materials = openmc.Materials()\n", - "materials.append(uo2)\n", - "materials += [zirconium, water]\n", - "isinstance(materials, list)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, we can create the XML file with the `export_to_xml()` method. In a Jupyter notebook, we can run a shell command by putting `!` before it, so in this case we are going to display the `materials.xml` file that we created." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\r\n", - "\r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - "\r\n" - ] - } - ], - "source": [ - "materials.export_to_xml()\n", - "!cat materials.xml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Element Expansion\n", - "\n", - "Did you notice something really cool that happened to our Zr element? OpenMC automatically turned it into a list of nuclides when it exported it! The way this feature works is as follows:\n", - "\n", - "- First, it checks whether `Materials.cross_sections` has been set, indicating the path to a `cross_sections.xml` file.\n", - "- If `Materials.cross_sections` isn't set, it looks for the `OPENMC_CROSS_SECTIONS` environment variable.\n", - "- If either of these are found, it scans the file to see what nuclides are actually available and will expand elements accordingly.\n", - "\n", - "Let's see what happens if we change O16 in water to elemental O." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\r\n", - "\r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - "\r\n" - ] - } - ], - "source": [ - "water.remove_nuclide('O16')\n", - "water.add_element('O', 1.0)\n", - "\n", - "materials.export_to_xml()\n", - "!cat materials.xml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that now O16 and O17 were automatically added. O18 is missing because our cross sections file (which is based on ENDF/B-VII.1) doesn't have O18. If OpenMC didn't know about the cross sections file, it would have assumed that all isotopes exist." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### The `cross_sections.xml` file\n", - "\n", - "The `cross_sections.xml` tells OpenMC where it can find nuclide cross sections and $S(\\alpha,\\beta)$ tables. It serves the same purpose as MCNP's `xsdir` file and Serpent's `xsdata` file. As we mentioned, this can be set either by the `OPENMC_CROSS_SECTIONS` environment variable or the `Materials.cross_sections` attribute.\n", - "\n", - "Let's have a look at what's inside this file:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " ...\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n" - ] - } - ], - "source": [ - "!cat $OPENMC_CROSS_SECTIONS | head -n 10\n", - "print(' ...')\n", - "!cat $OPENMC_CROSS_SECTIONS | tail -n 10" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Enrichment\n", - "\n", - "Note that the `add_element()` method has a special argument `enrichment` that can be used for Uranium. For example, if we know that we want to create 3% enriched UO2, the following would work:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "uo2_three = openmc.Material()\n", - "uo2_three.add_element('U', 1.0, enrichment=3.0)\n", - "uo2_three.add_element('O', 2.0)\n", - "uo2_three.set_density('g/cc', 10.0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Mixtures\n", - "\n", - "In OpenMC it is also possible to define materials by mixing existing materials. For example, if we wanted to create MOX fuel out of a mixture of UO2 (97 wt%) and PuO2 (3 wt%) we could do the following:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Create PuO2 material\n", - "puo2 = openmc.Material()\n", - "puo2.add_nuclide('Pu239', 0.94)\n", - "puo2.add_nuclide('Pu240', 0.06)\n", - "puo2.add_nuclide('O16', 2.0)\n", - "puo2.set_density('g/cm3', 11.5)\n", - "\n", - "# Create the mixture\n", - "mox = openmc.Material.mix_materials([uo2, puo2], [0.97, 0.03], 'wo')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The 'wo' argument in the `mix_materials()` method specifies that the fractions are weight fractions. Materials can also be mixed by atomic and volume fractions with 'ao' and 'vo', respectively. For 'ao' and 'wo' the fractions must sum to one. For 'vo', if fractions do not sum to one, the remaining fraction is set as void." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Defining Geometry\n", - "\n", - "At this point, we have three materials defined, exported to XML, and ready to be used in our model. To finish our model, we need to define the geometric arrangement of materials. OpenMC represents physical volumes using constructive solid geometry (CSG), also known as combinatorial geometry. The object that allows us to assign a material to a region of space is called a `Cell` (same concept in MCNP, for those familiar). In order to define a region that we can assign to a cell, we must first define surfaces which bound the region. A *surface* is a locus of zeros of a function of Cartesian coordinates $x$, $y$, and $z$, e.g.\n", - "\n", - "- A plane perpendicular to the x axis: $x - x_0 = 0$\n", - "- A cylinder parallel to the z axis: $(x - x_0)^2 + (y - y_0)^2 - R^2 = 0$\n", - "- A sphere: $(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 - R^2 = 0$\n", - "\n", - "Between those three classes of surfaces (planes, cylinders, spheres), one can construct a wide variety of models. It is also possible to define cones and general second-order surfaces (tori are not currently supported).\n", - "\n", - "Note that defining a surface is not sufficient to specify a volume -- in order to define an actual volume, one must reference the half-space of a surface. A surface *half-space* is the region whose points satisfy a positive or negative inequality of the surface equation. For example, for a sphere of radius one centered at the origin, the surface equation is $f(x,y,z) = x^2 + y^2 + z^2 - 1 = 0$. Thus, we say that the negative half-space of the sphere, is defined as the collection of points satisfying $f(x,y,z) < 0$, which one can reason is the inside of the sphere. Conversely, the positive half-space of the sphere would correspond to all points outside of the sphere.\n", - "\n", - "Let's go ahead and create a sphere and confirm that what we've told you is true." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "sphere = openmc.Sphere(r=1.0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that by default the sphere is centered at the origin so we didn't have to supply `x0`, `y0`, or `z0` arguments. Strictly speaking, we could have omitted `R` as well since it defaults to one. To get the negative or positive half-space, we simply need to apply the `-` or `+` unary operators, respectively.\n", - "\n", - "(NOTE: Those unary operators are defined by special methods: `__pos__` and `__neg__` in this case)." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "inside_sphere = -sphere\n", - "outside_sphere = +sphere" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's see if `inside_sphere` actually contains points inside the sphere:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True False\n", - "False True\n" - ] - } - ], - "source": [ - "print((0,0,0) in inside_sphere, (0,0,2) in inside_sphere)\n", - "print((0,0,0) in outside_sphere, (0,0,2) in outside_sphere)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Everything works as expected! Now that we understand how to create half-spaces, we can create more complex volumes by combining half-spaces using Boolean operators: `&` (intersection), `|` (union), and `~` (complement). For example, let's say we want to define a region that is the top part of the sphere (all points inside the sphere that have $z > 0$." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "z_plane = openmc.ZPlane(z0=0)\n", - "northern_hemisphere = -sphere & +z_plane" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For many regions, OpenMC can automatically determine a bounding box. To get the bounding box, we use the `bounding_box` property of a region, which returns a tuple of the lower-left and upper-right Cartesian coordinates for the bounding box:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(array([-1., -1., 0.]), array([1., 1., 1.]))" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "northern_hemisphere.bounding_box" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we see how to create volumes, we can use them to create a cell." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "cell = openmc.Cell()\n", - "cell.region = northern_hemisphere\n", - "\n", - "# or...\n", - "cell = openmc.Cell(region=northern_hemisphere)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By default, the cell is not filled by any material (void). In order to assign a material, we set the `fill` property of a `Cell`." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "cell.fill = water" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Universes and in-line plotting" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A collection of cells is known as a universe (again, this will be familiar to MCNP/Serpent users) and can be used as a repeatable unit when creating a model. Although we don't need it yet, the benefit of creating a universe is that we can visualize our geometry while we're creating it." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "universe = openmc.Universe()\n", - "universe.add_cell(cell)\n", - "\n", - "# this also works\n", - "universe = openmc.Universe(cells=[cell])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `Universe` object has a `plot` method that will display our the universe as current constructed:" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "universe.plot(width=(2.0, 2.0))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By default, the plot will appear in the $x$-$y$ plane. We can change that with the `basis` argument." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "universe.plot(width=(2.0, 2.0), basis='xz')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we have particular fondness for, say, fuchsia, we can tell the `plot()` method to make our cell that color." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "universe.plot(width=(2.0, 2.0), basis='xz',\n", - " colors={cell: 'fuchsia'})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Pin cell geometry\n", - "\n", - "We now have enough knowledge to create our pin-cell. We need three surfaces to define the fuel and clad:\n", - "\n", - "1. The outer surface of the fuel -- a cylinder parallel to the z axis\n", - "2. The inner surface of the clad -- same as above\n", - "3. The outer surface of the clad -- same as above\n", - "\n", - "These three surfaces will all be instances of `openmc.ZCylinder`, each with a different radius according to the specification." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "fuel_outer_radius = openmc.ZCylinder(r=0.39)\n", - "clad_inner_radius = openmc.ZCylinder(r=0.40)\n", - "clad_outer_radius = openmc.ZCylinder(r=0.46)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces created, we can now take advantage of the built-in operators on surfaces to create regions for the fuel, the gap, and the clad:" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "fuel_region = -fuel_outer_radius\n", - "gap_region = +fuel_outer_radius & -clad_inner_radius\n", - "clad_region = +clad_inner_radius & -clad_outer_radius" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can create corresponding cells that assign materials to these regions. As with materials, cells have unique IDs that are assigned either manually or automatically. Note that the gap cell doesn't have any material assigned (it is void by default)." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "fuel = openmc.Cell(name='fuel')\n", - "fuel.fill = uo2\n", - "fuel.region = fuel_region\n", - "\n", - "gap = openmc.Cell(name='air gap')\n", - "gap.region = gap_region\n", - "\n", - "clad = openmc.Cell(name='clad')\n", - "clad.fill = zirconium\n", - "clad.region = clad_region" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, we need to handle the coolant outside of our fuel pin. To do this, we create x- and y-planes that bound the geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "pitch = 1.26\n", - "left = openmc.XPlane(x0=-pitch/2, boundary_type='reflective')\n", - "right = openmc.XPlane(x0=pitch/2, boundary_type='reflective')\n", - "bottom = openmc.YPlane(y0=-pitch/2, boundary_type='reflective')\n", - "top = openmc.YPlane(y0=pitch/2, boundary_type='reflective')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The water region is going to be everything outside of the clad outer radius and within the box formed as the intersection of four half-spaces." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "water_region = +left & -right & +bottom & -top & +clad_outer_radius\n", - "\n", - "moderator = openmc.Cell(name='moderator')\n", - "moderator.fill = water\n", - "moderator.region = water_region" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC also includes a factory function that generates a rectangular prism that could have made our lives easier." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "openmc.region.Intersection" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "box = openmc.rectangular_prism(width=pitch, height=pitch,\n", - " boundary_type='reflective')\n", - "type(box)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Pay attention here -- the object that was returned is NOT a surface. It is actually the intersection of four surface half-spaces, just like we created manually before. Thus, we don't need to apply the unary operator (`-box`). Instead, we can directly combine it with `+clad_or`." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [], - "source": [ - "water_region = box & +clad_outer_radius" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The final step is to assign the cells we created to a universe and tell OpenMC that this universe is the \"root\" universe in our geometry. The `Geometry` is the final object that is actually exported to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\r\n", - "\r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - " \r\n", - "\r\n" - ] - } - ], - "source": [ - "root_universe = openmc.Universe(cells=(fuel, gap, clad, moderator))\n", - "\n", - "geometry = openmc.Geometry()\n", - "geometry.root_universe = root_universe\n", - "\n", - "# or...\n", - "geometry = openmc.Geometry(root_universe)\n", - "geometry.export_to_xml()\n", - "!cat geometry.xml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Starting source and settings\n", - "\n", - "The Python API has a module ``openmc.stats`` with various univariate and multivariate probability distributions. We can use these distributions to create a starting source using the ``openmc.Source`` object." - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a point source\n", - "point = openmc.stats.Point((0, 0, 0))\n", - "source = openmc.Source(space=point)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's create a `Settings` object and give it the source we created along with specifying how many batches and particles we want to run." - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "settings = openmc.Settings()\n", - "settings.source = source\n", - "settings.batches = 100\n", - "settings.inactive = 10\n", - "settings.particles = 1000" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\r\n", - "\r\n", - " eigenvalue\r\n", - " 1000\r\n", - " 100\r\n", - " 10\r\n", - " \r\n", - " \r\n", - " 0 0 0\r\n", - " \r\n", - " \r\n", - "\r\n" - ] - } - ], - "source": [ - "settings.export_to_xml()\n", - "!cat settings.xml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## User-defined tallies\n", - "\n", - "We actually have all the *required* files needed to run a simulation. Before we do that though, let's give a quick example of how to create tallies. We will show how one would tally the total, fission, absorption, and (n,$\\gamma$) reaction rates for $^{235}$U in the cell containing fuel. Recall that filters allow us to specify *where* in phase-space we want events to be tallied and scores tell us *what* we want to tally:\n", - "\n", - "$$X = \\underbrace{\\int d\\mathbf{r} \\int d\\mathbf{\\Omega} \\int dE}_{\\text{filters}} \\; \\underbrace{f(\\mathbf{r},\\mathbf{\\Omega},E)}_{\\text{scores}} \\psi (\\mathbf{r},\\mathbf{\\Omega},E)$$\n", - "\n", - "In this case, the *where* is \"the fuel cell\". So, we will create a cell filter specifying the fuel cell." - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [], - "source": [ - "cell_filter = openmc.CellFilter(fuel)\n", - "\n", - "tally = openmc.Tally(1)\n", - "tally.filters = [cell_filter]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The *what* is the total, fission, absorption, and (n,$\\gamma$) reaction rates in $^{235}$U. By default, if we only specify what reactions, it will gives us tallies over all nuclides. We can use the `nuclides` attribute to name specific nuclides we're interested in." - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "tally.nuclides = ['U235']\n", - "tally.scores = ['total', 'fission', 'absorption', '(n,gamma)']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Similar to the other files, we need to create a `Tallies` collection and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\r\n", - "\r\n", - " \r\n", - " 3\r\n", - " \r\n", - " \r\n", - " 1\r\n", - " U235\r\n", - " total fission absorption (n,gamma)\r\n", - " \r\n", - "\r\n" - ] - } - ], - "source": [ - "tallies = openmc.Tallies([tally])\n", - "tallies.export_to_xml()\n", - "!cat tallies.xml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Running OpenMC\n", - "\n", - "Running OpenMC from Python can be done using the `openmc.run()` function. This function allows you to set the number of MPI processes and OpenMP threads, if need be." - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2020 MIT and OpenMC contributors\n", - " License | https://docs.openmc.org/en/latest/license.html\n", - " Version | 0.12.0\n", - " Git SHA1 | 3d90a9f857ec72eae897e054d4225180f1fa4d93\n", - " Date/Time | 2020-08-25 14:58:51\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading U235 from /home/master/data/nuclear/endfb71_hdf5/U235.h5\n", - " Reading U238 from /home/master/data/nuclear/endfb71_hdf5/U238.h5\n", - " Reading O16 from /home/master/data/nuclear/endfb71_hdf5/O16.h5\n", - " Reading Zr90 from /home/master/data/nuclear/endfb71_hdf5/Zr90.h5\n", - " Reading Zr91 from /home/master/data/nuclear/endfb71_hdf5/Zr91.h5\n", - " Reading Zr92 from /home/master/data/nuclear/endfb71_hdf5/Zr92.h5\n", - " Reading Zr94 from /home/master/data/nuclear/endfb71_hdf5/Zr94.h5\n", - " Reading Zr96 from /home/master/data/nuclear/endfb71_hdf5/Zr96.h5\n", - " Reading H1 from /home/master/data/nuclear/endfb71_hdf5/H1.h5\n", - " Reading O17 from /home/master/data/nuclear/endfb71_hdf5/O17.h5\n", - " Reading c_H_in_H2O from /home/master/data/nuclear/endfb71_hdf5/c_H_in_H2O.h5\n", - " Minimum neutron data temperature: 294.000000 K\n", - " Maximum neutron data temperature: 294.000000 K\n", - " Reading tallies XML file...\n", - " Preparing distributed cell instances...\n", - " Writing summary.h5 file...\n", - " Maximum neutron transport energy: 20000000.000000 eV for U235\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 1.42066\n", - " 2/1 1.39831\n", - " 3/1 1.46207\n", - " 4/1 1.44888\n", - " 5/1 1.42595\n", - " 6/1 1.35549\n", - " 7/1 1.36717\n", - " 8/1 1.45095\n", - " 9/1 1.36061\n", - " 10/1 1.36554\n", - " 11/1 1.36973\n", - " 12/1 1.44276 1.40625 +/- 0.03652\n", - " 13/1 1.35512 1.38920 +/- 0.02711\n", - " 14/1 1.54216 1.42744 +/- 0.04277\n", - " 15/1 1.39353 1.42066 +/- 0.03382\n", - " 16/1 1.38650 1.41497 +/- 0.02820\n", - " 17/1 1.38760 1.41106 +/- 0.02415\n", - " 18/1 1.38413 1.40769 +/- 0.02118\n", - " 19/1 1.39088 1.40582 +/- 0.01877\n", - " 20/1 1.47468 1.41271 +/- 0.01815\n", - " 21/1 1.45695 1.41673 +/- 0.01690\n", - " 22/1 1.40308 1.41559 +/- 0.01547\n", - " 23/1 1.40821 1.41503 +/- 0.01424\n", - " 24/1 1.32301 1.40845 +/- 0.01473\n", - " 25/1 1.36702 1.40569 +/- 0.01399\n", - " 26/1 1.30968 1.39969 +/- 0.01440\n", - " 27/1 1.38099 1.39859 +/- 0.01357\n", - " 28/1 1.42103 1.39984 +/- 0.01285\n", - " 29/1 1.39741 1.39971 +/- 0.01216\n", - " 30/1 1.36548 1.39800 +/- 0.01166\n", - " 31/1 1.41573 1.39884 +/- 0.01112\n", - " 32/1 1.39788 1.39880 +/- 0.01061\n", - " 33/1 1.35942 1.39709 +/- 0.01028\n", - " 34/1 1.40483 1.39741 +/- 0.00985\n", - " 35/1 1.39418 1.39728 +/- 0.00944\n", - " 36/1 1.41492 1.39796 +/- 0.00910\n", - " 37/1 1.49392 1.40151 +/- 0.00945\n", - " 38/1 1.45114 1.40329 +/- 0.00928\n", - " 39/1 1.42619 1.40408 +/- 0.00899\n", - " 40/1 1.35249 1.40236 +/- 0.00885\n", - " 41/1 1.35401 1.40080 +/- 0.00870\n", - " 42/1 1.40220 1.40084 +/- 0.00842\n", - " 43/1 1.36437 1.39974 +/- 0.00824\n", - " 44/1 1.33642 1.39787 +/- 0.00821\n", - " 45/1 1.36953 1.39706 +/- 0.00801\n", - " 46/1 1.30034 1.39438 +/- 0.00824\n", - " 47/1 1.44097 1.39564 +/- 0.00811\n", - " 48/1 1.37981 1.39522 +/- 0.00790\n", - " 49/1 1.34870 1.39403 +/- 0.00779\n", - " 50/1 1.41247 1.39449 +/- 0.00761\n", - " 51/1 1.33382 1.39301 +/- 0.00756\n", - " 52/1 1.37043 1.39247 +/- 0.00740\n", - " 53/1 1.38754 1.39236 +/- 0.00723\n", - " 54/1 1.40160 1.39257 +/- 0.00707\n", - " 55/1 1.37511 1.39218 +/- 0.00692\n", - " 56/1 1.38589 1.39204 +/- 0.00677\n", - " 57/1 1.40630 1.39234 +/- 0.00663\n", - " 58/1 1.29944 1.39041 +/- 0.00677\n", - " 59/1 1.40019 1.39061 +/- 0.00663\n", - " 60/1 1.42384 1.39127 +/- 0.00653\n", - " 61/1 1.36502 1.39076 +/- 0.00643\n", - " 62/1 1.37042 1.39037 +/- 0.00631\n", - " 63/1 1.42295 1.39098 +/- 0.00622\n", - " 64/1 1.40042 1.39116 +/- 0.00611\n", - " 65/1 1.36382 1.39066 +/- 0.00602\n", - " 66/1 1.31659 1.38934 +/- 0.00606\n", - " 67/1 1.36101 1.38884 +/- 0.00597\n", - " 68/1 1.46359 1.39013 +/- 0.00601\n", - " 69/1 1.41012 1.39047 +/- 0.00591\n", - " 70/1 1.27411 1.38853 +/- 0.00613\n", - " 71/1 1.45399 1.38960 +/- 0.00612\n", - " 72/1 1.40455 1.38984 +/- 0.00603\n", - " 73/1 1.33020 1.38890 +/- 0.00601\n", - " 74/1 1.44599 1.38979 +/- 0.00598\n", - " 75/1 1.34985 1.38917 +/- 0.00592\n", - " 76/1 1.36183 1.38876 +/- 0.00584\n", - " 77/1 1.41080 1.38909 +/- 0.00576\n", - " 78/1 1.43991 1.38984 +/- 0.00573\n", - " 79/1 1.35613 1.38935 +/- 0.00566\n", - " 80/1 1.31659 1.38831 +/- 0.00568\n", - " 81/1 1.51344 1.39007 +/- 0.00587\n", - " 82/1 1.38404 1.38999 +/- 0.00579\n", - " 83/1 1.39613 1.39007 +/- 0.00571\n", - " 84/1 1.43037 1.39061 +/- 0.00566\n", - " 85/1 1.47316 1.39172 +/- 0.00569\n", - " 86/1 1.39220 1.39172 +/- 0.00561\n", - " 87/1 1.44400 1.39240 +/- 0.00558\n", - " 88/1 1.42419 1.39281 +/- 0.00552\n", - " 89/1 1.30930 1.39175 +/- 0.00556\n", - " 90/1 1.46976 1.39273 +/- 0.00557\n", - " 91/1 1.38334 1.39261 +/- 0.00550\n", - " 92/1 1.35260 1.39212 +/- 0.00546\n", - " 93/1 1.38505 1.39204 +/- 0.00539\n", - " 94/1 1.38290 1.39193 +/- 0.00533\n", - " 95/1 1.42597 1.39233 +/- 0.00528\n", - " 96/1 1.41624 1.39261 +/- 0.00523\n", - " 97/1 1.42053 1.39293 +/- 0.00518\n", - " 98/1 1.36268 1.39258 +/- 0.00513\n", - " 99/1 1.39175 1.39258 +/- 0.00507\n", - " 100/1 1.38148 1.39245 +/- 0.00502\n", - " Creating state point statepoint.100.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 6.9022e-01 seconds\n", - " Reading cross sections = 6.7913e-01 seconds\n", - " Total time in simulation = 1.7892e+00 seconds\n", - " Time in transport only = 1.7650e+00 seconds\n", - " Time in inactive batches = 1.5005e-01 seconds\n", - " Time in active batches = 1.6391e+00 seconds\n", - " Time synchronizing fission bank = 4.2308e-03 seconds\n", - " Sampling source sites = 3.4593e-03 seconds\n", - " SEND/RECV source sites = 6.2601e-04 seconds\n", - " Time accumulating tallies = 9.5555e-05 seconds\n", - " Total time for finalization = 7.4948e-05 seconds\n", - " Total time elapsed = 2.4836e+00 seconds\n", - " Calculation Rate (inactive) = 66645.8 particles/second\n", - " Calculation Rate (active) = 54907.5 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.39516 +/- 0.00457\n", - " k-effective (Track-length) = 1.39245 +/- 0.00502\n", - " k-effective (Absorption) = 1.40443 +/- 0.00333\n", - " Combined k-effective = 1.40145 +/- 0.00319\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Great! OpenMC already told us our k-effective. It also spit out a file called `tallies.out` that shows our tallies. This is a very basic method to look at tally data; for more sophisticated methods, see other example notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ============================> TALLY 1 <============================\r\n", - "\r\n", - " Cell 3\r\n", - " U235\r\n", - " Total Reaction Rate 0.726151 +/- 0.00251702\r\n", - " Fission Rate 0.543836 +/- 0.00205084\r\n", - " Absorption Rate 0.652874 +/- 0.002424\r\n", - " (n,gamma) 0.10904 +/- 0.000385793\r\n" - ] - } - ], - "source": [ - "!cat tallies.out" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Geometry plotting\n", - "\n", - "We saw before that we could call the `Universe.plot()` method to show a universe while we were creating our geometry. There is also a built-in plotter in the codebase that is much faster than the Python plotter and has more options. The interface looks somewhat similar to the `Universe.plot()` method. Instead though, we create `Plot` instances, assign them to a `Plots` collection, export it to XML, and then run OpenMC in geometry plotting mode. As an example, let's specify that we want the plot to be colored by material (rather than by cell) and we assign yellow to fuel and blue to water." - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [], - "source": [ - "plot = openmc.Plot()\n", - "plot.filename = 'pinplot'\n", - "plot.width = (pitch, pitch)\n", - "plot.pixels = (200, 200)\n", - "plot.color_by = 'material'\n", - "plot.colors = {uo2: 'yellow', water: 'blue'}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our plot created, we need to add it to a `Plots` collection which can be exported to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\r\n", - "\r\n", - " \r\n", - " 0.0 0.0 0.0\r\n", - " 1.26 1.26\r\n", - " 200 200\r\n", - " \r\n", - " \r\n", - " \r\n", - "\r\n" - ] - } - ], - "source": [ - "plots = openmc.Plots([plot])\n", - "plots.export_to_xml()\n", - "!cat plots.xml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can run OpenMC in plotting mode by calling the `plot_geometry()` function. Under the hood this is calling `openmc --plot`." - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2020 MIT and OpenMC contributors\n", - " License | https://docs.openmc.org/en/latest/license.html\n", - " Version | 0.12.0\n", - " Git SHA1 | 3d90a9f857ec72eae897e054d4225180f1fa4d93\n", - " Date/Time | 2020-08-25 14:58:54\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading tallies XML file...\n", - " Preparing distributed cell instances...\n", - " Reading plot XML file...\n", - "\n", - " =======================> PLOTTING SUMMARY <========================\n", - "\n", - "Plot ID: 1\n", - "Plot file: pinplot.ppm\n", - "Universe depth: -1\n", - "Plot Type: Slice\n", - "Origin: 0.0 0.0 0.0\n", - "Width: 1.26 1.26\n", - "Coloring: Materials\n", - "Basis: XY\n", - "Pixels: 200 200\n", - "\n", - " Processing plot 1: pinplot.ppm...\n" - ] - } - ], - "source": [ - "openmc.plot_geometry()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC writes out a peculiar image with a `.ppm` extension. If you have ImageMagick installed, this can be converted into a more normal `.png` file." - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [], - "source": [ - "!convert pinplot.ppm pinplot.png" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can use functionality from IPython to display the image inline in our notebook:" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAgMAAADQNkYNAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEUAAP9yEhL//////wAZPRNOAAAAAWJLR0QCZgt8ZAAAAAd0SU1FB+QIGQ86Nr0vrD0AAAI7SURBVGje7ZmxkcIwEEUhcAnuhxIIEIGvAwioxiU4QASU4GougA4gsM6SfNxh766sfx7N3Ix+zJv9X7KxtLtaZWVlZWWl1Fr12sQQpXLaRRMRTKFe2kbk+Na8POpNkbbmWlMqtkwxRsJllIotMxQ56F7neWX8LmrdGtNpPWc//Z4cLsbpfp6xN85XNRA904Sd2V/stXlJ16EFcL4O7Q/SnUPOrK/9xfzSvQ44K0dFhjLCmq0nRYYyvDPrq2rfka4RnVlfoyJ9GdGZ9XUdI89aWGYbpTITNUKYgvLlnXFhSsqXd7bjEcKXc8YhvYEjhdzY/Db9lUKebP4+/b6lkK7m8nNRhDAlE8WFoREuig/DpKej+DAbGmGiuDAUUsgItWR8ejZ/yaZ3+SmET+/zL4JIC8Ys2VpI7/JPkSKEbCnkyiNPCilDyI5A+AVzSzZFVAhRBCKssVvlBRB5W8iNwZCThDymiLyT5F5iSCsh3RSRN5/cfgwxoiikkpFmgqgwopZAPmTkcxnkKCO3BZDQs088/RhykpFHRjLyP5AE70uadz/Z/1iK/2TgYwF9klJ8K4GPeJrTBXDsSXMeS3O2RA69wNEaOMAD1wTgMgJceYCLVZobH3IVBS68wLUauLwDLQKgEYG0O4CmCtC6ARpEQBsKaXYBLTWgcQe0B4EmJNLqBBqqQNsWaA4jLWig0Q2005GmPTAaAAYQyJgDGKYgIxtgMISMn4AhFzJKAwZ2yFgQGT4iI86srKysrD/rC4LWcCSWwIp+AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI1VDE0OjU4OjU0KzAxOjAwkH0c4gAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNVQxNDo1ODo1NCswMTowMOEgpF4AAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from IPython.display import Image\n", - "Image(\"pinplot.png\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "That was a little bit cumbersome. Thankfully, OpenMC provides us with a method on the `Plot` class that does all that \"boilerplate\" work." - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAgMAAADQNkYNAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEUAAP9yEhL//////wAZPRNOAAAAAWJLR0QCZgt8ZAAAAAd0SU1FB+QIGQ86Nr0vrD0AAAI7SURBVGje7ZmxkcIwEEUhcAnuhxIIEIGvAwioxiU4QASU4GougA4gsM6SfNxh766sfx7N3Ix+zJv9X7KxtLtaZWVlZWWl1Fr12sQQpXLaRRMRTKFe2kbk+Na8POpNkbbmWlMqtkwxRsJllIotMxQ56F7neWX8LmrdGtNpPWc//Z4cLsbpfp6xN85XNRA904Sd2V/stXlJ16EFcL4O7Q/SnUPOrK/9xfzSvQ44K0dFhjLCmq0nRYYyvDPrq2rfka4RnVlfoyJ9GdGZ9XUdI89aWGYbpTITNUKYgvLlnXFhSsqXd7bjEcKXc8YhvYEjhdzY/Db9lUKebP4+/b6lkK7m8nNRhDAlE8WFoREuig/DpKej+DAbGmGiuDAUUsgItWR8ejZ/yaZ3+SmET+/zL4JIC8Ys2VpI7/JPkSKEbCnkyiNPCilDyI5A+AVzSzZFVAhRBCKssVvlBRB5W8iNwZCThDymiLyT5F5iSCsh3RSRN5/cfgwxoiikkpFmgqgwopZAPmTkcxnkKCO3BZDQs088/RhykpFHRjLyP5AE70uadz/Z/1iK/2TgYwF9klJ8K4GPeJrTBXDsSXMeS3O2RA69wNEaOMAD1wTgMgJceYCLVZobH3IVBS68wLUauLwDLQKgEYG0O4CmCtC6ARpEQBsKaXYBLTWgcQe0B4EmJNLqBBqqQNsWaA4jLWig0Q2005GmPTAaAAYQyJgDGKYgIxtgMISMn4AhFzJKAwZ2yFgQGT4iI86srKysrD/rC4LWcCSWwIp+AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA4LTI1VDE0OjU4OjU0KzAxOjAwkH0c4gAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wOC0yNVQxNDo1ODo1NCswMTowMOEgpF4AAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot.to_ipython_image()" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/pincell_depletion.ipynb b/examples/jupyter/pincell_depletion.ipynb deleted file mode 100644 index 3fa46c00bd4..00000000000 --- a/examples/jupyter/pincell_depletion.ipynb +++ /dev/null @@ -1,997 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Pincell Depletion\n", - "This notebook is intended to introduce the reader to the depletion interface contained in OpenMC. It is recommended that you are moderately familiar with building models using the OpenMC Python API. The earlier examples are excellent starting points, as this notebook will not focus heavily on model building.\n", - "\n", - "If you have a real power reactor, the fuel composition is constantly changing as fission events produce energy, remove some fissile isotopes, and produce fission products. Other reactions, like $(n, \\alpha)$ and $(n, \\gamma)$ will alter the composition as well. Furthermore, some nuclides undergo spontaneous decay with widely ranging frequencies. Depletion is the process of modeling this behavior.\n", - "\n", - "In this notebook, we will model a simple fuel pin in an infinite lattice using the Python API. We will then build and examine some of the necessary components for performing depletion analysis. Then, we will use the depletion interface in OpenMC to simulate the fuel pin producing power over several months. Lastly, we will wrap up with some helpful tips to improve the fidelity of depletion simulations." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import math\n", - "import openmc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Build the Geometry\n", - "\n", - "Much of this section is borrowed from the \"Modeling a Pin-Cell\" example. If you find yourself not understanding some aspects of this section, feel free to refer to that example, as some details may be glossed over for brevity.\n", - "\n", - "First, we will create our fuel, cladding, and water materials to represent a typical PWR." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "fuel = openmc.Material(name=\"uo2\")" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "fuel.add_element(\"U\", 1, percent_type=\"ao\", enrichment=4.25)\n", - "fuel.add_element(\"O\", 2)\n", - "fuel.set_density(\"g/cc\", 10.4)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "clad = openmc.Material(name=\"clad\")" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "clad.add_element(\"Zr\", 1)\n", - "clad.set_density(\"g/cc\", 6)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "water = openmc.Material(name=\"water\")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "water.add_element(\"O\", 1)\n", - "water.add_element(\"H\", 2)\n", - "water.set_density(\"g/cc\", 1.0)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "water.add_s_alpha_beta(\"c_H_in_H2O\")" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "materials = openmc.Materials([fuel, clad, water])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here, we are going to use the `openmc.model.pin` function to build our pin cell. The `pin` function anticipates concentric cylinders and materials to fill the inner regions. One additional material is needed than the number of cylinders to cover the domain outside the final ring. \n", - "\n", - "To do this, we define two radii for the outer radius of our fuel pin, and the outer radius of the cladding." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "radii = [0.42, 0.45]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Using these radii, we define concentric `ZCylinder` objects. So long as the cylinders are concentric and increasing in radius, any orientation can be used. We also take advantage of the fact that the `openmc.Materials` object is a subclass of the `list` object to assign materials to the regions defined by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "pin_surfaces = [openmc.ZCylinder(r=r) for r in radii]" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "pin_univ = openmc.model.pin(pin_surfaces, materials)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The first material, in our case `fuel`, is placed inside the first cylinder in the inner-most region. The second material, `clad`, fills the space between our cylinders, while `water` is placed outside the last ring. The `pin` function returns an `openmc.Universe` object, and has some additional features we will mention later." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "pin_univ.plot()" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "bound_box = openmc.rectangular_prism(0.62, 0.62, boundary_type=\"reflective\")" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "root_cell = openmc.Cell(fill=pin_univ, region=bound_box)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "root_univ = openmc.Universe(cells=[root_cell])" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "geometry = openmc.Geometry(root_univ)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Lastly we construct our settings. For the sake of time, a relatively low number of particles will be used." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "settings = openmc.Settings()" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "settings.particles = 100\n", - "settings.inactive = 10\n", - "settings.batches = 50" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The depletion interface relies on `OpenMC` to perform the transport simulation and obtain reaction rates and other important information. We then have to create the `xml` input files that `openmc` expects, specifically `geometry.xml`, `settings.xml`, and `materials.xml`." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "settings.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before we write the material file, we must add one bit of information: the volume of our fuel. In order to translate the reaction rates obtained by `openmc` to meaningful units for depletion, we have to normalize them to a correct power. This requires us to know, or be able to calculate, how much fuel is in our problem. Correctly setting the volumes is a critical step, and can lead to incorrect answers, as the fuel is over- or under-depleted due to poor normalization.\n", - "\n", - "For our problem, we can assign the \"volume\" to be the cross-sectional area of our fuel. This is identical to modeling our fuel pin inside a box with height of 1 cm." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "fuel.volume = math.pi * radii[0] ** 2" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "materials.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setting up for depletion\n", - "\n", - "The OpenMC depletion interface can be accessed from the `openmc.deplete` module, and has a variety of classes that will help us." - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "import openmc.deplete" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In order to run the depletion calculation we need the following information:\n", - "\n", - "1. Nuclide decay, fission yield, and reaction data\n", - "2. Operational power or power density\n", - "3. Desired depletion schedule\n", - "4. Desired time integration scheme\n", - "\n", - "The first item is necessary to determine the paths by which nuclides transmute over the depletion simulation. This includes spontaneous decay, fission product yield distributions, and nuclides produced through neutron-reactions. For example,\n", - "* Te129 decays to I129 with a half life of ~70 minutes\n", - "* A fission event for U-235 produces fission products like Xe135 according to a distribution\n", - "* For thermal problems, Am241 will produce metastable Am242 about 8% of the time during an $(n,\\gamma)$ reaction. The other 92% of capture reactions will produce ground state Am242\n", - "\n", - "These data are often distributed with other nuclear data, like incident neutron cross sections with ENDF/B-VII.\n", - "OpenMC uses the [`openmc.deplete.Chain`](https://docs.openmc.org/en/latest/pythonapi/generated/openmc.deplete.Chain.html#openmc.deplete.Chain) to collect represent the various decay and transmutation pathways in a single object.\n", - "While a complete `Chain` can be created using nuclear data files, users may prefer to download pre-generated XML-representations instead.\n", - "Such files can be found at https://openmc.org/depletion-chains/ and include full and compressed chains, with capture branching ratios derived using PWR- or SFR-spectra.\n", - "\n", - "For this problem, we will be using a much smaller depletion chain that contains very few nuclides. In a realistic problem, over 1000 isotopes may be included in the depletion chain." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "chain = openmc.deplete.Chain.from_xml(\"./chain_simple.xml\")" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "OrderedDict([('I135', 0),\n", - " ('Xe135', 1),\n", - " ('Xe136', 2),\n", - " ('Cs135', 3),\n", - " ('Gd157', 4),\n", - " ('Gd156', 5),\n", - " ('U234', 6),\n", - " ('U235', 7),\n", - " ('U238', 8)])" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "chain.nuclide_dict" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The primary entry point for depletion is the `openmc.deplete.Operator`. It relies on the `openmc.deplete.Chain` and helper classes to run `openmc`, retrieve and normalize reaction rates, and other perform other tasks. For a thorough description, please see the full API documentation." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will create our Operator using the geometry and settings from above, and our simple chain file. The materials are read in automatically using the `materials.xml` file." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "operator = openmc.deplete.Operator(geometry, settings, \"./chain_simple.xml\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will then simulate our fuel pin operating at linear power of 174 W/cm, or 174 W given a unit height for our problem." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "power = 174" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For this problem, we will take depletion step sizes of 30 days, and instruct OpenMC to re-run a transport simulation every 30 days until we have modeled the problem over a six month cycle. The depletion interface expects the time to be given in seconds, so we will have to convert. Note that these values are not cumulative." - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "time_steps = [30 * 24 * 60 * 60] * 6" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And lastly, we will use the basic predictor, or forward Euler, time integration scheme. Other, more advanced methods are provided to the user through `openmc.deplete`" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "integrator = openmc.deplete.PredictorIntegrator(operator, time_steps, power)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To perform the simulation, we use the `integrate` method, and let `openmc` take care of the rest." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [], - "source": [ - "integrator.integrate()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Processing the outputs\n", - "\n", - "The depletion simulation produces a few output files. First, the statepoint files from each individual transport simulation are written to `openmc_simulation_n.h5`, where `` indicates the current depletion step. Any tallies that we defined in `tallies.xml` will be included in these files across our simulations. We have 7 such files, one for each our of 6 depletion steps and the initial state." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "c5g7.h5\t\t\t openmc_simulation_n2.h5 openmc_simulation_n6.h5\r\n", - "depletion_results.h5\t openmc_simulation_n3.h5 statepoint.50.h5\r\n", - "openmc_simulation_n0.h5 openmc_simulation_n4.h5 summary.h5\r\n", - "openmc_simulation_n1.h5 openmc_simulation_n5.h5\r\n" - ] - } - ], - "source": [ - "!ls *.h5" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `depletion_results.h5` file contains information that is aggregated over all time steps through depletion. This includes the multiplication factor, as well as concentrations. We can process this file using the `openmc.deplete.ResultsList` object" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "results = openmc.deplete.ResultsList.from_hdf5(\"./depletion_results.h5\")" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "time, k = results.get_eigenvalue()" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "time /= (24 * 60 * 60) # convert back to days from seconds" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[0.76882937, 0.00982155],\n", - " [0.75724033, 0.00827689],\n", - " [0.75532242, 0.01031746],\n", - " [0.74796855, 0.00919769],\n", - " [0.74066561, 0.01157708],\n", - " [0.73184492, 0.00971504],\n", - " [0.7207293 , 0.00703074]])" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "k" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The first column of `k` is the value of `k-combined` at each point in our simulation, while the second column contains the associated uncertainty. We can plot this using `matplotlib`" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [], - "source": [ - "from matplotlib import pyplot" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "pyplot.errorbar(time, k[:, 0], yerr=k[:, 1])\n", - "pyplot.xlabel(\"Time [d]\")\n", - "pyplot.ylabel(\"$k_{eff}\\pm \\sigma$\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Due to the low number of particles selected, we have not only a very high uncertainty, but likely a horrendously poor fission source. This pin cell should have $k>1$, but we can still see the decline over time due to fuel consumption." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can then examine concentrations of atoms in each of our materials. This requires knowing the material ID, which can be obtained from the `materials.xml` file." - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "_time, u5 = results.get_atoms(\"1\", \"U235\")\n", - "_time, xe135 = results.get_atoms(\"1\", \"Xe135\")" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "pyplot.plot(time, u5, label=\"U235\")\n", - "pyplot.xlabel(\"Time [d]\")\n", - "pyplot.ylabel(\"Number of atoms - U235\");" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "pyplot.plot(time, xe135, label=\"Xe135\")\n", - "pyplot.xlabel(\"Time [d]\")\n", - "pyplot.ylabel(\"Number of atoms - Xe135\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also examine reaction rates over time using the `ResultsList`" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [], - "source": [ - "_time, u5_fission = results.get_reaction_rate(\"1\", \"U235\", \"fission\")" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "pyplot.plot(time, u5_fission)\n", - "pyplot.xlabel(\"Time [d]\")\n", - "pyplot.ylabel(\"Fission reactions / s\");" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Helpful tips\n", - "\n", - "Depletion is a tricky task to get correct. Use too short of time steps and you may never get your results due to running many transport simulations. Use long of time steps and you may get incorrect answers. Consider the xenon plot from above. Xenon-135 is a fission product with a thermal absorption cross section on the order of millions of barns, but has a half life of ~9 hours. Taking smaller time steps at the beginning of your simulation to build up some equilibrium in your fission products is highly recommended.\n", - "\n", - "When possible, differentiate materials that reappear in multiple places. If we had built an entire core with the single `fuel` material, every pin would be depleted using the same averaged spectrum and reaction rates which is incorrect. The `Operator` can differentiate these materials using the `diff_burnable_mats` argument, but note that the volumes will be copied from the original material.\n", - "\n", - "Using higher-order integrators, like the `CECMIntegrator`, `EPCRK4Integrator` with a fourth order Runge-Kutta, or the `LEQIIntegrator`, can improve the accuracy of a simulation, or at least allow you to take longer depletion steps between transport simulations with similar accuracy.\n", - "\n", - "Fuel pins with integrated burnable absorbers, like gadolinia, experience strong flux gradients until the absorbers are mostly burned away. This means that the spectrum and magnitude of the flux at the edge of the fuel pin can be vastly different than that in the interior. The helper `pin` function can be used to subdivide regions into equal volume segments, as follows." - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [], - "source": [ - "div_surfs_1 = [openmc.ZCylinder(r=1)]\n", - "div_1 = openmc.model.pin(div_surfs_1, [fuel, water], subdivisions={0: 10})" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "div_1.plot(width=(2.0, 2.0))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The innermost region has been divided into 10 equal volume regions. We can pass additional arguments to divide multiple regions, except for the region outside the last cylinder." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Register depletion chain\n", - "\n", - "The depletion chain we created can be registered into the OpenMC `cross_sections.xml` file, so we don't have to always pass the `chain_file` argument to the `Operator`. To do this, we create a `DataLibrary` using `openmc.data`. Without any arguments, the `from_xml` method will look for the file located at `OPENMC_CROSS_SECTIONS`. For this example, we will just create a bare library." - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [], - "source": [ - "data_lib = openmc.data.DataLibrary()" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [], - "source": [ - "data_lib.register_file(\"./chain_simple.xml\")" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [], - "source": [ - "data_lib.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\r\n", - "\r\n", - " \r\n", - "\r\n" - ] - } - ], - "source": [ - "!cat cross_sections.xml" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This allows us to make an `Operator` simply with the geometry and settings arguments, provided we exported our library to `OPENMC_CROSS_SECTIONS`. For a problem where we built and registered a `Chain` using all the available nuclear data, we might see something like the following." - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [], - "source": [ - "new_op = openmc.deplete.Operator(geometry, settings)" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3820" - ] - }, - "execution_count": 52, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(new_op.chain.nuclide_dict)" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'H7', 'He3', 'He4', 'He5']" - ] - }, - "execution_count": 53, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[nuc.name for nuc in new_op.chain.nuclides[:10]]" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['Ds268',\n", - " 'Ds269',\n", - " 'Ds270',\n", - " 'Ds270_m1',\n", - " 'Ds271',\n", - " 'Ds271_m1',\n", - " 'Ds272',\n", - " 'Ds273',\n", - " 'Ds279_m1',\n", - " 'Rg272']" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "[nuc.name for nuc in new_op.chain.nuclides[-10:]]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Choice of depletion step size\n", - "\n", - "A general rule of thumb is to use depletion step sizes around 2 MWd/kgHM, where kgHM is really the initial heavy metal mass in kg. If your problem includes integral burnable absorbers, these typically require shorter time steps at or below 1 MWd/kgHM. These are typically valid for the predictor scheme, as the point of recent schemes is to extend this step size. A good convergence study, where the step size is decreased until some convergence metric is satisfied, is a beneficial exercise.\n", - "\n", - "We can use the `Operator` to determine our maximum step size using this recommendation. The `heavy_metal` attribute returns the mass of initial heavy metal in g, which, using our power, can be used to compute this step size. $$\\frac{2\\,MWd}{kgHM} = \\frac{P\\times\\Delta}{hm_{op}}$$" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "5.080339195584719" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "operator.heavy_metal" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [], - "source": [ - "max_step = 2 * operator.heavy_metal / power * 1E3" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\"Maximum\" depletion step: 58.4 [d]\n" - ] - } - ], - "source": [ - "print(\"\\\"Maximum\\\" depletion step: {:5.3} [d]\".format(max_step))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Alternatively, if we were provided the power density of our problem, we can provide this directly with `openmc.deplete.PredictorIntegrator(operator, time_steps, power_density=pdens)`. The values of `power` and `power_density` do not have to be scalars. For problems with variable power, we can provide an iterable with the same number of elements as `time_steps`." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/jupyter/post-processing.ipynb b/examples/jupyter/post-processing.ipynb deleted file mode 100644 index 8d9e1096620..00000000000 --- a/examples/jupyter/post-processing.ipynb +++ /dev/null @@ -1,980 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Post Processing\n", - "This notebook demonstrates some basic post-processing tasks that can be performed with the Python API, such as plotting a 2D mesh tally and plotting neutron source sites from an eigenvalue calculation. The problem we will use is a simple reflected pin-cell." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "from IPython.display import Image\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import openmc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we need to define materials that will be used in the problem. We'll create three materials for the fuel, water, and cladding of the fuel pin." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# 1.6 enriched fuel\n", - "fuel = openmc.Material(name='1.6% Fuel')\n", - "fuel.set_density('g/cm3', 10.31341)\n", - "fuel.add_nuclide('U235', 3.7503e-4)\n", - "fuel.add_nuclide('U238', 2.2625e-2)\n", - "fuel.add_nuclide('O16', 4.6007e-2)\n", - "\n", - "# borated water\n", - "water = openmc.Material(name='Borated Water')\n", - "water.set_density('g/cm3', 0.740582)\n", - "water.add_nuclide('H1', 4.9457e-2)\n", - "water.add_nuclide('O16', 2.4732e-2)\n", - "water.add_nuclide('B10', 8.0042e-6)\n", - "\n", - "# zircaloy\n", - "zircaloy = openmc.Material(name='Zircaloy')\n", - "zircaloy.set_density('g/cm3', 6.55)\n", - "zircaloy.add_nuclide('Zr90', 7.2758e-3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our three materials, we can now create a materials file object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Materials collection\n", - "materials = openmc.Materials([fuel, water, zircaloy])\n", - "\n", - "# Export to \"materials.xml\"\n", - "materials.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. Our problem will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces -- in this case two cylinders and six reflective planes." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Create cylinders for the fuel and clad\n", - "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.39218)\n", - "clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.45720)\n", - "\n", - "# Create boundary planes to surround the geometry\n", - "min_x = openmc.XPlane(x0=-0.63, boundary_type='reflective')\n", - "max_x = openmc.XPlane(x0=+0.63, boundary_type='reflective')\n", - "min_y = openmc.YPlane(y0=-0.63, boundary_type='reflective')\n", - "max_y = openmc.YPlane(y0=+0.63, boundary_type='reflective')\n", - "min_z = openmc.ZPlane(z0=-0.63, boundary_type='reflective')\n", - "max_z = openmc.ZPlane(z0=+0.63, boundary_type='reflective')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now create cells that are defined by intersections of half-spaces created by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a Universe to encapsulate a fuel pin\n", - "pin_cell_universe = openmc.Universe(name='1.6% Fuel Pin')\n", - "\n", - "# Create fuel Cell\n", - "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", - "fuel_cell.fill = fuel\n", - "fuel_cell.region = -fuel_outer_radius\n", - "pin_cell_universe.add_cell(fuel_cell)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='1.6% Clad')\n", - "clad_cell.fill = zircaloy\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "pin_cell_universe.add_cell(clad_cell)\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", - "moderator_cell.fill = water\n", - "moderator_cell.region = +clad_outer_radius\n", - "pin_cell_universe.add_cell(moderator_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC requires that there is a \"root\" universe. Let us create a root cell that is filled by the pin cell universe and then assign it to the root universe." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Create root Cell\n", - "root_cell = openmc.Cell(name='root cell')\n", - "root_cell.fill = pin_cell_universe\n", - "\n", - "# Add boundary planes\n", - "root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z\n", - "\n", - "# Create root Universe\n", - "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", - "root_universe.add_cell(root_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now must create a geometry that is assigned a root universe, put the geometry into a geometry file, and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and set root Universe\n", - "geometry = openmc.Geometry(root_universe)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Export to \"geometry.xml\"\n", - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the geometry and materials finished, we now just need to define simulation parameters. In this case, we will use 10 inactive batches and 90 active batches each with 5000 particles." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "settings = openmc.Settings()\n", - "settings.batches = 100\n", - "settings.inactive = 10\n", - "settings.particles = 5000\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-0.63, -0.63, -0.63, 0.63, 0.63, 0.63]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us also create a plot file that we can use to verify that our pin cell geometry was created successfully." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEXpgJFyEhJNv8T///9xF1FxAAAAAWJLR0QDEQxM8gAAAAd0SU1FB+MHEwEWFzIBvcoAAAKlSURBVGje7ZrBscIwDETxwSWkn5TAgXCgBPqhBA6kyj/fDhCIJa2zZAwz0pmHpZWdSazd7Tw8PDw8PDw8vinCMBzW03HIsRLvhnv0HL7qD+IwjzXKzaNaxeEt9kz21RWEBV5XQbfka3pQWL4qgdLyNQkUcbwFT/FP4zjWt+D+++OY4laZQJgtnqNOwe5l9XkGmIIL/PEHUAGTeuc5P15wBbu34ucSIAXkX77h4xUtIBSXnxIAOhCLy98TANNfLj8lYBYQCuLPWmAWEBe9f90DUPdKy08JWB0U1HsoaAgQxPSnAgwBopz+VABQvoDnAnqTP0r8zealzfPcQqqAQSs/C6AKGLX0pwKs8uX0cwGaAHr6uYC9wSt46qDCB4RXBDTkMwWMhnxZQF3+s8pf1AZY5VsCWuVnAUQ+YPxB43X5koAiH035soCa/AaeBOw34m359AaQPCK/1oAAyJ8aIPBI+7QGRkD+3IBt+A6QPzeg34SH2pcauN+Kt9uXGljkse0jb6BP8AD+vwGKPLZ95A0UofbnDbAFj20/eQN+gD8h/LgRD25/8QCA2088AD/Oo8dPOoDo8ZMOoPPNeej4pwdAgUcfX9IDzHnnf5lnz88XnH/nSf4M8cIL7I+/P3yCP0G88P7W+v2z9ft36+8P9vuJ/X5r/f3Jfj83//5vff/R+v6Hvb9i78/Y+7vW94/N71/Z+2P2/pq9P2fv7+n5ATu/YOcn7PyGnR+x8yt6ftYN3PzOENCcH7LzS3Z+Ss9vO62DV5uPmgAXSz5+fs7O72n/QBQLwPwLrH+C9W/Q/hHWv8L6Z2j/ThZgvX+I9S/R/inWv8X6x2j/Guufo/17rH+Q9S/S/knWv0n7R2n/Kuufpf27tH+Y9i/vWP+0h4eHh4eHh8cW8QcxLJDBvLKoigAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOS0wNy0xOVQwNjoyMjoyMy0wNTowMKrH6zcAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTktMDctMTlUMDY6MjI6MjMtMDU6MDDbmlOLAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot = openmc.Plot.from_geometry(geometry)\n", - "plot.pixels = (250, 250)\n", - "plot.to_ipython_image()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As we can see from the plot, we have a nice pin cell with fuel, cladding, and water! Before we run our simulation, we need to tell the code what we want to tally. The following code shows how to create a 2D mesh tally." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate an empty Tallies object\n", - "tallies = openmc.Tallies()" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# Create mesh which will be used for tally\n", - "mesh = openmc.RegularMesh()\n", - "mesh.dimension = [100, 100]\n", - "mesh.lower_left = [-0.63, -0.63]\n", - "mesh.upper_right = [0.63, 0.63]\n", - "\n", - "# Create mesh filter for tally\n", - "mesh_filter = openmc.MeshFilter(mesh)\n", - "\n", - "# Create mesh tally to score flux and fission rate\n", - "tally = openmc.Tally(name='flux')\n", - "tally.filters = [mesh_filter]\n", - "tally.scores = ['flux', 'fission']\n", - "tallies.append(tally)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# Export to \"tallies.xml\"\n", - "tallies.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we a have a complete set of inputs, so we can go ahead and run our simulation." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | 61c911cffdae2406f9f4bc667a9a6954748bb70c\n", - " Date/Time | 2019-07-19 06:22:24\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading U235 from /opt/data/hdf5/nndc_hdf5_v15/U235.h5\n", - " Reading U238 from /opt/data/hdf5/nndc_hdf5_v15/U238.h5\n", - " Reading O16 from /opt/data/hdf5/nndc_hdf5_v15/O16.h5\n", - " Reading H1 from /opt/data/hdf5/nndc_hdf5_v15/H1.h5\n", - " Reading B10 from /opt/data/hdf5/nndc_hdf5_v15/B10.h5\n", - " Reading Zr90 from /opt/data/hdf5/nndc_hdf5_v15/Zr90.h5\n", - " Maximum neutron transport energy: 20000000.000000 eV for U235\n", - " Reading tallies XML file...\n", - " Writing summary.h5 file...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 1.04359\n", - " 2/1 1.04323\n", - " 3/1 1.04711\n", - " 4/1 1.03892\n", - " 5/1 1.02459\n", - " 6/1 1.03936\n", - " 7/1 1.03529\n", - " 8/1 1.01590\n", - " 9/1 1.03060\n", - " 10/1 1.02892\n", - " 11/1 1.03987\n", - " 12/1 1.04395 1.04191 +/- 0.00204\n", - " 13/1 1.04971 1.04451 +/- 0.00285\n", - " 14/1 1.03880 1.04308 +/- 0.00247\n", - " 15/1 1.03091 1.04065 +/- 0.00310\n", - " 16/1 1.03618 1.03990 +/- 0.00264\n", - " 17/1 1.04109 1.04007 +/- 0.00223\n", - " 18/1 1.02978 1.03879 +/- 0.00232\n", - " 19/1 1.06363 1.04155 +/- 0.00344\n", - " 20/1 1.06549 1.04394 +/- 0.00390\n", - " 21/1 1.03469 1.04310 +/- 0.00362\n", - " 22/1 1.01925 1.04111 +/- 0.00386\n", - " 23/1 1.03268 1.04046 +/- 0.00361\n", - " 24/1 1.03906 1.04036 +/- 0.00334\n", - " 25/1 1.02632 1.03943 +/- 0.00325\n", - " 26/1 1.03906 1.03940 +/- 0.00304\n", - " 27/1 1.05058 1.04006 +/- 0.00293\n", - " 28/1 1.03248 1.03964 +/- 0.00279\n", - " 29/1 1.04076 1.03970 +/- 0.00264\n", - " 30/1 1.00994 1.03821 +/- 0.00292\n", - " 31/1 1.04785 1.03867 +/- 0.00281\n", - " 32/1 1.03080 1.03831 +/- 0.00270\n", - " 33/1 1.01862 1.03746 +/- 0.00272\n", - " 34/1 1.05370 1.03813 +/- 0.00269\n", - " 35/1 1.02226 1.03750 +/- 0.00266\n", - " 36/1 1.02862 1.03716 +/- 0.00258\n", - " 37/1 1.04790 1.03755 +/- 0.00251\n", - " 38/1 1.03762 1.03756 +/- 0.00242\n", - " 39/1 1.02255 1.03704 +/- 0.00239\n", - " 40/1 1.06094 1.03784 +/- 0.00245\n", - " 41/1 1.03842 1.03786 +/- 0.00237\n", - " 42/1 1.00628 1.03687 +/- 0.00249\n", - " 43/1 1.04916 1.03724 +/- 0.00245\n", - " 44/1 1.06237 1.03798 +/- 0.00248\n", - " 45/1 1.08153 1.03922 +/- 0.00271\n", - " 46/1 1.05649 1.03970 +/- 0.00268\n", - " 47/1 1.06265 1.04032 +/- 0.00268\n", - " 48/1 1.05728 1.04077 +/- 0.00265\n", - " 49/1 1.07343 1.04161 +/- 0.00271\n", - " 50/1 1.04640 1.04173 +/- 0.00265\n", - " 51/1 1.05143 1.04196 +/- 0.00259\n", - " 52/1 1.03639 1.04183 +/- 0.00253\n", - " 53/1 1.04846 1.04199 +/- 0.00248\n", - " 54/1 1.02435 1.04158 +/- 0.00245\n", - " 55/1 1.04806 1.04173 +/- 0.00240\n", - " 56/1 1.04798 1.04186 +/- 0.00235\n", - " 57/1 1.06621 1.04238 +/- 0.00236\n", - " 58/1 1.05734 1.04269 +/- 0.00233\n", - " 59/1 1.04581 1.04276 +/- 0.00228\n", - " 60/1 1.02682 1.04244 +/- 0.00226\n", - " 61/1 1.05971 1.04278 +/- 0.00224\n", - " 62/1 1.02357 1.04241 +/- 0.00223\n", - " 63/1 1.02645 1.04211 +/- 0.00221\n", - " 64/1 1.00711 1.04146 +/- 0.00226\n", - " 65/1 1.06171 1.04183 +/- 0.00225\n", - " 66/1 1.03444 1.04170 +/- 0.00221\n", - " 67/1 1.05875 1.04199 +/- 0.00219\n", - " 68/1 1.04640 1.04207 +/- 0.00216\n", - " 69/1 1.04376 1.04210 +/- 0.00212\n", - " 70/1 1.07078 1.04258 +/- 0.00214\n", - " 71/1 1.03916 1.04252 +/- 0.00210\n", - " 72/1 1.01843 1.04213 +/- 0.00211\n", - " 73/1 1.03666 1.04205 +/- 0.00207\n", - " 74/1 1.04625 1.04211 +/- 0.00204\n", - " 75/1 1.05277 1.04228 +/- 0.00202\n", - " 76/1 1.04944 1.04238 +/- 0.00199\n", - " 77/1 1.01898 1.04203 +/- 0.00199\n", - " 78/1 1.03283 1.04190 +/- 0.00197\n", - " 79/1 1.02304 1.04163 +/- 0.00196\n", - " 80/1 1.01539 1.04125 +/- 0.00196\n", - " 81/1 1.03988 1.04123 +/- 0.00194\n", - " 82/1 1.02138 1.04096 +/- 0.00193\n", - " 83/1 1.02473 1.04073 +/- 0.00192\n", - " 84/1 1.03810 1.04070 +/- 0.00189\n", - " 85/1 1.07438 1.04115 +/- 0.00192\n", - " 86/1 1.03048 1.04101 +/- 0.00190\n", - " 87/1 1.06778 1.04135 +/- 0.00191\n", - " 88/1 1.07341 1.04177 +/- 0.00192\n", - " 89/1 1.06729 1.04209 +/- 0.00193\n", - " 90/1 1.05069 1.04220 +/- 0.00191\n", - " 91/1 1.07675 1.04262 +/- 0.00193\n", - " 92/1 1.06470 1.04289 +/- 0.00193\n", - " 93/1 1.02609 1.04269 +/- 0.00191\n", - " 94/1 1.04761 1.04275 +/- 0.00189\n", - " 95/1 1.08802 1.04328 +/- 0.00194\n", - " 96/1 1.04162 1.04326 +/- 0.00192\n", - " 97/1 1.04573 1.04329 +/- 0.00190\n", - " 98/1 1.03232 1.04317 +/- 0.00188\n", - " 99/1 1.03473 1.04307 +/- 0.00186\n", - " 100/1 1.04505 1.04309 +/- 0.00184\n", - " Creating state point statepoint.100.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 6.4445e-01 seconds\n", - " Reading cross sections = 6.1129e-01 seconds\n", - " Total time in simulation = 2.0000e+02 seconds\n", - " Time in transport only = 1.9970e+02 seconds\n", - " Time in inactive batches = 2.9966e+00 seconds\n", - " Time in active batches = 1.9701e+02 seconds\n", - " Time synchronizing fission bank = 4.0040e-02 seconds\n", - " Sampling source sites = 3.1522e-02 seconds\n", - " SEND/RECV source sites = 8.3459e-03 seconds\n", - " Time accumulating tallies = 9.3582e-03 seconds\n", - " Total time for finalization = 4.6582e-02 seconds\n", - " Total time elapsed = 2.0072e+02 seconds\n", - " Calculation Rate (inactive) = 16685.4 particles/second\n", - " Calculation Rate (active) = 2284.19 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.04342 +/- 0.00159\n", - " k-effective (Track-length) = 1.04309 +/- 0.00184\n", - " k-effective (Absorption) = 1.04107 +/- 0.00140\n", - " Combined k-effective = 1.04195 +/- 0.00117\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", - "\n" - ] - } - ], - "source": [ - "# Run OpenMC!\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our simulation ran successfully and created a statepoint file with all the tally data in it. We begin our analysis here loading the statepoint file and 'reading' the results. By default, data from the statepoint file is only read into memory when it is requested. This helps keep the memory use to a minimum even when a statepoint file may be huge." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Load the statepoint file\n", - "sp = openmc.StatePoint('statepoint.100.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next we need to get the tally, which can be done with the ``StatePoint.get_tally(...)`` method." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tally\n", - "\tID =\t1\n", - "\tName =\tflux\n", - "\tFilters =\tMeshFilter\n", - "\tNuclides =\ttotal \n", - "\tScores =\t['flux', 'fission']\n", - "\tEstimator =\ttracklength\n", - "\n" - ] - } - ], - "source": [ - "tally = sp.get_tally(scores=['flux'])\n", - "print(tally)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The statepoint file actually stores the sum and sum-of-squares for each tally bin from which the mean and variance can be calculated as described [here](../methods/tallies.rst#variance). The sum and sum-of-squares can be accessed using the ``sum`` and ``sum_sq`` properties:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[[0.40767451, 0. ]],\n", - "\n", - " [[0.40933814, 0. ]],\n", - "\n", - " [[0.4119165 , 0. ]],\n", - "\n", - " ...,\n", - "\n", - " [[0.40854327, 0. ]],\n", - "\n", - " [[0.40970805, 0. ]],\n", - "\n", - " [[0.40948065, 0. ]]])" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "tally.sum" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However, the mean and standard deviation of the mean are usually what you are more interested in. The Tally class also has properties ``mean`` and ``std_dev`` which automatically calculate these statistics on-the-fly." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(10000, 1, 2)\n" - ] - }, - { - "data": { - "text/plain": [ - "(array([[[0.00452972, 0. ]],\n", - " \n", - " [[0.0045482 , 0. ]],\n", - " \n", - " [[0.00457685, 0. ]],\n", - " \n", - " ...,\n", - " \n", - " [[0.00453937, 0. ]],\n", - " \n", - " [[0.00455231, 0. ]],\n", - " \n", - " [[0.00454978, 0. ]]]),\n", - " array([[[2.03553236e-05, 0.00000000e+00]],\n", - " \n", - " [[1.83847389e-05, 0.00000000e+00]],\n", - " \n", - " [[1.68647098e-05, 0.00000000e+00]],\n", - " \n", - " ...,\n", - " \n", - " [[1.71606078e-05, 0.00000000e+00]],\n", - " \n", - " [[1.87645811e-05, 0.00000000e+00]],\n", - " \n", - " [[1.94447454e-05, 0.00000000e+00]]]))" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "print(tally.mean.shape)\n", - "(tally.mean, tally.std_dev)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The tally data has three dimensions: one for filter combinations, one for nuclides, and one for scores. We see that there are 10000 filter combinations (corresponding to the 100 x 100 mesh bins), a single nuclide (since none was specified), and two scores. If we only want to look at a single score, we can use the ``get_slice(...)`` method as follows." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tally\n", - "\tID =\t2\n", - "\tName =\tflux\n", - "\tFilters =\tMeshFilter\n", - "\tNuclides =\ttotal \n", - "\tScores =\t['flux']\n", - "\tEstimator =\ttracklength\n", - "\n" - ] - } - ], - "source": [ - "flux = tally.get_slice(scores=['flux'])\n", - "fission = tally.get_slice(scores=['fission'])\n", - "print(flux)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To get the bins into a form that we can plot, we can simply change the shape of the array since it is a numpy array." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "flux.std_dev.shape = (100, 100)\n", - "flux.mean.shape = (100, 100)\n", - "fission.std_dev.shape = (100, 100)\n", - "fission.mean.shape = (100, 100)" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "fig = plt.subplot(121)\n", - "fig.imshow(flux.mean)\n", - "fig2 = plt.subplot(122)\n", - "fig2.imshow(fission.mean)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's say we want to look at the distribution of relative errors of our tally bins for flux. First we create a new variable called ``relative_error`` and set it to the ratio of the standard deviation and the mean, being careful not to divide by zero in case some bins were never scored to." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Determine relative error\n", - "relative_error = np.zeros_like(flux.std_dev)\n", - "nonzero = flux.mean > 0\n", - "relative_error[nonzero] = flux.std_dev[nonzero] / flux.mean[nonzero]\n", - "\n", - "# distribution of relative errors\n", - "ret = plt.hist(relative_error[nonzero], bins=50)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Source Sites" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Source sites can be accessed from the ``source`` property. As shown below, the source sites are represented as a numpy array with a structured datatype." - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([((-0.28690552, -0.23731283, 0.51447853), ( 0.02705364, -0.14292142, 0.98936422), 1780128.70101981, 1., 0, 0),\n", - " ((-0.28690552, -0.23731283, 0.51447853), (-0.16786951, 0.86432444, -0.47409186), 1553436.10501094, 1., 0, 0),\n", - " (( 0.17162994, 0.134092 , 0.42932363), ( 0.25199134, -0.11168216, 0.96126347), 829530.02360943, 1., 0, 0),\n", - " ...,\n", - " ((-0.24444068, -0.01351615, -0.41772172), ( 0.10437178, -0.86754673, 0.486281 ), 807617.55637656, 1., 0, 0),\n", - " ((-0.2146841 , 0.14307096, 0.07419328), ( 0.89645066, -0.35557279, -0.26446968), 6036005.44157462, 1., 0, 0),\n", - " ((-0.2146841 , 0.14307096, 0.07419328), (-0.95287644, -0.25857878, 0.15863005), 4923751.04163063, 1., 0, 0)],\n", - " dtype=[('r', [('x', '" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# Create log-spaced energy bins from 1 keV to 10 MeV\n", - "energy_bins = np.logspace(3,7)\n", - "\n", - "# Calculate pdf for source energies\n", - "probability, bin_edges = np.histogram(sp.source['E'], energy_bins, density=True)\n", - "\n", - "# Make sure integrating the PDF gives us unity\n", - "print(sum(probability*np.diff(energy_bins)))\n", - "\n", - "# Plot source energy PDF\n", - "plt.semilogx(energy_bins[:-1], probability*np.diff(energy_bins), drawstyle='steps')\n", - "plt.xlabel('Energy (eV)')\n", - "plt.ylabel('Probability/eV')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's also look at the spatial distribution of the sites. To make the plot a little more interesting, we can also include the direction of the particle emitted from the source and color each source by the logarithm of its energy." - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(-0.5, 0.5)" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.quiver(sp.source['r']['x'], sp.source['r']['y'],\n", - " sp.source['u']['x'], sp.source['u']['y'],\n", - " np.log(sp.source['E']), cmap='jet', scale=20.0)\n", - "plt.colorbar()\n", - "plt.xlim((-0.5,0.5))\n", - "plt.ylim((-0.5,0.5))" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/search.ipynb b/examples/jupyter/search.ipynb deleted file mode 100644 index d2163f8e2e0..00000000000 --- a/examples/jupyter/search.ipynb +++ /dev/null @@ -1,234 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Criticality Search\n", - "This notebook illustrates the usage of the OpenMC Python API's generic eigenvalue search capability. In this Notebook, we will do a critical boron concentration search of a typical PWR pin cell.\n", - "\n", - "To use the search functionality, we must create a function which creates our model according to the input parameter we wish to search for (in this case, the boron concentration). \n", - "\n", - "This notebook will first create that function, and then, run the search." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# Initialize third-party libraries and the OpenMC Python API\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "import openmc\n", - "import openmc.model\n", - "\n", - "%matplotlib inline" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Create Parametrized Model\n", - "\n", - "To perform the search we will use the `openmc.search_for_keff` function. This function requires a different function be defined which creates an parametrized model to analyze. This model is required to be stored in an `openmc.model.Model` object. The first parameter of this function will be modified during the search process for our critical eigenvalue.\n", - "\n", - "Our model will be a pin-cell from the [Multi-Group Mode Part II](mg-mode-part-ii.ipynb) assembly, except this time the entire model building process will be contained within a function, and the Boron concentration will be parametrized." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# Create the model. `ppm_Boron` will be the parametric variable.\n", - "\n", - "def build_model(ppm_Boron):\n", - " \n", - " # Create the pin materials\n", - " fuel = openmc.Material(name='1.6% Fuel')\n", - " fuel.set_density('g/cm3', 10.31341)\n", - " fuel.add_element('U', 1., enrichment=1.6)\n", - " fuel.add_element('O', 2.)\n", - "\n", - " zircaloy = openmc.Material(name='Zircaloy')\n", - " zircaloy.set_density('g/cm3', 6.55)\n", - " zircaloy.add_element('Zr', 1.)\n", - "\n", - " water = openmc.Material(name='Borated Water')\n", - " water.set_density('g/cm3', 0.741)\n", - " water.add_element('H', 2.)\n", - " water.add_element('O', 1.)\n", - "\n", - " # Include the amount of boron in the water based on the ppm,\n", - " # neglecting the other constituents of boric acid\n", - " water.add_element('B', ppm_Boron * 1e-6)\n", - " \n", - " # Instantiate a Materials object\n", - " materials = openmc.Materials([fuel, zircaloy, water])\n", - " \n", - " # Create cylinders for the fuel and clad\n", - " fuel_outer_radius = openmc.ZCylinder(r=0.39218)\n", - " clad_outer_radius = openmc.ZCylinder(r=0.45720)\n", - "\n", - " # Create boundary planes to surround the geometry\n", - " min_x = openmc.XPlane(x0=-0.63, boundary_type='reflective')\n", - " max_x = openmc.XPlane(x0=+0.63, boundary_type='reflective')\n", - " min_y = openmc.YPlane(y0=-0.63, boundary_type='reflective')\n", - " max_y = openmc.YPlane(y0=+0.63, boundary_type='reflective')\n", - "\n", - " # Create fuel Cell\n", - " fuel_cell = openmc.Cell(name='1.6% Fuel')\n", - " fuel_cell.fill = fuel\n", - " fuel_cell.region = -fuel_outer_radius\n", - "\n", - " # Create a clad Cell\n", - " clad_cell = openmc.Cell(name='1.6% Clad')\n", - " clad_cell.fill = zircaloy\n", - " clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "\n", - " # Create a moderator Cell\n", - " moderator_cell = openmc.Cell(name='1.6% Moderator')\n", - " moderator_cell.fill = water\n", - " moderator_cell.region = +clad_outer_radius & (+min_x & -max_x & +min_y & -max_y)\n", - "\n", - " # Create root Universe\n", - " root_universe = openmc.Universe(name='root universe')\n", - " root_universe.add_cells([fuel_cell, clad_cell, moderator_cell])\n", - "\n", - " # Create Geometry and set root universe\n", - " geometry = openmc.Geometry(root_universe)\n", - " \n", - " # Instantiate a Settings object\n", - " settings = openmc.Settings()\n", - " \n", - " # Set simulation parameters\n", - " settings.batches = 300\n", - " settings.inactive = 20\n", - " settings.particles = 1000\n", - " \n", - " # Create an initial uniform spatial source distribution over fissionable zones\n", - " bounds = [-0.63, -0.63, -10, 0.63, 0.63, 10.]\n", - " uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - " settings.source = openmc.source.Source(space=uniform_dist)\n", - " \n", - " # We dont need a tallies file so dont waste the disk input/output time\n", - " settings.output = {'tallies': False}\n", - " \n", - " model = openmc.model.Model(geometry, materials, settings)\n", - " \n", - " return model" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Search for the Critical Boron Concentration\n", - "\n", - "To perform the search we imply call the `openmc.search_for_keff` function and pass in the relvant arguments. For our purposes we will be passing in the model building function (`build_model` defined above), a bracketed range for the expected critical Boron concentration (1,000 to 2,500 ppm), the tolerance, and the method we wish to use. \n", - "\n", - "Instead of the bracketed range we could have used a single initial guess, but have elected not to in this example. Finally, due to the high noise inherent in using as few histories as are used in this example, our tolerance on the final keff value will be rather large (1.e-2) and the default 'bisection' method will be used for the search." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Iteration: 1; Guess of 1.00e+03 produced a keff of 1.08504 +/- 0.00169\n", - "Iteration: 2; Guess of 2.50e+03 produced a keff of 0.95243 +/- 0.00158\n", - "Iteration: 3; Guess of 1.75e+03 produced a keff of 1.01269 +/- 0.00163\n", - "Iteration: 4; Guess of 2.12e+03 produced a keff of 0.98165 +/- 0.00155\n", - "Iteration: 5; Guess of 1.94e+03 produced a keff of 0.99773 +/- 0.00158\n", - "Iteration: 6; Guess of 1.84e+03 produced a keff of 1.00872 +/- 0.00170\n", - "Iteration: 7; Guess of 1.89e+03 produced a keff of 1.00462 +/- 0.00154\n", - "Iteration: 8; Guess of 1.91e+03 produced a keff of 1.00202 +/- 0.00154\n", - "Iteration: 9; Guess of 1.93e+03 produced a keff of 0.99816 +/- 0.00155\n", - "Critical Boron Concentration: 1926 ppm\n" - ] - } - ], - "source": [ - "# Perform the search\n", - "crit_ppm, guesses, keffs = openmc.search_for_keff(build_model, bracket=[1000., 2500.],\n", - " tol=1e-2, print_iterations=True)\n", - "\n", - "print('Critical Boron Concentration: {:4.0f} ppm'.format(crit_ppm))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, the `openmc.search_for_keff` function also provided us with `List`s of the guesses and corresponding keff values generated during the search process with OpenMC. Let's use that information to make a quick plot of the value of keff versus the boron concentration." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.figure(figsize=(8, 4.5))\n", - "plt.title('Eigenvalue versus Boron Concentration')\n", - "# Create a scatter plot using the mean value of keff\n", - "plt.scatter(guesses, [keffs[i].nominal_value for i in range(len(keffs))])\n", - "plt.xlabel('Boron Concentration [ppm]')\n", - "plt.ylabel('Eigenvalue')\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "We see a nearly linear reactivity coefficient for the boron concentration, exactly as one would expect for a pure 1/v absorber at small concentrations." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/examples/jupyter/tally-arithmetic.ipynb b/examples/jupyter/tally-arithmetic.ipynb deleted file mode 100644 index 0e8b53ac71c..00000000000 --- a/examples/jupyter/tally-arithmetic.ipynb +++ /dev/null @@ -1,1754 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Tally Arithmetic\n", - "This notebook shows the how tallies can be combined (added, subtracted, multiplied, etc.) using the Python API in order to create derived tallies. Since no covariance information is obtained, it is assumed that tallies are completely independent of one another when propagating uncertainties. The target problem is a simple pin cell." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import glob\n", - "\n", - "from IPython.display import Image\n", - "import numpy as np\n", - "import openmc" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate Input Files" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we need to define materials that will be used in the problem. We'll create three materials for the fuel, water, and cladding of the fuel pin." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# 1.6 enriched fuel\n", - "fuel = openmc.Material(name='1.6% Fuel')\n", - "fuel.set_density('g/cm3', 10.31341)\n", - "fuel.add_nuclide('U235', 3.7503e-4)\n", - "fuel.add_nuclide('U238', 2.2625e-2)\n", - "fuel.add_nuclide('O16', 4.6007e-2)\n", - "\n", - "# borated water\n", - "water = openmc.Material(name='Borated Water')\n", - "water.set_density('g/cm3', 0.740582)\n", - "water.add_nuclide('H1', 4.9457e-2)\n", - "water.add_nuclide('O16', 2.4732e-2)\n", - "water.add_nuclide('B10', 8.0042e-6)\n", - "\n", - "# zircaloy\n", - "zircaloy = openmc.Material(name='Zircaloy')\n", - "zircaloy.set_density('g/cm3', 6.55)\n", - "zircaloy.add_nuclide('Zr90', 7.2758e-3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With our three materials, we can now create a materials file object that can be exported to an actual XML file." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate a Materials collection\n", - "materials_file = openmc.Materials([fuel, water, zircaloy])\n", - "\n", - "# Export to \"materials.xml\"\n", - "materials_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's move on to the geometry. Our problem will have three regions for the fuel, the clad, and the surrounding coolant. The first step is to create the bounding surfaces -- in this case two cylinders and six planes." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# Create cylinders for the fuel and clad\n", - "fuel_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.39218)\n", - "clad_outer_radius = openmc.ZCylinder(x0=0.0, y0=0.0, r=0.45720)\n", - "\n", - "# Create boundary planes to surround the geometry\n", - "# Use both reflective and vacuum boundaries to make life interesting\n", - "min_x = openmc.XPlane(x0=-0.63, boundary_type='reflective')\n", - "max_x = openmc.XPlane(x0=+0.63, boundary_type='reflective')\n", - "min_y = openmc.YPlane(y0=-0.63, boundary_type='reflective')\n", - "max_y = openmc.YPlane(y0=+0.63, boundary_type='reflective')\n", - "min_z = openmc.ZPlane(z0=-100., boundary_type='vacuum')\n", - "max_z = openmc.ZPlane(z0=+100., boundary_type='vacuum')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the surfaces defined, we can now create cells that are defined by intersections of half-spaces created by the surfaces." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# Create a Universe to encapsulate a fuel pin\n", - "pin_cell_universe = openmc.Universe(name='1.6% Fuel Pin')\n", - "\n", - "# Create fuel Cell\n", - "fuel_cell = openmc.Cell(name='1.6% Fuel')\n", - "fuel_cell.fill = fuel\n", - "fuel_cell.region = -fuel_outer_radius\n", - "pin_cell_universe.add_cell(fuel_cell)\n", - "\n", - "# Create a clad Cell\n", - "clad_cell = openmc.Cell(name='1.6% Clad')\n", - "clad_cell.fill = zircaloy\n", - "clad_cell.region = +fuel_outer_radius & -clad_outer_radius\n", - "pin_cell_universe.add_cell(clad_cell)\n", - "\n", - "# Create a moderator Cell\n", - "moderator_cell = openmc.Cell(name='1.6% Moderator')\n", - "moderator_cell.fill = water\n", - "moderator_cell.region = +clad_outer_radius\n", - "pin_cell_universe.add_cell(moderator_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "OpenMC requires that there is a \"root\" universe. Let us create a root cell that is filled by the pin cell universe and then assign it to the root universe." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# Create root Cell\n", - "root_cell = openmc.Cell(name='root cell')\n", - "root_cell.fill = pin_cell_universe\n", - "\n", - "# Add boundary planes\n", - "root_cell.region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z\n", - "\n", - "# Create root Universe\n", - "root_universe = openmc.Universe(universe_id=0, name='root universe')\n", - "root_universe.add_cell(root_cell)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now must create a geometry that is assigned a root universe, put the geometry into a geometry file, and export it to XML." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Geometry and set root Universe\n", - "geometry = openmc.Geometry(root_universe)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Export to \"geometry.xml\"\n", - "geometry.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the geometry and materials finished, we now just need to define simulation parameters. In this case, we will use 5 inactive batches and 15 active batches each with 2500 particles." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "# OpenMC simulation parameters\n", - "batches = 20\n", - "inactive = 5\n", - "particles = 2500\n", - "\n", - "# Instantiate a Settings object\n", - "settings_file = openmc.Settings()\n", - "settings_file.batches = batches\n", - "settings_file.inactive = inactive\n", - "settings_file.particles = particles\n", - "settings_file.output = {'tallies': True}\n", - "\n", - "# Create an initial uniform spatial source distribution over fissionable zones\n", - "bounds = [-0.63, -0.63, -100., 0.63, 0.63, 100.]\n", - "uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True)\n", - "settings_file.source = openmc.Source(space=uniform_dist)\n", - "\n", - "# Export to \"settings.xml\"\n", - "settings_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us also create a plot file that we can use to verify that our pin cell geometry was created successfully." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD6AgMAAAD1grKuAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAADFBMVEVyEhLpgJFNv8T///98iBL0AAAAAWJLR0QDEQxM8gAAAAd0SU1FB+MHEhEzAhO1TdMAAAKlSURBVGje7ZrBscIwDETxwSWkn5TAgXCgBPqhBA6kyj/fDhCIJa2zZAwz0pmHpZWdSazd7Tw8PDw8PDw8vinCMBzW03HIsRLvhnv0HL7qD+IwjzXKzaNaxeEt9kz21RWEBV5XQbfka3pQWL4qgdLyNQkUcbwFT/FP4zjWt+D+++OY4laZQJgtnqNOwe5l9XkGmIIL/PEHUAGTeuc5P15wBbu34ucSIAXkX77h4xUtIBSXnxIAOhCLy98TANNfLj8lYBYQCuLPWmAWEBe9f90DUPdKy08JWB0U1HsoaAgQxPSnAgwBopz+VABQvoDnAnqTP0r8zealzfPcQqqAQSs/C6AKGLX0pwKs8uX0cwGaAHr6uYC9wSt46qDCB4RXBDTkMwWMhnxZQF3+s8pf1AZY5VsCWuVnAUQ+YPxB43X5koAiH035soCa/AaeBOw34m359AaQPCK/1oAAyJ8aIPBI+7QGRkD+3IBt+A6QPzeg34SH2pcauN+Kt9uXGljkse0jb6BP8AD+vwGKPLZ95A0UofbnDbAFj20/eQN+gD8h/LgRD25/8QCA2088AD/Oo8dPOoDo8ZMOoPPNeej4pwdAgUcfX9IDzHnnf5lnz88XnH/nSf4M8cIL7I+/P3yCP0G88P7W+v2z9ft36+8P9vuJ/X5r/f3Jfj83//5vff/R+v6Hvb9i78/Y+7vW94/N71/Z+2P2/pq9P2fv7+n5ATu/YOcn7PyGnR+x8yt6ftYN3PzOENCcH7LzS3Z+Ss9vO62DV5uPmgAXSz5+fs7O72n/QBQLwPwLrH+C9W/Q/hHWv8L6Z2j/ThZgvX+I9S/R/inWv8X6x2j/Guufo/17rH+Q9S/S/knWv0n7R2n/Kuufpf27tH+Y9i/vWP+0h4eHh4eHh8cW8QcxLJDBvLKoigAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOS0wNy0xOFQyMjo1MTowMi0wNTowMAMmdtQAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTktMDctMThUMjI6NTE6MDItMDU6MDBye85oAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Instantiate a Plot\n", - "plot = openmc.Plot(plot_id=1)\n", - "plot.filename = 'materials-xy'\n", - "plot.origin = [0, 0, 0]\n", - "plot.width = [1.26, 1.26]\n", - "plot.pixels = [250, 250]\n", - "plot.color_by = 'material'\n", - "\n", - "# Show plot\n", - "openmc.plot_inline(plot)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As we can see from the plot, we have a nice pin cell with fuel, cladding, and water! Before we run our simulation, we need to tell the code what we want to tally. The following code shows how to create a variety of tallies." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate an empty Tallies object\n", - "tallies_file = openmc.Tallies()" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Tallies to compute microscopic multi-group cross-sections\n", - "\n", - "# Instantiate energy filter for multi-group cross-section Tallies\n", - "energy_filter = openmc.EnergyFilter([0., 0.625, 20.0e6])\n", - "\n", - "# Instantiate flux Tally in moderator and fuel\n", - "tally = openmc.Tally(name='flux')\n", - "tally.filters = [openmc.CellFilter([fuel_cell, moderator_cell])]\n", - "tally.filters.append(energy_filter)\n", - "tally.scores = ['flux']\n", - "tallies_file.append(tally)\n", - "\n", - "# Instantiate reaction rate Tally in fuel\n", - "tally = openmc.Tally(name='fuel rxn rates')\n", - "tally.filters = [openmc.CellFilter(fuel_cell)]\n", - "tally.filters.append(energy_filter)\n", - "tally.scores = ['nu-fission', 'scatter']\n", - "tally.nuclides = ['U238', 'U235']\n", - "tallies_file.append(tally)\n", - "\n", - "# Instantiate reaction rate Tally in moderator\n", - "tally = openmc.Tally(name='moderator rxn rates')\n", - "tally.filters = [openmc.CellFilter(moderator_cell)]\n", - "tally.filters.append(energy_filter)\n", - "tally.scores = ['absorption', 'total']\n", - "tally.nuclides = ['O16', 'H1']\n", - "tallies_file.append(tally)\n", - "\n", - "# Instantiate a tally mesh\n", - "mesh = openmc.RegularMesh(mesh_id=1)\n", - "mesh.dimension = [1, 1, 1]\n", - "mesh.lower_left = [-0.63, -0.63, -100.]\n", - "mesh.width = [1.26, 1.26, 200.]\n", - "meshsurface_filter = openmc.MeshSurfaceFilter(mesh)\n", - "\n", - "# Instantiate thermal, fast, and total leakage tallies\n", - "leak = openmc.Tally(name='leakage')\n", - "leak.filters = [meshsurface_filter]\n", - "leak.scores = ['current']\n", - "tallies_file.append(leak)\n", - "\n", - "thermal_leak = openmc.Tally(name='thermal leakage')\n", - "thermal_leak.filters = [meshsurface_filter, openmc.EnergyFilter([0., 0.625])]\n", - "thermal_leak.scores = ['current']\n", - "tallies_file.append(thermal_leak)\n", - "\n", - "fast_leak = openmc.Tally(name='fast leakage')\n", - "fast_leak.filters = [meshsurface_filter, openmc.EnergyFilter([0.625, 20.0e6])]\n", - "fast_leak.scores = ['current']\n", - "tallies_file.append(fast_leak)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "# K-Eigenvalue (infinity) tallies\n", - "fiss_rate = openmc.Tally(name='fiss. rate')\n", - "abs_rate = openmc.Tally(name='abs. rate')\n", - "fiss_rate.scores = ['nu-fission']\n", - "abs_rate.scores = ['absorption']\n", - "tallies_file += (fiss_rate, abs_rate)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "# Resonance Escape Probability tallies\n", - "therm_abs_rate = openmc.Tally(name='therm. abs. rate')\n", - "therm_abs_rate.scores = ['absorption']\n", - "therm_abs_rate.filters = [openmc.EnergyFilter([0., 0.625])]\n", - "tallies_file.append(therm_abs_rate)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# Thermal Flux Utilization tallies\n", - "fuel_therm_abs_rate = openmc.Tally(name='fuel therm. abs. rate')\n", - "fuel_therm_abs_rate.scores = ['absorption']\n", - "fuel_therm_abs_rate.filters = [openmc.EnergyFilter([0., 0.625]),\n", - " openmc.CellFilter([fuel_cell])]\n", - "tallies_file.append(fuel_therm_abs_rate)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "# Fast Fission Factor tallies\n", - "therm_fiss_rate = openmc.Tally(name='therm. fiss. rate')\n", - "therm_fiss_rate.scores = ['nu-fission']\n", - "therm_fiss_rate.filters = [openmc.EnergyFilter([0., 0.625])]\n", - "tallies_file.append(therm_fiss_rate)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# Instantiate energy filter to illustrate Tally slicing\n", - "fine_energy_filter = openmc.EnergyFilter(np.logspace(np.log10(1e-2), np.log10(20.0e6), 10))\n", - "\n", - "# Instantiate flux Tally in moderator and fuel\n", - "tally = openmc.Tally(name='need-to-slice')\n", - "tally.filters = [openmc.CellFilter([fuel_cell, moderator_cell])]\n", - "tally.filters.append(fine_energy_filter)\n", - "tally.scores = ['nu-fission', 'scatter']\n", - "tally.nuclides = ['H1', 'U238']\n", - "tallies_file.append(tally)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=6.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=3.\n", - " warn(msg, IDWarning)\n", - "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", - " warn(msg, IDWarning)\n" - ] - } - ], - "source": [ - "# Export to \"tallies.xml\"\n", - "tallies_file.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we a have a complete set of inputs, so we can go ahead and run our simulation." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2019 MIT and OpenMC contributors\n", - " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.11.0-dev\n", - " Git SHA1 | 61c911cffdae2406f9f4bc667a9a6954748bb70c\n", - " Date/Time | 2019-07-18 22:51:02\n", - " OpenMP Threads | 4\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading U235 from /opt/data/hdf5/nndc_hdf5_v15/U235.h5\n", - " Reading U238 from /opt/data/hdf5/nndc_hdf5_v15/U238.h5\n", - " Reading O16 from /opt/data/hdf5/nndc_hdf5_v15/O16.h5\n", - " Reading H1 from /opt/data/hdf5/nndc_hdf5_v15/H1.h5\n", - " Reading B10 from /opt/data/hdf5/nndc_hdf5_v15/B10.h5\n", - " Reading Zr90 from /opt/data/hdf5/nndc_hdf5_v15/Zr90.h5\n", - " Maximum neutron transport energy: 20000000.000000 eV for U235\n", - " Reading tallies XML file...\n", - " Writing summary.h5 file...\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 0.96168\n", - " 2/1 0.96651\n", - " 3/1 1.00678\n", - " 4/1 0.98773\n", - " 5/1 1.01883\n", - " 6/1 1.02959\n", - " 7/1 0.99859 1.01409 +/- 0.01550\n", - " 8/1 1.03441 1.02086 +/- 0.01123\n", - " 9/1 1.06097 1.03089 +/- 0.01279\n", - " 10/1 1.06132 1.03698 +/- 0.01163\n", - " 11/1 1.04687 1.03863 +/- 0.00964\n", - " 12/1 1.02982 1.03737 +/- 0.00824\n", - " 13/1 1.03520 1.03710 +/- 0.00714\n", - " 14/1 0.99508 1.03243 +/- 0.00784\n", - " 15/1 1.03987 1.03317 +/- 0.00705\n", - " 16/1 1.02743 1.03265 +/- 0.00640\n", - " 17/1 1.02975 1.03241 +/- 0.00585\n", - " 18/1 0.99671 1.02966 +/- 0.00604\n", - " 19/1 1.02040 1.02900 +/- 0.00563\n", - " 20/1 1.02024 1.02842 +/- 0.00527\n", - " Creating state point statepoint.20.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 3.4427e-01 seconds\n", - " Reading cross sections = 3.1628e-01 seconds\n", - " Total time in simulation = 3.7319e+00 seconds\n", - " Time in transport only = 3.6302e+00 seconds\n", - " Time in inactive batches = 4.9601e-01 seconds\n", - " Time in active batches = 3.2359e+00 seconds\n", - " Time synchronizing fission bank = 2.8100e-03 seconds\n", - " Sampling source sites = 2.4682e-03 seconds\n", - " SEND/RECV source sites = 3.2484e-04 seconds\n", - " Time accumulating tallies = 4.4538e-05 seconds\n", - " Total time for finalization = 9.3656e-04 seconds\n", - " Total time elapsed = 4.0859e+00 seconds\n", - " Calculation Rate (inactive) = 25201.2 particles/second\n", - " Calculation Rate (active) = 11588.7 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 1.02889 +/- 0.00492\n", - " k-effective (Track-length) = 1.02842 +/- 0.00527\n", - " k-effective (Absorption) = 1.02637 +/- 0.00349\n", - " Combined k-effective = 1.02700 +/- 0.00291\n", - " Leakage Fraction = 0.01717 +/- 0.00107\n", - "\n" - ] - } - ], - "source": [ - "# Run OpenMC!\n", - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tally Data Processing" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Our simulation ran successfully and created a statepoint file with all the tally data in it. We begin our analysis here loading the statepoint file and 'reading' the results. By default, the tally results are not read into memory because they might be large, even large enough to exceed the available memory on a computer." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Load the statepoint file\n", - "sp = openmc.StatePoint('statepoint.20.h5')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We have a tally of the total fission rate and the total absorption rate, so we can calculate k-eff as:\n", - "$$k_{eff} = \\frac{\\langle \\nu \\Sigma_f \\phi \\rangle}{\\langle \\Sigma_a \\phi \\rangle + \\langle L \\rangle}$$\n", - "In this notation, $\\langle \\cdot \\rangle^a_b$ represents an OpenMC that is integrated over region $a$ and energy range $b$. If $a$ or $b$ is not reported, it means the value represents an integral over all space or all energy, respectively." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
nuclidescoremeanstd. dev.
0total(nu-fission / (absorption + current))1.0230020.006647
\n", - "
" - ], - "text/plain": [ - " nuclide score mean std. dev.\n", - "0 total (nu-fission / (absorption + current)) 1.02e+00 6.65e-03" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Get the fission and absorption rate tallies\n", - "fiss_rate = sp.get_tally(name='fiss. rate')\n", - "abs_rate = sp.get_tally(name='abs. rate')\n", - "\n", - "# Get the leakage tally\n", - "leak = sp.get_tally(name='leakage')\n", - "leak = leak.summation(filter_type=openmc.MeshSurfaceFilter, remove_filter=True)\n", - "\n", - "# Compute k-infinity using tally arithmetic\n", - "keff = fiss_rate / (abs_rate + leak)\n", - "keff.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that even though the neutron production rate, absorption rate, and current are separate tallies, we still get a first-order estimate of the uncertainty on the quotient of them automatically!\n", - "\n", - "Often in textbooks you'll see k-eff represented using the six-factor formula $$k_{eff} = p \\epsilon f \\eta P_{FNL} P_{TNL}.$$ Let's analyze each of these factors, starting with the resonance escape probability which is defined as $$p=\\frac{\\langle\\Sigma_a\\phi\\rangle_T + \\langle L \\rangle_T}{\\langle\\Sigma_a\\phi\\rangle + \\langle L \\rangle_T}$$ where the subscript $T$ means thermal energies." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energy low [eV]energy high [eV]nuclidescoremeanstd. dev.
00.00.625total((absorption + current) / (absorption + current))0.6943680.004606
\n", - "
" - ], - "text/plain": [ - " energy low [eV] energy high [eV] nuclide \\\n", - "0 0.00e+00 6.25e-01 total \n", - "\n", - " score mean std. dev. \n", - "0 ((absorption + current) / (absorption + current)) 6.94e-01 4.61e-03 " - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Compute resonance escape probability using tally arithmetic\n", - "therm_abs_rate = sp.get_tally(name='therm. abs. rate')\n", - "thermal_leak = sp.get_tally(name='thermal leakage')\n", - "thermal_leak = thermal_leak.summation(filter_type=openmc.MeshSurfaceFilter, remove_filter=True)\n", - "res_esc = (therm_abs_rate + thermal_leak) / (abs_rate + thermal_leak)\n", - "res_esc.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The fast fission factor can be calculated as\n", - "$$\\epsilon=\\frac{\\langle\\nu\\Sigma_f\\phi\\rangle}{\\langle\\nu\\Sigma_f\\phi\\rangle_T}$$" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energy low [eV]energy high [eV]nuclidescoremeanstd. dev.
00.00.625total(nu-fission / nu-fission)1.2030990.009615
\n", - "
" - ], - "text/plain": [ - " energy low [eV] energy high [eV] nuclide score \\\n", - "0 0.00e+00 6.25e-01 total (nu-fission / nu-fission) \n", - "\n", - " mean std. dev. \n", - "0 1.20e+00 9.61e-03 " - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Compute fast fission factor factor using tally arithmetic\n", - "therm_fiss_rate = sp.get_tally(name='therm. fiss. rate')\n", - "fast_fiss = fiss_rate / therm_fiss_rate\n", - "fast_fiss.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The thermal flux utilization is calculated as\n", - "$$f=\\frac{\\langle\\Sigma_a\\phi\\rangle^F_T}{\\langle\\Sigma_a\\phi\\rangle_T}$$\n", - "where the superscript $F$ denotes fuel." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energy low [eV]energy high [eV]cellnuclidescoremeanstd. dev.
00.00.6251total(absorption / absorption)0.7494230.006089
\n", - "
" - ], - "text/plain": [ - " energy low [eV] energy high [eV] cell nuclide score \\\n", - "0 0.00e+00 6.25e-01 1 total (absorption / absorption) \n", - "\n", - " mean std. dev. \n", - "0 7.49e-01 6.09e-03 " - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Compute thermal flux utilization factor using tally arithmetic\n", - "fuel_therm_abs_rate = sp.get_tally(name='fuel therm. abs. rate')\n", - "therm_util = fuel_therm_abs_rate / therm_abs_rate\n", - "therm_util.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The next factor is the number of fission neutrons produced per absorption in fuel, calculated as $$\\eta = \\frac{\\langle \\nu\\Sigma_f\\phi \\rangle_T}{\\langle \\Sigma_a \\phi \\rangle^F_T}$$" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energy low [eV]energy high [eV]cellnuclidescoremeanstd. dev.
00.00.6251total(nu-fission / absorption)1.6637270.014403
\n", - "
" - ], - "text/plain": [ - " energy low [eV] energy high [eV] cell nuclide score \\\n", - "0 0.00e+00 6.25e-01 1 total (nu-fission / absorption) \n", - "\n", - " mean std. dev. \n", - "0 1.66e+00 1.44e-02 " - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Compute neutrons produced per absorption (eta) using tally arithmetic\n", - "eta = therm_fiss_rate / fuel_therm_abs_rate\n", - "eta.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are two leakage factors to account for fast and thermal leakage. The fast non-leakage probability is computed as $$P_{FNL} = \\frac{\\langle \\Sigma_a\\phi \\rangle + \\langle L \\rangle_T}{\\langle \\Sigma_a \\phi \\rangle + \\langle L \\rangle}$$" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energy low [eV]energy high [eV]nuclidescoremeanstd. dev.
00.00.625total((absorption + current) / (absorption + current))0.9846680.005509
\n", - "
" - ], - "text/plain": [ - " energy low [eV] energy high [eV] nuclide \\\n", - "0 0.00e+00 6.25e-01 total \n", - "\n", - " score mean std. dev. \n", - "0 ((absorption + current) / (absorption + current)) 9.85e-01 5.51e-03 " - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p_fnl = (abs_rate + thermal_leak) / (abs_rate + leak)\n", - "p_fnl.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The final factor is the thermal non-leakage probability and is computed as $$P_{TNL} = \\frac{\\langle \\Sigma_a\\phi \\rangle_T}{\\langle \\Sigma_a \\phi \\rangle_T + \\langle L \\rangle_T}$$" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energy low [eV]energy high [eV]nuclidescoremeanstd. dev.
00.00.625total(absorption / (absorption + current))0.9974390.007548
\n", - "
" - ], - "text/plain": [ - " energy low [eV] energy high [eV] nuclide \\\n", - "0 0.00e+00 6.25e-01 total \n", - "\n", - " score mean std. dev. \n", - "0 (absorption / (absorption + current)) 9.97e-01 7.55e-03 " - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "p_tnl = therm_abs_rate / (therm_abs_rate + thermal_leak)\n", - "p_tnl.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can calculate $k_{eff}$ using the product of the factors form the four-factor formula." - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
energy low [eV]energy high [eV]cellnuclidescoremeanstd. dev.
00.00.6251total(((((((absorption + current) / (absorption + c...1.0230020.018791
\n", - "
" - ], - "text/plain": [ - " energy low [eV] energy high [eV] cell nuclide \\\n", - "0 0.00e+00 6.25e-01 1 total \n", - "\n", - " score mean std. dev. \n", - "0 (((((((absorption + current) / (absorption + c... 1.02e+00 1.88e-02 " - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "keff = res_esc * fast_fiss * therm_util * eta * p_fnl * p_tnl\n", - "keff.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that the value we've obtained here has exactly the same mean as before. However, because of the way it was calculated, the standard deviation appears to be larger.\n", - "\n", - "Let's move on to a more complicated example now. Before we set up tallies to get reaction rates in the fuel and moderator in two energy groups for two different nuclides. We can use tally arithmetic to divide each of these reaction rates by the flux to get microscopic multi-group cross sections." - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": { - "scrolled": true - }, - "outputs": [], - "source": [ - "# Compute microscopic multi-group cross-sections\n", - "flux = sp.get_tally(name='flux')\n", - "flux = flux.get_slice(filters=[openmc.CellFilter], filter_bins=[(fuel_cell.id,)])\n", - "fuel_rxn_rates = sp.get_tally(name='fuel rxn rates')\n", - "mod_rxn_rates = sp.get_tally(name='moderator rxn rates')" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01(U238 / total)(nu-fission / flux)6.659486e-075.627975e-09
110.0006.250000e-01(U238 / total)(scatter / flux)2.099901e-011.748379e-03
210.0006.250000e-01(U235 / total)(nu-fission / flux)3.566329e-013.030782e-03
310.0006.250000e-01(U235 / total)(scatter / flux)5.555466e-034.635318e-05
410.6252.000000e+07(U238 / total)(nu-fission / flux)7.251304e-035.161998e-05
510.6252.000000e+07(U238 / total)(scatter / flux)2.272661e-019.576939e-04
610.6252.000000e+07(U235 / total)(nu-fission / flux)7.920169e-035.751231e-05
710.6252.000000e+07(U235 / total)(scatter / flux)3.358280e-031.341281e-05
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide \\\n", - "0 1 0.00e+00 6.25e-01 (U238 / total) \n", - "1 1 0.00e+00 6.25e-01 (U238 / total) \n", - "2 1 0.00e+00 6.25e-01 (U235 / total) \n", - "3 1 0.00e+00 6.25e-01 (U235 / total) \n", - "4 1 6.25e-01 2.00e+07 (U238 / total) \n", - "5 1 6.25e-01 2.00e+07 (U238 / total) \n", - "6 1 6.25e-01 2.00e+07 (U235 / total) \n", - "7 1 6.25e-01 2.00e+07 (U235 / total) \n", - "\n", - " score mean std. dev. \n", - "0 (nu-fission / flux) 6.66e-07 5.63e-09 \n", - "1 (scatter / flux) 2.10e-01 1.75e-03 \n", - "2 (nu-fission / flux) 3.57e-01 3.03e-03 \n", - "3 (scatter / flux) 5.56e-03 4.64e-05 \n", - "4 (nu-fission / flux) 7.25e-03 5.16e-05 \n", - "5 (scatter / flux) 2.27e-01 9.58e-04 \n", - "6 (nu-fission / flux) 7.92e-03 5.75e-05 \n", - "7 (scatter / flux) 3.36e-03 1.34e-05 " - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "fuel_xs = fuel_rxn_rates / flux\n", - "fuel_xs.get_pandas_dataframe()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that when the two tallies with multiple bins were divided, the derived tally contains the outer product of the combinations. If the filters/scores are the same, no outer product is needed. The `get_values(...)` method allows us to obtain a subset of tally scores. In the following example, we obtain just the neutron production microscopic cross sections." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[[6.65948580e-07]\n", - " [3.56632881e-01]]\n", - "\n", - " [[7.25130446e-03]\n", - " [7.92016892e-03]]]\n" - ] - } - ], - "source": [ - "# Show how to use Tally.get_values(...) with a CrossScore\n", - "nu_fiss_xs = fuel_xs.get_values(scores=['(nu-fission / flux)'])\n", - "print(nu_fiss_xs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The same idea can be used not only for scores but also for filters and nuclides." - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[[0.00555547]]\n", - "\n", - " [[0.00335828]]]\n" - ] - } - ], - "source": [ - "# Show how to use Tally.get_values(...) with a CrossScore and CrossNuclide\n", - "u235_scatter_xs = fuel_xs.get_values(nuclides=['(U235 / total)'], \n", - " scores=['(scatter / flux)'])\n", - "print(u235_scatter_xs)" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[[0.22726611]\n", - " [0.00335828]]]\n" - ] - } - ], - "source": [ - "# Show how to use Tally.get_values(...) with a CrossFilter and CrossScore\n", - "fast_scatter_xs = fuel_xs.get_values(filters=[openmc.EnergyFilter], \n", - " filter_bins=[((0.625, 20.0e6),)], \n", - " scores=['(scatter / flux)'])\n", - "print(fast_scatter_xs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "A more advanced method is to use `get_slice(...)` to create a new derived tally that is a subset of an existing tally. This has the benefit that we can use `get_pandas_dataframe()` to see the tallies in a more human-readable format." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
010.0006.250000e-01U238nu-fission0.0000029.679304e-09
110.0006.250000e-01U235nu-fission0.8548055.239673e-03
210.6252.000000e+07U238nu-fission0.0829785.346135e-04
310.6252.000000e+07U235nu-fission0.0906325.981942e-04
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide score mean \\\n", - "0 1 0.00e+00 6.25e-01 U238 nu-fission 1.60e-06 \n", - "1 1 0.00e+00 6.25e-01 U235 nu-fission 8.55e-01 \n", - "2 1 6.25e-01 2.00e+07 U238 nu-fission 8.30e-02 \n", - "3 1 6.25e-01 2.00e+07 U235 nu-fission 9.06e-02 \n", - "\n", - " std. dev. \n", - "0 9.68e-09 \n", - "1 5.24e-03 \n", - "2 5.35e-04 \n", - "3 5.98e-04 " - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# \"Slice\" the nu-fission data into a new derived Tally\n", - "nu_fission_rates = fuel_rxn_rates.get_slice(scores=['nu-fission'])\n", - "nu_fission_rates.get_pandas_dataframe()" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
cellenergy low [eV]energy high [eV]nuclidescoremeanstd. dev.
031.000000e-021.080060e-01H1scatter4.5411880.025230
131.080060e-011.166529e+00H1scatter2.0013320.006754
231.166529e+001.259921e+01H1scatter1.6392920.011374
331.259921e+011.360790e+02H1scatter1.8216330.009590
431.360790e+021.469734e+03H1scatter2.0323950.009953
531.469734e+031.587401e+04H1scatter2.1207450.011090
631.587401e+041.714488e+05H1scatter2.1817090.013602
731.714488e+051.851749e+06H1scatter2.0136440.009219
831.851749e+062.000000e+07H1scatter0.3726400.002903
\n", - "
" - ], - "text/plain": [ - " cell energy low [eV] energy high [eV] nuclide score mean \\\n", - "0 3 1.00e-02 1.08e-01 H1 scatter 4.54e+00 \n", - "1 3 1.08e-01 1.17e+00 H1 scatter 2.00e+00 \n", - "2 3 1.17e+00 1.26e+01 H1 scatter 1.64e+00 \n", - "3 3 1.26e+01 1.36e+02 H1 scatter 1.82e+00 \n", - "4 3 1.36e+02 1.47e+03 H1 scatter 2.03e+00 \n", - "5 3 1.47e+03 1.59e+04 H1 scatter 2.12e+00 \n", - "6 3 1.59e+04 1.71e+05 H1 scatter 2.18e+00 \n", - "7 3 1.71e+05 1.85e+06 H1 scatter 2.01e+00 \n", - "8 3 1.85e+06 2.00e+07 H1 scatter 3.73e-01 \n", - "\n", - " std. dev. \n", - "0 2.52e-02 \n", - "1 6.75e-03 \n", - "2 1.14e-02 \n", - "3 9.59e-03 \n", - "4 9.95e-03 \n", - "5 1.11e-02 \n", - "6 1.36e-02 \n", - "7 9.22e-03 \n", - "8 2.90e-03 " - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# \"Slice\" the H-1 scatter data in the moderator Cell into a new derived Tally\n", - "need_to_slice = sp.get_tally(name='need-to-slice')\n", - "slice_test = need_to_slice.get_slice(scores=['scatter'], nuclides=['H1'],\n", - " filters=[openmc.CellFilter], filter_bins=[(moderator_cell.id,)])\n", - "slice_test.get_pandas_dataframe()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/triso.ipynb b/examples/jupyter/triso.ipynb deleted file mode 100644 index ae17ee3441a..00000000000 --- a/examples/jupyter/triso.ipynb +++ /dev/null @@ -1,366 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Modeling TRISO Particles\n", - "OpenMC includes a few convenience functions for generationing TRISO particle locations and placing them in a lattice. To be clear, this capability is not a stochastic geometry capability like that included in MCNP. It's also important to note that OpenMC does not use delta tracking, which would normally speed up calculations in geometries with tons of surfaces and cells. However, the computational burden can be eased by placing TRISO particles in a lattice." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "from math import pi\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import openmc\n", - "import openmc.model" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's first start by creating materials that will be used in our TRISO particles and the background material." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "fuel = openmc.Material(name='Fuel')\n", - "fuel.set_density('g/cm3', 10.5)\n", - "fuel.add_nuclide('U235', 4.6716e-02)\n", - "fuel.add_nuclide('U238', 2.8697e-01)\n", - "fuel.add_nuclide('O16', 5.0000e-01)\n", - "fuel.add_element('C', 1.6667e-01)\n", - "\n", - "buff = openmc.Material(name='Buffer')\n", - "buff.set_density('g/cm3', 1.0)\n", - "buff.add_element('C', 1.0)\n", - "buff.add_s_alpha_beta('c_Graphite')\n", - "\n", - "PyC1 = openmc.Material(name='PyC1')\n", - "PyC1.set_density('g/cm3', 1.9)\n", - "PyC1.add_element('C', 1.0)\n", - "PyC1.add_s_alpha_beta('c_Graphite')\n", - "\n", - "PyC2 = openmc.Material(name='PyC2')\n", - "PyC2.set_density('g/cm3', 1.87)\n", - "PyC2.add_element('C', 1.0)\n", - "PyC2.add_s_alpha_beta('c_Graphite')\n", - "\n", - "SiC = openmc.Material(name='SiC')\n", - "SiC.set_density('g/cm3', 3.2)\n", - "SiC.add_element('C', 0.5)\n", - "SiC.add_element('Si', 0.5)\n", - "\n", - "graphite = openmc.Material()\n", - "graphite.set_density('g/cm3', 1.1995)\n", - "graphite.add_element('C', 1.0)\n", - "graphite.add_s_alpha_beta('c_Graphite')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To actually create individual TRISO particles, we first need to create a universe that will be used within each particle. The reason we use the same universe for each TRISO particle is to reduce the total number of cells/surfaces needed which can substantially improve performance over using unique cells/surfaces in each." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Create TRISO universe\n", - "spheres = [openmc.Sphere(r=1e-4*r)\n", - " for r in [215., 315., 350., 385.]]\n", - "cells = [openmc.Cell(fill=fuel, region=-spheres[0]),\n", - " openmc.Cell(fill=buff, region=+spheres[0] & -spheres[1]),\n", - " openmc.Cell(fill=PyC1, region=+spheres[1] & -spheres[2]),\n", - " openmc.Cell(fill=SiC, region=+spheres[2] & -spheres[3]),\n", - " openmc.Cell(fill=PyC2, region=+spheres[3])]\n", - "triso_univ = openmc.Universe(cells=cells)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, we need a region to pack the TRISO particles in. We will use a 1 cm x 1 cm x 1 cm box centered at the origin." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "min_x = openmc.XPlane(x0=-0.5, boundary_type='reflective')\n", - "max_x = openmc.XPlane(x0=0.5, boundary_type='reflective')\n", - "min_y = openmc.YPlane(y0=-0.5, boundary_type='reflective')\n", - "max_y = openmc.YPlane(y0=0.5, boundary_type='reflective')\n", - "min_z = openmc.ZPlane(z0=-0.5, boundary_type='reflective')\n", - "max_z = openmc.ZPlane(z0=0.5, boundary_type='reflective')\n", - "region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we need to randomly select locations for the TRISO particles. In this example, we will select locations at random within the box with a packing fraction of 30%. Note that `pack_spheres` can handle up to the theoretical maximum of 60% (it will just be slow)." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "outer_radius = 425.*1e-4\n", - "centers = openmc.model.pack_spheres(radius=outer_radius, region=region, pf=0.3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we have the locations of the TRISO particles determined and a universe that can be used for each particle, we can create the TRISO particles." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "trisos = [openmc.model.TRISO(outer_radius, triso_univ, center) for center in centers]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Each TRISO object actually **is** a Cell, in fact; we can look at the properties of the TRISO just as we would a cell:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Cell\n", - "\tID =\t6\n", - "\tName =\t\n", - "\tFill =\t1\n", - "\tRegion =\t-11\n", - "\tRotation =\tNone\n", - "\tTranslation =\t[-0.33455672 0.31790187 0.24135378]\n", - "\n" - ] - } - ], - "source": [ - "print(trisos[0])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's confirm that all our TRISO particles are within the box." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[-0.45718713 -0.45730405 -0.45725048]\n", - "[0.45705454 0.45743843 0.45741142]\n" - ] - } - ], - "source": [ - "centers = np.vstack([triso.center for triso in trisos])\n", - "print(centers.min(axis=0))\n", - "print(centers.max(axis=0))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can also look at what the actual packing fraction turned out to be:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.2996893513959326" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(trisos)*4/3*pi*outer_radius**3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we have our TRISO particles created, we need to place them in a lattice to provide optimal tracking performance in OpenMC. We can use the box we created above to place the lattice in. Actually creating a lattice containing TRISO particles can be done with the `model.create_triso_lattice()` function. This function requires that we give it a list of TRISO particles, the lower-left coordinates of the lattice, the pitch of each lattice cell, the overall shape of the lattice (number of cells in each direction), and a background material." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "box = openmc.Cell(region=region)\n", - "lower_left, upper_right = box.region.bounding_box\n", - "shape = (3, 3, 3)\n", - "pitch = (upper_right - lower_left)/shape\n", - "lattice = openmc.model.create_triso_lattice(\n", - " trisos, lower_left, pitch, shape, graphite)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can set the fill of our box cell to be the lattice:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "box.fill = lattice" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, let's take a look at our geometry by putting the box in a universe and plotting it. We're going to use the Fortran-side plotter since it's much faster." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "universe = openmc.Universe(cells=[box])\n", - "\n", - "geometry = openmc.Geometry(universe)\n", - "geometry.export_to_xml()\n", - "\n", - "materials = list(geometry.get_all_materials().values())\n", - "openmc.Materials(materials).export_to_xml()\n", - "\n", - "settings = openmc.Settings()\n", - "settings.run_mode = 'plot'\n", - "settings.export_to_xml()\n", - "\n", - "plot = openmc.Plot.from_geometry(geometry)\n", - "plot.to_ipython_image()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If we plot the universe by material rather than by cell, we can see that the entire background is just graphite." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "plot.color_by = 'material'\n", - "plot.colors = {graphite: 'gray'}\n", - "plot.to_ipython_image()" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.3" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/examples/jupyter/unstructured-mesh-part-i.ipynb b/examples/jupyter/unstructured-mesh-part-i.ipynb deleted file mode 100644 index 1b035fa8456..00000000000 --- a/examples/jupyter/unstructured-mesh-part-i.ipynb +++ /dev/null @@ -1,737 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Unstructured Mesh: Introduction\n", - "\n", - "In this example we'll look at how to setup and use unstructured mesh tallies in OpenMC. Unstructured meshes are able to provide results over spatial regions of a problem while conforming to a specific geometric features -- something that is often difficult to do using the regular and rectilinear meshes in OpenMC.\n", - "\n", - "Here, we'll apply an unstructured mesh tally to the PWR assembly model from the OpenMC examples.\n", - "\n", - "**_NOTE: This notebook will not run successfully if OpenMC has not been built with DAGMC or libMesh support enabled._**" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import Image\n", - "import openmc\n", - "import openmc.lib\n", - "\n", - "# ensure one of the two mesh librares is enabled\n", - "assert(openmc.lib._dagmc_enabled() or openmc.lib._libmesh_enabled())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We'll need to download the unstructured mesh file used in this notebook. We'll be retrieving those using the function and URLs below." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "from matplotlib import pyplot as plt\n", - "plt.rcParams[\"figure.figsize\"] = (30,10)\n", - "\n", - "import urllib.request\n", - "\n", - "pin_mesh_moab_url = 'https://tinyurl.com/u9ce9d7' # MOAB file - 22 MB\n", - "pin_mesh_libmesh_url = 'https://tinyurl.com/yysgs3tr' # Exodus file - 9.7 MB\n", - "\n", - "def download(url, filename='dagmc.h5m'):\n", - " \"\"\"\n", - " Helper function for retrieving dagmc models\n", - " \"\"\"\n", - " u = urllib.request.urlopen(url)\n", - " \n", - " if u.status != 200:\n", - " raise RuntimeError(\"Failed to download file.\")\n", - " \n", - " # save file as dagmc.h5m\n", - " with open(filename, 'wb') as f:\n", - " f.write(u.read())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First we'll import that model from the set of OpenMC examples." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "model = openmc.examples.pwr_assembly()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We'll make a couple of adjustments to this 2D model as it won't play very well with the 3D mesh we'll be looking at. First, we'll bound the pincell between +/- 10 cm in the Z dimension." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "min_z = openmc.ZPlane(z0=-10.0)\n", - "max_z = openmc.ZPlane(z0=10.0)\n", - "\n", - "z_region = +min_z & -max_z\n", - "\n", - "cells = model.geometry.get_all_cells()\n", - "for cell in cells.values():\n", - " cell.region &= z_region" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The other adjustment we'll make is to remove the reflective boundary conditions on the X and Y boundaries. (This is purely to generate a more interesting flux profile.)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "surfaces = model.geometry.get_all_surfaces()\n", - "# modify the boundary condition of the\n", - "# planar surfaces bounding the assembly\n", - "for surface in surfaces.values():\n", - " if isinstance(surface, openmc.Plane):\n", - " surface.boundary_type = 'vacuum'" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's take a quick look at the model to ensure our changs have been added properly." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "root_univ = model.geometry.root_universe\n", - "\n", - "# axial image\n", - "root_univ.plot(width=(22.0, 22.0),\n", - " pixels=(200, 300),\n", - " basis='xz',\n", - " color_by='material',\n", - " seed=0)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "# radial image\n", - "root_univ.plot(width=(22.0, 22.0),\n", - " pixels=(400, 400),\n", - " basis='xy',\n", - " color_by='material',\n", - " seed=0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looks good! Let's run some particles through the problem." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2020 MIT and OpenMC contributors\n", - " License | https://docs.openmc.org/en/latest/license.html\n", - " Version | 0.12.1-dev\n", - " Git SHA1 | e62681221a625ce7eb635df966826379fb4e9453\n", - " Date/Time | 2021-01-10 00:51:10\n", - " MPI Processes | 1\n", - " OpenMP Threads | 2\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading geometry XML file...\n", - " Reading U234 from /home/shriwise/opt/openmc/xs/nndc_hdf5/U234.h5\n", - " Reading U235 from /home/shriwise/opt/openmc/xs/nndc_hdf5/U235.h5\n", - " Reading U238 from /home/shriwise/opt/openmc/xs/nndc_hdf5/U238.h5\n", - " Reading O16 from /home/shriwise/opt/openmc/xs/nndc_hdf5/O16.h5\n", - " Reading Zr90 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Zr90.h5\n", - " Reading Zr91 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Zr91.h5\n", - " Reading Zr92 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Zr92.h5\n", - " Reading Zr94 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Zr94.h5\n", - " Reading Zr96 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Zr96.h5\n", - " Reading H1 from /home/shriwise/opt/openmc/xs/nndc_hdf5/H1.h5\n", - " Reading B10 from /home/shriwise/opt/openmc/xs/nndc_hdf5/B10.h5\n", - " Reading B11 from /home/shriwise/opt/openmc/xs/nndc_hdf5/B11.h5\n", - " Reading c_H_in_H2O from /home/shriwise/opt/openmc/xs/nndc_hdf5/c_H_in_H2O.h5\n", - " Minimum neutron data temperature: 294.0 K\n", - " Maximum neutron data temperature: 294.0 K\n", - " Preparing distributed cell instances...\n", - " Writing summary.h5 file...\n", - " Maximum neutron transport energy: 20000000.0 eV for U235\n", - " Initializing source particles...\n", - "\n", - " ====================> K EIGENVALUE SIMULATION <====================\n", - "\n", - " Bat./Gen. k Average k\n", - " ========= ======== ====================\n", - " 1/1 0.20444\n", - " 2/1 0.15502\n", - " 3/1 0.19804\n", - " 4/1 0.22159\n", - " 5/1 0.19776\n", - " 6/1 0.20086\n", - " 7/1 0.21896 0.20991 +/- 0.00905\n", - " 8/1 0.23134 0.21706 +/- 0.00885\n", - " 9/1 0.29029 0.23536 +/- 0.01935\n", - " 10/1 0.20094 0.22848 +/- 0.01649\n", - " Creating state point statepoint.10.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 2.1129e+00 seconds\n", - " Reading cross sections = 2.0943e+00 seconds\n", - " Total time in simulation = 1.1595e-01 seconds\n", - " Time in transport only = 1.1219e-01 seconds\n", - " Time in inactive batches = 5.8272e-02 seconds\n", - " Time in active batches = 5.7678e-02 seconds\n", - " Time synchronizing fission bank = 2.3802e-04 seconds\n", - " Sampling source sites = 1.3992e-04 seconds\n", - " SEND/RECV source sites = 2.9613e-05 seconds\n", - " Time accumulating tallies = 1.4423e-05 seconds\n", - " Time writing statepoints = 3.0105e-03 seconds\n", - " Total time for finalization = 4.0100e-06 seconds\n", - " Total time elapsed = 2.2442e+00 seconds\n", - " Calculation Rate (inactive) = 8580.51 particles/second\n", - " Calculation Rate (active) = 8668.78 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " k-effective (Collision) = 0.25094 +/- 0.02010\n", - " k-effective (Track-length) = 0.22848 +/- 0.01649\n", - " k-effective (Absorption) = 0.21556 +/- 0.04156\n", - " Combined k-effective = 0.20707 +/- 0.01965\n", - " Leakage Fraction = 0.79200 +/- 0.03382\n", - "\n" - ] - }, - { - "data": { - "text/plain": [ - "PosixPath('/home/shriwise/opt/openmc/openmc/examples/jupyter/statepoint.10.h5')" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now it's time to apply our mesh tally to the problem. We'll be using the tetrahedral mesh \"pins1-4.h5m\" shown below:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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F3WExhsn0dZW59wbszlUiB2rOdhRnETgE4qMmh2hufjii+m8886jvXv30ty5c2nXrl30yiuv0NFHH02nnXYazZ8/n6677jq6/PLL6ec//zmddNJJmXNceeWV1K1bN3rooYdoxIgR9Pzzz1PXrl1pw4YNdNNNN9EVV1xBCxYsoIsvvrjK97zzzqOLL76Y/vrXv9LcuXNp48aN9Oqrr1KnTp3ozDPPpKVLl9KVV15JV199Nc2bN4+6d+9e4d+5c2e69tprqX379vTQQw/RbbfdRr///e9p//791L17dxo/fjxNnDiRLrnkEnr44YfpxBNPbPR72RggyZWjJ0xymQxr4y+slzJJjj2S7pF7ubZGaLQYB9PZLwo0AqyRe6ID3XFPz9BGa6TOG5PxZN4IjUXkizpCg0ByK8dTmORqZNgi5nKPa2u0xRuh0fTeCA3qamGExiPsXhcbO+tWl1zmsHTaOA2Oulidd2smX6u/sXP2CQl5Rumuu+6quQ78ySefTH/3d39Hr7zyCvXt25feeOMN6t+/P/Xt25eOOeYY2r9/P73++uvUp08f6tevH/30pz+l73//+3TBBRdE5+jRowddddVV9Mtf/pIuvfRSOu+88+imm26irl270hFHHEHf/va3iYjozDPPpOnTp6u+e/fupS984Qv01FNPUf/+/emLX/widerUifbv30+7d++m6667js477zz62c9+Rg8++CD17NmTiOrHZr7+9a9Tly5daOHChTRr1izq3bs3feMb36CTTz6ZWrduTe+99x6dddZZdM0119DDDz9M//zP/0yf+9znDt2b3IDhw5Qu1913Vch5r8k5hlw3BTC3ZydrCvlYZ8orhhnnvfvuu6p0LIvR3d3wvsg17mUMzU/qLF/UafVZNWlnvzvHz3PY8GEV+7vvupuGDR9Wfo2Rcxy5bknIGrFeS4b6vGL4MPtcd919d5WeZZoO7TAHy9gf83uxPV8tlnWWUN1sO2zYMLr77vw+14QECzXZgb/kkkuIiGjAgAH0wQcf0He/+93ymAlR/V9sO+GEE8rjLRdddBGNHDkyE4E//fTTiYho3rx51KtXLxo5ciS1atWqHJ+IykT8/fffp44dOxIRUZs2bSrqe+aZZ2jmzJl0yimnVNTXrVs32r17N5133nnl+qZMmUJERGeccQZ16dKF/vM//5PmzJlD1157LV177bXlvERERx99NH388cdERHThhRfSmDFjmoTAe5DkViPxvJe6ECEO6TQCPXzY8Coirl0YtAsFniX2IpBHWORd08USes8PyTESe/nqEWm8FFgxvDN5Zy8KPLIrSTzb8h51GrH3ckhdVnusTYuBZ9H2RYdF3jUZklQeIvkAACAASURBVGgk5iy7C0ixjOn5anVpOq2u4cOGqbETEmoRNUfgu3TpQscccww9+uij9NBDD9GkSZMqyLvEX/7yFyIi+vDDD+nFF1/MlOenP/0p1dXV0aOPPkrjxo0rk3ei+k8AiIiefPJJ+vOf/0zt2rUr63r16kVHHnkkPf744/TDH/6QRo0aVUHeJd566y0iIurYsSPt27eP9u/fT6VSiXr16kVERKtWraIzzjiD+vfvX0HeGfv27Suf7//+7/8ynS8GFpHViDqRTeLRj23Rl+GRb602r9Mv91in9Lc+QSgqmSeyO+woj+mcawTZ03kd+CwxWCfXWr21BOy2WyRe6nAt7Xkt5ZYPyrxcGtn3uu7amWoBSNYtQow6y48RIulI8j3CreliLgteF967FCQkFAGtwibFwmmnnUZERPfddx+deeaZ9JnPfMa07dChAxER7d69m9q0yXbX+dvf/kaDBg2iDRs20DnnnFOWH3nkkXTRRRcREdHSpUupW7duFQSe69u6dSv16NHD7frv37+//PrSSy/Rnj17qFQq0Ycffkg/+9nP6F//9V/piiuuqLg8SPDF5emnn858voOFRaAlJFlHGybUWlce/TU/jCvtZFyv9tA4TZHJO5HdBcfxFCTHGuGXHXLea11zT67ttVihER3p6+UoIrRRGGs8RnbckWjzF8qsvZR7kJ1/K672SUBM7DyPz3iwxl40gq2RYiTzvMe1zGXVIMG+0l/GxVplfqvOhIRaQs114Pk3wtx///3BkRj+bS/PP/88de7cOXMuJsUnnHACHXnkkXTsscfS2WefTe3bt6f77ruP/umf/omGDh1a4dOlSxciIvrtb39Ll156qdo5ZzAB/5//+R/661//SkcffTTt37+fHnjgAdqwYQP16NGDevfurfq2atWKzjvvPCIi2rhxY6N+SDcrQmMmLLe626EOt9a1RxKvkXoN3oVAG6GxuvNFhzUOo823e/ask74o13y02XeENWaTZYTGq7dIsLrYRDa510ZpQp16jSzHjNBYcm20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kWcwiWZiy68s41eNCDOJLpNp4Ys2FtG3dEjutVhYu1ablEk7xpAhQ9QmU0JCEVBTBJ67zR999BG1b9/etGvdunWZwP/oRz8q/2XUEPgHQe+9917q2bOnOZpy/PHHExHRL37xi/KlAtGzZ0965513aN26dfTiiy/S5ZdfTuvXr6c//vGP9Pd///fUvXt3Gj58uHmxaNu2LV122WV06qmn0ksvvURf/vKX6bnnnqPRo0dTnz59os7TFEAiLMmyRo6lHeoruu1A7rcpRE/mQz+vRhkPa9YuHNa+qNDIM0Lrynsdbkm+NSKO+xCx17r3WjyWeXUWGZI041rKeC91GvnXYms6GRNllp8m12Jo9eMZiwyNACPZRUKPfmzDciTpWnfestVqs0i/Rsq1HAkJtYiaIvB/+9vfqG3btnT66adT69atTbtPfepTdMQRR9Bjjz1GL7zwAo0ePToq/r59+6hdu3b05JNP0nHHHacS+Hbt2tFZZ51FRPXjJ9oPqTKOOeYYuv7666lbt2509dVX0549e+iqq66i9u3b0/jx4yt++FWic+fOdNVVV1GnTp3owQcfpBtuuIE6duxIc+bMaZbf9x6C1oWXRD3UiccOuST3Wvc8RNrRl23wUqFdMqx8eIaiIkTYYzrjFomWryF4MSy91m338lpnLSKwc22ReGnPxBk75pJQa910q5OP9lZcJPneJwgoLwosEosdbJR73W2PRHs6rztv1RxzWbDqTUioVdQUgX/rrbfo5JNPphEjRtDDDz+sktnjjjuOLrzwQvr4449pzJgx1LNnT+ratWtZ3717d+rcuTO9/PLL9Pbbb1f4vvnmm3TSSSfRkCFDyj+MKtG6dWu69NJLqUOHDvRv//Zv9MADD9CECRPcmrt27UpXXnkl7du3j6666iras2cPzZo1q/xHphA9evSgSy+9lFq3bk133HEHzZs3j/r06UNDhgyhI444IvatalJYZBc73hqBltC64qhDP81Wq80i/RqJx/pqgbgzcDQFR0/YhvcaiddkMra0k7os9tIHO+xohzZFHKHxyKvWffcIPcs1GyuXdhGI6dBbOowr69bIepHIuwccmZFddo0Yx4zPyNiSRFud9pgxGMwv42v5E5FPSKixH2J95pln6OSTT6Zrr72WiIj+/Oc/0wcffEBERB06dKAzzzyTzj33XGrdujUtWbKE/uu/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xvCxJGuvP7sffxxDh1TdJxe5ux+ves6Amnum2N2PV339rHkAMHTo0Pha+5ppwnr344/H59tlHOVCFMXrkp/XNXTIkNSina+XtefVcWpLvShlOkbTrl07jBw5EosXL84T8JWVlejWrRsAYPXq1fjZz36G2267LdUHXhuaFi1aAAB+85vfxL85p7bQ781/+umncf311+edVW/Tpg0AYN++fSgrqznxdM4556Bx48bYv38/1q1bh69//evmUZ633noLQNXG44033sDJkydzcjmOkz1I2HKBK4WyJqLlNY+na2635kibFqvl1Pxp7knGZQ0ufAkpiLlo5z5rHs/NH2MRLtaW8VadHDlP5pb3IGtzHEen3lrdhw8fRrt27VBRUYGuXbvi8OHDqKysBFDVGe7VqxcA4MCBA7jxxhsxfPhwjB8/vr7KqVOoA/+b3/wGl156aZ3kHDhwYE63HACaNm0ab3IWL16M3r17xz46knTfffehd+/ecQdG49SpU/HjSy+9hIMHD6Jjx451UrfjOGc3UkQPGTokKIz5nJAotzrf2ro0trr0IRHOBTuvK2n9LMIFNhfsUsQTshMvO/J8zK8tIc/navm1Gi2bnC9jHccJU28C/vXXX4/Phk+bNg179+6NBTr/a6sf/OAHUVZWhs9//vNF86Mx6sA/+eSTmDFjxmnlev3119G5c2csWrQIDz30ECoqKlBRUYE2bdqge/fuqKiowH/+539iz549+MEPfhDPo079U089hYkTJwa/dlTvM888gxMnTsRdfcdxsktI5GrCmYt42ekupHvO19bs2ljr8Fv5pZgvFSFviVwpgNOIYk24S5+2jvRzQt177Vqr07vvjpOeehPw/BjN+PHj8YMf/ADjx49Hhw4dcM455wAA7r33Xmzfvh333ntv3J0/22nSpAkqKirw4osv4tChQ6f9G2heeOEFvPjiixgwYADmzZuX4zt48CA+9alPYenSpZg3b15Ot58+JxBFUV7nXtK5c2cAwP3334/zzjsPjRo1Oq2aHccpDqTITRLldC2PyfA8Vree/FYNPJdcWzsWowl16SsV8c7RBK8m0LXOuCaOkzrf1nEbLYfllxsGXkvSXMdxdOrlQ6zEm2++iXbt2qFp06Zo164dTp06FQvep59+Gl/60pcwd+5cvP/976+3GuoaOrP+xBNPoFOnTqe18SgrK0OX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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": { - "image/png": { - "width": 600 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "Image(\"./images/pin_mesh.png\", width=600)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This mesh was generated using Trelis with radii that match the fuel/coolant channels of the PWR model. These four channels correspond to the highlighted channels of the assembly below.\n", - "\n", - "Two of the channels are coolant and the other two are fuel." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "from matplotlib.patches import Rectangle\n", - "from matplotlib import pyplot as plt\n", - "\n", - "pitch = 1.26 # cm\n", - "\n", - "img = root_univ.plot(width=(22.0, 22.0),\n", - " pixels=(600, 600),\n", - " basis='xy',\n", - " color_by='material',\n", - " seed=0)\n", - "\n", - "# highlight channels\n", - "for i in range(0, 4):\n", - " corner = (i * pitch - pitch / 2.0, -i * pitch - pitch / 2.0)\n", - " rect = Rectangle(corner,\n", - " pitch,\n", - " pitch,\n", - " edgecolor='blue',\n", - " fill=False)\n", - " img.axes.add_artist(rect)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Applying an unstructured mesh tally" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To use this mesh, we'll create an unstructured mesh instance and apply it to a mesh filter. We do this by specifying a mesh file and mesh library on an `UnstructuredMesh` object. The specified mesh library will be used to load the mesh file during simulation initialization. OpenMC must be built with support for the specified mesh library enabled." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "mesh_library = 'moab' # change to 'libmesh' to use libMesh instead\n", - "\n", - "if mesh_library == 'moab':\n", - " assert(openmc.lib._dagmc_enabled())\n", - " mesh_file = 'pins1-4.h5m'\n", - " mesh_url = pin_mesh_moab_url\n", - "elif mesh_library == 'libmesh':\n", - " assert(openmc.lib._libmesh_enabled())\n", - " mesh_file = 'pins1-4.e'\n", - " mesh_url = pin_mesh_libmesh_url\n", - " \n", - "# download the file and create the UnstructuredMesh object\n", - "download(mesh_url, mesh_file)\n", - "umesh = openmc.UnstructuredMesh(mesh_file, library=mesh_library)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Regardless of the library used to represent the mesh, we can apply this mesh object in a `MeshFilter`." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "mesh_filter = openmc.MeshFilter(umesh)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now apply this filter like any other. For this demonstration we'll score both the flux and heating in these pins." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "tally = openmc.Tally()\n", - "tally.filters = [mesh_filter]\n", - "tally.scores = ['heating', 'flux']\n", - "# Only collision estimators are supported for \n", - "if umesh.library == 'libmesh':\n", - " tally.estimator = 'collision'\n", - "model.tallies = [tally]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we'll run this model with the unstructured mesh tally applied. Notice that the simulation takes some time to start due to some additional data structures used by the unstructured mesh tally. Additionally, the particle rate drops dramatically during the active cycles of this simulation.\n", - "\n", - "Unstructured meshes are useful, but they can be computationally expensive!" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "PosixPath('/home/shriwise/opt/openmc/openmc/examples/jupyter/statepoint.100.h5')" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.settings.particles = 100_000\n", - "model.settings.inactive = 20\n", - "model.settings.batches = 100\n", - "model.run(output=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "At the end of the simulation, we see the statepoint file along with a file named \"tally_1.100.vtk\". This file contains the results of the unstructured mesh tally with convenient labels for the scores applied. In our case the following scores will be present in the VTK:\n", - "\n", - " - flux_total_value\n", - " - flux_total_std_dev\n", - " - heating_total_value\n", - " - heating_total_std_dev\n", - " \n", - "Where \"total\" represents the nuclide entry in the tally. If a set of nuclides are specified in the tally, a different score will be added to the VTK for each one in addition to \"total\".\n", - " \n", - "\n", - "Currently, an unstructured VTK file will only be generated for tallies if the unstructured mesh is is the only filter applied to that tally. All results for the unstructured mesh tally are present in the statepoint file regardless of the number of filters applied, however.\n", - "\n", - "These files can be viewed using free tools like [Paraview](https://www.paraview.org/) and [VisIt](https://wci.llnl.gov/simulation/computer-codes/visit/) to examine the results." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "tally_1.100.vtk\r\n" - ] - } - ], - "source": [ - "!ls *.vtk" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Flux" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkkAAARrCAYAAACXNDIzAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AACAASURBVHic7L1plFz1ee777Lnm6nlQSy21ECAxyoDt4xjjGJOVZF0ZEBjHIV44H669cuyEc72Sc9dJsA3YDo6z4iEHnOTknOUVk2tfO8cCYhuQGGSDubZDjAGBQJGExm71WNVd467a4/2wa9eeq7vVg4rq97fWXl2156n3fup53//7Z77zne+YpmliuazXMuu5Ldq/9V9mPbdF+7f+y6zntmj/1n+Z9dwW7d/6L7Oe22rX/WOXvXaCIAiCIIgNAIkkgiAIgiCIEEgkEQRBEARBhEAiiSAIgiAIIgQSSQRBEARBECGQSCIIgiAIggiBRBJBEARBEEQIJJIIgiAIgiBCIJFEEARBEAQRAokkgiAIgiCIEEgkEQRBEARBhEAiiSAIgiAIIgQSSQRBEARBECGQSCIIgiAIggiBRBJBEARBEEQIJJIIgiAIgiBCIJFEEARBEAQRAokkgiAIgiCIEEgkEQRBEARBhEAiiSAIgiAIIgQSSQRBEARBECGQSCIIgiAIggiBRBJBEARBEEQIJJIIgiAIgiBCIJFEEARBEAQRAokkgiAIgiCIEEgkEQRBEARBhEAiiSAIgiAIIgQSSQRBEARBECGQSCIIgiAIggiBRBJBEARBEEQIJJIIgiAIgiBCIJFEEARBrJi/+Iu/wL59+/Dd734Xv/jFL1Z13ffcc8+qretzn/vcqq2L6HxIJBEEQRCrwu233469e/fi6aefvtC7QhCrAn+hd4AgCILoDEzTxFtvvQVBEHDw4EGMj49jeHgYN910E37yk59gamoKPM9j586duPLKK3HPPffgL//yL5vL33PPPbjnnnvw5JNPQtd1sCyLgYEBAEC1WsWBAwegaRoAgGVZ/M7v/A4YhsH+/fuh6zp4nkdPTw9uuOEGyLKMAwcOQFVVz/w2Uev7q7/6K7zjHe/ANddcg61bt67XqSPaFBJJBEEQxKpwzz33QJIk/O7v/i4OHjyIu+66C6VSCa+99hoymQxuvPFGAMCzzz6LmZmZ0HXs27cPV1xxBd7xjncAAF566aXm+KuuugpXX301AOCVV17BI488AoZhcMUVV2D37t0AgJdffhnz8/N4/PHHcdVVV+Gqq64CALz66qt49NFHm9t55JFHcOWVVzbX557+nve8B0NDQ6t9eoi3ISSSCIIgiFXhgQceaH7u7u7Go48+iquuugrz8/P45S9/iUceeaQ5PZ1OAwAMwwDLsk1H5+TJk/jIRz7SnO/yyy/HI488glOnTnnG79q1Cz/60Y8AAHfccUdzvC2u/PPv3LmzOb893b2ce/rg4OAKzgLRSVBOEkEQBLHqnDp1CnfeeSeef/55jIyM4A//8A/xwAMP4IEHHsDHPvYx7Ny5Ez09PZicnAQAnD59GgAwNjaG119/vbmew4cPN8e/+eabzfFHjx7F6OgoxsbG8MYbbzTHv/baaygUCpHz24yNjeHIkSOh0xmGWc1TQbyNISeJIAiCWBP+9V//Fe9973txzTXX4JlnnsGLL74IjuMwMjKCXbt24fbbb8eBAweQyWSQyWQAWMnf+/fvx/Hjx8FxHDZt2gQAuO2227B//34cO3asuf7bb78dLMs259c0DcPDw7jyyis985um2VzHV77yFQDA3r17ceDAgcjpBAEAzHe+8x3TvkGWw3ots57bov1b/2XWc1u0f+u/zHpui/Zv/ZdZz23R/q3/Muu5rXbdPwq3EQRBEARBhEAiiSAIglgR3/3ud1Gv1z3jvv/970OW5RWt99VXX8VDDz20KsUkl1JEcrF5Pv/5z694PwDg3nvvXZX1EGsPiSSCIAhiRVx99dWeZOtyuQye5xGPx1e03h//+Me48847V7p7BHHeUOI2QRAEsSJ27tyJ733ve7j22msBWDWMrrnmGlQqFTz55JPQNA08z2N4eBiPP/44AODaa6/FtddeG1mw8Wc/+xmq1Sqee+655rjPfvaz+NKXvuT5/hu/8RvYvXs3BgYG8P3vfx933HEHRFFszqOqanObjz32GG644QY899xzniKSdrFLe57rr78ezz33HHRdB8dxGB4expNPPtnyHOzbtw+33HILeJ6Hoij48Y9/jN/+7d/GU0891VzP0NAQ9u/f31zm3nvvxX333df8ft999+Hee+/F888/j+npafA8j0svvRSXX375oteAWBvISSIIgiBWBMdx6OnpwdzcHEzTxKlTp7Bt2zbs27cPF110ET760Y/iwx/+MBKJRHOZ97znPU2B9PWvfz2wzve9730ArFZorfit3/ot/PSnP8WB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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": { - "image/png": { - "width": 600 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "Image(\"./images/umesh_flux.png\", width=600)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Heating\n", - "Here is an image of the heating score as viewed in VisIt. Note that no heating is scored in the water-filled channels as expected." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAkgAAAReCAYAAAAsQc8TAAAABHNCSVQICAgIfAhkiAAAABl0RVh0U29mdHdhcmUAZ25vbWUtc2NyZWVuc2hvdO8Dvz4AACAASURBVHic7L15mCR1me/7jT33ququhl6hQWRYBxBtYJTtKHRjCyoOj8tgt4ozA87jcs69c8+MyiKtzrln7jnIeBXXXljuoI/KJjTb0AoM0AttCypby9ZL9VJb7rHH/SMy9ojMrKrMqurK98OTD1WRv4j4RVZ2xje/7/t7X+aOO+6wMEEsa8K7THq/6dpnOs9F85v+fabzXDS/6d9nOs9F85v+fabzXDS/6d9nOs81kX3YCR+dIAiCIAhijkMCiSAIgiAIIgQJJIIgCIIgiBAkkAiCIAiCIEKQQCIIgiAIgghBAokgCIIgCCIECSSCIAiCIIgQJJAIgiAIgiBCkEAiCIIgCIIIQQKJIAiCIAgiBAkkgiAIgiCIECSQCIIgCIIgQpBAIgiCIAiCCEECiSAIgiAIIgQJJIIgCIIgiBAkkAiCIAiXr371q/jpT3+K733ve7jtttuwd+/eaTnv17/+9a4e/4Ybbujq8Ym5Bz/TEyAIgiBmF9dccw0A4I033sA999yDL37xizM8I4KYfkggEQRBELEsXrwYw8PDAIDt27fj2WefBQC85z3vwXnnnYc//elPeOqpp8CyLARBwPve9z6ccMIJAICvfe1r+Na3vuUey/ndsixs3boVL7zwAjiOA8MweN/73ueOsywL27ZtwwsvvACGYWCaJk4//XSsWLECAPDss8/ij3/8IwCA53msXLkSS5YsCezHsiwMw8Bpp52Gc845ByzLBo794osvxo654YYbcM4556Cvrw/vfe97u/8CE7MaEkgEQRBEhHq9jh07duCoo44CADz00EP48pe/DFEU8dvf/hZ79uzBq6++is9//vPgOA6GYWDz5s2QJAnLli1LPO5vf/tbDA0N4TOf+QxEUYQsy/jFL37hPv+b3/wGBw8exNq1ayGKIlRVxS9+8QvU63VYloXh4WF87nOfA8/zGB0dxa9+9Sv8zd/8DbZu3RrZ75e//CUURcFFF13knvvgwYNYs2aNO+ZXv/pVYMyJJ57oijyityGBRBAEQQT46le/CpZlMTg4iI997GMAgBUrVuDnP/85VqxYgZUrV+I3v/kNtm/fju3btwf25Xm+qUDatm0brr32WoiiCABIpVL40Ic+hJdfftl9/rrrrnOfF0URH/zgB/GjH/0IlmXh2muvBc/bt6558+bh85//fOxxRVHEZZddhh//+Meu+Nm+fTv+/u//vumY4447bqovHzFHIIFEEARBBPj2t78d2XbZZZehWCziiSeewO9//3uceuqpuPLKK3H22We7Y8rlMjiOA2ALJVmWkUqlUC6XA8cyTTPx3AzDRLZxHAfLsmKfa7Yfy7KwLGtCY5z5EwStYiMIgiBactttt8E0TVx00UV4++23cdppp+H5559HsVgEYIujO+64wx2/cOFC/PnPfwYAvPrqq+72c845Bw8++CAURQEAqKqKhx9+2H1+xYoVePDBB6GqKgBA13U8/PDDOPvss/Hud78bmzdvhqZpAICxsTHcddddkGUZK1aswEMPPRTY75FHHgkIuPe85z3YvHlz0zEE4UAOEkEQBNGSc845Bxs3bgTDMFi9ejVSqRQ+8pGP4L777oMsy7AsCx/60IeQyWQAAB/72Mdw33334ZlnnsHxxx/vHueCCy7Ajh07cPvtt7vJ0xdffDH+8Ic/AAAuvPBCbNu2DZs2bXKTtE8++WT81V/9FQDgueeew4YNG8AwDFiWxcqVK5FKpXDBBRdg+/bt2LRpk5uA7d/POff27dvdc8eNIQgH5o477rBaDwvityO7vd907TOd56L5Tf8+03kumt/07zOd56L5Tf8+03kumt/07zOd55rIPhRiIwiCIAiCCEECiSAIgiAIIgQJJIIgCAIAcOedd2JoaCiy/Ve/+hXeeOONjp2nW21Frr/++sDv3WovcuONN7Y99qabbprQsb/xjW9McDbtsW7duq4cdy5DAokgCIIAYCdih+saybKMAwcOYPny5TMzqSnw0Y9+dKanQBzB0Co2giAIAgBwwgkn4JFHHoGqqm4xxV27duGss84CwzCwLAvPPfccdu3aBZ7nwbIsLrroIvz0pz9124p87Wtfw7nnnov+/n6cdNJJWLBgQey5HnnkEezZswcMw+CKK65wx7300ktu+xKe5932JeEWJc65169fj+uuuw6PPPIIAGDDhg24+OKLsXz5ctx3330466yzcMMNN+DCCy/EW2+9BQC44oorMDg4CNM0sW3bNvzhD38Ax3HgOA4XXHAB1q9fH+vkDA0N4dFHHwUAbNq0CRdddBGOOeYYbN++HS+++KK76u7UU0/FMcccg8cffxwAcPvtt+PCCy/EMccc47Y64XkeDMPgggsuwKZNm9pype6++25cdtllKBQKAIDR0VE8/vjjuOqqq7B9+3b3OliWxfnnn4/bb7894qKtW7cu4LT5f3/llVfwzDPPuK/9ueeeG1iB2GuQQCIIgiAA2IUUzzjjDLz44os4++yzYVkWdu3ahc985jMA7DYg+/fvx+c+9zlIkgRFUXDPPfdEjnPSSSfhne98Z6Qfm59FixZh5cqV2LlzJ+6991787d/+Lfbu3YtXXnkF11xzjdu+5OGHH4YkSdi9ezeGhoawdu1aSJIEVVVx7733ArB7xn32s5/F9ddfj89+9rPuOfwFKRcuXIj3v//92LVrF+677z5cc801ePLJJzE8PIy1a9dCEASoqor7778/8fVZtGgR1q5dixtvvBFr164F4LUvufrqq932Jffccw8URcGaNWtw0003Yc2aNQCAJ598EkNDQ/j0pz/tvn4PPPBA23+fs88+Gzt37nSrfu/YsQPvfve78fTTT2NoaCgwh4kcFwD27duH3bt3Y82aNeA4DqZp4tFHH4UkSViyZMmEjjVXoBAbQRAE4fKud70LO3fuBADs3bsXCxcuRCqVAgBs3boVH/rQhyBJEgC7VceqVasix3BchyRxBNg9zwDgL/7iL7B//34AwGuvvYYdO3bgxhtvxNe//nXceOONbnPa7du3Y/Xq1S3PncQ73vEOALZL5pxvx44dWLlyJQRBcI95ySWXtH1MwG5fsmrVqkD7klWrVuH555+PjN2xYwcuu+yywDVM5HwnnHAC3njjDZimCU3TsGfPHhx33HHYsWNHZA4TvY4///nP2LlzJ7797W9j3bp1+Na3voXt27fjpZdemtBx5hLkIBEEQRAu2WwWfX19GBoawtatWyNd7cN1ZOLqyrTTrsMRXdls1q2MXSgUcOWVV+Jd73qXO85pX/L73/8+cq5mLUuSzpfL5dzzWZYVOYZhGG0fE2ivfYmDZVltvX7NznXiiSfi5ZdfhqIoOPXUU93zt3tcjuPcFjCVSsXdns/ncfnll+PMM890t5XLZbeYZy/Su1dOEARBxHLuuefiqaeeQrFYxKJFi9ztK1aswAMPPBBoE7J58+bE4zhOVLuceuqpeP7551EqlQDYN+g777wTgN0m5Ne//nXg3E7e0WQJtx5RFAVbtmyZ0jF0Xcdjjz0WEHkO7373u/HQQw8FrsHJaWqXM888E7/73e+wa9cuV8ycffbZePjhhwPHfeyxx2L3P/roo/Hmm28CAHbv3u1uP/nkk7Fr1y73ta9UKvjZz342obnNNchBIgiCIAIsW7YM9957L84///zA9osvvhjPPfcc1q9fD57n3W1Om5Awv/zlL2OFQhKpVAof/vCHce+990JRFFiWhdWrVyOTyeCiiy7C1q1bsWnTJtehuuiiixLP3Q7nn3++23rESdI+66yz8Nprr034GHfeeaebpH3SSSfhvPPOi4y94IILsG3bNtxxxx3uNVxwwQX405/+1Pb5stks0uk08vm864o5c7jrrrvc455//vmxx73iiivw0EMPYevWrYGVialUCqtXr3b75FmWhZUrV7qtY3oRajUyA+ei+U3/PtN5Lprf9O8zneei+U3/Pt0617PPPotXXnkFq1atwvz58zE+Po5HH30Uoijir//6r2d8fp3aZzrPNZfmRw4SQRAE0ZOce+65AICf/exnKBaLKBQKOOmkk3DxxRfHLru/4oorcPbZZ3d9XnElBi6//PIJuXHE1CEHaQbORfOb/n2m81w0v+nfZzrPRfOb/n2m81yTnd+BAwfw2GOPQZZlWJaFVCqFSy65BAsXLnTHHDx4MDLmAx/4AObNm4fHHnsMhw8fhmVZWLhwIT7wgQ+4q+uGhoawZcsWfOITn4hNCm/3uiqVCh599FGUSiVwHId8Po+VK1cinU67455++mls2bIF119/fc//fclBIgiCIIgp8u///u/4+Mc/7ia179+/H3fffTe+8pWvJI7Zt28f7r77brzjHe9APp/H6tWrAQCPPfYYHn30UaxevRqyLOOJJ57Axz72scTVce1y//334/jjj8eVV14JANi2bRvuuecefOpTnwIADA8PuwncBK1iIwiCIIgp4xSzHB8fR6lUwhtvvBFwZpLGZDIZvPTSS264DwDe+9734o9//CMA4J577sHBgwfxb//2b3jooYeg6zoA4OWXX8b69euxceNG3HXXXXj99dcjc7r55psDv7/99ts45ZRT3N/POOMMt7q4ZVnYvHnzhGpLzXXIQSIIgiCIKXLVVVfhBz/4Af7jP/4DACAIAr7whS+0HHPddddhw4YNUBTFXZWmqiokScLOnTthGAau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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 17, - "metadata": { - "image/png": { - "width": 600 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "Image(\"./images/umesh_heating.png\", width=600)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Statepoint Data" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "with openmc.StatePoint(\"statepoint.100.h5\") as sp:\n", - " tally = sp.tallies[1]\n", - " umesh = sp.meshes[1]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Enough information for visualization of results on the unstructured mesh is also provided in the statepoint file. Namely, the mesh element volumes and centroids are available." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1.43381086e-04 1.48043747e-04 1.60408339e-04 ... 7.04197023e-05\n", - " 7.04197023e-05 7.04197023e-05]\n", - "[[ 2.88485691 -2.55429784 9.97768184]\n", - " [ 2.87565092 -2.60469781 9.8884092 ]\n", - " [ 2.85832254 -2.65291228 9.97768184]\n", - " ...\n", - " [ 1.46082175 -1.15569203 -3.62914358]\n", - " [ 1.4443143 -1.1321793 -3.65475081]\n", - " [ 1.46884412 -1.15657736 -3.68206543]]\n" - ] - } - ], - "source": [ - "print(umesh.volumes)\n", - "print(umesh.centroids)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The combination of these values can provide for an appoxmiate visualization of the unstructured mesh without its explicit representation or use of an additional mesh library.\n", - "\n", - "We hope you've found this example notebook useful!" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": { - "image/png": { - "width": 600 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "Image(\"./images/umesh_w_assembly.png\", width=600)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/jupyter/unstructured-mesh-part-ii.ipynb b/examples/jupyter/unstructured-mesh-part-ii.ipynb deleted file mode 100644 index 478417970ed..00000000000 --- a/examples/jupyter/unstructured-mesh-part-ii.ipynb +++ /dev/null @@ -1,646 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Unstructured Mesh: Tallies with CAD and Point Cloud Visualization\n", - "\n", - "In the first notebook on this topic, we looked at how to set up a tally using an unstructured mesh in OpenMC.\n", - "In this notebook, we will explore using unstructured mesh in conjunction with CAD-based geometry to perform detailed geometry analysis on complex geomerty.\n", - "\n", - "_**NOTE: This notebook will not run successfully if OpenMC has not been built with DAGMC support enabled.**_" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from IPython.display import Image\n", - "import openmc\n", - "import openmc.lib\n", - "\n", - "assert(openmc.lib._dagmc_enabled())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We'll need to download our DAGMC geometry and unstructured mesh files. We'll be retrieving those using the function and URLs below." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import display, clear_output\n", - "import urllib.request\n", - "\n", - "manifold_geom_url = 'https://tinyurl.com/rp7grox' # 99 MB\n", - "manifold_mesh_url = 'https://tinyurl.com/wojemuh' # 5.4 MB\n", - "\n", - " \n", - "def download(url, filename):\n", - " \"\"\"\n", - " Helper function for retrieving dagmc models\n", - " \"\"\"\n", - " def progress_hook(count, block_size, total_size):\n", - " prog_percent = 100 * count * block_size / total_size\n", - " prog_percent = min(100., prog_percent)\n", - " clear_output(wait=True)\n", - " display('Downloading {}: {:.1f}%'.format(filename, prog_percent))\n", - " \n", - " urllib.request.urlretrieve(url, filename, progress_hook)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The model we'll be looking at in this example is a steel piping manifold:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 3, - "metadata": { - "image/png": { - "width": 800 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "Image(\"./images/manifold-cad.png\", width=800)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This is a nice example of a model which would be extremely difficult to model using CSG. To get started, we'll need two files: \n", - " 1. the DAGMC gometry file on which we'll track particles and \n", - " 2. a tetrahedral mesh of the piping structure on which we'll score tallies\n", - " \n", - "To start, let's create the materials we'll need for this problem. The pipes are steel and we'll model the surrounding area as air." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "air = openmc.Material(name='air')\n", - "air.set_density('g/cc', 0.001205)\n", - "air.add_element('N', 0.784431)\n", - "air.add_element('O', 0.210748)\n", - "air.add_element('Ar',0.0046)\n", - "\n", - "steel = openmc.Material(name='steel')\n", - "steel.set_density('g/cc', 8.0)\n", - "steel.add_element('Si', 0.010048)\n", - "steel.add_element('S', 0.00023)\n", - "steel.add_element('Fe', 0.669)\n", - "steel.add_element('Ni', 0.12)\n", - "steel.add_element('Mo', 0.025)\n", - "steel.add_nuclide('P31',0.00023)\n", - "steel.add_nuclide('Mn55',0.011014)\n", - "\n", - "materials = openmc.Materials([air, steel])\n", - "materials.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's download the geometry and mesh files.\n", - "(This may take some time.)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'Downloading manifold.h5m: 100.0%'" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# get the manifold DAGMC geometry file\n", - "download(manifold_geom_url, 'dagmc.h5m') \n", - "# get the manifold tet mesh\n", - "download(manifold_mesh_url, 'manifold.h5m')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next we'll create a 5 MeV neutron point source at the entrance the single pipe on the low side of the model with " - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "src_pnt = openmc.stats.Point(xyz=(0.0, 0.0, 0.0))\n", - "src_energy = openmc.stats.Discrete(x=[5.e+06], p=[1.0])\n", - "\n", - "source = openmc.Source(space=src_pnt, energy=src_energy)\n", - "\n", - "settings = openmc.Settings()\n", - "settings.source = source\n", - "\n", - "settings.run_mode = \"fixed source\"\n", - "settings.batches = 10\n", - "settings.particles = 100" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And we'll indicate that we're using a CAD-based geometry." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "settings.dagmc = True\n", - "\n", - "settings.export_to_xml()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We'll run a few particles through this geometry to make sure everything is working properly." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", - "\n", - " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2020 MIT and OpenMC contributors\n", - " License | https://docs.openmc.org/en/latest/license.html\n", - " Version | 0.12.1-dev\n", - " Git SHA1 | 8ae407c90e927af62bfdc8f150e96bfd5d7b2ec2\n", - " Date/Time | 2021-01-06 09:17:05\n", - " MPI Processes | 1\n", - " OpenMP Threads | 2\n", - "\n", - " Reading settings XML file...\n", - " Reading cross sections XML file...\n", - " Reading materials XML file...\n", - " Reading DAGMC geometry...\n", - "Set overlap thickness = 0\n", - "Set numerical precision = 0.001\n", - "Loading file dagmc.h5m\n", - "Initializing the GeomQueryTool...\n", - "Using faceting tolerance: 0.001\n", - "Building acceleration data structures...\n", - "Implicit Complement assumed to be Vacuum\n", - " Reading N14 from /home/shriwise/opt/openmc/xs/nndc_hdf5/N14.h5\n", - " Reading N15 from /home/shriwise/opt/openmc/xs/nndc_hdf5/N15.h5\n", - " Reading O16 from /home/shriwise/opt/openmc/xs/nndc_hdf5/O16.h5\n", - " Reading O17 from /home/shriwise/opt/openmc/xs/nndc_hdf5/O17.h5\n", - " Reading Ar36 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Ar36.h5\n", - " WARNING: Negative value(s) found on probability table for nuclide Ar36 at 294K\n", - " Reading Ar38 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Ar38.h5\n", - " Reading Ar40 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Ar40.h5\n", - " Reading Si28 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Si28.h5\n", - " Reading Si29 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Si29.h5\n", - " Reading Si30 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Si30.h5\n", - " Reading S32 from /home/shriwise/opt/openmc/xs/nndc_hdf5/S32.h5\n", - " Reading S33 from /home/shriwise/opt/openmc/xs/nndc_hdf5/S33.h5\n", - " Reading S34 from /home/shriwise/opt/openmc/xs/nndc_hdf5/S34.h5\n", - " Reading S36 from /home/shriwise/opt/openmc/xs/nndc_hdf5/S36.h5\n", - " Reading Fe54 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Fe54.h5\n", - " Reading Fe56 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Fe56.h5\n", - " Reading Fe57 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Fe57.h5\n", - " Reading Fe58 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Fe58.h5\n", - " Reading Ni58 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Ni58.h5\n", - " Reading Ni60 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Ni60.h5\n", - " Reading Ni61 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Ni61.h5\n", - " Reading Ni62 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Ni62.h5\n", - " Reading Ni64 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Ni64.h5\n", - " Reading Mo100 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Mo100.h5\n", - " Reading Mo92 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Mo92.h5\n", - " Reading Mo94 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Mo94.h5\n", - " Reading Mo95 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Mo95.h5\n", - " Reading Mo96 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Mo96.h5\n", - " Reading Mo97 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Mo97.h5\n", - " Reading Mo98 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Mo98.h5\n", - " Reading P31 from /home/shriwise/opt/openmc/xs/nndc_hdf5/P31.h5\n", - " Reading Mn55 from /home/shriwise/opt/openmc/xs/nndc_hdf5/Mn55.h5\n", - " Minimum neutron data temperature: 294.0 K\n", - " Maximum neutron data temperature: 294.0 K\n", - " Preparing distributed cell instances...\n", - " Writing summary.h5 file...\n", - " Maximum neutron transport energy: 20000000.0 eV for N15\n", - "\n", - " ===============> FIXED SOURCE TRANSPORT SIMULATION <===============\n", - "\n", - " Simulating batch 1\n", - " Simulating batch 2\n", - " Simulating batch 3\n", - " Simulating batch 4\n", - " Simulating batch 5\n", - " Simulating batch 6\n", - " Simulating batch 7\n", - " Simulating batch 8\n", - " Simulating batch 9\n", - " Simulating batch 10\n", - " Creating state point statepoint.10.h5...\n", - "\n", - " =======================> TIMING STATISTICS <=======================\n", - "\n", - " Total time for initialization = 2.4196e+01 seconds\n", - " Reading cross sections = 2.1428e+00 seconds\n", - " Total time in simulation = 1.9512e-01 seconds\n", - " Time in transport only = 1.9269e-01 seconds\n", - " Time in active batches = 1.9512e-01 seconds\n", - " Time accumulating tallies = 2.0220e-06 seconds\n", - " Time writing statepoints = 2.2461e-03 seconds\n", - " Total time for finalization = 1.8940e-06 seconds\n", - " Total time elapsed = 2.4401e+01 seconds\n", - " Calculation Rate (active) = 5125.02 particles/second\n", - "\n", - " ============================> RESULTS <============================\n", - "\n", - " Leakage Fraction = 0.96800 +/- 0.00573\n", - "\n" - ] - } - ], - "source": [ - "openmc.run()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's setup the unstructured mesh tally. We'll do this the same way we did in the [previous notebook](./unstructured-mesh-part-i.ipynb)." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "unstructured_mesh = openmc.UnstructuredMesh(\"manifold.h5m\", library='moab')\n", - "\n", - "mesh_filter = openmc.MeshFilter(unstructured_mesh)\n", - "\n", - "tally = openmc.Tally()\n", - "tally.filters = [mesh_filter]\n", - "tally.scores = ['flux']\n", - "tally.estimator = 'tracklength'\n", - "\n", - "tallies = openmc.Tallies([tally])\n", - "tallies.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "settings.batches = 200\n", - "settings.particles = 5000\n", - "settings.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "openmc.run(output=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Again we should see that `tally_1.200.vtk` file which we can use to visualize our results in VisIt, ParaView, or another tool of your choice that supports VTK files." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "tally_1.200.vtk\r\n" - ] - } - ], - "source": [ - "!ls *.vtk" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 13, - "metadata": { - "image/png": { - "width": "800" - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "Image(\"./images/manifold_flux.png\", width=\"800\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For the purpose of this example, we haven't run enough particles to score in all of the tet elements, but we indeed see larger flux values near the source location at the bottom of the model." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Visualization with statepoint data\n", - "\n", - "It was mentioned in the previous unstructured mesh example that the centroids and volumes of elements are written to the state point file. Here, we'll explore how to use that information to produce point cloud information for visualization of this data.\n", - "\n", - "This is particularly important when combining an unstructured mesh tally with other filters as a `.vtk` file will not automatically be written with the statepoint file in that scenario. To demonstrate this, let's setup a tally similar to the one above, but add an energy filter and re-run the model." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tally\n", - "\tID =\t1\n", - "\tName =\t\n", - "\tFilters =\tMeshFilter, EnergyFilter\n", - "\tNuclides =\t\n", - "\tScores =\t['flux']\n", - "\tEstimator =\ttracklength\n", - "EnergyFilter\n", - "\tValues =\t[ 0. 1000000. 5000000.]\n", - "\tID =\t2\n", - "\n" - ] - } - ], - "source": [ - "# energy filter with bins from 0 to 1 MeV and 1 MeV to 5 MeV\n", - "energy_filter = openmc.EnergyFilter((0.0, 1.e+06, 5.e+06))\n", - "\n", - "tally.filters = [mesh_filter, energy_filter]\n", - "print(tally)\n", - "print(energy_filter)\n", - "tallies.export_to_xml()" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\r\n", - "\r\n", - " \r\n", - " manifold.h5m\r\n", - " \r\n", - " \r\n", - " 1\r\n", - " \r\n", - " \r\n", - " 0.0 1000000.0 5000000.0\r\n", - " \r\n", - " \r\n", - " 1 2\r\n", - " flux\r\n", - " tracklength\r\n", - " \r\n", - "\r\n" - ] - } - ], - "source": [ - "!cat tallies.xml" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "openmc.run(output=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Noice the warning at the end of the output above indicating that the .vtk file we used before isn't written in this case.\n", - "\n", - "Let's open up this statepoint file and get the information we need to create the point cloud data instead.\n", - "\n", - "_**NOTE: You will need the Python vtk module installed to run this part of the notebook.**_" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "with openmc.StatePoint(\"statepoint.200.h5\") as sp:\n", - " tally = sp.tallies[1]\n", - " \n", - " umesh = sp.meshes[1]\n", - " centroids = umesh.centroids\n", - " mesh_vols = umesh.volumes\n", - " \n", - " thermal_flux = tally.get_values(scores=['flux'], \n", - " filters=[openmc.EnergyFilter],\n", - " filter_bins=[((0.0, 1.e+06),)])\n", - " fast_flux = tally.get_values(scores=['flux'],\n", - " filters=[openmc.EnergyFilter],\n", - " filter_bins=[((1.e+06, 5.e+06),)])" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "data_dict = {'Flux 0 - 1 MeV' : thermal_flux,\n", - " 'Flux 1 - 5 MeV' : fast_flux,\n", - " 'Total Flux' : thermal_flux + fast_flux}\n", - "\n", - "umesh.write_data_to_vtk(\"manifold\", data_dict)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We should now see our new flux file in the directory. It can be used to visualize the results in the same way as our other `.vtk` files." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "manifold.vtk tally_1.200.vtk\r\n" - ] - } - ], - "source": [ - "!ls *.vtk" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "execution_count": 20, - "metadata": { - "image/png": { - "width": 800 - } - }, - "output_type": "execute_result" - } - ], - "source": [ - "Image(\"./images/manifold_pnt_cld.png\", width=800)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/examples/lattice/hexagonal/build_xml.py b/examples/lattice/hexagonal/build_xml.py index c0aa815b412..96ff3f34a11 100644 --- a/examples/lattice/hexagonal/build_xml.py +++ b/examples/lattice/hexagonal/build_xml.py @@ -115,7 +115,7 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings_file.source = openmc.source.Source(space=uniform_dist) +settings_file.source = openmc.IndependentSource(space=uniform_dist) settings_file.keff_trigger = {'type' : 'std_dev', 'threshold' : 5E-4} settings_file.trigger_active = True diff --git a/examples/lattice/nested/build_xml.py b/examples/lattice/nested/build_xml.py index 06641f5ac57..407a53a2327 100644 --- a/examples/lattice/nested/build_xml.py +++ b/examples/lattice/nested/build_xml.py @@ -125,7 +125,7 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings_file.source = openmc.source.Source(space=uniform_dist) +settings_file.source = openmc.IndependentSource(space=uniform_dist) settings_file.export_to_xml() diff --git a/examples/lattice/simple/build_xml.py b/examples/lattice/simple/build_xml.py index 17544b87f50..0da8d8cf086 100644 --- a/examples/lattice/simple/build_xml.py +++ b/examples/lattice/simple/build_xml.py @@ -116,7 +116,7 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings_file.source = openmc.source.Source(space=uniform_dist) +settings_file.source = openmc.IndependentSource(space=uniform_dist) settings_file.trigger_active = True settings_file.trigger_max_batches = 100 diff --git a/examples/parameterized_custom_source/CMakeLists.txt b/examples/parameterized_custom_source/CMakeLists.txt index 3024e90cffa..8232f3b546a 100644 --- a/examples/parameterized_custom_source/CMakeLists.txt +++ b/examples/parameterized_custom_source/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3 FATAL_ERROR) +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(openmc_sources CXX) add_library(parameterized_source SHARED parameterized_source_ring.cpp) find_package(OpenMC REQUIRED) diff --git a/examples/parameterized_custom_source/build_xml.py b/examples/parameterized_custom_source/build_xml.py index 5edb204df21..5ac6bf92870 100644 --- a/examples/parameterized_custom_source/build_xml.py +++ b/examples/parameterized_custom_source/build_xml.py @@ -8,8 +8,8 @@ mats.export_to_xml() # Create a 5 cm x 5 cm box filled with iron -box = openmc.model.rectangular_prism(10.0, 10.0, boundary_type='vacuum') -cell = openmc.Cell(fill=iron, region=box) +box = openmc.model.RectangularPrism(10.0, 10.0, boundary_type='vacuum') +cell = openmc.Cell(fill=iron, region=-box) geometry = openmc.Geometry([cell]) geometry.export_to_xml() @@ -18,7 +18,7 @@ settings.run_mode = 'fixed source' settings.batches = 10 settings.particles = 1000 -source = openmc.Source() +source = openmc.CompiledSource() source.library = 'build/libparameterized_source.so' source.parameters = 'radius=3.0, energy=14.08e6' settings.source = source diff --git a/examples/parameterized_custom_source/parameterized_source_ring.cpp b/examples/parameterized_custom_source/parameterized_source_ring.cpp index a334666ed7f..e70dc8bb190 100644 --- a/examples/parameterized_custom_source/parameterized_source_ring.cpp +++ b/examples/parameterized_custom_source/parameterized_source_ring.cpp @@ -34,9 +34,8 @@ class RingSource : public openmc::Source { openmc::SourceSite sample(uint64_t* seed) const { openmc::SourceSite particle; - // wgt + // particle type particle.particle = openmc::ParticleType::neutron; - particle.wgt = 1.0; // position double angle = 2.0 * M_PI * openmc::prn(seed); double radius = this->radius_; @@ -46,7 +45,6 @@ class RingSource : public openmc::Source { // angle particle.u = {1.0, 0.0, 0.0}; particle.E = this->energy_; - particle.delayed_group = 0; return particle; } diff --git a/examples/pincell/build_xml.py b/examples/pincell/build_xml.py index c5d614ea90c..d008c882237 100644 --- a/examples/pincell/build_xml.py +++ b/examples/pincell/build_xml.py @@ -43,13 +43,13 @@ # Create a region represented as the inside of a rectangular prism pitch = 1.25984 -box = openmc.rectangular_prism(pitch, pitch, boundary_type='reflective') +box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') # Create cells, mapping materials to regions fuel = openmc.Cell(fill=uo2, region=-fuel_or) gap = openmc.Cell(fill=helium, region=+fuel_or & -clad_ir) clad = openmc.Cell(fill=zircaloy, region=+clad_ir & -clad_or) -water = openmc.Cell(fill=borated_water, region=+clad_or & box) +water = openmc.Cell(fill=borated_water, region=+clad_or & -box) # Create a geometry and export to XML geometry = openmc.Geometry([fuel, gap, clad, water]) @@ -68,7 +68,7 @@ lower_left = (-pitch/2, -pitch/2, -1) upper_right = (pitch/2, pitch/2, 1) uniform_dist = openmc.stats.Box(lower_left, upper_right, only_fissionable=True) -settings.source = openmc.source.Source(space=uniform_dist) +settings.source = openmc.IndependentSource(space=uniform_dist) # For source convergence checks, add a mesh that can be used to calculate the # Shannon entropy diff --git a/examples/pincell_depletion/restart_depletion.py b/examples/pincell_depletion/restart_depletion.py index 0bbab57a589..de9fc16cb1f 100644 --- a/examples/pincell_depletion/restart_depletion.py +++ b/examples/pincell_depletion/restart_depletion.py @@ -12,7 +12,7 @@ geometry = sp.summary.geometry # Load previous depletion results -previous_results = openmc.deplete.ResultsList.from_hdf5("depletion_results.h5") +previous_results = openmc.deplete.Results("depletion_results.h5") ############################################################################### # Transport calculation settings @@ -26,8 +26,9 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] -uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings.source = openmc.source.Source(space=uniform_dist) +uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) +settings.source = openmc.IndependentSource( + space=uniform_dist, constraints={'fissionable': True}) entropy_mesh = openmc.RegularMesh() entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50] @@ -39,9 +40,11 @@ # Initialize and run depletion calculation ############################################################################### +model = openmc.Model(geometry=geometry, settings=settings) + # Create depletion "operator" -chain_file = './chain_simple.xml' -op = openmc.deplete.Operator(geometry, settings, chain_file, previous_results) +chain_file = 'chain_simple.xml' +op = openmc.deplete.CoupledOperator(model, chain_file, previous_results) # Perform simulation using the predictor algorithm time_steps = [1.0, 1.0, 1.0, 1.0, 1.0] # days @@ -54,37 +57,36 @@ ############################################################################### # Open results file -results = openmc.deplete.ResultsList.from_hdf5("depletion_results.h5") +results = openmc.deplete.Results("depletion_results.h5") # Obtain K_eff as a function of time -time, keff = results.get_eigenvalue() +time, keff = results.get_keff(time_units='d') # Obtain U235 concentration as a function of time -time, n_U235 = results.get_atoms('1', 'U235') +uo2 = geometry.get_all_material_cells()[1] +_, n_U235 = results.get_atoms(uo2, 'U235') # Obtain Xe135 capture reaction rate as a function of time -time, Xe_capture = results.get_reaction_rate('1', 'Xe135', '(n,gamma)') +_, Xe_capture = results.get_reaction_rate(uo2, 'Xe135', '(n,gamma)') ############################################################################### # Generate plots ############################################################################### -days = 24*60*60 -plt.figure() -plt.plot(time/days, keff, label="K-effective") -plt.xlabel("Time (days)") -plt.ylabel("Keff") +fig, ax = plt.subplots() +ax.errorbar(time, keff[:, 0], keff[:, 1], label="K-effective") +ax.set_xlabel("Time [d]") +ax.set_ylabel("Keff") plt.show() -plt.figure() -plt.plot(time/days, n_U235, label="U 235") -plt.xlabel("Time (days)") -plt.ylabel("n U5 (-)") +fig, ax = plt.subplots() +ax.plot(time, n_U235, label="U235") +ax.set_xlabel("Time [d]") +ax.set_ylabel("U235 atoms") plt.show() -plt.figure() -plt.plot(time/days, Xe_capture, label="Xe135 capture") -plt.xlabel("Time (days)") -plt.ylabel("RR (-)") +fig, ax = plt.subplots() +ax.plot(time, Xe_capture, label="Xe135 capture") +ax.set_xlabel("Time [d]") +ax.set_ylabel("Xe135 capture rate") plt.show() -plt.close('all') diff --git a/examples/pincell_depletion/run_depletion.py b/examples/pincell_depletion/run_depletion.py index ce4b0cf5e66..013c83c86a5 100644 --- a/examples/pincell_depletion/run_depletion.py +++ b/examples/pincell_depletion/run_depletion.py @@ -41,13 +41,13 @@ fuel_or = openmc.ZCylinder(r=0.39218, name='Fuel OR') clad_ir = openmc.ZCylinder(r=0.40005, name='Clad IR') clad_or = openmc.ZCylinder(r=0.45720, name='Clad OR') -box = openmc.model.rectangular_prism(pitch, pitch, boundary_type='reflective') +box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') # Define cells fuel = openmc.Cell(fill=uo2, region=-fuel_or) gap = openmc.Cell(fill=helium, region=+fuel_or & -clad_ir) clad = openmc.Cell(fill=zircaloy, region=+clad_ir & -clad_or) -water = openmc.Cell(fill=borated_water, region=+clad_or & box) +water = openmc.Cell(fill=borated_water, region=+clad_or & -box) # Define overall geometry geometry = openmc.Geometry([fuel, gap, clad, water]) @@ -71,8 +71,9 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] -uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings.source = openmc.source.Source(space=uniform_dist) +uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) +settings.source = openmc.IndependentSource( + space=uniform_dist, constraints={'fissionable': True}) entropy_mesh = openmc.RegularMesh() entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50] @@ -84,9 +85,11 @@ # Initialize and run depletion calculation ############################################################################### +model = openmc.Model(geometry=geometry, settings=settings) + # Create depletion "operator" -chain_file = './chain_simple.xml' -op = openmc.deplete.Operator(geometry, settings, chain_file) +chain_file = 'chain_simple.xml' +op = openmc.deplete.CoupledOperator(model, chain_file) # Perform simulation using the predictor algorithm time_steps = [1.0, 1.0, 1.0, 1.0, 1.0] # days @@ -99,37 +102,35 @@ ############################################################################### # Open results file -results = openmc.deplete.ResultsList.from_hdf5("depletion_results.h5") +results = openmc.deplete.Results("depletion_results.h5") # Obtain K_eff as a function of time -time, keff = results.get_eigenvalue() +time, keff = results.get_keff(time_units='d') # Obtain U235 concentration as a function of time -time, n_U235 = results.get_atoms('1', 'U235') +_, n_U235 = results.get_atoms(uo2, 'U235') # Obtain Xe135 capture reaction rate as a function of time -time, Xe_capture = results.get_reaction_rate('1', 'Xe135', '(n,gamma)') +_, Xe_capture = results.get_reaction_rate(uo2, 'Xe135', '(n,gamma)') ############################################################################### # Generate plots ############################################################################### -days = 24*60*60 -plt.figure() -plt.plot(time/days, keff, label="K-effective") -plt.xlabel("Time (days)") -plt.ylabel("Keff") +fig, ax = plt.subplots() +ax.errorbar(time, keff[:, 0], keff[:, 1], label="K-effective") +ax.set_xlabel("Time [d]") +ax.set_ylabel("Keff") plt.show() -plt.figure() -plt.plot(time/days, n_U235, label="U235") -plt.xlabel("Time (days)") -plt.ylabel("n U5 (-)") +fig, ax = plt.subplots() +ax.plot(time, n_U235, label="U235") +ax.set_xlabel("Time [d]") +ax.set_ylabel("U235 atoms") plt.show() -plt.figure() -plt.plot(time/days, Xe_capture, label="Xe135 capture") -plt.xlabel("Time (days)") -plt.ylabel("RR (-)") +fig, ax = plt.subplots() +ax.plot(time, Xe_capture, label="Xe135 capture") +ax.set_xlabel("Time [d]") +ax.set_ylabel("Xe135 capture rate") plt.show() -plt.close('all') diff --git a/examples/pincell_multigroup/build_xml.py b/examples/pincell_multigroup/build_xml.py index 1f34683919c..019ae6a113f 100644 --- a/examples/pincell_multigroup/build_xml.py +++ b/examples/pincell_multigroup/build_xml.py @@ -90,11 +90,11 @@ # Create a region represented as the inside of a rectangular prism pitch = 1.26 -box = openmc.rectangular_prism(pitch, pitch, boundary_type='reflective') +box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') # Instantiate Cells fuel = openmc.Cell(fill=uo2, region=-fuel_or, name='fuel') -moderator = openmc.Cell(fill=water, region=+fuel_or & box, name='moderator') +moderator = openmc.Cell(fill=water, region=+fuel_or & -box, name='moderator') # Create a geometry with the two cells and export to XML geometry = openmc.Geometry([fuel, moderator]) @@ -114,7 +114,7 @@ lower_left = (-pitch/2, -pitch/2, -1) upper_right = (pitch/2, pitch/2, 1) uniform_dist = openmc.stats.Box(lower_left, upper_right, only_fissionable=True) -settings.source = openmc.source.Source(space=uniform_dist) +settings.source = openmc.IndependentSource(space=uniform_dist) settings.export_to_xml() ############################################################################### diff --git a/examples/pincell_random_ray/build_xml.py b/examples/pincell_random_ray/build_xml.py new file mode 100644 index 00000000000..b3dd8020a51 --- /dev/null +++ b/examples/pincell_random_ray/build_xml.py @@ -0,0 +1,203 @@ +import numpy as np +import openmc +import openmc.mgxs + +############################################################################### +# Create multigroup data + +# Instantiate the energy group data +group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] +groups = openmc.mgxs.EnergyGroups(group_edges) + +# Instantiate the 7-group (C5G7) cross section data +uo2_xsdata = openmc.XSdata('UO2', groups) +uo2_xsdata.order = 0 +uo2_xsdata.set_total( + [0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, + 0.5644058]) +uo2_xsdata.set_absorption([8.0248e-03, 3.7174e-03, 2.6769e-02, 9.6236e-02, + 3.0020e-02, 1.1126e-01, 2.8278e-01]) +scatter_matrix = np.array( + [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]) +scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) +uo2_xsdata.set_scatter_matrix(scatter_matrix) +uo2_xsdata.set_fission([7.21206e-03, 8.19301e-04, 6.45320e-03, + 1.85648e-02, 1.78084e-02, 8.30348e-02, + 2.16004e-01]) +uo2_xsdata.set_nu_fission([2.005998e-02, 2.027303e-03, 1.570599e-02, + 4.518301e-02, 4.334208e-02, 2.020901e-01, + 5.257105e-01]) +uo2_xsdata.set_chi([5.8791e-01, 4.1176e-01, 3.3906e-04, 1.1761e-07, 0.0000e+00, + 0.0000e+00, 0.0000e+00]) + +h2o_xsdata = openmc.XSdata('LWTR', groups) +h2o_xsdata.order = 0 +h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435, + 0.718, 1.2544497, 2.650379]) +h2o_xsdata.set_absorption([6.0105e-04, 1.5793e-05, 3.3716e-04, + 1.9406e-03, 5.7416e-03, 1.5001e-02, + 3.7239e-02]) +scatter_matrix = np.array( + [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000], + [0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010], + [0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034], + [0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390], + [0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]) +scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) +h2o_xsdata.set_scatter_matrix(scatter_matrix) + +mg_cross_sections_file = openmc.MGXSLibrary(groups) +mg_cross_sections_file.add_xsdatas([uo2_xsdata, h2o_xsdata]) +mg_cross_sections_file.export_to_hdf5() + +############################################################################### +# Create materials for the problem + +# Instantiate some Materials and register the appropriate macroscopic data +uo2 = openmc.Material(name='UO2 fuel') +uo2.set_density('macro', 1.0) +uo2.add_macroscopic('UO2') + +water = openmc.Material(name='Water') +water.set_density('macro', 1.0) +water.add_macroscopic('LWTR') + +# Instantiate a Materials collection and export to XML +materials_file = openmc.Materials([uo2, water]) +materials_file.cross_sections = "mgxs.h5" +materials_file.export_to_xml() + +############################################################################### +# Define problem geometry + +# The geometry we will define a simplified pincell with fuel radius 0.54 cm +# surrounded by moderator (same as in the multigroup example). +# In random ray, we typically want several radial regions and azimuthal +# sectors in both the fuel and moderator areas of the pincell. This is +# due to the flat source approximation requiring that source regions are +# small compared to the typical mean free path of a neutron. Below we +# sudivide the basic pincell into 8 aziumthal sectors (pizza slices) and +# 5 concentric rings in both the fuel and moderator. + +# TODO: When available in OpenMC, use cylindrical lattice instead to +# simplify definition and improve runtime performance. + +pincell_base = openmc.Universe() + +# These are the subdivided radii (creating 5 concentric regions in the +# fuel and moderator) +ring_radii = [0.241, 0.341, 0.418, 0.482, 0.54, 0.572, 0.612, 0.694, 0.786] +fills = [uo2, uo2, uo2, uo2, uo2, water, water, water, water, water] + +# We then create cells representing the bounded rings, with special +# treatment for both the innermost and outermost cells +cells = [] +for r in range(10): + cell = [] + if r == 0: + outer_bound = openmc.ZCylinder(r=ring_radii[r]) + cell = openmc.Cell(fill=fills[r], region=-outer_bound) + elif r == 9: + inner_bound = openmc.ZCylinder(r=ring_radii[r-1]) + cell = openmc.Cell(fill=fills[r], region=+inner_bound) + else: + inner_bound = openmc.ZCylinder(r=ring_radii[r-1]) + outer_bound = openmc.ZCylinder(r=ring_radii[r]) + cell = openmc.Cell(fill=fills[r], region=+inner_bound & -outer_bound) + pincell_base.add_cell(cell) + +# We then generate 8 planes to bound 8 azimuthal sectors +azimuthal_planes = [] +for i in range(8): + angle = 2 * i * openmc.pi / 8 + normal_vector = (-openmc.sin(angle), openmc.cos(angle), 0) + azimuthal_planes.append(openmc.Plane(a=normal_vector[0], b=normal_vector[1], c=normal_vector[2], d=0)) + +# Create a cell for each azimuthal sector using the pincell base class +azimuthal_cells = [] +for i in range(8): + azimuthal_cell = openmc.Cell(name=f'azimuthal_cell_{i}') + azimuthal_cell.fill = pincell_base + azimuthal_cell.region = +azimuthal_planes[i] & -azimuthal_planes[(i+1) % 8] + azimuthal_cells.append(azimuthal_cell) + +# Create the (subdivided) geometry with the azimuthal universes +pincell = openmc.Universe(cells=azimuthal_cells) + +# Create a region represented as the inside of a rectangular prism +pitch = 1.26 +box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') +pincell_bounded = openmc.Cell(fill=pincell, region=-box, name='pincell') + +# Create a geometry (specifying merge surfaces option to remove +# all the redundant cylinder/plane surfaces) and export to XML +geometry = openmc.Geometry([pincell_bounded], merge_surfaces=True) +geometry.export_to_xml() + +############################################################################### +# Define problem settings + +# Instantiate a Settings object, set all runtime parameters, and export to XML +settings = openmc.Settings() +settings.energy_mode = "multi-group" +settings.batches = 600 +settings.inactive = 300 +settings.particles = 50 + +# Create an initial uniform spatial source distribution for sampling rays. +# Note that this must be uniform in space and angle. +lower_left = (-pitch/2, -pitch/2, -1) +upper_right = (pitch/2, pitch/2, 1) +uniform_dist = openmc.stats.Box(lower_left, upper_right) +settings.random_ray['ray_source'] = openmc.IndependentSource(space=uniform_dist) +settings.random_ray['distance_inactive'] = 40.0 +settings.random_ray['distance_active'] = 400.0 + +settings.export_to_xml() + +############################################################################### +# Define tallies + +# Create a mesh that will be used for tallying +mesh = openmc.RegularMesh() +mesh.dimension = (2, 2) +mesh.lower_left = (-pitch/2, -pitch/2) +mesh.upper_right = (pitch/2, pitch/2) + +# Create a mesh filter that can be used in a tally +mesh_filter = openmc.MeshFilter(mesh) + +# Let's also create a filter to measure each group +# indepdendently +energy_filter = openmc.EnergyFilter(group_edges) + +# Now use the mesh filter in a tally and indicate what scores are desired +tally = openmc.Tally(name="Mesh and Energy tally") +tally.filters = [mesh_filter, energy_filter] +tally.scores = ['flux', 'fission', 'nu-fission'] + +# Instantiate a Tallies collection and export to XML +tallies = openmc.Tallies([tally]) +tallies.export_to_xml() + +############################################################################### +# Exporting to OpenMC plots.xml file +############################################################################### + +plot = openmc.Plot() +plot.origin = [0, 0, 0] +plot.width = [pitch, pitch, pitch] +plot.pixels = [1000, 1000, 1] +plot.type = 'voxel' + +# Instantiate a Plots collection and export to XML +plots = openmc.Plots([plot]) +plots.export_to_xml() diff --git a/include/openmc/angle_energy.h b/include/openmc/angle_energy.h index e2f449c6aa5..ac931b1b533 100644 --- a/include/openmc/angle_energy.h +++ b/include/openmc/angle_energy.h @@ -14,11 +14,11 @@ namespace openmc { class AngleEnergy { public: - virtual void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const = 0; + virtual void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const = 0; virtual ~AngleEnergy() = default; }; -} +} // namespace openmc #endif // OPENMC_ANGLE_ENERGY_H diff --git a/include/openmc/boundary_condition.h b/include/openmc/boundary_condition.h index 7eb93a61d48..cd8988162f2 100644 --- a/include/openmc/boundary_condition.h +++ b/include/openmc/boundary_condition.h @@ -1,12 +1,16 @@ #ifndef OPENMC_BOUNDARY_CONDITION_H #define OPENMC_BOUNDARY_CONDITION_H +#include "openmc/hdf5_interface.h" +#include "openmc/particle.h" #include "openmc/position.h" +#include namespace openmc { // Forward declare some types used in function arguments. class Particle; +class RandomRay; class Surface; //============================================================================== @@ -15,16 +19,53 @@ class Surface; class BoundaryCondition { public: + virtual ~BoundaryCondition() = default; + //! Perform tracking operations for a particle that strikes the boundary. //! \param p The particle that struck the boundary. This class is not meant //! to directly modify anything about the particle, but it will do so //! indirectly by calling the particle's appropriate cross_*_bc function. //! \param surf The specific surface on the boundary the particle struck. - virtual void - handle_particle(Particle& p, const Surface& surf) const = 0; + virtual void handle_particle(Particle& p, const Surface& surf) const = 0; + + //! Modify the incident particle's weight according to the boundary's albedo. + //! \param p The particle that struck the boundary. This function calculates + //! the reduction in the incident particle's weight as it interacts + //! with a boundary. The lost weight is tallied before the remaining weight + //! is reassigned to the incident particle. Implementations of the + //! handle_particle function typically call this method in its body. + //! \param surf The specific surface on the boundary the particle struck. + void handle_albedo(Particle& p, const Surface& surf) const + { + if (!has_albedo()) + return; + double initial_wgt = p.wgt(); + // Treat the lost weight fraction as leakage, similar to VacuumBC. + // This ensures the lost weight is tallied properly. + p.wgt() *= (1.0 - albedo_); + p.cross_vacuum_bc(surf); + p.wgt() = initial_wgt * albedo_; + }; //! Return a string classification of this BC. virtual std::string type() const = 0; + + //! Write albedo data of this BC to hdf5. + void to_hdf5(hid_t surf_group) const + { + if (has_albedo()) { + write_string(surf_group, "albedo", fmt::format("{}", albedo_), false); + } + }; + + //! Set albedo of this BC. + void set_albedo(double albedo) { albedo_ = albedo; } + + //! Return if this BC has an albedo. + bool has_albedo() const { return (albedo_ > 0.0); } + +private: + double albedo_ = -1.0; }; //============================================================================== @@ -33,10 +74,9 @@ class BoundaryCondition { class VacuumBC : public BoundaryCondition { public: - void - handle_particle(Particle& p, const Surface& surf) const override; + void handle_particle(Particle& p, const Surface& surf) const override; - std::string type() const override {return "vacuum";} + std::string type() const override { return "vacuum"; } }; //============================================================================== @@ -45,10 +85,9 @@ class VacuumBC : public BoundaryCondition { class ReflectiveBC : public BoundaryCondition { public: - void - handle_particle(Particle& p, const Surface& surf) const override; + void handle_particle(Particle& p, const Surface& surf) const override; - std::string type() const override {return "reflective";} + std::string type() const override { return "reflective"; } }; //============================================================================== @@ -57,10 +96,9 @@ class ReflectiveBC : public BoundaryCondition { class WhiteBC : public BoundaryCondition { public: - void - handle_particle(Particle& p, const Surface& surf) const override; + void handle_particle(Particle& p, const Surface& surf) const override; - std::string type() const override {return "white";} + std::string type() const override { return "white"; } }; //============================================================================== @@ -69,11 +107,9 @@ class WhiteBC : public BoundaryCondition { class PeriodicBC : public BoundaryCondition { public: - PeriodicBC(int i_surf, int j_surf) - : i_surf_(i_surf), j_surf_(j_surf) - {}; + PeriodicBC(int i_surf, int j_surf) : i_surf_(i_surf), j_surf_(j_surf) {}; - std::string type() const override {return "periodic";} + std::string type() const override { return "periodic"; } protected: int i_surf_; @@ -88,8 +124,7 @@ class TranslationalPeriodicBC : public PeriodicBC { public: TranslationalPeriodicBC(int i_surf, int j_surf); - void - handle_particle(Particle& p, const Surface& surf) const override; + void handle_particle(Particle& p, const Surface& surf) const override; protected: //! Vector along which incident particles will be moved @@ -106,8 +141,7 @@ class RotationalPeriodicBC : public PeriodicBC { public: RotationalPeriodicBC(int i_surf, int j_surf); - void - handle_particle(Particle& p, const Surface& surf) const override; + void handle_particle(Particle& p, const Surface& surf) const override; protected: //! Angle about the axis by which particle coordinates will be rotated diff --git a/include/openmc/bremsstrahlung.h b/include/openmc/bremsstrahlung.h index bd9d012c1b3..2f7e41bf087 100644 --- a/include/openmc/bremsstrahlung.h +++ b/include/openmc/bremsstrahlung.h @@ -14,8 +14,8 @@ namespace openmc { class BremsstrahlungData { public: // Data - xt::xtensor pdf; //!< Bremsstrahlung energy PDF - xt::xtensor cdf; //!< Bremsstrahlung energy CDF + xt::xtensor pdf; //!< Bremsstrahlung energy PDF + xt::xtensor cdf; //!< Bremsstrahlung energy CDF xt::xtensor yield; //!< Photon yield }; @@ -32,8 +32,10 @@ class Bremsstrahlung { namespace data { -extern xt::xtensor ttb_e_grid; //! energy T of incident electron in [eV] -extern xt::xtensor ttb_k_grid; //! reduced energy W/T of emitted photon +extern xt::xtensor + ttb_e_grid; //! energy T of incident electron in [eV] +extern xt::xtensor + ttb_k_grid; //! reduced energy W/T of emitted photon } // namespace data diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 2ca9fc430fc..9401156a64f 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -1,196 +1,286 @@ #ifndef OPENMC_CAPI_H #define OPENMC_CAPI_H -#include #include #include +#include #ifdef __cplusplus extern "C" { #endif - int openmc_calculate_volumes(); - int openmc_cell_filter_get_bins(int32_t index, const int32_t** cells, int32_t* n); - int openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n); - int openmc_cell_get_id(int32_t index, int32_t* id); - int openmc_cell_get_temperature(int32_t index, const int32_t* instance, double* T); - int openmc_cell_get_name(int32_t index, const char** name); - int openmc_cell_set_name(int32_t index, const char* name); - int openmc_cell_set_fill(int32_t index, int type, int32_t n, const int32_t* indices); - int openmc_cell_set_id(int32_t index, int32_t id); - int openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance, bool set_contained = false); - int openmc_energy_filter_get_bins(int32_t index, const double** energies, size_t* n); - int openmc_energy_filter_set_bins(int32_t index, size_t n, const double* energies); - int openmc_energyfunc_filter_get_energy(int32_t index, size_t* n, const double** energy); - int openmc_energyfunc_filter_get_y(int32_t index, size_t* n, const double** y); - int openmc_energyfunc_filter_set_data(int32_t index, size_t n, - const double* energies, const double* y); - int openmc_extend_cells(int32_t n, int32_t* index_start, int32_t* index_end); - int openmc_extend_filters(int32_t n, int32_t* index_start, int32_t* index_end); - int openmc_extend_materials(int32_t n, int32_t* index_start, int32_t* index_end); - int openmc_extend_meshes(int32_t n, const char* type, int32_t* index_start, - int32_t* index_end); - int openmc_extend_tallies(int32_t n, int32_t* index_start, int32_t* index_end); - int openmc_filter_get_id(int32_t index, int32_t* id); - int openmc_filter_get_type(int32_t index, char* type); - int openmc_filter_set_id(int32_t index, int32_t id); - int openmc_finalize(); - int openmc_find_cell(const double* xyz, int32_t* index, int32_t* instance); - int openmc_cell_bounding_box(const int32_t index, double* llc, double* urc); - int openmc_global_bounding_box(double* llc, double* urc); - int openmc_fission_bank(void** ptr, int64_t* n); - int openmc_get_cell_index(int32_t id, int32_t* index); - int openmc_get_filter_index(int32_t id, int32_t* index); - void openmc_get_filter_next_id(int32_t* id); - int openmc_get_keff(double k_combined[]); - int openmc_get_material_index(int32_t id, int32_t* index); - int openmc_get_mesh_index(int32_t id, int32_t* index); - int openmc_get_n_batches(int* n_batches, bool get_max_batches); - int openmc_get_nuclide_index(const char name[], int* index); - int openmc_add_unstructured_mesh(const char filename[], const char library[], int* id); - int64_t openmc_get_seed(); - int openmc_get_tally_index(int32_t id, int32_t* index); - void openmc_get_tally_next_id(int32_t* id); - int openmc_global_tallies(double** ptr); - int openmc_hard_reset(); - int openmc_init(int argc, char* argv[], const void* intracomm); - bool openmc_is_statepoint_batch(); - int openmc_legendre_filter_get_order(int32_t index, int* order); - int openmc_legendre_filter_set_order(int32_t index, int order); - int openmc_load_nuclide(const char* name, const double* temps, int n); - int openmc_material_add_nuclide(int32_t index, const char name[], double density); - int openmc_material_get_densities(int32_t index, const int** nuclides, const double** densities, int* n); - int openmc_material_get_id(int32_t index, int32_t* id); - int openmc_material_get_fissionable(int32_t index, bool* fissionable); - int openmc_material_get_density(int32_t index, double* density); - int openmc_material_get_volume(int32_t index, double* volume); - int openmc_material_set_density(int32_t index, double density, const char* units); - int openmc_material_set_densities(int32_t index, int n, const char** name, const double* density); - int openmc_material_set_id(int32_t index, int32_t id); - int openmc_material_get_name(int32_t index, const char** name); - int openmc_material_set_name(int32_t index, const char* name); - int openmc_material_set_volume(int32_t index, double volume); - int openmc_material_filter_get_bins(int32_t index, const int32_t** bins, size_t* n); - int openmc_material_filter_set_bins(int32_t index, size_t n, const int32_t* bins); - int openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh); - int openmc_mesh_filter_set_mesh(int32_t index, int32_t index_mesh); - int openmc_mesh_filter_get_translation(int32_t index, double translation[3]); - int openmc_mesh_filter_set_translation(int32_t index, double translation[3]); - int openmc_mesh_get_id(int32_t index, int32_t* id); - int openmc_mesh_set_id(int32_t index, int32_t id); - int openmc_meshsurface_filter_get_mesh(int32_t index, int32_t* index_mesh); - int openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh); - int openmc_new_filter(const char* type, int32_t* index); - int openmc_next_batch(int* status); - int openmc_nuclide_name(int index, const char** name); - int openmc_plot_geometry(); - int openmc_id_map(const void* slice, int32_t* data_out); - int openmc_property_map(const void* slice, double* data_out); - int openmc_rectilinear_mesh_get_grid(int32_t index, double** grid_x, int* nx, - double** grid_y, int* ny, double** grid_z, int* nz); - int openmc_rectilinear_mesh_set_grid(int32_t index, const double* grid_x, - const int nx, const double* grid_y, const int ny, - const double* grid_z, const int nz); - int openmc_regular_mesh_get_dimension(int32_t index, int** id, int* n); - int openmc_regular_mesh_get_params(int32_t index, double** ll, double** ur, double** width, int* n); - int openmc_regular_mesh_set_dimension(int32_t index, int n, const int* dims); - int openmc_regular_mesh_set_params(int32_t index, int n, const double* ll, const double* ur, const double* width); - int openmc_reset(); - int openmc_reset_timers(); - int openmc_run(); - void openmc_set_seed(int64_t new_seed); - int openmc_set_n_batches(int32_t n_batches, bool set_max_batches, - bool add_statepoint_batch); - int openmc_simulation_finalize(); - int openmc_simulation_init(); - int openmc_source_bank(void** ptr, int64_t* n); - int openmc_spatial_legendre_filter_get_order(int32_t index, int* order); - int openmc_spatial_legendre_filter_get_params(int32_t index, int* axis, double* min, double* max); - int openmc_spatial_legendre_filter_set_order(int32_t index, int order); - int openmc_spatial_legendre_filter_set_params(int32_t index, const int* axis, - const double* min, const double* max); - int openmc_sphharm_filter_get_order(int32_t index, int* order); - int openmc_sphharm_filter_get_cosine(int32_t index, char cosine[]); - int openmc_sphharm_filter_set_order(int32_t index, int order); - int openmc_sphharm_filter_set_cosine(int32_t index, const char cosine[]); - int openmc_statepoint_write(const char* filename, bool* write_source); - int openmc_tally_allocate(int32_t index, const char* type); - int openmc_tally_get_active(int32_t index, bool* active); - int openmc_tally_get_estimator(int32_t index, int* estimator); - int openmc_tally_get_id(int32_t index, int32_t* id); - int openmc_tally_get_filters(int32_t index, const int32_t** indices, size_t* n); - int openmc_tally_get_n_realizations(int32_t index, int32_t* n); - int openmc_tally_get_nuclides(int32_t index, int** nuclides, int* n); - int openmc_tally_get_scores(int32_t index, int** scores, int* n); - int openmc_tally_get_type(int32_t index, int32_t* type); - int openmc_tally_get_writable(int32_t index, bool* writable); - int openmc_tally_reset(int32_t index); - int openmc_tally_results(int32_t index, double** ptr, size_t shape_[3]); - int openmc_tally_set_active(int32_t index, bool active); - int openmc_tally_set_estimator(int32_t index, const char* estimator); - int openmc_tally_set_filters(int32_t index, size_t n, const int32_t* indices); - int openmc_tally_set_id(int32_t index, int32_t id); - int openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides); - int openmc_tally_set_scores(int32_t index, int n, const char** scores); - int openmc_tally_set_type(int32_t index, const char* type); - int openmc_tally_set_writable(int32_t index, bool writable); - int openmc_zernike_filter_get_order(int32_t index, int* order); - int openmc_zernike_filter_get_params(int32_t index, double* x, double* y, double* r); - int openmc_zernike_filter_set_order(int32_t index, int order); - int openmc_zernike_filter_set_params(int32_t index, const double* x, - const double* y, const double* r); - - //! Sets the mesh and energy grid for CMFD reweight - //! \param[in] meshtyally_id id of CMFD Mesh Tally - //! \param[in] cmfd_indices indices storing spatial and energy dimensions of CMFD problem - //! \param[in] norm CMFD normalization factor - extern "C" void openmc_initialize_mesh_egrid(const int meshtally_id, const int* cmfd_indices, - const double norm); - - //! Sets the mesh and energy grid for CMFD reweight - //! \param[in] feedback whether or not to run CMFD feedback - //! \param[in] cmfd_src computed CMFD source - extern "C" void openmc_cmfd_reweight(const bool feedback, const double* cmfd_src); - - //! Sets the fixed variables that are used for CMFD linear solver - //! \param[in] indptr CSR format index pointer array of loss matrix - //! \param[in] len_indptr length of indptr - //! \param[in] indices CSR format index array of loss matrix - //! \param[in] n_elements number of non-zero elements in CMFD loss matrix - //! \param[in] dim dimension n of nxn CMFD loss matrix - //! \param[in] spectral spectral radius of CMFD matrices and tolerances - //! \param[in] map coremap for problem, storing accelerated regions - //! \param[in] use_all_threads whether to use all threads when running CMFD solver - extern "C" void openmc_initialize_linsolver(const int* indptr, int len_indptr, - const int* indices, int n_elements, - int dim, double spectral, - const int* map, bool use_all_threads); - - //! Runs a Gauss Seidel linear solver to solve CMFD matrix equations - //! linear solver - //! \param[in] A_data CSR format data array of coefficient matrix - //! \param[in] b right hand side vector - //! \param[out] x unknown vector - //! \param[in] tol tolerance on final error - //! \return number of inner iterations required to reach convergence - extern "C" int openmc_run_linsolver(const double* A_data, const double* b, - double* x, double tol); - - // Error codes - extern int OPENMC_E_UNASSIGNED; - extern int OPENMC_E_ALLOCATE; - extern int OPENMC_E_OUT_OF_BOUNDS; - extern int OPENMC_E_INVALID_SIZE; - extern int OPENMC_E_INVALID_ARGUMENT; - extern int OPENMC_E_INVALID_TYPE; - extern int OPENMC_E_INVALID_ID; - extern int OPENMC_E_GEOMETRY; - extern int OPENMC_E_DATA; - extern int OPENMC_E_PHYSICS; - extern int OPENMC_E_WARNING; - - // Global variables - extern char openmc_err_msg[256]; +int openmc_calculate_volumes(); +int openmc_cell_filter_get_bins( + int32_t index, const int32_t** cells, int32_t* n); +int openmc_cell_get_fill( + int32_t index, int* type, int32_t** indices, int32_t* n); +int openmc_cell_get_id(int32_t index, int32_t* id); +int openmc_cell_get_temperature( + int32_t index, const int32_t* instance, double* T); +int openmc_cell_get_translation(int32_t index, double xyz[]); +int openmc_cell_get_rotation(int32_t index, double rot[], size_t* n); +int openmc_cell_get_name(int32_t index, const char** name); +int openmc_cell_get_num_instances(int32_t index, int32_t* num_instances); +int openmc_cell_set_name(int32_t index, const char* name); +int openmc_cell_set_fill( + int32_t index, int type, int32_t n, const int32_t* indices); +int openmc_cell_set_id(int32_t index, int32_t id); +int openmc_cell_set_temperature( + int32_t index, double T, const int32_t* instance, bool set_contained = false); +int openmc_cell_set_translation(int32_t index, const double xyz[]); +int openmc_cell_set_rotation(int32_t index, const double rot[], size_t rot_len); +int openmc_energy_filter_get_bins( + int32_t index, const double** energies, size_t* n); +int openmc_energy_filter_set_bins( + int32_t index, size_t n, const double* energies); +int openmc_energyfunc_filter_get_energy( + int32_t index, size_t* n, const double** energy); +int openmc_energyfunc_filter_get_y(int32_t index, size_t* n, const double** y); +int openmc_energyfunc_filter_set_data( + int32_t index, size_t n, const double* energies, const double* y); +int openmc_energyfunc_filter_set_interpolation( + int32_t index, const char* interp); +int openmc_energyfunc_filter_get_interpolation(int32_t index, int* interp); +int openmc_extend_cells(int32_t n, int32_t* index_start, int32_t* index_end); +int openmc_extend_filters(int32_t n, int32_t* index_start, int32_t* index_end); +int openmc_extend_materials( + int32_t n, int32_t* index_start, int32_t* index_end); +int openmc_extend_meshes( + int32_t n, const char* type, int32_t* index_start, int32_t* index_end); +int openmc_extend_tallies(int32_t n, int32_t* index_start, int32_t* index_end); +int openmc_filter_get_id(int32_t index, int32_t* id); +int openmc_filter_get_type(int32_t index, char* type); +int openmc_filter_get_num_bins(int32_t index, int* n_bins); +int openmc_filter_set_id(int32_t index, int32_t id); +int openmc_finalize(); +int openmc_find_cell(const double* xyz, int32_t* index, int32_t* instance); +int openmc_cell_bounding_box(const int32_t index, double* llc, double* urc); +int openmc_global_bounding_box(double* llc, double* urc); +int openmc_fission_bank(void** ptr, int64_t* n); +int openmc_get_cell_index(int32_t id, int32_t* index); +int openmc_get_filter_index(int32_t id, int32_t* index); +void openmc_get_filter_next_id(int32_t* id); +int openmc_get_keff(double k_combined[]); +int openmc_get_material_index(int32_t id, int32_t* index); +int openmc_get_mesh_index(int32_t id, int32_t* index); +int openmc_get_n_batches(int* n_batches, bool get_max_batches); +int openmc_get_nuclide_index(const char name[], int* index); +int openmc_add_unstructured_mesh( + const char filename[], const char library[], int* id); +int64_t openmc_get_seed(); +int openmc_get_tally_index(int32_t id, int32_t* index); +void openmc_get_tally_next_id(int32_t* id); +int openmc_global_tallies(double** ptr); +int openmc_hard_reset(); +int openmc_init(int argc, char* argv[], const void* intracomm); +bool openmc_is_statepoint_batch(); +int openmc_legendre_filter_get_order(int32_t index, int* order); +int openmc_legendre_filter_set_order(int32_t index, int order); +int openmc_load_nuclide(const char* name, const double* temps, int n); +int openmc_material_add_nuclide( + int32_t index, const char name[], double density); +int openmc_material_get_densities( + int32_t index, const int** nuclides, const double** densities, int* n); +int openmc_material_get_id(int32_t index, int32_t* id); +int openmc_material_get_fissionable(int32_t index, bool* fissionable); +int openmc_material_get_density(int32_t index, double* density); +int openmc_material_get_volume(int32_t index, double* volume); +int openmc_material_set_density( + int32_t index, double density, const char* units); +int openmc_material_set_densities( + int32_t index, int n, const char** name, const double* density); +int openmc_material_set_id(int32_t index, int32_t id); +int openmc_material_get_name(int32_t index, const char** name); +int openmc_material_set_name(int32_t index, const char* name); +int openmc_material_set_volume(int32_t index, double volume); +int openmc_material_get_depletable(int32_t index, bool* depletable); +int openmc_material_set_depletable(int32_t index, bool depletable); +int openmc_material_filter_get_bins( + int32_t index, const int32_t** bins, size_t* n); +int openmc_material_filter_set_bins( + int32_t index, size_t n, const int32_t* bins); +int openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh); +int openmc_mesh_filter_set_mesh(int32_t index, int32_t index_mesh); +int openmc_mesh_filter_get_translation(int32_t index, double translation[3]); +int openmc_mesh_filter_set_translation(int32_t index, double translation[3]); +int openmc_mesh_get_id(int32_t index, int32_t* id); +int openmc_mesh_set_id(int32_t index, int32_t id); +int openmc_mesh_get_n_elements(int32_t index, size_t* n); +int openmc_mesh_get_volumes(int32_t index, double* volumes); +int openmc_mesh_material_volumes(int32_t index, int n_sample, int bin, + int result_size, void* result, int* hits, uint64_t* seed); +int openmc_meshsurface_filter_get_mesh(int32_t index, int32_t* index_mesh); +int openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh); +int openmc_new_filter(const char* type, int32_t* index); +int openmc_next_batch(int* status); +int openmc_nuclide_name(int index, const char** name); +int openmc_plot_geometry(); +int openmc_id_map(const void* slice, int32_t* data_out); +int openmc_property_map(const void* slice, double* data_out); +int openmc_rectilinear_mesh_get_grid(int32_t index, double** grid_x, int* nx, + double** grid_y, int* ny, double** grid_z, int* nz); +int openmc_rectilinear_mesh_set_grid(int32_t index, const double* grid_x, + const int nx, const double* grid_y, const int ny, const double* grid_z, + const int nz); +int openmc_regular_mesh_get_dimension(int32_t index, int** id, int* n); +int openmc_regular_mesh_get_params( + int32_t index, double** ll, double** ur, double** width, int* n); +int openmc_regular_mesh_set_dimension(int32_t index, int n, const int* dims); +int openmc_regular_mesh_set_params(int32_t index, int n, const double* ll, + const double* ur, const double* width); +int openmc_remove_tally(int32_t index); +int openmc_reset(); +int openmc_reset_timers(); +int openmc_run(); +int openmc_sample_external_source(size_t n, uint64_t* seed, void* sites); +void openmc_set_seed(int64_t new_seed); +int openmc_set_n_batches( + int32_t n_batches, bool set_max_batches, bool add_statepoint_batch); +int openmc_simulation_finalize(); +int openmc_simulation_init(); +int openmc_source_bank(void** ptr, int64_t* n); +int openmc_spatial_legendre_filter_get_order(int32_t index, int* order); +int openmc_spatial_legendre_filter_get_params( + int32_t index, int* axis, double* min, double* max); +int openmc_spatial_legendre_filter_set_order(int32_t index, int order); +int openmc_spatial_legendre_filter_set_params( + int32_t index, const int* axis, const double* min, const double* max); +int openmc_sphharm_filter_get_order(int32_t index, int* order); +int openmc_sphharm_filter_get_cosine(int32_t index, char cosine[]); +int openmc_sphharm_filter_set_order(int32_t index, int order); +int openmc_sphharm_filter_set_cosine(int32_t index, const char cosine[]); +int openmc_statepoint_write(const char* filename, bool* write_source); +int openmc_statepoint_load(const char* filename); +int openmc_tally_allocate(int32_t index, const char* type); +int openmc_tally_get_active(int32_t index, bool* active); +int openmc_tally_get_estimator(int32_t index, int* estimator); +int openmc_tally_get_id(int32_t index, int32_t* id); +int openmc_tally_get_filters(int32_t index, const int32_t** indices, size_t* n); +int openmc_tally_get_n_realizations(int32_t index, int32_t* n); +int openmc_tally_get_nuclides(int32_t index, int** nuclides, int* n); +int openmc_tally_get_scores(int32_t index, int** scores, int* n); +int openmc_tally_get_type(int32_t index, int32_t* type); +int openmc_tally_get_writable(int32_t index, bool* writable); +int openmc_tally_reset(int32_t index); +int openmc_tally_results(int32_t index, double** ptr, size_t shape_[3]); +int openmc_tally_set_active(int32_t index, bool active); +int openmc_tally_set_estimator(int32_t index, const char* estimator); +int openmc_tally_set_filters(int32_t index, size_t n, const int32_t* indices); +int openmc_tally_set_id(int32_t index, int32_t id); +int openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides); +int openmc_tally_set_scores(int32_t index, int n, const char** scores); +int openmc_tally_set_type(int32_t index, const char* type); +int openmc_tally_set_writable(int32_t index, bool writable); +int openmc_get_weight_windows_index(int32_t id, int32_t* idx); +int openmc_weight_windows_get_id(int32_t index, int32_t* id); +int openmc_weight_windows_set_id(int32_t index, int32_t id); + +//! Updates weight window values using the specified tally +//! \param[in] ww_idx Index of the weight window object +//! \param[in] tally_idx Index of the tally to use for the update +//! \param[in] value Tally value to use for the update (one of 'mean', +//! 'rel_err') \param[in] threshold Relative error threshold for applied results +//! \param[in] ratio Upper to lower weight window bound ratio +int openmc_weight_windows_update_magic(int32_t ww_idx, int32_t tally_idx, + const char* value, double threshold, double ratio); + +int openmc_extend_weight_windows( + int32_t n, int32_t* index_start, int32_t* index_end); +int openmc_weight_windows_get_mesh(int32_t index, int32_t* mesh_idx); +int openmc_weight_windows_set_mesh(int32_t index, int32_t mesh_idx); +int openmc_weight_windows_set_energy_bounds( + int32_t index, double* e_bounds, size_t e_bounds_size); +int openmc_weight_windows_get_energy_bounds( + int32_t index, const double** e_bounds, size_t* e_bounds_size); +int openmc_weight_windows_set_particle(int32_t index, int particle); +int openmc_weight_windows_get_particle(int32_t index, int* particle); +int openmc_weight_windows_get_bounds(int32_t index, const double** lower_bounds, + const double** upper_bounds, size_t* size); +int openmc_weight_windows_set_bounds(int32_t index, const double* lower_bounds, + const double* upper_bounds, size_t size); +int openmc_weight_windows_get_survival_ratio(int32_t index, double* ratio); +int openmc_weight_windows_set_survival_ratio(int32_t index, double ratio); +int openmc_weight_windows_get_max_lower_bound_ratio( + int32_t index, double* lb_ratio); +int openmc_weight_windows_set_max_lower_bound_ratio( + int32_t index, double lb_ratio); +int openmc_weight_windows_get_weight_cutoff(int32_t index, double* cutoff); +int openmc_weight_windows_set_weight_cutoff(int32_t index, double cutoff); +int openmc_weight_windows_get_max_split(int32_t index, int* max_split); +int openmc_weight_windows_set_max_split(int32_t index, int max_split); +size_t openmc_weight_windows_size(); +int openmc_weight_windows_export(const char* filename = nullptr); +int openmc_weight_windows_import(const char* filename = nullptr); +int openmc_zernike_filter_get_order(int32_t index, int* order); +int openmc_zernike_filter_get_params( + int32_t index, double* x, double* y, double* r); +int openmc_zernike_filter_set_order(int32_t index, int order); +int openmc_zernike_filter_set_params( + int32_t index, const double* x, const double* y, const double* r); + +int openmc_particle_filter_get_bins(int32_t idx, int bins[]); + +//! Sets the mesh and energy grid for CMFD reweight +//! \param[in] meshtyally_id id of CMFD Mesh Tally +//! \param[in] cmfd_indices indices storing spatial and energy dimensions of +//! CMFD problem \param[in] norm CMFD normalization factor +void openmc_initialize_mesh_egrid( + const int meshtally_id, const int* cmfd_indices, const double norm); + +//! Sets the mesh and energy grid for CMFD reweight +//! \param[in] feedback whether or not to run CMFD feedback +//! \param[in] cmfd_src computed CMFD source +void openmc_cmfd_reweight(const bool feedback, const double* cmfd_src); + +//! Sets the fixed variables that are used for CMFD linear solver +//! \param[in] indptr CSR format index pointer array of loss matrix +//! \param[in] len_indptr length of indptr +//! \param[in] indices CSR format index array of loss matrix +//! \param[in] n_elements number of non-zero elements in CMFD loss matrix +//! \param[in] dim dimension n of nxn CMFD loss matrix +//! \param[in] spectral spectral radius of CMFD matrices and tolerances +//! \param[in] map coremap for problem, storing accelerated regions +//! \param[in] use_all_threads whether to use all threads when running CMFD +//! solver +void openmc_initialize_linsolver(const int* indptr, int len_indptr, + const int* indices, int n_elements, int dim, double spectral, const int* map, + bool use_all_threads); + +//! Runs a Gauss Seidel linear solver to solve CMFD matrix equations +//! linear solver +//! \param[in] A_data CSR format data array of coefficient matrix +//! \param[in] b right hand side vector +//! \param[out] x unknown vector +//! \param[in] tol tolerance on final error +//! \return number of inner iterations required to reach convergence +int openmc_run_linsolver( + const double* A_data, const double* b, double* x, double tol); + +//! Export physical properties for model +//! \param[in] filename Filename to write to +//! \return Error code +int openmc_properties_export(const char* filename); + +//! Import physical properties for model +//! \param[in] filename Filename to read from +// \return Error code +int openmc_properties_import(const char* filename); + +// Error codes +extern int OPENMC_E_UNASSIGNED; +extern int OPENMC_E_ALLOCATE; +extern int OPENMC_E_OUT_OF_BOUNDS; +extern int OPENMC_E_INVALID_SIZE; +extern int OPENMC_E_INVALID_ARGUMENT; +extern int OPENMC_E_INVALID_TYPE; +extern int OPENMC_E_INVALID_ID; +extern int OPENMC_E_GEOMETRY; +extern int OPENMC_E_DATA; +extern int OPENMC_E_PHYSICS; +extern int OPENMC_E_WARNING; + +// Global variables +extern char openmc_err_msg[256]; #ifdef __cplusplus } diff --git a/include/openmc/cell.h b/include/openmc/cell.h index c7ba0ab1374..e68443a32fd 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -6,17 +6,18 @@ #include #include #include +#include -#include #include "hdf5.h" #include "pugixml.hpp" -#include "dagmc.h" +#include #include "openmc/constants.h" #include "openmc/memory.h" // for unique_ptr #include "openmc/neighbor_list.h" #include "openmc/position.h" #include "openmc/surface.h" +#include "openmc/universe.h" #include "openmc/vector.h" namespace openmc { @@ -25,57 +26,127 @@ namespace openmc { // Constants //============================================================================== -enum class Fill { - MATERIAL, - UNIVERSE, - LATTICE -}; +enum class Fill { MATERIAL, UNIVERSE, LATTICE }; // TODO: Convert to enum -constexpr int32_t OP_LEFT_PAREN {std::numeric_limits::max()}; -constexpr int32_t OP_RIGHT_PAREN {std::numeric_limits::max() - 1}; -constexpr int32_t OP_COMPLEMENT {std::numeric_limits::max() - 2}; +constexpr int32_t OP_LEFT_PAREN {std::numeric_limits::max()}; +constexpr int32_t OP_RIGHT_PAREN {std::numeric_limits::max() - 1}; +constexpr int32_t OP_COMPLEMENT {std::numeric_limits::max() - 2}; constexpr int32_t OP_INTERSECTION {std::numeric_limits::max() - 3}; -constexpr int32_t OP_UNION {std::numeric_limits::max() - 4}; +constexpr int32_t OP_UNION {std::numeric_limits::max() - 4}; //============================================================================== // Global variables //============================================================================== class Cell; +class GeometryState; class ParentCell; class CellInstance; class Universe; class UniversePartitioner; namespace model { - extern std::unordered_map cell_map; - extern vector> cells; +extern std::unordered_map cell_map; +extern vector> cells; - extern std::unordered_map universe_map; - extern vector> universes; } // namespace model -//============================================================================== -//! A geometry primitive that fills all space and contains cells. //============================================================================== -class Universe -{ +class Region { public: - int32_t id_; //!< Unique ID - vector cells_; //!< Cells within this universe + //---------------------------------------------------------------------------- + // Constructors + Region() {} + explicit Region(std::string region_spec, int32_t cell_id); - //! \brief Write universe information to an HDF5 group. - //! \param group_id An HDF5 group id. - void to_hdf5(hid_t group_id) const; + //---------------------------------------------------------------------------- + // Methods + + //! \brief Determine if a cell contains the particle at a given location. + //! + //! The bounds of the cell are determined by a logical expression involving + //! surface half-spaces. The expression used is given in infix notation + //! + //! The function is split into two cases, one for simple cells (those + //! involving only the intersection of half-spaces) and one for complex cells. + //! Both cases use short circuiting; however, in the case fo complex cells, + //! the complexity increases with the binary operators involved. + //! \param r The 3D Cartesian coordinate to check. + //! \param u A direction used to "break ties" the coordinates are very + //! close to a surface. + //! \param on_surface The signed index of a surface that the coordinate is + //! known to be on. This index takes precedence over surface sense + //! calculations. + bool contains(Position r, Direction u, int32_t on_surface) const; + + //! Find the oncoming boundary of this cell. + std::pair distance( + Position r, Direction u, int32_t on_surface) const; + + //! Get the BoundingBox for this cell. + BoundingBox bounding_box(int32_t cell_id) const; + + //! Get the CSG expression as a string + std::string str() const; + + //! Get a vector containing all the surfaces in the region expression + vector surfaces() const; + + //---------------------------------------------------------------------------- + // Accessors + + //! Get Boolean of if the cell is simple or not + bool is_simple() const { return simple_; } + +private: + //---------------------------------------------------------------------------- + // Private Methods + + //! Get a vector of the region expression in postfix notation + vector generate_postfix(int32_t cell_id) const; + + //! Determine if a particle is inside the cell for a simple cell (only + //! intersection operators) + bool contains_simple(Position r, Direction u, int32_t on_surface) const; + + //! Determine if a particle is inside the cell for a complex cell. + //! + //! Uses the comobination of half-spaces and binary operators to determine + //! if short circuiting can be used. Short cicuiting uses the relative and + //! absolute depth of parenthases in the expression. + bool contains_complex(Position r, Direction u, int32_t on_surface) const; + + //! BoundingBox if the paritcle is in a simple cell. + BoundingBox bounding_box_simple() const; + + //! BoundingBox if the particle is in a complex cell. + BoundingBox bounding_box_complex(vector postfix) const; - BoundingBox bounding_box() const; + //! Enfource precedence: Parenthases, Complement, Intersection, Union + void add_precedence(); - unique_ptr partitioner_; + //! Add parenthesis to enforce precedence + std::vector::iterator add_parentheses( + std::vector::iterator start); + + //! Remove complement operators from the expression + void remove_complement_ops(); + + //! Remove complement operators by using DeMorgan's laws + void apply_demorgan( + vector::iterator start, vector::iterator stop); + + //---------------------------------------------------------------------------- + // Private Data + + //! Definition of spatial region as Boolean expression of half-spaces + // TODO: Should this be a vector of some other type + vector expression_; + bool simple_; //!< Does the region contain only intersections? }; -//============================================================================== //============================================================================== class Cell { @@ -109,20 +180,35 @@ class Cell { //! \param on_surface The signed index of a surface that the coordinate is //! known to be on. This index takes precedence over surface sense //! calculations. - virtual bool - contains(Position r, Direction u, int32_t on_surface) const = 0; + virtual bool contains(Position r, Direction u, int32_t on_surface) const = 0; //! Find the oncoming boundary of this cell. - virtual std::pair - distance(Position r, Direction u, int32_t on_surface, Particle* p) const = 0; + virtual std::pair distance( + Position r, Direction u, int32_t on_surface, GeometryState* p) const = 0; //! Write all information needed to reconstruct the cell to an HDF5 group. //! \param group_id An HDF5 group id. - virtual void to_hdf5(hid_t group_id) const = 0; + void to_hdf5(hid_t group_id) const; + + virtual void to_hdf5_inner(hid_t group_id) const = 0; + + //! Export physical properties to HDF5 + //! \param[in] group HDF5 group to read from + void export_properties_hdf5(hid_t group) const; + + //! Import physical properties from HDF5 + //! \param[in] group HDF5 group to write to + void import_properties_hdf5(hid_t group); //! Get the BoundingBox for this cell. virtual BoundingBox bounding_box() const = 0; + //! Get a vector of surfaces in the cell + virtual vector surfaces() const { return vector(); } + + //! Check if the cell region expression is simple + virtual bool is_simple() const { return true; } + //---------------------------------------------------------------------------- // Accessors @@ -139,7 +225,12 @@ class Cell { //! \param[in] set_contained If this cell is not filled with a material, //! collect all contained cells with material fills and set their //! temperatures. - void set_temperature(double T, int32_t instance = -1, bool set_contained = false); + void set_temperature( + double T, int32_t instance = -1, bool set_contained = false); + + //! Set the rotation matrix of a cell instance + //! \param[in] rot The rotation matrix of length 3 or 9 + void set_rotation(const vector& rot); //! Get the name of a cell //! \return Cell name @@ -150,10 +241,71 @@ class Cell { void set_name(const std::string& name) { name_ = name; }; //! Get all cell instances contained by this cell - //! \return Map with cell indexes as keys and instances as values - std::unordered_map> get_contained_cells() const; + //! \param[in] instance Instance of the cell for which to get contained cells + //! (default instance is zero) + //! \param[in] hint positional hint for determining the parent cells + //! \return Map with cell indexes as keys and + //! instances as values + std::unordered_map> get_contained_cells( + int32_t instance = 0, Position* hint = nullptr) const; + + //! Determine the material index corresponding to a specific cell instance, + //! taking into account presence of distribcell material + //! \param[in] instance of the cell + //! \return material index + int32_t material(int32_t instance) const + { + // If distributed materials are used, then each instance has its own + // material definition. If distributed materials are not used, then + // all instances used the same material stored at material_[0]. The + // presence of distributed materials is inferred from the size of + // the material_ vector being greater than one. + if (material_.size() > 1) { + return material_[instance]; + } else { + return material_[0]; + } + } + + //! Determine the temperature index corresponding to a specific cell instance, + //! taking into account presence of distribcell temperature + //! \param[in] instance of the cell + //! \return temperature index + double sqrtkT(int32_t instance) const + { + // If distributed materials are used, then each instance has its own + // temperature definition. If distributed materials are not used, then + // all instances used the same temperature stored at sqrtkT_[0]. The + // presence of distributed materials is inferred from the size of + // the sqrtkT_ vector being greater than one. + if (sqrtkT_.size() > 1) { + return sqrtkT_[instance]; + } else { + return sqrtkT_[0]; + } + } protected: + //! Determine the path to this cell instance in the geometry hierarchy + //! \param[in] instance of the cell to find parent cells for + //! \param[in] r position used to do a fast search for parent cells + //! \return parent cells + vector find_parent_cells( + int32_t instance, const Position& r) const; + + //! Determine the path to this cell instance in the geometry hierarchy + //! \param[in] instance of the cell to find parent cells for + //! \param[in] p particle used to do a fast search for parent cells + //! \return parent cells + vector find_parent_cells( + int32_t instance, GeometryState& p) const; + + //! Determine the path to this cell instance in the geometry hierarchy + //! \param[in] instance of the cell to find parent cells for + //! \return parent cells + vector exhaustive_find_parent_cells(int32_t instance) const; + + //! Inner function for retrieving contained cells void get_contained_cells_inner( std::unordered_map>& contained_cells, vector& parent_cells) const; @@ -162,15 +314,16 @@ class Cell { //---------------------------------------------------------------------------- // Data members - int32_t id_; //!< Unique ID - std::string name_; //!< User-defined name - Fill type_; //!< Material, universe, or lattice - int32_t universe_; //!< Universe # this cell is in - int32_t fill_; //!< Universe # filling this cell - int32_t n_instances_{0}; //!< Number of instances of this cell + int32_t id_; //!< Unique ID + std::string name_; //!< User-defined name + Fill type_; //!< Material, universe, or lattice + int32_t universe_; //!< Universe # this cell is in + int32_t fill_; //!< Universe # filling this cell + int32_t n_instances_ {0}; //!< Number of instances of this cell + GeometryType geom_type_; //!< Geometric representation type (CSG, DAGMC) //! \brief Index corresponding to this cell in distribcell arrays - int distribcell_index_{C_NONE}; + int distribcell_index_ {C_NONE}; //! \brief Material(s) within this cell. //! @@ -183,12 +336,6 @@ class Cell { //! T. The units are sqrt(eV). vector sqrtkT_; - //! Definition of spatial region as Boolean expression of half-spaces - vector region_; - //! Reverse Polish notation for region expression - vector rpn_; - bool simple_; //!< Does the region contain only intersections? - //! \brief Neighboring cells in the same universe. NeighborList neighbors_; @@ -206,45 +353,44 @@ class Cell { }; struct CellInstanceItem { - int32_t index {-1}; //! Index into global cells array - int lattice_indx{-1}; //! Flat index value of the lattice cell + int32_t index {-1}; //! Index into global cells array + int lattice_indx {-1}; //! Flat index value of the lattice cell }; //============================================================================== -class CSGCell : public Cell -{ +class CSGCell : public Cell { public: + //---------------------------------------------------------------------------- + // Constructors CSGCell(); - explicit CSGCell(pugi::xml_node cell_node); - bool - contains(Position r, Direction u, int32_t on_surface) const; - - std::pair - distance(Position r, Direction u, int32_t on_surface, Particle* p) const; + //---------------------------------------------------------------------------- + // Methods + vector surfaces() const override { return region_.surfaces(); } - void to_hdf5(hid_t group_id) const; + std::pair distance(Position r, Direction u, + int32_t on_surface, GeometryState* p) const override + { + return region_.distance(r, u, on_surface); + } - BoundingBox bounding_box() const; + bool contains(Position r, Direction u, int32_t on_surface) const override + { + return region_.contains(r, u, on_surface); + } -protected: - bool contains_simple(Position r, Direction u, int32_t on_surface) const; - bool contains_complex(Position r, Direction u, int32_t on_surface) const; - BoundingBox bounding_box_simple() const; - static BoundingBox bounding_box_complex(vector rpn); + BoundingBox bounding_box() const override + { + return region_.bounding_box(id_); + } - //! Applies DeMorgan's laws to a section of the RPN - //! \param start Starting point for token modification - //! \param stop Stopping point for token modification - static void apply_demorgan( - vector::iterator start, vector::iterator stop); + void to_hdf5_inner(hid_t group_id) const override; - //! Removes complement operators from the RPN - //! \param rpn The rpn to remove complement operators from. - static void remove_complement_ops(vector& rpn); + bool is_simple() const override { return region_.is_simple(); } +protected: //! Returns the beginning position of a parenthesis block (immediately before //! two surface tokens) in the RPN given a starting position at the end of //! that block (immediately after two surface tokens) @@ -252,87 +398,33 @@ class CSGCell : public Cell //! \param rpn The rpn being searched static vector::iterator find_left_parenthesis( vector::iterator start, const vector& rpn); -}; - -//============================================================================== - -#ifdef DAGMC -class DAGCell : public Cell -{ -public: - DAGCell(); - - bool contains(Position r, Direction u, int32_t on_surface) const; - - std::pair - distance(Position r, Direction u, int32_t on_surface, Particle* p) const; - - BoundingBox bounding_box() const; - - void to_hdf5(hid_t group_id) const; - - moab::DagMC* dagmc_ptr_; //!< Pointer to DagMC instance - int32_t dag_index_; //!< DagMC index of cell -}; -#endif - -//============================================================================== -//! Speeds up geometry searches by grouping cells in a search tree. -// -//! Currently this object only works with universes that are divided up by a -//! bunch of z-planes. It could be generalized to other planes, cylinders, -//! and spheres. -//============================================================================== - -class UniversePartitioner -{ -public: - explicit UniversePartitioner(const Universe& univ); - - //! Return the list of cells that could contain the given coordinates. - const vector& get_cells(Position r, Direction u) const; private: - //! A sorted vector of indices to surfaces that partition the universe - vector surfs_; - - //! Vectors listing the indices of the cells that lie within each partition - // - //! There are n+1 partitions with n surfaces. `partitions_.front()` gives the - //! cells that lie on the negative side of `surfs_.front()`. - //! `partitions_.back()` gives the cells that lie on the positive side of - //! `surfs_.back()`. Otherwise, `partitions_[i]` gives cells sandwiched - //! between `surfs_[i-1]` and `surfs_[i]`. - vector> partitions_; -}; - - -//============================================================================== -//! Define a containing (parent) cell -//============================================================================== - -struct ParentCell { - gsl::index cell_index; - gsl::index lattice_index; + Region region_; }; //============================================================================== //! Define an instance of a particular cell //============================================================================== +//! Stores information used to identify a unique cell in the model struct CellInstance { //! Check for equality bool operator==(const CellInstance& other) const - { return index_cell == other.index_cell && instance == other.instance; } + { + return index_cell == other.index_cell && instance == other.instance; + } gsl::index index_cell; gsl::index instance; }; +//! Structure necessary for inserting CellInstance into hashed STL data +//! structures struct CellInstanceHash { std::size_t operator()(const CellInstance& k) const { - return 4096*k.index_cell + k.instance; + return 4096 * k.index_cell + k.instance; } }; @@ -342,9 +434,8 @@ struct CellInstanceHash { void read_cells(pugi::xml_node node); -#ifdef DAGMC -int32_t next_cell(DAGCell* cur_cell, DAGSurface* surf_xed); -#endif +//! Add cells to universes +void populate_universes(); } // namespace openmc #endif // OPENMC_CELL_H diff --git a/include/openmc/cmfd_solver.h b/include/openmc/cmfd_solver.h index 731fe7ffbdf..76c8bf6a89d 100644 --- a/include/openmc/cmfd_solver.h +++ b/include/openmc/cmfd_solver.h @@ -3,6 +3,17 @@ namespace openmc { +//============================================================================== +// Constants +//============================================================================== + +// For non-accelerated regions on coarse mesh overlay +constexpr int CMFD_NOACCEL {-1}; + +//============================================================================== +// Non-member functions +//============================================================================== + void free_memory_cmfd(); } // namespace openmc diff --git a/include/openmc/constants.h b/include/openmc/constants.h index aac3a52a832..1c683e5f50c 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -5,6 +5,7 @@ #define OPENMC_CONSTANTS_H #include +#include #include #include "openmc/array.h" @@ -24,13 +25,15 @@ using double_4dvec = vector>>>; constexpr int HDF5_VERSION[] {3, 0}; // Version numbers for binary files -constexpr array VERSION_STATEPOINT {17, 0}; +constexpr array VERSION_STATEPOINT {18, 1}; constexpr array VERSION_PARTICLE_RESTART {2, 0}; -constexpr array VERSION_TRACK {2, 0}; +constexpr array VERSION_TRACK {3, 0}; constexpr array VERSION_SUMMARY {6, 0}; constexpr array VERSION_VOLUME {1, 0}; constexpr array VERSION_VOXEL {2, 0}; constexpr array VERSION_MGXS_LIBRARY {1, 0}; +constexpr array VERSION_PROPERTIES {1, 0}; +constexpr array VERSION_WEIGHT_WINDOWS {1, 0}; // ============================================================================ // ADJUSTABLE PARAMETERS @@ -38,9 +41,6 @@ constexpr array VERSION_MGXS_LIBRARY {1, 0}; // NOTE: This is the only section of the constants module that should ever be // adjusted. Modifying constants in other sections may cause the code to fail. -// Monoatomic ideal-gas scattering treatment threshold -constexpr double FREE_GAS_THRESHOLD {400.0}; - // Significance level for confidence intervals constexpr double CONFIDENCE_LEVEL {0.95}; @@ -52,19 +52,12 @@ constexpr double FP_PRECISION {1e-14}; constexpr double FP_REL_PRECISION {1e-5}; constexpr double FP_COINCIDENT {1e-12}; -// Maximum number of collisions/crossings -constexpr int MAX_EVENTS {1000000}; -constexpr int MAX_SAMPLE {100000}; - -// Maximum number of words in a single line, length of line, and length of -// single word -constexpr int MAX_LINE_LEN {250}; -constexpr int MAX_WORD_LEN {150}; +// Coincidence tolerances +constexpr double TORUS_TOL {1e-10}; +constexpr double RADIAL_MESH_TOL {1e-10}; -// Maximum number of external source spatial resamples to encounter before an -// error is thrown. -constexpr int EXTSRC_REJECT_THRESHOLD {10000}; -constexpr double EXTSRC_REJECT_FRACTION {0.05}; +// Maximum number of random samples per history +constexpr int MAX_SAMPLE {100000}; // ============================================================================ // MATH AND PHYSICAL CONSTANTS @@ -78,16 +71,20 @@ constexpr double INFTY {std::numeric_limits::max()}; // (CODATA) 2018 recommendation (https://physics.nist.gov/cuu/Constants/). // Physical constants -constexpr double MASS_NEUTRON {1.00866491595}; // mass of a neutron in amu -constexpr double MASS_NEUTRON_EV {939.56542052e6}; // mass of a neutron in eV/c^2 -constexpr double MASS_PROTON {1.007276466621}; // mass of a proton in amu -constexpr double MASS_ELECTRON_EV {0.51099895000e6}; // electron mass energy equivalent in eV/c^2 -constexpr double FINE_STRUCTURE {137.035999084}; // inverse fine structure constant -constexpr double PLANCK_C {1.2398419839593942e4}; // Planck's constant times c in eV-Angstroms -constexpr double AMU {1.66053906660e-27}; // 1 amu in kg -constexpr double C_LIGHT {2.99792458e8}; // speed of light in m/s -constexpr double N_AVOGADRO {0.602214076}; // Avogadro's number in 10^24/mol -constexpr double K_BOLTZMANN {8.617333262e-5}; // Boltzmann constant in eV/K +constexpr double MASS_NEUTRON {1.00866491595}; // mass of a neutron in amu +constexpr double MASS_NEUTRON_EV { + 939.56542052e6}; // mass of a neutron in eV/c^2 +constexpr double MASS_PROTON {1.007276466621}; // mass of a proton in amu +constexpr double MASS_ELECTRON_EV { + 0.51099895000e6}; // electron mass energy equivalent in eV/c^2 +constexpr double FINE_STRUCTURE { + 137.035999084}; // inverse fine structure constant +constexpr double PLANCK_C { + 1.2398419839593942e4}; // Planck's constant times c in eV-Angstroms +constexpr double AMU {1.66053906660e-27}; // 1 amu in kg +constexpr double C_LIGHT {2.99792458e10}; // speed of light in cm/s +constexpr double N_AVOGADRO {0.602214076}; // Avogadro's number in 10^24/mol +constexpr double K_BOLTZMANN {8.617333262e-5}; // Boltzmann constant in eV/K // Electron subshell labels constexpr array SUBSHELLS = {"K", "L1", "L2", "L3", "M1", "M2", @@ -98,16 +95,13 @@ constexpr array SUBSHELLS = {"K", "L1", "L2", "L3", "M1", "M2", // Void material and nuclide // TODO: refactor and remove constexpr int MATERIAL_VOID {-1}; -constexpr int NUCLIDE_NONE {-1}; +constexpr int NUCLIDE_NONE {-1}; // ============================================================================ // CROSS SECTION RELATED CONSTANTS // Temperature treatment method -enum class TemperatureMethod { - NEAREST, - INTERPOLATION -}; +enum class TemperatureMethod { NEAREST, INTERPOLATION }; // Reaction types enum ReactionType { @@ -116,105 +110,105 @@ enum ReactionType { ELASTIC = 2, N_NONELASTIC = 3, N_LEVEL = 4, - MISC = 5, - N_2ND = 11, - N_2N = 16, - N_3N = 17, + MISC = 5, + N_2ND = 11, + N_2N = 16, + N_3N = 17, N_FISSION = 18, - N_F = 19, - N_NF = 20, - N_2NF = 21, - N_NA = 22, - N_N3A = 23, - N_2NA = 24, - N_3NA = 25, - N_NP = 28, - N_N2A = 29, - N_2N2A = 30, - N_ND = 32, - N_NT = 33, - N_N3HE = 34, - N_ND2A = 35, - N_NT2A = 36, - N_4N = 37, - N_3NF = 38, - N_2NP = 41, - N_3NP = 42, - N_N2P = 44, - N_NPA = 45, - N_N1 = 51, - N_N40 = 90, - N_NC = 91, + N_F = 19, + N_NF = 20, + N_2NF = 21, + N_NA = 22, + N_N3A = 23, + N_2NA = 24, + N_3NA = 25, + N_NP = 28, + N_N2A = 29, + N_2N2A = 30, + N_ND = 32, + N_NT = 33, + N_N3HE = 34, + N_ND2A = 35, + N_NT2A = 36, + N_4N = 37, + N_3NF = 38, + N_2NP = 41, + N_3NP = 42, + N_N2P = 44, + N_NPA = 45, + N_N1 = 51, + N_N40 = 90, + N_NC = 91, N_DISAPPEAR = 101, N_GAMMA = 102, - N_P = 103, - N_D = 104, - N_T = 105, - N_3HE = 106, - N_A = 107, - N_2A = 108, - N_3A = 109, - N_2P = 111, - N_PA = 112, - N_T2A = 113, - N_D2A = 114, - N_PD = 115, - N_PT = 116, - N_DA = 117, - N_5N = 152, - N_6N = 153, - N_2NT = 154, - N_TA = 155, - N_4NP = 156, - N_3ND = 157, - N_NDA = 158, - N_2NPA = 159, - N_7N = 160, - N_8N = 161, - N_5NP = 162, - N_6NP = 163, - N_7NP = 164, - N_4NA = 165, - N_5NA = 166, - N_6NA = 167, - N_7NA = 168, - N_4ND = 169, - N_5ND = 170, - N_6ND = 171, - N_3NT = 172, - N_4NT = 173, - N_5NT = 174, - N_6NT = 175, + N_P = 103, + N_D = 104, + N_T = 105, + N_3HE = 106, + N_A = 107, + N_2A = 108, + N_3A = 109, + N_2P = 111, + N_PA = 112, + N_T2A = 113, + N_D2A = 114, + N_PD = 115, + N_PT = 116, + N_DA = 117, + N_5N = 152, + N_6N = 153, + N_2NT = 154, + N_TA = 155, + N_4NP = 156, + N_3ND = 157, + N_NDA = 158, + N_2NPA = 159, + N_7N = 160, + N_8N = 161, + N_5NP = 162, + N_6NP = 163, + N_7NP = 164, + N_4NA = 165, + N_5NA = 166, + N_6NA = 167, + N_7NA = 168, + N_4ND = 169, + N_5ND = 170, + N_6ND = 171, + N_3NT = 172, + N_4NT = 173, + N_5NT = 174, + N_6NT = 175, N_2N3HE = 176, N_3N3HE = 177, N_4N3HE = 178, - N_3N2P = 179, - N_3N2A = 180, - N_3NPA = 181, - N_DT = 182, - N_NPD = 183, - N_NPT = 184, - N_NDT = 185, + N_3N2P = 179, + N_3N2A = 180, + N_3NPA = 181, + N_DT = 182, + N_NPD = 183, + N_NPT = 184, + N_NDT = 185, N_NP3HE = 186, N_ND3HE = 187, N_NT3HE = 188, - N_NTA = 189, - N_2N2P = 190, - N_P3HE = 191, - N_D3HE = 192, - N_3HEA = 193, - N_4N2P = 194, - N_4N2A = 195, - N_4NPA = 196, - N_3P = 197, - N_N3P = 198, + N_NTA = 189, + N_2N2P = 190, + N_P3HE = 191, + N_D3HE = 192, + N_3HEA = 193, + N_4N2P = 194, + N_4N2A = 195, + N_4NPA = 196, + N_3P = 197, + N_N3P = 198, N_3N2PA = 199, - N_5N2P = 200, - N_XP = 203, - N_XD = 204, - N_XT = 205, - N_X3HE = 206, - N_XA = 207, + N_5N2P = 200, + N_XP = 203, + N_XD = 204, + N_XT = 205, + N_X3HE = 206, + N_XA = 207, HEATING = 301, DAMAGE_ENERGY = 444, COHERENT = 502, @@ -223,40 +217,28 @@ enum ReactionType { PAIR_PROD = 516, PAIR_PROD_NUC = 517, PHOTOELECTRIC = 522, - N_P0 = 600, - N_PC = 649, - N_D0 = 650, - N_DC = 699, - N_T0 = 700, - N_TC = 749, - N_3HE0 = 750, - N_3HEC = 799, - N_A0 = 800, - N_AC = 849, - N_2N0 = 875, - N_2NC = 891, + N_P0 = 600, + N_PC = 649, + N_D0 = 650, + N_DC = 699, + N_T0 = 700, + N_TC = 749, + N_3HE0 = 750, + N_3HEC = 799, + N_A0 = 800, + N_AC = 849, + N_2N0 = 875, + N_2NC = 891, HEATING_LOCAL = 901 }; constexpr array DEPLETION_RX {N_GAMMA, N_P, N_A, N_2N, N_3N, N_4N}; -enum class URRTableParam { - CUM_PROB, - TOTAL, - ELASTIC, - FISSION, - N_GAMMA, - HEATING -}; - -// Maximum number of partial fission reactions -constexpr int PARTIAL_FISSION_MAX {4}; - // Resonance elastic scattering methods enum class ResScatMethod { - rvs, // Relative velocity sampling + rvs, // Relative velocity sampling dbrc, // Doppler broadening rejection correction - cxs // Constant cross section + cxs // Constant cross section }; enum class ElectronTreatment { @@ -295,31 +277,13 @@ enum class MgxsType { // ============================================================================ // TALLY-RELATED CONSTANTS -enum class TallyResult { - VALUE, - SUM, - SUM_SQ -}; +enum class TallyResult { VALUE, SUM, SUM_SQ, SIZE }; -enum class TallyType { - VOLUME, - MESH_SURFACE, - SURFACE -}; +enum class TallyType { VOLUME, MESH_SURFACE, SURFACE, PULSE_HEIGHT }; -enum class TallyEstimator { - ANALOG, - TRACKLENGTH, - COLLISION -}; +enum class TallyEstimator { ANALOG, TRACKLENGTH, COLLISION }; -enum class TallyEvent { - SURFACE, - LATTICE, - KILL, - SCATTER, - ABSORB -}; +enum class TallyEvent { SURFACE, LATTICE, KILL, SCATTER, ABSORB }; // Tally score type -- if you change these, make sure you also update the // _SCORES dictionary in openmc/capi/tally.py @@ -328,40 +292,43 @@ enum class TallyEvent { // store one of these enum values usually also may be responsible for storing // MT numbers from the long enum above. enum TallyScore { - SCORE_FLUX = -1, // flux - SCORE_TOTAL = -2, // total reaction rate - SCORE_SCATTER = -3, // scattering rate - SCORE_NU_SCATTER = -4, // scattering production rate - SCORE_ABSORPTION = -5, // absorption rate - SCORE_FISSION = -6, // fission rate - SCORE_NU_FISSION = -7, // neutron production rate - SCORE_KAPPA_FISSION = -8, // fission energy production rate - SCORE_CURRENT = -9, // current - SCORE_EVENTS = -10, // number of events + SCORE_FLUX = -1, // flux + SCORE_TOTAL = -2, // total reaction rate + SCORE_SCATTER = -3, // scattering rate + SCORE_NU_SCATTER = -4, // scattering production rate + SCORE_ABSORPTION = -5, // absorption rate + SCORE_FISSION = -6, // fission rate + SCORE_NU_FISSION = -7, // neutron production rate + SCORE_KAPPA_FISSION = -8, // fission energy production rate + SCORE_CURRENT = -9, // current + SCORE_EVENTS = -10, // number of events SCORE_DELAYED_NU_FISSION = -11, // delayed neutron production rate - SCORE_PROMPT_NU_FISSION = -12, // prompt neutron production rate - SCORE_INVERSE_VELOCITY = -13, // flux-weighted inverse velocity - SCORE_FISS_Q_PROMPT = -14, // prompt fission Q-value - SCORE_FISS_Q_RECOV = -15, // recoverable fission Q-value - SCORE_DECAY_RATE = -16 // delayed neutron precursor decay rate + SCORE_PROMPT_NU_FISSION = -12, // prompt neutron production rate + SCORE_INVERSE_VELOCITY = -13, // flux-weighted inverse velocity + SCORE_FISS_Q_PROMPT = -14, // prompt fission Q-value + SCORE_FISS_Q_RECOV = -15, // recoverable fission Q-value + SCORE_DECAY_RATE = -16, // delayed neutron precursor decay rate + SCORE_PULSE_HEIGHT = -17 // pulse-height }; // Global tally parameters constexpr int N_GLOBAL_TALLIES {4}; -enum class GlobalTally { - K_COLLISION, - K_ABSORPTION, - K_TRACKLENGTH, - LEAKAGE -}; +enum class GlobalTally { K_COLLISION, K_ABSORPTION, K_TRACKLENGTH, LEAKAGE }; // Miscellaneous constexpr int C_NONE {-1}; -constexpr int F90_NONE {0}; //TODO: replace usage of this with C_NONE // Interpolation rules enum class Interpolation { - histogram = 1, lin_lin = 2, lin_log = 3, log_lin = 4, log_log = 5 + histogram = 1, + lin_lin = 2, + lin_log = 3, + log_lin = 4, + log_log = 5, + // skip 6 b/c ENDF-6 reserves this value for + // "special one-dimensional interpolation law" + quadratic = 7, + cubic = 8 }; enum class RunMode { @@ -373,11 +340,12 @@ enum class RunMode { VOLUME }; -// ============================================================================ -// CMFD CONSTANTS +enum class SolverType { MONTE_CARLO, RANDOM_RAY }; + +//============================================================================== +// Geometry Constants -// For non-accelerated regions on coarse mesh overlay -constexpr int CMFD_NOACCEL {-1}; +enum class GeometryType { CSG, DAG }; } // namespace openmc diff --git a/include/openmc/container_util.h b/include/openmc/container_util.h index 1e65a18df6b..a40532343cb 100644 --- a/include/openmc/container_util.h +++ b/include/openmc/container_util.h @@ -2,7 +2,7 @@ #define OPENMC_CONTAINER_UTIL_H #include // for find -#include // for begin, end +#include // for begin, end namespace openmc { @@ -12,6 +12,6 @@ inline bool contains(const C& v, const T& x) return std::end(v) != std::find(std::begin(v), std::end(v), x); } -} +} // namespace openmc #endif // OPENMC_CONTAINER_UTIL_H diff --git a/include/openmc/cross_sections.h b/include/openmc/cross_sections.h index 8a78a4099d3..06140a6a8cf 100644 --- a/include/openmc/cross_sections.h +++ b/include/openmc/cross_sections.h @@ -3,8 +3,8 @@ #include "pugixml.hpp" -#include #include +#include #include "openmc/vector.h" @@ -18,22 +18,24 @@ class Library { public: // Types, enums enum class Type { - neutron = 1, photon = 3, thermal = 2, multigroup = 4, wmp = 5 + neutron = 1, + photon = 3, + thermal = 2, + multigroup = 4, + wmp = 5 }; // Constructors - Library() { }; + Library() {}; Library(pugi::xml_node node, const std::string& directory); // Comparison operator (for using in map) - bool operator<(const Library& other) { - return path_ < other.path_; - } + bool operator<(const Library& other) { return path_ < other.path_; } // Data members - Type type_; //!< Type of data library + Type type_; //!< Type of data library vector materials_; //!< Materials contained in library - std::string path_; //!< File path to library + std::string path_; //!< File path to library }; using LibraryKey = std::pair; @@ -60,11 +62,16 @@ extern vector libraries; //! libraries void read_cross_sections_xml(); +//! Read cross sections file (either XML or multigroup H5) and populate data +//! libraries +//! \param[in] root node of the cross_sections.xml +void read_cross_sections_xml(pugi::xml_node root); //! Load nuclide and thermal scattering data from HDF5 files // //! \param[in] nuc_temps Temperatures for each nuclide in [K] -//! \param[in] thermal_temps Temperatures for each thermal scattering table in [K] +//! \param[in] thermal_temps Temperatures for each thermal scattering table in +//! [K] void read_ce_cross_sections(const vector>& nuc_temps, const vector>& thermal_temps); diff --git a/include/openmc/dagmc.h b/include/openmc/dagmc.h index 9f409d8730e..2facf4fc05e 100644 --- a/include/openmc/dagmc.h +++ b/include/openmc/dagmc.h @@ -1,32 +1,196 @@ - #ifndef OPENMC_DAGMC_H #define OPENMC_DAGMC_H namespace openmc { extern "C" const bool DAGMC_ENABLED; -} +extern "C" const bool UWUW_ENABLED; +} // namespace openmc + +// always include the XML interface header +#include "openmc/xml_interface.h" + +//============================================================================== +// Functions that are always defined +//============================================================================== + +namespace openmc { + +void read_dagmc_universes(pugi::xml_node node); +void check_dagmc_root_univ(); + +} // namespace openmc #ifdef DAGMC #include "DagMC.hpp" -#include "openmc/xml_interface.h" +#include "dagmcmetadata.hpp" + +#include "openmc/cell.h" +#include "openmc/particle.h" #include "openmc/position.h" +#include "openmc/surface.h" + +class UWUW; namespace openmc { -namespace model { - extern moab::DagMC* DAG; -} +class DAGSurface : public Surface { +public: + DAGSurface(std::shared_ptr dag_ptr, int32_t dag_idx); + + moab::EntityHandle mesh_handle() const; + + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + Direction reflect(Position r, Direction u, GeometryState* p) const override; + + inline void to_hdf5_inner(hid_t group_id) const override {}; + + // Accessor methods + moab::DagMC* dagmc_ptr() const { return dagmc_ptr_.get(); } + int32_t dag_index() const { return dag_index_; } + +private: + std::shared_ptr dagmc_ptr_; //!< Pointer to DagMC instance + int32_t dag_index_; //!< DagMC index of surface +}; + +class DAGCell : public Cell { +public: + DAGCell(std::shared_ptr dag_ptr, int32_t dag_idx); + + moab::EntityHandle mesh_handle() const; + + bool contains(Position r, Direction u, int32_t on_surface) const override; + + std::pair distance(Position r, Direction u, + int32_t on_surface, GeometryState* p) const override; + + BoundingBox bounding_box() const override; + + void to_hdf5_inner(hid_t group_id) const override; + + // Accessor methods + moab::DagMC* dagmc_ptr() const { return dagmc_ptr_.get(); } + int32_t dag_index() const { return dag_index_; } + +private: + std::shared_ptr dagmc_ptr_; //!< Pointer to DagMC instance + int32_t dag_index_; //!< DagMC index of cell +}; + +class DAGUniverse : public Universe { + +public: + explicit DAGUniverse(pugi::xml_node node); + + //! Create a new DAGMC universe + //! \param[in] filename Name of the DAGMC file + //! \param[in] auto_geom_ids Whether or not to automatically assign cell and + //! surface IDs \param[in] auto_mat_ids Whether or not to automatically assign + //! material IDs + explicit DAGUniverse(const std::string& filename, bool auto_geom_ids = false, + bool auto_mat_ids = false); + + //! Alternative DAGMC universe constructor for external DAGMC instance + explicit DAGUniverse(std::shared_ptr external_dagmc_ptr, + const std::string& filename = "", bool auto_geom_ids = false, + bool auto_mat_ids = false); + + //! Initialize the DAGMC accel. data structures, indices, material + //! assignments, etc. + void initialize(); + + //! Reads UWUW materials and returns an ID map + void read_uwuw_materials(); + //! Indicates whether or not UWUW materials are present + //! \return True if UWUW materials are present, False if not + bool uses_uwuw() const; + + //! Returns the index to the implicit complement's index in OpenMC for this + //! DAGMC universe + int32_t implicit_complement_idx() const; + + //! Transform UWUW materials into an OpenMC-readable XML format + //! \return A string representing a materials.xml file of the UWUW materials + //! in this universe + std::string get_uwuw_materials_xml() const; + + //! Writes the UWUW material file to XML (for debugging purposes) + void write_uwuw_materials_xml( + const std::string& outfile = "uwuw_materials.xml") const; + + //! Assign a material to a cell from uwuw material library + //! \param[in] vol_handle The DAGMC material assignment string + //! \param[in] c The OpenMC cell to which the material is assigned + void uwuw_assign_material( + moab::EntityHandle vol_handle, std::unique_ptr& c) const; + + //! Assign a material to a cell based + //! \param[in] mat_string The DAGMC material assignment string + //! \param[in] c The OpenMC cell to which the material is assigned + void legacy_assign_material( + std::string mat_string, std::unique_ptr& c) const; + + //! Return the index into the model cells vector for a given DAGMC volume + //! handle in the universe + //! \param[in] vol MOAB handle to the DAGMC volume set + int32_t cell_index(moab::EntityHandle vol) const; + + //! Return the index into the model surfaces vector for a given DAGMC surface + //! handle in the universe + //! \param[in] surf MOAB handle to the DAGMC surface set + int32_t surface_index(moab::EntityHandle surf) const; + + //! Generate a string representing the ranges of IDs present in the DAGMC + //! model. Contiguous chunks of IDs are represented as a range (i.e. 1-10). If + //! there is a single ID a chunk, it will be represented as a single number + //! (i.e. 2, 4, 6, 8). \param[in] dim Dimension of the entities \return A + //! string of the ID ranges for entities of dimension \p dim + std::string dagmc_ids_for_dim(int dim) const; + + bool find_cell(GeometryState& p) const override; + + void to_hdf5(hid_t universes_group) const override; + + // Data Members + std::shared_ptr + dagmc_instance_; //!< DAGMC Instance for this universe + int32_t cell_idx_offset_; //!< An offset to the start of the cells in this + //!< universe in OpenMC's cell vector + int32_t surf_idx_offset_; //!< An offset to the start of the surfaces in this + //!< universe in OpenMC's surface vector + + // Accessors + moab::DagMC* dagmc_ptr() const { return dagmc_instance_.get(); } + bool has_graveyard() const { return has_graveyard_; } + +private: + void set_id(); //!< Deduce the universe id from model::universes + void init_dagmc(); //!< Create and initialise DAGMC pointer + void init_metadata(); //!< Create and initialise dagmcMetaData pointer + void init_geometry(); //!< Create cells and surfaces from DAGMC entities + + std::string + filename_; //!< Name of the DAGMC file used to create this universe + std::shared_ptr + uwuw_; //!< Pointer to the UWUW instance for this universe + std::unique_ptr dmd_ptr; //! Pointer to DAGMC metadata object + bool adjust_geometry_ids_; //!< Indicates whether or not to automatically + //!< generate new cell and surface IDs for the + //!< universe + bool adjust_material_ids_; //!< Indicates whether or not to automatically + //!< generate new material IDs for the universe + bool has_graveyard_; //!< Indicates if the DAGMC geometry has a "graveyard" + //!< volume +}; //============================================================================== // Non-member functions //============================================================================== -void load_dagmc_geometry(); -void free_memory_dagmc(); -void read_geometry_dagmc(); -bool read_uwuw_materials(pugi::xml_document& doc); -bool get_uwuw_materials_xml(std::string& s); +int32_t next_cell(int32_t surf, int32_t curr_cell, int32_t univ); } // namespace openmc diff --git a/include/openmc/distribution.h b/include/openmc/distribution.h index 888fab7d889..e70c803de2f 100644 --- a/include/openmc/distribution.h +++ b/include/openmc/distribution.h @@ -7,6 +7,7 @@ #include // for size_t #include "pugixml.hpp" +#include #include "openmc/constants.h" #include "openmc/memory.h" // for unique_ptr @@ -22,6 +23,52 @@ class Distribution { public: virtual ~Distribution() = default; virtual double sample(uint64_t* seed) const = 0; + + //! Return integral of distribution + //! \return Integral of distribution + virtual double integral() const { return 1.0; }; +}; + +using UPtrDist = unique_ptr; + +//! Return univariate probability distribution specified in XML file +//! \param[in] node XML node representing distribution +//! \return Unique pointer to distribution +UPtrDist distribution_from_xml(pugi::xml_node node); + +//============================================================================== +//! A discrete distribution index (probability mass function) +//============================================================================== + +class DiscreteIndex { +public: + DiscreteIndex() {}; + DiscreteIndex(pugi::xml_node node); + DiscreteIndex(gsl::span p); + + void assign(gsl::span p); + + //! Sample a value from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled value + size_t sample(uint64_t* seed) const; + + // Properties + const vector& prob() const { return prob_; } + const vector& alias() const { return alias_; } + double integral() const { return integral_; } + +private: + vector prob_; //!< Probability of accepting the uniformly sampled bin, + //!< mapped to alias method table + vector alias_; //!< Alias table + double integral_; //!< Integral of distribution + + //! Normalize distribution so that probabilities sum to unity + void normalize(); + + //! Initialize alias tables for distribution + void init_alias(); }; //============================================================================== @@ -31,23 +78,24 @@ class Distribution { class Discrete : public Distribution { public: explicit Discrete(pugi::xml_node node); - Discrete(const double* x, const double* p, int n); + Discrete(const double* x, const double* p, size_t n); //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled value - double sample(uint64_t* seed) const; + double sample(uint64_t* seed) const override; + + double integral() const override { return di_.integral(); }; // Properties const vector& x() const { return x_; } - const vector& p() const { return p_; } + const vector& prob() const { return di_.prob(); } + const vector& alias() const { return di_.alias(); } private: vector x_; //!< Possible outcomes - vector p_; //!< Probability of each outcome - - //! Normalize distribution so that probabilities sum to unity - void normalize(); + DiscreteIndex di_; //!< discrete probability distribution of + //!< outcome indices }; //============================================================================== @@ -57,20 +105,48 @@ class Discrete : public Distribution { class Uniform : public Distribution { public: explicit Uniform(pugi::xml_node node); - Uniform(double a, double b) : a_{a}, b_{b} {}; + Uniform(double a, double b) : a_ {a}, b_ {b} {}; //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled value - double sample(uint64_t* seed) const; + double sample(uint64_t* seed) const override; double a() const { return a_; } double b() const { return b_; } + private: double a_; //!< Lower bound of distribution double b_; //!< Upper bound of distribution }; +//============================================================================== +//! PowerLaw distribution over the interval [a,b] with exponent n : p(x)=c x^n +//============================================================================== + +class PowerLaw : public Distribution { +public: + explicit PowerLaw(pugi::xml_node node); + PowerLaw(double a, double b, double n) + : offset_ {std::pow(a, n + 1)}, span_ {std::pow(b, n + 1) - offset_}, + ninv_ {1 / (n + 1)} {}; + + //! Sample a value from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled value + double sample(uint64_t* seed) const override; + + double a() const { return std::pow(offset_, ninv_); } + double b() const { return std::pow(offset_ + span_, ninv_); } + double n() const { return 1 / ninv_ - 1; } + +private: + //! Store processed values in object to allow for faster sampling + double offset_; //!< a^(n+1) + double span_; //!< b^(n+1) - a^(n+1) + double ninv_; //!< 1/(n+1) +}; + //============================================================================== //! Maxwellian distribution of form c*sqrt(E)*exp(-E/theta) //============================================================================== @@ -78,14 +154,15 @@ class Uniform : public Distribution { class Maxwell : public Distribution { public: explicit Maxwell(pugi::xml_node node); - Maxwell(double theta) : theta_{theta} { }; + Maxwell(double theta) : theta_ {theta} {}; //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled value - double sample(uint64_t* seed) const; + double sample(uint64_t* seed) const override; double theta() const { return theta_; } + private: double theta_; //!< Factor in exponential [eV] }; @@ -97,66 +174,43 @@ class Maxwell : public Distribution { class Watt : public Distribution { public: explicit Watt(pugi::xml_node node); - Watt(double a, double b) : a_{a}, b_{b} { }; + Watt(double a, double b) : a_ {a}, b_ {b} {}; //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled value - double sample(uint64_t* seed) const; + double sample(uint64_t* seed) const override; double a() const { return a_; } double b() const { return b_; } + private: double a_; //!< Factor in exponential [eV] double b_; //!< Factor in square root [1/eV] }; //============================================================================== -//! Normal distributions with form 1/2*std_dev*sqrt(pi) exp (-(e-E0)/2*std_dev)^2 +//! Normal distributions with form 1/2*std_dev*sqrt(pi) exp +//! (-(e-E0)/2*std_dev)^2 //============================================================================== class Normal : public Distribution { public: explicit Normal(pugi::xml_node node); - Normal(double mean_value, double std_dev) : mean_value_{mean_value}, std_dev_{std_dev} { }; + Normal(double mean_value, double std_dev) + : mean_value_ {mean_value}, std_dev_ {std_dev} {}; //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled value - double sample(uint64_t* seed) const; + double sample(uint64_t* seed) const override; double mean_value() const { return mean_value_; } double std_dev() const { return std_dev_; } -private: - double mean_value_; //!< middle of distribution [eV] - double std_dev_; //!< standard deviation [eV] -}; - -//============================================================================== -//! Muir (fusion) spectrum derived from Normal with extra params e0 is mean -//! std dev is sqrt(4*e0*kt/m) -//============================================================================== - -class Muir : public Distribution { -public: - explicit Muir(pugi::xml_node node); - Muir(double e0, double m_rat, double kt) : e0_{e0}, m_rat_{m_rat}, kt_{kt} { }; - - //! Sample a value from the distribution - //! \param seed Pseudorandom number seed pointer - //! \return Sampled value - double sample(uint64_t* seed) const; - double e0() const { return e0_; } - double m_rat() const { return m_rat_; } - double kt() const { return kt_; } private: - // example DT fusion m_rat = 5 (D = 2 + T = 3) - // ion temp = 20000 eV - // mean neutron energy 14.08e6 eV - double e0_; //!< mean neutron energy [eV] - double m_rat_; //!< ratio of reactant masses relative to atomic mass unit - double kt_; //!< ion temperature [eV] + double mean_value_; //!< middle of distribution [eV] + double std_dev_; //!< standard deviation [eV] }; //============================================================================== @@ -167,30 +221,33 @@ class Tabular : public Distribution { public: explicit Tabular(pugi::xml_node node); Tabular(const double* x, const double* p, int n, Interpolation interp, - const double* c=nullptr); + const double* c = nullptr); //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled value - double sample(uint64_t* seed) const; + double sample(uint64_t* seed) const override; - // x property + // properties vector& x() { return x_; } const vector& x() const { return x_; } const vector& p() const { return p_; } Interpolation interp() const { return interp_; } + double integral() const override { return integral_; }; + private: - vector x_; //!< tabulated independent variable - vector p_; //!< tabulated probability density - vector c_; //!< cumulative distribution at tabulated values - Interpolation interp_; //!< interpolation rule + vector x_; //!< tabulated independent variable + vector p_; //!< tabulated probability density + vector c_; //!< cumulative distribution at tabulated values + Interpolation interp_; //!< interpolation rule + double integral_; //!< Integral of distribution //! Initialize tabulated probability density function //! \param x Array of values for independent variable //! \param p Array of tabulated probabilities //! \param n Number of tabulated values - void init(const double* x, const double* p, std::size_t n, - const double* c=nullptr); + void init( + const double* x, const double* p, std::size_t n, const double* c = nullptr); }; //============================================================================== @@ -200,12 +257,12 @@ class Tabular : public Distribution { class Equiprobable : public Distribution { public: explicit Equiprobable(pugi::xml_node node); - Equiprobable(const double* x, int n) : x_{x, x+n} { }; + Equiprobable(const double* x, int n) : x_ {x, x + n} {}; //! Sample a value from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled value - double sample(uint64_t* seed) const; + double sample(uint64_t* seed) const override; const vector& x() const { return x_; } @@ -213,12 +270,29 @@ class Equiprobable : public Distribution { vector x_; //! Possible outcomes }; -using UPtrDist = unique_ptr; +//============================================================================== +//! Mixture distribution +//============================================================================== -//! Return univariate probability distribution specified in XML file -//! \param[in] node XML node representing distribution -//! \return Unique pointer to distribution -UPtrDist distribution_from_xml(pugi::xml_node node); +class Mixture : public Distribution { +public: + explicit Mixture(pugi::xml_node node); + + //! Sample a value from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled value + double sample(uint64_t* seed) const override; + + double integral() const override { return integral_; } + +private: + // Storrage for probability + distribution + using DistPair = std::pair; + + vector + distribution_; //!< sub-distributions + cummulative probabilities + double integral_; //!< integral of distribution +}; } // namespace openmc diff --git a/include/openmc/distribution_energy.h b/include/openmc/distribution_energy.h index 9c7438f3312..9b08ed039dc 100644 --- a/include/openmc/distribution_energy.h +++ b/include/openmc/distribution_energy.h @@ -4,8 +4,8 @@ #ifndef OPENMC_DISTRIBUTION_ENERGY_H #define OPENMC_DISTRIBUTION_ENERGY_H -#include "xtensor/xtensor.hpp" #include "hdf5.h" +#include "xtensor/xtensor.hpp" #include "openmc/constants.h" #include "openmc/endf.h" @@ -37,12 +37,13 @@ class DiscretePhoton : public EnergyDistribution { //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const; + double sample(double E, uint64_t* seed) const override; + private: int primary_flag_; //!< Indicator of whether the photon is a primary or //!< non-primary photon. - double energy_; //!< Photon energy or binding energy - double A_; //!< Atomic weight ratio of the target nuclide + double energy_; //!< Photon energy or binding energy + double A_; //!< Atomic weight ratio of the target nuclide }; //=============================================================================== @@ -57,9 +58,10 @@ class LevelInelastic : public EnergyDistribution { //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const; + double sample(double E, uint64_t* seed) const override; + private: - double threshold_; //!< Energy threshold in lab, (A + 1)/A * |Q| + double threshold_; //!< Energy threshold in lab, (A + 1)/A * |Q| double mass_ratio_; //!< (A/(A+1))^2 }; @@ -77,18 +79,19 @@ class ContinuousTabular : public EnergyDistribution { //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const; + double sample(double E, uint64_t* seed) const override; + private: //! Outgoing energy for a single incoming energy struct CTTable { - Interpolation interpolation; //!< Interpolation law - int n_discrete; //!< Number of of discrete energies + Interpolation interpolation; //!< Interpolation law + int n_discrete; //!< Number of of discrete energies xt::xtensor e_out; //!< Outgoing energies in [eV] - xt::xtensor p; //!< Probability density - xt::xtensor c; //!< Cumulative distribution + xt::xtensor p; //!< Probability density + xt::xtensor c; //!< Cumulative distribution }; - int n_region_; //!< Number of inteprolation regions + int n_region_; //!< Number of inteprolation regions vector breakpoints_; //!< Breakpoints between regions vector interpolation_; //!< Interpolation laws vector energy_; //!< Incident energy in [eV] @@ -107,10 +110,11 @@ class Evaporation : public EnergyDistribution { //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const; + double sample(double E, uint64_t* seed) const override; + private: Tabulated1D theta_; //!< Incoming energy dependent parameter - double u_; //!< Restriction energy + double u_; //!< Restriction energy }; //=============================================================================== @@ -126,10 +130,11 @@ class MaxwellEnergy : public EnergyDistribution { //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const; + double sample(double E, uint64_t* seed) const override; + private: Tabulated1D theta_; //!< Incoming energy dependent parameter - double u_; //!< Restriction energy + double u_; //!< Restriction energy }; //=============================================================================== @@ -145,11 +150,12 @@ class WattEnergy : public EnergyDistribution { //! \param[in] E Incident particle energy in [eV] //! \param[inout] seed Pseudorandom number seed pointer //! \return Sampled energy in [eV] - double sample(double E, uint64_t* seed) const; + double sample(double E, uint64_t* seed) const override; + private: Tabulated1D a_; //!< Energy-dependent 'a' parameter Tabulated1D b_; //!< Energy-dependent 'b' parameter - double u_; //!< Restriction energy + double u_; //!< Restriction energy }; } // namespace openmc diff --git a/include/openmc/distribution_multi.h b/include/openmc/distribution_multi.h index 793e8f719f9..9e84d03d57f 100644 --- a/include/openmc/distribution_multi.h +++ b/include/openmc/distribution_multi.h @@ -17,17 +17,19 @@ namespace openmc { class UnitSphereDistribution { public: - UnitSphereDistribution() { }; - explicit UnitSphereDistribution(Direction u) : u_ref_{u} { }; + UnitSphereDistribution() {}; + explicit UnitSphereDistribution(Direction u) : u_ref_ {u} {}; explicit UnitSphereDistribution(pugi::xml_node node); virtual ~UnitSphereDistribution() = default; + static unique_ptr create(pugi::xml_node node); + //! Sample a direction from the distribution //! \param seed Pseudorandom number seed pointer //! \return Direction sampled virtual Direction sample(uint64_t* seed) const = 0; - Direction u_ref_ {0.0, 0.0, 1.0}; //!< reference direction + Direction u_ref_ {0.0, 0.0, 1.0}; //!< reference direction }; //============================================================================== @@ -42,7 +44,7 @@ class PolarAzimuthal : public UnitSphereDistribution { //! Sample a direction from the distribution //! \param seed Pseudorandom number seed pointer //! \return Direction sampled - Direction sample(uint64_t* seed) const; + Direction sample(uint64_t* seed) const override; // Observing pointers Distribution* mu() const { return mu_.get(); } @@ -61,12 +63,12 @@ Direction isotropic_direction(uint64_t* seed); class Isotropic : public UnitSphereDistribution { public: - Isotropic() { }; + Isotropic() {}; //! Sample a direction from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled direction - Direction sample(uint64_t* seed) const; + Direction sample(uint64_t* seed) const override; }; //============================================================================== @@ -75,13 +77,14 @@ class Isotropic : public UnitSphereDistribution { class Monodirectional : public UnitSphereDistribution { public: - Monodirectional(Direction u) : UnitSphereDistribution{u} { }; - explicit Monodirectional(pugi::xml_node node) : UnitSphereDistribution{node} { }; + Monodirectional(Direction u) : UnitSphereDistribution {u} {}; + explicit Monodirectional(pugi::xml_node node) + : UnitSphereDistribution {node} {}; //! Sample a direction from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled direction - Direction sample(uint64_t* seed) const; + Direction sample(uint64_t* seed) const override; }; using UPtrAngle = unique_ptr; diff --git a/include/openmc/distribution_spatial.h b/include/openmc/distribution_spatial.h index a56ff2dcf1b..28568c890d8 100644 --- a/include/openmc/distribution_spatial.h +++ b/include/openmc/distribution_spatial.h @@ -4,6 +4,7 @@ #include "pugixml.hpp" #include "openmc/distribution.h" +#include "openmc/mesh.h" #include "openmc/position.h" namespace openmc { @@ -18,6 +19,8 @@ class SpatialDistribution { //! Sample a position from the distribution virtual Position sample(uint64_t* seed) const = 0; + + static unique_ptr create(pugi::xml_node node); }; //============================================================================== @@ -31,12 +34,13 @@ class CartesianIndependent : public SpatialDistribution { //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled position - Position sample(uint64_t* seed) const; + Position sample(uint64_t* seed) const override; // Observer pointers Distribution* x() const { return x_.get(); } Distribution* y() const { return y_.get(); } Distribution* z() const { return z_.get(); } + private: UPtrDist x_; //!< Distribution of x coordinates UPtrDist y_; //!< Distribution of y coordinates @@ -54,22 +58,22 @@ class CylindricalIndependent : public SpatialDistribution { //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled position - Position sample(uint64_t* seed) const; - + Position sample(uint64_t* seed) const override; + Distribution* r() const { return r_.get(); } Distribution* phi() const { return phi_.get(); } Distribution* z() const { return z_.get(); } Position origin() const { return origin_; } + private: - UPtrDist r_; //!< Distribution of r coordinates - UPtrDist phi_; //!< Distribution of phi coordinates - UPtrDist z_; //!< Distribution of z coordinates + UPtrDist r_; //!< Distribution of r coordinates + UPtrDist phi_; //!< Distribution of phi coordinates + UPtrDist z_; //!< Distribution of z coordinates Position origin_; //!< Cartesian coordinates of the cylinder center }; - //============================================================================== -//! Distribution of points specified by spherical coordinates r,theta,phi +//! Distribution of points specified by spherical coordinates r,cos_theta,phi //============================================================================== class SphericalIndependent : public SpatialDistribution { @@ -79,17 +83,57 @@ class SphericalIndependent : public SpatialDistribution { //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled position - Position sample(uint64_t* seed) const; + Position sample(uint64_t* seed) const override; Distribution* r() const { return r_.get(); } - Distribution* theta() const { return theta_.get(); } + Distribution* cos_theta() const { return cos_theta_.get(); } Distribution* phi() const { return phi_.get(); } - Position origin () const { return origin_; } + Position origin() const { return origin_; } + private: - UPtrDist r_; //!< Distribution of r coordinates - UPtrDist theta_; //!< Distribution of theta coordinates - UPtrDist phi_; //!< Distribution of phi coordinates - Position origin_; //!< Cartesian coordinates of the sphere center + UPtrDist r_; //!< Distribution of r coordinates + UPtrDist cos_theta_; //!< Distribution of cos_theta coordinates + UPtrDist phi_; //!< Distribution of phi coordinates + Position origin_; //!< Cartesian coordinates of the sphere center +}; + +//============================================================================== +//! Distribution of points within a mesh +//============================================================================== + +class MeshSpatial : public SpatialDistribution { +public: + explicit MeshSpatial(pugi::xml_node node); + explicit MeshSpatial(int32_t mesh_id, gsl::span strengths); + + //! Sample a position from the distribution + //! \param seed Pseudorandom number seed pointer + //! \return Sampled position + Position sample(uint64_t* seed) const override; + + //! Sample the mesh for an element and position within that element + //! \param seed Pseudorandom number seed pointer + //! \return Sampled element index and position within that element + std::pair sample_mesh(uint64_t* seed) const; + + //! Sample a mesh element + //! \param seed Pseudorandom number seed pointer + //! \return Sampled element index + int32_t sample_element_index(uint64_t* seed) const; + + //! For unstructured meshes, ensure that elements are all linear tetrahedra + void check_element_types() const; + + // Accessors + const Mesh* mesh() const { return model::meshes.at(mesh_idx_).get(); } + int32_t n_sources() const { return this->mesh()->n_bins(); } + + double total_strength() { return this->elem_idx_dist_.integral(); } + +private: + int32_t mesh_idx_ {C_NONE}; + DiscreteIndex elem_idx_dist_; //!< Distribution of + //!< mesh element indices }; //============================================================================== @@ -98,20 +142,21 @@ class SphericalIndependent : public SpatialDistribution { class SpatialBox : public SpatialDistribution { public: - explicit SpatialBox(pugi::xml_node node, bool fission=false); + explicit SpatialBox(pugi::xml_node node, bool fission = false); //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled position - Position sample(uint64_t* seed) const; + Position sample(uint64_t* seed) const override; // Properties bool only_fissionable() const { return only_fissionable_; } Position lower_left() const { return lower_left_; } Position upper_right() const { return upper_right_; } + private: - Position lower_left_; //!< Lower-left coordinates of box - Position upper_right_; //!< Upper-right coordinates of box + Position lower_left_; //!< Lower-left coordinates of box + Position upper_right_; //!< Upper-right coordinates of box bool only_fissionable_ {false}; //!< Only accept sites in fissionable region? }; @@ -121,16 +166,17 @@ class SpatialBox : public SpatialDistribution { class SpatialPoint : public SpatialDistribution { public: - SpatialPoint() : r_{} { }; - SpatialPoint(Position r) : r_{r} { }; + SpatialPoint() : r_ {} {}; + SpatialPoint(Position r) : r_ {r} {}; explicit SpatialPoint(pugi::xml_node node); //! Sample a position from the distribution //! \param seed Pseudorandom number seed pointer //! \return Sampled position - Position sample(uint64_t* seed) const; + Position sample(uint64_t* seed) const override; Position r() const { return r_; } + private: Position r_; //!< Single position at which sites are generated }; diff --git a/include/openmc/endf.h b/include/openmc/endf.h index 40e1cef8339..e580874b4b1 100644 --- a/include/openmc/endf.h +++ b/include/openmc/endf.h @@ -57,6 +57,7 @@ class Polynomial : public Function1D { //! \param[in] x independent variable //! \return Polynomial evaluated at x double operator()(double x) const override; + private: vector coef_; //!< Polynomial coefficients }; @@ -86,9 +87,9 @@ class Tabulated1D : public Function1D { std::size_t n_regions_ {0}; //!< number of interpolation regions vector nbt_; //!< values separating interpolation regions vector int_; //!< interpolation schemes - std::size_t n_pairs_; //!< number of (x,y) pairs - vector x_; //!< values of abscissa - vector y_; //!< values of ordinate + std::size_t n_pairs_; //!< number of (x,y) pairs + vector x_; //!< values of abscissa + vector y_; //!< values of ordinate }; //============================================================================== @@ -118,9 +119,31 @@ class IncoherentElasticXS : public Function1D { explicit IncoherentElasticXS(hid_t dset); double operator()(double E) const override; + private: double bound_xs_; //!< Characteristic bound xs in [b] - double debye_waller_; //!< Debye-Waller integral divided by atomic mass in [eV^-1] + double + debye_waller_; //!< Debye-Waller integral divided by atomic mass in [eV^-1] +}; + +//============================================================================== +//! Sum of multiple 1D functions +//============================================================================== + +class Sum1D : public Function1D { +public: + // Constructors + explicit Sum1D(hid_t group); + + //! Evaluate each function and sum results + //! \param[in] x independent variable + //! \return Function evaluated at x + double operator()(double E) const override; + + const unique_ptr& functions(int i) const { return functions_[i]; } + +private: + vector> functions_; //!< individual functions }; //! Read 1D function from HDF5 dataset diff --git a/include/openmc/error.h b/include/openmc/error.h index 05378344634..d73795aee28 100644 --- a/include/openmc/error.h +++ b/include/openmc/error.h @@ -2,8 +2,8 @@ #define OPENMC_ERROR_H #include -#include #include +#include #include @@ -18,50 +18,43 @@ namespace openmc { -inline void -set_errmsg(const char* message) +inline void set_errmsg(const char* message) { std::strcpy(openmc_err_msg, message); } -inline void -set_errmsg(const std::string& message) +inline void set_errmsg(const std::string& message) { std::strcpy(openmc_err_msg, message.c_str()); } -inline void -set_errmsg(const std::stringstream& message) +inline void set_errmsg(const std::stringstream& message) { std::strcpy(openmc_err_msg, message.str().c_str()); } -[[noreturn]] void fatal_error(const std::string& message, int err=-1); +[[noreturn]] void fatal_error(const std::string& message, int err = -1); -[[noreturn]] inline -void fatal_error(const std::stringstream& message) +[[noreturn]] inline void fatal_error(const std::stringstream& message) { fatal_error(message.str()); } -[[noreturn]] inline -void fatal_error(const char* message) +[[noreturn]] inline void fatal_error(const char* message) { - fatal_error(std::string{message, std::strlen(message)}); + fatal_error(std::string {message, std::strlen(message)}); } void warning(const std::string& message); -inline -void warning(const std::stringstream& message) +inline void warning(const std::stringstream& message) { warning(message.str()); } -void write_message(const std::string& message, int level=0); +void write_message(const std::string& message, int level = 0); -inline -void write_message(const std::stringstream& message, int level) +inline void write_message(const std::stringstream& message, int level) { write_message(message.str(), level); } diff --git a/include/openmc/event.h b/include/openmc/event.h index 981fa9b17d9..2d215a10e46 100644 --- a/include/openmc/event.h +++ b/include/openmc/event.h @@ -7,7 +7,6 @@ #include "openmc/particle.h" #include "openmc/shared_array.h" - namespace openmc { //============================================================================== @@ -17,17 +16,17 @@ namespace openmc { // In the event-based model, instead of moving or sorting the particles // themselves based on which event they need, a queue is used to store the // index (and other useful info) for each event type. -// The EventQueueItem struct holds the relevant information about a particle needed -// for sorting the queue. For very high particle counts, a sorted queue has the -// potential to result in greatly improved cache efficiency. However, sorting -// will introduce some overhead due to the sorting process itself, and may not -// result in any benefits if not enough particles are present for them to achieve -// consistent locality improvements. -struct EventQueueItem{ - int64_t idx; //!< particle index in event-based particle buffer - ParticleType type; //!< particle type - int64_t material; //!< material that particle is in - double E; //!< particle energy +// The EventQueueItem struct holds the relevant information about a particle +// needed for sorting the queue. For very high particle counts, a sorted queue +// has the potential to result in greatly improved cache efficiency. However, +// sorting will introduce some overhead due to the sorting process itself, and +// may not result in any benefits if not enough particles are present for them +// to achieve consistent locality improvements. +struct EventQueueItem { + int64_t idx; //!< particle index in event-based particle buffer + ParticleType type; //!< particle type + int64_t material; //!< material that particle is in + double E; //!< particle energy // Constructors EventQueueItem() = default; @@ -35,16 +34,18 @@ struct EventQueueItem{ : idx(buffer_idx), type(p.type()), material(p.material()), E(p.E()) {} - // Compare by particle type, then by material type (4.5% fuel/7.0% fuel/cladding/etc), - // then by energy. - // TODO: Currently in OpenMC, the material ID corresponds not only to a general - // type, but also specific isotopic densities. Ideally we would - // like to be able to just sort by general material type, regardless of densities. - // A more general material type ID may be added in the future, in which case we - // can update the material field of this struct to contain the more general id. + // Compare by particle type, then by material type (4.5% fuel/7.0% + // fuel/cladding/etc), then by energy. + // TODO: Currently in OpenMC, the material ID corresponds not only to a + // general type, but also specific isotopic densities. Ideally we would like + // to be able to just sort by general material type, regardless of densities. + // A more general material type ID may be added in the future, in which case + // we can update the material field of this struct to contain the more general + // id. bool operator<(const EventQueueItem& rhs) const { - return std::tie(type, material, E) < std::tie(rhs.type, rhs.material, rhs.E); + return std::tie(type, material, E) < + std::tie(rhs.type, rhs.material, rhs.E); } }; diff --git a/vendor/faddeeva/Faddeeva.hh b/include/openmc/external/Faddeeva.hh similarity index 100% rename from vendor/faddeeva/Faddeeva.hh rename to include/openmc/external/Faddeeva.hh diff --git a/include/openmc/external/quartic_solver.h b/include/openmc/external/quartic_solver.h new file mode 100644 index 00000000000..376a014af62 --- /dev/null +++ b/include/openmc/external/quartic_solver.h @@ -0,0 +1,10 @@ +#ifndef OPENMC_EXTERNAL_QUARTIC_SOLVER_H +#define OPENMC_EXTERNAL_QUARTIC_SOLVER_H + +#include + +namespace oqs { +void quartic_solver(double coeff[5], std::complex roots[4]); +} // end namespace oqs + +#endif // OPENMC_EXTERNAL_QUARTIC_SOLVER_H diff --git a/include/openmc/file_utils.h b/include/openmc/file_utils.h index f9c23468dfd..6e9812d5e83 100644 --- a/include/openmc/file_utils.h +++ b/include/openmc/file_utils.h @@ -1,19 +1,31 @@ #ifndef OPENMC_FILE_UTILS_H #define OPENMC_FILE_UTILS_H -#include // for ifstream #include namespace openmc { +// TODO: replace with std::filesystem when switch to C++17 is made +//! Determine if a path is a directory +//! \param[in] path Path to check +//! \return Whether the path is a directory +bool dir_exists(const std::string& path); + //! Determine if a file exists //! \param[in] filename Path to file //! \return Whether file exists -inline bool file_exists(const std::string& filename) -{ - std::ifstream s {filename}; - return s.good(); -} +bool file_exists(const std::string& filename); + +//! Determine directory containing given file +//! \param[in] filename Path to file +//! \return Name of directory containing file +std::string dir_name(const std::string& filename); + +// Gets the file extension of whatever string is passed in. This is defined as +// a sequence of strictly alphanumeric characters which follow the last period, +// i.e. at least one alphabet character is present, and zero or more numbers. +// If such a sequence of characters is not found, an empty string is returned. +std::string get_file_extension(const std::string& filename); } // namespace openmc diff --git a/include/openmc/finalize.h b/include/openmc/finalize.h index f99201abe78..6d8cd9087b8 100644 --- a/include/openmc/finalize.h +++ b/include/openmc/finalize.h @@ -1,8 +1,6 @@ #ifndef OPENMC_FINALIZE_H #define OPENMC_FINALIZE_H -namespace openmc { - -} // namespace openmc +namespace openmc {} // namespace openmc #endif // OPENMC_FINALIZE_H diff --git a/include/openmc/geometry.h b/include/openmc/geometry.h index 0ba29ef4898..107cc7d1f3e 100644 --- a/include/openmc/geometry.h +++ b/include/openmc/geometry.h @@ -11,7 +11,7 @@ namespace openmc { class BoundaryInfo; -class Particle; +class GeometryState; //============================================================================== // Global variables @@ -19,7 +19,7 @@ class Particle; namespace model { -extern int root_universe; //!< Index of root universe +extern int root_universe; //!< Index of root universe extern "C" int n_coord_levels; //!< Number of CSG coordinate levels extern vector overlap_check_count; @@ -30,7 +30,8 @@ extern vector overlap_check_count; //! Check two distances by coincidence tolerance //============================================================================== -inline bool coincident(double d1, double d2) { +inline bool coincident(double d1, double d2) +{ return std::abs(d1 - d2) < FP_COINCIDENT; } @@ -38,7 +39,18 @@ inline bool coincident(double d1, double d2) { //! Check for overlapping cells at a particle's position. //============================================================================== -bool check_cell_overlap(Particle& p, bool error=true); +bool check_cell_overlap(GeometryState& p, bool error = true); + +//============================================================================== +//! Get the cell instance for a particle at the specified universe level +//! +//! \param p A particle for which to compute the instance using +//! its coordinates +//! \param level The level (zero indexed) of the geometry where the instance +//! should be computed. \return The instance of the cell at the specified level. +//============================================================================== + +int cell_instance_at_level(const GeometryState& p, int level); //============================================================================== //! Locate a particle in the geometry tree and set its geometry data fields. @@ -48,20 +60,22 @@ bool check_cell_overlap(Particle& p, bool error=true); //! \return True if the particle's location could be found and ascribed to a //! valid geometry coordinate stack. //============================================================================== -bool exhaustive_find_cell(Particle& p); -bool neighbor_list_find_cell(Particle& p); // Only usable on surface crossings +bool exhaustive_find_cell(GeometryState& p, bool verbose = false); +bool neighbor_list_find_cell( + GeometryState& p, bool verbose = false); // Only usable on surface crossings //============================================================================== //! Move a particle into a new lattice tile. //============================================================================== -void cross_lattice(Particle& p, const BoundaryInfo& boundary); +void cross_lattice( + GeometryState& p, const BoundaryInfo& boundary, bool verbose = false); //============================================================================== //! Find the next boundary a particle will intersect. //============================================================================== -BoundaryInfo distance_to_boundary(Particle& p); +BoundaryInfo distance_to_boundary(GeometryState& p); } // namespace openmc diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 28b19e315d2..0c870c9fb8e 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -7,18 +7,26 @@ #include #include #include +#include #include "openmc/vector.h" +#include "openmc/xml_interface.h" namespace openmc { namespace model { - extern std::unordered_map> universe_cell_counts; - extern std::unordered_map universe_level_counts; +extern std::unordered_map> + universe_cell_counts; +extern std::unordered_map universe_level_counts; } // namespace model +//! Read geometry from XML file void read_geometry_xml(); +//! Read geometry from XML node +//! \param[in] root node of geometry XML element +void read_geometry_xml(pugi::xml_node root); + //============================================================================== //! Replace Universe, Lattice, and Material IDs with indices. //============================================================================== @@ -63,9 +71,13 @@ int32_t find_root_universe(); //============================================================================== //! Populate all data structures needed for distribcells. +//! \param user_distribcells A set of cell indices to create distribcell data +//! structures for regardless of whether or not they are part of a tally +//! filter. //============================================================================== -void prepare_distribcell(); +void prepare_distribcell( + const std::vector* user_distribcells = nullptr); //============================================================================== //! Recursively search through the geometry and count cell instances. @@ -102,8 +114,8 @@ int count_universe_instances(int32_t search_univ, int32_t target_univ_id, //! desired instance of the target cell. //============================================================================== -std::string -distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset); +std::string distribcell_path( + int32_t target_cell, int32_t map, int32_t target_offset); //============================================================================== //! Determine the maximum number of nested coordinate levels in the geometry. @@ -114,6 +126,14 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset); int maximum_levels(int32_t univ); +//============================================================================== +//! Check whether or not a universe is the root universe using its ID. +//! \param univ_id The ID of the universe to check. +//! \return Whether or not it is the root universe. +//============================================================================== + +bool is_root_universe(int32_t univ_id); + //============================================================================== //! Deallocates global vectors and maps for cells, universes, and lattices. //============================================================================== diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index f6016730411..0092c08f8df 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -5,8 +5,8 @@ #include #include #include // for strlen -#include #include +#include #include #include "hdf5.h" @@ -25,8 +25,7 @@ namespace openmc { // Low-level internal functions //============================================================================== -void read_attr(hid_t obj_id, const char* name, hid_t mem_type_id, - void* buffer); +void read_attr(hid_t obj_id, const char* name, hid_t mem_type_id, void* buffer); void write_attr(hid_t obj_id, int ndim, const hsize_t* dims, const char* name, hid_t mem_type_id, const void* buffer); @@ -47,76 +46,77 @@ bool using_mpio_device(hid_t obj_id); hid_t create_group(hid_t parent_id, const std::string& name); inline hid_t create_group(hid_t parent_id, const std::stringstream& name) -{return create_group(parent_id, name.str());} - - -hid_t file_open(const std::string& filename, char mode, bool parallel=false); +{ + return create_group(parent_id, name.str()); +} -void write_string(hid_t group_id, const char* name, const std::string& buffer, - bool indep); +hid_t file_open(const std::string& filename, char mode, bool parallel = false); +hid_t open_group(hid_t group_id, const std::string& name); +void write_string( + hid_t group_id, const char* name, const std::string& buffer, bool indep); vector attribute_shape(hid_t obj_id, const char* name); vector dataset_names(hid_t group_id); -void ensure_exists(hid_t obj_id, const char* name, bool attribute=false); +void ensure_exists(hid_t obj_id, const char* name, bool attribute = false); vector group_names(hid_t group_id); vector object_shape(hid_t obj_id); std::string object_name(hid_t obj_id); +hid_t open_object(hid_t group_id, const std::string& name); +void close_object(hid_t obj_id); //============================================================================== // Fortran compatibility functions //============================================================================== extern "C" { - bool attribute_exists(hid_t obj_id, const char* name); - size_t attribute_typesize(hid_t obj_id, const char* name); - hid_t create_group(hid_t parent_id, const char* name); - void close_dataset(hid_t dataset_id); - void close_group(hid_t group_id); - int dataset_ndims(hid_t dset); - size_t dataset_typesize(hid_t obj_id, const char* name); - hid_t file_open(const char* filename, char mode, bool parallel); - void file_close(hid_t file_id); - void get_name(hid_t obj_id, char* name); - int get_num_datasets(hid_t group_id); - int get_num_groups(hid_t group_id); - void get_datasets(hid_t group_id, char* name[]); - void get_groups(hid_t group_id, char* name[]); - void get_shape(hid_t obj_id, hsize_t* dims); - void get_shape_attr(hid_t obj_id, const char* name, hsize_t* dims); - bool object_exists(hid_t object_id, const char* name); - hid_t open_dataset(hid_t group_id, const char* name); - hid_t open_group(hid_t group_id, const char* name); - void read_attr_double(hid_t obj_id, const char* name, double* buffer); - void read_attr_int(hid_t obj_id, const char* name, int* buffer); - void read_attr_string(hid_t obj_id, const char* name, size_t slen, - char* buffer); - void read_complex(hid_t obj_id, const char* name, - std::complex* buffer, bool indep); - void read_double(hid_t obj_id, const char* name, double* buffer, bool indep); - void read_int(hid_t obj_id, const char* name, int* buffer, bool indep); - void read_llong(hid_t obj_id, const char* name, long long* buffer, - bool indep); - void read_string(hid_t obj_id, const char* name, size_t slen, char* buffer, - bool indep); - - - void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, - double* results); - void write_attr_double(hid_t obj_id, int ndim, const hsize_t* dims, - const char* name, const double* buffer); - void write_attr_int(hid_t obj_id, int ndim, const hsize_t* dims, - const char* name, const int* buffer); - void write_attr_string(hid_t obj_id, const char* name, const char* buffer); - void write_double(hid_t group_id, int ndim, const hsize_t* dims, - const char* name, const double* buffer, bool indep); - void write_int(hid_t group_id, int ndim, const hsize_t* dims, - const char* name, const int* buffer, bool indep); - void write_llong(hid_t group_id, int ndim, const hsize_t* dims, - const char* name, const long long* buffer, bool indep); - void write_string(hid_t group_id, int ndim, const hsize_t* dims, size_t slen, - const char* name, char const* buffer, bool indep); - void write_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, - const double* results); +bool attribute_exists(hid_t obj_id, const char* name); +size_t attribute_typesize(hid_t obj_id, const char* name); +hid_t create_group(hid_t parent_id, const char* name); +void close_dataset(hid_t dataset_id); +void close_group(hid_t group_id); +int dataset_ndims(hid_t dset); +size_t dataset_typesize(hid_t obj_id, const char* name); +hid_t file_open(const char* filename, char mode, bool parallel); +void file_close(hid_t file_id); +void get_name(hid_t obj_id, std::string& name); +int get_num_datasets(hid_t group_id); +int get_num_groups(hid_t group_id); +void get_datasets(hid_t group_id, char* name[]); +void get_groups(hid_t group_id, char* name[]); +void get_shape(hid_t obj_id, hsize_t* dims); +void get_shape_attr(hid_t obj_id, const char* name, hsize_t* dims); +bool object_exists(hid_t object_id, const char* name); +hid_t open_dataset(hid_t group_id, const char* name); +hid_t open_group(hid_t group_id, const char* name); +void read_attr_double(hid_t obj_id, const char* name, double* buffer); +void read_attr_int(hid_t obj_id, const char* name, int* buffer); +void read_attr_string( + hid_t obj_id, const char* name, size_t slen, char* buffer); +void read_complex( + hid_t obj_id, const char* name, std::complex* buffer, bool indep); +void read_double(hid_t obj_id, const char* name, double* buffer, bool indep); +void read_int(hid_t obj_id, const char* name, int* buffer, bool indep); +void read_llong(hid_t obj_id, const char* name, long long* buffer, bool indep); +void read_string( + hid_t obj_id, const char* name, size_t slen, char* buffer, bool indep); + +void read_tally_results( + hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results); +void write_attr_double(hid_t obj_id, int ndim, const hsize_t* dims, + const char* name, const double* buffer); +void write_attr_int(hid_t obj_id, int ndim, const hsize_t* dims, + const char* name, const int* buffer); +void write_attr_string(hid_t obj_id, const char* name, const char* buffer); +void write_double(hid_t group_id, int ndim, const hsize_t* dims, + const char* name, const double* buffer, bool indep); +void write_int(hid_t group_id, int ndim, const hsize_t* dims, const char* name, + const int* buffer, bool indep); +void write_llong(hid_t group_id, int ndim, const hsize_t* dims, + const char* name, const long long* buffer, bool indep); +void write_string(hid_t group_id, int ndim, const hsize_t* dims, size_t slen, + const char* name, char const* buffer, bool indep); +void write_tally_results( + hid_t group_id, hsize_t n_filter, hsize_t n_score, const double* results); } // extern "C" //============================================================================== @@ -127,7 +127,9 @@ extern "C" { //============================================================================== template -struct H5TypeMap { static const hid_t type_id; }; +struct H5TypeMap { + static const hid_t type_id; +}; //============================================================================== // Templates/overloads for read_attribute @@ -185,8 +187,7 @@ void read_attribute(hid_t obj_id, const char* name, xt::xarray& arr) } // overload for std::string -inline void -read_attribute(hid_t obj_id, const char* name, std::string& str) +inline void read_attribute(hid_t obj_id, const char* name, std::string& str) { // Create buffer to read data into auto n = attribute_typesize(obj_id, name); @@ -194,7 +195,7 @@ read_attribute(hid_t obj_id, const char* name, std::string& str) // Read attribute and set string read_attr_string(obj_id, name, n, buffer); - str = std::string{buffer, n}; + str = std::string {buffer, n}; delete[] buffer; } @@ -207,7 +208,7 @@ inline void read_attribute( // Allocate a C char array to get strings auto n = attribute_typesize(obj_id, name); - char* buffer = new char[m*n]; + char* buffer = new char[m * n]; // Read char data in attribute read_attr_string(obj_id, name, n, buffer); @@ -216,10 +217,12 @@ inline void read_attribute( // Determine proper length of string -- strlen doesn't work because // buffer[i] might not have any null characters std::size_t k = 0; - for (; k < n; ++k) if (buffer[i*n + k] == '\0') break; + for (; k < n; ++k) + if (buffer[i * n + k] == '\0') + break; // Create string based on (char*, size_t) constructor - vec.emplace_back(&buffer[i*n], k); + vec.emplace_back(&buffer[i * n], k); } delete[] buffer; } @@ -232,25 +235,25 @@ inline void read_attribute( // this version of read_dataset for vectors, arrays, or other non-scalar types. // enable_if_t allows us to conditionally remove the function from overload // resolution when the type T doesn't meet a certain criterion. -template inline -std::enable_if_t>::value> -read_dataset(hid_t obj_id, const char* name, T& buffer, bool indep=false) +template +inline std::enable_if_t>::value> read_dataset( + hid_t obj_id, const char* name, T& buffer, bool indep = false) { - read_dataset_lowlevel(obj_id, name, H5TypeMap::type_id, H5S_ALL, indep, - &buffer); + read_dataset_lowlevel( + obj_id, name, H5TypeMap::type_id, H5S_ALL, indep, &buffer); } // overload for std::string -inline void -read_dataset(hid_t obj_id, const char* name, std::string& str, bool indep=false) +inline void read_dataset( + hid_t obj_id, const char* name, std::string& str, bool indep = false) { // Create buffer to read data into auto n = dataset_typesize(obj_id, name); - char* buffer = new char[n]; + std::vector buffer(n, '\0'); // Read attribute and set string - read_string(obj_id, name, n, buffer, indep); - str = std::string{buffer, n}; + read_string(obj_id, name, n, buffer.data(), indep); + str = std::string {buffer.begin(), buffer.end()}; } // array version @@ -258,8 +261,8 @@ template inline void read_dataset( hid_t dset, const char* name, array& buffer, bool indep = false) { - read_dataset_lowlevel(dset, name, H5TypeMap::type_id, H5S_ALL, indep, - buffer.data()); + read_dataset_lowlevel( + dset, name, H5TypeMap::type_id, H5S_ALL, indep, buffer.data()); } // vector version @@ -273,8 +276,8 @@ void read_dataset(hid_t dset, vector& vec, bool indep = false) vec.resize(shape[0]); // Read data into vector - read_dataset_lowlevel(dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, - vec.data()); + read_dataset_lowlevel( + dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, vec.data()); } template @@ -286,8 +289,8 @@ void read_dataset( close_dataset(dset); } -template -void read_dataset(hid_t dset, xt::xarray& arr, bool indep=false) +template +void read_dataset(hid_t dset, xt::xarray& arr, bool indep = false) { // Get shape of dataset vector shape = object_shape(dset); @@ -299,17 +302,17 @@ void read_dataset(hid_t dset, xt::xarray& arr, bool indep=false) arr.resize(shape); // Read data from attribute - read_dataset_lowlevel(dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, - arr.data()); + read_dataset_lowlevel( + dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, arr.data()); } template<> -void read_dataset(hid_t dset, xt::xarray>& arr, - bool indep); +void read_dataset( + hid_t dset, xt::xarray>& arr, bool indep); -template -void read_dataset(hid_t obj_id, const char* name, xt::xarray& arr, - bool indep=false) +template +void read_dataset( + hid_t obj_id, const char* name, xt::xarray& arr, bool indep = false) { // Open dataset and read array hid_t dset = open_dataset(obj_id, name); @@ -317,10 +320,9 @@ void read_dataset(hid_t obj_id, const char* name, xt::xarray& arr, close_dataset(dset); } - -template -void read_dataset(hid_t obj_id, const char* name, xt::xtensor& arr, - bool indep=false) +template +void read_dataset( + hid_t obj_id, const char* name, xt::xtensor& arr, bool indep = false) { // Open dataset and read array hid_t dset = open_dataset(obj_id, name); @@ -346,8 +348,8 @@ void read_dataset(hid_t obj_id, const char* name, xt::xtensor& arr, } // overload for Position -inline void -read_dataset(hid_t obj_id, const char* name, Position& r, bool indep=false) +inline void read_dataset( + hid_t obj_id, const char* name, Position& r, bool indep = false) { array x; read_dataset(obj_id, name, x, indep); @@ -356,9 +358,9 @@ read_dataset(hid_t obj_id, const char* name, Position& r, bool indep=false) r.z = x[2]; } -template -inline void read_dataset_as_shape(hid_t obj_id, const char* name, - xt::xtensor& arr, bool indep=false) +template +inline void read_dataset_as_shape( + hid_t obj_id, const char* name, xt::xtensor& arr, bool indep = false) { hid_t dset = open_dataset(obj_id, name); @@ -369,8 +371,8 @@ inline void read_dataset_as_shape(hid_t obj_id, const char* name, vector buffer(size); // Read data from attribute - read_dataset_lowlevel(dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, - buffer.data()); + read_dataset_lowlevel( + dset, nullptr, H5TypeMap::type_id, H5S_ALL, indep, buffer.data()); // Adapt into xarray arr = xt::adapt(buffer, arr.shape()); @@ -378,10 +380,9 @@ inline void read_dataset_as_shape(hid_t obj_id, const char* name, close_dataset(dset); } - -template +template inline void read_nd_vector(hid_t obj_id, const char* name, - xt::xtensor& result, bool must_have=false) + xt::xtensor& result, bool must_have = false) { if (object_exists(obj_id, name)) { read_dataset_as_shape(obj_id, name, result, true); @@ -394,20 +395,19 @@ inline void read_nd_vector(hid_t obj_id, const char* name, // Templates/overloads for write_attribute //============================================================================== -template inline void -write_attribute(hid_t obj_id, const char* name, T buffer) +template +inline void write_attribute(hid_t obj_id, const char* name, T buffer) { write_attr(obj_id, 0, nullptr, name, H5TypeMap::type_id, &buffer); } -inline void -write_attribute(hid_t obj_id, const char* name, const char* buffer) +inline void write_attribute(hid_t obj_id, const char* name, const char* buffer) { write_attr_string(obj_id, name, buffer); } -inline void -write_attribute(hid_t obj_id, const char* name, const std::string& buffer) +inline void write_attribute( + hid_t obj_id, const char* name, const std::string& buffer) { write_attr_string(obj_id, name, buffer.c_str()); } @@ -428,30 +428,26 @@ inline void write_attribute( write_attr(obj_id, 1, dims, name, H5TypeMap::type_id, buffer.data()); } -inline void -write_attribute(hid_t obj_id, const char* name, Position r) +inline void write_attribute(hid_t obj_id, const char* name, Position r) { array buffer {r.x, r.y, r.z}; write_attribute(obj_id, name, buffer); } - - //============================================================================== // Templates/overloads for write_dataset //============================================================================== // Template for scalars (ensured by SFINAE) -template inline -std::enable_if_t>::value> -write_dataset(hid_t obj_id, const char* name, T buffer) +template +inline std::enable_if_t>::value> write_dataset( + hid_t obj_id, const char* name, T buffer) { - write_dataset_lowlevel(obj_id, 0, nullptr, name, H5TypeMap::type_id, - H5S_ALL, false, &buffer); + write_dataset_lowlevel( + obj_id, 0, nullptr, name, H5TypeMap::type_id, H5S_ALL, false, &buffer); } -inline void -write_dataset(hid_t obj_id, const char* name, const char* buffer) +inline void write_dataset(hid_t obj_id, const char* name, const char* buffer) { write_string(obj_id, name, buffer, false); } @@ -461,8 +457,8 @@ inline void write_dataset( hid_t obj_id, const char* name, const array& buffer) { hsize_t dims[] {N}; - write_dataset_lowlevel(obj_id, 1, dims, name, H5TypeMap::type_id, - H5S_ALL, false, buffer.data()); + write_dataset_lowlevel(obj_id, 1, dims, name, H5TypeMap::type_id, H5S_ALL, + false, buffer.data()); } inline void write_dataset( @@ -478,10 +474,10 @@ inline void write_dataset( } // Copy data into contiguous buffer - char* temp = new char[n*m]; - std::fill(temp, temp + n*m, '\0'); + char* temp = new char[n * m]; + std::fill(temp, temp + n * m, '\0'); for (decltype(n) i = 0; i < n; ++i) { - std::copy(buffer[i].begin(), buffer[i].end(), temp + i*m); + std::copy(buffer[i].begin(), buffer[i].end(), temp + i * m); } // Write 2D data @@ -496,30 +492,29 @@ inline void write_dataset( hid_t obj_id, const char* name, const vector& buffer) { hsize_t dims[] {buffer.size()}; - write_dataset_lowlevel(obj_id, 1, dims, name, H5TypeMap::type_id, - H5S_ALL, false, buffer.data()); + write_dataset_lowlevel(obj_id, 1, dims, name, H5TypeMap::type_id, H5S_ALL, + false, buffer.data()); } // Template for xarray, xtensor, etc. -template inline void -write_dataset(hid_t obj_id, const char* name, const xt::xcontainer& arr) +template +inline void write_dataset( + hid_t obj_id, const char* name, const xt::xcontainer& arr) { using T = typename D::value_type; auto s = arr.shape(); vector dims {s.cbegin(), s.cend()}; write_dataset_lowlevel(obj_id, dims.size(), dims.data(), name, - H5TypeMap::type_id, H5S_ALL, false, arr.data()); + H5TypeMap::type_id, H5S_ALL, false, arr.data()); } -inline void -write_dataset(hid_t obj_id, const char* name, Position r) +inline void write_dataset(hid_t obj_id, const char* name, Position r) { array buffer {r.x, r.y, r.z}; write_dataset(obj_id, name, buffer); } -inline void -write_dataset(hid_t obj_id, const char* name, std::string buffer) +inline void write_dataset(hid_t obj_id, const char* name, std::string buffer) { write_string(obj_id, name, buffer.c_str(), false); } diff --git a/include/openmc/initialize.h b/include/openmc/initialize.h index eba616474ac..a9b8b336f96 100644 --- a/include/openmc/initialize.h +++ b/include/openmc/initialize.h @@ -1,6 +1,8 @@ #ifndef OPENMC_INITIALIZE_H #define OPENMC_INITIALIZE_H +#include + #ifdef OPENMC_MPI #include "mpi.h" #endif @@ -11,8 +13,14 @@ int parse_command_line(int argc, char* argv[]); #ifdef OPENMC_MPI void initialize_mpi(MPI_Comm intracomm); #endif -void read_input_xml(); -} +//! Read material, geometry, settings, and tallies from a single XML file +bool read_model_xml(); +//! Read inputs from separate XML files +void read_separate_xml_files(); +//! Write some output that occurs right after initialization +void initial_output(); + +} // namespace openmc #endif // OPENMC_INITIALIZE_H diff --git a/include/openmc/interpolate.h b/include/openmc/interpolate.h new file mode 100644 index 00000000000..db501f71b66 --- /dev/null +++ b/include/openmc/interpolate.h @@ -0,0 +1,99 @@ +#ifndef OPENMC_INTERPOLATE_H +#define OPENMC_INTERPOLATE_H + +#include +#include + +#include + +#include "openmc/error.h" +#include "openmc/search.h" + +namespace openmc { + +inline double interpolate_lin_lin( + double x0, double x1, double y0, double y1, double x) +{ + return y0 + (x - x0) / (x1 - x0) * (y1 - y0); +} + +inline double interpolate_lin_log( + double x0, double x1, double y0, double y1, double x) +{ + return y0 + std::log(x / x0) / std::log(x1 / x0) * (y1 - y0); +} + +inline double interpolate_log_lin( + double x0, double x1, double y0, double y1, double x) +{ + return y0 * std::exp((x - x0) / (x1 - x0) * std::log(y1 / y0)); +} + +inline double interpolate_log_log( + double x0, double x1, double y0, double y1, double x) +{ + double f = std::log(x / x0) / std::log(x1 / x0); + return y0 * std::exp(f * std::log(y1 / y0)); +} + +inline double interpolate_lagrangian(gsl::span xs, + gsl::span ys, int idx, double x, int order) +{ + double output {0.0}; + + for (int i = 0; i < order + 1; i++) { + double numerator {1.0}; + double denominator {1.0}; + for (int j = 0; j < order + 1; j++) { + if (i == j) + continue; + numerator *= (x - xs[idx + j]); + denominator *= (xs[idx + i] - xs[idx + j]); + } + output += (numerator / denominator) * ys[idx + i]; + } + + return output; +} + +inline double interpolate(gsl::span xs, + gsl::span ys, double x, + Interpolation i = Interpolation::lin_lin) +{ + int idx = lower_bound_index(xs.begin(), xs.end(), x); + + if (idx == xs.size()) + idx--; + + switch (i) { + case Interpolation::histogram: + return ys[idx]; + case Interpolation::lin_lin: + return interpolate_lin_lin(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x); + case Interpolation::log_log: + return interpolate_log_log(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x); + case Interpolation::lin_log: + return interpolate_lin_log(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x); + case Interpolation::log_lin: + return interpolate_log_lin(xs[idx], xs[idx + 1], ys[idx], ys[idx + 1], x); + case Interpolation::quadratic: + // move back one point if x is in the last interval of the x-grid + if (idx == xs.size() - 2 && idx > 0) + idx--; + return interpolate_lagrangian(xs, ys, idx, x, 2); + case Interpolation::cubic: + // if x is not in the first interval of the x-grid, move back one + if (idx > 0) + idx--; + // if the index was the last interval of the x-grid, move it back one more + if (idx == xs.size() - 3) + idx--; + return interpolate_lagrangian(xs, ys, idx, x, 3); + default: + fatal_error("Unsupported interpolation"); + } +} + +} // namespace openmc + +#endif diff --git a/include/openmc/lattice.h b/include/openmc/lattice.h index e7db9016b6e..11dda4a6b85 100644 --- a/include/openmc/lattice.h +++ b/include/openmc/lattice.h @@ -20,11 +20,9 @@ namespace openmc { // Module constants //============================================================================== -constexpr int32_t NO_OUTER_UNIVERSE{-1}; +constexpr int32_t NO_OUTER_UNIVERSE {-1}; -enum class LatticeType { - rect, hex -}; +enum class LatticeType { rect, hex }; //============================================================================== // Global variables @@ -33,8 +31,8 @@ enum class LatticeType { class Lattice; namespace model { - extern std::unordered_map lattice_map; - extern vector> lattices; +extern std::unordered_map lattice_map; +extern vector> lattices; } // namespace model //============================================================================== @@ -45,15 +43,14 @@ namespace model { class LatticeIter; class ReverseLatticeIter; -class Lattice -{ +class Lattice { public: - int32_t id_; //!< Universe ID number - std::string name_; //!< User-defined name + int32_t id_; //!< Universe ID number + std::string name_; //!< User-defined name LatticeType type_; - vector universes_; //!< Universes filling each lattice tile - int32_t outer_ {NO_OUTER_UNIVERSE}; //!< Universe tiled outside the lattice - vector offsets_; //!< Distribcell offset table + vector universes_; //!< Universes filling each lattice tile + int32_t outer_ {NO_OUTER_UNIVERSE}; //!< Universe tiled outside the lattice + vector offsets_; //!< Distribcell offset table explicit Lattice(pugi::xml_node lat_node); @@ -72,7 +69,9 @@ class Lattice //! Allocate offset table for distribcell. void allocate_offset_table(int n_maps) - {offsets_.resize(n_maps * universes_.size(), C_NONE);} + { + offsets_.resize(n_maps * universes_.size(), C_NONE); + } //! Populate the distribcell offset tables. int32_t fill_offset_table(int32_t offset, int32_t target_univ_id, int map, @@ -100,6 +99,11 @@ class Lattice virtual void get_indices( Position r, Direction u, array& result) const = 0; + //! \brief Compute the the flat index for a set of lattice cell indices + //! \param i_xyz The indices for a lattice cell. + //! \return Flat index into the universes vector. + virtual int get_flat_index(const array& i_xyz) const = 0; + //! \brief Get coordinates local to a lattice tile. //! \param r A 3D Cartesian coordinate. //! \param i_xyz The indices for a lattice tile. @@ -112,7 +116,9 @@ class Lattice //! \return true if the given index fit within the lattice bounds. False //! otherwise. virtual bool is_valid_index(int indx) const - {return (indx >= 0) && (indx < universes_.size());} + { + return (indx >= 0) && (indx < universes_.size()); + } //! \brief Get the distribcell offset for a lattice tile. //! \param The map index for the target cell. @@ -138,7 +144,7 @@ class Lattice void to_hdf5(hid_t group_id) const; protected: - bool is_3d_; //!< Has divisions along the z-axis? + bool is_3d_; //!< Has divisions along the z-axis? virtual void to_hdf5_inner(hid_t group_id) const = 0; }; @@ -147,26 +153,24 @@ class Lattice //! An iterator over lattice universes. //============================================================================== -class LatticeIter -{ +class LatticeIter { public: - int indx_; //!< An index to a Lattice universes or offsets array. + int indx_; //!< An index to a Lattice universes or offsets array. - LatticeIter(Lattice &lat, int indx) - : indx_(indx), lat_(lat) - {} + LatticeIter(Lattice& lat, int indx) : indx_(indx), lat_(lat) {} - bool operator==(const LatticeIter &rhs) {return (indx_ == rhs.indx_);} + bool operator==(const LatticeIter& rhs) { return (indx_ == rhs.indx_); } - bool operator!=(const LatticeIter &rhs) {return !(*this == rhs);} + bool operator!=(const LatticeIter& rhs) { return !(*this == rhs); } - int32_t& operator*() {return lat_.universes_[indx_];} + int32_t& operator*() { return lat_.universes_[indx_]; } LatticeIter& operator++() { while (indx_ < lat_.universes_.size()) { ++indx_; - if (lat_.is_valid_index(indx_)) return *this; + if (lat_.is_valid_index(indx_)) + return *this; } indx_ = lat_.universes_.size(); return *this; @@ -180,18 +184,16 @@ class LatticeIter //! A reverse iterator over lattice universes. //============================================================================== -class ReverseLatticeIter : public LatticeIter -{ +class ReverseLatticeIter : public LatticeIter { public: - ReverseLatticeIter(Lattice &lat, int indx) - : LatticeIter {lat, indx} - {} + ReverseLatticeIter(Lattice& lat, int indx) : LatticeIter {lat, indx} {} ReverseLatticeIter& operator++() { while (indx_ > -1) { --indx_; - if (lat_.is_valid_index(indx_)) return *this; + if (lat_.is_valid_index(indx_)) + return *this; } indx_ = -1; return *this; @@ -200,72 +202,78 @@ class ReverseLatticeIter : public LatticeIter //============================================================================== -class RectLattice : public Lattice -{ +class RectLattice : public Lattice { public: explicit RectLattice(pugi::xml_node lat_node); - int32_t const& operator[](array const& i_xyz); + int32_t const& operator[](array const& i_xyz) override; - bool are_valid_indices(array const& i_xyz) const; + bool are_valid_indices(array const& i_xyz) const override; std::pair> distance( - Position r, Direction u, const array& i_xyz) const; + Position r, Direction u, const array& i_xyz) const override; - void get_indices(Position r, Direction u, array& result) const; + void get_indices( + Position r, Direction u, array& result) const override; - Position get_local_position(Position r, const array& i_xyz) const; + int get_flat_index(const array& i_xyz) const override; - int32_t& offset(int map, array const& i_xyz); + Position get_local_position( + Position r, const array& i_xyz) const override; - int32_t offset(int map, int indx) const; + int32_t& offset(int map, array const& i_xyz) override; - std::string index_to_string(int indx) const; + int32_t offset(int map, int indx) const override; - void to_hdf5_inner(hid_t group_id) const; + std::string index_to_string(int indx) const override; + + void to_hdf5_inner(hid_t group_id) const override; private: - array n_cells_; //!< Number of cells along each axis - Position lower_left_; //!< Global lower-left corner of the lattice - Position pitch_; //!< Lattice tile width along each axis + array n_cells_; //!< Number of cells along each axis + Position lower_left_; //!< Global lower-left corner of the lattice + Position pitch_; //!< Lattice tile width along each axis }; //============================================================================== -class HexLattice : public Lattice -{ +class HexLattice : public Lattice { public: explicit HexLattice(pugi::xml_node lat_node); - int32_t const& operator[](array const& i_xyz); + int32_t const& operator[](array const& i_xyz) override; - LatticeIter begin(); + LatticeIter begin() override; - ReverseLatticeIter rbegin(); + ReverseLatticeIter rbegin() override; - bool are_valid_indices(array const& i_xyz) const; + bool are_valid_indices(array const& i_xyz) const override; std::pair> distance( - Position r, Direction u, const array& i_xyz) const; + Position r, Direction u, const array& i_xyz) const override; + + void get_indices( + Position r, Direction u, array& result) const override; - void get_indices(Position r, Direction u, array& result) const; + int get_flat_index(const array& i_xyz) const override; - Position get_local_position(Position r, const array& i_xyz) const; + Position get_local_position( + Position r, const array& i_xyz) const override; - bool is_valid_index(int indx) const; + bool is_valid_index(int indx) const override; - int32_t& offset(int map, array const& i_xyz); + int32_t& offset(int map, array const& i_xyz) override; - int32_t offset(int map, int indx) const; + int32_t offset(int map, int indx) const override; - std::string index_to_string(int indx) const; + std::string index_to_string(int indx) const override; - void to_hdf5_inner(hid_t group_id) const; + void to_hdf5_inner(hid_t group_id) const override; private: enum class Orientation { - y, //!< Flat side of lattice parallel to y-axis - x //!< Flat side of lattice parallel to x-axis + y, //!< Flat side of lattice parallel to y-axis + x //!< Flat side of lattice parallel to x-axis }; //! Fill universes_ vector for 'y' orientation @@ -274,11 +282,11 @@ class HexLattice : public Lattice //! Fill universes_ vector for 'x' orientation void fill_lattice_x(const vector& univ_words); - int n_rings_; //!< Number of radial tile positions - int n_axial_; //!< Number of axial tile positions - Orientation orientation_; //!< Orientation of lattice - Position center_; //!< Global center of lattice - array pitch_; //!< Lattice tile width and height + int n_rings_; //!< Number of radial tile positions + int n_axial_; //!< Number of axial tile positions + Orientation orientation_; //!< Orientation of lattice + Position center_; //!< Global center of lattice + array pitch_; //!< Lattice tile width and height }; //============================================================================== diff --git a/include/openmc/material.h b/include/openmc/material.h index 7e975a1bb66..9235be356f6 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -4,14 +4,15 @@ #include #include -#include -#include #include "pugixml.hpp" #include "xtensor/xtensor.hpp" +#include +#include #include "openmc/bremsstrahlung.h" #include "openmc/constants.h" #include "openmc/memory.h" // for unique_ptr +#include "openmc/ncrystal_interface.h" #include "openmc/particle.h" #include "openmc/vector.h" @@ -34,15 +35,14 @@ extern vector> materials; //! A substance with constituent nuclides and thermal scattering data //============================================================================== -class Material -{ +class Material { public: //---------------------------------------------------------------------------- // Types struct ThermalTable { - int index_table; //!< Index of table in data::thermal_scatt + int index_table; //!< Index of table in data::thermal_scatt int index_nuclide; //!< Index in nuclide_ - double fraction; //!< How often to use table + double fraction; //!< How often to use table }; //---------------------------------------------------------------------------- @@ -69,6 +69,14 @@ class Material //! Write material data to HDF5 void to_hdf5(hid_t group) const; + //! Export physical properties to HDF5 + //! \param[in] group HDF5 group to write to + void export_properties_hdf5(hid_t group) const; + + //! Import physical properties from HDF5 + //! \param[in] group HDF5 group to read from + void import_properties_hdf5(hid_t group); + //! Add nuclide to the material // //! \param[in] nuclide Name of the nuclide @@ -82,6 +90,12 @@ class Material void set_densities( const vector& name, const vector& density); + //! Clone the material by deep-copying all members, except for the ID, + // which will get auto-assigned to the next available ID. After creating + // the new material, it is added to openmc::model::materials. + //! \return reference to the cloned material + Material& clone(); + //---------------------------------------------------------------------------- // Accessors @@ -106,13 +120,22 @@ class Material //! \param[in] units Units of density void set_density(double density, gsl::cstring_span units); + //! Set temperature of the material + void set_temperature(double temperature) { temperature_ = temperature; }; + //! Get nuclides in material //! \return Indices into the global nuclides vector - gsl::span nuclides() const { return {nuclide_.data(), nuclide_.size()}; } + gsl::span nuclides() const + { + return {nuclide_.data(), nuclide_.size()}; + } //! Get densities of each nuclide in material //! \return Densities in [atom/b-cm] - gsl::span densities() const { return {atom_density_.data(), atom_density_.size()}; } + gsl::span densities() const + { + return {atom_density_.data(), atom_density_.size()}; + } //! Get ID of material //! \return ID of material @@ -126,6 +149,7 @@ class Material //! Get whether material is fissionable //! \return Whether material is fissionable bool fissionable() const { return fissionable_; } + bool& fissionable() { return fissionable_; } //! Get volume of material //! \return Volume in [cm^3] @@ -135,20 +159,27 @@ class Material //! \return Temperature in [K] double temperature() const; + //! Whether or not the material is depletable + bool depletable() const { return depletable_; } + bool& depletable() { return depletable_; } + + //! Get pointer to NCrystal material object + //! \return Pointer to NCrystal material object + const NCrystalMat& ncrystal_mat() const { return ncrystal_mat_; }; + //---------------------------------------------------------------------------- // Data - int32_t id_ {C_NONE}; //!< Unique ID - std::string name_; //!< Name of material + int32_t id_ {C_NONE}; //!< Unique ID + std::string name_; //!< Name of material vector nuclide_; //!< Indices in nuclides vector vector element_; //!< Indices in elements vector + NCrystalMat ncrystal_mat_; //!< NCrystal material object xt::xtensor atom_density_; //!< Nuclide atom density in [atom/b-cm] - double density_; //!< Total atom density in [atom/b-cm] - double density_gpcc_; //!< Total atom density in [g/cm^3] - double volume_ {-1.0}; //!< Volume in [cm^3] - bool fissionable_ {false}; //!< Does this material contain fissionable nuclides - bool depletable_ {false}; //!< Is the material depletable? - vector p0_; //!< Indicate which nuclides are to be treated with - //!< iso-in-lab scattering + double density_; //!< Total atom density in [atom/b-cm] + double density_gpcc_; //!< Total atom density in [g/cm^3] + double volume_ {-1.0}; //!< Volume in [cm^3] + vector p0_; //!< Indicate which nuclides are to be treated with + //!< iso-in-lab scattering // To improve performance of tallying, we store an array (direct address // table) that indicates for each nuclide in data::nuclides the index of the @@ -181,6 +212,9 @@ class Material // Private data members gsl::index index_; + bool depletable_ {false}; //!< Is the material depletable? + bool fissionable_ { + false}; //!< Does this material contain fissionable nuclides //! \brief Default temperature for cells containing this material. //! //! A negative value indicates no default temperature was specified. @@ -204,6 +238,10 @@ double density_effect(const vector& f, const vector& e_b_sq, //! Read material data from materials.xml void read_materials_xml(); +//! Read material data XML node +//! \param[in] root node of materials XML element +void read_materials_xml(pugi::xml_node root); + void free_memory_material(); } // namespace openmc diff --git a/include/openmc/math_functions.h b/include/openmc/math_functions.h index 0fd322556b0..c30ef75585a 100644 --- a/include/openmc/math_functions.h +++ b/include/openmc/math_functions.h @@ -10,7 +10,6 @@ #include "openmc/position.h" - namespace openmc { //============================================================================== @@ -130,11 +129,11 @@ extern "C" void calc_zn_rad(int n, double rho, double zn_rad[]); //! \param seed A pointer to the pseudorandom seed //============================================================================== -extern "C" void rotate_angle_c(double uvw[3], double mu, const double* phi, - uint64_t* seed); +extern "C" void rotate_angle_c( + double uvw[3], double mu, const double* phi, uint64_t* seed); -Direction rotate_angle(Direction u, double mu, const double* phi, - uint64_t* seed); +Direction rotate_angle( + Direction u, double mu, const double* phi, uint64_t* seed); //============================================================================== //! Constructs a natural cubic spline. @@ -167,8 +166,8 @@ void spline(int n, const double x[], const double y[], double z[]); //! \return Interpolated value //============================================================================== -double spline_interpolate(int n, const double x[], const double y[], - const double z[], double xint); +double spline_interpolate( + int n, const double x[], const double y[], const double z[], double xint); //============================================================================== //! Evaluate the definite integral of the interpolating cubic spline between diff --git a/include/openmc/mcpl_interface.h b/include/openmc/mcpl_interface.h new file mode 100644 index 00000000000..1f0c94d6dec --- /dev/null +++ b/include/openmc/mcpl_interface.h @@ -0,0 +1,42 @@ +#ifndef OPENMC_MCPL_INTERFACE_H +#define OPENMC_MCPL_INTERFACE_H + +#include "openmc/particle_data.h" +#include "openmc/vector.h" + +#include + +#include + +namespace openmc { + +//============================================================================== +// Constants +//============================================================================== + +extern "C" const bool MCPL_ENABLED; + +//============================================================================== +// Functions +//============================================================================== + +//! Get a vector of source sites from an MCPL file +// +//! \param[in] path Path to MCPL file +//! \return Vector of source sites +vector mcpl_source_sites(std::string path); + +//! Write an MCPL source file +// +//! \param[in] filename Path to MCPL file +//! \param[in] source_bank Vector of SourceSites to write to file for this +//! MPI rank +//! \param[in] bank_indx Pointer to vector of site index ranges over all +//! MPI ranks. This can be computed by calling +//! calculate_parallel_index_vector on +//! source_bank.size(). +void write_mcpl_source_point(const char* filename, + gsl::span source_bank, vector const& bank_index); +} // namespace openmc + +#endif // OPENMC_MCPL_INTERFACE_H diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index 260ee2ad780..3917e6368a4 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -9,17 +9,20 @@ #include "hdf5.h" #include "pugixml.hpp" #include "xtensor/xtensor.hpp" +#include +#include "openmc/error.h" #include "openmc/memory.h" // for unique_ptr #include "openmc/particle.h" #include "openmc/position.h" #include "openmc/vector.h" +#include "openmc/xml_interface.h" #ifdef DAGMC -#include "moab/Core.hpp" #include "moab/AdaptiveKDTree.hpp" -#include "moab/Matrix3.hpp" +#include "moab/Core.hpp" #include "moab/GeomUtil.hpp" +#include "moab/Matrix3.hpp" #endif #ifdef LIBMESH @@ -36,6 +39,12 @@ namespace openmc { +//============================================================================== +// Constants +//============================================================================== + +enum class ElementType { UNSUPPORTED = -1, LINEAR_TET, LINEAR_HEX }; + //============================================================================== // Global variables //============================================================================== @@ -53,21 +62,41 @@ extern vector> meshes; #ifdef LIBMESH namespace settings { -// used when creating new libMesh::Mesh instances +// used when creating new libMesh::MeshBase instances extern unique_ptr libmesh_init; extern const libMesh::Parallel::Communicator* libmesh_comm; -} +} // namespace settings #endif -class Mesh -{ +class Mesh { public: + // Types, aliases + struct MaterialVolume { + int32_t material; //!< material index + double volume; //!< volume in [cm^3] + }; + // Constructors and destructor Mesh() = default; Mesh(pugi::xml_node node); virtual ~Mesh() = default; // Methods + //! Perform any preparation needed to support use in mesh filters + virtual void prepare_for_tallies() {}; + + //! Update a position to the local coordinates of the mesh + virtual void local_coords(Position& r) const {}; + + //! Return a position in the local coordinates of the mesh + virtual Position local_coords(const Position& r) const { return r; }; + + //! Sample a position within a mesh element + // + //! \param[in] bin Bin value of the mesh element sampled + //! \param[inout] seed Seed to use for random sampling + //! \return sampled position within mesh element + virtual Position sample_element(int32_t bin, uint64_t* seed) const = 0; //! Determine which bins were crossed by a particle // @@ -76,11 +105,8 @@ class Mesh //! \param[in] u Particle direction //! \param[out] bins Bins that were crossed //! \param[out] lengths Fraction of tracklength in each bin - virtual void bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins, - vector& lengths) const = 0; + virtual void bins_crossed(Position r0, Position r1, const Direction& u, + vector& bins, vector& lengths) const = 0; //! Determine which surface bins were crossed by a particle // @@ -88,11 +114,8 @@ class Mesh //! \param[in] r1 Current position of the particle //! \param[in] u Particle direction //! \param[out] bins Surface bins that were crossed - virtual void - surface_bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins) const = 0; + virtual void surface_bins_crossed( + Position r0, Position r1, const Direction& u, vector& bins) const = 0; //! Get bin at a given position in space // @@ -106,8 +129,10 @@ class Mesh //! Get the number of mesh cell surfaces. virtual int n_surface_bins() const = 0; + int32_t id() const { return id_; } + //! Set the mesh ID - void set_id(int32_t id=-1); + void set_id(int32_t id = -1); //! Write mesh data to an HDF5 group // @@ -130,9 +155,39 @@ class Mesh //! \param[in] bin Mesh bin to generate a label for virtual std::string bin_label(int bin) const = 0; + //! Get the volume of a mesh bin + // + //! \param[in] bin Bin to return the volume for + //! \return Volume of the bin + virtual double volume(int bin) const = 0; + + //! Volumes of all elements in the mesh in bin ordering + vector volumes() const; + + virtual std::string get_mesh_type() const = 0; + + //! Determine volume of materials within a single mesh elemenet + // + //! \param[in] n_sample Number of samples within each element + //! \param[in] bin Index of mesh element + //! \param[out] Array of (material index, volume) for desired element + //! \param[inout] seed Pseudorandom number seed + //! \return Number of materials within element + int material_volumes(int n_sample, int bin, gsl::span volumes, + uint64_t* seed) const; + + //! Determine volume of materials within a single mesh elemenet + // + //! \param[in] n_sample Number of samples within each element + //! \param[in] bin Index of mesh element + //! \param[inout] seed Pseudorandom number seed + //! \return Vector of (material index, volume) for desired element + vector material_volumes( + int n_sample, int bin, uint64_t* seed) const; + // Data members - int id_ {-1}; //!< User-specified ID - int n_dimension_; //!< Number of dimensions + int id_ {-1}; //!< User-specified ID + int n_dimension_ {-1}; //!< Number of dimensions }; class StructuredMesh : public Mesh { @@ -141,17 +196,50 @@ class StructuredMesh : public Mesh { StructuredMesh(pugi::xml_node node) : Mesh {node} {}; virtual ~StructuredMesh() = default; + using MeshIndex = std::array; + + struct MeshDistance { + MeshDistance() = default; + MeshDistance(int _index, bool _max_surface, double _distance) + : next_index {_index}, max_surface {_max_surface}, distance {_distance} + {} + int next_index {-1}; + bool max_surface {true}; + double distance {INFTY}; + bool operator<(const MeshDistance& o) const + { + return distance < o.distance; + } + }; + + Position sample_element(int32_t bin, uint64_t* seed) const override + { + return sample_element(get_indices_from_bin(bin), seed); + }; + + virtual Position sample_element(const MeshIndex& ijk, uint64_t* seed) const; + int get_bin(Position r) const override; int n_bins() const override; int n_surface_bins() const override; - void bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins, - vector& lengths) const override; + void bins_crossed(Position r0, Position r1, const Direction& u, + vector& bins, vector& lengths) const override; + + void surface_bins_crossed(Position r0, Position r1, const Direction& u, + vector& bins) const override; + + //! Determine which cell or surface bins were crossed by a particle + // + //! \param[in] r0 Previous position of the particle + //! \param[in] r1 Current position of the particle + //! \param[in] u Particle direction + //! \param[in] tally Functor that eventually stores the tally data + template + void raytrace_mesh( + Position r0, Position r1, const Direction& u, T tally) const; //! Count number of bank sites in each mesh bin / energy bin // @@ -165,20 +253,20 @@ class StructuredMesh : public Mesh { // //! \param[in] Array of mesh indices //! \return Mesh bin - virtual int get_bin_from_indices(const int* ijk) const; + virtual int get_bin_from_indices(const MeshIndex& ijk) const; //! Get mesh indices given a position // //! \param[in] r Position to get indices for - //! \param[out] ijk Array of mesh indices //! \param[out] in_mesh Whether position is in mesh - virtual void get_indices(Position r, int* ijk, bool* in_mesh) const; + //! \return Array of mesh indices + virtual MeshIndex get_indices(Position r, bool& in_mesh) const; //! Get mesh indices corresponding to a mesh bin // //! \param[in] bin Mesh bin - //! \param[out] ijk Mesh indices - virtual void get_indices_from_bin(int bin, int* ijk) const; + //! \return ijk Mesh indices + virtual MeshIndex get_indices_from_bin(int bin) const; //! Get mesh index in a particular direction //! @@ -186,70 +274,123 @@ class StructuredMesh : public Mesh { //! \param[in] i Direction index virtual int get_index_in_direction(double r, int i) const = 0; - //! Check where a line segment intersects the mesh and if it intersects at all - // - //! \param[in,out] r0 In: starting position, out: intersection point - //! \param[in] r1 Ending position - //! \param[out] ijk Indices of the mesh bin containing the intersection point - //! \return Whether the line segment connecting r0 and r1 intersects mesh - virtual bool intersects(Position& r0, Position r1, int* ijk) const; - //! Get the coordinate for the mesh grid boundary in the positive direction //! //! \param[in] ijk Array of mesh indices //! \param[in] i Direction index - virtual double positive_grid_boundary(int* ijk, int i) const = 0; + virtual double positive_grid_boundary(const MeshIndex& ijk, int i) const + { + auto msg = + fmt::format("Attempting to call positive_grid_boundary on a {} mesh.", + get_mesh_type()); + fatal_error(msg); + }; //! Get the coordinate for the mesh grid boundary in the negative direction //! //! \param[in] ijk Array of mesh indices //! \param[in] i Direction index - virtual double negative_grid_boundary(int* ijk, int i) const = 0; + virtual double negative_grid_boundary(const MeshIndex& ijk, int i) const + { + auto msg = + fmt::format("Attempting to call negative_grid_boundary on a {} mesh.", + get_mesh_type()); + fatal_error(msg); + }; + + //! Get the closest distance from the coordinate r to the grid surface + //! in i direction that bounds mesh cell ijk and that is larger than l + //! The coordinate r does not have to be inside the mesh cell ijk. In + //! curved coordinates, multiple crossings of the same surface can happen, + //! these are selected by the parameter l + //! + //! \param[in] ijk Array of mesh indices + //! \param[in] i direction index of grid surface + //! \param[in] r0 position, from where to calculate the distance + //! \param[in] u direction of flight. actual position is r0 + l * u + //! \param[in] l actual chord length + //! \return MeshDistance struct with closest distance, next cell index in + //! i-direction and min/max surface indicator + virtual MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i, + const Position& r0, const Direction& u, double l) const = 0; //! Get a label for the mesh bin std::string bin_label(int bin) const override; + //! Get shape as xt::xtensor + xt::xtensor get_x_shape() const; + + double volume(int bin) const override + { + return this->volume(get_indices_from_bin(bin)); + } + + //! Get the volume of a specified element + //! \param[in] ijk Mesh index to return the volume for + //! \return Volume of the bin + virtual double volume(const MeshIndex& ijk) const = 0; + // Data members - xt::xtensor lower_left_; //!< Lower-left coordinates of mesh + xt::xtensor lower_left_; //!< Lower-left coordinates of mesh xt::xtensor upper_right_; //!< Upper-right coordinates of mesh - xt::xtensor shape_; //!< Number of mesh elements in each dimension + std::array shape_; //!< Number of mesh elements in each dimension protected: - virtual bool intersects_1d(Position& r0, Position r1, int* ijk) const; - virtual bool intersects_2d(Position& r0, Position r1, int* ijk) const; - virtual bool intersects_3d(Position& r0, Position r1, int* ijk) const; +}; + +class PeriodicStructuredMesh : public StructuredMesh { + +public: + PeriodicStructuredMesh() = default; + PeriodicStructuredMesh(pugi::xml_node node) : StructuredMesh {node} {}; + + void local_coords(Position& r) const override { r -= origin_; }; + + Position local_coords(const Position& r) const override + { + return r - origin_; + }; + + // Data members + Position origin_ {0.0, 0.0, 0.0}; //!< Origin of the mesh }; //============================================================================== //! Tessellation of n-dimensional Euclidean space by congruent squares or cubes //============================================================================== -class RegularMesh : public StructuredMesh -{ +class RegularMesh : public StructuredMesh { public: // Constructors RegularMesh() = default; RegularMesh(pugi::xml_node node); // Overridden methods - void - surface_bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins) const override; - int get_index_in_direction(double r, int i) const override; - double positive_grid_boundary(int* ijk, int i) const override; + virtual std::string get_mesh_type() const override; - double negative_grid_boundary(int* ijk, int i) const override; + static const std::string mesh_type; + + MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i, + const Position& r0, const Direction& u, double l) const override; std::pair, vector> plot( Position plot_ll, Position plot_ur) const override; void to_hdf5(hid_t group) const override; - // New methods + //! Get the coordinate for the mesh grid boundary in the positive direction + //! + //! \param[in] ijk Array of mesh indices + //! \param[in] i Direction index + double positive_grid_boundary(const MeshIndex& ijk, int i) const override; + + //! Get the coordinate for the mesh grid boundary in the negative direction + //! + //! \param[in] ijk Array of mesh indices + //! \param[in] i Direction index + double negative_grid_boundary(const MeshIndex& ijk, int i) const override; //! Count number of bank sites in each mesh bin / energy bin // @@ -259,40 +400,187 @@ class RegularMesh : public StructuredMesh xt::xtensor count_sites( const SourceSite* bank, int64_t length, bool* outside) const; + //! Return the volume for a given mesh index + double volume(const MeshIndex& ijk) const override; + // Data members - double volume_frac_; //!< Volume fraction of each mesh element + double volume_frac_; //!< Volume fraction of each mesh element + double element_volume_; //!< Volume of each mesh element xt::xtensor width_; //!< Width of each mesh element }; - -class RectilinearMesh : public StructuredMesh -{ +class RectilinearMesh : public StructuredMesh { public: // Constructors RectilinearMesh() = default; RectilinearMesh(pugi::xml_node node); // Overridden methods - void - surface_bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins) const override; + int get_index_in_direction(double r, int i) const override; + + virtual std::string get_mesh_type() const override; + + static const std::string mesh_type; + + MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i, + const Position& r0, const Direction& u, double l) const override; + + std::pair, vector> plot( + Position plot_ll, Position plot_ur) const override; + + void to_hdf5(hid_t group) const override; + + //! Get the coordinate for the mesh grid boundary in the positive direction + //! + //! \param[in] ijk Array of mesh indices + //! \param[in] i Direction index + double positive_grid_boundary(const MeshIndex& ijk, int i) const override; + + //! Get the coordinate for the mesh grid boundary in the negative direction + //! + //! \param[in] ijk Array of mesh indices + //! \param[in] i Direction index + double negative_grid_boundary(const MeshIndex& ijk, int i) const override; + + //! Return the volume for a given mesh index + double volume(const MeshIndex& ijk) const override; + + int set_grid(); + + // Data members + array, 3> grid_; +}; + +class CylindricalMesh : public PeriodicStructuredMesh { +public: + // Constructors + CylindricalMesh() = default; + CylindricalMesh(pugi::xml_node node); + + // Overridden methods + virtual MeshIndex get_indices(Position r, bool& in_mesh) const override; + + int get_index_in_direction(double r, int i) const override; + + virtual std::string get_mesh_type() const override; + + static const std::string mesh_type; + + Position sample_element(const MeshIndex& ijk, uint64_t* seed) const override; + + MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i, + const Position& r0, const Direction& u, double l) const override; + + std::pair, vector> plot( + Position plot_ll, Position plot_ur) const override; + + void to_hdf5(hid_t group) const override; + + double volume(const MeshIndex& ijk) const override; + + // grid accessors + double r(int i) const { return grid_[0][i]; } + double phi(int i) const { return grid_[1][i]; } + double z(int i) const { return grid_[2][i]; } + + int set_grid(); + + // Data members + array, 3> grid_; + +private: + double find_r_crossing( + const Position& r, const Direction& u, double l, int shell) const; + double find_phi_crossing( + const Position& r, const Direction& u, double l, int shell) const; + StructuredMesh::MeshDistance find_z_crossing( + const Position& r, const Direction& u, double l, int shell) const; + + bool full_phi_ {false}; + + inline int sanitize_angular_index(int idx, bool full, int N) const + { + if ((idx > 0) and (idx <= N)) { + return idx; + } else if (full) { + return (idx + N - 1) % N + 1; + } else { + return 0; + } + } + + inline int sanitize_phi(int idx) const + { + return sanitize_angular_index(idx, full_phi_, shape_[1]); + } +}; + +class SphericalMesh : public PeriodicStructuredMesh { +public: + // Constructors + SphericalMesh() = default; + SphericalMesh(pugi::xml_node node); + + // Overridden methods + virtual MeshIndex get_indices(Position r, bool& in_mesh) const override; int get_index_in_direction(double r, int i) const override; - double positive_grid_boundary(int* ijk, int i) const override; + virtual std::string get_mesh_type() const override; + + static const std::string mesh_type; + + Position sample_element(const MeshIndex& ijk, uint64_t* seed) const override; - double negative_grid_boundary(int* ijk, int i) const override; + MeshDistance distance_to_grid_boundary(const MeshIndex& ijk, int i, + const Position& r0, const Direction& u, double l) const override; std::pair, vector> plot( Position plot_ll, Position plot_ur) const override; void to_hdf5(hid_t group) const override; - vector> grid_; + double r(int i) const { return grid_[0][i]; } + double theta(int i) const { return grid_[1][i]; } + double phi(int i) const { return grid_[2][i]; } int set_grid(); + + // Data members + array, 3> grid_; + +private: + double find_r_crossing( + const Position& r, const Direction& u, double l, int shell) const; + double find_theta_crossing( + const Position& r, const Direction& u, double l, int shell) const; + double find_phi_crossing( + const Position& r, const Direction& u, double l, int shell) const; + + bool full_theta_ {false}; + bool full_phi_ {false}; + + inline int sanitize_angular_index(int idx, bool full, int N) const + { + if ((idx > 0) and (idx <= N)) { + return idx; + } else if (full) { + return (idx + N - 1) % N + 1; + } else { + return 0; + } + } + + double volume(const MeshIndex& ijk) const override; + + inline int sanitize_theta(int idx) const + { + return sanitize_angular_index(idx, full_theta_, shape_[1]); + } + inline int sanitize_phi(int idx) const + { + return sanitize_angular_index(idx, full_phi_, shape_[2]); + } }; // Abstract class for unstructured meshes @@ -304,12 +592,13 @@ class UnstructuredMesh : public Mesh { UnstructuredMesh(pugi::xml_node node); UnstructuredMesh(const std::string& filename); + static const std::string mesh_type; + virtual std::string get_mesh_type() const override; + // Overridden Methods - void - surface_bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins) const override; + + void surface_bins_crossed(Position r0, Position r1, const Direction& u, + vector& bins) const override; void to_hdf5(hid_t group) const override; @@ -339,19 +628,50 @@ class UnstructuredMesh : public Mesh { //! \return The centroid of the bin virtual Position centroid(int bin) const = 0; - //! Get the volume of a mesh bin + //! Get the number of vertices in the mesh // - //! \param[in] bin Bin to return the volume for - //! \return Volume of the bin - virtual double volume(int bin) const = 0; + //! \return Number of vertices + virtual int n_vertices() const = 0; + + //! Retrieve a vertex of the mesh + // + //! \param[in] vertex ID + //! \return vertex coordinates + virtual Position vertex(int id) const = 0; + + //! Retrieve connectivity of a mesh element + // + //! \param[in] element ID + //! \return element connectivity as IDs of the vertices + virtual std::vector connectivity(int id) const = 0; //! Get the library used for this unstructured mesh virtual std::string library() const = 0; // Data members - bool output_ {true}; //!< Write tallies onto the unstructured mesh at the end of a run + bool output_ { + true}; //!< Write tallies onto the unstructured mesh at the end of a run std::string filename_; //!< Path to unstructured mesh file + ElementType element_type(int bin) const; + +protected: + //! Set the length multiplier to apply to each point in the mesh + void set_length_multiplier(const double length_multiplier); + + //! Sample barycentric coordinates given a seed and the vertex positions and + //! return the sampled position + // + //! \param[in] coords Coordinates of the tetrahedron + //! \param[in] seed Random number generation seed + //! \return Sampled position within the tetrahedron + Position sample_tet(std::array coords, uint64_t* seed) const; + + // Data members + double length_multiplier_ { + -1.0}; //!< Multiplicative factor applied to mesh coordinates + std::string options_; //!< Options for search data structures + private: //! Setup method for the mesh. Builds data structures, //! sets up element mapping, creates bounding boxes, etc. @@ -365,16 +685,20 @@ class MOABMesh : public UnstructuredMesh { // Constructors MOABMesh() = default; MOABMesh(pugi::xml_node); - MOABMesh(const std::string& filename); + MOABMesh(const std::string& filename, double length_multiplier = 1.0); + MOABMesh(std::shared_ptr external_mbi); + + static const std::string mesh_lib_type; // Overridden Methods - void - bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins, - vector& lengths) const override; + //! Perform any preparation needed to support use in mesh filters + void prepare_for_tallies() override; + + Position sample_element(int32_t bin, uint64_t* seed) const override; + + void bins_crossed(Position r0, Position r1, const Direction& u, + vector& bins, vector& lengths) const override; int get_bin(Position r) const override; @@ -382,9 +706,8 @@ class MOABMesh : public UnstructuredMesh { int n_surface_bins() const override; - std::pair, vector> - plot(Position plot_ll, - Position plot_ur) const override; + std::pair, vector> plot( + Position plot_ll, Position plot_ur) const override; std::string library() const override; @@ -395,23 +718,34 @@ class MOABMesh : public UnstructuredMesh { void remove_scores() override; //! Set data for a score - void set_score_data(const std::string& score, - const vector& values, - const vector& std_dev) override; + void set_score_data(const std::string& score, const vector& values, + const vector& std_dev) override; //! Write the mesh with any current tally data void write(const std::string& base_filename) const override; Position centroid(int bin) const override; + int n_vertices() const override; + + Position vertex(int id) const override; + + std::vector connectivity(int id) const override; + + //! Get the volume of a mesh bin + // + //! \param[in] bin Bin to return the volume for + //! \return Volume of the bin double volume(int bin) const override; private: - void initialize() override; // Methods + //! Create the MOAB interface pointer + void create_interface(); + //! Find all intersections with faces of the mesh. // //! \param[in] start Staring location @@ -434,8 +768,9 @@ class MOABMesh : public UnstructuredMesh { moab::EntityHandle get_tet(const Position& r) const; //! Return the containing tet given a position - moab::EntityHandle get_tet(const moab::CartVect& r) const { - return get_tet(Position(r[0], r[1], r[2])); + moab::EntityHandle get_tet(const moab::CartVect& r) const + { + return get_tet(Position(r[0], r[1], r[2])); }; //! Check for point containment within a tet; uses @@ -444,8 +779,7 @@ class MOABMesh : public UnstructuredMesh { //! \param[in] r Position to check //! \param[in] MOAB terahedron to check //! \return True if r is inside, False if r is outside - bool point_in_tet(const moab::CartVect& r, - moab::EntityHandle tet) const; + bool point_in_tet(const moab::CartVect& r, moab::EntityHandle tet) const; //! Compute barycentric coordinate data for all tetrahedra //! in the mesh. @@ -466,6 +800,9 @@ class MOABMesh : public UnstructuredMesh { //! \return MOAB EntityHandle of tet moab::EntityHandle get_ent_handle_from_bin(int bin) const; + //! Get a vertex index into the global range from a handle + int get_vert_idx_from_handle(moab::EntityHandle vert) const; + //! Get the bin for a given mesh cell index // //! \param[in] idx Index of the mesh cell. @@ -496,14 +833,14 @@ class MOABMesh : public UnstructuredMesh { // //! \param[in] score Name of the score //! \return The MOAB value and error tag handles, respectively - std::pair - get_score_tags(std::string score) const; + std::pair get_score_tags(std::string score) const; // Data members - moab::Range ehs_; //!< Range of tetrahedra EntityHandle's in the mesh - moab::EntityHandle tetset_; //!< EntitySet containing all tetrahedra + moab::Range ehs_; //!< Range of tetrahedra EntityHandle's in the mesh + moab::Range verts_; //!< Range of vertex EntityHandle's in the mesh + moab::EntityHandle tetset_; //!< EntitySet containing all tetrahedra moab::EntityHandle kdtree_root_; //!< Root of the MOAB KDTree - unique_ptr mbi_; //!< MOAB instance + std::shared_ptr mbi_; //!< MOAB instance unique_ptr kdtree_; //!< MOAB KDTree instance vector baryc_data_; //!< Barycentric data for tetrahedra vector tag_names_; //!< Names of score tags added to the mesh @@ -517,14 +854,16 @@ class LibMesh : public UnstructuredMesh { public: // Constructors LibMesh(pugi::xml_node node); - LibMesh(const std::string& filename); + LibMesh(const std::string& filename, double length_multiplier = 1.0); + LibMesh(libMesh::MeshBase& input_mesh, double length_multiplier = 1.0); + + static const std::string mesh_lib_type; // Overridden Methods - void bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins, - vector& lengths) const override; + void bins_crossed(Position r0, Position r1, const Direction& u, + vector& bins, vector& lengths) const override; + + Position sample_element(int32_t bin, uint64_t* seed) const override; int get_bin(Position r) const override; @@ -532,9 +871,8 @@ class LibMesh : public UnstructuredMesh { int n_surface_bins() const override; - std::pair, vector> - plot(Position plot_ll, - Position plot_ur) const override; + std::pair, vector> plot( + Position plot_ll, Position plot_ur) const override; std::string library() const override; @@ -542,19 +880,30 @@ class LibMesh : public UnstructuredMesh { void remove_scores() override; - void set_score_data(const std::string& var_name, - const vector& values, - const vector& std_dev) override; + void set_score_data(const std::string& var_name, const vector& values, + const vector& std_dev) override; void write(const std::string& base_filename) const override; Position centroid(int bin) const override; + int n_vertices() const override; + + Position vertex(int id) const override; + + std::vector connectivity(int id) const override; + + //! Get the volume of a mesh bin + // + //! \param[in] bin Bin to return the volume for + //! \return Volume of the bin double volume(int bin) const override; -private: + libMesh::MeshBase* mesh_ptr() const { return m_; }; +private: void initialize() override; + void set_mesh_pointer_from_filename(const std::string& filename); // Methods @@ -565,15 +914,23 @@ class LibMesh : public UnstructuredMesh { int get_bin_from_element(const libMesh::Elem* elem) const; // Data members - unique_ptr m_; //!< pointer to the libMesh mesh instance + unique_ptr unique_m_ = + nullptr; //!< pointer to the libMesh MeshBase instance, only used if mesh is + //!< created inside OpenMC + libMesh::MeshBase* m_; //!< pointer to libMesh MeshBase instance, always set + //!< during intialization vector> pl_; //!< per-thread point locators unique_ptr - equation_systems_; //!< pointer to the equation systems of the mesh - std::string eq_system_name_; //!< name of the equation system holding OpenMC results - std::unordered_map variable_map_; //!< mapping of variable names (tally scores) to libMesh variable numbers + equation_systems_; //!< pointer to the equation systems of the mesh + std::string + eq_system_name_; //!< name of the equation system holding OpenMC results + std::unordered_map + variable_map_; //!< mapping of variable names (tally scores) to libMesh + //!< variable numbers libMesh::BoundingBox bbox_; //!< bounding box of the mesh - libMesh::dof_id_type first_element_id_; //!< id of the first element in the mesh + libMesh::dof_id_type + first_element_id_; //!< id of the first element in the mesh }; #endif diff --git a/include/openmc/message_passing.h b/include/openmc/message_passing.h index 82b27a77900..a1641a9069e 100644 --- a/include/openmc/message_passing.h +++ b/include/openmc/message_passing.h @@ -1,22 +1,38 @@ #ifndef OPENMC_MESSAGE_PASSING_H #define OPENMC_MESSAGE_PASSING_H +#include + #ifdef OPENMC_MPI #include #endif +#include "openmc/vector.h" + namespace openmc { namespace mpi { - extern int rank; - extern int n_procs; - extern bool master; +extern int rank; +extern int n_procs; +extern bool master; #ifdef OPENMC_MPI - extern MPI_Datatype source_site; - extern MPI_Comm intracomm; +extern MPI_Datatype source_site; +extern MPI_Comm intracomm; #endif +// Calculates global indices of the bank particles +// across all ranks using a parallel scan. This is used to write +// the surface source file in parallel runs. It will probably +// be used in the future for other types of bank like particles +// in flight used to kick off transient simulations. +// +// More abstractly, this just takes a number from each MPI rank, +// and returns a vector which is the exclusive parallel scan across +// all of those numbers, having a length of the number of MPI ranks +// plus one. +vector calculate_parallel_index_vector(int64_t size); + } // namespace mpi } // namespace openmc diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index bfa1200e86d..3fb0608104f 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -16,175 +16,174 @@ namespace openmc { -//============================================================================== -// Cache contains the cached data for an MGXS object -//============================================================================== - -struct CacheData { - double sqrtkT; // last temperature corresponding to t - int t; // temperature index - int a; // angle index - // last angle that corresponds to a - double u; - double v; - double w; -}; - //============================================================================== // MGXS contains the mgxs data for a nuclide/material //============================================================================== class Mgxs { - private: - - xt::xtensor kTs; // temperature in eV (k * T) - AngleDistributionType scatter_format; // flag for if this is legendre, histogram, or tabular - int num_groups; // number of energy groups - int num_delayed_groups; // number of delayed neutron groups - vector xs; // Cross section data - // MGXS Incoming Flux Angular grid information - bool is_isotropic; // used to skip search for angle indices if isotropic - int n_pol; - int n_azi; - vector polar; - vector azimuthal; - - //! \brief Initializes the Mgxs object metadata - //! - //! @param in_name Name of the object. - //! @param in_awr atomic-weight ratio. - //! @param in_kTs temperatures (in units of eV) that data is available. - //! @param in_fissionable Is this item fissionable or not. - //! @param in_scatter_format Denotes whether Legendre, Tabular, or - //! Histogram scattering is used. - //! @param in_is_isotropic Is this an isotropic or angular with respect to - //! the incoming particle. - //! @param in_polar Polar angle grid. - //! @param in_azimuthal Azimuthal angle grid. - void init(const std::string& in_name, double in_awr, - const vector& in_kTs, bool in_fissionable, - AngleDistributionType in_scatter_format, bool in_is_isotropic, - const vector& in_polar, const vector& in_azimuthal); - - //! \brief Initializes the Mgxs object metadata from the HDF5 file - //! - //! @param xs_id HDF5 group id for the cross section data. - //! @param temperature Temperatures to read. - //! @param temps_to_read Resultant list of temperatures in the library - //! to read which correspond to the requested temperatures. - //! @param order_dim Resultant dimensionality of the scattering order. - void metadata_from_hdf5(hid_t xs_id, const vector& temperature, - vector& temps_to_read, int& order_dim); - - //! \brief Performs the actual act of combining the microscopic data for a - //! single temperature. - //! - //! @param micros Microscopic objects to combine. - //! @param scalars Scalars to multiply the microscopic data by. - //! @param micro_ts The temperature index of the microscopic objects that - //! corresponds to the temperature of interest. - //! @param this_t The temperature index of the macroscopic object. - void combine(const vector& micros, const vector& scalars, - const vector& micro_ts, int this_t); - - //! \brief Checks to see if this and that are able to be combined - //! - //! This comparison is used when building macroscopic cross sections - //! from microscopic cross sections. - //! @param that The other Mgxs to compare to this one. - //! @return True if they can be combined, False otherwise. - bool equiv(const Mgxs& that); - - public: - - std::string name; // name of dataset, e.g., UO2 - double awr; // atomic weight ratio - bool fissionable; // Is this fissionable - vector cache; // index and data cache - - Mgxs() = default; - - //! \brief Constructor that loads the Mgxs object from the HDF5 file - //! - //! @param xs_id HDF5 group id for the cross section data. - //! @param temperature Temperatures to read. - //! @param num_group number of energy groups - //! @param num_delay number of delayed groups - Mgxs(hid_t xs_id, const vector& temperature, int num_group, - int num_delay); - - //! \brief Constructor that initializes and populates all data to build a - //! macroscopic cross section from microscopic cross sections. - //! - //! @param in_name Name of the object. - //! @param mat_kTs temperatures (in units of eV) that data is needed. - //! @param micros Microscopic objects to combine. - //! @param atom_densities Atom densities of those microscopic quantities. - //! @param num_group number of energy groups - //! @param num_delay number of delayed groups - Mgxs(const std::string& in_name, const vector& mat_kTs, - const vector& micros, const vector& atom_densities, - int num_group, int num_delay); - - //! \brief Provides a cross section value given certain parameters - //! - //! @param xstype Type of cross section requested, according to the - //! enumerated constants. - //! @param gin Incoming energy group. - //! @param gout Outgoing energy group; use nullptr if irrelevant, or if a - //! sum is requested. - //! @param mu Cosine of the change-in-angle, for scattering quantities; - //! use nullptr if irrelevant. - //! @param dg delayed group index; use nullptr if irrelevant. - //! @return Requested cross section value. - double - get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, - const int* dg); - - inline double - get_xs(MgxsType xstype, int gin) - {return get_xs(xstype, gin, nullptr, nullptr, nullptr);} - - - //! \brief Samples the fission neutron energy and if prompt or delayed. - //! - //! @param gin Incoming energy group. - //! @param dg Sampled delayed group index. - //! @param gout Sampled outgoing energy group. - //! @param seed Pseudorandom seed pointer - void - sample_fission_energy(int gin, int& dg, int& gout, uint64_t* seed); - - //! \brief Samples the outgoing energy and angle from a scatter event. - //! - //! @param gin Incoming energy group. - //! @param gout Sampled outgoing energy group. - //! @param mu Sampled cosine of the change-in-angle. - //! @param wgt Weight of the particle to be adjusted. - //! @param seed Pseudorandom seed pointer. - void - sample_scatter(int gin, int& gout, double& mu, double& wgt, uint64_t* seed); - - //! \brief Calculates cross section quantities needed for tracking. - //! - //! @param p The particle whose attributes set which MGXS to get. - void - calculate_xs(Particle& p); - - //! \brief Sets the temperature index in cache given a temperature - //! - //! @param sqrtkT Temperature of the material. - void - set_temperature_index(double sqrtkT); - - //! \brief Sets the angle index in cache given a direction - //! - //! @param u Incoming particle direction. - void - set_angle_index(Direction u); - - //! \brief Provide const access to list of XsData held by this - const vector& get_xsdata() const { return xs; } +private: + xt::xtensor kTs; // temperature in eV (k * T) + AngleDistributionType + scatter_format; // flag for if this is legendre, histogram, or tabular + int num_groups; // number of energy groups + int num_delayed_groups; // number of delayed neutron groups + vector xs; // Cross section data + // MGXS Incoming Flux Angular grid information + int n_pol; + int n_azi; + vector polar; + vector azimuthal; + + //! \brief Initializes the Mgxs object metadata + //! + //! @param in_name Name of the object. + //! @param in_awr atomic-weight ratio. + //! @param in_kTs temperatures (in units of eV) that data is available. + //! @param in_fissionable Is this item fissionable or not. + //! @param in_scatter_format Denotes whether Legendre, Tabular, or + //! Histogram scattering is used. + //! @param in_is_isotropic Is this an isotropic or angular with respect to + //! the incoming particle. + //! @param in_polar Polar angle grid. + //! @param in_azimuthal Azimuthal angle grid. + void init(const std::string& in_name, double in_awr, + const vector& in_kTs, bool in_fissionable, + AngleDistributionType in_scatter_format, bool in_is_isotropic, + const vector& in_polar, const vector& in_azimuthal); + + //! \brief Initializes the Mgxs object metadata from the HDF5 file + //! + //! @param xs_id HDF5 group id for the cross section data. + //! @param temperature Temperatures to read. + //! @param temps_to_read Resultant list of temperatures in the library + //! to read which correspond to the requested temperatures. + //! @param order_dim Resultant dimensionality of the scattering order. + void metadata_from_hdf5(hid_t xs_id, const vector& temperature, + vector& temps_to_read, int& order_dim); + + //! \brief Performs the actual act of combining the microscopic data for a + //! single temperature. + //! + //! @param micros Microscopic objects to combine. + //! @param scalars Scalars to multiply the microscopic data by. + //! @param micro_ts The temperature index of the microscopic objects that + //! corresponds to the temperature of interest. + //! @param this_t The temperature index of the macroscopic object. + void combine(const vector& micros, const vector& scalars, + const vector& micro_ts, int this_t); + + //! \brief Checks to see if this and that are able to be combined + //! + //! This comparison is used when building macroscopic cross sections + //! from microscopic cross sections. + //! @param that The other Mgxs to compare to this one. + //! @return True if they can be combined, False otherwise. + bool equiv(const Mgxs& that); + +public: + std::string name; // name of dataset, e.g., UO2 + double awr; // atomic weight ratio + bool fissionable; // Is this fissionable + bool is_isotropic { + true}; // used to skip search for angle indices if isotropic + + Mgxs() = default; + + //! \brief Constructor that loads the Mgxs object from the HDF5 file + //! + //! @param xs_id HDF5 group id for the cross section data. + //! @param temperature Temperatures to read. + //! @param num_group number of energy groups + //! @param num_delay number of delayed groups + Mgxs(hid_t xs_id, const vector& temperature, int num_group, + int num_delay); + + //! \brief Constructor that initializes and populates all data to build a + //! macroscopic cross section from microscopic cross sections. + //! + //! @param in_name Name of the object. + //! @param mat_kTs temperatures (in units of eV) that data is needed. + //! @param micros Microscopic objects to combine. + //! @param atom_densities Atom densities of those microscopic quantities. + //! @param num_group number of energy groups + //! @param num_delay number of delayed groups + Mgxs(const std::string& in_name, const vector& mat_kTs, + const vector& micros, const vector& atom_densities, + int num_group, int num_delay); + + //! \brief Provides a cross section value given certain parameters + //! + //! @param xstype Type of cross section requested, according to the + //! enumerated constants. + //! @param gin Incoming energy group. + //! @param gout Outgoing energy group; use nullptr if irrelevant, or if a + //! sum is requested. + //! @param mu Cosine of the change-in-angle, for scattering quantities; + //! use nullptr if irrelevant. + //! @param dg delayed group index; use nullptr if irrelevant. + //! @param t Temperature index. + //! @param a Angle index. + //! @return Requested cross section value. + double get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, + const int* dg, int t, int a); + + inline double get_xs(MgxsType xstype, int gin, int t, int a) + { + return get_xs(xstype, gin, nullptr, nullptr, nullptr, t, a); + } + + //! \brief Samples the fission neutron energy and if prompt or delayed. + //! + //! @param gin Incoming energy group. + //! @param dg Sampled delayed group index. + //! @param gout Sampled outgoing energy group. + //! @param seed Pseudorandom seed pointer + //! @param t Temperature index. + //! @param a Angle index. + void sample_fission_energy( + int gin, int& dg, int& gout, uint64_t* seed, int t, int a); + + //! \brief Samples the outgoing energy and angle from a scatter event. + //! + //! @param gin Incoming energy group. + //! @param gout Sampled outgoing energy group. + //! @param mu Sampled cosine of the change-in-angle. + //! @param wgt Weight of the particle to be adjusted. + //! @param seed Pseudorandom seed pointer. + //! @param t Temperature index. + //! @param a Angle index. + void sample_scatter( + int gin, int& gout, double& mu, double& wgt, uint64_t* seed, int t, int a); + + //! \brief Calculates cross section quantities needed for tracking. + //! + //! @param p The particle whose attributes set which MGXS to get. + void calculate_xs(Particle& p); + + //! \brief Sets the temperature index in the particle's cache. + //! + //! @param p Particle. + void set_temperature_index(Particle& p); + + //! \brief Gets the temperature index given a temperature. + //! + //! @param sqrtkT Temperature of the material. + //! @return The temperature index corresponding to sqrtkT. + int get_temperature_index(double sqrtkT) const; + + //! \brief Sets the angle index in the particle's cache. + //! + //! @param p Particle. + void set_angle_index(Particle& p); + + //! \brief Gets the angle index given a direction. + //! + //! @param u Incoming particle direction. + //! @return The angle index corresponding to u. + int get_angle_index(const Direction& u) const; + + //! \brief Provide const access to list of XsData held by this + const vector& get_xsdata() const { return xs; } }; } // namespace openmc diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index 57b5d9bf3ed..8bcdf6dc608 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -16,7 +16,6 @@ namespace openmc { class MgxsInterface { public: - MgxsInterface() = default; // Construct from path to cross sections file, as well as a list @@ -49,10 +48,10 @@ class MgxsInterface { int num_energy_groups_; int num_delayed_groups_; - vector xs_names_; // available names in HDF5 file - vector xs_to_read_; // XS which appear in materials - vector> xs_temps_to_read_; // temperatures used - std::string cross_sections_path_; // path to MGXS h5 file + vector xs_names_; // available names in HDF5 file + vector xs_to_read_; // XS which appear in materials + vector> xs_temps_to_read_; // temperatures used + std::string cross_sections_path_; // path to MGXS h5 file vector nuclides_; vector macro_xs_; vector energy_bins_; @@ -62,7 +61,7 @@ class MgxsInterface { }; namespace data { - extern MgxsInterface mg; +extern MgxsInterface mg; } // Puts available XS in MGXS file to globals so that when diff --git a/include/openmc/ncrystal_interface.h b/include/openmc/ncrystal_interface.h new file mode 100644 index 00000000000..5a3882df9c3 --- /dev/null +++ b/include/openmc/ncrystal_interface.h @@ -0,0 +1,94 @@ +#ifndef OPENMC_NCRYSTAL_INTERFACE_H +#define OPENMC_NCRYSTAL_INTERFACE_H + +#ifdef NCRYSTAL +#include "NCrystal/NCRNG.hh" +#include "NCrystal/NCrystal.hh" +#endif + +#include "openmc/particle.h" + +#include // for uint64_t +#include // for numeric_limits +#include + +namespace openmc { + +//============================================================================== +// Constants +//============================================================================== + +extern "C" const bool NCRYSTAL_ENABLED; + +//! Energy in [eV] to switch between NCrystal and ENDF +constexpr double NCRYSTAL_MAX_ENERGY {5.0}; + +//============================================================================== +// Wrapper class an NCrystal material +//============================================================================== + +class NCrystalMat { +public: + //---------------------------------------------------------------------------- + // Constructors + NCrystalMat() = default; + explicit NCrystalMat(const std::string& cfg); + + //---------------------------------------------------------------------------- + // Methods + +#ifdef NCRYSTAL + //! Return configuration string + std::string cfg() const; + + //! Get cross section from NCrystal material + // + //! \param[in] p Particle object + //! \return Cross section in [b] + double xs(const Particle& p) const; + + // Process scattering event + // + //! \param[in] p Particle object + void scatter(Particle& p) const; + + //! Whether the object holds a valid NCrystal material + operator bool() const; +#else + + //---------------------------------------------------------------------------- + // Trivial methods when compiling without NCRYSTAL + std::string cfg() const + { + return ""; + } + double xs(const Particle& p) const + { + return -1.0; + } + void scatter(Particle& p) const {} + operator bool() const + { + return false; + } +#endif + +private: + //---------------------------------------------------------------------------- + // Data members (only present when compiling with NCrystal support) +#ifdef NCRYSTAL + std::string cfg_; //!< NCrystal configuration string + std::shared_ptr + ptr_; //!< Pointer to NCrystal material object +#endif +}; + +//============================================================================== +// Functions +//============================================================================== + +void ncrystal_update_micro(double xs, NuclideMicroXS& micro); + +} // namespace openmc + +#endif // OPENMC_NCRYSTAL_INTERFACE_H diff --git a/include/openmc/neighbor_list.h b/include/openmc/neighbor_list.h index f6142101d89..f781424ff59 100644 --- a/include/openmc/neighbor_list.h +++ b/include/openmc/neighbor_list.h @@ -18,8 +18,7 @@ namespace openmc { //! number of threads can safely read data without locks or reference counting. //============================================================================== -class NeighborList -{ +class NeighborList { public: using value_type = int32_t; using const_iterator = std::forward_list::const_iterator; @@ -43,7 +42,8 @@ class NeighborList if (!list_.empty()) { auto it1 = list_.cbegin(); auto it2 = ++list_.cbegin(); - while (it2 != list_.cend()) it1 = it2++; + while (it2 != list_.cend()) + it1 = it2++; list_.insert_after(it1, new_elem); } else { list_.push_front(new_elem); @@ -52,12 +52,9 @@ class NeighborList } } - const_iterator cbegin() const - {return list_.cbegin();} - - const_iterator cend() const - {return list_.cend();} + const_iterator cbegin() const { return list_.cbegin(); } + const_iterator cend() const { return list_.cend(); } private: std::forward_list list_; diff --git a/include/openmc/nuclide.h b/include/openmc/nuclide.h index 6067c53a0de..1cc9d297287 100644 --- a/include/openmc/nuclide.h +++ b/include/openmc/nuclide.h @@ -7,7 +7,7 @@ #include #include // for pair -#include +#include #include #include "openmc/array.h" @@ -29,6 +29,7 @@ namespace openmc { class Nuclide { public: + //============================================================================ // Types, aliases using EmissionMode = ReactionProduct::EmissionMode; struct EnergyGrid { @@ -36,19 +37,33 @@ class Nuclide { vector energy; }; + //============================================================================ // Constructors/destructors Nuclide(hid_t group, const vector& temperature); ~Nuclide(); + //============================================================================ + // Methods + //! Initialize logarithmic grid for energy searches void init_grid(); + //! Calculate microscopic cross sections + // + //! \param[in] i_sab Index in data::thermal_scatt + //! \param[in] i_log_union Log-grid search index + //! \param[in] sab_frac S(a,b) table fraction + //! \param[in,out] p Particle object void calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle& p); + //! Calculate thermal scattering cross section + // + //! \param[in] i_sab Index in data::thermal_scatt + //! \param[in] sab_frac S(a,b) table fraction + //! \param[in,out] p Particle object void calculate_sab_xs(int i_sab, double sab_frac, Particle& p); - // Methods - double nu(double E, EmissionMode mode, int group=0) const; + double nu(double E, EmissionMode mode, int group = 0) const; void calculate_elastic_xs(Particle& p) const; //! Determines the microscopic 0K elastic cross section at a trial relative @@ -66,15 +81,16 @@ class Nuclide { //! \param[in] energy Energy group boundaries in [eV] //! \param[in] flux Flux in each energy group (not normalized per eV) //! \return Reaction rate - double collapse_rate(int MT, double temperature, gsl::span energy, - gsl::span flux) const; + double collapse_rate(int MT, double temperature, + gsl::span energy, gsl::span flux) const; + //============================================================================ // Data members std::string name_; //!< Name of nuclide, e.g. "U235" - int Z_; //!< Atomic number - int A_; //!< Mass number - int metastable_; //!< Metastable state - double awr_; //!< Atomic weight ratio + int Z_; //!< Atomic number + int A_; //!< Mass number + int metastable_; //!< Metastable state + double awr_; //!< Atomic weight ratio gsl::index index_; //!< Index in the nuclides array // Temperature dependent cross section data @@ -86,11 +102,11 @@ class Nuclide { unique_ptr multipole_; // Fission data - bool fissionable_ {false}; //!< Whether nuclide is fissionable + bool fissionable_ {false}; //!< Whether nuclide is fissionable bool has_partial_fission_ {false}; //!< has partial fission reactions? vector fission_rx_; //!< Fission reactions - int n_precursor_ {0}; //!< Number of delayed neutron precursors - unique_ptr total_nu_; //!< Total neutron yield + int n_precursor_ {0}; //!< Number of delayed neutron precursors + unique_ptr total_nu_; //!< Total neutron yield unique_ptr fission_q_prompt_; //!< Prompt fission energy release unique_ptr fission_q_recov_; //!< Recoverable fission energy release @@ -115,7 +131,8 @@ class Nuclide { vector index_inelastic_scatter_; private: - void create_derived(const Function1D* prompt_photons, const Function1D* delayed_photons); + void create_derived( + const Function1D* prompt_photons, const Function1D* delayed_photons); //! Determine temperature index and interpolation factor // diff --git a/include/openmc/openmp_interface.h b/include/openmc/openmp_interface.h index 4032ab1d4ca..fe517415baa 100644 --- a/include/openmc/openmp_interface.h +++ b/include/openmc/openmp_interface.h @@ -7,43 +7,78 @@ namespace openmc { +//============================================================================== +//! Accessor functions related to number of threads and thread number +//============================================================================== +inline int num_threads() +{ +#ifdef _OPENMP + return omp_get_max_threads(); +#else + return 1; +#endif +} + +inline int thread_num() +{ +#ifdef _OPENMP + return omp_get_thread_num(); +#else + return 0; +#endif +} + //============================================================================== //! An object used to prevent concurrent access to a piece of data. // //! This type meets the C++ "Lockable" requirements. //============================================================================== -class OpenMPMutex -{ +class OpenMPMutex { public: OpenMPMutex() { - #ifdef _OPENMP - omp_init_lock(&mutex_); - #endif +#ifdef _OPENMP + omp_init_lock(&mutex_); +#endif } ~OpenMPMutex() { - #ifdef _OPENMP - omp_destroy_lock(&mutex_); - #endif +#ifdef _OPENMP + omp_destroy_lock(&mutex_); +#endif } - // Mutexes cannot be copied. We need to explicitly delete the copy - // constructor and copy assignment operator to ensure the compiler doesn't - // "help" us by implicitly trying to copy the underlying mutexes. - OpenMPMutex(const OpenMPMutex&) = delete; - OpenMPMutex& operator= (const OpenMPMutex&) = delete; + // omp_lock_t objects cannot be deep copied, they can only be shallow + // copied. Thus, while shallow copying of an omp_lock_t object is + // completely valid (provided no race conditions exist), true copying + // of an OpenMPMutex object is not valid due to the action of the + // destructor. However, since locks are fungible, we can simply replace + // copying operations with default construction. This allows storage of + // OpenMPMutex objects within containers that may need to move/copy them + // (e.g., std::vector). It is left to the caller to understand that + // copying of OpenMPMutex does not produce two handles to the same mutex, + // rather, it produces two different mutexes. + + // Copy constructor + OpenMPMutex(const OpenMPMutex& other) { OpenMPMutex(); } + + // Copy assignment operator + OpenMPMutex& operator=(const OpenMPMutex& other) + { + OpenMPMutex(); + return *this; + } //! Lock the mutex. // //! This function blocks execution until the lock succeeds. void lock() { - #ifdef _OPENMP - omp_set_lock(&mutex_); - #endif +#ifdef _OPENMP + omp_set_lock(&mutex_); +#endif } //! Try to lock the mutex and indicate success. @@ -52,25 +87,25 @@ class OpenMPMutex //! the lock is unavailable. bool try_lock() noexcept { - #ifdef _OPENMP - return omp_test_lock(&mutex_); - #else - return true; - #endif +#ifdef _OPENMP + return omp_test_lock(&mutex_); +#else + return true; +#endif } //! Unlock the mutex. void unlock() noexcept { - #ifdef _OPENMP - omp_unset_lock(&mutex_); - #endif +#ifdef _OPENMP + omp_unset_lock(&mutex_); +#endif } private: - #ifdef _OPENMP - omp_lock_t mutex_; - #endif +#ifdef _OPENMP + omp_lock_t mutex_; +#endif }; } // namespace openmc diff --git a/include/openmc/output.h b/include/openmc/output.h index 2ebe2711f1e..1ece3de960c 100644 --- a/include/openmc/output.h +++ b/include/openmc/output.h @@ -40,6 +40,9 @@ void print_usage(); //! Display current version and copright/license information void print_version(); +//! Display compile flags employed, etc +void print_build_info(); + //! Display header listing what physical values will displayed void print_columns(); @@ -54,5 +57,29 @@ void print_results(); void write_tallies(); +void show_time(const char* label, double secs, int indent_level = 0); + } // namespace openmc #endif // OPENMC_OUTPUT_H + +////////////////////////////////////// +// Custom formatters +////////////////////////////////////// +namespace fmt { + +template +struct formatter> { + template + constexpr auto parse(ParseContext& ctx) + { + return ctx.begin(); + } + + template + auto format(const std::array& arr, FormatContext& ctx) + { + return format_to(ctx.out(), "({}, {})", arr[0], arr[1]); + } +}; + +} // namespace fmt diff --git a/include/openmc/particle.h b/include/openmc/particle.h index 0fda3d30799..e423880f87c 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -5,7 +5,6 @@ //! \brief Particle type #include -#include #include #include "openmc/constants.h" @@ -30,12 +29,20 @@ class Surface; class Particle : public ParticleData { public: - //========================================================================== // Constructors Particle() = default; + //========================================================================== + // Methods + + double speed() const; + + //! moves the particle by the distance length to its next location + //! \param length the distance the particle is moved + void move_distance(double length); + //! create a secondary particle // //! stores the current phase space attributes of the particle in the @@ -62,6 +69,10 @@ class Particle : public ParticleData { void event_revive_from_secondary(); void event_death(); + //! pulse-height recording + void pht_collision_energy(); + void pht_secondary_particles(); + //! Cross a surface and handle boundary conditions void cross_surface(); @@ -86,21 +97,26 @@ class Particle : public ParticleData { //! \param new_u The direction of the particle after translation/rotation. //! \param new_surface The signed index of the surface that the particle will //! reside on after translation/rotation. - void cross_periodic_bc(const Surface& surf, Position new_r, Direction new_u, - int new_surface); + void cross_periodic_bc( + const Surface& surf, Position new_r, Direction new_u, int new_surface); //! mark a particle as lost and create a particle restart file //! \param message A warning message to display - void mark_as_lost(const char* message); - - void mark_as_lost(const std::string& message) - {mark_as_lost(message.c_str());} - - void mark_as_lost(const std::stringstream& message) - {mark_as_lost(message.str());} + virtual void mark_as_lost(const char* message) override; + using GeometryState::mark_as_lost; //! create a particle restart HDF5 file void write_restart() const; + + //! Update microscopic cross section cache + // + //! \param[in] i_nuclide Index in data::nuclides + //! \param[in] i_grid Index on log union grid + //! \param[in] i_sab Index in data::thermal_scatt + //! \param[in] sab_frac S(a,b) table fraction + //! \param[in] ncrystal_xs Thermal scattering xs from NCrystal + void update_neutron_xs(int i_nuclide, int i_grid = C_NONE, int i_sab = C_NONE, + double sab_frac = 0.0, double ncrystal_xs = -1.0); }; //============================================================================ diff --git a/include/openmc/particle_data.h b/include/openmc/particle_data.h index f871e8032ae..5c765e2e605 100644 --- a/include/openmc/particle_data.h +++ b/include/openmc/particle_data.h @@ -44,14 +44,33 @@ struct SourceSite { Position r; Direction u; double E; - double wgt; - int delayed_group; - int surf_id; + double time {0.0}; + double wgt {1.0}; + int delayed_group {0}; + int surf_id {0}; ParticleType particle; int64_t parent_id; int64_t progeny_id; }; +//! State of a particle used for particle track files +struct TrackState { + Position r; //!< Position in [cm] + Direction u; //!< Direction + double E; //!< Energy in [eV] + double time {0.0}; //!< Time in [s] + double wgt {1.0}; //!< Weight + int cell_id; //!< Cell ID + int cell_instance; //!< Cell instance + int material_id {-1}; //!< Material ID (default value indicates void) +}; + +//! Full history of a single particle's track states +struct TrackStateHistory { + ParticleType particle; + std::vector states; +}; + //! Saved ("banked") state of a particle, for nu-fission tallying struct NuBank { double E; //!< particle energy @@ -148,6 +167,18 @@ struct MacroXS { double pair_production; //!< macroscopic pair production xs }; +//============================================================================== +// Cache contains the cached data for an MGXS object +//============================================================================== + +struct CacheDataMG { + int material {-1}; //!< material index + double sqrtkT; //!< last temperature corresponding to t + int t {0}; //!< temperature index + int a {0}; //!< angle index + Direction u; //!< angle that corresponds to a +}; + //============================================================================== // Information about nearest boundary crossing //============================================================================== @@ -160,6 +191,162 @@ struct BoundaryInfo { lattice_translation {}; //!< which way lattice indices will change }; +/* + * Contains all geometry state information for a particle. + */ +class GeometryState { +public: + GeometryState(); + + /* + * GeometryState does not store any ID info, so give some reasonable behavior + * here. The Particle class redefines this. This is only here for the error + * reporting behavior that occurs in geometry.cpp. The explanation for + * mark_as_lost is the same. + */ + virtual void mark_as_lost(const char* message); + void mark_as_lost(const std::string& message); + void mark_as_lost(const std::stringstream& message); + + // resets all coordinate levels for the particle + void clear() + { + for (auto& level : coord_) + level.reset(); + n_coord_ = 1; + } + + // Initialize all internal state from position and direction + void init_from_r_u(Position r_a, Direction u_a) + { + clear(); + surface() = 0; + material() = C_NONE; + r() = r_a; + u() = u_a; + r_last_current() = r_a; + r_last() = r_a; + u_last() = u_a; + } + + // Unique ID. This is not geometric info, but the + // error reporting in geometry.cpp requires this. + // We could save this to implement it in Particle, + // but that would require virtuals. + int64_t& id() { return id_; } + const int64_t& id() const { return id_; } + + // Number of current coordinate levels + int& n_coord() { return n_coord_; } + const int& n_coord() const { return n_coord_; } + + // Offset for distributed properties + int& cell_instance() { return cell_instance_; } + const int& cell_instance() const { return cell_instance_; } + + // Coordinates for all nesting levels + LocalCoord& coord(int i) { return coord_[i]; } + const LocalCoord& coord(int i) const { return coord_[i]; } + const vector& coord() const { return coord_; } + + // Innermost universe nesting coordinates + LocalCoord& lowest_coord() { return coord_[n_coord_ - 1]; } + const LocalCoord& lowest_coord() const { return coord_[n_coord_ - 1]; } + + // Last coordinates on all nesting levels, before crossing a surface + int& n_coord_last() { return n_coord_last_; } + const int& n_coord_last() const { return n_coord_last_; } + int& cell_last(int i) { return cell_last_[i]; } + const int& cell_last(int i) const { return cell_last_[i]; } + + // Coordinates at birth + Position& r_born() { return r_born_; } + const Position& r_born() const { return r_born_; } + + // Coordinates of last collision or reflective/periodic surface + // crossing for current tallies + Position& r_last_current() { return r_last_current_; } + const Position& r_last_current() const { return r_last_current_; } + + // Previous direction and spatial coordinates before a collision + Position& r_last() { return r_last_; } + const Position& r_last() const { return r_last_; } + Position& u_last() { return u_last_; } + const Position& u_last() const { return u_last_; } + + // Accessors for position in global coordinates + Position& r() { return coord_[0].r; } + const Position& r() const { return coord_[0].r; } + + // Accessors for position in local coordinates + Position& r_local() { return coord_[n_coord_ - 1].r; } + const Position& r_local() const { return coord_[n_coord_ - 1].r; } + + // Accessors for direction in global coordinates + Direction& u() { return coord_[0].u; } + const Direction& u() const { return coord_[0].u; } + + // Accessors for direction in local coordinates + Direction& u_local() { return coord_[n_coord_ - 1].u; } + const Direction& u_local() const { return coord_[n_coord_ - 1].u; } + + // Surface that the particle is on + int& surface() { return surface_; } + const int& surface() const { return surface_; } + + // Boundary information + BoundaryInfo& boundary() { return boundary_; } + +#ifdef DAGMC + // DagMC state variables + moab::DagMC::RayHistory& history() { return history_; } + Direction& last_dir() { return last_dir_; } +#endif + + // material of current and last cell + int& material() { return material_; } + const int& material() const { return material_; } + int& material_last() { return material_last_; } + const int& material_last() const { return material_last_; } + + // temperature of current and last cell + double& sqrtkT() { return sqrtkT_; } + const double& sqrtkT() const { return sqrtkT_; } + double& sqrtkT_last() { return sqrtkT_last_; } + +private: + int64_t id_ {-1}; //!< Unique ID + + int n_coord_ {1}; //!< number of current coordinate levels + int cell_instance_; //!< offset for distributed properties + vector coord_; //!< coordinates for all levels + + int n_coord_last_ {1}; //!< number of current coordinates + vector cell_last_; //!< coordinates for all levels + + Position r_born_; //!< coordinates at birth + Position r_last_current_; //!< coordinates of the last collision or + //!< reflective/periodic surface crossing for + //!< current tallies + Position r_last_; //!< previous coordinates + Direction u_last_; //!< previous direction coordinates + + int surface_ {0}; //!< index for surface particle is on + + BoundaryInfo boundary_; //!< Info about the next intersection + + int material_ {-1}; //!< index for current material + int material_last_ {-1}; //!< index for last material + + double sqrtkT_ {-1.0}; //!< sqrt(k_Boltzmann * temperature) in eV + double sqrtkT_last_ {0.0}; //!< last temperature + +#ifdef DAGMC + moab::DagMC::RayHistory history_; + Direction last_dir_; +#endif +}; + //============================================================================ //! Defines how particle data is laid out in memory //============================================================================ @@ -195,148 +382,112 @@ struct BoundaryInfo { * Algorithms.” Annals of Nuclear Energy 113 (March 2018): 506–18. * https://doi.org/10.1016/j.anucene.2017.11.032. */ -class ParticleData { - -public: - ParticleData(); - +class ParticleData : public GeometryState { private: //========================================================================== - // Data members (accessor methods are below) + // Data members -- see public: below for descriptions - // Cross section caches - vector neutron_xs_; //!< Microscopic neutron cross sections - vector photon_xs_; //!< Microscopic photon cross sections - MacroXS macro_xs_; //!< Macroscopic cross sections + vector neutron_xs_; + vector photon_xs_; + MacroXS macro_xs_; + CacheDataMG mg_xs_cache_; - int64_t id_; //!< Unique ID - ParticleType type_ {ParticleType::neutron}; //!< Particle type (n, p, e, etc.) + ParticleType type_ {ParticleType::neutron}; - int n_coord_ {1}; //!< number of current coordinate levels - int cell_instance_; //!< offset for distributed properties - vector coord_; //!< coordinates for all levels + double E_; + double E_last_; + int g_ {0}; + int g_last_; - // Particle coordinates before crossing a surface - int n_coord_last_ {1}; //!< number of current coordinates - vector cell_last_; //!< coordinates for all levels + double wgt_ {1.0}; + double mu_; + double time_ {0.0}; + double time_last_ {0.0}; + double wgt_last_ {1.0}; - // Energy data - double E_; //!< post-collision energy in eV - double E_last_; //!< pre-collision energy in eV - int g_ {0}; //!< post-collision energy group (MG only) - int g_last_; //!< pre-collision energy group (MG only) + bool fission_ {false}; + TallyEvent event_; + int event_nuclide_; + int event_mt_; + int delayed_group_ {0}; - // Other physical data - double wgt_ {1.0}; //!< particle weight - double mu_; //!< angle of scatter - bool alive_ {true}; //!< is particle alive? + int n_bank_ {0}; + int n_bank_second_ {0}; + double wgt_bank_ {0.0}; + int n_delayed_bank_[MAX_DELAYED_GROUPS]; - // Other physical data - Position r_last_current_; //!< coordinates of the last collision or - //!< reflective/periodic surface crossing for - //!< current tallies - Position r_last_; //!< previous coordinates - Direction u_last_; //!< previous direction coordinates - double wgt_last_ {1.0}; //!< pre-collision particle weight - double wgt_absorb_ {0.0}; //!< weight absorbed for survival biasing - - // What event took place - bool fission_ {false}; //!< did particle cause implicit fission - TallyEvent event_; //!< scatter, absorption - int event_nuclide_; //!< index in nuclides array - int event_mt_; //!< reaction MT - int delayed_group_ {0}; //!< delayed group - - // Post-collision physical data - int n_bank_ {0}; //!< number of fission sites banked - int n_bank_second_ {0}; //!< number of secondary particles banked - double wgt_bank_ {0.0}; //!< weight of fission sites banked - int n_delayed_bank_[MAX_DELAYED_GROUPS]; //!< number of delayed fission - //!< sites banked - - // Indices for various arrays - int surface_ {0}; //!< index for surface particle is on - int cell_born_ {-1}; //!< index for cell particle was born in - int material_ {-1}; //!< index for current material - int material_last_ {-1}; //!< index for last material + int cell_born_ {-1}; - // Boundary information - BoundaryInfo boundary_; + int n_collision_ {0}; - // Temperature of current cell - double sqrtkT_ {-1.0}; //!< sqrt(k_Boltzmann * temperature) in eV - double sqrtkT_last_ {0.0}; //!< last temperature - - // Statistical data - int n_collision_ {0}; //!< number of collisions - - // Track output bool write_track_ {false}; - // Current PRNG state - uint64_t seeds_[N_STREAMS]; // current seeds - int stream_; // current RNG stream + uint64_t seeds_[N_STREAMS]; + int stream_; - // Secondary particle bank vector secondary_bank_; - int64_t current_work_; // current work index + int64_t current_work_; - vector flux_derivs_; // for derivatives for this particle + vector flux_derivs_; - vector filter_matches_; // tally filter matches + vector filter_matches_; - vector> tracks_; // tracks for outputting to file + vector tracks_; - vector nu_bank_; // bank of most recently fissioned particles + vector nu_bank_; + + vector pht_storage_; - // Global tally accumulators double keff_tally_absorption_ {0.0}; double keff_tally_collision_ {0.0}; double keff_tally_tracklength_ {0.0}; double keff_tally_leakage_ {0.0}; - bool trace_ {false}; //!< flag to show debug information + bool trace_ {false}; - double collision_distance_; // distance to particle's next closest collision + double collision_distance_; - int n_event_ {0}; // number of events executed in this particle's history + int n_event_ {0}; -// DagMC state variables -#ifdef DAGMC - moab::DagMC::RayHistory history_; - Direction last_dir_; -#endif + int n_split_ {0}; + double ww_factor_ {0.0}; - int64_t n_progeny_ {0}; // Number of progeny produced by this particle + int64_t n_progeny_ {0}; public: + //---------------------------------------------------------------------------- + // Constructors + ParticleData(); + //========================================================================== // Methods and accessors - NuclideMicroXS& neutron_xs(int i) { return neutron_xs_[i]; } + // Cross section caches + NuclideMicroXS& neutron_xs(int i) + { + return neutron_xs_[i]; + } // Microscopic neutron cross sections const NuclideMicroXS& neutron_xs(int i) const { return neutron_xs_[i]; } + + // Microscopic photon cross sections ElementMicroXS& photon_xs(int i) { return photon_xs_[i]; } + + // Macroscopic cross sections MacroXS& macro_xs() { return macro_xs_; } const MacroXS& macro_xs() const { return macro_xs_; } - int64_t& id() { return id_; } - const int64_t& id() const { return id_; } + // Multigroup macroscopic cross sections + CacheDataMG& mg_xs_cache() { return mg_xs_cache_; } + const CacheDataMG& mg_xs_cache() const { return mg_xs_cache_; } + + // Particle type (n, p, e, gamma, etc) ParticleType& type() { return type_; } const ParticleType& type() const { return type_; } - int& n_coord() { return n_coord_; } - const int& n_coord() const { return n_coord_; } - int& cell_instance() { return cell_instance_; } - const int& cell_instance() const { return cell_instance_; } - LocalCoord& coord(int i) { return coord_[i]; } - const LocalCoord& coord(int i) const { return coord_[i]; } - - int& n_coord_last() { return n_coord_last_; } - const int& n_coord_last() const { return n_coord_last_; } - int& cell_last(int i) { return cell_last_[i]; } - const int& cell_last(int i) const { return cell_last_[i]; } - + // Current particle energy, energy before collision, + // and corresponding multigroup group indices. Energy + // units are eV. double& E() { return E_; } const double& E() const { return E_; } double& E_last() { return E_last_; } @@ -346,101 +497,118 @@ class ParticleData { int& g_last() { return g_last_; } const int& g_last() const { return g_last_; } + // Statistic weight of particle. Setting to zero + // indicates that the particle is dead. double& wgt() { return wgt_; } + double wgt() const { return wgt_; } + double& wgt_last() { return wgt_last_; } + const double& wgt_last() const { return wgt_last_; } + bool alive() const { return wgt_ != 0.0; } + + // Polar scattering angle after a collision double& mu() { return mu_; } const double& mu() const { return mu_; } - bool& alive() { return alive_; } - Position& r_last_current() { return r_last_current_; } - const Position& r_last_current() const { return r_last_current_; } - Position& r_last() { return r_last_; } - const Position& r_last() const { return r_last_; } - Position& u_last() { return u_last_; } - const Position& u_last() const { return u_last_; } - double& wgt_last() { return wgt_last_; } - const double& wgt_last() const { return wgt_last_; } - double& wgt_absorb() { return wgt_absorb_; } - const double& wgt_absorb() const { return wgt_absorb_; } + // Tracks the time of a particle as it traverses the problem. + // Units are seconds. + double& time() { return time_; } + const double& time() const { return time_; } + double& time_last() { return time_last_; } + const double& time_last() const { return time_last_; } - bool& fission() { return fission_; } + // What event took place, described in greater detail below TallyEvent& event() { return event_; } const TallyEvent& event() const { return event_; } - int& event_nuclide() { return event_nuclide_; } + bool& fission() { return fission_; } // true if implicit fission + int& event_nuclide() { return event_nuclide_; } // index of collision nuclide const int& event_nuclide() const { return event_nuclide_; } - int& event_mt() { return event_mt_; } - int& delayed_group() { return delayed_group_; } + int& event_mt() { return event_mt_; } // MT number of collision + int& delayed_group() { return delayed_group_; } // delayed group - int& n_bank() { return n_bank_; } - int& n_bank_second() { return n_bank_second_; } - double& wgt_bank() { return wgt_bank_; } - int* n_delayed_bank() { return n_delayed_bank_; } - int& n_delayed_bank(int i) { return n_delayed_bank_[i]; } + // Post-collision data + int& n_bank() { return n_bank_; } // number of banked fission sites + int& n_bank_second() + { + return n_bank_second_; + } // number of secondaries banked + double& wgt_bank() { return wgt_bank_; } // weight of banked fission sites + int* n_delayed_bank() + { + return n_delayed_bank_; + } // number of delayed fission sites + int& n_delayed_bank(int i) + { + return n_delayed_bank_[i]; + } // number of delayed fission sites - int& surface() { return surface_; } - const int& surface() const { return surface_; } + // Index of cell particle is born in int& cell_born() { return cell_born_; } const int& cell_born() const { return cell_born_; } - int& material() { return material_; } - const int& material() const { return material_; } - int& material_last() { return material_last_; } - - BoundaryInfo& boundary() { return boundary_; } - - double& sqrtkT() { return sqrtkT_; } - const double& sqrtkT() const { return sqrtkT_; } - double& sqrtkT_last() { return sqrtkT_last_; } + // index of the current and last material + // Total number of collisions suffered by particle int& n_collision() { return n_collision_; } const int& n_collision() const { return n_collision_; } + // whether this track is to be written bool& write_track() { return write_track_; } + + // RNG state uint64_t& seeds(int i) { return seeds_[i]; } uint64_t* seeds() { return seeds_; } int& stream() { return stream_; } + // secondary particle bank SourceSite& secondary_bank(int i) { return secondary_bank_[i]; } decltype(secondary_bank_)& secondary_bank() { return secondary_bank_; } + + // Current simulation work index int64_t& current_work() { return current_work_; } const int64_t& current_work() const { return current_work_; } + + // Used in tally derivatives double& flux_derivs(int i) { return flux_derivs_[i]; } const double& flux_derivs(int i) const { return flux_derivs_[i]; } + + // Matches of tallies decltype(filter_matches_)& filter_matches() { return filter_matches_; } FilterMatch& filter_matches(int i) { return filter_matches_[i]; } + + // Tracks to output to file decltype(tracks_)& tracks() { return tracks_; } + + // Bank of recently fissioned particles decltype(nu_bank_)& nu_bank() { return nu_bank_; } NuBank& nu_bank(int i) { return nu_bank_[i]; } + // Interim pulse height tally storage + vector& pht_storage() { return pht_storage_; } + + // Global tally accumulators double& keff_tally_absorption() { return keff_tally_absorption_; } double& keff_tally_collision() { return keff_tally_collision_; } double& keff_tally_tracklength() { return keff_tally_tracklength_; } double& keff_tally_leakage() { return keff_tally_leakage_; } + // Shows debug info bool& trace() { return trace_; } - double& collision_distance() { return collision_distance_; } - int& n_event() { return n_event_; } -#ifdef DAGMC - moab::DagMC::RayHistory& history() { return history_; } - Direction& last_dir() { return last_dir_; } -#endif - - int64_t& n_progeny() { return n_progeny_; } + // Distance to the next collision + double& collision_distance() { return collision_distance_; } - // Accessors for position in global coordinates - Position& r() { return coord_[0].r; } - const Position& r() const { return coord_[0].r; } + // Number of events particle has undergone + int& n_event() { return n_event_; } - // Accessors for position in local coordinates - Position& r_local() { return coord_[n_coord_ - 1].r; } - const Position& r_local() const { return coord_[n_coord_ - 1].r; } + // Number of times variance reduction has caused a particle split + int n_split() const { return n_split_; } + int& n_split() { return n_split_; } - // Accessors for direction in global coordinates - Direction& u() { return coord_[0].u; } - const Direction& u() const { return coord_[0].u; } + // Particle-specific factor for on-the-fly weight window adjustment + double ww_factor() const { return ww_factor_; } + double& ww_factor() { return ww_factor_; } - // Accessors for direction in local coordinates - Direction& u_local() { return coord_[n_coord_ - 1].u; } - const Direction& u_local() const { return coord_[n_coord_ - 1].u; } + // Number of progeny produced by this particle + int64_t& n_progeny() { return n_progeny_; } //! Gets the pointer to the particle's current PRN seed uint64_t* current_seed() { return seeds_ + stream_; } @@ -453,13 +621,8 @@ class ParticleData { micro.last_E = 0.0; } - //! resets all coordinate levels for the particle - void clear() - { - for (auto& level : coord_) - level.reset(); - n_coord_ = 1; - } + //! Get track information based on particle's current state + TrackState get_track_state() const; void zero_delayed_bank() { diff --git a/include/openmc/photon.h b/include/openmc/photon.h index ca8f75474d0..9901c8c6db5 100644 --- a/include/openmc/photon.h +++ b/include/openmc/photon.h @@ -6,9 +6,9 @@ #include "openmc/particle.h" #include "openmc/vector.h" -#include -#include #include "xtensor/xtensor.hpp" +#include +#include #include #include @@ -22,20 +22,21 @@ namespace openmc { class ElectronSubshell { public: + struct Transition { + int primary_subshell; //!< Index in shells_ of originating subshell + int secondary_subshell; //!< Index in shells_ of Auger electron subshell + double energy; //!< Energy of transition + double probability; //!< Probability of transition between subshells + }; + // Constructors - ElectronSubshell() { }; + ElectronSubshell() {}; - int index_subshell; //!< index in SUBSHELLS + int index_subshell; //!< index in SUBSHELLS int threshold; double n_electrons; double binding_energy; - xt::xtensor cross_section; - - // Transition data - int n_transitions; - xt::xtensor transition_subshells; - xt::xtensor transition_energy; - xt::xtensor transition_probability; + vector transitions; }; class PhotonInteraction { @@ -55,11 +56,11 @@ class PhotonInteraction { void pair_production(double alpha, double* E_electron, double* E_positron, double* mu_electron, double* mu_positron, uint64_t* seed) const; - void atomic_relaxation(const ElectronSubshell& shell, Particle& p) const; + void atomic_relaxation(int i_shell, Particle& p) const; // Data members std::string name_; //!< Name of element, e.g. "Zr" - int Z_; //!< Atomic number + int Z_; //!< Atomic number gsl::index index_; //!< Index in global elements vector // Microscopic cross sections @@ -78,10 +79,11 @@ class PhotonInteraction { Tabulated1D coherent_anomalous_real_; Tabulated1D coherent_anomalous_imag_; - // Photoionization and atomic relaxation data - std::unordered_map shell_map_; //!< Given a shell designator, e.g. 3, this - //!< dictionary gives an index in shells_ + // Photoionization and atomic relaxation data. Subshell cross sections are + // stored separately to improve memory access pattern when calculating the + // total cross section vector shells_; + xt::xtensor cross_sections_; // Compton profile data xt::xtensor profile_pdf_; @@ -98,9 +100,24 @@ class PhotonInteraction { // Bremsstrahlung scaled DCS xt::xtensor dcs_; + // Whether atomic relaxation data is present + bool has_atomic_relaxation_ {false}; + + // Constant data + static constexpr int MAX_STACK_SIZE = + 7; //!< maximum possible size of atomic relaxation stack private: - void compton_doppler(double alpha, double mu, double* E_out, int* i_shell, - uint64_t* seed) const; + void compton_doppler( + double alpha, double mu, double* E_out, int* i_shell, uint64_t* seed) const; + + //! Calculate the maximum size of the vacancy stack in atomic relaxation + // + //! These helper functions use the subshell transition data to calculate the + //! maximum size the stack of unprocessed subshell vacancies can grow to for + //! the given element while simulating the cascade of photons and electrons + //! in atomic relaxation. + int calc_max_stack_size() const; + int calc_helper(std::unordered_map& visited, int i_shell) const; }; //============================================================================== @@ -117,7 +134,8 @@ void free_memory_photon(); namespace data { -extern xt::xtensor compton_profile_pz; //! Compton profile momentum grid +extern xt::xtensor + compton_profile_pz; //! Compton profile momentum grid //! Photon interaction data for each element extern std::unordered_map element_map; diff --git a/include/openmc/physics.h b/include/openmc/physics.h index bf16083ef13..f62f43a02f2 100644 --- a/include/openmc/physics.h +++ b/include/openmc/physics.h @@ -10,6 +10,13 @@ namespace openmc { +//============================================================================== +// Constants +//============================================================================== + +// Monoatomic ideal-gas scattering treatment threshold +constexpr double FREE_GAS_THRESHOLD {400.0}; + //============================================================================== // Non-member functions //============================================================================== @@ -26,16 +33,17 @@ void sample_neutron_reaction(Particle& p); void sample_photon_reaction(Particle& p); //! Terminates the particle and either deposits all energy locally -//! (electron_treatment = ElectronTreatment::LED) or creates secondary bremsstrahlung -//! photons from electron deflections with charged particles (electron_treatment -//! = ElectronTreatment::TTB). +//! (electron_treatment = ElectronTreatment::LED) or creates secondary +//! bremsstrahlung photons from electron deflections with charged particles +//! (electron_treatment = ElectronTreatment::TTB). void sample_electron_reaction(Particle& p); //! Terminates the particle and either deposits all energy locally -//! (electron_treatment = ElectronTreatment::LED) or creates secondary bremsstrahlung -//! photons from electron deflections with charged particles (electron_treatment -//! = ElectronTreatment::TTB). Two annihilation photons of energy MASS_ELECTRON_EV (0.511 -//! MeV) are created and travel in opposite directions. +//! (electron_treatment = ElectronTreatment::LED) or creates secondary +//! bremsstrahlung photons from electron deflections with charged particles +//! (electron_treatment = ElectronTreatment::TTB). Two annihilation photons of +//! energy MASS_ELECTRON_EV (0.511 MeV) are created and travel in opposite +//! directions. void sample_positron_reaction(Particle& p); //! Sample a nuclide based on their total cross sections and densities within @@ -53,15 +61,15 @@ int sample_element(Particle& p); Reaction& sample_fission(int i_nuclide, Particle& p); -void sample_photon_product(int i_nuclide, Particle& p, int* i_rx, int* i_product); +void sample_photon_product( + int i_nuclide, Particle& p, int* i_rx, int* i_product); void absorption(Particle& p, int i_nuclide); void scatter(Particle& p, int i_nuclide); //! Treats the elastic scattering of a neutron with a target. -void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, - Particle& p); +void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, Particle& p); void sab_scatter(int i_nuclide, int i_sab, Particle& p); @@ -76,11 +84,11 @@ Direction sample_target_velocity(const Nuclide& nuc, double E, Direction u, //! by most Monte Carlo codes, in which cross section is assumed to be constant //! in energy. Excellent documentation for this method can be found in //! FRA-TM-123. -Direction sample_cxs_target_velocity(double awr, double E, Direction u, double kT, - uint64_t* seed); +Direction sample_cxs_target_velocity( + double awr, double E, Direction u, double kT, uint64_t* seed); -void sample_fission_neutron(int i_nuclide, const Reaction& rx, double E_in, - SourceSite* site, uint64_t* seed); +void sample_fission_neutron( + int i_nuclide, const Reaction& rx, SourceSite* site, Particle& p); //! handles all reactions with a single secondary neutron (other than fission), //! i.e. level scattering, (n,np), (n,na), etc. @@ -88,6 +96,12 @@ void inelastic_scatter(const Nuclide& nuc, const Reaction& rx, Particle& p); void sample_secondary_photons(Particle& p, int i_nuclide); +//! Split or Roulette particles based their weight and the lower weight window +//! bound. +// +//! \param[in] p, particle to be split or rouletted with the weight window. +void split_particle(Particle& p); + } // namespace openmc #endif // OPENMC_PHYSICS_H diff --git a/include/openmc/physics_common.h b/include/openmc/physics_common.h index 1398557dc58..e38a3c7f883 100644 --- a/include/openmc/physics_common.h +++ b/include/openmc/physics_common.h @@ -9,7 +9,9 @@ namespace openmc { //! \brief Performs the russian roulette operation for a particle -void russian_roulette(Particle& p); +//! \param[in,out] p Particle object +//! \param[in] weight_survive Weight assigned to particles that survive +void russian_roulette(Particle& p, double weight_survive); } // namespace openmc #endif // OPENMC_PHYSICS_COMMON_H diff --git a/include/openmc/physics_mg.h b/include/openmc/physics_mg.h index 05184d959d4..4d9d1afc482 100644 --- a/include/openmc/physics_mg.h +++ b/include/openmc/physics_mg.h @@ -12,32 +12,27 @@ namespace openmc { //! \brief samples particle behavior after a collision event. //! \param p Particle to operate on -void -collision_mg(Particle& p); +void collision_mg(Particle& p); //! \brief samples a reaction type. //! //! Note that there is special logic when suvival biasing is turned on since //! fission and disappearance are treated implicitly. //! \param p Particle to operate on -void -sample_reaction(Particle& p); +void sample_reaction(Particle& p); //! \brief Samples the scattering event //! \param p Particle to operate on -void -scatter(Particle& p); +void scatter(Particle& p); //! \brief Determines the average total, prompt and delayed neutrons produced //! from fission and creates the appropriate bank sites. //! \param p Particle to operate on -void -create_fission_sites(Particle& p); +void create_fission_sites(Particle& p); //! \brief Handles an absorption event //! \param p Particle to operate on -void -absorption(Particle& p); +void absorption(Particle& p); } // namespace openmc #endif // OPENMC_PHYSICS_MG_H diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 0e9ceea78b0..ee6c3fbec58 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -1,21 +1,22 @@ #ifndef OPENMC_PLOT_H #define OPENMC_PLOT_H -#include +#include #include +#include #include "pugixml.hpp" #include "xtensor/xarray.hpp" #include "hdf5.h" -#include "openmc/position.h" -#include "openmc/constants.h" #include "openmc/cell.h" +#include "openmc/constants.h" #include "openmc/error.h" #include "openmc/geometry.h" #include "openmc/particle.h" -#include "openmc/xml_interface.h" +#include "openmc/position.h" #include "openmc/random_lcg.h" +#include "openmc/xml_interface.h" namespace openmc { @@ -23,15 +24,15 @@ namespace openmc { // Global variables //=============================================================================== -class Plot; +class PlottableInterface; namespace model { extern std::unordered_map plot_map; //!< map of plot ids to index -extern vector plots; //!< Plot instance container +extern vector> + plots; //!< Plot instance container -extern uint64_t plotter_prn_seeds[N_STREAMS]; // Random number seeds used for plotter -extern int plotter_stream; // Stream index used by the plotter +extern uint64_t plotter_seed; // Stream index used by the plotter } // namespace model @@ -40,10 +41,10 @@ extern int plotter_stream; // Stream index used by the plotter //=============================================================================== struct RGBColor { - //Constructors - RGBColor() : red(0), green(0), blue(0) { }; - RGBColor(const int v[3]) : red(v[0]), green(v[1]), blue(v[2]) { }; - RGBColor(int r, int g, int b) : red(r), green(g), blue(b) { }; + // Constructors + RGBColor() : red(0), green(0), blue(0) {}; + RGBColor(const int v[3]) : red(v[0]), green(v[1]), blue(v[2]) {}; + RGBColor(int r, int g, int b) : red(r), green(g), blue(b) {}; RGBColor(const vector& v) { @@ -55,7 +56,8 @@ struct RGBColor { blue = v[2]; } - bool operator ==(const RGBColor& other) { + bool operator==(const RGBColor& other) + { return red == other.red && green == other.green && blue == other.blue; } @@ -65,8 +67,53 @@ struct RGBColor { // some default colors const RGBColor WHITE {255, 255, 255}; -const RGBColor RED {255, 0, 0}; +const RGBColor RED {255, 0, 0}; +const RGBColor BLACK {0, 0, 0}; + +/* + * PlottableInterface classes just have to have a unique ID in the plots.xml + * file, and guarantee being able to create output in some way. + */ +class PlottableInterface { +private: + void set_id(pugi::xml_node plot_node); + int id_; // unique plot ID + + void set_bg_color(pugi::xml_node plot_node); + void set_universe(pugi::xml_node plot_node); + void set_default_colors(pugi::xml_node plot_node); + void set_user_colors(pugi::xml_node plot_node); + void set_overlap_color(pugi::xml_node plot_node); + void set_mask(pugi::xml_node plot_node); +protected: + // Plot output filename, derived classes have logic to set it + std::string path_plot_; + +public: + enum class PlotColorBy { cells = 0, mats = 1 }; + + // Creates the output image named path_plot_ + virtual void create_output() const = 0; + + // Print useful info to the terminal + virtual void print_info() const = 0; + + const std::string& path_plot() const { return path_plot_; } + std::string& path_plot() { return path_plot_; } + int id() const { return id_; } + int level() const { return level_; } + + // Public color-related data + PlottableInterface(pugi::xml_node plot_node); + virtual ~PlottableInterface() = default; + int level_; // Universe level to plot + bool color_overlaps_; // Show overlapping cells? + PlotColorBy color_by_; // Plot coloring (cell/material) + RGBColor not_found_ {WHITE}; // Plot background color + RGBColor overlap_color_ {RED}; // Plot overlap color + vector colors_; // Plot colors +}; typedef xt::xtensor ImageData; @@ -75,7 +122,7 @@ struct IdData { IdData(size_t h_res, size_t v_res); // Methods - void set_value(size_t y, size_t x, const Particle& p, int level); + void set_value(size_t y, size_t x, const GeometryState& p, int level); void set_overlap(size_t y, size_t x); // Members @@ -87,55 +134,45 @@ struct PropertyData { PropertyData(size_t h_res, size_t v_res); // Methods - void set_value(size_t y, size_t x, const Particle& p, int level); + void set_value(size_t y, size_t x, const GeometryState& p, int level); void set_overlap(size_t y, size_t x); // Members xt::xtensor data_; //!< 2D array of temperature & density data }; -enum class PlotType { - slice = 1, - voxel = 2 -}; - -enum class PlotBasis { - xy = 1, - xz = 2, - yz = 3 -}; - -enum class PlotColorBy { - cells = 0, - mats = 1 -}; - //=============================================================================== // Plot class //=============================================================================== -class PlotBase { + +class SlicePlotBase { public: - template T get_map() const; + template + T get_map() const; + + enum class PlotBasis { xy = 1, xz = 2, yz = 3 }; // Members public: - Position origin_; //!< Plot origin in geometry - Position width_; //!< Plot width in geometry - PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) - array pixels_; //!< Plot size in pixels - bool color_overlaps_; //!< Show overlapping cells? - int level_; //!< Plot universe level + Position origin_; //!< Plot origin in geometry + Position width_; //!< Plot width in geometry + PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) + array pixels_; //!< Plot size in pixels + bool slice_color_overlaps_; //!< Show overlapping cells? + int slice_level_ {-1}; //!< Plot universe level +private: }; template -T PlotBase::get_map() const { +T SlicePlotBase::get_map() const +{ size_t width = pixels_[0]; size_t height = pixels_[1]; // get pixel size - double in_pixel = (width_[0])/static_cast(width); - double out_pixel = (width_[1])/static_cast(height); + double in_pixel = (width_[0]) / static_cast(width); + double out_pixel = (width_[1]) / static_cast(height); // size data array T data(width, height); @@ -143,16 +180,16 @@ T PlotBase::get_map() const { // setup basis indices and initial position centered on pixel int in_i, out_i; Position xyz = origin_; - switch(basis_) { - case PlotBasis::xy : + switch (basis_) { + case PlotBasis::xy: in_i = 0; out_i = 1; break; - case PlotBasis::xz : + case PlotBasis::xz: in_i = 0; out_i = 2; break; - case PlotBasis::yz : + case PlotBasis::yz: in_i = 1; out_i = 2; break; @@ -165,89 +202,166 @@ T PlotBase::get_map() const { xyz[out_i] = origin_[out_i] + width_[1] / 2. - out_pixel / 2.; // arbitrary direction - Direction dir = {0.7071, 0.7071, 0.0}; + Direction dir = {1. / std::sqrt(2.), 1. / std::sqrt(2.), 0.0}; - #pragma omp parallel +#pragma omp parallel { - Particle p; + GeometryState p; p.r() = xyz; p.u() = dir; p.coord(0).universe = model::root_universe; - int level = level_; - int j{}; + int level = slice_level_; + int j {}; - #pragma omp for +#pragma omp for for (int y = 0; y < height; y++) { - p.r()[out_i] = xyz[out_i] - out_pixel * y; + p.r()[out_i] = xyz[out_i] - out_pixel * y; for (int x = 0; x < width; x++) { p.r()[in_i] = xyz[in_i] + in_pixel * x; p.n_coord() = 1; // local variables bool found_cell = exhaustive_find_cell(p); j = p.n_coord() - 1; - if (level >= 0) { j = level; } + if (level >= 0) { + j = level; + } if (found_cell) { data.set_value(y, x, p, j); } - if (color_overlaps_ && check_cell_overlap(p, false)) { + if (slice_color_overlaps_ && check_cell_overlap(p, false)) { data.set_overlap(y, x); } } // inner for - } // outer for - } // omp parallel + } // outer for + } // omp parallel return data; } -class Plot : public PlotBase { +// Represents either a voxel or pixel plot +class Plot : public PlottableInterface, public SlicePlotBase { public: - // Constructor - Plot(pugi::xml_node plot); + enum class PlotType { slice = 1, voxel = 2 }; + + Plot(pugi::xml_node plot, PlotType type); - // Methods private: - void set_id(pugi::xml_node plot_node); - void set_type(pugi::xml_node plot_node); void set_output_path(pugi::xml_node plot_node); - void set_bg_color(pugi::xml_node plot_node); void set_basis(pugi::xml_node plot_node); void set_origin(pugi::xml_node plot_node); void set_width(pugi::xml_node plot_node); - void set_universe(pugi::xml_node plot_node); - void set_default_colors(pugi::xml_node plot_node); - void set_user_colors(pugi::xml_node plot_node); void set_meshlines(pugi::xml_node plot_node); - void set_mask(pugi::xml_node plot_node); - void set_overlap_color(pugi::xml_node plot_node); -// Members public: - int id_; //!< Plot ID - PlotType type_; //!< Plot type (Slice/Voxel) - PlotColorBy color_by_; //!< Plot coloring (cell/material) - int meshlines_width_; //!< Width of lines added to the plot + // Add mesh lines to ImageData + void draw_mesh_lines(ImageData& data) const; + void create_image() const; + void create_voxel() const; + + virtual void create_output() const; + virtual void print_info() const; + + PlotType type_; //!< Plot type (Slice/Voxel) + int meshlines_width_; //!< Width of lines added to the plot int index_meshlines_mesh_ {-1}; //!< Index of the mesh to draw on the plot - RGBColor meshlines_color_; //!< Color of meshlines on the plot - RGBColor not_found_ {WHITE}; //!< Plot background color - RGBColor overlap_color_ {RED}; //!< Plot overlap color - vector colors_; //!< Plot colors - std::string path_plot_; //!< Plot output filename + RGBColor meshlines_color_; //!< Color of meshlines on the plot +}; + +class ProjectionPlot : public PlottableInterface { + +public: + ProjectionPlot(pugi::xml_node plot); + + virtual void create_output() const; + virtual void print_info() const; + +private: + void set_output_path(pugi::xml_node plot_node); + void set_look_at(pugi::xml_node node); + void set_camera_position(pugi::xml_node node); + void set_field_of_view(pugi::xml_node node); + void set_pixels(pugi::xml_node node); + void set_opacities(pugi::xml_node node); + void set_orthographic_width(pugi::xml_node node); + void set_wireframe_thickness(pugi::xml_node node); + void set_wireframe_ids(pugi::xml_node node); + void set_wireframe_color(pugi::xml_node node); + + /* If starting the particle from outside the geometry, we have to + * find a distance to the boundary in a non-standard surface intersection + * check. It's an exhaustive search over surfaces in the top-level universe. + */ + static int advance_to_boundary_from_void(GeometryState& p); + + /* Checks if a vector of two TrackSegments is equivalent. We define this + * to mean not having matching intersection lengths, but rather having + * a matching sequence of surface/cell/material intersections. + */ + struct TrackSegment; + bool trackstack_equivalent(const vector& track1, + const vector& track2) const; + + /* Used for drawing wireframe and colors. We record the list of + * surface/cell/material intersections and the corresponding lengths as a ray + * traverses the geometry, then color by iterating in reverse. + */ + struct TrackSegment { + int id; // material or cell ID (which is being colored) + double length; // length of this track intersection + + /* Recording this allows us to draw edges on the wireframe. For instance + * if two surfaces bound a single cell, it allows drawing that sharp edge + * where the surfaces intersect. + */ + int surface; // last surface ID intersected in this segment + TrackSegment(int id_a, double length_a, int surface_a) + : id(id_a), length(length_a), surface(surface_a) + {} + }; + + // Max intersections before we assume ray tracing is caught in an infinite + // loop: + static const int MAX_INTERSECTIONS = 1000000; + + std::array pixels_; // pixel dimension of resulting image + double horizontal_field_of_view_ {70.0}; // horiz. f.o.v. in degrees + Position camera_position_; // where camera is + Position look_at_; // point camera is centered looking at + Direction up_ {0.0, 0.0, 1.0}; // which way is up + + // which color IDs should be wireframed. If empty, all cells are wireframed. + vector wireframe_ids_; + + /* The horizontal thickness, if using an orthographic projection. + * If set to zero, we assume using a perspective projection. + */ + double orthographic_width_ {0.0}; + + // Thickness of the wireframe lines. Can set to zero for no wireframe. + int wireframe_thickness_ {1}; + + RGBColor wireframe_color_ {BLACK}; // wireframe color + vector xs_; // macro cross section values for cell volume rendering }; //=============================================================================== // Non-member functions //=============================================================================== -//! Add mesh lines to image data of a plot object -//! \param[in] plot object -//! \param[out] image data associated with the plot object -void draw_mesh_lines(Plot const& pl, ImageData& data); +/* Write a PPM image + * filename - name of output file + * data - image data to write + */ +void output_ppm(const std::string& filename, const ImageData& data); -//! Write a ppm image to file using a plot object's image data -//! \param[in] plot object -//! \param[out] image data associated with the plot object -void output_ppm(Plot const& pl, const ImageData& data); +#ifdef USE_LIBPNG +/* Write a PNG image + * filename - name of output file + * data - image data to write + */ +void output_png(const std::string& filename, const ImageData& data); +#endif //! Initialize a voxel file //! \param[in] id of an open hdf5 file @@ -255,16 +369,16 @@ void output_ppm(Plot const& pl, const ImageData& data); //! \param[out] dataspace pointer to voxel data //! \param[out] dataset pointer to voxesl data //! \param[out] pointer to memory space of voxel data -void voxel_init(hid_t file_id, const hsize_t* dims, hid_t* dspace, - hid_t* dset, hid_t* memspace); +void voxel_init(hid_t file_id, const hsize_t* dims, hid_t* dspace, hid_t* dset, + hid_t* memspace); //! Write a section of the voxel data to hdf5 //! \param[in] voxel slice //! \param[out] dataspace pointer to voxel data //! \param[out] dataset pointer to voxesl data //! \param[out] pointer to data to write -void voxel_write_slice(int x, hid_t dspace, hid_t dset, - hid_t memspace, void* buf); +void voxel_write_slice( + int x, hid_t dspace, hid_t dset, hid_t memspace, void* buf); //! Close voxel file entities //! \param[in] data space to close @@ -279,18 +393,16 @@ void voxel_finalize(hid_t dspace, hid_t dset, hid_t memspace); //! Read plot specifications from a plots.xml file void read_plots_xml(); -//! Create a ppm image for a plot object -//! \param[in] plot object -void create_ppm(Plot const& pl); +//! Read plot specifications from an XML Node +//! \param[in] XML node containing plot info +void read_plots_xml(pugi::xml_node root); -//! Create an hdf5 voxel file for a plot object -//! \param[in] plot object -void create_voxel(Plot const& pl); +//! Clear memory +void free_memory_plot(); //! Create a randomly generated RGB color //! \return RGBColor with random value RGBColor random_color(); - } // namespace openmc #endif // OPENMC_PLOT_H diff --git a/include/openmc/position.h b/include/openmc/position.h index ff258d0dec2..11ea3764792 100644 --- a/include/openmc/position.h +++ b/include/openmc/position.h @@ -5,6 +5,7 @@ #include #include // for out_of_range +#include "fmt/format.h" #include "openmc/array.h" #include "openmc/vector.h" @@ -17,8 +18,8 @@ namespace openmc { struct Position { // Constructors Position() = default; - Position(double x_, double y_, double z_) : x{x_}, y{y_}, z{z_} { }; - Position(const double xyz[]) : x{xyz[0]}, y{xyz[1]}, z{xyz[2]} { }; + Position(double x_, double y_, double z_) : x {x_}, y {y_}, z {z_} {}; + Position(const double xyz[]) : x {xyz[0]}, y {xyz[1]}, z {xyz[2]} {}; Position(const vector& xyz) : x {xyz[0]}, y {xyz[1]}, z {xyz[2]} {}; Position(const array& xyz) : x {xyz[0]}, y {xyz[1]}, z {xyz[2]} {}; @@ -33,22 +34,30 @@ struct Position { Position& operator/=(double); Position operator-() const; - const double& operator[](int i) const { + const double& operator[](int i) const + { switch (i) { - case 0: return x; - case 1: return y; - case 2: return z; - default: - throw std::out_of_range{"Index in Position must be between 0 and 2."}; + case 0: + return x; + case 1: + return y; + case 2: + return z; + default: + throw std::out_of_range {"Index in Position must be between 0 and 2."}; } } - double& operator[](int i) { + double& operator[](int i) + { switch (i) { - case 0: return x; - case 1: return y; - case 2: return z; - default: - throw std::out_of_range{"Index in Position must be between 0 and 2."}; + case 0: + return x; + case 1: + return y; + case 2: + return z; + default: + throw std::out_of_range {"Index in Position must be between 0 and 2."}; } } @@ -69,11 +78,15 @@ struct Position { //! Dot product of two vectors //! \param[in] other Vector to take dot product with //! \result Resulting dot product - inline double dot(Position other) const { - return x*other.x + y*other.y + z*other.z; + inline double dot(Position other) const + { + return x * other.x + y * other.y + z * other.z; } - inline double norm() const { - return std::sqrt(x*x + y*y + z*z); + inline double norm() const { return std::sqrt(x * x + y * y + z * z); } + inline Position cross(Position other) const + { + return {y * other.z - z * other.y, z * other.x - x * other.z, + x * other.y - y * other.x}; } //! Reflect a direction across a normal vector @@ -123,23 +136,60 @@ inline double& Position::get<2>() } // Binary operators -inline Position operator+(Position a, Position b) { return a += b; } -inline Position operator+(Position a, double b) { return a += b; } -inline Position operator+(double a, Position b) { return b += a; } +inline Position operator+(Position a, Position b) +{ + return a += b; +} +inline Position operator+(Position a, double b) +{ + return a += b; +} +inline Position operator+(double a, Position b) +{ + return b += a; +} -inline Position operator-(Position a, Position b) { return a -= b; } -inline Position operator-(Position a, double b) { return a -= b; } -inline Position operator-(double a, Position b) { return b -= a; } +inline Position operator-(Position a, Position b) +{ + return a -= b; +} +inline Position operator-(Position a, double b) +{ + return a -= b; +} +inline Position operator-(double a, Position b) +{ + return b -= a; +} -inline Position operator*(Position a, Position b) { return a *= b; } -inline Position operator*(Position a, double b) { return a *= b; } -inline Position operator*(double a, Position b) { return b *= a; } +inline Position operator*(Position a, Position b) +{ + return a *= b; +} +inline Position operator*(Position a, double b) +{ + return a *= b; +} +inline Position operator*(double a, Position b) +{ + return b *= a; +} -inline Position operator/(Position a, Position b) { return a /= b; } -inline Position operator/(Position a, double b) { return a /= b; } -inline Position operator/(double a, Position b) { return b /= a; } +inline Position operator/(Position a, Position b) +{ + return a /= b; +} +inline Position operator/(Position a, double b) +{ + return a /= b; +} +inline Position operator/(double a, Position b) +{ + return b /= a; +} -inline Position Position::reflect(Position n) const { +inline Position Position::reflect(Position n) const +{ const double projection = n.dot(*this); const double magnitude = n.dot(n); n *= (2.0 * projection / magnitude); @@ -147,10 +197,14 @@ inline Position Position::reflect(Position n) const { } inline bool operator==(Position a, Position b) -{return a.x == b.x && a.y == b.y && a.z == b.z;} +{ + return a.x == b.x && a.y == b.y && a.z == b.z; +} inline bool operator!=(Position a, Position b) -{return a.x != b.x || a.y != b.y || a.z != b.z;} +{ + return a.x != b.x || a.y != b.y || a.z != b.z; +} std::ostream& operator<<(std::ostream& os, Position a); @@ -162,4 +216,18 @@ using Direction = Position; } // namespace openmc +namespace fmt { + +template<> +struct formatter : formatter { + template + auto format(const openmc::Position& pos, FormatContext& ctx) + { + return formatter::format( + fmt::format("({}, {}, {})", pos.x, pos.y, pos.z), ctx); + } +}; + +} // namespace fmt + #endif // OPENMC_POSITION_H diff --git a/include/openmc/progress_bar.h b/include/openmc/progress_bar.h index 18a3eea47fc..7708b9b037b 100644 --- a/include/openmc/progress_bar.h +++ b/include/openmc/progress_bar.h @@ -5,18 +5,16 @@ class ProgressBar { -public: +public: // Constructor ProgressBar(); void set_value(double val); - + private: std::string bar; - char bar_old[72] = "???% | |"; - + char bar_old[72] = + "???% | |"; }; - #endif // OPENMC_PROGRESSBAR_H - diff --git a/include/openmc/random_dist.h b/include/openmc/random_dist.h index 844c0ce52ce..0fb186edca0 100644 --- a/include/openmc/random_dist.h +++ b/include/openmc/random_dist.h @@ -48,9 +48,9 @@ extern "C" double maxwell_spectrum(double T, uint64_t* seed); extern "C" double watt_spectrum(double a, double b, uint64_t* seed); //============================================================================== -//! Samples an energy from the Gaussian energy-dependent fission distribution. +//! Samples an energy from the Gaussian distribution. //! -//! Samples from a Normal distribution with a given mean and standard deviation +//! Samples from a normal distribution with a given mean and standard deviation //! The PDF is defined as s(x) = (1/2*sigma*sqrt(2) * e-((mu-x)/2*sigma)^2 //! Its sampled according to //! http://www-pdg.lbl.gov/2009/reviews/rpp2009-rev-monte-carlo-techniques.pdf @@ -64,22 +64,6 @@ extern "C" double watt_spectrum(double a, double b, uint64_t* seed); extern "C" double normal_variate(double mean, double std_dev, uint64_t* seed); -//============================================================================== -//! Samples an energy from the Muir (Gaussian) energy-dependent distribution. -//! -//! This is another form of the Gaussian distribution but with more easily -//! modifiable parameters -//! https://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-05411-MS -//! -//! \param e0 peak neutron energy [eV] -//! \param m_rat ratio of the fusion reactants to AMU -//! \param kt the ion temperature of the reactants [eV] -//! \param seed A pointer to the pseudorandom seed -//! \result The sampled outgoing energy -//============================================================================== - -extern "C" double muir_spectrum(double e0, double m_rat, double kt, uint64_t* seed); - } // namespace openmc #endif // OPENMC_RANDOM_DIST_H diff --git a/include/openmc/random_lcg.h b/include/openmc/random_lcg.h index d73cc3ee257..4157b7cfe7a 100644 --- a/include/openmc/random_lcg.h +++ b/include/openmc/random_lcg.h @@ -3,19 +3,18 @@ #include - namespace openmc { //============================================================================== // Module constants. //============================================================================== -constexpr int N_STREAMS {4}; -constexpr int STREAM_TRACKING {0}; -constexpr int STREAM_SOURCE {1}; +constexpr int N_STREAMS {4}; +constexpr int STREAM_TRACKING {0}; +constexpr int STREAM_SOURCE {1}; constexpr int STREAM_URR_PTABLE {2}; -constexpr int STREAM_VOLUME {3}; -constexpr int64_t DEFAULT_SEED {1}; +constexpr int STREAM_VOLUME {3}; +constexpr int64_t DEFAULT_SEED {1}; //============================================================================== //! Generate a pseudo-random number using a linear congruential generator. diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h new file mode 100644 index 00000000000..5f64914edb9 --- /dev/null +++ b/include/openmc/random_ray/flat_source_domain.h @@ -0,0 +1,141 @@ +#ifndef OPENMC_RANDOM_RAY_FLAT_SOURCE_DOMAIN_H +#define OPENMC_RANDOM_RAY_FLAT_SOURCE_DOMAIN_H + +#include "openmc/openmp_interface.h" +#include "openmc/position.h" + +namespace openmc { + +/* + * The FlatSourceDomain class encompasses data and methods for storing + * scalar flux and source region for all flat source regions in a + * random ray simulation domain. + */ + +class FlatSourceDomain { +public: + //---------------------------------------------------------------------------- + // Helper Structs + + // A mapping object that is used to map between a specific random ray + // source region and an OpenMC native tally bin that it should score to + // every iteration. + struct TallyTask { + int tally_idx; + int filter_idx; + int score_idx; + int score_type; + TallyTask(int tally_idx, int filter_idx, int score_idx, int score_type) + : tally_idx(tally_idx), filter_idx(filter_idx), score_idx(score_idx), + score_type(score_type) + {} + }; + + //---------------------------------------------------------------------------- + // Constructors + FlatSourceDomain(); + + //---------------------------------------------------------------------------- + // Methods + void update_neutron_source(double k_eff); + double compute_k_eff(double k_eff_old) const; + void normalize_scalar_flux_and_volumes( + double total_active_distance_per_iteration); + int64_t add_source_to_scalar_flux(); + void batch_reset(); + void convert_source_regions_to_tallies(); + void random_ray_tally() const; + void accumulate_iteration_flux(); + void output_to_vtk() const; + void all_reduce_replicated_source_regions(); + + //---------------------------------------------------------------------------- + // Public Data members + + bool mapped_all_tallies_ {false}; // If all source regions have been visited + + int64_t n_source_regions_ {0}; // Total number of source regions in the model + + // 1D array representing source region starting offset for each OpenMC Cell + // in model::cells + vector source_region_offsets_; + + // 1D arrays representing values for all source regions + vector lock_; + vector was_hit_; + vector volume_; + vector position_recorded_; + vector position_; + + // 2D arrays stored in 1D representing values for all source regions x energy + // groups + vector scalar_flux_old_; + vector scalar_flux_new_; + vector source_; + + //---------------------------------------------------------------------------- + // Private data members +private: + int negroups_; // Number of energy groups in simulation + int64_t n_source_elements_ {0}; // Total number of source regions in the model + // times the number of energy groups + + // 2D array representing values for all source regions x energy groups x tally + // tasks + vector> tally_task_; + + // 1D arrays representing values for all source regions + vector material_; + vector volume_t_; + + // 2D arrays stored in 1D representing values for all source regions x energy + // groups + vector scalar_flux_final_; + +}; // class FlatSourceDomain + +//============================================================================ +//! Non-member functions +//============================================================================ + +// Returns the inputted value in big endian byte ordering. If the system is +// little endian, the byte ordering is flipped. If the system is big endian, +// the inputted value is returned as is. This function is necessary as +// .vtk binary files use big endian byte ordering. +template +T convert_to_big_endian(T in) +{ + // 4 byte integer + uint32_t test = 1; + + // 1 byte pointer to first byte of test integer + uint8_t* ptr = reinterpret_cast(&test); + + // If the first byte of test is 0, then the system is big endian. In this + // case, we don't have to do anything as .vtk files are big endian + if (*ptr == 0) + return in; + + // Otherwise, the system is in little endian, so we need to flip the + // endianness + uint8_t* orig = reinterpret_cast(&in); + uint8_t swapper[sizeof(T)]; + for (int i = 0; i < sizeof(T); i++) { + swapper[i] = orig[sizeof(T) - i - 1]; + } + T out = *reinterpret_cast(&swapper); + return out; +} + +template +void parallel_fill(vector& arr, T value) +{ +#pragma omp parallel for schedule(static) + for (int i = 0; i < arr.size(); i++) { + arr[i] = value; + } +} + +} // namespace openmc + +#endif // OPENMC_RANDOM_RAY_FLAT_SOURCE_DOMAIN_H diff --git a/include/openmc/random_ray/random_ray.h b/include/openmc/random_ray/random_ray.h new file mode 100644 index 00000000000..5ee64574ec1 --- /dev/null +++ b/include/openmc/random_ray/random_ray.h @@ -0,0 +1,55 @@ +#ifndef OPENMC_RANDOM_RAY_H +#define OPENMC_RANDOM_RAY_H + +#include "openmc/memory.h" +#include "openmc/particle.h" +#include "openmc/random_ray/flat_source_domain.h" +#include "openmc/source.h" + +namespace openmc { + +/* + * The RandomRay class encompasses data and methods for transporting random rays + * through the model. It is a small extension of the Particle class. + */ + +// TODO: Inherit from GeometryState instead of Particle +class RandomRay : public Particle { +public: + //---------------------------------------------------------------------------- + // Constructors + RandomRay(); + RandomRay(uint64_t ray_id, FlatSourceDomain* domain); + + //---------------------------------------------------------------------------- + // Methods + void event_advance_ray(); + void attenuate_flux(double distance, bool is_active); + void initialize_ray(uint64_t ray_id, FlatSourceDomain* domain); + uint64_t transport_history_based_single_ray(); + + //---------------------------------------------------------------------------- + // Static data members + static double distance_inactive_; // Inactive (dead zone) ray length + static double distance_active_; // Active ray length + static unique_ptr ray_source_; // Starting source for ray sampling + + //---------------------------------------------------------------------------- + // Public data members + vector angular_flux_; + +private: + //---------------------------------------------------------------------------- + // Private data members + vector delta_psi_; + int negroups_; + FlatSourceDomain* domain_ {nullptr}; // pointer to domain that has flat source + // data needed for ray transport + double distance_travelled_ {0}; + bool is_active_ {false}; + bool is_alive_ {true}; +}; // class RandomRay + +} // namespace openmc + +#endif // OPENMC_RANDOM_RAY_H diff --git a/include/openmc/random_ray/random_ray_simulation.h b/include/openmc/random_ray/random_ray_simulation.h new file mode 100644 index 00000000000..cde0d27dff2 --- /dev/null +++ b/include/openmc/random_ray/random_ray_simulation.h @@ -0,0 +1,59 @@ +#ifndef OPENMC_RANDOM_RAY_SIMULATION_H +#define OPENMC_RANDOM_RAY_SIMULATION_H + +#include "openmc/random_ray/flat_source_domain.h" + +namespace openmc { + +/* + * The RandomRaySimulation class encompasses data and methods for running a + * random ray simulation. + */ + +class RandomRaySimulation { +public: + //---------------------------------------------------------------------------- + // Constructors + RandomRaySimulation(); + + //---------------------------------------------------------------------------- + // Methods + void simulate(); + void reduce_simulation_statistics(); + void output_simulation_results() const; + void instability_check( + int64_t n_hits, double k_eff, double& avg_miss_rate) const; + void print_results_random_ray(uint64_t total_geometric_intersections, + double avg_miss_rate, int negroups, int64_t n_source_regions) const; + + //---------------------------------------------------------------------------- + // Data members +private: + // Contains all flat source region data + FlatSourceDomain domain_; + + // Random ray eigenvalue + double k_eff_ {1.0}; + + // Tracks the average FSR miss rate for analysis and reporting + double avg_miss_rate_ {0.0}; + + // Tracks the total number of geometric intersections by all rays for + // reporting + uint64_t total_geometric_intersections_ {0}; + + // Number of energy groups + int negroups_; + +}; // class RandomRaySimulation + +//============================================================================ +//! Non-member functions +//============================================================================ + +void openmc_run_random_ray(); +void validate_random_ray_inputs(); + +} // namespace openmc + +#endif // OPENMC_RANDOM_RAY_SIMULATION_H diff --git a/include/openmc/reaction.h b/include/openmc/reaction.h index a597e623712..93987d9d7ee 100644 --- a/include/openmc/reaction.h +++ b/include/openmc/reaction.h @@ -6,9 +6,10 @@ #include -#include #include "hdf5.h" +#include +#include "openmc/particle_data.h" #include "openmc/reaction_product.h" #include "openmc/vector.h" @@ -27,6 +28,18 @@ class Reaction { //! \param[in] temperatures Desired temperatures for cross sections explicit Reaction(hid_t group, const vector& temperatures); + //! Calculate cross section given temperautre/grid index, interpolation factor + // + //! \param[in] i_temp Temperature index + //! \param[in] i_grid Energy grid index + //! \param[in] interp_factor Interpolation factor between grid points + double xs(gsl::index i_temp, gsl::index i_grid, double interp_factor) const; + + //! Calculate cross section + // + //! \param[in] micro Microscopic cross section cache + double xs(const NuclideMicroXS& micro) const; + //! \brief Calculate reaction rate based on group-wise flux distribution // //! \param[in] i_temp Temperature index @@ -43,10 +56,10 @@ class Reaction { vector value; }; - int mt_; //!< ENDF MT value - double q_value_; //!< Reaction Q value in [eV] - bool scatter_in_cm_; //!< scattering system in center-of-mass? - bool redundant_; //!< redundant reaction? + int mt_; //!< ENDF MT value + double q_value_; //!< Reaction Q value in [eV] + bool scatter_in_cm_; //!< scattering system in center-of-mass? + bool redundant_; //!< redundant reaction? vector xs_; //!< Cross section at each temperature vector products_; //!< Reaction products }; diff --git a/include/openmc/reaction_product.h b/include/openmc/reaction_product.h index 2c0a703dc81..ce4fa8fc766 100644 --- a/include/openmc/reaction_product.h +++ b/include/openmc/reaction_product.h @@ -52,6 +52,6 @@ class ReactionProduct { vector distribution_; //!< Secondary angle-energy distribution }; -} // namespace opemc +} // namespace openmc #endif // OPENMC_REACTION_PRODUCT_H diff --git a/include/openmc/scattdata.h b/include/openmc/scattdata.h index bc1700319f5..a75ef09d97b 100644 --- a/include/openmc/scattdata.h +++ b/include/openmc/scattdata.h @@ -21,151 +21,139 @@ class ScattDataTabular; //============================================================================== class ScattData { - public: - virtual ~ScattData() = default; - protected: - //! \brief Initializes the attributes of the base class. - void - base_init(int order, const xt::xtensor& in_gmin, - const xt::xtensor& in_gmax, const double_2dvec& in_energy, - const double_2dvec& in_mult); - - //! \brief Combines microscopic ScattDatas into a macroscopic one. - void base_combine(size_t max_order, size_t order_dim, - const vector& those_scatts, const vector& scalars, - xt::xtensor& in_gmin, xt::xtensor& in_gmax, - double_2dvec& sparse_mult, double_3dvec& sparse_scatter); - - public: - - double_2dvec energy; // Normalized p0 matrix for sampling Eout - double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) - double_3dvec dist; // Angular distribution - xt::xtensor gmin; // minimum outgoing group - xt::xtensor gmax; // maximum outgoing group - xt::xtensor scattxs; // Isotropic Sigma_{s,g_{in}} - - //! \brief Calculates the value of normalized f(mu). - //! - //! The value of f(mu) is normalized as in the integral of f(mu)dmu across - //! [-1,1] is 1. - //! - //! @param gin Incoming energy group of interest. - //! @param gout Outgoing energy group of interest. - //! @param mu Cosine of the change-in-angle of interest. - //! @return The value of f(mu). - virtual double - calc_f(int gin, int gout, double mu) = 0; - - //! \brief Samples the outgoing energy and angle from the ScattData info. - //! - //! @param gin Incoming energy group. - //! @param gout Sampled outgoing energy group. - //! @param mu Sampled cosine of the change-in-angle. - //! @param wgt Weight of the particle to be adjusted. - //! @param seed Pseudorandom number seed pointer - virtual void - sample(int gin, int& gout, double& mu, double& wgt, uint64_t* seed) = 0; - - //! \brief Initializes the ScattData object from a given scatter and - //! multiplicity matrix. - //! - //! @param in_gmin List of minimum outgoing groups for every incoming group - //! @param in_gmax List of maximum outgoing groups for every incoming group - //! @param in_mult Input sparse multiplicity matrix - //! @param coeffs Input sparse scattering matrix - virtual void - init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs) = 0; - - //! \brief Combines the microscopic data. - //! - //! @param those_scatts Microscopic objects to combine. - //! @param scalars Scalars to multiply the microscopic data by. - virtual void combine(const vector& those_scatts, - const vector& scalars) = 0; - - //! \brief Getter for the dimensionality of the scattering order. - //! - //! If Legendre this is the "n" in "Pn"; for Tabular, this is the number - //! of points, and for Histogram this is the number of bins. - //! - //! @return The order. - virtual size_t - get_order() = 0; - - //! \brief Builds a dense scattering matrix from the constituent parts - //! - //! @param max_order If Legendre this is the maximum value of "n" in "Pn" - //! requested; ignored otherwise. - //! @return The dense scattering matrix. - virtual xt::xtensor - get_matrix(size_t max_order) = 0; - - //! \brief Samples the outgoing energy from the ScattData info. - //! - //! @param gin Incoming energy group. - //! @param gout Sampled outgoing energy group. - //! @param i_gout Sampled outgoing energy group index. - //! @param seed Pseudorandom number seed pointer - void - sample_energy(int gin, int& gout, int& i_gout, uint64_t* seed); - - //! \brief Provides a cross section value given certain parameters - //! - //! @param xstype Type of cross section requested, according to the - //! enumerated constants. - //! @param gin Incoming energy group. - //! @param gout Outgoing energy group; use nullptr if irrelevant, or if a - //! sum is requested. - //! @param mu Cosine of the change-in-angle, for scattering quantities; - //! use nullptr if irrelevant. - //! @return Requested cross section value. - double - get_xs(MgxsType xstype, int gin, const int* gout, const double* mu); +public: + virtual ~ScattData() = default; + +protected: + //! \brief Initializes the attributes of the base class. + void base_init(int order, const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_energy, + const double_2dvec& in_mult); + + //! \brief Combines microscopic ScattDatas into a macroscopic one. + void base_combine(size_t max_order, size_t order_dim, + const vector& those_scatts, const vector& scalars, + xt::xtensor& in_gmin, xt::xtensor& in_gmax, + double_2dvec& sparse_mult, double_3dvec& sparse_scatter); + +public: + double_2dvec energy; // Normalized p0 matrix for sampling Eout + double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) + double_3dvec dist; // Angular distribution + xt::xtensor gmin; // minimum outgoing group + xt::xtensor gmax; // maximum outgoing group + xt::xtensor scattxs; // Isotropic Sigma_{s,g_{in}} + + //! \brief Calculates the value of normalized f(mu). + //! + //! The value of f(mu) is normalized as in the integral of f(mu)dmu across + //! [-1,1] is 1. + //! + //! @param gin Incoming energy group of interest. + //! @param gout Outgoing energy group of interest. + //! @param mu Cosine of the change-in-angle of interest. + //! @return The value of f(mu). + virtual double calc_f(int gin, int gout, double mu) = 0; + + //! \brief Samples the outgoing energy and angle from the ScattData info. + //! + //! @param gin Incoming energy group. + //! @param gout Sampled outgoing energy group. + //! @param mu Sampled cosine of the change-in-angle. + //! @param wgt Weight of the particle to be adjusted. + //! @param seed Pseudorandom number seed pointer + virtual void sample( + int gin, int& gout, double& mu, double& wgt, uint64_t* seed) = 0; + + //! \brief Initializes the ScattData object from a given scatter and + //! multiplicity matrix. + //! + //! @param in_gmin List of minimum outgoing groups for every incoming group + //! @param in_gmax List of maximum outgoing groups for every incoming group + //! @param in_mult Input sparse multiplicity matrix + //! @param coeffs Input sparse scattering matrix + virtual void init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) = 0; + + //! \brief Combines the microscopic data. + //! + //! @param those_scatts Microscopic objects to combine. + //! @param scalars Scalars to multiply the microscopic data by. + virtual void combine( + const vector& those_scatts, const vector& scalars) = 0; + + //! \brief Getter for the dimensionality of the scattering order. + //! + //! If Legendre this is the "n" in "Pn"; for Tabular, this is the number + //! of points, and for Histogram this is the number of bins. + //! + //! @return The order. + virtual size_t get_order() = 0; + + //! \brief Builds a dense scattering matrix from the constituent parts + //! + //! @param max_order If Legendre this is the maximum value of "n" in "Pn" + //! requested; ignored otherwise. + //! @return The dense scattering matrix. + virtual xt::xtensor get_matrix(size_t max_order) = 0; + + //! \brief Samples the outgoing energy from the ScattData info. + //! + //! @param gin Incoming energy group. + //! @param gout Sampled outgoing energy group. + //! @param i_gout Sampled outgoing energy group index. + //! @param seed Pseudorandom number seed pointer + void sample_energy(int gin, int& gout, int& i_gout, uint64_t* seed); + + //! \brief Provides a cross section value given certain parameters + //! + //! @param xstype Type of cross section requested, according to the + //! enumerated constants. + //! @param gin Incoming energy group. + //! @param gout Outgoing energy group; use nullptr if irrelevant, or if a + //! sum is requested. + //! @param mu Cosine of the change-in-angle, for scattering quantities; + //! use nullptr if irrelevant. + //! @return Requested cross section value. + double get_xs(MgxsType xstype, int gin, const int* gout, const double* mu); }; //============================================================================== // ScattDataLegendre represents the angular distributions as Legendre kernels //============================================================================== -class ScattDataLegendre: public ScattData { +class ScattDataLegendre : public ScattData { - protected: +protected: + // Maximal value for rejection sampling from a rectangle + double_2dvec max_val; - // Maximal value for rejection sampling from a rectangle - double_2dvec max_val; + // Friend convert_legendre_to_tabular so it has access to protected + // parameters + friend void convert_legendre_to_tabular( + ScattDataLegendre& leg, ScattDataTabular& tab); - // Friend convert_legendre_to_tabular so it has access to protected - // parameters - friend void - convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab); +public: + void init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) override; - public: + void combine(const vector& those_scatts, + const vector& scalars) override; - void - init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs); + //! \brief Find the maximal value of the angular distribution to use as a + // bounding box with rejection sampling. + void update_max_val(); - void combine( - const vector& those_scatts, const vector& scalars); + double calc_f(int gin, int gout, double mu) override; - //! \brief Find the maximal value of the angular distribution to use as a - // bounding box with rejection sampling. - void - update_max_val(); + void sample( + int gin, int& gout, double& mu, double& wgt, uint64_t* seed) override; - double - calc_f(int gin, int gout, double mu); + size_t get_order() override { return dist[0][0].size() - 1; }; - void - sample(int gin, int& gout, double& mu, double& wgt, uint64_t* seed); - - size_t - get_order() {return dist[0][0].size() - 1;}; - - xt::xtensor - get_matrix(size_t max_order); + xt::xtensor get_matrix(size_t max_order) override; }; //============================================================================== @@ -173,34 +161,29 @@ class ScattDataLegendre: public ScattData { // would be if it came from a "mu" tally in OpenMC //============================================================================== -class ScattDataHistogram: public ScattData { - - protected: +class ScattDataHistogram : public ScattData { - xt::xtensor mu; // Angle distribution mu bin boundaries - double dmu; // Quick storage of the mu spacing - double_3dvec fmu; // The angular distribution histogram +protected: + xt::xtensor mu; // Angle distribution mu bin boundaries + double dmu; // Quick storage of the mu spacing + double_3dvec fmu; // The angular distribution histogram - public: +public: + void init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) override; - void - init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs); + void combine(const vector& those_scatts, + const vector& scalars) override; - void combine( - const vector& those_scatts, const vector& scalars); + double calc_f(int gin, int gout, double mu) override; - double - calc_f(int gin, int gout, double mu); + void sample( + int gin, int& gout, double& mu, double& wgt, uint64_t* seed) override; - void - sample(int gin, int& gout, double& mu, double& wgt, uint64_t* seed); + size_t get_order() override { return dist[0][0].size(); }; - size_t - get_order() {return dist[0][0].size();}; - - xt::xtensor - get_matrix(size_t max_order); + xt::xtensor get_matrix(size_t max_order) override; }; //============================================================================== @@ -208,39 +191,34 @@ class ScattDataHistogram: public ScattData { // f(mu) //============================================================================== -class ScattDataTabular: public ScattData { - - protected: - - xt::xtensor mu; // Angle distribution mu grid points - double dmu; // Quick storage of the mu spacing - double_3dvec fmu; // The angular distribution function +class ScattDataTabular : public ScattData { - // Friend convert_legendre_to_tabular so it has access to protected - // parameters - friend void - convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab); +protected: + xt::xtensor mu; // Angle distribution mu grid points + double dmu; // Quick storage of the mu spacing + double_3dvec fmu; // The angular distribution function - public: + // Friend convert_legendre_to_tabular so it has access to protected + // parameters + friend void convert_legendre_to_tabular( + ScattDataLegendre& leg, ScattDataTabular& tab); - void - init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs); +public: + void init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) override; - void combine( - const vector& those_scatts, const vector& scalars); + void combine(const vector& those_scatts, + const vector& scalars) override; - double - calc_f(int gin, int gout, double mu); + double calc_f(int gin, int gout, double mu) override; - void - sample(int gin, int& gout, double& mu, double& wgt, uint64_t* seed); + void sample( + int gin, int& gout, double& mu, double& wgt, uint64_t* seed) override; - size_t - get_order() {return dist[0][0].size();}; + size_t get_order() override { return dist[0][0].size(); }; - xt::xtensor - get_matrix(size_t max_order); + xt::xtensor get_matrix(size_t max_order) override; }; //============================================================================== @@ -253,9 +231,8 @@ class ScattDataTabular: public ScattData { //! @param leg The resultant ScattDataTabular object. //! @param n_mu The number of mu points to use when building the //! ScattDataTabular object. -void -convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, - int n_mu); +void convert_legendre_to_tabular( + ScattDataLegendre& leg, ScattDataTabular& tab, int n_mu); } // namespace openmc #endif // OPENMC_SCATTDATA_H diff --git a/include/openmc/search.h b/include/openmc/search.h index 446e2916aae..f22cc1858c0 100644 --- a/include/openmc/search.h +++ b/include/openmc/search.h @@ -11,20 +11,19 @@ namespace openmc { //! Perform binary search template -typename std::iterator_traits::difference_type -lower_bound_index(It first, It last, const T& value) +typename std::iterator_traits::difference_type lower_bound_index( + It first, It last, const T& value) { - if (*first == value) return 0; - It index = std::lower_bound(first, last, value) - 1; - return (index == last) ? -1 : index - first; + if (*first == value) + return 0; + return std::lower_bound(first, last, value) - first - 1; } template -typename std::iterator_traits::difference_type -upper_bound_index(It first, It last, const T& value) +typename std::iterator_traits::difference_type upper_bound_index( + It first, It last, const T& value) { - It index = std::upper_bound(first, last, value) - 1; - return (index == last) ? -1 : index - first; + return std::upper_bound(first, last, value) - first - 1; } } // namespace openmc diff --git a/include/openmc/secondary_correlated.h b/include/openmc/secondary_correlated.h index 46910c50788..6905c38e369 100644 --- a/include/openmc/secondary_correlated.h +++ b/include/openmc/secondary_correlated.h @@ -23,11 +23,11 @@ class CorrelatedAngleEnergy : public AngleEnergy { public: //! Outgoing energy/angle at a single incoming energy struct CorrTable { - int n_discrete; //!< Number of discrete lines - Interpolation interpolation; //!< Interpolation law - xt::xtensor e_out; //!< Outgoing energies [eV] - xt::xtensor p; //!< Probability density - xt::xtensor c; //!< Cumulative distribution + int n_discrete; //!< Number of discrete lines + Interpolation interpolation; //!< Interpolation law + xt::xtensor e_out; //!< Outgoing energies [eV] + xt::xtensor p; //!< Probability density + xt::xtensor c; //!< Cumulative distribution vector> angle; //!< Angle distribution }; @@ -38,8 +38,8 @@ class CorrelatedAngleEnergy : public AngleEnergy { //! \param[out] E_out Outgoing energy in [eV] //! \param[out] mu Outgoing cosine with respect to current direction //! \param[inout] seed Pseudorandom seed pointer - void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const override; + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; // energy property vector& energy() { return energy_; } @@ -50,7 +50,7 @@ class CorrelatedAngleEnergy : public AngleEnergy { const vector& distribution() const { return distribution_; } private: - int n_region_; //!< Number of interpolation regions + int n_region_; //!< Number of interpolation regions vector breakpoints_; //!< Breakpoints between regions vector interpolation_; //!< Interpolation laws vector energy_; //!< Energies [eV] at which distributions diff --git a/include/openmc/secondary_kalbach.h b/include/openmc/secondary_kalbach.h index ea9b8199ab8..83806d35248 100644 --- a/include/openmc/secondary_kalbach.h +++ b/include/openmc/secondary_kalbach.h @@ -29,21 +29,22 @@ class KalbachMann : public AngleEnergy { //! \param[out] E_out Outgoing energy in [eV] //! \param[out] mu Outgoing cosine with respect to current direction //! \param[inout] seed Pseudorandom seed pointer - void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const override; + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; + private: //! Outgoing energy/angle at a single incoming energy struct KMTable { - int n_discrete; //!< Number of discrete lines - Interpolation interpolation; //!< Interpolation law + int n_discrete; //!< Number of discrete lines + Interpolation interpolation; //!< Interpolation law xt::xtensor e_out; //!< Outgoing energies [eV] - xt::xtensor p; //!< Probability density - xt::xtensor c; //!< Cumulative distribution - xt::xtensor r; //!< Pre-compound fraction - xt::xtensor a; //!< Parameterized function + xt::xtensor p; //!< Probability density + xt::xtensor c; //!< Cumulative distribution + xt::xtensor r; //!< Pre-compound fraction + xt::xtensor a; //!< Parameterized function }; - int n_region_; //!< Number of interpolation regions + int n_region_; //!< Number of interpolation regions vector breakpoints_; //!< Breakpoints between regions vector interpolation_; //!< Interpolation laws vector energy_; //!< Energies [eV] at which distributions diff --git a/include/openmc/secondary_nbody.h b/include/openmc/secondary_nbody.h index a0f6787adfd..efb4fd75ba1 100644 --- a/include/openmc/secondary_nbody.h +++ b/include/openmc/secondary_nbody.h @@ -25,13 +25,14 @@ class NBodyPhaseSpace : public AngleEnergy { //! \param[out] E_out Outgoing energy in [eV] //! \param[out] mu Outgoing cosine with respect to current direction //! \param[inout] seed Pseudorandom seed pointer - void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const override; + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; + private: - int n_bodies_; //!< Number of particles distributed + int n_bodies_; //!< Number of particles distributed double mass_ratio_; //!< Total mass of particles [neutron mass] - double A_; //!< Atomic weight ratio - double Q_; //!< Reaction Q-value [eV] + double A_; //!< Atomic weight ratio + double Q_; //!< Reaction Q-value [eV] }; } // namespace openmc diff --git a/include/openmc/secondary_thermal.h b/include/openmc/secondary_thermal.h index 9848c37fed7..5b18902afbb 100644 --- a/include/openmc/secondary_thermal.h +++ b/include/openmc/secondary_thermal.h @@ -9,8 +9,8 @@ #include "openmc/secondary_correlated.h" #include "openmc/vector.h" -#include #include "xtensor/xtensor.hpp" +#include namespace openmc { @@ -25,14 +25,14 @@ class CoherentElasticAE : public AngleEnergy { //! \param[in] xs Coherent elastic scattering cross section explicit CoherentElasticAE(const CoherentElasticXS& xs); - //! Sample distribution for an angle and energy //! \param[in] E_in Incoming energy in [eV] //! \param[out] E_out Outgoing energy in [eV] //! \param[out] mu Outgoing cosine with respect to current direction //! \param[inout] seed Pseudorandom seed pointer - void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const override; + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; + private: const CoherentElasticXS& xs_; //!< Coherent elastic scattering cross section }; @@ -53,8 +53,9 @@ class IncoherentElasticAE : public AngleEnergy { //! \param[out] E_out Outgoing energy in [eV] //! \param[out] mu Outgoing cosine with respect to current direction //! \param[inout] seed Pseudorandom number seed pointer - void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const override; + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; + private: double debye_waller_; }; @@ -77,8 +78,9 @@ class IncoherentElasticAEDiscrete : public AngleEnergy { //! \param[out] E_out Outgoing energy in [eV] //! \param[out] mu Outgoing cosine with respect to current direction //! \param[inout] seed Pseudorandom number seed pointer - void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const override; + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; + private: const vector& energy_; //!< Energies at which cosines are tabulated xt::xtensor mu_out_; //!< Cosines for each incident energy @@ -102,12 +104,15 @@ class IncoherentInelasticAEDiscrete : public AngleEnergy { //! \param[out] E_out Outgoing energy in [eV] //! \param[out] mu Outgoing cosine with respect to current direction //! \param[inout] seed Pseudorandom number seed pointer - void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const override; + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; + private: - const vector& energy_; //!< Incident energies - xt::xtensor energy_out_; //!< Outgoing energies for each incident energy - xt::xtensor mu_out_; //!< Outgoing cosines for each incident/outgoing energy + const vector& energy_; //!< Incident energies + xt::xtensor + energy_out_; //!< Outgoing energies for each incident energy + xt::xtensor + mu_out_; //!< Outgoing cosines for each incident/outgoing energy bool skewed_; //!< Whether outgoing energy distribution is skewed }; @@ -127,12 +132,13 @@ class IncoherentInelasticAE : public AngleEnergy { //! \param[out] E_out Outgoing energy in [eV] //! \param[out] mu Outgoing cosine with respect to current direction //! \param[inout] seed Pseudorandom number seed pointer - void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const override; + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; + private: //! Secondary energy/angle distribution struct DistEnergySab { - std::size_t n_e_out; //!< Number of outgoing energies + std::size_t n_e_out; //!< Number of outgoing energies xt::xtensor e_out; //!< Outgoing energies xt::xtensor e_out_pdf; //!< Probability density function xt::xtensor e_out_cdf; //!< Cumulative distribution function @@ -144,6 +150,33 @@ class IncoherentInelasticAE : public AngleEnergy { //!< each incident energy }; +//============================================================================== +//! Mixed coherent/incoherent elastic angle-energy distribution +//============================================================================== + +class MixedElasticAE : public AngleEnergy { +public: + //! Construct from HDF5 file + // + //! \param[in] group HDF5 group + explicit MixedElasticAE( + hid_t group, const CoherentElasticXS& coh_xs, const Function1D& incoh_xs); + + //! Sample distribution for an angle and energy + //! \param[in] E_in Incoming energy in [eV] + //! \param[out] E_out Outgoing energy in [eV] + //! \param[out] mu Outgoing cosine with respect to current direction + //! \param[inout] seed Pseudorandom number seed pointer + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; + +private: + CoherentElasticAE coherent_dist_; //!< Coherent distribution + unique_ptr incoherent_dist_; //!< Incoherent distribution + + const CoherentElasticXS& coherent_xs_; //!< Ref. to coherent XS + const Function1D& incoherent_xs_; //!< Polymorphic ref. to incoherent XS +}; } // namespace openmc diff --git a/include/openmc/secondary_uncorrelated.h b/include/openmc/secondary_uncorrelated.h index 58527047dde..3afa3d9ceb7 100644 --- a/include/openmc/secondary_uncorrelated.h +++ b/include/openmc/secondary_uncorrelated.h @@ -29,13 +29,14 @@ class UncorrelatedAngleEnergy : public AngleEnergy { //! \param[out] E_out Outgoing energy in [eV] //! \param[out] mu Outgoing cosine with respect to current direction //! \param[inout] seed Pseudorandom seed pointer - void sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const override; + void sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const override; // Accessors AngleDistribution& angle() { return angle_; } + private: - AngleDistribution angle_; //!< Angle distribution + AngleDistribution angle_; //!< Angle distribution unique_ptr energy_; //!< Energy distribution }; diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 384f629b0f3..b71ec364931 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -22,90 +22,125 @@ namespace openmc { namespace settings { - // Boolean flags -extern bool assume_separate; //!< assume tallies are spatially separate? -extern bool check_overlaps; //!< check overlaps in geometry? -extern bool confidence_intervals; //!< use confidence intervals for results? -extern bool create_fission_neutrons; //!< create fission neutrons (fixed source)? -extern "C" bool cmfd_run; //!< is a CMFD run? -extern "C" bool dagmc; //!< indicator of DAGMC geometry -extern bool delayed_photon_scaling; //!< Scale fission photon yield to include delayed -extern "C" bool entropy_on; //!< calculate Shannon entropy? -extern bool event_based; //!< use event-based mode (instead of history-based) -extern bool legendre_to_tabular; //!< convert Legendre distributions to tabular? -extern bool material_cell_offsets; //!< create material cells offsets? -extern "C" bool output_summary; //!< write summary.h5? -extern bool output_tallies; //!< write tallies.out? -extern bool particle_restart_run; //!< particle restart run? -extern "C" bool photon_transport; //!< photon transport turned on? -extern "C" bool reduce_tallies; //!< reduce tallies at end of batch? -extern bool res_scat_on; //!< use resonance upscattering method? -extern "C" bool restart_run; //!< restart run? -extern "C" bool run_CE; //!< run with continuous-energy data? -extern bool source_latest; //!< write latest source at each batch? -extern bool source_separate; //!< write source to separate file? -extern bool source_write; //!< write source in HDF5 files? -extern bool surf_source_write; //!< write surface source file? -extern bool surf_source_read; //!< read surface source file? -extern bool survival_biasing; //!< use survival biasing? -extern bool temperature_multipole; //!< use multipole data? -extern "C" bool trigger_on; //!< tally triggers enabled? -extern bool trigger_predict; //!< predict batches for triggers? -extern bool ufs_on; //!< uniform fission site method on? -extern bool urr_ptables_on; //!< use unresolved resonance prob. tables? -extern bool write_all_tracks; //!< write track files for every particle? -extern bool write_initial_source; //!< write out initial source file? +extern bool assume_separate; //!< assume tallies are spatially separate? +extern bool check_overlaps; //!< check overlaps in geometry? +extern bool confidence_intervals; //!< use confidence intervals for results? +extern bool + create_fission_neutrons; //!< create fission neutrons (fixed source)? +extern bool create_delayed_neutrons; //!< create delayed fission neutrons? +extern "C" bool cmfd_run; //!< is a CMFD run? +extern bool + delayed_photon_scaling; //!< Scale fission photon yield to include delayed +extern "C" bool entropy_on; //!< calculate Shannon entropy? +extern "C" bool + event_based; //!< use event-based mode (instead of history-based) +extern bool legendre_to_tabular; //!< convert Legendre distributions to tabular? +extern bool material_cell_offsets; //!< create material cells offsets? +extern "C" bool output_summary; //!< write summary.h5? +extern bool output_tallies; //!< write tallies.out? +extern bool particle_restart_run; //!< particle restart run? +extern "C" bool photon_transport; //!< photon transport turned on? +extern "C" bool reduce_tallies; //!< reduce tallies at end of batch? +extern bool res_scat_on; //!< use resonance upscattering method? +extern "C" bool restart_run; //!< restart run? +extern "C" bool run_CE; //!< run with continuous-energy data? +extern bool source_latest; //!< write latest source at each batch? +extern bool source_separate; //!< write source to separate file? +extern bool source_write; //!< write source in HDF5 files? +extern bool source_mcpl_write; //!< write source in mcpl files? +extern bool surf_source_write; //!< write surface source file? +extern bool surf_mcpl_write; //!< write surface mcpl file? +extern bool surf_source_read; //!< read surface source file? +extern bool survival_biasing; //!< use survival biasing? +extern bool temperature_multipole; //!< use multipole data? +extern "C" bool trigger_on; //!< tally triggers enabled? +extern bool trigger_predict; //!< predict batches for triggers? +extern bool ufs_on; //!< uniform fission site method on? +extern bool urr_ptables_on; //!< use unresolved resonance prob. tables? +extern "C" bool weight_windows_on; //!< are weight windows are enabled? +extern bool weight_window_checkpoint_surface; //!< enable weight window check + //!< upon surface crossing? +extern bool weight_window_checkpoint_collision; //!< enable weight window check + //!< upon collision? +extern bool write_all_tracks; //!< write track files for every particle? +extern bool write_initial_source; //!< write out initial source file? // Paths to various files -extern std::string path_cross_sections; //!< path to cross_sections.xml -extern std::string path_input; //!< directory where main .xml files resides -extern std::string path_output; //!< directory where output files are written +extern std::string path_cross_sections; //!< path to cross_sections.xml +extern std::string path_input; //!< directory where main .xml files resides +extern std::string path_output; //!< directory where output files are written extern std::string path_particle_restart; //!< path to a particle restart file extern std::string path_sourcepoint; //!< path to a source file -extern "C" std::string path_statepoint; //!< path to a statepoint file - -extern "C" int32_t n_inactive; //!< number of inactive batches -extern "C" int32_t max_lost_particles; //!< maximum number of lost particles -extern double rel_max_lost_particles; //!< maximum number of lost particles, relative to the total number of particles -extern "C" int32_t gen_per_batch; //!< number of generations per batch -extern "C" int64_t n_particles; //!< number of particles per generation - - -extern int64_t max_particles_in_flight; //!< Max num. event-based particles in flight - -extern ElectronTreatment electron_treatment; //!< how to treat secondary electrons +extern std::string path_statepoint; //!< path to a statepoint file +extern std::string weight_windows_file; //!< Location of weight window file to + //!< load on simulation initialization + +// This is required because the c_str() may not be the first thing in +// std::string. Sometimes it is, but it seems libc++ may not be like that +// on some computers, like the intel Mac. +extern "C" const char* path_statepoint_c; //!< C pointer to statepoint file name + +extern "C" int32_t n_inactive; //!< number of inactive batches +extern "C" int32_t max_lost_particles; //!< maximum number of lost particles +extern double + rel_max_lost_particles; //!< maximum number of lost particles, relative to the + //!< total number of particles +extern "C" int32_t + max_write_lost_particles; //!< maximum number of lost particles + //!< to be written to files +extern "C" int32_t gen_per_batch; //!< number of generations per batch +extern "C" int64_t n_particles; //!< number of particles per generation + +extern int64_t + max_particles_in_flight; //!< Max num. event-based particles in flight +extern int max_particle_events; //!< Maximum number of particle events +extern ElectronTreatment + electron_treatment; //!< how to treat secondary electrons extern array energy_cutoff; //!< Energy cutoff in [eV] for each particle type -extern int legendre_to_tabular_points; //!< number of points to convert Legendres -extern int max_order; //!< Maximum Legendre order for multigroup data -extern int n_log_bins; //!< number of bins for logarithmic energy grid -extern int n_batches; //!< number of (inactive+active) batches -extern int n_max_batches; //!< Maximum number of batches +extern array + time_cutoff; //!< Time cutoff in [s] for each particle type +extern int + legendre_to_tabular_points; //!< number of points to convert Legendres +extern int max_order; //!< Maximum Legendre order for multigroup data +extern int n_log_bins; //!< number of bins for logarithmic energy grid +extern int n_batches; //!< number of (inactive+active) batches +extern int n_max_batches; //!< Maximum number of batches +extern int max_tracks; //!< Maximum number of particle tracks written to file extern ResScatMethod res_scat_method; //!< resonance upscattering method -extern double res_scat_energy_min; //!< Min energy in [eV] for res. upscattering -extern double res_scat_energy_max; //!< Max energy in [eV] for res. upscattering +extern double res_scat_energy_min; //!< Min energy in [eV] for res. upscattering +extern double res_scat_energy_max; //!< Max energy in [eV] for res. upscattering extern vector - res_scat_nuclides; //!< Nuclides using res. upscattering treatment -extern RunMode run_mode; //!< Run mode (eigenvalue, fixed src, etc.) -extern std::unordered_set sourcepoint_batch; //!< Batches when source should be written -extern std::unordered_set statepoint_batch; //!< Batches when state should be written -extern std::unordered_set source_write_surf_id; //!< Surface ids where sources will be written -extern int64_t max_surface_particles; //!< maximum number of particles to be banked on surfaces per process -extern TemperatureMethod temperature_method; //!< method for choosing temperatures -extern double temperature_tolerance; //!< Tolerance in [K] on choosing temperatures -extern double temperature_default; //!< Default T in [K] + res_scat_nuclides; //!< Nuclides using res. upscattering treatment +extern RunMode run_mode; //!< Run mode (eigenvalue, fixed src, etc.) +extern SolverType solver_type; //!< Solver Type (Monte Carlo or Random Ray) +extern std::unordered_set + sourcepoint_batch; //!< Batches when source should be written +extern std::unordered_set + statepoint_batch; //!< Batches when state should be written +extern std::unordered_set + source_write_surf_id; //!< Surface ids where sources will be written +extern int max_splits; //!< maximum number of particle splits for weight windows +extern int64_t max_surface_particles; //!< maximum number of particles to be + //!< banked on surfaces per process +extern TemperatureMethod + temperature_method; //!< method for choosing temperatures +extern double + temperature_tolerance; //!< Tolerance in [K] on choosing temperatures +extern double temperature_default; //!< Default T in [K] extern array - temperature_range; //!< Min/max T in [K] over which to load xs -extern int trace_batch; //!< Batch to trace particle on -extern int trace_gen; //!< Generation to trace particle on -extern int64_t trace_particle; //!< Particle ID to enable trace on + temperature_range; //!< Min/max T in [K] over which to load xs +extern int trace_batch; //!< Batch to trace particle on +extern int trace_gen; //!< Generation to trace particle on +extern int64_t trace_particle; //!< Particle ID to enable trace on extern vector> - track_identifiers; //!< Particle numbers for writing tracks -extern int trigger_batch_interval; //!< Batch interval for triggers -extern "C" int verbosity; //!< How verbose to make output -extern double weight_cutoff; //!< Weight cutoff for Russian roulette -extern double weight_survive; //!< Survival weight after Russian roulette + track_identifiers; //!< Particle numbers for writing tracks +extern int trigger_batch_interval; //!< Batch interval for triggers +extern "C" int verbosity; //!< How verbose to make output +extern double weight_cutoff; //!< Weight cutoff for Russian roulette +extern double weight_survive; //!< Survival weight after Russian roulette + } // namespace settings //============================================================================== @@ -113,9 +148,12 @@ extern double weight_survive; //!< Survival weight after Russian roulette //============================================================================== //! Read settings from XML file -//! \param[in] root XML node for void read_settings_xml(); +//! Read settings from XML node +//! \param[in] root XML node for +void read_settings_xml(pugi::xml_node root); + void free_memory_settings(); } // namespace openmc diff --git a/include/openmc/shared_array.h b/include/openmc/shared_array.h index 588b8812be2..7e9ef28c580 100644 --- a/include/openmc/shared_array.h +++ b/include/openmc/shared_array.h @@ -20,10 +20,10 @@ namespace openmc { // call the thread_safe_append() function concurrently and store data to the // object at the index returned from thread_safe_append() safely, but no other // operations are protected. -template -class SharedArray { +template +class SharedArray { -public: +public: //========================================================================== // Constructors @@ -45,7 +45,7 @@ class SharedArray { //! Return a reference to the element at specified location i. No bounds //! checking is performed. - T& operator[](int64_t i) {return data_[i];} + T& operator[](int64_t i) { return data_[i]; } const T& operator[](int64_t i) const { return data_[i]; } //! Allocate space in the container for the specified number of elements. @@ -58,7 +58,7 @@ class SharedArray { capacity_ = capacity; } - //! Increase the size of the container by one and append value to the + //! Increase the size of the container by one and append value to the //! array. Returns an index to the element of the array written to. Also //! tests to enforce that the append operation does not read off the end //! of the array. In the event that this does happen, set the size to be @@ -72,12 +72,12 @@ class SharedArray { { // Atomically capture the index we want to write to int64_t idx; - #pragma omp atomic capture seq_cst +#pragma omp atomic capture seq_cst idx = size_++; // Check that we haven't written off the end of the array if (idx >= capacity_) { - #pragma omp atomic write seq_cst +#pragma omp atomic write seq_cst size_ = capacity_; return -1; } @@ -98,32 +98,40 @@ class SharedArray { } //! Return the number of elements in the container - int64_t size() {return size_;} + int64_t size() { return size_; } //! Resize the container to contain a specified number of elements. This is - //! useful in cases where the container is written to in a non-thread safe manner, - //! where the internal size of the array needs to be manually updated. + //! useful in cases where the container is written to in a non-thread safe + //! manner, where the internal size of the array needs to be manually updated. // //! \param size The new size of the container - void resize(int64_t size) {size_ = size;} + void resize(int64_t size) { size_ = size; } + + //! Return whether the array is full + bool full() const { return size_ == capacity_; } //! Return the number of elements that the container has currently allocated //! space for. - int64_t capacity() {return capacity_;} + int64_t capacity() { return capacity_; } //! Return pointer to the underlying array serving as element storage. - T* data() {return data_.get();} - const T* data() const {return data_.get();} + T* data() { return data_.get(); } + const T* data() const { return data_.get(); } + + //! Classic iterators + T* begin() { return data_.get(); } + const T* cbegin() const { return data_.get(); } + T* end() { return data_.get() + size_; } + const T* cend() const { return data_.get() + size_; } -private: +private: //========================================================================== // Data members unique_ptr data_; //!< An RAII handle to the elements - int64_t size_ {0}; //!< The current number of elements + int64_t size_ {0}; //!< The current number of elements int64_t capacity_ {0}; //!< The total space allocated for elements - -}; +}; } // namespace openmc diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index e7f8eb75843..dd8bb7cdfd7 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -22,22 +22,24 @@ constexpr int STATUS_EXIT_ON_TRIGGER {2}; namespace simulation { -extern "C" int current_batch; //!< current batch -extern "C" int current_gen; //!< current fission generation -extern "C" bool initialized; //!< has simulation been initialized? -extern "C" double keff; //!< average k over batches -extern "C" double keff_std; //!< standard deviation of average k -extern "C" double k_col_abs; //!< sum over batches of k_collision * k_absorption -extern "C" double k_col_tra; //!< sum over batches of k_collision * k_tracklength -extern "C" double k_abs_tra; //!< sum over batches of k_absorption * k_tracklength -extern double log_spacing; //!< lethargy spacing for energy grid searches -extern "C" int n_lost_particles; //!< cumulative number of lost particles +extern "C" int current_batch; //!< current batch +extern "C" int current_gen; //!< current fission generation +extern "C" bool initialized; //!< has simulation been initialized? +extern "C" double keff; //!< average k over batches +extern "C" double keff_std; //!< standard deviation of average k +extern "C" double k_col_abs; //!< sum over batches of k_collision * k_absorption +extern "C" double + k_col_tra; //!< sum over batches of k_collision * k_tracklength +extern "C" double + k_abs_tra; //!< sum over batches of k_absorption * k_tracklength +extern double log_spacing; //!< lethargy spacing for energy grid searches +extern "C" int n_lost_particles; //!< cumulative number of lost particles extern "C" bool need_depletion_rx; //!< need to calculate depletion rx? -extern "C" int restart_batch; //!< batch at which a restart job resumed -extern "C" bool satisfy_triggers; //!< have tally triggers been satisfied? -extern "C" int total_gen; //!< total number of generations simulated -extern double total_weight; //!< Total source weight in a batch -extern int64_t work_per_rank; //!< number of particles per MPI rank +extern "C" int restart_batch; //!< batch at which a restart job resumed +extern "C" bool satisfy_triggers; //!< have tally triggers been satisfied? +extern "C" int total_gen; //!< total number of generations simulated +extern double total_weight; //!< Total source weight in a batch +extern int64_t work_per_rank; //!< number of particles per MPI rank extern const RegularMesh* entropy_mesh; extern const RegularMesh* ufs_mesh; diff --git a/include/openmc/source.h b/include/openmc/source.h index 5cbccf27212..9ef8b925127 100644 --- a/include/openmc/source.h +++ b/include/openmc/source.h @@ -4,6 +4,9 @@ #ifndef OPENMC_SOURCE_H #define OPENMC_SOURCE_H +#include +#include + #include "pugixml.hpp" #include "openmc/distribution_multi.h" @@ -14,6 +17,15 @@ namespace openmc { +//============================================================================== +// Constants +//============================================================================== + +// Maximum number of external source spatial resamples to encounter before an +// error is thrown. +constexpr int EXTSRC_REJECT_THRESHOLD {10000}; +constexpr double EXTSRC_REJECT_FRACTION {0.05}; + //============================================================================== // Global variables //============================================================================== @@ -28,27 +40,84 @@ extern vector> external_sources; //============================================================================== //! Abstract source interface +// +//! The Source class provides the interface that must be implemented by derived +//! classes, namely the sample() method that returns a sampled source site. From +//! this base class, source rejection is handled within the +//! sample_with_constraints() method. However, note that some classes directly +//! check for constraints for efficiency reasons (like IndependentSource), in +//! which case the constraints_applied() method indicates that constraints +//! should not be checked a second time from the base class. //============================================================================== class Source { public: + // Constructors, destructors + Source() = default; + explicit Source(pugi::xml_node node); virtual ~Source() = default; - // Methods that must be implemented + // Methods that can be overridden + virtual double strength() const { return strength_; } + + //! Sample a source site and apply constraints + // + //! \param[inout] seed Pseudorandom seed pointer + //! \return Sampled site + SourceSite sample_with_constraints(uint64_t* seed) const; + + //! Sample a source site (without applying constraints) + // + //! Sample from the external source distribution + //! \param[inout] seed Pseudorandom seed pointer + //! \return Sampled site virtual SourceSite sample(uint64_t* seed) const = 0; - // Methods that can be overridden - virtual double strength() const { return 1.0; } + static unique_ptr create(pugi::xml_node node); + +protected: + // Domain types + enum class DomainType { UNIVERSE, MATERIAL, CELL }; + + // Strategy used for rejecting sites when constraints are applied. KILL means + // that sites are always accepted but if they don't satisfy constraints, they + // are given weight 0. RESAMPLE means that a new source site will be sampled + // until constraints are met. + enum class RejectionStrategy { KILL, RESAMPLE }; + + // Indicates whether derived class already handles constraints + virtual bool constraints_applied() const { return false; } + + // Methods for constraints + void read_constraints(pugi::xml_node node); + bool satisfies_spatial_constraints(Position r) const; + bool satisfies_energy_constraints(double E) const; + bool satisfies_time_constraints(double time) const; + + // Data members + double strength_ {1.0}; //!< Source strength + std::unordered_set domain_ids_; //!< Domains to reject from + DomainType domain_type_; //!< Domain type for rejection + std::pair time_bounds_ {-std::numeric_limits::max(), + std::numeric_limits::max()}; //!< time limits + std::pair energy_bounds_ { + 0, std::numeric_limits::max()}; //!< energy limits + bool only_fissionable_ { + false}; //!< Whether site must be in fissionable material + RejectionStrategy rejection_strategy_ { + RejectionStrategy::RESAMPLE}; //!< Procedure for rejecting }; //============================================================================== -//! Source composed of independent spatial, angle, and energy distributions +//! Source composed of independent spatial, angle, energy, and time +//! distributions //============================================================================== class IndependentSource : public Source { public: // Constructors - IndependentSource(UPtrSpace space, UPtrAngle angle, UPtrDist energy); + IndependentSource( + UPtrSpace space, UPtrAngle angle, UPtrDist energy, UPtrDist time); explicit IndependentSource(pugi::xml_node node); //! Sample from the external source distribution @@ -58,19 +127,24 @@ class IndependentSource : public Source { // Properties ParticleType particle_type() const { return particle_; } - double strength() const override { return strength_; } // Make observing pointers available SpatialDistribution* space() const { return space_.get(); } UnitSphereDistribution* angle() const { return angle_.get(); } Distribution* energy() const { return energy_.get(); } + Distribution* time() const { return time_.get(); } + +protected: + // Indicates whether derived class already handles constraints + bool constraints_applied() const override { return true; } private: + // Data members ParticleType particle_ {ParticleType::neutron}; //!< Type of particle emitted - double strength_ {1.0}; //!< Source strength - UPtrSpace space_; //!< Spatial distribution - UPtrAngle angle_; //!< Angular distribution - UPtrDist energy_; //!< Energy distribution + UPtrSpace space_; //!< Spatial distribution + UPtrAngle angle_; //!< Angular distribution + UPtrDist energy_; //!< Energy distribution + UPtrDist time_; //!< Time distribution }; //============================================================================== @@ -80,9 +154,14 @@ class IndependentSource : public Source { class FileSource : public Source { public: // Constructors - explicit FileSource(std::string path); + explicit FileSource(pugi::xml_node node); + explicit FileSource(const std::string& path); // Methods + void load_sites_from_file( + const std::string& path); //!< Load source sites from file + +protected: SourceSite sample(uint64_t* seed) const override; private: @@ -93,25 +172,61 @@ class FileSource : public Source { //! Wrapper for custom sources that manages opening/closing shared library //============================================================================== -class CustomSourceWrapper : public Source { +class CompiledSourceWrapper : public Source { public: // Constructors, destructors - CustomSourceWrapper(std::string path, std::string parameters); - ~CustomSourceWrapper(); + CompiledSourceWrapper(pugi::xml_node node); + ~CompiledSourceWrapper(); + + double strength() const override { return compiled_source_->strength(); } + void setup(const std::string& path, const std::string& parameters); + +protected: // Defer implementation to custom source library SourceSite sample(uint64_t* seed) const override { - return custom_source_->sample(seed); + return compiled_source_->sample(seed); } - double strength() const override { return custom_source_->strength(); } private: void* shared_library_; //!< library from dlopen - unique_ptr custom_source_; + unique_ptr compiled_source_; }; -typedef unique_ptr create_custom_source_t(std::string parameters); +typedef unique_ptr create_compiled_source_t(std::string parameters); + +//============================================================================== +//! Mesh-based source with different distributions for each element +//============================================================================== + +class MeshSource : public Source { +public: + // Constructors + explicit MeshSource(pugi::xml_node node); + + //! Sample from the external source distribution + //! \param[inout] seed Pseudorandom seed pointer + //! \return Sampled site + SourceSite sample(uint64_t* seed) const override; + + // Properties + double strength() const override { return space_->total_strength(); } + + // Accessors + const std::unique_ptr& source(int32_t i) const + { + return sources_.size() == 1 ? sources_[0] : sources_[i]; + } + +protected: + bool constraints_applied() const override { return true; } + +private: + // Data members + unique_ptr space_; //!< Mesh spatial + vector> sources_; //!< Source distributions +}; //============================================================================== // Functions diff --git a/include/openmc/state_point.h b/include/openmc/state_point.h index 5ada2bf88dc..95524f6b622 100644 --- a/include/openmc/state_point.h +++ b/include/openmc/state_point.h @@ -3,18 +3,44 @@ #include +#include + #include "hdf5.h" #include "openmc/capi.h" #include "openmc/particle.h" +#include "openmc/shared_array.h" #include "openmc/vector.h" namespace openmc { void load_state_point(); -vector calculate_surf_source_size(); -void write_source_point(const char* filename, bool surf_source_bank = false); -void write_source_bank(hid_t group_id, bool surf_source_bank); + +// By passing in a filename, source bank, and list of source indices +// on each MPI rank, this writes an HDF5 file which contains that +// information which can later be read in by read_source_bank +// (defined below). If you're writing code to write out a new kind +// of particle bank, this function is the one you want to use! +// +// For example, this is used to write both the surface source sites +// or fission source sites for eigenvalue continuation runs. +// +// This function ends up calling write_source_bank, and is responsible +// for opening the file to be written to and controlling whether the +// write is done in parallel (if compiled with parallel HDF5). +// +// bank_index is an exclusive parallel scan of the source_bank.size() +// values on each rank, used to create global indexing. This vector +// can be created by calling calculate_parallel_index_vector on +// source_bank.size() if such a vector is not already available. +void write_source_point(const char* filename, gsl::span source_bank, + const vector& bank_index); + +// This appends a source bank specification to an HDF5 file +// that's already open. It is used internally by write_source_point. +void write_source_bank(hid_t group_id, gsl::span source_bank, + const vector& bank_index); + void read_source_bank( hid_t group_id, vector& sites, bool distribute); void write_tally_results_nr(hid_t file_id); diff --git a/include/openmc/summary.h b/include/openmc/summary.h index ff2ab71a897..10e445aed66 100644 --- a/include/openmc/summary.h +++ b/include/openmc/summary.h @@ -11,6 +11,6 @@ void write_nuclides(hid_t file); void write_geometry(hid_t file); void write_materials(hid_t file); -} +} // namespace openmc #endif // OPENMC_SUMMARY_H diff --git a/include/openmc/surface.h b/include/openmc/surface.h index 5a8a88aa41d..350775123c1 100644 --- a/include/openmc/surface.h +++ b/include/openmc/surface.h @@ -1,14 +1,13 @@ #ifndef OPENMC_SURFACE_H #define OPENMC_SURFACE_H -#include // For numeric_limits +#include // For numeric_limits #include #include #include "hdf5.h" #include "pugixml.hpp" -#include "dagmc.h" #include "openmc/boundary_condition.h" #include "openmc/constants.h" #include "openmc/memory.h" // for unique_ptr @@ -25,16 +24,15 @@ namespace openmc { class Surface; namespace model { - extern std::unordered_map surface_map; - extern vector> surfaces; +extern std::unordered_map surface_map; +extern vector> surfaces; } // namespace model //============================================================================== -//! Coordinates for an axis-aligned cuboid bounding a geometric object. +//! Coordinates for an axis-aligned cuboid that bounds a geometric object. //============================================================================== -struct BoundingBox -{ +struct BoundingBox { double xmin = -INFTY; double xmax = INFTY; double ymin = -INFTY; @@ -42,19 +40,21 @@ struct BoundingBox double zmin = -INFTY; double zmax = INFTY; - - inline BoundingBox operator &(const BoundingBox& other) { + inline BoundingBox operator&(const BoundingBox& other) + { BoundingBox result = *this; return result &= other; } - inline BoundingBox operator |(const BoundingBox& other) { + inline BoundingBox operator|(const BoundingBox& other) + { BoundingBox result = *this; return result |= other; } // intersect operator - inline BoundingBox& operator &=(const BoundingBox& other) { + inline BoundingBox& operator&=(const BoundingBox& other) + { xmin = std::max(xmin, other.xmin); xmax = std::min(xmax, other.xmax); ymin = std::max(ymin, other.ymin); @@ -65,7 +65,8 @@ struct BoundingBox } // union operator - inline BoundingBox& operator |=(const BoundingBox& other) { + inline BoundingBox& operator|=(const BoundingBox& other) + { xmin = std::min(xmin, other.xmin); xmax = std::max(xmax, other.xmax); ymin = std::min(ymin, other.ymin); @@ -74,21 +75,19 @@ struct BoundingBox zmax = std::max(zmax, other.zmax); return *this; } - }; //============================================================================== //! A geometry primitive used to define regions of 3D space. //============================================================================== -class Surface -{ +class Surface { public: - - int id_; //!< Unique ID - std::string name_; //!< User-defined name - std::shared_ptr bc_ {nullptr}; //!< Boundary condition - bool surf_source_ {false}; //!< Activate source banking for the surface? + int id_; //!< Unique ID + std::string name_; //!< User-defined name + unique_ptr bc_; //!< Boundary condition + GeometryType geom_type_; //!< Geometry type indicator (CSG or DAGMC) + bool surf_source_ {false}; //!< Activate source banking for the surface? explicit Surface(pugi::xml_node surf_node); Surface(); @@ -106,12 +105,13 @@ class Surface //! Determine the direction of a ray reflected from the surface. //! \param[in] r The point at which the ray is incident. //! \param[in] u Incident direction of the ray - //! \param[inout] p Pointer to the particle + //! \param[inout] p Pointer to the particle. Only DAGMC uses this. //! \return Outgoing direction of the ray - virtual Direction reflect(Position r, Direction u, Particle* p) const; + virtual Direction reflect( + Position r, Direction u, GeometryState* p = nullptr) const; - virtual Direction diffuse_reflect(Position r, Direction u, - uint64_t* seed) const; + virtual Direction diffuse_reflect( + Position r, Direction u, uint64_t* seed, GeometryState* p = nullptr) const; //! Evaluate the equation describing the surface. //! @@ -134,44 +134,20 @@ class Surface //! Write all information needed to reconstruct the surface to an HDF5 group. //! \param group_id An HDF5 group id. - virtual void to_hdf5(hid_t group_id) const = 0; + void to_hdf5(hid_t group_id) const; //! Get the BoundingBox for this surface. virtual BoundingBox bounding_box(bool /*pos_side*/) const { return {}; } -}; - -class CSGSurface : public Surface -{ -public: - explicit CSGSurface(pugi::xml_node surf_node); - CSGSurface(); - - void to_hdf5(hid_t group_id) const; protected: virtual void to_hdf5_inner(hid_t group_id) const = 0; }; -//============================================================================== -//! A `Surface` representing a DAGMC-based surface in DAGMC. -//============================================================================== -#ifdef DAGMC -class DAGSurface : public Surface -{ +class CSGSurface : public Surface { public: - DAGSurface(); - - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - Direction reflect(Position r, Direction u, Particle* p) const; - - void to_hdf5(hid_t group_id) const; - - moab::DagMC* dagmc_ptr_; //!< Pointer to DagMC instance - int32_t dag_index_; //!< DagMC index of surface + explicit CSGSurface(pugi::xml_node surf_node); + CSGSurface(); }; -#endif //============================================================================== //! A plane perpendicular to the x-axis. @@ -179,15 +155,14 @@ class DAGSurface : public Surface //! The plane is described by the equation \f$x - x_0 = 0\f$ //============================================================================== -class SurfaceXPlane : public CSGSurface -{ +class SurfaceXPlane : public CSGSurface { public: explicit SurfaceXPlane(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; - BoundingBox bounding_box(bool pos_side) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + BoundingBox bounding_box(bool pos_side) const override; double x0_; }; @@ -198,15 +173,14 @@ class SurfaceXPlane : public CSGSurface //! The plane is described by the equation \f$y - y_0 = 0\f$ //============================================================================== -class SurfaceYPlane : public CSGSurface -{ +class SurfaceYPlane : public CSGSurface { public: explicit SurfaceYPlane(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; - BoundingBox bounding_box(bool pos_side) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + BoundingBox bounding_box(bool pos_side) const override; double y0_; }; @@ -217,15 +191,14 @@ class SurfaceYPlane : public CSGSurface //! The plane is described by the equation \f$z - z_0 = 0\f$ //============================================================================== -class SurfaceZPlane : public CSGSurface -{ +class SurfaceZPlane : public CSGSurface { public: explicit SurfaceZPlane(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; - BoundingBox bounding_box(bool pos_side) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + BoundingBox bounding_box(bool pos_side) const override; double z0_; }; @@ -236,14 +209,13 @@ class SurfaceZPlane : public CSGSurface //! The plane is described by the equation \f$A x + B y + C z - D = 0\f$ //============================================================================== -class SurfacePlane : public CSGSurface -{ +class SurfacePlane : public CSGSurface { public: explicit SurfacePlane(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; double A_, B_, C_, D_; }; @@ -255,15 +227,14 @@ class SurfacePlane : public CSGSurface //! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceXCylinder : public CSGSurface -{ +class SurfaceXCylinder : public CSGSurface { public: explicit SurfaceXCylinder(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; - BoundingBox bounding_box(bool pos_side) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + BoundingBox bounding_box(bool pos_side) const override; double y0_, z0_, radius_; }; @@ -275,15 +246,14 @@ class SurfaceXCylinder : public CSGSurface //! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceYCylinder : public CSGSurface -{ +class SurfaceYCylinder : public CSGSurface { public: explicit SurfaceYCylinder(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; - BoundingBox bounding_box(bool pos_side) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + BoundingBox bounding_box(bool pos_side) const override; double x0_, z0_, radius_; }; @@ -295,15 +265,14 @@ class SurfaceYCylinder : public CSGSurface //! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceZCylinder : public CSGSurface -{ +class SurfaceZCylinder : public CSGSurface { public: explicit SurfaceZCylinder(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; - BoundingBox bounding_box(bool pos_side) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + BoundingBox bounding_box(bool pos_side) const override; double x0_, y0_, radius_; }; @@ -315,15 +284,14 @@ class SurfaceZCylinder : public CSGSurface //! \f$(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 - R^2 = 0\f$ //============================================================================== -class SurfaceSphere : public CSGSurface -{ +class SurfaceSphere : public CSGSurface { public: explicit SurfaceSphere(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; - BoundingBox bounding_box(bool pos_side) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + BoundingBox bounding_box(bool pos_side) const override; double x0_, y0_, z0_, radius_; }; @@ -335,14 +303,13 @@ class SurfaceSphere : public CSGSurface //! \f$(y - y_0)^2 + (z - z_0)^2 - R^2 (x - x_0)^2 = 0\f$ //============================================================================== -class SurfaceXCone : public CSGSurface -{ +class SurfaceXCone : public CSGSurface { public: explicit SurfaceXCone(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; double x0_, y0_, z0_, radius_sq_; }; @@ -354,14 +321,13 @@ class SurfaceXCone : public CSGSurface //! \f$(x - x_0)^2 + (z - z_0)^2 - R^2 (y - y_0)^2 = 0\f$ //============================================================================== -class SurfaceYCone : public CSGSurface -{ +class SurfaceYCone : public CSGSurface { public: explicit SurfaceYCone(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; double x0_, y0_, z0_, radius_sq_; }; @@ -373,14 +339,13 @@ class SurfaceYCone : public CSGSurface //! \f$(x - x_0)^2 + (y - y_0)^2 - R^2 (z - z_0)^2 = 0\f$ //============================================================================== -class SurfaceZCone : public CSGSurface -{ +class SurfaceZCone : public CSGSurface { public: explicit SurfaceZCone(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; double x0_, y0_, z0_, radius_sq_; }; @@ -388,22 +353,73 @@ class SurfaceZCone : public CSGSurface //============================================================================== //! A general surface described by a quadratic equation. // -//! \f$A x^2 + B y^2 + C z^2 + D x y + E y z + F x z + G x + H y + J z + K = 0\f$ +//! \f$A x^2 + B y^2 + C z^2 + D x y + E y z + F x z + G x + H y + J z + K = +//! 0\f$ //============================================================================== -class SurfaceQuadric : public CSGSurface -{ +class SurfaceQuadric : public CSGSurface { public: explicit SurfaceQuadric(pugi::xml_node surf_node); - double evaluate(Position r) const; - double distance(Position r, Direction u, bool coincident) const; - Direction normal(Position r) const; - void to_hdf5_inner(hid_t group_id) const; + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; // Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + Jz + K = 0 double A_, B_, C_, D_, E_, F_, G_, H_, J_, K_; }; +//============================================================================== +//! A toroidal surface described by the quartic torus lies in the x direction +// +//! \f$(x-x_0)^2/B^2 + (\sqrt{(y-y_0)^2 + (z-z_0)^2} - A)^2/C^2 -1 \f$ +//============================================================================== + +class SurfaceXTorus : public CSGSurface { +public: + explicit SurfaceXTorus(pugi::xml_node surf_node); + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + + double x0_, y0_, z0_, A_, B_, C_; +}; + +//============================================================================== +//! A toroidal surface described by the quartic torus lies in the y direction +// +//! \f$(y-y_0)^2/B^2 + (\sqrt{(x-x_0)^2 + (z-z_0)^2} - A)^2/C^2 -1 \f$ +//============================================================================== + +class SurfaceYTorus : public CSGSurface { +public: + explicit SurfaceYTorus(pugi::xml_node surf_node); + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + + double x0_, y0_, z0_, A_, B_, C_; +}; + +//============================================================================== +//! A toroidal surface described by the quartic torus lies in the z direction +// +//! \f$(z-z_0)^2/B^2 + (\sqrt{(x-x_0)^2 + (y-y_0)^2} - A)^2/C^2 -1 \f$ +//============================================================================== + +class SurfaceZTorus : public CSGSurface { +public: + explicit SurfaceZTorus(pugi::xml_node surf_node); + double evaluate(Position r) const override; + double distance(Position r, Direction u, bool coincident) const override; + Direction normal(Position r) const override; + void to_hdf5_inner(hid_t group_id) const override; + + double x0_, y0_, z0_, A_, B_, C_; +}; + //============================================================================== // Non-member functions //============================================================================== diff --git a/include/openmc/tallies/derivative.h b/include/openmc/tallies/derivative.h index d3a7b8b2080..38362e85fb2 100644 --- a/include/openmc/tallies/derivative.h +++ b/include/openmc/tallies/derivative.h @@ -15,18 +15,14 @@ namespace openmc { // Different independent variables -enum class DerivativeVariable { - DENSITY, - NUCLIDE_DENSITY, - TEMPERATURE -}; +enum class DerivativeVariable { DENSITY, NUCLIDE_DENSITY, TEMPERATURE }; struct TallyDerivative { - DerivativeVariable variable; //!< Independent variable (like temperature) - int id; //!< User-defined identifier - int diff_material; //!< Material this derivative is applied to - int diff_nuclide; //!< Nuclide this material is applied to + DerivativeVariable variable; //!< Independent variable (like temperature) + int id; //!< User-defined identifier + int diff_material; //!< Material this derivative is applied to + int diff_nuclide; //!< Nuclide this material is applied to TallyDerivative() {} explicit TallyDerivative(pugi::xml_node node); @@ -41,8 +37,7 @@ void read_tally_derivatives(pugi::xml_node node); //! Scale the given score by its logarithmic derivative -void -apply_derivative_to_score(const Particle& p, int i_tally, int i_nuclide, +void apply_derivative_to_score(const Particle& p, int i_tally, int i_nuclide, double atom_density, int score_bin, double& score); //! Adjust diff tally flux derivatives for a particle scattering event. diff --git a/include/openmc/tallies/filter.h b/include/openmc/tallies/filter.h index 9620632a340..1166c0eee53 100644 --- a/include/openmc/tallies/filter.h +++ b/include/openmc/tallies/filter.h @@ -6,7 +6,7 @@ #include #include "pugixml.hpp" -#include +#include #include "openmc/constants.h" #include "openmc/hdf5_interface.h" @@ -17,12 +17,41 @@ namespace openmc { +enum class FilterType { + AZIMUTHAL, + CELLBORN, + CELLFROM, + CELL, + CELL_INSTANCE, + COLLISION, + DELAYED_GROUP, + DISTRIBCELL, + ENERGY_FUNCTION, + ENERGY, + ENERGY_OUT, + LEGENDRE, + MATERIAL, + MATERIALFROM, + MESH, + MESHBORN, + MESH_SURFACE, + MU, + PARTICLE, + POLAR, + SPHERICAL_HARMONICS, + SPATIAL_LEGENDRE, + SURFACE, + TIME, + UNIVERSE, + ZERNIKE, + ZERNIKE_RADIAL +}; + //============================================================================== //! Modifies tally score events. //============================================================================== -class Filter -{ +class Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors, factory functions @@ -59,7 +88,8 @@ class Filter //---------------------------------------------------------------------------- // Methods - virtual std::string type() const = 0; + virtual std::string type_str() const = 0; + virtual FilterType type() const = 0; //! Matches a tally event to a set of filter bins and weights. //! @@ -67,14 +97,13 @@ class Filter //! \param[in] estimator Tally estimator being used //! \param[out] match will contain the matching bins and corresponding //! weights; note that there may be zero matching bins - virtual void - get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) const = 0; + virtual void get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const = 0; //! Writes data describing this filter to an HDF5 statepoint group. - virtual void - to_statepoint(hid_t filter_group) const + virtual void to_statepoint(hid_t filter_group) const { - write_dataset(filter_group, "type", type()); + write_dataset(filter_group, "type", type_str()); write_dataset(filter_group, "n_bins", n_bins_); } @@ -107,6 +136,7 @@ class Filter protected: int n_bins_; + private: int32_t id_ {C_NONE}; gsl::index index_; @@ -117,10 +147,10 @@ class Filter //============================================================================== namespace model { - extern "C" int32_t n_filters; - extern std::unordered_map filter_map; - extern vector> tally_filters; -} +extern "C" int32_t n_filters; +extern std::unordered_map filter_map; +extern vector> tally_filters; +} // namespace model //============================================================================== // Non-member functions @@ -129,5 +159,24 @@ namespace model { //! Make sure index corresponds to a valid filter int verify_filter(int32_t index); +//============================================================================== +// Filter implementation +//============================================================================== + +template +T* Filter::create(int32_t id) +{ + static_assert(std::is_base_of::value, + "Type specified is not derived from openmc::Filter"); + // Create filter and add to filters vector + auto filter = make_unique(); + auto ptr_out = filter.get(); + model::tally_filters.emplace_back(std::move(filter)); + // Assign ID + model::tally_filters.back()->set_id(id); + + return ptr_out; +} + } // namespace openmc #endif // OPENMC_TALLIES_FILTER_H diff --git a/include/openmc/tallies/filter_azimuthal.h b/include/openmc/tallies/filter_azimuthal.h index d1c46823306..37e1ef07356 100644 --- a/include/openmc/tallies/filter_azimuthal.h +++ b/include/openmc/tallies/filter_azimuthal.h @@ -4,7 +4,7 @@ #include "openmc/vector.h" #include -#include +#include #include "openmc/tallies/filter.h" @@ -14,8 +14,7 @@ namespace openmc { //! Bins the incident neutron azimuthal angle (relative to the global xy-plane). //============================================================================== -class AzimuthalFilter : public Filter -{ +class AzimuthalFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -25,12 +24,13 @@ class AzimuthalFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "azimuthal";} + std::string type_str() const override { return "azimuthal"; } + FilterType type() const override { return FilterType::AZIMUTHAL; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_cell.h b/include/openmc/tallies/filter_cell.h index e4180148f45..b7ea01ce6cb 100644 --- a/include/openmc/tallies/filter_cell.h +++ b/include/openmc/tallies/filter_cell.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -15,8 +15,7 @@ namespace openmc { //! Specifies which geometric cells tally events reside in. //============================================================================== -class CellFilter : public Filter -{ +class CellFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -26,12 +25,13 @@ class CellFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "cell";} + std::string type_str() const override { return "cell"; } + FilterType type() const override { return FilterType::CELL; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_cell_instance.h b/include/openmc/tallies/filter_cell_instance.h index dee9b8bea4f..f500f48896f 100644 --- a/include/openmc/tallies/filter_cell_instance.h +++ b/include/openmc/tallies/filter_cell_instance.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include "openmc/cell.h" #include "openmc/tallies/filter.h" @@ -28,12 +28,13 @@ class CellInstanceFilter : public Filter { //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "cellinstance";} + std::string type_str() const override { return "cellinstance"; } + FilterType type() const override { return FilterType::CELL_INSTANCE; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; @@ -44,6 +45,8 @@ class CellInstanceFilter : public Filter { const vector& cell_instances() const { return cell_instances_; } + const std::unordered_set& cells() const { return cells_; } + void set_cell_instances(gsl::span instances); private: @@ -53,8 +56,14 @@ class CellInstanceFilter : public Filter { //! The indices of the cells binned by this filter. vector cell_instances_; + //! The set of cells used in this filter + std::unordered_set cells_; + //! A map from cell/instance indices to filter bin indices. std::unordered_map map_; + + //! Indicates if filter uses only material-filled cells + bool material_cells_only_; }; } // namespace openmc diff --git a/include/openmc/tallies/filter_cellborn.h b/include/openmc/tallies/filter_cellborn.h index e1e1225dda4..417aedeced1 100644 --- a/include/openmc/tallies/filter_cellborn.h +++ b/include/openmc/tallies/filter_cellborn.h @@ -11,16 +11,16 @@ namespace openmc { //! Specifies which cell the particle was born in. //============================================================================== -class CellbornFilter : public CellFilter -{ +class CellBornFilter : public CellFilter { public: //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "cellborn";} + std::string type_str() const override { return "cellborn"; } + FilterType type() const override { return FilterType::CELLBORN; } - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; std::string text_label(int bin) const override; }; diff --git a/include/openmc/tallies/filter_cellfrom.h b/include/openmc/tallies/filter_cellfrom.h index cf11937bd91..61ff50b055c 100644 --- a/include/openmc/tallies/filter_cellfrom.h +++ b/include/openmc/tallies/filter_cellfrom.h @@ -11,16 +11,16 @@ namespace openmc { //! Specifies which geometric cells particles exit when crossing a surface. //============================================================================== -class CellFromFilter : public CellFilter -{ +class CellFromFilter : public CellFilter { public: //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "cellfrom";} + std::string type_str() const override { return "cellfrom"; } + FilterType type() const override { return FilterType::CELLFROM; } - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; std::string text_label(int bin) const override; }; diff --git a/include/openmc/tallies/filter_collision.h b/include/openmc/tallies/filter_collision.h index 1b23bd44037..d2dab70ca06 100644 --- a/include/openmc/tallies/filter_collision.h +++ b/include/openmc/tallies/filter_collision.h @@ -1,8 +1,8 @@ #ifndef OPENMC_TALLIES_FILTER_COLLISIONS_H #define OPENMC_TALLIES_FILTER_COLLISIONS_H +#include #include -#include #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -23,11 +23,12 @@ class CollisionFilter : public Filter { //---------------------------------------------------------------------------- // Methods - std::string type() const override { return "collision"; } + std::string type_str() const override { return "collision"; } + FilterType type() const override { return FilterType::COLLISION; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, + void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; @@ -46,8 +47,7 @@ class CollisionFilter : public Filter { vector bins_; - std::unordered_map map_; - + std::unordered_map map_; }; } // namespace openmc diff --git a/include/openmc/tallies/filter_delayedgroup.h b/include/openmc/tallies/filter_delayedgroup.h index 63987e3390f..71919b2ece5 100644 --- a/include/openmc/tallies/filter_delayedgroup.h +++ b/include/openmc/tallies/filter_delayedgroup.h @@ -1,7 +1,7 @@ #ifndef OPENMC_TALLIES_FILTER_DELAYEDGROUP_H #define OPENMC_TALLIES_FILTER_DELAYEDGROUP_H -#include +#include #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -15,8 +15,7 @@ namespace openmc { //! iterated over in the scoring subroutines. //============================================================================== -class DelayedGroupFilter : public Filter -{ +class DelayedGroupFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -26,12 +25,13 @@ class DelayedGroupFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "delayedgroup";} + std::string type_str() const override { return "delayedgroup"; } + FilterType type() const override { return FilterType::DELAYED_GROUP; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_distribcell.h b/include/openmc/tallies/filter_distribcell.h index 68cb694e793..b5cdcce84c9 100644 --- a/include/openmc/tallies/filter_distribcell.h +++ b/include/openmc/tallies/filter_distribcell.h @@ -11,8 +11,7 @@ namespace openmc { //! Specifies which distributed geometric cells tally events reside in. //============================================================================== -class DistribcellFilter : public Filter -{ +class DistribcellFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -22,12 +21,13 @@ class DistribcellFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "distribcell";} + std::string type_str() const override { return "distribcell"; } + FilterType type() const override { return FilterType::DISTRIBCELL; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_energy.h b/include/openmc/tallies/filter_energy.h index 2db0231e2c6..e35e01a6dae 100644 --- a/include/openmc/tallies/filter_energy.h +++ b/include/openmc/tallies/filter_energy.h @@ -1,7 +1,7 @@ #ifndef OPENMC_TALLIES_FILTER_ENERGY_H #define OPENMC_TALLIES_FILTER_ENERGY_H -#include +#include #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -12,8 +12,7 @@ namespace openmc { //! Bins the incident neutron energy. //============================================================================== -class EnergyFilter : public Filter -{ +class EnergyFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -23,12 +22,13 @@ class EnergyFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "energy";} + std::string type_str() const override { return "energy"; } + FilterType type() const override { return FilterType::ENERGY; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; @@ -59,16 +59,16 @@ class EnergyFilter : public Filter //! tallies manually iterate over the filter bins. //============================================================================== -class EnergyoutFilter : public EnergyFilter -{ +class EnergyoutFilter : public EnergyFilter { public: //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "energyout";} + std::string type_str() const override { return "energyout"; } + FilterType type() const override { return FilterType::ENERGY_OUT; } - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; std::string text_label(int bin) const override; }; diff --git a/include/openmc/tallies/filter_energyfunc.h b/include/openmc/tallies/filter_energyfunc.h index 5c131ba69f2..d77ef0fa839 100644 --- a/include/openmc/tallies/filter_energyfunc.h +++ b/include/openmc/tallies/filter_energyfunc.h @@ -1,6 +1,7 @@ #ifndef OPENMC_TALLIES_FILTER_ENERGYFUNC_H #define OPENMC_TALLIES_FILTER_ENERGYFUNC_H +#include "openmc/constants.h" #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -11,29 +12,25 @@ namespace openmc { //! described by a piecewise linear-linear interpolation. //============================================================================== -class EnergyFunctionFilter : public Filter -{ +class EnergyFunctionFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors - EnergyFunctionFilter() - : Filter {} - { - n_bins_ = 1; - } + EnergyFunctionFilter() : Filter {} { n_bins_ = 1; } ~EnergyFunctionFilter() = default; //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "energyfunction";} + std::string type_str() const override { return "energyfunction"; } + FilterType type() const override { return FilterType::ENERGY_FUNCTION; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; @@ -44,7 +41,9 @@ class EnergyFunctionFilter : public Filter const vector& energy() const { return energy_; } const vector& y() const { return y_; } + Interpolation interpolation() const { return interpolation_; } void set_data(gsl::span energy, gsl::span y); + void set_interpolation(const std::string& interpolation); private: //---------------------------------------------------------------------------- @@ -55,6 +54,9 @@ class EnergyFunctionFilter : public Filter //! Interpolant values. vector y_; + + //! Interpolation scheme + Interpolation interpolation_ {Interpolation::lin_lin}; }; } // namespace openmc diff --git a/include/openmc/tallies/filter_legendre.h b/include/openmc/tallies/filter_legendre.h index 5a489b94651..839fd77bfe7 100644 --- a/include/openmc/tallies/filter_legendre.h +++ b/include/openmc/tallies/filter_legendre.h @@ -11,8 +11,7 @@ namespace openmc { //! Gives Legendre moments of the change in scattering angle //============================================================================== -class LegendreFilter : public Filter -{ +class LegendreFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -22,12 +21,13 @@ class LegendreFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "legendre";} + std::string type_str() const override { return "legendre"; } + FilterType type() const override { return FilterType::LEGENDRE; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_match.h b/include/openmc/tallies/filter_match.h index b07656f175a..613a729f5d6 100644 --- a/include/openmc/tallies/filter_match.h +++ b/include/openmc/tallies/filter_match.h @@ -1,15 +1,13 @@ #ifndef OPENMC_TALLIES_FILTERMATCH_H #define OPENMC_TALLIES_FILTERMATCH_H - namespace openmc { //============================================================================== //! Stores bins and weights for filtered tally events. //============================================================================== -class FilterMatch -{ +class FilterMatch { public: vector bins_; vector weights_; diff --git a/include/openmc/tallies/filter_material.h b/include/openmc/tallies/filter_material.h index 65bfce04eb4..aa5df5b3ab2 100644 --- a/include/openmc/tallies/filter_material.h +++ b/include/openmc/tallies/filter_material.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -15,8 +15,7 @@ namespace openmc { //! Specifies which material tally events reside in. //============================================================================== -class MaterialFilter : public Filter -{ +class MaterialFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -26,12 +25,13 @@ class MaterialFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "material";} + std::string type_str() const override { return "material"; } + FilterType type() const override { return FilterType::MATERIAL; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; @@ -46,7 +46,7 @@ class MaterialFilter : public Filter void set_materials(gsl::span materials); -private: +protected: //---------------------------------------------------------------------------- // Data members diff --git a/include/openmc/tallies/filter_materialfrom.h b/include/openmc/tallies/filter_materialfrom.h new file mode 100644 index 00000000000..52039852a5d --- /dev/null +++ b/include/openmc/tallies/filter_materialfrom.h @@ -0,0 +1,29 @@ +#ifndef OPENMC_TALLIES_FILTER_MATERIALFROM_H +#define OPENMC_TALLIES_FILTER_MATERIALFROM_H + +#include + +#include "openmc/tallies/filter_material.h" + +namespace openmc { + +//============================================================================== +//! Specifies which material particles exit when crossing a surface. +//============================================================================== + +class MaterialFromFilter : public MaterialFilter { +public: + //---------------------------------------------------------------------------- + // Methods + + std::string type_str() const override { return "materialfrom"; } + FilterType type() const override { return FilterType::MATERIALFROM; } + + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; + + std::string text_label(int bin) const override; +}; + +} // namespace openmc +#endif // OPENMC_TALLIES_FILTER_MATERIALFROM_H diff --git a/include/openmc/tallies/filter_mesh.h b/include/openmc/tallies/filter_mesh.h index 8a712f4cb06..2f48b6d4d48 100644 --- a/include/openmc/tallies/filter_mesh.h +++ b/include/openmc/tallies/filter_mesh.h @@ -3,8 +3,8 @@ #include -#include "openmc/tallies/filter.h" #include "openmc/position.h" +#include "openmc/tallies/filter.h" namespace openmc { @@ -14,8 +14,7 @@ namespace openmc { //! correspond to the fraction of the track length that lies in that bin. //============================================================================== -class MeshFilter : public Filter -{ +class MeshFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -25,12 +24,13 @@ class MeshFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "mesh";} + std::string type_str() const override { return "mesh"; } + FilterType type() const override { return FilterType::MESH; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; @@ -39,7 +39,7 @@ class MeshFilter : public Filter //---------------------------------------------------------------------------- // Accessors - virtual int32_t mesh() const {return mesh_;} + virtual int32_t mesh() const { return mesh_; } virtual void set_mesh(int32_t mesh); @@ -47,18 +47,17 @@ class MeshFilter : public Filter virtual void set_translation(const double translation[3]); - virtual const Position& translation() const {return translation_;} - - virtual bool translated() const {return translated_;} + virtual const Position& translation() const { return translation_; } + virtual bool translated() const { return translated_; } protected: //---------------------------------------------------------------------------- // Data members - int32_t mesh_; - bool translated_ {false}; - Position translation_ {0.0, 0.0, 0.0}; + int32_t mesh_; //!< Index of the mesh + bool translated_ {false}; //!< Whether or not the filter is translated + Position translation_ {0.0, 0.0, 0.0}; //!< Filter translation }; } // namespace openmc diff --git a/include/openmc/tallies/filter_meshborn.h b/include/openmc/tallies/filter_meshborn.h new file mode 100644 index 00000000000..8ab7a8c766b --- /dev/null +++ b/include/openmc/tallies/filter_meshborn.h @@ -0,0 +1,26 @@ +#ifndef OPENMC_TALLIES_FILTER_MESHBORN_H +#define OPENMC_TALLIES_FILTER_MESHBORN_H + +#include + +#include "openmc/position.h" +#include "openmc/tallies/filter_mesh.h" + +namespace openmc { + +class MeshBornFilter : public MeshFilter { +public: + //---------------------------------------------------------------------------- + // Methods + + std::string type_str() const override { return "meshborn"; } + FilterType type() const override { return FilterType::MESHBORN; } + + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; + + std::string text_label(int bin) const override; +}; + +} // namespace openmc +#endif // OPENMC_TALLIES_FILTER_MESHBORN_H diff --git a/include/openmc/tallies/filter_meshsurface.h b/include/openmc/tallies/filter_meshsurface.h index baaf1e53cac..195995c699f 100644 --- a/include/openmc/tallies/filter_meshsurface.h +++ b/include/openmc/tallies/filter_meshsurface.h @@ -5,16 +5,16 @@ namespace openmc { -class MeshSurfaceFilter : public MeshFilter -{ +class MeshSurfaceFilter : public MeshFilter { public: //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "meshsurface";} + std::string type_str() const override { return "meshsurface"; } + FilterType type() const override { return FilterType::MESH_SURFACE; } - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; std::string text_label(int bin) const override; @@ -24,18 +24,18 @@ class MeshSurfaceFilter : public MeshFilter void set_mesh(int32_t mesh) override; enum class MeshDir { - OUT_LEFT, // x min - IN_LEFT, // x min + OUT_LEFT, // x min + IN_LEFT, // x min OUT_RIGHT, // x max - IN_RIGHT, // x max - OUT_BACK, // y min - IN_BACK, // y min + IN_RIGHT, // x max + OUT_BACK, // y min + IN_BACK, // y min OUT_FRONT, // y max - IN_FRONT, // y max - OUT_BOTTOM, // z min - IN_BOTTOM, // z min - OUT_TOP, // z max - IN_TOP // z max + IN_FRONT, // y max + OUT_BOTTOM, // z min + IN_BOTTOM, // z min + OUT_TOP, // z max + IN_TOP // z max }; }; diff --git a/include/openmc/tallies/filter_mu.h b/include/openmc/tallies/filter_mu.h index cad5bad1f40..942ee60c225 100644 --- a/include/openmc/tallies/filter_mu.h +++ b/include/openmc/tallies/filter_mu.h @@ -1,7 +1,7 @@ #ifndef OPENMC_TALLIES_FILTER_MU_H #define OPENMC_TALLIES_FILTER_MU_H -#include +#include #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -13,8 +13,7 @@ namespace openmc { //! reactions. //============================================================================== -class MuFilter : public Filter -{ +class MuFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -24,12 +23,13 @@ class MuFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "mu";} + std::string type_str() const override { return "mu"; } + FilterType type() const override { return FilterType::MU; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_particle.h b/include/openmc/tallies/filter_particle.h index da022b81e19..a181d5cee64 100644 --- a/include/openmc/tallies/filter_particle.h +++ b/include/openmc/tallies/filter_particle.h @@ -11,8 +11,7 @@ namespace openmc { //! Bins by type of particle (e.g. neutron, photon). //============================================================================== -class ParticleFilter : public Filter -{ +class ParticleFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -22,12 +21,13 @@ class ParticleFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "particle";} + std::string type_str() const override { return "particle"; } + FilterType type() const override { return FilterType::PARTICLE; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_polar.h b/include/openmc/tallies/filter_polar.h index ecfbc6f9c58..78bb25aa45e 100644 --- a/include/openmc/tallies/filter_polar.h +++ b/include/openmc/tallies/filter_polar.h @@ -3,7 +3,7 @@ #include -#include +#include #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -14,8 +14,7 @@ namespace openmc { //! Bins the incident neutron polar angle (relative to the global z-axis). //============================================================================== -class PolarFilter : public Filter -{ +class PolarFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -25,12 +24,13 @@ class PolarFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "polar";} + std::string type_str() const override { return "polar"; } + FilterType type() const override { return FilterType::POLAR; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_sph_harm.h b/include/openmc/tallies/filter_sph_harm.h index 91c81bdae7f..5d4a4bd999c 100644 --- a/include/openmc/tallies/filter_sph_harm.h +++ b/include/openmc/tallies/filter_sph_harm.h @@ -3,22 +3,19 @@ #include -#include +#include #include "openmc/tallies/filter.h" namespace openmc { -enum class SphericalHarmonicsCosine { - scatter, particle -}; +enum class SphericalHarmonicsCosine { scatter, particle }; //============================================================================== //! Gives spherical harmonics expansion moments of a tally score //============================================================================== -class SphericalHarmonicsFilter : public Filter -{ +class SphericalHarmonicsFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -28,12 +25,13 @@ class SphericalHarmonicsFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "sphericalharmonics";} + std::string type_str() const override { return "sphericalharmonics"; } + FilterType type() const override { return FilterType::SPHERICAL_HARMONICS; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_sptl_legendre.h b/include/openmc/tallies/filter_sptl_legendre.h index 581142f788f..b6c380e9b8d 100644 --- a/include/openmc/tallies/filter_sptl_legendre.h +++ b/include/openmc/tallies/filter_sptl_legendre.h @@ -7,16 +7,13 @@ namespace openmc { -enum class LegendreAxis { - x, y, z -}; +enum class LegendreAxis { x, y, z }; //============================================================================== //! Gives Legendre moments of the particle's normalized position along an axis //============================================================================== -class SpatialLegendreFilter : public Filter -{ +class SpatialLegendreFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -26,12 +23,13 @@ class SpatialLegendreFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "spatiallegendre";} + std::string type_str() const override { return "spatiallegendre"; } + FilterType type() const override { return FilterType::SPATIAL_LEGENDRE; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_surface.h b/include/openmc/tallies/filter_surface.h index 28b5105341a..3537f1cc748 100644 --- a/include/openmc/tallies/filter_surface.h +++ b/include/openmc/tallies/filter_surface.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -15,8 +15,7 @@ namespace openmc { //! Specifies which surface particles are crossing //============================================================================== -class SurfaceFilter : public Filter -{ +class SurfaceFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -26,12 +25,13 @@ class SurfaceFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "surface";} + std::string type_str() const override { return "surface"; } + FilterType type() const override { return FilterType::SURFACE; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_time.h b/include/openmc/tallies/filter_time.h new file mode 100644 index 00000000000..105ef9880a7 --- /dev/null +++ b/include/openmc/tallies/filter_time.h @@ -0,0 +1,51 @@ +#ifndef OPENMC_TALLIES_FILTER_TIME_H +#define OPENMC_TALLIES_FILTER_TIME_H + +#include + +#include "openmc/tallies/filter.h" +#include "openmc/vector.h" + +namespace openmc { + +//============================================================================== +//! Bins the incident particle time. +//============================================================================== + +class TimeFilter : public Filter { +public: + //---------------------------------------------------------------------------- + // Constructors, destructors + + ~TimeFilter() = default; + + //---------------------------------------------------------------------------- + // Methods + + std::string type_str() const override { return "time"; } + FilterType type() const override { return FilterType::TIME; } + + void from_xml(pugi::xml_node node) override; + + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; + + void to_statepoint(hid_t filter_group) const override; + + std::string text_label(int bin) const override; + + //---------------------------------------------------------------------------- + // Accessors + + const vector& bins() const { return bins_; } + void set_bins(gsl::span bins); + +protected: + //---------------------------------------------------------------------------- + // Data members + + vector bins_; +}; + +} // namespace openmc +#endif // OPENMC_TALLIES_FILTER_ENERGY_H diff --git a/include/openmc/tallies/filter_universe.h b/include/openmc/tallies/filter_universe.h index dfdbb8cf98b..d4894353bc9 100644 --- a/include/openmc/tallies/filter_universe.h +++ b/include/openmc/tallies/filter_universe.h @@ -4,7 +4,7 @@ #include #include -#include +#include #include "openmc/tallies/filter.h" #include "openmc/vector.h" @@ -15,8 +15,7 @@ namespace openmc { //! Specifies which geometric universes tally events reside in. //============================================================================== -class UniverseFilter : public Filter -{ +class UniverseFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -26,12 +25,13 @@ class UniverseFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "universe";} + std::string type_str() const override { return "universe"; } + FilterType type() const override { return FilterType::UNIVERSE; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; diff --git a/include/openmc/tallies/filter_zernike.h b/include/openmc/tallies/filter_zernike.h index a1248eac1a1..b6d9c91e6d5 100644 --- a/include/openmc/tallies/filter_zernike.h +++ b/include/openmc/tallies/filter_zernike.h @@ -11,8 +11,7 @@ namespace openmc { //! Gives Zernike polynomial moments of a particle's position //============================================================================== -class ZernikeFilter : public Filter -{ +class ZernikeFilter : public Filter { public: //---------------------------------------------------------------------------- // Constructors, destructors @@ -22,12 +21,13 @@ class ZernikeFilter : public Filter //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "zernike";} + std::string type_str() const override { return "zernike"; } + FilterType type() const override { return FilterType::ZERNIKE; } void from_xml(pugi::xml_node node) override; - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; void to_statepoint(hid_t filter_group) const override; @@ -68,16 +68,16 @@ class ZernikeFilter : public Filter //! Gives even order radial Zernike polynomial moments of a particle's position //============================================================================== -class ZernikeRadialFilter : public ZernikeFilter -{ +class ZernikeRadialFilter : public ZernikeFilter { public: //---------------------------------------------------------------------------- // Methods - std::string type() const override {return "zernikeradial";} + std::string type_str() const override { return "zernikeradial"; } + FilterType type() const override { return FilterType::ZERNIKE_RADIAL; } - void get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) - const override; + void get_all_bins(const Particle& p, TallyEstimator estimator, + FilterMatch& match) const override; std::string text_label(int bin) const override; diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index aaaff0e700e..2f0cddcf0ae 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -7,10 +7,10 @@ #include "openmc/tallies/trigger.h" #include "openmc/vector.h" -#include #include "pugixml.hpp" #include "xtensor/xfixed.hpp" #include "xtensor/xtensor.hpp" +#include #include #include @@ -35,34 +35,81 @@ class Tally { void set_id(int32_t id); + int id() const { return id_; } + void set_active(bool active) { active_ = active; } + void set_multiply_density(bool value) { multiply_density_ = value; } + void set_writable(bool writable) { writable_ = writable; } void set_scores(pugi::xml_node node); void set_scores(const vector& scores); + std::vector scores() const; + + int32_t n_scores() const { return scores_.size(); } + void set_nuclides(pugi::xml_node node); void set_nuclides(const vector& nuclides); + const xt::xtensor& results() const { return results_; } + + //! returns vector of indices corresponding to the tally this is called on const vector& filters() const { return filters_; } - int32_t filters(int i) const {return filters_[i];} + //! returns a vector of filter types for the tally + std::vector filter_types() const; + + //! returns a mapping of filter types to index into the tally's filters + std::unordered_map filter_indices() const; + + //! \brief Returns the tally filter at index i + int32_t filters(int i) const { return filters_[i]; } + + //! \brief Return a const pointer to a filter instance based on type. Always + //! returns the first matching filter type + template + const T* get_filter() const + { + const T* out; + for (auto filter_idx : filters_) { + if ((out = dynamic_cast(model::tally_filters[filter_idx].get()))) + return out; + } + return nullptr; + } + + template + const T* get_filter(int idx) const + { + if (const T* out = dynamic_cast(model::tally_filters[filters_.at(idx)])) + return out; + return nullptr; + } + + //! \brief Check if this tally has a specified type of filter + bool has_filter(FilterType filter_type) const; void set_filters(gsl::span filters); - int32_t strides(int i) const {return strides_[i];} + //! Given already-set filters, set the stride lengths + void set_strides(); + + int32_t strides(int i) const { return strides_[i]; } - int32_t n_filter_bins() const {return n_filter_bins_;} + int32_t n_filter_bins() const { return n_filter_bins_; } - bool writable() const { return writable_;} + bool multiply_density() const { return multiply_density_; } + + bool writable() const { return writable_; } //---------------------------------------------------------------------------- // Other methods. - void add_filter(Filter* filter) { set_filters({&filter, 1}); } + void add_filter(Filter* filter); void init_triggers(pugi::xml_node node); @@ -72,6 +119,12 @@ class Tally { void accumulate(); + //! return the index of a score specified by name + int score_index(const std::string& score) const; + + //! Tally results reshaped according to filter sizes + xt::xarray get_reshaped_data() const; + //! A string representing the i-th score on this tally std::string score_name(int score_idx) const; @@ -101,9 +154,6 @@ class Tally { //! Index of each nuclide to be tallied. -1 indicates total material. vector nuclides_ {-1}; - //! True if this tally has a bin for every nuclide in the problem - bool all_nuclides_ {false}; - //! Results for each bin -- the first dimension of the array is for the //! combination of filters (e.g. specific cell, specific energy group, etc.) //! and the second dimension of the array is for scores (e.g. flux, total @@ -119,8 +169,10 @@ class Tally { // We need to have quick access to some filters. The following gives indices // for various filters that could be in the tally or C_NONE if they are not // present. + int energy_filter_ {C_NONE}; int energyout_filter_ {C_NONE}; int delayedgroup_filter_ {C_NONE}; + int cell_filter_ {C_NONE}; vector triggers_; @@ -137,6 +189,9 @@ class Tally { int32_t n_filter_bins_ {0}; + //! Whether to multiply by atom density for reaction rates + bool multiply_density_ {true}; + gsl::index index_; }; @@ -145,23 +200,26 @@ class Tally { //============================================================================== namespace model { - extern std::unordered_map tally_map; - extern vector> tallies; - extern vector active_tallies; - extern vector active_analog_tallies; - extern vector active_tracklength_tallies; - extern vector active_collision_tallies; - extern vector active_meshsurf_tallies; - extern vector active_surface_tallies; -} +extern std::unordered_map tally_map; +extern vector> tallies; +extern vector active_tallies; +extern vector active_analog_tallies; +extern vector active_tracklength_tallies; +extern vector active_collision_tallies; +extern vector active_meshsurf_tallies; +extern vector active_surface_tallies; +extern vector active_pulse_height_tallies; +extern vector pulse_height_cells; +} // namespace model namespace simulation { - //! Global tallies (such as k-effective estimators) - extern xt::xtensor_fixed> global_tallies; +//! Global tallies (such as k-effective estimators) +extern xt::xtensor_fixed> + global_tallies; - //! Number of realizations for global tallies - extern "C" int32_t n_realizations; -} +//! Number of realizations for global tallies +extern "C" int32_t n_realizations; +} // namespace simulation extern double global_tally_absorption; extern double global_tally_collision; @@ -175,6 +233,10 @@ extern double global_tally_leakage; //! Read tally specification from tallies.xml void read_tallies_xml(); +//! Read tally specification from an XML node +//! \param[in] root node of tallies XML element +void read_tallies_xml(pugi::xml_node root); + //! \brief Accumulate the sum of the contributions from each history within the //! batch to a new random variable void accumulate_tallies(); @@ -184,8 +246,9 @@ void setup_active_tallies(); // Alias for the type returned by xt::adapt(...). N is the dimension of the // multidimensional array -template -using adaptor_type = xt::xtensor_adaptor, N>; +template +using adaptor_type = + xt::xtensor_adaptor, N>; #ifdef OPENMC_MPI //! Collect all tally results onto master process diff --git a/include/openmc/tallies/tally_scoring.h b/include/openmc/tallies/tally_scoring.h index 4510f725fc1..28f1f16223d 100644 --- a/include/openmc/tallies/tally_scoring.h +++ b/include/openmc/tallies/tally_scoring.h @@ -18,10 +18,8 @@ namespace openmc { //! bins that are valid for the current tally event. //============================================================================== -class FilterBinIter -{ +class FilterBinIter { public: - //! Construct an iterator over bins that match a given particle's state. FilterBinIter(const Tally& tally, Particle& p); @@ -32,10 +30,14 @@ class FilterBinIter const Tally& tally, bool end, vector* particle_filter_matches); bool operator==(const FilterBinIter& other) const - {return index_ == other.index_;} + { + return index_ == other.index_; + } bool operator!=(const FilterBinIter& other) const - {return !(*this == other);} + { + return !(*this == other); + } FilterBinIter& operator++(); @@ -92,9 +94,16 @@ void score_tracklength_tally(Particle& p, double distance); //! Score surface or mesh-surface tallies for particle currents. // //! \param p The particle being tracked -//! \param tallies A vector of tallies to score to +//! \param tallies A vector of the indices of the tallies to score to void score_surface_tally(Particle& p, const vector& tallies); +//! Score the pulse-height tally +//! This is triggered at the end of every particle history +// +//! \param p The particle being tracked +//! \param tallies A vector of the indices of the tallies to score to +void score_pulse_height_tally(Particle& p, const vector& tallies); + } // namespace openmc #endif // OPENMC_TALLIES_TALLY_SCORING_H diff --git a/include/openmc/tallies/trigger.h b/include/openmc/tallies/trigger.h index a11759114a5..7feed5e8ad2 100644 --- a/include/openmc/tallies/trigger.h +++ b/include/openmc/tallies/trigger.h @@ -12,21 +12,24 @@ namespace openmc { //============================================================================== enum class TriggerMetric { - variance, relative_error, standard_deviation, not_active + variance, + relative_error, + standard_deviation, + not_active }; //! Stops the simulation early if a desired tally uncertainty is reached. struct Trigger { - TriggerMetric metric; //!< The type of uncertainty (e.g. std dev) measured - double threshold; //!< Uncertainty value below which trigger is satisfied - int score_index; //!< Index of the relevant score in the tally's arrays + TriggerMetric metric; //!< The type of uncertainty (e.g. std dev) measured + double threshold; //!< Uncertainty value below which trigger is satisfied + bool ignore_zeros; //!< Whether to allow zero tally bins to be ignored + int score_index; //!< Index of the relevant score in the tally's arrays }; //! Stops the simulation early if a desired k-effective uncertainty is reached. -struct KTrigger -{ +struct KTrigger { TriggerMetric metric {TriggerMetric::not_active}; double threshold {0.}; }; @@ -35,9 +38,9 @@ struct KTrigger // Global variable declarations //============================================================================== -//TODO: consider a different namespace +// TODO: consider a different namespace namespace settings { - extern KTrigger keff_trigger; +extern KTrigger keff_trigger; } //============================================================================== diff --git a/include/openmc/thermal.h b/include/openmc/thermal.h index d2db789e201..de0767d0af0 100644 --- a/include/openmc/thermal.h +++ b/include/openmc/thermal.h @@ -25,7 +25,7 @@ class ThermalScattering; namespace data { extern std::unordered_map thermal_scatt_map; extern vector> thermal_scatt; -} +} // namespace data //============================================================================== //! Secondary angle-energy data for thermal neutron scattering at a single @@ -50,12 +50,13 @@ class ThermalData { //! \param[out] E_out Outgoing neutron energy in [eV] //! \param[out] mu Outgoing scattering angle cosine //! \param[inout] seed Pseudorandom seed pointer - void sample(const NuclideMicroXS& micro_xs, double E_in, - double* E_out, double* mu, uint64_t* seed); + void sample(const NuclideMicroXS& micro_xs, double E_in, double* E_out, + double* mu, uint64_t* seed); + private: struct Reaction { // Default constructor - Reaction() { } + Reaction() {} // Data members unique_ptr xs; //!< Cross section @@ -83,13 +84,13 @@ class ThermalScattering { //! Determine inelastic/elastic cross section at given energy //! //! \param[in] E incoming energy in [eV] - //! \param[in] sqrtkT square-root of temperature multipled by Boltzmann's constant - //! \param[out] i_temp corresponding temperature index - //! \param[out] elastic Thermal elastic scattering cross section - //! \param[out] inelastic Thermal inelastic scattering cross section - //! \param[inout] seed Pseudorandom seed pointer + //! \param[in] sqrtkT square-root of temperature multipled by Boltzmann's + //! constant \param[out] i_temp corresponding temperature index \param[out] + //! elastic Thermal elastic scattering cross section \param[out] inelastic + //! Thermal inelastic scattering cross section \param[inout] seed Pseudorandom + //! seed pointer void calculate_xs(double E, double sqrtkT, int* i_temp, double* elastic, - double* inelastic, uint64_t* seed) const; + double* inelastic, uint64_t* seed) const; //! Determine whether table applies to a particular nuclide //! @@ -98,13 +99,13 @@ class ThermalScattering { bool has_nuclide(const char* name) const; // Sample an outgoing energy and angle - void sample(const NuclideMicroXS& micro_xs, double E_in, - double* E_out, double* mu); + void sample( + const NuclideMicroXS& micro_xs, double E_in, double* E_out, double* mu); - std::string name_; //!< name of table, e.g. "c_H_in_H2O" - double awr_; //!< weight of nucleus in neutron masses - double energy_max_; //!< maximum energy for thermal scattering in [eV] - vector kTs_; //!< temperatures in [eV] (k*T) + std::string name_; //!< name of table, e.g. "c_H_in_H2O" + double awr_; //!< weight of nucleus in neutron masses + double energy_max_; //!< maximum energy for thermal scattering in [eV] + vector kTs_; //!< temperatures in [eV] (k*T) vector nuclides_; //!< Valid nuclides //! cross sections and distributions at each temperature diff --git a/include/openmc/timer.h b/include/openmc/timer.h index 3acf483d6b0..d928aad4560 100644 --- a/include/openmc/timer.h +++ b/include/openmc/timer.h @@ -31,6 +31,7 @@ extern Timer time_event_advance_particle; extern Timer time_event_surface_crossing; extern Timer time_event_collision; extern Timer time_event_death; +extern Timer time_update_src; } // namespace simulation @@ -58,9 +59,9 @@ class Timer { void reset(); private: - bool running_ {false}; //!< is timer running? + bool running_ {false}; //!< is timer running? std::chrono::time_point start_; //!< starting point for clock - double elapsed_ {0.0}; //!< elapsed time in [s] + double elapsed_ {0.0}; //!< elapsed time in [s] }; //============================================================================== diff --git a/include/openmc/track_output.h b/include/openmc/track_output.h index fc65a2eaab6..2380fe44055 100644 --- a/include/openmc/track_output.h +++ b/include/openmc/track_output.h @@ -9,8 +9,31 @@ namespace openmc { // Non-member functions //============================================================================== +//! Open HDF5 track file for writing and create track datatype +void open_track_file(); + +//! Close HDF5 resources for track file +void close_track_file(); + +//! Determine whether a given particle should collect/write track information +// +//! \param[in] p Current particle +//! \return Whether to collect/write track information +bool check_track_criteria(const Particle& p); + +//! Create a new track state history for a primary/secondary particle +// +//! \param[in] p Current particle void add_particle_track(Particle& p); + +//! Store particle's current state +// +//! \param[in] p Current particle void write_particle_track(Particle& p); + +//! Write full particle state history to HDF5 track file +// +//! \param[in] p Current particle void finalize_particle_track(Particle& p); } // namespace openmc diff --git a/include/openmc/universe.h b/include/openmc/universe.h new file mode 100644 index 00000000000..26f33cb383d --- /dev/null +++ b/include/openmc/universe.h @@ -0,0 +1,79 @@ +#ifndef OPENMC_UNIVERSE_H +#define OPENMC_UNIVERSE_H + +#include "openmc/cell.h" + +namespace openmc { + +#ifdef DAGMC +class DAGUniverse; +#endif + +class GeometryState; +class Universe; +class UniversePartitioner; + +namespace model { + +extern std::unordered_map universe_map; +extern vector> universes; + +} // namespace model + +//============================================================================== +//! A geometry primitive that fills all space and contains cells. +//============================================================================== + +class Universe { +public: + int32_t id_; //!< Unique ID + vector cells_; //!< Cells within this universe + + //! \brief Write universe information to an HDF5 group. + //! \param group_id An HDF5 group id. + virtual void to_hdf5(hid_t group_id) const; + + virtual bool find_cell(GeometryState& p) const; + + BoundingBox bounding_box() const; + + const GeometryType& geom_type() const { return geom_type_; } + GeometryType& geom_type() { return geom_type_; } + + unique_ptr partitioner_; + +private: + GeometryType geom_type_ = GeometryType::CSG; +}; + +//============================================================================== +//! Speeds up geometry searches by grouping cells in a search tree. +// +//! Currently this object only works with universes that are divided up by a +//! bunch of z-planes. It could be generalized to other planes, cylinders, +//! and spheres. +//============================================================================== + +class UniversePartitioner { +public: + explicit UniversePartitioner(const Universe& univ); + + //! Return the list of cells that could contain the given coordinates. + const vector& get_cells(Position r, Direction u) const; + +private: + //! A sorted vector of indices to surfaces that partition the universe + vector surfs_; + + //! Vectors listing the indices of the cells that lie within each partition + // + //! There are n+1 partitions with n surfaces. `partitions_.front()` gives the + //! cells that lie on the negative side of `surfs_.front()`. + //! `partitions_.back()` gives the cells that lie on the positive side of + //! `surfs_.back()`. Otherwise, `partitions_[i]` gives cells sandwiched + //! between `surfs_[i-1]` and `surfs_[i]`. + vector> partitions_; +}; + +} // namespace openmc +#endif // OPENMC_UNIVERSE_H diff --git a/include/openmc/urr.h b/include/openmc/urr.h index 6764254425c..3978c7b86a2 100644 --- a/include/openmc/urr.h +++ b/include/openmc/urr.h @@ -7,6 +7,7 @@ #include "openmc/constants.h" #include "openmc/hdf5_interface.h" +#include "openmc/vector.h" namespace openmc { @@ -14,18 +15,48 @@ namespace openmc { //! UrrData contains probability tables for the unresolved resonance range. //============================================================================== -class UrrData{ +class UrrData { public: + // Since we access all of these at once, we want + // them contiguous in memory. + struct XSSet { + double total; + double elastic; + double fission; + double n_gamma; + double heating; + }; + Interpolation interp_; //!< interpolation type int inelastic_flag_; //!< inelastic competition flag int absorption_flag_; //!< other absorption flag bool multiply_smooth_; //!< multiply by smooth cross section? - int n_energy_; //!< number of energy points - xt::xtensor energy_; //!< incident energies - xt::xtensor prob_; //!< Actual probability tables + + vector energy_; //!< incident energies + auto n_energy() const { return energy_.size(); } + + /* The row indexes correspond to the incident energy table, and column + * indices correspond to values of the CDF at that energy. For the CDF matrix + * below, obviously, values of the CDF are stored. For the xs_values + * variable, the columns line up with the index of cdf_values. + */ + xt::xtensor cdf_values_; // Note: must be row major! + xt::xtensor xs_values_; + + // Number of points in the CDF + auto n_cdf() const { return cdf_values_.shape()[1]; } //! \brief Load the URR data from the provided HDF5 group explicit UrrData(hid_t group_id); + + // Checks if any negative CDF or XS values are present + bool has_negative() const; + + // Checks if the passed energy is within the bounds of the URR table + bool energy_in_bounds(double E) const + { + return energy_.front() < E && E < energy_.back(); + } }; } // namespace openmc diff --git a/include/openmc/version.h.in b/include/openmc/version.h.in index fe282be7c01..e1c2b0541a5 100644 --- a/include/openmc/version.h.in +++ b/include/openmc/version.h.in @@ -1,12 +1,19 @@ +#ifndef OPENMC_VERSION_H +#define OPENMC_VERSION_H + #include "openmc/array.h" namespace openmc { // OpenMC major, minor, and release numbers +// clang-format off constexpr int VERSION_MAJOR {@OPENMC_VERSION_MAJOR@}; constexpr int VERSION_MINOR {@OPENMC_VERSION_MINOR@}; constexpr int VERSION_RELEASE {@OPENMC_VERSION_RELEASE@}; -constexpr bool VERSION_DEV {false}; +constexpr bool VERSION_DEV {true}; constexpr std::array VERSION {VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE}; +// clang-format on + +} // namespace openmc -} +#endif // OPENMC_VERSION_H diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 2071411f8bf..376b8c707dd 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -1,16 +1,23 @@ #ifndef OPENMC_VOLUME_CALC_H #define OPENMC_VOLUME_CALC_H +#include // for find +#include +#include +#include + #include "openmc/array.h" +#include "openmc/openmp_interface.h" #include "openmc/position.h" #include "openmc/tallies/trigger.h" #include "openmc/vector.h" #include "pugixml.hpp" #include "xtensor/xtensor.hpp" - -#include -#include +#include +#ifdef _OPENMP +#include +#endif namespace openmc { @@ -28,14 +35,17 @@ class VolumeCalculation { vector atoms; //!< Number of atoms for each nuclide vector uncertainty; //!< Uncertainty on number of atoms int iterations; //!< Number of iterations needed to obtain the results - }; // Results for a single domain + }; // Results for a single domain // Constructors VolumeCalculation(pugi::xml_node node); + VolumeCalculation() = default; + // Methods - //! \brief Stochastically determine the volume of a set of domains along with the + //! \brief Stochastically determine the volume of a set of domains along with + //! the //! average number densities of nuclides within the domain // //! \return Vector of results for each user-specified domain @@ -49,20 +59,17 @@ class VolumeCalculation { const std::string& filename, const vector& results) const; // Tally filter and map types - enum class TallyDomain { - UNIVERSE, - MATERIAL, - CELL - }; + enum class TallyDomain { UNIVERSE, MATERIAL, CELL }; // Data members TallyDomain domain_type_; //!< Type of domain (cell, material, etc.) - size_t n_samples_; //!< Number of samples to use + size_t n_samples_; //!< Number of samples to use double threshold_ {-1.0}; //!< Error threshold for domain volumes - TriggerMetric trigger_type_ {TriggerMetric::not_active}; //!< Trigger metric for the volume calculation - Position lower_left_; //!< Lower-left position of bounding box - Position upper_right_; //!< Upper-right position of bounding box - vector domain_ids_; //!< IDs of domains to find volumes of + TriggerMetric trigger_type_ { + TriggerMetric::not_active}; //!< Trigger metric for the volume calculation + Position lower_left_; //!< Lower-left position of bounding box + Position upper_right_; //!< Upper-right position of bounding box + vector domain_ids_; //!< IDs of domains to find volumes of private: //! \brief Check whether a material has already been hit for a given domain. @@ -71,7 +78,8 @@ class VolumeCalculation { //! \param[in] i_material Index in global materials vector //! \param[in,out] indices Vector of material indices //! \param[in,out] hits Number of hits corresponding to each material - void check_hit(int i_material, vector& indices, vector& hits) const; + void check_hit( + int i_material, vector& indices, vector& hits) const; }; //============================================================================== @@ -86,6 +94,35 @@ extern vector volume_calcs; // Non-member functions //============================================================================== +//! Reduce vector of indices and hits from each thread to a single copy +// +//! \param[in] local_indices Indices specific to each thread +//! \param[in] local_hits Hit count specific to each thread +//! \param[out] indices Reduced vector of indices +//! \param[out] hits Reduced vector of hits +template +void reduce_indices_hits(const vector& local_indices, + const vector& local_hits, vector& indices, vector& hits) +{ + const int n_threads = num_threads(); + +#pragma omp for ordered schedule(static, 1) + for (int i = 0; i < n_threads; ++i) { +#pragma omp ordered + for (int j = 0; j < local_indices.size(); ++j) { + // Check if this material has been added to the master list and if + // so, accumulate the number of hits + auto it = std::find(indices.begin(), indices.end(), local_indices[j]); + if (it == indices.end()) { + indices.push_back(local_indices[j]); + hits.push_back(local_hits[j]); + } else { + hits[it - indices.begin()] += local_hits[j]; + } + } + } +} + void free_memory_volume(); } // namespace openmc diff --git a/include/openmc/weight_windows.h b/include/openmc/weight_windows.h new file mode 100644 index 00000000000..9852fe679d0 --- /dev/null +++ b/include/openmc/weight_windows.h @@ -0,0 +1,245 @@ +#ifndef OPENMC_WEIGHT_WINDOWS_H +#define OPENMC_WEIGHT_WINDOWS_H + +#include +#include + +#include +#include +#include + +#include "openmc/constants.h" +#include "openmc/memory.h" +#include "openmc/mesh.h" +#include "openmc/particle.h" +#include "openmc/tallies/tally.h" +#include "openmc/vector.h" + +namespace openmc { + +enum class WeightWindowUpdateMethod { + MAGIC, +}; + +//============================================================================== +// Constants +//============================================================================== + +constexpr double DEFAULT_WEIGHT_CUTOFF {1.0e-38}; // default low weight cutoff + +//============================================================================== +// Non-member functions +//============================================================================== + +//! Apply weight windows to a particle +//! \param[in] p Particle to apply weight windows to +void apply_weight_windows(Particle& p); + +//! Free memory associated with weight windows +void free_memory_weight_windows(); + +//============================================================================== +// Global variables +//============================================================================== + +class WeightWindows; +class WeightWindowsGenerator; + +namespace variance_reduction { + +extern std::unordered_map ww_map; +extern vector> weight_windows; +extern vector> weight_windows_generators; + +} // namespace variance_reduction + +//============================================================================== +//! Individual weight window information +//============================================================================== + +struct WeightWindow { + double lower_weight {-1}; // -1 indicates invalid state + double upper_weight {1}; + double max_lb_ratio {1}; + double survival_weight {0.5}; + double weight_cutoff {DEFAULT_WEIGHT_CUTOFF}; + int max_split {10}; + + //! Whether the weight window is in a valid state + bool is_valid() const { return lower_weight >= 0.0; } + + //! Adjust the weight window by a constant factor + void scale(double factor) + { + lower_weight *= factor; + upper_weight *= factor; + } +}; + +//============================================================================== +//! Weight window settings +//============================================================================== + +class WeightWindows { +public: + //---------------------------------------------------------------------------- + // Constructors + WeightWindows(int32_t id = -1); + WeightWindows(pugi::xml_node node); + ~WeightWindows(); + static WeightWindows* create(int32_t id = -1); + static WeightWindows* from_hdf5( + hid_t wws_group, const std::string& group_name); + + //---------------------------------------------------------------------------- + // Methods +private: + template + void check_bounds(const T& lower, const T& upper) const; + + template + void check_bounds(const T& lower) const; + + void check_tally_update_compatibility(const Tally* tally); + +public: + //! Set the weight window ID + void set_id(int32_t id = -1); + + void set_energy_bounds(gsl::span bounds); + + void set_mesh(const std::unique_ptr& mesh); + + void set_mesh(const Mesh* mesh); + + void set_mesh(int32_t mesh_idx); + + //! Ready the weight window class for use + void set_defaults(); + + //! Ensure the weight window lower bounds are properly allocated + void allocate_ww_bounds(); + + //! Update weight window boundaries using tally results + //! \param[in] tally Pointer to the tally whose results will be used to + //! update weight windows \param[in] value String representing the type of + //! value to use for weight window generation (one of "mean" or "rel_err") + //! \param[in] threshold Relative error threshold. Results over this + //! threshold will be ignored \param[in] ratio Ratio of upper to lower + //! weight window bounds + void update_magic(const Tally* tally, const std::string& value = "mean", + double threshold = 1.0, double ratio = 5.0); + + // NOTE: This is unused for now but may be used in the future + //! Write weight window settings to an HDF5 file + //! \param[in] group HDF5 group to write to + void to_hdf5(hid_t group) const; + + //! Retrieve the weight window for a particle + //! \param[in] p Particle to get weight window for + WeightWindow get_weight_window(const Particle& p) const; + + std::array bounds_size() const; + + const vector& energy_bounds() const { return energy_bounds_; } + + void set_bounds(const xt::xtensor& lower_ww_bounds, + const xt::xtensor& upper_bounds); + + void set_bounds(const xt::xtensor& lower_bounds, double ratio); + + void set_bounds( + gsl::span lower_bounds, gsl::span upper_bounds); + + void set_bounds(gsl::span lower_bounds, double ratio); + + void set_particle_type(ParticleType p_type); + + double survival_ratio() const { return survival_ratio_; } + + double& survival_ratio() { return survival_ratio_; } + + double max_lower_bound_ratio() const { return max_lb_ratio_; } + + double& max_lower_bound_ratio() { return max_lb_ratio_; } + + int max_split() const { return max_split_; } + + int& max_split() { return max_split_; } + + double weight_cutoff() const { return weight_cutoff_; } + + double& weight_cutoff() { return weight_cutoff_; } + + //---------------------------------------------------------------------------- + // Accessors + int32_t id() const { return id_; } + int32_t& id() { return id_; } + + int32_t index() const { return index_; } + + vector& energy_bounds() { return energy_bounds_; } + + const std::unique_ptr& mesh() const { return model::meshes[mesh_idx_]; } + + const xt::xtensor& lower_ww_bounds() const { return lower_ww_; } + xt::xtensor& lower_ww_bounds() { return lower_ww_; } + + const xt::xtensor& upper_ww_bounds() const { return upper_ww_; } + xt::xtensor& upper_ww_bounds() { return upper_ww_; } + + ParticleType particle_type() const { return particle_type_; } + +private: + //---------------------------------------------------------------------------- + // Data members + int32_t id_; //!< Unique ID + gsl::index index_; //!< Index into weight windows vector + ParticleType particle_type_ { + ParticleType::neutron}; //!< Particle type to apply weight windows to + vector energy_bounds_; //!< Energy boundaries [eV] + xt::xtensor lower_ww_; //!< Lower weight window bounds (shape: + //!< energy_bins, mesh_bins (k, j, i)) + xt::xtensor + upper_ww_; //!< Upper weight window bounds (shape: energy_bins, mesh_bins) + double survival_ratio_ {3.0}; //!< Survival weight ratio + double max_lb_ratio_ {1.0}; //!< Maximum lower bound to particle weight ratio + double weight_cutoff_ {DEFAULT_WEIGHT_CUTOFF}; //!< Weight cutoff + int max_split_ {10}; //!< Maximum value for particle splitting + int32_t mesh_idx_ {-1}; //!< Index in meshes vector +}; + +class WeightWindowsGenerator { +public: + // Constructors + WeightWindowsGenerator(pugi::xml_node node); + + // Methods + void update() const; + + //! Create the tally used for weight window generation + void create_tally(); + + // Data members + int32_t tally_idx_; //!< Index of the tally used to update the weight windows + int32_t ww_idx_; //!< Index of the weight windows object being generated + std::string method_; //!< Method used to update weight window. Only "magic" + //!< is valid for now. + int32_t max_realizations_; //!< Maximum number of tally realizations + int32_t update_interval_; //!< Determines how often updates occur + bool on_the_fly_; //!< Whether or not to keep tally results between batches or + //!< realizations + + // MAGIC update parameters + std::string tally_value_ { + "mean"}; // evaluate(double E, double sqrtkT) const; //! \brief Evaluates the windowed multipole equations for the derivative of @@ -65,18 +66,20 @@ class WindowedMultipole { //! \param sqrtkT Square root of temperature times Boltzmann constant //! \return Tuple of derivatives of elastic scattering, absorption, and //! fission cross sections in [b/K] - std::tuple evaluate_deriv(double E, double sqrtkT) const; + std::tuple evaluate_deriv( + double E, double sqrtkT) const; // Data members - std::string name_; //!< Name of nuclide - double E_min_; //!< Minimum energy in [eV] - double E_max_; //!< Maximum energy in [eV] - double sqrt_awr_; //!< Square root of atomic weight ratio - double inv_spacing_; //!< 1 / spacing in sqrt(E) space - int fit_order_; //!< Order of the fit - bool fissionable_; //!< Is the nuclide fissionable? - vector window_info_; // Information about a window - xt::xtensor curvefit_; // Curve fit coefficients (window, poly order, reaction) + std::string name_; //!< Name of nuclide + double E_min_; //!< Minimum energy in [eV] + double E_max_; //!< Maximum energy in [eV] + double sqrt_awr_; //!< Square root of atomic weight ratio + double inv_spacing_; //!< 1 / spacing in sqrt(E) space + int fit_order_; //!< Order of the fit + bool fissionable_; //!< Is the nuclide fissionable? + vector window_info_; // Information about a window + xt::xtensor + curvefit_; // Curve fit coefficients (window, poly order, reaction) xt::xtensor, 2> data_; //!< Poles and residues // Constant data @@ -99,7 +102,6 @@ void check_wmp_version(hid_t file); //! \param[in] i_nuclide Index in global nuclides array void read_multipole_data(int i_nuclide); - //============================================================================== //! Doppler broadens the windowed multipole curvefit. //! @@ -111,7 +113,8 @@ void read_multipole_data(int i_nuclide); //! \param factors The output leading coefficient //============================================================================== -extern "C" void broaden_wmp_polynomials(double E, double dopp, int n, double factors[]); +extern "C" void broaden_wmp_polynomials( + double E, double dopp, int n, double factors[]); } // namespace openmc diff --git a/include/openmc/xml_interface.h b/include/openmc/xml_interface.h index ddd92ad7e3e..bd6554c134a 100644 --- a/include/openmc/xml_interface.h +++ b/include/openmc/xml_interface.h @@ -6,21 +6,21 @@ #include #include "pugixml.hpp" -#include "xtensor/xarray.hpp" #include "xtensor/xadapt.hpp" +#include "xtensor/xarray.hpp" +#include "openmc/position.h" #include "openmc/vector.h" namespace openmc { -inline bool -check_for_node(pugi::xml_node node, const char *name) +inline bool check_for_node(pugi::xml_node node, const char* name) { return node.attribute(name) || node.child(name); } std::string get_node_value(pugi::xml_node node, const char* name, - bool lowercase=false, bool strip=false); + bool lowercase = false, bool strip = false); bool get_node_value_bool(pugi::xml_node node, const char* name); @@ -41,14 +41,17 @@ vector get_node_array( return values; } -template -xt::xarray get_node_xarray(pugi::xml_node node, const char* name, - bool lowercase=false) +template +xt::xarray get_node_xarray( + pugi::xml_node node, const char* name, bool lowercase = false) { vector v = get_node_array(node, name, lowercase); vector shape = {v.size()}; return xt::adapt(v, shape); } +Position get_node_position( + pugi::xml_node node, const char* name, bool lowercase = false); + } // namespace openmc #endif // OPENMC_XML_INTERFACE_H diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index cf6d8058bf3..feafde68dd3 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -28,127 +28,117 @@ enum class AngleDistributionType { class XsData { - private: - - //! \brief Reads scattering data from the HDF5 file - void - scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, AngleDistributionType scatter_format, - AngleDistributionType final_scatter_format, int order_data); - - //! \brief Reads fission data from the HDF5 file - void - fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic); - - //! \brief Reads fission data formatted as chi and nu-fission vectors from - // the HDF5 file when beta is provided. - void - fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic); - - //! \brief Reads fission data formatted as chi and nu-fission vectors from - // the HDF5 file when beta is not provided. - void - fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang); - - //! \brief Reads fission data formatted as chi and nu-fission vectors from - // the HDF5 file when no delayed data is provided. - void - fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang); - - //! \brief Reads fission data formatted as a nu-fission matrix from - // the HDF5 file when beta is provided. - void - fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic); - - //! \brief Reads fission data formatted as a nu-fission matrix from - // the HDF5 file when beta is not provided. - void - fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang); - - //! \brief Reads fission data formatted as a nu-fission matrix from - // the HDF5 file when no delayed data is provided. - void - fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang); - - //! Number of energy and delayed neutron groups - size_t n_g_, n_dg_; - - public: - - // The following quantities have the following dimensions: - // [angle][incoming group] - xt::xtensor total; - xt::xtensor absorption; - xt::xtensor nu_fission; - xt::xtensor prompt_nu_fission; - xt::xtensor kappa_fission; - xt::xtensor fission; - xt::xtensor inverse_velocity; - - // decay_rate has the following dimensions: - // [angle][delayed group] - xt::xtensor decay_rate; - // delayed_nu_fission has the following dimensions: - // [angle][delayed group][incoming group] - xt::xtensor delayed_nu_fission; - // chi_prompt has the following dimensions: - // [angle][incoming group][outgoing group] - xt::xtensor chi_prompt; - // chi_delayed has the following dimensions: - // [angle][incoming group][outgoing group][delayed group] - xt::xtensor chi_delayed; - // scatter has the following dimensions: [angle] - vector> scatter; - - XsData() = default; - - //! \brief Constructs the XsData object metadata. - //! - //! @param num_groups Number of energy groups. - //! @param num_delayed_groups Number of delayed groups. - //! @param fissionable Is this a fissionable data set or not. - //! @param scatter_format The scattering representation of the file. - //! @param n_pol Number of polar angles. - //! @param n_azi Number of azimuthal angles. - //! @param n_groups Number of energy groups. - //! @param n_d_groups Number of delayed neutron groups. - XsData(bool fissionable, AngleDistributionType scatter_format, int n_pol, - int n_azi, size_t n_groups, size_t n_d_groups); - - //! \brief Loads the XsData object from the HDF5 file - //! - //! @param xs_id HDF5 group id for the cross section data. - //! @param fissionable Is this a fissionable data set or not. - //! @param scatter_format The scattering representation of the file. - //! @param final_scatter_format The scattering representation after reading; - //! this is different from scatter_format if converting a Legendre to - //! a tabular representation. - //! @param order_data The dimensionality of the scattering data in the file. - //! @param is_isotropic Is this an isotropic or angular with respect to - //! the incoming particle. - //! @param n_pol Number of polar angles. - //! @param n_azi Number of azimuthal angles. - void - from_hdf5(hid_t xsdata_grp, bool fissionable, AngleDistributionType scatter_format, - AngleDistributionType final_scatter_format, int order_data, bool is_isotropic, int n_pol, - int n_azi); - - //! \brief Combines the microscopic data to a macroscopic object. - //! - //! @param micros Microscopic objects to combine. - //! @param scalars Scalars to multiply the microscopic data by. - void combine( - const vector& those_xs, const vector& scalars); - - //! \brief Checks to see if this and that are able to be combined - //! - //! This comparison is used when building macroscopic cross sections - //! from microscopic cross sections. - //! @param that The other XsData to compare to this one. - //! @return True if they can be combined. - bool - equiv(const XsData& that); +private: + //! \brief Reads scattering data from the HDF5 file + void scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, + AngleDistributionType scatter_format, + AngleDistributionType final_scatter_format, int order_data); + + //! \brief Reads fission data from the HDF5 file + void fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic); + + //! \brief Reads fission data formatted as chi and nu-fission vectors from + // the HDF5 file when beta is provided. + void fission_vector_beta_from_hdf5( + hid_t xsdata_grp, size_t n_ang, bool is_isotropic); + + //! \brief Reads fission data formatted as chi and nu-fission vectors from + // the HDF5 file when beta is not provided. + void fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang); + + //! \brief Reads fission data formatted as chi and nu-fission vectors from + // the HDF5 file when no delayed data is provided. + void fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang); + + //! \brief Reads fission data formatted as a nu-fission matrix from + // the HDF5 file when beta is provided. + void fission_matrix_beta_from_hdf5( + hid_t xsdata_grp, size_t n_ang, bool is_isotropic); + + //! \brief Reads fission data formatted as a nu-fission matrix from + // the HDF5 file when beta is not provided. + void fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang); + + //! \brief Reads fission data formatted as a nu-fission matrix from + // the HDF5 file when no delayed data is provided. + void fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang); + + //! Number of energy and delayed neutron groups + size_t n_g_, n_dg_; + +public: + // The following quantities have the following dimensions: + // [angle][incoming group] + xt::xtensor total; + xt::xtensor absorption; + xt::xtensor nu_fission; + xt::xtensor prompt_nu_fission; + xt::xtensor kappa_fission; + xt::xtensor fission; + xt::xtensor inverse_velocity; + + // decay_rate has the following dimensions: + // [angle][delayed group] + xt::xtensor decay_rate; + // delayed_nu_fission has the following dimensions: + // [angle][delayed group][incoming group] + xt::xtensor delayed_nu_fission; + // chi_prompt has the following dimensions: + // [angle][incoming group][outgoing group] + xt::xtensor chi_prompt; + // chi_delayed has the following dimensions: + // [angle][incoming group][outgoing group][delayed group] + xt::xtensor chi_delayed; + // scatter has the following dimensions: [angle] + vector> scatter; + + XsData() = default; + + //! \brief Constructs the XsData object metadata. + //! + //! @param num_groups Number of energy groups. + //! @param num_delayed_groups Number of delayed groups. + //! @param fissionable Is this a fissionable data set or not. + //! @param scatter_format The scattering representation of the file. + //! @param n_pol Number of polar angles. + //! @param n_azi Number of azimuthal angles. + //! @param n_groups Number of energy groups. + //! @param n_d_groups Number of delayed neutron groups. + XsData(bool fissionable, AngleDistributionType scatter_format, int n_pol, + int n_azi, size_t n_groups, size_t n_d_groups); + + //! \brief Loads the XsData object from the HDF5 file + //! + //! @param xs_id HDF5 group id for the cross section data. + //! @param fissionable Is this a fissionable data set or not. + //! @param scatter_format The scattering representation of the file. + //! @param final_scatter_format The scattering representation after reading; + //! this is different from scatter_format if converting a Legendre to + //! a tabular representation. + //! @param order_data The dimensionality of the scattering data in the file. + //! @param is_isotropic Is this an isotropic or angular with respect to + //! the incoming particle. + //! @param n_pol Number of polar angles. + //! @param n_azi Number of azimuthal angles. + void from_hdf5(hid_t xsdata_grp, bool fissionable, + AngleDistributionType scatter_format, + AngleDistributionType final_scatter_format, int order_data, + bool is_isotropic, int n_pol, int n_azi); + + //! \brief Combines the microscopic data to a macroscopic object. + //! + //! @param micros Microscopic objects to combine. + //! @param scalars Scalars to multiply the microscopic data by. + void combine(const vector& those_xs, const vector& scalars); + + //! \brief Checks to see if this and that are able to be combined + //! + //! This comparison is used when building macroscopic cross sections + //! from microscopic cross sections. + //! @param that The other XsData to compare to this one. + //! @return True if they can be combined. + bool equiv(const XsData& that); }; - -} //namespace openmc +} // namespace openmc #endif // OPENMC_XSDATA_H diff --git a/man/man1/openmc.1 b/man/man1/openmc.1 index 8a93af514e9..d121a8956d9 100644 --- a/man/man1/openmc.1 +++ b/man/man1/openmc.1 @@ -8,7 +8,10 @@ sections are available. .SH SYNOPSIS \fBopenmc\fR [\fIoptions\fR] [\fIpath\fR] .PP -It is assumed that if no +.I path +specifies either the path to a single model XML file containing the full model +or a directory containing either a model.xml file or a set of individual XML +files (settings.xml, materials.xml, geometry.xml). It is assumed that if no .I path is specified, the XML input files are present in the current directory. .SH OPTIONS @@ -34,7 +37,7 @@ Restart a previous run from a state point or a particle restart file named Use \fIN\fP OpenMP threads. .TP .B "\-t\fR, \fP\-\-track" -Write tracks for all particles. +Write tracks for all particles (up to max_tracks). .TP .B "\-v\fR, \fP\-\-version" Show version information. @@ -46,6 +49,9 @@ The behavior of .B openmc is affected by the following environment variables. .TP +.B OPENMC_CHAIN_FILE +Indicates the path to a depletion chain XML file. +.TP .B OPENMC_CROSS_SECTIONS Indicates the default path to the cross_sections.xml summary file that is used to locate HDF5 format cross section libraries if the user has not specified the @@ -57,8 +63,8 @@ Indicates the default path to an HDF5 file that contains multi-group cross section libraries if the user has not specified the tag in .I materials.xml\fP. .SH LICENSE -Copyright \(co 2011-2021 Massachusetts Institute of Technology and OpenMC -contributors. +Copyright \(co 2011-2024 Massachusetts Institute of Technology, UChicago +Argonne LLC, and OpenMC contributors. .PP Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -80,7 +86,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. The OpenMC source code is hosted on GitHub at https://github.com/openmc-dev/openmc. With a github account, you can submit issues directly on the github repository that will then be reviewed by OpenMC -developers. Alternatively, you can send a bug report to -.I openmc-users@googlegroups.com\fP. +developers. Alternatively, you can post a message on the discussion forum at +https://openmc.discourse.group. .SH AUTHOR Paul K. Romano (\fIpaul.k.romano@gmail.com\fP) diff --git a/openmc/__init__.py b/openmc/__init__.py index bd27ab308ed..17b0abe2f69 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -1,4 +1,5 @@ from openmc.arithmetic import * +from openmc.bounding_box import * from openmc.cell import * from openmc.checkvalue import * from openmc.mesh import * @@ -10,10 +11,11 @@ from openmc.plots import * from openmc.region import * from openmc.volume import * -from openmc.source import * -from openmc.settings import * +from openmc.weight_windows import * from openmc.surface import * from openmc.universe import * +from openmc.source import * +from openmc.settings import * from openmc.lattice import * from openmc.filter import * from openmc.filter_expansion import * @@ -29,9 +31,12 @@ from openmc.plotter import * from openmc.search import * from openmc.polynomial import * +from openmc.tracks import * from . import examples +from .config import * + +# Import a few names from the model module +from openmc.model import Model -# Import a few convencience functions that used to be here -from openmc.model import rectangular_prism, hexagonal_prism -__version__ = '0.12.2' +__version__ = '0.14.1-dev' diff --git a/openmc/_xml.py b/openmc/_xml.py index 32679fd89ec..b40ecb258a9 100644 --- a/openmc/_xml.py +++ b/openmc/_xml.py @@ -1,22 +1,40 @@ -def clean_indentation(element, level=0, spaces_per_level=2): - """ - copy and paste from https://effbot.org/zone/element-lib.htm#prettyprint - it basically walks your tree and adds spaces and newlines so the tree is - printed in a nice way +def clean_indentation(element, level=0, spaces_per_level=2, trailing_indent=True): + """Set indentation of XML element and its sub-elements. + Copied and pasted from https://effbot.org/zone/element-lib.htm#prettyprint. + It walks your tree and adds spaces and newlines so the tree is + printed in a nice way. + + Parameters + ---------- + level : int + Indentation level for the element passed in (default 0) + spaces_per_level : int + Number of spaces per indentation level (default 2) + trailing_indent : bool + Whether or not to add indentation after closing the element + """ i = "\n" + level*spaces_per_level*" " + # ensure there's always some tail for the element passed in + if not element.tail: + element.tail = "" + if len(element): if not element.text or not element.text.strip(): element.text = i + spaces_per_level*" " - if not element.tail or not element.tail.strip(): + if trailing_indent and (not element.tail or not element.tail.strip()): element.tail = i for sub_element in element: + # `trailing_indent` is intentionally not forwarded to the recursive + # call. Any child element of the topmost element should add + # indentation at the end to ensure its parent's indentation is + # correct. clean_indentation(sub_element, level+1, spaces_per_level) if not sub_element.tail or not sub_element.tail.strip(): sub_element.tail = i else: - if level and (not element.tail or not element.tail.strip()): + if trailing_indent and level and (not element.tail or not element.tail.strip()): element.tail = i @@ -25,7 +43,7 @@ def get_text(elem, name, default=None): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element Element from which to search name : str Name of attribute/subelement @@ -50,7 +68,7 @@ def reorder_attributes(root): Parameters ---------- - root : xml.etree.ElementTree.Element + root : lxml.etree._Element Root element """ @@ -61,3 +79,25 @@ def reorder_attributes(root): attribs = sorted(attrib.items()) attrib.clear() attrib.update(attribs) + + +def get_elem_tuple(elem, name, dtype=int): + '''Helper function to get a tuple of values from an elem + + Parameters + ---------- + elem : lxml.etree._Element + XML element that should contain a tuple + name : str + Name of the subelement to obtain tuple from + dtype : data-type + The type of each element in the tuple + + Returns + ------- + tuple of dtype + Data read from the tuple + ''' + subelem = elem.find(name) + if subelem is not None: + return tuple([dtype(x) for x in subelem.text.split()]) diff --git a/openmc/arithmetic.py b/openmc/arithmetic.py index 0daea5f79d6..4520553dafc 100644 --- a/openmc/arithmetic.py +++ b/openmc/arithmetic.py @@ -54,33 +54,32 @@ def __eq__(self, other): return str(other) == str(self) def __repr__(self): - return '({} {} {})'.format(self.left_score, self.binary_op, - self.right_score) + return f'({self.left_score} {self.binary_op} {self.right_score})' @property def left_score(self): return self._left_score - @property - def right_score(self): - return self._right_score - - @property - def binary_op(self): - return self._binary_op - @left_score.setter def left_score(self, left_score): cv.check_type('left_score', left_score, (str, CrossScore, AggregateScore)) self._left_score = left_score + @property + def right_score(self): + return self._right_score + @right_score.setter def right_score(self, right_score): cv.check_type('right_score', right_score, (str, CrossScore, AggregateScore)) self._right_score = right_score + @property + def binary_op(self): + return self._binary_op + @binary_op.setter def binary_op(self, binary_op): cv.check_type('binary_op', binary_op, str) @@ -132,14 +131,32 @@ def __repr__(self): def left_nuclide(self): return self._left_nuclide + @left_nuclide.setter + def left_nuclide(self, left_nuclide): + cv.check_type('left_nuclide', left_nuclide, + (openmc.Nuclide, CrossNuclide, AggregateNuclide)) + self._left_nuclide = left_nuclide + @property def right_nuclide(self): return self._right_nuclide + @right_nuclide.setter + def right_nuclide(self, right_nuclide): + cv.check_type('right_nuclide', right_nuclide, + (openmc.Nuclide, CrossNuclide, AggregateNuclide)) + self._right_nuclide = right_nuclide + @property def binary_op(self): return self._binary_op + @binary_op.setter + def binary_op(self, binary_op): + cv.check_type('binary_op', binary_op, str) + cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) + self._binary_op = binary_op + @property def name(self): @@ -163,24 +180,6 @@ def name(self): return string - @left_nuclide.setter - def left_nuclide(self, left_nuclide): - cv.check_type('left_nuclide', left_nuclide, - (openmc.Nuclide, CrossNuclide, AggregateNuclide)) - self._left_nuclide = left_nuclide - - @right_nuclide.setter - def right_nuclide(self, right_nuclide): - cv.check_type('right_nuclide', right_nuclide, - (openmc.Nuclide, CrossNuclide, AggregateNuclide)) - self._right_nuclide = right_nuclide - - @binary_op.setter - def binary_op(self, binary_op): - cv.check_type('binary_op', binary_op, str) - cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) - self._binary_op = binary_op - class CrossFilter: """A special-purpose filter used to encapsulate all combinations of two @@ -188,9 +187,9 @@ class CrossFilter: Parameters ---------- - left_filter : Filter or CrossFilter + left_filter : openmc.Filter or CrossFilter The left filter in the outer product - right_filter : Filter or CrossFilter + right_filter : openmc.Filter or CrossFilter The right filter in the outer product binary_op : str The tally arithmetic binary operator (e.g., '+', '-', etc.) used to @@ -200,9 +199,9 @@ class CrossFilter: ---------- type : str The type of the crossfilter (e.g., 'energy / energy') - left_filter : Filter or CrossFilter + left_filter : openmc.Filter or CrossFilter The left filter in the outer product - right_filter : Filter or CrossFilter + right_filter : openmc.Filter or CrossFilter The right filter in the outer product binary_op : str The tally arithmetic binary operator (e.g., '+', '-', etc.) used to @@ -241,19 +240,37 @@ def __repr__(self): def left_filter(self): return self._left_filter + @left_filter.setter + def left_filter(self, left_filter): + cv.check_type('left_filter', left_filter, + (openmc.Filter, CrossFilter, AggregateFilter)) + self._left_filter = left_filter + @property def right_filter(self): return self._right_filter + @right_filter.setter + def right_filter(self, right_filter): + cv.check_type('right_filter', right_filter, + (openmc.Filter, CrossFilter, AggregateFilter)) + self._right_filter = right_filter + @property def binary_op(self): return self._binary_op + @binary_op.setter + def binary_op(self, binary_op): + cv.check_type('binary_op', binary_op, str) + cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) + self._binary_op = binary_op + @property def type(self): left_type = self.left_filter.type right_type = self.right_filter.type - return '({} {} {})'.format(left_type, self.binary_op, right_type) + return f'({left_type} {self.binary_op} {right_type})' @property def bins(self): @@ -266,24 +283,6 @@ def num_bins(self): else: return 0 - @left_filter.setter - def left_filter(self, left_filter): - cv.check_type('left_filter', left_filter, - (openmc.Filter, CrossFilter, AggregateFilter)) - self._left_filter = left_filter - - @right_filter.setter - def right_filter(self, right_filter): - cv.check_type('right_filter', right_filter, - (openmc.Filter, CrossFilter, AggregateFilter)) - self._right_filter = right_filter - - @binary_op.setter - def binary_op(self, binary_op): - cv.check_type('binary_op', binary_op, str) - cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) - self._binary_op = binary_op - def get_bin_index(self, filter_bin): """Returns the index in the CrossFilter for some bin. @@ -360,7 +359,7 @@ def get_pandas_dataframe(self, data_size, summary=None): right_df = self.right_filter.get_pandas_dataframe(data_size, summary) left_df = left_df.astype(str) right_df = right_df.astype(str) - df = '(' + left_df + ' ' + self.binary_op + ' ' + right_df + ')' + df = f'({left_df} {self.binary_op} {right_df})' return df @@ -405,35 +404,35 @@ def __eq__(self, other): def __repr__(self): string = ', '.join(map(str, self.scores)) - string = '{}({})'.format(self.aggregate_op, string) + string = f'{self.aggregate_op}({string})' return string @property def scores(self): return self._scores - @property - def aggregate_op(self): - return self._aggregate_op - - @property - def name(self): - - # Append each score in the aggregate to the string - string = '(' + ', '.join(self.scores) + ')' - return string - @scores.setter def scores(self, scores): cv.check_iterable_type('scores', scores, str) self._scores = scores + @property + def aggregate_op(self): + return self._aggregate_op + @aggregate_op.setter def aggregate_op(self, aggregate_op): cv.check_type('aggregate_op', aggregate_op, (str, CrossScore)) cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) self._aggregate_op = aggregate_op + @property + def name(self): + + # Append each score in the aggregate to the string + string = '(' + ', '.join(self.scores) + ')' + return string + class AggregateNuclide: """A special-purpose tally nuclide used to encapsulate an aggregate of a @@ -476,7 +475,7 @@ def __eq__(self, other): def __repr__(self): # Append each nuclide in the aggregate to the string - string = '{}('.format(self.aggregate_op) + string = f'{self.aggregate_op}(' names = [nuclide.name if isinstance(nuclide, openmc.Nuclide) else str(nuclide) for nuclide in self.nuclides] string += ', '.join(map(str, names)) + ')' @@ -486,10 +485,21 @@ def __repr__(self): def nuclides(self): return self._nuclides + @nuclides.setter + def nuclides(self, nuclides): + cv.check_iterable_type('nuclides', nuclides, (str, CrossNuclide)) + self._nuclides = nuclides + @property def aggregate_op(self): return self._aggregate_op + @aggregate_op.setter + def aggregate_op(self, aggregate_op): + cv.check_type('aggregate_op', aggregate_op, str) + cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) + self._aggregate_op = aggregate_op + @property def name(self): @@ -499,17 +509,6 @@ def name(self): string = '(' + ', '.join(map(str, names)) + ')' return string - @nuclides.setter - def nuclides(self, nuclides): - cv.check_iterable_type('nuclides', nuclides, (str, CrossNuclide)) - self._nuclides = nuclides - - @aggregate_op.setter - def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, str) - cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) - self._aggregate_op = aggregate_op - class AggregateFilter: """A special-purpose tally filter used to encapsulate an aggregate of a @@ -517,7 +516,7 @@ class AggregateFilter: Parameters ---------- - aggregate_filter : Filter or CrossFilter + aggregate_filter : openmc.Filter or CrossFilter The filter included in the aggregation bins : Iterable of tuple The filter bins included in the aggregation @@ -529,7 +528,7 @@ class AggregateFilter: ---------- type : str The type of the aggregatefilter (e.g., 'sum(energy)', 'sum(cell)') - aggregate_filter : filter + aggregate_filter : openmc.Filter The filter included in the aggregation aggregate_op : str The tally aggregation operator (e.g., 'sum', 'avg', etc.) used @@ -543,8 +542,7 @@ class AggregateFilter: def __init__(self, aggregate_filter, bins=None, aggregate_op=None): - self._type = '{}({})'.format(aggregate_op, - aggregate_filter.short_name.lower()) + self._type = f'{aggregate_op}({aggregate_filter.short_name.lower()})' self._bins = None self._aggregate_filter = None @@ -589,47 +587,51 @@ def __repr__(self): def aggregate_filter(self): return self._aggregate_filter + @aggregate_filter.setter + def aggregate_filter(self, aggregate_filter): + cv.check_type('aggregate_filter', aggregate_filter, + (openmc.Filter, CrossFilter)) + self._aggregate_filter = aggregate_filter + @property def aggregate_op(self): return self._aggregate_op + @aggregate_op.setter + def aggregate_op(self, aggregate_op): + cv.check_type('aggregate_op', aggregate_op, str) + cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) + self._aggregate_op = aggregate_op + @property def type(self): return self._type - @property - def bins(self): - return self._bins - - @property - def num_bins(self): - return len(self.bins) if self.aggregate_filter else 0 - @type.setter def type(self, filter_type): if filter_type not in _FILTER_TYPES: - msg = 'Unable to set AggregateFilter type to "{}" since it ' \ - 'is not one of the supported types'.format(filter_type) + msg = f'Unable to set AggregateFilter type to "{filter_type}" ' \ + 'since it is not one of the supported types' raise ValueError(msg) self._type = filter_type - @aggregate_filter.setter - def aggregate_filter(self, aggregate_filter): - cv.check_type('aggregate_filter', aggregate_filter, - (openmc.Filter, CrossFilter)) - self._aggregate_filter = aggregate_filter + @property + def bins(self): + return self._bins @bins.setter def bins(self, bins): cv.check_iterable_type('bins', bins, Iterable) self._bins = list(map(tuple, bins)) - @aggregate_op.setter - def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, str) - cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) - self._aggregate_op = aggregate_op + @property + def num_bins(self): + return len(self.bins) if self.aggregate_filter else 0 + + @property + def shape(self): + return (self.num_bins,) def get_bin_index(self, filter_bin): """Returns the index in the AggregateFilter for some bin. @@ -660,8 +662,8 @@ def get_bin_index(self, filter_bin): """ if filter_bin not in self.bins: - msg = 'Unable to get the bin index for AggregateFilter since ' \ - '"{}" is not one of the bins'.format(filter_bin) + msg = ('Unable to get the bin index for AggregateFilter since ' + f'"{filter_bin}" is not one of the bins') raise ValueError(msg) else: return self.bins.index(filter_bin) @@ -757,8 +759,7 @@ def merge(self, other): """ if not self.can_merge(other): - msg = 'Unable to merge "{}" with "{}" filters'.format( - self.type, other.type) + msg = f'Unable to merge "{self.type}" with "{other.type}" filters' raise ValueError(msg) # Create deep copy of filter to return as merged filter diff --git a/openmc/bounding_box.py b/openmc/bounding_box.py new file mode 100644 index 00000000000..6e58ca8ba02 --- /dev/null +++ b/openmc/bounding_box.py @@ -0,0 +1,201 @@ +from __future__ import annotations +from typing import Iterable + +import numpy as np + +from .checkvalue import check_length + + +class BoundingBox: + """Axis-aligned bounding box. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + lower_left : iterable of float + The x, y, z coordinates of the lower left corner of the bounding box in [cm] + upper_right : iterable of float + The x, y, z coordinates of the upper right corner of the bounding box in [cm] + + Attributes + ---------- + center : numpy.ndarray + x, y, z coordinates of the center of the bounding box in [cm] + lower_left : numpy.ndarray + The x, y, z coordinates of the lower left corner of the bounding box in [cm] + upper_right : numpy.ndarray + The x, y, z coordinates of the upper right corner of the bounding box in [cm] + volume : float + The volume of the bounding box in [cm^3] + extent : dict + A dictionary of basis as keys and the extent (left, right, bottom, top) + as values. Intended use in Matplotlib plots when setting extent + width : iterable of float + The width of the x, y and z axis in [cm] + """ + + def __init__(self, lower_left: Iterable[float], upper_right: Iterable[float]): + check_length("lower_left", lower_left, 3, 3) + check_length("upper_right", upper_right, 3, 3) + self._bounds = np.asarray([lower_left, upper_right], dtype=float) + + def __repr__(self) -> str: + return "BoundingBox(lower_left={}, upper_right={})".format( + tuple(self.lower_left), tuple(self.upper_right)) + + def __getitem__(self, key) -> np.ndarray: + return self._bounds[key] + + def __len__(self): + return 2 + + def __setitem__(self, key, val): + self._bounds[key] = val + + def __iand__(self, other: BoundingBox) -> BoundingBox: + """Updates the box be the intersection of itself and another box + + Parameters + ---------- + other : BoundingBox + The box used to resize this box + + Returns + ------- + An updated bounding box + """ + self.lower_left = np.maximum(self.lower_left, other.lower_left) + self.upper_right = np.minimum(self.upper_right, other.upper_right) + return self + + def __and__(self, other: BoundingBox) -> BoundingBox: + new = BoundingBox(*self) + new &= other + return new + + def __ior__(self, other: BoundingBox) -> BoundingBox: + """Updates the box be the union of itself and another box + + Parameters + ---------- + other : BoundingBox + The box used to resize this box + + Returns + ------- + An updated bounding box + """ + self.lower_left = np.minimum(self.lower_left, other.lower_left) + self.upper_right = np.maximum(self.upper_right, other.upper_right) + return self + + def __or__(self, other: BoundingBox) -> BoundingBox: + new = BoundingBox(*self) + new |= other + return new + + def __contains__(self, other): + """Check whether or not a point or another bounding box is in the bounding box. + + For another bounding box to be in the parent it must lie fully inside of it. + """ + # test for a single point + if isinstance(other, (tuple, list, np.ndarray)): + point = other + check_length("Point", point, 3, 3) + return all(point > self.lower_left) and all(point < self.upper_right) + elif isinstance(other, BoundingBox): + return all([p in self for p in [other.lower_left, other.upper_right]]) + else: + raise TypeError( + f"Unable to determine if {other} is in the bounding box." + f" Expected a tuple or a bounding box, but {type(other)} given" + ) + + @property + def center(self) -> np.ndarray: + return (self[0] + self[1]) / 2 + + @property + def lower_left(self) -> np.ndarray: + return self[0] + + @lower_left.setter + def lower_left(self, llc): + check_length('lower_left', llc, 3, 3) + self[0] = llc + + @property + def upper_right(self) -> np.ndarray: + return self[1] + + @upper_right.setter + def upper_right(self, urc): + check_length('upper_right', urc, 3, 3) + self[1] = urc + + @property + def volume(self) -> float: + return np.abs(np.prod(self[1] - self[0])) + + @property + def extent(self): + return { + "xy": ( + self.lower_left[0], + self.upper_right[0], + self.lower_left[1], + self.upper_right[1], + ), + "xz": ( + self.lower_left[0], + self.upper_right[0], + self.lower_left[2], + self.upper_right[2], + ), + "yz": ( + self.lower_left[1], + self.upper_right[1], + self.lower_left[2], + self.upper_right[2], + ), + } + + @property + def width(self): + return self.upper_right - self.lower_left + + def expand(self, padding_distance: float, inplace: bool = False) -> BoundingBox: + """Returns an expanded bounding box + + Parameters + ---------- + padding_distance : float + The distance to enlarge the bounding box by + inplace : bool + Whether or not to return a new BoundingBox instance or to modify the + current BoundingBox object. + + Returns + ------- + An expanded bounding box + """ + if inplace: + self[0] -= padding_distance + self[1] += padding_distance + return self + else: + return BoundingBox(self[0] - padding_distance, self[1] + padding_distance) + + @classmethod + def infinite(cls) -> BoundingBox: + """Create an infinite box. Useful as a starting point for determining + geometry bounds. + + Returns + ------- + An infinitely large bounding box. + """ + infs = np.full((3,), np.inf) + return cls(-infs, infs) diff --git a/openmc/cell.py b/openmc/cell.py index c55238df860..94fac841358 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -1,10 +1,8 @@ -from collections import OrderedDict from collections.abc import Iterable -from copy import deepcopy from math import cos, sin, pi from numbers import Real -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np from uncertainties import UFloat @@ -14,6 +12,7 @@ from .mixin import IDManagerMixin from .region import Region, Complement from .surface import Halfspace +from .bounding_box import BoundingBox class Cell(IDManagerMixin): @@ -27,7 +26,7 @@ class Cell(IDManagerMixin): automatically be assigned. name : str, optional Name of the cell. If not specified, the name is the empty string. - fill : openmc.Material or openmc.Universe or openmc.Lattice or None or iterable of openmc.Material, optional + fill : openmc.Material or openmc.UniverseBase or openmc.Lattice or None or iterable of openmc.Material, optional Indicates what the region of space is filled with region : openmc.Region, optional Region of space that is assigned to the cell. @@ -38,7 +37,7 @@ class Cell(IDManagerMixin): Unique identifier for the cell name : str Name of the cell - fill : openmc.Material or openmc.Universe or openmc.Lattice or None or iterable of openmc.Material + fill : openmc.Material or openmc.UniverseBase or openmc.Lattice or None or iterable of openmc.Material Indicates what the region of space is filled with. If None, the cell is treated as a void. An iterable of materials is used to fill repeated instances of a cell with different materials. @@ -86,12 +85,14 @@ class Cell(IDManagerMixin): calculated in a stochastic volume calculation and added via the :meth:`Cell.add_volume_information` method. For 'distribmat' cells it is the total volume of all instances. - atoms : collections.OrderedDict + atoms : dict Mapping of nuclides to the total number of atoms for each nuclide present in the cell, or in all of its instances for a 'distribmat' fill. For example, {'U235': 1.0e22, 'U238': 5.0e22, ...}. .. versionadded:: 0.12 + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the cell """ @@ -148,15 +149,42 @@ def __repr__(self): def name(self): return self._name + @name.setter + def name(self, name): + if name is not None: + cv.check_type('cell name', name, str) + self._name = name + else: + self._name = '' + @property def fill(self): return self._fill + @fill.setter + def fill(self, fill): + if fill is not None: + if isinstance(fill, Iterable): + for i, f in enumerate(fill): + if f is not None: + cv.check_type('cell.fill[i]', f, openmc.Material) + + elif not isinstance(fill, (openmc.Material, openmc.Lattice, + openmc.UniverseBase)): + msg = (f'Unable to set Cell ID="{self._id}" to use a ' + f'non-Material or Universe fill "{fill}"') + raise ValueError(msg) + self._fill = fill + + # Info about atom content can now be invalid + # (since fill has just changed) + self._atoms = None + @property def fill_type(self): if isinstance(self.fill, openmc.Material): return 'material' - elif isinstance(self.fill, openmc.Universe): + elif isinstance(self.fill, openmc.UniverseBase): return 'universe' elif isinstance(self.fill, openmc.Lattice): return 'lattice' @@ -169,10 +197,37 @@ def fill_type(self): def region(self): return self._region + @region.setter + def region(self, region): + if region is not None: + cv.check_type('cell region', region, Region) + self._region = region + @property def rotation(self): return self._rotation + @rotation.setter + def rotation(self, rotation): + cv.check_length('cell rotation', rotation, 3) + self._rotation = np.asarray(rotation) + + # Save rotation matrix -- the reason we do this instead of having it be + # automatically calculated when the rotation_matrix property is accessed + # is so that plotting on a rotated geometry can be done faster. + if self._rotation.ndim == 2: + # User specified rotation matrix directly + self._rotation_matrix = self._rotation + else: + phi, theta, psi = self.rotation*(-pi/180.) + c3, s3 = cos(phi), sin(phi) + c2, s2 = cos(theta), sin(theta) + c1, s1 = cos(psi), sin(psi) + self._rotation_matrix = np.array([ + [c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2], + [c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3], + [-s2, c2*s3, c2*c3]]) + @property def rotation_matrix(self): return self._rotation_matrix @@ -181,19 +236,57 @@ def rotation_matrix(self): def temperature(self): return self._temperature + @temperature.setter + def temperature(self, temperature): + # Make sure temperatures are positive + cv.check_type('cell temperature', temperature, (Iterable, Real), none_ok=True) + if isinstance(temperature, Iterable): + cv.check_type('cell temperature', temperature, Iterable, Real) + for T in temperature: + cv.check_greater_than('cell temperature', T, 0.0, True) + elif isinstance(temperature, Real): + cv.check_greater_than('cell temperature', temperature, 0.0, True) + + # If this cell is filled with a universe or lattice, propagate + # temperatures to all cells contained. Otherwise, simply assign it. + if self.fill_type in ('universe', 'lattice'): + for c in self.get_all_cells().values(): + if c.fill_type == 'material': + c._temperature = temperature + else: + self._temperature = temperature + @property def translation(self): return self._translation + @translation.setter + def translation(self, translation): + cv.check_type('cell translation', translation, Iterable, Real) + cv.check_length('cell translation', translation, 3) + self._translation = np.asarray(translation) + @property def volume(self): return self._volume + @volume.setter + def volume(self, volume): + if volume is not None: + cv.check_type('cell volume', volume, (Real, UFloat)) + cv.check_greater_than('cell volume', volume, 0.0, equality=True) + + self._volume = volume + + # Info about atom content can now be invalid + # (since volume has just changed) + self._atoms = None + @property def atoms(self): if self._atoms is None: if self._volume is None: - msg = ('Cannot calculate atom content becouse no volume ' + msg = ('Cannot calculate atom content because no volume ' 'is set. Use Cell.volume to provide it or perform ' 'a stochastic volume calculation.') raise ValueError(msg) @@ -214,26 +307,26 @@ def atoms(self): self._atoms = self._fill.get_nuclide_atom_densities() # Convert to total number of atoms - for key, nuclide in self._atoms.items(): - atom = nuclide[1] * self._volume * 1.0e+24 + for key, atom_per_bcm in self._atoms.items(): + atom = atom_per_bcm * self._volume * 1.0e+24 self._atoms[key] = atom elif self.fill_type == 'distribmat': # Assumes that volume is total volume of all instances # Also assumes that all instances have the same volume partial_volume = self.volume / len(self.fill) - self._atoms = OrderedDict() + self._atoms = {} for mat in self.fill: - for key, nuclide in mat.get_nuclide_atom_densities().items(): + for key, atom_per_bcm in mat.get_nuclide_atom_densities().items(): # To account for overlap of nuclides between distribmat # we need to append new atoms to any existing value # hence it is necessary to ask for default. atom = self._atoms.setdefault(key, 0) - atom += nuclide[1] * partial_volume * 1.0e+24 + atom += atom_per_bcm * partial_volume * 1.0e+24 self._atoms[key] = atom else: - msg = 'Unrecognized fill_type: {}'.format(self.fill_type) + msg = f'Unrecognized fill_type: {self.fill_type}' raise ValueError(msg) return self._atoms @@ -250,8 +343,7 @@ def bounding_box(self): if self.region is not None: return self.region.bounding_box else: - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) + return BoundingBox.infinite() @property def num_instances(self): @@ -261,99 +353,6 @@ def num_instances(self): 'Geometry.determine_paths() method.') return self._num_instances - @name.setter - def name(self, name): - if name is not None: - cv.check_type('cell name', name, str) - self._name = name - else: - self._name = '' - - @fill.setter - def fill(self, fill): - if fill is not None: - if isinstance(fill, Iterable): - for i, f in enumerate(fill): - if f is not None: - cv.check_type('cell.fill[i]', f, openmc.Material) - - elif not isinstance(fill, (openmc.Material, openmc.Lattice, - openmc.Universe)): - msg = ('Unable to set Cell ID="{0}" to use a non-Material or ' - 'Universe fill "{1}"'.format(self._id, fill)) - raise ValueError(msg) - - self._fill = fill - - # Info about atom content can now be invalid - # (since fill has just changed) - self._atoms = None - - @rotation.setter - def rotation(self, rotation): - cv.check_length('cell rotation', rotation, 3) - self._rotation = np.asarray(rotation) - - # Save rotation matrix -- the reason we do this instead of having it be - # automatically calculated when the rotation_matrix property is accessed - # is so that plotting on a rotated geometry can be done faster. - if self._rotation.ndim == 2: - # User specified rotation matrix directly - self._rotation_matrix = self._rotation - else: - phi, theta, psi = self.rotation*(-pi/180.) - c3, s3 = cos(phi), sin(phi) - c2, s2 = cos(theta), sin(theta) - c1, s1 = cos(psi), sin(psi) - self._rotation_matrix = np.array([ - [c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2], - [c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3], - [-s2, c2*s3, c2*c3]]) - - @translation.setter - def translation(self, translation): - cv.check_type('cell translation', translation, Iterable, Real) - cv.check_length('cell translation', translation, 3) - self._translation = np.asarray(translation) - - @temperature.setter - def temperature(self, temperature): - # Make sure temperatures are positive - cv.check_type('cell temperature', temperature, (Iterable, Real)) - if isinstance(temperature, Iterable): - cv.check_type('cell temperature', temperature, Iterable, Real) - for T in temperature: - cv.check_greater_than('cell temperature', T, 0.0, True) - else: - cv.check_greater_than('cell temperature', temperature, 0.0, True) - - # If this cell is filled with a universe or lattice, propagate - # temperatures to all cells contained. Otherwise, simply assign it. - if self.fill_type in ('universe', 'lattice'): - for c in self.get_all_cells().values(): - if c.fill_type == 'material': - c._temperature = temperature - else: - self._temperature = temperature - - @region.setter - def region(self, region): - if region is not None: - cv.check_type('cell region', region, Region) - self._region = region - - @volume.setter - def volume(self, volume): - if volume is not None: - cv.check_type('cell volume', volume, (Real, UFloat)) - cv.check_greater_than('cell volume', volume, 0.0, equality=True) - - self._volume = volume - - # Info about atom content can now be invalid - # (sice volume has just changed) - self._atoms = None - def add_volume_information(self, volume_calc): """Add volume information to a cell. @@ -388,13 +387,13 @@ def get_nuclide_densities(self): Returns ------- - nuclides : collections.OrderedDict + nuclides : dict Dictionary whose keys are nuclide names and values are 2-tuples of (nuclide, density) """ - nuclides = OrderedDict() + nuclides = {} if self.fill_type == 'material': nuclides.update(self.fill.get_nuclide_densities()) @@ -409,10 +408,10 @@ def get_nuclide_densities(self): nuclides[name] = (nuclide, density) else: raise RuntimeError( - 'Volume information is needed to calculate microscopic cross ' - 'sections for cell {}. This can be done by running a ' - 'stochastic volume calculation via the ' - 'openmc.VolumeCalculation object'.format(self.id)) + 'Volume information is needed to calculate microscopic ' + f'cross sections for cell {self.id}. This can be done by ' + 'running a stochastic volume calculation via the ' + 'openmc.VolumeCalculation object') return nuclides @@ -422,13 +421,13 @@ def get_all_cells(self, memo=None): Returns ------- - cells : collections.orderedDict + cells : dict Dictionary whose keys are cell IDs and values are :class:`Cell` instances """ - cells = OrderedDict() + cells = {} if memo and self in memo: return cells @@ -446,12 +445,12 @@ def get_all_materials(self, memo=None): Returns ------- - materials : collections.OrderedDict + materials : dict Dictionary whose keys are material IDs and values are :class:`Material` instances """ - materials = OrderedDict() + materials = {} if self.fill_type == 'material': materials[self.fill.id] = self.fill elif self.fill_type == 'distribmat': @@ -472,13 +471,13 @@ def get_all_universes(self): Returns ------- - universes : collections.OrderedDict + universes : dict Dictionary whose keys are universe IDs and values are :class:`Universe` instances """ - universes = OrderedDict() + universes = {} if self.fill_type == 'universe': universes[self.fill.id] = self.fill @@ -520,8 +519,14 @@ def clone(self, clone_materials=True, clone_regions=True, memo=None): paths = self._paths self._paths = None - clone = deepcopy(self) - clone.id = None + clone = openmc.Cell(name=self.name) + clone.volume = self.volume + if self.temperature is not None: + clone.temperature = self.temperature + if self.translation is not None: + clone.translation = self.translation + if self.rotation is not None: + clone.rotation = self.rotation clone._num_instances = None # Restore paths on original instance @@ -553,12 +558,78 @@ def clone(self, clone_materials=True, clone_regions=True, memo=None): return memo[self] + def plot(self, *args, **kwargs): + """Display a slice plot of the cell. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + origin : iterable of float + Coordinates at the origin of the plot. If left as None then the + bounding box center will be used to attempt to ascertain the origin. + Defaults to (0, 0, 0) if the bounding box is not finite + width : iterable of float + Width of the plot in each basis direction. If left as none then the + bounding box width will be used to attempt to ascertain the plot + width. Defaults to (10, 10) if the bounding box is not finite + pixels : Iterable of int or int + If iterable of ints provided, then this directly sets the number of + pixels to use in each basis direction. If int provided, then this + sets the total number of pixels in the plot and the number of pixels + in each basis direction is calculated from this total and the image + aspect ratio. + basis : {'xy', 'xz', 'yz'} + The basis directions for the plot + color_by : {'cell', 'material'} + Indicate whether the plot should be colored by cell or by material + colors : dict + Assigns colors to specific materials or cells. Keys are instances of + :class:`Cell` or :class:`Material` and values are RGB 3-tuples, RGBA + 4-tuples, or strings indicating SVG color names. Red, green, blue, + and alpha should all be floats in the range [0.0, 1.0], for example: + + .. code-block:: python + + # Make water blue + water = openmc.Cell(fill=h2o) + water.plot(colors={water: (0., 0., 1.)}) + seed : int + Seed for the random number generator + openmc_exec : str + Path to OpenMC executable. + axes : matplotlib.Axes + Axes to draw to + legend : bool + Whether a legend showing material or cell names should be drawn + legend_kwargs : dict + Keyword arguments passed to :func:`matplotlib.pyplot.legend`. + outline : bool + Whether outlines between color boundaries should be drawn + axis_units : {'km', 'm', 'cm', 'mm'} + Units used on the plot axis + **kwargs + Keyword arguments passed to :func:`matplotlib.pyplot.imshow` + + Returns + ------- + matplotlib.axes.Axes + Axes containing resulting image + + """ + # Create dummy universe but preserve used_ids + next_id = openmc.Universe.next_id + u = openmc.Universe(cells=[self]) + openmc.Universe.used_ids.remove(u.id) + openmc.Universe.next_id = next_id + return u.plot(*args, **kwargs) + def create_xml_subelement(self, xml_element, memo=None): """Add the cell's xml representation to an incoming xml element Parameters ---------- - xml_element : xml.etree.ElementTree.Element + xml_element : lxml.etree._Element XML element to be added to memo : set or None @@ -635,6 +706,9 @@ def create_surface_elements(node, element, memo=None): if self.rotation is not None: element.set("rotation", ' '.join(map(str, self.rotation.ravel()))) + if self.volume is not None: + element.set("volume", str(self.volume)) + return element @classmethod @@ -643,13 +717,13 @@ def from_xml_element(cls, elem, surfaces, materials, get_universe): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element `` element surfaces : dict Dictionary mapping surface IDs to :class:`openmc.Surface` instances materials : dict - Dictionary mapping material IDs to :class:`openmc.Material` - instances (defined in :math:`openmc.Geometry.from_xml`) + Dictionary mapping material ID strings to :class:`openmc.Material` + instances (defined in :meth:`openmc.Geometry.from_xml`) get_universe : function Function returning universe (defined in :meth:`openmc.Geometry.from_xml`) @@ -688,10 +762,16 @@ def from_xml_element(cls, elem, surfaces, materials, get_universe): c.temperature = [float(t_i) for t_i in t.split()] else: c.temperature = float(t) + v = get_text(elem, 'volume') + if v is not None: + c.volume = float(v) for key in ('temperature', 'rotation', 'translation'): value = get_text(elem, key) if value is not None: - setattr(c, key, [float(x) for x in value.split()]) + values = [float(x) for x in value.split()] + if key == 'rotation' and len(values) == 9: + values = np.array(values).reshape(3, 3) + setattr(c, key, values) # Add this cell to appropriate universe univ_id = int(get_text(elem, 'universe', 0)) diff --git a/openmc/checkvalue.py b/openmc/checkvalue.py index a59b38a6305..840306486ff 100644 --- a/openmc/checkvalue.py +++ b/openmc/checkvalue.py @@ -1,8 +1,13 @@ import copy +import os +import typing # required to prevent typing.Union namespace overwriting Union from collections.abc import Iterable import numpy as np +# Type for arguments that accept file paths +PathLike = typing.Union[str, os.PathLike] + def check_type(name, value, expected_type, expected_iter_type=None, *, none_ok=False): """Ensure that an object is of an expected type. Optionally, if the object is @@ -32,16 +37,15 @@ def check_type(name, value, expected_type, expected_iter_type=None, *, none_ok=F 'following types: "{}"'.format(name, value, ', '.join( [t.__name__ for t in expected_type])) else: - msg = 'Unable to set "{}" to "{}" which is not of type "{}"'.format( - name, value, expected_type.__name__) + msg = (f'Unable to set "{name}" to "{value}" which is not of type "' + f'{expected_type.__name__}"') raise TypeError(msg) if expected_iter_type: if isinstance(value, np.ndarray): if not issubclass(value.dtype.type, expected_iter_type): - msg = 'Unable to set "{}" to "{}" since each item must be ' \ - 'of type "{}"'.format(name, value, - expected_iter_type.__name__) + msg = (f'Unable to set "{name}" to "{value}" since each item ' + f'must be of type "{expected_iter_type.__name__}"') raise TypeError(msg) else: return @@ -54,9 +58,8 @@ def check_type(name, value, expected_type, expected_iter_type=None, *, none_ok=F name, value, ', '.join([t.__name__ for t in expected_iter_type])) else: - msg = 'Unable to set "{}" to "{}" since each item must be ' \ - 'of type "{}"'.format(name, value, - expected_iter_type.__name__) + msg = (f'Unable to set "{name}" to "{value}" since each ' + f'item must be of type "{expected_iter_type.__name__}"') raise TypeError(msg) @@ -106,8 +109,8 @@ def check_iterable_type(name, value, expected_type, min_depth=1, max_depth=1): if isinstance(current_item, expected_type): # Is this deep enough? if len(tree) < min_depth: - msg = 'Error setting "{0}": The item at {1} does not meet the '\ - 'minimum depth of {2}'.format(name, ind_str, min_depth) + msg = (f'Error setting "{name}": The item at {ind_str} does not ' + f'meet the minimum depth of {min_depth}') raise TypeError(msg) # This item is okay. Move on to the next item. @@ -123,17 +126,16 @@ def check_iterable_type(name, value, expected_type, min_depth=1, max_depth=1): # But first, have we exceeded the max depth? if len(tree) > max_depth: - msg = 'Error setting {0}: Found an iterable at {1}, items '\ - 'in that iterable exceed the maximum depth of {2}' \ - .format(name, ind_str, max_depth) + msg = (f'Error setting {name}: Found an iterable at ' + f'{ind_str}, items in that iterable exceed the ' + f'maximum depth of {max_depth}') raise TypeError(msg) else: # This item is completely unexpected. - msg = "Error setting {0}: Items must be of type '{1}', but " \ - "item at {2} is of type '{3}'"\ - .format(name, expected_type.__name__, ind_str, - type(current_item).__name__) + msg = (f'Error setting {name}: Items must be of type ' + f'"{expected_type.__name__}", but item at {ind_str} is ' + f'of type "{type(current_item).__name__}"') raise TypeError(msg) @@ -156,17 +158,16 @@ def check_length(name, value, length_min, length_max=None): if length_max is None: if len(value) < length_min: - msg = 'Unable to set "{}" to "{}" since it must be at least of ' \ - 'length "{}"'.format(name, value, length_min) + msg = (f'Unable to set "{name}" to "{value}" since it must be at ' + f'least of length "{length_min}"') raise ValueError(msg) elif not length_min <= len(value) <= length_max: if length_min == length_max: - msg = 'Unable to set "{}" to "{}" since it must be of ' \ - 'length "{}"'.format(name, value, length_min) + msg = (f'Unable to set "{name}" to "{value}" since it must be of ' + f'length "{length_min}"') else: - msg = 'Unable to set "{}" to "{}" since it must have length ' \ - 'between "{}" and "{}"'.format(name, value, length_min, - length_max) + msg = (f'Unable to set "{name}" to "{value}" since it must have ' + f'length between "{length_min}" and "{length_max}"') raise ValueError(msg) @@ -185,8 +186,8 @@ def check_value(name, value, accepted_values): """ if value not in accepted_values: - msg = 'Unable to set "{0}" to "{1}" since it is not in "{2}"'.format( - name, value, accepted_values) + msg = (f'Unable to set "{name}" to "{value}" since it is not in ' + f'"{accepted_values}"') raise ValueError(msg) @@ -208,13 +209,13 @@ def check_less_than(name, value, maximum, equality=False): if equality: if value > maximum: - msg = 'Unable to set "{0}" to "{1}" since it is greater than ' \ - '"{2}"'.format(name, value, maximum) + msg = (f'Unable to set "{name}" to "{value}" since it is greater ' + f'than "{maximum}"') raise ValueError(msg) else: if value >= maximum: - msg = 'Unable to set "{0}" to "{1}" since it is greater than ' \ - 'or equal to "{2}"'.format(name, value, maximum) + msg = (f'Unable to set "{name}" to "{value}" since it is greater ' + f'than or equal to "{maximum}"') raise ValueError(msg) @@ -236,13 +237,13 @@ def check_greater_than(name, value, minimum, equality=False): if equality: if value < minimum: - msg = 'Unable to set "{0}" to "{1}" since it is less than ' \ - '"{2}"'.format(name, value, minimum) + msg = (f'Unable to set "{name}" to "{value}" since it is less than ' + f'"{minimum}"') raise ValueError(msg) else: if value <= minimum: - msg = 'Unable to set "{0}" to "{1}" since it is less than ' \ - 'or equal to "{2}"'.format(name, value, minimum) + msg = (f'Unable to set "{name}" to "{value}" since it is less than ' + f'or equal to "{minimum}"') raise ValueError(msg) @@ -265,8 +266,7 @@ def check_filetype_version(obj, expected_type, expected_version): # Check filetype if this_filetype != expected_type: - raise IOError('{} is not a {} file.'.format( - obj.filename, expected_type)) + raise IOError(f'{obj.filename} is not a {expected_type} file.') # Check version if this_version[0] != expected_version: @@ -276,9 +276,9 @@ def check_filetype_version(obj, expected_type, expected_version): '.'.join(str(v) for v in this_version), expected_version)) except AttributeError: - raise IOError('Could not read {} file. This most likely means the ' - 'file was produced by a different version of OpenMC than ' - 'the one you are using.'.format(obj.filename)) + raise IOError(f'Could not read {obj.filename} file. This most likely ' + 'means the file was produced by a different version of ' + 'OpenMC than the one you are using.') class CheckedList(list): diff --git a/openmc/cmfd.py b/openmc/cmfd.py index 61bda9ed99f..eff6a151fbb 100644 --- a/openmc/cmfd.py +++ b/openmc/cmfd.py @@ -135,7 +135,7 @@ def __repr__(self): return outstr def _get_repr(self, list_var, label): - outstr = "\t{:<11} = ".format(label) + outstr = f"\t{label:<11} = " if list(list_var): outstr += ", ".join(str(i) for i in list_var) return outstr @@ -242,17 +242,17 @@ def grid(self, grid): check_length('CMFD mesh grid', grid, grid_length) for i in range(grid_length): - check_type('CMFD mesh {}-grid'.format(dims[i]), grid[i], Iterable, + check_type(f'CMFD mesh {dims[i]}-grid', grid[i], Iterable, Real) - check_greater_than('CMFD mesh {}-grid length'.format(dims[i]), + check_greater_than(f'CMFD mesh {dims[i]}-grid length', len(grid[i]), 1) - self._grid = np.array(grid) + self._grid = [np.array(g) for g in grid] self._display_mesh_warning('rectilinear', 'CMFD mesh grid') def _display_mesh_warning(self, mesh_type, variable_label): if self._mesh_type != mesh_type: - warn_msg = 'Setting {} if mesh type is not set to {} ' \ - 'will have no effect'.format(variable_label, mesh_type) + warn_msg = (f'Setting {variable_label} if mesh type is not set to ' + f'{mesh_type} will have no effect') warnings.warn(warn_msg, RuntimeWarning) @@ -262,7 +262,7 @@ class CMFDRun: Attributes ---------- tally_begin : int - Batch number at which CMFD tallies should begin accummulating + Batch number at which CMFD tallies should begin accumulating solver_begin: int Batch number at which CMFD solver should start executing ref_d : list of floats @@ -271,13 +271,13 @@ class CMFDRun: Dictionary indicating which CMFD results to output. Note that CMFD k-effective will always be outputted. Acceptable keys are: - * "balance" - Whether to output RMS [%] of the resdiual from the + * "balance" - Whether to output RMS [%] of the residual from the neutron balance equation on CMFD tallies (bool) * "dominance" - Whether to output the estimated dominance ratio from the CMFD iterations (bool) * "entropy" - Whether to output the *entropy* of the CMFD predicted fission source (bool) - * "source" - Whether to ouput the RMS [%] between the OpenMC fission + * "source" - Whether to output the RMS [%] between the OpenMC fission source and CMFD fission source (bool) downscatter : bool @@ -315,7 +315,7 @@ class CMFDRun: adjoint_type : {'physical', 'math'} Stores type of adjoint calculation that should be performed. ``run_adjoint`` must be true for an adjoint calculation to be - perfomed. Options are: + performed. Options are: * "physical" - Create adjoint matrices from physical parameters of CMFD problem @@ -612,7 +612,7 @@ def display(self, display): for key, value in display.items(): check_value('display key', key, ('balance', 'entropy', 'dominance', 'source')) - check_type("display['{}']".format(key), value, bool) + check_type(f"display['{key}']", value, bool) self._display[key] = value @downscatter.setter @@ -887,7 +887,7 @@ def finalize(self): information. """ - # Finalize simuation + # Finalize simulation openmc.lib.simulation_finalize() if openmc.lib.master(): @@ -906,7 +906,7 @@ def statepoint_write(self, filename=None): if filename is None: batch_str_len = len(str(openmc.lib.settings.get_batches())) batch_str = str(openmc.lib.current_batch()).zfill(batch_str_len) - filename = 'statepoint.{}.h5'.format(batch_str) + filename = f'statepoint.{batch_str}.h5' # Call C API statepoint_write to save source distribution with CMFD # feedback @@ -928,7 +928,7 @@ def _write_cmfd_statepoint(self, filename): with h5py.File(filename, 'a') as f: if 'cmfd' not in f: if openmc.lib.settings.verbosity >= 5: - print(' Writing CMFD data to {}...'.format(filename)) + print(f' Writing CMFD data to {filename}...') sys.stdout.flush() cmfd_group = f.create_group("cmfd") cmfd_group.attrs['cmfd_on'] = self._cmfd_on @@ -982,14 +982,16 @@ def _initialize_linsolver(self): temp_data = np.ones(len(loss_row)) temp_loss = sparse.csr_matrix((temp_data, (loss_row, loss_col)), shape=(n, n)) + temp_loss.sort_indices() # Pass coremap as 1-d array of 32-bit integers coremap = np.swapaxes(self._coremap, 0, 2).flatten().astype(np.int32) - args = temp_loss.indptr, len(temp_loss.indptr), \ - temp_loss.indices, len(temp_loss.indices), n, \ + return openmc.lib._dll.openmc_initialize_linsolver( + temp_loss.indptr.astype(np.int32), len(temp_loss.indptr), + temp_loss.indices.astype(np.int32), len(temp_loss.indices), n, self._spectral, coremap, self._use_all_threads - return openmc.lib._dll.openmc_initialize_linsolver(*args) + ) def _write_cmfd_output(self): """Write CMFD output to buffer at the end of each batch""" @@ -1074,13 +1076,12 @@ def _initialize_cmfd(self): # Get acceleration map, otherwise set all regions to be accelerated if self._mesh.map is not None: check_length('CMFD coremap', self._mesh.map, - np.product(self._indices[0:3])) + np.prod(self._indices[:3])) if openmc.lib.master(): self._coremap = np.array(self._mesh.map) else: if openmc.lib.master(): - self._coremap = np.ones((np.product(self._indices[0:3])), - dtype=int) + self._coremap = np.ones(np.prod(self._indices[:3]), dtype=int) # Check CMFD tallies accummulated before feedback turned on if self._feedback and self._solver_begin < self._tally_begin: @@ -1133,12 +1134,12 @@ def _reset_cmfd(self, filename): with h5py.File(filename, 'r') as f: if 'cmfd' not in f: raise OpenMCError('Could not find CMFD parameters in ', - 'file {}'.format(filename)) + f'file {filename}') else: # Overwrite CMFD values from statepoint if (openmc.lib.master() and openmc.lib.settings.verbosity >= 5): - print(' Loading CMFD data from {}...'.format(filename)) + print(f' Loading CMFD data from {filename}...') sys.stdout.flush() cmfd_group = f['cmfd'] @@ -1309,9 +1310,6 @@ def _cmfd_solver_execute(self, adjoint=False): Whether or not to run an adjoint calculation """ - # Check for physical adjoint - physical_adjoint = adjoint and self._adjoint_type == 'physical' - # Start timer for build time_start_buildcmfd = time.time() @@ -1382,9 +1380,7 @@ def _write_vector(self, vector, base_filename): """ # Write each element in vector to file - with open(base_filename+'.dat', 'w') as fh: - for val in vector: - fh.write('{:0.8f}\n'.format(val)) + np.savetxt(f'{base_filename}.dat', vector, fmt='%.8f') # Save as numpy format np.save(base_filename, vector) @@ -1413,8 +1409,7 @@ def _write_matrix(self, matrix, base_filename): # Get all data entries for particular row in matrix data = matrix.data[matrix.indptr[row]:matrix.indptr[row+1]] for i in range(len(cols)): - fh.write('{:3d}, {:3d}, {:0.8f}\n'.format( - row, cols[i], data[i])) + fh.write(f'{row:3d}, {cols[i]:3d}, {data[i]:0.8f}\n') # Save matrix in scipy format sparse.save_npz(base_filename, matrix) @@ -1431,13 +1426,10 @@ def _calc_fission_source(self): nx, ny, nz, ng = self._indices n = self._mat_dim - # Compute cmfd_src in a vecotorized manner by phi to the spatial + # Compute cmfd_src in a vectorized manner by phi to the spatial # indices of the actual problem so that cmfd_flux can be multiplied by # nfissxs - # Calculate volume - vol = np.product(self._hxyz, axis=3) - # Reshape phi by number of groups phi = self._phi.reshape((n, ng)) @@ -1594,6 +1586,7 @@ def _build_loss_matrix(self, adjoint): loss_row = self._loss_row loss_col = self._loss_col loss = sparse.csr_matrix((data, (loss_row, loss_col)), shape=(n, n)) + loss.sort_indices() return loss def _build_prod_matrix(self, adjoint): @@ -1620,6 +1613,7 @@ def _build_prod_matrix(self, adjoint): prod_row = self._prod_row prod_col = self._prod_col prod = sparse.csr_matrix((data, (prod_row, prod_col)), shape=(n, n)) + prod.sort_indices() return prod def _execute_power_iter(self, loss, prod): @@ -2151,7 +2145,6 @@ def _precompute_array_indices(self): is_accel = self._coremap != _CMFD_NOACCEL # Logical for determining whether a zero flux "albedo" b.c. should be # applied - is_zero_flux_alb = abs(self._albedo - _ZERO_FLUX) < _TINY_BIT x_inds, y_inds, z_inds = np.indices((nx, ny, nz)) # Define slice equivalent to is_accel[0,:,:] @@ -2317,8 +2310,8 @@ def _precompute_matrix_indices(self): constant_values=_CMFD_NOACCEL)[:,:,1:] # Create empty row and column vectors to store for loss matrix - row = np.array([]) - col = np.array([]) + row = np.array([], dtype=int) + col = np.array([], dtype=int) # Store all indices used to populate production and loss matrix is_accel = self._coremap != _CMFD_NOACCEL @@ -2728,8 +2721,6 @@ def _compute_dhat(self): # Define flux in each cell cell_flux = self._flux / dxdydz - # Extract indices of coremap that are accelerated - is_accel = self._coremap != _CMFD_NOACCEL # Define dhat at left surface for all mesh cells on left boundary boundary = self._first_x_accel diff --git a/openmc/config.py b/openmc/config.py new file mode 100644 index 00000000000..b823d6b06b2 --- /dev/null +++ b/openmc/config.py @@ -0,0 +1,93 @@ +from collections.abc import MutableMapping +import os +from pathlib import Path +import warnings + +from openmc.data import DataLibrary +from openmc.data.decay import _DECAY_ENERGY, _DECAY_PHOTON_ENERGY + +__all__ = ["config"] + + +class _Config(MutableMapping): + def __init__(self, data=()): + self._mapping = {} + self.update(data) + + def __getitem__(self, key): + return self._mapping[key] + + def __delitem__(self, key): + del self._mapping[key] + if key == 'cross_sections': + del os.environ['OPENMC_CROSS_SECTIONS'] + elif key == 'mg_cross_sections': + del os.environ['OPENMC_MG_CROSS_SECTIONS'] + elif key == 'chain_file': + del os.environ['OPENMC_CHAIN_FILE'] + # Reset photon source data since it relies on chain file + _DECAY_PHOTON_ENERGY.clear() + + def __setitem__(self, key, value): + if key == 'cross_sections': + # Force environment variable to match + self._set_path(key, value) + os.environ['OPENMC_CROSS_SECTIONS'] = str(value) + elif key == 'mg_cross_sections': + self._set_path(key, value) + os.environ['OPENMC_MG_CROSS_SECTIONS'] = str(value) + elif key == 'chain_file': + self._set_path(key, value) + os.environ['OPENMC_CHAIN_FILE'] = str(value) + # Reset photon source data since it relies on chain file + _DECAY_PHOTON_ENERGY.clear() + _DECAY_ENERGY.clear() + else: + raise KeyError(f'Unrecognized config key: {key}. Acceptable keys ' + 'are "cross_sections", "mg_cross_sections" and ' + '"chain_file"') + + def __iter__(self): + return iter(self._mapping) + + def __len__(self): + return len(self._mapping) + + def __repr__(self): + return repr(self._mapping) + + def _set_path(self, key, value): + self._mapping[key] = p = Path(value) + if not p.exists(): + warnings.warn(f"'{value}' does not exist.") + + +def _default_config(): + """Return default configuration""" + config = _Config() + + # Set cross sections using environment variable + if "OPENMC_CROSS_SECTIONS" in os.environ: + config['cross_sections'] = os.environ["OPENMC_CROSS_SECTIONS"] + if "OPENMC_MG_CROSS_SECTIONS" in os.environ: + config['mg_cross_sections'] = os.environ["OPENMC_MG_CROSS_SECTIONS"] + + # Set depletion chain + chain_file = os.environ.get("OPENMC_CHAIN_FILE") + if (chain_file is None and + config.get('cross_sections') is not None and + config['cross_sections'].exists() + ): + # Check for depletion chain in cross_sections.xml + data = DataLibrary.from_xml(config['cross_sections']) + for lib in reversed(data.libraries): + if lib['type'] == 'depletion_chain': + chain_file = lib['path'] + break + if chain_file is not None: + config['chain_file'] = chain_file + + return config + + +config = _default_config() diff --git a/openmc/data/ace.py b/openmc/data/ace.py index e4c0c4ed053..1247593a806 100644 --- a/openmc/data/ace.py +++ b/openmc/data/ace.py @@ -15,7 +15,6 @@ """ -from collections import OrderedDict import enum from pathlib import Path import struct @@ -24,7 +23,7 @@ import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -from .data import ATOMIC_SYMBOL, gnd_name, EV_PER_MEV, K_BOLTZMANN +from .data import ATOMIC_SYMBOL, gnds_name, EV_PER_MEV, K_BOLTZMANN from .endf import ENDF_FLOAT_RE @@ -88,7 +87,7 @@ def get_metadata(zaid, metastable_scheme='nndc'): # Determine name element = ATOMIC_SYMBOL[Z] - name = gnd_name(Z, mass_number, metastable) + name = gnds_name(Z, mass_number, metastable) return (name, element, Z, mass_number, metastable) @@ -144,7 +143,7 @@ def ascii_to_binary(ascii_file, binary_file): # that XSS will start at the second record nxs = [int(x) for x in ' '.join(lines[idx + 6:idx + 8]).split()] jxs = [int(x) for x in ' '.join(lines[idx + 8:idx + 12]).split()] - binary_file.write(struct.pack(str('=16i32i{}x'.format(record_length - 500)), + binary_file.write(struct.pack(str(f'=16i32i{record_length - 500}x'), *(nxs + jxs))) # Read/write XSS array. Null bytes are added to form a complete record @@ -153,8 +152,7 @@ def ascii_to_binary(ascii_file, binary_file): start = idx + _ACE_HEADER_SIZE xss = np.fromstring(' '.join(lines[start:start + n_lines]), sep=' ') extra_bytes = record_length - ((len(xss)*8 - 1) % record_length + 1) - binary_file.write(struct.pack(str('={}d{}x'.format( - nxs[0], extra_bytes)), *xss)) + binary_file.write(struct.pack(str(f'={nxs[0]}d{extra_bytes}x'), *xss)) # Advance to next table in file idx += _ACE_HEADER_SIZE + n_lines @@ -185,8 +183,7 @@ def get_table(filename, name=None): if lib.tables: return lib.tables[0] else: - raise ValueError('Could not find ACE table with name: {}' - .format(name)) + raise ValueError(f'Could not find ACE table with name: {name}') # The beginning of an ASCII ACE file consists of 12 lines that include the name, @@ -296,14 +293,14 @@ def _read_binary(self, ace_file, table_names, verbose=False, if verbose: kelvin = round(temperature * EV_PER_MEV / K_BOLTZMANN) - print("Loading nuclide {} at {} K".format(name, kelvin)) + print(f"Loading nuclide {name} at {kelvin} K") # Read JXS jxs = list(struct.unpack(str('=32i'), ace_file.read(128))) # Read XSS ace_file.seek(start_position + recl_length) - xss = list(struct.unpack(str('={}d'.format(length)), + xss = list(struct.unpack(str(f'={length}d'), ace_file.read(length*8))) # Insert zeros at beginning of NXS, JXS, and XSS arrays so that the @@ -394,7 +391,7 @@ def _read_ascii(self, ace_file, table_names, verbose=False): if verbose: kelvin = round(temperature * EV_PER_MEV / K_BOLTZMANN) - print("Loading nuclide {} at {} K".format(name, kelvin)) + print(f"Loading nuclide {name} at {kelvin} K") # Insert zeros at beginning of NXS, JXS, and XSS arrays so that the # indexing will be the same as Fortran. This makes it easier to @@ -456,8 +453,7 @@ def from_suffix(cls, suffix): for member in cls: if suffix.endswith(member.value): return member - raise ValueError("Suffix '{}' has no corresponding ACE table type." - .format(suffix)) + raise ValueError(f"Suffix '{suffix}' has no corresponding ACE table type.") class Table(EqualityMixin): @@ -508,7 +504,7 @@ def data_type(self): return TableType.from_suffix(xs[-1]) def __repr__(self): - return "".format(self.name) + return f"" def get_libraries_from_xsdir(path): @@ -540,11 +536,11 @@ def get_libraries_from_xsdir(path): continue_lines = [i for i, line in enumerate(lines) if line.strip().endswith('+')] for i in reversed(continue_lines): - lines[i] += lines[i].strip()[:-1] + lines.pop(i + 1) + lines[i] = lines[i].strip()[:-1] + lines.pop(i + 1) # Create list of ACE libraries -- we use an ordered dictionary while # building to get O(1) membership checks while retaining insertion order - libraries = OrderedDict() + libraries = {} for line in lines: words = line.split() if len(words) < 3: @@ -573,11 +569,11 @@ def get_libraries_from_xsdata(path): List of paths to ACE libraries """ xsdata = Path(path) - with open(xsdata, 'r') as xsdata: + with open(xsdata, 'r') as xsdata_file: # As in get_libraries_from_xsdir, we use a dict for O(1) membership # check while retaining insertion order - libraries = OrderedDict() - for line in xsdata: + libraries = {} + for line in xsdata_file: words = line.split() if len(words) >= 9: lib = (xsdata.parent / words[8]).resolve() diff --git a/openmc/data/angle_distribution.py b/openmc/data/angle_distribution.py index 4d058bcb7cb..e59ffa0c737 100644 --- a/openmc/data/angle_distribution.py +++ b/openmc/data/angle_distribution.py @@ -42,16 +42,16 @@ def __init__(self, energy, mu): def energy(self): return self._energy - @property - def mu(self): - return self._mu - @energy.setter def energy(self, energy): cv.check_type('angle distribution incoming energy', energy, Iterable, Real) self._energy = energy + @property + def mu(self): + return self._mu + @mu.setter def mu(self, mu): cv.check_type('angle distribution scattering cosines', mu, @@ -235,7 +235,6 @@ def from_endf(cls, ev, mt): items = get_cont_record(file_obj) li = items[2] nk = items[4] - center_of_mass = (items[3] == 2) # Check for obsolete energy transformation matrix. If present, just skip # it and keep reading @@ -259,7 +258,6 @@ def from_endf(cls, ev, mt): mu = [] for i in range(n_energy): items, al = get_list_record(file_obj) - temperature = items[0] energy[i] = items[1] coefficients = np.asarray([1.0] + al) mu.append(Legendre(coefficients)) @@ -273,7 +271,6 @@ def from_endf(cls, ev, mt): mu = [] for i in range(n_energy): params, f = get_tab1_record(file_obj) - temperature = params[0] energy[i] = params[1] if f.n_regions > 1: raise NotImplementedError('Angular distribution with multiple ' @@ -289,7 +286,6 @@ def from_endf(cls, ev, mt): mu = [] for i in range(n_energy_legendre): items, al = get_list_record(file_obj) - temperature = items[0] energy_legendre[i] = items[1] coefficients = np.asarray([1.0] + al) mu.append(Legendre(coefficients)) @@ -300,7 +296,6 @@ def from_endf(cls, ev, mt): energy_tabulated = np.zeros(n_energy_tabulated) for i in range(n_energy_tabulated): params, f = get_tab1_record(file_obj) - temperature = params[0] energy_tabulated[i] = params[1] if f.n_regions > 1: raise NotImplementedError('Angular distribution with multiple ' diff --git a/openmc/data/angle_energy.py b/openmc/data/angle_energy.py index 6009dc748a1..71ca47587d7 100644 --- a/openmc/data/angle_energy.py +++ b/openmc/data/angle_energy.py @@ -44,6 +44,8 @@ def from_hdf5(group): return openmc.data.IncoherentInelasticAEDiscrete.from_hdf5(group) elif dist_type == 'incoherent_inelastic': return openmc.data.IncoherentInelasticAE.from_hdf5(group) + elif dist_type == 'mixed_elastic': + return openmc.data.MixedElasticAE.from_hdf5(group) @staticmethod def from_ace(ace, location_dist, location_start, rx=None): @@ -110,7 +112,6 @@ def from_ace(ace, location_dist, location_start, rx=None): distribution = openmc.data.NBodyPhaseSpace.from_ace( ace, idx, rx.q_value) else: - raise ValueError("Unsupported ACE secondary energy " - "distribution law {}".format(law)) + raise ValueError(f"Unsupported ACE secondary energy distribution law {law}") return distribution diff --git a/openmc/data/correlated.py b/openmc/data/correlated.py index 1aa4c20c8c5..2ff095a5c4e 100644 --- a/openmc/data/correlated.py +++ b/openmc/data/correlated.py @@ -58,46 +58,46 @@ def __init__(self, breakpoints, interpolation, energy, energy_out, mu): def breakpoints(self): return self._breakpoints - @property - def interpolation(self): - return self._interpolation - - @property - def energy(self): - return self._energy - - @property - def energy_out(self): - return self._energy_out - - @property - def mu(self): - return self._mu - @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('correlated angle-energy breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('correlated angle-energy interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('correlated angle-energy incoming energy', energy, Iterable, Real) self._energy = energy + @property + def energy_out(self): + return self._energy_out + @energy_out.setter def energy_out(self, energy_out): cv.check_type('correlated angle-energy outgoing energy', energy_out, Iterable, Univariate) self._energy_out = energy_out + @property + def mu(self): + return self._mu + @mu.setter def mu(self, mu): cv.check_iterable_type('correlated angle-energy outgoing cosine', @@ -113,7 +113,7 @@ def to_hdf5(self, group): HDF5 group to write to """ - group.attrs['type'] = np.string_(self._name) + group.attrs['type'] = np.bytes_(self._name) dset = group.create_dataset('energy', data=self.energy) dset.attrs['interpolation'] = np.vstack((self.breakpoints, diff --git a/openmc/data/data.py b/openmc/data/data.py index a1d0ee1dced..7caf31e26ee 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -1,9 +1,11 @@ import itertools -from math import sqrt +import json import os import re +from pathlib import Path +from math import sqrt, log from warnings import warn - +from typing import Dict # Isotopic abundances from Meija J, Coplen T B, et al, "Isotopic compositions # of the elements 2013 (IUPAC Technical Report)", Pure. Appl. Chem. 88 (3), @@ -177,6 +179,93 @@ 118: 'Og'} ATOMIC_NUMBER = {value: key for key, value in ATOMIC_SYMBOL.items()} +DADZ = { + '(n,2nd)': (-3, -1), + '(n,2n)': (-1, 0), + '(n,3n)': (-2, 0), + '(n,na)': (-4, -2), + '(n,n3a)': (-12, -6), + '(n,2na)': (-5, -2), + '(n,3na)': (-6, -2), + '(n,np)': (-1, -1), + '(n,n2a)': (-8, -4), + '(n,2n2a)': (-9, -4), + '(n,nd)': (-2, -1), + '(n,nt)': (-3, -1), + '(n,n3He)': (-3, -2), + '(n,nd2a)': (-10, -5), + '(n,nt2a)': (-11, -5), + '(n,4n)': (-3, 0), + '(n,2np)': (-2, -1), + '(n,3np)': (-3, -1), + '(n,n2p)': (-2, -2), + '(n,npa)': (-5, -3), + '(n,gamma)': (1, 0), + '(n,p)': (0, -1), + '(n,d)': (-1, -1), + '(n,t)': (-2, -1), + '(n,3He)': (-2, -2), + '(n,a)': (-3, -2), + '(n,2a)': (-7, -4), + '(n,3a)': (-11, -6), + '(n,2p)': (-1, -2), + '(n,pa)': (-4, -3), + '(n,t2a)': (-10, -5), + '(n,d2a)': (-9, -5), + '(n,pd)': (-2, -2), + '(n,pt)': (-3, -2), + '(n,da)': (-5, -3), + '(n,5n)': (-4, 0), + '(n,6n)': (-5, 0), + '(n,2nt)': (-4, -1), + '(n,ta)': (-6, -3), + '(n,4np)': (-4, -1), + '(n,3nd)': (-4, -1), + '(n,nda)': (-6, -3), + '(n,2npa)': (-6, -3), + '(n,7n)': (-6, 0), + '(n,8n)': (-7, 0), + '(n,5np)': (-5, -1), + '(n,6np)': (-6, -1), + '(n,7np)': (-7, -1), + '(n,4na)': (-7, -2), + '(n,5na)': (-8, -2), + '(n,6na)': (-9, -2), + '(n,7na)': (-10, -2), + '(n,4nd)': (-5, -1), + '(n,5nd)': (-6, -1), + '(n,6nd)': (-7, -1), + '(n,3nt)': (-5, -1), + '(n,4nt)': (-6, -1), + '(n,5nt)': (-7, -1), + '(n,6nt)': (-8, -1), + '(n,2n3He)': (-4, -2), + '(n,3n3He)': (-5, -2), + '(n,4n3He)': (-6, -2), + '(n,3n2p)': (-4, -2), + '(n,3n2a)': (-10, -4), + '(n,3npa)': (-7, -3), + '(n,dt)': (-4, -2), + '(n,npd)': (-3, -2), + '(n,npt)': (-4, -2), + '(n,ndt)': (-5, -2), + '(n,np3He)': (-4, -3), + '(n,nd3He)': (-5, -3), + '(n,nt3He)': (-6, -3), + '(n,nta)': (-7, -3), + '(n,2n2p)': (-3, -2), + '(n,p3He)': (-4, -3), + '(n,d3He)': (-5, -3), + '(n,3Hea)': (-6, -4), + '(n,4n2p)': (-5, -2), + '(n,4n2a)': (-11, -4), + '(n,4npa)': (-8, -3), + '(n,3p)': (-2, -3), + '(n,n3p)': (-3, -3), + '(n,3n2pa)': (-8, -4), + '(n,5n2p)': (-6, -2), +} + # Values here are from the Committee on Data for Science and Technology # (CODATA) 2018 recommendation (https://physics.nist.gov/cuu/Constants/). @@ -194,17 +283,20 @@ NEUTRON_MASS = 1.00866491595 # Used in atomic_mass function as a cache -_ATOMIC_MASS = {} +_ATOMIC_MASS: Dict[str, float] = {} -# Regex for GND nuclide names (used in zam function) -_GND_NAME_RE = re.compile(r'([A-Zn][a-z]*)(\d+)((?:_[em]\d+)?)') +# Regex for GNDS nuclide names (used in zam function) +_GNDS_NAME_RE = re.compile(r'([A-Zn][a-z]*)(\d+)((?:_[em]\d+)?)') +# Used in half_life function as a cache +_HALF_LIFE: Dict[str, float] = {} +_LOG_TWO = log(2.0) def atomic_mass(isotope): """Return atomic mass of isotope in atomic mass units. - Atomic mass data comes from the `Atomic Mass Evaluation 2016 - `_. + Atomic mass data comes from the `Atomic Mass Evaluation 2020 + `_. Parameters ---------- @@ -219,19 +311,19 @@ def atomic_mass(isotope): """ if not _ATOMIC_MASS: - # Load data from AME2016 file - mass_file = os.path.join(os.path.dirname(__file__), 'mass16.txt') + # Load data from AME2020 file + mass_file = os.path.join(os.path.dirname(__file__), 'mass_1.mas20.txt') with open(mass_file, 'r') as ame: - # Read lines in file starting at line 40 - for line in itertools.islice(ame, 39, None): - name = '{}{}'.format(line[20:22].strip(), int(line[16:19])) - mass = float(line[96:99]) + 1e-6*float( - line[100:106] + '.' + line[107:112]) + # Read lines in file starting at line 37 + for line in itertools.islice(ame, 36, None): + name = f'{line[20:22].strip()}{int(line[16:19])}' + mass = float(line[106:109]) + 1e-6*float( + line[110:116] + '.' + line[117:123]) _ATOMIC_MASS[name.lower()] = mass # For isotopes found in some libraries that represent all natural # isotopes of their element (e.g. C0), calculate the atomic mass as - # the sum of the atomic mass times the natural abudance of the isotopes + # the sum of the atomic mass times the natural abundance of the isotopes # that make up the element. for element in ['C', 'Zn', 'Pt', 'Os', 'Tl']: isotope_zero = element.lower() + '0' @@ -269,8 +361,63 @@ def atomic_weight(element): if weight > 0.: return weight else: - raise ValueError("No naturally-occurring isotopes for element '{}'." - .format(element)) + raise ValueError(f"No naturally-occurring isotopes for element '{element}'.") + + +def half_life(isotope): + """Return half-life of isotope in seconds or None if isotope is stable + + Half-life values are from the `ENDF/B-VIII.0 decay sublibrary + `_. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + isotope : str + Name of isotope, e.g., 'Pu239' + + Returns + ------- + float + Half-life of isotope in [s] + + """ + global _HALF_LIFE + if not _HALF_LIFE: + # Load ENDF/B-VIII.0 data from JSON file + half_life_path = Path(__file__).with_name('half_life.json') + _HALF_LIFE = json.loads(half_life_path.read_text()) + + return _HALF_LIFE.get(isotope.lower()) + + +def decay_constant(isotope): + """Return decay constant of isotope in [s^-1] + + Decay constants are based on half-life values from the + :func:`~openmc.data.half_life` function. When the isotope is stable, a decay + constant of zero is returned. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + isotope : str + Name of isotope, e.g., 'Pu239' + + Returns + ------- + float + Decay constant of isotope in [s^-1] + + See also + -------- + openmc.data.half_life + + """ + t = half_life(isotope) + return _LOG_TWO / t if t else 0.0 def water_density(temperature, pressure=0.1013): @@ -377,8 +524,11 @@ def water_density(temperature, pressure=0.1013): return coeff / pi / gamma1_pi -def gnd_name(Z, A, m=0): - """Return nuclide name using GND convention +def gnds_name(Z, A, m=0): + """Return nuclide name using GNDS convention + + .. versionchanged:: 0.14.0 + Function name changed from ``gnd_name`` to ``gnds_name`` Parameters ---------- @@ -392,13 +542,12 @@ def gnd_name(Z, A, m=0): Returns ------- str - Nuclide name in GND convention, e.g., 'Am242_m1' + Nuclide name in GNDS convention, e.g., 'Am242_m1' """ if m > 0: - return '{}{}_m{}'.format(ATOMIC_SYMBOL[Z], A, m) - else: - return '{}{}'.format(ATOMIC_SYMBOL[Z], A) + return f'{ATOMIC_SYMBOL[Z]}{A}_m{m}' + return f'{ATOMIC_SYMBOL[Z]}{A}' def isotopes(element): @@ -426,12 +575,12 @@ def isotopes(element): if len(element) > 2: symbol = ELEMENT_SYMBOL.get(element.lower()) if symbol is None: - raise ValueError('Element name "{}" not recognised'.format(element)) + raise ValueError(f'Element name "{element}" not recognised') element = symbol # Get the nuclides present in nature result = [] - for kv in sorted(NATURAL_ABUNDANCE.items()): + for kv in NATURAL_ABUNDANCE.items(): if re.match(r'{}\d+'.format(element), kv[0]): result.append(kv) @@ -444,7 +593,7 @@ def zam(name): Parameters ---------- name : str - Name of nuclide using GND convention, e.g., 'Am242_m1' + Name of nuclide using GNDS convention, e.g., 'Am242_m1' Returns ------- @@ -453,14 +602,13 @@ def zam(name): """ try: - symbol, A, state = _GND_NAME_RE.match(name).groups() + symbol, A, state = _GNDS_NAME_RE.match(name).groups() except AttributeError: - raise ValueError("'{}' does not appear to be a nuclide name in GND " - "format".format(name)) + raise ValueError(f"'{name}' does not appear to be a nuclide name in " + "GNDS format") if symbol not in ATOMIC_NUMBER: - raise ValueError("'{}' is not a recognized element symbol" - .format(symbol)) + raise ValueError(f"'{symbol}' is not a recognized element symbol") metastable = int(state[2:]) if state else 0 return (ATOMIC_NUMBER[symbol], int(A), metastable) diff --git a/openmc/data/decay.py b/openmc/data/decay.py index 3e7d9599c6f..be3dab77abf 100644 --- a/openmc/data/decay.py +++ b/openmc/data/decay.py @@ -2,14 +2,19 @@ from io import StringIO from math import log import re +from typing import Optional from warnings import warn import numpy as np from uncertainties import ufloat, UFloat +import openmc import openmc.checkvalue as cv +from openmc.exceptions import DataError from openmc.mixin import EqualityMixin +from openmc.stats import Discrete, Tabular, Univariate, combine_distributions from .data import ATOMIC_SYMBOL, ATOMIC_NUMBER +from .function import INTERPOLATION_SCHEME from .endf import Evaluation, get_head_record, get_list_record, get_tab1_record @@ -57,8 +62,13 @@ def get_decay_modes(value): List of successive decays, e.g. ('beta-', 'neutron') """ - return [_DECAY_MODES[int(x)][0] for x in - str(value).strip('0').replace('.', '')] + if int(value) == 10: + # The logic below would treat 10.0 as [1, 0] rather than [10] as it + # should, so we handle this case separately + return ['unknown'] + else: + return [_DECAY_MODES[int(x)][0] for x in + str(value).strip('0').replace('.', '')] class FissionProductYields(EqualityMixin): @@ -118,7 +128,7 @@ def get_yields(file_obj): isomeric_state = int(values[4*j + 1]) name = ATOMIC_SYMBOL[Z] + str(A) if isomeric_state > 0: - name += '_m{}'.format(isomeric_state) + name += f'_m{isomeric_state}' yield_j = ufloat(values[4*j + 2], values[4*j + 3]) yields[name] = yield_j @@ -134,7 +144,7 @@ def get_yields(file_obj): # Assign basic nuclide properties self.nuclide = { - 'name': ev.gnd_name, + 'name': ev.gnds_name, 'atomic_number': ev.target['atomic_number'], 'mass_number': ev.target['mass_number'], 'isomeric_state': ev.target['isomeric_state'] @@ -218,6 +228,18 @@ def __repr__(self): def branching_ratio(self): return self._branching_ratio + @branching_ratio.setter + def branching_ratio(self, branching_ratio): + cv.check_type('branching ratio', branching_ratio, UFloat) + cv.check_greater_than('branching ratio', + branching_ratio.nominal_value, 0.0, True) + if branching_ratio.nominal_value == 0.0: + warn('Decay mode {} of parent {} has a zero branching ratio.' + .format(self.modes, self.parent)) + cv.check_greater_than('branching ratio uncertainty', + branching_ratio.std_dev, 0.0, True) + self._branching_ratio = branching_ratio + @property def daughter(self): # Determine atomic number and mass number of parent @@ -235,33 +257,22 @@ def daughter(self): Z += delta_Z if self._daughter_state > 0: - return '{}{}_m{}'.format(ATOMIC_SYMBOL[Z], A, self._daughter_state) + return f'{ATOMIC_SYMBOL[Z]}{A}_m{self._daughter_state}' else: - return '{}{}'.format(ATOMIC_SYMBOL[Z], A) - - @property - def energy(self): - return self._energy - - @property - def modes(self): - return self._modes + return f'{ATOMIC_SYMBOL[Z]}{A}' @property def parent(self): return self._parent - @branching_ratio.setter - def branching_ratio(self, branching_ratio): - cv.check_type('branching ratio', branching_ratio, UFloat) - cv.check_greater_than('branching ratio', - branching_ratio.nominal_value, 0.0, True) - if branching_ratio.nominal_value == 0.0: - warn('Decay mode {} of parent {} has a zero branching ratio.' - .format(self.modes, self.parent)) - cv.check_greater_than('branching ratio uncertainty', - branching_ratio.std_dev, 0.0, True) - self._branching_ratio = branching_ratio + @parent.setter + def parent(self, parent): + cv.check_type('parent nuclide', parent, str) + self._parent = parent + + @property + def energy(self): + return self._energy @energy.setter def energy(self, energy): @@ -271,16 +282,15 @@ def energy(self, energy): energy.std_dev, 0.0, True) self._energy = energy + @property + def modes(self): + return self._modes + @modes.setter def modes(self, modes): cv.check_type('decay modes', modes, Iterable, str) self._modes = modes - @parent.setter - def parent(self, parent): - cv.check_type('parent nuclide', parent, str) - self._parent = parent - class Decay(EqualityMixin): """Radioactive decay data. @@ -309,6 +319,12 @@ class Decay(EqualityMixin): 'excited_state', 'mass', 'stable', 'spin', and 'parity'. spectra : dict Resulting radiation spectra for each radiation type. + sources : dict + Radioactive decay source distributions represented as a dictionary + mapping particle types (e.g., 'photon') to instances of + :class:`openmc.stats.Univariate`. + + .. versionadded:: 0.13.1 """ def __init__(self, ev_or_filename): @@ -324,6 +340,7 @@ def __init__(self, ev_or_filename): self.modes = [] self.spectra = {} self.average_energies = {} + self._sources = None # Get head record items = get_head_record(file_obj) @@ -333,10 +350,9 @@ def __init__(self, ev_or_filename): self.nuclide['mass_number'] = A self.nuclide['isomeric_state'] = metastable if metastable > 0: - self.nuclide['name'] = '{}{}_m{}'.format(ATOMIC_SYMBOL[Z], A, - metastable) + self.nuclide['name'] = f'{ATOMIC_SYMBOL[Z]}{A}_m{metastable}' else: - self.nuclide['name'] = '{}{}'.format(ATOMIC_SYMBOL[Z], A) + self.nuclide['name'] = f'{ATOMIC_SYMBOL[Z]}{A}' self.nuclide['mass'] = items[1] # AWR self.nuclide['excited_state'] = items[2] # State of the original nuclide self.nuclide['stable'] = (items[4] == 1) # Nucleus stability flag @@ -437,7 +453,7 @@ def __init__(self, ev_or_filename): # Read continuous spectrum ci = {} params, ci['probability'] = get_tab1_record(file_obj) - ci['type'] = get_decay_modes(params[0]) + ci['from_mode'] = get_decay_modes(params[0]) # Read covariance (Ek, Fk) table LCOV = params[3] @@ -460,11 +476,10 @@ def __init__(self, ev_or_filename): @property def decay_constant(self): - if hasattr(self.half_life, 'n'): - return log(2.)/self.half_life - else: - mu, sigma = self.half_life - return ufloat(log(2.)/mu, log(2.)/mu**2*sigma) + if self.half_life.n == 0.0: + name = self.nuclide['name'] + raise ValueError(f"{name} is listed as unstable but has a zero half-life.") + return log(2.)/self.half_life @property def decay_energy(self): @@ -491,3 +506,163 @@ def from_endf(cls, ev_or_filename): """ return cls(ev_or_filename) + + @property + def sources(self): + """Radioactive decay source distributions""" + # If property has been computed already, return it + # TODO: Replace with functools.cached_property when support is Python 3.9+ + if self._sources is not None: + return self._sources + + sources = {} + name = self.nuclide['name'] + decay_constant = self.decay_constant.n + for particle, spectra in self.spectra.items(): + # Set particle type based on 'particle' above + particle_type = { + 'gamma': 'photon', + 'beta-': 'electron', + 'ec/beta+': 'positron', + 'alpha': 'alpha', + 'n': 'neutron', + 'sf': 'fragment', + 'p': 'proton', + 'e-': 'electron', + 'xray': 'photon', + 'anti-neutrino': 'anti-neutrino', + 'neutrino': 'neutrino', + }[particle] + + if particle_type not in sources: + sources[particle_type] = [] + + # Create distribution for discrete + if spectra['continuous_flag'] in ('discrete', 'both'): + energies = [] + intensities = [] + for discrete_data in spectra['discrete']: + energies.append(discrete_data['energy'].n) + intensities.append(discrete_data['intensity'].n) + energies = np.array(energies) + intensity = spectra['discrete_normalization'].n + rates = decay_constant * intensity * np.array(intensities) + dist_discrete = Discrete(energies, rates) + sources[particle_type].append(dist_discrete) + + # Create distribution for continuous + if spectra['continuous_flag'] in ('continuous', 'both'): + f = spectra['continuous']['probability'] + if len(f.interpolation) > 1: + raise NotImplementedError("Multiple interpolation regions: {name}, {particle}") + interpolation = INTERPOLATION_SCHEME[f.interpolation[0]] + if interpolation not in ('histogram', 'linear-linear'): + warn( + f"Continuous spectra with {interpolation} interpolation " + f"({name}, {particle}) encountered.") + + intensity = spectra['continuous_normalization'].n + rates = decay_constant * intensity * f.y + dist_continuous = Tabular(f.x, rates, interpolation) + sources[particle_type].append(dist_continuous) + + # Combine discrete distributions + merged_sources = {} + for particle_type, dist_list in sources.items(): + merged_sources[particle_type] = combine_distributions( + dist_list, [1.0]*len(dist_list)) + + self._sources = merged_sources + return self._sources + + +_DECAY_PHOTON_ENERGY = {} + + +def decay_photon_energy(nuclide: str) -> Optional[Univariate]: + """Get photon energy distribution resulting from the decay of a nuclide + + This function relies on data stored in a depletion chain. Before calling it + for the first time, you need to ensure that a depletion chain has been + specified in openmc.config['chain_file']. + + .. versionadded:: 0.13.2 + + Parameters + ---------- + nuclide : str + Name of nuclide, e.g., 'Co58' + + Returns + ------- + openmc.stats.Univariate or None + Distribution of energies in [eV] of photons emitted from decay, or None + if no photon source exists. Note that the probabilities represent + intensities, given as [Bq]. + """ + if not _DECAY_PHOTON_ENERGY: + chain_file = openmc.config.get('chain_file') + if chain_file is None: + raise DataError( + "A depletion chain file must be specified with " + "openmc.config['chain_file'] in order to load decay data." + ) + + from openmc.deplete import Chain + chain = Chain.from_xml(chain_file) + for nuc in chain.nuclides: + if 'photon' in nuc.sources: + _DECAY_PHOTON_ENERGY[nuc.name] = nuc.sources['photon'] + + # If the chain file contained no sources at all, warn the user + if not _DECAY_PHOTON_ENERGY: + warn(f"Chain file '{chain_file}' does not have any decay photon " + "sources listed.") + + return _DECAY_PHOTON_ENERGY.get(nuclide) + + +_DECAY_ENERGY = {} + + +def decay_energy(nuclide: str): + """Get decay energy value resulting from the decay of a nuclide + + This function relies on data stored in a depletion chain. Before calling it + for the first time, you need to ensure that a depletion chain has been + specified in openmc.config['chain_file']. + + .. versionadded:: 0.13.3 + + Parameters + ---------- + nuclide : str + Name of nuclide, e.g., 'H3' + + Returns + ------- + float + Decay energy of nuclide in [eV]. If the nuclide is stable, a value of + 0.0 is returned. + """ + if not _DECAY_ENERGY: + chain_file = openmc.config.get('chain_file') + if chain_file is None: + raise DataError( + "A depletion chain file must be specified with " + "openmc.config['chain_file'] in order to load decay data." + ) + + from openmc.deplete import Chain + chain = Chain.from_xml(chain_file) + for nuc in chain.nuclides: + if nuc.decay_energy: + _DECAY_ENERGY[nuc.name] = nuc.decay_energy + + # If the chain file contained no decay energy, warn the user + if not _DECAY_ENERGY: + warn(f"Chain file '{chain_file}' does not have any decay energy.") + + return _DECAY_ENERGY.get(nuclide, 0.0) + + diff --git a/openmc/data/effective_dose/dose.py b/openmc/data/effective_dose/dose.py index 6ceb2c09e01..ae981ee7dc8 100644 --- a/openmc/data/effective_dose/dose.py +++ b/openmc/data/effective_dose/dose.py @@ -23,7 +23,7 @@ def _load_dose_icrp116(): """Load effective dose tables from text files""" for particle, filename in _FILES: path = Path(__file__).parent / filename - data = np.loadtxt(path, skiprows=3) + data = np.loadtxt(path, skiprows=3, encoding='utf-8') data[:, 0] *= 1e6 # Change energies to eV _DOSE_ICRP116[particle] = data @@ -60,7 +60,7 @@ def dose_coefficients(particle, geometry='AP'): # Get all data for selected particle data = _DOSE_ICRP116.get(particle) if data is None: - raise ValueError("{} has no effective dose data".format(particle)) + raise ValueError(f"{particle} has no effective dose data") # Determine index for selected geometry if particle in ('neutron', 'photon', 'proton', 'photon kerma'): diff --git a/openmc/data/endf.c b/openmc/data/endf.c index 936fd3bbbe2..dd5eee54184 100644 --- a/openmc/data/endf.c +++ b/openmc/data/endf.c @@ -14,7 +14,7 @@ double cfloat_endf(const char* buffer, int n) { - char arr[12]; // 11 characters plus a null terminator + char arr[13]; // 11 characters plus e and a null terminator int j = 0; // current position in arr int found_significand = 0; int found_exponent = 0; diff --git a/openmc/data/endf.py b/openmc/data/endf.py index f9b9d069418..73299723a8b 100644 --- a/openmc/data/endf.py +++ b/openmc/data/endf.py @@ -12,7 +12,7 @@ import numpy as np -from .data import gnd_name +from .data import gnds_name from .function import Tabulated1D try: from ._endf import float_endf @@ -449,8 +449,7 @@ def __init__(self, filename_or_obj): def __repr__(self): name = self.target['zsymam'].replace(' ', '') - return '<{} for {} {}>'.format(self.info['sublibrary'], name, - self.info['library']) + return f"<{self.info['sublibrary']} for {name} {self.info['library']}>" def _read_header(self): file_obj = io.StringIO(self.section[1, 451]) @@ -520,10 +519,10 @@ def _read_header(self): self.reaction_list.append((mf, mt, nc, mod)) @property - def gnd_name(self): - return gnd_name(self.target['atomic_number'], - self.target['mass_number'], - self.target['isomeric_state']) + def gnds_name(self): + return gnds_name(self.target['atomic_number'], + self.target['mass_number'], + self.target['isomeric_state']) class Tabulated2D: @@ -531,7 +530,7 @@ class Tabulated2D: This is a dummy class that is not really used other than to store the interpolation information for a two-dimensional function. Once we refactor - to adopt GND-like data containers, this will probably be removed or + to adopt GNDS-like data containers, this will probably be removed or extended. Parameters diff --git a/openmc/data/energy_distribution.py b/openmc/data/energy_distribution.py index 3b6d325effe..069ab1b9beb 100644 --- a/openmc/data/energy_distribution.py +++ b/openmc/data/energy_distribution.py @@ -53,8 +53,7 @@ def from_hdf5(group): elif energy_type == 'continuous': return ContinuousTabular.from_hdf5(group) else: - raise ValueError("Unknown energy distribution type: {}" - .format(energy_type)) + raise ValueError(f"Unknown energy distribution type: {energy_type}") @staticmethod def from_endf(file_obj, params): @@ -253,15 +252,15 @@ def __init__(self, theta, u): def theta(self): return self._theta - @property - def u(self): - return self._u - @theta.setter def theta(self, theta): cv.check_type('Maxwell theta', theta, Tabulated1D) self._theta = theta + @property + def u(self): + return self._u + @u.setter def u(self, u): cv.check_type('Maxwell restriction energy', u, Real) @@ -277,7 +276,7 @@ def to_hdf5(self, group): """ - group.attrs['type'] = np.string_('maxwell') + group.attrs['type'] = np.bytes_('maxwell') group.attrs['u'] = self.u self.theta.to_hdf5(group, 'theta') @@ -386,15 +385,15 @@ def __init__(self, theta, u): def theta(self): return self._theta - @property - def u(self): - return self._u - @theta.setter def theta(self, theta): cv.check_type('Evaporation theta', theta, Tabulated1D) self._theta = theta + @property + def u(self): + return self._u + @u.setter def u(self, u): cv.check_type('Evaporation restriction energy', u, Real) @@ -410,7 +409,7 @@ def to_hdf5(self, group): """ - group.attrs['type'] = np.string_('evaporation') + group.attrs['type'] = np.bytes_('evaporation') group.attrs['u'] = self.u self.theta.to_hdf5(group, 'theta') @@ -523,24 +522,24 @@ def __init__(self, a, b, u): def a(self): return self._a - @property - def b(self): - return self._b - - @property - def u(self): - return self._u - @a.setter def a(self, a): cv.check_type('Watt a', a, Tabulated1D) self._a = a + @property + def b(self): + return self._b + @b.setter def b(self, b): cv.check_type('Watt b', b, Tabulated1D) self._b = b + @property + def u(self): + return self._u + @u.setter def u(self, u): cv.check_type('Watt restriction energy', u, Real) @@ -556,7 +555,7 @@ def to_hdf5(self, group): """ - group.attrs['type'] = np.string_('watt') + group.attrs['type'] = np.bytes_('watt') group.attrs['u'] = self.u self.a.to_hdf5(group, 'a') self.b.to_hdf5(group, 'b') @@ -691,14 +690,6 @@ def __init__(self, efl, efh, tm): def efl(self): return self._efl - @property - def efh(self): - return self._efh - - @property - def tm(self): - return self._tm - @efl.setter def efl(self, efl): name = 'Madland-Nix light fragment energy' @@ -706,6 +697,10 @@ def efl(self, efl): cv.check_greater_than(name, efl, 0.) self._efl = efl + @property + def efh(self): + return self._efh + @efh.setter def efh(self, efh): name = 'Madland-Nix heavy fragment energy' @@ -713,6 +708,10 @@ def efh(self, efh): cv.check_greater_than(name, efh, 0.) self._efh = efh + @property + def tm(self): + return self._tm + @tm.setter def tm(self, tm): cv.check_type('Madland-Nix maximum temperature', tm, Tabulated1D) @@ -728,7 +727,7 @@ def to_hdf5(self, group): """ - group.attrs['type'] = np.string_('madland-nix') + group.attrs['type'] = np.bytes_('madland-nix') group.attrs['efl'] = self.efl group.attrs['efh'] = self.efh self.tm.to_hdf5(group) @@ -778,7 +777,6 @@ def from_endf(cls, file_obj, params): return cls(efl, efh, tm) - class DiscretePhoton(EnergyDistribution): """Discrete photon energy distribution @@ -814,24 +812,24 @@ def __init__(self, primary_flag, energy, atomic_weight_ratio): def primary_flag(self): return self._primary_flag - @property - def energy(self): - return self._energy - - @property - def atomic_weight_ratio(self): - return self._atomic_weight_ratio - @primary_flag.setter def primary_flag(self, primary_flag): cv.check_type('discrete photon primary_flag', primary_flag, Integral) self._primary_flag = primary_flag + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('discrete photon energy', energy, Real) self._energy = energy + @property + def atomic_weight_ratio(self): + return self._atomic_weight_ratio + @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): cv.check_type('atomic weight ratio', atomic_weight_ratio, Real) @@ -847,7 +845,7 @@ def to_hdf5(self, group): """ - group.attrs['type'] = np.string_('discrete_photon') + group.attrs['type'] = np.bytes_('discrete_photon') group.attrs['primary_flag'] = self.primary_flag group.attrs['energy'] = self.energy group.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio @@ -922,15 +920,15 @@ def __init__(self, threshold, mass_ratio): def threshold(self): return self._threshold - @property - def mass_ratio(self): - return self._mass_ratio - @threshold.setter def threshold(self, threshold): cv.check_type('level inelastic threhsold', threshold, Real) self._threshold = threshold + @property + def mass_ratio(self): + return self._mass_ratio + @mass_ratio.setter def mass_ratio(self, mass_ratio): cv.check_type('level inelastic mass ratio', mass_ratio, Real) @@ -946,7 +944,7 @@ def to_hdf5(self, group): """ - group.attrs['type'] = np.string_('level') + group.attrs['type'] = np.bytes_('level') group.attrs['threshold'] = self.threshold group.attrs['mass_ratio'] = self.mass_ratio @@ -1029,36 +1027,36 @@ def __init__(self, breakpoints, interpolation, energy, energy_out): def breakpoints(self): return self._breakpoints - @property - def interpolation(self): - return self._interpolation - - @property - def energy(self): - return self._energy - - @property - def energy_out(self): - return self._energy_out - @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('continuous tabular breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('continuous tabular interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('continuous tabular incoming energy', energy, Iterable, Real) self._energy = energy + @property + def energy_out(self): + return self._energy_out + @energy_out.setter def energy_out(self, energy_out): cv.check_type('continuous tabular outgoing energy', energy_out, @@ -1075,7 +1073,7 @@ def to_hdf5(self, group): """ - group.attrs['type'] = np.string_('continuous') + group.attrs['type'] = np.bytes_('continuous') dset = group.create_dataset('energy', data=self.energy) dset.attrs['interpolation'] = np.vstack((self.breakpoints, diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index bdce84ff79f..870881dbaf7 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -100,30 +100,65 @@ def __init__(self, fragments, prompt_neutrons, delayed_neutrons, def fragments(self): return self._fragments + @fragments.setter + def fragments(self, energy_release): + cv.check_type('fragments', energy_release, Callable) + self._fragments = energy_release + @property def prompt_neutrons(self): return self._prompt_neutrons + @prompt_neutrons.setter + def prompt_neutrons(self, energy_release): + cv.check_type('prompt_neutrons', energy_release, Callable) + self._prompt_neutrons = energy_release + @property def delayed_neutrons(self): return self._delayed_neutrons + @delayed_neutrons.setter + def delayed_neutrons(self, energy_release): + cv.check_type('delayed_neutrons', energy_release, Callable) + self._delayed_neutrons = energy_release + @property def prompt_photons(self): return self._prompt_photons + @prompt_photons.setter + def prompt_photons(self, energy_release): + cv.check_type('prompt_photons', energy_release, Callable) + self._prompt_photons = energy_release + @property def delayed_photons(self): return self._delayed_photons + @delayed_photons.setter + def delayed_photons(self, energy_release): + cv.check_type('delayed_photons', energy_release, Callable) + self._delayed_photons = energy_release + @property def betas(self): return self._betas + @betas.setter + def betas(self, energy_release): + cv.check_type('betas', energy_release, Callable) + self._betas = energy_release + @property def neutrinos(self): return self._neutrinos + @neutrinos.setter + def neutrinos(self, energy_release): + cv.check_type('neutrinos', energy_release, Callable) + self._neutrinos = energy_release + @property def recoverable(self): components = ['fragments', 'prompt_neutrons', 'delayed_neutrons', @@ -154,41 +189,6 @@ def q_total(self): # Use a polynomial to subtract incident energy. return sum_functions([self.total, Polynomial((0.0, -1.0))]) - @fragments.setter - def fragments(self, energy_release): - cv.check_type('fragments', energy_release, Callable) - self._fragments = energy_release - - @prompt_neutrons.setter - def prompt_neutrons(self, energy_release): - cv.check_type('prompt_neutrons', energy_release, Callable) - self._prompt_neutrons = energy_release - - @delayed_neutrons.setter - def delayed_neutrons(self, energy_release): - cv.check_type('delayed_neutrons', energy_release, Callable) - self._delayed_neutrons = energy_release - - @prompt_photons.setter - def prompt_photons(self, energy_release): - cv.check_type('prompt_photons', energy_release, Callable) - self._prompt_photons = energy_release - - @delayed_photons.setter - def delayed_photons(self, energy_release): - cv.check_type('delayed_photons', energy_release, Callable) - self._delayed_photons = energy_release - - @betas.setter - def betas(self, energy_release): - cv.check_type('betas', energy_release, Callable) - self._betas = energy_release - - @neutrinos.setter - def neutrinos(self, energy_release): - cv.check_type('neutrinos', energy_release, Callable) - self._neutrinos = energy_release - @classmethod def from_endf(cls, ev, incident_neutron): """Generate fission energy release data from an ENDF file. diff --git a/openmc/data/function.py b/openmc/data/function.py index b5aa2117d3a..23fd5e9d4fa 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -255,46 +255,46 @@ def __len__(self): def x(self): return self._x - @property - def y(self): - return self._y - - @property - def breakpoints(self): - return self._breakpoints - - @property - def interpolation(self): - return self._interpolation - - @property - def n_pairs(self): - return len(self.x) - - @property - def n_regions(self): - return len(self.breakpoints) - @x.setter def x(self, x): cv.check_type('x values', x, Iterable, Real) self._x = x + @property + def y(self): + return self._y + @y.setter def y(self, y): cv.check_type('y values', y, Iterable, Real) self._y = y + @property + def breakpoints(self): + return self._breakpoints + @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def n_pairs(self): + return len(self.x) + + @property + def n_regions(self): + return len(self.breakpoints) + def integral(self): """Integral of the tabulated function over its tabulated range. @@ -364,7 +364,7 @@ def to_hdf5(self, group, name='xy'): """ dataset = group.create_dataset(name, data=np.vstack( [self.x, self.y])) - dataset.attrs['type'] = np.string_(type(self).__name__) + dataset.attrs['type'] = np.bytes_(type(self).__name__) dataset.attrs['breakpoints'] = self.breakpoints dataset.attrs['interpolation'] = self.interpolation @@ -460,7 +460,7 @@ def to_hdf5(self, group, name='xy'): """ dataset = group.create_dataset(name, data=self.coef) - dataset.attrs['type'] = np.string_(type(self).__name__) + dataset.attrs['type'] = np.bytes_(type(self).__name__) @classmethod def from_hdf5(cls, dataset): @@ -544,7 +544,7 @@ def operations(self, operations): self._operations = operations -class Sum(EqualityMixin): +class Sum(Function1D): """Sum of multiple functions. This class allows you to create a callable object which represents the sum @@ -578,6 +578,49 @@ def functions(self, functions): cv.check_type('functions', functions, Iterable, Callable) self._functions = functions + def to_hdf5(self, group, name='xy'): + """Write sum of functions to an HDF5 group + + .. versionadded:: 0.13.1 + + Parameters + ---------- + group : h5py.Group + HDF5 group to write to + name : str + Name of the dataset to create + + """ + sum_group = group.create_group(name) + sum_group.attrs['type'] = np.bytes_(type(self).__name__) + sum_group.attrs['n'] = len(self.functions) + for i, f in enumerate(self.functions): + f.to_hdf5(sum_group, f'func_{i+1}') + + @classmethod + def from_hdf5(cls, group): + """Generate sum of functions from an HDF5 group + + .. versionadded:: 0.13.1 + + Parameters + ---------- + group : h5py.Group + Group to read from + + Returns + ------- + openmc.data.Sum + Functions read from the group + + """ + n = group.attrs['n'] + functions = [ + Function1D.from_hdf5(group[f'func_{i+1}']) + for i in range(n) + ] + return cls(functions) + class Regions1D(EqualityMixin): r"""Piecewise composition of multiple functions. @@ -621,15 +664,15 @@ def __call__(self, x): def functions(self): return self._functions - @property - def breakpoints(self): - return self._breakpoints - @functions.setter def functions(self, functions): cv.check_type('functions', functions, Iterable, Callable) self._functions = functions + @property + def breakpoints(self): + return self._breakpoints + @breakpoints.setter def breakpoints(self, breakpoints): cv.check_iterable_type('breakpoints', breakpoints, Real) @@ -691,24 +734,24 @@ def __call__(self, x): def background(self): return self._background - @property - def mt(self): - return self._mt - - @property - def resonances(self): - return self._resonances - @background.setter def background(self, background): cv.check_type('background cross section', background, Callable) self._background = background + @property + def mt(self): + return self._mt + @mt.setter def mt(self, mt): cv.check_type('MT value', mt, Integral) self._mt = mt + @property + def resonances(self): + return self._resonances + @resonances.setter def resonances(self, resonances): cv.check_type('resolved resonance parameters', resonances, diff --git a/openmc/data/half_life.json b/openmc/data/half_life.json new file mode 100644 index 00000000000..4f670918b5d --- /dev/null +++ b/openmc/data/half_life.json @@ -0,0 +1,3563 @@ +{ + "h3": 388789600.0, + "h4": 9.90652e-23, + "h5": 7.99473e-23, + "h6": 2.84812e-22, + "h7": 2.3e-23, + "he5": 7.595e-22, + "he6": 0.8067, + "he7": 3.038e-21, + "he8": 0.1191, + "he9": 7e-21, + "he10": 1.519e-21, + "li4": 7.55721e-23, + "li5": 3.06868e-22, + "li8": 0.838, + "li9": 0.1783, + "li10": 2e-21, + "li11": 0.00859, + "li12": 1e-08, + "be5": 1e-09, + "be6": 4.95326e-21, + "be7": 4598208.0, + "be8": 8.18132e-17, + "be10": 47652000000000.0, + "be11": 13.81, + "be12": 0.0213, + "be13": 2.7e-21, + "be14": 0.00435, + "be15": 2e-07, + "be16": 2e-07, + "b6": 1e-09, + "b7": 3.255e-22, + "b8": 0.77, + "b9": 8.43888e-19, + "b12": 0.0202, + "b13": 0.01736, + "b14": 0.0125, + "b15": 0.00993, + "b16": 1.9e-10, + "b17": 0.00508, + "b18": 2.6e-08, + "b19": 0.00292, + "c8": 1.9813e-21, + "c9": 0.1265, + "c10": 19.29, + "c11": 1223.1, + "c14": 179878000000.0, + "c15": 2.449, + "c16": 0.747, + "c17": 0.193, + "c18": 0.092, + "c19": 0.049, + "c20": 0.0145, + "c21": 3e-08, + "c22": 0.0062, + "n10": 2e-22, + "n11": 3.12742e-22, + "n12": 0.011, + "n13": 597.9, + "n16": 7.13, + "n17": 4.171, + "n18": 0.624, + "n19": 0.271, + "n20": 0.13, + "n21": 0.085, + "n22": 0.024, + "n23": 0.0145, + "n24": 5.2e-08, + "n25": 2.6e-07, + "o12": 1.13925e-21, + "o13": 0.00858, + "o14": 70.606, + "o15": 122.24, + "o19": 26.88, + "o20": 13.51, + "o21": 3.42, + "o22": 2.25, + "o23": 0.0905, + "o24": 0.065, + "o25": 5e-08, + "o26": 4e-08, + "o27": 2.6e-07, + "o28": 1e-07, + "f14": 5.0007e-22, + "f15": 4.557e-22, + "f16": 1.13925e-20, + "f17": 64.49, + "f18": 6586.2, + "f20": 11.163, + "f21": 4.158, + "f22": 4.23, + "f23": 2.23, + "f24": 0.39, + "f25": 0.05, + "f26": 0.0096, + "f27": 0.005, + "f28": 4e-08, + "f29": 0.0025, + "f30": 2.6e-07, + "f31": 2.5e-07, + "ne16": 3.73524e-21, + "ne17": 0.1092, + "ne18": 1.672, + "ne19": 17.22, + "ne23": 37.24, + "ne24": 202.8, + "ne25": 0.602, + "ne26": 0.197, + "ne27": 0.032, + "ne28": 0.0189, + "ne29": 0.0148, + "ne30": 0.0073, + "ne31": 0.0034, + "ne32": 0.0035, + "ne33": 1.8e-07, + "ne34": 6e-08, + "na18": 1.3e-21, + "na19": 4e-08, + "na20": 0.4479, + "na21": 22.49, + "na22": 82134970.0, + "na24": 53989.2, + "na24_m1": 0.02018, + "na25": 59.1, + "na26": 1.077, + "na27": 0.301, + "na28": 0.0305, + "na29": 0.0449, + "na30": 0.048, + "na31": 0.017, + "na32": 0.0132, + "na33": 0.008, + "na34": 0.0055, + "na35": 0.0015, + "na36": 1.8e-07, + "na37": 6e-08, + "mg19": 4e-12, + "mg20": 0.0908, + "mg21": 0.122, + "mg22": 3.8755, + "mg23": 11.317, + "mg27": 567.48, + "mg28": 75294.0, + "mg29": 1.3, + "mg30": 0.335, + "mg31": 0.232, + "mg32": 0.086, + "mg33": 0.0905, + "mg34": 0.02, + "mg35": 0.07, + "mg36": 0.0039, + "mg37": 2.6e-07, + "mg38": 2.6e-07, + "mg39": 1.8e-07, + "mg40": 1.7e-07, + "al21": 3.5e-08, + "al22": 0.059, + "al23": 0.47, + "al24": 2.053, + "al24_m1": 0.13, + "al25": 7.183, + "al26": 22626800000000.0, + "al26_m1": 6.3452, + "al28": 134.484, + "al29": 393.6, + "al30": 3.62, + "al31": 0.644, + "al32": 0.033, + "al33": 0.0417, + "al34": 0.042, + "al35": 0.0386, + "al36": 0.09, + "al37": 0.0107, + "al38": 0.0076, + "al39": 7.6e-06, + "al40": 2.6e-07, + "al41": 2.6e-07, + "al42": 1.7e-07, + "si22": 0.029, + "si23": 0.0423, + "si24": 0.14, + "si25": 0.22, + "si26": 2.234, + "si27": 4.16, + "si31": 9438.0, + "si32": 4828310000.0, + "si33": 6.11, + "si34": 2.77, + "si35": 0.78, + "si36": 0.45, + "si37": 0.09, + "si38": 1e-06, + "si39": 0.0475, + "si40": 0.033, + "si41": 0.02, + "si42": 0.0125, + "si43": 6e-08, + "si44": 3.6e-07, + "p24": 0.0074, + "p25": 3e-08, + "p26": 0.0437, + "p27": 0.26, + "p28": 0.2703, + "p29": 4.142, + "p30": 149.88, + "p32": 1232323.0, + "p33": 2189376.0, + "p34": 12.43, + "p35": 47.3, + "p36": 5.6, + "p37": 2.31, + "p38": 0.64, + "p39": 0.28, + "p40": 0.125, + "p41": 0.1, + "p42": 0.0485, + "p43": 0.0365, + "p44": 0.0185, + "p45": 2e-07, + "p46": 2e-07, + "s26": 0.01, + "s27": 0.0155, + "s28": 0.125, + "s29": 0.187, + "s30": 1.178, + "s31": 2.572, + "s35": 7560864.0, + "s37": 303.0, + "s38": 10218.0, + "s39": 11.5, + "s40": 8.8, + "s41": 1.99, + "s42": 1.013, + "s43": 0.28, + "s44": 0.1, + "s45": 0.068, + "s46": 0.05, + "s48": 2e-07, + "s49": 2e-07, + "cl28": 0.0017, + "cl29": 2e-08, + "cl30": 3e-08, + "cl31": 0.15, + "cl32": 0.298, + "cl33": 2.511, + "cl34": 1.5264, + "cl34_m1": 1920.0, + "cl36": 9498840000000.0, + "cl38": 2233.8, + "cl38_m1": 0.715, + "cl39": 3336.0, + "cl40": 81.0, + "cl41": 38.4, + "cl42": 6.8, + "cl43": 3.13, + "cl44": 0.56, + "cl45": 0.413, + "cl46": 0.232, + "cl47": 0.101, + "cl48": 2e-07, + "cl49": 1.7e-07, + "cl50": 0.02, + "cl51": 2e-07, + "ar30": 2e-08, + "ar31": 0.0151, + "ar32": 0.098, + "ar33": 0.173, + "ar34": 0.8445, + "ar35": 1.775, + "ar37": 3027456.0, + "ar39": 8488990000.0, + "ar41": 6576.6, + "ar42": 1038250000.0, + "ar43": 322.2, + "ar44": 712.2, + "ar45": 21.48, + "ar46": 8.4, + "ar47": 1.23, + "ar48": 0.475, + "ar49": 0.17, + "ar50": 0.085, + "ar51": 2e-07, + "ar52": 0.01, + "ar53": 0.003, + "k32": 0.0033, + "k33": 2.5e-08, + "k34": 2.5e-08, + "k35": 0.178, + "k36": 0.342, + "k37": 1.226, + "k38": 458.16, + "k38_m1": 0.924, + "k40": 3.93839e16, + "k42": 44496.0, + "k43": 80280.0, + "k44": 1327.8, + "k45": 1068.6, + "k46": 105.0, + "k47": 17.5, + "k48": 6.8, + "k49": 1.26, + "k50": 0.472, + "k51": 0.365, + "k52": 0.105, + "k53": 0.03, + "k54": 0.01, + "k55": 0.003, + "ca34": 3.5e-08, + "ca35": 0.0257, + "ca36": 0.102, + "ca37": 0.1811, + "ca38": 0.44, + "ca39": 0.8596, + "ca41": 3218880000000.0, + "ca45": 14049500.0, + "ca47": 391910.4, + "ca48": 7.25824e26, + "ca49": 523.08, + "ca50": 13.9, + "ca51": 10.0, + "ca52": 4.6, + "ca53": 0.09, + "ca54": 0.086, + "ca55": 0.022, + "ca56": 0.01, + "ca57": 0.005, + "sc36": 0.0088, + "sc37": 0.056, + "sc38": 0.0423, + "sc39": 3e-07, + "sc40": 0.1823, + "sc41": 0.5963, + "sc42": 0.6808, + "sc42_m1": 62.0, + "sc43": 14007.6, + "sc44": 14292.0, + "sc44_m1": 210996.0, + "sc45_m1": 0.318, + "sc46": 7239456.0, + "sc46_m1": 18.75, + "sc47": 289370.9, + "sc48": 157212.0, + "sc49": 3430.8, + "sc50": 102.5, + "sc50_m1": 0.35, + "sc51": 12.4, + "sc52": 8.2, + "sc53": 3.0, + "sc54": 0.36, + "sc55": 0.105, + "sc56": 0.06, + "sc57": 0.013, + "sc58": 0.012, + "sc59": 0.01, + "sc60": 0.003, + "ti38": 1.2e-07, + "ti39": 0.032, + "ti40": 0.0533, + "ti41": 0.0804, + "ti42": 0.199, + "ti43": 0.509, + "ti44": 1893460000.0, + "ti45": 11088.0, + "ti51": 345.6, + "ti52": 102.0, + "ti53": 32.7, + "ti54": 1.5, + "ti55": 1.3, + "ti56": 0.2, + "ti57": 0.06, + "ti58": 0.059, + "ti59": 0.03, + "ti60": 0.022, + "ti61": 3e-07, + "ti62": 0.01, + "ti63": 0.003, + "v40": 0.0077, + "v41": 0.0244, + "v42": 5.5e-08, + "v43": 0.8, + "v44": 0.111, + "v44_m1": 0.15, + "v45": 0.547, + "v46": 0.4225, + "v46_m1": 0.00102, + "v47": 1956.0, + "v48": 1380110.0, + "v49": 28512000.0, + "v50": 4.41806e24, + "v52": 224.58, + "v53": 92.58, + "v54": 49.8, + "v55": 6.54, + "v56": 0.216, + "v57": 0.35, + "v58": 0.185, + "v59": 0.075, + "v60": 0.068, + "v61": 0.047, + "v62": 1.5e-07, + "v63": 0.017, + "v64": 0.019, + "v65": 0.01, + "cr42": 0.014, + "cr43": 0.0216, + "cr44": 0.0535, + "cr45": 0.0609, + "cr46": 0.26, + "cr47": 0.5, + "cr48": 77616.0, + "cr49": 2538.0, + "cr51": 2393366.0, + "cr55": 209.82, + "cr56": 356.4, + "cr57": 21.1, + "cr58": 7.0, + "cr59": 0.46, + "cr60": 0.49, + "cr61": 0.27, + "cr62": 0.19, + "cr63": 0.129, + "cr64": 0.043, + "cr65": 0.027, + "cr66": 0.01, + "cr67": 0.05, + "mn44": 1.05e-07, + "mn45": 7e-08, + "mn46": 0.0345, + "mn47": 0.1, + "mn48": 0.1581, + "mn49": 0.382, + "mn50": 0.28319, + "mn50_m1": 105.0, + "mn51": 2772.0, + "mn52": 483062.4, + "mn52_m1": 1266.0, + "mn53": 116763000000000.0, + "mn54": 26961120.0, + "mn56": 9284.04, + "mn57": 85.4, + "mn58": 3.0, + "mn58_m1": 65.4, + "mn59": 4.59, + "mn60": 51.0, + "mn60_m1": 1.77, + "mn61": 0.67, + "mn62": 0.671, + "mn62_m1": 0.092, + "mn63": 0.29, + "mn64": 0.09, + "mn65": 0.092, + "mn66": 0.064, + "mn67": 0.047, + "mn68": 0.028, + "mn69": 0.014, + "fe45": 0.00203, + "fe46": 0.013, + "fe47": 0.0219, + "fe48": 0.044, + "fe49": 0.0647, + "fe50": 0.155, + "fe51": 0.305, + "fe52": 29790.0, + "fe52_m1": 45.9, + "fe53": 510.6, + "fe53_m1": 152.4, + "fe55": 86594050.0, + "fe59": 3844368.0, + "fe60": 47336400000000.0, + "fe61": 358.8, + "fe62": 68.0, + "fe63": 6.1, + "fe64": 2.0, + "fe65": 0.81, + "fe65_m1": 1.12, + "fe66": 0.44, + "fe67": 0.416, + "fe68": 0.187, + "fe69": 0.109, + "fe70": 0.094, + "fe71": 0.028, + "fe72": 1.5e-07, + "co49": 3.5e-08, + "co50": 0.044, + "co51": 2e-07, + "co52": 0.115, + "co53": 0.24, + "co53_m1": 0.247, + "co54": 0.19328, + "co54_m1": 88.8, + "co55": 63108.0, + "co56": 6672931.0, + "co57": 23478340.0, + "co58": 6122304.0, + "co58_m1": 32760.0, + "co60": 166344200.0, + "co60_m1": 628.02, + "co61": 5940.0, + "co62": 90.0, + "co62_m1": 834.6, + "co63": 27.4, + "co64": 0.3, + "co65": 1.16, + "co66": 0.2, + "co67": 0.425, + "co68": 0.199, + "co68_m1": 1.6, + "co69": 0.22, + "co70": 0.119, + "co70_m1": 0.5, + "co71": 0.079, + "co72": 0.0599, + "co73": 0.041, + "co74": 0.03, + "co75": 0.034, + "ni48": 0.0021, + "ni49": 0.0075, + "ni50": 0.012, + "ni51": 2e-07, + "ni52": 0.038, + "ni53": 0.045, + "ni54": 0.104, + "ni55": 0.2047, + "ni56": 524880.0, + "ni57": 128160.0, + "ni59": 2398380000000.0, + "ni63": 3193630000.0, + "ni65": 9061.884, + "ni66": 196560.0, + "ni67": 21.0, + "ni68": 29.0, + "ni69": 11.4, + "ni69_m1": 3.5, + "ni70": 6.0, + "ni71": 2.56, + "ni72": 1.57, + "ni73": 0.84, + "ni74": 0.68, + "ni75": 0.6, + "ni76": 0.238, + "ni77": 0.061, + "ni78": 0.11, + "cu52": 0.0069, + "cu53": 3e-07, + "cu54": 7.5e-08, + "cu55": 0.04, + "cu56": 0.094, + "cu57": 0.1963, + "cu58": 3.204, + "cu59": 81.5, + "cu60": 1422.0, + "cu61": 11998.8, + "cu62": 580.38, + "cu64": 45723.6, + "cu66": 307.2, + "cu67": 222588.0, + "cu68": 31.1, + "cu68_m1": 225.0, + "cu69": 171.0, + "cu70": 44.5, + "cu70_m1": 33.0, + "cu70_m2": 6.6, + "cu71": 19.5, + "cu72": 6.63, + "cu73": 4.2, + "cu74": 1.75, + "cu75": 1.224, + "cu76": 0.653, + "cu76_m1": 1.27, + "cu77": 0.469, + "cu78": 0.335, + "cu79": 0.188, + "cu80": 0.17, + "cu81": 0.028, + "zn54": 0.0037, + "zn55": 0.02, + "zn56": 5e-07, + "zn57": 0.038, + "zn58": 0.084, + "zn59": 0.182, + "zn60": 142.8, + "zn61": 89.1, + "zn61_m1": 0.43, + "zn61_m2": 0.14, + "zn62": 33336.0, + "zn63": 2308.2, + "zn65": 21075550.0, + "zn69": 3384.0, + "zn69_m1": 49536.0, + "zn71": 147.0, + "zn71_m1": 14256.0, + "zn72": 167400.0, + "zn73": 23.5, + "zn73_m1": 5.8, + "zn73_m2": 0.013, + "zn74": 95.6, + "zn75": 10.2, + "zn76": 5.7, + "zn77": 2.08, + "zn77_m1": 1.05, + "zn78": 1.47, + "zn79": 0.995, + "zn80": 0.54, + "zn81": 0.32, + "zn82": 0.052, + "zn83": 0.043, + "ga56": 0.0059, + "ga57": 0.0123, + "ga58": 0.0152, + "ga59": 0.0418, + "ga60": 0.07, + "ga61": 0.168, + "ga62": 0.11612, + "ga63": 32.4, + "ga64": 157.62, + "ga65": 912.0, + "ga66": 34164.0, + "ga67": 281810.9, + "ga68": 4062.6, + "ga70": 1268.4, + "ga72": 50760.0, + "ga72_m1": 0.03968, + "ga73": 17496.0, + "ga74": 487.2, + "ga74_m1": 9.5, + "ga75": 126.0, + "ga76": 32.6, + "ga77": 13.2, + "ga78": 5.09, + "ga79": 2.847, + "ga80": 1.676, + "ga81": 1.217, + "ga82": 0.599, + "ga83": 0.3081, + "ga84": 0.085, + "ga85": 0.048, + "ga86": 0.029, + "ge58": 0.0152, + "ge59": 0.0418, + "ge60": 0.03, + "ge61": 0.039, + "ge62": 1.5e-07, + "ge63": 0.142, + "ge64": 63.7, + "ge65": 30.9, + "ge66": 8136.0, + "ge67": 1134.0, + "ge68": 23410080.0, + "ge69": 140580.0, + "ge71": 987552.0, + "ge71_m1": 0.02041, + "ge73_m1": 0.499, + "ge75": 4966.8, + "ge75_m1": 47.7, + "ge77": 40680.0, + "ge77_m1": 52.9, + "ge78": 5280.0, + "ge79": 18.98, + "ge79_m1": 39.0, + "ge80": 29.5, + "ge81": 7.6, + "ge81_m1": 7.6, + "ge82": 4.55, + "ge83": 1.85, + "ge84": 0.954, + "ge85": 0.535, + "ge86": 0.095, + "ge87": 0.14, + "ge88": 0.066, + "ge89": 0.039, + "as60": 0.0083, + "as61": 0.0166, + "as62": 0.0259, + "as63": 0.0921, + "as64": 0.036, + "as65": 0.128, + "as66": 0.09579, + "as67": 42.5, + "as68": 151.6, + "as69": 913.8, + "as70": 3156.0, + "as71": 235080.0, + "as72": 93600.0, + "as73": 6937920.0, + "as74": 1535328.0, + "as75_m1": 0.01762, + "as76": 94464.0, + "as77": 139788.0, + "as78": 5442.0, + "as79": 540.6, + "as80": 15.2, + "as81": 33.3, + "as82": 19.1, + "as82_m1": 13.6, + "as83": 13.4, + "as84": 4.2, + "as85": 2.021, + "as86": 0.945, + "as87": 0.56, + "as88": 0.112, + "as89": 0.059, + "as90": 0.043, + "as91": 0.044, + "as92": 0.027, + "se65": 0.05, + "se66": 0.033, + "se67": 0.136, + "se68": 35.5, + "se69": 27.4, + "se70": 2466.0, + "se71": 284.4, + "se72": 725760.0, + "se73": 25740.0, + "se73_m1": 2388.0, + "se75": 10349860.0, + "se77_m1": 17.36, + "se79": 9309490000000.0, + "se79_m1": 235.2, + "se81": 1107.0, + "se81_m1": 3436.8, + "se83": 1338.0, + "se83_m1": 70.1, + "se84": 195.6, + "se85": 31.7, + "se86": 14.3, + "se87": 5.5, + "se88": 1.53, + "se89": 0.41, + "se90": 0.161, + "se91": 0.27, + "se92": 0.093, + "se93": 0.062, + "se94": 0.059, + "br67": 0.0443, + "br68": 1.2e-06, + "br69": 2.4e-08, + "br70": 0.0791, + "br70_m1": 2.2, + "br71": 21.4, + "br72": 78.6, + "br72_m1": 10.6, + "br73": 204.0, + "br74": 1524.0, + "br74_m1": 2760.0, + "br75": 5802.0, + "br76": 58320.0, + "br76_m1": 1.31, + "br77": 205329.6, + "br77_m1": 256.8, + "br78": 387.0, + "br79_m1": 4.86, + "br80": 1060.8, + "br80_m1": 15913.8, + "br82": 127015.2, + "br82_m1": 367.8, + "br83": 8640.0, + "br84": 1905.6, + "br84_m1": 360.0, + "br85": 174.0, + "br86": 55.0, + "br87": 55.65, + "br88": 16.29, + "br89": 4.4, + "br90": 1.92, + "br91": 0.541, + "br92": 0.343, + "br93": 0.102, + "br94": 0.07, + "br95": 0.066, + "br96": 0.042, + "br97": 0.04, + "kr69": 0.032, + "kr70": 0.052, + "kr71": 0.1, + "kr72": 17.1, + "kr73": 27.3, + "kr74": 690.0, + "kr75": 257.4, + "kr76": 53280.0, + "kr77": 4464.0, + "kr79": 126144.0, + "kr79_m1": 50.0, + "kr81": 7226690000000.0, + "kr81_m1": 13.1, + "kr83_m1": 6588.0, + "kr85": 339433500.0, + "kr85_m1": 16128.0, + "kr87": 4578.0, + "kr88": 10224.0, + "kr89": 189.0, + "kr90": 32.32, + "kr91": 8.57, + "kr92": 1.84, + "kr93": 1.286, + "kr94": 0.212, + "kr95": 0.114, + "kr96": 0.08, + "kr97": 0.063, + "kr98": 0.046, + "kr99": 0.027, + "kr100": 0.007, + "rb71": 1e-09, + "rb72": 1.2e-06, + "rb73": 3e-08, + "rb74": 0.064776, + "rb75": 19.0, + "rb76": 36.5, + "rb77": 226.2, + "rb78": 1059.6, + "rb78_m1": 344.4, + "rb79": 1374.0, + "rb80": 34.0, + "rb81": 16459.2, + "rb81_m1": 1830.0, + "rb82": 75.45, + "rb82_m1": 23299.2, + "rb83": 7447680.0, + "rb84": 2835648.0, + "rb84_m1": 1215.6, + "rb86": 1609718.0, + "rb86_m1": 61.02, + "rb87": 1.51792e18, + "rb88": 1066.38, + "rb89": 909.0, + "rb90": 158.0, + "rb90_m1": 258.0, + "rb91": 58.4, + "rb92": 4.492, + "rb93": 5.84, + "rb94": 2.702, + "rb95": 0.3777, + "rb96": 0.203, + "rb97": 0.1691, + "rb98": 0.114, + "rb98_m1": 0.096, + "rb99": 0.054, + "rb100": 0.051, + "rb101": 0.032, + "rb102": 0.037, + "sr73": 0.025, + "sr74": 1.2e-06, + "sr75": 0.088, + "sr76": 7.89, + "sr77": 9.0, + "sr78": 150.0, + "sr79": 135.0, + "sr80": 6378.0, + "sr81": 1338.0, + "sr82": 2190240.0, + "sr83": 116676.0, + "sr83_m1": 4.95, + "sr85": 5602176.0, + "sr85_m1": 4057.8, + "sr87_m1": 10134.0, + "sr89": 4365792.0, + "sr90": 908543300.0, + "sr91": 34668.0, + "sr92": 9756.0, + "sr93": 445.38, + "sr94": 75.3, + "sr95": 23.9, + "sr96": 1.07, + "sr97": 0.429, + "sr98": 0.653, + "sr99": 0.27, + "sr100": 0.202, + "sr101": 0.118, + "sr102": 0.069, + "sr103": 0.068, + "sr104": 0.043, + "sr105": 0.0556, + "y76": 2e-07, + "y77": 0.062, + "y78": 0.05, + "y78_m1": 5.7, + "y79": 14.8, + "y80": 30.1, + "y80_m1": 4.8, + "y81": 70.4, + "y82": 8.3, + "y83": 424.8, + "y83_m1": 171.0, + "y84": 2370.0, + "y84_m1": 4.6, + "y85": 9648.0, + "y85_m1": 17496.0, + "y86": 53064.0, + "y86_m1": 2880.0, + "y87": 287280.0, + "y87_m1": 48132.0, + "y88": 9212486.0, + "y88_m1": 0.000301, + "y88_m2": 0.01397, + "y89_m1": 15.663, + "y90": 230400.0, + "y90_m1": 11484.0, + "y91": 5055264.0, + "y91_m1": 2982.6, + "y92": 12744.0, + "y93": 36648.0, + "y93_m1": 0.82, + "y94": 1122.0, + "y95": 618.0, + "y96": 5.34, + "y96_m1": 9.6, + "y97": 3.75, + "y97_m1": 1.17, + "y97_m2": 0.142, + "y98": 0.548, + "y98_m1": 2.0, + "y99": 1.47, + "y100": 0.735, + "y100_m1": 0.94, + "y101": 0.45, + "y102": 0.36, + "y102_m1": 0.298, + "y103": 0.23, + "y104": 0.18, + "y105": 0.088, + "y106": 0.066, + "y107": 0.03, + "y108": 0.048, + "zr78": 2e-07, + "zr79": 0.056, + "zr80": 4.6, + "zr81": 5.5, + "zr82": 32.0, + "zr83": 41.6, + "zr84": 1554.0, + "zr85": 471.6, + "zr85_m1": 10.9, + "zr86": 59400.0, + "zr87": 6048.0, + "zr87_m1": 14.0, + "zr88": 7205760.0, + "zr89": 282276.0, + "zr89_m1": 249.66, + "zr90_m1": 0.8092, + "zr93": 48283100000000.0, + "zr95": 5532365.0, + "zr96": 6.31152e26, + "zr97": 60296.4, + "zr98": 30.7, + "zr99": 2.1, + "zr100": 7.1, + "zr101": 2.3, + "zr102": 2.9, + "zr103": 1.3, + "zr104": 1.2, + "zr105": 0.6, + "zr106": 0.27, + "zr107": 0.15, + "zr108": 0.08, + "zr109": 0.117, + "zr110": 0.098, + "nb81": 0.8, + "nb82": 0.05, + "nb83": 4.1, + "nb84": 9.8, + "nb85": 20.9, + "nb85_m1": 3.3, + "nb86": 88.0, + "nb87": 225.0, + "nb87_m1": 156.0, + "nb88": 873.0, + "nb88_m1": 466.8, + "nb89": 7308.0, + "nb89_m1": 3960.0, + "nb90": 52560.0, + "nb90_m1": 18.81, + "nb90_m2": 0.00619, + "nb91": 21459200000.0, + "nb91_m1": 5258304.0, + "nb92": 1095050000000000.0, + "nb92_m1": 876960.0, + "nb93_m1": 509024100.0, + "nb94": 640619000000.0, + "nb94_m1": 375.78, + "nb95": 3023222.0, + "nb95_m1": 311904.0, + "nb96": 84060.0, + "nb97": 4326.0, + "nb97_m1": 58.7, + "nb98": 2.86, + "nb98_m1": 3078.0, + "nb99": 15.0, + "nb99_m1": 150.0, + "nb100": 1.5, + "nb100_m1": 2.99, + "nb101": 7.1, + "nb102": 4.3, + "nb102_m1": 1.3, + "nb103": 1.5, + "nb104": 4.9, + "nb104_m1": 0.94, + "nb105": 2.95, + "nb106": 0.93, + "nb107": 0.3, + "nb108": 0.193, + "nb109": 0.19, + "nb110": 0.17, + "nb111": 0.08, + "nb112": 0.069, + "nb113": 0.03, + "mo83": 0.0195, + "mo84": 3.8, + "mo85": 3.2, + "mo86": 19.6, + "mo87": 14.02, + "mo88": 480.0, + "mo89": 126.6, + "mo89_m1": 0.19, + "mo90": 20412.0, + "mo91": 929.4, + "mo91_m1": 64.6, + "mo93": 126230000000.0, + "mo93_m1": 24660.0, + "mo99": 237513.6, + "mo100": 2.3037e26, + "mo101": 876.6, + "mo102": 678.0, + "mo103": 67.5, + "mo104": 60.0, + "mo105": 35.6, + "mo106": 8.73, + "mo107": 3.5, + "mo108": 1.09, + "mo109": 0.53, + "mo110": 0.3, + "mo111": 0.2, + "mo112": 0.287, + "mo113": 0.1, + "mo114": 0.08, + "mo115": 0.092, + "tc85": 0.5, + "tc86": 0.054, + "tc86_m1": 1.1e-06, + "tc87": 2.2, + "tc88": 5.8, + "tc88_m1": 6.4, + "tc89": 12.8, + "tc89_m1": 12.9, + "tc90": 8.7, + "tc90_m1": 49.2, + "tc91": 188.4, + "tc91_m1": 198.0, + "tc92": 255.0, + "tc93": 9900.0, + "tc93_m1": 2610.0, + "tc94": 17580.0, + "tc94_m1": 3120.0, + "tc95": 72000.0, + "tc95_m1": 5270400.0, + "tc96": 369792.0, + "tc96_m1": 3090.0, + "tc97": 132857000000000.0, + "tc97_m1": 7862400.0, + "tc98": 132542000000000.0, + "tc99": 6661810000000.0, + "tc99_m1": 21624.12, + "tc100": 15.46, + "tc101": 852.0, + "tc102": 5.28, + "tc102_m1": 261.0, + "tc103": 54.2, + "tc104": 1098.0, + "tc105": 456.0, + "tc106": 35.6, + "tc107": 21.2, + "tc108": 5.17, + "tc109": 0.86, + "tc110": 0.92, + "tc111": 0.29, + "tc112": 0.28, + "tc113": 0.16, + "tc114": 0.15, + "tc115": 0.073, + "tc116": 0.09, + "tc117": 0.04, + "tc118": 0.066, + "ru87": 1.5e-06, + "ru88": 1.25, + "ru89": 1.5, + "ru90": 11.7, + "ru91": 7.9, + "ru91_m1": 7.6, + "ru92": 219.0, + "ru93": 59.7, + "ru93_m1": 10.8, + "ru94": 3108.0, + "ru95": 5914.8, + "ru97": 244512.0, + "ru103": 3390941.0, + "ru103_m1": 0.00169, + "ru105": 15984.0, + "ru106": 32123520.0, + "ru107": 225.0, + "ru108": 273.0, + "ru109": 34.5, + "ru110": 11.6, + "ru111": 2.12, + "ru112": 1.75, + "ru113": 0.8, + "ru113_m1": 0.51, + "ru114": 0.52, + "ru115": 0.74, + "ru116": 0.204, + "ru117": 0.142, + "ru118": 0.123, + "ru119": 0.162, + "ru120": 0.149, + "rh89": 1.5e-06, + "rh90": 0.0145, + "rh90_m1": 1.05, + "rh91": 1.47, + "rh92": 4.66, + "rh93": 11.9, + "rh94": 70.6, + "rh94_m1": 25.8, + "rh95": 301.2, + "rh95_m1": 117.6, + "rh96": 594.0, + "rh96_m1": 90.6, + "rh97": 1842.0, + "rh97_m1": 2772.0, + "rh98": 523.2, + "rh98_m1": 216.0, + "rh99": 1391040.0, + "rh99_m1": 16920.0, + "rh100": 74880.0, + "rh100_m1": 276.0, + "rh101": 104140100.0, + "rh101_m1": 374976.0, + "rh102": 17910720.0, + "rh102_m1": 118088500.0, + "rh103_m1": 3366.84, + "rh104": 42.3, + "rh104_m1": 260.4, + "rh105": 127296.0, + "rh105_m1": 40.0, + "rh106": 30.07, + "rh106_m1": 7860.0, + "rh107": 1302.0, + "rh108": 16.8, + "rh108_m1": 360.0, + "rh109": 80.0, + "rh110": 3.2, + "rh110_m1": 28.5, + "rh111": 11.0, + "rh112": 2.1, + "rh112_m1": 6.73, + "rh113": 2.8, + "rh114": 1.85, + "rh115": 0.99, + "rh116": 0.68, + "rh116_m1": 0.57, + "rh117": 0.44, + "rh118": 0.266, + "rh119": 0.171, + "rh120": 0.136, + "rh121": 0.151, + "rh122": 0.108, + "rh123": 0.0489, + "pd91": 1e-06, + "pd92": 0.8, + "pd93": 1.3, + "pd94": 9.0, + "pd95": 10.0, + "pd95_m1": 13.3, + "pd96": 122.0, + "pd97": 186.0, + "pd98": 1062.0, + "pd99": 1284.0, + "pd100": 313632.0, + "pd101": 30492.0, + "pd103": 1468022.0, + "pd107": 205124000000000.0, + "pd107_m1": 21.3, + "pd109": 49324.32, + "pd109_m1": 281.4, + "pd111": 1404.0, + "pd111_m1": 19800.0, + "pd112": 75708.0, + "pd113": 93.0, + "pd113_m1": 0.3, + "pd114": 145.2, + "pd115": 25.0, + "pd115_m1": 50.0, + "pd116": 11.8, + "pd117": 4.3, + "pd117_m1": 0.0191, + "pd118": 1.9, + "pd119": 0.92, + "pd120": 0.5, + "pd121": 0.285, + "pd122": 0.175, + "pd123": 0.244, + "pd124": 0.038, + "pd125": 0.3987, + "pd126": 0.2499, + "ag93": 1.5e-06, + "ag94": 0.035, + "ag94_m1": 0.55, + "ag94_m2": 0.4, + "ag95": 2.0, + "ag95_m1": 0.5, + "ag95_m2": 0.016, + "ag95_m3": 0.04, + "ag96": 4.4, + "ag96_m1": 6.9, + "ag97": 25.5, + "ag98": 47.5, + "ag99": 124.0, + "ag99_m1": 10.5, + "ag100": 120.6, + "ag100_m1": 134.4, + "ag101": 666.0, + "ag101_m1": 3.1, + "ag102": 774.0, + "ag102_m1": 462.0, + "ag103": 3942.0, + "ag103_m1": 5.7, + "ag104": 4152.0, + "ag104_m1": 2010.0, + "ag105": 3567456.0, + "ag105_m1": 433.8, + "ag106": 1437.6, + "ag106_m1": 715392.0, + "ag107_m1": 44.3, + "ag108": 142.92, + "ag108_m1": 13822200000.0, + "ag109_m1": 39.6, + "ag110": 24.6, + "ag110_m1": 21579260.0, + "ag111": 643680.0, + "ag111_m1": 64.8, + "ag112": 11268.0, + "ag113": 19332.0, + "ag113_m1": 68.7, + "ag114": 4.6, + "ag114_m1": 0.0015, + "ag115": 1200.0, + "ag115_m1": 18.0, + "ag116": 237.0, + "ag116_m1": 20.0, + "ag116_m2": 9.3, + "ag117": 72.8, + "ag117_m1": 5.34, + "ag118": 3.76, + "ag118_m1": 2.0, + "ag119": 2.1, + "ag119_m1": 6.0, + "ag120": 1.23, + "ag120_m1": 0.32, + "ag121": 0.78, + "ag122": 0.529, + "ag122_m1": 0.2, + "ag123": 0.3, + "ag124": 0.172, + "ag125": 0.166, + "ag126": 0.107, + "ag127": 0.109, + "ag128": 0.058, + "ag129": 0.046, + "ag130": 0.05, + "cd95": 0.005, + "cd96": 1.0, + "cd97": 2.8, + "cd98": 9.2, + "cd99": 16.0, + "cd100": 49.1, + "cd101": 81.6, + "cd102": 330.0, + "cd103": 438.0, + "cd104": 3462.0, + "cd105": 3330.0, + "cd107": 23400.0, + "cd109": 39864960.0, + "cd111_m1": 2912.4, + "cd113": 2.53723e23, + "cd113_m1": 444962200.0, + "cd115": 192456.0, + "cd115_m1": 3849984.0, + "cd116": 9.78286e26, + "cd117": 8964.0, + "cd117_m1": 12096.0, + "cd118": 3018.0, + "cd119": 161.4, + "cd119_m1": 132.0, + "cd120": 50.8, + "cd121": 13.5, + "cd121_m1": 8.3, + "cd122": 5.24, + "cd123": 2.1, + "cd123_m1": 1.82, + "cd124": 1.25, + "cd125": 0.68, + "cd125_m1": 0.48, + "cd126": 0.515, + "cd127": 0.37, + "cd128": 0.28, + "cd129": 0.27, + "cd130": 0.162, + "cd131": 0.068, + "cd132": 0.097, + "in97": 0.005, + "in98": 0.0425, + "in98_m1": 1.6, + "in99": 3.05, + "in100": 5.9, + "in101": 15.1, + "in102": 23.3, + "in103": 65.0, + "in103_m1": 34.0, + "in104": 108.0, + "in104_m1": 15.7, + "in105": 304.2, + "in105_m1": 48.0, + "in106": 372.0, + "in106_m1": 312.0, + "in107": 1944.0, + "in107_m1": 50.4, + "in108": 3480.0, + "in108_m1": 2376.0, + "in109": 15001.2, + "in109_m1": 80.4, + "in109_m2": 0.209, + "in110": 17640.0, + "in110_m1": 4146.0, + "in111": 242326.1, + "in111_m1": 462.0, + "in112": 898.2, + "in112_m1": 1233.6, + "in113_m1": 5968.56, + "in114": 71.9, + "in114_m1": 4277664.0, + "in114_m2": 0.0431, + "in115": 1.39169e22, + "in115_m1": 16149.6, + "in116": 14.1, + "in116_m1": 3257.4, + "in116_m2": 2.18, + "in117": 2592.0, + "in117_m1": 6972.0, + "in118": 5.0, + "in118_m1": 267.0, + "in118_m2": 8.5, + "in119": 144.0, + "in119_m1": 1080.0, + "in120": 3.08, + "in120_m1": 46.2, + "in120_m2": 47.3, + "in121": 23.1, + "in121_m1": 232.8, + "in122": 1.5, + "in122_m1": 10.3, + "in122_m2": 10.8, + "in123": 6.17, + "in123_m1": 47.4, + "in124": 3.12, + "in124_m1": 3.7, + "in125": 2.36, + "in125_m1": 12.2, + "in126": 1.53, + "in126_m1": 1.64, + "in127": 1.09, + "in127_m1": 3.67, + "in128": 0.84, + "in128_m1": 0.72, + "in129": 0.61, + "in129_m1": 1.23, + "in130": 0.29, + "in130_m1": 0.54, + "in130_m2": 0.54, + "in131": 0.28, + "in131_m1": 0.35, + "in131_m2": 0.32, + "in132": 0.207, + "in133": 0.165, + "in133_m1": 0.18, + "in134": 0.14, + "in135": 0.092, + "sn99": 0.005, + "sn100": 0.86, + "sn101": 1.7, + "sn102": 4.5, + "sn103": 7.0, + "sn104": 20.8, + "sn105": 34.0, + "sn106": 115.0, + "sn107": 174.0, + "sn108": 618.0, + "sn109": 1080.0, + "sn110": 14796.0, + "sn111": 2118.0, + "sn113": 9943776.0, + "sn113_m1": 1284.0, + "sn117_m1": 1175040.0, + "sn119_m1": 25315200.0, + "sn121": 97308.0, + "sn121_m1": 1385380000.0, + "sn123": 11162880.0, + "sn123_m1": 2403.6, + "sn125": 832896.0, + "sn125_m1": 571.2, + "sn126": 7258250000000.0, + "sn127": 7560.0, + "sn127_m1": 247.8, + "sn128": 3544.2, + "sn128_m1": 6.5, + "sn129": 133.8, + "sn129_m1": 414.0, + "sn130": 223.2, + "sn130_m1": 102.0, + "sn131": 56.0, + "sn131_m1": 58.4, + "sn132": 39.7, + "sn133": 1.46, + "sn134": 1.05, + "sn135": 0.53, + "sn136": 0.25, + "sn137": 0.19, + "sb103": 1.5e-06, + "sb104": 0.46, + "sb105": 1.22, + "sb106": 0.6, + "sb107": 4.0, + "sb108": 7.4, + "sb109": 17.0, + "sb110": 23.0, + "sb111": 75.0, + "sb112": 51.4, + "sb113": 400.2, + "sb114": 209.4, + "sb115": 1926.0, + "sb116": 948.0, + "sb116_m1": 3618.0, + "sb117": 10080.0, + "sb118": 216.0, + "sb118_m1": 18000.0, + "sb119": 137484.0, + "sb119_m1": 0.85, + "sb120": 953.4, + "sb120_m1": 497664.0, + "sb122": 235336.3, + "sb122_m1": 251.46, + "sb124": 5201280.0, + "sb124_m1": 93.0, + "sb124_m2": 1212.0, + "sb125": 87053530.0, + "sb126": 1067040.0, + "sb126_m1": 1149.0, + "sb126_m2": 11.0, + "sb127": 332640.0, + "sb128": 32436.0, + "sb128_m1": 624.0, + "sb129": 15840.0, + "sb129_m1": 1062.0, + "sb130": 2370.0, + "sb130_m1": 378.0, + "sb131": 1381.8, + "sb132": 167.4, + "sb132_m1": 246.0, + "sb133": 150.0, + "sb134": 0.78, + "sb134_m1": 10.07, + "sb135": 1.679, + "sb136": 0.923, + "sb137": 0.45, + "sb138": 0.168, + "sb139": 0.127, + "te105": 6.2e-07, + "te106": 6e-05, + "te107": 0.0031, + "te108": 2.1, + "te109": 4.6, + "te110": 18.6, + "te111": 19.3, + "te112": 120.0, + "te113": 102.0, + "te114": 912.0, + "te115": 348.0, + "te115_m1": 402.0, + "te116": 8964.0, + "te117": 3720.0, + "te117_m1": 0.103, + "te118": 518400.0, + "te119": 57780.0, + "te119_m1": 406080.0, + "te121": 1656288.0, + "te121_m1": 14186880.0, + "te123_m1": 10298880.0, + "te125_m1": 4959360.0, + "te127": 33660.0, + "te127_m1": 9417600.0, + "te128": 2.77707e26, + "te129": 4176.0, + "te129_m1": 2903040.0, + "te131": 1500.0, + "te131_m1": 119700.0, + "te132": 276825.6, + "te133": 750.0, + "te133_m1": 3324.0, + "te134": 2508.0, + "te135": 19.0, + "te136": 17.5, + "te137": 2.49, + "te138": 1.4, + "te139": 0.347, + "te140": 0.304, + "te141": 0.213, + "te142": 0.2, + "i108": 0.036, + "i109": 0.000103, + "i110": 0.65, + "i111": 2.5, + "i112": 3.42, + "i113": 6.6, + "i114": 2.1, + "i114_m1": 6.2, + "i115": 78.0, + "i116": 2.91, + "i117": 133.2, + "i118": 822.0, + "i118_m1": 510.0, + "i119": 1146.0, + "i120": 4896.0, + "i120_m1": 3180.0, + "i121": 7632.0, + "i122": 217.8, + "i123": 47604.24, + "i124": 360806.4, + "i125": 5132160.0, + "i126": 1117152.0, + "i128": 1499.4, + "i129": 495454000000000.0, + "i130": 44496.0, + "i130_m1": 530.4, + "i131": 693377.3, + "i132": 8262.0, + "i132_m1": 4993.2, + "i133": 74880.0, + "i133_m1": 9.0, + "i134": 3150.0, + "i134_m1": 211.2, + "i135": 23652.0, + "i136": 83.4, + "i136_m1": 46.9, + "i137": 24.5, + "i138": 6.23, + "i139": 2.28, + "i140": 0.86, + "i141": 0.43, + "i142": 0.222, + "i143": 0.296, + "i144": 0.194, + "i145": 0.127, + "xe110": 0.093, + "xe111": 0.81, + "xe112": 2.7, + "xe113": 2.74, + "xe114": 10.0, + "xe115": 18.0, + "xe116": 59.0, + "xe117": 61.0, + "xe118": 228.0, + "xe119": 348.0, + "xe120": 2400.0, + "xe121": 2406.0, + "xe122": 72360.0, + "xe123": 7488.0, + "xe125": 60840.0, + "xe125_m1": 56.9, + "xe127": 3144960.0, + "xe127_m1": 69.2, + "xe129_m1": 767232.0, + "xe131_m1": 1022976.0, + "xe132_m1": 0.00839, + "xe133": 452995.2, + "xe133_m1": 189216.0, + "xe134_m1": 0.29, + "xe135": 32904.0, + "xe135_m1": 917.4, + "xe137": 229.08, + "xe138": 844.8, + "xe139": 39.68, + "xe140": 13.6, + "xe141": 1.73, + "xe142": 1.23, + "xe143": 0.3, + "xe144": 1.15, + "xe145": 0.188, + "xe146": 0.369, + "xe147": 0.1, + "cs112": 0.0005, + "cs113": 1.67e-05, + "cs114": 0.57, + "cs115": 1.4, + "cs116": 0.7, + "cs116_m1": 3.85, + "cs117": 8.4, + "cs117_m1": 6.5, + "cs118": 14.0, + "cs118_m1": 17.0, + "cs119": 43.0, + "cs119_m1": 30.4, + "cs120": 61.3, + "cs120_m1": 57.0, + "cs121": 155.0, + "cs121_m1": 122.0, + "cs122": 21.18, + "cs122_m1": 0.36, + "cs122_m2": 222.0, + "cs123": 352.8, + "cs123_m1": 1.64, + "cs124": 30.8, + "cs124_m1": 6.3, + "cs125": 2802.0, + "cs125_m1": 0.0009, + "cs126": 98.4, + "cs127": 22500.0, + "cs128": 217.2, + "cs129": 115416.0, + "cs130": 1752.6, + "cs130_m1": 207.6, + "cs131": 837129.6, + "cs132": 559872.0, + "cs134": 65172760.0, + "cs134_m1": 10483.2, + "cs135": 72582500000000.0, + "cs135_m1": 3180.0, + "cs136": 1137024.0, + "cs136_m1": 19.0, + "cs137": 949252600.0, + "cs138": 2004.6, + "cs138_m1": 174.6, + "cs139": 556.2, + "cs140": 63.7, + "cs141": 24.84, + "cs142": 1.684, + "cs143": 1.791, + "cs144": 0.994, + "cs144_m1": 1.0, + "cs145": 0.587, + "cs146": 0.321, + "cs147": 0.23, + "cs148": 0.146, + "cs149": 0.05, + "cs150": 0.05, + "cs151": 0.05, + "ba114": 0.43, + "ba115": 0.45, + "ba116": 1.3, + "ba117": 1.75, + "ba118": 5.5, + "ba119": 5.4, + "ba120": 24.0, + "ba121": 29.7, + "ba122": 117.0, + "ba123": 162.0, + "ba124": 660.0, + "ba125": 210.0, + "ba126": 6000.0, + "ba127": 762.0, + "ba127_m1": 1.9, + "ba128": 209952.0, + "ba129": 8028.0, + "ba129_m1": 7776.0, + "ba130_m1": 0.0094, + "ba131": 993600.0, + "ba131_m1": 876.0, + "ba133": 331862400.0, + "ba133_m1": 140040.0, + "ba135_m1": 103320.0, + "ba136_m1": 0.3084, + "ba137_m1": 153.12, + "ba139": 4983.6, + "ba140": 1101833.0, + "ba141": 1096.2, + "ba142": 636.0, + "ba143": 14.5, + "ba144": 11.5, + "ba145": 4.31, + "ba146": 2.22, + "ba147": 0.894, + "ba148": 0.612, + "ba149": 0.344, + "ba150": 0.3, + "ba151": 0.259, + "ba152": 0.228, + "ba153": 0.158, + "la117": 0.0235, + "la117_m1": 0.01, + "la118": 1.0, + "la119": 2.0, + "la120": 2.8, + "la121": 5.3, + "la122": 8.6, + "la123": 17.0, + "la124": 29.21, + "la124_m1": 21.0, + "la125": 64.8, + "la125_m1": 0.4, + "la126": 54.0, + "la126_m1": 50.0, + "la127": 306.0, + "la127_m1": 222.0, + "la128": 310.8, + "la128_m1": 60.0, + "la129": 696.0, + "la129_m1": 0.56, + "la130": 522.0, + "la131": 3540.0, + "la132": 17280.0, + "la132_m1": 1458.0, + "la133": 14083.2, + "la134": 387.0, + "la135": 70200.0, + "la136": 592.2, + "la136_m1": 0.114, + "la137": 1893460000000.0, + "la138": 3.21888e18, + "la140": 145026.7, + "la141": 14112.0, + "la142": 5466.0, + "la143": 852.0, + "la144": 40.8, + "la145": 24.8, + "la146": 6.27, + "la146_m1": 10.0, + "la147": 4.06, + "la148": 1.26, + "la149": 1.05, + "la150": 0.86, + "la151": 0.778, + "la152": 0.451, + "la153": 0.342, + "la154": 0.228, + "la155": 0.184, + "ce119": 0.2, + "ce120": 0.25, + "ce121": 1.1, + "ce122": 2.73, + "ce123": 3.8, + "ce124": 6.0, + "ce125": 10.2, + "ce126": 51.0, + "ce127": 31.0, + "ce127_m1": 28.6, + "ce128": 235.8, + "ce129": 210.0, + "ce130": 1374.0, + "ce131": 618.0, + "ce131_m1": 324.0, + "ce132": 12636.0, + "ce132_m1": 0.0094, + "ce133": 5820.0, + "ce133_m1": 17640.0, + "ce134": 273024.0, + "ce135": 63720.0, + "ce135_m1": 20.0, + "ce137": 32400.0, + "ce137_m1": 123840.0, + "ce138_m1": 0.00865, + "ce139": 11892180.0, + "ce139_m1": 54.8, + "ce141": 2808691.0, + "ce143": 118940.4, + "ce144": 24616220.0, + "ce145": 180.6, + "ce146": 811.2, + "ce147": 56.4, + "ce148": 56.0, + "ce149": 5.3, + "ce150": 4.0, + "ce151": 1.76, + "ce152": 1.4, + "ce153": 0.979, + "ce154": 0.775, + "ce155": 0.471, + "ce156": 0.369, + "ce157": 0.2428, + "pr121": 1.4, + "pr122": 0.5, + "pr123": 0.8, + "pr124": 1.2, + "pr125": 3.3, + "pr126": 3.14, + "pr127": 4.2, + "pr128": 2.85, + "pr129": 32.0, + "pr130": 40.0, + "pr131": 90.6, + "pr131_m1": 5.73, + "pr132": 96.0, + "pr133": 390.0, + "pr134": 1020.0, + "pr134_m1": 660.0, + "pr135": 1440.0, + "pr136": 786.0, + "pr137": 4608.0, + "pr138": 87.0, + "pr138_m1": 7632.0, + "pr139": 15876.0, + "pr140": 203.4, + "pr142": 68832.0, + "pr142_m1": 876.0, + "pr143": 1172448.0, + "pr144": 1036.8, + "pr144_m1": 432.0, + "pr145": 21542.4, + "pr146": 1449.0, + "pr147": 804.0, + "pr148": 137.4, + "pr148_m1": 120.6, + "pr149": 135.6, + "pr150": 6.19, + "pr151": 18.9, + "pr152": 3.63, + "pr153": 4.28, + "pr154": 2.3, + "pr155": 0.852, + "pr156": 0.733, + "pr157": 0.598, + "pr158": 0.1342, + "pr159": 0.1055, + "nd124": 0.5, + "nd125": 0.6, + "nd126": 2e-07, + "nd127": 1.8, + "nd128": 5.0, + "nd129": 4.9, + "nd130": 21.0, + "nd131": 26.0, + "nd132": 94.0, + "nd133": 70.0, + "nd133_m1": 70.0, + "nd134": 510.0, + "nd135": 744.0, + "nd135_m1": 330.0, + "nd136": 3039.0, + "nd137": 2310.0, + "nd137_m1": 1.6, + "nd138": 18144.0, + "nd139": 1782.0, + "nd139_m1": 19800.0, + "nd140": 291168.0, + "nd141": 8964.0, + "nd141_m1": 62.0, + "nd144": 7.22669e22, + "nd147": 948672.0, + "nd149": 6220.8, + "nd150": 2.49305e26, + "nd151": 746.4, + "nd152": 684.0, + "nd153": 31.6, + "nd154": 25.9, + "nd155": 8.9, + "nd156": 5.49, + "nd157": 1.906, + "nd158": 1.331, + "nd159": 0.773, + "nd160": 0.5883, + "nd161": 0.4884, + "pm126": 0.5, + "pm127": 1.0, + "pm128": 1.0, + "pm129": 2.4, + "pm130": 2.6, + "pm131": 6.3, + "pm132": 6.2, + "pm133": 15.0, + "pm133_m1": 8.8, + "pm134": 5.0, + "pm134_m1": 22.0, + "pm135": 49.0, + "pm135_m1": 45.0, + "pm136": 47.0, + "pm136_m1": 107.0, + "pm137": 144.0, + "pm138": 10.0, + "pm138_m1": 194.4, + "pm139": 249.0, + "pm139_m1": 0.18, + "pm140": 357.0, + "pm140_m1": 357.0, + "pm141": 1254.0, + "pm142": 40.5, + "pm142_m1": 0.002, + "pm143": 22896000.0, + "pm144": 31363200.0, + "pm145": 558569500.0, + "pm146": 174513500.0, + "pm147": 82788210.0, + "pm148": 463795.2, + "pm148_m1": 3567456.0, + "pm149": 191088.0, + "pm150": 9648.0, + "pm151": 102240.0, + "pm152": 247.2, + "pm152_m1": 451.2, + "pm152_m2": 828.0, + "pm153": 315.0, + "pm154": 103.8, + "pm154_m1": 160.8, + "pm155": 41.5, + "pm156": 26.7, + "pm157": 10.56, + "pm158": 4.8, + "pm159": 1.47, + "pm160": 1.561, + "pm161": 1.065, + "pm162": 0.2679, + "pm163": 0.2, + "sm128": 0.5, + "sm129": 0.55, + "sm130": 1.0, + "sm131": 1.2, + "sm132": 4.0, + "sm133": 3.7, + "sm134": 9.5, + "sm135": 10.3, + "sm136": 47.0, + "sm137": 45.0, + "sm138": 186.0, + "sm139": 154.2, + "sm139_m1": 10.7, + "sm140": 889.2, + "sm141": 612.0, + "sm141_m1": 1356.0, + "sm142": 4349.4, + "sm143": 525.0, + "sm143_m1": 66.0, + "sm143_m2": 0.03, + "sm145": 29376000.0, + "sm146": 3250430000000000.0, + "sm147": 3.34511e18, + "sm148": 2.20903e23, + "sm151": 2840184000.0, + "sm153": 167400.0, + "sm153_m1": 0.0106, + "sm155": 1338.0, + "sm156": 33840.0, + "sm157": 482.0, + "sm158": 318.0, + "sm159": 11.37, + "sm160": 9.6, + "sm161": 4.8, + "sm162": 2.4, + "sm163": 1.748, + "sm164": 1.226, + "sm165": 0.764, + "eu130": 0.001, + "eu131": 0.0178, + "eu132": 0.1, + "eu133": 1.0, + "eu134": 0.5, + "eu135": 1.5, + "eu136": 3.8, + "eu136_m1": 3.3, + "eu136_m2": 3.8, + "eu137": 11.0, + "eu138": 12.1, + "eu139": 17.9, + "eu140": 1.51, + "eu140_m1": 0.125, + "eu141": 40.7, + "eu141_m1": 2.7, + "eu142": 2.34, + "eu142_m1": 73.38, + "eu143": 155.4, + "eu144": 10.2, + "eu145": 512352.0, + "eu146": 396576.0, + "eu147": 2082240.0, + "eu148": 4708800.0, + "eu149": 8043840.0, + "eu150": 1164480000.0, + "eu150_m1": 46080.0, + "eu152": 427195200.0, + "eu152_m1": 33521.76, + "eu152_m2": 5760.0, + "eu154": 271426900.0, + "eu154_m1": 2760.0, + "eu155": 149993300.0, + "eu156": 1312416.0, + "eu157": 54648.0, + "eu158": 2754.0, + "eu159": 1086.0, + "eu160": 38.0, + "eu161": 26.0, + "eu162": 10.6, + "eu163": 7.7, + "eu164": 2.844, + "eu165": 2.3, + "eu166": 0.4, + "eu167": 0.2, + "gd134": 0.4, + "gd135": 1.1, + "gd136": 2e-05, + "gd137": 2.2, + "gd138": 4.7, + "gd139": 5.8, + "gd139_m1": 4.8, + "gd140": 15.8, + "gd141": 14.0, + "gd141_m1": 24.5, + "gd142": 70.2, + "gd143": 39.0, + "gd143_m1": 110.0, + "gd144": 268.2, + "gd145": 1380.0, + "gd145_m1": 85.0, + "gd146": 4170528.0, + "gd147": 137016.0, + "gd148": 2354197000.0, + "gd149": 801792.0, + "gd150": 56488100000000.0, + "gd151": 10713600.0, + "gd152": 3.40822e21, + "gd153": 20770560.0, + "gd155_m1": 0.03197, + "gd159": 66524.4, + "gd161": 219.6, + "gd162": 504.0, + "gd163": 68.0, + "gd164": 45.0, + "gd165": 10.3, + "gd166": 4.8, + "gd167": 3.0, + "gd168": 0.3, + "gd169": 1.0, + "tb135": 0.995, + "tb136": 0.2, + "tb137": 0.6, + "tb138": 2e-07, + "tb139": 1.6, + "tb140": 2.4, + "tb141": 3.5, + "tb141_m1": 7.9, + "tb142": 0.597, + "tb142_m1": 0.303, + "tb143": 12.0, + "tb143_m1": 21.0, + "tb144": 1.0, + "tb144_m1": 4.25, + "tb145": 30.9, + "tb145_m1": 30.9, + "tb146": 8.0, + "tb146_m1": 23.0, + "tb146_m2": 0.00118, + "tb147": 5904.0, + "tb147_m1": 109.8, + "tb148": 3600.0, + "tb148_m1": 132.0, + "tb149": 14824.8, + "tb149_m1": 249.6, + "tb150": 12528.0, + "tb150_m1": 348.0, + "tb151": 63392.4, + "tb151_m1": 25.0, + "tb152": 63000.0, + "tb152_m1": 252.0, + "tb153": 202176.0, + "tb154": 77400.0, + "tb154_m1": 33840.0, + "tb154_m2": 81720.0, + "tb155": 459648.0, + "tb156": 462240.0, + "tb156_m1": 87840.0, + "tb156_m2": 19080.0, + "tb157": 2240590000.0, + "tb158": 5680368000.0, + "tb158_m1": 10.7, + "tb160": 6246720.0, + "tb161": 596678.4, + "tb162": 456.0, + "tb163": 1170.0, + "tb164": 180.0, + "tb165": 126.6, + "tb166": 25.1, + "tb167": 19.4, + "tb168": 8.2, + "tb169": 2.0, + "tb170": 3.0, + "tb171": 0.5, + "dy138": 0.2, + "dy139": 0.6, + "dy140": 0.84, + "dy141": 0.9, + "dy142": 2.3, + "dy143": 3.2, + "dy143_m1": 3.0, + "dy144": 9.1, + "dy145": 6.0, + "dy145_m1": 14.1, + "dy146": 29.0, + "dy146_m1": 0.15, + "dy147": 40.0, + "dy147_m1": 55.7, + "dy148": 198.0, + "dy149": 252.0, + "dy149_m1": 0.49, + "dy150": 430.2, + "dy151": 1074.0, + "dy152": 8568.0, + "dy153": 23040.0, + "dy154": 94672800000000.0, + "dy155": 35640.0, + "dy157": 29304.0, + "dy157_m1": 0.0216, + "dy159": 12476160.0, + "dy165": 8402.4, + "dy165_m1": 75.42, + "dy166": 293760.0, + "dy167": 372.0, + "dy168": 522.0, + "dy169": 39.0, + "dy170": 30.0, + "dy171": 6.0, + "dy172": 3.0, + "dy173": 2.0, + "ho140": 0.006, + "ho141": 0.0041, + "ho142": 0.4, + "ho143": 2e-07, + "ho144": 0.7, + "ho145": 2.4, + "ho146": 3.6, + "ho147": 5.8, + "ho148": 2.2, + "ho148_m1": 9.59, + "ho148_m2": 0.00236, + "ho149": 21.1, + "ho149_m1": 56.0, + "ho150": 72.0, + "ho150_m1": 23.3, + "ho151": 35.2, + "ho151_m1": 47.2, + "ho152": 161.8, + "ho152_m1": 50.0, + "ho153": 120.6, + "ho153_m1": 558.0, + "ho154": 705.6, + "ho154_m1": 186.0, + "ho155": 2880.0, + "ho155_m1": 0.00088, + "ho156": 3360.0, + "ho156_m1": 9.5, + "ho156_m2": 468.0, + "ho157": 756.0, + "ho158": 678.0, + "ho158_m1": 1680.0, + "ho158_m2": 1278.0, + "ho159": 1983.0, + "ho159_m1": 8.3, + "ho160": 1536.0, + "ho160_m1": 18072.0, + "ho160_m2": 3.0, + "ho161": 8928.0, + "ho161_m1": 6.76, + "ho162": 900.0, + "ho162_m1": 4020.0, + "ho163": 144218000000.0, + "ho163_m1": 1.09, + "ho164": 1740.0, + "ho164_m1": 2250.0, + "ho166": 96480.0, + "ho166_m1": 37869100000.0, + "ho167": 11160.0, + "ho168": 179.4, + "ho168_m1": 132.0, + "ho169": 283.2, + "ho170": 165.6, + "ho170_m1": 43.0, + "ho171": 53.0, + "ho172": 25.0, + "ho173": 10.0, + "ho174": 8.0, + "ho175": 5.0, + "er143": 0.2, + "er144": 2e-07, + "er146": 1.7, + "er147": 2.5, + "er147_m1": 2.5, + "er148": 4.6, + "er149": 4.0, + "er149_m1": 8.9, + "er150": 18.5, + "er151": 23.5, + "er151_m1": 0.58, + "er152": 10.3, + "er153": 37.1, + "er154": 223.8, + "er155": 318.0, + "er156": 1170.0, + "er157": 1119.0, + "er157_m1": 0.076, + "er158": 8244.0, + "er159": 2160.0, + "er160": 102888.0, + "er161": 11556.0, + "er163": 4500.0, + "er165": 37296.0, + "er167_m1": 2.269, + "er169": 811468.8, + "er171": 27057.6, + "er172": 177480.0, + "er173": 84.0, + "er174": 192.0, + "er175": 72.0, + "er176": 20.0, + "er177": 3.0, + "tm145": 3.1e-06, + "tm146": 0.08, + "tm146_m1": 0.2, + "tm147": 0.58, + "tm148": 0.7, + "tm149": 0.9, + "tm150": 2.2, + "tm150_m1": 0.0052, + "tm151": 4.17, + "tm151_m1": 4.51e-07, + "tm152": 8.0, + "tm152_m1": 5.2, + "tm153": 1.48, + "tm153_m1": 2.5, + "tm154": 8.1, + "tm154_m1": 3.3, + "tm155": 21.6, + "tm155_m1": 45.0, + "tm156": 83.8, + "tm157": 217.8, + "tm158": 238.8, + "tm159": 547.8, + "tm160": 564.0, + "tm160_m1": 74.5, + "tm161": 1812.0, + "tm162": 1302.0, + "tm162_m1": 24.3, + "tm163": 6516.0, + "tm164": 120.0, + "tm164_m1": 306.0, + "tm165": 108216.0, + "tm166": 27720.0, + "tm166_m1": 0.34, + "tm167": 799200.0, + "tm168": 8043840.0, + "tm170": 11111040.0, + "tm171": 60590590.0, + "tm172": 228960.0, + "tm173": 29664.0, + "tm174": 324.0, + "tm175": 912.0, + "tm176": 114.0, + "tm177": 90.0, + "tm178": 30.0, + "tm179": 20.0, + "yb148": 0.25, + "yb149": 0.7, + "yb150": 2e-07, + "yb151": 1.6, + "yb151_m1": 1.6, + "yb152": 3.04, + "yb153": 4.2, + "yb154": 0.409, + "yb155": 1.793, + "yb156": 26.1, + "yb157": 38.6, + "yb158": 89.4, + "yb159": 100.2, + "yb160": 288.0, + "yb161": 252.0, + "yb162": 1132.2, + "yb163": 663.0, + "yb164": 4548.0, + "yb165": 594.0, + "yb166": 204120.0, + "yb167": 1050.0, + "yb169": 2766355.0, + "yb169_m1": 46.0, + "yb171_m1": 0.00525, + "yb175": 361584.0, + "yb175_m1": 0.0682, + "yb176_m1": 11.4, + "yb177": 6879.6, + "yb177_m1": 6.41, + "yb178": 4440.0, + "yb179": 480.0, + "yb180": 144.0, + "yb181": 60.0, + "lu150": 0.043, + "lu151": 0.0806, + "lu152": 0.7, + "lu153": 0.9, + "lu153_m1": 1.0, + "lu154": 2.0, + "lu154_m1": 1.12, + "lu155": 0.068, + "lu155_m1": 0.138, + "lu155_m2": 0.00269, + "lu156": 0.494, + "lu156_m1": 0.198, + "lu157": 6.8, + "lu157_m1": 4.79, + "lu158": 10.6, + "lu159": 12.1, + "lu160": 36.1, + "lu160_m1": 40.0, + "lu161": 77.0, + "lu161_m1": 0.0073, + "lu162": 82.2, + "lu162_m1": 90.0, + "lu162_m2": 114.0, + "lu163": 238.2, + "lu164": 188.4, + "lu165": 644.4, + "lu166": 159.0, + "lu166_m1": 84.6, + "lu166_m2": 127.2, + "lu167": 3090.0, + "lu167_m1": 60.0, + "lu168": 330.0, + "lu168_m1": 402.0, + "lu169": 122616.0, + "lu169_m1": 160.0, + "lu170": 173836.8, + "lu170_m1": 0.67, + "lu171": 711936.0, + "lu171_m1": 79.0, + "lu172": 578880.0, + "lu172_m1": 222.0, + "lu173": 43233910.0, + "lu174": 104455700.0, + "lu174_m1": 12268800.0, + "lu176": 1.18657e18, + "lu176_m1": 13086.0, + "lu177": 574300.8, + "lu177_m1": 13862020.0, + "lu177_m2": 390.0, + "lu178": 1704.0, + "lu178_m1": 1386.0, + "lu179": 16524.0, + "lu179_m1": 0.0031, + "lu180": 342.0, + "lu180_m1": 0.001, + "lu181": 210.0, + "lu182": 120.0, + "lu183": 58.0, + "lu184": 20.0, + "hf153": 6e-06, + "hf154": 2.0, + "hf155": 0.89, + "hf156": 0.023, + "hf157": 0.11, + "hf158": 2.85, + "hf159": 5.6, + "hf160": 13.6, + "hf161": 18.2, + "hf162": 39.4, + "hf163": 40.0, + "hf164": 111.0, + "hf165": 76.0, + "hf166": 406.2, + "hf167": 123.0, + "hf168": 1557.0, + "hf169": 194.4, + "hf170": 57636.0, + "hf171": 43560.0, + "hf171_m1": 29.5, + "hf172": 59012710.0, + "hf173": 84960.0, + "hf174": 6.31152e22, + "hf175": 6048000.0, + "hf177_m1": 1.09, + "hf177_m2": 3084.0, + "hf178_m1": 4.0, + "hf178_m2": 978285600.0, + "hf179_m1": 18.67, + "hf179_m2": 2164320.0, + "hf180_m1": 19800.0, + "hf181": 3662496.0, + "hf182": 280863000000000.0, + "hf182_m1": 3690.0, + "hf183": 3841.2, + "hf184": 14832.0, + "hf184_m1": 48.0, + "hf185": 210.0, + "hf186": 156.0, + "hf187": 30.0, + "hf188": 20.0, + "ta155": 0.0031, + "ta156": 0.144, + "ta156_m1": 0.36, + "ta157": 0.0101, + "ta157_m1": 0.0043, + "ta157_m2": 0.0017, + "ta158": 0.055, + "ta158_m1": 0.0367, + "ta159": 0.83, + "ta159_m1": 0.515, + "ta160": 1.55, + "ta160_m1": 1.7, + "ta161": 2.89, + "ta162": 3.57, + "ta163": 10.6, + "ta164": 14.2, + "ta165": 31.0, + "ta166": 34.4, + "ta167": 80.0, + "ta168": 120.0, + "ta169": 294.0, + "ta170": 405.6, + "ta171": 1398.0, + "ta172": 2208.0, + "ta173": 11304.0, + "ta174": 4104.0, + "ta175": 37800.0, + "ta176": 29124.0, + "ta176_m1": 0.0011, + "ta176_m2": 0.00097, + "ta177": 203616.0, + "ta178": 558.6, + "ta178_m1": 8496.0, + "ta178_m2": 0.058, + "ta179": 57434830.0, + "ta179_m1": 0.009, + "ta179_m2": 0.0541, + "ta180": 29354.4, + "ta182": 9913536.0, + "ta182_m1": 0.283, + "ta182_m2": 950.4, + "ta183": 440640.0, + "ta184": 31320.0, + "ta185": 2964.0, + "ta185_m1": 0.002, + "ta186": 630.0, + "ta187": 120.0, + "ta188": 20.0, + "ta189": 3.0, + "ta190": 0.3, + "w158": 0.00125, + "w159": 0.0073, + "w160": 0.091, + "w161": 0.409, + "w162": 1.36, + "w163": 2.8, + "w164": 6.3, + "w165": 5.1, + "w166": 19.2, + "w167": 19.9, + "w168": 53.0, + "w169": 74.0, + "w170": 145.2, + "w171": 142.8, + "w172": 396.0, + "w173": 456.0, + "w174": 1992.0, + "w175": 2112.0, + "w176": 9000.0, + "w177": 7920.0, + "w178": 1866240.0, + "w179": 2223.0, + "w179_m1": 384.0, + "w180": 5.68037e25, + "w180_m1": 0.00547, + "w181": 10471680.0, + "w183_m1": 5.2, + "w185": 6488640.0, + "w185_m1": 100.2, + "w186": 5.36e27, + "w186_m1": 0.003, + "w187": 86400.0, + "w188": 6028992.0, + "w189": 642.0, + "w190": 1800.0, + "w190_m1": 0.0031, + "w191": 20.0, + "w192": 10.0, + "re160": 0.00085, + "re161": 0.00037, + "re161_m1": 0.0156, + "re162": 0.107, + "re162_m1": 0.077, + "re163": 0.39, + "re163_m1": 0.214, + "re164": 0.53, + "re164_m1": 0.87, + "re165": 1.0, + "re165_m1": 2.1, + "re166": 2.25, + "re167": 5.9, + "re167_m1": 3.4, + "re168": 4.4, + "re169": 8.1, + "re169_m1": 15.1, + "re170": 9.2, + "re171": 15.2, + "re172": 55.0, + "re172_m1": 15.0, + "re173": 118.8, + "re174": 144.0, + "re175": 353.4, + "re176": 318.0, + "re177": 840.0, + "re178": 792.0, + "re179": 1170.0, + "re180": 146.4, + "re181": 71640.0, + "re182": 230400.0, + "re182_m1": 45720.0, + "re183": 6048000.0, + "re183_m1": 0.00104, + "re184": 3058560.0, + "re184_m1": 14601600.0, + "re186": 321261.1, + "re186_m1": 6311520000000.0, + "re187": 1.36644e18, + "re188": 61214.4, + "re188_m1": 1115.4, + "re189": 87480.0, + "re190": 186.0, + "re190_m1": 11520.0, + "re191": 588.0, + "re192": 16.0, + "re193": 51.9, + "re194": 1.0, + "os162": 0.00205, + "os163": 0.0055, + "os164": 0.021, + "os165": 0.071, + "os166": 0.199, + "os167": 0.81, + "os168": 2.1, + "os169": 3.43, + "os170": 7.37, + "os171": 8.3, + "os172": 19.2, + "os173": 22.4, + "os174": 44.0, + "os175": 84.0, + "os176": 216.0, + "os177": 180.0, + "os178": 300.0, + "os179": 390.0, + "os180": 1290.0, + "os181": 6300.0, + "os181_m1": 162.0, + "os182": 78624.0, + "os183": 46800.0, + "os183_m1": 35640.0, + "os185": 8087040.0, + "os186": 6.31152e22, + "os189_m1": 20916.0, + "os190_m1": 594.0, + "os191": 1330560.0, + "os191_m1": 47160.0, + "os192_m1": 5.9, + "os193": 108396.0, + "os194": 189345600.0, + "os195": 540.0, + "os196": 2094.0, + "ir164": 0.14, + "ir164_m1": 9.5e-05, + "ir165": 1e-06, + "ir166": 0.0105, + "ir166_m1": 0.0151, + "ir167": 0.0352, + "ir167_m1": 0.0257, + "ir168": 0.232, + "ir168_m1": 0.16, + "ir169": 0.64, + "ir169_m1": 0.281, + "ir170": 0.9, + "ir170_m1": 0.811, + "ir171": 3.5, + "ir171_m1": 1.4, + "ir172": 4.4, + "ir172_m1": 2.0, + "ir173": 9.0, + "ir173_m1": 2.2, + "ir174": 7.9, + "ir174_m1": 4.9, + "ir175": 9.0, + "ir176": 8.7, + "ir177": 30.0, + "ir178": 12.0, + "ir179": 79.0, + "ir180": 90.0, + "ir181": 294.0, + "ir182": 900.0, + "ir183": 3480.0, + "ir184": 11124.0, + "ir185": 51840.0, + "ir186": 59904.0, + "ir186_m1": 6840.0, + "ir187": 37800.0, + "ir187_m1": 0.0303, + "ir188": 149400.0, + "ir188_m1": 0.0042, + "ir189": 1140480.0, + "ir189_m1": 0.0133, + "ir189_m2": 0.0037, + "ir190": 1017792.0, + "ir190_m1": 4032.0, + "ir190_m2": 11113.2, + "ir191_m1": 4.899, + "ir191_m2": 5.5, + "ir192": 6378653.0, + "ir192_m1": 87.0, + "ir192_m2": 7605382000.0, + "ir193_m1": 909792.0, + "ir194": 69408.0, + "ir194_m1": 0.03185, + "ir194_m2": 14774400.0, + "ir195": 9000.0, + "ir195_m1": 13680.0, + "ir196": 52.0, + "ir196_m1": 5040.0, + "ir197": 348.0, + "ir197_m1": 534.0, + "ir198": 8.0, + "ir199": 6.5, + "pt166": 0.0003, + "pt167": 0.00078, + "pt168": 0.002, + "pt169": 0.007, + "pt170": 0.014, + "pt171": 0.051, + "pt172": 0.096, + "pt173": 0.382, + "pt174": 0.889, + "pt175": 2.53, + "pt176": 6.33, + "pt177": 10.6, + "pt178": 21.1, + "pt179": 21.2, + "pt180": 56.0, + "pt181": 52.0, + "pt182": 180.0, + "pt183": 390.0, + "pt183_m1": 43.0, + "pt184": 1038.0, + "pt184_m1": 0.00101, + "pt185": 4254.0, + "pt185_m1": 1980.0, + "pt186": 7488.0, + "pt187": 8460.0, + "pt188": 881280.0, + "pt189": 39132.0, + "pt190": 2.05124e19, + "pt191": 242092.8, + "pt193": 1577880000.0, + "pt193_m1": 374112.0, + "pt195_m1": 346464.0, + "pt197": 71609.4, + "pt197_m1": 5724.6, + "pt199": 1848.0, + "pt199_m1": 13.6, + "pt200": 45360.0, + "pt201": 150.0, + "pt202": 158400.0, + "au169": 0.00015, + "au170": 0.000291, + "au170_m1": 0.00062, + "au171": 1.9e-05, + "au171_m1": 0.00102, + "au172": 0.0047, + "au173": 0.025, + "au173_m1": 0.014, + "au174": 0.139, + "au174_m1": 0.1629, + "au175": 0.1, + "au175_m1": 0.156, + "au176": 1.05, + "au176_m1": 1.36, + "au177": 1.462, + "au177_m1": 1.18, + "au178": 2.6, + "au179": 3.3, + "au180": 8.1, + "au181": 13.7, + "au182": 15.6, + "au183": 42.8, + "au184": 20.6, + "au184_m1": 47.6, + "au185": 255.0, + "au186": 642.0, + "au187": 504.0, + "au187_m1": 2.3, + "au188": 530.4, + "au189": 1722.0, + "au189_m1": 275.4, + "au190": 2568.0, + "au190_m1": 0.125, + "au191": 11448.0, + "au191_m1": 0.92, + "au192": 17784.0, + "au192_m1": 0.029, + "au192_m2": 0.16, + "au193": 63540.0, + "au193_m1": 3.9, + "au194": 136872.0, + "au194_m1": 0.6, + "au194_m2": 0.42, + "au195": 16078870.0, + "au195_m1": 30.5, + "au196": 532820.2, + "au196_m1": 8.1, + "au196_m2": 34560.0, + "au197_m1": 7.73, + "au198": 232822.1, + "au198_m1": 196300.8, + "au199": 271209.6, + "au200": 2904.0, + "au200_m1": 67320.0, + "au201": 1560.0, + "au202": 28.4, + "au203": 60.0, + "au204": 39.8, + "au205": 31.0, + "hg171": 6.9e-05, + "hg172": 0.000365, + "hg173": 0.0007, + "hg174": 0.0019, + "hg175": 0.0107, + "hg176": 0.0203, + "hg177": 0.1273, + "hg178": 0.269, + "hg179": 1.08, + "hg180": 2.58, + "hg181": 3.6, + "hg182": 10.83, + "hg183": 9.4, + "hg184": 30.9, + "hg185": 49.1, + "hg185_m1": 21.6, + "hg186": 82.8, + "hg187": 144.0, + "hg187_m1": 114.0, + "hg188": 195.0, + "hg189": 456.0, + "hg189_m1": 516.0, + "hg190": 1200.0, + "hg191": 2940.0, + "hg191_m1": 3048.0, + "hg192": 17460.0, + "hg193": 13680.0, + "hg193_m1": 42480.0, + "hg194": 14011600000.0, + "hg195": 37908.0, + "hg195_m1": 149760.0, + "hg197": 230904.0, + "hg197_m1": 85680.0, + "hg199_m1": 2560.2, + "hg203": 4025722.0, + "hg205": 308.4, + "hg205_m1": 0.00109, + "hg206": 499.2, + "hg207": 174.0, + "hg208": 2490.0, + "hg209": 36.5, + "hg210": 146.0, + "tl176": 0.006, + "tl177": 0.018, + "tl178": 0.06, + "tl179": 0.23, + "tl179_m1": 0.0017, + "tl180": 1.09, + "tl181": 3.2, + "tl181_m1": 0.0014, + "tl182": 3.1, + "tl183": 6.9, + "tl183_m1": 0.0533, + "tl184": 11.0, + "tl185": 19.5, + "tl185_m1": 1.93, + "tl186": 27.5, + "tl186_m1": 2.9, + "tl187": 51.0, + "tl187_m1": 15.6, + "tl188": 71.0, + "tl188_m1": 71.0, + "tl188_m2": 0.041, + "tl189": 138.0, + "tl189_m1": 84.0, + "tl190": 222.0, + "tl190_m1": 156.0, + "tl191": 1200.0, + "tl191_m1": 313.2, + "tl192": 576.0, + "tl192_m1": 648.0, + "tl193": 1296.0, + "tl193_m1": 126.6, + "tl194": 1980.0, + "tl194_m1": 1968.0, + "tl195": 4176.0, + "tl195_m1": 3.6, + "tl196": 6624.0, + "tl196_m1": 5076.0, + "tl197": 10224.0, + "tl197_m1": 0.54, + "tl198": 19080.0, + "tl198_m1": 6732.0, + "tl198_m2": 0.0321, + "tl199": 26712.0, + "tl199_m1": 0.0284, + "tl200": 93960.0, + "tl200_m1": 0.034, + "tl201": 262837.4, + "tl201_m1": 0.00201, + "tl202": 1063584.0, + "tl204": 119382400.0, + "tl206": 252.12, + "tl206_m1": 224.4, + "tl207": 286.2, + "tl207_m1": 1.33, + "tl208": 183.18, + "tl209": 132.0, + "tl210": 78.0, + "tl211": 60.0, + "tl212": 67.0, + "pb178": 0.00023, + "pb179": 0.003, + "pb180": 0.0045, + "pb181": 0.036, + "pb181_m1": 0.045, + "pb182": 0.0575, + "pb183": 0.535, + "pb183_m1": 0.415, + "pb184": 0.49, + "pb185": 6.3, + "pb185_m1": 4.3, + "pb186": 4.82, + "pb187": 15.2, + "pb187_m1": 18.3, + "pb188": 25.1, + "pb189": 39.0, + "pb189_m1": 50.0, + "pb190": 71.0, + "pb191": 79.8, + "pb191_m1": 130.8, + "pb192": 210.0, + "pb193": 120.0, + "pb193_m1": 348.0, + "pb194": 720.0, + "pb195": 900.0, + "pb195_m1": 900.0, + "pb196": 2220.0, + "pb197": 480.0, + "pb197_m1": 2580.0, + "pb198": 8640.0, + "pb199": 5400.0, + "pb199_m1": 732.0, + "pb200": 77400.0, + "pb201": 33588.0, + "pb201_m1": 60.8, + "pb202": 1656770000000.0, + "pb202_m1": 12744.0, + "pb203": 186912.0, + "pb203_m1": 6.21, + "pb203_m2": 0.48, + "pb204": 4.4e24, + "pb204_m1": 4015.8, + "pb205": 545946000000000.0, + "pb205_m1": 0.00555, + "pb207_m1": 0.806, + "pb209": 11710.8, + "pb210": 700578700.0, + "pb211": 2166.0, + "pb212": 38304.0, + "pb213": 612.0, + "pb214": 1608.0, + "pb215": 36.0, + "bi184": 0.013, + "bi184_m1": 0.0066, + "bi185": 5.8e-05, + "bi186": 0.015, + "bi186_m1": 0.0098, + "bi187": 0.032, + "bi187_m1": 0.00031, + "bi188": 0.06, + "bi188_m1": 0.265, + "bi189": 0.674, + "bi189_m1": 0.005, + "bi190": 6.3, + "bi190_m1": 6.2, + "bi191": 12.4, + "bi191_m1": 0.125, + "bi192": 34.6, + "bi192_m1": 39.6, + "bi193": 63.6, + "bi193_m1": 3.2, + "bi194": 95.0, + "bi194_m1": 125.0, + "bi194_m2": 115.0, + "bi195": 183.0, + "bi195_m1": 87.0, + "bi196": 308.0, + "bi196_m1": 0.6, + "bi196_m2": 240.0, + "bi197": 559.8, + "bi197_m1": 302.4, + "bi198": 618.0, + "bi198_m1": 696.0, + "bi198_m2": 7.7, + "bi199": 1620.0, + "bi199_m1": 1482.0, + "bi200": 2184.0, + "bi200_m1": 1860.0, + "bi200_m2": 0.4, + "bi201": 6180.0, + "bi201_m1": 3450.0, + "bi202": 6156.0, + "bi203": 42336.0, + "bi203_m1": 0.305, + "bi204": 40392.0, + "bi204_m1": 0.013, + "bi204_m2": 0.00107, + "bi205": 1322784.0, + "bi206": 539395.2, + "bi207": 995642300.0, + "bi208": 11613200000000.0, + "bi208_m1": 0.00258, + "bi209": 5.99594e26, + "bi210": 433036.8, + "bi210_m1": 95935100000000.0, + "bi211": 128.4, + "bi212": 3633.0, + "bi212_m1": 1500.0, + "bi212_m2": 420.0, + "bi213": 2735.4, + "bi214": 1194.0, + "bi215": 462.0, + "bi215_m1": 36.4, + "bi216": 135.0, + "bi217": 98.5, + "bi218": 33.0, + "po188": 0.000425, + "po189": 0.0035, + "po190": 0.00245, + "po191": 0.022, + "po191_m1": 0.093, + "po192": 0.0332, + "po193": 0.37, + "po193_m1": 0.373, + "po194": 0.392, + "po195": 4.64, + "po195_m1": 1.92, + "po196": 5.8, + "po197": 84.0, + "po197_m1": 32.0, + "po198": 106.2, + "po199": 328.2, + "po199_m1": 250.2, + "po200": 690.6, + "po201": 936.0, + "po201_m1": 537.6, + "po202": 2676.0, + "po203": 2202.0, + "po203_m1": 45.0, + "po204": 12708.0, + "po205": 6264.0, + "po205_m1": 0.000645, + "po205_m2": 0.0574, + "po206": 760320.0, + "po207": 20880.0, + "po207_m1": 2.79, + "po208": 91453920.0, + "po209": 3218880000.0, + "po210": 11955690.0, + "po211": 0.516, + "po211_m1": 25.2, + "po212": 2.99e-07, + "po212_m1": 45.1, + "po213": 4.2e-06, + "po214": 0.0001643, + "po215": 0.001781, + "po216": 0.145, + "po217": 1.53, + "po218": 185.88, + "po219": 3e-07, + "po220": 3e-07, + "at193": 0.0285, + "at194": 0.04, + "at194_m1": 0.25, + "at195": 0.328, + "at195_m1": 0.147, + "at196": 0.388, + "at196_m1": 1.1e-05, + "at197": 0.388, + "at197_m1": 2.0, + "at198": 4.2, + "at198_m1": 1.0, + "at199": 7.03, + "at200": 43.0, + "at200_m1": 47.0, + "at200_m2": 7.9, + "at201": 85.2, + "at202": 184.0, + "at202_m1": 182.0, + "at202_m2": 0.46, + "at203": 444.0, + "at204": 553.2, + "at204_m1": 0.108, + "at205": 1614.0, + "at206": 1836.0, + "at207": 6480.0, + "at208": 5868.0, + "at209": 19476.0, + "at210": 29160.0, + "at211": 25970.4, + "at212": 0.314, + "at212_m1": 0.119, + "at213": 1.25e-07, + "at214": 5.58e-07, + "at215": 0.0001, + "at216": 0.0003, + "at217": 0.0323, + "at218": 1.5, + "at219": 56.0, + "at220": 222.6, + "at221": 138.0, + "at222": 54.0, + "at223": 50.0, + "rn195": 0.0065, + "rn195_m1": 0.005, + "rn196": 0.0046, + "rn197": 0.066, + "rn197_m1": 0.021, + "rn198": 0.065, + "rn199": 0.59, + "rn199_m1": 0.31, + "rn200": 1.075, + "rn201": 7.0, + "rn201_m1": 3.8, + "rn202": 9.7, + "rn203": 44.0, + "rn203_m1": 26.9, + "rn204": 70.2, + "rn205": 170.0, + "rn206": 340.2, + "rn207": 555.0, + "rn208": 1461.0, + "rn209": 1728.0, + "rn210": 8640.0, + "rn211": 52560.0, + "rn212": 1434.0, + "rn213": 0.025, + "rn214": 2.7e-07, + "rn215": 2.3e-06, + "rn216": 4.5e-05, + "rn217": 0.00054, + "rn218": 0.035, + "rn219": 3.96, + "rn220": 55.6, + "rn221": 1542.0, + "rn222": 330350.4, + "rn223": 1458.0, + "rn224": 6420.0, + "rn225": 279.6, + "rn226": 444.0, + "rn227": 20.8, + "rn228": 65.0, + "fr199": 0.015, + "fr200": 0.049, + "fr201": 0.069, + "fr202": 0.3, + "fr202_m1": 0.29, + "fr203": 0.55, + "fr204": 1.7, + "fr204_m1": 2.6, + "fr204_m2": 1.0, + "fr205": 3.8, + "fr206": 16.0, + "fr206_m1": 16.0, + "fr206_m2": 0.7, + "fr207": 14.8, + "fr208": 59.1, + "fr209": 50.0, + "fr210": 190.8, + "fr211": 186.0, + "fr212": 1200.0, + "fr213": 34.82, + "fr214": 0.005, + "fr214_m1": 0.00335, + "fr215": 8.6e-08, + "fr216": 7e-07, + "fr217": 1.9e-05, + "fr218": 0.001, + "fr218_m1": 0.022, + "fr219": 0.02, + "fr220": 27.4, + "fr221": 294.0, + "fr222": 852.0, + "fr223": 1320.0, + "fr224": 199.8, + "fr225": 237.0, + "fr226": 49.0, + "fr227": 148.2, + "fr228": 38.0, + "fr229": 50.2, + "fr230": 19.1, + "fr231": 17.6, + "fr232": 5.5, + "ra202": 0.0275, + "ra203": 0.031, + "ra203_m1": 0.025, + "ra204": 0.0605, + "ra205": 0.22, + "ra205_m1": 0.18, + "ra206": 0.24, + "ra207": 1.3, + "ra207_m1": 0.055, + "ra208": 1.3, + "ra209": 4.6, + "ra210": 3.7, + "ra211": 13.0, + "ra212": 13.0, + "ra213": 163.8, + "ra213_m1": 0.0021, + "ra214": 2.46, + "ra215": 0.00155, + "ra216": 1.82e-07, + "ra217": 1.6e-06, + "ra218": 2.52e-05, + "ra219": 0.01, + "ra220": 0.018, + "ra221": 28.0, + "ra222": 36.17, + "ra223": 987552.0, + "ra224": 316224.0, + "ra225": 1287360.0, + "ra226": 50492200000.0, + "ra227": 2532.0, + "ra228": 181456200.0, + "ra229": 240.0, + "ra230": 5580.0, + "ra231": 103.0, + "ra232": 252.0, + "ra233": 30.0, + "ra234": 30.0, + "ac206": 0.024, + "ac206_m1": 0.0395, + "ac207": 0.027, + "ac208": 0.095, + "ac208_m1": 0.025, + "ac209": 0.098, + "ac210": 0.35, + "ac211": 0.21, + "ac212": 0.93, + "ac213": 0.8, + "ac214": 8.2, + "ac215": 0.17, + "ac216": 0.00044, + "ac216_m1": 0.000441, + "ac217": 6.9e-08, + "ac218": 1.08e-06, + "ac219": 1.18e-05, + "ac220": 0.0264, + "ac221": 0.052, + "ac222": 5.0, + "ac222_m1": 63.0, + "ac223": 126.0, + "ac224": 10008.0, + "ac225": 864000.0, + "ac226": 105732.0, + "ac227": 687072100.0, + "ac228": 22140.0, + "ac229": 3762.0, + "ac230": 122.0, + "ac231": 450.0, + "ac232": 119.0, + "ac233": 145.0, + "ac234": 44.0, + "ac235": 60.0, + "ac236": 120.0, + "th209": 0.0065, + "th210": 0.016, + "th211": 0.05, + "th212": 0.035, + "th213": 0.14, + "th214": 0.1, + "th215": 1.2, + "th216": 0.026, + "th217": 0.000251, + "th218": 1.17e-07, + "th219": 1.05e-06, + "th220": 9.7e-06, + "th221": 0.00173, + "th222": 0.002237, + "th223": 0.6, + "th224": 1.05, + "th225": 523.2, + "th226": 1834.2, + "th227": 1613952.0, + "th228": 60338130.0, + "th229": 231633000000.0, + "th230": 2378810000000.0, + "th231": 91872.0, + "th232": 4.43384e17, + "th233": 1338.0, + "th234": 2082240.0, + "th235": 426.0, + "th236": 2238.0, + "th237": 282.0, + "th238": 564.0, + "pa212": 0.0051, + "pa213": 0.0053, + "pa214": 0.017, + "pa215": 0.014, + "pa216": 0.16, + "pa217": 0.0036, + "pa217_m1": 0.0012, + "pa218": 0.000113, + "pa219": 5.3e-08, + "pa220": 7.8e-07, + "pa221": 5.9e-06, + "pa222": 0.0033, + "pa223": 0.0051, + "pa224": 0.79, + "pa225": 1.7, + "pa226": 108.0, + "pa227": 2298.0, + "pa228": 79200.0, + "pa229": 129600.0, + "pa230": 1503360.0, + "pa231": 1033830000000.0, + "pa232": 114048.0, + "pa233": 2330640.0, + "pa234": 24120.0, + "pa234_m1": 69.54, + "pa235": 1466.4, + "pa236": 546.0, + "pa237": 522.0, + "pa238": 136.2, + "pa239": 6480.0, + "pa240": 120.0, + "u217": 0.0235, + "u218": 0.000545, + "u219": 4.2e-05, + "u220": 6e-08, + "u222": 1.3e-06, + "u223": 1.8e-05, + "u224": 0.0009, + "u225": 0.084, + "u226": 0.35, + "u227": 66.0, + "u228": 546.0, + "u229": 3480.0, + "u230": 1797120.0, + "u231": 362880.0, + "u232": 2174319000.0, + "u233": 5023970000000.0, + "u234": 7747390000000.0, + "u235": 2.22102e16, + "u235_m1": 1560.0, + "u236": 739079000000000.0, + "u237": 583200.0, + "u238": 1.40999e17, + "u239": 1407.0, + "u240": 50760.0, + "u241": 300.0, + "u242": 1008.0, + "np225": 2e-06, + "np226": 0.035, + "np227": 0.51, + "np228": 61.4, + "np229": 240.0, + "np230": 276.0, + "np231": 2928.0, + "np232": 882.0, + "np233": 2172.0, + "np234": 380160.0, + "np235": 34231680.0, + "np236": 4828310000000.0, + "np236_m1": 81000.0, + "np237": 67659500000000.0, + "np238": 182908.8, + "np239": 203558.4, + "np240": 3714.0, + "np240_m1": 433.2, + "np241": 834.0, + "np242": 132.0, + "np242_m1": 330.0, + "np243": 111.0, + "np244": 137.4, + "pu228": 1.85, + "pu229": 112.0, + "pu230": 102.0, + "pu231": 516.0, + "pu232": 2028.0, + "pu233": 1254.0, + "pu234": 31680.0, + "pu235": 1518.0, + "pu236": 90191620.0, + "pu237": 3943296.0, + "pu237_m1": 0.18, + "pu238": 2767602000.0, + "pu239": 760854000000.0, + "pu240": 207049000000.0, + "pu241": 450958100.0, + "pu242": 11786800000000.0, + "pu243": 17841.6, + "pu244": 2559320000000000.0, + "pu245": 37800.0, + "pu246": 936576.0, + "pu247": 196128.0, + "am231": 10.0, + "am232": 79.0, + "am233": 192.0, + "am234": 139.2, + "am235": 618.0, + "am236": 216.0, + "am237": 4416.0, + "am238": 5880.0, + "am239": 42840.0, + "am240": 182880.0, + "am241": 13651800000.0, + "am242": 57672.0, + "am242_m1": 4449622000.0, + "am242_m2": 0.014, + "am243": 232580000000.0, + "am244": 36360.0, + "am244_m1": 1560.0, + "am245": 7380.0, + "am246": 2340.0, + "am246_m1": 1500.0, + "am247": 1380.0, + "am248": 600.0, + "am249": 120.0, + "cm233": 17.7, + "cm234": 51.0, + "cm235": 300.0, + "cm236": 1900.0, + "cm237": 1200.0, + "cm238": 8640.0, + "cm239": 10440.0, + "cm240": 2332800.0, + "cm241": 2833920.0, + "cm242": 14078020.0, + "cm243": 918326200.0, + "cm244": 571508100.0, + "cm244_m1": 5e-07, + "cm245": 268240000000.0, + "cm246": 150214000000.0, + "cm247": 492299000000000.0, + "cm248": 10982000000000.0, + "cm249": 3849.0, + "cm250": 261928000000.0, + "cm251": 1008.0, + "bk235": 20.0, + "bk237": 60.0, + "bk238": 144.0, + "bk240": 288.0, + "bk241": 276.0, + "bk242": 420.0, + "bk243": 16200.0, + "bk244": 15660.0, + "bk245": 426816.0, + "bk246": 155520.0, + "bk247": 43549500000.0, + "bk248": 283824000.0, + "bk248_m1": 85320.0, + "bk249": 27648000.0, + "bk250": 11563.2, + "bk251": 3336.0, + "bk253": 600.0, + "bk254": 120.0, + "cf237": 2.1, + "cf238": 0.021, + "cf239": 51.5, + "cf240": 57.6, + "cf241": 226.8, + "cf242": 222.0, + "cf243": 642.0, + "cf244": 1164.0, + "cf245": 2700.0, + "cf246": 128520.0, + "cf247": 11196.0, + "cf248": 28814400.0, + "cf249": 11076700000.0, + "cf250": 412773400.0, + "cf251": 28338700000.0, + "cf252": 83468070.0, + "cf253": 1538784.0, + "cf254": 5227200.0, + "cf255": 5100.0, + "cf256": 738.0, + "es240": 1.0, + "es241": 8.5, + "es242": 13.5, + "es243": 21.0, + "es244": 37.0, + "es245": 66.0, + "es246": 462.0, + "es247": 273.0, + "es247_m1": 54000000.0, + "es248": 1620.0, + "es249": 6132.0, + "es250": 30960.0, + "es250_m1": 7992.0, + "es251": 118800.0, + "es252": 40754880.0, + "es253": 1768608.0, + "es254": 23820480.0, + "es254_m1": 141479.9, + "es255": 3438720.0, + "es256": 1524.0, + "es256_m1": 27360.0, + "es257": 665280.0, + "es258": 180.0, + "fm242": 0.0008, + "fm243": 0.2, + "fm244": 0.0033, + "fm245": 4.2, + "fm246": 1.1, + "fm247": 29.0, + "fm248": 36.0, + "fm249": 156.0, + "fm250": 1800.0, + "fm250_m1": 1.8, + "fm251": 19080.0, + "fm252": 91404.0, + "fm253": 259200.0, + "fm254": 11664.0, + "fm255": 72252.0, + "fm256": 9456.0, + "fm257": 8683200.0, + "fm258": 0.00037, + "fm259": 1.5, + "fm260": 0.004, + "md245": 0.0009, + "md245_m1": 0.39, + "md246": 0.9, + "md247": 1.12, + "md247_m1": 0.26, + "md248": 7.0, + "md249": 24.0, + "md249_m1": 1.9, + "md250": 27.5, + "md251": 240.0, + "md252": 138.0, + "md253": 630.0, + "md254": 1680.0, + "md254_m1": 1680.0, + "md255": 1620.0, + "md256": 4620.0, + "md257": 19872.0, + "md258": 4449600.0, + "md258_m1": 3420.0, + "md259": 5760.0, + "md260": 2747520.0, + "md261": 2400.0, + "no250": 4.35e-06, + "no251": 0.8, + "no251_m1": 1.02, + "no252": 2.44, + "no253": 97.2, + "no254": 51.0, + "no254_m1": 0.28, + "no255": 186.0, + "no256": 2.91, + "no257": 25.0, + "no258": 0.0012, + "no259": 3480.0, + "no260": 0.106, + "no261": 160000.0, + "no262": 0.005, + "lr251": 1.341, + "lr252": 0.38, + "lr253": 0.575, + "lr253_m1": 1.535, + "lr254": 13.0, + "lr255": 22.0, + "lr255_m1": 2.53, + "lr256": 27.0, + "lr257": 0.646, + "lr258": 4.1, + "lr259": 6.2, + "lr260": 180.0, + "lr261": 2340.0, + "lr262": 14400.0, + "lr263": 18000.0, + "rf253": 5.15e-05, + "rf254": 2.3e-05, + "rf255": 1.68, + "rf256": 0.0064, + "rf257": 4.7, + "rf257_m1": 3.9, + "rf258": 0.012, + "rf259": 3.2, + "rf260": 0.021, + "rf261": 65.0, + "rf261_m1": 81.0, + "rf262": 2.3, + "rf263": 600.0, + "rf264": 3600.0, + "rf265": 1.0, + "db255": 1.7, + "db256": 1.7, + "db257": 1.52, + "db257_m1": 0.78, + "db258": 4.0, + "db258_m1": 20.0, + "db259": 0.51, + "db260": 1.52, + "db261": 1.8, + "db262": 35.0, + "db263": 28.5, + "db264": 180.0, + "db265": 900.0, + "sg258": 0.0032, + "sg259": 0.555, + "sg260": 0.0036, + "sg261": 0.23, + "sg262": 0.0079, + "sg263": 1.0, + "sg263_m1": 0.12, + "sg264": 0.045, + "sg265": 8.0, + "sg266": 25.0, + "sg269": 50.0, + "bh260": 0.0003, + "bh261": 0.013, + "bh262": 0.102, + "bh262_m1": 0.022, + "bh263": 0.0002, + "bh264": 0.66, + "bh265": 1.1, + "bh266": 5.4, + "bh267": 21.0, + "bh269": 50.0, + "hs263": 0.00355, + "hs264": 0.0008, + "hs265": 0.00205, + "hs265_m1": 0.0003, + "hs266": 0.00265, + "hs267": 0.0545, + "hs268": 1.2, + "hs269": 12.9, + "hs273": 50.0, + "mt265": 120.0, + "mt266": 0.0018, + "mt266_m1": 0.0017, + "mt267": 0.01, + "mt268": 0.0225, + "mt269": 0.05, + "mt270": 0.00605, + "mt271": 5.0, + "mt273": 20.0, + "ds267": 2.8e-06, + "ds268": 0.0001, + "ds269": 0.000268, + "ds270": 0.00015, + "ds270_m1": 0.009, + "ds271": 0.001705, + "ds271_m1": 0.0865, + "ds272": 1.0, + "ds273": 0.000225, + "ds279_m1": 0.19, + "rg272": 0.0041 +} diff --git a/openmc/data/kalbach_mann.py b/openmc/data/kalbach_mann.py index f4c914d9094..d92bf9c213a 100644 --- a/openmc/data/kalbach_mann.py +++ b/openmc/data/kalbach_mann.py @@ -5,6 +5,7 @@ import numpy as np import openmc.checkvalue as cv +from openmc.mixin import EqualityMixin from openmc.stats import Tabular, Univariate, Discrete, Mixture from .function import Tabulated1D, INTERPOLATION_SCHEME from .angle_energy import AngleEnergy @@ -12,6 +13,242 @@ from .endf import get_list_record, get_tab2_record +class _AtomicRepresentation(EqualityMixin): + """Atomic representation of an isotope or a particle. + + Parameters + ---------- + z : int + Number of protons (atomic number) + a : int + Number of nucleons (mass number) + + Raises + ------ + ValueError + When the number of protons (z) declared is higher than the number + of nucleons (a) + + Attributes + ---------- + z : int + Number of protons (atomic number) + a : int + Number of nucleons (mass number) + n : int + Number of neutrons + za : int + ZA identifier, 1000*Z + A, where Z is the atomic number and A the mass + number + + """ + def __init__(self, z, a): + # Sanity checks on values + cv.check_type('z', z, Integral) + cv.check_greater_than('z', z, 0, equality=True) + cv.check_type('a', a, Integral) + cv.check_greater_than('a', a, 0, equality=True) + if z > a: + raise ValueError(f"Number of protons ({z}) must be less than or " + f"equal to number of nucleons ({a}).") + + self._z = z + self._a = a + + def __add__(self, other): + """Add two _AtomicRepresentations""" + z = self.z + other.z + a = self.a + other.a + return _AtomicRepresentation(z=z, a=a) + + def __sub__(self, other): + """Substract two _AtomicRepresentations""" + z = self.z - other.z + a = self.a - other.a + return _AtomicRepresentation(z=z, a=a) + + @property + def a(self): + return self._a + + @property + def z(self): + return self._z + + @property + def n(self): + return self.a - self.z + + @property + def za(self): + return self.z * 1000 + self.a + + @classmethod + def from_za(cls, za): + """Instantiate an _AtomicRepresentation from a ZA identifier. + + Parameters + ---------- + za : int + ZA identifier, 1000*Z + A, where Z is the atomic number and A the + mass number + + Returns + ------- + _AtomicRepresentation + Atomic representation of the isotope/particle + + """ + z, a = divmod(za, 1000) + return cls(z, a) + + +def _separation_energy(compound, nucleus, particle): + """Calculates the separation energy as defined in ENDF-6 manual + BNL-203218-2018-INRE, Revision 215, File 6 description for LAW=1 + and LANG=2. This function can be used for the incident or emitted + particle of the following reaction: A + a -> C -> B + b + + Parameters + ---------- + compound : _AtomicRepresentation + Atomic representation of the compound (C) + nucleus : _AtomicRepresentation + Atomic representation of the nucleus (A or B) + particle : _AtomicRepresentation + Atomic representation of the particle (a or b) + + Returns + ------- + separation_energy : float + Separation energy in MeV + + """ + # Determine A, Z, and N for compound and nucleus + A_c = compound.a + Z_c = compound.z + N_c = compound.n + A_a = nucleus.a + Z_a = nucleus.z + N_a = nucleus.n + + # Determine breakup energy of incident particle (ENDF-6 Formats Manual, + # Appendix H, Table 3) in MeV + za_to_breaking_energy = { + 1: 0.0, + 1001: 0.0, + 1002: 2.224566, + 1003: 8.481798, + 2003: 7.718043, + 2004: 28.29566 + } + I_a = za_to_breaking_energy[particle.za] + + # Eq. 4 in in doi:10.1103/PhysRevC.37.2350 or ENDF-6 Formats Manual section + # 6.2.3.2 + return ( + 15.68 * (A_c - A_a) - + 28.07 * ((N_c - Z_c)**2 / A_c - (N_a - Z_a)**2 / A_a) - + 18.56 * (A_c**(2./3.) - A_a**(2./3.)) + + 33.22 * ((N_c - Z_c)**2 / A_c**(4./3.) - (N_a - Z_a)**2 / A_a**(4./3.)) - + 0.717 * (Z_c**2 / A_c**(1./3.) - Z_a**2 / A_a**(1./3.)) + + 1.211 * (Z_c**2 / A_c - Z_a**2 / A_a) - + I_a + ) + + +def kalbach_slope(energy_projectile, energy_emitted, za_projectile, + za_emitted, za_target): + """Returns Kalbach-Mann slope from calculations. + + The associated reaction is defined as: + A + a -> C -> B + b + + Where: + + - A is the targeted nucleus, + - a is the projectile, + - C is the compound, + - B is the residual nucleus, + - b is the emitted particle. + + The Kalbach-Mann slope calculation is done as defined in ENDF-6 manual + BNL-203218-2018-INRE, Revision 215, File 6 description for LAW=1 and + LANG=2. One exception to this, is that the entrance and emission channel + energies are not calculated with the AWR number, but approximated with + the number of mass instead. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + energy_projectile : float + Energy of the projectile in the laboratory system in eV + energy_emitted : float + Energy of the emitted particle in the center of mass system in eV + za_projectile : int + ZA identifier of the projectile + za_emitted : int + ZA identifier of the emitted particle + za_target : int + ZA identifier of the targeted nucleus + + Raises + ------ + NotImplementedError + When the projectile is not a neutron + + Returns + ------- + slope : float + Kalbach-Mann slope given with the same format as ACE file. + + """ + # TODO: develop for photons as projectile + # TODO: test for other particles than neutron + if za_projectile != 1: + raise NotImplementedError( + "Developed and tested for neutron projectile only." + ) + + # Special handling of elemental carbon + if za_emitted == 6000: + za_emitted = 6012 + if za_target == 6000: + za_target = 6012 + + projectile = _AtomicRepresentation.from_za(za_projectile) + emitted = _AtomicRepresentation.from_za(za_emitted) + target = _AtomicRepresentation.from_za(za_target) + compound = projectile + target + residual = compound - emitted + + # Calculate entrance and emission channel energy in MeV, defined in section + # 6.2.3.2 in the ENDF-6 Formats Manual + epsilon_a = energy_projectile * target.a / (target.a + projectile.a) / EV_PER_MEV + epsilon_b = energy_emitted * (residual.a + emitted.a) \ + / (residual.a * EV_PER_MEV) + + # Calculate separation energies using Eq. 4 in doi:10.1103/PhysRevC.37.2350 + # or ENDF-6 Formats Manual section 6.2.3.2 + s_a = _separation_energy(compound, target, projectile) + s_b = _separation_energy(compound, residual, emitted) + + # See Eq. 10 in doi:10.1103/PhysRevC.37.2350 or section 6.2.3.2 in the + # ENDF-6 Formats Manual + za_to_M = {1: 1.0, 1001: 1.0, 1002: 1.0, 2004: 0.0} + za_to_m = {1: 0.5, 1001: 1.0, 1002: 1.0, 1003: 1.0, 2003: 1.0, 2004: 2.0} + M = za_to_M[projectile.za] + m = za_to_m[emitted.za] + e_a = epsilon_a + s_a + e_b = epsilon_b + s_b + r_1 = min(e_a, 130.) + r_3 = min(e_a, 41.) + x_1 = r_1 * e_b / e_a + x_3 = r_3 * e_b / e_a + return 0.04 * x_1 + 1.8e-6 * x_1**3 + 6.7e-7 * M * m * x_3**4 + + class KalbachMann(AngleEnergy): """Kalbach-Mann distribution @@ -65,56 +302,56 @@ def __init__(self, breakpoints, interpolation, energy, energy_out, def breakpoints(self): return self._breakpoints - @property - def interpolation(self): - return self._interpolation - - @property - def energy(self): - return self._energy - - @property - def energy_out(self): - return self._energy_out - - @property - def precompound(self): - return self._precompound - - @property - def slope(self): - return self._slope - @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('Kalbach-Mann breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('Kalbach-Mann interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('Kalbach-Mann incoming energy', energy, Iterable, Real) self._energy = energy + @property + def energy_out(self): + return self._energy_out + @energy_out.setter def energy_out(self, energy_out): cv.check_type('Kalbach-Mann distributions', energy_out, Iterable, Univariate) self._energy_out = energy_out + @property + def precompound(self): + return self._precompound + @precompound.setter def precompound(self, precompound): cv.check_type('Kalbach-Mann precompound factor', precompound, Iterable, Tabulated1D) self._precompound = precompound + @property + def slope(self): + return self._slope + @slope.setter def slope(self, slope): cv.check_type('Kalbach-Mann slope', slope, Iterable, Tabulated1D) @@ -129,7 +366,7 @@ def to_hdf5(self, group): HDF5 group to write to """ - group.attrs['type'] = np.string_('kalbach-mann') + group.attrs['type'] = np.bytes_('kalbach-mann') dset = group.create_dataset('energy', data=self.energy) dset.attrs['interpolation'] = np.vstack((self.breakpoints, @@ -319,7 +556,7 @@ def from_ace(cls, ace, idx, ldis): n_energy_out = int(ace.xss[idx + 1]) data = ace.xss[idx + 2:idx + 2 + 5*n_energy_out].copy() data.shape = (5, n_energy_out) - data[0,:] *= EV_PER_MEV + data[0, :] *= EV_PER_MEV # Create continuous distribution eout_continuous = Tabular(data[0][n_discrete_lines:], @@ -352,13 +589,31 @@ def from_ace(cls, ace, idx, ldis): return cls(breakpoints, interpolation, energy, energy_out, km_r, km_a) @classmethod - def from_endf(cls, file_obj): - """Generate Kalbach-Mann distribution from an ENDF evaluation + def from_endf(cls, file_obj, za_emitted, za_target, projectile_mass): + """Generate Kalbach-Mann distribution from an ENDF evaluation. + + If the projectile is a neutron, the slope is calculated when it is + not given explicitly. + + .. versionchanged:: 0.13.1 + Arguments changed to accommodate slope calculation Parameters ---------- file_obj : file-like object ENDF file positioned at the start of the Kalbach-Mann distribution + za_emitted : int + ZA identifier of the emitted particle + za_target : int + ZA identifier of the target + projectile_mass : float + Mass of the projectile + + Warns + ----- + UserWarning + If the mass of the projectile is not equal to 1 (other than + a neutron), the slope is not calculated and set to 0 if missing. Returns ------- @@ -374,6 +629,7 @@ def from_endf(cls, file_obj): energy_out = [] precompound = [] slope = [] + calculated_slope = [] for i in range(ne): items, values = get_list_record(file_obj) energy[i] = items[1] @@ -385,19 +641,46 @@ def from_endf(cls, file_obj): values.shape = (n_energy_out, n_angle + 2) # Outgoing energy distribution at the i-th incoming energy - eout_i = values[:,0] - eout_p_i = values[:,1] + eout_i = values[:, 0] + eout_p_i = values[:, 1] energy_out_i = Tabular(eout_i, eout_p_i, INTERPOLATION_SCHEME[lep]) energy_out.append(energy_out_i) - # Precompound and slope factors for Kalbach-Mann - r_i = values[:,2] + # Precompound factors for Kalbach-Mann + r_i = values[:, 2] + + # Slope factors for Kalbach-Mann if n_angle == 2: - a_i = values[:,3] + a_i = values[:, 3] + calculated_slope.append(False) else: - a_i = np.zeros_like(r_i) + # Check if the projectile is not a neutron + if not np.isclose(projectile_mass, 1.0, atol=1.0e-12, rtol=0.): + warn( + "Kalbach-Mann slope calculation is only available with " + "neutrons as projectile. Slope coefficients are set to 0." + ) + a_i = np.zeros_like(r_i) + calculated_slope.append(False) + + else: + # TODO: retrieve ZA of the projectile + za_projectile = 1 + a_i = [kalbach_slope(energy_projectile=energy[i], + energy_emitted=e, + za_projectile=za_projectile, + za_emitted=za_emitted, + za_target=za_target) + for e in eout_i] + calculated_slope.append(True) + precompound.append(Tabulated1D(eout_i, r_i)) slope.append(Tabulated1D(eout_i, a_i)) - return cls(tab2.breakpoints, tab2.interpolation, energy, - energy_out, precompound, slope) + km_distribution = cls(tab2.breakpoints, tab2.interpolation, energy, + energy_out, precompound, slope) + + # List of bool to indicate slope calculation by OpenMC + km_distribution._calculated_slope = calculated_slope + + return km_distribution diff --git a/openmc/data/laboratory.py b/openmc/data/laboratory.py index 87d9d296183..c20b4596846 100644 --- a/openmc/data/laboratory.py +++ b/openmc/data/laboratory.py @@ -54,45 +54,46 @@ def __init__(self, breakpoints, interpolation, energy, mu, energy_out): def breakpoints(self): return self._breakpoints - @property - def interpolation(self): - return self._interpolation - @property - def energy(self): - return self._energy - - @property - def mu(self): - return self._mu - - @property - def energy_out(self): - return self._energy_out - @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('laboratory angle-energy breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('laboratory angle-energy interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('laboratory angle-energy incoming energy', energy, Iterable, Real) self._energy = energy + @property + def mu(self): + return self._mu + @mu.setter def mu(self, mu): cv.check_type('laboratory angle-energy outgoing cosine', mu, Iterable, Univariate) self._mu = mu + @property + def energy_out(self): + return self._energy_out + @energy_out.setter def energy_out(self, energy_out): cv.check_iterable_type('laboratory angle-energy outgoing energy', diff --git a/openmc/data/library.py b/openmc/data/library.py index cd0fe0895b3..a6ce1bbd32c 100644 --- a/openmc/data/library.py +++ b/openmc/data/library.py @@ -1,27 +1,33 @@ import os -import xml.etree.ElementTree as ET import pathlib import h5py +import lxml.etree as ET -from openmc.mixin import EqualityMixin +import openmc from openmc._xml import clean_indentation, reorder_attributes -class DataLibrary(EqualityMixin): +class DataLibrary(list): """Collection of cross section data libraries. - Attributes - ---------- - libraries : list of dict - List in which each item is a dictionary summarizing cross section data - from a single file. The dictionary has keys 'path', 'type', and - 'materials'. + This class behaves like a list where each item is a dictionary summarizing + cross section data from a single file. The dictionary has keys 'path', + 'type', and 'materials'. + + .. versionchanged:: 0.14.0 + This class now behaves like a list rather than requiring you to access + the list of libraries through a special attribute. """ def __init__(self): - self.libraries = [] + super().__init__() + + @property + def libraries(self): + # For backwards compatibility + return self def get_by_material(self, name, data_type='neutron'): """Return the library dictionary containing a given material. @@ -42,11 +48,26 @@ def get_by_material(self, name, data_type='neutron'): the dictionary has keys 'path', 'type', and 'materials'. """ - for library in self.libraries: + for library in self: if name in library['materials'] and data_type in library['type']: return library return None + def remove_by_material(self, name: str, data_type='neutron'): + """Remove the library dictionary containing a specific material + + Parameters + ---------- + name : str + Name of material, e.g. 'Am241' + data_type : str + Name of data type, e.g. 'neutron', 'photon', 'wmp', or 'thermal' + + """ + library = self.get_by_material(name, data_type) + if library is not None: + self.remove(library) + def register_file(self, filename): """Register a file with the data library. @@ -72,11 +93,10 @@ def register_file(self, filename): materials = list(h5file) else: raise ValueError( - "File type {} not supported by {}" - .format(path.name, self.__class__.__name__)) + f"File type {path.name} not supported by {self.__class__.__name__}") library = {'path': str(path), 'type': filetype, 'materials': materials} - self.libraries.append(library) + self.append(library) def export_to_xml(self, path='cross_sections.xml'): """Export cross section data library to an XML file. @@ -91,7 +111,7 @@ def export_to_xml(self, path='cross_sections.xml'): # Determine common directory for library paths common_dir = os.path.dirname(os.path.commonprefix( - [lib['path'] for lib in self.libraries])) + [lib['path'] for lib in self])) if common_dir == '': common_dir = '.' @@ -99,7 +119,7 @@ def export_to_xml(self, path='cross_sections.xml'): dir_element = ET.SubElement(root, "directory") dir_element.text = os.path.realpath(common_dir) - for library in self.libraries: + for library in self: if library['type'] == "depletion_chain": lib_element = ET.SubElement(root, "depletion_chain") else: @@ -124,8 +144,8 @@ def from_xml(cls, path=None): Parameters ---------- path : str, optional - Path to XML file to read. If not provided, the - :envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used. + Path to XML file to read. If not provided, + openmc.config['cross_sections'] will be used. Returns ------- @@ -136,19 +156,14 @@ def from_xml(cls, path=None): data = cls() - # If path is None, get the cross sections from the - # OPENMC_CROSS_SECTIONS environment variable + # If path is None, get the cross sections from the global configuration if path is None: - path = os.environ.get('OPENMC_CROSS_SECTIONS') + path = openmc.config.get('cross_sections') - # Check to make sure there was an environmental variable. + # Check to make sure we picked up cross sections if path is None: - raise ValueError("Either path or OPENMC_CROSS_SECTIONS " - "environmental variable must be set") - - # Convert to string to support pathlib - # TODO: Remove when support is Python 3.6+ only - path = str(path) + raise ValueError("Either path or openmc.config['cross_sections'] " + "must be set") tree = ET.parse(path) root = tree.getroot() @@ -166,7 +181,6 @@ def from_xml(cls, path=None): data.libraries.append(library) # get depletion chain data - dep_node = root.find("depletion_chain") if dep_node is not None: filename = os.path.join(directory, dep_node.attrib['path']) diff --git a/openmc/data/mass16.txt b/openmc/data/mass16.txt deleted file mode 100644 index 4b479be459b..00000000000 --- a/openmc/data/mass16.txt +++ /dev/null @@ -1,3475 +0,0 @@ -1 a0boogfu A T O M I C M A S S A D J U S T M E N T -0 DATE 1 Mar 2017 TIME 17:26 -0 ********************* A= 0 TO 295 - * file : mass16.txt * - ********************* - - This is one file out of a series of 3 files published in: - "The Ame2016 atomic mass evaluation (I)" by W.J.Huang, G.Audi, M.Wang, F.G.Kondev, S.Naimi and X.Xu - Chinese Physics C41 030002, March 2017. - "The Ame2016 atomic mass evaluation (II)" by M.Wang, G.Audi, F.G.Kondev, W.J.Huang, S.Naimi and X.Xu - Chinese Physics C41 030003, March 2017. - for files : mass16.txt : atomic masses - rct1-16.txt : react and sep energies, part 1 - rct2-16.txt : react and sep energies, part 2 - A fourth file is the "Rounded" version of the atomic mass table (the first file) - mass16round.txt : atomic masses "Rounded" version - - All files are 3436 lines long with 124 character per line. - Headers are 39 lines long. - Values in files 1, 2 and 3 are unrounded copy of the published ones - Values in file 4 are exact copy of the published ones - - col 1 : Fortran character control: 1 = page feed 0 = line feed - format : a1,i3,i5,i5,i5,1x,a3,a4,1x,f13.5,f11.5,f11.3,f9.3,1x,a2,f11.3,f9.3,1x,i3,1x,f12.5,f11.5 - cc NZ N Z A el o mass unc binding unc B beta unc atomic_mass unc - Warnings : this format is identical to the ones used in Ame2003 and Ame2012 - in particular "Mass Excess" and "Atomic Mass" values are given now, when necessary, - with 5 digits after decimal point. - decimal point is replaced by # for (non-experimental) estimated values. - * in place of value : not calculable - -....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+...10....+...11....+...12.... - - - MASS LIST - for analysis - -1N-Z N Z A EL O MASS EXCESS BINDING ENERGY/A BETA-DECAY ENERGY ATOMIC MASS - (keV) (keV) (keV) (micro-u) -0 1 1 0 1 n 8071.31713 0.00046 0.0 0.0 B- 782.347 0.000 1 008664.91582 0.00049 - -1 0 1 1 H 7288.97061 0.00009 0.0 0.0 B- * 1 007825.03224 0.00009 -0 0 1 1 2 H 13135.72176 0.00011 1112.283 0.000 B- * 2 014101.77811 0.00012 -0 1 2 1 3 H 14949.80993 0.00022 2827.265 0.000 B- 18.592 0.000 3 016049.28199 0.00023 - -1 1 2 3 He 14931.21793 0.00021 2572.680 0.000 B- -13736# 2000# 3 016029.32265 0.00022 - -3 0 3 3 Li -pp 28667# 2000# -2267# 667# B- * 3 030775# 2147# -0 2 3 1 4 H -n 24621.127 100.000 1720.449 25.000 B- 22196.211 100.000 4 026431.868 107.354 - 0 2 2 4 He 2424.91561 0.00006 7073.915 0.000 B- -22898.273 212.132 4 002603.25413 0.00006 - -2 1 3 4 Li -p 25323.189 212.132 1153.760 53.033 B- * 4 027185.562 227.733 -0 3 4 1 5 H -nn 32892.444 89.443 1336.359 17.889 B- 21661.211 91.652 5 035311.493 96.020 - 1 3 2 5 He -n 11231.233 20.000 5512.132 4.000 B- -447.654 53.852 5 012057.224 21.470 - -1 2 3 5 Li -p 11678.886 50.000 5266.132 10.000 B- -25460# 2003# 5 012537.800 53.677 - -3 1 4 5 Be x 37139# 2003# 18# 401# B- * 5 039870# 2150# -0 4 5 1 6 H -3n 41875.721 254.127 961.639 42.354 B- 24283.626 254.127 6 044955.437 272.816 - 2 4 2 6 He 17592.095 0.053 4878.519 0.009 B- 3505.216 0.053 6 018885.891 0.057 - 0 3 3 6 Li 14086.87895 0.00144 5332.331 0.000 B- -4288.154 5.448 6 015122.88742 0.00155 - -2 2 4 6 Be - 18375.033 5.448 4487.247 0.908 B- -28945# 2003# 6 019726.409 5.848 - -4 1 5 6 B x 47320# 2003# -467# 334# B- * 6 050800# 2150# -0 5 6 1 7 H -nn 49135# 1004# 940# 143# B- 23062# 1004# 7 052749# 1078# - 3 5 2 7 He -n 26073.126 7.559 4123.057 1.080 B- 11166.021 7.559 7 027990.654 8.115 - 1 4 3 7 Li 14907.10529 0.00423 5606.439 0.001 B- -861.893 0.071 7 016003.43666 0.00454 - -1 3 4 7 Be 15768.999 0.071 5371.548 0.010 B- -11907.551 25.150 7 016928.717 0.076 - -3 2 5 7 B p4n 27676.550 25.150 3558.705 3.593 B- * 7 029712.000 27.000 -0 4 6 2 8 He 31609.681 0.089 3924.520 0.011 B- 10663.878 0.100 8 033934.390 0.095 - 2 5 3 8 Li 20945.804 0.047 5159.712 0.006 B- 16004.133 0.059 8 022486.246 0.050 - 0 4 4 8 Be -a 4941.671 0.035 7062.435 0.004 B- -17979.896 1.000 8 005305.102 0.037 - -2 3 5 8 B 22921.567 1.000 4717.155 0.125 B- -12142.701 18.270 8 024607.316 1.073 - -4 2 6 8 C 35064.268 18.243 3101.524 2.280 B- * 8 037643.042 19.584 -0 5 7 2 9 He 40935.826 46.816 3349.037 5.202 B- 15980.924 46.817 9 043946.419 50.259 - 3 6 3 9 Li -3n 24954.902 0.186 5037.768 0.021 B- 13606.449 0.201 9 026790.191 0.200 - 1 5 4 9 Be 11348.453 0.077 6462.668 0.009 B- -1068.035 0.899 9 012183.066 0.082 - -1 4 5 9 B - 12416.488 0.903 6257.070 0.100 B- -16494.484 2.319 9 013329.649 0.969 - -3 3 6 9 C -pp 28910.972 2.137 4337.423 0.237 B- * 9 031037.207 2.293 -0 6 8 2 10 He -nn 49197.143 92.848 2995.134 9.285 B- 16144.519 93.715 10 052815.308 99.676 - 4 7 3 10 Li -n 33052.624 12.721 4531.351 1.272 B- 20445.136 12.722 10 035483.453 13.656 - 2 6 4 10 Be 12607.488 0.081 6497.630 0.008 B- 556.878 0.082 10 013534.695 0.086 - 0 5 5 10 B 12050.609 0.015 6475.083 0.002 B- -3648.062 0.069 10 012936.862 0.016 - -2 4 6 10 C 15698.672 0.070 6032.042 0.007 B- -23101.355 400.000 10 016853.218 0.075 - -4 3 7 10 N -- 38800.026 400.000 3643.672 40.000 B- * 10 041653.543 429.417 -0 5 8 3 11 Li x 40728.254 0.615 4155.381 0.056 B- 20551.087 0.659 11 043723.581 0.660 - 3 7 4 11 Be 20177.167 0.238 5952.540 0.022 B- 11509.460 0.238 11 021661.081 0.255 - 1 6 5 11 B 8667.707 0.012 6927.732 0.001 B- -1981.689 0.061 11 009305.166 0.013 - -1 5 6 11 C 10649.396 0.060 6676.456 0.005 B- -13654.163 46.154 11 011432.597 0.064 - -3 4 7 11 N -p 24303.559 46.154 5364.046 4.196 B- * 11 026090.945 49.548 -0 6 9 3 12 Li -n 49009.571 30.006 3791.600 2.501 B- 23931.812 30.067 12 052613.941 32.213 - 4 8 4 12 Be 25077.760 1.909 5720.722 0.159 B- 11708.363 2.321 12 026922.083 2.048 - 2 7 5 12 B 13369.397 1.321 6631.223 0.110 B- 13369.397 1.321 12 014352.638 1.418 - 0 6 6 12 C 0.0 0.0 7680.144 0.000 B- -17338.068 1.000 12 000000.0 0.0 - -2 5 7 12 N 17338.068 1.000 6170.109 0.083 B- -14576.544 24.021 12 018613.182 1.073 - -4 4 8 12 O -pp 31914.613 24.000 4890.202 2.000 B- * 12 034261.747 25.765 -0 7 10 3 13 Li -nn 56980.888 70.003 3507.630 5.385 B- 23321.812 70.739 13 061171.503 75.150 - 5 9 4 13 Be -n 33659.077 10.180 5241.435 0.783 B- 17097.130 10.230 13 036134.507 10.929 - 3 8 5 13 B -nn 16561.947 1.000 6496.419 0.077 B- 13436.938 1.000 13 017779.981 1.073 - 1 7 6 13 C 3125.00888 0.00021 7469.849 0.000 B- -2220.472 0.270 13 003354.83521 0.00023 - -1 6 7 13 N 5345.481 0.270 7238.863 0.021 B- -17769.951 9.530 13 005738.609 0.289 - -3 5 8 13 O +3n 23115.432 9.526 5811.763 0.733 B- * 13 024815.437 10.226 -0 6 10 4 14 Be x 39954.498 132.245 4993.897 9.446 B- 16290.813 133.936 14 042892.920 141.970 - 4 9 5 14 B 23663.685 21.213 6101.644 1.515 B- 20643.792 21.213 14 025404.012 22.773 - 2 8 6 14 C 3019.89278 0.00376 7520.319 0.000 B- 156.476 0.004 14 003241.98843 0.00403 - 0 7 7 14 N 2863.41672 0.00019 7475.614 0.000 B- -5144.364 0.025 14 003074.00446 0.00021 - -2 6 8 14 O 8007.781 0.025 7052.278 0.002 B- -23956.622 41.119 14 008596.706 0.027 - -4 5 9 14 F -p 31964.402 41.119 5285.208 2.937 B- * 14 034315.199 44.142 -0 7 11 4 15 Be -n 49825.815 165.797 4540.970 11.053 B- 20867.573 167.126 15 053490.215 177.990 - 5 10 5 15 B 28958.242 21.032 5879.985 1.402 B- 19085.098 21.047 15 031087.953 22.578 - 3 9 6 15 C -n 9873.144 0.800 7100.169 0.053 B- 9771.705 0.800 15 010599.256 0.858 - 1 8 7 15 N 101.43871 0.00060 7699.460 0.000 B- -2754.166 0.491 15 000108.89894 0.00065 - -1 7 8 15 O 2855.605 0.491 7463.692 0.033 B- -13711.146 14.009 15 003065.618 0.526 - -3 6 9 15 F -p 16566.751 14.000 6497.459 0.933 B- -23648.622 68.138 15 017785.139 15.029 - -5 5 10 15 Ne -pp 40215.373 66.684 4868.728 4.446 B- * 15 043172.980 71.588 -0 8 12 4 16 Be -nn 57447.132 165.797 4285.285 10.362 B- 20334.623 167.608 16 061672.036 177.990 - 6 11 5 16 B 37112.510 24.569 5507.302 1.536 B- 23418.378 24.828 16 039841.920 26.375 - 4 10 6 16 C -nn 13694.132 3.578 6922.054 0.224 B- 8010.225 4.254 16 014701.256 3.840 - 2 9 7 16 N -n 5683.907 2.301 7373.796 0.144 B- 10420.908 2.301 16 006101.925 2.470 - 0 8 8 16 O -4737.00135 0.00016 7976.206 0.000 B- -15417.254 8.321 15 994914.61960 0.00017 - -2 7 9 16 F - 10680.253 8.321 6963.731 0.520 B- -13306.523 22.106 16 011465.723 8.932 - -4 6 10 16 Ne -- 23986.776 20.480 6083.177 1.280 B- * 16 025750.864 21.986 -0 7 12 5 17 B x 43716.317 204.104 5269.667 12.006 B- 22684.419 204.841 17 046931.399 219.114 - 5 11 6 17 C 2p-n 21031.898 17.365 6558.024 1.021 B- 13161.820 22.946 17 022578.672 18.641 - 3 10 7 17 N +p 7870.079 15.000 7286.229 0.882 B- 8678.842 15.000 17 008448.877 16.103 - 1 9 8 17 O -808.76348 0.00066 7750.728 0.000 B- -2760.465 0.248 16 999131.75664 0.00070 - -1 8 9 17 F 1951.702 0.248 7542.328 0.015 B- -14548.746 0.432 17 002095.238 0.266 - -3 7 10 17 Ne 16500.447 0.354 6640.499 0.021 B- -18672.766 1001.356 17 017713.959 0.380 - -5 6 11 17 Na x 35173.214 1001.356 5496.080 58.903 B- * 17 037760.000 1075.000 -0 8 13 5 18 B -n 51792.634 204.165 4976.630 11.342 B- 26873.370 206.357 18 055601.682 219.180 - 6 12 6 18 C ++ 24919.264 30.000 6426.131 1.667 B- 11806.096 35.282 18 026751.932 32.206 - 4 11 7 18 N + 13113.168 18.570 7038.562 1.032 B- 13895.984 18.570 18 014077.565 19.935 - 2 10 8 18 O -782.81560 0.00071 7767.097 0.000 B- -1655.929 0.463 17 999159.61284 0.00076 - 0 9 9 18 F 873.113 0.463 7631.638 0.026 B- -4444.501 0.589 18 000937.325 0.497 - -2 8 10 18 Ne 5317.614 0.363 7341.257 0.020 B- -19720.374 93.882 18 005708.693 0.390 - -4 7 11 18 Na 25037.988 93.881 6202.217 5.216 B- * 18 026879.386 100.785 -0 9 14 5 19 B x 59770.244 525.363 4719.634 27.651 B- 27356.492 534.496 19 064166.000 564.000 - 7 13 6 19 C -n 32413.752 98.389 6118.273 5.178 B- 16557.471 99.748 19 034797.596 105.625 - 5 12 7 19 N p-2n 15856.282 16.404 6948.543 0.863 B- 12523.424 16.614 19 017022.419 17.610 - 3 11 8 19 O -n 3332.858 2.637 7566.495 0.139 B- 4820.302 2.637 19 003577.970 2.830 - 1 10 9 19 F -1487.44420 0.00086 7779.018 0.000 B- -3239.494 0.160 18 998403.16288 0.00093 - -1 9 10 19 Ne +3n 1752.050 0.160 7567.343 0.008 B- -11177.340 10.536 19 001880.903 0.171 - -3 8 11 19 Na 12929.390 10.535 6937.885 0.554 B- -18898.998 51.099 19 013880.272 11.309 - -5 7 12 19 Mg -pp 31828.389 50.001 5902.025 2.632 B- * 19 034169.182 53.678 -0 10 15 5 20 B x 68450# 800# 4453# 40# B- 30946# 833# 20 073484# 859# - 8 14 6 20 C x 37503.563 230.625 5961.435 11.531 B- 15737.067 243.746 20 040261.732 247.585 - 6 13 7 20 N x 21766.496 78.894 6709.171 3.945 B- 17970.324 78.899 20 023367.295 84.696 - 4 12 8 20 O -nn 3796.172 0.885 7568.570 0.044 B- 3813.635 0.885 20 004075.358 0.950 - 2 11 9 20 F -n -17.463 0.030 7720.134 0.002 B- 7024.467 0.030 19 999981.252 0.031 - 0 10 10 20 Ne -7041.93055 0.00157 8032.240 0.000 B- -13892.535 1.114 19 992440.17619 0.00168 - -2 9 11 20 Na 6850.604 1.114 7298.496 0.056 B- -10627.088 2.171 20 007354.426 1.195 - -4 8 12 20 Mg +t 17477.692 1.863 6728.025 0.093 B- * 20 018763.075 2.000 -0 11 16 5 21 B x 77330# 900# 4203# 43# B- 31687# 1079# 21 083017# 966# - 9 15 6 21 C x 45643# 596# 5674# 28# B- 20411# 611# 21 049000# 640# - 7 14 7 21 N x 25231.913 134.048 6609.015 6.383 B- 17169.878 134.584 21 027087.573 143.906 - 5 13 8 21 O -3n 8062.035 12.000 7389.374 0.571 B- 8109.640 12.134 21 008654.950 12.882 - 3 12 9 21 F -nn -47.605 1.800 7738.293 0.086 B- 5684.171 1.800 20 999948.894 1.932 - 1 11 10 21 Ne -5731.776 0.038 7971.713 0.002 B- -3547.145 0.090 20 993846.685 0.041 - -1 10 11 21 Na -2184.631 0.098 7765.547 0.005 B- -13088.480 0.761 20 997654.702 0.105 - -3 9 12 21 Mg x 10903.850 0.755 7105.031 0.036 B- -16086# 596# 21 011705.764 0.810 - -5 8 13 21 Al x 26990# 596# 6302# 28# B- * 21 028975# 640# -0 10 16 6 22 C -nn 53611.197 231.490 5421.077 10.522 B- 21846.396 311.063 22 057553.990 248.515 - 8 15 7 22 N x 31764.801 207.779 6378.534 9.445 B- 22481.768 215.435 22 034100.918 223.060 - 6 14 8 22 O -4n 9283.033 56.921 7364.871 2.587 B- 6489.660 58.256 22 009965.746 61.107 - 4 13 9 22 F + 2793.373 12.399 7624.295 0.564 B- 10818.092 12.399 22 002998.809 13.310 - 2 12 10 22 Ne -8024.719 0.018 8080.465 0.001 B- -2843.207 0.171 21 991385.109 0.018 - 0 11 11 22 Na -5181.511 0.171 7915.667 0.008 B- -4781.578 0.321 21 994437.418 0.183 - -2 10 12 22 Mg -399.933 0.313 7662.761 0.014 B- -18601# 401# 21 999570.654 0.335 - -4 9 13 22 Al x 18201# 401# 6782# 18# B- -15137# 643# 22 019540# 430# - -6 8 14 22 Si x 33338# 503# 6058# 23# B- * 22 035790# 540# -0 11 17 6 23 C x 64171# 997# 5077# 43# B- 27450# 1082# 23 068890# 1070# - 9 16 7 23 N x 36720.425 420.570 6236.671 18.286 B- 22099.056 437.827 23 039421.000 451.500 - 7 15 8 23 O x 14621.369 121.712 7163.485 5.292 B- 11336.106 126.190 23 015696.686 130.663 - 5 14 9 23 F 3285.263 33.320 7622.344 1.449 B- 8439.312 33.321 23 003526.874 35.770 - 3 13 10 23 Ne -n -5154.049 0.104 7955.256 0.005 B- 4375.804 0.104 22 994466.900 0.112 - 1 12 11 23 Na -9529.85248 0.00181 8111.493 0.000 B- -4056.340 0.158 22 989769.28199 0.00194 - -1 11 12 23 Mg - -5473.513 0.158 7901.115 0.007 B- -12221.583 0.379 22 994123.941 0.170 - -3 10 13 23 Al -- 6748.070 0.345 7335.727 0.015 B- -16949# 503# 23 007244.351 0.370 - -5 9 14 23 Si x 23697# 503# 6565# 22# B- * 23 025440# 540# -0 10 17 7 24 N x 46938# 401# 5887# 17# B- 28438# 433# 24 050390# 430# - 8 16 8 24 O x 18500.402 164.874 7039.685 6.870 B- 10955.887 191.633 24 019861.000 177.000 - 6 15 9 24 F x 7544.515 97.670 7463.582 4.070 B- 13496.161 97.672 24 008099.370 104.853 - 4 14 10 24 Ne -nn -5951.646 0.513 7993.325 0.021 B- 2466.255 0.513 23 993610.645 0.550 - 2 13 11 24 Na -n -8417.901 0.017 8063.488 0.001 B- 5515.669 0.021 23 990963.011 0.017 - 0 12 12 24 Mg -13933.569 0.013 8260.709 0.001 B- -13884.704 0.233 23 985041.697 0.014 - -2 11 13 24 Al ep -48.865 0.233 7649.582 0.010 B- -10794.060 19.473 23 999947.541 0.250 - -4 10 14 24 Si -- 10745.195 19.472 7167.232 0.811 B- -22574# 503# 24 011535.441 20.904 - -6 9 15 24 P x 33320# 503# 6194# 21# B- * 24 035770# 540# -0 11 18 7 25 N x 55983# 503# 5613# 20# B- 28654# 529# 25 060100# 540# - 9 17 8 25 O -n 27329.027 165.084 6727.805 6.603 B- 15994.862 191.191 25 029338.919 177.225 - 7 16 9 25 F x 11334.166 96.442 7336.306 3.858 B- 13369.667 100.721 25 012167.727 103.535 - 5 15 10 25 Ne -2035.502 29.045 7839.799 1.162 B- 7322.312 29.070 24 997814.799 31.181 - 3 14 11 25 Na -nn -9357.813 1.200 8101.397 0.048 B- 3834.969 1.201 24 989953.973 1.288 - 1 13 12 25 Mg -13192.783 0.047 8223.502 0.002 B- -4276.808 0.045 24 985836.964 0.050 - -1 12 13 25 Al -8915.975 0.065 8021.136 0.003 B- -12743.299 10.000 24 990428.306 0.069 - -3 11 14 25 Si +3n 3827.324 10.000 7480.110 0.400 B- -15911# 401# 25 004108.801 10.735 - -5 10 15 25 P x 19738# 401# 6812# 16# B- * 25 021190# 430# -0 10 18 8 26 O -nn 34661.037 164.950 6497.478 6.344 B- 16012.161 198.932 26 037210.155 177.081 - 8 17 9 26 F x 18648.875 111.199 7083.240 4.277 B- 18167.762 112.716 26 020020.392 119.377 - 6 16 10 26 Ne x 481.114 18.429 7751.910 0.709 B- 7341.893 18.758 26 000516.496 19.784 - 4 15 11 26 Na x -6860.780 3.502 8004.201 0.135 B- 9353.763 3.502 25 992634.649 3.759 - 2 14 12 26 Mg -16214.542 0.030 8333.870 0.001 B- -4004.391 0.063 25 982592.971 0.032 - 0 13 13 26 Al -12210.151 0.067 8149.765 0.003 B- -5069.136 0.085 25 986891.863 0.071 - -2 12 14 26 Si - -7141.015 0.108 7924.708 0.004 B- -18114# 196# 25 992333.804 0.115 - -4 11 15 26 P x 10973# 196# 7198# 8# B- -16106# 627# 26 011780# 210# - -6 10 16 26 S x 27079# 596# 6548# 23# B- * 26 029070# 640# -0 11 19 8 27 O x 44670# 500# 6185# 19# B- 19220# 634# 27 047955# 537# - 9 18 9 27 F x 25450.279 389.830 6867.932 14.438 B- 18399.370 400.258 27 027322.000 418.500 - 7 17 10 27 Ne x 7050.909 90.770 7520.414 3.362 B- 12568.699 90.847 27 007569.462 97.445 - 5 16 11 27 Na ++ -5517.790 3.726 7956.946 0.138 B- 9068.821 3.727 26 994076.408 4.000 - 3 15 12 27 Mg -n -14586.611 0.050 8263.852 0.002 B- 2610.251 0.069 26 984340.628 0.053 - 1 14 13 27 Al -17196.861 0.047 8331.553 0.002 B- -4812.359 0.096 26 981538.408 0.050 - -1 13 14 27 Si - -12384.503 0.107 8124.341 0.004 B- -11662.044 26.340 26 986704.688 0.115 - -3 12 15 27 P p4n -722.458 26.340 7663.438 0.976 B- -17750# 400# 26 999224.409 28.277 - -5 11 16 27 S - 17028# 401# 6977# 15# B- * 27 018280# 430# -0 12 20 8 28 O x 52080# 699# 5988# 25# B- 18338# 802# 28 055910# 750# - 10 19 9 28 F -n 33741.596 393.024 6614.792 14.037 B- 22441.859 412.748 28 036223.095 421.928 - 8 18 10 28 Ne x 11299.737 126.068 7388.346 4.502 B- 12288.052 126.483 28 012130.767 135.339 - 6 17 11 28 Na x -988.315 10.246 7799.264 0.366 B- 14030.529 10.440 27 998939.000 11.000 - 4 16 12 28 Mg + -15018.845 2.001 8272.413 0.071 B- 1831.800 2.000 27 983876.606 2.148 - 2 15 13 28 Al -n -16850.645 0.077 8309.894 0.003 B- 4642.150 0.077 27 981910.087 0.083 - 0 14 14 28 Si -21492.79430 0.00049 8447.744 0.000 B- -14345.055 1.152 27 976926.53499 0.00052 - -2 13 15 28 P -7147.740 1.152 7907.479 0.041 B- -11220.945 160.004 27 992326.585 1.236 - -4 12 16 28 S -- 4073.206 160.000 7478.790 5.714 B- -23443# 617# 28 004372.766 171.767 - -6 11 17 28 Cl x 27516# 596# 6614# 21# B- * 28 029540# 640# -0 11 20 9 29 F x 40150.186 525.363 6444.031 18.116 B- 21750.385 546.221 29 043103.000 564.000 - 9 19 10 29 Ne x 18399.801 149.505 7167.067 5.155 B- 15719.807 149.685 29 019753.000 160.500 - 7 18 11 29 Na 2679.994 7.337 7682.151 0.253 B- 13282.824 13.557 29 002877.092 7.876 - 5 17 12 29 Mg x -10602.829 11.400 8113.202 0.393 B- 7604.931 11.405 28 988617.393 12.238 - 3 16 13 29 Al x -18207.760 0.345 8348.464 0.012 B- 3687.318 0.345 28 980453.164 0.370 - 1 15 14 29 Si -21895.07838 0.00056 8448.635 0.000 B- -4942.230 0.359 28 976494.66525 0.00060 - -1 14 15 29 P -16952.848 0.359 8251.236 0.012 B- -13796.432 50.001 28 981800.368 0.385 - -3 13 16 29 S +3n -3156.416 50.000 7748.520 1.724 B- -16318.592 195.192 28 996611.448 53.677 - -5 12 17 29 Cl -p 13162.176 188.680 7158.832 6.506 B- * 29 014130.178 202.555 -0 12 21 9 30 F x 48112# 596# 6233# 20# B- 24832# 648# 30 051650# 640# - 10 20 10 30 Ne 23280.117 253.250 7034.531 8.442 B- 14805.448 253.295 30 024992.235 271.875 - 8 19 11 30 Na 8474.670 4.727 7501.968 0.158 B- 17358.490 5.850 30 009097.932 5.074 - 6 18 12 30 Mg x -8883.820 3.447 8054.506 0.115 B- 6981.024 4.496 29 990462.826 3.700 - 4 17 13 30 Al x -15864.844 2.888 8261.128 0.096 B- 8568.116 2.888 29 982968.388 3.100 - 2 16 14 30 Si -n -24432.960 0.022 8520.654 0.001 B- -4232.106 0.061 29 973770.136 0.023 - 0 15 15 30 P - -20200.854 0.065 8353.506 0.002 B- -6141.601 0.196 29 978313.489 0.069 - -2 14 16 30 S - -14059.253 0.206 8122.707 0.007 B- -18502# 196# 29 984906.769 0.221 - -4 13 17 30 Cl x 4443# 196# 7480# 7# B- -16488# 284# 30 004770# 210# - -6 12 18 30 Ar -pp 20931.147 206.155 6904.204 6.872 B- * 30 022470.511 221.316 -0 13 22 9 31 F -nn 56143# 546# 6033# 18# B- 24961# 608# 31 060272# 587# - 11 21 10 31 Ne 31181.591 266.195 6813.090 8.587 B- 18935.559 266.562 31 033474.816 285.772 - 9 20 11 31 Na x 12246.031 13.972 7398.677 0.451 B- 15368.182 14.307 31 013146.656 15.000 - 7 19 12 31 Mg x -3122.151 3.074 7869.188 0.099 B- 11828.555 3.801 30 996648.232 3.300 - 5 18 13 31 Al x -14950.706 2.236 8225.517 0.072 B- 7998.330 2.236 30 983949.756 2.400 - 3 17 14 31 Si -n -22949.036 0.043 8458.291 0.001 B- 1491.505 0.043 30 975363.194 0.046 - 1 16 15 31 P -24440.54095 0.00067 8481.167 0.000 B- -5398.016 0.229 30 973761.99863 0.00072 - -1 15 16 31 S -19042.525 0.229 8281.800 0.007 B- -12007.974 3.454 30 979557.007 0.246 - -3 14 17 31 Cl -- -7034.551 3.447 7869.209 0.111 B- -18360# 200# 30 992448.098 3.700 - -5 13 18 31 Ar - 11325# 200# 7252# 6# B- * 31 012158# 215# -0 12 22 10 32 Ne x 36999# 503# 6671# 16# B- 18359# 504# 32 039720# 540# - 10 21 11 32 Na x 18640.151 37.260 7219.881 1.164 B- 19469.051 37.402 32 020011.026 40.000 - 8 20 12 32 Mg x -828.900 3.260 7803.840 0.102 B- 10270.467 7.879 31 999110.139 3.500 - 6 19 13 32 Al x -11099.367 7.173 8100.344 0.224 B- 12978.319 7.179 31 988084.339 7.700 - 4 18 14 32 Si x -24077.686 0.298 8481.468 0.009 B- 227.188 0.301 31 974151.539 0.320 - 2 17 15 32 P -n -24304.874 0.040 8464.120 0.001 B- 1710.660 0.040 31 973907.643 0.042 - 0 16 16 32 S -26015.53355 0.00132 8493.129 0.000 B- -12680.860 0.562 31 972071.17443 0.00141 - -2 15 17 32 Cl -13334.674 0.562 8072.404 0.018 B- -11134.323 1.857 31 985684.637 0.603 - -4 14 18 32 Ar x -2200.351 1.770 7700.008 0.055 B- -23299# 401# 31 997637.826 1.900 - -6 13 19 32 K x 21098# 401# 6947# 13# B- * 32 022650# 430# -0 13 23 10 33 Ne x 45997# 596# 6440# 18# B- 22217# 747# 33 049380# 640# - 11 22 11 33 Na x 23780.110 449.912 7089.926 13.634 B- 18817.813 449.921 33 025529.000 483.000 - 9 21 12 33 Mg x 4962.297 2.888 7636.455 0.088 B- 13459.677 7.559 33 005327.245 3.100 - 7 20 13 33 Al x -8497.380 6.986 8020.616 0.212 B- 12016.945 7.021 32 990877.687 7.500 - 5 19 14 33 Si x -20514.325 0.699 8361.059 0.021 B- 5823.021 1.295 32 977976.964 0.750 - 3 18 15 33 P + -26337.346 1.090 8513.806 0.033 B- 248.508 1.090 32 971725.694 1.170 - 1 17 16 33 S -26585.85434 0.00135 8497.630 0.000 B- -5582.517 0.391 32 971458.90985 0.00145 - -1 16 17 33 Cl -21003.337 0.391 8304.755 0.012 B- -11619.044 0.560 32 977451.989 0.419 - -3 15 18 33 Ar x -9384.292 0.401 7928.955 0.012 B- -16426# 196# 32 989925.547 0.430 - -5 14 19 33 K x 7042# 196# 7407# 6# B- * 33 007560# 210# -0 14 24 10 34 Ne -nn 52842# 513# 6287# 15# B- 21161# 789# 34 056728# 551# - 12 23 11 34 Na x 31680.111 599.416 6886.437 17.630 B- 23356.764 600.112 34 034010.000 643.500 - 10 22 12 34 Mg x 8323.348 28.876 7550.390 0.849 B- 11323.637 29.039 34 008935.481 31.000 - 8 21 13 34 Al x -3000.289 3.074 7860.428 0.090 B- 16956.563 14.448 33 996779.057 3.300 - 6 20 14 34 Si +pp -19956.852 14.118 8336.141 0.415 B- 4591.847 14.141 33 978575.437 15.155 - 4 19 15 34 P x -24548.698 0.810 8448.185 0.024 B- 5382.987 0.812 33 973645.887 0.870 - 2 18 16 34 S -29931.685 0.045 8583.498 0.001 B- -5491.603 0.038 33 967867.012 0.047 - 0 17 17 34 Cl -24440.082 0.049 8398.970 0.001 B- -6061.792 0.063 33 973762.491 0.052 - -2 16 18 34 Ar -18378.290 0.078 8197.672 0.002 B- -17158# 196# 33 980270.093 0.083 - -4 15 19 34 K x -1220# 196# 7670# 6# B- -15072# 357# 33 998690# 210# - -6 14 20 34 Ca x 13851# 298# 7204# 9# B- * 34 014870# 320# -0 13 24 11 35 Na -n 38231# 670# 6733# 19# B- 22592# 723# 35 041043# 720# - 11 23 12 35 Mg x 15639.784 269.668 7356.233 7.705 B- 15863.512 269.768 35 016790.000 289.500 - 9 22 13 35 Al x -223.728 7.359 7787.124 0.210 B- 14167.729 36.605 34 999759.817 7.900 - 7 21 14 35 Si 2p-n -14391.457 35.857 8169.563 1.024 B- 10466.342 35.905 34 984550.134 38.494 - 5 20 15 35 P +p -24857.799 1.866 8446.249 0.053 B- 3988.407 1.867 34 973314.053 2.003 - 3 19 16 35 S -28846.206 0.040 8537.850 0.001 B- 167.322 0.026 34 969032.322 0.043 - 1 18 17 35 Cl -29013.528 0.035 8520.278 0.001 B- -5966.243 0.679 34 968852.694 0.038 - -1 17 18 35 Ar - -23047.284 0.680 8327.461 0.019 B- -11874.394 0.852 34 975257.721 0.730 - -3 16 19 35 K 4n -11172.891 0.512 7965.840 0.015 B- -15961# 196# 34 988005.407 0.550 - -5 15 20 35 Ca x 4788# 196# 7487# 6# B- * 35 005140# 210# -0 14 25 11 36 Na -n 46303# 678# 6546# 19# B- 25923# 967# 36 049708# 728# - 12 24 12 36 Mg x 20380.157 690.237 7244.419 19.173 B- 14429.774 706.243 36 021879.000 741.000 - 10 23 13 36 Al x 5950.384 149.505 7623.515 4.153 B- 18386.508 165.851 36 006388.000 160.500 - 8 22 14 36 Si x -12436.124 71.797 8112.519 1.994 B- 7814.911 72.985 35 986649.271 77.077 - 6 21 15 36 P + -20251.034 13.114 8307.868 0.364 B- 10413.096 13.112 35 978259.619 14.078 - 4 20 16 36 S -30664.131 0.188 8575.389 0.005 B- -1142.126 0.189 35 967080.699 0.201 - 2 19 17 36 Cl -29522.005 0.036 8521.931 0.001 B- 709.535 0.045 35 968306.822 0.038 - 0 18 18 36 Ar -30231.540 0.027 8519.909 0.001 B- -12814.475 0.342 35 967545.105 0.028 - -2 17 19 36 K -17417.065 0.341 8142.219 0.009 B- -10965.916 40.001 35 981302.010 0.366 - -4 16 20 36 Ca 4n -6451.149 40.000 7815.879 1.111 B- -21802# 301# 35 993074.406 42.941 - -6 15 21 36 Sc x 15351# 298# 7189# 8# B- * 36 016480# 320# -0 15 26 11 37 Na -nn 53534# 687# 6392# 19# B- 25323# 980# 37 057471# 737# - 13 25 12 37 Mg -n 28211.474 698.947 7055.111 18.890 B- 18401.911 721.814 37 030286.265 750.350 - 11 24 13 37 Al x 9809.563 180.244 7531.315 4.871 B- 16381.075 213.168 37 010531.000 193.500 - 9 23 14 37 Si x -6571.511 113.809 7952.903 3.076 B- 12424.486 119.969 36 992945.191 122.179 - 7 22 15 37 P p-2n -18995.998 37.948 8267.555 1.026 B- 7900.419 37.947 36 979606.956 40.738 - 5 21 16 37 S -n -26896.417 0.198 8459.935 0.005 B- 4865.121 0.196 36 971125.507 0.212 - 3 20 17 37 Cl -31761.538 0.052 8570.281 0.001 B- -813.873 0.200 36 965902.584 0.055 - 1 19 18 37 Ar - -30947.664 0.207 8527.139 0.006 B- -6147.465 0.227 36 966776.314 0.221 - -1 18 19 37 K -p -24800.199 0.094 8339.847 0.003 B- -11664.133 0.641 36 973375.889 0.100 - -3 17 20 37 Ca x -13136.066 0.634 8003.456 0.017 B- -16656# 300# 36 985897.852 0.680 - -5 16 21 37 Sc x 3520# 300# 7532# 8# B- * 37 003779# 322# -0 14 26 12 38 Mg x 34074# 503# 6928# 13# B- 17864# 627# 38 036580# 540# - 12 25 13 38 Al x 16209.859 374.461 7377.097 9.854 B- 20380.157 388.847 38 017402.000 402.000 - 10 24 14 38 Si x -4170.299 104.793 7892.829 2.758 B- 10451.265 127.474 37 995523.000 112.500 - 8 23 15 38 P x -14621.563 72.581 8147.274 1.910 B- 12239.640 72.934 37 984303.105 77.918 - 6 22 16 38 S + -26861.203 7.172 8448.782 0.189 B- 2936.900 7.171 37 971163.310 7.699 - 4 21 17 38 Cl -n -29798.103 0.098 8505.481 0.003 B- 4916.718 0.218 37 968010.418 0.105 - 2 20 18 38 Ar -34714.821 0.195 8614.280 0.005 B- -5914.066 0.045 37 962732.104 0.209 - 0 19 19 38 K -28800.755 0.195 8438.058 0.005 B- -6742.256 0.063 37 969081.116 0.209 - -2 18 20 38 Ca -22058.499 0.194 8240.043 0.005 B- -17809# 200# 37 976319.226 0.208 - -4 17 21 38 Sc x -4249# 200# 7751# 5# B- -15119# 361# 37 995438# 215# - -6 16 22 38 Ti x 10870# 300# 7332# 8# B- * 38 011669# 322# -0 15 27 12 39 Mg -n 42275# 513# 6747# 13# B- 21625# 650# 39 045384# 551# - 13 26 13 39 Al x 20650# 400# 7281# 10# B- 18330# 422# 39 022169# 429# - 11 25 14 39 Si x 2320.352 135.532 7730.979 3.475 B- 15094.986 176.232 39 002491.000 145.500 - 9 24 15 39 P x -12774.634 112.645 8097.969 2.888 B- 10388.033 123.243 38 986285.865 120.929 - 7 23 16 39 S 2p-n -23162.667 50.000 8344.269 1.282 B- 6637.538 50.030 38 975133.852 53.677 - 5 22 17 39 Cl -nn -29800.205 1.732 8494.402 0.044 B- 3441.985 5.292 38 968008.162 1.859 - 3 21 18 39 Ar + -33242.190 5.000 8562.598 0.128 B- 565.000 5.000 38 964313.039 5.367 - 1 20 19 39 K -33807.19010 0.00458 8557.025 0.000 B- -6524.488 0.596 38 963706.48661 0.00492 - -1 19 20 39 Ca -27282.702 0.596 8369.670 0.015 B- -13109.993 24.007 38 970710.813 0.640 - -3 18 21 39 Sc 2n-p -14172.709 24.000 8013.456 0.615 B- -16373# 202# 38 984784.970 25.765 - -5 17 22 39 Ti x 2200# 200# 7574# 5# B- * 39 002362# 215# -0 16 28 12 40 Mg x 48350# 500# 6628# 13# B- 20760# 640# 40 051906# 537# - 14 27 13 40 Al x 27590# 400# 7127# 10# B- 22160# 528# 40 029619# 429# - 12 26 14 40 Si x 5429.679 345.119 7661.754 8.628 B- 13544.049 377.749 40 005829.000 370.500 - 10 25 15 40 P x -8114.370 153.582 7980.796 3.840 B- 14723.476 153.633 39 991288.865 164.876 - 8 24 16 40 S -22837.846 3.982 8329.325 0.100 B- 4719.967 32.312 39 975482.562 4.274 - 6 23 17 40 Cl + -27557.813 32.066 8427.765 0.802 B- 7482.082 32.066 39 970415.469 34.423 - 4 22 18 40 Ar -35039.89464 0.00224 8595.259 0.000 B- -1504.403 0.056 39 962383.12378 0.00240 - 2 21 19 40 K -33535.492 0.056 8538.090 0.001 B- 1310.893 0.060 39 963998.166 0.060 - 0 20 20 40 Ca -34846.384 0.021 8551.303 0.001 B- -14323.050 2.828 39 962590.865 0.022 - -2 19 21 40 Sc - -20523.335 2.828 8173.669 0.071 B- -11672.950 160.025 39 977967.292 3.036 - -4 18 22 40 Ti -- -8850.384 160.000 7862.286 4.000 B- -21020# 340# 39 990498.721 171.767 - -6 17 23 40 V x 12170# 300# 7317# 7# B- * 40 013065# 322# -0 15 28 13 41 Al x 33420# 500# 7008# 12# B- 21300# 747# 41 035878# 537# - 13 27 14 41 Si x 12119.668 554.705 7508.573 13.529 B- 17099.435 567.571 41 013011.000 595.500 - 11 26 15 41 P x -4979.767 120.163 7906.551 2.931 B- 14028.810 120.233 40 994654.000 129.000 - 9 25 16 41 S x -19008.577 4.099 8229.635 0.100 B- 8298.611 68.846 40 979593.451 4.400 - 7 24 17 41 Cl x -27307.189 68.723 8412.959 1.676 B- 5760.317 68.724 40 970684.525 73.777 - 5 23 18 41 Ar -n -33067.505 0.347 8534.372 0.008 B- 2492.038 0.347 40 964500.571 0.372 - 3 22 19 41 K -35559.54331 0.00380 8576.072 0.000 B- -421.653 0.138 40 961825.25796 0.00408 - 1 21 20 41 Ca -35137.890 0.138 8546.706 0.003 B- -6495.478 0.158 40 962277.921 0.147 - -1 20 21 41 Sc -28642.412 0.083 8369.198 0.002 B- -12944.875 27.945 40 969251.104 0.088 - -3 19 22 41 Ti x -15697.537 27.945 8034.388 0.682 B- -16018# 202# 40 983148.000 30.000 - -5 18 23 41 V x 320# 200# 7625# 5# B- * 41 000344# 215# -0 16 29 13 42 Al x 40100# 600# 6874# 14# B- 23630# 781# 42 043049# 644# - 14 28 14 42 Si x 16470# 500# 7418# 12# B- 15460# 591# 42 017681# 537# - 12 27 15 42 P x 1009.740 314.379 7767.866 7.485 B- 18647.485 314.392 42 001084.000 337.500 - 10 26 16 42 S x -17637.746 2.794 8193.227 0.067 B- 7194.021 59.681 41 981065.100 3.000 - 8 25 17 42 Cl x -24831.767 59.616 8345.886 1.419 B- 9590.908 59.895 41 973342.000 64.000 - 6 24 18 42 Ar x -34422.675 5.775 8555.613 0.138 B- 599.351 5.776 41 963045.736 6.200 - 4 23 19 42 K -n -35022.026 0.106 8551.256 0.003 B- 3525.219 0.183 41 962402.306 0.113 - 2 22 20 42 Ca -38547.245 0.149 8616.563 0.004 B- -6426.092 0.097 41 958617.828 0.159 - 0 21 21 42 Sc -32121.153 0.169 8444.933 0.004 B- -7016.479 0.224 41 965516.522 0.181 - -2 20 22 42 Ti -25104.674 0.277 8259.247 0.007 B- -17485# 196# 41 973049.022 0.297 - -4 19 23 42 V x -7620# 196# 7824# 5# B- -14350# 445# 41 991820# 210# - -6 18 24 42 Cr x 6730# 400# 7464# 10# B- * 42 007225# 429# -0 17 30 13 43 Al x 47020# 800# 6741# 19# B- 23919# 998# 43 050478# 859# - 15 29 14 43 Si x 23101# 596# 7279# 14# B- 18421# 814# 43 024800# 640# - 13 28 15 43 P x 4679.826 554.705 7689.572 12.900 B- 16875.285 554.727 43 005024.000 595.500 - 11 27 16 43 S x -12195.459 4.970 8063.827 0.116 B- 11964.049 62.058 42 986907.635 5.335 - 9 26 17 43 Cl x -24159.508 61.858 8323.866 1.439 B- 7850.300 62.086 42 974063.700 66.407 - 7 25 18 43 Ar x -32009.808 5.310 8488.237 0.123 B- 4565.581 5.325 42 965636.055 5.700 - 5 24 19 43 K -4n -36575.389 0.410 8576.220 0.010 B- 1833.434 0.469 42 960734.703 0.440 - 3 23 20 43 Ca -38408.822 0.228 8600.663 0.005 B- -2220.720 1.865 42 958766.430 0.244 - 1 22 21 43 Sc -p -36188.102 1.863 8530.825 0.043 B- -6867.020 7.481 42 961150.472 1.999 - -1 21 22 43 Ti -n2p -29321.082 7.245 8352.932 0.168 B- -11404.726 43.457 42 968522.521 7.777 - -3 20 23 43 V x -17916.356 42.849 8069.512 0.996 B- -15946# 402# 42 980766.000 46.000 - -5 19 24 43 Cr x -1970# 400# 7680# 9# B- * 42 997885# 429# -0 16 30 14 44 Si x 28513# 596# 7174# 14# B- 18063# 778# 44 030610# 640# - 14 29 15 44 P x 10450# 500# 7567# 11# B- 19655# 500# 44 011219# 537# - 12 28 16 44 S x -9204.233 5.216 7996.015 0.119 B- 11180.290 136.421 43 990118.848 5.600 - 10 27 17 44 Cl x -20384.523 136.321 8232.332 3.098 B- 12288.731 136.330 43 978116.312 146.346 - 8 26 18 44 Ar x -32673.255 1.584 8493.840 0.036 B- 3108.237 1.638 43 964923.816 1.700 - 6 25 19 44 K x -35781.492 0.419 8546.701 0.010 B- 5687.183 0.530 43 961586.986 0.450 - 4 24 20 44 Ca -41468.675 0.325 8658.175 0.007 B- -3652.690 1.757 43 955481.543 0.348 - 2 23 21 44 Sc -p -37815.985 1.756 8557.379 0.040 B- -267.416 1.890 43 959402.867 1.884 - 0 22 22 44 Ti -a -37548.569 0.700 8533.520 0.016 B- -13432.189 181.643 43 959689.951 0.751 - -2 21 23 44 V x -24116.380 181.641 8210.463 4.128 B- -10756# 351# 43 974110.000 195.000 - -4 20 24 44 Cr x -13360# 300# 7948# 7# B- -20390# 583# 43 985657# 322# - -6 19 25 44 Mn x 7030# 500# 7467# 11# B- * 44 007547# 537# -0 17 31 14 45 Si x 37490# 700# 6995# 16# B- 21890# 860# 45 040247# 751# - 15 30 15 45 P x 15600# 500# 7464# 11# B- 19589# 1150# 45 016747# 537# - 13 29 16 45 S x -3989.589 1035.356 7881.807 23.008 B- 14272.954 1044.271 44 995717.000 1111.500 - 11 28 17 45 Cl x -18262.543 136.163 8181.598 3.026 B- 11508.254 136.164 44 980394.353 146.177 - 9 27 18 45 Ar x -29770.796 0.512 8419.952 0.011 B- 6844.841 0.731 44 968039.733 0.550 - 7 26 19 45 K x -36615.638 0.522 8554.674 0.012 B- 4196.536 0.637 44 960691.493 0.560 - 5 25 20 45 Ca -40812.174 0.366 8630.545 0.008 B- 259.722 0.747 44 956186.326 0.392 - 3 24 21 45 Sc -41071.896 0.675 8618.931 0.015 B- -2062.056 0.509 44 955907.503 0.724 - 1 23 22 45 Ti -39009.840 0.845 8555.722 0.019 B- -7123.824 0.214 44 958121.211 0.907 - -1 22 23 45 V -31886.016 0.872 8380.029 0.019 B- -12371.217 35.408 44 965768.951 0.935 - -3 21 24 45 Cr x -19514.799 35.397 8087.728 0.787 B- -14265# 401# 44 979050.000 38.000 - -5 20 25 45 Mn x -5250# 400# 7753# 9# B- -19012# 565# 44 994364# 429# - -7 19 26 45 Fe -pp 13762# 400# 7313# 9# B- * 45 014774# 429# -0 16 31 15 46 P x 22970# 700# 7317# 15# B- 22630# 860# 46 024659# 751# - 14 30 16 46 S x 340# 500# 7792# 11# B- 14199# 542# 46 000365# 537# - 12 29 17 46 Cl x -13859.398 208.661 8083.480 4.536 B- 15913.528 208.664 45 985121.323 224.006 - 10 28 18 46 Ar x -29772.926 1.118 8412.419 0.024 B- 5640.997 1.333 45 968037.446 1.200 - 8 27 19 46 K x -35413.924 0.727 8518.042 0.016 B- 7725.438 2.350 45 961981.586 0.780 - 6 26 20 46 Ca -43139.361 2.235 8668.979 0.049 B- -1378.143 2.333 45 953687.988 2.399 - 4 25 21 46 Sc -n -41761.219 0.683 8622.012 0.015 B- 2366.581 0.667 45 955167.485 0.732 - 2 24 22 46 Ti -44127.799 0.165 8656.451 0.004 B- -7052.449 0.093 45 952626.856 0.176 - 0 23 23 46 V -37075.351 0.202 8486.130 0.004 B- -7603.784 11.455 45 960197.971 0.216 - -2 22 24 46 Cr -29471.567 11.453 8303.823 0.249 B- -16902# 400# 45 968360.970 12.295 - -4 21 25 46 Mn x -12570# 400# 7919# 9# B- -13480# 640# 45 986506# 429# - -6 20 26 46 Fe x 910# 500# 7609# 11# B- * 46 000977# 537# -0 17 32 15 47 P x 29710# 800# 7190# 17# B- 22340# 944# 47 031895# 859# - 15 31 16 47 S x 7370# 500# 7648# 11# B- 17150# 640# 47 007912# 537# - 13 30 17 47 Cl x -9780# 400# 7996# 9# B- 15587# 400# 46 989501# 429# - 11 29 18 47 Ar x -25366.338 1.118 8311.404 0.024 B- 10345.638 1.789 46 972768.114 1.200 - 9 28 19 47 K x -35711.976 1.397 8514.879 0.030 B- 6632.442 2.625 46 961661.614 1.500 - 7 27 20 47 Ca -42344.418 2.222 8639.349 0.047 B- 1992.177 1.185 46 954541.394 2.385 - 5 26 21 47 Sc -44336.595 1.933 8665.090 0.041 B- 600.769 1.929 46 952402.704 2.074 - 3 25 22 47 Ti -44937.364 0.115 8661.227 0.002 B- -2930.746 0.138 46 951757.752 0.123 - 1 24 23 47 V -42006.618 0.169 8582.225 0.004 B- -7444.040 6.032 46 954904.038 0.181 - -1 23 24 47 Cr -34562.578 6.030 8407.195 0.128 B- -11996.204 32.240 46 962895.544 6.473 - -3 22 25 47 Mn x -22566.374 31.671 8135.311 0.674 B- -15697# 501# 46 975774.000 34.000 - -5 21 26 47 Fe x -6870# 500# 7785# 11# B- -17240# 781# 46 992625# 537# - -7 20 27 47 Co x 10370# 600# 7401# 13# B- * 47 011133# 644# -0 16 32 16 48 S x 12761# 596# 7545# 12# B- 17042# 778# 48 013700# 640# - 14 31 17 48 Cl x -4280# 500# 7883# 10# B- 18001# 587# 47 995405# 537# - 12 30 18 48 Ar x -22281.337 307.393 8242.132 6.404 B- 10003.140 307.394 47 976080.000 330.000 - 10 29 19 48 K x -32284.477 0.773 8434.232 0.016 B- 11940.153 0.779 47 965341.186 0.830 - 8 28 20 48 Ca -44224.629 0.096 8666.686 0.002 B- 279.213 4.950 47 952522.904 0.103 - 6 27 21 48 Sc -44503.842 4.951 8656.204 0.103 B- 3988.866 4.950 47 952223.157 5.314 - 4 26 22 48 Ti -48492.709 0.109 8723.006 0.002 B- -4015.015 0.969 47 947940.932 0.117 - 2 25 23 48 V -44477.694 0.975 8623.061 0.020 B- -1655.673 7.388 47 952251.229 1.046 - 0 24 24 48 Cr +nn -42822.020 7.324 8572.269 0.153 B- -13525.682 10.087 47 954028.667 7.862 - -2 23 25 48 Mn -29296.338 6.939 8274.185 0.145 B- -11296# 400# 47 968549.085 7.449 - -4 22 26 48 Fe x -18000# 400# 8023# 8# B- -19500# 640# 47 980676# 429# - -6 21 27 48 Co x 1500# 500# 7600# 10# B- -15293# 708# 48 001610# 537# - -8 20 28 48 Ni -pp 16793# 502# 7265# 10# B- * 48 018028# 538# -0 17 33 16 49 S -n 21093# 667# 7385# 14# B- 20153# 897# 49 022644# 716# - 15 32 17 49 Cl x 940# 600# 7781# 12# B- 18130# 721# 49 001009# 644# - 13 31 18 49 Ar x -17190# 400# 8135# 8# B- 12422# 400# 48 981546# 429# - 11 30 19 49 K x -29611.490 0.801 8372.274 0.016 B- 11688.275 0.826 48 968210.755 0.860 - 9 29 20 49 Ca -n -41299.765 0.201 8594.844 0.004 B- 5261.500 2.702 48 955662.875 0.216 - 7 28 21 49 Sc -46561.265 2.698 8686.256 0.055 B- 2002.522 2.697 48 950014.423 2.896 - 5 27 22 49 Ti -48563.787 0.114 8711.157 0.002 B- -601.856 0.820 48 947864.627 0.122 - 3 26 23 49 V - -47961.931 0.828 8682.908 0.017 B- -2628.871 2.391 48 948510.746 0.889 - 1 25 24 49 Cr -45333.060 2.243 8613.291 0.046 B- -7712.426 0.233 48 951332.955 2.407 - -1 24 25 49 Mn -37620.634 2.255 8439.929 0.046 B- -12869.907 24.324 48 959612.585 2.420 - -3 23 26 49 Fe x -24750.727 24.219 8161.311 0.494 B- -14870# 501# 48 973429.000 26.000 - -5 22 27 49 Co x -9880# 500# 7842# 10# B- -18080# 781# 48 989393# 537# - -7 21 28 49 Ni x 8200# 600# 7457# 12# B- * 49 008803# 644# -0 16 33 17 50 Cl x 7740# 600# 7651# 12# B- 21069# 781# 50 008309# 644# - 14 32 18 50 Ar x -13330# 500# 8056# 10# B- 12398# 500# 49 985690# 537# - 12 31 19 50 K x -25727.848 7.731 8288.582 0.155 B- 13861.376 7.892 49 972380.017 8.300 - 10 30 20 50 Ca x -39589.224 1.584 8550.163 0.032 B- 4958.158 15.084 49 957499.217 1.700 - 8 29 21 50 Sc -pn -44547.382 15.000 8633.679 0.300 B- 6884.278 15.000 49 952176.415 16.103 - 6 28 22 50 Ti -51431.660 0.121 8755.718 0.002 B- -2207.647 0.426 49 944785.839 0.129 - 4 27 23 50 V +n -49224.013 0.409 8695.918 0.008 B- 1038.059 0.299 49 947155.845 0.438 - 2 26 24 50 Cr -50262.072 0.437 8701.032 0.009 B- -7634.477 0.067 49 946041.443 0.468 - 0 25 25 50 Mn -42627.595 0.442 8532.696 0.009 B- -8151.139 8.395 49 954237.391 0.474 - -2 24 26 50 Fe x -34476.456 8.383 8354.026 0.168 B- -16846# 400# 49 962988.000 9.000 - -4 23 27 50 Co x -17630# 400# 8001# 8# B- -13510# 640# 49 981073# 429# - -6 22 28 50 Ni x -4120# 500# 7716# 10# B- * 49 995577# 537# -0 17 34 17 51 Cl x 14290# 700# 7530# 14# B- 20980# 922# 51 015341# 751# - 15 33 18 51 Ar x -6690# 600# 7926# 12# B- 15826# 600# 50 992818# 644# - 13 32 19 51 K x -22516.196 13.047 8221.349 0.256 B- 13816.107 13.057 50 975827.867 14.006 - 11 31 20 51 Ca x -36332.304 0.522 8476.913 0.010 B- 6896.381 20.007 50 960995.665 0.560 - 9 30 21 51 Sc -p2n -43228.684 20.000 8596.796 0.392 B- 6504.153 20.006 50 953592.095 21.471 - 7 29 22 51 Ti -n -49732.837 0.505 8708.988 0.010 B- 2471.005 0.644 50 946609.600 0.541 - 5 28 23 51 V -52203.842 0.401 8742.099 0.008 B- -752.447 0.213 50 943956.867 0.430 - 3 27 24 51 Cr -51451.395 0.400 8712.005 0.008 B- -3207.518 0.346 50 944764.652 0.429 - 1 26 25 51 Mn -48243.877 0.502 8633.772 0.010 B- -8041.321 8.977 50 948208.065 0.539 - -1 25 26 51 Fe -40202.555 8.964 8460.759 0.176 B- -12860.412 49.260 50 956840.779 9.623 - -3 24 27 51 Co x -27342.143 48.438 8193.254 0.950 B- -15442# 503# 50 970647.000 52.000 - -5 23 28 51 Ni x -11900# 500# 7875# 10# B- * 50 987225# 537# -0 16 34 18 52 Ar x -1280# 600# 7825# 12# B- 15858# 601# 51 998626# 644# - 14 33 19 52 K x -17137.627 33.534 8115.029 0.645 B- 17128.639 33.540 51 981602.000 36.000 - 12 32 20 52 Ca x -34266.266 0.671 8429.381 0.013 B- 6177.013 81.855 51 963213.648 0.720 - 10 31 21 52 Sc x -40443.279 81.852 8533.125 1.574 B- 9026.541 82.157 51 956582.351 87.871 - 8 30 22 52 Ti -nn -49469.820 7.072 8691.667 0.136 B- 1973.948 7.085 51 946891.960 7.592 - 6 29 23 52 V -n -51443.769 0.420 8714.582 0.008 B- 3975.473 0.531 51 944772.839 0.450 - 4 28 24 52 Cr -55419.242 0.340 8775.989 0.007 B- -4711.958 1.851 51 940504.992 0.364 - 2 27 25 52 Mn -50707.284 1.845 8670.329 0.035 B- -2376.920 5.017 51 945563.488 1.980 - 0 26 26 52 Fe -48330.363 5.117 8609.574 0.098 B- -13969.413 9.822 51 948115.217 5.493 - -2 25 27 52 Co x -34360.951 8.383 8325.886 0.161 B- -12031# 400# 51 963112.000 9.000 - -4 24 28 52 Ni x -22330# 400# 8079# 8# B- -20049# 721# 51 976028# 429# - -6 23 29 52 Cu x -2280# 600# 7679# 12# B- * 51 997552# 644# -0 17 35 18 53 Ar x 6791# 699# 7677# 13# B- 19086# 708# 53 007290# 750# - 15 34 19 53 K x -12295.721 111.779 8022.848 2.109 B- 17091.983 120.047 52 986800.000 120.000 - 13 33 20 53 Ca x -29387.704 43.780 8330.577 0.826 B- 9519.104 103.774 52 968451.000 47.000 - 11 32 21 53 Sc x -38906.808 94.087 8495.421 1.775 B- 7924.253 137.339 52 958231.821 101.006 - 9 31 22 53 Ti + -46831.061 100.049 8630.174 1.888 B- 5020.000 100.000 52 949724.785 107.406 - 7 30 23 53 V +p -51851.061 3.120 8710.130 0.059 B- 3435.938 3.102 52 944335.593 3.349 - 5 29 24 53 Cr -55286.999 0.348 8760.198 0.007 B- -596.884 0.356 52 940646.961 0.373 - 3 28 25 53 Mn -54690.116 0.450 8734.175 0.009 B- -3742.586 1.686 52 941287.742 0.483 - 1 27 26 53 Fe -50947.530 1.656 8648.799 0.031 B- -8288.101 0.443 52 945305.574 1.777 - -1 26 27 53 Co -42659.428 1.713 8477.658 0.032 B- -13028.604 25.209 52 954203.217 1.839 - -3 25 28 53 Ni x -29630.824 25.150 8217.074 0.475 B- -16361# 501# 52 968190.000 27.000 - -5 24 29 53 Cu x -13270# 500# 7894# 9# B- * 52 985754# 537# -0 16 35 19 54 K x -5002# 596# 7889# 11# B- 20158# 598# 53 994630# 640# - 14 34 20 54 Ca x -25160.585 48.438 8247.496 0.897 B- 8730.315 277.066 53 972989.000 52.000 - 12 33 21 54 Sc x -33890.900 272.800 8394.681 5.052 B- 11731.081 284.990 53 963616.620 292.862 - 10 32 22 54 Ti x -45621.981 82.461 8597.435 1.527 B- 4271.192 83.815 53 951022.786 88.526 - 8 31 23 54 V + -49893.173 15.004 8662.043 0.278 B- 7041.592 15.000 53 946437.472 16.107 - 6 30 24 54 Cr -56934.765 0.353 8777.955 0.007 B- -1377.136 1.008 53 938878.012 0.378 - 4 29 25 54 Mn -p -55557.629 1.059 8737.965 0.020 B- 696.872 1.076 53 940356.429 1.136 - 2 28 26 54 Fe -56254.500 0.372 8736.382 0.007 B- -8244.547 0.089 53 939608.306 0.399 - 0 27 27 54 Co -48009.953 0.383 8569.217 0.007 B- -8731.646 4.673 53 948459.192 0.411 - -2 26 28 54 Ni x -39278.308 4.657 8393.032 0.086 B- -17868# 400# 53 957833.000 5.000 - -4 25 29 54 Cu x -21410# 400# 8048# 7# B- -15139# 565# 53 977015# 429# - -6 24 30 54 Zn -pp -6272# 400# 7753# 7# B- * 53 993267# 430# -0 17 36 19 55 K x 708# 699# 7788# 13# B- 19058# 760# 55 000760# 750# - 15 35 20 55 Ca x -18350# 300# 8120# 5# B- 11809# 544# 54 980300# 322# - 13 34 21 55 Sc x -30159.352 454.342 8320.955 8.261 B- 11508.735 482.226 54 967622.601 487.756 - 11 33 22 55 Ti -41668.088 161.602 8515.980 2.938 B- 7476.498 157.206 54 955267.465 173.486 - 9 32 23 55 V -49144.586 95.104 8637.692 1.729 B- 5965.125 95.103 54 947241.114 102.098 - 7 31 24 55 Cr -55109.710 0.399 8731.924 0.007 B- 2602.703 0.368 54 940837.289 0.428 - 5 30 25 55 Mn -57712.413 0.303 8765.022 0.006 B- -231.114 0.179 54 938043.172 0.325 - 3 29 26 55 Fe -57481.300 0.342 8746.595 0.006 B- -3451.417 0.324 54 938291.283 0.367 - 1 28 27 55 Co -54029.883 0.428 8669.618 0.008 B- -8694.034 0.578 54 941996.531 0.459 - -1 27 28 55 Ni - -45335.849 0.719 8497.320 0.013 B- -13700.449 155.561 54 951329.961 0.771 - -3 26 29 55 Cu x -31635.399 155.559 8233.996 2.828 B- -17065# 429# 54 966038.000 167.000 - -5 25 30 55 Zn x -14570# 400# 7909# 7# B- * 54 984358# 429# -0 18 37 19 56 K x 7927# 801# 7664# 14# B- 21825# 895# 56 008510# 860# - 16 36 20 56 Ca x -13898# 400# 8040# 7# B- 10954# 710# 55 985080# 429# - 14 35 21 56 Sc x -24852.260 586.841 8221.728 10.479 B- 14467.788 599.236 55 973320.000 630.000 - 12 34 22 56 Ti -39320.048 121.247 8466.110 2.165 B- 6834.833 194.550 55 957788.190 130.164 - 10 33 23 56 V -46154.881 176.898 8574.191 3.159 B- 9130.120 176.899 55 950450.694 189.907 - 8 32 24 56 Cr ++ -55285.001 0.603 8723.258 0.011 B- 1626.538 0.561 55 940649.107 0.647 - 6 31 25 56 Mn -n -56911.538 0.331 8738.333 0.006 B- 3695.544 0.207 55 938902.947 0.355 - 4 30 26 56 Fe -60607.082 0.302 8790.354 0.005 B- -4566.680 0.411 55 934935.617 0.324 - 2 29 27 56 Co -56040.402 0.493 8694.836 0.009 B- -2132.863 0.374 55 939838.150 0.529 - 0 28 28 56 Ni -53907.539 0.422 8642.779 0.008 B- -15264.511 14.910 55 942127.872 0.452 - -2 27 29 56 Cu x -38643.029 14.904 8356.227 0.266 B- -13253# 400# 55 958515.000 16.000 - -4 26 30 56 Zn x -25390# 400# 8106# 7# B- -22000# 640# 55 972743# 429# - -6 25 31 56 Ga x -3390# 500# 7699# 9# B- * 55 996361# 537# -0 17 37 20 57 Ca x -6874# 400# 7917# 7# B- 14121# 1364# 56 992620# 429# - 15 36 21 57 Sc x -20995.875 1304.092 8151.433 22.879 B- 12919.758 1329.062 56 977460.000 1400.000 - 13 35 22 57 Ti x -33915.633 256.417 8364.370 4.499 B- 10497.818 268.750 56 963590.068 275.274 - 11 34 23 57 V x -44413.450 80.479 8534.817 1.412 B- 8111.252 80.486 56 952320.197 86.397 - 9 33 24 57 Cr x -52524.702 1.068 8663.394 0.019 B- 4961.548 1.846 56 943612.409 1.146 - 7 32 25 57 Mn -57486.251 1.505 8736.713 0.026 B- 2695.589 1.526 56 938285.968 1.615 - 5 31 26 57 Fe -60181.839 0.304 8770.279 0.005 B- -836.276 0.451 56 935392.134 0.326 - 3 30 27 57 Co -59345.564 0.533 8741.882 0.009 B- -3261.731 0.642 56 936289.913 0.572 - 1 29 28 57 Ni -56083.833 0.582 8670.933 0.010 B- -8774.947 0.439 56 939791.525 0.624 - -1 28 29 57 Cu -47308.886 0.519 8503.262 0.009 B- -14759# 200# 56 949211.819 0.557 - -3 27 30 57 Zn x -32550# 200# 8231# 4# B- -17540# 447# 56 965056# 215# - -5 26 31 57 Ga x -15010# 400# 7909# 7# B- * 56 983886# 429# -0 18 38 20 58 Ca x -1919# 500# 7835# 9# B- 12957# 640# 57 997940# 537# - 16 37 21 58 Sc x -14876# 400# 8045# 7# B- 16234# 447# 57 984030# 429# - 14 36 22 58 Ti x -31110# 200# 8311# 3# B- 9292# 219# 57 966602# 215# - 12 35 23 58 V x -40401.753 89.374 8457.658 1.541 B- 11590.049 89.386 57 956626.932 95.947 - 10 34 24 58 Cr x -51991.801 1.490 8643.998 0.026 B- 3835.759 3.085 57 944184.502 1.600 - 8 33 25 58 Mn x -55827.560 2.701 8696.643 0.047 B- 6327.553 2.723 57 940066.646 2.900 - 6 32 26 58 Fe -62155.113 0.343 8792.250 0.006 B- -2307.955 1.139 57 933273.738 0.368 - 4 31 27 58 Co -59847.158 1.160 8738.969 0.020 B- 381.586 1.107 57 935751.429 1.245 - 2 30 28 58 Ni -60228.744 0.373 8732.059 0.006 B- -8561.019 0.443 57 935341.780 0.400 - 0 29 29 58 Cu -51667.725 0.578 8570.967 0.010 B- -9368.981 50.002 57 944532.413 0.621 - -2 28 30 58 Zn -- -42298.744 50.001 8395.944 0.862 B- -18759# 304# 57 954590.428 53.678 - -4 27 31 58 Ga x -23540# 300# 8059# 5# B- -16459# 583# 57 974729# 322# - -6 26 32 58 Ge x -7080# 500# 7762# 9# B- * 57 992399# 537# -0 17 38 21 59 Sc x -10302# 400# 7967# 7# B- 15208# 447# 58 988940# 429# - 15 37 22 59 Ti x -25510# 200# 8212# 3# B- 12322# 258# 58 972614# 215# - 13 36 23 59 V x -37832.015 161.874 8407.555 2.744 B- 10253.745 270.218 58 959385.659 173.778 - 11 35 24 59 Cr x -48085.760 216.367 8568.087 3.667 B- 7439.560 216.380 58 948377.810 232.279 - 9 34 25 59 Mn x -55525.320 2.329 8680.921 0.039 B- 5139.485 2.356 58 940391.113 2.500 - 7 33 26 59 Fe -60664.805 0.355 8754.771 0.006 B- 1564.903 0.369 58 934873.649 0.380 - 5 32 27 59 Co -62229.709 0.418 8768.035 0.007 B- -1073.002 0.194 58 933193.656 0.448 - 3 31 28 59 Ni -61156.707 0.374 8736.588 0.006 B- -4798.380 0.397 58 934345.571 0.402 - 1 30 29 59 Cu -56358.327 0.544 8642.000 0.009 B- -9142.775 0.602 58 939496.844 0.584 - -1 29 30 59 Zn -47215.551 0.771 8473.777 0.013 B- -13455# 170# 58 949312.017 0.827 - -3 28 31 59 Ga x -33760# 170# 8232# 3# B- -17890# 434# 58 963757# 183# - -5 27 32 59 Ge x -15870# 400# 7916# 7# B- * 58 982963# 429# -0 18 39 21 60 Sc x -4052# 500# 7865# 8# B- 18278# 583# 59 995650# 537# - 16 38 22 60 Ti x -22330# 300# 8157# 5# B- 10912# 372# 59 976028# 322# - 14 37 23 60 V x -33241.956 220.159 8325.450 3.669 B- 13427.621 293.169 59 964313.290 236.350 - 12 36 24 60 Cr x -46669.576 193.593 8536.205 3.227 B- 6298.361 193.607 59 949898.146 207.830 - 10 35 25 60 Mn x -52967.938 2.329 8628.138 0.039 B- 8445.079 4.128 59 943136.576 2.500 - 8 34 26 60 Fe -nn -61413.017 3.409 8755.851 0.057 B- 237.293 3.411 59 934070.411 3.659 - 6 33 27 60 Co -n -61650.309 0.424 8746.766 0.007 B- 2822.809 0.212 59 933815.667 0.455 - 4 32 28 60 Ni -64473.118 0.376 8780.774 0.006 B- -6127.982 1.573 59 930785.256 0.403 - 2 31 29 60 Cu - -58345.137 1.618 8665.602 0.027 B- -4170.797 1.629 59 937363.916 1.736 - 0 30 30 60 Zn -54174.340 0.564 8583.050 0.009 B- -14584# 200# 59 941841.450 0.605 - -2 29 31 60 Ga x -39590# 200# 8327# 3# B- -12501# 361# 59 957498# 215# - -4 28 32 60 Ge x -27090# 300# 8106# 5# B- -21620# 500# 59 970918# 322# - -6 27 33 60 As x -5470# 400# 7732# 7# B- * 59 994128# 429# -0 19 40 21 61 Sc x 931# 600# 7787# 10# B- 17281# 721# 61 001000# 644# - 17 39 22 61 Ti x -16350# 400# 8057# 7# B- 14157# 979# 60 982448# 429# - 15 38 23 61 V x -30506.429 894.234 8276.439 14.660 B- 11968.800 899.958 60 967250.000 960.000 - 13 37 24 61 Cr x -42475.229 101.341 8459.824 1.661 B- 9266.893 101.367 60 954400.963 108.793 - 11 36 25 61 Mn x -51742.122 2.329 8598.915 0.038 B- 7178.372 3.497 60 944452.544 2.500 - 9 35 26 61 Fe x -58920.494 2.608 8703.768 0.043 B- 3977.572 2.742 60 936746.244 2.800 - 7 34 27 61 Co p2n -62898.066 0.846 8756.148 0.014 B- 1323.839 0.790 60 932476.145 0.908 - 5 33 28 61 Ni -64221.905 0.378 8765.025 0.006 B- -2237.845 0.966 60 931054.945 0.405 - 3 32 29 61 Cu p2n -61984.059 0.953 8715.514 0.016 B- -5635.156 15.903 60 933457.371 1.023 - 1 31 30 61 Zn -56348.903 15.899 8610.309 0.261 B- -9214.245 37.679 60 939506.960 17.068 - -1 30 31 61 Ga -47134.659 37.994 8446.431 0.623 B- -13775# 302# 60 949398.859 40.787 - -3 29 32 61 Ge x -33360# 300# 8208# 5# B- -16459# 424# 60 964187# 322# - -5 28 33 61 As x -16900# 300# 7925# 5# B- * 60 981857# 322# -0 18 40 22 62 Ti x -12500# 400# 7995# 6# B- 12977# 499# 61 986581# 429# - 16 39 23 62 V x -25476# 298# 8192# 5# B- 15419# 333# 61 972650# 320# - 14 38 24 62 Cr x -40894.961 148.099 8428.069 2.389 B- 7628.996 148.244 61 956097.451 158.991 - 12 37 25 62 Mn IT -48523.957 6.542 8538.499 0.106 B- 10354.091 7.114 61 947907.386 7.023 - 10 36 26 62 Fe x -58878.048 2.794 8692.882 0.045 B- 2546.235 18.784 61 936791.812 3.000 - 8 35 27 62 Co + -61424.282 18.575 8721.332 0.300 B- 5322.040 18.570 61 934058.317 19.940 - 6 34 28 62 Ni -66746.323 0.439 8794.553 0.007 B- -3958.896 0.475 61 928344.871 0.470 - 4 33 29 62 Cu - -62787.426 0.647 8718.081 0.010 B- -1619.455 0.651 61 932594.921 0.694 - 2 32 30 62 Zn -61167.972 0.625 8679.343 0.010 B- -9181.066 0.376 61 934333.477 0.670 - 0 31 31 62 Ga -51986.906 0.647 8518.642 0.010 B- -10247# 140# 61 944189.757 0.694 - -2 30 32 62 Ge x -41740# 140# 8341# 2# B- -17420# 331# 61 955190# 150# - -4 29 33 62 As x -24320# 300# 8047# 5# B- * 61 973891# 322# -0 19 41 22 63 Ti x -5750# 500# 7889# 8# B- 16140# 640# 62 993827# 537# - 17 40 23 63 V x -21890# 400# 8133# 6# B- 14117# 537# 62 976500# 429# - 15 39 24 63 Cr x -36007.474 358.073 8344.828 5.684 B- 10879.579 358.092 62 961344.384 384.407 - 13 38 25 63 Mn x -46887.053 3.726 8505.101 0.059 B- 8748.568 5.692 62 949664.675 4.000 - 11 37 26 63 Fe -55635.621 4.302 8631.549 0.068 B- 6215.819 19.067 62 940272.700 4.618 - 9 36 27 63 Co -61851.440 18.575 8717.795 0.295 B- 3661.335 18.570 62 933599.744 19.941 - 7 35 28 63 Ni -65512.775 0.440 8763.493 0.007 B- 66.977 0.015 62 929669.139 0.472 - 5 34 29 63 Cu -65579.752 0.440 8752.138 0.007 B- -3366.355 1.546 62 929597.236 0.472 - 3 33 30 63 Zn -62213.397 1.561 8686.285 0.025 B- -5666.304 2.034 62 933211.167 1.676 - 1 32 31 63 Ga x -56547.093 1.304 8583.926 0.021 B- -9625.877 37.283 62 939294.195 1.400 - -1 31 32 63 Ge x -46921.216 37.260 8418.716 0.591 B- -13421# 204# 62 949628.000 40.000 - -3 30 33 63 As x -33500# 200# 8193# 3# B- * 62 964036# 215# -0 20 42 22 64 Ti x -1025# 600# 7818# 9# B- 15295# 721# 63 998900# 644# - 18 41 23 64 V x -16320# 400# 8045# 6# B- 17160# 594# 63 982480# 429# - 16 40 24 64 Cr x -33479.757 439.665 8301.058 6.870 B- 9509.277 439.679 63 964058.000 472.000 - 14 39 25 64 Mn x -42989.035 3.540 8437.417 0.055 B- 11980.510 6.140 63 953849.370 3.800 - 12 38 26 64 Fe x -54969.544 5.017 8612.388 0.078 B- 4822.785 20.625 63 940987.763 5.386 - 10 37 27 64 Co + -59792.329 20.006 8675.520 0.313 B- 7306.592 20.000 63 935810.291 21.476 - 8 36 28 64 Ni -67098.921 0.475 8777.461 0.007 B- -1674.376 0.225 63 927966.341 0.510 - 6 35 29 64 Cu -65424.545 0.448 8739.075 0.007 B- 579.469 0.650 63 929763.857 0.481 - 4 34 30 64 Zn -66004.014 0.647 8735.905 0.010 B- -7171.194 1.483 63 929141.772 0.694 - 2 33 31 64 Ga -58832.821 1.429 8611.631 0.022 B- -4517.325 3.991 63 936840.365 1.533 - 0 32 32 64 Ge x -54315.496 3.726 8528.823 0.058 B- -14783# 203# 63 941689.913 4.000 - -2 31 33 64 As -p -39532# 203# 8286# 3# B- -12832# 543# 63 957560# 218# - -4 30 34 64 Se x -26700# 503# 8073# 8# B- * 63 971336# 540# -0 19 42 23 65 V x -11780# 500# 7976# 8# B- 16440# 583# 64 987354# 537# - 17 41 24 65 Cr x -28220# 300# 8217# 5# B- 12748# 300# 64 969705# 322# - 15 40 25 65 Mn x -40967.339 3.726 8400.681 0.057 B- 10250.557 6.326 64 956019.750 4.000 - 13 39 26 65 Fe x -51217.895 5.112 8546.346 0.079 B- 7967.303 5.520 64 945015.324 5.487 - 11 38 27 65 Co x -59185.198 2.083 8656.884 0.032 B- 5940.487 2.141 64 936462.073 2.235 - 9 37 28 65 Ni -n -65125.685 0.495 8736.240 0.008 B- 2137.975 0.706 64 930084.697 0.531 - 7 36 29 65 Cu -67263.660 0.650 8757.096 0.010 B- -1351.640 0.360 64 927789.487 0.697 - 5 35 30 65 Zn -65912.019 0.650 8724.265 0.010 B- -3254.513 0.662 64 929240.532 0.697 - 3 34 31 65 Ga -62657.507 0.815 8662.160 0.013 B- -6179.291 2.313 64 932734.395 0.874 - 1 33 32 65 Ge -56478.216 2.165 8555.058 0.033 B- -9541.165 84.794 64 939368.137 2.323 - -1 32 33 65 As x -46937.051 84.766 8396.234 1.304 B- -13917# 312# 64 949611.000 91.000 - -3 31 34 65 Se x -33020# 300# 8170# 5# B- * 64 964552# 322# -0 20 43 23 66 V x -5610# 500# 7884# 8# B- 19110# 640# 65 993977# 537# - 18 42 24 66 Cr x -24720# 400# 8161# 6# B- 12030# 400# 65 973462# 429# - 16 41 25 66 Mn x -36750.387 11.178 8331.798 0.169 B- 13317.452 11.906 65 960546.834 12.000 - 14 40 26 66 Fe x -50067.839 4.099 8521.724 0.062 B- 6340.694 14.561 65 946249.960 4.400 - 12 39 27 66 Co x -56408.533 13.972 8605.941 0.212 B- 9597.752 14.042 65 939442.945 15.000 - 10 38 28 66 Ni x -66006.285 1.397 8739.508 0.021 B- 251.987 1.543 65 929139.334 1.500 - 8 37 29 66 Cu -66258.272 0.655 8731.472 0.010 B- 2640.888 0.931 65 928868.814 0.703 - 6 36 30 66 Zn -68899.160 0.749 8759.632 0.011 B- -5175.500 0.800 65 926033.704 0.804 - 4 35 31 66 Ga - -63723.660 1.096 8669.361 0.017 B- -2116.628 2.639 65 931589.832 1.176 - 2 34 32 66 Ge x -61607.032 2.401 8625.437 0.036 B- -9581.955 6.168 65 933862.126 2.577 - 0 33 33 66 As x -52025.077 5.682 8468.403 0.086 B- -10365# 200# 65 944148.779 6.100 - -2 32 34 66 Se x -41660# 200# 8300# 3# B- * 65 955276# 215# -0 21 44 23 67 V x -650# 600# 7812# 9# B- 18030# 721# 66 999302# 644# - 19 43 24 67 Cr x -18680# 400# 8070# 6# B- 14780# 500# 66 979946# 429# - 17 42 25 67 Mn x -33460# 300# 8279# 4# B- 12150# 404# 66 964079# 322# - 15 41 26 67 Fe x -45610.155 270.285 8448.469 4.034 B- 9711.620 270.362 66 951035.482 290.163 - 13 40 27 67 Co x -55321.775 6.443 8581.741 0.096 B- 8420.905 7.061 66 940609.628 6.917 - 11 39 28 67 Ni x -63742.680 2.888 8695.750 0.043 B- 3576.832 3.023 66 931569.414 3.100 - 9 38 29 67 Cu -67319.513 0.894 8737.458 0.013 B- 560.800 0.830 66 927729.526 0.959 - 7 37 30 67 Zn -67880.313 0.760 8734.152 0.011 B- -1001.265 1.122 66 927127.482 0.815 - 5 36 31 67 Ga -66879.048 1.181 8707.531 0.018 B- -4220.819 4.799 66 928202.384 1.268 - 3 35 32 67 Ge -n2p -62658.230 4.661 8632.857 0.070 B- -6071.005 4.682 66 932733.620 5.003 - 1 34 33 67 As -56587.225 0.443 8530.568 0.007 B- -10006.936 67.069 66 939251.111 0.475 - -1 33 34 67 Se x -46580.289 67.068 8369.534 1.001 B- -13790# 405# 66 949994.000 72.000 - -3 32 35 67 Br x -32790# 400# 8152# 6# B- * 66 964798# 429# -0 20 44 24 68 Cr x -14800# 500# 8013# 7# B- 13580# 640# 67 984112# 537# - 18 43 25 68 Mn x -28380# 400# 8201# 6# B- 15107# 541# 67 969533# 429# - 16 42 26 68 Fe x -43486.914 365.259 8411.698 5.371 B- 8443.751 411.489 67 953314.875 392.121 - 14 41 27 68 Co x -51930.665 189.497 8524.366 2.787 B- 11533.150 189.520 67 944250.135 203.433 - 12 40 28 68 Ni x -63463.814 2.981 8682.466 0.044 B- 2103.220 3.375 67 931868.789 3.200 - 10 39 29 68 Cu x -65567.035 1.584 8701.890 0.023 B- 4440.057 1.767 67 929610.889 1.700 - 8 38 30 68 Zn -70007.092 0.784 8755.680 0.012 B- -2921.100 1.200 67 924844.291 0.841 - 6 37 31 68 Ga - -67085.992 1.433 8701.218 0.021 B- -107.203 2.361 67 927980.221 1.538 - 4 36 32 68 Ge x -66978.789 1.876 8688.136 0.028 B- -8084.270 2.632 67 928095.308 2.014 - 2 35 33 68 As -58894.519 1.846 8557.745 0.027 B- -4705.078 1.911 67 936774.130 1.981 - 0 34 34 68 Se x -54189.441 0.496 8477.047 0.007 B- -15398# 259# 67 941825.239 0.532 - -2 33 35 68 Br -p -38791# 259# 8239# 4# B- * 67 958356# 278# -0 21 45 24 69 Cr x -8580# 500# 7924# 7# B- 16190# 640# 68 990789# 537# - 19 44 25 69 Mn x -24770# 400# 8147# 6# B- 14259# 565# 68 973408# 429# - 17 43 26 69 Fe x -39030# 400# 8342# 6# B- 11250# 424# 68 958100# 429# - 15 42 27 69 Co x -50279.157 140.506 8493.865 2.036 B- 9699.492 140.556 68 946023.102 150.839 - 13 41 28 69 Ni x -59978.648 3.726 8623.099 0.054 B- 5757.564 3.979 68 935610.268 4.000 - 11 40 29 69 Cu x -65736.213 1.397 8695.204 0.020 B- 2681.632 1.610 68 929429.268 1.500 - 9 39 30 69 Zn -n -68417.845 0.800 8722.729 0.012 B- 909.964 1.426 68 926550.418 0.858 - 7 38 31 69 Ga -69327.809 1.197 8724.579 0.017 B- -2227.146 0.550 68 925573.531 1.285 - 5 37 32 69 Ge -67100.663 1.318 8680.963 0.019 B- -3988.492 31.982 68 927964.471 1.414 - 3 36 33 69 As -63112.171 31.999 8611.821 0.464 B- -6677.465 32.021 68 932246.294 34.352 - 1 35 34 69 Se -56434.706 1.490 8503.707 0.022 B- -10175.236 42.029 68 939414.847 1.599 - -1 34 35 69 Br -p -46259.470 42.003 8344.902 0.609 B- -13825# 403# 68 950338.413 45.092 - -3 33 36 69 Kr x -32435# 401# 8133# 6# B- * 68 965180# 430# -0 22 46 24 70 Cr x -4480# 600# 7867# 9# B- 15020# 781# 69 995191# 644# - 20 45 25 70 Mn x -19500# 500# 8070# 7# B- 17010# 640# 69 979066# 537# - 18 44 26 70 Fe x -36510# 400# 8302# 6# B- 10120# 500# 69 960805# 429# - 16 43 27 70 Co x -46630# 300# 8436# 4# B- 12584# 300# 69 949941# 322# - 14 42 28 70 Ni x -59213.860 2.144 8604.291 0.031 B- 3762.513 2.401 69 936431.303 2.301 - 12 41 29 70 Cu x -62976.373 1.082 8646.865 0.015 B- 6588.362 2.202 69 932392.079 1.161 - 10 40 30 70 Zn -69564.735 1.918 8729.808 0.027 B- -654.595 1.574 69 925319.181 2.058 - 8 39 31 70 Ga -68910.140 1.201 8709.280 0.017 B- 1651.736 1.462 69 926021.917 1.289 - 6 38 32 70 Ge -70561.876 0.838 8721.700 0.012 B- -6220.000 50.000 69 924248.706 0.900 - 4 37 33 70 As - -64341.876 50.007 8621.666 0.714 B- -2411.985 50.032 69 930926.151 53.684 - 2 36 34 70 Se x -61929.891 1.584 8576.033 0.023 B- -10504.272 14.988 69 933515.523 1.700 - 0 35 35 70 Br x -51425.619 14.904 8414.796 0.213 B- -10325# 201# 69 944792.323 16.000 - -2 34 36 70 Kr x -41100# 200# 8256# 3# B- * 69 955877# 215# -0 21 46 25 71 Mn x -15570# 500# 8015# 7# B- 15860# 640# 70 983285# 537# - 19 45 26 71 Fe x -31430# 400# 8227# 6# B- 12940# 613# 70 966259# 429# - 17 44 27 71 Co x -44369.926 465.030 8398.734 6.550 B- 11036.302 465.035 70 952366.923 499.230 - 15 43 28 71 Ni x -55406.228 2.237 8543.156 0.032 B- 7304.899 2.688 70 940518.964 2.401 - 13 42 29 71 Cu x -62711.127 1.490 8635.022 0.021 B- 4617.651 3.044 70 932676.832 1.600 - 11 41 30 71 Zn -67328.777 2.654 8689.041 0.037 B- 2810.358 2.775 70 927719.580 2.849 - 9 40 31 71 Ga -70139.135 0.812 8717.604 0.011 B- -232.638 0.223 70 924702.536 0.871 - 7 39 32 71 Ge -69906.497 0.834 8703.309 0.012 B- -2013.400 4.082 70 924952.284 0.894 - 5 38 33 71 As - -67893.097 4.167 8663.932 0.059 B- -4746.590 5.017 70 927113.758 4.473 - 3 37 34 71 Se x -63146.507 2.794 8586.060 0.039 B- -6644.089 6.082 70 932209.432 3.000 - 1 36 35 71 Br -56502.418 5.402 8481.462 0.076 B- -10175.212 128.845 70 939342.156 5.799 - -1 35 36 71 Kr -46327.205 128.769 8327.130 1.814 B- -14267# 420# 70 950265.696 138.238 - -3 34 37 71 Rb x -32060# 400# 8115# 6# B- * 70 965582# 429# -0 22 47 25 72 Mn x -9900# 600# 7937# 8# B- 18530# 781# 71 989372# 644# - 20 46 26 72 Fe x -28430# 500# 8184# 7# B- 11769# 640# 71 969479# 537# - 18 45 27 72 Co x -40200# 400# 8336# 6# B- 14027# 400# 71 956844# 429# - 16 44 28 72 Ni x -54226.060 2.237 8520.211 0.031 B- 5556.938 2.637 71 941785.926 2.401 - 14 43 29 72 Cu x -59782.999 1.397 8586.525 0.019 B- 8362.487 2.558 71 935820.307 1.500 - 12 42 30 72 Zn x -68145.486 2.142 8691.805 0.030 B- 442.807 2.294 71 926842.807 2.300 - 10 41 31 72 Ga -68588.293 0.819 8687.089 0.011 B- 3997.607 0.822 71 926367.434 0.878 - 8 40 32 72 Ge -72585.900 0.076 8731.745 0.001 B- -4356.102 4.082 71 922075.826 0.081 - 6 39 33 72 As - -68229.798 4.083 8660.378 0.057 B- -361.618 4.528 71 926752.295 4.383 - 4 38 34 72 Se x -67868.180 1.956 8644.489 0.027 B- -8806.437 2.208 71 927140.507 2.100 - 2 37 35 72 Br x -59061.743 1.025 8511.312 0.014 B- -5121.168 8.076 71 936594.607 1.100 - 0 36 36 72 Kr x -53940.575 8.011 8429.319 0.111 B- -15611# 500# 71 942092.407 8.600 - -2 35 37 72 Rb x -38330# 500# 8202# 7# B- * 71 958851# 537# -0 21 47 26 73 Fe x -22900# 500# 8106# 7# B- 14518# 640# 72 975416# 537# - 19 46 27 73 Co x -37418# 400# 8295# 5# B- 12690# 400# 72 959830# 429# - 17 45 28 73 Ni x -50108.152 2.423 8457.652 0.033 B- 8879.285 3.104 72 946206.683 2.601 - 15 44 29 73 Cu -58987.437 1.942 8568.569 0.027 B- 6605.966 2.691 72 936674.378 2.084 - 13 43 30 73 Zn x -65593.402 1.863 8648.345 0.026 B- 4105.932 2.506 72 929582.582 2.000 - 11 42 31 73 Ga x -69699.335 1.677 8693.873 0.023 B- 1598.188 1.678 72 925174.682 1.800 - 9 41 32 73 Ge -71297.523 0.057 8705.049 0.001 B- -344.776 3.853 72 923458.956 0.061 - 7 40 33 73 As -70952.747 3.853 8689.609 0.053 B- -2725.360 7.399 72 923829.089 4.136 - 5 39 34 73 Se -68227.387 7.424 8641.558 0.102 B- -4579.912 10.388 72 926754.883 7.969 - 3 38 35 73 Br x -63647.475 7.266 8568.103 0.100 B- -7095.725 9.801 72 931671.621 7.800 - 1 37 36 73 Kr x -56551.751 6.578 8460.184 0.090 B- -10470# 200# 72 939289.195 7.061 - -1 36 37 73 Rb -p -46082# 200# 8306# 3# B- -14131# 448# 72 950529# 215# - -3 35 38 73 Sr x -31950# 401# 8102# 5# B- * 72 965700# 430# -0 22 48 26 74 Fe x -19590# 600# 8061# 8# B- 13230# 781# 73 978969# 644# - 20 47 27 74 Co x -32820# 500# 8229# 7# B- 15636# 537# 73 964766# 537# - 18 46 28 74 Ni x -48456# 196# 8430# 3# B- 7550# 196# 73 947980# 210# - 16 45 29 74 Cu x -56006.205 6.148 8521.562 0.083 B- 9750.507 6.642 73 939874.862 6.600 - 14 44 30 74 Zn x -65756.712 2.515 8642.754 0.034 B- 2292.905 3.910 73 929407.262 2.700 - 12 43 31 74 Ga x -68049.617 2.994 8663.167 0.040 B- 5372.824 2.994 73 926945.726 3.214 - 10 42 32 74 Ge -73422.442 0.013 8725.200 0.000 B- -2562.387 1.693 73 921177.762 0.013 - 8 41 33 74 As -70860.054 1.693 8680.001 0.023 B- 1353.147 1.693 73 923928.598 1.817 - 6 40 34 74 Se -72213.201 0.015 8687.715 0.000 B- -6925.049 5.835 73 922475.935 0.015 - 4 39 35 74 Br -65288.153 5.835 8583.561 0.079 B- -2956.317 6.173 73 929910.281 6.264 - 2 38 36 74 Kr -62331.836 2.013 8533.038 0.027 B- -10415.827 3.424 73 933084.017 2.161 - 0 37 37 74 Rb -51916.009 3.027 8381.712 0.041 B- -11089# 100# 73 944265.868 3.249 - -2 36 38 74 Sr x -40827# 100# 8221# 1# B- * 73 956170# 107# -0 23 49 26 75 Fe x -13640# 600# 7982# 8# B- 16010# 781# 74 985357# 644# - 21 48 27 75 Co x -29649# 500# 8185# 7# B- 14380# 583# 74 968170# 537# - 19 47 28 75 Ni x -44030# 300# 8366# 4# B- 10441# 300# 74 952732# 322# - 17 46 29 75 Cu x -54471.341 2.330 8495.094 0.031 B- 8087.567 3.042 74 941522.606 2.501 - 15 45 30 75 Zn x -62558.908 1.956 8592.497 0.026 B- 5905.672 3.113 74 932840.246 2.100 - 13 44 31 75 Ga x -68464.580 2.422 8660.808 0.032 B- 3392.384 2.422 74 926500.246 2.600 - 11 43 32 75 Ge -n -71856.965 0.052 8695.609 0.001 B- 1177.231 0.885 74 922858.371 0.055 - 9 42 33 75 As -73034.195 0.884 8700.874 0.012 B- -864.714 0.882 74 921594.562 0.948 - 7 41 34 75 Se -72169.481 0.073 8678.913 0.001 B- -3062.472 4.285 74 922522.871 0.078 - 5 40 35 75 Br x -69107.009 4.285 8627.649 0.057 B- -4783.385 9.167 74 925810.570 4.600 - 3 39 36 75 Kr x -64323.624 8.104 8553.439 0.108 B- -7104.929 8.189 74 930945.746 8.700 - 1 38 37 75 Rb x -57218.694 1.180 8448.275 0.016 B- -10600.000 220.000 74 938573.201 1.266 - -1 37 38 75 Sr - -46618.694 220.003 8296.511 2.933 B- -14799# 372# 74 949952.770 236.183 - -3 36 39 75 Y x -31820# 300# 8089# 4# B- * 74 965840# 322# -0 22 49 27 76 Co x -24510# 600# 8116# 8# B- 17120# 721# 75 973687# 644# - 20 48 28 76 Ni x -41630# 400# 8331# 5# B- 9346# 400# 75 955308# 429# - 18 47 29 76 Cu x -50975.985 6.707 8443.527 0.088 B- 11327.031 6.863 75 945275.025 7.200 - 16 46 30 76 Zn -62303.016 1.456 8582.273 0.019 B- 3993.624 2.438 75 933114.957 1.562 - 14 45 31 76 Ga x -66296.640 1.956 8624.526 0.026 B- 6916.249 1.956 75 928827.625 2.100 - 12 44 32 76 Ge -73212.889 0.018 8705.236 0.000 B- -921.512 0.886 75 921402.726 0.019 - 10 43 33 76 As -n -72291.377 0.886 8682.816 0.012 B- 2960.573 0.886 75 922392.010 0.951 - 8 42 34 76 Se -75251.950 0.016 8711.477 0.000 B- -4962.881 9.322 75 919213.704 0.017 - 6 41 35 76 Br - -70289.068 9.322 8635.882 0.123 B- -1275.355 10.149 75 924541.577 10.007 - 4 40 36 76 Kr -69013.714 4.013 8608.807 0.053 B- -8534.633 4.121 75 925910.726 4.308 - 2 39 37 76 Rb x -60479.081 0.938 8486.215 0.012 B- -6231.442 34.478 75 935073.032 1.006 - 0 38 38 76 Sr x -54247.639 34.465 8393.929 0.453 B- -15768# 302# 75 941762.761 37.000 - -2 37 39 76 Y x -38480# 300# 8176# 4# B- * 75 958690# 322# -0 23 50 27 77 Co x -21015# 600# 8070# 8# B- 15785# 781# 76 977440# 644# - 21 49 28 77 Ni x -36800# 500# 8265# 6# B- 11824# 522# 76 960494# 537# - 19 48 29 77 Cu x -48624# 149# 8408# 2# B- 10165# 149# 76 947800# 160# - 17 47 30 77 Zn -58789.195 1.973 8530.003 0.026 B- 7203.149 3.124 76 936887.199 2.117 - 15 46 31 77 Ga x -65992.344 2.422 8613.390 0.031 B- 5220.518 2.422 76 929154.300 2.600 - 13 45 32 77 Ge -n -71212.862 0.053 8671.028 0.001 B- 2703.456 1.694 76 923549.844 0.056 - 11 44 33 77 As -73916.318 1.693 8695.978 0.022 B- 683.170 1.693 76 920647.564 1.817 - 9 43 34 77 Se -74599.488 0.062 8694.690 0.001 B- -1364.680 2.810 76 919914.150 0.067 - 7 42 35 77 Br - -73234.809 2.811 8666.806 0.037 B- -3065.366 3.424 76 921379.194 3.017 - 5 41 36 77 Kr x -70169.443 1.956 8616.836 0.025 B- -5338.951 2.351 76 924670.000 2.100 - 3 40 37 77 Rb x -64830.492 1.304 8537.339 0.017 B- -7027.055 8.024 76 930401.600 1.400 - 1 39 38 77 Sr x -57803.436 7.918 8435.918 0.103 B- -11365# 203# 76 937945.455 8.500 - -1 38 39 77 Y -p -46439# 203# 8278# 3# B- -14399# 448# 76 950146# 218# - -3 37 40 77 Zr x -32040# 400# 8081# 5# B- * 76 965604# 429# -0 22 50 28 78 Ni x -33890# 600# 8225# 8# B- 10608# 783# 77 963618# 644# - 20 49 29 78 Cu x -44497.469 503.007 8350.925 6.449 B- 12985.766 503.011 77 952230.000 540.000 - 18 48 30 78 Zn -57483.235 1.944 8507.379 0.025 B- 6222.716 2.719 77 938289.205 2.086 - 16 47 31 78 Ga -63705.950 1.903 8577.127 0.024 B- 8156.099 4.015 77 931608.845 2.043 - 14 46 32 78 Ge -nn -71862.050 3.536 8671.663 0.045 B- 954.890 10.400 77 922852.912 3.795 - 12 45 33 78 As +pn -72816.940 9.781 8673.875 0.125 B- 4209.004 9.782 77 921827.795 10.500 - 10 44 34 78 Se -77025.944 0.179 8717.806 0.002 B- -3573.784 3.575 77 917309.243 0.191 - 8 43 35 78 Br - -73452.160 3.580 8661.959 0.046 B- 726.116 3.584 77 921145.859 3.842 - 6 42 36 78 Kr -74178.275 0.307 8661.238 0.004 B- -7242.857 3.252 77 920366.341 0.329 - 4 41 37 78 Rb x -66935.419 3.237 8558.350 0.042 B- -3761.477 8.125 77 928141.868 3.475 - 2 40 38 78 Sr x -63173.941 7.452 8500.096 0.096 B- -11001# 298# 77 932179.980 8.000 - 0 39 39 78 Y x -52173# 298# 8349# 4# B- -11323# 499# 77 943990# 320# - -2 38 40 78 Zr x -40850# 400# 8194# 5# B- * 77 956146# 429# -0 23 51 28 79 Ni x -27570# 600# 8143# 8# B- 14170# 671# 78 970402# 644# - 21 50 29 79 Cu x -41740# 300# 8312# 4# B- 11692# 300# 78 955190# 322# - 19 49 30 79 Zn -53432.295 2.225 8450.582 0.028 B- 9115.384 2.901 78 942638.068 2.388 - 17 48 31 79 Ga -62547.679 1.868 8556.063 0.024 B- 6978.913 37.147 78 932852.301 2.005 - 15 47 32 79 Ge -69526.592 37.181 8634.501 0.471 B- 4109.457 37.456 78 925360.129 39.915 - 13 46 33 79 As -73636.049 5.328 8676.616 0.067 B- 2281.410 5.331 78 920948.445 5.719 - 11 45 34 79 Se -n -75917.459 0.223 8695.592 0.003 B- 150.576 1.038 78 918499.251 0.238 - 9 44 35 79 Br +n -76068.035 1.021 8687.594 0.013 B- -1625.778 3.333 78 918337.601 1.095 - 7 43 36 79 Kr - -74442.257 3.486 8657.112 0.044 B- -3639.271 4.092 78 920082.945 3.742 - 5 42 37 79 Rb x -70802.985 2.142 8601.142 0.027 B- -5326.096 8.653 78 923989.864 2.300 - 3 41 38 79 Sr x -65476.889 8.383 8523.820 0.106 B- -7659.056 79.620 78 929707.664 9.000 - 1 40 39 79 Y x -57817.833 79.177 8416.967 1.002 B- -11048# 310# 78 937930.000 85.000 - -1 39 40 79 Zr x -46770# 300# 8267# 4# B- -15120# 583# 78 949790# 322# - -3 38 41 79 Nb x -31650# 500# 8066# 6# B- * 78 966022# 537# -0 24 52 28 80 Ni x -22630# 700# 8080# 9# B- 13570# 806# 79 975706# 751# - 22 51 29 80 Cu x -36200# 400# 8240# 5# B- 15449# 400# 79 961138# 429# - 20 50 30 80 Zn -51648.612 2.585 8423.545 0.032 B- 7575.055 3.877 79 944552.930 2.774 - 18 49 31 80 Ga x -59223.667 2.891 8508.454 0.036 B- 10311.639 3.541 79 936420.774 3.103 - 16 48 32 80 Ge x -69535.306 2.054 8627.570 0.026 B- 2679.187 3.915 79 925350.774 2.205 - 14 47 33 80 As x -72214.493 3.333 8651.280 0.042 B- 5544.964 3.445 79 922474.548 3.577 - 12 46 34 80 Se -77759.457 0.963 8710.813 0.012 B- -1870.464 0.310 79 916521.785 1.034 - 10 45 35 80 Br - -75888.993 1.012 8677.653 0.013 B- 2004.353 1.154 79 918529.810 1.086 - 8 44 36 80 Kr -77893.346 0.691 8692.928 0.009 B- -5717.879 1.987 79 916378.048 0.742 - 6 43 37 80 Rb x -72175.467 1.863 8611.675 0.023 B- -1864.009 3.933 79 922516.444 2.000 - 4 42 38 80 Sr x -70311.459 3.464 8578.596 0.043 B- -9163.307 7.139 79 924517.540 3.718 - 2 41 39 80 Y x -61148.152 6.242 8454.275 0.078 B- -6788# 300# 79 934354.755 6.701 - 0 40 40 80 Zr x -54360# 300# 8360# 4# B- -15940# 500# 79 941642# 322# - -2 39 41 80 Nb x -38420# 400# 8151# 5# B- * 79 958754# 429# -0 23 52 29 81 Cu x -31420# 500# 8179# 6# B- 14779# 500# 80 966269# 537# - 21 51 30 81 Zn x -46199.663 5.030 8351.925 0.062 B- 11428.292 5.996 80 950402.619 5.400 - 19 50 31 81 Ga x -57627.954 3.264 8483.357 0.040 B- 8663.733 3.851 80 938133.842 3.503 - 17 49 32 81 Ge x -66291.687 2.055 8580.658 0.025 B- 6241.617 3.344 80 928832.942 2.205 - 15 48 33 81 As -72533.304 2.644 8648.056 0.033 B- 3855.684 2.812 80 922132.290 2.838 - 13 47 34 81 Se -76388.988 0.992 8685.999 0.012 B- 1588.046 1.389 80 917993.044 1.065 - 11 46 35 81 Br -77977.034 0.978 8695.946 0.012 B- -280.853 0.471 80 916288.206 1.049 - 9 45 36 81 Kr -77696.181 1.074 8682.820 0.013 B- -2239.511 5.019 80 916589.714 1.152 - 7 44 37 81 Rb -75456.670 4.904 8645.513 0.061 B- -3928.545 5.817 80 918993.927 5.264 - 5 43 38 81 Sr x -71528.125 3.128 8587.354 0.039 B- -5815.214 6.245 80 923211.394 3.358 - 3 42 39 81 Y x -65712.912 5.405 8505.902 0.067 B- -8252.773 94.236 80 929454.283 5.802 - 1 41 40 81 Zr x -57460.139 94.081 8394.358 1.161 B- -11100# 411# 80 938314.000 101.000 - -1 40 41 81 Nb x -46360# 400# 8248# 5# B- -14610# 640# 80 950230# 429# - -3 39 42 81 Mo x -31750# 500# 8058# 6# B- * 80 965915# 537# -0 24 53 29 82 Cu x -25320# 600# 8103# 7# B- 16994# 600# 81 972818# 644# - 22 52 30 82 Zn x -42313.954 3.074 8301.117 0.037 B- 10616.764 3.916 81 954574.099 3.300 - 20 51 31 82 Ga x -52930.719 2.426 8421.049 0.030 B- 12484.348 3.296 81 943176.533 2.604 - 18 50 32 82 Ge x -65415.067 2.241 8563.756 0.027 B- 4690.352 4.345 81 929774.033 2.405 - 16 49 33 82 As x -70105.419 3.729 8611.414 0.045 B- 7488.463 3.758 81 924738.733 4.003 - 14 48 34 82 Se -77593.882 0.467 8693.196 0.006 B- -95.221 1.077 81 916699.537 0.500 - 12 47 35 82 Br -77498.661 0.971 8682.494 0.012 B- 3093.124 0.971 81 916801.760 1.042 - 10 46 36 82 Kr -80591.78515 0.00549 8710.675 0.000 B- -4403.982 3.009 81 913481.15520 0.00589 - 8 45 37 82 Rb IT -76187.803 3.009 8647.427 0.037 B- -177.751 6.705 81 918209.024 3.230 - 6 44 38 82 Sr -76010.053 5.992 8635.718 0.073 B- -7945.961 8.132 81 918399.847 6.432 - 4 43 39 82 Y x -68064.091 5.499 8529.275 0.067 B- -4432.804 12.457 81 926930.188 5.902 - 2 42 40 82 Zr x -63631.287 11.178 8465.676 0.136 B- -11541# 300# 81 931689.000 12.000 - 0 41 41 82 Nb x -52090# 300# 8315# 4# B- -11720# 500# 81 944079# 322# - -2 40 42 82 Mo x -40370# 400# 8163# 5# B- * 81 956661# 429# -0 23 53 30 83 Zn x -36290# 300# 8226# 4# B- 12967# 300# 82 961041# 322# - 21 52 31 83 Ga x -49257.122 2.613 8372.575 0.031 B- 11719.312 3.559 82 947120.301 2.804 - 19 51 32 83 Ge x -60976.435 2.427 8504.345 0.029 B- 8692.888 3.698 82 934539.101 2.605 - 17 50 33 83 As x -69669.323 2.799 8599.653 0.034 B- 5671.207 4.129 82 925206.901 3.004 - 15 49 34 83 Se -n -75340.530 3.036 8658.555 0.037 B- 3673.179 4.839 82 919118.609 3.259 - 13 48 35 83 Br -79013.709 3.795 8693.384 0.046 B- 976.924 3.795 82 915175.289 4.073 - 11 47 36 83 Kr -79990.633 0.009 8695.729 0.000 B- -920.004 2.329 82 914126.518 0.009 - 9 46 37 83 Rb -79070.630 2.329 8675.218 0.028 B- -2273.024 6.424 82 915114.182 2.500 - 7 45 38 83 Sr -76797.606 6.834 8638.407 0.082 B- -4591.941 19.844 82 917554.374 7.336 - 5 44 39 83 Y x -72205.665 18.631 8573.656 0.224 B- -6294.012 19.707 82 922484.025 20.000 - 3 43 40 83 Zr x -65911.654 6.430 8488.399 0.077 B- -8355.571 151.039 82 929240.925 6.902 - 1 42 41 83 Nb x -57556.083 150.902 8378.304 1.818 B- -11216# 428# 82 938211.000 162.000 - -1 41 42 83 Mo x -46340# 401# 8234# 5# B- -15020# 641# 82 950252# 430# - -3 40 43 83 Tc x -31320# 500# 8043# 6# B- * 82 966377# 537# -0 24 54 30 84 Zn x -31930# 400# 8172# 5# B- 12158# 447# 83 965722# 429# - 22 53 31 84 Ga x -44088# 200# 8307# 2# B- 14061# 200# 83 952670# 215# - 20 52 32 84 Ge x -58148.428 3.171 8465.524 0.038 B- 7705.132 4.479 83 937575.091 3.403 - 18 51 33 84 As x -65853.560 3.171 8547.938 0.038 B- 10094.161 3.722 83 929303.291 3.403 - 16 50 34 84 Se -75947.721 1.961 8658.793 0.023 B- 1835.363 25.765 83 918466.762 2.105 - 14 49 35 84 Br -77783.084 25.730 8671.329 0.306 B- 4656.251 25.730 83 916496.419 27.622 - 12 48 36 84 Kr -82439.33510 0.00379 8717.446 0.000 B- -2680.371 2.194 83 911497.72863 0.00407 - 10 47 37 84 Rb -79758.964 2.194 8676.224 0.026 B- 890.606 2.336 83 914375.225 2.355 - 8 46 38 84 Sr -80649.570 1.243 8677.512 0.015 B- -6755.139 4.411 83 913419.120 1.334 - 6 45 39 84 Y -73894.431 4.299 8587.780 0.051 B- -2472.745 6.977 83 920671.061 4.615 - 4 44 40 84 Zr x -71421.686 5.499 8549.029 0.065 B- -10202.968 14.153 83 923325.662 5.903 - 2 43 41 84 Nb x -61218.717 13.041 8418.252 0.155 B- -7049# 298# 83 934279.000 14.000 - 0 42 42 84 Mo x -54170# 298# 8325# 4# B- -16470# 499# 83 941846# 320# - -2 41 43 84 Tc x -37700# 400# 8120# 5# B- * 83 959527# 429# -0 25 55 30 85 Zn x -25230# 500# 8092# 6# B- 14619# 582# 84 972914# 537# - 23 54 31 85 Ga x -39849# 298# 8255# 4# B- 13274# 298# 84 957220# 320# - 21 53 32 85 Ge x -53123.420 3.729 8401.768 0.044 B- 10065.724 4.830 84 942969.659 4.003 - 19 52 33 85 As x -63189.144 3.078 8510.984 0.036 B- 9224.492 4.031 84 932163.659 3.304 - 17 51 34 85 Se +3p -72413.636 2.613 8610.304 0.031 B- 6161.833 4.031 84 922260.759 2.804 - 15 50 35 85 Br +n2p -78575.469 3.078 8673.592 0.036 B- 2904.861 3.671 84 915645.759 3.304 - 13 49 36 85 Kr + -81480.331 2.000 8698.562 0.024 B- 687.000 2.000 84 912527.262 2.147 - 11 48 37 85 Rb -82167.33050 0.00498 8697.441 0.000 B- -1064.051 2.813 84 911789.73760 0.00534 - 9 47 38 85 Sr -81103.280 2.813 8675.718 0.033 B- -3261.157 19.173 84 912932.043 3.020 - 7 46 39 85 Y x -77842.123 18.965 8628.148 0.223 B- -4666.934 20.026 84 916433.039 20.360 - 5 45 40 85 Zr x -73175.189 6.430 8564.039 0.076 B- -6895.514 7.625 84 921443.198 6.902 - 3 44 41 85 Nb x -66279.676 4.099 8473.711 0.048 B- -8769.923 16.357 84 928845.837 4.400 - 1 43 42 85 Mo x -57509.753 15.835 8361.331 0.186 B- -11660# 400# 84 938260.737 17.000 - -1 42 43 85 Tc x -45850# 400# 8215# 5# B- -14900# 640# 84 950778# 429# - -3 41 44 85 Ru x -30950# 500# 8030# 6# B- * 84 966774# 537# -0 24 55 31 86 Ga x -34080# 400# 8186# 5# B- 15320# 593# 85 963414# 429# - 22 54 32 86 Ge x -49399.922 437.802 8354.629 5.091 B- 9562.221 437.816 85 946967.000 470.000 - 20 53 33 86 As x -58962.142 3.450 8456.721 0.040 B- 11541.024 4.267 85 936701.533 3.703 - 18 52 34 86 Se x -70503.167 2.520 8581.822 0.029 B- 5129.085 3.972 85 924311.733 2.705 - 16 51 35 86 Br +pp -75632.252 3.078 8632.365 0.036 B- 7633.414 3.078 85 918805.433 3.304 - 14 50 36 86 Kr -83265.66564 0.00369 8712.029 0.000 B- -518.672 0.200 85 910610.62627 0.00396 - 12 49 37 86 Rb -n -82746.993 0.200 8696.901 0.002 B- 1776.096 0.200 85 911167.443 0.214 - 10 48 38 86 Sr -84523.08935 0.00522 8708.456 0.000 B- -5240.000 14.142 85 909260.72631 0.00561 - 8 47 39 86 Y - -79283.089 14.142 8638.428 0.164 B- -1314.075 14.585 85 914886.098 15.182 - 6 46 40 86 Zr -77969.014 3.566 8614.051 0.041 B- -8834.960 6.552 85 916296.815 3.827 - 4 45 41 86 Nb x -69134.054 5.499 8502.222 0.064 B- -5023.810 6.642 85 925781.535 5.903 - 2 44 42 86 Mo x -64110.245 3.726 8434.709 0.043 B- -12540# 300# 85 931174.817 4.000 - 0 43 43 86 Tc x -51570# 300# 8280# 3# B- -11800# 500# 85 944637# 322# - -2 42 44 86 Ru x -39770# 400# 8133# 5# B- * 85 957305# 429# -0 25 56 31 87 Ga x -29250# 500# 8129# 6# B- 14828# 583# 86 968599# 537# - 23 55 32 87 Ge x -44078# 300# 8290# 3# B- 11540# 300# 86 952680# 322# - 21 54 33 87 As x -55617.907 2.985 8413.851 0.034 B- 10808.218 3.726 86 940291.718 3.204 - 19 53 34 87 Se x -66426.125 2.241 8529.091 0.026 B- 7465.552 3.877 86 928688.618 2.405 - 17 52 35 87 Br 2p-n -73891.676 3.171 8605.910 0.036 B- 6817.845 3.181 86 920674.018 3.404 - 15 51 36 87 Kr -n -80709.522 0.246 8675.283 0.003 B- 3888.269 0.246 86 913354.759 0.264 - 13 50 37 87 Rb -84597.791 0.006 8710.983 0.000 B- 282.275 0.006 86 909180.531 0.006 - 11 49 38 87 Sr -84880.06595 0.00510 8705.236 0.000 B- -1861.690 1.128 86 908877.49615 0.00548 - 9 48 39 87 Y - -83018.376 1.128 8674.844 0.013 B- -3671.239 4.296 86 910876.102 1.210 - 7 47 40 87 Zr -79347.137 4.146 8623.654 0.048 B- -5472.651 7.963 86 914817.339 4.450 - 5 46 41 87 Nb x -73874.486 6.802 8551.757 0.078 B- -6989.678 7.378 86 920692.472 7.302 - 3 45 42 87 Mo -66884.808 2.857 8462.424 0.033 B- -9194.764 5.073 86 928196.201 3.067 - 1 44 43 87 Tc x -57690.044 4.192 8347.744 0.048 B- -12170# 400# 86 938067.187 4.500 - -1 43 44 87 Ru x -45520# 400# 8199# 5# B- * 86 951132# 429# -0 24 56 32 88 Ge x -40138# 400# 8243# 5# B- 10582# 445# 87 956910# 429# - 22 55 33 88 As x -50720# 196# 8354# 2# B- 13164# 196# 87 945550# 210# - 20 54 34 88 Se x -63884.195 3.357 8495.004 0.038 B- 6831.763 4.613 87 931417.491 3.604 - 18 53 35 88 Br ++ -70715.959 3.171 8563.747 0.036 B- 8975.327 4.106 87 924083.291 3.404 - 16 52 36 88 Kr x -79691.286 2.608 8656.849 0.030 B- 2917.709 2.613 87 914447.881 2.800 - 14 51 37 88 Rb -82608.995 0.159 8681.115 0.002 B- 5312.623 0.159 87 911315.591 0.171 - 12 50 38 88 Sr -87921.61793 0.00558 8732.595 0.000 B- -3622.600 1.500 87 905612.25561 0.00599 - 10 49 39 88 Y - -84299.018 1.500 8682.539 0.017 B- -670.147 5.608 87 909501.276 1.610 - 8 48 40 88 Zr -83628.871 5.403 8666.033 0.061 B- -7455.284 58.886 87 910220.709 5.800 - 6 47 41 88 Nb -76173.586 58.810 8572.424 0.668 B- -3487.042 58.933 87 918224.287 63.134 - 4 46 42 88 Mo x -72686.544 3.819 8523.908 0.043 B- -11005.229 149.088 87 921967.781 4.100 - 2 45 43 88 Tc x -61681.315 149.039 8389.958 1.694 B- -7342# 335# 87 933782.381 160.000 - 0 44 44 88 Ru x -54340# 300# 8298# 3# B- -17479# 500# 87 941664# 322# - -2 43 45 88 Rh x -36860# 400# 8090# 5# B- * 87 960429# 429# -0 25 57 32 89 Ge x -33729# 400# 8169# 4# B- 13069# 499# 88 963790# 429# - 23 56 33 89 As x -46798# 298# 8307# 3# B- 12194# 298# 88 949760# 320# - 21 55 34 89 Se x -58992.391 3.729 8435.279 0.042 B- 9281.872 4.951 88 936669.059 4.003 - 19 54 35 89 Br x -68274.263 3.264 8530.779 0.037 B- 8261.522 3.904 88 926704.559 3.504 - 17 53 36 89 Kr x -76535.785 2.142 8614.815 0.024 B- 5176.604 5.834 88 917835.450 2.300 - 15 52 37 89 Rb -81712.388 5.427 8664.189 0.061 B- 4496.628 5.427 88 912278.137 5.825 - 13 51 38 89 Sr -86209.017 0.092 8705.922 0.001 B- 1499.336 1.615 88 907450.808 0.098 - 11 50 39 89 Y -87708.352 1.612 8713.978 0.018 B- -2832.792 2.776 88 905841.205 1.730 - 9 49 40 89 Zr -84875.561 3.083 8673.359 0.035 B- -4250.351 23.743 88 908882.332 3.310 - 7 48 41 89 Nb -80625.209 23.631 8616.812 0.266 B- -5610.275 23.953 88 913445.272 25.369 - 5 47 42 89 Mo x -75014.935 3.912 8544.984 0.044 B- -7620.087 5.467 88 919468.150 4.200 - 3 46 43 89 Tc x -67394.848 3.819 8450.575 0.043 B- -9135# 298# 88 927648.650 4.100 - 1 45 44 89 Ru x -58260# 298# 8339# 3# B- -12400# 468# 88 937455# 320# - -1 44 45 89 Rh -p -45861# 361# 8191# 4# B- * 88 950767# 387# -0 26 58 32 90 Ge x -29221# 500# 8118# 6# B- 12109# 640# 89 968630# 537# - 24 57 33 90 As x -41330# 400# 8244# 4# B- 14470# 518# 89 955630# 429# - 22 56 34 90 Se x -55800.217 329.749 8395.766 3.664 B- 8200.081 329.766 89 940096.000 354.000 - 20 55 35 90 Br x -64000.298 3.357 8478.186 0.037 B- 10958.952 3.840 89 931292.850 3.604 - 18 54 36 90 Kr x -74959.250 1.863 8591.259 0.021 B- 4405.154 6.746 89 919527.930 2.000 - 16 53 37 90 Rb -79364.404 6.484 8631.512 0.072 B- 6583.723 6.544 89 914798.803 6.960 - 14 52 38 90 Sr -85948.127 2.124 8695.972 0.024 B- 545.934 1.406 89 907730.885 2.280 - 12 51 39 90 Y -86494.062 1.611 8693.345 0.018 B- 2278.474 1.609 89 907144.800 1.729 - 10 50 40 90 Zr -88772.535 0.118 8709.969 0.001 B- -6111.016 3.316 89 904698.758 0.126 - 8 49 41 90 Nb -82661.519 3.317 8633.376 0.037 B- -2489.016 3.316 89 911259.204 3.561 - 6 48 42 90 Mo -80172.503 3.463 8597.028 0.038 B- -9447.816 3.611 89 913931.272 3.717 - 4 47 43 90 Tc x -70724.687 1.025 8483.359 0.011 B- -5840.895 3.869 89 924073.921 1.100 - 2 46 44 90 Ru -64883.792 3.730 8409.768 0.041 B- -13184# 300# 89 930344.379 4.004 - 0 45 45 90 Rh x -51700# 300# 8255# 3# B- -11990# 500# 89 944498# 322# - -2 44 46 90 Pd x -39710# 400# 8113# 4# B- * 89 957370# 429# -0 25 58 33 91 As x -36896# 400# 8193# 4# B- 13684# 589# 90 960390# 429# - 23 57 34 91 Se x -50580.124 433.145 8334.837 4.760 B- 10527.169 433.159 90 945700.000 465.000 - 21 56 35 91 Br -n2p -61107.294 3.544 8441.923 0.039 B- 9866.671 4.190 90 934398.618 3.804 - 19 55 36 91 Kr x -70973.965 2.236 8541.751 0.025 B- 6771.072 8.115 90 923806.310 2.400 - 17 54 37 91 Rb -77745.037 7.801 8607.561 0.086 B- 5906.890 8.873 90 916537.265 8.375 - 15 53 38 91 Sr -83651.927 5.453 8663.875 0.060 B- 2699.369 5.247 90 910195.958 5.853 - 13 52 39 91 Y -86351.295 1.843 8684.941 0.020 B- 1544.271 1.840 90 907298.066 1.978 - 11 51 40 91 Zr -87895.566 0.105 8693.314 0.001 B- -1257.565 2.924 90 905640.223 0.112 - 9 50 41 91 Nb -86638.001 2.926 8670.897 0.032 B- -4429.180 6.744 90 906990.274 3.141 - 7 49 42 91 Mo -82208.821 6.238 8613.628 0.069 B- -6222.175 6.671 90 911745.195 6.696 - 5 48 43 91 Tc -75986.646 2.363 8536.655 0.026 B- -7746.824 3.242 90 918424.975 2.536 - 3 47 44 91 Ru -68239.823 2.221 8442.928 0.024 B- -9670# 298# 90 926741.532 2.384 - 1 46 45 91 Rh x -58570# 298# 8328# 3# B- -12639# 499# 90 937123# 320# - -1 45 46 91 Pd x -45930# 401# 8181# 4# B- * 90 950692# 430# -0 26 59 33 92 As x -30981# 500# 8127# 5# B- 15742# 640# 91 966740# 537# - 24 58 34 92 Se x -46724# 400# 8290# 4# B- 9509# 400# 91 949840# 429# - 22 57 35 92 Br x -56232.805 6.709 8384.911 0.073 B- 12536.514 7.232 91 939631.597 7.202 - 20 56 36 92 Kr x -68769.320 2.701 8512.674 0.029 B- 6003.118 6.692 91 926173.094 2.900 - 18 55 37 92 Rb -74772.438 6.123 8569.422 0.067 B- 8094.923 6.419 91 919728.481 6.573 - 16 54 38 92 Sr -82867.361 3.423 8648.906 0.037 B- 1949.132 9.384 91 911038.224 3.675 - 14 53 39 92 Y -84816.492 9.127 8661.589 0.099 B- 3642.535 9.127 91 908945.745 9.798 - 12 52 40 92 Zr -88459.028 0.102 8692.678 0.001 B- -2005.736 1.782 91 905035.322 0.109 - 10 51 41 92 Nb -86453.292 1.785 8662.372 0.019 B- 355.284 1.791 91 907188.568 1.915 - 8 50 42 92 Mo -86808.576 0.157 8657.730 0.002 B- -7882.884 3.106 91 906807.155 0.168 - 6 49 43 92 Tc -78925.693 3.102 8563.543 0.034 B- -4624.492 4.125 91 915269.779 3.330 - 4 48 44 92 Ru -74301.201 2.718 8504.773 0.030 B- -11302.114 5.153 91 920234.375 2.917 - 2 47 45 92 Rh x -62999.087 4.378 8373.420 0.048 B- -8419# 300# 91 932367.694 4.700 - 0 46 46 92 Pd x -54580# 300# 8273# 3# B- -17450# 583# 91 941406# 322# - -2 45 47 92 Ag x -37130# 500# 8075# 5# B- * 91 960139# 537# -0 25 59 34 93 Se x -40716# 400# 8223# 4# B- 12175# 588# 92 956290# 429# - 23 58 35 93 Br x -52890.230 430.816 8345.598 4.632 B- 11245.765 430.823 92 943220.000 462.500 - 21 57 36 93 Kr x -64135.994 2.515 8458.108 0.027 B- 8483.907 8.224 92 931147.174 2.700 - 19 56 37 93 Rb -72619.901 7.830 8540.920 0.084 B- 7465.938 8.876 92 922039.325 8.406 - 17 55 38 93 Sr -80085.838 7.554 8612.787 0.081 B- 4141.319 11.697 92 914024.311 8.109 - 15 54 39 93 Y -84227.157 10.488 8648.905 0.113 B- 2894.875 10.483 92 909578.422 11.259 - 13 53 40 93 Zr -87122.032 0.457 8671.620 0.005 B- 90.806 1.484 92 906470.646 0.490 - 11 52 41 93 Nb -87212.838 1.491 8664.184 0.016 B- -405.769 1.501 92 906373.161 1.600 - 9 51 42 93 Mo -n -86807.069 0.181 8651.409 0.002 B- -3200.963 1.004 92 906808.773 0.193 - 7 50 43 93 Tc -p -83606.106 1.012 8608.577 0.011 B- -6389.393 2.299 92 910245.149 1.086 - 5 49 44 93 Ru -77216.713 2.065 8531.462 0.022 B- -8204.913 3.343 92 917104.444 2.216 - 3 48 45 93 Rh -69011.800 2.629 8434.825 0.028 B- -10011# 301# 92 925912.781 2.821 - 1 47 46 93 Pd +p -59001# 300# 8319# 3# B- -12734# 501# 92 936660# 323# - -1 46 47 93 Ag x -46267# 401# 8173# 4# B- * 92 950330# 430# -0 26 60 34 94 Se x -36803# 500# 8180# 5# B- 10597# 583# 93 960490# 537# - 24 59 35 94 Br x -47400# 300# 8284# 3# B- 13948# 300# 93 949114# 322# - 22 58 36 94 Kr x -61347.772 12.109 8424.331 0.129 B- 7215.013 12.278 93 934140.454 13.000 - 20 57 37 94 Rb -68562.785 2.029 8492.764 0.022 B- 10282.926 2.623 93 926394.818 2.177 - 18 56 38 94 Sr -78845.711 1.663 8593.834 0.018 B- 3505.752 6.422 93 915355.643 1.785 - 16 55 39 94 Y -82351.463 6.380 8622.806 0.068 B- 4917.859 6.380 93 911592.063 6.849 - 14 54 40 94 Zr -87269.322 0.164 8666.801 0.002 B- -900.260 1.500 93 906312.524 0.175 - 12 53 41 94 Nb -86369.062 1.491 8648.901 0.016 B- 2045.002 1.494 93 907278.992 1.601 - 10 52 42 94 Mo -88414.065 0.141 8662.333 0.002 B- -4255.748 4.069 93 905083.592 0.151 - 8 51 43 94 Tc - -84158.317 4.071 8608.736 0.043 B- -1574.726 5.143 93 909652.325 4.370 - 6 50 44 94 Ru -82583.591 3.143 8583.661 0.033 B- -9675.978 4.615 93 911342.863 3.374 - 4 49 45 94 Rh -72907.613 3.379 8472.402 0.036 B- -6805.345 5.459 93 921730.453 3.627 - 2 48 46 94 Pd x -66102.268 4.287 8391.682 0.046 B- -13693# 400# 93 929036.292 4.602 - 0 47 47 94 Ag x -52410# 400# 8238# 4# B- -12270# 640# 93 943736# 429# - -2 46 48 94 Cd x -40140# 500# 8099# 5# B- * 93 956908# 537# -0 27 61 34 95 Se x -30460# 500# 8112# 5# B- 13311# 582# 94 967300# 537# - 25 60 35 95 Br x -43771# 298# 8244# 3# B- 12388# 299# 94 953010# 320# - 23 59 36 95 Kr x -56158.913 18.630 8365.995 0.196 B- 9732.580 27.513 94 939710.923 20.000 - 21 58 37 95 Rb -65891.493 20.245 8460.208 0.213 B- 9228.058 20.204 94 929262.568 21.734 - 19 57 38 95 Sr -75119.551 5.812 8549.111 0.061 B- 6089.296 7.240 94 919355.840 6.239 - 17 56 39 95 Y -81208.848 6.779 8604.973 0.071 B- 4451.092 6.772 94 912818.711 7.277 - 15 55 40 95 Zr -85659.940 0.869 8643.592 0.009 B- 1126.318 0.985 94 908040.267 0.933 - 13 54 41 95 Nb -86786.258 0.508 8647.212 0.005 B- 925.601 0.494 94 906831.115 0.545 - 11 53 42 95 Mo -87711.858 0.123 8648.720 0.001 B- -1690.518 5.078 94 905837.442 0.132 - 9 52 43 95 Tc -86021.341 5.080 8622.690 0.053 B- -2563.596 10.531 94 907652.287 5.453 - 7 51 44 95 Ru -83457.745 9.502 8587.470 0.100 B- -5117.138 10.266 94 910404.420 10.200 - 5 50 45 95 Rh -78340.606 3.886 8525.370 0.041 B- -8374.706 4.928 94 915897.895 4.171 - 3 49 46 95 Pd x -69965.900 3.031 8428.980 0.032 B- -10369# 298# 94 924888.512 3.253 - 1 48 47 95 Ag x -59597# 298# 8312# 3# B- -12966# 499# 94 936020# 320# - -1 47 48 95 Cd x -46631# 401# 8167# 4# B- * 94 949940# 430# -0 26 61 35 96 Br x -38163# 298# 8184# 3# B- 14916# 299# 95 959030# 320# - 24 60 36 96 Kr x -53079.678 20.493 8330.851 0.213 B- 8274.671 20.765 95 943016.618 22.000 - 22 59 37 96 Rb -61354.349 3.353 8408.896 0.035 B- 11569.808 9.115 95 934133.393 3.599 - 20 58 38 96 Sr -72924.157 8.475 8521.265 0.088 B- 5411.738 9.726 95 921712.692 9.098 - 18 57 39 96 Y -78335.895 6.088 8569.488 0.063 B- 7102.951 6.087 95 915902.953 6.535 - 16 56 40 96 Zr -85438.846 0.114 8635.327 0.001 B- 163.971 0.100 95 908277.621 0.122 - 14 55 41 96 Nb -85602.816 0.147 8628.886 0.002 B- 3192.059 0.107 95 908101.591 0.157 - 12 54 42 96 Mo -88794.876 0.120 8653.987 0.001 B- -2973.242 5.145 95 904674.774 0.128 - 10 53 43 96 Tc - -85821.634 5.146 8614.866 0.054 B- 258.738 5.146 95 907866.681 5.524 - 8 52 44 96 Ru -86080.372 0.170 8609.412 0.002 B- -6392.654 10.000 95 907588.914 0.182 - 6 51 45 96 Rh - -79687.718 10.001 8534.673 0.104 B- -3504.312 10.844 95 914451.710 10.737 - 4 50 46 96 Pd x -76183.406 4.194 8490.020 0.044 B- -11671.771 90.181 95 918213.744 4.502 - 2 49 47 96 Ag ep -64511.636 90.084 8360.290 0.938 B- -8939# 411# 95 930743.906 96.708 - 0 48 48 96 Cd x -55573# 401# 8259# 4# B- -17683# 641# 95 940340# 430# - -2 47 49 96 In x -37890# 500# 8067# 5# B- * 95 959323# 537# -0 27 62 35 97 Br x -34055# 401# 8140# 4# B- 13368# 421# 96 963440# 430# - 25 61 36 97 Kr x -47423.492 130.409 8269.864 1.344 B- 11095.645 130.423 96 949088.784 140.000 - 23 60 37 97 Rb -58519.137 1.912 8376.186 0.020 B- 10062.317 3.888 96 937177.118 2.052 - 21 59 38 97 Sr -68581.454 3.385 8471.856 0.035 B- 7539.969 7.521 96 926374.776 3.633 - 19 58 39 97 Y + -76121.424 6.719 8541.522 0.069 B- 6821.237 6.707 96 918280.286 7.213 - 17 57 40 97 Zr -82942.661 0.414 8603.779 0.004 B- 2663.115 4.248 96 910957.386 0.444 - 15 56 41 97 Nb -85605.776 4.249 8623.168 0.044 B- 1938.915 4.248 96 908098.414 4.561 - 13 55 42 97 Mo -87544.691 0.165 8635.092 0.002 B- -320.266 4.117 96 906016.903 0.176 - 11 54 43 97 Tc -87224.424 4.118 8623.725 0.042 B- -1103.873 4.956 96 906360.723 4.420 - 9 53 44 97 Ru -n -86120.552 2.763 8604.279 0.028 B- -3523.000 35.355 96 907545.779 2.965 - 7 52 45 97 Rh - -82597.552 35.463 8559.894 0.366 B- -4791.709 35.792 96 911327.876 38.071 - 5 51 46 97 Pd x -77805.843 4.844 8502.430 0.050 B- -6980.000 110.000 96 916471.987 5.200 - 3 50 47 97 Ag - -70825.843 110.107 8422.405 1.135 B- -10372# 318# 96 923965.326 118.204 - 1 49 48 97 Cd x -60454# 298# 8307# 3# B- -13264# 499# 96 935100# 320# - -1 48 49 97 In x -47189# 401# 8163# 4# B- * 96 949340# 430# -0 28 63 35 98 Br x -28250# 400# 8080# 4# B- 16061# 499# 97 969672# 429# - 26 62 36 98 Kr x -44311# 298# 8236# 3# B- 10058# 299# 97 952430# 320# - 24 61 37 98 Rb -54369.146 16.083 8330.729 0.164 B- 12053.958 16.403 97 941632.317 17.265 - 22 60 38 98 Sr -66423.104 3.226 8445.745 0.033 B- 5871.673 8.558 97 928691.860 3.463 - 20 59 39 98 Y p-2n -72294.777 7.929 8497.677 0.081 B- 8991.932 11.576 97 922388.360 8.511 - 18 58 40 98 Zr -81286.709 8.451 8581.448 0.086 B- 2237.890 9.819 97 912735.124 9.072 - 16 57 41 98 Nb -pn -83524.598 5.001 8596.301 0.051 B- 4591.373 5.003 97 910332.650 5.369 - 14 56 42 98 Mo -88115.972 0.174 8635.168 0.002 B- -1683.766 3.377 97 905403.608 0.186 - 12 55 43 98 Tc -86432.205 3.380 8610.004 0.034 B- 1792.653 7.157 97 907211.205 3.628 - 10 54 44 98 Ru -88224.858 6.463 8620.313 0.066 B- -5049.653 10.000 97 905286.713 6.937 - 8 53 45 98 Rh - -83175.205 11.906 8560.803 0.121 B- -1854.229 12.816 97 910707.740 12.782 - 6 52 46 98 Pd -81320.975 4.742 8533.899 0.048 B- -8254.560 33.098 97 912698.337 5.090 - 4 51 47 98 Ag -73066.415 32.907 8441.686 0.336 B- -5430.000 40.000 97 921559.972 35.327 - 2 50 48 98 Cd - -67636.415 51.797 8378.295 0.529 B- -13740# 303# 97 927389.317 55.605 - 0 49 49 98 In x -53896# 298# 8230# 3# B- * 97 942140# 320# -0 27 63 36 99 Kr x -38759# 401# 8178# 4# B- 12362# 401# 98 958390# 430# - 25 62 37 99 Rb x -51121.143 4.031 8295.300 0.041 B- 11400.258 6.223 98 945119.192 4.327 - 23 61 38 99 Sr -62521.401 4.741 8402.552 0.048 B- 8128.424 8.138 98 932880.511 5.089 - 21 60 39 99 Y x -70649.825 6.627 8476.755 0.067 B- 6970.792 12.409 98 924154.288 7.114 - 19 59 40 99 Zr -77620.617 10.502 8539.264 0.106 B- 4714.724 15.950 98 916670.835 11.274 - 17 58 41 99 Nb +p -82335.341 12.004 8578.985 0.121 B- 3634.758 12.006 98 911609.371 12.886 - 15 57 42 99 Mo -85970.098 0.229 8607.797 0.002 B- 1357.764 0.890 98 907707.298 0.245 - 13 56 43 99 Tc -87327.862 0.908 8613.610 0.009 B- 297.519 0.946 98 906249.678 0.974 - 11 55 44 99 Ru -87625.381 0.344 8608.712 0.003 B- -2044.081 6.690 98 905930.278 0.369 - 9 54 45 99 Rh -85581.300 6.697 8580.163 0.068 B- -3398.649 8.008 98 908124.690 7.189 - 7 53 46 99 Pd -82182.651 4.981 8537.930 0.050 B- -5470.178 8.004 98 911773.290 5.347 - 5 52 47 99 Ag x -76712.473 6.265 8474.774 0.063 B- -6781.350 6.462 98 917645.768 6.725 - 3 51 48 99 Cd x -69931.123 1.584 8398.373 0.016 B- -8555# 298# 98 924925.847 1.700 - 1 50 49 99 In x -61376# 298# 8304# 3# B- -13432# 585# 98 934110# 320# - -1 49 50 99 Sn x -47944# 503# 8160# 5# B- * 98 948530# 540# -0 28 64 36 100 Kr x -35052# 401# 8140# 4# B- 11195# 401# 99 962370# 430# - 26 63 37 100 Rb x -46247.064 19.561 8244.320 0.196 B- 13573.838 20.831 99 950351.731 21.000 - 24 62 38 100 Sr -59820.903 7.160 8372.234 0.072 B- 7506.493 13.273 99 935779.615 7.686 - 22 61 39 100 Y x -67327.396 11.186 8439.476 0.112 B- 9050.041 13.830 99 927721.063 12.008 - 20 60 40 100 Zr -76377.437 8.149 8522.153 0.081 B- 3419.963 11.398 99 918005.444 8.748 - 18 59 41 100 Nb IT -79797.399 7.986 8548.529 0.080 B- 6395.626 7.992 99 914333.963 8.573 - 16 58 42 100 Mo -86193.025 0.302 8604.662 0.003 B- -172.080 1.371 99 907467.976 0.323 - 14 57 43 100 Tc -n -86020.945 1.351 8595.118 0.014 B- 3206.444 1.376 99 907652.711 1.450 - 12 56 44 100 Ru -89227.389 0.343 8619.359 0.003 B- -3636.262 18.123 99 904210.452 0.368 - 10 55 45 100 Rh -85591.126 18.125 8575.172 0.181 B- -378.348 25.289 99 908114.141 19.458 - 8 54 46 100 Pd -85212.778 17.638 8563.566 0.176 B- -7074.819 18.333 99 908520.315 18.935 - 6 53 47 100 Ag x -78137.959 5.000 8484.994 0.050 B- -3943.363 5.273 99 916115.445 5.367 - 4 52 48 100 Cd -74194.596 1.677 8437.737 0.017 B- -9881.624 182.517 99 920348.820 1.799 - 2 51 49 100 In -64312.972 182.519 8331.097 1.825 B- -7030.000 240.000 99 930957.180 195.942 - 0 50 50 100 Sn - -57282.972 301.518 8252.974 3.015 B- * 99 938504.196 323.693 -0 29 65 36 101 Kr x -29128# 503# 8081# 5# B- 13717# 541# 100 968730# 540# - 27 64 37 101 Rb + -42845# 200# 8209# 2# B- 12480# 200# 100 954004# 215# - 25 63 38 101 Sr x -55324.907 8.480 8324.740 0.084 B- 9736.095 11.055 100 940606.266 9.103 - 23 62 39 101 Y x -65061.002 7.092 8413.391 0.070 B- 8104.955 10.933 100 930154.138 7.614 - 21 61 40 101 Zr -73165.957 8.339 8485.892 0.083 B- 5725.534 9.143 100 921453.110 8.951 - 19 60 41 101 Nb x -78891.491 3.749 8534.835 0.037 B- 4628.458 3.738 100 915306.496 4.024 - 17 59 42 101 Mo -n -83519.949 0.309 8572.915 0.003 B- 2824.645 24.002 100 910337.641 0.331 - 15 58 43 101 Tc + -86344.594 24.004 8593.136 0.238 B- 1613.520 24.000 100 907305.260 25.768 - 13 57 44 101 Ru -87958.114 0.415 8601.365 0.004 B- -545.697 5.852 100 905573.075 0.445 - 11 56 45 101 Rh -87412.416 5.841 8588.216 0.058 B- -1980.284 3.903 100 906158.905 6.270 - 9 55 46 101 Pd -85432.132 4.588 8560.864 0.045 B- -4097.759 6.668 100 908284.828 4.925 - 7 54 47 101 Ag x -81334.374 4.838 8512.546 0.048 B- -5497.918 5.063 100 912683.953 5.193 - 5 53 48 101 Cd x -75836.456 1.490 8450.365 0.015 B- -7223# 196# 100 918586.211 1.600 - 3 52 49 101 In x -68614# 196# 8371# 2# B- -8308# 358# 100 926340# 210# - 1 51 50 101 Sn ep -60305.626 300.005 8281.102 2.970 B- * 100 935259.244 322.068 -0 28 65 37 102 Rb x -37707# 298# 8157# 3# B- 14452# 306# 101 959520# 320# - 26 64 38 102 Sr x -52159.304 67.068 8291.220 0.658 B- 9013.873 67.191 101 944004.680 72.000 - 24 63 39 102 Y x -61173.177 4.077 8371.922 0.040 B- 10414.530 9.669 101 934327.889 4.377 - 22 62 40 102 Zr -71587.707 8.767 8466.355 0.086 B- 4716.837 9.053 101 923147.431 9.412 - 20 61 41 102 Nb -76304.544 2.545 8504.928 0.025 B- 7261.517 8.675 101 918083.697 2.732 - 18 60 42 102 Mo -83566.061 8.312 8568.450 0.081 B- 1006.817 12.373 101 910288.138 8.923 - 16 59 43 102 Tc -84572.878 9.166 8570.650 0.090 B- 4533.558 9.165 101 909207.275 9.840 - 14 58 44 102 Ru -89106.437 0.418 8607.427 0.004 B- -2323.119 6.396 101 904340.300 0.448 - 12 57 45 102 Rh - -86783.318 6.410 8576.981 0.063 B- 1119.853 6.406 101 906834.270 6.881 - 10 56 46 102 Pd -87903.171 0.554 8580.290 0.005 B- -5656.480 8.190 101 905632.058 0.594 - 8 55 47 102 Ag + -82246.691 8.171 8517.164 0.080 B- -2587.000 8.000 101 911704.540 8.771 - 6 54 48 102 Cd -79659.691 1.662 8484.131 0.016 B- -8964.807 4.865 101 914481.799 1.784 - 4 53 49 102 In -70694.884 4.573 8388.571 0.045 B- -5760.000 100.000 101 924105.916 4.909 - 2 52 50 102 Sn - -64934.884 100.105 8324.430 0.981 B- * 101 930289.530 107.466 -0 29 66 37 103 Rb x -33608# 401# 8117# 4# B- 13814# 446# 102 963920# 430# - 27 65 38 103 Sr x -47422# 196# 8243# 2# B- 11035# 196# 102 949090# 210# - 25 64 39 103 Y x -58457.575 11.204 8342.638 0.109 B- 9357.759 14.518 102 937243.208 12.028 - 23 63 40 103 Zr x -67815.334 9.232 8425.895 0.090 B- 7213.337 10.036 102 927197.240 9.911 - 21 62 41 103 Nb x -75028.671 3.935 8488.331 0.038 B- 5931.999 10.036 102 919453.403 4.224 - 19 61 42 103 Mo x -80960.670 9.232 8538.328 0.090 B- 3643.197 13.471 102 913085.140 9.911 - 17 60 43 103 Tc +p -84603.867 9.810 8566.103 0.095 B- 2663.304 9.808 102 909174.008 10.531 - 15 59 44 103 Ru -87267.171 0.443 8584.365 0.004 B- 764.538 2.260 102 906314.833 0.475 - 13 58 45 103 Rh -88031.708 2.301 8584.192 0.022 B- -574.519 2.420 102 905494.068 2.470 - 11 57 46 103 Pd -n -87457.189 0.950 8571.019 0.009 B- -2654.498 4.207 102 906110.840 1.019 - 9 56 47 103 Ag x -84802.692 4.099 8537.651 0.040 B- -4151.075 4.481 102 908960.560 4.400 - 7 55 48 103 Cd -80651.616 1.811 8489.754 0.018 B- -6019.026 9.754 102 913416.923 1.943 - 5 54 49 103 In -74632.591 9.625 8423.721 0.093 B- -7660.000 70.000 102 919878.613 10.332 - 3 53 50 103 Sn - -66972.591 70.659 8341.757 0.686 B- -10794# 306# 102 928101.962 75.855 - 1 52 51 103 Sb x -56178# 298# 8229# 3# B- * 102 939690# 320# -0 28 66 38 104 Sr x -44106# 298# 8210# 3# B- 9958# 499# 103 952650# 320# - 26 65 39 104 Y x -54064# 401# 8298# 4# B- 11660# 401# 103 941960# 430# - 24 64 40 104 Zr x -65724.060 9.325 8402.377 0.090 B- 6094.952 9.699 103 929442.315 10.011 - 22 63 41 104 Nb x -71819.012 2.737 8453.459 0.026 B- 8530.957 9.311 103 922899.115 2.938 - 20 62 42 104 Mo -80349.968 8.921 8527.965 0.086 B- 2153.476 24.167 103 913740.756 9.576 - 18 61 43 104 Tc -82503.444 24.888 8541.149 0.239 B- 5592.266 24.939 103 911428.905 26.718 - 16 60 44 104 Ru -88095.710 2.498 8587.399 0.024 B- -1136.362 3.364 103 905425.360 2.681 - 14 59 45 104 Rh -n -86959.348 2.303 8568.949 0.022 B- 2435.758 2.660 103 906645.295 2.472 - 12 58 46 104 Pd +n -89395.105 1.336 8584.848 0.013 B- -4278.654 4.000 103 904030.401 1.434 - 10 57 47 104 Ag - -85116.452 4.217 8536.184 0.041 B- -1148.072 4.537 103 908623.725 4.527 - 8 56 48 104 Cd -83968.380 1.673 8517.622 0.016 B- -7785.716 6.013 103 909856.230 1.795 - 6 55 49 104 In x -76182.665 5.775 8435.237 0.056 B- -4555.617 8.146 103 918214.540 6.200 - 4 54 50 104 Sn -71627.047 5.745 8383.911 0.055 B- -12453.427 122.579 103 923105.197 6.167 - 2 53 51 104 Sb -p -59173.620 122.444 8256.644 1.177 B- * 103 936474.502 131.449 -0 29 67 38 105 Sr x -38610# 503# 8156# 5# B- 12660# 1428# 104 958550# 540# - 27 66 39 105 Y x -51270.361 1336.694 8269.020 12.730 B- 10194.373 1336.749 104 944959.000 1435.000 - 25 65 40 105 Zr x -61464.734 12.118 8358.659 0.115 B- 8450.817 12.770 104 934014.890 13.008 - 23 64 41 105 Nb x -69915.551 4.028 8431.692 0.038 B- 7421.590 9.920 104 924942.564 4.324 - 21 63 42 105 Mo -77337.141 9.065 8494.923 0.086 B- 4952.947 35.031 104 916975.159 9.731 - 19 62 43 105 Tc -82290.088 35.264 8534.643 0.336 B- 3644.402 35.280 104 911657.952 37.857 - 17 61 44 105 Ru -85934.490 2.499 8561.900 0.024 B- 1916.752 2.851 104 907745.525 2.682 - 15 60 45 105 Rh -87851.243 2.502 8572.704 0.024 B- 566.646 2.346 104 905687.806 2.685 - 13 59 46 105 Pd -88417.888 1.138 8570.650 0.011 B- -1347.052 4.670 104 905079.487 1.222 - 11 58 47 105 Ag -87070.836 4.544 8550.370 0.043 B- -2736.997 4.362 104 906525.607 4.877 - 9 57 48 105 Cd -84333.839 1.392 8516.852 0.013 B- -4693.267 10.341 104 909463.895 1.494 - 7 56 49 105 In x -79640.572 10.246 8464.704 0.098 B- -6302.580 10.989 104 914502.324 11.000 - 5 55 50 105 Sn -73337.992 3.971 8397.228 0.038 B- -9322.510 22.185 104 921268.423 4.263 - 3 54 51 105 Sb +a -64015.482 21.827 8300.992 0.208 B- -11203.972 300.813 104 931276.549 23.431 - 1 53 52 105 Te -a -52811.510 300.020 8186.836 2.857 B- * 104 943304.508 322.084 -0 30 68 38 106 Sr x -34790# 600# 8119# 6# B- 11263# 783# 105 962651# 644# - 28 67 39 106 Y x -46053# 503# 8218# 5# B- 12497# 664# 105 950560# 540# - 26 66 40 106 Zr x -58549.987 433.145 8328.450 4.086 B- 7653.370 433.164 105 937144.000 465.000 - 24 65 41 106 Nb x -66203.357 4.122 8393.271 0.039 B- 9931.170 10.026 105 928927.768 4.424 - 22 64 42 106 Mo x -76134.528 9.140 8479.581 0.086 B- 3641.695 15.284 105 918266.218 9.812 - 20 63 43 106 Tc + -79776.223 12.250 8506.556 0.116 B- 6547.000 11.000 105 914356.697 13.150 - 18 62 44 106 Ru -86323.223 5.391 8560.940 0.051 B- 39.404 0.212 105 907328.203 5.787 - 16 61 45 106 Rh -86362.627 5.390 8553.931 0.051 B- 3544.901 5.335 105 907285.901 5.785 - 14 60 46 106 Pd -89907.527 1.106 8579.992 0.010 B- -2965.145 2.817 105 903480.293 1.186 - 12 59 47 106 Ag -86942.383 3.016 8544.639 0.028 B- 189.755 2.819 105 906663.507 3.237 - 10 58 48 106 Cd -87132.138 1.104 8539.048 0.010 B- -6524.004 12.176 105 906459.797 1.184 - 8 57 49 106 In - -80608.134 12.226 8470.120 0.115 B- -3254.447 13.244 105 913463.603 13.125 - 6 56 50 106 Sn -77353.687 5.091 8432.038 0.048 B- -10880.396 9.025 105 916957.396 5.465 - 4 55 51 106 Sb x -66473.292 7.452 8322.012 0.070 B- -8253.544 100.816 105 928637.982 8.000 - 2 54 52 106 Te -a -58219.748 100.541 8236.767 0.948 B- * 105 937498.526 107.934 -0 31 69 38 107 Sr x -28900# 700# 8064# 7# B- 13465# 862# 106 968975# 751# - 29 68 39 107 Y x -42364# 503# 8182# 5# B- 12015# 1230# 106 954520# 540# - 27 67 40 107 Zr x -54379.688 1122.450 8287.073 10.490 B- 9344.122 1122.479 106 941621.000 1205.000 - 25 66 41 107 Nb x -63723.810 8.023 8367.089 0.075 B- 8827.750 12.232 106 931589.672 8.612 - 23 65 42 107 Mo x -72551.560 9.233 8442.280 0.086 B- 6198.355 12.667 106 922112.692 9.912 - 21 64 43 107 Tc x -78749.914 8.673 8492.897 0.081 B- 5112.598 11.724 106 915458.485 9.310 - 19 63 44 107 Ru -nn -83862.512 8.673 8533.366 0.081 B- 3001.191 14.847 106 909969.885 9.310 - 17 62 45 107 Rh +p -86863.703 12.051 8554.103 0.113 B- 1508.936 12.111 106 906747.974 12.937 - 15 61 46 107 Pd -88372.639 1.201 8560.894 0.011 B- 34.031 2.318 106 905128.064 1.289 - 13 60 47 107 Ag -88406.670 2.382 8553.900 0.022 B- -1416.409 2.567 106 905091.531 2.557 - 11 59 48 107 Cd -86990.261 1.665 8533.351 0.016 B- -3426.000 11.000 106 906612.108 1.787 - 9 58 49 107 In - -83564.261 11.125 8494.021 0.104 B- -5052.033 12.327 106 910290.071 11.943 - 7 57 50 107 Sn x -78512.228 5.310 8439.494 0.050 B- -7858.989 6.738 106 915713.651 5.700 - 5 56 51 107 Sb -70653.239 4.148 8358.734 0.039 B- -10113.913 70.952 106 924150.624 4.452 - 3 55 52 107 Te -a -60539.326 70.830 8256.899 0.662 B- -11110# 308# 106 935008.356 76.039 - 1 54 53 107 I x -49430# 300# 8146# 3# B- * 106 946935# 322# -0 30 69 39 108 Y x -37297# 596# 8134# 6# B- 14056# 718# 107 959960# 640# - 28 68 40 108 Zr x -51353# 401# 8257# 4# B- 8193# 401# 107 944870# 430# - 26 67 41 108 Nb x -59545.765 8.237 8325.665 0.076 B- 11210.177 12.373 107 936074.988 8.842 - 24 66 42 108 Mo x -70755.942 9.233 8422.219 0.085 B- 5166.835 12.734 107 924040.367 9.912 - 22 65 43 108 Tc x -75922.778 8.769 8462.816 0.081 B- 7738.573 11.790 107 918493.541 9.413 - 20 64 44 108 Ru -3n -83661.350 8.680 8527.225 0.080 B- 1370.370 16.469 107 910185.841 9.318 - 18 63 45 108 Rh x -85031.721 13.996 8532.670 0.130 B- 4492.486 14.039 107 908714.688 15.024 - 16 62 46 108 Pd -89524.206 1.108 8567.023 0.010 B- -1917.444 2.633 107 903891.805 1.189 - 14 61 47 108 Ag -n -87606.763 2.388 8542.025 0.022 B- 1645.651 2.639 107 905950.266 2.563 - 12 60 48 108 Cd -89252.414 1.123 8550.019 0.010 B- -5132.595 8.584 107 904183.587 1.205 - 10 59 49 108 In -84119.819 8.641 8495.251 0.080 B- -2049.881 9.836 107 909693.655 9.276 - 8 58 50 108 Sn -82069.938 5.382 8469.027 0.050 B- -9624.607 7.692 107 911894.292 5.778 - 6 57 51 108 Sb x -72445.331 5.496 8372.666 0.051 B- -6663.664 7.712 107 922226.734 5.900 - 4 56 52 108 Te -65781.667 5.411 8303.721 0.050 B- -13132.062 132.370 107 929380.471 5.808 - 2 55 53 108 I -a -52649.605 132.260 8174.884 1.225 B- * 107 943478.321 141.986 -0 31 70 39 109 Y x -33200# 700# 8096# 6# B- 12992# 862# 108 964358# 751# - 29 69 40 109 Zr x -46193# 503# 8208# 5# B- 10497# 566# 108 950410# 540# - 27 68 41 109 Nb x -56689.794 258.490 8297.130 2.371 B- 9976.202 258.732 108 939141.000 277.500 - 25 67 42 109 Mo x -66665.996 11.188 8381.477 0.103 B- 7616.780 14.787 108 928431.106 12.010 - 23 66 43 109 Tc x -74282.775 9.669 8444.178 0.089 B- 6455.626 12.657 108 920254.156 10.380 - 21 65 44 109 Ru -4n -80738.401 8.954 8496.227 0.082 B- 4261.054 9.822 108 913323.756 9.612 - 19 64 45 109 Rh -84999.455 4.039 8528.142 0.037 B- 2607.021 4.187 108 908749.326 4.336 - 17 63 46 109 Pd -87606.476 1.114 8544.882 0.010 B- 1112.950 1.402 108 905950.574 1.195 - 15 62 47 109 Ag -88719.426 1.287 8547.915 0.012 B- -215.105 1.780 108 904755.773 1.381 - 13 61 48 109 Cd -88504.321 1.536 8538.764 0.014 B- -2014.809 4.066 108 904986.698 1.649 - 11 60 49 109 In -86489.511 3.969 8513.102 0.036 B- -3859.327 8.887 108 907149.685 4.261 - 9 59 50 109 Sn -82630.184 7.949 8470.518 0.073 B- -6379.206 8.807 108 911292.843 8.533 - 7 58 51 109 Sb -76250.977 5.265 8404.815 0.048 B- -8535.587 6.850 108 918141.204 5.652 - 5 57 52 109 Te -67715.390 4.382 8319.330 0.040 B- -10042.894 8.030 108 927304.534 4.704 - 3 56 53 109 I -p -57672.496 6.729 8220.016 0.062 B- -11502.948 300.183 108 938086.025 7.223 - 1 55 54 109 Xe -a -46169.548 300.108 8107.306 2.753 B- * 108 950434.948 322.178 -0 30 70 40 110 Zr x -42886# 596# 8177# 5# B- 9424# 1029# 109 953960# 640# - 28 69 41 110 Nb x -52309.909 838.345 8255.260 7.621 B- 12232.677 838.694 109 943843.000 900.000 - 26 68 42 110 Mo x -64542.585 24.223 8359.354 0.220 B- 6491.925 26.018 109 930710.680 26.004 - 24 67 43 110 Tc x -71034.510 9.497 8411.259 0.086 B- 9038.066 12.509 109 923741.312 10.195 - 22 66 44 110 Ru -80072.576 8.924 8486.311 0.081 B- 2756.110 19.404 109 914038.548 9.580 - 20 65 45 110 Rh -82828.686 17.805 8504.254 0.162 B- 5502.218 17.797 109 911079.742 19.114 - 18 64 46 110 Pd -88330.905 0.612 8547.162 0.006 B- -873.603 1.378 109 905172.868 0.657 - 16 63 47 110 Ag -87457.302 1.286 8532.108 0.012 B- 2890.667 1.277 109 906110.719 1.380 - 14 62 48 110 Cd -90347.969 0.380 8551.275 0.003 B- -3878.000 11.547 109 903007.460 0.407 - 12 61 49 110 In - -86469.969 11.553 8508.908 0.105 B- -627.985 17.980 109 907170.665 12.402 - 10 60 50 110 Sn x -85841.983 13.777 8496.087 0.125 B- -8392.250 15.012 109 907844.835 14.790 - 8 59 51 110 Sb x -77449.734 5.962 8412.681 0.054 B- -5219.923 8.875 109 916854.286 6.400 - 6 58 52 110 Te -72229.811 6.575 8358.115 0.060 B- -11765.635 50.978 109 922458.104 7.058 - 4 57 53 110 I -a -60464.176 50.552 8244.043 0.460 B- -8541.551 112.934 109 935089.033 54.270 - 2 56 54 110 Xe -a -51922.625 100.988 8159.280 0.918 B- * 109 944258.765 108.415 -0 31 71 40 111 Zr x -37560# 700# 8128# 6# B- 11316# 760# 110 959678# 751# - 29 70 41 111 Nb x -48875# 298# 8223# 3# B- 11064# 298# 110 947530# 320# - 27 69 42 111 Mo + -59939.761 12.578 8315.292 0.113 B- 9084.861 6.800 110 935652.016 13.502 - 25 68 43 111 Tc x -69024.622 10.581 8390.089 0.095 B- 7760.649 13.848 110 925899.016 11.359 - 23 67 44 111 Ru x -76785.271 9.682 8452.957 0.087 B- 5519.181 11.860 110 917567.616 10.394 - 21 66 45 111 Rh -82304.452 6.850 8495.631 0.062 B- 3681.435 6.887 110 911642.531 7.354 - 19 65 46 111 Pd -n -85985.888 0.731 8521.749 0.007 B- 2229.560 1.572 110 907690.347 0.785 - 17 64 47 111 Ag + -88215.447 1.459 8534.787 0.013 B- 1036.800 1.414 110 905296.816 1.565 - 15 63 48 111 Cd -89252.247 0.357 8537.079 0.003 B- -860.204 3.417 110 904183.766 0.383 - 13 62 49 111 In -88392.043 3.424 8522.282 0.031 B- -2453.456 6.337 110 905107.233 3.675 - 11 61 50 111 Sn +n -85938.587 5.336 8493.130 0.048 B- -5101.851 10.334 110 907741.126 5.728 - 9 60 51 111 Sb x -80836.736 8.849 8440.120 0.080 B- -7249.259 10.937 110 913218.189 9.500 - 7 59 52 111 Te x -73587.477 6.427 8367.763 0.058 B- -8633.692 7.994 110 921000.589 6.900 - 5 58 53 111 I -64953.785 4.754 8282.934 0.043 B- -10558.252 86.830 110 930269.239 5.103 - 3 57 54 111 Xe -a -54395.534 86.700 8180.766 0.781 B- -11575# 214# 110 941603.989 93.076 - 1 56 55 111 Cs x -42821# 196# 8069# 2# B- * 110 954030# 210# -0 32 72 40 112 Zr x -33810# 700# 8094# 6# B- 10463# 760# 111 963703# 751# - 30 71 41 112 Nb x -44274# 298# 8180# 3# B- 13190# 357# 111 952470# 320# - 28 70 42 112 Mo x -57464# 196# 8291# 2# B- 7795# 196# 111 938310# 210# - 26 69 43 112 Tc x -65258.938 5.515 8353.621 0.049 B- 10371.881 11.060 111 929941.644 5.920 - 24 68 44 112 Ru x -75630.818 9.599 8439.242 0.086 B- 4100.685 45.118 111 918806.972 10.305 - 22 67 45 112 Rh -79731.503 44.085 8468.870 0.394 B- 6590.059 43.927 111 914404.705 47.327 - 20 66 46 112 Pd -86321.562 6.544 8520.724 0.058 B- 262.156 6.978 111 907329.986 7.025 - 18 65 47 112 Ag x -86583.718 2.422 8516.080 0.022 B- 3991.141 2.435 111 907048.550 2.600 - 16 64 48 112 Cd -90574.859 0.250 8544.730 0.002 B- -2584.728 4.243 111 902763.883 0.268 - 14 63 49 112 In -87990.131 4.251 8514.667 0.038 B- 664.925 4.243 111 905538.704 4.563 - 12 62 50 112 Sn -88655.056 0.294 8513.618 0.003 B- -7056.091 17.832 111 904824.877 0.315 - 10 61 51 112 Sb x -81598.965 17.829 8443.632 0.159 B- -4031.457 19.702 111 912399.903 19.140 - 8 60 52 112 Te x -77567.508 8.383 8400.652 0.075 B- -10504.178 13.239 111 916727.850 9.000 - 6 59 53 112 I x -67063.330 10.246 8299.879 0.091 B- -7036.991 13.175 111 928004.550 11.000 - 4 58 54 112 Xe -a -60026.338 8.283 8230.064 0.074 B- -13736.062 87.190 111 935559.071 8.891 - 2 57 55 112 Cs -p -46290.277 86.796 8100.435 0.775 B- * 111 950305.341 93.178 -0 31 72 41 113 Nb x -40511# 401# 8146# 4# B- 11979# 500# 112 956510# 430# - 29 71 42 113 Mo x -52490# 300# 8245# 3# B- 10322# 300# 112 943650# 322# - 27 70 43 113 Tc x -62811.541 3.353 8329.464 0.030 B- 9056.578 37.028 112 932569.033 3.600 - 25 69 44 113 Ru -71868.119 36.875 8402.688 0.326 B- 6899.417 37.558 112 922846.396 39.587 - 23 68 45 113 Rh x -78767.536 7.130 8456.821 0.063 B- 4823.555 9.881 112 915439.567 7.653 - 21 67 46 113 Pd x -83591.092 6.945 8492.584 0.061 B- 3435.731 18.033 112 910261.267 7.455 - 19 66 47 113 Ag + -87026.822 16.643 8516.065 0.147 B- 2016.462 16.641 112 906572.858 17.866 - 17 65 48 113 Cd -89043.284 0.244 8526.987 0.002 B- 323.833 0.265 112 904408.097 0.262 - 15 64 49 113 In -89367.117 0.188 8522.929 0.002 B- -1038.985 1.573 112 904060.448 0.202 - 13 63 50 113 Sn -88328.132 1.575 8506.811 0.014 B- -3911.164 17.121 112 905175.845 1.690 - 11 62 51 113 Sb - -84416.968 17.193 8465.275 0.152 B- -6069.939 32.810 112 909374.652 18.457 - 9 61 52 113 Te x -78347.029 27.945 8404.636 0.247 B- -7227.522 29.070 112 915891.000 30.000 - 7 60 53 113 I x -71119.507 8.011 8333.752 0.071 B- -8915.889 10.533 112 923650.064 8.600 - 5 59 54 113 Xe -62203.618 6.840 8247.927 0.061 B- -10439.088 10.970 112 933221.666 7.342 - 3 58 55 113 Cs -p -51764.530 8.577 8148.622 0.076 B- -11980# 298# 112 944428.488 9.207 - 1 57 56 113 Ba x -39784# 298# 8036# 3# B- * 112 957290# 320# -0 32 73 41 114 Nb x -35387# 503# 8100# 4# B- 14420# 585# 113 962010# 540# - 30 72 42 114 Mo x -49807# 298# 8220# 3# B- 8793# 526# 113 946530# 320# - 28 71 43 114 Tc x -58600.288 433.145 8290.259 3.800 B- 11621.524 433.159 113 937090.000 465.000 - 26 70 44 114 Ru x -70221.811 3.550 8385.340 0.031 B- 5488.813 71.643 113 924613.780 3.811 - 24 69 45 114 Rh -75710.625 71.561 8426.624 0.628 B- 7780.319 71.891 113 918721.296 76.824 - 22 68 46 114 Pd x -83490.943 6.945 8488.010 0.061 B- 1439.856 8.311 113 910368.780 7.456 - 20 67 47 114 Ag x -84930.800 4.564 8493.778 0.040 B- 5084.133 4.573 113 908823.031 4.900 - 18 66 48 114 Cd -90014.932 0.276 8531.513 0.002 B- -1445.132 0.382 113 903364.990 0.296 - 16 65 49 114 In -88569.801 0.301 8511.973 0.003 B- 1989.923 0.302 113 904916.402 0.323 - 14 64 50 114 Sn -90559.723 0.029 8522.566 0.000 B- -6063.149 21.838 113 902780.132 0.031 - 12 63 51 114 Sb -84496.574 21.838 8462.518 0.192 B- -2608.005 35.466 113 909289.191 23.444 - 10 62 52 114 Te x -81888.569 27.945 8432.778 0.245 B- -9092# 152# 113 912089.000 30.000 - 8 61 53 114 I x -72796# 149# 8346# 1# B- -5710# 149# 113 921850# 160# - 6 60 54 114 Xe x -67085.890 11.178 8289.205 0.098 B- -12403.629 71.976 113 927980.331 12.000 - 4 59 55 114 Cs -a -54682.261 71.102 8173.538 0.624 B- -8776.835 124.892 113 941296.175 76.331 - 2 58 56 114 Ba -a -45905.426 102.676 8089.686 0.901 B- * 113 950718.495 110.227 -0 33 74 41 115 Nb x -31354# 503# 8065# 4# B- 13395# 643# 114 966340# 540# - 31 73 42 115 Mo x -44749# 401# 8175# 3# B- 11571# 885# 114 951960# 430# - 29 72 43 115 Tc x -56319.990 789.441 8268.527 6.865 B- 9869.744 794.386 114 939538.000 847.500 - 27 71 44 115 Ru x -66189.734 88.496 8347.547 0.770 B- 8040.097 88.790 114 928942.393 95.004 - 25 70 45 115 Rh x -74229.831 7.316 8410.658 0.064 B- 6196.554 15.350 114 920310.993 7.854 - 23 69 46 115 Pd -80426.386 13.546 8457.738 0.118 B- 4556.268 21.649 114 913658.718 14.541 - 21 68 47 115 Ag -84982.654 18.268 8490.555 0.159 B- 3101.825 18.274 114 908767.363 19.611 - 19 67 48 115 Cd -88084.479 0.651 8510.724 0.006 B- 1451.867 0.651 114 905437.417 0.699 - 17 66 49 115 In -89536.346 0.012 8516.546 0.000 B- 497.489 0.010 114 903878.773 0.012 - 15 65 50 115 Sn -90033.835 0.015 8514.069 0.000 B- -3030.432 16.025 114 903344.697 0.016 - 13 64 51 115 Sb x -87003.403 16.025 8480.915 0.139 B- -4940.644 32.214 114 906598.000 17.203 - 11 63 52 115 Te x -82062.759 27.945 8431.150 0.243 B- -5724.962 40.184 114 911902.000 30.000 - 9 62 53 115 I x -76337.797 28.876 8374.564 0.251 B- -7681.049 31.313 114 918048.000 31.000 - 7 61 54 115 Xe x -68656.748 12.109 8300.970 0.105 B- -8957# 103# 114 926293.945 13.000 - 5 60 55 115 Cs x -59699# 102# 8216# 1# B- -10680# 225# 114 935910# 110# - 3 59 56 115 Ba x -49020# 200# 8117# 2# B- * 114 947375# 215# -0 32 74 42 116 Mo x -41500# 500# 8146# 4# B- 9956# 582# 115 955448# 537# - 30 73 43 116 Tc x -51456# 298# 8225# 3# B- 12613# 298# 115 944760# 320# - 28 72 44 116 Ru x -64068.909 3.726 8326.883 0.032 B- 6667.213 73.926 115 931219.193 4.000 - 26 71 45 116 Rh -70736.122 73.832 8377.615 0.636 B- 9095.512 74.169 115 924061.645 79.261 - 24 70 46 116 Pd x -79831.635 7.132 8449.280 0.061 B- 2711.019 7.842 115 914297.210 7.656 - 22 69 47 116 Ag x -82542.653 3.260 8465.907 0.028 B- 6169.827 3.264 115 911386.812 3.500 - 20 68 48 116 Cd -88712.480 0.160 8512.350 0.001 B- -462.731 0.272 115 904763.230 0.172 - 18 67 49 116 In -n -88249.749 0.220 8501.617 0.002 B- 3276.221 0.240 115 905259.992 0.236 - 16 66 50 116 Sn -91525.970 0.096 8523.116 0.001 B- -4703.820 5.160 115 901742.824 0.103 - 14 65 51 116 Sb -86822.150 5.160 8475.821 0.044 B- -1553.189 28.417 115 906792.583 5.539 - 12 64 52 116 Te x -85268.961 27.945 8455.687 0.241 B- -7776.725 100.553 115 908460.000 30.000 - 10 63 53 116 I + -77492.236 96.592 8381.902 0.833 B- -4445.512 95.707 115 916808.658 103.695 - 8 62 54 116 Xe x -73046.724 13.041 8336.834 0.112 B- -11004# 101# 115 921581.112 14.000 - 6 61 55 116 Cs ea -62043# 100# 8235# 1# B- -7463# 224# 115 933395# 108# - 4 60 56 116 Ba x -54580# 200# 8164# 2# B- -13935# 371# 115 941406# 215# - 2 59 57 116 La -a -40645# 312# 8037# 3# B- * 115 956365# 335# -0 33 75 42 117 Mo x -36170# 500# 8100# 4# B- 12212# 641# 116 961170# 537# - 31 74 43 117 Tc x -48382# 401# 8197# 3# B- 11108# 590# 116 948060# 430# - 29 73 44 117 Ru x -59489.865 433.145 8285.562 3.702 B- 9407.508 433.236 116 936135.000 465.000 - 27 72 45 117 Rh x -68897.373 8.892 8359.281 0.076 B- 7527.104 11.411 116 926035.623 9.546 - 25 71 46 117 Pd -76424.477 7.252 8416.929 0.062 B- 5757.537 14.766 116 917954.944 7.785 - 23 70 47 117 Ag -82182.014 13.572 8459.452 0.116 B- 4236.375 13.610 116 911773.974 14.570 - 21 69 48 117 Cd -n -86418.389 1.013 8488.973 0.009 B- 2524.653 4.983 116 907226.038 1.087 - 19 68 49 117 In -88943.042 4.881 8503.865 0.042 B- 1454.709 4.857 116 904515.712 5.239 - 17 67 50 117 Sn -90397.751 0.483 8509.611 0.004 B- -1758.212 8.445 116 902954.017 0.518 - 15 66 51 117 Sb -88639.539 8.437 8487.897 0.072 B- -3544.128 13.079 116 904841.535 9.057 - 13 65 52 117 Te -85095.411 13.456 8450.919 0.115 B- -4659.334 28.673 116 908646.313 14.446 - 11 64 53 117 I -80436.077 26.196 8404.409 0.224 B- -6250.740 28.177 116 913648.314 28.123 - 9 63 54 117 Xe x -74185.337 10.378 8344.297 0.089 B- -7692.245 63.267 116 920358.760 11.141 - 7 62 55 117 Cs x -66493.092 62.410 8271.864 0.533 B- -9035.338 258.002 116 928616.726 67.000 - 5 61 56 117 Ba ep -57457.753 250.340 8187.953 2.140 B- -10987# 321# 116 938316.561 268.750 - 3 60 57 117 La -p -46471# 200# 8087# 2# B- * 116 950111# 215# -0 34 76 42 118 Mo x -32630# 500# 8069# 4# B- 11159# 641# 117 964970# 537# - 32 75 43 118 Tc x -43790# 401# 8157# 3# B- 13470# 448# 117 952990# 430# - 30 74 44 118 Ru x -57260# 200# 8265# 2# B- 7628# 202# 117 938529# 215# - 28 73 45 118 Rh x -64887.460 24.235 8322.858 0.205 B- 10501.286 24.342 117 930340.443 26.017 - 26 72 46 118 Pd -75388.746 2.491 8405.222 0.021 B- 4165.046 3.539 117 919066.847 2.673 - 24 71 47 118 Ag x -79553.792 2.515 8433.889 0.021 B- 7147.849 20.158 117 914595.487 2.700 - 22 70 48 118 Cd -nn -86701.641 20.001 8487.834 0.169 B- 526.570 21.450 117 906921.955 21.471 - 20 69 49 118 In -87228.211 7.752 8485.667 0.066 B- 4424.643 7.740 117 906356.659 8.322 - 18 68 50 118 Sn -91652.853 0.499 8516.533 0.004 B- -3656.640 2.975 117 901606.609 0.536 - 16 67 51 118 Sb - -87996.213 3.016 8478.915 0.026 B- -299.630 18.726 117 905532.174 3.238 - 14 66 52 118 Te +nn -87696.584 18.481 8469.746 0.157 B- -6725.536 27.056 117 905853.839 19.840 - 12 65 53 118 I x -80971.048 19.760 8406.120 0.167 B- -2891.991 22.320 117 913074.000 21.213 - 10 64 54 118 Xe x -78079.057 10.378 8374.981 0.088 B- -9669.689 16.442 117 916178.680 11.141 - 8 63 55 118 Cs IT -68409.367 12.753 8286.404 0.108 B- -6055# 196# 117 926559.519 13.690 - 6 62 56 118 Ba x -62354# 196# 8228# 2# B- -12794# 358# 117 933060# 210# - 4 61 57 118 La x -49560# 300# 8113# 3# B- * 117 946795# 322# -0 33 76 43 119 Tc x -40371# 503# 8128# 4# B- 12193# 585# 118 956660# 540# - 31 75 44 119 Ru x -52564# 298# 8224# 3# B- 10259# 298# 118 943570# 320# - 29 74 45 119 Rh x -62822.794 9.315 8303.394 0.078 B- 8585.108 12.440 118 932556.952 10.000 - 27 73 46 119 Pd x -71407.902 8.245 8368.964 0.069 B- 7237.863 16.855 118 923340.459 8.851 - 25 72 47 119 Ag -78645.765 14.703 8423.212 0.124 B- 5331.303 35.926 118 915570.293 15.783 - 23 71 48 119 Cd -83977.068 37.695 8461.438 0.317 B- 3722.212 38.088 118 909846.903 40.467 - 21 70 49 119 In -87699.281 7.307 8486.143 0.061 B- 2365.742 7.336 118 905850.944 7.844 - 19 69 50 119 Sn -90065.022 0.725 8499.449 0.006 B- -590.843 7.689 118 903311.216 0.778 - 17 68 51 119 Sb -89474.180 7.701 8487.910 0.065 B- -2293.000 2.000 118 903945.512 8.267 - 15 67 52 119 Te - -87181.180 7.957 8462.066 0.067 B- -3415.650 29.055 118 906407.148 8.541 - 13 66 53 119 I x -83765.530 27.945 8426.789 0.235 B- -4971.117 29.810 118 910074.000 30.000 - 11 65 54 119 Xe x -78794.413 10.378 8378.441 0.087 B- -6489.361 17.379 118 915410.713 11.141 - 9 64 55 119 Cs IT -72305.051 13.940 8317.334 0.117 B- -7714.965 200.754 118 922377.330 14.965 - 7 63 56 119 Ba ep -64590.086 200.269 8245.928 1.683 B- -9801# 361# 118 930659.686 214.997 - 5 62 57 119 La x -54790# 300# 8157# 3# B- -10849# 583# 118 941181# 322# - 3 61 58 119 Ce x -43940# 500# 8059# 4# B- * 118 952828# 537# -0 34 77 43 120 Tc x -35518# 503# 8087# 4# B- 14494# 643# 119 961870# 540# - 32 76 44 120 Ru x -50012# 401# 8201# 3# B- 8803# 446# 119 946310# 430# - 30 75 45 120 Rh x -58815# 196# 8268# 2# B- 11466# 196# 119 936860# 210# - 28 74 46 120 Pd -70280.050 2.291 8357.085 0.019 B- 5371.451 5.024 119 924551.258 2.459 - 26 73 47 120 Ag x -75651.502 4.471 8395.327 0.037 B- 8305.853 5.820 119 918784.767 4.800 - 24 72 48 120 Cd x -83957.354 3.726 8458.023 0.031 B- 1771.015 40.183 119 909868.067 4.000 - 22 71 49 120 In + -85728.369 40.010 8466.262 0.333 B- 5370.000 40.000 119 907966.805 42.952 - 20 70 50 120 Sn -91098.369 0.896 8504.492 0.007 B- -2680.608 7.140 119 902201.873 0.962 - 18 69 51 120 Sb - -88417.761 7.196 8475.635 0.060 B- 950.226 7.811 119 905079.624 7.725 - 16 68 52 120 Te -89367.987 3.085 8477.034 0.026 B- -5615.000 15.000 119 904059.514 3.311 - 14 67 53 120 I - -83752.987 15.314 8423.722 0.128 B- -1580.563 19.343 119 910087.465 16.440 - 12 66 54 120 Xe x -82172.423 11.817 8404.031 0.098 B- -8283.785 15.461 119 911784.270 12.686 - 10 65 55 120 Cs IT -73888.639 9.970 8328.480 0.083 B- -5000.000 300.000 119 920677.279 10.702 - 8 64 56 120 Ba - -68888.639 300.166 8280.294 2.501 B- -11319# 424# 119 926045.000 322.241 - 6 63 57 120 La x -57570# 300# 8179# 2# B- -7970# 583# 119 938196# 322# - 4 62 58 120 Ce x -49600# 500# 8107# 4# B- * 119 946752# 537# -0 35 78 43 121 Tc x -31780# 500# 8056# 4# B- 13267# 641# 120 965883# 537# - 33 77 44 121 Ru x -45047# 401# 8159# 3# B- 11203# 738# 120 951640# 430# - 31 76 45 121 Rh x -56250.128 619.444 8245.239 5.119 B- 9932.201 619.453 120 939613.000 665.000 - 29 75 46 121 Pd x -66182.329 3.353 8320.858 0.028 B- 8220.492 12.565 120 928950.343 3.600 - 27 74 47 121 Ag x -74402.821 12.109 8382.330 0.100 B- 6671.005 12.264 120 920125.282 13.000 - 25 73 48 121 Cd x -81073.826 1.942 8430.996 0.016 B- 4762.148 27.483 120 912963.663 2.085 - 23 72 49 121 In +p -85835.974 27.414 8463.887 0.227 B- 3361.291 27.408 120 907851.286 29.430 - 21 71 50 121 Sn -89197.265 0.955 8485.201 0.008 B- 403.057 2.690 120 904242.792 1.025 - 19 70 51 121 Sb -89600.321 2.582 8482.066 0.021 B- -1054.819 25.767 120 903810.093 2.771 - 17 69 52 121 Te -88545.502 25.850 8466.883 0.214 B- -2294.053 26.047 120 904942.488 27.751 - 15 68 53 121 I -86251.449 5.356 8441.458 0.044 B- -3770.463 11.558 120 907405.255 5.749 - 13 67 54 121 Xe -82480.986 10.243 8403.832 0.085 B- -5378.654 13.979 120 911453.014 10.995 - 11 66 55 121 Cs -77102.331 14.290 8352.914 0.118 B- -6357.495 141.176 120 917227.238 15.340 - 9 65 56 121 Ba - -70744.837 141.898 8293.907 1.173 B- -8555# 332# 120 924052.289 152.333 - 7 64 57 121 La x -62190# 300# 8217# 2# B- -9500# 500# 120 933236# 322# - 5 63 58 121 Ce x -52690# 401# 8132# 3# B- -11268# 641# 120 943435# 430# - 3 62 59 121 Pr -p -41422# 500# 8032# 4# B- * 120 955532# 537# -0 34 78 44 122 Ru x -42150# 500# 8135# 4# B- 9930# 583# 121 954750# 537# - 32 77 45 122 Rh x -52080# 300# 8210# 2# B- 12536# 301# 121 944090# 322# - 30 76 46 122 Pd x -64616.161 19.561 8305.975 0.160 B- 6489.948 42.909 121 930631.694 21.000 - 28 75 47 122 Ag x -71106.108 38.191 8352.758 0.313 B- 9506.265 38.260 121 923664.448 41.000 - 26 74 48 122 Cd -80612.374 2.299 8424.266 0.019 B- 2960.368 50.110 121 913459.052 2.468 - 24 73 49 122 In + -83572.741 50.057 8442.118 0.410 B- 6368.592 50.000 121 910280.966 53.738 - 22 72 50 122 Sn -89941.333 2.395 8487.907 0.020 B- -1605.963 3.384 121 903444.001 2.570 - 20 71 51 122 Sb -88335.370 2.578 8468.331 0.021 B- 1979.089 2.127 121 905168.074 2.768 - 18 70 52 122 Te -90314.460 1.507 8478.140 0.012 B- -4234.000 5.000 121 903043.434 1.617 - 16 69 53 122 I - -86080.460 5.222 8437.023 0.043 B- -725.483 12.277 121 907588.820 5.606 - 14 68 54 122 Xe x -85354.977 11.111 8424.664 0.091 B- -7210.218 35.472 121 908367.658 11.928 - 12 67 55 122 Cs -78144.759 33.687 8359.151 0.276 B- -3535.815 43.769 121 916108.145 36.164 - 10 66 56 122 Ba x -74608.944 27.945 8323.756 0.229 B- -10066# 299# 121 919904.000 30.000 - 8 65 57 122 La x -64543# 298# 8235# 2# B- -6669# 499# 121 930710# 320# - 6 64 58 122 Ce x -57874# 401# 8174# 3# B- -13094# 641# 121 937870# 430# - 4 63 59 122 Pr x -44780# 500# 8060# 4# B- * 121 951927# 537# -0 35 79 44 123 Ru x -37080# 500# 8093# 4# B- 12280# 640# 122 960193# 537# - 33 78 45 123 Rh x -49360# 400# 8186# 3# B- 11070# 885# 122 947010# 429# - 31 77 46 123 Pd x -60429.742 789.441 8270.031 6.418 B- 9118.336 790.039 122 935126.000 847.500 - 29 76 47 123 Ag x -69548.078 30.739 8337.803 0.250 B- 7866.103 30.857 122 925337.062 33.000 - 27 75 48 123 Cd -77414.181 2.696 8395.395 0.022 B- 6016.172 19.893 122 916892.453 2.894 - 25 74 49 123 In -83430.353 19.827 8437.946 0.161 B- 4385.828 19.839 122 910433.826 21.285 - 23 73 50 123 Sn -87816.181 2.416 8467.243 0.020 B- 1407.888 2.662 122 905725.446 2.594 - 21 72 51 123 Sb -89224.069 1.506 8472.328 0.012 B- -51.913 0.066 122 904214.016 1.616 - 19 71 52 123 Te -89172.156 1.505 8465.546 0.012 B- -1228.429 3.445 122 904269.747 1.615 - 17 70 53 123 I -87943.727 3.740 8449.198 0.030 B- -2695.027 9.690 122 905588.520 4.014 - 15 69 54 123 Xe -85248.701 9.537 8420.927 0.078 B- -4205.055 15.414 122 908481.750 10.238 - 13 68 55 123 Cs x -81043.646 12.109 8380.379 0.098 B- -5388.693 17.125 122 912996.062 13.000 - 11 67 56 123 Ba x -75654.953 12.109 8330.208 0.098 B- -7004# 196# 122 918781.062 13.000 - 9 66 57 123 La x -68651# 196# 8267# 2# B- -8365# 357# 122 926300# 210# - 7 65 58 123 Ce x -60286# 298# 8193# 2# B- -10056# 499# 122 935280# 320# - 5 64 59 123 Pr x -50230# 400# 8104# 3# B- * 122 946076# 429# -0 36 80 44 124 Ru x -33960# 600# 8068# 5# B- 10929# 721# 123 963542# 644# - 34 79 45 124 Rh x -44890# 400# 8149# 3# B- 13500# 499# 123 951809# 429# - 32 78 46 124 Pd x -58390# 298# 8252# 2# B- 7810# 390# 123 937316# 320# - 30 77 47 124 Ag x -66200.134 251.503 8308.655 2.028 B- 10501.538 251.521 123 928931.229 270.000 - 28 76 48 124 Cd -76701.672 2.995 8387.035 0.024 B- 4168.529 30.539 123 917657.363 3.215 - 26 75 49 124 In -80870.201 30.572 8414.343 0.247 B- 7363.992 30.576 123 913182.263 32.820 - 24 74 50 124 Sn -88234.193 1.014 8467.421 0.008 B- -613.944 1.513 123 905276.692 1.088 - 22 73 51 124 Sb -n -87620.248 1.507 8456.160 0.012 B- 2905.073 0.132 123 905935.789 1.618 - 20 72 52 124 Te -90525.321 1.502 8473.279 0.012 B- -3159.587 1.859 123 902817.064 1.612 - 18 71 53 124 I - -87365.734 2.390 8441.489 0.019 B- 295.686 2.846 123 906209.021 2.566 - 16 70 54 124 Xe -87661.421 1.793 8437.565 0.014 B- -5930.086 8.495 123 905891.588 1.924 - 14 69 55 124 Cs x -81731.334 8.304 8383.432 0.067 B- -2641.559 15.004 123 912257.798 8.914 - 12 68 56 124 Ba x -79089.775 12.497 8355.820 0.101 B- -8831.165 58.030 123 915093.629 13.416 - 10 67 57 124 La x -70258.610 56.669 8278.292 0.457 B- -5343# 303# 123 924574.275 60.836 - 8 66 58 124 Ce x -64916# 298# 8229# 2# B- -11765# 499# 123 930310# 320# - 6 65 59 124 Pr x -53151# 401# 8128# 3# B- -8626# 643# 123 942940# 430# - 4 64 60 124 Nd x -44525# 503# 8052# 4# B- * 123 952200# 540# -0 35 80 45 125 Rh x -42000# 500# 8126# 4# B- 12120# 640# 124 954911# 537# - 33 79 46 125 Pd x -54120# 400# 8216# 3# B- 10400# 589# 124 941900# 429# - 31 78 47 125 Ag x -64519.932 433.145 8293.314 3.465 B- 8828.163 433.154 124 930735.000 465.000 - 29 77 48 125 Cd -73348.095 2.885 8357.681 0.023 B- 7128.710 27.119 124 921257.577 3.097 - 27 76 49 125 In -80476.805 27.023 8408.452 0.216 B- 5419.571 27.011 124 913604.591 29.010 - 25 75 50 125 Sn -85896.376 1.033 8445.550 0.008 B- 2359.899 2.610 124 907786.442 1.109 - 23 74 51 125 Sb + -88256.274 2.599 8458.170 0.021 B- 766.700 2.121 124 905252.987 2.790 - 21 73 52 125 Te -89022.974 1.502 8458.045 0.012 B- -185.770 0.060 124 904429.900 1.612 - 19 72 53 125 I - -88837.204 1.504 8450.300 0.012 B- -1643.824 2.192 124 904629.333 1.614 - 17 71 54 125 Xe -87193.381 1.836 8430.890 0.015 B- -3105.430 7.831 124 906394.050 1.971 - 15 70 55 125 Cs -84087.950 7.744 8399.788 0.062 B- -4418.985 13.446 124 909727.867 8.313 - 13 69 56 125 Ba -79668.965 10.992 8358.178 0.088 B- -5909.481 27.631 124 914471.843 11.800 - 11 68 57 125 La -73759.484 25.997 8304.643 0.208 B- -7102# 197# 124 920815.932 27.909 - 9 67 58 125 Ce x -66658# 196# 8242# 2# B- -8718# 358# 124 928440# 210# - 7 66 59 125 Pr x -57940# 300# 8166# 2# B- -10341# 500# 124 937799# 322# - 5 65 60 125 Nd x -47599# 401# 8077# 3# B- * 124 948900# 430# -0 36 81 45 126 Rh x -37300# 500# 8088# 4# B- 14560# 640# 125 959957# 537# - 34 80 46 126 Pd x -51860# 400# 8197# 3# B- 8820# 447# 125 944326# 429# - 32 79 47 126 Ag x -60680# 200# 8261# 2# B- 11576# 200# 125 934857# 215# - 30 78 48 126 Cd -72256.802 2.476 8346.747 0.020 B- 5516.106 26.908 125 922429.127 2.658 - 28 77 49 126 In -77772.908 26.921 8384.317 0.214 B- 8242.332 27.078 125 916507.344 28.901 - 26 76 50 126 Sn -86015.240 10.447 8443.523 0.083 B- 378.000 30.000 125 907658.836 11.215 - 24 75 51 126 Sb - -86393.240 31.767 8440.314 0.252 B- 3672.108 31.787 125 907253.036 34.103 - 22 74 52 126 Te -90065.348 1.504 8463.248 0.012 B- -2154.031 3.677 125 903310.866 1.614 - 20 73 53 126 I -87911.318 3.809 8439.944 0.030 B- 1235.644 5.173 125 905623.313 4.089 - 18 72 54 126 Xe -89146.962 3.500 8443.541 0.028 B- -4796.133 10.671 125 904296.794 3.757 - 16 71 55 126 Cs -84350.829 10.401 8399.268 0.083 B- -1680.927 16.259 125 909445.655 11.166 - 14 70 56 126 Ba x -82669.902 12.497 8379.718 0.099 B- -7696.435 91.366 125 911250.204 13.416 - 12 69 57 126 La x -74973.468 90.508 8312.426 0.718 B- -4152.910 94.723 125 919512.667 97.163 - 10 68 58 126 Ce x -70820.558 27.945 8273.257 0.222 B- -10497# 198# 125 923971.000 30.000 - 8 67 59 126 Pr x -60324# 196# 8184# 2# B- -7331# 357# 125 935240# 210# - 6 66 60 126 Nd x -52993# 298# 8119# 2# B- -13643# 582# 125 943110# 320# - 4 65 61 126 Pm x -39350# 500# 8005# 4# B- * 125 957756# 537# -0 37 82 45 127 Rh x -34030# 600# 8062# 5# B- 13150# 781# 126 963467# 644# - 35 81 46 127 Pd x -47180# 500# 8159# 4# B- 11260# 539# 126 949350# 537# - 33 80 47 127 Ag x -58440# 200# 8242# 2# B- 10307# 201# 126 937262# 215# - 31 79 48 127 Cd x -68747.402 12.109 8316.945 0.095 B- 8148.782 24.378 126 926196.624 13.000 - 29 78 49 127 In -76896.184 21.157 8374.949 0.167 B- 6574.619 19.098 126 917448.546 22.713 - 27 77 50 127 Sn -83470.803 10.057 8420.557 0.079 B- 3228.674 10.875 126 910390.401 10.796 - 25 76 51 127 Sb -86699.477 5.126 8439.820 0.040 B- 1582.201 4.913 126 906924.277 5.502 - 23 75 52 127 Te -88281.678 1.514 8446.118 0.012 B- 702.231 3.575 126 905225.714 1.625 - 21 74 53 127 I -88983.909 3.647 8445.487 0.029 B- -662.349 2.044 126 904471.838 3.915 - 19 73 54 127 Xe -88321.560 4.110 8434.111 0.032 B- -2081.406 6.421 126 905182.899 4.412 - 17 72 55 127 Cs -86240.154 5.578 8411.562 0.044 B- -3422.210 12.653 126 907417.381 5.988 - 15 71 56 127 Ba -82817.944 11.357 8378.455 0.089 B- -4921.836 27.740 126 911091.275 12.192 - 13 70 57 127 La -77896.108 26.000 8333.540 0.205 B- -5916.772 38.857 126 916375.084 27.912 - 11 69 58 127 Ce x -71979.336 28.876 8280.791 0.227 B- -7436# 198# 126 922727.000 31.000 - 9 68 59 127 Pr x -64543# 196# 8216# 2# B- -9008# 357# 126 930710# 210# - 7 67 60 127 Nd x -55536# 298# 8139# 2# B- -10749# 499# 126 940380# 320# - 5 66 61 127 Pm x -44786# 401# 8048# 3# B- * 126 951920# 430# -0 36 82 46 128 Pd x -44490# 500# 8138# 4# B- 10130# 583# 127 952238# 537# - 34 81 47 128 Ag x -54620# 300# 8211# 2# B- 12622# 300# 127 941363# 322# - 32 80 48 128 Cd -67241.890 7.244 8303.264 0.057 B- 6904.051 153.554 127 927812.857 7.776 - 30 79 49 128 In -74145.941 153.479 8351.090 1.199 B- 9216.067 153.027 127 920401.053 164.766 - 28 78 50 128 Sn -83362.008 17.660 8416.979 0.138 B- 1268.278 13.796 127 910507.197 18.958 - 26 77 51 128 Sb IT -84630.286 19.119 8420.775 0.149 B- 4363.429 19.117 127 909145.645 20.525 - 24 76 52 128 Te -88993.716 0.866 8448.752 0.007 B- -1254.992 3.714 127 904461.311 0.929 - 22 75 53 128 I -87738.724 3.647 8432.836 0.028 B- 2121.575 3.748 127 905808.600 3.915 - 20 74 54 128 Xe -89860.298 1.061 8443.298 0.008 B- -3928.717 5.380 127 903530.996 1.138 - 18 73 55 128 Cs -85931.581 5.443 8406.493 0.043 B- -553.084 7.525 127 907748.648 5.843 - 16 72 56 128 Ba -85378.497 5.195 8396.060 0.041 B- -6753.066 54.695 127 908342.408 5.577 - 14 71 57 128 La x -78625.431 54.448 8337.190 0.425 B- -3091.513 61.200 127 915592.123 58.452 - 12 70 58 128 Ce x -75533.917 27.945 8306.925 0.218 B- -9203.161 40.859 127 918911.000 30.000 - 10 69 59 128 Pr x -66330.757 29.808 8228.913 0.233 B- -6017# 198# 127 928791.000 32.000 - 8 68 60 128 Nd x -60314# 196# 8176# 2# B- -12529# 357# 127 935250# 210# - 6 67 61 128 Pm x -47786# 298# 8072# 2# B- -9116# 582# 127 948700# 320# - 4 66 62 128 Sm x -38670# 500# 7994# 4# B- * 127 958486# 537# -0 37 83 46 129 Pd x -37610# 600# 8084# 5# B- 14370# 721# 128 959624# 644# - 35 82 47 129 Ag x -51980# 400# 8189# 3# B- 11078# 400# 128 944197# 429# - 33 81 48 129 Cd x -63058.046 16.767 8269.034 0.130 B- 9779.674 16.982 128 932304.399 18.000 - 31 80 49 129 In -72837.720 2.693 8338.780 0.021 B- 7753.183 17.302 128 921805.486 2.891 - 29 79 50 129 Sn -80590.903 17.277 8392.818 0.134 B- 4038.404 27.372 128 913482.102 18.547 - 27 78 51 129 Sb + -84629.307 21.231 8418.058 0.165 B- 2375.500 21.213 128 909146.696 22.792 - 25 77 52 129 Te -87004.807 0.869 8430.409 0.007 B- 1502.318 3.142 128 906596.492 0.933 - 23 76 53 129 I -88507.125 3.168 8435.990 0.025 B- 188.934 3.168 128 904983.687 3.401 - 21 75 54 129 Xe -88696.05896 0.00537 8431.390 0.000 B- -1196.813 4.555 128 904780.85892 0.00576 - 19 74 55 129 Cs -87499.246 4.555 8416.047 0.035 B- -2436.048 10.623 128 906065.690 4.889 - 17 73 56 129 Ba -85063.198 10.577 8391.098 0.082 B- -3738.625 21.639 128 908680.896 11.354 - 15 72 57 129 La -81324.573 21.351 8356.052 0.166 B- -5037.077 35.168 128 912694.475 22.920 - 13 71 58 129 Ce x -76287.496 27.945 8310.940 0.217 B- -6513.938 40.859 128 918102.000 30.000 - 11 70 59 129 Pr x -69773.558 29.808 8254.380 0.231 B- -7459# 204# 128 925095.000 32.000 - 9 69 60 129 Nd ep -62315# 202# 8190# 2# B- -9434# 360# 128 933102# 217# - 7 68 61 129 Pm x -52881# 298# 8111# 2# B- -10881# 582# 128 943230# 320# - 5 67 62 129 Sm x -42000# 500# 8021# 4# B- * 128 954911# 537# -0 36 83 47 130 Ag -nn -45697# 500# 8140# 4# B- 15420# 500# 129 950942# 537# - 34 82 48 130 Cd x -61117.589 22.356 8252.586 0.172 B- 8765.617 44.128 129 934387.566 24.000 - 32 81 49 130 In + -69883.206 38.046 8313.996 0.293 B- 10249.000 38.000 129 924977.288 40.844 - 30 80 50 130 Sn -80132.206 1.873 8386.816 0.014 B- 2153.470 14.113 129 913974.533 2.010 - 28 79 51 130 Sb -82285.676 14.212 8397.363 0.109 B- 5067.273 14.212 129 911662.688 15.257 - 26 78 52 130 Te -87352.949 0.011 8430.324 0.000 B- -416.811 3.168 129 906222.747 0.012 - 24 77 53 130 I -n -86936.138 3.168 8421.100 0.024 B- 2944.325 3.168 129 906670.211 3.401 - 22 76 54 130 Xe -89880.463 0.009 8437.731 0.000 B- -2980.720 8.357 129 903509.349 0.010 - 20 75 55 130 Cs -86899.743 8.357 8408.784 0.064 B- 361.801 8.738 129 906709.283 8.971 - 18 74 56 130 Ba -87261.544 2.553 8405.549 0.020 B- -5634.178 26.071 129 906320.874 2.741 - 16 73 57 130 La x -81627.366 25.946 8356.191 0.200 B- -2204.461 38.133 129 912369.413 27.854 - 14 72 58 130 Ce x -79422.905 27.945 8333.216 0.215 B- -8247.448 70.085 129 914736.000 30.000 - 12 71 59 130 Pr x -71175.457 64.273 8263.756 0.494 B- -4579.225 70.085 129 923590.000 69.000 - 10 70 60 130 Nd x -66596.232 27.945 8222.513 0.215 B- -11200# 198# 129 928506.000 30.000 - 8 69 61 130 Pm x -55396# 196# 8130# 2# B- -7890# 446# 129 940530# 210# - 6 68 62 130 Sm x -47506# 401# 8064# 3# B- -13823# 641# 129 949000# 430# - 4 67 63 130 Eu -p -33683# 500# 7951# 4# B- * 129 963840# 537# -0 37 84 47 131 Ag x -40380# 500# 8099# 4# B- 14839# 511# 130 956650# 537# - 35 83 48 131 Cd x -55218.965 102.464 8206.175 0.782 B- 12806.066 102.500 130 940720.000 110.000 - 33 82 49 131 In x -68025.030 2.701 8297.959 0.021 B- 9239.541 4.518 130 926972.122 2.900 - 31 81 50 131 Sn -77264.571 3.621 8362.517 0.028 B- 4716.830 3.962 130 917053.066 3.887 - 29 80 51 131 Sb -81981.401 2.084 8392.552 0.016 B- 3229.611 2.085 130 911989.341 2.236 - 27 79 52 131 Te -n -85211.012 0.061 8411.233 0.001 B- 2231.699 0.608 130 908522.211 0.065 - 25 78 53 131 I + -87442.710 0.605 8422.297 0.005 B- 970.848 0.605 130 906126.384 0.649 - 23 77 54 131 Xe -88413.558 0.009 8423.736 0.000 B- -354.772 4.974 130 905084.136 0.009 - 21 76 55 131 Cs -88058.786 4.974 8415.056 0.038 B- -1375.055 5.279 130 905464.999 5.340 - 19 75 56 131 Ba -86683.731 2.569 8398.587 0.020 B- -2914.475 28.063 130 906941.181 2.757 - 17 74 57 131 La x -83769.256 27.945 8370.367 0.213 B- -4060.816 43.092 130 910070.000 30.000 - 15 73 58 131 Ce -79708.440 32.802 8333.396 0.250 B- -5407.784 55.446 130 914429.465 35.214 - 13 72 59 131 Pr -74300.656 46.995 8286.143 0.359 B- -6532.623 53.081 130 920234.960 50.451 - 11 71 60 131 Nd -67768.033 27.517 8230.304 0.210 B- -8108# 202# 130 927248.020 29.541 - 9 70 61 131 Pm x -59660# 200# 8162# 2# B- -9527# 448# 130 935952# 215# - 7 69 62 131 Sm x -50133# 401# 8084# 3# B- -10863# 566# 130 946180# 430# - 5 68 63 131 Eu -p -39270# 401# 7995# 3# B- * 130 957842# 430# -0 38 85 47 132 Ag x -33790# 500# 8049# 4# B- 16473# 537# 131 963725# 537# - 36 84 48 132 Cd x -50263# 196# 8168# 1# B- 12148# 205# 131 946040# 210# - 34 83 49 132 In + -62411.542 60.033 8253.715 0.455 B- 14135.000 60.000 131 932998.449 64.447 - 32 82 50 132 Sn -76546.542 1.976 8354.872 0.015 B- 3088.729 3.161 131 917823.902 2.121 - 30 81 51 132 Sb -79635.271 2.467 8372.344 0.019 B- 5552.915 4.271 131 914508.015 2.648 - 28 80 52 132 Te -85188.186 3.486 8408.485 0.026 B- 515.304 3.483 131 908546.716 3.742 - 26 79 53 132 I -85703.490 4.065 8406.462 0.031 B- 3575.472 4.065 131 907993.514 4.364 - 24 78 54 132 Xe -89278.96179 0.00515 8427.622 0.000 B- -2126.280 1.036 131 904155.08697 0.00553 - 22 77 55 132 Cs -87152.681 1.036 8405.587 0.008 B- 1282.336 1.478 131 906437.743 1.112 - 20 76 56 132 Ba -88435.017 1.054 8409.375 0.008 B- -4711.367 36.354 131 905061.098 1.131 - 18 75 57 132 La -83723.650 36.359 8367.756 0.275 B- -1252.754 41.718 131 910118.959 39.032 - 16 74 58 132 Ce -82470.896 20.442 8352.338 0.155 B- -7243.440 35.380 131 911463.846 21.945 - 14 73 59 132 Pr x -75227.456 28.876 8291.537 0.219 B- -3801.648 37.679 131 919240.000 31.000 - 12 72 60 132 Nd x -71425.807 24.205 8256.810 0.183 B- -9798# 151# 131 923321.237 25.985 - 10 71 61 132 Pm x -61628# 149# 8177# 1# B- -6548# 333# 131 933840# 160# - 8 70 62 132 Sm x -55079# 298# 8121# 2# B- -12879# 499# 131 940870# 320# - 6 69 63 132 Eu x -42200# 400# 8018# 3# B- * 131 954696# 429# -0 37 85 48 133 Cd x -43920# 298# 8119# 2# B- 13544# 357# 132 952850# 320# - 35 84 49 133 In x -57464# 196# 8215# 1# B- 13410# 196# 132 938310# 210# - 33 83 50 133 Sn -70873.880 1.904 8310.088 0.014 B- 8049.623 3.662 132 923913.756 2.044 - 31 82 51 133 Sb -78923.503 3.128 8364.729 0.024 B- 4013.619 3.518 132 915272.130 3.357 - 29 81 52 133 Te -82937.122 2.066 8389.025 0.016 B- 2921.139 6.751 132 910963.332 2.218 - 27 80 53 133 I ++ -85858.260 6.427 8405.106 0.048 B- 1785.311 6.861 132 907827.361 6.900 - 25 79 54 133 Xe + -87643.571 2.400 8412.647 0.018 B- 427.360 2.400 132 905910.750 2.576 - 23 78 55 133 Cs -88070.931 0.008 8409.978 0.000 B- -517.319 0.992 132 905451.961 0.008 - 21 77 56 133 Ba -87553.613 0.992 8400.206 0.007 B- -2059.230 27.962 132 906007.325 1.065 - 19 76 57 133 La x -85494.383 27.945 8378.841 0.210 B- -3076.168 32.379 132 908218.000 30.000 - 17 75 58 133 Ce x -82418.214 16.354 8349.829 0.123 B- -4480.634 20.583 132 911520.402 17.557 - 15 74 59 133 Pr x -77937.581 12.497 8310.258 0.094 B- -5605.208 48.222 132 916330.561 13.416 - 13 73 60 133 Nd x -72332.372 46.575 8262.231 0.350 B- -6924.726 68.552 132 922348.000 50.000 - 11 72 61 133 Pm x -65407.646 50.301 8204.283 0.378 B- -8177# 302# 132 929782.000 54.000 - 9 71 62 133 Sm x -57231# 298# 8137# 2# B- -9995# 422# 132 938560# 320# - 7 70 63 133 Eu x -47236# 298# 8056# 2# B- -11376# 582# 132 949290# 320# - 5 69 64 133 Gd x -35860# 500# 7964# 4# B- * 132 961503# 537# -0 38 86 48 134 Cd x -38920# 400# 8082# 3# B- 12741# 499# 133 958218# 429# - 36 85 49 134 In x -51661# 298# 8171# 2# B- 14773# 298# 133 944540# 320# - 34 84 50 134 Sn x -66433.748 3.167 8275.171 0.024 B- 7586.794 3.597 133 928680.433 3.400 - 32 83 51 134 Sb x -74020.542 1.705 8325.950 0.013 B- 8513.200 3.233 133 920535.675 1.830 - 30 82 52 134 Te -82533.741 2.746 8383.643 0.020 B- 1509.687 4.933 133 911396.379 2.948 - 28 81 53 134 I -84043.429 4.857 8389.071 0.036 B- 4082.393 4.857 133 909775.663 5.213 - 26 80 54 134 Xe -88125.822 0.009 8413.699 0.000 B- -1234.667 0.018 133 905393.033 0.010 - 24 79 55 134 Cs -86891.154 0.016 8398.646 0.000 B- 2058.699 0.304 133 906718.503 0.017 - 22 78 56 134 Ba -88949.853 0.304 8408.171 0.002 B- -3731.204 19.932 133 904508.399 0.326 - 20 77 57 134 La x -85218.650 19.930 8374.488 0.149 B- -385.760 28.510 133 908514.011 21.395 - 18 76 58 134 Ce x -84832.889 20.387 8365.771 0.152 B- -6304.898 28.781 133 908928.142 21.886 - 16 75 59 134 Pr x -78527.991 20.316 8312.881 0.152 B- -2881.559 23.503 133 915696.729 21.810 - 14 74 60 134 Nd x -75646.432 11.817 8285.538 0.088 B- -8907.681 58.949 133 918790.210 12.686 - 12 73 61 134 Pm x -66738.751 57.753 8213.225 0.431 B- -5363# 204# 133 928353.000 62.000 - 10 72 62 134 Sm x -61376# 196# 8167# 1# B- -11448# 357# 133 934110# 210# - 8 71 63 134 Eu x -49928# 298# 8076# 2# B- -8626# 499# 133 946400# 320# - 6 70 64 134 Gd x -41302# 401# 8006# 3# B- * 133 955660# 430# -0 37 86 49 135 In x -46528# 401# 8132# 3# B- 14104# 401# 134 950050# 430# - 35 85 50 135 Sn x -60632.244 3.074 8230.687 0.023 B- 9058.079 4.052 134 934908.605 3.300 - 33 84 51 135 Sb -69690.323 2.640 8291.989 0.020 B- 8038.457 3.152 134 925184.357 2.834 - 31 83 52 135 Te -77728.780 1.722 8345.738 0.013 B- 6050.366 2.686 134 916554.718 1.848 - 29 82 53 135 I -83779.145 2.061 8384.760 0.015 B- 2634.005 3.868 134 910059.382 2.212 - 27 81 54 135 Xe -86413.151 3.720 8398.476 0.028 B- 1168.492 3.675 134 907231.661 3.993 - 25 80 55 135 Cs -87581.643 0.992 8401.336 0.007 B- 268.855 1.038 134 905977.234 1.064 - 23 79 56 135 Ba -87850.498 0.306 8397.533 0.002 B- -1207.181 9.430 134 905688.606 0.328 - 21 78 57 135 La -86643.317 9.434 8382.795 0.070 B- -2027.146 4.610 134 906984.568 10.127 - 19 77 58 135 Ce -84616.171 10.267 8361.984 0.076 B- -3680.310 15.655 134 909160.799 11.022 - 17 76 59 135 Pr x -80935.861 11.817 8328.928 0.088 B- -4722.252 22.484 134 913111.774 12.686 - 15 75 60 135 Nd x -76213.609 19.128 8288.153 0.142 B- -6161.534 77.838 134 918181.320 20.534 - 13 74 61 135 Pm x -70052.075 75.451 8236.717 0.559 B- -7194.860 172.054 134 924796.000 81.000 - 11 73 62 135 Sm x -62857.215 154.628 8177.626 1.145 B- -8709# 249# 134 932520.000 166.000 - 9 72 63 135 Eu x -54148# 196# 8107# 1# B- -9757# 445# 134 941870# 210# - 7 71 64 135 Gd x -44390# 400# 8029# 3# B- -11565# 566# 134 952345# 429# - 5 70 65 135 Tb -p -32825# 401# 7938# 3# B- * 134 964760# 430# -0 38 87 49 136 In x -40510# 400# 8087# 3# B- 15389# 499# 135 956511# 429# - 36 86 50 136 Sn x -55899# 298# 8195# 2# B- 8608# 298# 135 939990# 320# - 34 85 51 136 Sb -64506.880 5.830 8252.252 0.043 B- 9918.389 6.260 135 930749.011 6.258 - 32 84 52 136 Te -74425.269 2.281 8319.429 0.017 B- 5119.945 14.188 135 920101.182 2.448 - 30 83 53 136 I -79545.214 14.188 8351.323 0.104 B- 6883.945 14.188 135 914604.695 15.231 - 28 82 54 136 Xe -86429.159 0.007 8396.188 0.000 B- -90.462 1.882 135 907214.476 0.007 - 26 81 55 136 Cs + -86338.697 1.882 8389.770 0.014 B- 2548.224 1.857 135 907311.590 2.020 - 24 80 56 136 Ba -88886.921 0.306 8402.755 0.002 B- -2849.443 53.172 135 904575.959 0.328 - 22 79 57 136 La x -86037.479 53.171 8376.050 0.391 B- 470.893 53.173 135 907634.962 57.081 - 20 78 58 136 Ce -86508.372 0.408 8373.760 0.003 B- -5168.017 11.457 135 907129.438 0.438 - 18 77 59 136 Pr -81340.355 11.455 8330.008 0.084 B- -2141.068 16.458 135 912677.532 12.297 - 16 76 60 136 Nd x -79199.287 11.817 8308.512 0.087 B- -8029.371 70.076 135 914976.064 12.686 - 14 75 61 136 Pm x -71169.915 69.073 8243.720 0.508 B- -4359.026 70.194 135 923595.949 74.152 - 12 74 62 136 Sm x -66810.890 12.497 8205.916 0.092 B- -10567# 196# 135 928275.555 13.416 - 10 73 63 136 Eu x -56244# 196# 8122# 1# B- -7154# 357# 135 939620# 210# - 8 72 64 136 Gd x -49090# 298# 8064# 2# B- -12960# 582# 135 947300# 320# - 6 71 65 136 Tb x -36130# 500# 7963# 4# B- * 135 961213# 537# -0 39 88 49 137 In x -35040# 500# 8047# 4# B- 14748# 641# 136 962383# 537# - 37 87 50 137 Sn x -49788# 401# 8149# 3# B- 10272# 404# 136 946550# 430# - 35 86 51 137 Sb x -60060.384 52.164 8218.476 0.381 B- 9243.369 52.206 136 935522.522 56.000 - 33 85 52 137 Te -69303.753 2.100 8280.235 0.015 B- 7052.506 8.643 136 925599.357 2.254 - 31 84 53 137 I p-2n -76356.258 8.383 8326.002 0.061 B- 6027.145 8.384 136 918028.180 9.000 - 29 83 54 137 Xe -n -82383.404 0.103 8364.286 0.001 B- 4162.203 0.373 136 911557.773 0.111 - 27 82 55 137 Cs + -86545.606 0.358 8388.956 0.003 B- 1175.629 0.172 136 907089.464 0.384 - 25 81 56 137 Ba -87721.235 0.314 8391.827 0.002 B- -580.547 1.632 136 905827.375 0.337 - 23 80 57 137 La + -87140.688 1.659 8381.879 0.012 B- -1222.100 1.600 136 906450.618 1.780 - 21 79 58 137 Ce -85918.588 0.437 8367.248 0.003 B- -2716.895 8.133 136 907762.596 0.469 - 19 78 59 137 Pr -83201.693 8.137 8341.706 0.059 B- -3617.126 14.282 136 910679.304 8.735 - 17 77 60 137 Nd -79584.567 11.737 8309.593 0.086 B- -5511.719 17.545 136 914562.448 12.600 - 15 76 61 137 Pm x -74072.848 13.041 8263.651 0.095 B- -6046.323 44.355 136 920479.522 14.000 - 13 75 62 137 Sm -68026.525 42.395 8213.806 0.309 B- -7880.630 42.620 136 926970.517 45.512 - 11 74 63 137 Eu x -60145.895 4.378 8150.573 0.032 B- -8932# 298# 136 935430.722 4.700 - 9 73 64 137 Gd x -51214# 298# 8080# 2# B- -10246# 499# 136 945020# 320# - 7 72 65 137 Tb x -40967# 401# 7999# 3# B- * 136 956020# 430# -0 38 88 50 138 Sn x -44861# 503# 8113# 4# B- 9360# 1177# 137 951840# 540# - 36 87 51 138 Sb x -54220.403 1064.232 8175.091 7.712 B- 11475.582 1064.239 137 941792.000 1142.500 - 34 86 52 138 Te -65695.985 3.787 8252.578 0.027 B- 6283.914 7.063 137 929472.454 4.065 - 32 85 53 138 I x -71979.900 5.962 8292.444 0.043 B- 7992.334 6.588 137 922726.394 6.400 - 30 84 54 138 Xe -79972.233 2.804 8344.690 0.020 B- 2914.704 9.579 137 914146.271 3.010 - 28 83 55 138 Cs -82886.937 9.159 8360.142 0.066 B- 5374.700 9.159 137 911017.207 9.832 - 26 82 56 138 Ba -88261.638 0.317 8393.420 0.002 B- -1742.458 3.191 137 905247.229 0.339 - 24 81 57 138 La -86519.180 3.188 8375.125 0.023 B- 1051.742 4.038 137 907117.834 3.422 - 22 80 58 138 Ce -87570.922 4.931 8377.077 0.036 B- -4437.000 10.000 137 905988.743 5.293 - 20 79 59 138 Pr - -83133.922 11.150 8339.255 0.081 B- -1115.612 16.090 137 910752.059 11.969 - 18 78 60 138 Nd -82018.310 11.601 8325.502 0.084 B- -7077.827 28.756 137 911949.717 12.454 - 16 77 61 138 Pm -74940.483 27.739 8268.544 0.201 B- -3442.721 30.151 137 919548.077 29.778 - 14 76 62 138 Sm x -71497.762 11.817 8237.928 0.086 B- -9748.093 30.341 137 923243.990 12.686 - 12 75 63 138 Eu x -61749.669 27.945 8161.620 0.202 B- -5949# 198# 137 933709.000 30.000 - 10 74 64 138 Gd x -55800# 196# 8113# 1# B- -12132# 357# 137 940096# 210# - 8 73 65 138 Tb x -43668# 298# 8019# 2# B- -8737# 585# 137 953120# 320# - 6 72 66 138 Dy x -34931# 503# 7950# 4# B- * 137 962500# 540# -0 39 89 50 139 Sn x -38440# 500# 8066# 4# B- 11348# 641# 138 958733# 537# - 37 88 51 139 Sb x -49788# 401# 8142# 3# B- 10417# 401# 138 946550# 430# - 35 87 52 139 Te x -60205.072 3.540 8211.771 0.025 B- 8265.882 5.345 138 935367.193 3.800 - 33 86 53 139 I x -68470.954 4.005 8265.609 0.029 B- 7173.622 4.542 138 926493.403 4.300 - 31 85 54 139 Xe x -75644.576 2.142 8311.590 0.015 B- 5056.346 3.801 138 918792.203 2.300 - 29 84 55 139 Cs + -80700.921 3.140 8342.338 0.023 B- 4212.829 3.123 138 913363.992 3.370 - 27 83 56 139 Ba -84913.751 0.319 8367.017 0.002 B- 2312.461 2.013 138 908841.334 0.342 - 25 82 57 139 La -87226.212 2.009 8378.025 0.014 B- -278.350 6.953 138 906358.804 2.156 - 23 81 58 139 Ce -86947.862 7.230 8370.395 0.052 B- -2129.064 2.996 138 906657.625 7.761 - 21 80 59 139 Pr -84818.798 7.809 8349.449 0.056 B- -2804.856 28.033 138 908943.270 8.383 - 19 79 60 139 Nd -82013.942 27.600 8323.642 0.199 B- -4513.460 25.927 138 911954.407 29.630 - 17 78 61 139 Pm -77500.481 13.593 8285.543 0.098 B- -5120.263 17.414 138 916799.806 14.592 - 15 77 62 139 Sm x -72380.219 10.884 8243.078 0.078 B- -6982.177 17.071 138 922296.634 11.684 - 13 76 63 139 Eu x -65398.042 13.151 8187.218 0.095 B- -7767# 196# 138 929792.310 14.117 - 11 75 64 139 Gd x -57632# 196# 8126# 1# B- -9501# 357# 138 938130# 210# - 9 74 65 139 Tb x -48130# 298# 8052# 2# B- -10489# 585# 138 948330# 320# - 7 73 66 139 Dy x -37642# 503# 7971# 4# B- * 138 959590# 540# -0 38 89 51 140 Sb x -43939# 596# 8100# 4# B- 12638# 599# 139 952830# 640# - 36 88 52 140 Te x -56576.228 62.410 8184.847 0.446 B- 7029.985 63.574 139 939262.917 67.000 - 34 87 53 140 I x -63606.213 12.109 8229.473 0.086 B- 9380.238 12.331 139 931715.917 13.000 - 32 86 54 140 Xe x -72986.451 2.329 8290.887 0.017 B- 4063.654 8.525 139 921645.817 2.500 - 30 85 55 140 Cs -77050.105 8.201 8314.325 0.059 B- 6219.249 9.882 139 917283.305 8.804 - 28 84 56 140 Ba -83269.354 7.933 8353.160 0.057 B- 1046.517 7.993 139 910606.666 8.516 - 26 83 57 140 La -84315.871 2.009 8355.047 0.014 B- 3760.218 1.727 139 909483.184 2.156 - 24 82 58 140 Ce -88076.089 1.596 8376.317 0.011 B- -3388.000 6.000 139 905446.424 1.713 - 22 81 59 140 Pr - -84688.089 6.209 8346.529 0.044 B- -429.177 7.101 139 909083.592 6.665 - 20 80 60 140 Nd x -84258.912 3.447 8337.875 0.025 B- -6045.200 24.000 139 909544.332 3.700 - 18 79 61 140 Pm - -78213.712 24.246 8289.107 0.173 B- -2757.777 27.277 139 916034.122 26.029 - 16 78 62 140 Sm x -75455.935 12.497 8263.820 0.089 B- -8470.000 50.000 139 918994.717 13.416 - 14 77 63 140 Eu - -66985.935 51.538 8197.732 0.368 B- -5203.664 58.627 139 928087.637 55.328 - 12 76 64 140 Gd x -61782.271 27.945 8154.975 0.200 B- -11300.000 800.000 139 933674.000 30.000 - 10 75 65 140 Tb - -50482.271 800.488 8068.672 5.718 B- -7652# 895# 139 945805.049 859.359 - 8 74 66 140 Dy x -42830# 401# 8008# 3# B- -13571# 643# 139 954020# 430# - 6 73 67 140 Ho -p -29259# 503# 7906# 4# B- * 139 968589# 540# -0 39 90 51 141 Sb x -39110# 500# 8066# 4# B- 11377# 641# 140 958014# 537# - 37 89 52 141 Te x -50487# 401# 8141# 3# B- 9440# 401# 140 945800# 430# - 35 88 53 141 I x -59926.657 15.835 8202.255 0.112 B- 8270.642 16.097 140 935666.084 17.000 - 33 87 54 141 Xe x -68197.299 2.888 8255.364 0.020 B- 6280.224 9.638 140 926787.184 3.100 - 31 86 55 141 Cs -74477.523 9.195 8294.356 0.065 B- 5255.103 9.617 140 920045.086 9.871 - 29 85 56 141 Ba -79732.626 5.319 8326.078 0.038 B- 3199.010 6.600 140 914403.500 5.710 - 27 84 57 141 La -82931.636 4.219 8343.217 0.030 B- 2501.280 3.928 140 910969.222 4.528 - 25 83 58 141 Ce -85432.916 1.597 8355.408 0.011 B- 582.728 1.202 140 908283.987 1.714 - 23 82 59 141 Pr -86015.644 1.665 8353.992 0.012 B- -1823.014 2.809 140 907658.403 1.787 - 21 81 60 141 Nd - -84192.630 3.265 8335.515 0.023 B- -3669.709 14.349 140 909615.488 3.505 - 19 80 61 141 Pm x -80522.921 13.972 8303.940 0.099 B- -4589.012 16.375 140 913555.084 15.000 - 17 79 62 141 Sm -75933.909 8.539 8265.845 0.061 B- -6008.280 14.285 140 918481.591 9.167 - 15 78 63 141 Eu -69925.629 12.639 8217.684 0.090 B- -6701.405 23.456 140 924931.745 13.568 - 13 77 64 141 Gd x -63224.224 19.760 8164.608 0.140 B- -8683.387 107.098 140 932126.000 21.213 - 11 76 65 141 Tb x -54540.837 105.259 8097.475 0.747 B- -9158# 316# 140 941448.000 113.000 - 9 75 66 141 Dy x -45382# 298# 8027# 2# B- -11018# 499# 140 951280# 320# - 7 74 67 141 Ho -p -34364# 401# 7943# 3# B- * 140 963108# 430# -0 38 90 52 142 Te x -46370# 503# 8111# 4# B- 8400# 627# 141 950220# 540# - 36 89 53 142 I x -54769.984 374.461 8165.019 2.637 B- 10459.655 374.470 141 941202.000 402.000 - 34 88 54 142 Xe x -65229.639 2.701 8233.169 0.019 B- 5284.911 7.565 141 929973.098 2.900 - 32 87 55 142 Cs -70514.550 7.067 8264.877 0.050 B- 7327.714 8.363 141 924299.512 7.586 - 30 86 56 142 Ba -77842.264 5.920 8310.971 0.042 B- 2181.963 8.391 141 916432.888 6.355 - 28 85 57 142 La -80024.227 6.309 8320.828 0.044 B- 4508.961 5.845 141 914090.454 6.773 - 26 84 58 142 Ce -84533.188 2.509 8347.071 0.018 B- -745.712 2.500 141 909249.884 2.693 - 24 83 59 142 Pr -83787.476 1.665 8336.310 0.012 B- 2162.505 1.416 141 910050.440 1.786 - 22 82 60 142 Nd -85949.980 1.368 8346.030 0.010 B- -4807.936 23.629 141 907728.895 1.468 - 20 81 61 142 Pm -81142.044 23.597 8306.662 0.166 B- -2155.574 23.752 141 912890.428 25.332 - 18 80 62 142 Sm -78986.470 3.079 8285.972 0.022 B- -7673.000 30.000 141 915204.532 3.305 - 16 79 63 142 Eu - -71313.470 30.158 8226.427 0.212 B- -4353.955 41.114 141 923441.836 32.375 - 14 78 64 142 Gd x -66959.515 27.945 8190.256 0.197 B- -10400.000 700.000 141 928116.000 30.000 - 12 77 65 142 Tb - -56559.515 700.558 8111.507 4.934 B- -6440# 200# 141 939280.859 752.079 - 10 76 66 142 Dy - -50120# 729# 8061# 5# B- -12869# 831# 141 946194# 782# - 8 75 67 142 Ho x -37250# 401# 7965# 3# B- -9221# 641# 141 960010# 430# - 6 74 68 142 Er x -28030# 500# 7894# 4# B- * 141 969909# 537# -0 39 91 52 143 Te x -40278# 503# 8068# 4# B- 10353# 541# 142 956760# 540# - 37 90 53 143 I x -50630# 200# 8135# 1# B- 9572# 200# 142 945646# 215# - 35 89 54 143 Xe x -60202.873 4.657 8196.885 0.033 B- 7472.636 8.891 142 935369.553 5.000 - 33 88 55 143 Cs -67675.509 7.573 8243.670 0.053 B- 6261.688 9.730 142 927347.348 8.130 - 31 87 56 143 Ba -73937.197 6.756 8281.987 0.047 B- 4234.318 9.969 142 920625.150 7.253 - 29 86 57 143 La -78171.515 7.330 8306.127 0.051 B- 3435.156 7.595 142 916079.422 7.869 - 27 85 58 143 Ce -81606.671 2.508 8324.678 0.018 B- 1461.575 1.866 142 912391.630 2.692 - 25 84 59 143 Pr -83068.246 1.897 8329.428 0.013 B- 933.988 1.368 142 910822.564 2.037 - 23 83 60 143 Nd -84002.234 1.367 8330.488 0.010 B- -1041.583 2.682 142 909819.887 1.467 - 21 82 61 143 Pm -82960.651 2.996 8317.733 0.021 B- -3443.499 3.560 142 910938.073 3.216 - 19 81 62 143 Sm -79517.152 2.804 8288.182 0.020 B- -5275.851 11.338 142 914634.821 3.010 - 17 80 63 143 Eu x -74241.300 10.986 8245.817 0.077 B- -6010.000 200.000 142 920298.681 11.793 - 15 79 64 143 Gd - -68231.300 200.301 8198.318 1.401 B- -7812.117 206.750 142 926750.682 215.032 - 13 78 65 143 Tb x -60419.183 51.232 8138.217 0.358 B- -8250.242 52.866 142 935137.335 55.000 - 11 77 66 143 Dy x -52168.941 13.041 8075.052 0.091 B- -10121# 298# 142 943994.335 14.000 - 9 76 67 143 Ho x -42048# 298# 7999# 2# B- -10788# 499# 142 954860# 320# - 7 75 68 143 Er x -31260# 400# 7918# 3# B- * 142 966441# 429# -0 38 91 53 144 I x -45280# 401# 8098# 3# B- 11592# 401# 143 951390# 430# - 36 90 54 144 Xe x -56872.293 5.310 8172.884 0.037 B- 6399.060 20.820 143 938945.079 5.700 - 34 89 55 144 Cs -63271.353 20.132 8211.889 0.140 B- 8495.768 20.416 143 932075.404 21.612 - 32 88 56 144 Ba -71767.121 7.136 8265.454 0.050 B- 3082.530 14.774 143 922954.821 7.661 - 30 87 57 144 La x -74849.652 12.937 8281.428 0.090 B- 5582.219 13.254 143 919645.589 13.888 - 28 86 58 144 Ce + -80431.870 2.885 8314.760 0.020 B- 318.646 0.832 143 913652.830 3.096 - 26 85 59 144 Pr + -80750.517 2.762 8311.540 0.019 B- 2997.440 2.400 143 913310.750 2.965 - 24 84 60 144 Nd -83747.957 1.367 8326.922 0.009 B- -2331.863 2.646 143 910092.865 1.467 - 22 83 61 144 Pm -81416.093 2.964 8305.296 0.021 B- 549.442 2.668 143 912596.224 3.181 - 20 82 62 144 Sm -81965.535 1.554 8303.679 0.011 B- -6346.402 10.814 143 912006.373 1.668 - 18 81 63 144 Eu -75619.133 10.789 8254.173 0.075 B- -3859.630 29.955 143 918819.517 11.582 - 16 80 64 144 Gd x -71759.504 27.945 8221.937 0.194 B- -9391.323 39.520 143 922963.000 30.000 - 14 79 65 144 Tb x -62368.181 27.945 8151.287 0.194 B- -5798.098 28.851 143 933045.000 30.000 - 12 78 66 144 Dy x -56570.083 7.173 8105.589 0.050 B- -11960.569 11.104 143 939269.514 7.700 - 10 77 67 144 Ho x -44609.513 8.477 8017.097 0.059 B- -8002# 196# 143 952109.714 9.100 - 8 76 68 144 Er x -36608# 196# 7956# 1# B- -14349# 445# 143 960700# 210# - 6 75 69 144 Tm -p -22259# 400# 7851# 3# B- * 143 976104# 429# -0 39 92 53 145 I x -40939# 503# 8068# 3# B- 10554# 503# 144 956050# 540# - 37 91 54 145 Xe x -51493.329 11.178 8135.087 0.077 B- 8561.086 14.393 144 944719.634 12.000 - 35 90 55 145 Cs -60054.415 9.067 8188.733 0.063 B- 7461.761 12.412 144 935528.930 9.733 - 33 89 56 145 Ba x -67516.176 8.477 8234.798 0.058 B- 5319.141 14.912 144 927518.400 9.100 - 31 88 57 145 La -72835.317 12.269 8266.087 0.085 B- 4231.705 35.300 144 921808.066 13.170 - 29 87 58 145 Ce -77067.022 33.902 8289.875 0.234 B- 2558.918 33.635 144 917265.144 36.395 - 27 86 59 145 Pr -79625.940 7.169 8302.127 0.049 B- 1806.012 7.037 144 914518.033 7.696 - 25 85 60 145 Nd -81431.951 1.384 8309.187 0.010 B- -164.478 2.536 144 912579.199 1.485 - 23 84 61 145 Pm -81267.474 2.859 8302.657 0.020 B- -616.156 2.539 144 912755.773 3.068 - 21 83 62 145 Sm -80651.318 1.578 8293.013 0.011 B- -2659.810 2.723 144 913417.244 1.694 - 19 82 63 145 Eu -77991.507 3.106 8269.274 0.021 B- -5065.187 19.953 144 916272.668 3.334 - 17 81 64 145 Gd -72926.320 19.709 8228.946 0.136 B- -6537.909 108.066 144 921710.370 21.158 - 15 80 65 145 Tb -66388.411 109.174 8178.461 0.753 B- -8145.812 109.369 144 928729.105 117.203 - 13 79 66 145 Dy x -58242.599 6.520 8116.888 0.045 B- -9122.493 9.902 144 937473.994 7.000 - 11 78 67 145 Ho x -49120.105 7.452 8048.578 0.051 B- -9880# 200# 144 947267.394 8.000 - 9 77 68 145 Er x -39240# 200# 7975# 1# B- -11657# 280# 144 957874# 215# - 7 76 69 145 Tm -p -27583# 196# 7889# 1# B- * 144 970389# 210# -0 38 92 54 146 Xe x -47954.943 24.219 8110.415 0.166 B- 7355.429 24.391 145 948518.248 26.000 - 36 91 55 146 Cs x -55310.372 2.893 8155.436 0.020 B- 9636.714 21.063 145 940621.870 3.106 - 34 90 56 146 Ba -64947.086 20.863 8216.082 0.143 B- 4103.197 33.503 145 930276.431 22.397 - 32 89 57 146 La -69050.283 33.616 8238.828 0.230 B- 6585.107 34.456 145 925871.468 36.088 - 30 88 58 146 Ce -75635.389 16.306 8278.573 0.112 B- 1045.616 32.519 145 918802.065 17.504 - 28 87 59 146 Pr -76681.006 34.816 8280.376 0.238 B- 4244.861 34.830 145 917679.549 37.376 - 26 86 60 146 Nd -80925.867 1.386 8304.092 0.009 B- -1471.558 4.119 145 913122.503 1.488 - 24 85 61 146 Pm + -79454.309 4.308 8288.654 0.030 B- 1542.000 3.000 145 914702.286 4.624 - 22 84 62 146 Sm -80996.309 3.092 8293.857 0.021 B- -3878.768 5.869 145 913046.881 3.319 - 20 83 63 146 Eu -77117.541 6.026 8261.932 0.041 B- -1031.758 7.076 145 917210.909 6.468 - 18 82 64 146 Gd -76085.783 4.108 8249.506 0.028 B- -8322.173 44.749 145 918318.548 4.409 - 16 81 65 146 Tb -67763.610 44.862 8187.146 0.307 B- -5208.691 45.160 145 927252.768 48.161 - 14 80 66 146 Dy -62554.918 6.695 8146.112 0.046 B- -11316.699 9.392 145 932844.529 7.187 - 12 79 67 146 Ho -51238.219 6.587 8063.242 0.045 B- -6916.206 9.399 145 944993.506 7.071 - 10 78 68 146 Er -44322.012 6.705 8010.512 0.046 B- -13267# 200# 145 952418.359 7.197 - 8 77 69 146 Tm -p -31055# 200# 7914# 1# B- * 145 966661# 215# -0 39 93 54 147 Xe x -42360# 200# 8072# 1# B- 9560# 200# 146 954525# 215# - 37 92 55 147 Cs x -51920.064 8.383 8131.800 0.057 B- 8343.965 21.454 146 944261.515 9.000 - 35 91 56 147 Ba x -60264.029 19.748 8183.240 0.134 B- 6414.361 22.466 146 935303.900 21.200 - 33 90 57 147 La x -66678.390 10.712 8221.553 0.073 B- 5335.501 13.725 146 928417.800 11.500 - 31 89 58 147 Ce -72013.891 8.580 8252.527 0.058 B- 3430.176 15.533 146 922689.903 9.211 - 29 88 59 147 Pr -75444.067 15.857 8270.539 0.108 B- 2702.681 15.860 146 919007.458 17.023 - 27 87 60 147 Nd -78146.748 1.388 8283.603 0.009 B- 895.512 0.482 146 916106.010 1.490 - 25 86 61 147 Pm -79042.260 1.399 8284.372 0.010 B- 224.094 0.293 146 915144.638 1.501 - 23 85 62 147 Sm -79266.354 1.372 8280.575 0.009 B- -1721.598 2.281 146 914904.064 1.473 - 21 84 63 147 Eu -77544.756 2.630 8263.541 0.018 B- -2187.811 2.524 146 916752.276 2.823 - 19 83 64 147 Gd -75356.945 1.965 8243.336 0.013 B- -4614.280 8.147 146 919100.987 2.109 - 17 82 65 147 Tb -70742.665 8.100 8206.624 0.055 B- -6546.628 11.997 146 924054.620 8.695 - 15 81 66 147 Dy x -64196.038 8.849 8156.767 0.060 B- -8438.945 10.164 146 931082.715 9.500 - 13 80 67 147 Ho -55757.092 5.001 8094.037 0.034 B- -9149.286 38.517 146 940142.295 5.368 - 11 79 68 147 Er x -46607.807 38.191 8026.475 0.260 B- -10633.406 38.799 146 949964.458 41.000 - 9 78 69 147 Tm -35974.400 6.839 7948.817 0.047 B- * 146 961379.890 7.341 -0 40 94 54 148 Xe x -38600# 300# 8047# 2# B- 8311# 300# 147 958561# 322# - 38 93 55 148 Cs x -46910.942 13.041 8097.546 0.088 B- 10682.793 64.413 147 949639.029 14.000 - 36 92 56 148 Ba + -57593.735 63.079 8164.441 0.426 B- 5115.000 60.000 147 938170.578 67.718 - 34 91 57 148 La x -62708.735 19.468 8193.716 0.132 B- 7689.672 22.457 147 932679.400 20.900 - 32 90 58 148 Ce -70398.408 11.195 8240.387 0.076 B- 2137.016 12.567 147 924424.196 12.018 - 30 89 59 148 Pr -72535.424 15.043 8249.540 0.102 B- 4872.572 15.090 147 922130.015 16.148 - 28 88 60 148 Nd -77407.996 2.127 8277.177 0.014 B- -542.280 5.874 147 916899.093 2.283 - 26 87 61 148 Pm +p -76865.716 5.723 8268.226 0.039 B- 2470.548 5.642 147 917481.255 6.143 - 24 86 62 148 Sm -79336.264 1.367 8279.633 0.009 B- -3036.933 10.019 147 914829.012 1.467 - 22 85 63 148 Eu -76299.331 10.013 8253.827 0.068 B- -30.003 10.019 147 918089.294 10.748 - 20 84 64 148 Gd -76269.329 1.554 8248.338 0.011 B- -5732.246 12.529 147 918121.503 1.668 - 18 83 65 148 Tb -70537.082 12.464 8204.321 0.084 B- -2677.532 9.596 147 924275.323 13.380 - 16 82 66 148 Dy -67859.550 8.724 8180.943 0.059 B- -9868.393 84.287 147 927149.772 9.366 - 14 81 67 148 Ho x -57991.158 83.834 8108.979 0.566 B- -6512.169 84.458 147 937743.928 90.000 - 12 80 68 148 Er x -51478.989 10.246 8059.692 0.069 B- -12713.962 14.491 147 944735.029 11.000 - 10 79 69 148 Tm x -38765.027 10.246 7968.500 0.069 B- -8435# 400# 147 958384.029 11.000 - 8 78 70 148 Yb x -30330# 400# 7906# 3# B- * 147 967439# 429# -0 39 94 55 149 Cs x -43250# 400# 8073# 3# B- 9870# 593# 148 953569# 429# - 37 93 56 149 Ba x -53120.309 437.802 8133.793 2.938 B- 7099.605 481.431 148 942973.000 470.000 - 35 92 57 149 La + -60219.913 200.262 8176.191 1.344 B- 6450.000 200.000 148 935351.260 214.990 - 33 91 58 149 Ce x -66669.913 10.246 8214.229 0.069 B- 4369.452 14.230 148 928426.900 11.000 - 31 90 59 149 Pr x -71039.366 9.874 8238.303 0.066 B- 3336.100 10.101 148 923736.100 10.600 - 29 89 60 149 Nd -n -74375.466 2.128 8255.442 0.014 B- 1688.790 2.455 148 920154.648 2.284 - 27 88 61 149 Pm -76064.256 2.267 8261.526 0.015 B- 1071.481 1.875 148 918341.658 2.434 - 25 87 62 149 Sm -77135.737 1.311 8263.466 0.009 B- -694.625 3.788 148 917191.375 1.407 - 23 86 63 149 Eu -76441.112 3.951 8253.554 0.027 B- -1314.101 4.136 148 917937.086 4.241 - 21 85 64 149 Gd -75127.011 3.360 8239.484 0.023 B- -3638.343 4.339 148 919347.831 3.607 - 19 84 65 149 Tb -71488.669 3.667 8209.815 0.025 B- -3792.760 9.162 148 923253.753 3.936 - 17 83 66 149 Dy -67695.909 9.221 8179.109 0.062 B- -6049.330 12.803 148 927325.448 9.898 - 15 82 67 149 Ho -61646.578 11.990 8133.259 0.080 B- -7904.963 30.408 148 933819.672 12.871 - 13 81 68 149 Er x -53741.615 27.945 8074.955 0.188 B- -9859# 198# 148 942306.000 30.000 - 11 80 69 149 Tm x -43883# 196# 8004# 1# B- -10684# 358# 148 952890# 210# - 9 79 70 149 Yb x -33198# 300# 7927# 2# B- * 148 964360# 322# -0 40 95 55 150 Cs x -38170# 400# 8039# 3# B- 11730# 500# 149 959023# 429# - 38 94 56 150 Ba x -49900# 300# 8112# 2# B- 6230# 529# 149 946430# 322# - 36 93 57 150 La x -56129.966 435.473 8148.225 2.903 B- 8716.888 435.631 149 939742.000 467.500 - 34 92 58 150 Ce -64846.854 11.697 8201.122 0.078 B- 3453.625 14.291 149 930384.035 12.556 - 32 91 59 150 Pr -68300.479 9.015 8218.931 0.060 B- 5379.276 9.085 149 926676.415 9.678 - 30 90 60 150 Nd -73679.755 1.289 8249.577 0.009 B- -82.616 20.001 149 920901.525 1.384 - 28 89 61 150 Pm + -73597.139 20.041 8243.810 0.134 B- 3454.000 20.000 149 920990.217 21.514 - 26 88 62 150 Sm -77051.139 1.274 8261.621 0.009 B- -2258.905 6.181 149 917282.195 1.368 - 24 87 63 150 Eu -74792.234 6.253 8241.346 0.042 B- 971.700 3.543 149 919707.229 6.712 - 22 86 64 150 Gd -75763.934 6.076 8242.609 0.041 B- -4658.213 8.379 149 918664.066 6.523 - 20 85 65 150 Tb -71105.721 7.384 8206.338 0.049 B- -1796.122 8.389 149 923664.864 7.927 - 18 84 66 150 Dy -69309.600 4.348 8189.149 0.029 B- -7363.719 14.468 149 925593.080 4.667 - 16 83 67 150 Ho -61945.881 14.168 8134.842 0.094 B- -4114.568 13.591 149 933498.358 15.210 - 14 82 68 150 Er -57831.313 17.195 8102.195 0.115 B- -11340# 196# 149 937915.528 18.459 - 12 81 69 150 Tm x -46491# 196# 8021# 1# B- -7852# 358# 149 950090# 210# - 10 80 70 150 Yb x -38638# 300# 7964# 2# B- -13998# 424# 149 958520# 322# - 8 79 71 150 Lu -p -24640# 300# 7865# 2# B- * 149 973548# 322# -0 41 96 55 151 Cs x -34230# 500# 8013# 3# B- 10710# 640# 150 963253# 537# - 39 95 56 151 Ba x -44940# 400# 8079# 3# B- 8370# 591# 150 951755# 429# - 37 94 57 151 La x -53310.333 435.473 8129.043 2.884 B- 7914.718 435.833 150 942769.000 467.500 - 35 93 58 151 Ce x -61225.052 17.698 8176.277 0.117 B- 5554.578 21.189 150 934272.200 19.000 - 33 92 59 151 Pr -66779.630 11.651 8207.881 0.077 B- 4163.358 11.689 150 928309.114 12.507 - 31 91 60 151 Nd -70942.988 1.293 8230.272 0.009 B- 2443.075 4.473 150 923839.565 1.387 - 29 90 61 151 Pm -73386.063 4.653 8241.270 0.031 B- 1190.217 4.476 150 921216.817 4.994 - 27 89 62 151 Sm -74576.279 1.273 8243.971 0.008 B- 76.574 0.538 150 919939.066 1.367 - 25 88 63 151 Eu -74652.854 1.325 8239.297 0.009 B- -464.116 2.779 150 919856.860 1.422 - 23 87 64 151 Gd -74188.737 3.056 8231.043 0.020 B- -2565.233 3.762 150 920355.109 3.280 - 21 86 65 151 Tb -71623.504 4.137 8208.873 0.027 B- -2871.099 4.944 150 923109.001 4.441 - 19 85 66 151 Dy -a -68752.405 3.293 8184.678 0.022 B- -5129.667 8.756 150 926191.253 3.535 - 17 84 67 151 Ho -a -63622.738 8.302 8145.526 0.055 B- -5356.454 18.444 150 931698.177 8.912 - 15 83 68 151 Er x -58266.284 16.470 8104.872 0.109 B- -7493.528 25.460 150 937448.567 17.681 - 13 82 69 151 Tm +a -50772.756 19.416 8050.064 0.129 B- -9230.414 300.136 150 945493.201 20.843 - 11 81 70 151 Yb ep -41542.342 300.492 7983.755 1.990 B- -11434# 425# 150 955402.458 322.591 - 9 80 71 151 Lu -p -30108# 300# 7903# 2# B- * 150 967677# 322# -0 42 97 55 152 Cs x -28930# 500# 7979# 3# B- 12780# 640# 151 968942# 537# - 40 96 56 152 Ba x -41710# 400# 8057# 3# B- 7580# 500# 151 955222# 429# - 38 95 57 152 La x -49290# 300# 8102# 2# B- 9690# 361# 151 947085# 322# - 36 94 58 152 Ce x -58980# 200# 8161# 1# B- 4778# 201# 151 936682# 215# - 34 93 59 152 Pr x -63758.063 18.537 8187.104 0.122 B- 6391.344 30.710 151 931552.900 19.900 - 32 92 60 152 Nd -70149.407 24.485 8224.005 0.161 B- 1104.778 18.501 151 924691.509 26.285 - 30 91 61 152 Pm -71254.186 25.912 8226.127 0.170 B- 3508.417 25.886 151 923505.481 27.817 - 28 90 62 152 Sm -74762.603 1.212 8244.061 0.008 B- -1874.348 0.687 151 919739.040 1.301 - 26 89 63 152 Eu -72888.255 1.326 8226.583 0.009 B- 1818.661 0.702 151 921751.235 1.423 - 24 88 64 152 Gd -74706.916 1.206 8233.401 0.008 B- -3990.000 40.000 151 919798.822 1.294 - 22 87 65 152 Tb - -70716.916 40.018 8202.004 0.263 B- -599.044 40.258 151 924082.263 42.961 - 20 86 66 152 Dy -a -70117.873 4.624 8192.916 0.030 B- -6513.102 13.325 151 924725.363 4.963 - 18 85 67 152 Ho -63604.771 12.529 8144.919 0.082 B- -3104.394 9.815 151 931717.465 13.450 - 16 84 68 152 Er -60500.377 8.830 8119.349 0.058 B- -8780.104 54.743 151 935050.169 9.479 - 14 83 69 152 Tm -51720.273 54.027 8056.438 0.355 B- -5449.892 139.620 151 944476.000 58.000 - 12 82 70 152 Yb -46270.381 149.708 8015.436 0.985 B- -12848# 246# 151 950326.700 160.718 - 10 81 71 152 Lu x -33422# 196# 7926# 1# B- * 151 964120# 210# -0 41 97 56 153 Ba x -36470# 400# 8023# 3# B- 9590# 500# 152 960848# 429# - 39 96 57 153 La x -46060# 300# 8081# 2# B- 8850# 361# 152 950553# 322# - 37 95 58 153 Ce x -54910# 200# 8134# 1# B- 6659# 201# 152 941052# 215# - 35 94 59 153 Pr -61568.463 11.882 8172.036 0.078 B- 5761.834 12.190 152 933903.532 12.755 - 33 93 60 153 Nd -67330.297 2.747 8204.582 0.018 B- 3317.527 9.355 152 927717.949 2.948 - 31 92 61 153 Pm -70647.824 9.066 8221.152 0.059 B- 1911.862 9.093 152 924156.436 9.732 - 29 91 62 153 Sm -n -72559.686 1.219 8228.534 0.008 B- 807.536 0.708 152 922103.969 1.309 - 27 90 63 153 Eu -73367.222 1.330 8228.699 0.009 B- -484.671 0.717 152 921237.043 1.428 - 25 89 64 153 Gd -72882.551 1.203 8220.418 0.008 B- -1569.213 3.845 152 921757.359 1.291 - 23 88 65 153 Tb -71313.338 3.995 8205.048 0.026 B- -2170.394 1.933 152 923441.978 4.289 - 21 87 66 153 Dy -69142.943 4.048 8185.749 0.026 B- -4130.840 6.157 152 925771.992 4.346 - 19 86 67 153 Ho -a -65012.103 5.094 8153.637 0.033 B- -4543.499 9.916 152 930206.632 5.468 - 17 85 68 153 Er -60468.604 9.321 8118.827 0.061 B- -6495.276 12.891 152 935084.279 10.006 - 15 84 69 153 Tm -53973.329 11.983 8071.261 0.078 B- -6765# 196# 152 942057.244 12.864 - 13 83 70 153 Yb x -47208# 196# 8022# 1# B- -8835# 247# 152 949320# 210# - 11 82 71 153 Lu +a -38372.844 150.034 7959.070 0.981 B- -11073# 335# 152 958805.054 161.068 - 9 81 72 153 Hf x -27300# 300# 7882# 2# B- * 152 970692# 322# -0 42 98 56 154 Ba x -32820# 500# 8000# 3# B- 8709# 583# 153 964766# 537# - 40 97 57 154 La x -41530# 300# 8051# 2# B- 10690# 361# 153 955416# 322# - 38 96 58 154 Ce x -52220# 200# 8116# 1# B- 5885# 230# 153 943940# 215# - 36 95 59 154 Pr + -58104.976 113.009 8148.892 0.734 B- 7720.000 100.000 153 937621.738 121.320 - 34 94 60 154 Nd + -65824.976 52.642 8193.942 0.342 B- 2687.000 25.000 153 929333.977 56.513 - 32 93 61 154 Pm IT -68511.976 46.326 8206.310 0.301 B- 3943.200 46.303 153 926449.364 49.733 - 30 92 62 154 Sm -72455.176 1.462 8226.835 0.009 B- -717.056 1.103 153 922216.164 1.569 - 28 91 63 154 Eu -71738.121 1.346 8217.098 0.009 B- 1967.834 0.755 153 922985.955 1.444 - 26 90 64 154 Gd -73705.954 1.197 8224.796 0.008 B- -3549.651 45.298 153 920873.398 1.285 - 24 89 65 154 Tb - -70156.303 45.314 8196.666 0.294 B- 237.604 45.901 153 924684.106 48.646 - 22 88 66 154 Dy -70393.907 7.445 8193.129 0.048 B- -5754.596 10.178 153 924429.028 7.992 - 20 87 67 154 Ho -a -64639.311 8.228 8150.681 0.053 B- -2034.291 9.463 153 930606.841 8.833 - 18 86 68 154 Er -62605.020 4.986 8132.392 0.032 B- -8177.888 14.916 153 932790.743 5.353 - 16 85 69 154 Tm -a -54427.131 14.412 8074.208 0.094 B- -4495.048 13.953 153 941570.067 15.472 - 14 84 70 154 Yb -49932.083 17.281 8039.939 0.112 B- -10217# 197# 153 946395.701 18.552 - 12 83 71 154 Lu +a -39715# 196# 7969# 1# B- -7045# 358# 153 957364# 211# - 10 82 72 154 Hf x -32670# 300# 7918# 2# B- * 153 964927# 322# -0 41 98 57 155 La x -37930# 400# 8028# 3# B- 9850# 500# 154 959280# 429# - 39 97 58 155 Ce x -47780# 300# 8087# 2# B- 7635# 300# 154 948706# 322# - 37 96 59 155 Pr -55415.268 17.198 8131.039 0.111 B- 6868.456 19.472 154 940509.259 18.462 - 35 95 60 155 Nd -62283.724 9.153 8170.304 0.059 B- 4656.207 10.278 154 933135.668 9.826 - 33 94 61 155 Pm -66939.931 4.718 8195.296 0.030 B- 3250.888 4.946 154 928137.024 5.065 - 31 93 62 155 Sm -n -70190.819 1.487 8211.223 0.010 B- 1627.273 1.202 154 924647.051 1.595 - 29 92 63 155 Eu -71818.092 1.401 8216.674 0.009 B- 251.788 0.870 154 922900.102 1.504 - 27 91 64 155 Gd -72069.880 1.191 8213.251 0.008 B- -819.830 9.789 154 922629.796 1.278 - 25 90 65 155 Tb + -71250.050 9.849 8202.914 0.064 B- -2094.500 1.897 154 923509.921 10.573 - 23 89 66 155 Dy -69155.550 9.665 8184.354 0.062 B- -3116.011 16.590 154 925758.459 10.375 - 21 88 67 155 Ho -66039.539 17.474 8159.203 0.113 B- -3830.350 18.474 154 929103.634 18.759 - 19 87 68 155 Er -a -62209.189 6.098 8129.444 0.039 B- -5583.276 11.515 154 933215.684 6.546 - 17 86 69 155 Tm -a -56625.913 9.925 8088.375 0.064 B- -6123.305 19.341 154 939209.578 10.654 - 15 85 70 155 Yb -a -50502.608 16.600 8043.823 0.107 B- -7957.561 25.416 154 945783.217 17.820 - 13 84 71 155 Lu +a -42545.047 19.246 7987.436 0.124 B- -8375# 299# 154 954326.011 20.661 - 11 83 72 155 Hf x -34170# 298# 7928# 2# B- -10242# 423# 154 963317# 320# - 9 82 73 155 Ta -p -23928# 300# 7857# 2# B- * 154 974312# 322# -0 42 99 57 156 La x -33050# 400# 7997# 3# B- 11769# 500# 155 964519# 429# - 40 98 58 156 Ce x -44820# 300# 8068# 2# B- 6748# 361# 155 951884# 322# - 38 97 59 156 Pr x -51568# 200# 8106# 1# B- 8906# 283# 155 944640# 215# - 36 96 60 156 Nd + -60473.644 200.033 8158.066 1.282 B- 3690.000 200.000 155 935078.868 214.744 - 34 95 61 156 Pm -64163.644 3.631 8176.705 0.023 B- 5196.786 9.285 155 931117.490 3.897 - 32 94 62 156 Sm -69360.430 8.546 8205.003 0.055 B- 722.118 7.902 155 925538.511 9.174 - 30 93 63 156 Eu -70082.548 3.590 8204.617 0.023 B- 2452.366 3.409 155 924763.285 3.853 - 28 92 64 156 Gd -72534.914 1.190 8215.322 0.008 B- -2444.117 3.679 155 922130.562 1.277 - 26 91 65 156 Tb -70090.797 3.814 8194.639 0.024 B- 438.167 3.681 155 924754.430 4.094 - 24 90 66 156 Dy -70528.964 1.194 8192.433 0.008 B- -5050.000 60.000 155 924284.038 1.281 - 22 89 67 156 Ho - -65478.964 60.012 8155.046 0.385 B- -1267.255 64.869 155 929705.436 64.425 - 20 88 68 156 Er -64211.709 24.629 8141.908 0.158 B- -7377.159 26.710 155 931065.890 26.440 - 18 87 69 156 Tm -56834.550 14.279 8089.603 0.092 B- -3568.830 12.548 155 938985.597 15.328 - 16 86 70 156 Yb -53265.721 9.308 8061.711 0.060 B- -9566.176 54.916 155 942816.893 9.992 - 14 85 71 156 Lu -a -43699.544 54.122 7995.374 0.347 B- -5882.648 139.709 155 953086.606 58.102 - 12 84 72 156 Hf -37816.896 149.757 7952.650 0.960 B- -11956# 334# 155 959401.889 160.770 - 10 83 73 156 Ta -p -25861# 298# 7871# 2# B- * 155 972237# 320# -0 41 99 58 157 Ce x -39930# 400# 8037# 3# B- 8610# 500# 156 957133# 429# - 39 98 59 157 Pr x -48540# 300# 8086# 2# B- 7921# 301# 156 947890# 322# - 37 97 60 157 Nd -56461.543 24.918 8131.959 0.159 B- 5835.500 25.877 156 939386.037 26.750 - 35 96 61 157 Pm -62297.043 7.006 8164.145 0.045 B- 4380.534 8.265 156 933121.370 7.521 - 33 95 62 157 Sm -66677.577 4.433 8187.063 0.028 B- 2781.331 6.136 156 928418.673 4.759 - 31 94 63 157 Eu -69458.908 4.259 8199.795 0.027 B- 1364.565 4.203 156 925432.791 4.572 - 29 93 64 157 Gd -70823.473 1.189 8203.504 0.008 B- -60.043 0.297 156 923967.870 1.276 - 27 92 65 157 Tb -70763.430 1.222 8198.138 0.008 B- -1338.872 5.134 156 924032.328 1.311 - 25 91 66 157 Dy -69424.558 5.177 8184.627 0.033 B- -2591.725 23.787 156 925469.667 5.557 - 23 90 67 157 Ho -66832.832 23.469 8163.136 0.149 B- -3419.194 33.668 156 928251.999 25.195 - 21 89 68 157 Er -63413.639 26.505 8136.375 0.169 B- -4704.366 38.515 156 931922.655 28.454 - 19 88 69 157 Tm x -58709.273 27.945 8101.428 0.178 B- -5287.374 30.003 156 936973.000 30.000 - 17 87 70 157 Yb -53421.898 10.920 8062.767 0.070 B- -6981.376 14.241 156 942649.230 11.723 - 15 86 71 157 Lu -46440.523 12.078 8013.317 0.077 B- -7537# 196# 156 950144.045 12.965 - 13 85 72 157 Hf -a -38903# 196# 7960# 1# B- -9310# 247# 156 958236# 210# - 11 84 73 157 Ta IT -29593.330 150.069 7896.043 0.956 B- -10123# 427# 156 968230.251 161.105 - 9 83 74 157 W x -19470# 400# 7827# 3# B- * 156 979098# 429# -0 42 100 58 158 Ce x -36660# 400# 8016# 3# B- 7670# 500# 157 960644# 429# - 40 99 59 158 Pr x -44330# 300# 8060# 2# B- 9725# 361# 157 952410# 322# - 38 98 60 158 Nd x -54055# 200# 8116# 1# B- 5035# 201# 157 941970# 215# - 36 97 61 158 Pm -59089.209 13.453 8143.254 0.085 B- 6161.034 14.299 157 936565.121 14.442 - 34 96 62 158 Sm -65250.243 4.892 8177.297 0.031 B- 2004.945 10.369 157 929950.979 5.251 - 32 95 63 158 Eu -67255.188 10.255 8185.035 0.065 B- 3434.358 10.323 157 927798.581 11.008 - 30 94 64 158 Gd -70689.546 1.189 8201.819 0.008 B- -1218.878 0.987 157 924111.646 1.276 - 28 93 65 158 Tb -69470.668 1.401 8189.153 0.009 B- 936.681 2.495 157 925420.166 1.503 - 26 92 66 158 Dy -70407.349 2.365 8190.130 0.015 B- -4219.755 27.005 157 924414.597 2.538 - 24 91 67 158 Ho - -66187.593 27.108 8158.471 0.172 B- -883.785 37.025 157 928944.692 29.101 - 22 90 68 158 Er -65303.808 25.219 8147.926 0.160 B- -6600.615 31.341 157 929893.474 27.074 - 20 89 69 158 Tm -58703.194 25.219 8101.199 0.160 B- -2692.957 26.456 157 936979.525 27.074 - 18 88 70 158 Yb -56010.237 7.994 8079.203 0.051 B- -8798.047 16.872 157 939870.534 8.582 - 16 87 71 158 Lu -a -47212.190 15.125 8018.568 0.096 B- -5109.800 14.937 157 949315.626 16.237 - 14 86 72 158 Hf -42102.390 17.494 7981.276 0.111 B- -10936# 197# 157 954801.222 18.780 - 12 85 73 158 Ta +a -31167# 196# 7907# 1# B- -7534# 358# 157 966541# 210# - 10 84 74 158 W -a -23633# 300# 7854# 2# B- * 157 974629# 322# -0 41 100 59 159 Pr x -41088# 400# 8039# 3# B- 8719# 500# 158 955890# 429# - 39 99 60 159 Nd x -49807# 300# 8089# 2# B- 6747# 300# 158 946530# 322# - 37 98 61 159 Pm -56554.280 10.039 8126.859 0.063 B- 5653.495 11.644 158 939286.479 10.777 - 35 97 62 159 Sm -62207.775 5.934 8157.495 0.037 B- 3835.510 7.324 158 933217.202 6.369 - 33 96 63 159 Eu -66043.285 4.325 8176.697 0.027 B- 2518.150 4.391 158 929099.612 4.643 - 31 95 64 159 Gd -68561.436 1.192 8187.614 0.007 B- 970.927 0.759 158 926396.267 1.279 - 29 94 65 159 Tb -69532.363 1.256 8188.800 0.008 B- -365.229 1.162 158 925353.933 1.348 - 27 93 66 159 Dy -69167.134 1.528 8181.583 0.010 B- -1837.600 2.683 158 925746.023 1.640 - 25 92 67 159 Ho - -67329.534 3.088 8165.105 0.019 B- -2768.500 2.000 158 927718.768 3.314 - 23 91 68 159 Er - -64561.034 3.679 8142.773 0.023 B- -3990.637 28.186 158 930690.875 3.949 - 21 90 69 159 Tm x -60570.398 27.945 8112.754 0.176 B- -4731.792 33.129 158 934975.000 30.000 - 19 89 70 159 Yb x -55838.606 17.794 8078.074 0.112 B- -6130.002 41.655 158 940054.787 19.102 - 17 88 71 159 Lu x -49708.604 37.663 8034.600 0.237 B- -6856.004 41.246 158 946635.615 40.433 - 15 87 72 159 Hf -a -42852.600 16.813 7986.560 0.106 B- -8413.452 25.891 158 953995.838 18.049 - 13 86 73 159 Ta IT -34439.148 19.689 7928.725 0.124 B- -9145# 299# 158 963028.052 21.137 - 11 85 74 159 W -a -25295# 298# 7866# 2# B- -10550# 426# 158 972845# 320# - 9 84 75 159 Re IT -14745# 305# 7795# 2# B- * 158 984171# 327# -0 42 101 59 160 Pr x -36520# 400# 8011# 2# B- 10613# 500# 159 960794# 429# - 40 100 60 160 Nd x -47134# 300# 8073# 2# B- 5868# 361# 159 949400# 322# - 38 99 61 160 Pm x -53002# 200# 8104# 1# B- 7233# 200# 159 943100# 215# - 36 98 62 160 Sm -60234.793 5.934 8144.625 0.037 B- 3245.670 11.183 159 935335.286 6.370 - 34 97 63 160 Eu -63480.463 9.501 8160.021 0.059 B- 4461.278 9.586 159 931850.916 10.199 - 32 96 64 160 Gd -67941.741 1.278 8183.014 0.008 B- -105.483 1.022 159 927061.537 1.371 - 30 95 65 160 Tb -67836.257 1.262 8177.465 0.008 B- 1836.472 1.172 159 927174.778 1.354 - 28 94 66 160 Dy -69672.730 0.772 8184.054 0.005 B- -3290.000 15.000 159 925203.244 0.828 - 26 93 67 160 Ho - -66382.730 15.020 8158.602 0.094 B- -318.502 28.528 159 928735.204 16.124 - 24 92 68 160 Er -66064.228 24.254 8151.721 0.152 B- -5762.200 40.311 159 929077.130 26.037 - 22 91 69 160 Tm -60302.028 34.262 8110.818 0.214 B- -2139.322 35.017 159 935263.106 36.781 - 20 90 70 160 Yb -58162.706 7.233 8092.557 0.045 B- -7892.769 57.280 159 937559.763 7.764 - 18 89 71 160 Lu x -50269.937 56.821 8038.338 0.355 B- -4330.994 57.617 159 946033.000 61.000 - 16 88 72 160 Hf -45938.943 9.541 8006.380 0.060 B- -10115.249 55.147 159 950682.513 10.242 - 14 87 73 160 Ta -a -35823.695 54.316 7938.270 0.339 B- -6497.240 139.859 159 961541.679 58.310 - 12 86 74 160 W -29326.455 149.827 7892.772 0.936 B- -12588# 334# 159 968516.753 160.846 - 10 85 75 160 Re -a -16739# 298# 7809# 2# B- * 159 982030# 320# -0 41 101 60 161 Nd x -42588# 400# 8044# 2# B- 7648# 499# 160 954280# 429# - 39 100 61 161 Pm x -50235# 298# 8087# 2# B- 6436# 298# 160 946070# 320# - 37 99 62 161 Sm -56671.962 6.817 8122.041 0.042 B- 5119.562 12.415 160 939160.143 7.318 - 35 98 63 161 Eu -61791.524 10.399 8148.980 0.065 B- 3714.299 10.525 160 933664.066 11.164 - 33 97 64 161 Gd -n -65505.824 1.622 8167.191 0.010 B- 1955.765 1.442 160 929676.602 1.741 - 31 96 65 161 Tb -67461.589 1.350 8174.479 0.008 B- 594.212 1.260 160 927577.001 1.449 - 29 95 66 161 Dy -68055.801 0.768 8173.310 0.005 B- -858.530 2.166 160 926939.088 0.824 - 27 94 67 161 Ho -67197.270 2.242 8163.119 0.014 B- -1995.663 9.011 160 927860.759 2.406 - 25 93 68 161 Er +n -65201.608 8.780 8145.864 0.055 B- -3302.900 29.292 160 930003.191 9.425 - 23 92 69 161 Tm x -61898.708 27.945 8120.490 0.174 B- -4059.308 31.885 160 933549.000 30.000 - 21 91 70 161 Yb x -57839.400 15.354 8090.417 0.095 B- -5277.056 31.885 160 937906.846 16.483 - 19 90 71 161 Lu x -52562.344 27.945 8052.781 0.174 B- -6247.672 35.909 160 943572.000 30.000 - 17 89 72 161 Hf -46314.672 22.551 8009.117 0.140 B- -7535.674 33.097 160 950279.151 24.209 - 15 88 73 161 Ta +a -38778.997 24.382 7957.452 0.151 B- -8224# 197# 160 958369.031 26.175 - 13 87 74 161 W -a -30555# 196# 7902# 1# B- -9715# 247# 160 967197# 210# - 11 86 75 161 Re -20840.203 149.922 7836.312 0.931 B- -10861# 427# 160 977627.121 160.948 - 9 85 76 161 Os -a -9979# 400# 7764# 2# B- * 160 989287# 429# -0 42 102 60 162 Nd x -39550# 400# 8026# 2# B- 6819# 500# 161 957541# 429# - 40 101 61 162 Pm x -46370# 300# 8063# 2# B- 8160# 358# 161 950220# 322# - 38 100 62 162 Sm x -54530# 196# 8109# 1# B- 4174# 199# 161 941460# 210# - 36 99 63 162 Eu + -58703.401 35.229 8129.438 0.217 B- 5577.000 35.000 161 936979.303 37.819 - 34 98 64 162 Gd -nn -64280.401 4.009 8159.035 0.025 B- 1395.556 36.581 161 930992.146 4.303 - 32 97 65 162 Tb + -65675.958 36.372 8162.820 0.225 B- 2505.521 36.364 161 929493.955 39.046 - 30 96 66 162 Dy -68181.478 0.767 8173.457 0.005 B- -2139.937 3.113 161 926804.168 0.822 - 28 95 67 162 Ho -66041.541 3.166 8155.418 0.020 B- 292.978 3.127 161 929101.485 3.398 - 26 94 68 162 Er -66334.519 0.822 8152.397 0.005 B- -4856.728 26.047 161 928786.960 0.882 - 24 93 69 162 Tm - -61477.791 26.060 8117.588 0.161 B- -1651.444 30.240 161 934000.872 27.977 - 22 92 70 162 Yb x -59826.347 15.359 8102.565 0.095 B- -6994.593 76.592 161 935773.771 16.488 - 20 91 71 162 Lu x -52831.753 75.036 8054.559 0.463 B- -3662.746 75.570 161 943282.776 80.554 - 18 90 72 162 Hf -49169.008 8.968 8027.120 0.055 B- -9388.814 52.931 161 947214.896 9.627 - 16 89 73 162 Ta -a -39780.194 52.238 7964.335 0.322 B- -5780.987 52.239 161 957294.202 56.079 - 14 88 74 162 W -33999.207 17.658 7923.821 0.109 B- -11498# 197# 161 963500.347 18.956 - 12 87 75 162 Re +a -22501# 196# 7848# 1# B- -8061# 358# 161 975844# 210# - 10 86 76 162 Os -a -14440# 300# 7793# 2# B- * 161 984498# 322# -0 41 102 61 163 Pm x -43249# 400# 8044# 2# B- 7471# 499# 162 953570# 429# - 39 101 62 163 Sm x -50720# 298# 8085# 2# B- 5765# 305# 162 945550# 320# - 37 100 63 163 Eu + -56484.886 65.544 8115.471 0.402 B- 4829.000 65.000 162 939360.977 70.364 - 35 99 64 163 Gd -61313.886 8.426 8140.297 0.052 B- 3282.185 9.358 162 934176.832 9.045 - 33 98 65 163 Tb +p -64596.071 4.073 8155.633 0.025 B- 1785.099 4.001 162 930653.261 4.372 - 31 97 66 163 Dy -66381.170 0.765 8161.785 0.005 B- -2.834 0.019 162 928736.879 0.821 - 29 96 67 163 Ho -66378.335 0.765 8156.968 0.005 B- -1210.612 4.575 162 928739.921 0.821 - 27 95 68 163 Er -65167.723 4.639 8144.741 0.028 B- -2439.000 3.000 162 930039.567 4.980 - 25 94 69 163 Tm - -62728.723 5.524 8124.979 0.034 B- -3429.629 16.309 162 932657.941 5.930 - 23 93 70 163 Yb x -59299.094 15.364 8099.138 0.094 B- -4507.685 31.890 162 936339.800 16.493 - 21 92 71 163 Lu x -54791.409 27.945 8066.684 0.171 B- -5527.726 37.348 162 941179.000 30.000 - 19 91 72 163 Hf -49263.682 24.778 8027.972 0.152 B- -6729.054 45.416 162 947113.258 26.599 - 17 90 73 163 Ta -a -42534.629 38.061 7981.890 0.234 B- -7626.436 65.049 162 954337.195 40.860 - 15 89 74 163 W -a -34908.193 52.751 7930.302 0.324 B- -8905.949 55.912 162 962524.511 56.630 - 13 88 75 163 Re +a -26002.244 18.534 7870.865 0.114 B- -9810# 299# 162 972085.441 19.897 - 11 87 76 163 Os -a -16192# 298# 7806# 2# B- * 162 982617# 320# -0 42 103 61 164 Pm x -38870# 400# 8017# 2# B- 9232# 499# 163 958271# 429# - 40 102 62 164 Sm x -48102# 298# 8069# 2# B- 5279# 319# 163 948360# 320# - 38 101 63 164 Eu + -53381# 114# 8096# 1# B- 6393.000 50.000 163 942693# 122# - 36 100 64 164 Gd x -59774# 102# 8130# 1# B- 2304# 143# 163 935830# 110# - 34 99 65 164 Tb + -62077.965 100.003 8139.765 0.610 B- 3890.000 100.000 163 933356.559 107.357 - 32 98 66 164 Dy -65967.965 0.767 8158.714 0.005 B- -986.463 1.415 163 929180.472 0.823 - 30 97 67 164 Ho -64981.503 1.528 8147.929 0.009 B- 961.387 1.420 163 930239.483 1.639 - 28 96 68 164 Er -65942.890 0.775 8149.020 0.005 B- -4038.855 24.401 163 929207.392 0.832 - 26 95 69 164 Tm -61904.035 24.394 8119.623 0.149 B- -886.617 28.829 163 933543.281 26.188 - 24 94 70 164 Yb x -61017.418 15.369 8109.446 0.094 B- -6375.048 31.892 163 934495.103 16.499 - 22 93 71 164 Lu x -54642.370 27.945 8065.804 0.170 B- -2823.865 32.112 163 941339.000 30.000 - 20 92 72 164 Hf -51818.505 15.820 8043.814 0.096 B- -8535.704 32.112 163 944370.544 16.983 - 18 91 73 164 Ta x -43282.800 27.945 7986.997 0.170 B- -5047.041 29.572 163 953534.000 30.000 - 16 90 74 164 W -38235.759 9.674 7951.452 0.059 B- -10763.323 55.406 163 958952.222 10.385 - 14 89 75 164 Re -a -27472.436 54.555 7881.052 0.333 B- -7050.331 140.051 163 970507.124 58.566 - 12 88 76 164 Os -20422.106 149.919 7833.291 0.914 B- -13078# 348# 163 978075.966 160.945 - 10 87 77 164 Ir -a -7344# 314# 7749# 2# B- * 163 992116# 338# -0 41 103 62 165 Sm x -43808# 401# 8043# 2# B- 6916# 424# 164 952970# 430# - 39 102 63 165 Eu + -50724# 138# 8080# 1# B- 5729.000 65.000 164 945546# 148# - 37 101 64 165 Gd + -56453# 121# 8110# 1# B- 4113.000 65.000 164 939395# 130# - 35 100 65 165 Tb x -60566# 102# 8130# 1# B- 3047# 102# 164 934980# 110# - 33 99 66 165 Dy -n -63612.606 0.769 8143.909 0.005 B- 1286.400 0.829 164 931709.054 0.825 - 31 98 67 165 Ho -64899.006 1.010 8146.964 0.006 B- -377.396 1.033 164 930328.047 1.084 - 29 97 68 165 Er -64521.610 0.964 8139.936 0.006 B- -1591.990 1.538 164 930733.198 1.034 - 27 96 69 165 Tm -62929.621 1.671 8125.546 0.010 B- -2634.239 26.592 164 932442.269 1.793 - 25 95 70 165 Yb -60295.382 26.539 8104.839 0.161 B- -3853.140 35.432 164 935270.241 28.490 - 23 94 71 165 Lu -56442.242 26.539 8076.745 0.161 B- -4806.734 38.539 164 939406.758 28.490 - 21 93 72 165 Hf x -51635.507 27.945 8042.872 0.169 B- -5787.655 31.195 164 944567.000 30.000 - 19 92 73 165 Ta -45847.853 13.863 8003.054 0.084 B- -6986.830 28.566 164 950780.303 14.882 - 17 91 74 165 W -38861.022 24.977 7955.968 0.151 B- -8201.246 34.332 164 958280.974 26.813 - 15 90 75 165 Re +a -30659.776 23.594 7901.522 0.143 B- -8865# 197# 164 967085.375 25.329 - 13 89 76 165 Os -a -21795# 196# 7843# 1# B- -10202# 252# 164 976602# 210# - 11 88 77 165 Ir IT -11593# 158# 7776# 1# B- * 164 987555# 170# -0 42 104 62 166 Sm x -40730# 400# 8024# 2# B- 6478# 537# 165 956275# 429# - 40 103 63 166 Eu + -47208# 358# 8059# 2# B- 7322.000 300.000 165 949320# 384# - 38 102 64 166 Gd x -54530# 196# 8098# 1# B- 3355# 208# 165 941460# 210# - 36 101 65 166 Tb + -57884.789 70.005 8113.680 0.422 B- 4700.000 70.000 165 937858.119 75.153 - 34 100 66 166 Dy -n -62584.789 0.867 8137.280 0.005 B- 486.540 0.921 165 932812.461 0.930 - 32 99 67 166 Ho -63071.329 1.010 8135.499 0.006 B- 1854.713 0.922 165 932290.139 1.084 - 30 98 68 166 Er -64926.042 1.165 8141.959 0.007 B- -3037.667 11.547 165 930299.023 1.251 - 28 97 69 166 Tm - -61888.375 11.606 8118.946 0.070 B- -292.635 13.507 165 933560.092 12.459 - 26 96 70 166 Yb +nn -61595.740 7.101 8112.471 0.043 B- -5574.759 30.642 165 933874.249 7.623 - 24 95 71 166 Lu x -56020.981 29.808 8074.175 0.180 B- -2161.998 40.859 165 939859.000 32.000 - 22 94 72 166 Hf x -53858.983 27.945 8056.438 0.168 B- -7761.208 39.520 165 942180.000 30.000 - 20 93 73 166 Ta x -46097.775 27.945 8004.971 0.168 B- -4209.744 29.508 165 950512.000 30.000 - 18 92 74 166 W -41888.031 9.478 7974.898 0.057 B- -9994.553 72.879 165 955031.346 10.174 - 16 91 75 166 Re -a -31893.478 72.310 7909.977 0.436 B- -6461.961 72.387 165 965760.940 77.628 - 14 90 76 166 Os -25431.517 17.966 7866.336 0.108 B- -12078# 197# 165 972698.141 19.287 - 12 89 77 166 Ir -p -13354# 196# 7789# 1# B- -8624# 359# 165 985664# 210# - 10 88 78 166 Pt -a -4730# 300# 7732# 2# B- * 165 994923# 322# -0 41 104 63 167 Eu x -44010# 400# 8040# 2# B- 6803# 499# 166 952753# 429# - 39 103 64 167 Gd x -50813# 298# 8076# 2# B- 5114# 357# 166 945450# 320# - 37 102 65 167 Tb x -55927# 196# 8102# 1# B- 4004# 205# 166 939960# 210# - 35 101 66 167 Dy + -59930.626 60.228 8120.992 0.361 B- 2350.000 60.000 166 935661.823 64.657 - 33 100 67 167 Ho p2n -62280.626 5.234 8130.379 0.031 B- 1010.554 5.208 166 933138.994 5.618 - 31 99 68 167 Er -63291.180 1.166 8131.746 0.007 B- -747.539 1.501 166 932054.119 1.252 - 29 98 69 167 Tm -62543.641 1.298 8122.585 0.008 B- -1953.065 3.798 166 932856.635 1.393 - 27 97 70 167 Yb -60590.576 3.981 8106.205 0.024 B- -3089.451 31.920 166 934953.337 4.273 - 25 96 71 167 Lu x -57501.125 31.671 8083.021 0.190 B- -4033.369 42.237 166 938270.000 34.000 - 23 95 72 167 Hf x -53467.756 27.945 8054.184 0.167 B- -5116.697 39.520 166 942600.000 30.000 - 21 94 73 167 Ta x -48351.059 27.945 8018.861 0.167 B- -6253.001 33.382 166 948093.000 30.000 - 19 93 74 167 W -42098.058 18.261 7976.733 0.109 B- -7267# 44# 166 954805.873 19.603 - 17 92 75 167 Re +a -34831# 40# 7929# 0# B- -8329# 83# 166 962607# 43# - 15 91 76 167 Os -a -26501.993 72.682 7873.974 0.435 B- -9429.554 74.962 166 971548.938 78.027 - 13 90 77 167 Ir -17072.440 18.346 7812.825 0.110 B- -10460# 303# 166 981671.981 19.695 - 11 89 78 167 Pt -a -6612# 302# 7746# 2# B- * 166 992901# 325# -0 42 105 63 168 Eu x -39740# 500# 8014# 3# B- 8623# 641# 167 957337# 537# - 40 104 64 168 Gd x -48363# 401# 8061# 2# B- 4359# 499# 167 948080# 430# - 38 103 65 168 Tb x -52723# 298# 8082# 2# B- 5837# 329# 167 943400# 320# - 36 102 66 168 Dy +pp -58559.566 140.009 8112.536 0.833 B- 1501.605 143.186 167 937133.716 150.305 - 34 101 67 168 Ho + -60061.171 30.023 8116.817 0.179 B- 2930.000 30.000 167 935521.676 32.230 - 32 100 68 168 Er -62991.171 1.168 8129.601 0.007 B- -1678.250 1.870 167 932376.192 1.254 - 30 99 69 168 Tm -61312.921 1.709 8114.954 0.010 B- 268.980 1.887 167 934177.868 1.834 - 28 98 70 168 Yb -61581.901 1.195 8111.898 0.007 B- -4514.051 39.248 167 933889.106 1.282 - 26 97 71 168 Lu - -57067.850 39.266 8080.372 0.234 B- -1707.299 48.195 167 938735.139 42.153 - 24 96 72 168 Hf x -55360.552 27.945 8065.553 0.166 B- -6966.644 39.520 167 940568.000 30.000 - 22 95 73 168 Ta x -48393.908 27.945 8019.428 0.166 B- -3500.799 30.936 167 948047.000 30.000 - 20 94 74 168 W -44893.109 13.271 7993.933 0.079 B- -9098.224 33.556 167 951805.262 14.247 - 18 93 75 168 Re -a -35794.885 30.821 7935.120 0.183 B- -5799.672 32.373 167 961572.608 33.087 - 16 92 76 168 Os -29995.213 9.904 7895.941 0.059 B- -11328.987 56.098 167 967798.812 10.632 - 14 91 77 168 Ir -a -18666.226 55.216 7823.850 0.329 B- -7658.765 140.344 167 979960.981 59.277 - 12 90 78 168 Pt -a -11007.460 149.951 7773.605 0.893 B- * 167 988183.004 160.978 -0 41 105 64 169 Gd x -44153# 503# 8036# 3# B- 6176# 585# 168 952600# 540# - 39 104 65 169 Tb x -50329# 298# 8068# 2# B- 5269# 423# 168 945970# 320# - 37 103 66 169 Dy + -55597.177 300.670 8094.763 1.779 B- 3200.000 300.000 168 940313.971 322.782 - 35 102 67 169 Ho +p -58797.177 20.060 8109.068 0.119 B- 2125.927 20.053 168 936878.630 21.534 - 33 101 68 169 Er -n -60923.104 1.179 8117.019 0.007 B- 352.108 1.114 168 934596.353 1.265 - 31 100 69 169 Tm -61275.212 0.812 8114.473 0.005 B- -897.650 1.141 168 934218.350 0.871 - 29 99 70 169 Yb -n -60377.563 1.205 8104.532 0.007 B- -2293.000 3.000 168 935182.016 1.293 - 27 98 71 169 Lu - -58084.563 3.233 8086.335 0.019 B- -3367.673 28.131 168 937643.653 3.470 - 25 97 72 169 Hf x -54716.889 27.945 8061.778 0.165 B- -4426.460 39.520 168 941259.000 30.000 - 23 96 73 169 Ta x -50290.430 27.945 8030.957 0.165 B- -5372.557 31.925 168 946011.000 30.000 - 21 95 74 169 W -44917.873 15.436 7994.537 0.091 B- -6508.641 19.173 168 951778.677 16.571 - 19 94 75 169 Re +a -38409.232 11.374 7951.395 0.067 B- -7686.541 27.618 168 958765.991 12.210 - 17 93 76 169 Os -a -30722.691 25.167 7901.284 0.149 B- -8628.852 34.276 168 967017.833 27.017 - 15 92 77 169 Ir +a -22093.839 23.308 7845.596 0.138 B- -9581# 197# 168 976281.287 25.021 - 13 91 78 169 Pt -a -12512# 196# 7784# 1# B- -10724# 357# 168 986567# 210# - 11 90 79 169 Au x -1788# 298# 7716# 2# B- * 168 998080# 320# -0 42 106 64 170 Gd x -41380# 596# 8020# 4# B- 5344# 718# 169 955577# 640# - 40 105 65 170 Tb x -46724# 401# 8047# 2# B- 6940# 446# 169 949840# 430# - 38 104 66 170 Dy x -53663# 196# 8083# 1# B- 2575# 202# 169 942390# 210# - 36 103 67 170 Ho + -56238.681 50.024 8093.796 0.294 B- 3870.000 50.000 169 939625.289 53.702 - 34 102 68 170 Er -60108.681 1.546 8111.959 0.009 B- -312.828 1.821 169 935470.673 1.659 - 32 101 69 170 Tm -59795.853 0.801 8105.517 0.005 B- 968.066 0.801 169 935806.507 0.859 - 30 100 70 170 Yb -60763.919 0.010 8106.609 0.000 B- -3457.695 16.843 169 934767.245 0.011 - 28 99 71 170 Lu - -57306.224 16.843 8081.668 0.099 B- -1052.370 32.628 169 938479.234 18.081 - 26 98 72 170 Hf x -56253.854 27.945 8070.875 0.164 B- -6116.190 39.520 169 939609.000 30.000 - 24 97 73 170 Ta x -50137.665 27.945 8030.296 0.164 B- -2846.832 30.904 169 946175.000 30.000 - 22 96 74 170 W -47290.832 13.195 8008.948 0.078 B- -8377.639 26.611 169 949231.200 14.165 - 20 95 75 170 Re -38913.193 23.109 7955.065 0.136 B- -4986.946 25.091 169 958224.966 24.808 - 18 94 76 170 Os -33926.247 9.773 7921.128 0.057 B- -10567# 89# 169 963578.673 10.491 - 16 93 77 170 Ir -a -23360# 89# 7854# 1# B- -7060# 89# 169 974922# 95# - 14 92 78 170 Pt -16299.193 18.247 7808.236 0.107 B- -12547# 197# 169 982502.095 19.588 - 12 91 79 170 Au -p -3752# 196# 7730# 1# B- * 169 995972# 211# -0 41 106 65 171 Tb x -44032# 503# 8031# 3# B- 6157# 585# 170 952730# 540# - 39 105 66 171 Dy x -50189# 298# 8063# 2# B- 4330# 670# 170 946120# 320# - 37 104 67 171 Ho + -54518.956 600.002 8083.608 3.509 B- 3200.000 600.000 170 941471.490 644.128 - 35 103 68 171 Er -57718.956 1.557 8097.746 0.009 B- 1491.342 1.256 170 938036.148 1.670 - 33 102 69 171 Tm -59210.298 0.972 8101.893 0.006 B- 96.512 0.972 170 936435.126 1.043 - 31 101 70 171 Yb -59306.810 0.013 8097.882 0.000 B- -1478.414 1.862 170 936331.517 0.014 - 29 100 71 171 Lu -57828.395 1.862 8084.661 0.011 B- -2397.050 28.936 170 937918.660 1.998 - 27 99 72 171 Hf x -55431.345 28.876 8066.068 0.169 B- -3711.072 40.184 170 940492.000 31.000 - 25 98 73 171 Ta x -51720.273 27.945 8039.791 0.163 B- -4634.183 39.520 170 944476.000 30.000 - 23 97 74 171 W x -47086.090 27.945 8008.115 0.163 B- -5835.810 39.520 170 949451.000 30.000 - 21 96 75 171 Re x -41250.280 27.945 7969.412 0.163 B- -6948.339 33.145 170 955716.000 30.000 - 19 95 76 171 Os -34301.942 17.823 7924.204 0.104 B- -7889.916 42.395 170 963175.348 19.133 - 17 94 77 171 Ir -a -26412.025 38.466 7873.489 0.225 B- -8942.323 82.291 170 971645.522 41.295 - 15 93 78 171 Pt -a -17469.702 72.747 7816.619 0.425 B- -9907.407 75.639 170 981245.502 78.097 - 13 92 79 171 Au -p -7562.295 20.713 7754.106 0.121 B- -11043# 303# 170 991881.542 22.236 - 11 91 80 171 Hg -a 3480# 303# 7685# 2# B- * 171 003736# 325# -0 42 107 65 172 Tb x -39850# 503# 8007# 3# B- 8159# 585# 171 957219# 540# - 40 106 66 172 Dy x -48009# 298# 8050# 2# B- 3474# 357# 171 948460# 320# - 38 105 67 172 Ho x -51484# 196# 8066# 1# B- 5000# 196# 171 944730# 210# - 36 104 68 172 Er -56483.612 4.008 8090.410 0.023 B- 890.767 4.543 171 939362.344 4.302 - 34 103 69 172 Tm -57374.379 5.503 8091.041 0.032 B- 1881.067 5.503 171 938406.067 5.907 - 32 102 70 172 Yb -59255.446 0.014 8097.429 0.000 B- -2519.466 2.336 171 936386.658 0.014 - 30 101 71 172 Lu -56735.980 2.336 8078.232 0.014 B- -333.754 24.540 171 939091.417 2.507 - 28 100 72 172 Hf x -56402.226 24.428 8071.743 0.142 B- -5072.248 37.117 171 939449.716 26.224 - 26 99 73 172 Ta x -51329.977 27.945 8037.705 0.162 B- -2232.791 39.520 171 944895.000 30.000 - 24 98 74 172 W x -49097.186 27.945 8020.175 0.162 B- -7560.080 47.974 171 947292.000 30.000 - 22 97 75 172 Re -41537.106 38.995 7971.672 0.227 B- -4293.264 41.036 171 955408.079 41.862 - 20 96 76 172 Os -37243.842 12.782 7942.163 0.074 B- -9864.473 34.832 171 960017.088 13.721 - 18 95 77 172 Ir -a -27379.369 32.402 7880.263 0.188 B- -6272.449 34.023 171 970607.036 34.785 - 16 94 78 172 Pt -21106.920 10.377 7839.247 0.060 B- -11788.914 57.108 171 977340.788 11.139 - 14 93 79 172 Au -a -9318.006 56.158 7766.158 0.326 B- -8259.262 140.853 171 989996.708 60.287 - 12 92 80 172 Hg -a -1058.744 150.079 7713.591 0.873 B- * 171 998863.391 161.116 -0 41 107 66 173 Dy x -43939# 401# 8027# 2# B- 5412# 499# 172 952830# 430# - 39 106 67 173 Ho x -49351# 298# 8054# 2# B- 4304# 357# 172 947020# 320# - 37 105 68 173 Er x -53654# 196# 8074# 1# B- 2602# 196# 172 942400# 210# - 35 104 69 173 Tm p2n -56256.059 4.400 8084.463 0.025 B- 1295.166 4.400 172 939606.632 4.723 - 33 103 70 173 Yb -57551.225 0.011 8087.427 0.000 B- -670.310 1.567 172 938216.215 0.012 - 31 102 71 173 Lu -56880.916 1.567 8079.030 0.009 B- -1469.132 27.989 172 938935.822 1.682 - 29 101 72 173 Hf x -55411.784 27.945 8066.016 0.162 B- -3015.246 39.520 172 940513.000 30.000 - 27 100 73 173 Ta x -52396.538 27.945 8044.064 0.162 B- -3669.155 39.520 172 943750.000 30.000 - 25 99 74 173 W x -48727.383 27.945 8018.333 0.162 B- -5173.518 39.520 172 947689.000 30.000 - 23 98 75 173 Re x -43553.865 27.945 7983.906 0.162 B- -6115.608 31.697 172 953243.000 30.000 - 21 97 76 173 Os -37438.257 14.959 7944.033 0.086 B- -7169.822 18.583 172 959808.375 16.059 - 19 96 77 173 Ir -30268.435 11.026 7898.067 0.064 B- -8325.524 57.052 172 967505.496 11.837 - 17 95 78 173 Pt -a -21942.911 55.977 7845.420 0.324 B- -9110.471 60.421 172 976443.315 60.093 - 15 94 79 173 Au +a -12832.440 22.784 7788.237 0.132 B- -10123# 197# 172 986223.808 24.459 - 13 93 80 173 Hg -a -2710# 196# 7725# 1# B- * 172 997091# 210# -0 42 108 66 174 Dy x -41370# 503# 8012# 3# B- 4319# 585# 173 955587# 540# - 40 107 67 174 Ho x -45690# 298# 8033# 2# B- 6260# 422# 173 950950# 320# - 38 106 68 174 Er x -51949# 298# 8064# 2# B- 1915# 301# 173 944230# 320# - 36 105 69 174 Tm + -53864.512 44.721 8070.642 0.257 B- 3080.000 44.721 173 942174.064 48.010 - 34 104 70 174 Yb -56944.512 0.011 8083.847 0.000 B- -1374.317 1.567 173 938867.548 0.011 - 32 103 71 174 Lu -55570.195 1.567 8071.453 0.009 B- 274.286 2.169 173 940342.938 1.682 - 30 102 72 174 Hf -55844.481 2.259 8068.533 0.013 B- -4103.715 28.036 173 940048.480 2.424 - 28 101 73 174 Ta x -51740.766 27.945 8040.452 0.161 B- -1513.678 39.520 173 944454.000 30.000 - 26 100 74 174 W x -50227.088 27.945 8027.256 0.161 B- -6553.992 39.520 173 946079.000 30.000 - 24 99 75 174 Re x -43673.096 27.945 7985.094 0.161 B- -3677.681 29.767 173 953115.000 30.000 - 22 98 76 174 Os -39995.416 10.254 7959.461 0.059 B- -9131.924 26.395 173 957063.152 11.008 - 20 97 77 174 Ir -30863.492 24.322 7902.483 0.140 B- -5545.329 26.433 173 966866.676 26.111 - 18 96 78 174 Pt -a -25318.163 10.351 7866.117 0.059 B- -11083# 89# 173 972819.832 11.112 - 16 95 79 174 Au -a -14235# 89# 7798# 1# B- -7594# 89# 173 984718# 95# - 14 94 80 174 Hg -a -6641.009 19.211 7749.784 0.110 B- * 173 992870.583 20.624 -0 41 108 67 175 Ho x -43203# 401# 8019# 2# B- 5449# 566# 174 953620# 430# - 39 107 68 175 Er x -48652# 401# 8045# 2# B- 3659# 404# 174 947770# 430# - 37 106 69 175 Tm + -52310.549 50.000 8061.766 0.286 B- 2385.000 50.000 174 943842.313 53.677 - 35 105 70 175 Yb -54695.549 0.071 8070.925 0.000 B- 470.033 1.206 174 941281.910 0.076 - 33 104 71 175 Lu -55165.582 1.207 8069.140 0.007 B- -683.920 1.952 174 940777.308 1.295 - 31 103 72 175 Hf -54481.662 2.282 8060.761 0.013 B- -2073.015 28.038 174 941511.527 2.449 - 29 102 73 175 Ta x -52408.647 27.945 8044.445 0.160 B- -2775.852 39.520 174 943737.000 30.000 - 27 101 74 175 W x -49632.795 27.945 8024.112 0.160 B- -4344.488 39.520 174 946717.000 30.000 - 25 100 75 175 Re x -45288.307 27.945 7994.816 0.160 B- -5182.931 30.324 174 951381.000 30.000 - 23 99 76 175 Os -40105.376 11.775 7960.729 0.067 B- -6710.870 17.089 174 956945.105 12.640 - 21 98 77 175 Ir -33394.506 12.384 7917.910 0.071 B- -7681.040 22.001 174 964149.521 13.295 - 19 97 78 175 Pt -25713.466 18.185 7869.548 0.104 B- -8309.511 42.705 174 972395.457 19.522 - 17 96 79 175 Au -a -17403.955 38.640 7817.595 0.221 B- -9431.379 82.504 174 981316.085 41.481 - 15 95 80 175 Hg -a -7972.576 72.896 7759.231 0.417 B- * 174 991441.086 78.257 -0 42 109 67 176 Ho x -39290# 503# 7997# 3# B- 7340# 643# 175 957820# 540# - 40 108 68 176 Er x -46631# 401# 8034# 2# B- 2741# 413# 175 949940# 430# - 38 107 69 176 Tm + -49371.314 100.000 8045.121 0.568 B- 4120.000 100.000 175 946997.711 107.354 - 36 106 70 176 Yb -53491.314 0.015 8064.085 0.000 B- -109.078 1.212 175 942574.708 0.015 - 34 105 71 176 Lu -53382.236 1.212 8059.020 0.007 B- 1194.085 0.874 175 942691.809 1.301 - 32 104 72 176 Hf -54576.321 1.481 8061.359 0.008 B- -3210.948 30.775 175 941409.905 1.590 - 30 103 73 176 Ta x -51365.374 30.739 8038.670 0.175 B- -723.771 41.543 175 944857.000 33.000 - 28 102 74 176 W x -50641.603 27.945 8030.112 0.159 B- -5578.718 39.520 175 945634.000 30.000 - 26 101 75 176 Re x -45062.885 27.945 7993.970 0.159 B- -2964.945 39.520 175 951623.000 30.000 - 24 100 76 176 Os x -42097.940 27.945 7972.679 0.159 B- -8219.614 32.580 175 954806.000 30.000 - 22 99 77 176 Ir -33878.326 16.750 7921.531 0.095 B- -4944.459 21.035 175 963630.119 17.981 - 20 98 78 176 Pt -28933.867 12.724 7888.992 0.072 B- -10412.904 35.541 175 968938.214 13.660 - 18 97 79 176 Au -a -18520.963 33.185 7825.383 0.189 B- -6736.013 34.998 175 980116.927 35.625 - 16 96 80 176 Hg -11784.950 11.119 7782.665 0.063 B- -12366.544 75.904 175 987348.335 11.937 - 14 95 81 176 Tl -p 581.594 75.086 7707.955 0.427 B- * 176 000624.367 80.607 -0 41 109 68 177 Er x -42858# 503# 8013# 3# B- 4611# 585# 176 953990# 540# - 39 108 69 177 Tm x -47469# 298# 8035# 2# B- 3517# 298# 176 949040# 320# - 37 107 70 177 Yb -n -50986.397 0.220 8049.973 0.001 B- 1397.409 1.240 176 945263.848 0.236 - 35 106 71 177 Lu -52383.806 1.220 8053.448 0.007 B- 496.810 0.791 176 943763.668 1.310 - 33 105 72 177 Hf -52880.616 1.408 8051.835 0.008 B- -1166.000 3.000 176 943230.320 1.511 - 31 104 73 177 Ta - -51714.616 3.314 8040.827 0.019 B- -2012.890 28.141 176 944482.073 3.557 - 29 103 74 177 W x -49701.726 27.945 8025.035 0.158 B- -3432.555 39.520 176 946643.000 30.000 - 27 102 75 177 Re x -46269.170 27.945 8001.222 0.158 B- -4312.708 31.535 176 950328.000 30.000 - 25 101 76 177 Os +a -41956.462 14.613 7972.436 0.083 B- -5909.041 24.576 176 954957.882 15.687 - 23 100 77 177 Ir x -36047.421 19.760 7934.632 0.112 B- -6676.976 24.801 176 961301.500 21.213 - 21 99 78 177 Pt -29370.444 14.988 7892.489 0.085 B- -7825.341 18.297 176 968469.529 16.090 - 19 98 79 177 Au -21545.103 10.496 7843.858 0.059 B- -8762.561 75.786 176 976870.379 11.268 - 17 97 80 177 Hg -a -12782.542 75.056 7789.932 0.424 B- -9442.016 78.098 176 986277.376 80.575 - 15 96 81 177 Tl IT -3340.526 21.629 7732.167 0.122 B- * 176 996413.797 23.219 -0 42 110 68 178 Er x -40260# 596# 7999# 3# B- 3855# 718# 177 956779# 640# - 40 109 69 178 Tm x -44116# 401# 8016# 2# B- 5580# 401# 177 952640# 430# - 38 108 70 178 Yb -nn -49695.475 10.000 8042.841 0.056 B- 642.309 10.250 177 946649.710 10.735 - 36 107 71 178 Lu -50337.784 2.251 8042.054 0.013 B- 2097.451 2.057 177 945960.162 2.416 - 34 106 72 178 Hf -52435.236 1.412 8049.442 0.008 B- -1837# 52# 177 943708.456 1.516 - 32 105 73 178 Ta IT -50598# 52# 8035# 0# B- -191# 50# 177 945681# 56# - 30 104 74 178 W - -50406.936 15.199 8029.257 0.085 B- -4753.483 31.810 177 945885.925 16.316 - 28 103 75 178 Re x -45653.453 27.945 7998.157 0.157 B- -2109.183 31.093 177 950989.000 30.000 - 26 102 76 178 Os -43544.270 13.632 7981.912 0.077 B- -7292.386 24.006 177 953253.300 14.634 - 24 101 77 178 Ir x -36251.884 19.760 7936.549 0.111 B- -4254.365 22.207 177 961082.000 21.213 - 22 100 78 178 Pt -31997.519 10.133 7908.252 0.057 B- -9693.776 14.297 177 965649.248 10.878 - 20 99 79 178 Au -22303.743 10.086 7849.398 0.057 B- -5987.841 14.755 177 976055.945 10.827 - 18 98 80 178 Hg -a -16315.901 10.770 7811.363 0.061 B- -11526# 90# 177 982484.158 11.562 - 16 97 81 178 Tl -a -4790# 89# 7742# 1# B- -8365# 91# 177 994857# 96# - 14 96 82 178 Pb -a 3574.294 23.963 7690.830 0.135 B- * 178 003837.163 25.724 -0 41 110 69 179 Tm x -41601# 503# 8002# 3# B- 4937# 540# 178 955340# 540# - 39 109 70 179 Yb x -46537# 196# 8025# 1# B- 2521# 196# 178 950040# 210# - 37 108 71 179 Lu -49058.918 5.150 8035.073 0.029 B- 1403.989 5.067 178 947333.082 5.528 - 35 107 72 179 Hf -50462.907 1.413 8038.546 0.008 B- -105.584 0.409 178 945825.838 1.517 - 33 106 73 179 Ta -50357.323 1.463 8033.585 0.008 B- -1062.195 14.520 178 945939.187 1.571 - 31 105 74 179 W -49295.127 14.573 8023.281 0.081 B- -2710.847 26.802 178 947079.501 15.644 - 29 104 75 179 Re -46584.280 24.639 8003.766 0.138 B- -3564.785 29.656 178 949989.715 26.450 - 27 103 76 179 Os -43019.495 16.504 7979.480 0.092 B- -4937.781 19.180 178 953816.669 17.718 - 25 102 77 179 Ir -38081.714 9.771 7947.524 0.055 B- -5813.569 12.613 178 959117.596 10.489 - 23 101 78 179 Pt -32268.145 7.977 7910.675 0.045 B- -7279.578 14.157 178 965358.719 8.563 - 21 100 79 179 Au -24988.567 11.696 7865.637 0.065 B- -8060.433 29.669 178 973173.668 12.555 - 19 99 80 179 Hg -16928.134 27.267 7816.236 0.152 B- -8659.639 47.417 178 981826.899 29.272 - 17 98 81 179 Tl -a -8268.495 38.793 7763.487 0.217 B- -10319.134 84.963 178 991123.405 41.646 - 15 97 82 179 Pb -a 2050.639 75.590 7701.468 0.422 B- * 179 002201.452 81.149 -0 42 111 69 180 Tm x -37920# 503# 7982# 3# B- 6680# 585# 179 959291# 540# - 40 110 70 180 Yb x -44600# 298# 8015# 2# B- 2076# 306# 179 952120# 320# - 38 109 71 180 Lu + -46676.348 70.725 8022.038 0.393 B- 3103.000 70.711 179 949890.876 75.926 - 36 108 72 180 Hf -49779.348 1.419 8034.930 0.008 B- -846.471 2.269 179 946559.669 1.522 - 34 107 73 180 Ta +n -48932.877 1.939 8025.881 0.011 B- 703.238 2.281 179 947468.392 2.081 - 32 106 74 180 W -49636.115 1.436 8025.442 0.008 B- -3798.757 21.440 179 946713.435 1.542 - 30 105 75 180 Re x -45837.359 21.392 7999.991 0.119 B- -1479.549 26.950 179 950791.568 22.965 - 28 104 76 180 Os -44357.810 16.391 7987.425 0.091 B- -6380.284 27.200 179 952379.930 17.596 - 26 103 77 180 Ir x -37977.526 21.706 7947.633 0.121 B- -3541.649 24.323 179 959229.446 23.302 - 24 102 78 180 Pt +a -34435.877 10.974 7923.611 0.061 B- -8810.368 11.973 179 963031.563 11.781 - 22 101 79 180 Au -25625.509 4.786 7870.318 0.027 B- -5375.062 13.524 179 972489.883 5.137 - 20 100 80 180 Hg -20250.447 12.649 7836.110 0.070 B- -10863.800 61.329 179 978260.249 13.579 - 18 99 81 180 Tl -a -9386.647 60.010 7771.409 0.333 B- -7445.267 61.277 179 989923.019 64.423 - 16 98 82 180 Pb -a -1941.380 12.396 7725.700 0.069 B- * 179 997915.842 13.307 -0 43 112 69 181 Tm x -35170# 596# 7967# 3# B- 5918# 667# 180 962243# 640# - 41 111 70 181 Yb x -41088# 298# 7996# 2# B- 3709# 324# 180 955890# 320# - 39 110 71 181 Lu x -44797.410 125.752 8011.929 0.695 B- 2605.421 125.760 180 951908.000 135.000 - 37 109 72 181 Hf -n -47402.831 1.420 8022.002 0.008 B- 1035.480 1.834 180 949110.965 1.524 - 35 108 73 181 Ta -48438.311 1.403 8023.400 0.008 B- -204.493 1.854 180 947999.331 1.506 - 33 107 74 181 W -n -48233.818 1.445 8017.948 0.008 B- -1716.427 12.629 180 948218.863 1.551 - 31 106 75 181 Re 4n -46517.391 12.549 8004.143 0.069 B- -2967.428 28.275 180 950061.523 13.471 - 29 105 76 181 Os -43549.963 25.338 7983.426 0.140 B- -4086.935 25.876 180 953247.188 27.201 - 27 104 77 181 Ir +a -39463.028 5.245 7956.523 0.029 B- -5081.517 14.660 180 957634.694 5.631 - 25 103 78 181 Pt -34381.511 13.689 7924.126 0.076 B- -6510.375 24.216 180 963089.927 14.695 - 23 102 79 181 Au -a -27871.136 19.976 7883.835 0.110 B- -7210.000 25.212 180 970079.103 21.445 - 21 101 80 181 Hg -20661.136 15.382 7839.679 0.085 B- -7862.401 17.876 180 977819.357 16.513 - 19 100 81 181 Tl -12798.735 9.108 7791.918 0.050 B- -9681.385 75.959 180 986259.992 9.778 - 17 99 82 181 Pb -a -3117.350 75.411 7734.107 0.417 B- * 180 996653.386 80.957 -0 42 112 70 182 Yb x -38820# 401# 7984# 2# B- 3060# 446# 181 958325# 430# - 40 111 71 182 Lu x -41880# 196# 7996# 1# B- 4170# 196# 181 955040# 210# - 38 110 72 182 Hf -nn -46049.508 6.165 8014.837 0.034 B- 380.425 6.274 181 950563.816 6.618 - 36 109 73 182 Ta -46429.934 1.405 8012.628 0.008 B- 1816.126 1.399 181 950155.413 1.508 - 34 108 74 182 W -48246.060 0.738 8018.308 0.004 B- -2800.000 101.980 181 948205.721 0.791 - 32 107 75 182 Re IT -45446.060 101.983 7998.625 0.560 B- -836.955 104.276 181 951211.645 109.483 - 30 106 76 182 Os -44609.104 21.745 7989.728 0.119 B- -5557.426 30.207 181 952110.153 23.344 - 28 105 77 182 Ir -39051.679 20.967 7954.894 0.115 B- -2883.230 24.720 181 958076.296 22.509 - 26 104 78 182 Pt -36168.449 13.095 7934.754 0.072 B- -7867.680 24.123 181 961171.571 14.057 - 24 103 79 182 Au -a -28300.768 20.260 7887.226 0.111 B- -4723.846 22.501 181 969617.874 21.749 - 22 102 80 182 Hg -23576.922 9.790 7856.972 0.054 B- -10248.994 15.363 181 974689.132 10.510 - 20 101 81 182 Tl -a -13327.927 11.839 7796.360 0.065 B- -6502.815 16.927 181 985691.880 12.709 - 18 100 82 182 Pb -a -6825.112 12.098 7756.332 0.066 B- * 181 992672.940 12.987 -0 43 113 70 183 Yb x -35100# 401# 7964# 2# B- 4616# 408# 182 962319# 430# - 41 112 71 183 Lu x -39716.110 80.108 7984.812 0.438 B- 3566.687 85.553 182 957363.000 86.000 - 39 111 72 183 Hf + -43282.796 30.034 8000.027 0.164 B- 2010.000 30.000 182 953534.004 32.242 - 37 110 73 183 Ta -n -45292.796 1.419 8006.735 0.008 B- 1072.783 1.413 182 951376.180 1.523 - 35 109 74 183 W -46365.580 0.737 8008.322 0.004 B- -556.000 8.000 182 950224.500 0.790 - 33 108 75 183 Re - -45809.580 8.034 8001.009 0.044 B- -2145.537 50.405 182 950821.390 8.624 - 31 107 76 183 Os -43664.043 49.760 7985.010 0.272 B- -3460.732 52.733 182 953124.719 53.420 - 29 106 77 183 Ir -40203.311 24.398 7961.823 0.133 B- -4430.824 28.923 182 956839.968 26.191 - 27 105 78 183 Pt -35772.487 15.533 7933.336 0.085 B- -5581.004 18.168 182 961596.653 16.675 - 25 104 79 183 Au -30191.483 9.423 7898.564 0.051 B- -6386.809 11.789 182 967588.108 10.116 - 23 103 80 183 Hg -23804.674 7.084 7859.388 0.039 B- -7217.417 11.716 182 974444.629 7.604 - 21 102 81 183 Tl -16587.257 9.331 7815.673 0.051 B- -9012.038 29.657 182 982192.846 10.017 - 19 101 82 183 Pb -a -7575.218 28.151 7762.152 0.154 B- * 182 991867.668 30.221 -0 44 114 70 184 Yb x -32540# 503# 7951# 3# B- 3872# 585# 183 965067# 540# - 42 113 71 184 Lu x -36412# 298# 7967# 2# B- 5087# 301# 183 960910# 320# - 40 112 72 184 Hf + -41499.373 39.706 7990.722 0.216 B- 1340.000 30.000 183 955448.587 42.625 - 38 111 73 184 Ta + -42839.373 26.010 7993.752 0.141 B- 2866.000 26.000 183 954010.038 27.923 - 36 110 74 184 W -45705.373 0.731 8005.077 0.004 B- -1485.739 4.198 183 950933.260 0.785 - 34 109 75 184 Re -44219.634 4.275 7992.750 0.023 B- 32.898 4.140 183 952528.267 4.589 - 32 108 76 184 Os -44252.533 0.827 7988.677 0.005 B- -4641.682 27.957 183 952492.949 0.887 - 30 107 77 184 Ir x -39610.851 27.945 7959.198 0.152 B- -2276.608 31.997 183 957476.000 30.000 - 28 106 78 184 Pt -37334.243 15.584 7942.574 0.085 B- -7015.533 27.185 183 959920.039 16.730 - 26 105 79 184 Au -a -30318.710 22.275 7900.194 0.121 B- -3969.745 24.442 183 967451.524 23.912 - 24 104 80 184 Hg -26348.965 10.062 7874.367 0.055 B- -9465.723 14.200 183 971713.221 10.802 - 22 103 81 184 Tl -16883.242 10.020 7818.671 0.054 B- -5831.720 16.260 183 981875.093 10.757 - 20 102 82 184 Pb -11051.522 12.806 7782.725 0.070 B- -12114.590 79.153 183 988135.702 13.748 - 18 101 83 184 Bi -a 1063.068 78.110 7712.633 0.425 B- * 184 001141.250 83.854 -0 45 115 70 185 Yb x -28500# 503# 7929# 3# B- 5388# 585# 184 969404# 540# - 43 114 71 185 Lu x -33888# 298# 7954# 2# B- 4432# 305# 184 963620# 320# - 41 113 72 185 Hf x -38319.800 64.273 7973.970 0.347 B- 3074.492 65.815 184 958862.000 69.000 - 39 112 73 185 Ta + -41394.293 14.161 7986.360 0.077 B- 1993.500 14.142 184 955561.396 15.202 - 37 111 74 185 W -43387.793 0.733 7992.907 0.004 B- 431.234 0.661 184 953421.286 0.786 - 35 110 75 185 Re -43819.027 0.818 7991.009 0.004 B- -1013.147 0.419 184 952958.337 0.877 - 33 109 76 185 Os -42805.880 0.830 7981.304 0.004 B- -2470.326 27.957 184 954045.995 0.891 - 31 108 77 185 Ir x -40335.553 27.945 7963.722 0.151 B- -3647.414 38.055 184 956698.000 30.000 - 29 107 78 185 Pt -36688.140 25.832 7939.777 0.140 B- -4829.997 25.963 184 960613.659 27.731 - 27 106 79 185 Au x -31858.143 2.608 7909.440 0.014 B- -5674.477 13.886 184 965798.874 2.800 - 25 105 80 185 Hg -26183.666 13.639 7874.538 0.074 B- -6425.925 24.767 184 971890.676 14.641 - 23 104 81 185 Tl IT -19757.741 20.674 7835.575 0.112 B- -8216.521 26.249 184 978789.191 22.194 - 21 103 82 185 Pb -a -11541.220 16.175 7786.932 0.087 B- -9305# 83# 184 987609.989 17.364 - 19 102 83 185 Bi IT -2236# 81# 7732# 0# B- * 184 997600# 87# -0 44 115 71 186 Lu x -30210# 401# 7935# 2# B- 6214# 404# 185 967568# 430# - 42 114 72 186 Hf x -36424.210 51.232 7964.302 0.275 B- 2183.318 78.906 185 960897.000 55.000 - 40 113 73 186 Ta + -38607.528 60.012 7971.835 0.323 B- 3901.000 60.000 185 958553.111 64.425 - 38 112 74 186 W -42508.528 1.212 7988.601 0.007 B- -581.442 1.244 185 954365.215 1.300 - 36 111 75 186 Re -41927.086 0.826 7981.269 0.004 B- 1072.857 0.837 185 954989.419 0.886 - 34 110 76 186 Os -42999.943 0.761 7982.831 0.004 B- -3827.596 16.543 185 953837.660 0.816 - 32 109 77 186 Ir x -39172.346 16.526 7958.047 0.089 B- -1307.903 27.312 185 957946.754 17.740 - 30 108 78 186 Pt -37864.443 21.745 7946.809 0.117 B- -6149.591 30.207 185 959350.846 23.344 - 28 107 79 186 Au -31714.852 20.967 7909.540 0.113 B- -3175.756 23.987 185 965952.703 22.509 - 26 106 80 186 Hg -28539.097 11.650 7888.260 0.063 B- -8652.484 25.209 185 969362.017 12.507 - 24 105 81 186 Tl x -19886.613 22.356 7837.535 0.120 B- -5204.588 25.078 185 978650.841 24.000 - 22 104 82 186 Pb -a -14682.026 11.363 7805.347 0.061 B- -11535.814 20.329 185 984238.196 12.199 - 20 103 83 186 Bi -a -3146.212 16.857 7739.121 0.091 B- -7247.186 24.870 185 996622.402 18.096 - 18 102 84 186 Po -a 4100.974 18.286 7695.951 0.098 B- * 186 004402.577 19.630 -0 45 116 71 187 Lu x -27580# 401# 7922# 2# B- 5237# 499# 186 970392# 430# - 43 115 72 187 Hf x -32817# 298# 7946# 2# B- 4079# 303# 186 964770# 320# - 41 114 73 187 Ta x -36895.546 55.890 7963.212 0.299 B- 3008.424 55.903 186 960391.000 60.000 - 39 113 74 187 W -39903.970 1.212 7975.116 0.006 B- 1312.508 1.122 186 957161.323 1.300 - 37 112 75 187 Re -41216.478 0.736 7977.951 0.004 B- 2.467 0.002 186 955752.288 0.790 - 35 111 76 187 Os -41218.945 0.736 7973.780 0.004 B- -1669.572 27.955 186 955749.640 0.790 - 33 110 77 187 Ir x -39549.372 27.945 7960.668 0.149 B- -2864.323 36.868 186 957542.000 30.000 - 31 109 78 187 Pt -36685.050 24.048 7941.168 0.129 B- -3657.212 27.377 186 960616.976 25.816 - 29 108 79 187 Au -33027.838 22.308 7917.427 0.119 B- -4909.908 26.287 186 964543.155 23.948 - 27 107 80 187 Hg -28117.930 13.905 7886.987 0.074 B- -5673.343 16.067 186 969814.158 14.928 - 25 106 81 187 Tl -22444.587 8.048 7852.464 0.043 B- -7457.628 9.525 186 975904.743 8.640 - 23 105 82 187 Pb -14986.959 5.094 7808.400 0.027 B- -8603.688 11.227 186 983910.836 5.468 - 21 104 83 187 Bi -a -6383.271 10.005 7758.208 0.054 B- -9211.868 33.430 186 993147.276 10.740 - 19 103 84 187 Po -a 2828.597 31.898 7704.763 0.171 B- * 187 003036.624 34.243 -0 46 117 71 188 Lu x -23790# 503# 7902# 3# B- 7089# 585# 187 974460# 540# - 44 116 72 188 Hf x -30879# 298# 7936# 2# B- 2733# 303# 187 966850# 320# - 42 115 73 188 Ta x -33612.030 54.958 7946.321 0.292 B- 5055.781 55.045 187 963916.000 59.000 - 40 114 74 188 W + -38667.811 3.089 7969.052 0.016 B- 349.000 3.000 187 958488.395 3.316 - 38 113 75 188 Re -n -39016.811 0.738 7966.747 0.004 B- 2120.422 0.152 187 958113.728 0.791 - 36 112 76 188 Os -41137.233 0.734 7973.864 0.004 B- -2792.326 9.416 187 955837.361 0.787 - 34 111 77 188 Ir -38344.907 9.423 7954.850 0.050 B- -523.979 8.686 187 958835.046 10.116 - 32 110 78 188 Pt -37820.929 5.304 7947.902 0.028 B- -5449.621 5.953 187 959397.560 5.694 - 30 109 79 188 Au x -32371.308 2.701 7914.753 0.014 B- -2169.394 12.569 187 965247.969 2.900 - 28 108 80 188 Hg -30201.914 12.275 7899.052 0.065 B- -7865.513 32.325 187 967576.910 13.178 - 26 107 81 188 Tl x -22336.400 29.904 7853.053 0.159 B- -4521.198 31.734 187 976020.886 32.103 - 24 106 82 188 Pb -a -17815.202 10.622 7824.843 0.057 B- -10620.515 15.427 187 980874.592 11.403 - 22 105 83 188 Bi -a -7194.687 11.187 7764.189 0.060 B- -6650.374 22.892 187 992276.184 12.009 - 20 104 84 188 Po -a -544.313 19.973 7724.653 0.106 B- * 187 999415.655 21.441 -0 45 117 72 189 Hf x -27162# 298# 7917# 2# B- 4667# 357# 188 970840# 320# - 43 116 73 189 Ta x -31829# 196# 7938# 1# B- 3788# 200# 188 965830# 210# - 41 115 74 189 W x -35617.536 40.054 7953.454 0.212 B- 2361.507 40.883 188 961763.000 43.000 - 39 114 75 189 Re +p -37979.043 8.191 7961.809 0.043 B- 1007.702 8.167 188 959227.817 8.793 - 37 113 76 189 Os -38986.745 0.666 7963.002 0.004 B- -537.159 12.563 188 958146.005 0.715 - 35 112 77 189 Ir -38449.586 12.576 7956.020 0.067 B- -1980.238 13.636 188 958722.669 13.500 - 33 111 78 189 Pt -36469.348 10.090 7941.403 0.053 B- -2887.394 22.474 188 960848.542 10.832 - 31 110 79 189 Au x -33581.955 20.081 7921.987 0.106 B- -3955.554 37.401 188 963948.286 21.558 - 29 109 80 189 Hg -29626.401 31.553 7896.919 0.167 B- -5010.300 32.643 188 968194.748 33.873 - 27 108 81 189 Tl -24616.100 8.368 7866.270 0.044 B- -6772.066 16.364 188 973573.527 8.983 - 25 107 82 189 Pb -17844.035 14.062 7826.299 0.074 B- -7779.374 25.150 188 980843.639 15.096 - 23 106 83 189 Bi -a -10064.660 20.851 7780.999 0.110 B- -8642.656 30.354 188 989195.141 22.384 - 21 105 84 189 Po -a -1422.005 22.059 7731.131 0.117 B- * 188 998473.415 23.681 -0 46 118 72 190 Hf x -25030# 401# 7907# 2# B- 3483# 446# 189 973129# 430# - 44 117 73 190 Ta x -28513# 196# 7921# 1# B- 5869# 200# 189 969390# 210# - 42 116 74 190 W -34382.313 39.726 7947.573 0.209 B- 1253.517 63.522 189 963089.066 42.647 - 40 115 75 190 Re -35635.830 70.852 7950.053 0.373 B- 3071.941 70.854 189 961743.360 76.063 - 38 114 76 190 Os -38707.771 0.650 7962.104 0.003 B- -1954.227 1.213 189 958445.496 0.697 - 36 113 77 190 Ir +n -36753.544 1.370 7947.701 0.007 B- 552.906 1.282 189 960543.445 1.470 - 34 112 78 190 Pt -37306.450 0.657 7946.493 0.003 B- -4472.917 3.509 189 959949.876 0.704 - 32 111 79 190 Au x -32833.533 3.447 7918.834 0.018 B- -1462.836 16.276 189 964751.750 3.700 - 30 110 80 190 Hg -31370.697 15.907 7907.017 0.084 B- -6998.670 17.782 189 966322.169 17.076 - 28 109 81 190 Tl +a -24372.027 7.948 7866.064 0.042 B- -3955.382 14.825 189 973835.551 8.532 - 26 108 82 190 Pb -a -20416.645 12.514 7841.129 0.066 B- -9817.066 25.800 189 978081.828 13.434 - 24 107 83 190 Bi -a -10599.579 22.562 7785.342 0.119 B- -6035.742 26.275 189 988620.883 24.221 - 22 106 84 190 Po -a -4563.837 13.465 7749.458 0.071 B- * 189 995100.519 14.455 -0 45 118 73 191 Ta x -26492# 298# 7911# 2# B- 4684# 301# 190 971560# 320# - 43 117 74 191 W x -31176.173 41.917 7931.435 0.219 B- 3174.124 43.156 190 966531.000 45.000 - 41 116 75 191 Re +p -34350.296 10.265 7943.957 0.054 B- 2044.889 10.244 190 963123.437 11.019 - 39 115 76 191 Os -36395.185 0.659 7950.568 0.003 B- 313.570 1.141 190 960928.159 0.707 - 37 114 77 191 Ir -36708.756 1.311 7948.113 0.007 B- -1010.518 3.636 190 960591.527 1.406 - 35 113 78 191 Pt -35698.237 4.127 7938.727 0.022 B- -1900.333 6.426 190 961676.363 4.430 - 33 112 79 191 Au -33797.904 4.926 7924.681 0.026 B- -3206.008 22.710 190 963716.455 5.288 - 31 111 80 191 Hg -30591.896 22.280 7903.800 0.117 B- -4308.951 23.461 190 967158.247 23.918 - 29 110 81 191 Tl +a -26282.945 7.349 7877.144 0.038 B- -6051.827 37.978 190 971784.096 7.889 - 27 109 82 191 Pb x -20231.118 37.260 7841.363 0.195 B- -6991.772 38.005 190 978281.000 40.000 - 25 108 83 191 Bi -13239.347 7.487 7800.661 0.039 B- -8170.612 10.320 190 985786.975 8.037 - 23 107 84 191 Po -5068.735 7.103 7753.786 0.037 B- -8932.653 17.600 190 994558.488 7.624 - 21 106 85 191 At -a 3863.917 16.103 7702.923 0.084 B- * 191 004148.086 17.287 -0 46 119 73 192 Ta x -23064# 401# 7894# 2# B- 6586# 446# 191 975240# 430# - 44 118 74 192 W x -29649# 196# 7924# 1# B- 1939# 208# 191 968170# 210# - 42 117 75 192 Re x -31588.825 70.794 7930.238 0.369 B- 4293.366 70.831 191 966088.000 76.000 - 40 116 76 192 Os -35882.191 2.315 7948.525 0.012 B- -1046.630 2.397 191 961478.881 2.485 - 38 115 77 192 Ir -34835.561 1.314 7938.999 0.007 B- 1452.896 2.274 191 962602.485 1.410 - 36 114 78 192 Pt -36288.457 2.570 7942.491 0.013 B- -3516.341 15.617 191 961042.736 2.758 - 34 113 79 192 Au - -32772.116 15.827 7920.102 0.082 B- -760.563 22.178 191 964817.684 16.991 - 32 112 80 192 Hg x -32011.553 15.537 7912.066 0.081 B- -6139.307 35.277 191 965634.182 16.679 - 30 111 81 192 Tl x -25872.246 31.671 7876.016 0.165 B- -3316.226 34.348 191 972225.000 34.000 - 28 110 82 192 Pb -a -22556.020 13.295 7854.669 0.069 B- -9021.485 32.917 191 975785.115 14.273 - 26 109 83 192 Bi -a -13534.535 30.112 7803.608 0.157 B- -5463.873 32.096 191 985470.078 32.326 - 24 108 84 192 Po -a -8070.661 11.110 7771.075 0.058 B- -10996.516 30.008 191 991335.788 11.926 - 22 107 85 192 At -a 2925.854 27.876 7709.727 0.145 B- * 192 003141.034 29.926 -0 47 120 73 193 Ta x -20870# 401# 7884# 2# B- 5417# 446# 192 977595# 430# - 45 119 74 193 W x -26287# 196# 7908# 1# B- 3945# 199# 192 971780# 210# - 43 118 75 193 Re x -30231.638 39.123 7923.937 0.203 B- 3162.652 39.192 192 967545.000 42.000 - 41 117 76 193 Os -33394.289 2.321 7936.270 0.012 B- 1141.946 2.400 192 964149.753 2.491 - 39 116 77 193 Ir -34536.235 1.328 7938.133 0.007 B- -56.628 0.300 192 962923.824 1.425 - 37 115 78 193 Pt -34479.608 1.359 7933.786 0.007 B- -1074.787 8.768 192 962984.616 1.458 - 35 114 79 193 Au -33404.821 8.674 7924.164 0.045 B- -2342.642 14.370 192 964138.447 9.311 - 33 113 80 193 Hg -31062.179 15.505 7907.972 0.080 B- -3584.967 16.894 192 966653.377 16.645 - 31 112 81 193 Tl x -27477.212 6.707 7885.344 0.035 B- -5282.723 50.028 192 970501.997 7.200 - 29 111 82 193 Pb x -22194.490 49.577 7853.919 0.257 B- -6309.931 50.152 192 976173.234 53.222 - 27 110 83 193 Bi -15884.559 7.576 7817.171 0.039 B- -7559.241 16.387 192 982947.223 8.132 - 25 109 84 193 Po -a -8325.318 14.531 7773.950 0.075 B- -8257.998 26.059 192 991062.403 15.599 - 23 108 85 193 At -a -67.320 21.632 7727.109 0.112 B- -9110.231 33.144 192 999927.728 23.222 - 21 107 86 193 Rn -a 9042.911 25.112 7675.852 0.130 B- * 193 009707.964 26.958 -0 48 121 73 194 Ta x -17300# 503# 7866# 3# B- 7227# 585# 193 981428# 540# - 46 120 74 194 W x -24526# 298# 7899# 2# B- 2711# 357# 193 973670# 320# - 44 119 75 194 Re x -27237# 196# 7909# 1# B- 5198# 196# 193 970760# 210# - 42 118 76 194 Os + -32435.108 2.403 7932.022 0.012 B- 96.600 2.000 193 965179.477 2.579 - 40 117 77 194 Ir -n -32531.708 1.332 7928.487 0.007 B- 2228.362 1.257 193 965075.773 1.430 - 38 116 78 194 Pt -34760.070 0.496 7935.941 0.003 B- -2548.134 2.117 193 962683.527 0.532 - 36 115 79 194 Au +3n -32211.936 2.118 7918.774 0.011 B- -27.991 3.581 193 965419.062 2.273 - 34 114 80 194 Hg x -32183.945 2.888 7914.597 0.015 B- -5246.454 14.268 193 965449.111 3.100 - 32 113 81 194 Tl x -26937.491 13.972 7883.520 0.072 B- -2729.552 22.343 193 971081.411 15.000 - 30 112 82 194 Pb -24207.940 17.435 7865.418 0.090 B- -8179.128 18.498 193 974011.706 18.717 - 28 111 83 194 Bi +a -16028.811 6.178 7819.225 0.032 B- -5024.156 14.313 193 982792.362 6.632 - 26 110 84 194 Po -a -11004.655 12.911 7789.294 0.067 B- -10284.492 28.076 193 988186.015 13.860 - 24 109 85 194 At -a -720.163 24.931 7732.249 0.129 B- -6443.658 30.119 193 999226.872 26.764 - 22 108 86 194 Rn -a 5723.495 16.899 7695.001 0.087 B- * 194 006144.424 18.141 -0 47 121 74 195 W x -21010# 298# 7882# 2# B- 4569# 422# 194 977445# 320# - 45 120 75 195 Re x -25579# 298# 7902# 2# B- 3933# 303# 194 972540# 320# - 43 119 76 195 Os x -29511.593 55.890 7917.744 0.287 B- 2180.658 55.906 194 968318.000 60.000 - 41 118 77 195 Ir -n -31692.251 1.333 7924.915 0.007 B- 1101.598 1.264 194 965976.967 1.431 - 39 117 78 195 Pt -32793.849 0.503 7926.552 0.003 B- -226.817 1.000 194 964794.353 0.539 - 37 116 79 195 Au -32567.031 1.119 7921.377 0.006 B- -1553.638 23.156 194 965037.851 1.201 - 35 115 80 195 Hg -31013.393 23.142 7909.397 0.119 B- -2858.145 25.657 194 966705.751 24.843 - 33 114 81 195 Tl -28155.248 11.093 7890.728 0.057 B- -4447.555 21.106 194 969774.096 11.909 - 31 113 82 195 Pb -23707.693 17.960 7863.908 0.092 B- -5682.132 18.722 194 974548.743 19.280 - 29 112 83 195 Bi -18025.561 5.287 7830.757 0.027 B- -6969.303 37.737 194 980648.762 5.675 - 27 111 84 195 Po -a -11056.259 37.364 7791.005 0.192 B- -7585.964 38.571 194 988130.617 40.112 - 25 110 85 195 At -a -3470.295 9.573 7748.091 0.049 B- -8520.575 51.401 194 996274.485 10.276 - 23 109 86 195 Rn -a 5050.281 50.502 7700.383 0.259 B- * 195 005421.699 54.216 -0 48 122 74 196 W x -18880# 401# 7872# 2# B- 3662# 499# 195 979731# 430# - 46 121 75 196 Re x -22542# 298# 7887# 2# B- 5735# 301# 195 975800# 320# - 44 120 76 196 Os +pp -28277.105 40.055 7912.229 0.204 B- 1158.388 55.495 195 969643.277 43.000 - 42 119 77 196 Ir + -29435.493 38.414 7914.148 0.196 B- 3209.016 38.411 195 968399.696 41.239 - 40 118 78 196 Pt -32644.510 0.510 7926.529 0.003 B- -1505.803 2.960 195 964954.675 0.547 - 38 117 79 196 Au -31138.706 2.962 7914.855 0.015 B- 687.235 3.118 195 966571.221 3.179 - 36 116 80 196 Hg -31825.941 2.946 7914.369 0.015 B- -4329.349 12.463 195 965833.444 3.163 - 34 115 81 196 Tl x -27496.592 12.109 7888.289 0.062 B- -2148.280 14.356 195 970481.192 13.000 - 32 114 82 196 Pb -25348.312 7.710 7873.337 0.039 B- -7339.281 25.616 195 972787.466 8.277 - 30 113 83 196 Bi x -18009.031 24.428 7831.900 0.125 B- -4535.989 27.916 195 980666.509 26.224 - 28 112 84 196 Po -a -13473.042 13.512 7804.766 0.069 B- -9558.365 33.162 195 985536.094 14.506 - 26 111 85 196 At -a -3914.677 30.284 7752.007 0.155 B- -5885.668 33.540 195 995797.421 32.511 - 24 110 86 196 Rn -a 1970.991 14.417 7717.987 0.074 B- * 196 002115.945 15.476 -0 49 123 74 197 W x -15140# 401# 7854# 2# B- 5363# 499# 196 983747# 430# - 47 122 75 197 Re x -20502# 298# 7878# 2# B- 4807# 357# 196 977990# 320# - 45 121 76 197 Os x -25309# 196# 7898# 1# B- 2955# 197# 196 972830# 210# - 43 120 77 197 Ir +p -28264.105 20.110 7908.999 0.102 B- 2155.645 20.106 196 969657.233 21.588 - 41 119 78 197 Pt -30419.750 0.536 7915.971 0.003 B- 719.988 0.502 196 967343.053 0.575 - 39 118 79 197 Au -31139.738 0.542 7915.654 0.003 B- -599.509 3.202 196 966570.114 0.581 - 37 117 80 197 Hg -30540.229 3.207 7908.640 0.016 B- -2198.580 16.637 196 967213.713 3.442 - 35 116 81 197 Tl +a -28341.649 16.325 7893.508 0.083 B- -3596.247 17.014 196 969573.986 17.526 - 33 115 82 197 Pb -24745.401 4.804 7871.282 0.024 B- -5058.210 9.619 196 973434.717 5.157 - 31 114 83 197 Bi +a -19687.191 8.333 7841.634 0.042 B- -6329.202 50.373 196 978864.929 8.946 - 29 113 84 197 Po -a -13357.990 49.679 7805.535 0.252 B- -7002.739 50.317 196 985659.607 53.332 - 27 112 85 197 At -6355.250 7.983 7766.017 0.041 B- -7865.603 18.054 196 993177.357 8.570 - 25 111 86 197 Rn -a 1510.353 16.193 7722.118 0.082 B- -8743.618 56.762 197 001621.430 17.383 - 23 110 87 197 Fr -a 10253.971 54.404 7673.763 0.276 B- * 197 011008.090 58.404 -0 48 123 75 198 Re x -17139# 401# 7862# 2# B- 6697# 446# 197 981600# 430# - 46 122 76 198 Os x -23837# 196# 7891# 1# B- 1984# 277# 197 974410# 210# - 44 121 77 198 Ir x -25821# 196# 7897# 1# B- 4083# 196# 197 972280# 210# - 42 120 78 198 Pt -29903.999 2.100 7914.150 0.011 B- -323.219 2.059 197 967896.734 2.254 - 40 119 79 198 Au -29580.781 0.540 7908.567 0.003 B- 1373.530 0.490 197 968243.724 0.579 - 38 118 80 198 Hg -30954.310 0.458 7911.552 0.002 B- -3425.564 7.559 197 966769.179 0.491 - 36 117 81 198 Tl x -27528.746 7.545 7890.300 0.038 B- -1461.257 11.554 197 970446.673 8.100 - 34 116 82 198 Pb -26067.489 8.750 7878.969 0.044 B- -6698.003 29.283 197 972015.397 9.393 - 32 115 83 198 Bi x -19369.486 27.945 7841.189 0.141 B- -3896.134 32.932 197 979206.000 30.000 - 30 114 84 198 Po -15473.352 17.424 7817.561 0.088 B- -8758.839 18.386 197 983388.672 18.705 - 28 113 85 198 At x -6714.513 5.868 7769.373 0.030 B- -5484.155 14.647 197 992791.673 6.300 - 26 112 86 198 Rn -a -1230.358 13.420 7737.724 0.068 B- -10804.382 34.905 197 998679.156 14.406 - 24 111 87 198 Fr -a 9574.024 32.222 7679.205 0.163 B- * 198 010278.138 34.591 -0 49 124 75 199 Re x -14860# 401# 7851# 2# B- 5623# 446# 198 984047# 430# - 47 123 76 199 Os x -20484# 196# 7875# 1# B- 3915# 200# 198 978010# 210# - 45 122 77 199 Ir p-2n -24398.515 41.054 7891.206 0.206 B- 2990.167 41.003 198 973807.115 44.073 - 43 121 78 199 Pt -n -27388.682 2.159 7902.300 0.011 B- 1705.059 2.120 198 970597.038 2.317 - 41 120 79 199 Au -29093.741 0.542 7906.937 0.003 B- 452.327 0.613 198 968766.582 0.581 - 39 119 80 199 Hg -29546.068 0.526 7905.279 0.003 B- -1486.674 27.950 198 968280.989 0.564 - 37 118 81 199 Tl x -28059.394 27.945 7893.877 0.140 B- -2827.589 29.679 198 969877.000 30.000 - 35 117 82 199 Pb +a -25231.804 9.996 7875.736 0.050 B- -4434.239 14.547 198 972912.542 10.730 - 33 116 83 199 Bi -20797.566 10.568 7849.522 0.053 B- -5589.083 20.919 198 977672.893 11.345 - 31 115 84 199 Po -a -15208.483 18.060 7817.505 0.091 B- -6385.111 18.845 198 983673.021 19.387 - 29 114 85 199 At -8823.372 5.384 7781.488 0.027 B- -7323.921 37.972 198 990527.719 5.780 - 27 113 86 199 Rn -a -1499.451 37.588 7740.753 0.189 B- -8270.844 40.015 198 998390.273 40.352 - 25 112 87 199 Fr -a 6771.393 13.726 7695.259 0.069 B- * 199 007269.389 14.734 -0 48 124 76 200 Os x -18779# 298# 7868# 1# B- 2832# 357# 199 979840# 320# - 46 123 77 200 Ir x -21611# 196# 7878# 1# B- 4988# 197# 199 976800# 210# - 44 122 78 200 Pt -nn -26599.160 20.110 7899.198 0.101 B- 640.932 33.439 199 971444.625 21.588 - 42 121 79 200 Au -27240.092 26.717 7898.491 0.134 B- 2263.178 26.719 199 970756.556 28.681 - 40 120 80 200 Hg -29503.270 0.529 7905.895 0.003 B- -2456.040 5.735 199 968326.934 0.568 - 38 119 81 200 Tl - -27047.230 5.759 7889.703 0.029 B- -796.176 12.340 199 970963.602 6.182 - 36 118 82 200 Pb 4n -26251.054 10.927 7881.810 0.055 B- -5880.299 24.852 199 971818.332 11.730 - 34 117 83 200 Bi +a -20370.755 22.321 7848.497 0.112 B- -3428.994 23.573 199 978131.093 23.962 - 32 116 84 200 Po -16941.761 7.579 7827.440 0.038 B- -7953.869 25.612 199 981812.270 8.135 - 30 115 85 200 At -a -8987.892 24.465 7783.759 0.122 B- -4983.127 28.030 199 990351.100 26.264 - 28 114 86 200 Rn -a -4004.765 13.681 7754.932 0.068 B- -10137.263 33.529 199 995700.707 14.686 - 26 113 87 200 Fr -a 6132.498 30.611 7700.334 0.153 B- * 200 006583.507 32.861 -0 49 125 76 201 Os x -15239# 298# 7851# 1# B- 4657# 357# 200 983640# 320# - 47 124 77 201 Ir x -19897# 196# 7871# 1# B- 3844# 202# 200 978640# 210# - 45 123 78 201 Pt + -23740.714 50.103 7885.833 0.249 B- 2660.000 50.000 200 974513.293 53.788 - 43 122 79 201 Au -26400.714 3.218 7895.175 0.016 B- 1261.827 3.147 200 971657.665 3.454 - 41 121 80 201 Hg -27662.542 0.711 7897.560 0.004 B- -481.704 14.181 200 970303.038 0.763 - 39 120 81 201 Tl -27180.838 14.185 7891.271 0.071 B- -1909.802 18.530 200 970820.168 15.228 - 37 119 82 201 Pb -25271.036 13.747 7877.877 0.068 B- -3854.603 20.481 200 972870.425 14.758 - 35 118 83 201 Bi +a -21416.433 15.183 7854.808 0.076 B- -4895.248 15.962 200 977008.512 16.299 - 33 117 84 201 Po -16521.185 4.942 7826.561 0.025 B- -5731.747 9.561 200 982263.777 5.305 - 31 116 85 201 At +a -10789.438 8.184 7794.153 0.041 B- -6717.113 50.401 200 988417.061 8.786 - 29 115 86 201 Rn -a -4072.324 49.732 7756.842 0.247 B- -7660.902 50.554 200 995628.179 53.389 - 27 114 87 201 Fr -a 3588.577 9.080 7714.836 0.045 B- -8348.224 22.239 201 003852.496 9.747 - 25 113 88 201 Ra -a 11936.801 20.301 7669.410 0.101 B- * 201 012814.683 21.794 -0 50 126 76 202 Os x -13087# 401# 7842# 2# B- 3689# 499# 201 985950# 430# - 48 125 77 202 Ir x -16776# 298# 7856# 1# B- 5916# 299# 201 981990# 320# - 46 124 78 202 Pt x -22692.125 25.150 7881.560 0.125 B- 1660.854 34.276 201 975639.000 27.000 - 44 123 79 202 Au x -24352.979 23.287 7885.909 0.115 B- 2992.345 23.298 201 973856.000 25.000 - 42 122 80 202 Hg -27345.324 0.705 7896.850 0.003 B- -1365.108 1.636 201 970643.585 0.756 - 40 121 81 202 Tl -25980.216 1.606 7886.219 0.008 B- -39.602 4.096 201 972109.089 1.723 - 38 120 82 202 Pb -25940.614 3.796 7882.150 0.019 B- -5199.130 15.856 201 972151.604 4.075 - 36 119 83 202 Bi -20741.484 15.396 7852.539 0.076 B- -2799.868 17.666 201 977733.100 16.528 - 34 118 84 202 Po -17941.616 8.670 7834.805 0.043 B- -7350.884 29.289 201 980738.881 9.307 - 32 117 85 202 At -a -10590.732 27.977 7794.541 0.138 B- -4316.097 33.010 201 988630.380 30.034 - 30 116 86 202 Rn -a -6274.635 17.520 7769.301 0.087 B- -9370.871 18.881 201 993263.902 18.808 - 28 115 87 202 Fr -a 3096.237 7.040 7719.038 0.035 B- -5978.625 16.586 202 003323.946 7.557 - 26 114 88 202 Ra -a 9074.861 15.018 7685.568 0.074 B- * 202 009742.264 16.122 -0 51 127 76 203 Os x -7640# 401# 7816# 2# B- 7050# 566# 202 991798# 430# - 49 126 77 203 Ir x -14690# 401# 7847# 2# B- 4937# 446# 202 984230# 430# - 47 125 78 203 Pt x -19627# 196# 7867# 1# B- 3517# 196# 202 978930# 210# - 45 124 79 203 Au -23143.436 3.083 7880.864 0.015 B- 2125.829 3.451 202 975154.498 3.309 - 43 123 80 203 Hg -25269.265 1.627 7887.482 0.008 B- 492.112 1.225 202 972872.326 1.746 - 41 122 81 203 Tl -25761.377 1.166 7886.053 0.006 B- -974.820 6.461 202 972344.022 1.252 - 39 121 82 203 Pb -24786.557 6.554 7877.397 0.032 B- -3261.729 14.356 202 973390.535 7.036 - 37 120 83 203 Bi +a -21524.827 12.778 7857.475 0.063 B- -4213.939 15.433 202 976892.145 13.717 - 35 119 84 203 Po +a -17310.889 8.655 7832.863 0.043 B- -5148.332 13.666 202 981415.995 9.291 - 33 118 85 203 At -12162.557 10.576 7803.648 0.052 B- -6008.858 21.027 202 986942.957 11.353 - 31 117 86 203 Rn -a -6153.699 18.179 7770.193 0.090 B- -7030.116 19.218 202 993393.732 19.516 - 29 116 87 203 Fr 876.417 6.232 7731.708 0.031 B- -7785.309 38.630 203 000940.872 6.689 - 27 115 88 203 Ra -a 8661.726 38.124 7689.503 0.188 B- * 203 009298.745 40.928 -0 50 127 77 204 Ir x -9688# 401# 7824# 2# B- 8234# 446# 203 989600# 430# - 48 126 78 204 Pt x -17922# 196# 7860# 1# B- 2728# 280# 203 980760# 210# - 46 125 79 204 Au + -20650# 200# 7870# 1# B- 4040# 200# 203 977831# 215# - 44 124 80 204 Hg -24690.145 0.498 7885.545 0.002 B- -344.000 1.186 203 973494.037 0.534 - 42 123 81 204 Tl -24346.145 1.152 7880.023 0.006 B- 763.748 0.177 203 973863.337 1.236 - 40 122 82 204 Pb -25109.892 1.146 7879.932 0.006 B- -4463.996 9.248 203 973043.420 1.230 - 38 121 83 204 Bi +a -20645.896 9.180 7854.215 0.045 B- -2304.652 14.335 203 977835.717 9.854 - 36 120 84 204 Po -a -18341.244 11.013 7839.083 0.054 B- -6465.811 24.860 203 980309.863 11.822 - 34 119 85 204 At -11875.433 22.288 7803.552 0.109 B- -3905.240 23.498 203 987251.197 23.926 - 32 118 86 204 Rn -7970.193 7.444 7780.574 0.036 B- -8577.503 25.684 203 991443.644 7.991 - 30 117 87 204 Fr -a 607.310 24.581 7734.692 0.120 B- -5449.477 28.940 204 000651.974 26.389 - 28 116 88 204 Ra -a 6056.787 15.273 7704.144 0.075 B- * 204 006502.228 16.396 -0 51 128 77 205 Ir x -5960# 503# 7807# 2# B- 7007# 585# 204 993602# 540# - 49 127 78 205 Pt x -12966# 298# 7837# 1# B- 5803# 357# 204 986080# 320# - 47 126 79 205 Au x -18770# 196# 7861# 1# B- 3518# 196# 204 979850# 210# - 45 125 80 205 Hg -22287.740 3.654 7874.732 0.018 B- 1533.135 3.724 204 976073.125 3.923 - 43 124 81 205 Tl -23820.874 1.237 7878.394 0.006 B- -50.636 0.503 204 974427.237 1.328 - 41 123 82 205 Pb -23770.239 1.144 7874.331 0.006 B- -2705.734 5.107 204 974481.597 1.228 - 39 122 83 205 Bi -21064.504 5.111 7857.316 0.025 B- -3543.106 11.280 204 977386.323 5.487 - 37 121 84 205 Po -17521.398 10.059 7836.216 0.049 B- -4549.452 18.130 204 981190.004 10.798 - 35 120 85 205 At +a -12971.946 15.085 7810.207 0.074 B- -5262.161 15.913 204 986074.041 16.194 - 33 119 86 205 Rn -7709.786 5.080 7780.722 0.025 B- -6399.973 9.329 204 991723.204 5.453 - 31 118 87 205 Fr x -1309.813 7.824 7745.686 0.038 B- -7148.804 70.954 204 998593.858 8.399 - 29 117 88 205 Ra -a 5838.991 70.521 7706.998 0.344 B- -8267.702 86.923 205 006268.415 75.707 - 27 116 89 205 Ac -a 14106.693 50.818 7662.851 0.248 B- * 205 015144.158 54.555 -0 50 128 78 206 Pt x -9632# 298# 7822# 1# B- 4583# 422# 205 989660# 320# - 48 127 79 206 Au x -14215# 298# 7840# 1# B- 6731# 299# 205 984740# 320# - 46 126 80 206 Hg +a -20945.801 20.440 7869.172 0.099 B- 1307.566 20.410 205 977513.756 21.943 - 44 125 81 206 Tl -22253.367 1.284 7871.721 0.006 B- 1532.217 0.612 205 976110.026 1.378 - 42 124 82 206 Pb -23785.584 1.144 7875.362 0.006 B- -3757.306 7.546 205 974465.124 1.227 - 40 123 83 206 Bi - -20028.278 7.632 7853.324 0.037 B- -1839.604 8.600 205 978498.757 8.193 - 38 122 84 206 Po -a -18188.674 4.012 7840.597 0.019 B- -5758.956 15.580 205 980473.654 4.306 - 36 121 85 206 At -12429.718 15.056 7808.843 0.073 B- -3296.753 17.330 205 986656.148 16.162 - 34 120 86 206 Rn -9132.965 8.591 7789.041 0.042 B- -7890.549 29.475 205 990195.358 9.223 - 32 119 87 206 Fr -a -1242.416 28.195 7746.940 0.137 B- -4807.955 33.455 205 998666.211 30.268 - 30 118 88 206 Ra -a 3565.539 18.008 7719.802 0.087 B- -9913.913 53.608 206 003827.763 19.332 - 28 117 89 206 Ac -a 13479.452 50.493 7667.879 0.245 B- * 206 014470.787 54.206 -0 51 129 78 207 Pt x -4540# 401# 7798# 2# B- 6270# 500# 206 995126# 430# - 49 128 79 207 Au x -10810# 300# 7825# 1# B- 5677# 301# 206 988395# 322# - 47 127 80 207 Hg x -16487.444 29.808 7848.610 0.144 B- 4547.008 30.300 206 982300.000 32.000 - 45 126 81 207 Tl -21034.451 5.439 7866.797 0.026 B- 1417.595 5.402 206 977418.586 5.839 - 43 125 82 207 Pb -22452.047 1.147 7869.866 0.006 B- -2397.420 2.118 206 975896.735 1.230 - 41 124 83 207 Bi -20054.627 2.397 7854.505 0.012 B- -2908.852 6.614 206 978470.471 2.573 - 39 123 84 207 Po -17145.775 6.659 7836.673 0.032 B- -3918.358 14.075 206 981593.252 7.148 - 37 122 85 207 At +a -13227.416 12.406 7813.964 0.060 B- -4592.654 15.037 206 985799.783 13.318 - 35 121 86 207 Rn +a -8634.762 8.497 7787.998 0.041 B- -5790.421 19.458 206 990730.200 9.121 - 33 120 87 207 Fr -2844.341 17.505 7756.246 0.085 B- -6388.826 56.008 206 996946.474 18.792 - 31 119 88 207 Ra -a 3544.485 53.202 7721.602 0.257 B- -7601.748 73.276 207 003805.161 57.115 - 29 118 89 207 Ac -a 11146.233 50.387 7681.099 0.243 B- * 207 011965.973 54.092 -0 52 130 78 208 Pt x -990# 400# 7783# 2# B- 5111# 499# 207 998937# 429# - 50 129 79 208 Au x -6101# 298# 7804# 1# B- 7164# 300# 207 993450# 320# - 48 128 80 208 Hg x -13265.406 30.739 7834.191 0.148 B- 3484.726 30.795 207 985759.000 33.000 - 46 127 81 208 Tl +a -16750.132 1.854 7847.183 0.009 B- 4998.466 1.669 207 982017.992 1.990 - 44 126 82 208 Pb -21748.598 1.148 7867.453 0.006 B- -2878.375 2.013 207 976651.918 1.231 - 42 125 83 208 Bi +n -18870.223 2.304 7849.853 0.011 B- -1400.628 2.397 207 979741.981 2.473 - 40 124 84 208 Po -a -17469.596 1.737 7839.358 0.008 B- -4999.725 9.086 207 981245.616 1.864 - 38 123 85 208 At +a -12469.871 8.921 7811.560 0.043 B- -2814.279 14.269 207 986613.042 9.577 - 36 122 86 208 Rn -a -9655.591 11.138 7794.268 0.054 B- -6989.672 16.251 207 989634.295 11.957 - 34 121 87 208 Fr -2665.919 11.834 7756.903 0.057 B- -4393.774 14.881 207 997138.018 12.704 - 32 120 88 208 Ra -a 1727.856 9.023 7732.017 0.043 B- -9025.380 56.442 208 001854.929 9.686 - 30 119 89 208 Ac -a 10753.235 55.716 7684.865 0.268 B- -5930.495 65.370 208 011544.073 59.813 - 28 118 90 208 Th -a 16683.730 34.190 7652.592 0.164 B- * 208 017910.722 36.704 -0 51 130 79 209 Au x -2540# 400# 7788# 2# B- 6104# 426# 208 997273# 429# - 49 129 80 209 Hg x -8644# 149# 7813# 1# B- 5000# 149# 208 990720# 160# - 47 128 81 209 Tl +a -13644.757 6.110 7833.397 0.029 B- 3969.889 6.211 208 985351.750 6.559 - 45 127 82 209 Pb -17614.646 1.747 7848.648 0.008 B- 644.016 1.146 208 981089.898 1.875 - 43 126 83 209 Bi -18258.662 1.364 7847.987 0.007 B- -1892.570 1.564 208 980398.519 1.464 - 41 125 84 209 Po -a -16366.092 1.778 7835.188 0.009 B- -3483.478 5.287 208 982430.276 1.908 - 39 124 85 209 At -12882.613 5.102 7814.777 0.024 B- -3941.564 11.188 208 986169.944 5.477 - 37 123 86 209 Rn -8941.049 9.960 7792.175 0.048 B- -5171.477 17.713 208 990401.388 10.692 - 35 122 87 209 Fr x -3769.572 14.648 7763.688 0.070 B- -5627.791 15.730 208 995953.197 15.725 - 33 121 88 209 Ra -a 1858.219 5.747 7733.017 0.027 B- -6985.590 50.934 209 001994.879 6.169 - 31 120 89 209 Ac -a 8843.809 50.608 7695.850 0.242 B- -7523# 148# 209 009494.220 54.330 - 29 119 90 209 Th IT 16367# 140# 7656# 1# B- * 209 017571# 150# -0 52 131 79 210 Au x 2329# 401# 7766# 2# B- 7694# 446# 210 002500# 430# - 50 130 80 210 Hg x -5365# 196# 7799# 1# B- 3882# 196# 209 994240# 210# - 48 129 81 210 Tl +a -9246.969 11.604 7813.588 0.055 B- 5481.534 11.561 209 990072.970 12.456 - 46 128 82 210 Pb -14728.502 1.447 7835.965 0.007 B- 63.476 0.499 209 984188.301 1.553 - 44 127 83 210 Bi -14791.979 1.363 7832.542 0.006 B- 1161.159 0.766 209 984120.156 1.462 - 42 126 84 210 Po -15953.137 1.146 7834.346 0.005 B- -3980.960 7.610 209 982873.601 1.230 - 40 125 85 210 At -a -11972.177 7.695 7811.663 0.037 B- -2367.407 8.922 209 987147.338 8.261 - 38 124 86 210 Rn -a -9604.770 4.557 7796.665 0.022 B- -6271.565 15.824 209 989688.854 4.892 - 36 123 87 210 Fr -3333.205 15.154 7763.075 0.072 B- -3775.997 17.720 209 996421.657 16.268 - 34 122 88 210 Ra -a 442.792 9.193 7741.368 0.044 B- -8346.908 58.133 210 000475.356 9.868 - 32 121 89 210 Ac -a 8789.699 57.402 7697.896 0.273 B- -5269.747 60.436 210 009436.130 61.623 - 30 120 90 210 Th -a 14059.446 18.909 7669.076 0.090 B- * 210 015093.437 20.299 -0 51 131 80 211 Hg x -624# 196# 7778# 1# B- 5454# 200# 210 999330# 210# - 49 130 81 211 Tl x -6077.998 41.917 7799.791 0.199 B- 4414.950 41.978 210 993475.000 45.000 - 47 129 82 211 Pb -10492.948 2.261 7817.007 0.011 B- 1366.183 5.471 210 988735.356 2.426 - 45 128 83 211 Bi -11859.131 5.442 7819.774 0.026 B- 573.439 5.430 210 987268.698 5.842 - 43 127 84 211 Po -a -12432.571 1.255 7818.784 0.006 B- -785.307 2.539 210 986653.085 1.347 - 41 126 85 211 At -a -11647.264 2.729 7811.354 0.013 B- -2891.860 6.894 210 987496.147 2.929 - 39 125 86 211 Rn -a -8755.404 6.813 7793.941 0.032 B- -4615.155 13.786 210 990600.686 7.314 - 37 124 87 211 Fr -4140.249 11.991 7768.360 0.057 B- -4972.272 14.369 210 995555.259 12.872 - 35 123 88 211 Ra x 832.023 7.918 7741.087 0.038 B- -6370.191 53.564 211 000893.213 8.500 - 33 122 89 211 Ac -a 7202.214 52.976 7707.189 0.251 B- -6707.958 90.205 211 007731.894 56.871 - 31 121 90 211 Th -a 13910.171 73.010 7671.690 0.346 B- -8170# 126# 211 014933.183 78.379 - 29 120 91 211 Pa x 22080# 102# 7629# 0# B- * 211 023704# 110# -0 52 132 80 212 Hg x 2757# 298# 7763# 1# B- 4308# 359# 212 002960# 320# - 50 131 81 212 Tl +a -1551# 200# 7780# 1# B- 5998# 200# 211 998335# 215# - 48 130 82 212 Pb -7548.850 1.842 7804.319 0.009 B- 569.104 1.825 211 991895.975 1.977 - 46 129 83 212 Bi -8117.954 1.854 7803.313 0.009 B- 2251.533 1.667 211 991285.016 1.989 - 44 128 84 212 Po -10369.487 1.152 7810.243 0.005 B- -1741.266 2.107 211 988867.896 1.236 - 42 127 85 212 At -a -8628.221 2.384 7798.340 0.011 B- 31.387 3.605 211 990737.223 2.559 - 40 126 86 212 Rn -a -8659.608 3.145 7794.797 0.015 B- -5143.640 9.318 211 990703.528 3.376 - 38 125 87 212 Fr -3515.968 8.775 7766.845 0.041 B- -3317.000 14.276 211 996225.453 9.420 - 36 124 88 212 Ra -a -198.968 11.263 7747.508 0.053 B- -7476.266 52.601 211 999786.399 12.091 - 34 123 89 212 Ac -a 7277.298 51.381 7708.552 0.242 B- -4833.510 52.366 212 007812.501 55.160 - 32 122 90 212 Th -a 12110.808 10.109 7682.062 0.048 B- -9482.551 75.541 212 013001.487 10.852 - 30 121 91 212 Pa -a 21593.358 74.862 7633.643 0.353 B- * 212 023181.425 80.367 -0 53 133 80 213 Hg x 7666# 298# 7741# 1# B- 5882# 299# 213 008230# 320# - 51 132 81 213 Tl x 1783.811 27.013 7765.430 0.127 B- 4987.343 27.894 213 001915.000 29.000 - 49 131 82 213 Pb +a -3203.532 6.954 7785.172 0.033 B- 2028.103 8.371 212 996560.867 7.465 - 47 130 83 213 Bi -5231.635 5.082 7791.021 0.024 B- 1421.949 5.490 212 994383.608 5.456 - 45 129 84 213 Po -6653.584 3.053 7794.024 0.014 B- -73.989 5.465 212 992857.083 3.277 - 43 128 85 213 At -a -6579.595 4.898 7790.003 0.023 B- -883.569 5.724 212 992936.514 5.257 - 41 127 86 213 Rn -a -5696.026 3.370 7782.182 0.016 B- -2143.179 6.006 212 993885.064 3.617 - 39 126 87 213 Fr -3552.848 5.091 7768.447 0.024 B- -3898.405 11.057 212 996185.861 5.465 - 37 125 88 213 Ra 345.557 9.818 7746.472 0.046 B- -5809.134 18.156 213 000370.970 10.540 - 35 124 89 213 Ac -a 6154.692 15.272 7715.526 0.072 B- -5965.394 17.834 213 006607.333 16.395 - 33 123 90 213 Th -a 12120.086 9.217 7683.846 0.043 B- -7542.539 71.737 213 013011.447 9.895 - 31 122 91 213 Pa -a 19662.625 71.142 7644.762 0.334 B- * 213 021108.697 76.374 -0 54 134 80 214 Hg x 11178# 401# 7727# 2# B- 4713# 446# 214 012000# 430# - 52 133 81 214 Tl x 6465# 196# 7745# 1# B- 6647# 196# 214 006940# 210# - 50 132 82 214 Pb -182.769 1.975 7772.394 0.009 B- 1017.984 11.256 213 999803.788 2.120 - 48 131 83 214 Bi -1200.753 11.209 7773.495 0.052 B- 3269.293 11.165 213 998710.938 12.033 - 46 130 84 214 Po -4470.046 1.449 7785.116 0.007 B- -1090.215 4.107 213 995201.208 1.555 - 44 129 85 214 At -a -3379.831 4.298 7776.366 0.020 B- 939.911 10.014 213 996371.601 4.614 - 42 128 86 214 Rn -a -4319.742 9.187 7777.102 0.043 B- -3361.035 12.503 213 995362.566 9.862 - 40 127 87 214 Fr -a -958.707 8.634 7757.740 0.040 B- -1051.441 10.086 213 998970.785 9.268 - 38 126 88 214 Ra -a 92.734 5.250 7749.171 0.025 B- -6351.120 16.232 214 000099.554 5.636 - 36 125 89 214 Ac -a 6443.854 15.360 7715.837 0.072 B- -4251.030 18.693 214 006917.762 16.489 - 34 124 90 214 Th -a 10694.885 10.661 7692.317 0.050 B- -8790.630 76.867 214 011481.431 11.445 - 32 123 91 214 Pa -a 19485.515 76.125 7647.583 0.356 B- * 214 020918.561 81.723 -0 55 135 80 215 Hg x 16208# 401# 7705# 2# B- 6297# 499# 215 017400# 430# - 53 134 81 215 Tl x 9911# 298# 7730# 1# B- 5569# 303# 215 010640# 320# - 51 133 82 215 Pb +a 4342.244 52.448 7752.737 0.244 B- 2712.922 52.748 215 004661.590 56.304 - 49 132 83 215 Bi 1629.322 5.624 7761.717 0.026 B- 2171.028 5.530 215 001749.149 6.037 - 47 131 84 215 Po -541.706 2.121 7768.176 0.010 B- 714.049 6.819 214 999418.454 2.276 - 45 130 85 215 At -a -1255.756 6.799 7767.858 0.032 B- -87.195 10.168 214 998651.890 7.299 - 43 129 86 215 Rn -a -1168.561 7.672 7763.814 0.036 B- -1486.625 10.306 214 998745.498 8.236 - 41 128 87 215 Fr -a 318.065 7.066 7753.260 0.033 B- -2215.674 10.077 215 000341.456 7.585 - 39 127 88 215 Ra -a 2533.739 7.613 7739.316 0.035 B- -3496.877 14.551 215 002720.080 8.172 - 37 126 89 215 Ac -a 6030.615 12.406 7719.413 0.058 B- -4890.971 15.234 215 006474.132 13.318 - 35 125 90 215 Th -a 10921.586 8.840 7693.025 0.041 B- -6942.353 73.380 215 011724.805 9.490 - 33 124 91 215 Pa -a 17863.939 72.845 7657.096 0.339 B- -7059.147 114.616 215 019177.728 78.202 - 31 123 92 215 U -a 24923.087 88.490 7620.624 0.412 B- * 215 026756.035 94.997 -0 56 136 80 216 Hg x 19859# 401# 7690# 2# B- 5142# 499# 216 021320# 430# - 54 135 81 216 Tl x 14718# 298# 7710# 1# B- 7238# 357# 216 015800# 320# - 52 134 82 216 Pb x 7480# 196# 7740# 1# B- 1606# 196# 216 008030# 210# - 50 133 83 216 Bi x 5873.991 11.178 7743.499 0.052 B- 4091.571 11.324 216 006305.989 12.000 - 48 132 84 216 Po 1782.420 1.816 7758.819 0.008 B- -474.246 3.571 216 001913.506 1.949 - 46 131 85 216 At -a 2256.666 3.575 7753.002 0.017 B- 2003.799 6.836 216 002422.631 3.837 - 44 130 86 216 Rn -a 252.868 5.994 7758.657 0.028 B- -2718.082 7.126 216 000271.464 6.435 - 42 129 87 216 Fr -a 2970.950 4.173 7742.451 0.019 B- -320.128 9.548 216 003189.445 4.480 - 40 128 88 216 Ra -a 3291.077 8.737 7737.347 0.040 B- -4853.317 13.921 216 003533.117 9.379 - 38 127 89 216 Ac -a 8144.395 10.840 7711.256 0.050 B- -2153.937 16.201 216 008743.367 11.637 - 36 126 90 216 Th -a 10298.332 12.042 7697.662 0.056 B- -7500.882 54.864 216 011055.714 12.928 - 34 125 91 216 Pa -a 17799.214 53.526 7659.314 0.248 B- -5267.137 60.450 216 019108.242 57.462 - 32 124 92 216 U -a 23066.351 28.093 7631.307 0.130 B- * 216 024762.747 30.158 -0 55 136 81 217 Tl x 18313# 401# 7695# 2# B- 6073# 499# 217 019660# 430# - 53 135 82 217 Pb x 12240# 298# 7719# 1# B- 3510# 299# 217 013140# 320# - 51 134 83 217 Bi x 8729.962 17.698 7731.848 0.082 B- 2846.444 18.870 217 009372.000 19.000 - 49 133 84 217 Po +a 5883.518 6.544 7741.360 0.030 B- 1488.883 7.979 217 006316.216 7.025 - 47 132 85 217 At 4394.635 5.001 7744.616 0.023 B- 736.135 6.151 217 004717.835 5.369 - 45 131 86 217 Rn -a 3658.501 4.198 7744.403 0.019 B- -656.089 7.538 217 003927.562 4.506 - 43 130 87 217 Fr -a 4314.590 6.531 7737.775 0.030 B- -1575.067 9.588 217 004631.902 7.010 - 41 129 88 217 Ra -a 5889.656 7.202 7726.911 0.033 B- -2814.017 13.430 217 006322.806 7.731 - 39 128 89 217 Ac -a 8703.673 11.389 7710.338 0.052 B- -3502.107 15.566 217 009343.777 12.226 - 37 127 90 217 Th -a 12205.780 10.614 7690.594 0.049 B- -4862.630 19.132 217 013103.444 11.394 - 35 126 91 217 Pa -a 17068.410 15.918 7664.580 0.073 B- -5905# 73# 217 018323.692 17.089 - 33 125 92 217 U -a 22973# 71# 7634# 0# B- * 217 024663# 77# -0 56 137 81 218 Tl x 23180# 400# 7674# 2# B- 7727# 499# 218 024885# 429# - 54 136 82 218 Pb x 15453# 298# 7706# 1# B- 2237# 299# 218 016590# 320# - 52 135 83 218 Bi x 13216.037 27.013 7712.827 0.124 B- 4859.136 27.085 218 014188.000 29.000 - 50 134 84 218 Po 8356.901 1.973 7731.528 0.009 B- 258.738 11.649 218 008971.502 2.118 - 48 133 85 218 At -a 8098.162 11.604 7729.126 0.053 B- 2880.816 11.705 218 008693.735 12.456 - 46 132 86 218 Rn 5217.347 2.316 7738.752 0.011 B- -1841.770 4.942 218 005601.052 2.486 - 44 131 87 218 Fr -a 7059.117 4.757 7726.715 0.022 B- 407.947 12.039 218 007578.274 5.106 - 42 130 88 218 Ra -a 6651.170 11.176 7724.998 0.051 B- -4192.439 51.931 218 007140.325 11.997 - 40 129 89 218 Ac -a 10843.609 50.740 7702.177 0.233 B- -1523.132 51.815 218 011641.093 54.471 - 38 128 90 218 Th -a 12366.741 10.516 7691.602 0.048 B- -6317.029 21.130 218 013276.242 11.289 - 36 127 91 218 Pa -a 18683.770 18.329 7659.036 0.084 B- -3210.838 22.888 218 020057.853 19.676 - 34 126 92 218 U -a 21894.608 13.714 7640.719 0.063 B- * 218 023504.829 14.722 -0 55 137 82 219 Pb x 20279# 401# 7686# 2# B- 3996# 446# 219 021770# 430# - 53 136 83 219 Bi x 16283# 196# 7700# 1# B- 3601# 196# 219 017480# 210# - 51 135 84 219 Po x 12681.359 15.835 7713.333 0.072 B- 2285.283 16.163 219 013614.000 17.000 - 49 134 85 219 At 10396.076 3.237 7720.196 0.015 B- 1566.675 2.947 219 011160.647 3.474 - 47 133 86 219 Rn 8829.402 2.100 7723.777 0.010 B- 211.635 7.058 219 009478.753 2.254 - 45 132 87 219 Fr -a 8617.767 7.039 7721.171 0.032 B- -776.515 10.772 219 009251.553 7.556 - 43 131 88 219 Ra -a 9394.282 8.258 7714.053 0.038 B- -2175.199 51.142 219 010085.176 8.865 - 41 130 89 219 Ac -a 11569.480 50.497 7700.549 0.231 B- -2901.910 71.425 219 012420.348 54.210 - 39 129 90 219 Th -a 14471.390 50.576 7683.725 0.231 B- -4068.741 72.192 219 015535.677 54.295 - 37 128 91 219 Pa -a 18540.131 51.516 7661.574 0.235 B- -4746.439 72.333 219 019903.650 55.304 - 35 127 92 219 U -a 23286.569 50.775 7636.329 0.232 B- -6170.086 101.905 219 024999.161 54.509 - 33 126 93 219 Np -a 29456.655 88.354 7604.583 0.403 B- * 219 031623.021 94.851 -0 56 138 82 220 Pb x 23669# 401# 7672# 2# B- 2850# 499# 220 025410# 430# - 54 137 83 220 Bi x 20819# 298# 7682# 1# B- 5555# 299# 220 022350# 320# - 52 136 84 220 Po x 15263.461 17.698 7703.224 0.080 B- 887.714 22.549 220 016386.000 19.000 - 50 135 85 220 At x 14375.747 13.972 7703.703 0.064 B- 3763.670 14.090 220 015433.000 15.000 - 48 134 86 220 Rn 10612.077 1.815 7717.254 0.008 B- -870.242 4.026 220 011392.534 1.948 - 46 133 87 220 Fr -a 11482.320 4.028 7709.742 0.018 B- 1212.075 9.061 220 012326.778 4.324 - 44 132 88 220 Ra -a 10270.245 8.237 7711.696 0.037 B- -3473.437 10.141 220 011025.562 8.843 - 42 131 89 220 Ac -a 13743.682 6.129 7692.351 0.028 B- -925.417 22.941 220 014754.450 6.579 - 40 130 90 220 Th -a 14669.100 22.166 7684.589 0.101 B- -5549# 56# 220 015747.926 23.795 - 38 129 91 220 Pa -a 20218# 51# 7656# 0# B- -2715# 113# 220 021705# 55# - 36 128 92 220 U -a 22933# 101# 7640# 0# B- -7378# 220# 220 024620# 108# - 34 127 93 220 Np x 30311# 196# 7603# 1# B- * 220 032540# 210# -0 55 138 83 221 Bi x 24098# 298# 7668# 1# B- 4324# 299# 221 025870# 320# - 53 137 84 221 Po x 19773.755 19.561 7684.481 0.089 B- 2991.027 24.039 221 021228.000 21.000 - 51 136 85 221 At x 16782.727 13.972 7694.475 0.063 B- 2311.308 15.096 221 018017.000 15.000 - 49 135 86 221 Rn +a 14471.420 5.714 7701.393 0.026 B- 1194.130 7.231 221 015535.709 6.134 - 47 134 87 221 Fr 13277.290 4.886 7703.256 0.022 B- 313.479 6.386 221 014253.757 5.245 - 45 133 88 221 Ra -a 12963.811 4.630 7701.135 0.021 B- -1559.298 50.603 221 013917.224 4.970 - 43 132 89 221 Ac -a 14523.109 50.425 7690.539 0.228 B- -2417.261 51.056 221 015591.199 54.133 - 41 131 90 221 Th -a 16940.371 8.166 7676.061 0.037 B- -3435.918 51.915 221 018186.236 8.766 - 39 130 91 221 Pa -a 20376.288 51.281 7656.974 0.232 B- -4143.707 72.404 221 021874.846 55.052 - 37 129 92 221 U -a 24519.995 51.114 7634.684 0.231 B- -5330# 207# 221 026323.299 54.873 - 35 128 93 221 Np x 29850# 200# 7607# 1# B- * 221 032045# 215# -0 56 139 83 222 Bi x 28729# 300# 7649# 1# B- 6243# 303# 222 030842# 322# - 54 138 84 222 Po x 22486.265 40.054 7674.005 0.180 B- 1533.239 43.071 222 024140.000 43.000 - 52 137 85 222 At x 20953.026 15.835 7677.387 0.071 B- 4580.820 15.955 222 022494.000 17.000 - 50 136 86 222 Rn 16372.206 1.950 7694.497 0.009 B- -5.900 7.703 222 017576.286 2.093 - 48 135 87 222 Fr x 16378.105 7.452 7690.947 0.034 B- 2057.917 8.682 222 017582.620 8.000 - 46 134 88 222 Ra 14320.188 4.454 7696.692 0.020 B- -2301.285 6.637 222 015373.355 4.781 - 44 133 89 222 Ac -a 16621.474 5.174 7682.802 0.023 B- -581.637 13.228 222 017843.887 5.554 - 42 132 90 222 Th -a 17203.111 12.279 7676.658 0.055 B- -4951# 74# 222 018468.300 13.182 - 40 131 91 222 Pa -a 22155# 72# 7651# 0# B- -2118# 89# 222 023784# 78# - 38 130 92 222 U -a 24272.827 51.994 7637.764 0.234 B- -6746# 202# 222 026057.953 55.817 - 36 129 93 222 Np x 31019# 196# 7604# 1# B- * 222 033300# 210# -0 57 140 83 223 Bi x 32137# 401# 7636# 2# B- 5058# 446# 223 034500# 430# - 55 139 84 223 Po x 27079# 196# 7655# 1# B- 3651# 196# 223 029070# 210# - 53 138 85 223 At x 23428.006 13.972 7668.055 0.063 B- 3038.267 16.013 223 025151.000 15.000 - 51 137 86 223 Rn 20389.739 7.822 7678.171 0.035 B- 2007.344 8.057 223 021889.285 8.397 - 49 136 87 223 Fr 18382.394 1.932 7683.664 0.009 B- 1149.085 0.848 223 019734.313 2.073 - 47 135 88 223 Ra 17233.309 2.090 7685.309 0.009 B- -592.573 7.128 223 018500.719 2.244 - 45 134 89 223 Ac -a 17825.882 7.110 7679.143 0.032 B- -1559.948 11.563 223 019136.872 7.632 - 43 133 90 223 Th -a 19385.831 9.212 7668.640 0.041 B- -2934.845 71.639 223 020811.546 9.889 - 41 132 91 223 Pa -a 22320.676 71.063 7651.971 0.319 B- -3516.330 100.506 223 023962.232 76.289 - 39 131 92 223 U -a 25837.006 71.119 7632.694 0.319 B- -4763# 208# 223 027737.168 76.349 - 37 130 93 223 Np x 30600# 196# 7608# 1# B- * 223 032850# 210# -0 58 141 83 224 Bi x 36830# 400# 7617# 2# B- 6920# 445# 224 039539# 429# - 56 140 84 224 Po x 29910# 196# 7644# 1# B- 2199# 197# 224 032110# 210# - 54 139 85 224 At x 27711.015 22.356 7650.735 0.100 B- 5265.917 24.415 224 029749.000 24.000 - 52 138 86 224 Rn 22445.098 9.814 7670.751 0.044 B- 696.482 14.875 224 024095.804 10.536 - 50 137 87 224 Fr x 21748.616 11.178 7670.367 0.050 B- 2922.699 11.324 224 023348.100 12.000 - 48 136 88 224 Ra 18825.917 1.813 7679.922 0.008 B- -1408.219 4.087 224 020210.453 1.945 - 46 135 89 224 Ac -a 20234.135 4.089 7670.143 0.018 B- 240.401 10.823 224 021722.239 4.389 - 44 134 90 224 Th -a 19993.734 10.120 7667.724 0.045 B- -3868.544 12.546 224 021464.157 10.864 - 42 133 91 224 Pa -a 23862.278 7.587 7646.961 0.034 B- -1859.974 24.329 224 025617.210 8.145 - 40 132 92 224 U -a 25722.252 23.171 7635.165 0.103 B- -6153# 197# 224 027613.974 24.875 - 38 131 93 224 Np x 31876# 196# 7604# 1# B- * 224 034220# 210# -0 57 141 84 225 Po x 34530# 298# 7626# 1# B- 4136# 422# 225 037070# 320# - 55 140 85 225 At x 30395# 298# 7641# 1# B- 3861# 298# 225 032630# 320# - 53 139 86 225 Rn 26534.141 11.140 7654.357 0.050 B- 2713.531 16.349 225 028485.574 11.958 - 51 138 87 225 Fr 23820.610 11.967 7662.940 0.053 B- 1827.501 12.158 225 025572.478 12.847 - 49 137 88 225 Ra 21993.109 2.596 7667.586 0.012 B- 355.763 5.007 225 023610.574 2.787 - 47 136 89 225 Ac 21637.346 4.758 7665.690 0.021 B- -672.781 6.658 225 023228.647 5.107 - 45 135 90 225 Th -a 22310.127 5.093 7659.222 0.023 B- -2030.598 71.170 225 023950.907 5.467 - 43 134 91 225 Pa -a 24340.725 71.012 7646.720 0.316 B- -3039.196 71.827 225 026130.844 76.234 - 41 133 92 225 U -a 27379.921 10.909 7629.736 0.048 B- -4207.783 72.440 225 029393.555 11.711 - 39 132 93 225 Np -a 31587.704 71.622 7607.557 0.318 B- * 225 033910.797 76.889 -0 58 142 84 226 Po x 37549# 401# 7614# 2# B- 2934# 499# 226 040310# 430# - 56 141 85 226 At x 34614# 298# 7624# 1# B- 5867# 298# 226 037160# 320# - 54 140 86 226 Rn 28747.192 10.477 7646.410 0.046 B- 1226.653 12.190 226 030861.382 11.247 - 52 139 87 226 Fr 27520.539 6.230 7648.376 0.028 B- 3852.715 6.523 226 029544.515 6.688 - 50 138 88 226 Ra 23667.824 1.933 7661.962 0.009 B- -641.440 3.274 226 025408.455 2.075 - 48 137 89 226 Ac 24309.264 3.100 7655.662 0.014 B- 1111.630 4.563 226 026097.069 3.328 - 46 136 90 226 Th 23197.634 4.481 7657.119 0.020 B- -2835.642 12.165 226 024903.686 4.810 - 44 135 91 226 Pa -a 26033.276 11.420 7641.110 0.051 B- -1295.593 17.228 226 027947.872 12.259 - 42 134 92 226 U -a 27328.869 12.999 7631.916 0.058 B- -5448# 89# 226 029338.749 13.955 - 40 133 93 226 Np -a 32777# 88# 7604# 0# B- * 226 035188# 95# -0 59 143 84 227 Po x 42281# 401# 7596# 2# B- 4797# 499# 227 045390# 430# - 57 142 85 227 At x 37483# 298# 7613# 1# B- 4597# 298# 227 040240# 320# - 55 141 86 227 Rn 32885.834 14.091 7630.050 0.062 B- 3203.388 15.276 227 035304.396 15.127 - 53 140 87 227 Fr 29682.445 5.898 7640.715 0.026 B- 2504.734 6.213 227 031865.417 6.332 - 51 139 88 227 Ra -n 27177.711 1.952 7648.303 0.009 B- 1328.132 2.265 227 029176.474 2.095 - 49 138 89 227 Ac 25849.580 1.927 7650.707 0.008 B- 44.757 0.830 227 027750.666 2.068 - 47 137 90 227 Th 25804.823 2.088 7647.458 0.009 B- -1026.375 7.437 227 027702.618 2.241 - 45 136 91 227 Pa -a 26831.198 7.420 7639.490 0.033 B- -2214.264 12.146 227 028804.477 7.965 - 43 135 92 227 U -a 29045.462 9.705 7626.289 0.043 B- -3516.618 73.135 227 031181.587 10.419 - 41 134 93 227 Np -a 32562.080 72.506 7607.351 0.319 B- -4208# 123# 227 034956.832 77.838 - 39 133 94 227 Pu x 36770# 100# 7585# 0# B- * 227 039474# 107# -0 58 143 85 228 At x 41684# 401# 7597# 2# B- 6441# 401# 228 044750# 430# - 56 142 86 228 Rn 35243.465 17.677 7621.645 0.078 B- 1859.244 18.916 228 037835.418 18.977 - 54 141 87 228 Fr 33384.221 6.732 7626.368 0.030 B- 4443.953 7.021 228 035839.437 7.226 - 52 140 88 228 Ra +a 28940.268 1.996 7642.428 0.009 B- 45.540 0.634 228 031068.657 2.142 - 50 139 89 228 Ac - 28894.728 2.094 7639.196 0.009 B- 2123.743 2.645 228 031019.767 2.247 - 48 138 90 228 Th 26770.984 1.807 7645.080 0.008 B- -2152.602 4.340 228 028739.835 1.940 - 46 137 91 228 Pa -a 28923.586 4.340 7632.207 0.019 B- -298.640 14.929 228 031050.748 4.659 - 44 136 92 228 U -a 29222.226 14.354 7627.466 0.063 B- -4373.468 52.545 228 031371.351 15.409 - 42 135 93 228 Np -a 33595.694 50.572 7604.853 0.222 B- -2491.677 58.346 228 036066.462 54.291 - 40 134 94 228 Pu -a 36087.370 29.143 7590.493 0.128 B- * 228 038741.387 31.286 -0 59 144 85 229 At x 44823# 401# 7585# 2# B- 5461# 401# 229 048120# 430# - 57 143 86 229 Rn x 39362.400 13.041 7605.622 0.057 B- 3694.138 13.967 229 042257.276 14.000 - 55 142 87 229 Fr 35668.262 5.001 7618.337 0.022 B- 3106.298 16.231 229 038291.455 5.368 - 53 141 88 229 Ra x 32561.963 15.441 7628.485 0.067 B- 1872.030 19.623 229 034956.707 16.576 - 51 140 89 229 Ac x 30689.933 12.109 7633.244 0.053 B- 1104.350 12.346 229 032947.000 13.000 - 49 139 90 229 Th 29585.583 2.405 7634.650 0.011 B- -311.325 3.715 229 031761.431 2.581 - 47 138 91 229 Pa 29896.908 3.280 7629.874 0.014 B- -1313.646 6.655 229 032095.652 3.521 - 45 137 92 229 U -a 31210.554 5.938 7620.721 0.026 B- -2569.122 87.031 229 033505.909 6.374 - 43 136 93 229 Np -a 33779.675 86.848 7606.086 0.379 B- -3615.915 100.792 229 036263.974 93.235 - 41 135 94 229 Pu -a 37395.590 51.176 7586.880 0.223 B- -4754.430 101.230 229 040145.819 54.939 - 39 134 95 229 Am -a 42150.020 87.348 7562.702 0.381 B- * 229 045249.909 93.772 -0 58 144 86 230 Rn x 42048# 196# 7596# 1# B- 2561# 196# 230 045140# 210# - 56 143 87 230 Fr 39486.768 6.541 7603.704 0.028 B- 4970.462 12.198 230 042390.791 7.022 - 54 142 88 230 Ra x 34516.306 10.296 7621.914 0.045 B- 677.924 18.888 230 037054.780 11.053 - 52 141 89 230 Ac x 33838.383 15.835 7621.460 0.069 B- 2975.789 15.882 230 036327.000 17.000 - 50 140 90 230 Th 30862.593 1.210 7630.996 0.005 B- -1311.014 2.833 230 033132.358 1.299 - 48 139 91 230 Pa 32173.607 3.038 7621.895 0.013 B- 558.605 4.592 230 034539.789 3.261 - 46 138 92 230 U -a 31615.002 4.509 7620.922 0.020 B- -3621.290 51.461 230 033940.102 4.841 - 44 137 93 230 Np -a 35236.291 51.288 7601.776 0.223 B- -1698.101 53.363 230 037827.716 55.059 - 42 136 94 230 Pu -a 36934.392 14.824 7590.991 0.064 B- -5998# 134# 230 039650.703 15.913 - 40 135 95 230 Am -a 42932# 133# 7562# 1# B- * 230 046089# 143# -0 59 145 86 231 Rn x 46454# 298# 7579# 1# B- 4373# 298# 231 049870# 320# - 57 144 87 231 Fr x 42080.575 7.731 7594.500 0.033 B- 3864.089 13.749 231 045175.357 8.300 - 55 143 88 231 Ra 38216.486 11.370 7607.841 0.049 B- 2453.636 17.301 231 041027.086 12.206 - 53 142 89 231 Ac x 35762.849 13.041 7615.076 0.056 B- 1946.959 13.098 231 038393.000 14.000 - 51 141 90 231 Th 33815.891 1.218 7620.118 0.005 B- 391.487 1.460 231 036302.853 1.308 - 49 140 91 231 Pa 33424.404 1.772 7618.426 0.008 B- -381.611 2.033 231 035882.575 1.902 - 47 139 92 231 U -a 33806.015 2.670 7613.387 0.012 B- -1818.498 50.577 231 036292.252 2.866 - 45 138 93 231 Np -a 35624.513 50.547 7602.128 0.219 B- -2684.492 55.333 231 038244.490 54.264 - 43 137 94 231 Pu -a 38309.005 22.549 7587.120 0.098 B- -4101# 301# 231 041126.410 24.206 - 41 136 95 231 Am x 42410# 300# 7566# 1# B- -4860# 424# 231 045529# 322# - 39 135 96 231 Cm x 47270# 300# 7542# 1# B- * 231 050746# 322# -0 58 145 87 232 Fr x 46072.834 13.972 7579.347 0.060 B- 5575.880 16.702 232 049461.224 15.000 - 56 144 88 232 Ra 40496.953 9.151 7600.009 0.039 B- 1342.534 15.931 232 043475.270 9.823 - 54 143 89 232 Ac x 39154.419 13.041 7602.424 0.056 B- 3707.635 13.118 232 042034.000 14.000 - 52 142 90 232 Th 35446.784 1.422 7615.033 0.006 B- -499.850 7.734 232 038053.689 1.526 - 50 141 91 232 Pa + 35946.633 7.645 7609.506 0.033 B- 1337.103 7.428 232 038590.300 8.207 - 48 140 92 232 U 34609.530 1.809 7611.897 0.008 B- -2750# 100# 232 037154.860 1.942 - 46 139 93 232 Np - 37360# 100# 7597# 0# B- -1004# 102# 232 040107# 107# - 44 138 94 232 Pu -a 38363.140 17.595 7588.974 0.076 B- -4976# 300# 232 041184.526 18.888 - 42 137 95 232 Am x 43340# 300# 7564# 1# B- -2973# 362# 232 046527# 322# - 40 136 96 232 Cm -a 46312# 202# 7548# 1# B- * 232 049718# 217# -0 59 146 87 233 Fr x 48920.051 19.561 7569.239 0.084 B- 4585.991 21.369 233 052517.838 21.000 - 57 145 88 233 Ra 44334.060 8.603 7585.564 0.037 B- 3026.027 15.623 233 047594.573 9.235 - 55 144 89 233 Ac x 41308.033 13.041 7595.193 0.056 B- 2576.318 13.118 233 044346.000 14.000 - 53 143 90 233 Th 38731.715 1.425 7602.893 0.006 B- 1242.243 1.122 233 041580.208 1.529 - 51 142 91 233 Pa 37489.472 1.336 7604.866 0.006 B- 570.296 1.975 233 040246.605 1.434 - 49 141 92 233 U 36919.176 2.255 7603.956 0.010 B- -1029.415 51.005 233 039634.367 2.420 - 47 140 93 233 Np -a 37948.590 50.981 7596.181 0.219 B- -2103.179 71.642 233 040739.489 54.729 - 45 139 94 233 Pu -a 40051.769 50.351 7583.796 0.216 B- -3211# 113# 233 042997.345 54.054 - 43 138 95 233 Am -a 43263# 102# 7567# 0# B- -4031# 124# 233 046445# 109# - 41 137 96 233 Cm -a 47294.006 71.547 7545.998 0.307 B- -5567# 235# 233 050772.206 76.809 - 39 136 97 233 Bk -a 52861# 224# 7519# 1# B- * 233 056748# 240# -0 58 146 88 234 Ra x 46930.629 8.383 7576.543 0.036 B- 2089.439 16.294 234 050382.104 9.000 - 56 145 89 234 Ac x 44841.190 13.972 7582.129 0.060 B- 4228.181 14.210 234 048139.000 15.000 - 54 144 90 234 Th +a 40613.009 2.589 7596.855 0.011 B- 274.088 3.172 234 043599.860 2.779 - 52 143 91 234 Pa IT 40338.921 4.094 7594.683 0.017 B- 2193.896 4.000 234 043305.615 4.395 - 50 142 92 234 U 38145.025 1.130 7600.715 0.005 B- -1809.846 8.321 234 040950.370 1.213 - 48 141 93 234 Np - 39954.871 8.397 7589.637 0.036 B- -395.100 10.752 234 042893.320 9.014 - 46 140 94 234 Pu -a 40349.971 6.798 7584.605 0.029 B- -4111# 159# 234 043317.478 7.298 - 44 139 95 234 Am -a 44461# 159# 7564# 1# B- -2263# 159# 234 047731# 170# - 42 138 96 234 Cm -a 46724.633 17.394 7550.677 0.074 B- -6731# 143# 234 050160.959 18.673 - 40 137 97 234 Bk -a 53455# 142# 7519# 1# B- * 234 057387# 153# -0 59 147 88 235 Ra x 51130# 300# 7561# 1# B- 3773# 300# 235 054890# 322# - 57 146 89 235 Ac x 47357.155 13.972 7573.504 0.059 B- 3339.406 19.113 235 050840.000 15.000 - 55 145 90 235 Th x 44017.749 13.041 7584.385 0.055 B- 1728.853 19.113 235 047255.000 14.000 - 53 144 91 235 Pa x 42288.896 13.972 7588.413 0.059 B- 1370.050 14.017 235 045399.000 15.000 - 51 143 92 235 U 40918.846 1.117 7590.914 0.005 B- -124.262 0.852 235 043928.190 1.199 - 49 142 93 235 Np 41043.108 1.389 7587.056 0.006 B- -1139.302 20.499 235 044061.591 1.491 - 47 141 94 235 Pu -a 42182.410 20.521 7578.879 0.087 B- -2443.019 56.045 235 045284.682 22.030 - 45 140 95 235 Am -a 44625.429 52.192 7565.154 0.222 B- -3408# 208# 235 047907.371 56.030 - 43 139 96 235 Cm -a 48034# 201# 7547# 1# B- -4670# 448# 235 051567# 216# - 41 138 97 235 Bk x 52704# 401# 7524# 2# B- * 235 056580# 430# -0 58 147 89 236 Ac x 51220.992 38.191 7559.242 0.162 B- 4965.795 40.667 236 054988.000 41.000 - 56 146 90 236 Th x 46255.198 13.972 7576.968 0.059 B- 921.248 19.760 236 049657.000 15.000 - 54 145 91 236 Pa x 45333.950 13.972 7577.557 0.059 B- 2889.306 14.017 236 048668.000 15.000 - 52 144 92 236 U 42444.644 1.113 7586.484 0.005 B- -933.534 50.415 236 045566.201 1.194 - 50 143 93 236 Np IT 43378.178 50.421 7579.214 0.214 B- 476.585 50.389 236 046568.392 54.129 - 48 142 94 236 Pu 42901.593 1.811 7577.918 0.008 B- -3139# 112# 236 046056.756 1.944 - 46 141 95 236 Am -a 46041# 112# 7561# 0# B- -1814# 113# 236 049427# 120# - 44 140 96 236 Cm -a 47855.045 18.315 7550.299 0.078 B- -5687# 401# 236 051374.506 19.662 - 42 139 97 236 Bk x 53542# 401# 7523# 2# B- * 236 057480# 430# -0 59 148 89 237 Ac x 54020# 400# 7550# 2# B- 4065# 400# 237 057993# 429# - 57 147 90 237 Th x 49955.092 15.835 7563.443 0.067 B- 2427.473 20.514 237 053629.000 17.000 - 55 146 91 237 Pa x 47527.619 13.041 7570.384 0.055 B- 2137.425 13.096 237 051023.000 14.000 - 53 145 92 237 U 45390.194 1.203 7576.102 0.005 B- 518.534 0.520 237 048728.380 1.291 - 51 144 93 237 Np 44871.659 1.120 7574.989 0.005 B- -220.063 1.294 237 048171.710 1.202 - 49 143 94 237 Pu 45091.722 1.697 7570.759 0.007 B- -1478# 59# 237 048407.957 1.822 - 47 142 95 237 Am -a 46570# 59# 7561# 0# B- -2677# 93# 237 049995# 64# - 45 141 96 237 Cm -a 49247.085 70.960 7546.624 0.299 B- -3941# 235# 237 052868.923 76.178 - 43 140 97 237 Bk -a 53188# 224# 7527# 1# B- -4751# 241# 237 057100# 241# - 41 139 98 237 Cf -a 57938.921 87.287 7503.347 0.368 B- * 237 062199.993 93.706 -0 58 148 90 238 Th +a 52525# 283# 7555# 1# B- 1631# 284# 238 056388# 304# - 56 147 91 238 Pa x 50894.038 15.835 7558.344 0.067 B- 3586.255 15.906 238 054637.000 17.000 - 54 146 92 238 U 47307.783 1.493 7570.125 0.006 B- -146.874 1.201 238 050786.996 1.602 - 52 145 93 238 Np -n 47454.656 1.138 7566.221 0.005 B- 1291.443 0.457 238 050944.671 1.221 - 50 144 94 238 Pu 46163.213 1.139 7568.360 0.005 B- -2258.273 50.688 238 049558.250 1.222 - 48 143 95 238 Am -a 48421.487 50.700 7555.584 0.213 B- -1023.701 52.145 238 051982.607 54.428 - 46 142 96 238 Cm -a 49445.188 12.234 7547.996 0.051 B- -4771# 255# 238 053081.595 13.133 - 44 141 97 238 Bk -a 54216# 255# 7525# 1# B- -3061# 392# 238 058203# 274# - 42 140 98 238 Cf x 57278# 298# 7509# 1# B- * 238 061490# 320# -0 59 149 90 239 Th x 56450# 400# 7541# 2# B- 3113# 445# 239 060602# 429# - 57 148 91 239 Pa x 53337# 196# 7550# 1# B- 2765# 196# 239 057260# 210# - 55 147 92 239 U -n 50572.718 1.503 7558.561 0.006 B- 1261.661 1.493 239 054292.048 1.613 - 53 146 93 239 Np 49311.057 1.311 7560.567 0.005 B- 722.774 0.930 239 052937.599 1.407 - 51 145 94 239 Pu 48588.282 1.113 7560.318 0.005 B- -802.142 1.664 239 052161.669 1.195 - 49 144 95 239 Am -a 49390.424 1.982 7553.688 0.008 B- -1756.602 54.058 239 053022.803 2.128 - 47 143 96 239 Cm -a 51147.025 54.047 7543.065 0.226 B- -3103# 214# 239 054908.593 58.022 - 45 142 97 239 Bk -a 54250# 207# 7527# 1# B- -4019# 294# 239 058240# 222# - 43 141 98 239 Cf -a 58269# 209# 7507# 1# B- -5287# 364# 239 062554# 224# - 41 140 99 239 Es x 63556# 298# 7481# 1# B- * 239 068230# 320# -0 58 149 91 240 Pa x 56910# 200# 7538# 1# B- 4194# 200# 240 061095# 215# - 56 148 92 240 U 52715.505 2.553 7551.770 0.011 B- 399.233 17.083 240 056592.425 2.740 - 54 147 93 240 Np 52316.272 17.032 7550.173 0.071 B- 2190.891 17.015 240 056163.830 18.284 - 52 146 94 240 Pu 50125.380 1.106 7556.042 0.005 B- -1384.789 13.788 240 053811.812 1.187 - 50 145 95 240 Am +n 51510.169 13.832 7547.013 0.058 B- -214.137 13.897 240 055298.444 14.849 - 48 144 96 240 Cm 51724.306 1.906 7542.861 0.008 B- -3940# 150# 240 055528.329 2.046 - 46 143 97 240 Bk - 55664# 150# 7523# 1# B- -2327# 151# 240 059758# 161# - 44 142 98 240 Cf -a 57990.944 18.700 7510.230 0.078 B- -6208# 401# 240 062255.842 20.075 - 42 141 99 240 Es x 64199# 401# 7481# 2# B- * 240 068920# 430# -0 59 150 91 241 Pa x 59640# 300# 7528# 1# B- 3443# 358# 241 064026# 322# - 57 149 92 241 U x 56197# 196# 7539# 1# B- 1937# 208# 241 060330# 210# - 55 148 93 241 Np + 54260.175 70.719 7544.270 0.293 B- 1305.000 70.711 241 058250.697 75.920 - 53 147 94 241 Pu 52955.175 1.106 7546.439 0.005 B- 20.780 0.166 241 056849.722 1.187 - 51 146 95 241 Am 52934.395 1.114 7543.278 0.005 B- -767.434 1.168 241 056827.413 1.195 - 49 145 96 241 Cm 53701.830 1.608 7536.848 0.007 B- -2330# 200# 241 057651.288 1.726 - 47 144 97 241 Bk - 56032# 200# 7524# 1# B- -3295# 260# 241 060153# 215# - 45 143 98 241 Cf -a 59327# 166# 7507# 1# B- -4537# 280# 241 063690# 178# - 43 142 99 241 Es -a 63863# 225# 7485# 1# B- -5263# 374# 241 068560# 242# - 41 141 100 241 Fm x 69126# 298# 7460# 1# B- * 241 074210# 320# -0 58 150 92 242 U +a 58620# 201# 7532# 1# B- 1203# 283# 242 062931# 215# - 56 149 93 242 Np + 57416.932 200.004 7533.403 0.826 B- 2700.000 200.000 242 061639.615 214.713 - 54 148 94 242 Pu 54716.932 1.245 7541.327 0.005 B- -751.140 0.708 242 058741.045 1.336 - 52 147 95 242 Am -n 55468.072 1.119 7534.991 0.005 B- 664.309 0.414 242 059547.428 1.200 - 50 146 96 242 Cm 54803.764 1.142 7534.503 0.005 B- -2930# 200# 242 058834.263 1.225 - 48 145 97 242 Bk - 57734# 200# 7519# 1# B- -1653# 200# 242 061980# 215# - 46 144 98 242 Cf -a 59386.966 12.892 7509.098 0.053 B- -5414# 256# 242 063754.533 13.840 - 44 143 99 242 Es -a 64801# 256# 7483# 1# B- -3598# 475# 242 069567# 275# - 42 142 100 242 Fm x 68400# 401# 7465# 2# B- * 242 073430# 430# -0 59 151 92 243 U x 62360# 300# 7518# 1# B- 2484# 302# 243 066946# 322# - 57 150 93 243 Np IT 59876# 32# 7525# 0# B- 2121# 32# 243 064279# 34# - 55 149 94 243 Pu 57754.602 2.542 7531.008 0.010 B- 579.556 2.622 243 062002.119 2.728 - 53 148 95 243 Am 57175.046 1.388 7530.173 0.006 B- -6.952 1.569 243 061379.940 1.490 - 51 147 96 243 Cm -a 57181.998 1.496 7526.925 0.006 B- -1507.695 4.506 243 061387.403 1.606 - 49 146 97 243 Bk -a 58689.693 4.524 7517.501 0.019 B- -2300# 114# 243 063005.980 4.857 - 47 145 98 243 Cf -a 60990# 114# 7505# 0# B- -3757# 236# 243 065475# 123# - 45 144 99 243 Es -a 64747# 207# 7486# 1# B- -4640# 298# 243 069509# 222# - 43 143 100 243 Fm -a 69387# 215# 7464# 1# B- * 243 074490# 231# -0 58 151 93 244 Np x 63202# 298# 7514# 1# B- 3396# 298# 244 067850# 320# - 56 150 94 244 Pu 59806.028 2.346 7524.815 0.010 B- -73.168 2.686 244 064204.415 2.518 - 54 149 95 244 Am + 59879.196 1.492 7521.308 0.006 B- 1427.300 1.000 244 064282.964 1.601 - 52 148 96 244 Cm -a 58451.896 1.107 7523.952 0.005 B- -2261.989 14.357 244 062750.694 1.188 - 50 147 97 244 Bk -a 60713.885 14.399 7511.475 0.059 B- -764.294 14.572 244 065179.039 15.457 - 48 146 98 244 Cf 61478.179 2.618 7505.136 0.011 B- -4547# 181# 244 065999.543 2.810 - 46 145 99 244 Es -a 66026# 181# 7483# 1# B- -2940# 271# 244 070881# 195# - 44 144 100 244 Fm -a 68966# 201# 7468# 1# B- * 244 074038# 216# -0 59 152 93 245 Np x 65890# 300# 7505# 1# B- 2712# 300# 245 070736# 322# - 57 151 94 245 Pu -n 63178.179 13.620 7513.281 0.056 B- 1277.710 13.733 245 067824.568 14.621 - 55 150 95 245 Am +a 61900.469 1.887 7515.303 0.008 B- 895.889 1.549 245 066452.890 2.025 - 53 149 96 245 Cm 61004.580 1.150 7515.767 0.005 B- -809.256 1.496 245 065491.113 1.234 - 51 148 97 245 Bk -a 61813.836 1.793 7509.270 0.007 B- -1571.374 2.586 245 066359.885 1.924 - 49 147 98 245 Cf 63385.210 2.428 7499.663 0.010 B- -2981# 200# 245 068046.825 2.606 - 47 146 99 245 Es -a 66366# 200# 7484# 1# B- -3821# 279# 245 071247# 215# - 45 145 100 245 Fm -a 70187# 195# 7466# 1# B- -5085# 362# 245 075349# 209# - 43 144 101 245 Md -a 75272# 305# 7442# 1# B- * 245 080808# 328# -0 58 152 94 246 Pu 65394.801 14.985 7506.539 0.061 B- 401# 14# 246 070204.209 16.087 - 56 151 95 246 Am IT 64994# 18# 7505# 0# B- 2377# 18# 246 069774# 19# - 54 150 96 246 Cm 62616.967 1.526 7511.471 0.006 B- -1350.000 60.000 246 067222.082 1.638 - 52 149 97 246 Bk - 63966.967 60.019 7502.803 0.244 B- -123.325 60.020 246 068671.367 64.433 - 50 148 98 246 Cf 64090.292 1.515 7499.121 0.006 B- -3810# 224# 246 068803.762 1.626 - 48 147 99 246 Es -a 67901# 224# 7480# 1# B- -2288# 224# 246 072894# 240# - 46 146 100 246 Fm -a 70188.833 15.333 7467.970 0.062 B- -5926# 260# 246 075350.815 16.460 - 44 145 101 246 Md -a 76115# 259# 7441# 1# B- * 246 081713# 278# -0 59 153 94 247 Pu x 69108# 196# 7494# 1# B- 1954# 220# 247 074190# 210# - 57 152 95 247 Am + 67153# 100# 7499# 0# B- 1620# 100# 247 072092# 107# - 55 151 96 247 Cm 65533.143 3.797 7501.931 0.015 B- 43.581 6.324 247 070352.726 4.076 - 53 150 97 247 Bk -a 65489.562 5.189 7498.940 0.021 B- -614.341 16.188 247 070305.940 5.570 - 51 149 98 247 Cf +a 66103.903 15.334 7493.285 0.062 B- -2474.485 24.760 247 070965.462 16.461 - 49 148 99 247 Es +a 68578.388 19.441 7480.100 0.079 B- -3094# 116# 247 073621.932 20.870 - 47 147 100 247 Fm +a 71673# 115# 7464# 0# B- -4264# 237# 247 076944# 123# - 45 146 101 247 Md -a 75937# 207# 7444# 1# B- * 247 081521# 222# -0 58 153 95 248 Am + 70563# 200# 7487# 1# B- 3170# 200# 248 075752# 215# - 56 152 96 248 Cm 67392.755 2.358 7496.728 0.010 B- -687# 71# 248 072349.101 2.531 - 54 151 97 248 Bk IT 68080# 71# 7491# 0# B- 842# 71# 248 073087# 76# - 52 150 98 248 Cf -a 67238.012 5.121 7491.043 0.021 B- -3061# 53# 248 072182.978 5.497 - 50 149 99 248 Es -a 70299# 52# 7476# 0# B- -1599# 53# 248 075469# 56# - 48 148 100 248 Fm 71897.857 8.497 7465.944 0.034 B- -5250# 238# 248 077185.528 9.122 - 46 147 101 248 Md -a 77148# 237# 7442# 1# B- -3473# 327# 248 082822# 255# - 44 146 102 248 No -a 80621# 224# 7424# 1# B- * 248 086550# 241# -0 59 154 95 249 Am x 73104# 298# 7479# 1# B- 2353# 298# 249 078480# 320# - 57 153 96 249 Cm -n 70750.702 2.371 7485.550 0.010 B- 904.317 2.594 249 075954.006 2.545 - 55 152 97 249 Bk + 69846.384 1.249 7486.040 0.005 B- 123.600 0.400 249 074983.182 1.340 - 53 151 98 249 Cf 69722.784 1.183 7483.394 0.005 B- -1452# 30# 249 074850.491 1.270 - 51 150 99 249 Es -a 71175# 30# 7474# 0# B- -2344# 31# 249 076409# 32# - 49 149 100 249 Fm 73519.188 6.212 7461.864 0.025 B- -3713# 201# 249 078926.098 6.668 - 47 148 101 249 Md -a 77232# 201# 7444# 1# B- -4550# 344# 249 082912# 216# - 45 147 102 249 No -a 81782# 279# 7422# 1# B- * 249 087797# 300# -0 58 154 96 250 Cm -nn 72989.594 10.274 7478.938 0.041 B- 39.616 10.894 250 078357.556 11.029 - 56 153 97 250 Bk +a 72949.978 3.719 7475.967 0.015 B- 1779.587 3.386 250 078315.027 3.992 - 54 152 98 250 Cf -a 71170.391 1.538 7479.956 0.006 B- -2055# 100# 250 076404.561 1.651 - 52 151 99 250 Es - 73225# 100# 7469# 0# B- -847# 100# 250 078611# 107# - 50 150 100 250 Fm 74072.243 7.888 7462.090 0.032 B- -4558# 301# 250 079519.828 8.468 - 48 149 101 250 Md -a 78630# 301# 7441# 1# B- -2933# 362# 250 084413# 323# - 46 148 102 250 No -a 81564# 201# 7426# 1# B- * 250 087562# 215# -0 59 155 96 251 Cm + 76648.018 22.698 7466.722 0.090 B- 1420.000 20.000 251 082285.036 24.367 - 57 154 97 251 Bk + 75228.018 10.734 7469.263 0.043 B- 1093.000 10.000 251 080760.603 11.523 - 55 153 98 251 Cf -a 74135.018 3.901 7470.500 0.016 B- -377.259 7.057 251 079587.219 4.187 - 53 152 99 251 Es -a 74512.277 5.994 7465.881 0.024 B- -1441.641 16.342 251 079992.224 6.434 - 51 151 100 251 Fm +a 75953.919 15.203 7457.020 0.061 B- -3012.825 24.271 251 081539.889 16.320 - 49 150 101 251 Md +a 78966.744 18.919 7441.900 0.075 B- -3882# 116# 251 084774.291 20.310 - 47 149 102 251 No IT 82849# 114# 7423# 0# B- -4879# 319# 251 088942# 123# - 45 148 103 251 Lr x 87728# 298# 7401# 1# B- * 251 094180# 320# -0 60 156 96 252 Cm x 79056# 298# 7460# 1# B- 521# 359# 252 084870# 320# - 58 155 97 252 Bk + 78535# 200# 7459# 1# B- 2500# 200# 252 084310# 215# - 56 154 98 252 Cf -a 76034.617 2.358 7465.347 0.009 B- -1260.000 50.000 252 081626.523 2.531 - 54 153 99 252 Es - 77294.617 50.056 7457.242 0.199 B- 478.990 50.351 252 082979.189 53.736 - 52 152 100 252 Fm -a 76815.627 5.498 7456.038 0.022 B- -3695# 130# 252 082464.972 5.902 - 50 151 101 252 Md IT 80510# 130# 7438# 1# B- -2361# 131# 252 086432# 140# - 48 150 102 252 No 82871.427 9.292 7425.798 0.037 B- -5866# 238# 252 088966.141 9.975 - 46 149 103 252 Lr -a 88737# 238# 7399# 1# B- * 252 095263# 255# -0 59 156 97 253 Bk -a 80929# 359# 7451# 1# B- 1627# 359# 253 086880# 385# - 57 155 98 253 Cf -a 79301.567 4.257 7454.829 0.017 B- 291.030 4.385 253 085133.738 4.570 - 55 154 99 253 Es -a 79010.538 1.250 7452.887 0.005 B- -335.202 2.713 253 084821.305 1.341 - 53 153 100 253 Fm -a 79345.740 2.932 7448.470 0.012 B- -1827# 31# 253 085181.160 3.148 - 51 152 101 253 Md -a 81173# 31# 7438# 0# B- -3186# 32# 253 087143# 34# - 49 151 102 253 No 84358.735 6.912 7422.471 0.027 B- -4217# 202# 253 090562.831 7.420 - 47 150 103 253 Lr -a 88575# 202# 7403# 1# B- -4982# 457# 253 095089# 217# - 45 149 104 253 Rf -a 93557# 410# 7380# 2# B- * 253 100438# 440# -0 60 157 97 254 Bk x 84393# 298# 7440# 1# B- 3052# 298# 254 090600# 320# - 58 156 98 254 Cf -a 81341.401 11.462 7449.225 0.045 B- -649.193 12.113 254 087323.590 12.304 - 56 155 99 254 Es -a 81990.594 4.010 7443.589 0.016 B- 1087.800 3.202 254 088020.527 4.304 - 54 154 100 254 Fm -a 80902.794 2.414 7444.792 0.010 B- -2550# 100# 254 086852.726 2.591 - 52 153 101 254 Md - 83453# 100# 7432# 0# B- -1271# 100# 254 089590# 107# - 50 152 102 254 No 84723.347 9.658 7423.590 0.038 B- -5148# 301# 254 090954.259 10.367 - 48 151 103 254 Lr -a 89871# 301# 7400# 1# B- -3327# 414# 254 096481# 323# - 46 150 104 254 Rf -a 93199# 283# 7384# 1# B- * 254 100053# 304# -0 59 157 98 255 Cf + 84809# 200# 7438# 1# B- 720# 200# 255 091047# 215# - 57 156 99 255 Es -a 84089.274 10.817 7437.821 0.042 B- 289.620 10.247 255 090273.553 11.612 - 55 155 100 255 Fm -a 83799.654 4.291 7435.888 0.017 B- -1043.416 7.747 255 089962.633 4.607 - 53 154 101 255 Md -a 84843.070 6.553 7428.729 0.026 B- -1964.164 16.281 255 091082.787 7.035 - 51 153 102 255 No x 86807.234 14.904 7417.958 0.058 B- -3140.066 23.138 255 093191.404 16.000 - 49 152 103 255 Lr x 89947.300 17.698 7402.576 0.069 B- -4382# 116# 255 096562.404 19.000 - 47 151 104 255 Rf -a 94330# 115# 7382# 0# B- -5263# 377# 255 101267# 123# - 45 150 105 255 Db -a 99593# 359# 7359# 1# B- * 255 106918# 385# -0 60 158 98 256 Cf -a 87041# 314# 7432# 1# B- -146# 330# 256 093442# 338# - 58 157 99 256 Es + 87187# 100# 7428# 0# B- 1700# 100# 256 093599# 108# - 56 156 100 256 Fm -a 85486.817 5.600 7431.780 0.022 B- -1969# 123# 256 091773.878 6.012 - 54 155 101 256 Md IT 87456# 122# 7421# 0# B- -366# 123# 256 093888# 132# - 52 154 102 256 No -a 87822.062 7.743 7416.546 0.030 B- -3924.536 83.264 256 094280.866 8.312 - 50 153 103 256 Lr x 91746.598 82.903 7398.160 0.324 B- -2475.451 84.802 256 098494.029 89.000 - 48 152 104 256 Rf -a 94222.049 17.848 7385.434 0.070 B- -6276# 241# 256 101151.535 19.160 - 46 151 105 256 Db -a 100498# 240# 7358# 1# B- * 256 107889# 258# -0 59 158 99 257 Es -a 89403# 411# 7422# 2# B- 813# 411# 257 095979# 441# - 57 157 100 257 Fm -a 88590.033 4.486 7422.194 0.017 B- -403.020 4.715 257 095105.317 4.815 - 55 156 101 257 Md -a 88993.053 1.601 7417.582 0.006 B- -1254.202 6.661 257 095537.977 1.718 - 53 155 102 257 No -a 90247.256 6.678 7409.657 0.026 B- -2418# 45# 257 096884.419 7.169 - 51 154 103 257 Lr -a 92665# 44# 7397# 0# B- -3201# 45# 257 099480# 47# - 49 153 104 257 Rf -a 95866.427 10.817 7381.704 0.042 B- -4340# 203# 257 102916.848 11.612 - 47 152 105 257 Db -a 100207# 203# 7362# 1# B- * 257 107576# 218# -0 60 159 99 258 Es x 92702# 401# 7412# 2# B- 2276# 448# 258 099520# 430# - 58 158 100 258 Fm -a 90426# 200# 7418# 1# B- -1260# 200# 258 097077# 215# - 56 157 101 258 Md -a 91686.792 4.419 7409.675 0.017 B- 209# 100# 258 098429.825 4.743 - 54 156 102 258 No -a 91478# 100# 7407# 0# B- -3304# 143# 258 098205# 107# - 52 155 103 258 Lr -a 94782# 102# 7392# 0# B- -1559# 107# 258 101753# 109# - 50 154 104 258 Rf -a 96341.036 31.967 7382.538 0.124 B- -5456# 307# 258 103426.362 34.317 - 48 153 105 258 Db -a 101797# 305# 7358# 1# B- -3447# 513# 258 109284# 328# - 46 152 106 258 Sg -a 105244# 413# 7342# 2# B- * 258 112984# 443# -0 59 159 100 259 Fm -a 93704# 283# 7407# 1# B- 80# 346# 259 100596# 304# - 57 158 101 259 Md -a 93624# 200# 7405# 1# B- -454# 200# 259 100510# 215# - 55 157 102 259 No -a 94078.569 6.589 7399.974 0.025 B- -1773# 71# 259 100997.503 7.073 - 53 156 103 259 Lr -a 95852# 71# 7390# 0# B- -2510# 101# 259 102901# 76# - 51 155 104 259 Rf -a 98362# 72# 7377# 0# B- -3629# 90# 259 105596# 78# - 49 154 105 259 Db -a 101991.016 53.040 7360.362 0.205 B- -4529# 126# 259 109491.865 56.940 - 47 153 106 259 Sg -a 106520# 115# 7340# 0# B- * 259 114353# 123# -0 60 160 100 260 Fm -a 95766# 435# 7402# 2# B- -786# 537# 260 102809# 467# - 58 159 101 260 Md -a 96552# 316# 7396# 1# B- 940# 374# 260 103653# 340# - 56 158 102 260 No -a 95612# 200# 7397# 1# B- -2665# 235# 260 102643# 215# - 54 157 103 260 Lr -a 98277# 124# 7383# 0# B- -870# 236# 260 105504# 133# - 52 156 104 260 Rf -a 99147# 200# 7377# 1# B- -4526# 221# 260 106439# 215# - 50 155 105 260 Db -a 103673# 93# 7357# 0# B- -2875# 95# 260 111297# 100# - 48 154 106 260 Sg -a 106547.552 20.536 7342.562 0.079 B- -6776# 246# 260 114383.508 22.045 - 46 153 107 260 Bh -a 113323# 245# 7313# 1# B- * 260 121658# 263# -0 59 160 101 261 Md -a 98578# 509# 7391# 2# B- 123# 547# 261 105828# 546# - 57 159 102 261 No -a 98455# 200# 7388# 1# B- -1103# 283# 261 105696# 215# - 55 158 103 261 Lr -a 99558# 200# 7381# 1# B- -1761# 206# 261 106880# 215# - 53 157 104 261 Rf -a 101318.594 50.444 7371.384 0.193 B- -2990# 121# 261 108769.990 54.153 - 51 156 105 261 Db -a 104308# 110# 7357# 0# B- -3697# 112# 261 111980# 118# - 49 155 106 261 Sg -a 108005.043 18.494 7339.770 0.071 B- -5128# 210# 261 115948.188 19.853 - 47 154 107 261 Bh -a 113133# 209# 7317# 1# B- * 261 121454# 224# -0 60 161 101 262 Md -a 101627# 500# 7382# 2# B- 1526# 617# 262 109101# 537# - 58 160 102 262 No -a 100101# 361# 7385# 1# B- -2000# 412# 262 107463# 387# - 56 159 103 262 Lr -a 102102# 200# 7374# 1# B- -291# 300# 262 109611# 215# - 54 158 104 262 Rf -a 102393# 224# 7370# 1# B- -3861# 265# 262 109923# 240# - 52 157 105 262 Db -a 106253# 143# 7352# 1# B- -2112# 147# 262 114068# 154# - 50 156 106 262 Sg -a 108365.771 35.411 7341.185 0.135 B- -6176# 308# 262 116335.446 38.015 - 48 155 107 262 Bh -a 114541# 306# 7315# 1# B- * 262 122965# 328# -0 59 161 102 263 No -a 103129# 490# 7376# 2# B- -600# 566# 263 110714# 526# - 57 160 103 263 Lr -a 103729# 283# 7371# 1# B- -1027# 322# 263 111358# 304# - 55 159 104 263 Rf -a 104756# 153# 7364# 1# B- -2355# 227# 263 112460# 164# - 53 158 105 263 Db -a 107111# 168# 7352# 1# B- -3079# 193# 263 114988# 181# - 51 157 106 263 Sg -a 110190# 95# 7337# 0# B- -4306# 319# 263 118294# 102# - 49 156 107 263 Bh -a 114496# 305# 7318# 1# B- -5182# 329# 263 122916# 327# - 47 155 108 263 Hs -a 119678# 125# 7295# 0# B- * 263 128480# 134# -0 60 162 102 264 No -a 105011# 591# 7371# 2# B- -1366# 734# 264 112734# 634# - 58 161 103 264 Lr -a 106377# 436# 7363# 2# B- 300# 566# 264 114200# 468# - 56 160 104 264 Rf -a 106077# 361# 7361# 1# B- -3285# 431# 264 113878# 387# - 54 159 105 264 Db -a 109362# 235# 7346# 1# B- -1420# 368# 264 117405# 253# - 52 158 106 264 Sg -a 110782# 283# 7338# 1# B- -5276# 334# 264 118929# 304# - 50 157 107 264 Bh -a 116058# 177# 7315# 1# B- -3506# 180# 264 124593# 190# - 48 156 108 264 Hs -a 119563.222 28.881 7298.375 0.109 B- * 264 128356.405 31.005 -0 59 162 103 265 Lr -a 108233# 547# 7359# 2# B- -457# 655# 265 116193# 587# - 57 161 104 265 Rf -a 108690# 361# 7354# 1# B- -1793# 424# 265 116683# 387# - 55 160 105 265 Db -a 110483# 224# 7344# 1# B- -2312# 255# 265 118608# 240# - 53 159 106 265 Sg -a 112794# 123# 7333# 0# B- -3621# 264# 265 121090# 132# - 51 158 107 265 Bh -a 116415# 234# 7316# 1# B- -4485# 235# 265 124977# 251# - 49 157 108 265 Hs -a 120900.283 23.958 7296.247 0.090 B- -5778# 452# 265 129791.799 25.719 - 47 156 109 265 Mt -a 126678# 451# 7271# 2# B- * 265 135995# 484# -0 60 163 103 266 Lr -a 111622# 583# 7349# 2# B- 1546# 749# 266 119831# 626# - 58 162 104 266 Rf -a 110076# 469# 7352# 2# B- -2660# 548# 266 118172# 504# - 56 161 105 266 Db -a 112737# 283# 7339# 1# B- -881# 374# 266 121028# 304# - 54 160 106 266 Sg -a 113618# 245# 7332# 1# B- -4487# 294# 266 121973# 263# - 52 159 107 266 Bh -a 118104# 163# 7313# 1# B- -3032# 167# 266 126790# 175# - 50 158 108 266 Hs -a 121136.373 38.695 7298.273 0.145 B- -6826# 309# 266 130045.252 41.540 - 48 157 109 266 Mt -a 127962# 307# 7270# 1# B- * 266 137373# 329# -0 59 163 104 267 Rf -a 113444# 575# 7342# 2# B- -630# 707# 267 121787# 617# - 57 162 105 267 Db -a 114074# 412# 7336# 2# B- -1732# 486# 267 122464# 443# - 55 161 106 267 Sg -a 115806# 257# 7327# 1# B- -2960# 367# 267 124322# 276# - 53 160 107 267 Bh -a 118766# 263# 7313# 1# B- -3887# 279# 267 127500# 282# - 51 159 108 267 Hs -a 122653# 96# 7295# 0# B- -5138# 512# 267 131673# 103# - 49 158 109 267 Mt -a 127791# 503# 7273# 2# B- -6089# 521# 267 137189# 540# - 47 157 110 267 Ds -a 133880# 135# 7248# 1# B- * 267 143726# 145# -0 60 164 104 268 Rf -a 115476# 662# 7337# 2# B- -1586# 848# 268 123968# 711# - 58 163 105 268 Db -a 117062# 529# 7328# 2# B- 260# 707# 268 125671# 568# - 56 162 106 268 Sg -a 116802# 469# 7326# 2# B- -4005# 605# 268 125392# 504# - 54 161 107 268 Bh -a 120807# 381# 7308# 1# B- -2023# 475# 268 129691# 409# - 52 160 108 268 Hs -a 122830# 283# 7298# 1# B- -6321# 367# 268 131863# 304# - 50 159 109 268 Mt -a 129151# 233# 7271# 1# B- -4497# 381# 268 138649# 250# - 48 158 110 268 Ds -a 133648# 301# 7252# 1# B- * 268 143477# 324# -0 59 164 105 269 Db -a 119148# 624# 7323# 2# B- -614# 722# 269 127911# 669# - 57 163 106 269 Sg -a 119763# 364# 7318# 1# B- -1715# 522# 269 128570# 391# - 55 162 107 269 Bh -a 121478# 374# 7309# 1# B- -3086# 394# 269 130412# 402# - 53 161 108 269 Hs -a 124564# 124# 7294# 0# B- -4806# 480# 269 133725# 133# - 51 160 109 269 Mt -a 129370# 463# 7273# 2# B- -5465# 464# 269 138884# 497# - 49 159 110 269 Ds -a 134834.709 31.403 7250.154 0.117 B- * 269 144751.021 33.712 -0 60 165 105 270 Db -a 122307# 617# 7314# 2# B- 816# 831# 270 131302# 662# - 58 164 106 270 Sg -a 121491# 557# 7314# 2# B- -2735# 627# 270 130426# 598# - 56 163 107 270 Bh -a 124226# 287# 7301# 1# B- -886# 379# 270 133362# 308# - 54 162 108 270 Hs -a 125112# 248# 7295# 1# B- -5598# 301# 270 134314# 266# - 52 161 109 270 Mt -a 130710# 170# 7271# 1# B- -3968# 177# 270 140323# 183# - 50 160 110 270 Ds -a 134678.282 48.011 7253.775 0.178 B- * 270 144583.090 51.542 -0 59 165 106 271 Sg -a 124757# 585# 7305# 2# B- -1164# 718# 271 133932# 628# - 57 164 107 271 Bh -a 125921# 415# 7298# 2# B- -1819# 501# 271 135182# 446# - 55 163 108 271 Hs -a 127740# 280# 7288# 1# B- -3361# 433# 271 137135# 301# - 53 162 109 271 Mt -a 131101# 330# 7273# 1# B- -4847# 344# 271 140742# 354# - 51 161 110 271 Ds -a 135948# 97# 7252# 0# B- * 271 145946# 104# -0 60 166 106 272 Sg -a 126580# 727# 7301# 3# B- -2209# 901# 272 135890# 781# - 58 165 107 272 Bh -a 128789# 532# 7290# 2# B- -217# 737# 272 138261# 571# - 56 164 108 272 Hs -a 129006# 510# 7286# 2# B- -4575# 704# 272 138494# 547# - 54 163 109 272 Mt -a 133581# 485# 7267# 2# B- -2433# 637# 272 143406# 521# - 52 162 110 272 Ds -a 136015# 413# 7255# 2# B- -6758# 474# 272 146018# 443# - 50 161 111 272 Rg -a 142773# 233# 7227# 1# B- * 272 153273# 251# -0 61 167 106 273 Sg x 130018# 503# 7291# 2# B- -615# 855# 273 139580# 540# - 59 166 107 273 Bh -a 130633# 692# 7286# 3# B- -1257# 783# 273 140240# 743# - 57 165 108 273 Hs -a 131890# 367# 7279# 1# B- -2822# 561# 273 141590# 394# - 55 164 109 273 Mt -a 134713# 424# 7265# 2# B- -3643# 445# 273 144620# 455# - 53 163 110 273 Ds -a 138356# 134# 7249# 0# B- -4339# 543# 273 148531# 144# - 51 162 111 273 Rg -a 142695# 526# 7231# 2# B- * 273 153189# 565# -0 60 167 107 274 Bh -a 133682# 619# 7278# 2# B- 196# 856# 274 143513# 664# - 58 166 108 274 Hs -a 133486# 592# 7276# 2# B- -3760# 689# 274 143303# 635# - 56 165 109 274 Mt -a 137246# 354# 7259# 1# B- -1952# 526# 274 147339# 380# - 54 164 110 274 Ds -a 139197# 389# 7249# 1# B- -5416# 428# 274 149434# 418# - 52 163 111 274 Rg -a 144613# 177# 7227# 1# B- * 274 155249# 190# -0 61 168 107 275 Bh x 135691# 596# 7273# 2# B- -929# 837# 275 145670# 640# - 59 167 108 275 Hs -a 136620# 587# 7267# 2# B- -2209# 721# 275 146667# 631# - 57 166 109 275 Mt -a 138829# 418# 7256# 2# B- -2736# 586# 275 149039# 449# - 55 165 110 275 Ds -a 141565# 410# 7244# 1# B- -3731# 661# 275 151976# 441# - 53 164 111 275 Rg -a 145296# 519# 7227# 2# B- * 275 155981# 557# -0 60 168 108 276 Hs -a 138285# 754# 7264# 3# B- -3029# 923# 276 148455# 810# - 58 167 109 276 Mt -a 141315# 532# 7250# 2# B- -1227# 763# 276 151708# 571# - 56 166 110 276 Ds -a 142541# 548# 7243# 2# B- -4945# 834# 276 153024# 588# - 54 165 111 276 Rg -a 147486# 629# 7222# 2# B- -2866# 866# 276 158333# 675# - 52 164 112 276 Cn x 150352# 596# 7209# 2# B- * 276 161410# 640# -0 61 169 108 277 Hs -a 141493# 541# 7255# 2# B- -1475# 884# 277 151899# 581# - 59 168 109 277 Mt -a 142968# 699# 7247# 3# B- -2172# 798# 277 153483# 751# - 57 167 110 277 Ds -a 145140# 384# 7237# 1# B- -3197# 646# 277 155815# 412# - 55 166 111 277 Rg -a 148338# 520# 7222# 2# B- -4065# 539# 277 159247# 558# - 53 165 112 277 Cn -a 152403# 143# 7205# 1# B- * 277 163611# 153# -0 60 169 109 278 Mt -a 145736# 621# 7240# 2# B- -645# 881# 278 156454# 666# - 58 168 110 278 Ds -a 146381# 625# 7235# 2# B- -4136# 719# 278 157146# 671# - 56 167 111 278 Rg -a 150517# 357# 7218# 1# B- -2415# 565# 278 161587# 383# - 54 166 112 278 Cn -a 152932# 438# 7206# 2# B- -5957# 475# 278 164179# 470# - 52 165 113 278 Ed -a 158889# 184# 7182# 1# B- * 278 170574# 198# -0 61 170 109 279 Mt -a 147496# 667# 7237# 2# B- -1630# 896# 279 158343# 716# - 59 169 110 279 Ds -a 149126# 598# 7228# 2# B- -2649# 731# 279 160093# 642# - 57 168 111 279 Rg -a 151775# 421# 7216# 2# B- -3255# 621# 279 162937# 452# - 55 167 112 279 Cn -a 155030# 456# 7202# 2# B- -4209# 835# 279 166432# 490# - 53 166 113 279 Ed x 159239# 699# 7184# 3# B- * 279 170950# 750# -0 60 170 110 280 Ds -a 150520# 780# 7226# 3# B- -3366# 944# 280 161590# 838# - 58 169 111 280 Rg -a 153886# 532# 7212# 2# B- -1810# 789# 280 165203# 571# - 56 168 112 280 Cn -a 155696# 583# 7202# 2# B- -5444# 707# 280 167147# 626# - 54 167 113 280 Ed x 161140# 400# 7180# 1# B- * 280 172991# 429# -0 61 171 110 281 Ds -a 153431# 579# 7219# 2# B- -1866# 992# 281 164715# 622# - 59 170 111 281 Rg -a 155297# 806# 7210# 3# B- -2722# 894# 281 166718# 865# - 57 169 112 281 Cn -a 158019# 387# 7197# 1# B- -3790# 490# 281 169641# 416# - 55 168 113 281 Ed x 161810# 300# 7181# 1# B- * 281 173710# 322# -0 60 171 111 282 Rg -a 157800# 654# 7204# 2# B- -1176# 926# 282 169405# 702# - 58 170 112 282 Cn -a 158976# 656# 7197# 2# B- -4749# 748# 282 170668# 704# - 56 169 113 282 Ed -a 163725# 361# 7177# 1# B- * 282 175766# 387# -0 61 172 111 283 Rg -a 159281# 697# 7202# 2# B- -2205# 925# 283 170995# 748# - 59 171 112 283 Cn -a 161486# 608# 7191# 2# B- -3221# 748# 283 173362# 653# - 57 170 113 283 Ed -a 164707# 436# 7177# 2# B- * 283 176820# 468# -0 60 172 112 284 Cn -a 162545# 806# 7190# 3# B- -4046# 966# 284 174499# 865# - 58 171 113 284 Ed -a 166591# 534# 7173# 2# B- -2330# 846# 284 178843# 573# - 56 170 114 284 Fl -a 168921# 656# 7162# 2# B- * 284 181344# 704# -0 61 173 112 285 Cn -a 165173# 581# 7184# 2# B- -2557# 995# 285 177321# 624# - 59 172 113 285 Ed -a 167731# 807# 7173# 3# B- -3272# 897# 285 180066# 866# - 57 171 114 285 Fl -a 171003# 391# 7158# 1# B- * 285 183579# 419# -0 60 173 113 286 Ed -a 170014# 656# 7168# 2# B- -1758# 928# 286 182518# 704# - 58 172 114 286 Fl -a 171773# 657# 7159# 2# B- * 286 184406# 705# -0 61 174 113 287 Ed -a 171245# 725# 7167# 3# B- -2827# 948# 287 183840# 778# - 59 173 114 287 Fl -a 174073# 610# 7154# 2# B- -3823# 752# 287 186875# 655# - 57 172 115 287 Ef -a 177895# 439# 7138# 2# B- * 287 190978# 471# -0 60 174 114 288 Fl -a 175042# 806# 7154# 3# B- -4728# 968# 288 187916# 865# - 58 173 115 288 Ef -a 179771# 536# 7135# 2# B- * 288 192992# 576# -0 61 175 114 289 Fl -a 177564# 584# 7148# 2# B- -3102# 997# 289 190623# 626# - 59 174 115 289 Ef -a 180666# 809# 7135# 3# B- -3861# 947# 289 193953# 868# - 57 173 116 289 Lv -a 184528# 492# 7119# 2# B- * 289 198099# 529# -0 60 175 115 290 Ef -a 182894# 658# 7130# 2# B- -2304# 932# 290 196345# 706# - 58 174 116 290 Lv -a 185198# 660# 7120# 2# B- * 290 198818# 708# -0 61 176 115 291 Ef -a 183990# 784# 7130# 3# B- -3397# 995# 291 197522# 842# - 59 175 116 291 Lv -a 187387# 612# 7116# 2# B- -4413# 853# 291 201169# 658# - 57 174 117 291 Eh -a 191800# 594# 7098# 2# B- * 291 205906# 637# -0 60 176 116 292 Lv -a 188242# 806# 7116# 3# B- -5334# 1047# 292 202086# 865# - 58 175 117 292 Eh -a 193576# 669# 7095# 2# B- * 292 207812# 718# -0 61 177 116 293 Lv -a 190669# 586# 7111# 2# B- -3716# 1000# 293 204691# 629# - 59 176 117 293 Eh -a 194385# 810# 7095# 3# B- -4488# 1072# 293 208680# 870# - 57 175 118 293 Ei -a 198873# 702# 7077# 2# B- * 293 213498# 753# -0 60 177 117 294 Eh -a 196521# 660# 7092# 2# B- -2942# 936# 294 210974# 708# - 58 176 118 294 Ei -a 199463# 663# 7079# 2# B- * 294 214132# 712# -0 59 177 118 295 Ei -a 201512# 644# 7075# 2# B- * 295 216332# 692# diff --git a/openmc/data/mass_1.mas20.txt b/openmc/data/mass_1.mas20.txt new file mode 100644 index 00000000000..ce12b2c4a57 --- /dev/null +++ b/openmc/data/mass_1.mas20.txt @@ -0,0 +1,3594 @@ +1 a0dsskgw A T O M I C M A S S A D J U S T M E N T +0 DATE 3 Mar 2021 TIME 22:41 +0 ********************* A= 0 TO 295 + * file : mass.mas20 * + ********************* + + This is one file out of a series of 3 files published in: + "The Ame2020 atomic mass evaluation (I)" by W.J.Huang, M.Wang, F.G.Kondev, G.Audi and S.Naimi + Chinese Physics C45, 030002, March 2021. + "The Ame2020 atomic mass evaluation (II)" by M.Wang, W.J.Huang, F.G.Kondev, G.Audi and S.Naimi + Chinese Physics C45, 030003, March 2021. + for files : mass.mas20 : atomic masses + rct1.mas20 : react and sep energies, part 1 + rct2.mas20 : react and sep energies, part 2 + A fourth file is the "Rounded" version of the atomic mass table (the first file) + massround.mas20 atomic masses "Rounded" version + + Values in files 1, 2 and 3 are unrounded version of the published ones + Values in file 4 are exact copy of the published ones + + col 1 : Fortran character control: 1 = page feed 0 = line feed + format : a1,i3,i5,i5,i5,1x,a3,a4,1x,f14.6,f12.6,f13.5,1x,f10.5,1x,a2,f13.5,f11.5,1x,i3,1x,f13.6,f12.6 + cc NZ N Z A el o mass unc binding unc B beta unc atomic_mass unc + Warnings : this format is not identical to that used in AME2016; + one more digit is added to the "BINDING ENERGY/A", "BETA-DECAY ENERGY" and "ATOMIC-MASS" values and their uncertainties; + # in a place of decimal point : estimated (non-experimental) value; + * in a place of value : the not calculable quantity + +....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+...10....+...11....+...12....+...13 + + + MASS LIST + for analysis + +1N-Z N Z A EL O MASS EXCESS BINDING ENERGY/A BETA-DECAY ENERGY ATOMIC MASS + (keV) (keV) (keV) (micro-u) +0 1 1 0 1 n 8071.31806 0.00044 0.0 0.0 B- 782.3470 0.0004 1 008664.91590 0.00047 + -1 0 1 1 H 7288.971064 0.000013 0.0 0.0 B- * 1 007825.031898 0.000014 +0 0 1 1 2 H 13135.722895 0.000015 1112.2831 0.0002 B- * 2 014101.777844 0.000015 +0 1 2 1 3 H 14949.81090 0.00008 2827.2654 0.0003 B- 18.59202 0.00006 3 016049.28132 0.00008 + -1 1 2 3 He 14931.21888 0.00006 2572.68044 0.00015 B- -13736# 2000# 3 016029.32197 0.00006 + -3 0 3 3 Li -pp 28667# 2000# -2267# 667# B- * 3 030775# 2147# +0 2 3 1 4 H -n 24621.129 100.000 1720.4491 25.0000 B- 22196.2131 100.0000 4 026431.867 107.354 + 0 2 2 4 He 2424.91587 0.00015 7073.9156 0.0002 B- -22898.2740 212.1320 4 002603.25413 0.00016 + -2 1 3 4 Li -p 25323.190 212.132 1153.7603 53.0330 B- * 4 027185.561 227.733 +0 3 4 1 5 H -nn 32892.447 89.443 1336.3592 17.8885 B- 21661.2131 91.6515 5 035311.492 96.020 + 1 3 2 5 He -n 11231.234 20.000 5512.1325 4.0000 B- -447.6529 53.8516 5 012057.224 21.470 + -1 2 3 5 Li -p 11678.887 50.000 5266.1325 10.0000 B- -25460# 2003# 5 012537.800 53.677 + -3 1 4 5 Be x 37139# 2003# 18# 401# B- * 5 039870# 2150# +0 4 5 1 6 H -3n 41875.725 254.127 961.6395 42.3545 B- 24283.6294 254.1268 6 044955.437 272.816 + 2 4 2 6 He 17592.095 0.053 4878.5199 0.0089 B- 3505.2147 0.0532 6 018885.889 0.057 + 0 3 3 6 Li 14086.88044 0.00144 5332.3312 0.0003 B- -4288.1534 5.4478 6 015122.88742 0.00155 + -2 2 4 6 Be - 18375.034 5.448 4487.2478 0.9080 B- -28945# 2003# 6 019726.409 5.848 + -4 1 5 6 B x 47320# 2003# -467# 334# B- * 6 050800# 2150# +0 5 6 1 7 H -nn 49135# 1004# 940# 143# B- 23062# 1004# 7 052749# 1078# + 3 5 2 7 He -n 26073.128 7.559 4123.0578 1.0799 B- 11166.0229 7.5595 7 027990.652 8.115 + 1 4 3 7 Li 14907.10463 0.00419 5606.4401 0.0006 B- -861.8930 0.0707 7 016003.43426 0.00450 + -1 3 4 7 Be 15768.998 0.071 5371.5487 0.0101 B- -11907.5551 25.1504 7 016928.714 0.076 + -3 2 5 7 B p4n 27676.553 25.150 3558.7055 3.5929 B- * 7 029712.000 27.000 +0 4 6 2 8 He 31609.683 0.089 3924.5210 0.0111 B- 10663.8784 0.1005 8 033934.388 0.095 + 2 5 3 8 Li 20945.805 0.047 5159.7124 0.0059 B- 16004.1329 0.0591 8 022486.244 0.050 + 0 4 4 8 Be -a 4941.672 0.035 7062.4356 0.0044 B- -17979.8973 1.0005 8 005305.102 0.037 + -2 3 5 8 B 22921.569 1.000 4717.1551 0.1250 B- -12142.7002 18.2704 8 024607.315 1.073 + -4 2 6 8 C 35064.269 18.243 3101.5242 2.2804 B- * 8 037643.039 19.584 +0 5 7 2 9 He 40935.826 46.816 3349.0380 5.2018 B- 15980.9213 46.8169 9 043946.414 50.259 + 3 6 3 9 Li -3n 24954.905 0.186 5037.7685 0.0207 B- 13606.4541 0.2014 9 026790.191 0.200 + 1 5 4 9 Be 11348.451 0.076 6462.6693 0.0085 B- -1068.0349 0.8994 9 012183.062 0.082 + -1 4 5 9 B - 12416.486 0.903 6257.0713 0.1003 B- -16494.4854 2.3195 9 013329.645 0.969 + -3 3 6 9 C -pp 28910.971 2.137 4337.4233 0.2374 B- * 9 031037.202 2.293 +0 6 8 2 10 He -nn 49197.147 92.848 2995.1340 9.2848 B- 16144.5191 93.7152 10 052815.306 99.676 + 4 7 3 10 Li -n 33052.628 12.721 4531.3512 1.2721 B- 20445.1411 12.7216 10 035483.453 13.656 + 2 6 4 10 Be 12607.487 0.081 6497.6306 0.0081 B- 556.8759 0.0822 10 013534.692 0.086 + 0 5 5 10 B 12050.611 0.015 6475.0835 0.0015 B- -3648.0623 0.0687 10 012936.862 0.016 + -2 4 6 10 C 15698.673 0.070 6032.0426 0.0070 B- -23101.3545 400.0000 10 016853.217 0.075 + -4 3 7 10 N -- 38800.027 400.000 3643.6724 40.0000 B- * 10 041653.540 429.417 +0 5 8 3 11 Li x 40728.259 0.615 4155.3817 0.0559 B- 20551.0898 0.6591 11 043723.581 0.660 + 3 7 4 11 Be 20177.169 0.238 5952.5402 0.0216 B- 11509.4607 0.2380 11 021661.080 0.255 + 1 6 5 11 B 8667.708 0.012 6927.7323 0.0011 B- -1981.6889 0.0608 11 009305.166 0.013 + -1 5 6 11 C 10649.397 0.060 6676.4563 0.0054 B- -13716.2469 5.0008 11 011432.597 0.064 + -3 4 7 11 N -p 24365.644 5.000 5358.4023 0.4546 B- -23373.2693 60.2459 11 026157.593 5.368 + -5 3 8 11 O -pp 47738.913 60.038 3162.4372 5.4580 B- * 11 051249.828 64.453 +0 6 9 3 12 Li -n 49009.577 30.006 3791.5999 2.5005 B- 23931.8152 30.0669 12 052613.942 32.213 + 4 8 4 12 Be 25077.761 1.909 5720.7223 0.1590 B- 11708.3636 2.3214 12 026922.082 2.048 + 2 7 5 12 B 13369.398 1.321 6631.2237 0.1101 B- 13369.3979 1.3214 12 014352.638 1.418 + 0 6 6 12 C 0.0 0.0 7680.1446 0.0002 B- -17338.0681 0.9999 12 000000.0 0.0 + -2 5 7 12 N 17338.068 1.000 6170.1100 0.0833 B- -14675.2668 12.0418 12 018613.180 1.073 + -4 4 8 12 O -pp 32013.335 12.000 4881.9755 1.0000 B- * 12 034367.726 12.882 +0 7 10 3 13 Li -nn 56980.895 70.003 3507.6307 5.3848 B- 23321.8152 70.7391 13 061171.503 75.150 + 5 9 4 13 Be -n 33659.080 10.180 5241.4359 0.7831 B- 17097.1315 10.2295 13 036134.506 10.929 + 3 8 5 13 B -nn 16561.948 1.000 6496.4194 0.0769 B- 13436.9387 1.0001 13 017779.981 1.073 + 1 7 6 13 C 3125.00933 0.00023 7469.8495 0.0002 B- -2220.4718 0.2695 13 003354.83534 0.00025 + -1 6 7 13 N -p 5345.481 0.270 7238.8634 0.0207 B- -17769.9506 9.5301 13 005738.609 0.289 + -3 5 8 13 O +3n 23115.432 9.526 5811.7636 0.7328 B- -18915# 500# 13 024815.435 10.226 + -5 4 9 13 F x 42030# 500# 4297# 38# B- * 13 045121# 537# +0 6 10 4 14 Be x 39954.502 132.245 4993.8973 9.4461 B- 16290.8166 133.9357 14 042892.920 141.970 + 4 9 5 14 B 23663.686 21.213 6101.6451 1.5152 B- 20643.7926 21.2133 14 025404.010 22.773 + 2 8 6 14 C 3019.89328 0.00375 7520.3198 0.0004 B- 156.4765 0.0037 14 003241.98862 0.00403 + 0 7 7 14 N 2863.41683 0.00022 7475.6148 0.0002 B- -5144.3643 0.0252 14 003074.00425 0.00024 + -2 6 8 14 O 8007.781 0.025 7052.2783 0.0018 B- -23956.6215 41.1187 14 008596.706 0.027 + -4 5 9 14 F -p 31964.403 41.119 5285.2091 2.9371 B- * 14 034315.196 44.142 +0 7 11 4 15 Be -n 49825.821 165.797 4540.9708 11.0532 B- 20868.4411 167.1256 15 053490.215 177.990 + 5 10 5 15 B 28957.379 21.029 5880.0438 1.4019 B- 19084.2343 21.0442 15 031087.023 22.575 + 3 9 6 15 C -n 9873.145 0.800 7100.1696 0.0533 B- 9771.7071 0.8000 15 010599.256 0.858 + 1 8 7 15 N 101.43809 0.00058 7699.4603 0.0002 B- -2754.1841 0.4902 15 000108.89827 0.00062 + -1 7 8 15 O 2855.622 0.490 7463.6915 0.0327 B- -13711.1300 14.0086 15 003065.636 0.526 + -3 6 9 15 F -p 16566.752 14.000 6497.4597 0.9333 B- -23648.6215 68.1377 15 017785.139 15.029 + -5 5 10 15 Ne -pp 40215.374 66.684 4868.7285 4.4456 B- * 15 043172.977 71.588 +0 8 12 4 16 Be -nn 57447.139 165.797 4285.2851 10.3623 B- 20335.4399 167.6075 16 061672.036 177.990 + 6 11 5 16 B 37111.699 24.566 5507.3535 1.5354 B- 23417.5656 24.8254 16 039841.045 26.373 + 4 10 6 16 C -nn 13694.133 3.578 6922.0546 0.2236 B- 8010.2260 4.2540 16 014701.255 3.840 + 2 9 7 16 N -n 5683.907 2.301 7373.7971 0.1438 B- 10420.9094 2.3014 16 006101.925 2.470 + 0 8 8 16 O -4737.00217 0.00030 7976.2072 0.0002 B- -15412.1840 5.3642 15 994914.61926 0.00032 + -2 7 9 16 F 10675.182 5.364 6964.0490 0.3353 B- -13311.5932 21.1709 16 011460.278 5.758 + -4 6 10 16 Ne -- 23986.775 20.480 6083.1777 1.2800 B- * 16 025750.860 21.986 +0 7 12 5 17 B x 43716.322 204.104 5269.6677 12.0061 B- 22684.4422 204.8410 17 046931.399 219.114 + 5 11 6 17 C 2p-n 21031.880 17.365 6558.0262 1.0215 B- 13161.8007 22.9464 17 022578.650 18.641 + 3 10 7 17 N +p 7870.079 15.000 7286.2294 0.8824 B- 8678.8430 15.0000 17 008448.876 16.103 + 1 9 8 17 O -808.76421 0.00064 7750.7291 0.0002 B- -2760.4655 0.2479 16 999131.75595 0.00069 + -1 8 9 17 F 1951.701 0.248 7542.3284 0.0146 B- -14548.7507 0.4323 17 002095.237 0.266 + -3 7 10 17 Ne 16500.452 0.354 6640.4991 0.0208 B- -18219.1277 59.6167 17 017713.962 0.380 + -5 6 11 17 Na x 34719.580 59.616 5522.7653 3.5068 B- * 17 037273.000 64.000 +0 8 13 5 18 B -n 51792.640 204.165 4976.6306 11.3425 B- 26873.3742 206.3572 18 055601.683 219.180 + 6 12 6 18 C ++ 24919.266 30.000 6426.1321 1.6667 B- 11806.0982 35.2821 18 026751.930 32.206 + 4 11 7 18 N + 13113.167 18.570 7038.5627 1.0316 B- 13895.9838 18.5695 18 014077.563 19.935 + 2 10 8 18 O -782.81634 0.00064 7767.0981 0.0002 B- -1655.9288 0.4633 17 999159.61214 0.00069 + 0 9 9 18 F 873.112 0.463 7631.6383 0.0257 B- -4444.5049 0.5888 18 000937.324 0.497 + -2 8 10 18 Ne 5317.617 0.363 7341.2577 0.0202 B- -19720.3745 93.8819 18 005708.696 0.390 + -4 7 11 18 Na 25037.992 93.881 6202.2176 5.2156 B- * 18 026879.388 100.785 +0 9 14 5 19 B x 59770.251 525.363 4719.6346 27.6507 B- 27356.4961 534.4964 19 064166.000 564.000 + 7 13 6 19 C -n 32413.754 98.389 6118.2740 5.1784 B- 16557.4995 99.7475 19 034797.594 105.625 + 5 12 7 19 N p-2n 15856.255 16.404 6948.5452 0.8634 B- 12523.3972 16.6143 19 017022.389 17.610 + 3 11 8 19 O -n 3332.858 2.637 7566.4952 0.1388 B- 4820.3029 2.6370 19 003577.969 2.830 + 1 10 9 19 F -1487.44512 0.00082 7779.0192 0.0002 B- -3239.4986 0.1601 18 998403.16207 0.00088 + -1 9 10 19 Ne +3n 1752.054 0.160 7567.3431 0.0084 B- -11177.3310 10.5364 19 001880.906 0.171 + -3 8 11 19 Na 12929.384 10.535 6937.8864 0.5545 B- -18909.0095 60.9189 19 013880.264 11.309 + -5 7 12 19 Mg -pp 31838.394 60.001 5901.4992 3.1579 B- * 19 034179.920 64.413 +0 10 15 5 20 B -n 69401.569 546.357 4405.6529 27.3178 B- 31898.0019 593.0377 20 074505.644 586.538 + 8 14 6 20 C x 37503.567 230.625 5961.4356 11.5312 B- 15737.0689 243.7459 20 040261.732 247.585 + 6 13 7 20 N x 21766.498 78.894 6709.1717 3.9447 B- 17970.3261 78.8991 20 023367.295 84.696 + 4 12 8 20 O -nn 3796.172 0.885 7568.5707 0.0442 B- 3813.6349 0.8854 20 004075.357 0.950 + 2 11 9 20 F -n -17.463 0.030 7720.1351 0.0015 B- 7024.4689 0.0297 19 999981.252 0.031 + 0 10 10 20 Ne -7041.93217 0.00154 8032.2412 0.0002 B- -13892.4207 1.1090 19 992440.17525 0.00165 + -2 9 11 20 Na 6850.489 1.109 7298.5028 0.0554 B- -10627.2054 2.1681 20 007354.301 1.190 + -4 8 12 20 Mg +t 17477.694 1.863 6728.0252 0.0931 B- * 20 018763.075 2.000 +0 11 16 5 21 B -nn 78382.887 558.664 4152.5265 26.6031 B- 32740# 817# 21 084147.485 599.750 + 9 15 6 21 C x 45643# 596# 5674# 28# B- 20411# 611# 21 049000# 640# + 7 14 7 21 N x 25231.915 134.048 6609.0159 6.3832 B- 17169.8816 134.5840 21 027087.573 143.906 + 5 13 8 21 O -3n 8062.034 12.000 7389.3747 0.5714 B- 8109.6390 12.1342 21 008654.948 12.882 + 3 12 9 21 F -nn -47.605 1.800 7738.2934 0.0857 B- 5684.1712 1.8004 20 999948.893 1.932 + 1 11 10 21 Ne -5731.776 0.038 7971.7136 0.0018 B- -3546.9190 0.0177 20 993846.685 0.041 + -1 10 11 21 Na -2184.857 0.042 7765.5581 0.0020 B- -13088.7080 0.7557 20 997654.459 0.045 + -3 9 12 21 Mg x 10903.851 0.755 7105.0317 0.0359 B- -16186# 600# 21 011705.764 0.810 + -5 8 13 21 Al x 27090# 600# 6297# 29# B- * 21 029082# 644# +0 10 16 6 22 C -nn 53611.203 231.490 5421.0778 10.5223 B- 21846.3983 311.0627 22 057553.990 248.515 + 8 15 7 22 N x 31764.805 207.779 6378.5347 9.4445 B- 22481.7725 215.4350 22 034100.918 223.060 + 6 14 8 22 O -4n 9283.032 56.921 7364.8722 2.5873 B- 6489.6562 58.2558 22 009965.744 61.107 + 4 13 9 22 F + 2793.376 12.399 7624.2954 0.5636 B- 10818.0916 12.3990 22 002998.812 13.310 + 2 12 10 22 Ne -8024.716 0.018 8080.4656 0.0008 B- -2843.3243 0.1325 21 991385.113 0.018 + 0 11 11 22 Na -5181.391 0.132 7915.6624 0.0060 B- -4781.4051 0.1631 21 994437.547 0.141 + -2 10 12 22 Mg -399.986 0.159 7662.7645 0.0072 B- -18601# 401# 21 999570.597 0.170 + -4 9 13 22 Al x 18201# 401# 6782# 18# B- -15439# 641# 22 019540# 430# + -6 8 14 22 Si x 33640# 500# 6044# 23# B- * 22 036114# 537# +0 11 17 6 23 C x 64171# 997# 5077# 43# B- 27450# 1082# 23 068890# 1070# + 9 16 7 23 N x 36720.429 420.570 6236.6721 18.2856 B- 22099.0584 437.8271 23 039421.000 451.500 + 7 15 8 23 O x 14621.371 121.712 7163.4856 5.2918 B- 11336.1072 126.1904 23 015696.686 130.663 + 5 14 9 23 F 3285.263 33.320 7622.3447 1.4487 B- 8439.3084 33.3206 23 003526.875 35.770 + 3 13 10 23 Ne -n -5154.045 0.104 7955.2561 0.0045 B- 4375.8085 0.1044 22 994466.905 0.112 + 1 12 11 23 Na -9529.85352 0.00181 8111.4936 0.0002 B- -4056.1790 0.0317 22 989769.28195 0.00194 + -1 11 12 23 Mg - -5473.675 0.032 7901.1229 0.0014 B- -12221.7457 0.3461 22 994123.768 0.034 + -3 10 13 23 Al -- 6748.071 0.345 7335.7275 0.0150 B- -17202# 500# 23 007244.351 0.370 + -5 9 14 23 Si x 23950# 500# 6554# 22# B- * 23 025711# 537# +0 10 17 7 24 N x 46938# 401# 5887# 17# B- 28438# 433# 24 050390# 430# + 8 16 8 24 O x 18500.404 164.874 7039.6855 6.8698 B- 10955.8885 191.6327 24 019861.000 177.000 + 6 15 9 24 F x 7544.516 97.670 7463.5831 4.0696 B- 13496.1583 97.6717 24 008099.370 104.853 + 4 14 10 24 Ne -nn -5951.642 0.513 7993.3252 0.0214 B- 2466.2583 0.5130 23 993610.649 0.550 + 2 13 11 24 Na -n -8417.901 0.017 8063.4882 0.0007 B- 5515.6774 0.0210 23 990963.012 0.017 + 0 12 12 24 Mg -13933.578 0.013 8260.7103 0.0006 B- -13884.7660 0.2282 23 985041.689 0.013 + -2 11 13 24 Al -48.812 0.228 7649.5806 0.0095 B- -10793.9978 19.4734 23 999947.598 0.244 + -4 10 14 24 Si -- 10745.186 19.472 7167.2329 0.8113 B- -23275# 501# 24 011535.430 20.904 + -6 9 15 24 P x 34020# 500# 6165# 21# B- * 24 036522# 537# +0 11 18 7 25 N x 55983# 503# 5613# 20# B- 28654# 529# 25 060100# 540# + 9 17 8 25 O -n 27329.030 165.084 6727.8058 6.6034 B- 15994.8633 191.1909 25 029338.919 177.225 + 7 16 9 25 F x 11334.167 96.442 7336.3065 3.8577 B- 13369.6698 100.7212 25 012167.727 103.535 + 5 15 10 25 Ne -2035.503 29.045 7839.7994 1.1618 B- 7322.3107 29.0701 24 997814.797 31.181 + 3 14 11 25 Na -nn -9357.814 1.200 8101.3979 0.0480 B- 3834.9684 1.2009 24 989953.974 1.288 + 1 13 12 25 Mg -13192.782 0.047 8223.5028 0.0019 B- -4276.8080 0.0447 24 985836.966 0.050 + -1 12 13 25 Al -8915.974 0.065 8021.1366 0.0026 B- -12743.2956 10.0002 24 990428.308 0.069 + -3 11 14 25 Si +3n 3827.322 10.000 7480.1109 0.4000 B- -16363# 400# 25 004108.798 10.735 + -5 10 15 25 P x 20190# 400# 6794# 16# B- * 25 021675# 429# +0 10 18 8 26 O -nn 34661.041 164.950 6497.4790 6.3442 B- 15986.3855 196.6301 26 037210.155 177.081 + 8 17 9 26 F 18674.655 107.027 7082.2497 4.1164 B- 18193.5414 108.6022 26 020048.065 114.898 + 6 16 10 26 Ne x 481.114 18.429 7751.9110 0.7088 B- 7341.8940 18.7585 26 000516.496 19.784 + 4 15 11 26 Na x -6860.780 3.502 8004.2013 0.1347 B- 9353.7631 3.5018 25 992634.649 3.759 + 2 14 12 26 Mg -16214.544 0.029 8333.8711 0.0011 B- -4004.4042 0.0629 25 982592.972 0.031 + 0 13 13 26 Al -12210.139 0.066 8149.7653 0.0026 B- -5069.1361 0.0849 25 986891.876 0.071 + -2 12 14 26 Si - -7141.003 0.108 7924.7083 0.0041 B- -18114# 196# 25 992333.818 0.115 + -4 11 15 26 P x 10973# 196# 7198# 8# B- -16707# 631# 26 011780# 210# + -6 10 16 26 S x 27680# 600# 6525# 23# B- * 26 029716# 644# +0 11 19 8 27 O x 44670# 500# 6185# 19# B- 19536# 514# 27 047955# 537# + 9 18 9 27 F 25133.478 120.198 6879.6662 4.4518 B- 18082.5680 150.6211 27 026981.897 129.037 + 7 17 10 27 Ne x 7050.910 90.770 7520.4151 3.3619 B- 12568.7005 90.8467 27 007569.462 97.445 + 5 16 11 27 Na ++ -5517.791 3.726 7956.9467 0.1380 B- 9068.8037 3.7266 26 994076.408 4.000 + 3 15 12 27 Mg -14586.594 0.047 8263.8525 0.0018 B- 2610.2694 0.0669 26 984340.647 0.050 + 1 14 13 27 Al -17196.864 0.047 8331.5533 0.0018 B- -4812.3583 0.0964 26 981538.408 0.050 + -1 13 14 27 Si - -12384.505 0.107 8124.3420 0.0040 B- -11725.4730 9.0013 26 986704.687 0.115 + -3 12 15 27 P -p -659.032 9.001 7661.0894 0.3334 B- -18150# 400# 26 999292.499 9.662 + -5 11 16 27 S - 17491# 400# 6960# 15# B- * 27 018777# 430# +0 12 20 8 28 O x 52080# 699# 5988# 25# B- 18676# 709# 28 055910# 750# + 10 19 9 28 F -n 33403.796 120.347 6626.8567 4.2981 B- 22104.0579 174.2886 28 035860.448 129.198 + 8 18 10 28 Ne x 11299.738 126.068 7388.3463 4.5024 B- 12288.0534 126.4833 28 012130.767 135.339 + 6 17 11 28 Na x -988.315 10.246 7799.2644 0.3659 B- 14031.6303 10.2498 27 998939.000 11.000 + 4 16 12 28 Mg x -15019.946 0.261 8272.4531 0.0093 B- 1830.7740 0.2653 27 983875.426 0.280 + 2 15 13 28 Al -n -16850.719 0.049 8309.8969 0.0018 B- 4642.0776 0.0486 27 981910.009 0.052 + 0 14 14 28 Si -21492.79711 0.00051 8447.7445 0.0002 B- -14344.9407 1.1473 27 976926.53442 0.00055 + -2 13 15 28 P -7147.856 1.147 7907.4842 0.0410 B- -11221.0593 160.0041 27 992326.460 1.231 + -4 12 16 28 S -- 4073.203 160.000 7478.7911 5.7143 B- -24197# 525# 28 004372.762 171.767 + -6 11 17 28 Cl -p 28270# 500# 6587# 18# B- * 28 030349# 537# +0 11 20 9 29 F x 40150.190 525.363 6444.0314 18.1160 B- 21750.3873 546.2212 29 043103.000 564.000 + 9 19 10 29 Ne x 18399.803 149.505 7167.0673 5.1553 B- 15719.8092 149.6847 29 019753.000 160.500 + 7 18 11 29 Na 2679.994 7.337 7682.1522 0.2530 B- 13292.3538 7.3447 29 002877.091 7.876 + 5 17 12 29 Mg -10612.360 0.345 8113.5317 0.0119 B- 7595.4023 0.4873 28 988607.163 0.369 + 3 16 13 29 Al x -18207.762 0.345 8348.4647 0.0119 B- 3687.3192 0.3447 28 980453.164 0.370 + 1 15 14 29 Si -21895.08154 0.00056 8448.6361 0.0002 B- -4942.2325 0.3589 28 976494.66434 0.00060 + -1 14 15 29 P -16952.849 0.359 8251.2368 0.0124 B- -13858.4257 13.0459 28 981800.368 0.385 + -3 13 16 29 S x -3094.423 13.041 7746.3826 0.4497 B- -17117# 189# 28 996678.000 14.000 + -5 12 17 29 Cl -p 14022# 189# 7129# 7# B- -23947# 478# 29 015053# 203# + -7 11 18 29 Ar -pp 37969# 439# 6276# 15# B- * 29 040761# 471# +0 12 21 9 30 F x 48960# 500# 6205# 17# B- 25680# 561# 30 052561# 537# + 10 20 10 30 Ne 23280.120 253.250 7034.5317 8.4417 B- 14805.4501 253.2946 30 024992.235 271.875 + 8 19 11 30 Na 8474.670 4.727 7501.9685 0.1576 B- 17356.0423 4.9011 30 009097.931 5.074 + 6 18 12 30 Mg -8881.373 1.295 8054.4250 0.0432 B- 6982.7440 2.3287 29 990465.454 1.390 + 4 17 13 30 Al -15864.116 1.936 8261.1049 0.0645 B- 8568.8459 1.9357 29 982969.171 2.077 + 2 16 14 30 Si -n -24432.962 0.022 8520.6549 0.0008 B- -4232.1065 0.0615 29 973770.137 0.023 + 0 15 15 30 P - -20200.856 0.065 8353.5064 0.0022 B- -6141.6014 0.1956 29 978313.490 0.069 + -2 14 16 30 S - -14059.254 0.206 8122.7081 0.0069 B- -18733.8020 23.8769 29 984906.770 0.221 + -4 13 17 30 Cl -p 4674.548 23.876 7472.1698 0.7959 B- -17397# 180# 30 005018.333 25.631 + -6 12 18 30 Ar -pp 22071# 179# 6866# 6# B- * 30 023694# 192# +0 13 22 9 31 F -nn 56843# 535# 6011# 17# B- 25661# 597# 31 061023# 574# + 11 21 10 31 Ne 31181.594 266.195 6813.0902 8.5869 B- 18935.5625 266.5617 31 033474.816 285.772 + 9 20 11 31 Na x 12246.031 13.972 7398.6778 0.4507 B- 15368.1833 14.3065 31 013146.654 15.000 + 7 19 12 31 Mg x -3122.152 3.074 7869.1886 0.0992 B- 11828.5569 3.8009 30 996648.232 3.300 + 5 18 13 31 Al x -14950.709 2.236 8225.5180 0.0721 B- 7998.3286 2.2360 30 983949.754 2.400 + 3 17 14 31 Si -n -22949.037 0.043 8458.2916 0.0014 B- 1491.5071 0.0434 30 975363.196 0.046 + 1 16 15 31 P -24440.54442 0.00075 8481.1677 0.0002 B- -5398.0130 0.2292 30 973761.99768 0.00080 + -1 15 16 31 S -19042.531 0.229 8281.8013 0.0074 B- -12007.9790 3.4541 30 979557.002 0.246 + -3 14 17 31 Cl -- -7034.552 3.447 7869.2101 0.1112 B- -18360# 200# 30 992448.097 3.700 + -5 13 18 31 Ar - 11325# 200# 7252# 6# B- -22935# 361# 31 012158# 215# + -7 12 19 31 K x 34260# 300# 6487# 10# B- * 31 036780# 322# +0 12 22 10 32 Ne x 36999# 503# 6671# 16# B- 18359# 504# 32 039720# 540# + 10 21 11 32 Na x 18640.152 37.260 7219.8815 1.1644 B- 19469.0523 37.4021 32 020011.024 40.000 + 8 20 12 32 Mg x -828.901 3.260 7803.8411 0.1019 B- 10270.4677 7.8787 31 999110.138 3.500 + 6 19 13 32 Al x -11099.368 7.173 8100.3449 0.2241 B- 12978.3208 7.1787 31 988084.338 7.700 + 4 18 14 32 Si x -24077.689 0.298 8481.4690 0.0093 B- 227.1872 0.3008 31 974151.538 0.320 + 2 17 15 32 P -n -24304.876 0.040 8464.1203 0.0013 B- 1710.6608 0.0400 31 973907.643 0.042 + 0 16 16 32 S -26015.53714 0.00131 8493.1301 0.0002 B- -12680.8313 0.5617 31 972071.17354 0.00141 + -2 15 17 32 Cl -13334.706 0.562 8072.4058 0.0176 B- -11134.3536 1.8568 31 985684.605 0.603 + -4 14 18 32 Ar x -2200.352 1.770 7700.0089 0.0553 B- -24190# 400# 31 997637.824 1.900 + -6 13 19 32 K x 21990# 400# 6920# 12# B- * 32 023607# 429# +0 13 23 10 33 Ne x 46130# 600# 6436# 18# B- 22350# 750# 33 049523# 644# + 11 22 11 33 Na x 23780.113 449.912 7089.9262 13.6337 B- 18817.2400 449.9195 33 025529.000 483.000 + 9 21 12 33 Mg 4962.873 2.663 7636.4382 0.0807 B- 13460.2550 7.4767 33 005327.862 2.859 + 7 20 13 33 Al x -8497.382 6.986 8020.6172 0.2117 B- 12016.9460 7.0211 32 990877.685 7.500 + 5 19 14 33 Si x -20514.328 0.699 8361.0596 0.0212 B- 5823.0223 1.2947 32 977976.964 0.750 + 3 18 15 33 P + -26337.350 1.090 8513.8073 0.0330 B- 248.5079 1.0900 32 971725.692 1.170 + 1 17 16 33 S -26585.85830 0.00134 8497.6304 0.0002 B- -5582.5182 0.3908 32 971458.90862 0.00144 + -1 16 17 33 Cl -21003.340 0.391 8304.7557 0.0118 B- -11619.0452 0.5596 32 977451.988 0.419 + -3 15 18 33 Ar x -9384.295 0.401 7928.9559 0.0121 B- -16925# 200# 32 989925.545 0.430 + -5 14 19 33 K x 7540# 200# 7392# 6# B- -23489# 447# 33 008095# 215# + -7 13 20 33 Ca x 31030# 400# 6657# 12# B- * 33 033312# 429# +0 14 24 10 34 Ne -nn 52842# 513# 6287# 15# B- 21161# 789# 34 056728# 551# + 12 23 11 34 Na x 31680.114 599.416 6886.4377 17.6299 B- 23356.7903 599.4561 34 034010.000 643.500 + 10 22 12 34 Mg x 8323.324 6.893 7550.3919 0.2027 B- 11320.9428 7.2072 34 008935.455 7.400 + 8 21 13 34 Al x -2997.619 2.105 7860.3506 0.0619 B- 16994.0653 2.2519 33 996781.924 2.259 + 6 20 14 34 Si x -19991.684 0.801 8337.1659 0.0236 B- 4557.0175 1.1395 33 978538.045 0.860 + 4 19 15 34 P x -24548.702 0.810 8448.1856 0.0238 B- 5382.9879 0.8116 33 973645.886 0.870 + 2 18 16 34 S -29931.689 0.045 8583.4986 0.0013 B- -5491.6037 0.0378 33 967867.011 0.047 + 0 17 17 34 Cl -24440.086 0.049 8398.9706 0.0014 B- -6061.7930 0.0631 33 973762.490 0.052 + -2 16 18 34 Ar -18378.293 0.078 8197.6724 0.0023 B- -17158# 196# 33 980270.092 0.083 + -4 15 19 34 K x -1220# 196# 7670# 6# B- -16110# 358# 33 998690# 210# + -6 14 20 34 Ca x 14890# 300# 7173# 9# B- * 34 015985# 322# +0 13 24 11 35 Na -n 37831# 670# 6745# 19# B- 22192# 723# 35 040614# 720# + 11 23 12 35 Mg x 15639.786 269.668 7356.2338 7.7048 B- 15863.5156 269.7679 35 016790.000 289.500 + 9 22 13 35 Al x -223.730 7.359 7787.1243 0.2103 B- 14167.7504 36.6047 34 999759.816 7.900 + 7 21 14 35 Si 2p-n -14391.480 35.857 8169.5644 1.0245 B- 10466.3291 35.9049 34 984550.111 38.494 + 5 20 15 35 P +p -24857.809 1.866 8446.2496 0.0533 B- 3988.4006 1.8667 34 973314.045 2.003 + 3 19 16 35 S -28846.210 0.040 8537.8511 0.0012 B- 167.3218 0.0257 34 969032.321 0.043 + 1 18 17 35 Cl -29013.532 0.035 8520.2790 0.0010 B- -5966.2429 0.6794 34 968852.694 0.038 + -1 17 18 35 Ar - -23047.289 0.680 8327.4621 0.0194 B- -11874.3955 0.8516 34 975257.719 0.730 + -3 16 19 35 K 4n -11172.893 0.512 7965.8409 0.0146 B- -16363# 200# 34 988005.406 0.550 + -5 15 20 35 Ca x 5190# 200# 7476# 6# B- -21910# 447# 35 005572# 215# + -7 14 21 35 Sc x 27100# 400# 6828# 11# B- * 35 029093# 429# +0 14 25 11 36 Na -n 45903# 687# 6557# 19# B- 25523# 974# 36 049279# 737# + 12 24 12 36 Mg x 20380.159 690.237 7244.4202 19.1733 B- 14429.7751 706.2429 36 021879.000 741.000 + 10 23 13 36 Al x 5950.384 149.505 7623.5154 4.1529 B- 18386.5096 165.8510 36 006388.000 160.500 + 8 22 14 36 Si x -12436.125 71.797 8112.5199 1.9944 B- 7814.9194 72.9852 35 986649.271 77.077 + 6 21 15 36 P + -20251.045 13.114 8307.8692 0.3643 B- 10413.0962 13.1124 35 978259.610 14.078 + 4 20 16 36 S -30664.141 0.188 8575.3900 0.0052 B- -1142.1329 0.1893 35 967080.692 0.201 + 2 19 17 36 Cl -29522.008 0.036 8521.9322 0.0010 B- 709.5343 0.0449 35 968306.822 0.038 + 0 18 18 36 Ar -30231.542 0.027 8519.9096 0.0008 B- -12814.3607 0.3259 35 967545.106 0.028 + -2 17 19 36 K -17417.182 0.325 8142.2233 0.0090 B- -10966.0155 40.0013 35 981301.887 0.349 + -4 16 20 36 Ca 4n -6451.166 40.000 7815.8799 1.1111 B- -22601# 303# 35 993074.388 42.941 + -6 15 21 36 Sc x 16150# 300# 7166# 8# B- * 36 017338# 322# +0 15 26 11 37 Na -nn 53134# 687# 6403# 19# B- 24923# 980# 37 057042# 737# + 13 25 12 37 Mg -n 28211.478 698.947 7055.1115 18.8905 B- 18401.9132 721.8139 37 030286.265 750.350 + 11 24 13 37 Al x 9809.564 180.244 7531.3160 4.8715 B- 16381.0765 213.1678 37 010531.000 193.500 + 9 23 14 37 Si x -6571.512 113.809 7952.9033 3.0759 B- 12424.5003 119.9691 36 992945.191 122.179 + 7 22 15 37 P p-2n -18996.012 37.948 8267.5561 1.0256 B- 7900.4135 37.9474 36 979606.942 40.738 + 5 21 16 37 S -n -26896.426 0.198 8459.9363 0.0054 B- 4865.1258 0.1965 36 971125.500 0.212 + 3 20 17 37 Cl -31761.552 0.052 8570.2816 0.0014 B- -813.8729 0.2000 36 965902.573 0.055 + 1 19 18 37 Ar - -30947.679 0.207 8527.1406 0.0056 B- -6147.4775 0.2270 36 966776.301 0.221 + -1 18 19 37 K -p -24800.201 0.094 8339.8480 0.0025 B- -11664.1314 0.6412 36 973375.890 0.100 + -3 17 20 37 Ca x -13136.070 0.634 8003.4567 0.0171 B- -16916# 300# 36 985897.849 0.680 + -5 16 21 37 Sc x 3780# 300# 7525# 8# B- -21390# 500# 37 004058# 322# + -7 15 22 37 Ti x 25170# 400# 6926# 11# B- * 37 027021# 429# +0 16 27 11 38 Na -n 61905# 715# 6216# 19# B- 27831# 875# 38 066458# 768# + 14 26 12 38 Mg x 34074# 503# 6928# 13# B- 17604# 525# 38 036580# 540# + 12 25 13 38 Al x 16470# 150# 7370# 4# B- 20640# 183# 38 017681# 161# + 10 24 14 38 Si x -4170.299 104.793 7892.8297 2.7577 B- 10451.2656 127.4736 37 995523.000 112.500 + 8 23 15 38 P x -14621.565 72.581 8147.2749 1.9100 B- 12239.6512 72.9340 37 984303.105 77.918 + 6 22 16 38 S + -26861.216 7.172 8448.7829 0.1887 B- 2936.9000 7.1714 37 971163.300 7.699 + 4 21 17 38 Cl -n -29798.116 0.098 8505.4817 0.0026 B- 4916.7109 0.2182 37 968010.408 0.105 + 2 20 18 38 Ar -34714.827 0.195 8614.2807 0.0051 B- -5914.0671 0.0448 37 962732.102 0.209 + 0 19 19 38 K -28800.760 0.195 8438.0593 0.0051 B- -6742.2563 0.0626 37 969081.114 0.209 + -2 18 20 38 Ca -22058.503 0.194 8240.0434 0.0051 B- -17809# 200# 37 976319.223 0.208 + -4 17 21 38 Sc x -4249# 200# 7751# 5# B- -15619# 361# 37 995438# 215# + -6 16 22 38 Ti x 11370# 300# 7319# 8# B- * 38 012206# 322# +0 17 28 11 39 Na -n 69977# 743# 6056# 19# B- 27201# 903# 39 075123# 797# + 15 27 12 39 Mg -n 42775# 513# 6734# 13# B- 21286# 594# 39 045921# 551# + 13 26 13 39 Al x 21490# 300# 7260# 8# B- 19169# 329# 39 023070# 322# + 11 25 14 39 Si x 2320.352 135.532 7730.9793 3.4752 B- 15094.9874 176.2324 39 002491.000 145.500 + 9 24 15 39 P x -12774.636 112.645 8097.9701 2.8883 B- 10388.0361 123.2430 38 986285.865 120.929 + 7 23 16 39 S 2p-n -23162.672 50.000 8344.2698 1.2821 B- 6637.5463 50.0300 38 975133.850 53.677 + 5 22 17 39 Cl -nn -29800.218 1.732 8494.4032 0.0444 B- 3441.9774 5.2915 38 968008.151 1.859 + 3 21 18 39 Ar + -33242.195 5.000 8562.5988 0.1282 B- 565.0000 5.0000 38 964313.037 5.367 + 1 20 19 39 K -33807.19535 0.00456 8557.0258 0.0003 B- -6524.4888 0.5962 38 963706.48482 0.00489 + -1 19 20 39 Ca -27282.707 0.596 8369.6711 0.0153 B- -13109.9804 24.0074 38 970710.811 0.640 + -3 18 21 39 Sc 2n-p -14172.726 24.000 8013.4575 0.6154 B- -16673# 202# 38 984784.953 25.765 + -5 17 22 39 Ti x 2500# 200# 7566# 5# B- -20070# 447# 39 002684# 215# + -7 16 23 39 V x 22570# 400# 7031# 10# B- * 39 024230# 429# +0 16 28 12 40 Mg x 49550# 500# 6598# 13# B- 20729# 583# 40 053194# 537# + 14 27 13 40 Al x 28820# 300# 7097# 7# B- 23154# 324# 40 030940# 322# + 12 26 14 40 Si x 5666.876 121.991 7655.8247 3.0498 B- 13806.0653 147.8912 40 006083.641 130.962 + 10 25 15 40 P x -8139.189 83.607 7981.4177 2.0902 B- 14698.6603 83.7017 39 991262.221 89.755 + 8 24 16 40 S -22837.850 3.982 8329.3255 0.0996 B- 4719.9687 32.3118 39 975482.561 4.274 + 6 23 17 40 Cl + -27557.818 32.066 8427.7660 0.8016 B- 7482.0816 32.0655 39 970415.466 34.423 + 4 22 18 40 Ar -35039.89997 0.00218 8595.2594 0.0002 B- -1504.4031 0.0559 39 962383.12204 0.00234 + 2 21 19 40 K -33535.497 0.056 8538.0907 0.0014 B- 1310.9051 0.0596 39 963998.165 0.060 + 0 20 20 40 Ca -34846.402 0.020 8551.3046 0.0006 B- -14323.0493 2.8281 39 962590.850 0.022 + -2 19 21 40 Sc - -20523.353 2.828 8173.6697 0.0707 B- -11529.9139 68.3023 39 977967.275 3.036 + -4 18 22 40 Ti -8993.439 68.244 7865.8632 1.7061 B- -21463# 308# 39 990345.146 73.262 + -6 17 23 40 V x 12470# 300# 7310# 7# B- * 40 013387# 322# +0 17 29 12 41 Mg x 58100# 500# 6425# 12# B- 23510# 640# 41 062373# 537# + 15 28 13 41 Al x 34590# 400# 6980# 10# B- 21390# 500# 41 037134# 429# + 13 27 14 41 Si x 13200# 300# 7482# 7# B- 18180# 323# 41 014171# 322# + 11 26 15 41 P x -4979.767 120.163 7906.5513 2.9308 B- 14028.8125 120.2326 40 994654.000 129.000 + 9 25 16 41 S x -19008.580 4.099 8229.6358 0.1000 B- 8298.6116 68.8456 40 979593.451 4.400 + 7 24 17 41 Cl x -27307.192 68.723 8412.9593 1.6762 B- 5760.3180 68.7243 40 970684.525 73.777 + 5 23 18 41 Ar -n -33067.510 0.347 8534.3733 0.0085 B- 2492.0392 0.3473 40 964500.570 0.372 + 3 22 19 41 K -35559.54880 0.00376 8576.0731 0.0003 B- -421.6406 0.1377 40 961825.25611 0.00403 + 1 21 20 41 Ca -35137.908 0.138 8546.7075 0.0034 B- -6495.5482 0.1553 40 962277.905 0.147 + -1 20 21 41 Sc -28642.360 0.077 8369.1979 0.0019 B- -12944.8214 27.9449 40 969251.163 0.083 + -3 19 22 41 Ti x -15697.539 27.945 8034.3889 0.6816 B- -16008# 202# 40 983148.000 30.000 + -5 18 23 41 V x 310# 200# 7625# 5# B- -20100# 447# 41 000333# 215# + -7 17 24 41 Cr x 20410# 400# 7116# 10# B- * 41 021911# 429# +0 16 29 13 42 Al x 41990# 500# 6829# 12# B- 25150# 583# 42 045078# 537# + 14 28 14 42 Si x 16840# 300# 7410# 7# B- 15748# 315# 42 018078# 322# + 12 27 15 42 P x 1091.842 95.009 7765.9122 2.2621 B- 18729.5899 95.0504 42 001172.140 101.996 + 10 26 16 42 S x -17637.748 2.794 8193.2275 0.0665 B- 7194.0221 59.6811 41 981065.100 3.000 + 8 25 17 42 Cl x -24831.770 59.616 8345.8864 1.4194 B- 9590.9082 59.8947 41 973342.000 64.000 + 6 24 18 42 Ar x -34422.678 5.775 8555.6141 0.1375 B- 599.3527 5.7763 41 963045.737 6.200 + 4 23 19 42 K -n -35022.031 0.106 8551.2571 0.0025 B- 3525.2626 0.1825 41 962402.305 0.113 + 2 22 20 42 Ca -38547.293 0.148 8616.5646 0.0035 B- -6426.2904 0.0485 41 958617.780 0.159 + 0 21 21 42 Sc -32121.003 0.154 8444.9303 0.0037 B- -7016.6496 0.2239 41 965516.686 0.165 + -2 20 22 42 Ti -25104.353 0.269 8259.2400 0.0064 B- -17485# 196# 41 973049.369 0.289 + -4 19 23 42 V x -7620# 196# 7824# 5# B- -14679# 358# 41 991820# 210# + -6 18 24 42 Cr x 7060# 300# 7456# 7# B- * 42 007579# 322# +0 17 30 13 43 Al x 48270# 600# 6712# 14# B- 23940# 721# 43 051820# 644# + 15 29 14 43 Si x 24330# 400# 7251# 9# B- 19289# 500# 43 026119# 429# + 13 28 15 43 P x 5040# 300# 7681# 7# B- 17236# 300# 43 005411# 322# + 11 27 16 43 S x -12195.461 4.970 8063.8276 0.1156 B- 11964.0500 62.0579 42 986907.635 5.335 + 9 26 17 43 Cl x -24159.510 61.859 8323.8672 1.4386 B- 7850.3002 62.0860 42 974063.700 66.407 + 7 25 18 43 Ar x -32009.811 5.310 8488.2382 0.1235 B- 4565.5836 5.3254 42 965636.056 5.700 + 5 24 19 43 K -4n -36575.394 0.410 8576.2204 0.0095 B- 1833.4783 0.4687 42 960734.701 0.440 + 3 23 20 43 Ca -38408.873 0.227 8600.6653 0.0053 B- -2220.7227 1.8650 42 958766.381 0.244 + 1 22 21 43 Sc -p -36188.150 1.863 8530.8265 0.0433 B- -6872.5591 6.0147 42 961150.425 1.999 + -1 21 22 43 Ti -29315.591 5.719 8352.8054 0.1330 B- -11399.2333 43.2287 42 968528.420 6.139 + -3 20 23 43 V x -17916.358 42.849 8069.5129 0.9965 B- -15946# 205# 42 980766.000 46.000 + -5 19 24 43 Cr x -1970# 200# 7680# 5# B- -19340# 447# 42 997885# 215# + -7 18 25 43 Mn x 17370# 400# 7213# 9# B- * 43 018647# 429# +0 16 30 14 44 Si x 29310# 500# 7156# 11# B- 18200# 640# 44 031466# 537# + 14 29 15 44 P x 11110# 400# 7552# 9# B- 20314# 400# 44 011927# 429# + 12 28 16 44 S x -9204.236 5.216 7996.0154 0.1186 B- 11274.7373 85.7253 43 990118.846 5.600 + 10 27 17 44 Cl x -20478.973 85.566 8234.4788 1.9447 B- 12194.2869 85.5811 43 978014.918 91.859 + 8 26 18 44 Ar x -32673.260 1.584 8493.8411 0.0360 B- 3108.2375 1.6381 43 964923.814 1.700 + 6 25 19 44 K x -35781.498 0.419 8546.7023 0.0095 B- 5687.2319 0.5303 43 961586.984 0.450 + 4 24 20 44 Ca -41468.730 0.325 8658.1769 0.0074 B- -3652.6948 1.7565 43 955481.489 0.348 + 2 23 21 44 Sc -p -37816.035 1.756 8557.3805 0.0399 B- -267.4488 1.8899 43 959402.818 1.884 + 0 22 22 44 Ti -a -37548.586 0.700 8533.5215 0.0159 B- -13740.5071 7.2986 43 959689.936 0.751 + -2 21 23 44 V -23808.079 7.265 8203.4567 0.1651 B- -10386.1805 51.7447 43 974440.977 7.799 + -4 20 24 44 Cr x -13421.899 51.232 7949.6265 1.1644 B- -20882# 304# 43 985591.000 55.000 + -6 19 25 44 Mn x 7460# 300# 7457# 7# B- * 44 008009# 322# +0 17 31 14 45 Si x 37090# 600# 7004# 13# B- 21130# 781# 45 039818# 644# + 15 30 15 45 P x 15960# 500# 7456# 11# B- 19301# 583# 45 017134# 537# + 13 29 16 45 S x -3340# 300# 7867# 7# B- 14922# 329# 44 996414# 322# + 11 28 17 45 Cl x -18262.544 136.163 8181.5991 3.0259 B- 11508.2568 136.1643 44 980394.353 146.177 + 9 27 18 45 Ar x -29770.801 0.512 8419.9526 0.0114 B- 6844.8422 0.7311 44 968039.731 0.550 + 7 26 19 45 K x -36615.643 0.522 8554.6747 0.0116 B- 4196.5868 0.6369 44 960691.491 0.560 + 5 25 20 45 Ca -40812.230 0.365 8630.5467 0.0081 B- 260.0910 0.7377 44 956186.270 0.392 + 3 24 21 45 Sc -41072.321 0.663 8618.9410 0.0147 B- -2062.0551 0.5086 44 955907.051 0.712 + 1 23 22 45 Ti -39010.266 0.836 8555.7321 0.0186 B- -7123.8247 0.2142 44 958120.758 0.897 + -1 22 23 45 V -31886.441 0.863 8380.0394 0.0192 B- -12371.6400 35.4073 44 965768.498 0.926 + -3 21 24 45 Cr x -19514.801 35.397 8087.7286 0.7866 B- -14535# 302# 44 979050.000 38.000 + -5 20 25 45 Mn x -4980# 300# 7747# 7# B- -19388# 412# 44 994654# 322# + -7 19 26 45 Fe -pp 14408# 283# 7299# 6# B- * 45 015467# 304# +0 16 31 15 46 P x 22840# 500# 7320# 11# B- 22200# 640# 46 024520# 537# + 14 30 16 46 S x 640# 400# 7785# 9# B- 14375# 411# 46 000687# 429# + 12 29 17 46 Cl x -13734.949 97.249 8080.7757 2.1141 B- 16036.3062 97.2766 45 985254.926 104.400 + 10 28 18 46 Ar x -29771.255 2.329 8412.3835 0.0506 B- 5642.6746 2.4394 45 968039.244 2.500 + 8 27 19 46 K x -35413.929 0.727 8518.0428 0.0158 B- 7725.6802 2.3490 45 961981.584 0.780 + 6 26 20 46 Ca -43139.610 2.234 8668.9848 0.0486 B- -1377.9665 2.3305 45 953687.726 2.398 + 4 25 21 46 Sc -n -41761.643 0.671 8622.0215 0.0146 B- 2366.6260 0.6666 45 955167.034 0.720 + 2 24 22 46 Ti -44128.269 0.090 8656.4623 0.0020 B- -7052.3723 0.0923 45 952626.356 0.097 + 0 23 23 46 V -37075.897 0.134 8486.1423 0.0029 B- -7604.3264 11.4538 45 960197.389 0.143 + -2 22 24 46 Cr -29471.570 11.453 8303.8233 0.2490 B- -17053.8226 87.3828 45 968360.969 12.295 + -4 21 25 46 Mn x -12417.748 86.629 7916.0805 1.8832 B- -13628# 312# 45 986669.000 93.000 + -6 20 26 46 Fe x 1210# 300# 7603# 7# B- * 46 001299# 322# +0 17 32 15 47 P x 28810# 600# 7209# 13# B- 21610# 721# 47 030929# 644# + 15 31 16 47 S x 7200# 400# 7652# 9# B- 16781# 447# 47 007730# 429# + 13 30 17 47 Cl x -9580# 200# 7992# 4# B- 15787# 200# 46 989715# 215# + 11 29 18 47 Ar x -25367.274 1.211 8311.4250 0.0258 B- 10344.7078 1.8490 46 972767.112 1.300 + 9 28 19 47 K x -35711.982 1.397 8514.8795 0.0297 B- 6632.6837 2.6237 46 961661.612 1.500 + 7 27 20 47 Ca -42344.665 2.221 8639.3548 0.0473 B- 1992.1770 1.1849 46 954541.134 2.384 + 5 26 21 47 Sc -44336.842 1.931 8665.0958 0.0411 B- 600.7694 1.9292 46 952402.444 2.072 + 3 25 22 47 Ti -44937.612 0.080 8661.2325 0.0017 B- -2930.5422 0.0879 46 951757.491 0.085 + 1 24 23 47 V -42007.070 0.110 8582.2348 0.0024 B- -7443.9769 5.1976 46 954903.558 0.118 + -1 23 24 47 Cr -34563.093 5.197 8407.2067 0.1106 B- -11996.7167 32.0943 46 962894.995 5.578 + -3 22 25 47 Mn x -22566.376 31.671 8135.3117 0.6738 B- -15437# 501# 46 975774.000 34.000 + -5 21 26 47 Fe x -7130# 500# 7790# 11# B- -17750# 781# 46 992346# 537# + -7 20 27 47 Co x 10620# 600# 7396# 13# B- * 47 011401# 644# +0 16 32 16 48 S x 12390# 500# 7552# 10# B- 16670# 707# 48 013301# 537# + 14 31 17 48 Cl x -4280# 500# 7883# 10# B- 18075# 500# 47 995405# 537# + 12 30 18 48 Ar x -22354.927 16.767 8243.6656 0.3493 B- 9929.5550 16.7847 47 976001.000 18.000 + 10 29 19 48 K x -32284.482 0.773 8434.2324 0.0161 B- 11940.3857 0.7734 47 965341.184 0.830 + 8 28 20 48 Ca -44224.868 0.018 8666.6916 0.0004 B- 279.2155 4.9499 47 952522.654 0.018 + 6 27 21 48 Sc -44504.083 4.950 8656.2097 0.1031 B- 3988.8685 4.9499 47 952222.903 5.313 + 4 26 22 48 Ti -48492.952 0.074 8723.0122 0.0016 B- -4014.9467 0.9691 47 947940.677 0.079 + 2 25 23 48 V -44478.005 0.972 8623.0686 0.0202 B- -1656.6918 7.3746 47 952250.900 1.043 + 0 24 24 48 Cr +nn -42821.313 7.311 8572.2553 0.1523 B- -13524.6692 9.9157 47 954029.431 7.848 + -2 23 25 48 Mn -29296.644 6.699 8274.1924 0.1396 B- -11288.0685 92.4609 47 968548.760 7.191 + -4 22 26 48 Fe x -18008.575 92.218 8022.7254 1.9212 B- -19738# 509# 47 980667.000 99.000 + -6 21 27 48 Co x 1730# 500# 7595# 10# B- -16448# 656# 48 001857# 537# + -8 20 28 48 Ni -pp 18178# 424# 7236# 9# B- * 48 019515# 455# +0 17 33 16 49 S -n 20391# 583# 7400# 12# B- 19652# 707# 49 021891# 626# + 15 32 17 49 Cl x 740# 400# 7785# 8# B- 17800# 565# 49 000794# 429# + 13 31 18 49 Ar x -17060# 400# 8132# 8# B- 12551# 400# 48 981685# 429# + 11 30 19 49 K x -29611.496 0.801 8372.2753 0.0164 B- 11688.5069 0.8205 48 968210.753 0.860 + 9 29 20 49 Ca -n -41300.003 0.178 8594.8500 0.0036 B- 5262.4445 2.2745 48 955662.625 0.190 + 7 28 21 49 Sc -46562.447 2.268 8686.2805 0.0463 B- 2001.5652 2.2684 48 950013.159 2.434 + 5 27 22 49 Ti -48564.012 0.078 8711.1625 0.0016 B- -601.8555 0.8203 48 947864.391 0.084 + 3 26 23 49 V - -47962.157 0.824 8682.9135 0.0168 B- -2629.8047 2.3487 48 948510.509 0.884 + 1 25 24 49 Cr -45332.352 2.202 8613.2777 0.0449 B- -7712.4265 0.2329 48 951333.720 2.363 + -1 24 25 49 Mn -37619.925 2.214 8439.9150 0.0452 B- -12869.1957 24.3199 48 959613.350 2.377 + -3 23 26 49 Fe x -24750.730 24.219 8161.3121 0.4943 B- -14971# 501# 48 973429.000 26.000 + -5 22 27 49 Co x -9780# 500# 7840# 10# B- -18309# 781# 48 989501# 537# + -7 21 28 49 Ni x 8530# 600# 7450# 12# B- * 49 009157# 644# +0 16 33 17 50 Cl x 7700# 400# 7651# 8# B- 20930# 640# 50 008266# 429# + 14 32 18 50 Ar x -13230# 500# 8054# 10# B- 12498# 500# 49 985797# 537# + 12 31 19 50 K x -25727.853 7.731 8288.5833 0.1546 B- 13861.3774 7.8919 49 972380.015 8.300 + 10 30 20 50 Ca x -39589.230 1.584 8550.1639 0.0317 B- 4947.8903 2.9723 49 957499.215 1.700 + 8 29 21 50 Sc -44537.120 2.515 8633.4747 0.0503 B- 6894.7470 2.5166 49 952187.437 2.700 + 6 28 22 50 Ti -51431.867 0.082 8755.7227 0.0017 B- -2208.6274 0.0579 49 944785.622 0.088 + 4 27 23 50 V -49223.240 0.093 8695.9032 0.0019 B- 1038.1240 0.0551 49 947156.681 0.099 + 2 26 24 50 Cr -50261.364 0.094 8701.0188 0.0019 B- -7634.4776 0.0672 49 946042.209 0.100 + 0 25 25 50 Mn -42626.886 0.115 8532.6823 0.0023 B- -8150.4267 8.3842 49 954238.157 0.123 + -2 24 26 50 Fe x -34476.460 8.383 8354.0268 0.1677 B- -16887.0566 126.0308 49 962988.000 9.000 + -4 23 27 50 Co x -17589.403 125.752 8000.6387 2.5150 B- -14130# 516# 49 981117.000 135.000 + -6 22 28 50 Ni x -3460# 500# 7702# 10# B- * 49 996286# 537# +0 17 34 17 51 Cl x 14290# 700# 7530# 14# B- 20780# 806# 51 015341# 751# + 15 33 18 51 Ar x -6490# 400# 7922# 8# B- 16026# 400# 50 993033# 429# + 13 32 19 51 K x -22515.457 13.041 8221.3350 0.2557 B- 13816.8529 13.0517 50 975828.664 14.000 + 11 31 20 51 Ca x -36332.310 0.522 8476.9135 0.0102 B- 6918.0432 2.5686 50 960995.663 0.560 + 9 30 21 51 Sc -43250.353 2.515 8597.2213 0.0493 B- 6482.6122 2.5612 50 953568.838 2.700 + 7 29 22 51 Ti -49732.965 0.484 8708.9912 0.0095 B- 2470.1402 0.4820 50 946609.468 0.519 + 5 28 23 51 V -52203.105 0.097 8742.0852 0.0019 B- -752.3907 0.1494 50 943957.664 0.104 + 3 27 24 51 Cr -51450.715 0.167 8711.9923 0.0033 B- -3207.4893 0.3256 50 944765.388 0.178 + 1 26 25 51 Mn -48243.225 0.304 8633.7602 0.0060 B- -8054.0400 1.4309 50 948208.770 0.326 + -1 25 26 51 Fe x -40189.185 1.398 8460.4977 0.0274 B- -12847.0389 48.4579 50 956855.137 1.501 + -3 24 27 51 Co x -27342.146 48.438 8193.2549 0.9498 B- -15692# 503# 50 970647.000 52.000 + -5 23 28 51 Ni x -11650# 500# 7870# 10# B- * 50 987493# 537# +0 18 35 17 52 Cl x 22360# 700# 7386# 13# B- 23739# 922# 52 024004# 751# + 16 34 18 52 Ar x -1380# 600# 7827# 12# B- 15758# 601# 51 998519# 644# + 14 33 19 52 K x -17137.628 33.534 8115.0303 0.6449 B- 17128.6431 33.5405 51 981602.000 36.000 + 12 32 20 52 Ca x -34266.272 0.671 8429.3821 0.0129 B- 6257.2889 3.1463 51 963213.646 0.720 + 10 31 21 52 Sc -40523.560 3.074 8534.6695 0.0591 B- 8954.1372 4.1223 51 956496.170 3.300 + 8 30 22 52 Ti -49477.698 2.747 8691.8193 0.0528 B- 1965.3340 2.7510 51 946883.509 2.948 + 6 29 23 52 V -n -51443.032 0.159 8714.5690 0.0031 B- 3976.4763 0.1601 51 944773.636 0.170 + 4 28 24 52 Cr -55419.508 0.112 8775.9946 0.0022 B- -4708.1214 0.0633 51 940504.714 0.120 + 2 27 25 52 Mn - -50711.387 0.129 8670.4087 0.0025 B- -2379.2912 0.1534 51 945559.090 0.138 + 0 26 26 52 Fe -- -48332.095 0.179 8609.6079 0.0035 B- -13988.1167 5.2831 51 948113.364 0.192 + -2 25 27 52 Co -34343.979 5.282 8325.5606 0.1016 B- -11784.1230 83.0710 51 963130.224 5.669 + -4 24 28 52 Ni x -22559.856 82.903 8083.8977 1.5943 B- -20680# 606# 51 975781.000 89.000 + -6 23 29 52 Cu x -1880# 600# 7671# 12# B- * 51 997982# 644# +0 17 35 18 53 Ar x 6791# 699# 7677# 13# B- 19086# 708# 53 007290# 750# + 15 34 19 53 K x -12295.722 111.779 8022.8488 2.1090 B- 17091.9853 120.0471 52 986800.000 120.000 + 13 33 20 53 Ca x -29387.707 43.780 8330.5778 0.8260 B- 9381.8471 47.2223 52 968451.000 47.000 + 11 32 21 53 Sc -38769.555 17.698 8492.8325 0.3339 B- 8111.8785 17.9325 52 958379.173 19.000 + 9 31 22 53 Ti x -46881.433 2.888 8631.1256 0.0545 B- 4970.2419 4.2386 52 949670.714 3.100 + 7 30 23 53 V +p -51851.675 3.103 8710.1425 0.0585 B- 3435.9426 3.1017 52 944334.940 3.331 + 5 29 24 53 Cr -55287.618 0.116 8760.2103 0.0022 B- -597.2679 0.3430 52 940646.304 0.124 + 3 28 25 53 Mn -54690.350 0.346 8734.1798 0.0065 B- -3742.8664 1.6971 52 941287.497 0.371 + 1 27 26 53 Fe -50947.483 1.669 8648.7985 0.0315 B- -8288.1073 0.4431 52 945305.629 1.792 + -1 26 27 53 Co -42659.376 1.727 8477.6578 0.0326 B- -13028.5485 25.2096 52 954203.278 1.854 + -3 25 28 53 Ni x -29630.827 25.150 8217.0749 0.4745 B- -16491# 501# 52 968190.000 27.000 + -5 24 29 53 Cu x -13140# 500# 7891# 9# B- * 52 985894# 537# +0 18 36 18 54 Ar x 12560# 800# 7578# 15# B- 17710# 894# 54 013484# 859# + 16 35 19 54 K x -5150# 400# 7891# 7# B- 20010# 403# 53 994471# 429# + 14 34 20 54 Ca x -25160.587 48.438 8247.4967 0.8970 B- 9277.3463 50.4129 53 972989.000 52.000 + 12 33 21 54 Sc x -34437.934 13.973 8404.8115 0.2588 B- 11305.8789 21.1188 53 963029.359 15.000 + 10 32 22 54 Ti x -45743.812 15.835 8599.6917 0.2932 B- 4154.4548 19.3840 53 950892.000 17.000 + 8 31 23 54 V -49898.267 11.180 8662.1382 0.2070 B- 7037.1118 11.1794 53 946432.009 12.001 + 6 30 24 54 Cr -56935.379 0.132 8777.9672 0.0025 B- -1377.1325 1.0051 53 938877.359 0.142 + 4 29 25 54 Mn -p -55558.247 1.007 8737.9768 0.0186 B- 696.3688 1.0587 53 940355.772 1.080 + 2 28 26 54 Fe -56254.615 0.343 8736.3846 0.0064 B- -8244.5478 0.0893 53 939608.189 0.368 + 0 27 27 54 Co -48010.068 0.355 8569.2199 0.0066 B- -8731.7558 4.6710 53 948459.075 0.380 + -2 26 28 54 Ni x -39278.312 4.657 8393.0328 0.0862 B- -18038# 400# 53 957833.000 5.000 + -4 25 29 54 Cu x -21240# 400# 8045# 7# B- -15538# 454# 53 977198# 429# + -6 24 30 54 Zn -pp -5702# 217# 7742# 4# B- * 53 993879# 232# +0 17 36 19 55 K x 470# 500# 7792# 9# B- 19121# 525# 55 000505# 537# + 15 35 20 55 Ca x -18650.375 160.217 8125.9260 2.9130 B- 12191.7329 171.9435 54 979978.000 172.000 + 13 34 21 55 Sc x -30842.108 62.411 8333.3694 1.1347 B- 10990.3608 68.7671 54 966889.637 67.000 + 11 33 22 55 Ti x -41832.469 28.876 8518.9696 0.5250 B- 7292.6673 39.5419 54 955091.000 31.000 + 9 32 23 55 V x -49125.136 27.013 8637.3391 0.4912 B- 5985.1877 27.0143 54 947262.000 29.000 + 7 31 24 55 Cr -n -55110.324 0.228 8731.9362 0.0042 B- 2602.2183 0.3219 54 940836.637 0.245 + 5 30 25 55 Mn -57712.542 0.260 8765.0247 0.0047 B- -231.1204 0.1786 54 938043.040 0.279 + 3 29 26 55 Fe -57481.422 0.308 8746.5981 0.0056 B- -3451.4254 0.3241 54 938291.158 0.330 + 1 28 27 55 Co -54029.996 0.405 8669.6204 0.0074 B- -8694.0350 0.5775 54 941996.416 0.434 + -1 27 28 55 Ni - -45335.961 0.705 8497.3225 0.0128 B- -13700.5585 155.5611 54 951329.846 0.757 + -3 26 29 55 Cu x -31635.403 155.560 8233.9970 2.8284 B- -17366# 429# 54 966038.000 167.000 + -5 25 30 55 Zn x -14270# 400# 7904# 7# B- * 54 984681# 429# +0 18 37 19 56 K x 7980# 600# 7663# 11# B- 21491# 650# 56 008567# 644# + 16 36 20 56 Ca x -13510.390 249.640 8033.1654 4.4579 B- 12005.4580 360.2029 55 985496.000 268.000 + 14 35 21 56 Sc x -25515.848 259.665 8233.5781 4.6369 B- 13907.1470 278.3271 55 972607.611 278.761 + 12 34 22 56 Ti -39422.995 100.201 8467.9495 1.7893 B- 6760.4051 188.1842 55 957677.675 107.569 + 10 33 23 56 V -46183.401 175.884 8574.7006 3.1408 B- 9101.7270 175.8854 55 950420.082 188.819 + 8 32 24 56 Cr ++ -55285.128 0.578 8723.2609 0.0103 B- 1626.5384 0.5524 55 940648.977 0.620 + 6 31 25 56 Mn -n -56911.666 0.293 8738.3358 0.0052 B- 3695.4973 0.2065 55 938902.816 0.314 + 4 30 26 56 Fe -60607.163 0.268 8790.3563 0.0048 B- -4566.6455 0.4104 55 934935.537 0.287 + 2 29 27 56 Co -56040.518 0.475 8694.8386 0.0085 B- -2132.8689 0.3735 55 939838.032 0.510 + 0 28 28 56 Ni -53907.649 0.399 8642.7811 0.0071 B- -15277.9163 6.4070 55 942127.761 0.428 + -2 27 29 56 Cu x -38629.733 6.395 8355.9907 0.1142 B- -13240# 400# 55 958529.278 6.864 + -4 26 30 56 Zn x -25390# 400# 8106# 7# B- -21550# 640# 55 972743# 429# + -6 25 31 56 Ga x -3840# 500# 7707# 9# B- * 55 995878# 537# +0 19 38 19 57 K x 14130# 600# 7563# 11# B- 20689# 721# 57 015169# 644# + 17 37 20 57 Ca x -6560# 400# 7912# 7# B- 14820# 438# 56 992958# 429# + 15 36 21 57 Sc x -21379.653 179.778 8158.1666 3.1540 B- 13022.1957 273.3249 56 977048.000 193.000 + 13 35 22 57 Ti x -34401.848 205.879 8372.9008 3.6119 B- 10033.2148 222.6466 56 963068.098 221.020 + 11 34 23 57 V x -44435.063 84.766 8535.1967 1.4871 B- 8089.9214 84.7864 56 952297.000 91.000 + 9 33 24 57 Cr x -52524.985 1.863 8663.3998 0.0327 B- 4961.2946 2.3948 56 943612.112 2.000 + 7 32 25 57 Mn -57486.279 1.505 8736.7146 0.0264 B- 2695.7375 1.5219 56 938285.944 1.615 + 5 31 26 57 Fe -60182.017 0.268 8770.2829 0.0047 B- -836.3589 0.4493 56 935391.950 0.287 + 3 30 27 57 Co -59345.658 0.516 8741.8845 0.0090 B- -3261.6970 0.6417 56 936289.819 0.553 + 1 29 28 57 Ni -56083.961 0.566 8670.9364 0.0099 B- -8774.9466 0.4393 56 939791.394 0.608 + -1 28 29 57 Cu -47309.014 0.501 8503.2646 0.0088 B- -14759# 200# 56 949211.686 0.537 + -3 27 30 57 Zn x -32550# 200# 8231# 4# B- -17140# 447# 56 965056# 215# + -5 26 31 57 Ga x -15410# 400# 7916# 7# B- * 56 983457# 429# +0 20 39 19 58 K x 21930# 700# 7437# 12# B- 23461# 860# 58 023543# 751# + 18 38 20 58 Ca x -1530# 500# 7828# 9# B- 13949# 535# 57 998357# 537# + 16 37 21 58 Sc x -15479.569 190.025 8054.9436 3.2763 B- 15438.0995 264.0509 57 983382.000 204.000 + 14 36 22 58 Ti x -30917.668 183.340 8307.6290 3.1610 B- 9512.9152 206.8675 57 966808.519 196.823 + 12 35 23 58 V x -40430.584 95.816 8458.1560 1.6520 B- 11561.2240 95.8625 57 956595.985 102.862 + 10 34 24 58 Cr x -51991.808 2.981 8643.9987 0.0514 B- 3835.7607 4.0227 57 944184.501 3.200 + 8 33 25 58 Mn x -55827.568 2.701 8696.6438 0.0466 B- 6327.7027 2.7198 57 940066.643 2.900 + 6 32 26 58 Fe -62155.271 0.316 8792.2534 0.0055 B- -2307.9785 1.1389 57 933273.575 0.339 + 4 31 27 58 Co -59847.292 1.153 8738.9719 0.0199 B- 381.5789 1.1071 57 935751.292 1.237 + 2 30 28 58 Ni -60228.871 0.349 8732.0621 0.0060 B- -8561.0204 0.4425 57 935341.650 0.374 + 0 29 29 58 Cu -51667.851 0.564 8570.9696 0.0097 B- -9368.9796 50.0020 57 944532.283 0.604 + -2 28 30 58 Zn -- -42298.871 50.001 8395.9467 0.8621 B- -18759# 304# 57 954590.296 53.678 + -4 27 31 58 Ga x -23540# 300# 8059# 5# B- -15960# 583# 57 974729# 322# + -6 26 32 58 Ge x -7580# 500# 7770# 9# B- * 57 991863# 537# +0 21 40 19 59 K x 28750# 800# 7332# 14# B- 22940# 1000# 59 030864# 859# + 19 39 20 59 Ca x 5810# 600# 7708# 10# B- 16639# 650# 59 006237# 644# + 17 38 21 59 Sc x -10829.550 249.640 7976.4073 4.2312 B- 15050# 390# 58 988374.000 268.000 + 15 37 22 59 Ti x -25880# 300# 8218# 5# B- 11731# 330# 58 972217# 322# + 13 36 23 59 V x -37610.617 137.400 8403.8034 2.3288 B- 10505.3137 137.4021 58 959623.343 147.505 + 11 35 24 59 Cr x -48115.931 0.671 8568.5995 0.0114 B- 7409.3977 2.4234 58 948345.426 0.720 + 9 34 25 59 Mn x -55525.328 2.329 8680.9224 0.0395 B- 5139.6290 2.3520 58 940391.111 2.500 + 7 33 26 59 Fe -60664.957 0.330 8754.7746 0.0056 B- 1564.8804 0.3690 58 934873.492 0.354 + 5 32 27 59 Co -62229.838 0.397 8768.0379 0.0067 B- -1073.0050 0.1944 58 933193.524 0.426 + 3 31 28 59 Ni -61156.833 0.351 8736.5912 0.0060 B- -4798.3786 0.3973 58 934345.442 0.376 + 1 30 29 59 Cu -56358.454 0.528 8642.0027 0.0090 B- -9142.7760 0.6018 58 939496.713 0.566 + -1 29 30 59 Zn -47215.678 0.759 8473.7802 0.0129 B- -13456# 170# 58 949311.886 0.814 + -3 28 31 59 Ga x -33760# 170# 8232# 3# B- -17390# 434# 58 963757# 183# + -5 27 32 59 Ge x -16370# 400# 7924# 7# B- * 58 982426# 429# +0 20 40 20 60 Ca x 11000# 700# 7627# 12# B- 15550# 860# 60 011809# 751# + 18 39 21 60 Sc x -4550# 500# 7873# 8# B- 17549# 555# 59 995115# 537# + 16 38 22 60 Ti x -22099.698 240.325 8152.7858 4.0054 B- 10987.7040 301.4311 59 976275.000 258.000 + 14 37 23 60 V x -33087.402 181.946 8322.8751 3.0324 B- 13821.0986 181.9496 59 964479.215 195.327 + 12 36 24 60 Cr x -46908.500 1.118 8540.1876 0.0186 B- 6059.4457 2.5831 59 949641.656 1.200 + 10 35 25 60 Mn x -52967.946 2.329 8628.1392 0.0388 B- 8445.2283 4.1261 59 943136.574 2.500 + 8 34 26 60 Fe -nn -61413.174 3.406 8755.8539 0.0568 B- 237.2633 3.4106 59 934070.249 3.656 + 6 33 27 60 Co -n -61650.437 0.403 8746.7692 0.0067 B- 2822.8058 0.2124 59 933815.536 0.433 + 4 32 28 60 Ni -64473.243 0.353 8780.7769 0.0059 B- -6127.9810 1.5735 59 930785.129 0.378 + 2 31 29 60 Cu - -58345.262 1.613 8665.6047 0.0269 B- -4170.7922 1.6286 59 937363.787 1.731 + 0 30 30 60 Zn -54174.470 0.548 8583.0524 0.0091 B- -14584# 200# 59 941841.317 0.588 + -2 29 31 60 Ga x -39590# 200# 8327# 3# B- -12060# 361# 59 957498# 215# + -4 28 32 60 Ge x -27530# 300# 8113# 5# B- -21890# 500# 59 970445# 322# + -6 27 33 60 As x -5640# 400# 7735# 7# B- * 59 993945# 429# +0 21 41 20 61 Ca x 19010# 800# 7503# 13# B- 18510# 1000# 61 020408# 859# + 19 40 21 61 Sc x 500# 600# 7794# 10# B- 16870# 671# 61 000537# 644# + 17 39 22 61 Ti x -16370# 300# 8058# 5# B- 13807# 381# 60 982426# 322# + 15 38 23 61 V x -30177.121 234.920 8271.0417 3.8511 B- 12319.3807 234.9272 60 967603.529 252.196 + 13 37 24 61 Cr x -42496.502 1.863 8460.1734 0.0305 B- 9245.6277 2.9822 60 954378.130 2.000 + 11 36 25 61 Mn x -51742.130 2.329 8598.9157 0.0382 B- 7178.3730 3.4965 60 944452.541 2.500 + 9 35 26 61 Fe x -58920.503 2.608 8703.7686 0.0428 B- 3977.6759 2.7399 60 936746.241 2.800 + 7 34 27 61 Co p2n -62898.179 0.839 8756.1510 0.0138 B- 1323.8504 0.7899 60 932476.031 0.901 + 5 33 28 61 Ni -64222.029 0.355 8765.0281 0.0058 B- -2237.9663 0.9617 60 931054.819 0.381 + 3 32 29 61 Cu p2n -61984.063 0.951 8715.5148 0.0156 B- -5635.1565 15.9028 60 933457.375 1.020 + 1 31 30 61 Zn -56348.906 15.899 8610.3098 0.2606 B- -9214.2438 37.6786 60 939506.964 17.068 + -1 30 31 61 Ga -47134.662 37.994 8446.4313 0.6228 B- -13345# 302# 60 949398.861 40.787 + -3 29 32 61 Ge x -33790# 300# 8215# 5# B- -16590# 424# 60 963725# 322# + -5 28 33 61 As x -17200# 300# 7930# 5# B- * 60 981535# 322# +0 20 41 21 62 Sc x 7310# 600# 7688# 10# B- 19510# 721# 62 007848# 644# + 18 40 22 62 Ti x -12200# 400# 7990# 6# B- 13013# 479# 61 986903# 429# + 16 39 23 62 V x -25213.164 264.287 8187.7565 4.2627 B- 15639.4478 264.3094 61 972932.556 283.723 + 14 38 24 62 Cr x -40852.611 3.447 8427.3871 0.0556 B- 7671.3532 7.3947 61 956142.920 3.700 + 12 37 25 62 Mn IT -48523.965 6.542 8538.5002 0.1055 B- 10354.0920 7.1142 61 947907.384 7.023 + 10 36 26 62 Fe x -58878.057 2.794 8692.8831 0.0451 B- 2546.3427 18.7834 61 936791.809 3.000 + 8 35 27 62 Co + -61424.399 18.574 8721.3347 0.2996 B- 5322.0404 18.5695 61 934058.198 19.940 + 6 34 28 62 Ni -66746.440 0.425 8794.5555 0.0069 B- -3958.8965 0.4751 61 928344.753 0.455 + 4 33 29 62 Cu - -62787.543 0.637 8718.0839 0.0103 B- -1619.4548 0.6507 61 932594.803 0.683 + 2 32 30 62 Zn -61168.088 0.615 8679.3451 0.0099 B- -9181.0666 0.3763 61 934333.359 0.660 + 0 31 31 62 Ga -51987.022 0.637 8518.6449 0.0103 B- -9847# 140# 61 944189.639 0.684 + -2 30 32 62 Ge x -42140# 140# 8347# 2# B- -17720# 331# 61 954761# 150# + -4 29 33 62 As x -24420# 300# 8049# 5# B- * 61 973784# 322# +0 21 42 21 63 Sc x 13070# 700# 7603# 11# B- 18930# 860# 63 014031# 751# + 19 41 22 63 Ti x -5860# 500# 7891# 8# B- 15880# 605# 62 993709# 537# + 17 40 23 63 V x -21740.141 339.995 8130.7809 5.3968 B- 14438.1586 347.6720 62 976661.000 365.000 + 15 39 24 63 Cr x -36178.299 72.657 8347.5398 1.1533 B- 10708.7611 72.7520 62 961161.000 78.000 + 13 38 25 63 Mn x -46887.061 3.726 8505.1020 0.0591 B- 8748.5685 5.6915 62 949664.672 4.000 + 11 37 26 63 Fe -55635.629 4.302 8631.5499 0.0683 B- 6215.9238 19.0668 62 940272.698 4.618 + 9 36 27 63 Co -61851.553 18.575 8717.7972 0.2948 B- 3661.3385 18.5704 62 933599.630 19.941 + 7 35 28 63 Ni -65512.891 0.426 8763.4955 0.0068 B- 66.9768 0.0149 62 929669.021 0.457 + 5 34 29 63 Cu -65579.868 0.426 8752.1404 0.0068 B- -3366.4392 1.5450 62 929597.119 0.457 + 3 33 30 63 Zn -62213.429 1.560 8686.2866 0.0248 B- -5666.3294 2.0330 62 933211.140 1.674 + 1 32 31 63 Ga x -56547.100 1.304 8583.9267 0.0207 B- -9625.8787 37.2826 62 939294.194 1.400 + -1 31 32 63 Ge x -46921.221 37.260 8418.7167 0.5914 B- -13421# 204# 62 949628.000 40.000 + -3 30 33 63 As x -33500# 200# 8193# 3# B- -16650# 539# 62 964036# 215# + -5 29 34 63 Se x -16850# 500# 7917# 8# B- * 62 981911# 537# +0 20 42 22 64 Ti x -1480# 600# 7826# 9# B- 14840# 721# 63 998411# 644# + 18 41 23 64 V x -16320# 400# 8045# 6# B- 17320# 500# 63 982480# 429# + 16 40 24 64 Cr x -33639.978 299.941 8303.5626 4.6866 B- 9349.0622 299.9620 63 963886.000 322.000 + 14 39 25 64 Mn x -42989.040 3.540 8437.4175 0.0553 B- 11980.5117 6.1402 63 953849.369 3.800 + 12 38 26 64 Fe x -54969.552 5.017 8612.3888 0.0784 B- 4822.8898 20.6249 63 940987.761 5.386 + 10 37 27 64 Co + -59792.442 20.005 8675.5223 0.3126 B- 7306.5921 20.0000 63 935810.176 21.476 + 8 36 28 64 Ni -67099.034 0.463 8777.4637 0.0072 B- -1674.6156 0.2055 63 927966.228 0.497 + 6 35 29 64 Cu -65424.418 0.427 8739.0736 0.0067 B- 579.5996 0.6447 63 929764.001 0.458 + 4 34 30 64 Zn -66004.018 0.644 8735.9057 0.0101 B- -7171.1912 1.4825 63 929141.776 0.690 + 2 33 31 64 Ga -58832.827 1.429 8611.6317 0.0223 B- -4517.3237 3.9905 63 936840.366 1.533 + 0 32 32 64 Ge x -54315.503 3.726 8528.8243 0.0582 B- -14783# 203# 63 941689.912 4.000 + -2 31 33 64 As -p -39532# 203# 8286# 3# B- -12673# 540# 63 957560# 218# + -4 30 34 64 Se x -26860# 500# 8075# 8# B- * 63 971165# 537# +0 21 43 22 65 Ti x 5210# 700# 7726# 11# B- 17320# 860# 65 005593# 751# + 19 42 23 65 V x -12110# 500# 7981# 8# B- 16200# 539# 64 986999# 537# + 17 41 24 65 Cr x -28310# 200# 8218# 3# B- 12657# 200# 64 969608# 215# + 15 40 25 65 Mn x -40967.344 3.726 8400.6822 0.0573 B- 10250.5576 6.3257 64 956019.749 4.000 + 13 39 26 65 Fe x -51217.902 5.112 8546.3470 0.0786 B- 7967.3036 5.5198 64 945015.323 5.487 + 11 38 27 65 Co x -59185.205 2.083 8656.8848 0.0320 B- 5940.5911 2.1379 64 936462.071 2.235 + 9 37 28 65 Ni -n -65125.796 0.483 8736.2424 0.0074 B- 2137.8808 0.6997 64 930084.585 0.518 + 7 36 29 65 Cu -67263.677 0.643 8757.0967 0.0099 B- -1351.6527 0.3557 64 927789.476 0.690 + 5 35 30 65 Zn -65912.024 0.646 8724.2660 0.0099 B- -3254.5380 0.6305 64 929240.534 0.693 + 3 34 31 65 Ga -62657.486 0.791 8662.1601 0.0122 B- -6179.2631 2.3046 64 932734.424 0.849 + 1 33 32 65 Ge -56478.223 2.165 8555.0584 0.0333 B- -9541.1670 84.7936 64 939368.136 2.323 + -1 32 33 65 As x -46937.056 84.766 8396.2351 1.3041 B- -13917# 312# 64 949611.000 91.000 + -3 31 34 65 Se x -33020# 300# 8170# 5# B- -16529# 583# 64 964552# 322# + -5 30 35 65 Br x -16490# 500# 7904# 8# B- * 64 982297# 537# +0 20 43 23 66 V x -6300# 500# 7894# 8# B- 18840# 583# 65 993237# 537# + 18 42 24 66 Cr x -25140# 300# 8168# 5# B- 11610# 300# 65 973011# 322# + 16 41 25 66 Mn x -36750.392 11.178 8331.7986 0.1694 B- 13317.4543 11.9056 65 960546.833 12.000 + 14 40 26 66 Fe x -50067.847 4.099 8521.7245 0.0621 B- 6340.6944 14.5611 65 946249.958 4.400 + 12 39 27 66 Co x -56408.541 13.972 8605.9419 0.2117 B- 9597.7522 14.0421 65 939442.943 15.000 + 10 38 28 66 Ni x -66006.293 1.397 8739.5086 0.0212 B- 251.9958 1.5405 65 929139.333 1.500 + 8 37 29 66 Cu -66258.289 0.649 8731.4730 0.0098 B- 2640.9396 0.9255 65 928868.804 0.696 + 6 36 30 66 Zn -68899.229 0.744 8759.6335 0.0113 B- -5175.5000 0.8000 65 926033.639 0.798 + 4 35 31 66 Ga - -63723.729 1.092 8669.3631 0.0166 B- -2116.6879 2.6376 65 931589.766 1.172 + 2 34 32 66 Ge x -61607.041 2.401 8625.4383 0.0364 B- -9581.9570 6.1685 65 933862.124 2.577 + 0 33 33 66 As x -52025.084 5.682 8468.4034 0.0861 B- -10365# 200# 65 944148.778 6.100 + -2 32 34 66 Se x -41660# 200# 8300# 3# B- -18091# 447# 65 955276# 215# + -4 31 35 66 Br x -23570# 400# 8014# 6# B- * 65 974697# 429# +0 21 44 23 67 V x -1744# 600# 7829# 9# B- 17526# 721# 66 998128# 644# + 19 43 24 67 Cr x -19270# 400# 8079# 6# B- 14311# 447# 66 979313# 429# + 17 42 25 67 Mn x -33580# 200# 8281# 3# B- 12128# 200# 66 963950# 215# + 15 41 26 67 Fe x -45708.416 3.819 8449.9359 0.0570 B- 9613.3678 7.4900 66 950930.000 4.100 + 13 40 27 67 Co x -55321.783 6.443 8581.7422 0.0962 B- 8420.9047 7.0607 66 940609.625 6.917 + 11 39 28 67 Ni x -63742.688 2.888 8695.7505 0.0431 B- 3576.8654 3.0223 66 931569.413 3.100 + 9 38 29 67 Cu -67319.553 0.892 8737.4597 0.0133 B- 560.8226 0.8296 66 927729.490 0.957 + 7 37 30 67 Zn -67880.376 0.755 8734.1534 0.0113 B- -1001.2201 1.1196 66 927127.422 0.810 + 5 36 31 67 Ga -66879.156 1.176 8707.5330 0.0176 B- -4205.4380 4.4066 66 928202.276 1.262 + 3 35 32 67 Ge -62673.718 4.319 8633.0884 0.0645 B- -6086.4858 4.3418 66 932716.999 4.636 + 1 34 33 67 As -56587.232 0.443 8530.5685 0.0066 B- -10006.9381 67.0690 66 939251.110 0.475 + -1 33 34 67 Se x -46580.294 67.068 8369.5344 1.0010 B- -14051# 307# 66 949994.000 72.000 + -3 32 35 67 Br x -32530# 300# 8148# 4# B- -16978# 520# 66 965078# 322# + -5 31 36 67 Kr -pp -15552# 424# 7883# 6# B- * 66 983305# 455# +0 20 44 24 68 Cr x -15690# 500# 8026# 7# B- 13230# 583# 67 983156# 537# + 18 43 25 68 Mn x -28920# 300# 8209# 4# B- 14977# 356# 67 968953# 322# + 16 42 26 68 Fe x -43897# 193# 8418# 3# B- 7746# 193# 67 952875# 207# + 14 41 27 68 Co -51642.591 3.859 8520.1301 0.0567 B- 11821.2318 4.8760 67 944559.401 4.142 + 12 40 28 68 Ni x -63463.822 2.981 8682.4667 0.0438 B- 2103.2205 3.3753 67 931868.787 3.200 + 10 39 29 68 Cu x -65567.043 1.584 8701.8913 0.0233 B- 4440.1115 1.7645 67 929610.887 1.700 + 8 38 30 68 Zn -70007.154 0.778 8755.6820 0.0115 B- -2921.1000 1.2000 67 924844.232 0.835 + 6 37 31 68 Ga - -67086.054 1.430 8701.2195 0.0210 B- -107.2555 2.3594 67 927980.161 1.535 + 4 36 32 68 Ge x -66978.799 1.876 8688.1371 0.0276 B- -8084.2715 2.6320 67 928095.305 2.014 + 2 35 33 68 As -58894.527 1.846 8557.7457 0.0271 B- -4705.0786 1.9112 67 936774.127 1.981 + 0 34 34 68 Se x -54189.449 0.496 8477.0482 0.0073 B- -15398# 259# 67 941825.236 0.532 + -2 33 35 68 Br -p -38791# 259# 8239# 4# B- -13165# 563# 67 958356# 278# + -4 32 36 68 Kr x -25626# 500# 8034# 7# B- * 67 972489# 537# +0 21 45 24 69 Cr x -9630# 500# 7939# 7# B- 15730# 640# 68 989662# 537# + 19 44 25 69 Mn x -25360# 400# 8155# 6# B- 13839# 447# 68 972775# 429# + 17 43 26 69 Fe x -39199# 200# 8345# 3# B- 11186# 218# 68 957918# 215# + 15 42 27 69 Co x -50385.447 85.697 8495.4062 1.2420 B- 9593.2084 85.7784 68 945909.000 92.000 + 13 41 28 69 Ni x -59978.656 3.726 8623.0998 0.0540 B- 5757.5650 3.9793 68 935610.267 4.000 + 11 40 29 69 Cu x -65736.221 1.397 8695.2044 0.0203 B- 2681.6854 1.6075 68 929429.267 1.500 + 9 39 30 69 Zn -n -68417.906 0.795 8722.7311 0.0115 B- 909.9134 1.4234 68 926550.360 0.853 + 7 38 31 69 Ga -69327.820 1.197 8724.5798 0.0174 B- -2227.1455 0.5500 68 925573.528 1.285 + 5 37 32 69 Ge -67100.674 1.318 8680.9640 0.0191 B- -3988.4927 31.9822 68 927964.467 1.414 + 3 36 33 69 As -63112.181 31.999 8611.8214 0.4638 B- -6677.4672 32.0215 68 932246.289 34.352 + 1 35 34 69 Se -56434.714 1.490 8503.7082 0.0216 B- -10175.2364 42.0293 68 939414.845 1.599 + -1 34 35 69 Br -p -46259.478 42.003 8344.9026 0.6087 B- -14119# 303# 68 950338.410 45.091 + -3 33 36 69 Kr x -32140# 300# 8129# 4# B- * 68 965496# 322# +0 22 46 24 70 Cr x -5640# 600# 7884# 9# B- 14810# 781# 69 993945# 644# + 20 45 25 70 Mn x -20450# 500# 8084# 7# B- 16440# 583# 69 978046# 537# + 18 44 26 70 Fe x -36890# 300# 8308# 4# B- 9635# 300# 69 960397# 322# + 16 43 27 70 Co x -46524.963 10.992 8434.1980 0.1570 B- 12688.9049 11.1987 69 950053.400 11.800 + 14 42 28 70 Ni x -59213.868 2.144 8604.2917 0.0306 B- 3762.5123 2.4011 69 936431.300 2.301 + 12 41 29 70 Cu x -62976.381 1.082 8646.8655 0.0155 B- 6588.3675 2.2018 69 932392.078 1.161 + 10 40 30 70 Zn -69564.748 1.918 8729.8086 0.0274 B- -654.5979 1.5737 69 925319.175 2.058 + 8 39 31 70 Ga -68910.150 1.201 8709.2808 0.0172 B- 1651.8861 1.4520 69 926021.914 1.289 + 6 38 32 70 Ge -70562.036 0.820 8721.7028 0.0117 B- -6228.0630 1.6200 69 924248.542 0.880 + 4 37 33 70 As x -64333.973 1.397 8621.5541 0.0200 B- -2404.0737 2.1118 69 930934.642 1.500 + 2 36 34 70 Se x -61929.900 1.584 8576.0338 0.0226 B- -10504.2727 14.9878 69 933515.521 1.700 + 0 35 35 70 Br x -51425.627 14.904 8414.7964 0.2129 B- -10325# 201# 69 944792.321 16.000 + -2 34 36 70 Kr x -41100# 200# 8256# 3# B- * 69 955877# 215# +0 21 46 25 71 Mn x -16620# 500# 8030# 7# B- 15310# 640# 70 982158# 537# + 19 45 26 71 Fe x -31930# 400# 8235# 6# B- 12440# 613# 70 965722# 429# + 17 44 27 71 Co x -44369.930 465.030 8398.7344 6.5497 B- 11036.3053 465.0353 70 952366.923 499.230 + 15 43 28 71 Ni x -55406.236 2.237 8543.1564 0.0315 B- 7304.8989 2.6879 70 940518.962 2.401 + 13 42 29 71 Cu x -62711.134 1.490 8635.0233 0.0210 B- 4617.6517 3.0437 70 932676.831 1.600 + 11 41 30 71 Zn -67328.786 2.654 8689.0417 0.0374 B- 2810.3405 2.7748 70 927719.578 2.849 + 9 40 31 71 Ga -70139.127 0.811 8717.6050 0.0114 B- -232.4698 0.0934 70 924702.554 0.870 + 7 39 32 71 Ge -69906.657 0.815 8703.3118 0.0115 B- -2013.4000 4.0825 70 924952.120 0.874 + 5 38 33 71 As - -67893.257 4.163 8663.9350 0.0586 B- -4746.7420 5.0140 70 927113.594 4.469 + 3 37 34 71 Se x -63146.515 2.794 8586.0606 0.0394 B- -6644.0883 6.0820 70 932209.431 3.000 + 1 36 35 71 Br -56502.426 5.402 8481.4629 0.0761 B- -10175.2155 128.8452 70 939342.153 5.799 + -1 35 36 71 Kr -46327.211 128.769 8327.1310 1.8136 B- -14037# 420# 70 950265.695 138.238 + -3 34 37 71 Rb x -32290# 400# 8118# 6# B- * 70 965335# 429# +0 22 47 25 72 Mn x -11170# 600# 7955# 8# B- 18080# 781# 71 988009# 644# + 20 46 26 72 Fe x -29250# 500# 8195# 7# B- 11050# 583# 71 968599# 537# + 18 45 27 72 Co x -40300# 300# 8338# 4# B- 13926# 300# 71 956736# 322# + 16 44 28 72 Ni x -54226.068 2.237 8520.2118 0.0311 B- 5556.9381 2.6374 71 941785.924 2.401 + 14 43 29 72 Cu x -59783.006 1.397 8586.5256 0.0194 B- 8362.4883 2.5578 71 935820.306 1.500 + 12 42 30 72 Zn x -68145.495 2.142 8691.8053 0.0298 B- 442.7892 2.2934 71 926842.806 2.300 + 10 41 31 72 Ga -68588.284 0.818 8687.0893 0.0114 B- 3997.6263 0.8217 71 926367.452 0.878 + 8 40 32 72 Ge -72585.910 0.076 8731.7459 0.0011 B- -4356.1019 4.0825 71 922075.824 0.081 + 6 39 33 72 As - -68229.808 4.083 8660.3786 0.0567 B- -361.6194 4.5276 71 926752.291 4.383 + 4 38 34 72 Se x -67868.189 1.956 8644.4902 0.0272 B- -8806.4384 2.2083 71 927140.506 2.100 + 2 37 35 72 Br x -59061.750 1.025 8511.3126 0.0142 B- -5121.1683 8.0761 71 936594.606 1.100 + 0 36 36 72 Kr x -53940.582 8.011 8429.3193 0.1113 B- -15611# 500# 71 942092.406 8.600 + -2 35 37 72 Rb x -38330# 500# 8202# 7# B- * 71 958851# 537# +0 23 48 25 73 Mn x -6700# 600# 7895# 8# B- 17289# 781# 72 992807# 644# + 21 47 26 73 Fe x -23990# 500# 8121# 7# B- 13980# 583# 72 974246# 537# + 19 46 27 73 Co x -37970# 300# 8302# 4# B- 12139# 300# 72 959238# 322# + 17 45 28 73 Ni x -50108.159 2.423 8457.6529 0.0332 B- 8879.2856 3.1038 72 946206.681 2.601 + 15 44 29 73 Cu -58987.445 1.942 8568.5699 0.0266 B- 6605.9659 2.6910 72 936674.376 2.084 + 13 43 30 73 Zn x -65593.411 1.863 8648.3455 0.0255 B- 4105.9329 2.5064 72 929582.580 2.000 + 11 42 31 73 Ga x -69699.343 1.677 8693.8740 0.0230 B- 1598.1889 1.6777 72 925174.680 1.800 + 9 41 32 73 Ge -71297.532 0.057 8705.0500 0.0008 B- -344.7759 3.8528 72 923458.954 0.061 + 7 40 33 73 As -70952.757 3.853 8689.6099 0.0528 B- -2725.3604 7.3993 72 923829.086 4.136 + 5 39 34 73 Se -68227.396 7.424 8641.5591 0.1017 B- -4581.6095 10.0278 72 926754.881 7.969 + 3 38 35 73 Br -63645.787 6.741 8568.0803 0.0923 B- -7094.0287 9.4187 72 931673.441 7.237 + 1 37 36 73 Kr x -56551.758 6.578 8460.1847 0.0901 B- -10540.1468 41.3212 72 939289.193 7.061 + -1 36 37 73 Rb -p -46011.611 40.794 8305.0821 0.5588 B- -14061# 403# 72 950604.506 43.794 + -3 35 38 73 Sr x -31950# 401# 8102# 5# B- * 72 965700# 430# +0 22 48 26 74 Fe x -20660# 500# 8076# 7# B- 12881# 640# 73 977821# 537# + 20 47 27 74 Co x -33540# 400# 8239# 5# B- 15160# 447# 73 963993# 429# + 18 46 28 74 Ni x -48700# 200# 8433# 3# B- 7306# 200# 73 947718# 215# + 16 45 29 74 Cu x -56006.213 6.148 8521.5633 0.0831 B- 9750.5077 6.6424 73 939874.860 6.600 + 14 44 30 74 Zn x -65756.720 2.515 8642.7547 0.0340 B- 2292.9057 3.9102 73 929407.260 2.700 + 12 43 31 74 Ga x -68049.626 2.994 8663.1676 0.0405 B- 5372.8249 2.9941 73 926945.725 3.214 + 10 42 32 74 Ge -73422.451 0.013 8725.2011 0.0003 B- -2562.3871 1.6931 73 921177.760 0.013 + 8 41 33 74 As -70860.064 1.693 8680.0020 0.0229 B- 1353.1467 1.6931 73 923928.596 1.817 + 6 40 34 74 Se -72213.210 0.015 8687.7155 0.0003 B- -6925.0492 5.8354 73 922475.933 0.015 + 4 39 35 74 Br -65288.161 5.835 8583.5615 0.0789 B- -2956.3173 6.1730 73 929910.279 6.264 + 2 38 36 74 Kr -62331.844 2.013 8533.0390 0.0272 B- -10415.8280 3.4240 73 933084.016 2.161 + 0 37 37 74 Rb -51916.016 3.027 8381.7123 0.0409 B- -11089# 100# 73 944265.867 3.249 + -2 36 38 74 Sr x -40827# 100# 8221# 1# B- * 73 956170# 107# +0 23 49 26 75 Fe x -14700# 600# 7996# 8# B- 15861# 721# 74 984219# 644# + 21 48 27 75 Co x -30560# 400# 8197# 5# B- 13680# 447# 74 967192# 429# + 19 47 28 75 Ni x -44240# 200# 8369# 3# B- 10230# 200# 74 952506# 215# + 17 46 29 75 Cu -54470.219 0.718 8495.0801 0.0096 B- 8088.6967 2.0837 74 941523.817 0.770 + 15 45 30 75 Zn x -62558.916 1.956 8592.4981 0.0261 B- 5901.7231 2.0679 74 932840.244 2.100 + 13 44 31 75 Ga x -68460.639 0.671 8660.7565 0.0089 B- 3396.3337 0.6727 74 926504.484 0.720 + 11 43 32 75 Ge -n -71856.973 0.052 8695.6096 0.0007 B- 1177.2301 0.8851 74 922858.370 0.055 + 9 42 33 75 As -73034.203 0.884 8700.8748 0.0118 B- -864.7139 0.8816 74 921594.562 0.948 + 7 41 34 75 Se -72169.489 0.073 8678.9139 0.0010 B- -3062.4694 4.2855 74 922522.870 0.078 + 5 40 35 75 Br x -69107.020 4.285 8627.6497 0.0571 B- -4783.3880 9.1671 74 925810.566 4.600 + 3 39 36 75 Kr x -64323.632 8.104 8553.4399 0.1081 B- -7104.9299 8.1895 74 930945.744 8.700 + 1 38 37 75 Rb x -57218.702 1.180 8448.2762 0.0157 B- -10600.0000 220.0000 74 938573.200 1.266 + -1 37 38 75 Sr - -46618.702 220.003 8296.5116 2.9334 B- -14799# 372# 74 949952.767 236.183 + -3 36 39 75 Y x -31820# 300# 8089# 4# B- * 74 965840# 322# +0 24 50 26 76 Fe x -10590# 600# 7943# 8# B- 15070# 781# 75 988631# 644# + 22 49 27 76 Co x -25660# 500# 8131# 7# B- 16530# 583# 75 972453# 537# + 20 48 28 76 Ni x -42190# 300# 8338# 4# B- 8791# 300# 75 954707# 322# + 18 47 29 76 Cu x -50981.627 0.913 8443.6018 0.0120 B- 11321.3964 1.7183 75 945268.974 0.980 + 16 46 30 76 Zn -62303.024 1.456 8582.2735 0.0192 B- 3993.6241 2.4384 75 933114.956 1.562 + 14 45 31 76 Ga x -66296.648 1.956 8624.5272 0.0257 B- 6916.2501 1.9562 75 928827.624 2.100 + 12 44 32 76 Ge -73212.898 0.018 8705.2364 0.0003 B- -921.5145 0.8864 75 921402.725 0.019 + 10 43 33 76 As -n -72291.384 0.886 8682.8172 0.0117 B- 2960.5756 0.8864 75 922392.011 0.951 + 8 42 34 76 Se -75251.959 0.016 8711.4781 0.0003 B- -4962.8810 9.3218 75 919213.702 0.017 + 6 41 35 76 Br - -70289.078 9.322 8635.8830 0.1227 B- -1275.3724 10.1490 75 924541.574 10.007 + 4 40 36 76 Kr -69013.706 4.013 8608.8077 0.0528 B- -8534.6172 4.1214 75 925910.743 4.308 + 2 39 37 76 Rb x -60479.089 0.938 8486.2161 0.0123 B- -6231.4432 34.4780 75 935073.031 1.006 + 0 38 38 76 Sr x -54247.645 34.465 8393.9294 0.4535 B- -15998# 302# 75 941762.760 37.000 + -2 37 39 76 Y x -38250# 300# 8173# 4# B- * 75 958937# 322# +0 23 50 27 77 Co x -21910# 600# 8082# 8# B- 15440# 721# 76 976479# 644# + 21 49 28 77 Ni x -37350# 400# 8272# 5# B- 11513# 400# 76 959903# 429# + 19 48 29 77 Cu x -48862.828 1.211 8411.2501 0.0157 B- 9926.3750 2.3148 76 947543.599 1.300 + 17 47 30 77 Zn -58789.203 1.973 8530.0037 0.0256 B- 7203.1495 3.1237 76 936887.197 2.117 + 15 46 31 77 Ga x -65992.352 2.422 8613.3907 0.0315 B- 5220.5176 2.4225 76 929154.299 2.600 + 13 45 32 77 Ge -n -71212.870 0.053 8671.0293 0.0007 B- 2703.4642 1.6926 76 923549.843 0.056 + 11 44 33 77 As -73916.334 1.692 8695.9789 0.0220 B- 683.1627 1.6920 76 920647.555 1.816 + 9 43 34 77 Se -74599.497 0.062 8694.6908 0.0008 B- -1364.6792 2.8099 76 919914.150 0.067 + 7 42 35 77 Br - -73234.818 2.811 8666.8073 0.0365 B- -3065.3663 3.4244 76 921379.193 3.017 + 5 41 36 77 Kr x -70169.451 1.956 8616.8370 0.0254 B- -5338.9516 2.3510 76 924669.999 2.100 + 3 40 37 77 Rb x -64830.500 1.304 8537.3396 0.0169 B- -7027.0566 8.0244 76 930401.599 1.400 + 1 39 38 77 Sr x -57803.443 7.918 8435.9188 0.1028 B- -11365# 203# 76 937945.454 8.500 + -1 38 39 77 Y -p -46439# 203# 8278# 3# B- -14839# 448# 76 950146# 218# + -3 37 40 77 Zr x -31600# 400# 8075# 5# B- * 76 966076# 429# +0 24 51 27 78 Co x -15320# 700# 7997# 9# B- 19560# 806# 77 983553# 751# + 22 50 28 78 Ni x -34880# 400# 8238# 5# B- 9910# 400# 77 962555# 429# + 20 49 29 78 Cu -44789.474 13.332 8354.6695 0.1709 B- 12693.7680 13.4727 77 951916.524 14.312 + 18 48 30 78 Zn -57483.242 1.944 8507.3800 0.0249 B- 6220.8433 2.2088 77 938289.204 2.086 + 16 47 31 78 Ga -63704.085 1.051 8577.1043 0.0135 B- 8157.9729 3.6884 77 931610.854 1.127 + 14 46 32 78 Ge -nn -71862.058 3.536 8671.6636 0.0453 B- 954.9114 10.3987 77 922852.911 3.795 + 12 45 33 78 As +pn -72816.970 9.779 8673.8760 0.1254 B- 4208.9819 9.7801 77 921827.771 10.498 + 10 44 34 78 Se -77025.952 0.179 8717.8072 0.0023 B- -3573.7836 3.5750 77 917309.244 0.191 + 8 43 35 78 Br - -73452.168 3.580 8661.9594 0.0459 B- 726.1153 3.5845 77 921145.858 3.842 + 6 42 36 78 Kr -74178.283 0.307 8661.2385 0.0039 B- -7242.8560 3.2520 77 920366.341 0.329 + 4 41 37 78 Rb x -66935.427 3.237 8558.3512 0.0415 B- -3761.4779 8.1248 77 928141.866 3.475 + 2 40 38 78 Sr x -63173.949 7.452 8500.0971 0.0955 B- -11001# 298# 77 932179.979 8.000 + 0 39 39 78 Y x -52173# 298# 8349# 4# B- -11323# 499# 77 943990# 320# + -2 38 40 78 Zr x -40850# 400# 8194# 5# B- * 77 956146# 429# +0 23 51 28 79 Ni x -28160# 500# 8150# 6# B- 14248# 511# 78 969769# 537# + 21 50 29 79 Cu x -42408.039 104.979 8320.9380 1.3289 B- 11024.2629 105.0030 78 954473.100 112.700 + 19 49 30 79 Zn -53432.302 2.225 8450.5825 0.0282 B- 9116.0536 2.5295 78 942638.067 2.388 + 17 48 31 79 Ga -62548.355 1.208 8556.0725 0.0153 B- 6978.8242 37.1467 78 932851.582 1.296 + 15 47 32 79 Ge -69527.180 37.161 8634.5089 0.4704 B- 4108.9014 37.4361 78 925359.506 39.893 + 13 46 33 79 As -73636.081 5.325 8676.6172 0.0674 B- 2281.3849 5.3284 78 920948.419 5.716 + 11 45 34 79 Se -n -75917.466 0.223 8695.5923 0.0028 B- 150.6016 1.0186 78 918499.252 0.238 + 9 44 35 79 Br -76068.067 1.001 8687.5956 0.0127 B- -1625.7778 3.3333 78 918337.574 1.074 + 7 43 36 79 Kr - -74442.290 3.480 8657.1130 0.0441 B- -3639.5114 3.9423 78 920082.919 3.736 + 5 42 37 79 Rb -70802.778 1.943 8601.1401 0.0246 B- -5323.1140 7.5630 78 923990.095 2.085 + 3 41 38 79 Sr -65479.664 7.421 8523.8558 0.0939 B- -7676.7291 80.4515 78 929704.692 7.967 + 1 40 39 79 Y x -57802.935 80.108 8416.7788 1.0140 B- -11033# 310# 78 937946.000 86.000 + -1 39 40 79 Zr x -46770# 300# 8267# 4# B- -15120# 583# 78 949790# 322# + -3 38 41 79 Nb x -31650# 500# 8066# 6# B- * 78 966022# 537# +0 24 52 28 80 Ni x -23240# 600# 8088# 7# B- 13440# 671# 79 975051# 644# + 22 51 29 80 Cu x -36679# 300# 8246# 4# B- 14969# 300# 79 960623# 322# + 20 50 30 80 Zn -51648.619 2.585 8423.5457 0.0323 B- 7575.0553 3.8774 79 944552.929 2.774 + 18 49 31 80 Ga x -59223.675 2.891 8508.4545 0.0361 B- 10311.6397 3.5409 79 936420.773 3.103 + 16 48 32 80 Ge x -69535.314 2.054 8627.5707 0.0257 B- 2679.2869 3.9156 79 925350.773 2.205 + 14 47 33 80 As x -72214.601 3.333 8651.2824 0.0417 B- 5544.8861 3.4412 79 922474.440 3.578 + 12 46 34 80 Se -77759.487 0.947 8710.8142 0.0118 B- -1870.4623 0.3095 79 916521.761 1.016 + 10 45 35 80 Br -75889.025 0.993 8677.6541 0.0124 B- 2004.4299 1.1413 79 918529.784 1.065 + 8 44 36 80 Kr -77893.455 0.695 8692.9301 0.0087 B- -5717.9785 1.9883 79 916377.940 0.745 + 6 43 37 80 Rb x -72175.476 1.863 8611.6760 0.0233 B- -1864.0090 3.9331 79 922516.442 2.000 + 4 42 38 80 Sr x -70311.467 3.464 8578.5966 0.0433 B- -9163.3050 7.1389 79 924517.538 3.718 + 2 41 39 80 Y x -61148.162 6.242 8454.2759 0.0780 B- -6388# 300# 79 934354.750 6.701 + 0 40 40 80 Zr x -54760# 300# 8365# 4# B- -16339# 500# 79 941213# 322# + -2 39 41 80 Nb x -38420# 400# 8151# 5# B- * 79 958754# 429# +0 25 53 28 81 Ni x -16090# 700# 8000# 9# B- 15820# 761# 80 982727# 751# + 23 52 29 81 Cu x -31910# 300# 8185# 4# B- 14289# 300# 80 965743# 322# + 21 51 30 81 Zn x -46199.669 5.030 8351.9262 0.0621 B- 11428.2924 5.9960 80 950402.617 5.400 + 19 50 31 81 Ga x -57627.962 3.264 8483.3576 0.0403 B- 8663.7335 3.8508 80 938133.841 3.503 + 17 49 32 81 Ge x -66291.695 2.055 8580.6587 0.0254 B- 6241.6189 3.3436 80 928832.941 2.205 + 15 48 33 81 As -72533.314 2.644 8648.0571 0.0326 B- 3855.7050 2.8072 80 922132.288 2.838 + 13 47 34 81 Se -76389.019 0.977 8685.9998 0.0121 B- 1588.0317 1.3787 80 917993.019 1.049 + 11 46 35 81 Br -77977.051 0.978 8695.9465 0.0121 B- -280.8517 0.4713 80 916288.197 1.049 + 9 45 36 81 Kr -77696.199 1.074 8682.8206 0.0133 B- -2239.4954 5.0188 80 916589.703 1.152 + 7 44 37 81 Rb -75456.704 4.904 8645.5139 0.0605 B- -3928.5695 5.8170 80 918993.900 5.265 + 5 43 38 81 Sr x -71528.134 3.128 8587.3545 0.0386 B- -5815.2156 6.2451 80 923211.393 3.358 + 3 42 39 81 Y x -65712.919 5.405 8505.9031 0.0667 B- -8188.5003 92.3762 80 929454.283 5.802 + 1 41 40 81 Zr x -57524.418 92.218 8395.1519 1.1385 B- -11164# 410# 80 938245.000 99.000 + -1 40 41 81 Nb x -46360# 400# 8248# 5# B- -14900# 640# 80 950230# 429# + -3 39 42 81 Mo x -31460# 500# 8054# 6# B- * 80 966226# 537# +0 26 54 28 82 Ni x -10720# 800# 7935# 10# B- 15010# 894# 81 988492# 859# + 24 53 29 82 Cu x -25730# 400# 8108# 5# B- 16584# 400# 81 972378# 429# + 22 52 30 82 Zn x -42313.960 3.074 8301.1175 0.0375 B- 10616.7652 3.9162 81 954574.097 3.300 + 20 51 31 82 Ga x -52930.725 2.426 8421.0494 0.0296 B- 12484.3497 3.2960 81 943176.531 2.604 + 18 50 32 82 Ge x -65415.075 2.240 8563.7567 0.0273 B- 4690.3523 4.3452 81 929774.031 2.405 + 16 49 33 82 As x -70105.427 3.729 8611.4153 0.0455 B- 7488.4677 3.7579 81 924738.731 4.003 + 14 48 34 82 Se -77593.895 0.466 8693.1973 0.0057 B- -95.2184 1.0767 81 916699.531 0.500 + 12 47 35 82 Br -77498.677 0.971 8682.4953 0.0118 B- 3093.1185 0.9714 81 916801.752 1.042 + 10 46 36 82 Kr -80591.79509 0.00551 8710.6754 0.0003 B- -4403.9824 3.0088 81 913481.15368 0.00591 + 8 45 37 82 Rb IT -76187.813 3.009 8647.4275 0.0367 B- -177.7503 6.7048 81 918209.023 3.230 + 6 44 38 82 Sr -76010.062 5.992 8635.7190 0.0731 B- -7945.9650 8.1324 81 918399.845 6.432 + 4 43 39 82 Y x -68064.097 5.499 8529.2762 0.0671 B- -4450.0341 5.7221 81 926930.189 5.902 + 2 42 40 82 Zr x -63614.063 1.584 8465.4666 0.0193 B- -11804# 300# 81 931707.497 1.700 + 0 41 41 82 Nb x -51810# 300# 8312# 4# B- -11440# 500# 81 944380# 322# + -2 40 42 82 Mo x -40370# 400# 8163# 5# B- * 81 956661# 429# +0 25 54 29 83 Cu x -20390# 500# 8044# 6# B- 15900# 583# 82 978110# 537# + 23 53 30 83 Zn x -36290# 300# 8226# 4# B- 12967# 300# 82 961041# 322# + 21 52 31 83 Ga x -49257.129 2.612 8372.5756 0.0315 B- 11719.3136 3.5592 82 947120.300 2.804 + 19 51 32 83 Ge x -60976.442 2.427 8504.3462 0.0292 B- 8692.8893 3.6979 82 934539.100 2.604 + 17 50 33 83 As x -69669.331 2.799 8599.6540 0.0337 B- 5671.2117 4.1290 82 925206.900 3.004 + 15 49 34 83 Se -n -75340.543 3.036 8658.5560 0.0366 B- 3673.1780 4.8392 82 919118.604 3.259 + 13 48 35 83 Br -79013.721 3.795 8693.3852 0.0457 B- 976.9222 3.7947 82 915175.285 4.073 + 11 47 36 83 Kr -79990.643 0.009 8695.7295 0.0003 B- -920.0039 2.3288 82 914126.516 0.009 + 9 46 37 83 Rb -79070.639 2.329 8675.2193 0.0281 B- -2273.0239 6.4245 82 915114.181 2.500 + 7 45 38 83 Sr -76797.616 6.834 8638.4076 0.0823 B- -4591.9435 19.8444 82 917554.372 7.336 + 5 44 39 83 Y x -72205.672 18.631 8573.6571 0.2245 B- -6294.0125 19.7074 82 922484.026 20.000 + 3 43 40 83 Zr x -65911.659 6.430 8488.3997 0.0775 B- -8298.7493 162.2075 82 929240.926 6.902 + 1 42 41 83 Nb x -57612.910 162.080 8378.9889 1.9528 B- -11273# 432# 82 938150.000 174.000 + -1 41 42 83 Mo x -46340# 401# 8234# 5# B- -15020# 641# 82 950252# 430# + -3 40 43 83 Tc x -31320# 500# 8043# 6# B- * 82 966377# 537# +0 26 55 29 84 Cu x -13720# 500# 7965# 6# B- 18110# 640# 83 985271# 537# + 24 54 30 84 Zn x -31830# 400# 8171# 5# B- 12264# 401# 83 965829# 429# + 22 53 31 84 Ga x -44094.136 29.808 8307.5250 0.3549 B- 14054.2989 29.9760 83 952663.000 32.000 + 20 52 32 84 Ge x -58148.435 3.171 8465.5244 0.0377 B- 7705.1329 4.4789 83 937575.090 3.403 + 18 51 33 84 As x -65853.568 3.171 8547.9385 0.0377 B- 10094.1624 3.7219 83 929303.290 3.403 + 16 50 34 84 Se -75947.731 1.961 8658.7935 0.0233 B- 1835.3638 25.7652 83 918466.761 2.105 + 14 49 35 84 Br -77783.094 25.730 8671.3294 0.3063 B- 4656.2510 25.7300 83 916496.417 27.622 + 12 48 36 84 Kr -82439.34527 0.00382 8717.4473 0.0003 B- -2680.3708 2.1940 83 911497.72708 0.00410 + 10 47 37 84 Rb -79758.975 2.194 8676.2244 0.0261 B- 890.6058 2.3356 83 914375.223 2.355 + 8 46 38 84 Sr -80649.580 1.243 8677.5132 0.0148 B- -6755.1411 4.4114 83 913419.118 1.334 + 6 45 39 84 Y -73894.439 4.299 8587.7812 0.0512 B- -2472.7471 6.9767 83 920671.060 4.615 + 4 44 40 84 Zr x -71421.692 5.499 8549.0301 0.0655 B- -10227.8497 5.5133 83 923325.663 5.903 + 2 43 41 84 Nb x -61193.842 0.401 8417.9563 0.0048 B- -7024# 298# 83 934305.711 0.430 + 0 42 42 84 Mo x -54170# 298# 8325# 4# B- -16470# 499# 83 941846# 320# + -2 41 43 84 Tc x -37700# 400# 8120# 5# B- * 83 959527# 429# +0 25 55 30 85 Zn x -25100# 500# 8090# 6# B- 14644# 502# 84 973054# 537# + 23 54 31 85 Ga x -39744.059 37.260 8253.5687 0.4384 B- 13379.3679 37.4459 84 957333.000 40.000 + 21 53 32 85 Ge x -53123.427 3.729 8401.7689 0.0439 B- 10065.7253 4.8303 84 942969.658 4.003 + 19 52 33 85 As x -63189.152 3.078 8510.9851 0.0362 B- 9224.4929 4.0313 84 932163.658 3.304 + 17 51 34 85 Se +3p -72413.645 2.613 8610.3045 0.0307 B- 6161.8335 4.0313 84 922260.758 2.804 + 15 50 35 85 Br +n2p -78575.478 3.078 8673.5926 0.0362 B- 2904.8622 3.6705 84 915645.758 3.304 + 13 49 36 85 Kr + -81480.341 2.000 8698.5633 0.0235 B- 687.0000 2.0000 84 912527.260 2.147 + 11 48 37 85 Rb -82167.34065 0.00500 8697.4416 0.0003 B- -1064.0510 2.8132 84 911789.73604 0.00537 + 9 47 38 85 Sr -81103.290 2.813 8675.7193 0.0331 B- -3261.1584 19.1729 84 912932.041 3.020 + 7 46 39 85 Y x -77842.131 18.965 8628.1486 0.2231 B- -4666.9352 20.0257 84 916433.039 20.360 + 5 45 40 85 Zr x -73175.196 6.430 8564.0394 0.0756 B- -6895.5120 7.6250 84 921443.199 6.902 + 3 44 41 85 Nb x -66279.684 4.099 8473.7117 0.0482 B- -8769.9238 16.3572 84 928845.836 4.400 + 1 43 42 85 Mo x -57509.760 15.835 8361.3320 0.1863 B- -11660# 400# 84 938260.736 17.000 + -1 42 43 85 Tc x -45850# 400# 8215# 5# B- -15220# 640# 84 950778# 429# + -3 41 44 85 Ru x -30630# 500# 8027# 6# B- * 84 967117# 537# +0 26 56 30 86 Zn x -20062# 500# 8032# 6# B- 13699# 640# 85 978463# 537# + 24 55 31 86 Ga x -33760# 400# 8182# 5# B- 15640# 593# 85 963757# 429# + 22 54 32 86 Ge x -49399.927 437.802 8354.6300 5.0907 B- 9562.2229 437.8158 85 946967.000 470.000 + 20 53 33 86 As x -58962.150 3.450 8456.7215 0.0401 B- 11541.0256 4.2666 85 936701.532 3.703 + 18 52 34 86 Se x -70503.175 2.520 8581.8224 0.0293 B- 5129.0860 3.9717 85 924311.732 2.705 + 16 51 35 86 Br +pp -75632.261 3.078 8632.3659 0.0358 B- 7633.4147 3.0779 85 918805.432 3.304 + 14 50 36 86 Kr -83265.67593 0.00372 8712.0295 0.0003 B- -518.6734 0.2000 85 910610.62468 0.00399 + 12 49 37 86 Rb -n -82747.003 0.200 8696.9014 0.0023 B- 1776.0972 0.2001 85 911167.443 0.214 + 10 48 38 86 Sr -84523.09977 0.00524 8708.4566 0.0003 B- -5240.0000 14.1421 85 909260.72473 0.00563 + 8 47 39 86 Y - -79283.100 14.142 8638.4293 0.1644 B- -1314.0763 14.5847 85 914886.095 15.182 + 6 46 40 86 Zr -77969.023 3.566 8614.0523 0.0415 B- -8834.9627 6.5521 85 916296.814 3.827 + 4 45 41 86 Nb x -69134.061 5.499 8502.2231 0.0639 B- -5023.1337 6.2316 85 925781.536 5.903 + 2 44 42 86 Mo x -64110.927 2.932 8434.7175 0.0341 B- -12541# 300# 85 931174.092 3.147 + 0 43 43 86 Tc x -51570# 300# 8280# 3# B- -11800# 500# 85 944637# 322# + -2 42 44 86 Ru x -39770# 400# 8133# 5# B- * 85 957305# 429# +0 25 56 31 87 Ga x -28870# 500# 8124# 6# B- 14720# 583# 86 969007# 537# + 23 55 32 87 Ge x -43590# 300# 8285# 3# B- 12028# 300# 86 953204# 322# + 21 54 33 87 As x -55617.914 2.985 8413.8521 0.0343 B- 10808.2192 3.7260 86 940291.716 3.204 + 19 53 34 87 Se x -66426.133 2.241 8529.0920 0.0258 B- 7465.5526 3.8766 86 928688.616 2.405 + 17 52 35 87 Br 2p-n -73891.685 3.171 8605.9105 0.0364 B- 6817.8455 3.1805 86 920674.016 3.404 + 15 51 36 87 Kr -n -80709.531 0.246 8675.2840 0.0028 B- 3888.2706 0.2463 86 913354.759 0.264 + 13 50 37 87 Rb -84597.802 0.006 8710.9843 0.0003 B- 282.2749 0.0063 86 909180.529 0.006 + 11 49 38 87 Sr -84880.07643 0.00513 8705.2363 0.0003 B- -1861.6894 1.1278 86 908877.49454 0.00550 + 9 48 39 87 Y - -83018.387 1.128 8674.8451 0.0130 B- -3671.2405 4.2962 86 910876.100 1.210 + 7 47 40 87 Zr -79347.147 4.146 8623.6545 0.0477 B- -5472.6536 7.9633 86 914817.338 4.450 + 5 46 41 87 Nb x -73874.493 6.802 8551.7579 0.0782 B- -6989.6757 7.3781 86 920692.473 7.302 + 3 45 42 87 Mo -66884.817 2.857 8462.4243 0.0328 B- -9194.7656 5.0729 86 928196.198 3.067 + 1 44 43 87 Tc x -57690.052 4.192 8347.7449 0.0482 B- -11960# 400# 86 938067.185 4.500 + -1 43 44 87 Ru x -45730# 400# 8201# 5# B- * 86 950907# 429# +0 26 57 31 88 Ga x -22390# 500# 8050# 6# B- 17129# 640# 87 975963# 537# + 24 56 32 88 Ge x -39520# 400# 8236# 5# B- 10930# 447# 87 957574# 429# + 22 55 33 88 As x -50450# 200# 8351# 2# B- 13434# 200# 87 945840# 215# + 20 54 34 88 Se x -63884.203 3.357 8495.0045 0.0382 B- 6831.7640 4.6125 87 931417.490 3.604 + 18 53 35 88 Br ++ -70715.967 3.171 8563.7479 0.0360 B- 8975.3282 4.1059 87 924083.290 3.404 + 16 52 36 88 Kr x -79691.295 2.608 8656.8499 0.0296 B- 2917.7090 2.6130 87 914447.879 2.800 + 14 51 37 88 Rb -82609.004 0.159 8681.1154 0.0018 B- 5312.6243 0.1590 87 911315.590 0.170 + 12 50 38 88 Sr -87921.62876 0.00561 8732.5958 0.0003 B- -3622.6000 1.5000 87 905612.253 0.006 + 10 49 39 88 Y - -84299.029 1.500 8682.5396 0.0170 B- -670.1549 5.6076 87 909501.274 1.610 + 8 48 40 88 Zr -83628.874 5.403 8666.0339 0.0614 B- -7457.3187 57.8921 87 910220.715 5.800 + 6 47 41 88 Nb -76171.555 57.808 8572.4013 0.6569 B- -3485.0021 57.9345 87 918226.476 62.059 + 4 46 42 88 Mo x -72686.553 3.819 8523.9087 0.0434 B- -11016.2515 5.6021 87 921967.779 4.100 + 2 45 43 88 Tc x -61670.301 4.099 8389.8338 0.0466 B- -7331# 300# 87 933794.211 4.400 + 0 44 44 88 Ru x -54340# 300# 8298# 3# B- -17479# 500# 87 941664# 322# + -2 43 45 88 Rh x -36860# 400# 8090# 5# B- * 87 960429# 429# +0 25 57 32 89 Ge x -33040# 400# 8161# 4# B- 13490# 500# 88 964530# 429# + 23 56 33 89 As x -46530# 300# 8304# 3# B- 12462# 300# 88 950048# 322# + 21 55 34 89 Se x -58992.398 3.729 8435.2799 0.0419 B- 9281.8730 4.9510 88 936669.058 4.003 + 19 54 35 89 Br x -68274.271 3.264 8530.7802 0.0367 B- 8261.5231 3.9045 88 926704.558 3.504 + 17 53 36 89 Kr x -76535.795 2.142 8614.8158 0.0241 B- 5176.6042 5.8342 88 917835.449 2.300 + 15 52 37 89 Rb -81712.399 5.427 8664.1895 0.0610 B- 4496.6278 5.4265 88 912278.136 5.825 + 13 51 38 89 Sr -86209.026 0.092 8705.9230 0.0011 B- 1502.1757 0.3510 88 907450.808 0.098 + 11 50 39 89 Y -87711.202 0.339 8714.0110 0.0038 B- -2833.2285 2.7652 88 905838.156 0.363 + 9 49 40 89 Zr -84877.974 2.780 8673.3865 0.0312 B- -4252.2191 23.7199 88 908879.751 2.983 + 7 48 41 89 Nb -80625.755 23.630 8616.8184 0.2655 B- -5610.8105 23.9513 88 913444.696 25.367 + 5 47 42 89 Mo x -75014.944 3.912 8544.9851 0.0440 B- -7620.0875 5.4673 88 919468.149 4.200 + 3 46 43 89 Tc x -67394.857 3.819 8450.5758 0.0429 B- -9025.4327 24.5181 88 927648.649 4.100 + 1 45 44 89 Ru x -58369.424 24.219 8340.3760 0.2721 B- -12719# 361# 88 937337.849 26.000 + -1 44 45 89 Rh -p -45651# 361# 8189# 4# B- * 88 950992# 387# +0 26 58 32 90 Ge x -28470# 500# 8109# 6# B- 12520# 640# 89 969436# 537# + 24 57 33 90 As x -40990# 400# 8240# 4# B- 14810# 518# 89 955995# 429# + 22 56 34 90 Se x -55800.223 329.749 8395.7672 3.6639 B- 8200.0834 329.7660 89 940096.000 354.000 + 20 55 35 90 Br x -64000.306 3.357 8478.1865 0.0373 B- 10958.9533 3.8396 89 931292.848 3.604 + 18 54 36 90 Kr x -74959.259 1.863 8591.2599 0.0207 B- 4406.3133 6.7158 89 919527.929 2.000 + 16 53 37 90 Rb -79365.573 6.452 8631.5262 0.0717 B- 6585.3721 6.4806 89 914797.557 6.926 + 14 52 38 90 Sr -85950.945 1.449 8696.0043 0.0161 B- 545.9674 1.4060 89 907727.870 1.555 + 12 51 39 90 Y -86496.912 0.354 8693.3778 0.0039 B- 2275.6350 0.3726 89 907141.749 0.379 + 10 50 40 90 Zr -88772.547 0.118 8709.9699 0.0013 B- -6111.0165 3.3163 89 904698.755 0.126 + 8 49 41 90 Nb -82661.531 3.317 8633.3770 0.0369 B- -2489.0165 3.3163 89 911259.201 3.561 + 6 48 42 90 Mo -80172.514 3.463 8597.0285 0.0385 B- -9447.8181 3.6110 89 913931.270 3.717 + 4 47 43 90 Tc x -70724.696 1.025 8483.3600 0.0114 B- -5840.8951 3.8685 89 924073.919 1.100 + 2 46 44 90 Ru -64883.801 3.730 8409.7684 0.0414 B- -13250# 200# 89 930344.378 4.004 + 0 45 45 90 Rh - -51634# 200# 8254# 2# B- -11924# 447# 89 944569# 215# + -2 44 46 90 Pd x -39710# 400# 8113# 4# B- * 89 957370# 429# +0 25 58 33 91 As x -36500# 400# 8189# 4# B- 14080# 589# 90 960816# 429# + 23 57 34 91 Se x -50580.130 433.145 8334.8382 4.7598 B- 10527.1716 433.1593 90 945700.000 465.000 + 21 56 35 91 Br -n2p -61107.301 3.543 8441.9242 0.0389 B- 9866.6724 4.1898 90 934398.617 3.804 + 19 55 36 91 Kr x -70973.974 2.236 8541.7519 0.0246 B- 6771.0748 8.1153 90 923806.309 2.400 + 17 54 37 91 Rb -77745.049 7.801 8607.5621 0.0857 B- 5906.9010 8.8732 90 916537.261 8.375 + 15 53 38 91 Sr -83651.950 5.453 8663.8759 0.0599 B- 2699.3714 5.2468 90 910195.942 5.853 + 13 52 39 91 Y -86351.321 1.843 8684.9421 0.0203 B- 1544.2710 1.8403 90 907298.048 1.978 + 11 51 40 91 Zr -87895.592 0.095 8693.3149 0.0011 B- -1257.5644 2.9243 90 905640.205 0.101 + 9 50 41 91 Nb -86638.028 2.926 8670.8983 0.0322 B- -4429.1934 6.7439 90 906990.256 3.140 + 7 49 42 91 Mo -82208.834 6.238 8613.6286 0.0686 B- -6222.1768 6.6706 90 911745.190 6.696 + 5 48 43 91 Tc -75986.657 2.363 8536.6558 0.0260 B- -7746.8246 3.2422 90 918424.972 2.536 + 3 47 44 91 Ru -68239.833 2.221 8442.9287 0.0244 B- -9670# 298# 90 926741.530 2.384 + 1 46 45 91 Rh x -58570# 298# 8328# 3# B- -12400# 300# 90 937123# 320# + -1 45 46 91 Pd - -46170# 423# 8183# 5# B- * 90 950435# 454# +0 26 59 33 92 As x -30380# 500# 8121# 5# B- 16344# 640# 91 967386# 537# + 24 58 34 92 Se x -46724# 400# 8290# 4# B- 9509# 400# 91 949840# 429# + 22 57 35 92 Br x -56232.812 6.709 8384.9123 0.0729 B- 12536.5161 7.2322 91 939631.595 7.202 + 20 56 36 92 Kr x -68769.329 2.701 8512.6750 0.0294 B- 6003.1210 6.6924 91 926173.092 2.900 + 18 55 37 92 Rb -74772.450 6.123 8569.4225 0.0666 B- 8094.9212 6.4187 91 919728.477 6.573 + 16 54 38 92 Sr -82867.371 3.423 8648.9070 0.0372 B- 1949.1237 9.3841 91 911038.222 3.675 + 14 53 39 92 Y -84816.494 9.127 8661.5894 0.0992 B- 3642.5294 9.1271 91 908945.752 9.798 + 12 52 40 92 Zr -88459.024 0.094 8692.6783 0.0011 B- -2005.7335 1.7823 91 905035.336 0.101 + 10 51 41 92 Nb -86453.290 1.784 8662.3731 0.0194 B- 355.2968 1.7911 91 907188.580 1.915 + 8 50 42 92 Mo -86808.587 0.157 8657.7312 0.0017 B- -7882.8841 3.1063 91 906807.153 0.168 + 6 49 43 92 Tc -78925.703 3.102 8563.5440 0.0337 B- -4624.4922 4.1246 91 915269.777 3.330 + 4 48 44 92 Ru -74301.211 2.718 8504.7740 0.0295 B- -11302.1155 5.1531 91 920234.373 2.917 + 2 47 45 92 Rh x -62999.095 4.378 8373.4211 0.0476 B- -8220.0000 345.0000 91 932367.692 4.700 + 0 46 46 92 Pd - -54779.095 345.028 8275.5695 3.7503 B- -17249# 528# 91 941192.225 370.402 + -2 45 47 92 Ag x -37530# 400# 8080# 4# B- * 91 959710# 429# +0 25 59 34 93 Se x -40860# 400# 8225# 4# B- 12030# 588# 92 956135# 429# + 23 58 35 93 Br x -52890.235 430.816 8345.5986 4.6324 B- 11245.7673 430.8234 92 943220.000 462.500 + 21 57 36 93 Kr x -64136.002 2.515 8458.1085 0.0270 B- 8483.8977 8.2243 92 931147.172 2.700 + 19 56 37 93 Rb -72619.900 7.830 8540.9209 0.0842 B- 7465.9434 8.8761 92 922039.334 8.406 + 17 55 38 93 Sr -80085.844 7.554 8612.7875 0.0812 B- 4141.3118 11.6972 92 914024.314 8.109 + 15 54 39 93 Y -84227.155 10.488 8648.9054 0.1128 B- 2894.8723 10.4830 92 909578.434 11.259 + 13 53 40 93 Zr -87122.028 0.456 8671.6207 0.0049 B- 90.8123 1.4838 92 906470.661 0.489 + 11 52 41 93 Nb -87212.840 1.490 8664.1849 0.0160 B- -405.7609 1.5012 92 906373.170 1.599 + 9 51 42 93 Mo -n -86807.079 0.181 8651.4095 0.0020 B- -3200.9629 1.0040 92 906808.772 0.193 + 7 50 43 93 Tc -p -83606.116 1.012 8608.5782 0.0109 B- -6389.3929 2.2995 92 910245.147 1.086 + 5 49 44 93 Ru -77216.723 2.065 8531.4627 0.0222 B- -8204.9136 3.3425 92 917104.442 2.216 + 3 48 45 93 Rh -69011.810 2.629 8434.8255 0.0283 B- -10030.0000 370.0000 92 925912.778 2.821 + 1 47 46 93 Pd - -58981.810 370.009 8318.5637 3.9786 B- -12582# 545# 92 936680.426 397.221 + -1 46 47 93 Ag x -46400# 401# 8175# 4# B- * 92 950188# 430# +0 26 60 34 94 Se x -36803# 500# 8180# 5# B- 10846# 539# 93 960490# 537# + 24 59 35 94 Br x -47650# 200# 8287# 2# B- 13698# 201# 93 948846# 215# + 22 58 36 94 Kr x -61347.780 12.109 8424.3318 0.1288 B- 7215.0114 12.2782 93 934140.452 13.000 + 20 57 37 94 Rb -68562.791 2.029 8492.7644 0.0216 B- 10282.9297 2.6230 93 926394.819 2.177 + 18 56 38 94 Sr -78845.721 1.663 8593.8344 0.0177 B- 3505.7517 6.4220 93 915355.641 1.785 + 16 55 39 94 Y -82351.473 6.380 8622.8068 0.0679 B- 4917.8589 6.3799 93 911592.062 6.849 + 14 54 40 94 Zr -87269.332 0.164 8666.8016 0.0018 B- -900.2684 1.5000 93 906312.523 0.175 + 12 53 41 94 Nb -86369.063 1.491 8648.9014 0.0159 B- 2045.0163 1.4937 93 907279.001 1.600 + 10 52 42 94 Mo -88414.079 0.141 8662.3341 0.0015 B- -4255.7476 4.0687 93 905083.586 0.151 + 8 51 43 94 Tc - -84158.332 4.071 8608.7373 0.0433 B- -1574.7296 5.1433 93 909652.319 4.370 + 6 50 44 94 Ru -82583.602 3.143 8583.6620 0.0334 B- -9675.9789 4.6150 93 911342.860 3.374 + 4 49 45 94 Rh -72907.623 3.379 8472.4033 0.0359 B- -6805.3428 5.4588 93 921730.450 3.627 + 2 48 46 94 Pd x -66102.281 4.287 8391.6832 0.0456 B- -13700# 400# 93 929036.286 4.602 + 0 47 47 94 Ag - -52402# 400# 8238# 4# B- -11962# 640# 93 943744# 429# + -2 46 48 94 Cd x -40440# 500# 8102# 5# B- * 93 956586# 537# +0 27 61 34 95 Se x -30460# 500# 8112# 5# B- 13390# 583# 94 967300# 537# + 25 60 35 95 Br x -43850# 300# 8245# 3# B- 12309# 301# 94 952925# 322# + 23 59 36 95 Kr x -56158.920 18.630 8365.9963 0.1961 B- 9731.3868 27.5124 94 939710.922 20.000 + 21 58 37 95 Rb -65890.307 20.245 8460.1967 0.2131 B- 9226.9772 20.2036 94 929263.849 21.733 + 19 57 38 95 Sr -75117.284 5.810 8549.0875 0.0612 B- 6090.6528 7.2395 94 919358.282 6.237 + 17 56 39 95 Y -81207.937 6.779 8604.9644 0.0714 B- 4452.0031 6.7718 94 912819.697 7.277 + 15 55 40 95 Zr -85659.940 0.869 8643.5924 0.0092 B- 1126.3312 0.9854 94 908040.276 0.933 + 13 54 41 95 Nb -86786.272 0.508 8647.2133 0.0054 B- 925.6009 0.4938 94 906831.110 0.545 + 11 53 42 95 Mo -87711.872 0.123 8648.7212 0.0013 B- -1690.5175 5.0782 94 905837.436 0.132 + 9 52 43 95 Tc -86021.355 5.080 8622.6911 0.0535 B- -2563.5961 10.5310 94 907652.281 5.453 + 7 51 44 95 Ru -83457.759 9.502 8587.4706 0.1000 B- -5117.1423 10.2656 94 910404.415 10.200 + 5 50 45 95 Rh -78340.616 3.886 8525.3707 0.0409 B- -8374.7035 4.9281 94 915897.893 4.171 + 3 49 46 95 Pd x -69965.913 3.031 8428.9807 0.0319 B- -10060# 400# 94 924888.506 3.253 + 1 48 47 95 Ag - -59906# 400# 8315# 4# B- -12850# 400# 94 935688# 429# + -1 47 48 95 Cd - -47056# 566# 8171# 6# B- * 94 949483# 607# +0 26 61 35 96 Br x -38210# 300# 8184# 3# B- 14872# 301# 95 958980# 322# + 24 60 36 96 Kr -53081.682 19.277 8330.8721 0.2008 B- 8272.6693 19.5669 95 943014.473 20.695 + 22 59 37 96 Rb -61354.351 3.353 8408.8963 0.0349 B- 11563.8970 9.1062 95 934133.398 3.599 + 20 58 38 96 Sr -72918.248 8.466 8521.2041 0.0882 B- 5411.7380 9.7257 95 921719.045 9.089 + 18 57 39 96 Y -78329.986 6.075 8569.4269 0.0633 B- 7108.8741 6.0740 95 915909.305 6.521 + 16 56 40 96 Zr -85438.860 0.114 8635.3283 0.0012 B- 163.9704 0.1000 95 908277.615 0.122 + 14 55 41 96 Nb -85602.830 0.147 8628.8868 0.0015 B- 3192.0590 0.1070 95 908101.586 0.157 + 12 54 42 96 Mo -88794.889 0.120 8653.9880 0.0013 B- -2973.2411 5.1450 95 904674.770 0.128 + 10 53 43 96 Tc - -85821.648 5.146 8614.8673 0.0536 B- 258.7369 5.1464 95 907866.675 5.524 + 8 52 44 96 Ru -86080.385 0.170 8609.4130 0.0018 B- -6392.6529 10.0000 95 907588.910 0.182 + 6 51 45 96 Rh - -79687.732 10.001 8534.6735 0.1042 B- -3504.3127 10.8442 95 914451.705 10.737 + 4 50 46 96 Pd x -76183.420 4.194 8490.0207 0.0437 B- -11671.7741 90.1814 95 918213.739 4.502 + 2 49 47 96 Ag ep -64511.645 90.084 8360.2903 0.9384 B- -8940# 400# 95 930743.903 96.708 + 0 48 48 96 Cd - -55572# 410# 8259# 4# B- -17482# 647# 95 940341# 440# + -2 47 49 96 In x -38090# 500# 8069# 5# B- * 95 959109# 537# +0 27 62 35 97 Br x -34000# 400# 8140# 4# B- 13423# 420# 96 963499# 429# + 25 61 36 97 Kr x -47423.499 130.409 8269.8645 1.3444 B- 11095.6460 130.4232 96 949088.782 140.000 + 23 60 37 97 Rb -58519.145 1.912 8376.1872 0.0197 B- 10061.5295 3.8872 96 937177.117 2.052 + 21 59 38 97 Sr -68580.674 3.385 8471.8489 0.0349 B- 7534.7807 7.5131 96 926375.621 3.633 + 19 58 39 97 Y + -76115.455 6.708 8541.4616 0.0692 B- 6821.2382 6.7068 96 918286.702 7.201 + 17 57 40 97 Zr -82936.693 0.121 8603.7182 0.0013 B- 2666.1038 4.2435 96 910963.802 0.130 + 15 56 41 97 Nb -85602.797 4.244 8623.1384 0.0438 B- 1941.9038 4.2435 96 908101.622 4.556 + 13 55 42 97 Mo -87544.700 0.165 8635.0926 0.0017 B- -320.2640 4.1169 96 906016.903 0.176 + 11 54 43 97 Tc -87224.436 4.118 8623.7254 0.0425 B- -1103.8722 4.9563 96 906360.720 4.420 + 9 53 44 97 Ru -n -86120.564 2.763 8604.2799 0.0285 B- -3523.0000 35.3553 96 907545.776 2.965 + 7 52 45 97 Rh - -82597.564 35.463 8559.8949 0.3656 B- -4791.7118 35.7924 96 911327.872 38.071 + 5 51 46 97 Pd x -77805.852 4.844 8502.4303 0.0499 B- -6901.8255 12.9558 96 916471.985 5.200 + 3 50 47 97 Ag x -70904.027 12.016 8423.2121 0.1239 B- -10170.0000 420.0000 96 923881.400 12.900 + 1 49 48 97 Cd - -60734.027 420.172 8310.3013 4.3317 B- -13344# 580# 96 934799.343 451.073 + -1 48 49 97 In x -47390# 401# 8165# 4# B- * 96 949125# 430# +0 28 63 35 98 Br x -28050# 400# 8078# 4# B- 16070# 500# 97 969887# 429# + 26 62 36 98 Kr x -44120# 300# 8234# 3# B- 10249# 300# 97 952635# 322# + 24 61 37 98 Rb -54369.152 16.083 8330.7294 0.1641 B- 12053.2361 16.4029 97 941632.317 17.265 + 22 60 38 98 Sr -66422.389 3.226 8445.7385 0.0329 B- 5866.3591 8.5504 97 928692.636 3.463 + 20 59 39 98 Y p-2n -72288.748 7.919 8497.6162 0.0808 B- 8993.0098 11.5755 97 922394.841 8.501 + 18 58 40 98 Zr -81281.757 8.445 8581.3984 0.0862 B- 2242.8547 9.8134 97 912740.448 9.065 + 16 57 41 98 Nb -pn -83524.612 5.001 8596.3016 0.0510 B- 4591.3681 5.0032 97 910332.645 5.369 + 14 56 42 98 Mo -88115.980 0.174 8635.1691 0.0018 B- -1683.7664 3.3768 97 905403.609 0.186 + 12 55 43 98 Tc -86432.214 3.380 8610.0047 0.0345 B- 1792.6575 7.1568 97 907211.206 3.628 + 10 54 44 98 Ru -88224.871 6.463 8620.3140 0.0659 B- -5049.6529 10.0000 97 905286.709 6.937 + 8 53 45 98 Rh - -83175.219 11.906 8560.8038 0.1215 B- -1854.2331 12.8161 97 910707.734 12.782 + 6 52 46 98 Pd -81320.985 4.742 8533.8999 0.0484 B- -8254.5607 33.0975 97 912698.335 5.090 + 4 51 47 98 Ag -73066.425 32.907 8441.6866 0.3358 B- -5430.0000 40.0000 97 921559.970 35.327 + 2 50 48 98 Cd - -67636.425 51.797 8378.2953 0.5285 B- -13730# 300# 97 927389.315 55.605 + 0 49 49 98 In - -53906# 304# 8230# 3# B- * 97 942129# 327# +0 27 63 36 99 Kr x -38400# 400# 8175# 4# B- 12721# 400# 98 958776# 429# + 25 62 37 99 Rb x -51121.150 4.031 8295.3010 0.0407 B- 11397.3767 6.2201 98 945119.190 4.327 + 23 61 38 99 Sr -62518.527 4.737 8402.5235 0.0479 B- 8125.2037 8.1353 98 932883.604 5.085 + 21 60 39 99 Y x -70643.730 6.615 8476.6938 0.0668 B- 6972.9398 12.4082 98 924160.839 7.101 + 19 59 40 99 Zr -77616.670 10.499 8539.2250 0.1061 B- 4718.6736 15.9474 98 916675.081 11.271 + 17 58 41 99 Nb +p -82335.344 12.004 8578.9859 0.1213 B- 3634.7623 12.0059 98 911609.377 12.886 + 15 57 42 99 Mo -85970.106 0.229 8607.7982 0.0023 B- 1357.7631 0.8905 98 907707.299 0.245 + 13 56 43 99 Tc -87327.869 0.908 8613.6105 0.0092 B- 297.5156 0.9453 98 906249.681 0.974 + 11 55 44 99 Ru -87625.385 0.343 8608.7132 0.0035 B- -2040.8632 19.4529 98 905930.284 0.368 + 9 54 45 99 Rh -85584.522 19.451 8580.1959 0.1965 B- -3401.6603 18.9153 98 908121.241 20.881 + 7 53 46 99 Pd -82182.861 5.107 8537.9332 0.0516 B- -5470.3785 8.0829 98 911773.073 5.482 + 5 52 47 99 Ag x -76712.483 6.265 8474.7744 0.0633 B- -6781.3511 6.4622 98 917645.766 6.725 + 3 51 48 99 Cd x -69931.132 1.584 8398.3734 0.0160 B- -8555# 298# 98 924925.845 1.700 + 1 50 49 99 In x -61376# 298# 8304# 3# B- -13400# 500# 98 934110# 320# + -1 49 50 99 Sn - -47976# 582# 8161# 6# B- * 98 948495# 625# +0 28 64 36 100 Kr x -34470# 400# 8134# 4# B- 11796# 400# 99 962995# 429# + 26 63 37 100 Rb -46265.884 13.124 8244.5085 0.1312 B- 13551.6204 14.8355 99 950331.532 14.089 + 24 62 38 100 Sr -59817.505 6.918 8372.2012 0.0692 B- 7503.7365 13.1453 99 935783.270 7.426 + 22 61 39 100 Y x -67321.241 11.179 8439.4151 0.1118 B- 9051.4949 13.8293 99 927727.678 12.000 + 20 60 40 100 Zr -76372.736 8.143 8522.1066 0.0814 B- 3418.5098 11.3976 99 918010.499 8.742 + 18 59 41 100 Nb IT -79791.246 7.976 8548.4683 0.0798 B- 6401.7829 7.9817 99 914340.578 8.562 + 16 58 42 100 Mo -86193.029 0.301 8604.6626 0.0030 B- -172.0776 1.3704 99 907467.982 0.322 + 14 57 43 100 Tc -n -86020.951 1.351 8595.1184 0.0135 B- 3206.4401 1.3760 99 907652.715 1.450 + 12 56 44 100 Ru -89227.391 0.342 8619.3593 0.0034 B- -3636.2612 18.1231 99 904210.460 0.367 + 10 55 45 100 Rh -85591.130 18.125 8575.1732 0.1813 B- -378.4577 25.2879 99 908114.147 19.458 + 8 54 46 100 Pd -85212.672 17.637 8563.5652 0.1764 B- -7074.7030 18.3319 99 908520.438 18.934 + 6 53 47 100 Ag x -78137.969 5.000 8484.9947 0.0500 B- -3943.3740 5.2735 99 916115.443 5.367 + 4 52 48 100 Cd x -74194.595 1.677 8437.7375 0.0168 B- -10016.4492 2.7945 99 920348.829 1.800 + 2 51 49 100 In x -64178.146 2.236 8329.7495 0.0224 B- -7030.0000 240.0000 99 931101.929 2.400 + 0 50 50 100 Sn - -57148.146 240.010 8251.6260 2.4001 B- * 99 938648.944 257.661 +0 29 65 36 101 Kr x -28580# 500# 8075# 5# B- 13987# 501# 100 969318# 537# + 27 64 37 101 Rb x -42567.417 20.493 8206.1753 0.2029 B- 12757.4969 22.1781 100 954302.000 22.000 + 25 63 38 101 Sr x -55324.914 8.480 8324.7411 0.0840 B- 9729.8721 11.0473 100 940606.264 9.103 + 23 62 39 101 Y x -65054.787 7.080 8413.3305 0.0701 B- 8106.2003 10.9331 100 930160.817 7.601 + 21 61 40 101 Zr -73160.987 8.332 8485.8439 0.0825 B- 5730.5011 9.1366 100 921458.454 8.944 + 19 60 41 101 Nb x -78891.488 3.749 8534.8355 0.0371 B- 4628.4637 3.7378 100 915306.508 4.024 + 17 59 42 101 Mo -n -83519.952 0.308 8572.9159 0.0031 B- 2824.6411 24.0018 100 910337.648 0.331 + 15 58 43 101 Tc + -86344.593 24.004 8593.1366 0.2377 B- 1613.5200 24.0000 100 907305.271 25.768 + 13 57 44 101 Ru -87958.113 0.413 8601.3660 0.0041 B- -545.6846 5.8518 100 905573.086 0.443 + 11 56 45 101 Rh -87412.428 5.841 8588.2172 0.0578 B- -1980.2833 3.9027 100 906158.903 6.270 + 9 55 46 101 Pd -85432.145 4.588 8560.8644 0.0454 B- -4097.7606 6.6679 100 908284.824 4.925 + 7 54 47 101 Ag x -81334.384 4.838 8512.5465 0.0479 B- -5497.9186 5.0625 100 912683.951 5.193 + 5 53 48 101 Cd x -75836.466 1.490 8450.3657 0.0148 B- -7291.5642 11.7569 100 918586.209 1.600 + 3 52 49 101 In x -68544.901 11.662 8370.4260 0.1155 B- -8239.2770 300.2313 100 926414.025 12.519 + 1 51 50 101 Sn ep -60305.624 300.005 8281.1030 2.9703 B- * 100 935259.252 322.068 +0 28 65 37 102 Rb x -37252.312 82.903 8152.7443 0.8128 B- 14906.9991 106.6347 101 960008.000 89.000 + 26 64 38 102 Sr x -52159.311 67.068 8291.2213 0.6575 B- 9013.3301 67.1916 101 944004.679 72.000 + 24 63 39 102 Y x -61172.641 4.081 8371.9172 0.0400 B- 10408.7856 9.6618 101 934328.471 4.381 + 22 62 40 102 Zr -71581.427 8.758 8466.2940 0.0859 B- 4716.8380 9.0530 101 923154.181 9.401 + 20 61 41 102 Nb -76298.265 2.511 8504.8675 0.0246 B- 7262.6008 8.6750 101 918090.447 2.695 + 18 60 42 102 Mo -83560.866 8.305 8568.3994 0.0814 B- 1012.0557 12.3682 101 910293.725 8.916 + 16 59 43 102 Tc -84572.921 9.166 8570.6514 0.0899 B- 4533.5134 9.1646 101 909207.239 9.840 + 14 58 44 102 Ru -89106.435 0.416 8607.4275 0.0041 B- -2323.1187 6.3960 101 904340.312 0.446 + 12 57 45 102 Rh - -86783.316 6.410 8576.9818 0.0628 B- 1119.6470 6.3962 101 906834.282 6.880 + 10 56 46 102 Pd -87902.963 0.419 8580.2887 0.0041 B- -5656.2615 8.1816 101 905632.292 0.449 + 8 55 47 102 Ag + -82246.702 8.171 8517.1650 0.0801 B- -2587.0000 8.0000 101 911704.538 8.771 + 6 54 48 102 Cd -79659.702 1.662 8484.1322 0.0163 B- -8964.8059 4.8654 101 914481.797 1.784 + 4 53 49 102 In -70694.896 4.573 8388.5719 0.0448 B- -5760.0000 100.0000 101 924105.911 4.909 + 2 52 50 102 Sn - -64934.896 100.105 8324.4313 0.9814 B- -13835# 412# 101 930289.525 107.466 + 0 51 51 102 Sb x -51100# 400# 8181# 4# B- * 101 945142# 429# +0 29 66 37 103 Rb x -33160# 400# 8112# 4# B- 14120# 447# 102 964401# 429# + 27 65 38 103 Sr x -47280# 200# 8242# 2# B- 11177# 201# 102 949243# 215# + 25 64 39 103 Y x -58457.034 11.206 8342.6336 0.1088 B- 9351.9600 14.5130 102 937243.796 12.029 + 23 63 40 103 Zr x -67808.993 9.223 8425.8337 0.0895 B- 7219.6740 10.0270 102 927204.054 9.900 + 21 62 41 103 Nb x -75028.667 3.935 8488.3320 0.0382 B- 5925.6639 10.0270 102 919453.416 4.224 + 19 61 42 103 Mo x -80954.331 9.223 8538.2672 0.0895 B- 3649.5889 13.4648 102 913091.954 9.900 + 17 60 43 103 Tc +p -84603.920 9.810 8566.1045 0.0952 B- 2663.2474 9.8086 102 909173.960 10.531 + 15 59 44 103 Ru -87267.168 0.441 8584.3656 0.0043 B- 764.5378 2.2598 102 906314.846 0.473 + 13 58 45 103 Rh -88031.705 2.301 8584.1927 0.0223 B- -574.7252 2.3928 102 905494.081 2.470 + 11 57 46 103 Pd -n -87456.980 0.878 8571.0173 0.0085 B- -2654.2778 4.1916 102 906111.074 0.942 + 9 56 47 103 Ag x -84802.702 4.099 8537.6520 0.0398 B- -4151.0761 4.4806 102 908960.558 4.400 + 7 55 48 103 Cd -80651.626 1.811 8489.7547 0.0176 B- -6019.2293 9.1242 102 913416.922 1.943 + 5 54 49 103 In -74632.397 8.980 8423.7199 0.0872 B- -7540# 100# 102 919878.830 9.640 + 3 53 50 103 Sn - -67092# 100# 8343# 1# B- -10422# 316# 102 927973# 108# + 1 52 51 103 Sb x -56670# 300# 8234# 3# B- * 102 939162# 322# +0 30 67 37 104 Rb x -27450# 500# 8057# 5# B- 16310# 583# 103 970531# 537# + 28 66 38 104 Sr x -43760# 300# 8206# 3# B- 10320# 361# 103 953022# 322# + 26 65 39 104 Y x -54080# 200# 8298# 2# B- 11638# 200# 103 941943# 215# + 24 64 40 104 Zr x -65717.660 9.316 8402.3159 0.0896 B- 6093.3367 9.4851 103 929449.193 10.000 + 22 63 41 104 Nb x -71810.997 1.784 8453.3832 0.0172 B- 8532.7512 9.0879 103 922907.728 1.915 + 20 62 42 104 Mo -80343.748 8.911 8527.9063 0.0857 B- 2155.2212 24.1665 103 913747.443 9.566 + 18 61 43 104 Tc -82498.969 24.886 8541.1070 0.2393 B- 5596.7945 24.9370 103 911433.718 26.716 + 16 60 44 104 Ru -88095.763 2.498 8587.3998 0.0240 B- -1136.4195 3.3643 103 905425.312 2.682 + 14 59 45 104 Rh -n -86959.344 2.303 8568.9501 0.0221 B- 2435.7789 2.6595 103 906645.309 2.471 + 12 58 46 104 Pd +n -89395.123 1.336 8584.8485 0.0129 B- -4278.6529 4.0000 103 904030.393 1.434 + 10 57 47 104 Ag - -85116.470 4.217 8536.1850 0.0406 B- -1148.0787 4.5370 103 908623.715 4.527 + 8 56 48 104 Cd -83968.391 1.673 8517.6232 0.0161 B- -7785.7166 6.0127 103 909856.228 1.795 + 6 55 49 104 In x -76182.675 5.775 8435.2380 0.0555 B- -4555.6174 8.1461 103 918214.538 6.200 + 4 54 50 104 Sn -71627.057 5.745 8383.9114 0.0552 B- -12332# 102# 103 923105.195 6.167 + 2 53 51 104 Sb +a -59295# 101# 8258# 1# B- -9668# 333# 103 936344# 109# + 0 52 52 104 Te -a -49626.831 317.609 8157.3256 3.0539 B- * 103 946723.408 340.967 +0 29 67 38 105 Sr x -38190# 500# 8152# 5# B- 12380# 640# 104 959001# 537# + 27 66 39 105 Y x -50570# 400# 8262# 4# B- 10888# 400# 104 945711# 429# + 25 65 40 105 Zr x -61458.274 12.110 8358.5980 0.1153 B- 8457.2728 12.7625 104 934021.832 13.000 + 23 64 41 105 Nb x -69915.547 4.028 8431.6925 0.0384 B- 7415.2411 9.9106 104 924942.577 4.324 + 21 63 42 105 Mo -77330.788 9.055 8494.8630 0.0862 B- 4955.5157 35.0307 104 916981.989 9.721 + 19 62 43 105 Tc -82286.303 35.263 8534.6074 0.3358 B- 3648.2396 35.2787 104 911662.024 37.856 + 17 61 44 105 Ru -85934.543 2.499 8561.9016 0.0238 B- 1916.7271 2.8508 104 907745.478 2.683 + 15 60 45 105 Rh -87851.270 2.502 8572.7053 0.0238 B- 566.6347 2.3459 104 905687.787 2.685 + 13 59 46 105 Pd -88417.905 1.138 8570.6509 0.0108 B- -1347.0564 4.6695 104 905079.479 1.222 + 11 58 47 105 Ag -87070.848 4.544 8550.3708 0.0433 B- -2736.9989 4.3618 104 906525.604 4.877 + 9 57 48 105 Cd -84333.849 1.392 8516.8532 0.0133 B- -4693.2673 10.3405 104 909463.893 1.494 + 7 56 49 105 In x -79640.582 10.246 8464.7045 0.0976 B- -6302.5807 10.9891 104 914502.322 11.000 + 5 55 50 105 Sn -73338.001 3.971 8397.2290 0.0378 B- -9322.5103 22.1849 104 921268.421 4.263 + 3 54 51 105 Sb +a -64015.491 21.827 8300.9923 0.2079 B- -11203.9825 300.8126 104 931276.547 23.431 + 1 53 52 105 Te -a -52811.509 300.020 8186.8368 2.8573 B- * 104 943304.516 322.084 +0 30 68 38 106 Sr x -34300# 600# 8114# 6# B- 11490# 781# 105 963177# 644# + 28 67 39 106 Y x -45790# 500# 8215# 5# B- 12959# 539# 105 950842# 537# + 26 66 40 106 Zr x -58749# 200# 8330# 2# B- 7453# 200# 105 936930# 215# + 24 65 41 106 Nb -66202.678 1.416 8393.2657 0.0134 B- 9925.3249 9.2388 105 928928.505 1.520 + 22 64 42 106 Mo x -76128.003 9.130 8479.5202 0.0861 B- 3648.2494 15.2778 105 918273.231 9.801 + 20 63 43 106 Tc + -79776.253 12.250 8506.5570 0.1156 B- 6547.0000 11.0000 105 914356.674 13.150 + 18 62 44 106 Ru -86323.253 5.391 8560.9406 0.0509 B- 39.4038 0.2121 105 907328.181 5.787 + 16 61 45 106 Rh -86362.656 5.390 8553.9317 0.0508 B- 3544.8865 5.3348 105 907285.879 5.786 + 14 60 46 106 Pd -89907.543 1.106 8579.9934 0.0104 B- -2965.1434 2.8172 105 903480.287 1.186 + 12 59 47 106 Ag -86942.399 3.016 8544.6397 0.0285 B- 189.7534 2.8190 105 906663.499 3.237 + 10 58 48 106 Cd -87132.153 1.104 8539.0492 0.0104 B- -6524.0031 12.1765 105 906459.791 1.184 + 8 57 49 106 In - -80608.150 12.226 8470.1213 0.1153 B- -3254.4521 13.2439 105 913463.596 13.125 + 6 56 50 106 Sn -77353.698 5.091 8432.0383 0.0480 B- -10880.3964 9.0249 105 916957.394 5.465 + 4 55 51 106 Sb x -66473.301 7.452 8322.0124 0.0703 B- -8253.5423 100.8163 105 928637.979 8.000 + 2 54 52 106 Te -a -58219.759 100.541 8236.7682 0.9485 B- -14920# 412# 105 937498.521 107.934 + 0 53 53 106 I x -43300# 400# 8089# 4# B- * 105 953516# 429# +0 31 69 38 107 Sr x -28250# 700# 8057# 7# B- 13720# 860# 106 969672# 751# + 29 68 39 107 Y x -41970# 500# 8178# 5# B- 12050# 583# 106 954943# 537# + 27 67 40 107 Zr x -54020# 300# 8284# 3# B- 9704# 300# 106 942007# 322# + 25 66 41 107 Nb x -63723.805 8.023 8367.0898 0.0750 B- 8821.1703 12.2239 106 931589.685 8.612 + 23 65 42 107 Mo x -72544.975 9.223 8442.2190 0.0862 B- 6204.9921 12.6599 106 922119.770 9.901 + 21 64 43 107 Tc x -78749.967 8.673 8492.8979 0.0811 B- 5112.5985 11.7243 106 915458.437 9.310 + 19 63 44 107 Ru -nn -83862.565 8.673 8533.3676 0.0811 B- 3001.1457 14.8473 106 909969.837 9.310 + 17 62 45 107 Rh +p -86863.711 12.051 8554.1040 0.1126 B- 1508.9427 12.1108 106 906747.975 12.937 + 15 61 46 107 Pd -88372.654 1.201 8560.8946 0.0112 B- 34.0458 2.3174 106 905128.058 1.289 + 13 60 47 107 Ag -88406.700 2.382 8553.9012 0.0223 B- -1416.3741 2.5654 106 905091.509 2.556 + 11 59 48 107 Cd -86990.325 1.660 8533.3524 0.0155 B- -3423.6586 9.5800 106 906612.049 1.782 + 9 58 49 107 In -83566.667 9.654 8494.0439 0.0902 B- -5054.4281 11.0175 106 910287.497 10.363 + 7 57 50 107 Sn x -78512.239 5.310 8439.4946 0.0496 B- -7858.9903 6.7377 106 915713.649 5.700 + 5 56 51 107 Sb -70653.248 4.148 8358.7344 0.0388 B- -9996# 101# 106 924150.621 4.452 + 3 55 52 107 Te -a -60657# 101# 8258# 1# B- -11227# 316# 106 934882# 108# + 1 54 53 107 I x -49430# 300# 8146# 3# B- * 106 946935# 322# +0 30 69 39 108 Y x -36780# 600# 8129# 6# B- 14170# 721# 107 960515# 644# + 28 68 40 108 Zr x -50950# 400# 8253# 4# B- 8595# 400# 107 945303# 429# + 26 67 41 108 Nb x -59545.198 8.239 8325.6604 0.0763 B- 11204.0998 12.3668 107 936075.604 8.844 + 24 66 42 108 Mo x -70749.297 9.223 8422.1581 0.0854 B- 5173.5330 12.7262 107 924047.508 9.901 + 22 65 43 108 Tc x -75922.831 8.769 8462.8172 0.0812 B- 7738.5736 11.7903 107 918493.493 9.413 + 20 64 44 108 Ru -3n -83661.404 8.680 8527.2267 0.0804 B- 1369.7517 16.4699 107 910185.793 9.318 + 18 63 45 108 Rh x -85031.156 13.997 8532.6657 0.1296 B- 4493.0596 14.0405 107 908715.304 15.026 + 16 62 46 108 Pd -89524.215 1.108 8567.0241 0.0103 B- -1917.4238 2.6323 107 903891.806 1.189 + 14 61 47 108 Ag -n -87606.792 2.388 8542.0262 0.0221 B- 1645.6311 2.6386 107 905950.245 2.563 + 12 60 48 108 Cd -89252.423 1.123 8550.0196 0.0104 B- -5132.5944 8.5845 107 904183.588 1.205 + 10 59 49 108 In -84119.828 8.641 8495.2516 0.0800 B- -2049.8794 9.8365 107 909693.654 9.276 + 8 58 50 108 Sn -82069.949 5.382 8469.0273 0.0498 B- -9624.6079 7.6925 107 911894.290 5.778 + 6 57 51 108 Sb x -72445.341 5.496 8372.6666 0.0509 B- -6663.6646 7.7125 107 922226.731 5.900 + 4 56 52 108 Te -65781.676 5.411 8303.7221 0.0501 B- -13011# 101# 107 929380.469 5.808 + 2 55 53 108 I -p -52771# 101# 8176# 1# B- -10139# 393# 107 943348# 109# + 0 54 54 108 Xe -a -42632.357 379.497 8074.8886 3.5139 B- * 107 954232.285 407.406 +0 31 70 39 109 Y x -32480# 700# 8089# 6# B- 13250# 860# 108 965131# 751# + 29 69 40 109 Zr x -45730# 500# 8204# 5# B- 10960# 660# 108 950907# 537# + 27 68 41 109 Nb x -56689.800 430.816 8297.1307 3.9524 B- 9969.4851 430.9610 108 939141.000 462.500 + 25 67 42 109 Mo x -66659.285 11.179 8381.4163 0.1026 B- 7623.5438 14.7805 108 928438.318 12.000 + 23 66 43 109 Tc x -74282.828 9.669 8444.1796 0.0887 B- 6455.6267 12.6574 108 920254.107 10.380 + 21 65 44 109 Ru -4n -80738.455 8.954 8496.2280 0.0821 B- 4260.7958 9.8229 108 913323.707 9.612 + 19 64 45 109 Rh -84999.251 4.040 8528.1404 0.0371 B- 2607.2327 4.1874 108 908749.555 4.336 + 17 63 46 109 Pd -87606.484 1.114 8544.8825 0.0102 B- 1112.9469 1.4024 108 905950.576 1.195 + 15 62 47 109 Ag -88719.431 1.287 8547.9155 0.0118 B- -215.1002 1.7795 108 904755.778 1.381 + 13 61 48 109 Cd -88504.330 1.536 8538.7646 0.0141 B- -2014.8047 4.0662 108 904986.697 1.649 + 11 60 49 109 In -86489.526 3.969 8513.1027 0.0364 B- -3859.3453 8.8866 108 907149.679 4.261 + 9 59 50 109 Sn -82630.180 7.949 8470.5183 0.0729 B- -6379.1940 8.8074 108 911292.857 8.533 + 7 58 51 109 Sb -76250.986 5.265 8404.8161 0.0483 B- -8535.5871 6.8502 108 918141.203 5.652 + 5 57 52 109 Te -67715.399 4.382 8319.3305 0.0402 B- -10042.8941 8.0301 108 927304.532 4.704 + 3 56 53 109 I -p -57672.505 6.729 8220.0164 0.0617 B- -11502.9589 300.1831 108 938086.022 7.223 + 1 55 54 109 Xe -a -46169.546 300.108 8107.3071 2.7533 B- * 108 950434.955 322.178 +0 30 70 40 110 Zr x -42220# 500# 8171# 5# B- 10090# 976# 109 954675# 537# + 28 69 41 110 Nb x -52309.914 838.345 8255.2607 7.6213 B- 12225.9002 838.6945 109 943843.000 900.000 + 26 68 42 110 Mo x -64535.814 24.219 8359.2930 0.2202 B- 6498.7491 26.0147 109 930717.956 26.000 + 24 67 43 110 Tc x -71034.564 9.497 8411.2603 0.0863 B- 9038.0654 12.5086 109 923741.263 10.195 + 22 66 44 110 Ru -80072.629 8.924 8486.3123 0.0811 B- 2756.0638 19.4044 109 914038.501 9.580 + 20 65 45 110 Rh -82828.693 17.805 8504.2551 0.1619 B- 5502.2116 17.7967 109 911079.745 19.114 + 18 64 46 110 Pd -88330.904 0.612 8547.1630 0.0056 B- -873.5982 1.3777 109 905172.878 0.657 + 16 63 47 110 Ag -87457.306 1.286 8532.1089 0.0117 B- 2890.6633 1.2771 109 906110.724 1.380 + 14 62 48 110 Cd -90347.969 0.380 8551.2755 0.0035 B- -3878.0000 11.5470 109 903007.470 0.407 + 12 61 49 110 In - -86469.969 11.553 8508.9087 0.1050 B- -627.9769 17.9802 109 907170.674 12.402 + 10 60 50 110 Sn x -85841.993 13.777 8496.0875 0.1252 B- -8392.2480 15.0117 109 907844.835 14.790 + 8 59 51 110 Sb x -77449.745 5.962 8412.6821 0.0542 B- -5219.9240 8.8753 109 916854.283 6.400 + 6 58 52 110 Te -72229.821 6.575 8358.1160 0.0598 B- -11761.9766 62.2875 109 922458.102 7.058 + 4 57 53 110 I -a -60467.844 61.940 8244.0767 0.5631 B- -8545.2075 118.4700 109 935085.102 66.494 + 2 56 54 110 Xe -a -51922.636 100.988 8159.2808 0.9181 B- * 109 944258.759 108.415 +0 31 71 40 111 Zr x -36480# 600# 8118# 5# B- 12480# 671# 110 960837# 644# + 29 70 41 111 Nb x -48960# 300# 8223# 3# B- 10980# 300# 110 947439# 322# + 27 69 42 111 Mo + -59939.813 12.578 8315.2932 0.1133 B- 9084.8620 6.7999 110 935651.966 13.503 + 25 68 43 111 Tc x -69024.675 10.582 8390.0906 0.0953 B- 7760.6500 13.8477 110 925898.966 11.359 + 23 67 44 111 Ru x -76785.325 9.682 8452.9582 0.0872 B- 5518.5456 11.8621 110 917567.566 10.394 + 21 66 45 111 Rh -82303.871 6.853 8495.6267 0.0617 B- 3682.0153 6.8899 110 911643.164 7.356 + 19 65 46 111 Pd -n -85985.886 0.731 8521.7498 0.0066 B- 2229.5607 1.5721 110 907690.358 0.785 + 17 64 47 111 Ag + -88215.447 1.459 8534.7878 0.0131 B- 1036.8000 1.4142 110 905296.827 1.565 + 15 63 48 111 Cd -89252.247 0.357 8537.0801 0.0032 B- -860.1972 3.4170 110 904183.776 0.383 + 13 62 49 111 In -88392.050 3.424 8522.2824 0.0308 B- -2453.4692 6.3368 110 905107.236 3.675 + 11 61 50 111 Sn +n -85938.581 5.336 8493.1310 0.0481 B- -5101.8340 10.3337 110 907741.143 5.728 + 9 60 51 111 Sb x -80836.747 8.849 8440.1203 0.0797 B- -7249.2597 10.9370 110 913218.187 9.500 + 7 59 52 111 Te x -73587.487 6.427 8367.7635 0.0579 B- -8633.6922 7.9943 110 921000.587 6.900 + 5 58 53 111 I -64953.795 4.754 8282.9343 0.0428 B- -10434# 116# 110 930269.236 5.103 + 3 57 54 111 Xe -a -54520# 115# 8182# 1# B- -11620# 231# 110 941470# 124# + 1 56 55 111 Cs x -42900# 200# 8070# 2# B- * 110 953945# 215# +0 32 72 40 112 Zr x -32420# 700# 8081# 6# B- 11650# 761# 111 965196# 751# + 30 71 41 112 Nb x -44070# 300# 8178# 3# B- 13410# 361# 111 952689# 322# + 28 70 42 112 Mo x -57480# 200# 8291# 2# B- 7779# 200# 111 938293# 215# + 26 69 43 112 Tc x -65258.932 5.515 8353.6217 0.0492 B- 10371.9409 11.0602 111 929941.658 5.920 + 24 68 44 112 Ru x -75630.873 9.600 8439.2431 0.0857 B- 4100.1790 45.1185 111 918806.922 10.305 + 22 67 45 112 Rh -79731.052 44.085 8468.8666 0.3936 B- 6589.9874 43.9269 111 914405.199 47.327 + 20 66 46 112 Pd -86321.039 6.546 8520.7205 0.0584 B- 262.6897 6.9799 111 907330.557 7.027 + 18 65 47 112 Ag x -86583.729 2.422 8516.0807 0.0216 B- 3991.1283 2.4348 111 907048.548 2.600 + 16 64 48 112 Cd -90574.857 0.250 8544.7306 0.0022 B- -2584.7306 4.2434 111 902763.896 0.268 + 14 63 49 112 In -87990.127 4.251 8514.6674 0.0380 B- 664.9224 4.2434 111 905538.718 4.563 + 12 62 50 112 Sn -88655.049 0.294 8513.6189 0.0026 B- -7056.0760 17.8317 111 904824.894 0.315 + 10 61 51 112 Sb x -81598.973 17.829 8443.6330 0.1592 B- -4031.4550 19.7019 111 912399.903 19.140 + 8 60 52 112 Te x -77567.518 8.383 8400.6527 0.0749 B- -10504.1795 13.2390 111 916727.848 9.000 + 6 59 53 112 I x -67063.339 10.246 8299.8801 0.0915 B- -7036.9910 13.1754 111 928004.548 11.000 + 4 58 54 112 Xe -a -60026.348 8.283 8230.0646 0.0740 B- -13612# 116# 111 935559.068 8.891 + 2 57 55 112 Cs -p -46415# 116# 8102# 1# B- * 111 950172# 124# +0 33 73 40 113 Zr x -26340# 300# 8027# 3# B- 13870# 500# 112 971723# 322# + 31 72 41 113 Nb x -40210# 400# 8143# 4# B- 12440# 500# 112 956833# 429# + 29 71 42 113 Mo x -52650# 300# 8246# 3# B- 10162# 300# 112 943478# 322# + 27 70 43 113 Tc x -62811.549 3.353 8329.4652 0.0297 B- 9056.2674 38.4285 112 932569.032 3.600 + 25 69 44 113 Ru -71867.816 38.282 8402.6857 0.3388 B- 6899.1276 38.9406 112 922846.729 41.097 + 23 68 45 113 Rh x -78766.944 7.132 8456.8165 0.0631 B- 4823.5559 9.8809 112 915440.212 7.656 + 21 67 46 113 Pd x -83590.500 6.947 8492.5795 0.0615 B- 3436.3252 18.0341 112 910261.912 7.458 + 19 66 47 113 Ag + -87026.825 16.643 8516.0660 0.1473 B- 2016.4615 16.6410 112 906572.865 17.866 + 17 65 48 113 Cd -89043.286 0.245 8526.9874 0.0022 B- 323.8370 0.2653 112 904408.105 0.262 + 15 64 49 113 In -89367.123 0.188 8522.9297 0.0017 B- -1038.9941 1.5733 112 904060.451 0.202 + 13 63 50 113 Sn -88328.129 1.575 8506.8117 0.0139 B- -3911.1637 17.1206 112 905175.857 1.690 + 11 62 51 113 Sb - -84416.966 17.193 8465.2762 0.1521 B- -6069.9281 32.8102 112 909374.664 18.457 + 9 61 52 113 Te x -78347.037 27.945 8404.6366 0.2473 B- -7227.5210 29.0704 112 915891.000 30.000 + 7 60 53 113 I x -71119.517 8.011 8333.7528 0.0709 B- -8915.8902 10.5334 112 923650.062 8.600 + 5 59 54 113 Xe -62203.626 6.840 8247.9277 0.0605 B- -10439.0876 10.9702 112 933221.663 7.342 + 3 58 55 113 Cs -p -51764.539 8.577 8148.6230 0.0759 B- -12055# 300# 112 944428.484 9.207 + 1 57 56 113 Ba x -39710# 300# 8035# 3# B- * 112 957370# 322# +0 32 73 41 114 Nb x -34960# 500# 8097# 4# B- 14720# 583# 113 962469# 537# + 30 72 42 114 Mo x -49680# 300# 8219# 3# B- 8920# 527# 113 946666# 322# + 28 71 43 114 Tc x -58600.294 433.145 8290.2599 3.7995 B- 11620.9190 433.1594 113 937090.000 465.000 + 26 70 44 114 Ru x -70221.213 3.556 8385.3351 0.0312 B- 5489.0622 71.6432 113 924614.430 3.817 + 24 69 45 114 Rh -75710.275 71.561 8426.6221 0.6277 B- 7780.0712 71.8915 113 918721.680 76.824 + 22 68 46 114 Pd x -83490.346 6.948 8488.0056 0.0610 B- 1440.4642 8.3133 113 910369.430 7.459 + 20 67 47 114 Ag x -84930.811 4.564 8493.7786 0.0400 B- 5084.1233 4.5727 113 908823.029 4.900 + 18 66 48 114 Cd -90014.934 0.276 8531.5135 0.0024 B- -1445.1268 0.3817 113 903364.998 0.296 + 16 65 49 114 In -88569.807 0.301 8511.9742 0.0027 B- 1989.9281 0.3018 113 904916.405 0.323 + 14 64 50 114 Sn -90559.735 0.029 8522.5671 0.0004 B- -6063.1189 19.7724 113 902780.130 0.031 + 12 63 51 114 Sb -84496.616 19.772 8462.5191 0.1734 B- -2606.9398 31.4275 113 909289.155 21.226 + 10 62 52 114 Te x -81889.676 24.428 8432.7885 0.2143 B- -9250.7417 31.5883 113 912087.820 26.224 + 8 61 53 114 I x -72638.935 20.027 8344.7790 0.1757 B- -5553.0360 22.9354 113 922018.900 21.500 + 6 60 54 114 Xe x -67085.899 11.178 8289.2054 0.0981 B- -12399.9706 85.7989 113 927980.329 12.000 + 4 59 55 114 Cs -a -54685.928 85.068 8173.5711 0.7462 B- -8780.4915 133.3375 113 941292.244 91.323 + 2 58 56 114 Ba -a -45905.437 102.676 8089.6865 0.9007 B- * 113 950718.489 110.227 +0 33 74 41 115 Nb x -30880# 500# 8061# 4# B- 13670# 640# 114 966849# 537# + 31 73 42 115 Mo x -44550# 400# 8173# 3# B- 11247# 445# 114 952174# 429# + 29 72 43 115 Tc x -55796# 196# 8264# 2# B- 10309# 197# 114 940100# 210# + 27 71 44 115 Ru x -66105.296 25.166 8346.8140 0.2188 B- 8123.9327 26.1788 114 929033.049 27.016 + 25 70 45 115 Rh x -74229.228 7.319 8410.6538 0.0636 B- 6196.5938 15.3503 114 920311.649 7.857 + 23 69 46 115 Pd -80425.822 13.547 8457.7342 0.1178 B- 4556.7647 21.6496 114 913659.333 14.543 + 21 68 47 115 Ag -84982.587 18.268 8490.5553 0.1589 B- 3101.8930 18.2744 114 908767.445 19.611 + 19 67 48 115 Cd -88084.480 0.651 8510.7252 0.0057 B- 1451.8768 0.6514 114 905437.426 0.699 + 17 66 49 115 In -89536.357 0.012 8516.5472 0.0003 B- 497.4892 0.0097 114 903878.772 0.012 + 15 65 50 115 Sn -90033.846 0.015 8514.0702 0.0003 B- -3030.4336 16.0253 114 903344.695 0.016 + 13 64 51 115 Sb x -87003.412 16.025 8480.9156 0.1394 B- -4940.6447 32.2137 114 906598.000 17.203 + 11 63 52 115 Te x -82062.767 27.945 8431.1504 0.2430 B- -5724.9628 40.1840 114 911902.000 30.000 + 9 62 53 115 I x -76337.805 28.876 8374.5651 0.2511 B- -7681.0475 31.3126 114 918048.000 31.000 + 7 61 54 115 Xe x -68656.757 12.109 8300.9704 0.1053 B- -8957# 103# 114 926293.943 13.000 + 5 60 55 115 Cs x -59699# 102# 8216# 1# B- -10779# 225# 114 935910# 110# + 3 59 56 115 Ba x -48920# 200# 8116# 2# B- * 114 947482# 215# +0 34 75 41 116 Nb x -25230# 300# 8012# 3# B- 15980# 583# 115 972914# 322# + 32 74 42 116 Mo x -41210# 500# 8143# 4# B- 10003# 582# 115 955759# 537# + 30 73 43 116 Tc x -51214# 298# 8223# 3# B- 12855# 298# 115 945020# 320# + 28 72 44 116 Ru x -64068.917 3.726 8326.8840 0.0321 B- 6666.8252 73.9257 115 931219.191 4.000 + 26 71 45 116 Rh -70735.742 73.832 8377.6123 0.6365 B- 9095.2839 74.1690 115 924062.060 79.261 + 24 70 46 116 Pd x -79831.026 7.135 8449.2755 0.0615 B- 2711.6378 7.8446 115 914297.872 7.659 + 22 69 47 116 Ag x -82542.664 3.260 8465.9073 0.0281 B- 6169.8248 3.2642 115 911386.809 3.500 + 20 68 48 116 Cd -88712.489 0.160 8512.3511 0.0014 B- -462.7305 0.2720 115 904763.230 0.172 + 18 67 49 116 In -n -88249.758 0.220 8501.6177 0.0019 B- 3276.2204 0.2397 115 905259.992 0.236 + 16 66 50 116 Sn -91525.979 0.096 8523.1166 0.0009 B- -4703.9591 5.1540 115 901742.825 0.103 + 14 65 51 116 Sb -86822.020 5.154 8475.8208 0.0444 B- -1558.2272 24.7485 115 906792.732 5.533 + 12 64 52 116 Te -85263.793 24.206 8455.6435 0.2087 B- -7843.1388 75.3230 115 908465.558 25.986 + 10 63 53 116 I -77420.654 75.037 8381.2858 0.6469 B- -4373.7764 75.8444 115 916885.513 80.555 + 8 62 54 116 Xe -73046.877 13.017 8336.8365 0.1122 B- -11004# 101# 115 921580.955 13.974 + 6 61 55 116 Cs ea -62043# 100# 8235# 1# B- -7663# 224# 115 933395# 108# + 4 60 56 116 Ba x -54380# 200# 8162# 2# B- -14330# 379# 115 941621# 215# + 2 59 57 116 La -a -40050# 321# 8032# 3# B- * 115 957005# 345# +0 33 75 42 117 Mo x -35689# 500# 8096# 4# B- 12450# 640# 116 961686# 537# + 31 74 43 117 Tc x -48140# 400# 8195# 3# B- 11350# 589# 116 948320# 429# + 29 73 44 117 Ru x -59489.871 433.145 8285.5625 3.7021 B- 9406.8875 433.2361 116 936135.000 465.000 + 27 72 45 117 Rh x -68896.758 8.895 8359.2766 0.0760 B- 7527.1313 11.4108 116 926036.291 9.548 + 25 71 46 117 Pd -76423.890 7.255 8416.9243 0.0620 B- 5758.0284 14.7674 116 917955.584 7.788 + 23 70 47 117 Ag -82181.918 13.572 8459.4515 0.1160 B- 4236.4790 13.6099 116 911774.086 14.570 + 21 69 48 117 Cd -n -86418.397 1.013 8488.9740 0.0087 B- 2524.6381 4.9829 116 907226.039 1.087 + 19 68 49 117 In -88943.035 4.881 8503.8653 0.0417 B- 1454.7073 4.8567 116 904515.729 5.239 + 17 67 50 117 Sn -90397.742 0.483 8509.6120 0.0041 B- -1758.1788 8.4449 116 902954.036 0.518 + 15 66 51 117 Sb -88639.564 8.437 8487.8981 0.0721 B- -3544.0634 13.0785 116 904841.519 9.057 + 13 65 52 117 Te -85095.500 13.455 8450.9203 0.1150 B- -4656.9321 28.1284 116 908646.227 14.444 + 11 64 53 117 I -80438.568 25.558 8404.4307 0.2184 B- -6253.2213 27.5845 116 913645.649 27.437 + 9 63 54 117 Xe x -74185.347 10.378 8344.2976 0.0887 B- -7692.2462 63.2672 116 920358.758 11.141 + 7 62 55 117 Cs x -66493.101 62.410 8271.8652 0.5334 B- -9035.1943 258.0009 116 928616.723 67.000 + 5 61 56 117 Ba ep -57457.906 250.339 8187.9546 2.1396 B- -11187# 321# 116 938316.403 268.749 + 3 60 57 117 La -p -46271# 200# 8086# 2# B- * 116 950326# 215# +0 34 76 42 118 Mo x -32370# 500# 8067# 4# B- 10920# 640# 117 965249# 537# + 32 75 43 118 Tc x -43290# 400# 8153# 3# B- 13710# 447# 117 953526# 429# + 30 74 44 118 Ru x -57000# 200# 8263# 2# B- 7887# 202# 117 938808# 215# + 28 73 45 118 Rh x -64886.840 24.236 8322.8539 0.2054 B- 10501.5182 24.3424 117 930341.116 26.018 + 26 72 46 118 Pd -75388.358 2.494 8405.2197 0.0211 B- 4165.4444 3.5419 117 919067.273 2.677 + 24 71 47 118 Ag x -79553.802 2.515 8433.8900 0.0213 B- 7147.8469 20.1582 117 914595.484 2.700 + 22 70 48 118 Cd -nn -86701.649 20.001 8487.8350 0.1695 B- 526.5277 21.4501 117 906921.956 21.471 + 20 69 49 118 In -87228.177 7.752 8485.6670 0.0657 B- 4424.6664 7.7396 117 906356.705 8.322 + 18 68 50 118 Sn -91652.843 0.499 8516.5341 0.0042 B- -3656.6393 2.9745 117 901606.630 0.536 + 16 67 51 118 Sb - -87996.204 3.016 8478.9156 0.0256 B- -305.4459 18.5521 117 905532.194 3.237 + 14 66 52 118 Te +nn -87690.758 18.306 8469.6970 0.1551 B- -6719.7015 26.9364 117 905860.104 19.652 + 12 65 53 118 I x -80971.056 19.760 8406.1203 0.1675 B- -2891.9893 22.3197 117 913074.000 21.213 + 10 64 54 118 Xe x -78079.067 10.378 8374.9819 0.0880 B- -9669.6905 16.4423 117 916178.678 11.141 + 8 63 55 118 Cs IT -68409.377 12.753 8286.4053 0.1081 B- -6210# 201# 117 926559.517 13.690 + 6 62 56 118 Ba x -62200# 200# 8227# 2# B- -12580# 361# 117 933226# 215# + 4 61 57 118 La x -49620# 300# 8114# 3# B- * 117 946731# 322# +0 35 77 42 119 Mo x -26580# 300# 8019# 3# B- 13590# 583# 118 971465# 322# + 33 76 43 119 Tc x -40170# 500# 8126# 4# B- 11910# 583# 118 956876# 537# + 31 75 44 119 Ru x -52080# 300# 8220# 3# B- 10743# 300# 118 944090# 322# + 29 74 45 119 Rh x -62822.802 9.315 8303.3953 0.0783 B- 8584.4751 12.4416 118 932556.951 10.000 + 27 73 46 119 Pd x -71407.277 8.248 8368.9594 0.0693 B- 7238.4816 16.8566 118 923341.138 8.854 + 25 72 47 119 Ag -78645.759 14.703 8423.2126 0.1236 B- 5331.1799 35.9259 118 915570.309 15.783 + 23 71 48 119 Cd -83976.939 37.695 8461.4381 0.3168 B- 3721.7197 38.0880 118 909847.052 40.467 + 21 70 49 119 In -87698.658 7.310 8486.1387 0.0614 B- 2366.3263 7.3381 118 905851.622 7.847 + 19 69 50 119 Sn -90064.985 0.725 8499.4494 0.0061 B- -589.4452 6.9937 118 903311.266 0.778 + 17 68 51 119 Sb -89475.539 6.998 8487.9218 0.0588 B- -2293.0000 2.0000 118 903944.062 7.512 + 15 67 52 119 Te - -87182.539 7.278 8462.0785 0.0612 B- -3404.8080 22.8941 118 906405.699 7.813 + 13 66 53 119 I x -83777.731 21.706 8426.8924 0.1824 B- -4983.2433 24.0598 118 910060.910 23.302 + 11 65 54 119 Xe -78794.488 10.378 8378.4420 0.0872 B- -6489.4269 17.3790 118 915410.641 11.141 + 9 64 55 119 Cs IT -72305.061 13.940 8317.3347 0.1171 B- -7714.9651 200.7537 118 922377.327 14.965 + 7 63 56 119 Ba ep -64590.096 200.269 8245.9287 1.6829 B- -9570# 361# 118 930659.683 214.997 + 5 62 57 119 La x -55020# 300# 8159# 3# B- -11199# 583# 118 940934# 322# + 3 61 58 119 Ce x -43820# 500# 8058# 4# B- * 118 952957# 537# +0 34 77 43 120 Tc x -35000# 500# 8083# 4# B- 14720# 640# 119 962426# 537# + 32 76 44 120 Ru x -49720# 400# 8199# 3# B- 8899# 447# 119 946623# 429# + 30 75 45 120 Rh x -58620# 200# 8266# 2# B- 11660# 200# 119 937069# 215# + 28 74 46 120 Pd -70279.604 2.296 8357.0817 0.0191 B- 5371.9076 5.0261 119 924551.745 2.464 + 26 73 47 120 Ag x -75651.512 4.471 8395.3281 0.0373 B- 8305.8535 5.8202 119 918784.765 4.800 + 24 72 48 120 Cd x -83957.365 3.726 8458.0240 0.0311 B- 1770.3754 40.1837 119 909868.065 4.000 + 22 71 49 120 In + -85727.741 40.011 8466.2575 0.3334 B- 5370.0000 40.0000 119 907967.489 42.953 + 20 70 50 120 Sn -91097.741 0.920 8504.4880 0.0077 B- -2680.6076 7.1399 119 902202.557 0.987 + 18 69 51 120 Sb - -88417.133 7.199 8475.6300 0.0600 B- 945.0271 7.3530 119 905080.308 7.728 + 16 68 52 120 Te -89362.160 1.751 8476.9857 0.0146 B- -5615.0000 15.0000 119 904065.779 1.880 + 14 67 53 120 I - -83747.160 15.102 8423.6745 0.1258 B- -1574.7260 19.1760 119 910093.729 16.212 + 12 66 54 120 Xe x -82172.434 11.817 8404.0322 0.0985 B- -8283.7857 15.4611 119 911784.267 12.686 + 10 65 55 120 Cs IT -73888.649 9.970 8328.4811 0.0831 B- -5000.0000 300.0000 119 920677.277 10.702 + 8 64 56 120 Ba - -68888.649 300.166 8280.2949 2.5014 B- -11319# 424# 119 926044.997 322.241 + 6 63 57 120 La x -57570# 300# 8179# 2# B- -7840# 583# 119 938196# 322# + 4 62 58 120 Ce x -49730# 500# 8108# 4# B- * 119 946613# 537# +0 35 78 43 121 Tc x -31540# 500# 8054# 4# B- 13080# 640# 120 966140# 537# + 33 77 44 121 Ru x -44620# 400# 8156# 3# B- 11630# 737# 120 952098# 429# + 31 76 45 121 Rh x -56250.134 619.444 8245.2397 5.1194 B- 9932.2030 619.4527 120 939613.000 665.000 + 29 75 46 121 Pd x -66182.337 3.353 8320.8584 0.0277 B- 8220.4934 12.5652 120 928950.342 3.600 + 27 74 47 121 Ag x -74402.831 12.109 8382.3306 0.1001 B- 6671.0057 12.2642 120 920125.279 13.000 + 25 73 48 121 Cd x -81073.837 1.942 8430.9972 0.0161 B- 4760.7564 27.4876 120 912963.660 2.085 + 23 72 49 121 In +p -85834.593 27.419 8463.8767 0.2266 B- 3362.0331 27.4098 120 907852.778 29.435 + 21 71 50 121 Sn -89196.626 0.978 8485.1964 0.0081 B- 402.5306 2.5239 120 904243.488 1.050 + 19 70 51 121 Sb -89599.157 2.506 8482.0574 0.0207 B- -1056.0462 25.7587 120 903811.353 2.690 + 17 69 52 121 Te -88543.111 25.835 8466.8641 0.2135 B- -2297.4615 25.9856 120 904945.065 27.734 + 15 68 53 121 I -86245.649 4.723 8441.4111 0.0390 B- -3764.6525 11.2790 120 907411.492 5.070 + 13 67 54 121 Xe -82480.997 10.243 8403.8326 0.0847 B- -5378.6549 13.9791 120 911453.012 10.995 + 11 66 55 121 Cs -77102.342 14.290 8352.9152 0.1181 B- -6357.4948 141.1765 120 917227.235 15.340 + 9 65 56 121 Ba - -70744.847 141.898 8293.9083 1.1727 B- -8555# 332# 120 924052.286 152.333 + 7 64 57 121 La x -62190# 300# 8217# 2# B- -9500# 500# 120 933236# 322# + 5 63 58 121 Ce x -52690# 401# 8132# 3# B- -11139# 641# 120 943435# 430# + 3 62 59 121 Pr -p -41551# 500# 8033# 4# B- * 120 955393# 537# +0 36 79 43 122 Tc x -26305# 300# 8011# 2# B- 15475# 583# 121 971760# 322# + 34 78 44 122 Ru x -41780# 500# 8132# 4# B- 10099# 583# 121 955147# 537# + 32 77 45 122 Rh x -51880# 300# 8208# 2# B- 12737# 301# 121 944305# 322# + 30 76 46 122 Pd x -64616.169 19.561 8305.9755 0.1603 B- 6489.9492 42.9094 121 930631.693 21.000 + 28 75 47 122 Ag x -71106.118 38.191 8352.7591 0.3130 B- 9506.2662 38.2604 121 923664.446 41.000 + 26 74 48 122 Cd -80612.384 2.299 8424.2667 0.0188 B- 2958.9765 50.1126 121 913459.050 2.468 + 24 73 49 122 In + -83571.361 50.060 8442.1079 0.4103 B- 6368.5921 50.0000 121 910282.458 53.741 + 22 72 50 122 Sn -89939.953 2.448 8487.8968 0.0201 B- -1605.7483 3.2135 121 903445.494 2.627 + 20 71 51 122 Sb -88334.205 2.503 8468.3222 0.0205 B- 1979.0772 2.1265 121 905169.335 2.687 + 18 70 52 122 Te -90313.282 1.357 8478.1315 0.0111 B- -4234.0000 5.0000 121 903044.708 1.456 + 16 69 53 122 I - -86079.282 5.181 8437.0139 0.0425 B- -724.2937 12.2596 121 907590.094 5.561 + 14 68 54 122 Xe x -85354.988 11.111 8424.6644 0.0911 B- -7210.2195 35.4720 121 908367.655 11.928 + 12 67 55 122 Cs -78144.769 33.687 8359.1515 0.2761 B- -3535.8170 43.7690 121 916108.144 36.164 + 10 66 56 122 Ba x -74608.952 27.945 8323.7567 0.2291 B- -10066# 299# 121 919904.000 30.000 + 8 65 57 122 La x -64543# 298# 8235# 2# B- -6669# 499# 121 930710# 320# + 6 64 58 122 Ce x -57874# 401# 8174# 3# B- -13094# 641# 121 937870# 430# + 4 63 59 122 Pr x -44780# 500# 8060# 4# B- * 121 951927# 537# +0 35 79 44 123 Ru x -36550# 500# 8089# 4# B- 12640# 640# 122 960762# 537# + 33 78 45 123 Rh x -49190# 400# 8185# 3# B- 11239# 885# 122 947192# 429# + 31 77 46 123 Pd x -60429.748 789.441 8270.0318 6.4182 B- 9138.8323 790.1142 122 935126.000 847.500 + 29 76 47 123 Ag x -69568.581 32.602 8337.9707 0.2651 B- 7845.6026 32.7136 122 925315.060 35.000 + 27 75 48 123 Cd -77414.183 2.696 8395.3955 0.0219 B- 6014.8503 19.8980 122 916892.460 2.894 + 25 74 49 123 In -83429.034 19.832 8437.9362 0.1612 B- 4385.6489 19.8392 122 910435.252 21.290 + 23 73 50 123 Sn -87814.683 2.479 8467.2313 0.0202 B- 1408.2079 2.4203 122 905727.065 2.661 + 21 72 51 123 Sb -89222.890 1.356 8472.3196 0.0110 B- -51.9128 0.0661 122 904215.292 1.456 + 19 71 52 123 Te -89170.978 1.355 8465.5370 0.0110 B- -1228.3898 3.4448 122 904271.022 1.454 + 17 70 53 123 I -87942.588 3.686 8449.1896 0.0300 B- -2694.3302 9.6829 122 905589.753 3.956 + 15 69 54 123 Xe -85248.258 9.534 8420.9239 0.0775 B- -4204.6012 15.4121 122 908482.235 10.234 + 13 68 55 123 Cs x -81043.657 12.109 8380.3796 0.0985 B- -5388.6934 17.1253 122 912996.060 13.000 + 11 67 56 123 Ba x -75654.963 12.109 8330.2086 0.0985 B- -7004# 196# 122 918781.060 13.000 + 9 66 57 123 La x -68651# 196# 8267# 2# B- -8365# 357# 122 926300# 210# + 7 65 58 123 Ce x -60286# 298# 8193# 2# B- -10056# 499# 122 935280# 320# + 5 64 59 123 Pr x -50230# 400# 8104# 3# B- * 122 946076# 429# +0 36 80 44 124 Ru x -33590# 600# 8065# 5# B- 11120# 721# 123 963940# 644# + 34 79 45 124 Rh x -44710# 400# 8148# 3# B- 13690# 500# 123 952002# 429# + 32 78 46 124 Pd x -58400# 300# 8252# 2# B- 7830# 391# 123 937305# 322# + 30 77 47 124 Ag x -66229.951 251.503 8308.8958 2.0283 B- 10469.4858 251.5169 123 928899.227 270.000 + 28 76 48 124 Cd -76699.436 2.609 8387.0179 0.0210 B- 4168.3420 30.5355 123 917659.772 2.800 + 26 75 49 124 In -80867.778 30.561 8414.3243 0.2465 B- 7363.6970 30.5668 123 913184.873 32.808 + 24 74 50 124 Sn -88231.475 1.314 8467.3997 0.0106 B- -612.4067 0.4101 123 905279.619 1.410 + 22 73 51 124 Sb -n -87619.069 1.358 8456.1517 0.0110 B- 2905.0730 0.1317 123 905937.065 1.457 + 20 72 52 124 Te -90524.142 1.352 8473.2705 0.0109 B- -3159.5870 1.8593 123 902818.341 1.451 + 18 71 53 124 I - -87364.555 2.299 8441.4807 0.0185 B- 302.8501 1.8639 123 906210.297 2.467 + 16 70 54 124 Xe -87667.405 1.358 8437.6138 0.0110 B- -5926.3445 9.2512 123 905885.174 1.457 + 14 69 55 124 Cs x -81741.060 9.151 8383.5114 0.0738 B- -2651.2748 15.4894 123 912247.366 9.823 + 12 68 56 124 Ba x -79089.786 12.497 8355.8209 0.1008 B- -8831.1685 58.0305 123 915093.627 13.416 + 10 67 57 124 La x -70258.617 56.669 8278.2926 0.4570 B- -5343# 303# 123 924574.275 60.836 + 8 66 58 124 Ce x -64916# 298# 8229# 2# B- -11765# 499# 123 930310# 320# + 6 65 59 124 Pr x -53151# 401# 8128# 3# B- -8321# 641# 123 942940# 430# + 4 64 60 124 Nd x -44830# 500# 8054# 4# B- * 123 951873# 537# +0 37 81 44 125 Ru x -28370# 300# 8023# 2# B- 13460# 583# 124 969544# 322# + 35 80 45 125 Rh x -41830# 500# 8124# 4# B- 12130# 640# 124 955094# 537# + 33 79 46 125 Pd x -53960# 400# 8215# 3# B- 10560# 589# 124 942072# 429# + 31 78 47 125 Ag x -64519.939 433.145 8293.3151 3.4652 B- 8828.1511 433.1544 124 930735.000 465.000 + 29 77 48 125 Cd x -73348.090 2.888 8357.6815 0.0231 B- 7064.2177 3.3869 124 921257.590 3.100 + 27 76 49 125 In x -80412.308 1.770 8407.9365 0.0142 B- 5481.3495 2.2131 124 913673.841 1.900 + 25 75 50 125 Sn -n -85893.657 1.329 8445.5285 0.0106 B- 2361.4366 2.1661 124 907789.370 1.426 + 23 74 51 125 Sb + -88255.094 2.515 8458.1612 0.0201 B- 766.7000 2.1213 124 905254.264 2.700 + 21 73 52 125 Te -89021.794 1.352 8458.0361 0.0108 B- -185.7700 0.0600 124 904431.178 1.451 + 19 72 53 125 I - -88836.024 1.353 8450.2911 0.0108 B- -1636.6632 0.4259 124 904630.610 1.452 + 17 71 54 125 Xe -87199.361 1.415 8430.9390 0.0113 B- -3109.6184 7.7879 124 906387.640 1.518 + 15 70 55 125 Cs -84089.742 7.736 8399.8033 0.0619 B- -4420.7663 13.4415 124 909725.953 8.304 + 13 69 56 125 Ba -79668.976 10.992 8358.1784 0.0879 B- -5909.4836 27.6308 124 914471.840 11.800 + 11 68 57 125 La -73759.492 25.997 8304.6438 0.2080 B- -7102# 197# 124 920815.931 27.909 + 9 67 58 125 Ce x -66658# 196# 8242# 2# B- -8587# 358# 124 928440# 210# + 7 66 59 125 Pr x -58070# 300# 8167# 2# B- -10001# 500# 124 937659# 322# + 5 65 60 125 Nd x -48070# 400# 8080# 3# B- * 124 948395# 429# +0 36 81 45 126 Rh x -37200# 500# 8087# 4# B- 14590# 640# 125 960064# 537# + 34 80 46 126 Pd x -51790# 400# 8197# 3# B- 8930# 447# 125 944401# 429# + 32 79 47 126 Ag x -60720# 200# 8261# 2# B- 11535# 200# 125 934814# 215# + 30 78 48 126 Cd -72255.727 2.304 8346.7393 0.0183 B- 5553.6500 4.7831 125 922430.290 2.473 + 28 77 49 126 In x -77809.377 4.192 8384.6067 0.0333 B- 8205.7585 11.4802 125 916468.202 4.500 + 26 76 50 126 Sn -nn -86015.135 10.688 8443.5227 0.0848 B- 378.0000 30.0000 125 907658.958 11.473 + 24 75 51 126 Sb - -86393.135 31.847 8440.3136 0.2528 B- 3671.0321 31.8223 125 907253.158 34.189 + 22 74 52 126 Te -90064.168 1.354 8463.2397 0.0107 B- -2153.6712 3.6717 125 903312.144 1.453 + 20 73 53 126 I -87910.496 3.778 8439.9379 0.0300 B- 1235.8904 3.7779 125 905624.205 4.055 + 18 72 54 126 Xe -89146.38687 0.00562 8443.5375 0.0003 B- -4795.7039 10.3587 125 904297.422 0.006 + 16 71 55 126 Cs -84350.683 10.359 8399.2673 0.0822 B- -1680.7697 16.2322 125 909445.821 11.120 + 14 70 56 126 Ba x -82669.913 12.497 8379.7187 0.0992 B- -7696.4376 91.3663 125 911250.202 13.416 + 12 69 57 126 La x -74973.476 90.508 8312.4268 0.7183 B- -4152.9106 94.7235 125 919512.667 97.163 + 10 68 58 126 Ce x -70820.565 27.945 8273.2581 0.2218 B- -10497# 198# 125 923971.000 30.000 + 8 67 59 126 Pr x -60324# 196# 8184# 2# B- -6943# 358# 125 935240# 210# + 6 66 60 126 Nd x -53380# 300# 8122# 2# B- -13631# 583# 125 942694# 322# + 4 65 61 126 Pm x -39750# 500# 8008# 4# B- * 125 957327# 537# +0 37 82 45 127 Rh x -33730# 600# 8060# 5# B- 13490# 781# 126 963789# 644# + 35 81 46 127 Pd x -47220# 500# 8160# 4# B- 11429# 539# 126 949307# 537# + 33 80 47 127 Ag x -58650# 200# 8244# 2# B- 10092# 200# 126 937037# 215# + 31 79 48 127 Cd x -68741.199 6.200 8316.8971 0.0488 B- 8138.6978 11.7675 126 926203.291 6.656 + 29 78 49 127 In -76879.897 10.001 8374.8212 0.0788 B- 6589.6810 12.0260 126 917466.040 10.736 + 27 77 50 127 Sn -83469.578 9.226 8420.5482 0.0726 B- 3228.7160 10.1668 126 910391.726 9.904 + 25 76 51 127 Sb -86698.294 5.083 8439.8110 0.0400 B- 1582.2030 4.9102 126 906925.557 5.457 + 23 75 52 127 Te -88280.497 1.365 8446.1090 0.0108 B- 702.7199 3.5652 126 905226.993 1.465 + 21 74 53 127 I -88983.217 3.621 8445.4820 0.0285 B- -662.3336 2.0442 126 904472.592 3.887 + 19 73 54 127 Xe -88320.883 4.088 8434.1066 0.0322 B- -2080.8562 6.4115 126 905183.636 4.388 + 17 72 55 127 Cs -86240.027 5.578 8411.5617 0.0439 B- -3422.0719 12.6525 126 907417.527 5.987 + 15 71 56 127 Ba -82817.955 11.357 8378.4560 0.0894 B- -4921.8386 27.7403 126 911091.272 12.192 + 13 70 57 127 La -77896.116 26.000 8333.5412 0.2047 B- -5916.7727 38.8567 126 916375.083 27.912 + 11 69 58 127 Ce x -71979.344 28.876 8280.7922 0.2274 B- -7436# 198# 126 922727.000 31.000 + 9 68 59 127 Pr x -64543# 196# 8216# 2# B- -8633# 358# 126 930710# 210# + 7 67 60 127 Nd x -55910# 300# 8142# 2# B- -10600# 500# 126 939978# 322# + 5 66 61 127 Pm x -45310# 400# 8052# 3# B- * 126 951358# 429# +0 38 83 45 128 Rh x -27340# 300# 8010# 2# B- 17050# 583# 127 970649# 322# + 36 82 46 128 Pd x -44390# 500# 8137# 4# B- 10320# 583# 127 952345# 537# + 34 81 47 128 Ag x -54710# 300# 8211# 2# B- 12528# 300# 127 941266# 322# + 32 80 48 128 Cd -67238.245 6.432 8303.2367 0.0503 B- 6951.8716 6.5665 127 927816.778 6.905 + 30 79 49 128 In x -74190.117 1.322 8351.4361 0.0103 B- 9171.3131 17.7194 127 920353.637 1.419 + 28 78 50 128 Sn -83361.430 17.682 8416.9749 0.1381 B- 1268.4219 13.3175 127 910507.828 18.982 + 26 77 51 128 Sb IT -84629.852 18.788 8420.7724 0.1468 B- 4363.9419 18.7862 127 909146.121 20.169 + 24 76 52 128 Te -88993.794 0.706 8448.7536 0.0055 B- -1255.7634 3.6807 127 904461.237 0.758 + 22 75 53 128 I -87738.030 3.621 8432.8309 0.0283 B- 2122.5041 3.6211 127 905809.355 3.887 + 20 74 54 128 Xe -89860.53427 0.00520 8443.3008 0.0003 B- -3928.7617 5.3762 127 903530.75341 0.00558 + 18 73 55 128 Cs -85931.773 5.376 8406.4953 0.0420 B- -562.6171 5.6122 127 907748.452 5.771 + 16 72 56 128 Ba -85369.156 1.610 8395.9878 0.0126 B- -6743.7167 54.4716 127 908352.446 1.728 + 14 71 57 128 La x -78625.439 54.448 8337.1904 0.4254 B- -3091.5136 61.2003 127 915592.123 58.452 + 12 70 58 128 Ce x -75533.925 27.945 8306.9259 0.2183 B- -9203.1617 40.8585 127 918911.000 30.000 + 10 69 59 128 Pr x -66330.764 29.808 8228.9141 0.2329 B- -5800# 202# 127 928791.000 32.000 + 8 68 60 128 Nd x -60530# 200# 8177# 2# B- -12311# 361# 127 935018# 215# + 6 67 61 128 Pm x -48220# 300# 8075# 2# B- -9070# 583# 127 948234# 322# + 4 66 62 128 Sm x -39150# 500# 7998# 4# B- * 127 957971# 537# +0 37 83 46 129 Pd x -37880# 600# 8086# 5# B- 13990# 721# 128 959334# 644# + 35 82 47 129 Ag x -51870# 400# 8188# 3# B- 11252# 400# 128 944315# 429# + 33 81 48 129 Cd x -63122.142 5.310 8269.5311 0.0412 B- 9712.7471 5.6637 128 932235.597 5.700 + 31 80 49 129 In -72834.889 1.971 8338.7590 0.0153 B- 7755.7081 17.2376 128 921808.534 2.116 + 29 79 50 129 Sn -80590.597 17.270 8392.8161 0.1339 B- 4038.7874 27.3634 128 913482.440 18.540 + 27 78 51 129 Sb + -84629.384 21.225 8418.0598 0.1645 B- 2375.5000 21.2132 128 909146.623 22.786 + 25 77 52 129 Te -87004.884 0.711 8430.4098 0.0055 B- 1502.2919 3.1358 128 906596.419 0.763 + 23 76 53 129 I -88507.176 3.153 8435.9908 0.0244 B- 188.8936 3.1534 128 904983.643 3.385 + 21 75 54 129 Xe -88696.06975 0.00505 8431.3904 0.0003 B- -1197.0197 4.5532 128 904780.85742 0.00542 + 19 74 55 129 Cs -87499.050 4.553 8416.0465 0.0353 B- -2438.1843 10.5627 128 906065.910 4.888 + 17 73 56 129 Ba -85060.866 10.504 8391.0811 0.0814 B- -3737.3247 21.6280 128 908683.409 11.276 + 15 72 57 129 La -81323.541 21.343 8356.0449 0.1655 B- -5036.0370 35.1633 128 912695.592 22.913 + 13 71 58 129 Ce x -76287.504 27.945 8310.9411 0.2166 B- -6513.9383 40.8585 128 918102.000 30.000 + 11 70 59 129 Pr x -69773.566 29.808 8254.3808 0.2311 B- -7399# 204# 128 925095.000 32.000 + 9 69 60 129 Nd ep -62375# 202# 8191# 2# B- -9195# 362# 128 933038# 217# + 7 68 61 129 Pm x -53180# 300# 8114# 2# B- -10850# 583# 128 942909# 322# + 5 67 62 129 Sm x -42330# 500# 8023# 4# B- * 128 954557# 537# +0 38 84 46 130 Pd x -32730# 300# 8046# 2# B- 13168# 520# 129 964863# 322# + 36 83 47 130 Ag -nn -45898# 424# 8142# 3# B- 15220# 425# 129 950727# 455# + 34 82 48 130 Cd x -61117.597 22.356 8252.5868 0.1720 B- 8788.9322 22.4274 129 934387.563 24.000 + 32 81 49 130 In -69906.530 1.790 8314.1760 0.0138 B- 10225.6870 2.5905 129 924952.257 1.921 + 30 80 50 130 Sn -80132.217 1.873 8386.8170 0.0144 B- 2153.4702 14.1129 129 913974.531 2.010 + 28 79 51 130 Sb -82285.687 14.212 8397.3641 0.1093 B- 5067.2728 14.2124 129 911662.686 15.257 + 26 78 52 130 Te -87352.960 0.011 8430.3251 0.0003 B- -416.7716 3.1537 129 906222.745 0.011 + 24 77 53 130 I -n -86936.188 3.154 8421.1011 0.0243 B- 2944.2864 3.1537 129 906670.168 3.385 + 22 76 54 130 Xe -89880.474 0.009 8437.7314 0.0003 B- -2980.7199 8.3567 129 903509.346 0.010 + 20 75 55 130 Cs -86899.754 8.357 8408.7848 0.0643 B- 357.0219 8.3617 129 906709.281 8.971 + 18 74 56 130 Ba -87256.776 0.287 8405.5130 0.0022 B- -5629.4021 25.9477 129 906326.002 0.308 + 16 73 57 130 La x -81627.374 25.946 8356.1919 0.1996 B- -2204.4611 38.1328 129 912369.413 27.854 + 14 72 58 130 Ce x -79422.913 27.945 8333.2164 0.2150 B- -8247.4488 70.0853 129 914736.000 30.000 + 12 71 59 130 Pr x -71175.464 64.273 8263.7565 0.4944 B- -4579.2250 70.0853 129 923590.000 69.000 + 10 70 60 130 Nd x -66596.239 27.945 8222.5136 0.2150 B- -11127# 202# 129 928506.000 30.000 + 8 69 61 130 Pm x -55470# 200# 8131# 2# B- -7770# 447# 129 940451# 215# + 6 68 62 130 Sm x -47700# 400# 8065# 3# B- -14187# 671# 129 948792# 429# + 4 67 63 130 Eu -p -33513# 539# 7950# 4# B- * 129 964022# 578# +0 39 85 46 131 Pd x -25740# 300# 7993# 2# B- 15010# 583# 130 972367# 322# + 37 84 47 131 Ag x -40750# 500# 8102# 4# B- 14462# 501# 130 956253# 537# + 35 83 48 131 Cd -55211.760 19.238 8206.1204 0.1469 B- 12812.6089 19.3644 130 940727.740 20.653 + 33 82 49 131 In -68024.369 2.205 8297.9544 0.0168 B- 9240.2095 4.2397 130 926972.839 2.367 + 31 81 50 131 Sn -77264.579 3.621 8362.5183 0.0276 B- 4716.8328 3.9621 130 917053.067 3.887 + 29 80 51 131 Sb -81981.412 2.084 8392.5525 0.0159 B- 3229.6099 2.0845 130 911989.339 2.236 + 27 79 52 131 Te -n -85211.022 0.061 8411.2339 0.0005 B- 2231.7057 0.6077 130 908522.210 0.065 + 25 78 53 131 I + -87442.727 0.605 8422.2977 0.0046 B- 970.8477 0.6046 130 906126.375 0.649 + 23 77 54 131 Xe -88413.57492 0.00512 8423.7367 0.0003 B- -358.0009 0.1771 130 905084.12808 0.00549 + 21 76 55 131 Cs +nn -88055.574 0.177 8415.0317 0.0014 B- -1376.6158 0.4515 130 905468.457 0.190 + 19 75 56 131 Ba -n -86678.958 0.415 8398.5511 0.0032 B- -2909.6936 27.9479 130 906946.315 0.445 + 17 74 57 131 La x -83769.265 27.945 8370.3676 0.2133 B- -4060.8167 43.0918 130 910070.000 30.000 + 15 73 58 131 Ce -79708.448 32.802 8333.3969 0.2504 B- -5407.7842 55.4462 130 914429.465 35.214 + 13 72 59 131 Pr -74300.664 46.995 8286.1439 0.3587 B- -6532.6235 53.0809 130 920234.960 50.451 + 11 71 60 131 Nd -67768.040 27.517 8230.3045 0.2101 B- -7998# 202# 130 927248.020 29.541 + 9 70 61 131 Pm x -59770# 200# 8163# 2# B- -9490# 447# 130 935834# 215# + 7 69 62 131 Sm x -50280# 400# 8085# 3# B- -10816# 565# 130 946022# 429# + 5 68 63 131 Eu -p -39464# 400# 7996# 3# B- * 130 957634# 429# +0 38 85 47 132 Ag x -34400# 500# 8053# 4# B- 16065# 504# 131 963070# 537# + 36 84 48 132 Cd x -50465.429 60.068 8169.1421 0.4551 B- 11946.1243 84.9236 131 945823.136 64.485 + 34 83 49 132 In + -62411.554 60.033 8253.7162 0.4548 B- 14135.0000 60.0000 131 932998.444 64.447 + 32 82 50 132 Sn -76546.554 1.976 8354.8726 0.0150 B- 3088.7280 3.1606 131 917823.898 2.121 + 30 81 51 132 Sb -79635.282 2.467 8372.3452 0.0187 B- 5552.9155 4.2708 131 914508.013 2.648 + 28 80 52 132 Te -85188.197 3.486 8408.4859 0.0264 B- 515.3046 3.4830 131 908546.713 3.742 + 26 79 53 132 I -85703.502 4.065 8406.4628 0.0308 B- 3575.4729 4.0654 131 907993.511 4.364 + 24 78 54 132 Xe -89278.97451 0.00507 8427.6229 0.0003 B- -2126.2813 1.0359 131 904155.08346 0.00544 + 22 77 55 132 Cs -87152.693 1.036 8405.5878 0.0079 B- 1282.2099 1.4773 131 906437.740 1.112 + 20 76 56 132 Ba -88434.903 1.053 8409.3747 0.0080 B- -4711.3256 36.3537 131 905061.231 1.130 + 18 75 57 132 La -83723.578 36.359 8367.7559 0.2754 B- -1254.8898 41.7025 131 910119.047 39.032 + 16 74 58 132 Ce -82468.688 20.407 8352.3223 0.1546 B- -7241.2240 35.3594 131 911466.226 21.907 + 14 73 59 132 Pr x -75227.464 28.876 8291.5377 0.2188 B- -3801.6487 37.6795 131 919240.000 31.000 + 12 72 60 132 Nd x -71425.815 24.205 8256.8104 0.1834 B- -9798# 151# 131 923321.237 25.985 + 10 71 61 132 Pm x -61628# 149# 8177# 1# B- -6488# 335# 131 933840# 160# + 8 70 62 132 Sm x -55140# 300# 8122# 2# B- -12939# 500# 131 940805# 322# + 6 69 63 132 Eu x -42200# 400# 8018# 3# B- * 131 954696# 429# +0 39 86 47 133 Ag x -29080# 500# 8013# 4# B- 15059# 539# 132 968781# 537# + 37 85 48 133 Cd x -44140# 200# 8121# 2# B- 13550# 283# 132 952614# 215# + 35 84 49 133 In x -57690# 200# 8217# 2# B- 13184# 200# 132 938067# 215# + 33 83 50 133 Sn -70873.890 1.904 8310.0890 0.0143 B- 8049.6228 3.6617 132 923913.753 2.043 + 31 82 51 133 Sb -78923.513 3.128 8364.7302 0.0235 B- 4013.6198 3.5179 132 915272.128 3.357 + 29 81 52 133 Te -82937.133 2.066 8389.0255 0.0155 B- 2920.1690 6.2531 132 910963.330 2.218 + 27 80 53 133 I -85857.302 5.902 8405.0993 0.0444 B- 1786.2812 6.3712 132 907828.400 6.335 + 25 79 54 133 Xe + -87643.583 2.400 8412.6477 0.0180 B- 427.3600 2.4000 132 905910.748 2.576 + 23 78 55 133 Cs -88070.943 0.008 8409.9786 0.0003 B- -517.4310 0.9920 132 905451.958 0.008 + 21 77 56 133 Ba -87553.512 0.992 8400.2059 0.0075 B- -2059.1203 27.9624 132 906007.443 1.065 + 19 76 57 133 La x -85494.392 27.945 8378.8415 0.2101 B- -3076.1685 32.3786 132 908218.000 30.000 + 17 75 58 133 Ce x -82418.223 16.354 8349.8301 0.1230 B- -4480.6319 20.5826 132 911520.402 17.557 + 15 74 59 133 Pr x -77937.591 12.497 8310.2588 0.0940 B- -5605.2112 48.2223 132 916330.558 13.416 + 13 73 60 133 Nd x -72332.380 46.575 8262.2320 0.3502 B- -6924.7272 68.5519 132 922348.000 50.000 + 11 72 61 133 Pm x -65407.653 50.301 8204.2841 0.3782 B- -8177# 302# 132 929782.000 54.000 + 9 71 62 133 Sm x -57231# 298# 8137# 2# B- -9995# 422# 132 938560# 320# + 7 70 63 133 Eu x -47236# 298# 8056# 2# B- -11176# 582# 132 949290# 320# + 5 69 64 133 Gd x -36060# 500# 7966# 4# B- * 132 961288# 537# +0 38 86 48 134 Cd x -39460# 300# 8086# 2# B- 12510# 361# 133 957638# 322# + 36 85 49 134 In x -51970# 200# 8173# 1# B- 14464# 200# 133 944208# 215# + 34 84 50 134 Sn x -66433.759 3.167 8275.1719 0.0236 B- 7585.2453 4.4136 133 928680.430 3.400 + 32 83 51 134 Sb x -74019.004 3.074 8325.9398 0.0229 B- 8514.7483 4.1221 133 920537.334 3.300 + 30 82 52 134 Te -82533.752 2.746 8383.6442 0.0205 B- 1509.6875 4.9335 133 911396.376 2.948 + 28 81 53 134 I -84043.440 4.857 8389.0722 0.0362 B- 4082.3946 4.8567 133 909775.660 5.213 + 26 80 54 134 Xe -88125.83443 0.00577 8413.6994 0.0003 B- -1234.6691 0.0160 133 905393.030 0.006 + 24 79 55 134 Cs -86891.165 0.016 8398.6470 0.0003 B- 2058.8368 0.2508 133 906718.501 0.017 + 22 78 56 134 Ba -88950.002 0.251 8408.1731 0.0019 B- -3731.3434 19.9312 133 904508.249 0.269 + 20 77 57 134 La x -85218.659 19.930 8374.4888 0.1487 B- -385.7605 28.5098 133 908514.011 21.395 + 18 76 58 134 Ce x -84832.898 20.387 8365.7716 0.1521 B- -6304.8987 28.7814 133 908928.142 21.886 + 16 75 59 134 Pr x -78528.000 20.316 8312.8817 0.1516 B- -2881.5569 23.5032 133 915696.729 21.810 + 14 74 60 134 Nd x -75646.443 11.817 8285.5391 0.0882 B- -8882.5343 43.5512 133 918790.207 12.686 + 12 73 61 134 Pm x -66763.908 41.917 8213.4131 0.3128 B- -5388# 200# 133 928326.000 45.000 + 10 72 62 134 Sm x -61376# 196# 8167# 1# B- -11576# 358# 133 934110# 210# + 8 71 63 134 Eu x -49800# 300# 8075# 2# B- -8271# 500# 133 946537# 322# + 6 70 64 134 Gd x -41530# 400# 8008# 3# B- * 133 955416# 429# +0 39 87 48 135 Cd x -32820# 400# 8036# 3# B- 14290# 500# 134 964766# 429# + 37 86 49 135 In x -47110# 300# 8136# 2# B- 13522# 300# 134 949425# 322# + 35 85 50 135 Sn x -60632.252 3.074 8230.6877 0.0228 B- 9058.0800 4.0522 134 934908.603 3.300 + 33 84 51 135 Sb -69690.332 2.640 8291.9894 0.0196 B- 8038.4581 3.1524 134 925184.354 2.834 + 31 83 52 135 Te -77728.790 1.722 8345.7384 0.0128 B- 6050.3894 2.6850 134 916554.715 1.848 + 29 82 53 135 I -83779.180 2.060 8384.7609 0.0153 B- 2634.1851 3.8284 134 910059.355 2.211 + 27 81 54 135 Xe -86413.365 3.668 8398.4783 0.0272 B- 1168.5917 3.6623 134 907231.441 3.938 + 25 80 55 135 Cs -87581.956 0.364 8401.3393 0.0027 B- 268.6983 0.2862 134 905976.907 0.390 + 23 79 56 135 Ba -87850.655 0.245 8397.5345 0.0018 B- -1207.1973 9.4299 134 905688.447 0.263 + 21 78 57 135 La -86643.458 9.432 8382.7972 0.0699 B- -2027.1499 4.6101 134 906984.427 10.126 + 19 77 58 135 Ce -84616.308 10.266 8361.9861 0.0760 B- -3680.4357 15.6540 134 909160.662 11.021 + 17 76 59 135 Pr x -80935.872 11.817 8328.9284 0.0875 B- -4722.2522 22.4837 134 913111.772 12.686 + 15 75 60 135 Nd x -76213.620 19.128 8288.1536 0.1417 B- -6151.2907 85.0809 134 918181.318 20.534 + 13 74 61 135 Pm x -70062.329 82.903 8236.7933 0.6141 B- -7205.1069 175.4501 134 924785.000 89.000 + 11 73 62 135 Sm x -62857.222 154.628 8177.6270 1.1454 B- -8709# 249# 134 932520.000 166.000 + 9 72 63 135 Eu x -54148# 196# 8107# 1# B- -9898# 445# 134 941870# 210# + 7 71 64 135 Gd x -44250# 400# 8028# 3# B- -11197# 565# 134 952496# 429# + 5 70 65 135 Tb -p -33053# 400# 7939# 3# B- * 134 964516# 429# +0 38 87 49 136 In x -40970# 300# 8091# 2# B- 15200# 361# 135 956017# 322# + 36 86 50 136 Sn x -56170# 200# 8197# 1# B- 8337# 200# 135 939699# 215# + 34 85 51 136 Sb -64506.890 5.830 8252.2533 0.0429 B- 9918.3897 6.2599 135 930749.009 6.258 + 32 84 52 136 Te -74425.279 2.281 8319.4301 0.0168 B- 5119.9455 14.1880 135 920101.180 2.448 + 30 83 53 136 I -79545.225 14.188 8351.3242 0.1043 B- 6883.9455 14.1880 135 914604.693 15.231 + 28 82 54 136 Xe -86429.170 0.007 8396.1889 0.0003 B- -90.3151 1.8730 135 907214.474 0.007 + 26 81 55 136 Cs + -86338.855 1.873 8389.7723 0.0138 B- 2548.2241 1.8570 135 907311.431 2.010 + 24 80 56 136 Ba -88887.079 0.245 8402.7566 0.0018 B- -2849.5915 53.1715 135 904575.800 0.262 + 22 79 57 136 La x -86037.488 53.171 8376.0512 0.3910 B- 471.0621 53.1720 135 907634.962 57.081 + 20 78 58 136 Ce -86508.550 0.324 8373.7624 0.0024 B- -5168.1290 11.4561 135 907129.256 0.348 + 18 77 59 136 Pr -81340.421 11.455 8330.0089 0.0842 B- -2141.1234 16.4578 135 912677.470 12.296 + 16 76 60 136 Nd x -79199.297 11.817 8308.5127 0.0869 B- -8029.3747 70.0764 135 914976.061 12.686 + 14 75 61 136 Pm x -71169.923 69.073 8243.7207 0.5079 B- -4359.0237 70.1942 135 923595.949 74.152 + 12 74 62 136 Sm x -66810.899 12.497 8205.9165 0.0919 B- -10567# 196# 135 928275.553 13.416 + 10 73 63 136 Eu x -56244# 196# 8122# 1# B- -7154# 357# 135 939620# 210# + 8 72 64 136 Gd x -49090# 298# 8064# 2# B- -13190# 582# 135 947300# 320# + 6 71 65 136 Tb x -35900# 500# 7961# 4# B- * 135 961460# 537# +0 39 88 49 137 In x -35830# 400# 8053# 3# B- 14320# 500# 136 961535# 429# + 37 87 50 137 Sn x -50150# 300# 8152# 2# B- 9911# 304# 136 946162# 322# + 35 86 51 137 Sb x -60060.392 52.164 8218.4764 0.3808 B- 9243.3698 52.2059 136 935522.519 56.000 + 33 85 52 137 Te -69303.762 2.100 8280.2357 0.0153 B- 7052.5063 8.6426 136 925599.354 2.254 + 31 84 53 137 I p-2n -76356.268 8.383 8326.0033 0.0612 B- 6027.1455 8.3841 136 918028.178 9.000 + 29 83 54 137 Xe -n -82383.414 0.104 8364.2865 0.0008 B- 4162.3582 0.3193 136 911557.771 0.111 + 27 82 55 137 Cs + -86545.772 0.302 8388.9581 0.0022 B- 1175.6285 0.1723 136 907089.296 0.324 + 25 81 56 137 Ba -87721.401 0.248 8391.8288 0.0018 B- -580.5356 1.6231 136 905827.207 0.266 + 23 80 57 137 La + -87140.865 1.640 8381.8807 0.0120 B- -1222.1000 1.6000 136 906450.438 1.760 + 21 79 58 137 Ce -85918.765 0.360 8367.2497 0.0026 B- -2716.9515 8.1328 136 907762.416 0.386 + 19 78 59 137 Pr -83201.814 8.135 8341.7074 0.0594 B- -3617.8447 14.2706 136 910679.183 8.733 + 17 77 60 137 Nd -79583.969 11.725 8309.5892 0.0856 B- -5511.1108 17.5366 136 914563.099 12.586 + 15 76 61 137 Pm x -74072.858 13.041 8263.6516 0.0952 B- -6081.2029 31.4460 136 920479.519 14.000 + 13 75 62 137 Sm -67991.655 28.614 8213.5527 0.2089 B- -7845.7518 28.9474 136 927007.959 30.718 + 11 74 63 137 Eu x -60145.904 4.378 8150.5738 0.0320 B- -8932# 298# 136 935430.719 4.700 + 9 73 64 137 Gd x -51214# 298# 8080# 2# B- -10246# 499# 136 945020# 320# + 7 72 65 137 Tb x -40967# 401# 7999# 3# B- * 136 956020# 430# +0 38 88 50 138 Sn x -45510# 400# 8118# 3# B- 9140# 500# 137 951143# 429# + 36 87 51 138 Sb x -54650# 300# 8178# 2# B- 11046# 300# 137 941331# 322# + 34 86 52 138 Te -65695.995 3.787 8252.5786 0.0274 B- 6283.9149 7.0625 137 929472.452 4.065 + 32 85 53 138 I x -71979.910 5.962 8292.4450 0.0432 B- 7992.3346 6.5881 137 922726.392 6.400 + 30 84 54 138 Xe -79972.244 2.804 8344.6913 0.0203 B- 2914.7839 9.5780 137 914146.268 3.010 + 28 83 55 138 Cs -82887.028 9.158 8360.1437 0.0664 B- 5374.7776 9.1584 137 911017.119 9.831 + 26 82 56 138 Ba -88261.806 0.249 8393.4222 0.0018 B- -1748.3977 0.3384 137 905247.059 0.267 + 24 81 57 138 La -86513.408 0.416 8375.0835 0.0030 B- 1052.4585 0.4018 137 907124.041 0.446 + 22 80 58 138 Ce -87565.867 0.499 8377.0408 0.0036 B- -4437.0000 10.0000 137 905994.180 0.536 + 20 79 59 138 Pr - -83128.867 10.012 8339.2195 0.0726 B- -1111.6847 15.3256 137 910757.495 10.748 + 18 78 60 138 Nd -82017.182 11.603 8325.4946 0.0841 B- -7102.8119 16.0995 137 911950.938 12.456 + 16 77 61 138 Pm -74914.370 11.603 8268.3558 0.0841 B- -3416.5976 16.5613 137 919576.119 12.456 + 14 76 62 138 Sm x -71497.772 11.817 8237.9286 0.0856 B- -9748.0968 30.3408 137 923243.988 12.686 + 12 75 63 138 Eu x -61749.676 27.945 8161.6211 0.2025 B- -6090# 202# 137 933709.000 30.000 + 10 74 64 138 Gd x -55660# 200# 8112# 1# B- -12059# 361# 137 940247# 215# + 8 73 65 138 Tb x -43600# 300# 8019# 2# B- -8669# 586# 137 953193# 322# + 6 72 66 138 Dy x -34931# 503# 7950# 4# B- * 137 962500# 540# +0 39 89 50 139 Sn x -39310# 400# 8073# 3# B- 10740# 565# 138 957799# 429# + 37 88 51 139 Sb x -50050# 400# 8144# 3# B- 10155# 400# 138 946269# 429# + 35 87 52 139 Te x -60205.080 3.540 8211.7716 0.0255 B- 8265.8835 5.3454 138 935367.191 3.800 + 33 86 53 139 I x -68470.964 4.005 8265.6100 0.0288 B- 7173.6224 4.5424 138 926493.400 4.300 + 31 85 54 139 Xe x -75644.586 2.142 8311.5904 0.0154 B- 5056.5023 3.7960 138 918792.200 2.300 + 29 84 55 139 Cs + -80701.088 3.134 8342.3397 0.0225 B- 4212.8293 3.1235 138 913363.822 3.364 + 27 83 56 139 Ba -n -84913.918 0.253 8367.0194 0.0018 B- 2308.4632 0.6571 138 908841.164 0.271 + 25 82 57 139 La -87222.381 0.607 8377.9987 0.0044 B- -264.6396 1.9989 138 906362.927 0.651 + 23 81 58 139 Ce -86957.741 2.089 8370.4664 0.0150 B- -2129.0890 2.9962 138 906647.029 2.242 + 21 80 59 139 Pr -84828.652 3.649 8349.5208 0.0263 B- -2811.7226 27.6166 138 908932.700 3.917 + 19 79 60 139 Nd -82016.930 27.521 8323.6642 0.1980 B- -4515.9014 25.8700 138 911951.208 29.545 + 17 78 61 139 Pm -77501.028 13.588 8285.5473 0.0978 B- -5120.7993 17.4098 138 916799.228 14.587 + 15 77 62 139 Sm x -72380.229 10.884 8243.0786 0.0783 B- -6982.1777 17.0705 138 922296.631 11.684 + 13 76 63 139 Eu x -65398.051 13.151 8187.2187 0.0946 B- -7767# 196# 138 929792.307 14.117 + 11 75 64 139 Gd x -57632# 196# 8126# 1# B- -9501# 357# 138 938130# 210# + 9 74 65 139 Tb x -48130# 298# 8052# 2# B- -10430# 582# 138 948330# 320# + 7 73 66 139 Dy x -37700# 500# 7971# 4# B- * 138 959527# 537# +0 40 90 50 140 Sn x -34490# 300# 8038# 2# B- 9900# 671# 139 962973# 322# + 38 89 51 140 Sb x -44390# 600# 8103# 4# B- 11977# 600# 139 952345# 644# + 36 88 52 140 Te -56367.449 14.377 8183.3567 0.1027 B- 7238.7734 18.7976 139 939487.057 15.434 + 34 87 53 140 I x -63606.223 12.109 8229.4740 0.0865 B- 9380.2388 12.3313 139 931715.914 13.000 + 32 86 54 140 Xe x -72986.461 2.329 8290.8875 0.0166 B- 4063.2768 8.5232 139 921645.814 2.500 + 30 85 55 140 Cs -77049.738 8.199 8314.3227 0.0586 B- 6218.1669 9.8671 139 917283.707 8.801 + 28 84 56 140 Ba -83267.905 7.900 8353.1500 0.0564 B- 1044.1542 7.9051 139 910608.231 8.480 + 26 83 57 140 La -84312.059 0.607 8355.0201 0.0043 B- 3762.1676 1.3364 139 909487.285 0.651 + 24 82 58 140 Ce -88074.227 1.313 8376.3045 0.0094 B- -3388.0000 6.0000 139 905448.433 1.409 + 22 81 59 140 Pr - -84686.227 6.142 8346.5163 0.0439 B- -428.9806 6.9536 139 909085.600 6.593 + 20 80 60 140 Nd x -84257.246 3.260 8337.8640 0.0233 B- -6045.2000 24.0000 139 909546.130 3.500 + 18 79 61 140 Pm - -78212.046 24.220 8289.0958 0.1730 B- -2756.1010 27.2546 139 916035.918 26.001 + 16 78 62 140 Sm x -75455.945 12.497 8263.8211 0.0893 B- -8470.0000 50.0000 139 918994.714 13.416 + 14 77 63 140 Eu - -66985.945 51.538 8197.7330 0.3681 B- -5203.6675 58.6268 139 928087.633 55.328 + 12 76 64 140 Gd x -61782.278 27.945 8154.9757 0.1996 B- -11300.0000 800.0000 139 933674.000 30.000 + 10 75 65 140 Tb - -50482.278 800.488 8068.6732 5.7178 B- -7652# 895# 139 945805.048 859.359 + 8 74 66 140 Dy x -42830# 401# 8008# 3# B- -13513# 641# 139 954020# 430# + 6 73 67 140 Ho -p -29317# 500# 7906# 4# B- * 139 968526# 537# +0 39 90 51 141 Sb x -39540# 500# 8069# 4# B- 11129# 640# 140 957552# 537# + 37 89 52 141 Te x -50670# 400# 8142# 3# B- 9257# 400# 140 945604# 429# + 35 88 53 141 I x -59926.666 15.835 8202.2562 0.1123 B- 8270.6430 16.0965 140 935666.081 17.000 + 33 87 54 141 Xe x -68197.309 2.888 8255.3647 0.0205 B- 6280.0423 9.6378 140 926787.181 3.100 + 31 86 55 141 Cs -74477.351 9.195 8294.3554 0.0652 B- 5255.1410 9.6174 140 920045.279 9.871 + 29 85 56 141 Ba -79732.492 5.318 8326.0774 0.0377 B- 3197.3515 6.5510 140 914403.653 5.709 + 27 84 57 141 La -82929.844 4.127 8343.2050 0.0293 B- 2501.2141 3.9279 140 910971.155 4.430 + 25 83 58 141 Ce -85431.058 1.315 8355.3956 0.0093 B- 583.4758 1.1784 140 908285.991 1.411 + 23 82 59 141 Pr -86014.533 1.498 8353.9852 0.0106 B- -1823.0137 2.8090 140 907659.604 1.607 + 21 81 60 141 Nd - -84191.520 3.183 8335.5074 0.0226 B- -3668.5879 14.3304 140 909616.690 3.417 + 19 80 61 141 Pm x -80522.932 13.972 8303.9405 0.0991 B- -4588.9724 16.3730 140 913555.081 15.000 + 17 79 62 141 Sm -75933.959 8.535 8265.8460 0.0605 B- -6008.3127 14.2829 140 918481.545 9.162 + 15 78 63 141 Eu -69925.647 12.639 8217.6853 0.0896 B- -6701.4161 23.4562 140 924931.734 13.568 + 13 77 64 141 Gd x -63224.231 19.760 8164.6090 0.1401 B- -8683.3880 107.0975 140 932126.000 21.213 + 11 76 65 141 Tb x -54540.843 105.259 8097.4761 0.7465 B- -9158# 316# 140 941448.000 113.000 + 9 75 66 141 Dy x -45382# 298# 8027# 2# B- -11018# 499# 140 951280# 320# + 7 74 67 141 Ho -p -34364# 401# 7943# 3# B- * 140 963108# 430# +0 40 91 51 142 Sb x -33610# 300# 8027# 2# B- 12939# 583# 141 963918# 322# + 38 90 52 142 Te x -46550# 500# 8113# 4# B- 8253# 500# 141 950027# 537# + 36 89 53 142 I x -54802.969 4.937 8165.2517 0.0348 B- 10426.6792 5.6276 141 941166.595 5.300 + 34 88 54 142 Xe x -65229.648 2.701 8233.1695 0.0190 B- 5284.9078 7.5655 141 929973.095 2.900 + 32 87 55 142 Cs -70514.556 7.067 8264.8777 0.0498 B- 7327.7007 8.3627 141 924299.514 7.586 + 30 86 56 142 Ba -77842.257 5.920 8310.9718 0.0417 B- 2181.6932 8.3754 141 916432.904 6.355 + 28 85 57 142 La -80023.950 6.286 8320.8263 0.0443 B- 4508.9455 5.8446 141 914090.760 6.748 + 26 84 58 142 Ce -84532.896 2.443 8347.0700 0.0172 B- -746.5288 2.4868 141 909250.208 2.623 + 24 83 59 142 Pr -83786.367 1.498 8336.3032 0.0106 B- 2163.6885 1.3656 141 910051.640 1.607 + 22 82 60 142 Nd -85950.055 1.256 8346.0310 0.0088 B- -4808.5196 23.6216 141 907728.824 1.348 + 20 81 61 142 Pm -81141.536 23.596 8306.6587 0.1662 B- -2159.6062 23.6524 141 912890.982 25.330 + 18 80 62 142 Sm -78981.930 1.866 8285.9407 0.0131 B- -7673.0000 30.0000 141 915209.415 2.002 + 16 79 63 142 Eu - -71308.930 30.058 8226.3960 0.2117 B- -4349.4074 41.0414 141 923446.719 32.268 + 14 78 64 142 Gd x -66959.522 27.945 8190.2569 0.1968 B- -10400.0000 700.0000 141 928116.000 30.000 + 12 77 65 142 Tb - -56559.522 700.558 8111.5080 4.9335 B- -6440# 200# 141 939280.858 752.079 + 10 76 66 142 Dy - -50120# 729# 8061# 5# B- -12869# 831# 141 946194# 782# + 8 75 67 142 Ho x -37250# 401# 7965# 3# B- -9321# 641# 141 960010# 430# + 6 74 68 142 Er x -27930# 500# 7893# 4# B- * 141 970016# 537# +0 39 91 52 143 Te x -40530# 500# 8070# 3# B- 10259# 539# 142 956489# 537# + 37 90 53 143 I x -50790# 200# 8137# 1# B- 9413# 200# 142 945475# 215# + 35 89 54 143 Xe x -60202.882 4.657 8196.8855 0.0326 B- 7472.6365 8.8908 142 935369.550 5.000 + 33 88 55 143 Cs -67675.519 7.573 8243.6707 0.0530 B- 6261.6865 9.7303 142 927347.346 8.130 + 31 87 56 143 Ba -73937.205 6.756 8281.9878 0.0472 B- 4234.2623 9.9682 142 920625.149 7.253 + 29 86 57 143 La -78171.467 7.329 8306.1271 0.0513 B- 3434.9108 7.5812 142 916079.482 7.868 + 27 85 58 143 Ce -81606.378 2.442 8324.6765 0.0171 B- 1461.8214 1.8649 142 912391.953 2.621 + 25 84 59 143 Pr -83068.200 1.816 8329.4280 0.0127 B- 934.1107 1.3673 142 910822.624 1.949 + 23 83 60 143 Nd -84002.310 1.255 8330.4893 0.0088 B- -1041.6463 2.6830 142 909819.815 1.347 + 21 82 61 143 Pm -82960.664 2.944 8317.7341 0.0206 B- -3443.5291 3.5604 142 910938.068 3.160 + 19 81 62 143 Sm -79517.135 2.750 8288.1825 0.0192 B- -5275.8240 11.3245 142 914634.848 2.951 + 17 80 63 143 Eu x -74241.311 10.986 8245.8177 0.0768 B- -6010.0000 200.0000 142 920298.678 11.793 + 15 79 64 143 Gd - -68231.311 200.301 8198.3188 1.4007 B- -7812.1185 206.7497 142 926750.678 215.032 + 13 78 65 143 Tb x -60419.192 51.232 8138.2176 0.3583 B- -8250.2433 52.8659 142 935137.332 55.000 + 11 77 66 143 Dy x -52168.949 13.041 8075.0527 0.0912 B- -10121# 298# 142 943994.332 14.000 + 9 76 67 143 Ho x -42048# 298# 7999# 2# B- -10887# 499# 142 954860# 320# + 7 75 68 143 Er x -31160# 400# 7917# 3# B- * 142 966548# 429# +0 40 92 52 144 Te x -36220# 300# 8040# 2# B- 9110# 500# 143 961116# 322# + 38 91 53 144 I x -45330# 400# 8098# 3# B- 11542# 400# 143 951336# 429# + 36 90 54 144 Xe x -56872.301 5.310 8172.8845 0.0369 B- 6399.0606 20.8203 143 938945.076 5.700 + 34 89 55 144 Cs -63271.362 20.132 8211.8894 0.1398 B- 8495.7679 20.4163 143 932075.402 21.612 + 32 88 56 144 Ba -71767.130 7.136 8265.4549 0.0496 B- 3082.5300 14.7744 143 922954.821 7.661 + 30 87 57 144 La x -74849.660 12.937 8281.4283 0.0898 B- 5582.2823 13.2432 143 919645.589 13.888 + 28 86 58 144 Ce + -80431.942 2.833 8314.7612 0.0197 B- 318.6462 0.8321 143 913652.763 3.041 + 26 85 59 144 Pr + -80750.588 2.708 8311.5411 0.0188 B- 2997.4400 2.4000 143 913310.682 2.907 + 24 84 60 144 Nd -83748.028 1.255 8326.9237 0.0087 B- -2331.9117 2.6464 143 910092.798 1.346 + 22 83 61 144 Pm -81416.116 2.912 8305.2969 0.0202 B- 549.5096 2.6679 143 912596.208 3.126 + 20 82 62 144 Sm -81965.626 1.459 8303.6800 0.0101 B- -6346.4515 10.8092 143 912006.285 1.566 + 18 81 63 144 Eu -75619.175 10.787 8254.1744 0.0749 B- -3859.6633 29.9546 143 918819.481 11.580 + 16 80 64 144 Gd x -71759.511 27.945 8221.9382 0.1941 B- -9391.3235 39.5199 143 922963.000 30.000 + 14 79 65 144 Tb x -62368.188 27.945 8151.2877 0.1941 B- -5798.0965 28.8506 143 933045.000 30.000 + 12 78 66 144 Dy x -56570.091 7.173 8105.5902 0.0498 B- -11960.5706 11.1039 143 939269.512 7.700 + 10 77 67 144 Ho x -44609.521 8.477 8017.0977 0.0589 B- -8002# 196# 143 952109.712 9.100 + 8 76 68 144 Er x -36608# 196# 7956# 1# B- -14448# 445# 143 960700# 210# + 6 75 69 144 Tm -p -22159# 400# 7850# 3# B- * 143 976211# 429# +0 41 93 52 145 Te x -30010# 300# 7998# 2# B- 11120# 583# 144 967783# 322# + 39 92 53 145 I x -41130# 500# 8069# 3# B- 10363# 500# 144 955845# 537# + 37 91 54 145 Xe x -51493.337 11.178 8135.0877 0.0771 B- 8561.0867 14.3929 144 944719.631 12.000 + 35 90 55 145 Cs -60054.424 9.067 8188.7342 0.0625 B- 7461.7591 12.4121 144 935528.927 9.733 + 33 89 56 145 Ba x -67516.183 8.477 8234.7991 0.0585 B- 5319.1425 14.9122 144 927518.400 9.100 + 31 88 57 145 La -72835.325 12.269 8266.0873 0.0846 B- 4231.7331 35.2977 144 921808.065 13.170 + 29 87 58 145 Ce -77067.059 33.900 8289.8762 0.2338 B- 2558.9318 33.6347 144 917265.113 36.393 + 27 86 59 145 Pr -79625.990 7.149 8302.1285 0.0493 B- 1806.0140 7.0370 144 914517.987 7.674 + 25 85 60 145 Nd -81432.004 1.271 8309.1883 0.0088 B- -164.4982 2.5361 144 912579.151 1.364 + 23 84 61 145 Pm -81267.506 2.805 8302.6583 0.0193 B- -616.0990 2.5390 144 912755.748 3.011 + 21 83 62 145 Sm -80651.407 1.485 8293.0139 0.0102 B- -2659.8832 2.7224 144 913417.157 1.594 + 19 82 63 145 Eu -77991.524 3.060 8269.2744 0.0211 B- -5064.8984 19.9521 144 916272.659 3.285 + 17 81 64 145 Gd -72926.626 19.716 8228.9485 0.1360 B- -6526.9329 109.7144 144 921710.051 21.165 + 15 80 65 145 Tb -66399.693 110.896 8178.5397 0.7648 B- -8157.0853 111.0872 144 928717.001 119.051 + 13 79 66 145 Dy x -58242.607 6.520 8116.8884 0.0450 B- -9122.4943 9.9019 144 937473.992 7.000 + 11 78 67 145 Ho x -49120.113 7.452 8048.5792 0.0514 B- -9880# 200# 144 947267.392 8.000 + 9 77 68 145 Er x -39240# 200# 7975# 1# B- -11657# 280# 144 957874# 215# + 7 76 69 145 Tm -p -27583# 196# 7889# 1# B- * 144 970389# 210# +0 40 93 53 146 I x -35540# 300# 8031# 2# B- 12415# 301# 145 961846# 322# + 38 92 54 146 Xe x -47954.950 24.219 8110.4154 0.1659 B- 7355.4298 24.3911 145 948518.245 26.000 + 36 91 55 146 Cs x -55310.380 2.893 8155.4365 0.0198 B- 9555.8882 3.3918 145 940621.867 3.106 + 34 90 56 146 Ba x -64866.269 1.770 8215.5293 0.0121 B- 4354.9052 2.4366 145 930363.200 1.900 + 32 89 57 146 La -69221.174 1.675 8239.9988 0.0115 B- 6404.6947 14.7146 145 925688.017 1.797 + 30 88 58 146 Ce -75625.868 14.665 8278.5081 0.1004 B- 1047.6178 32.4842 145 918812.294 15.743 + 28 87 59 146 Pr -76673.486 34.356 8280.3250 0.2353 B- 4252.4300 34.3686 145 917687.630 36.882 + 26 86 60 146 Nd -80925.916 1.273 8304.0927 0.0087 B- -1471.5560 4.1194 145 913122.459 1.366 + 24 85 61 146 Pm + -79454.360 4.275 8288.6550 0.0293 B- 1542.0000 3.0000 145 914702.240 4.589 + 22 84 62 146 Sm -80996.360 3.045 8293.8581 0.0209 B- -3878.7573 5.8685 145 913046.835 3.269 + 20 83 63 146 Eu -77117.603 6.009 8261.9327 0.0412 B- -1031.7798 7.0750 145 917210.852 6.451 + 18 82 64 146 Gd -76085.823 4.076 8249.5072 0.0279 B- -8322.1791 44.7488 145 918318.513 4.376 + 16 81 65 146 Tb -67763.644 44.860 8187.1474 0.3073 B- -5208.7165 45.1580 145 927252.739 48.159 + 14 80 66 146 Dy -62554.928 6.695 8146.1128 0.0459 B- -11316.7007 9.3917 145 932844.526 7.187 + 12 79 67 146 Ho -51238.227 6.587 8063.2426 0.0451 B- -6916.2074 9.3987 145 944993.503 7.071 + 10 78 68 146 Er -44322.019 6.705 8010.5127 0.0459 B- -13267# 200# 145 952418.357 7.197 + 8 77 69 146 Tm -p -31055# 200# 7914# 1# B- * 145 966661# 215# +0 41 94 53 147 I x -31200# 300# 8001# 2# B- 11199# 361# 146 966505# 322# + 39 93 54 147 Xe x -42400# 200# 8072# 1# B- 9520# 200# 146 954482# 215# + 37 92 55 147 Cs x -51920.073 8.383 8131.8010 0.0570 B- 8343.9631 21.4535 146 944261.512 9.000 + 35 91 56 147 Ba x -60264.036 19.748 8183.2405 0.1343 B- 6414.3615 22.4660 146 935303.900 21.200 + 33 90 57 147 La x -66678.397 10.712 8221.5536 0.0729 B- 5335.5046 13.7248 146 928417.800 11.500 + 31 89 58 147 Ce -72013.902 8.580 8252.5274 0.0584 B- 3430.1913 15.5317 146 922689.900 9.211 + 29 88 59 147 Pr -75444.093 15.855 8270.5400 0.1079 B- 2702.7013 15.8571 146 919007.438 17.020 + 27 87 60 147 Nd -78146.794 1.275 8283.6036 0.0087 B- 895.1896 0.5664 146 916105.969 1.368 + 25 86 61 147 Pm -79041.984 1.288 8284.3712 0.0088 B- 224.0638 0.2940 146 915144.944 1.382 + 23 85 62 147 Sm -79266.048 1.262 8280.5734 0.0086 B- -1721.4367 2.2832 146 914904.401 1.354 + 21 84 63 147 Eu -77544.611 2.569 8263.5409 0.0175 B- -2187.6833 2.5273 146 916752.440 2.758 + 19 83 64 147 Gd -75356.928 1.887 8243.3366 0.0128 B- -4614.2543 8.1414 146 919101.014 2.025 + 17 82 65 147 Tb -70742.674 8.096 8206.6250 0.0551 B- -6546.6266 11.9939 146 924054.620 8.691 + 15 81 66 147 Dy x -64196.047 8.849 8156.7680 0.0602 B- -8438.9460 10.1644 146 931082.712 9.500 + 13 80 67 147 Ho -55757.101 5.001 8094.0381 0.0340 B- -9149.2869 38.5173 146 940142.293 5.368 + 11 79 68 147 Er x -46607.814 38.191 8026.4760 0.2598 B- -10633.4071 38.7987 146 949964.456 41.000 + 9 78 69 147 Tm -35974.407 6.839 7948.8178 0.0465 B- * 146 961379.887 7.341 +0 40 94 54 148 Xe x -38650# 300# 8047# 2# B- 8261# 300# 147 958508# 322# + 38 93 55 148 Cs x -46910.950 13.041 8097.5469 0.0881 B- 10633.9614 13.1258 147 949639.026 14.000 + 36 92 56 148 Ba x -57544.911 1.490 8164.1118 0.0101 B- 5163.8307 19.5252 147 938223.000 1.600 + 34 91 57 148 La x -62708.742 19.468 8193.7165 0.1315 B- 7689.6824 22.4573 147 932679.400 20.900 + 32 90 58 148 Ce -70398.424 11.195 8240.3876 0.0756 B- 2137.0282 12.5663 147 924424.186 12.017 + 30 89 59 148 Pr -72535.452 15.041 8249.5409 0.1016 B- 4872.6133 15.0858 147 922129.992 16.147 + 28 88 60 148 Nd -77408.066 2.053 8277.1778 0.0139 B- -542.1891 5.8755 147 916899.027 2.203 + 26 87 61 148 Pm +p -76865.877 5.690 8268.2283 0.0384 B- 2470.1898 5.6409 147 917481.091 6.108 + 24 86 62 148 Sm -79336.067 1.246 8279.6326 0.0084 B- -3038.5844 9.9657 147 914829.233 1.337 + 22 85 63 148 Eu -76297.482 9.961 8253.8155 0.0673 B- -28.0630 9.9633 147 918091.288 10.693 + 20 84 64 148 Gd -76269.419 1.460 8248.3398 0.0099 B- -5732.4723 12.5208 147 918121.414 1.566 + 18 83 65 148 Tb -70536.947 12.463 8204.3207 0.0842 B- -2677.5501 9.5961 147 924275.476 13.379 + 16 82 66 148 Dy -67859.397 8.724 8180.9430 0.0589 B- -9868.2304 84.2872 147 927149.944 9.365 + 14 81 67 148 Ho x -57991.166 83.834 8108.9797 0.5664 B- -6512.1694 84.4583 147 937743.925 90.000 + 12 80 68 148 Er x -51478.997 10.246 8059.6924 0.0692 B- -12713.9630 14.4906 147 944735.026 11.000 + 10 79 69 148 Tm x -38765.034 10.246 7968.5011 0.0692 B- -8535# 400# 147 958384.026 11.000 + 8 78 70 148 Yb x -30230# 400# 7906# 3# B- * 147 967547# 429# +0 41 95 54 149 Xe x -33000# 300# 8009# 2# B- 10300# 500# 148 964573# 322# + 39 94 55 149 Cs x -43300# 400# 8073# 3# B- 9531# 400# 148 953516# 429# + 37 93 56 149 Ba x -52830.620 2.515 8131.8495 0.0169 B- 7389.3010 200.2781 148 943284.000 2.700 + 35 92 57 149 La + -60219.921 200.262 8176.1915 1.3440 B- 6450.0000 200.0000 148 935351.259 214.990 + 33 91 58 149 Ce x -66669.921 10.246 8214.2294 0.0688 B- 4369.4525 14.2296 148 928426.900 11.000 + 31 90 59 149 Pr x -71039.373 9.874 8238.3040 0.0663 B- 3336.1617 10.0853 148 923736.100 10.600 + 29 89 60 149 Nd -n -74375.535 2.054 8255.4437 0.0138 B- 1688.8697 2.4588 148 920154.583 2.205 + 27 88 61 149 Pm -76064.404 2.184 8261.5277 0.0147 B- 1071.4936 1.8747 148 918341.507 2.344 + 25 87 62 149 Sm -77135.898 1.157 8263.4683 0.0078 B- -694.5812 3.7881 148 917191.211 1.241 + 23 86 63 149 Eu -76441.317 3.903 8253.5560 0.0262 B- -1314.1437 4.1361 148 917936.875 4.190 + 21 85 64 149 Gd -75127.173 3.310 8239.4856 0.0222 B- -3638.5336 4.3388 148 919347.666 3.553 + 19 84 65 149 Tb -71488.639 3.629 8209.8153 0.0244 B- -3794.6493 9.1335 148 923253.792 3.895 + 17 83 66 149 Dy -67693.990 9.183 8179.0972 0.0616 B- -6048.1366 12.7928 148 927327.516 9.858 + 15 82 67 149 Ho -61645.854 11.985 8133.2550 0.0804 B- -7904.2328 30.4066 148 933820.457 12.866 + 13 81 68 149 Er x -53741.621 27.945 8074.9558 0.1875 B- -9801# 202# 148 942306.000 30.000 + 11 80 69 149 Tm x -43940# 200# 8004# 1# B- -10611# 361# 148 952828# 215# + 9 79 70 149 Yb x -33330# 300# 7927# 2# B- * 148 964219# 322# +0 42 96 54 150 Xe x -28990# 300# 7983# 2# B- 9180# 500# 149 968878# 322# + 40 95 55 150 Cs x -38170# 400# 8039# 3# B- 11720# 400# 149 959023# 429# + 38 94 56 150 Ba x -49889.799 5.682 8111.8405 0.0379 B- 6421.3477 6.2138 149 946441.100 6.100 + 36 93 57 150 La x -56311.147 2.515 8149.4339 0.0168 B- 8535.7155 11.9641 149 939547.500 2.700 + 34 92 58 150 Ce -64846.863 11.697 8201.1230 0.0780 B- 3453.6462 14.2913 149 930384.032 12.556 + 32 91 59 150 Pr -68300.509 9.015 8218.9316 0.0601 B- 5379.4422 9.0682 149 926676.391 9.677 + 30 90 60 150 Nd -73679.951 1.129 8249.5789 0.0075 B- -82.6155 20.0010 149 920901.322 1.211 + 28 89 61 150 Pm + -73597.336 20.031 8243.8125 0.1335 B- 3454.0000 20.0000 149 920990.014 21.504 + 26 88 62 150 Sm -77051.336 1.112 8261.6235 0.0074 B- -2258.9662 6.1803 149 917281.993 1.193 + 24 87 63 150 Eu -74792.369 6.231 8241.3481 0.0415 B- 971.6815 3.5428 149 919707.092 6.688 + 22 86 64 150 Gd -75764.051 6.055 8242.6103 0.0404 B- -4658.2621 8.3784 149 918663.949 6.500 + 20 85 65 150 Tb -71105.789 7.371 8206.3396 0.0491 B- -1796.1707 8.3886 149 923664.799 7.912 + 18 84 66 150 Dy -69309.618 4.319 8189.1495 0.0288 B- -7363.7264 14.4629 149 925593.068 4.636 + 16 83 67 150 Ho -61945.892 14.168 8134.8423 0.0945 B- -4114.5689 13.5910 149 933498.353 15.209 + 14 82 68 150 Er -57831.323 17.194 8102.1962 0.1146 B- -11340# 196# 149 937915.524 18.458 + 12 81 69 150 Tm x -46491# 196# 8021# 1# B- -7661# 358# 149 950090# 210# + 10 80 70 150 Yb x -38830# 300# 7965# 2# B- -14059# 424# 149 958314# 322# + 8 79 71 150 Lu -p -24771# 300# 7866# 2# B- * 149 973407# 322# +0 41 96 55 151 Cs x -34280# 500# 8013# 3# B- 10660# 640# 150 963199# 537# + 39 95 56 151 Ba x -44940# 400# 8079# 3# B- 8370# 591# 150 951755# 429# + 37 94 57 151 La x -53310.339 435.473 8129.0436 2.8839 B- 7914.7191 435.8330 150 942769.000 467.500 + 35 93 58 151 Ce x -61225.058 17.698 8176.2779 0.1172 B- 5554.6233 21.1885 150 934272.200 19.000 + 33 92 59 151 Pr -66779.681 11.650 8207.8824 0.0772 B- 4163.5021 11.6789 150 928309.066 12.506 + 31 91 60 151 Nd -70943.183 1.133 8230.2741 0.0075 B- 2443.0767 4.4734 150 923839.363 1.215 + 29 90 61 151 Pm -73386.260 4.611 8241.2723 0.0305 B- 1190.2198 4.4757 150 921216.613 4.949 + 27 89 62 151 Sm -74576.480 1.110 8243.9735 0.0074 B- 76.6182 0.5375 150 919938.859 1.191 + 25 88 63 151 Eu -74653.098 1.166 8239.2998 0.0077 B- -464.1779 2.7791 150 919856.606 1.251 + 23 87 64 151 Gd -74188.920 2.993 8231.0446 0.0198 B- -2565.3796 3.7615 150 920354.922 3.212 + 21 86 65 151 Tb -71623.541 4.094 8208.8743 0.0271 B- -2871.1525 4.9455 150 923108.970 4.395 + 19 85 66 151 Dy -a -68752.388 3.247 8184.6789 0.0215 B- -5129.6421 8.7507 150 926191.279 3.486 + 17 84 67 151 Ho -a -63622.746 8.298 8145.5267 0.0550 B- -5356.4558 18.4420 150 931698.176 8.908 + 15 83 68 151 Er x -58266.290 16.470 8104.8723 0.1091 B- -7494.6768 25.4292 150 937448.567 17.681 + 13 82 69 151 Tm -50771.613 19.375 8050.0576 0.1283 B- -9229.2615 300.1329 150 945494.433 20.799 + 11 81 70 151 Yb ep -41542.352 300.492 7983.7556 1.9900 B- -11242# 425# 150 955402.453 322.591 + 9 80 71 151 Lu -p -30300# 300# 7904# 2# B- * 150 967471# 322# +0 42 97 55 152 Cs x -29130# 500# 7980# 3# B- 12480# 640# 151 968728# 537# + 40 96 56 152 Ba x -41610# 400# 8057# 3# B- 7680# 500# 151 955330# 429# + 38 95 57 152 La x -49290# 300# 8102# 2# B- 9690# 361# 151 947085# 322# + 36 94 58 152 Ce x -58980# 200# 8161# 1# B- 4778# 201# 151 936682# 215# + 34 93 59 152 Pr x -63758.070 18.537 8187.1049 0.1220 B- 6391.5934 30.7035 151 931552.900 19.900 + 32 92 60 152 Nd -70149.663 24.476 8224.0078 0.1610 B- 1104.8050 18.5011 151 924691.242 26.276 + 30 91 61 152 Pm -71254.468 25.904 8226.1293 0.1704 B- 3508.5089 25.8859 151 923505.185 27.809 + 28 90 62 152 Sm -74762.977 1.016 8244.0645 0.0067 B- -1874.4774 0.6857 151 919738.646 1.090 + 26 89 63 152 Eu -72888.500 1.166 8226.5854 0.0077 B- 1818.8037 0.7002 151 921750.980 1.252 + 24 88 64 152 Gd -74707.304 1.007 8233.4042 0.0066 B- -3990.0000 40.0000 151 919798.414 1.081 + 22 87 65 152 Tb - -70717.304 40.013 8202.0072 0.2632 B- -599.3405 40.2575 151 924081.855 42.955 + 20 86 66 152 Dy -a -70117.963 4.593 8192.9171 0.0302 B- -6513.3275 13.3176 151 924725.274 4.930 + 18 85 67 152 Ho -63604.636 12.528 8144.9193 0.0824 B- -3104.4174 9.8150 151 931717.618 13.449 + 16 84 68 152 Er -60500.218 8.830 8119.3485 0.0581 B- -8779.9397 54.7434 151 935050.347 9.478 + 14 83 69 152 Tm -51720.279 54.027 8056.4387 0.3554 B- -5449.8923 139.6200 151 944476.000 58.000 + 12 82 70 152 Yb -46270.386 149.708 8015.4371 0.9849 B- -12848# 246# 151 950326.699 160.718 + 10 81 71 152 Lu x -33422# 196# 7926# 1# B- * 151 964120# 210# +0 41 97 56 153 Ba x -36470# 400# 8023# 3# B- 9590# 500# 152 960848# 429# + 39 96 57 153 La x -46060# 300# 8081# 2# B- 8850# 361# 152 950553# 322# + 37 95 58 153 Ce x -54910# 200# 8134# 1# B- 6659# 201# 152 941052# 215# + 35 94 59 153 Pr -61568.490 11.882 8172.0371 0.0777 B- 5761.8901 12.1896 152 933903.511 12.755 + 33 93 60 153 Nd -67330.380 2.747 8204.5832 0.0180 B- 3317.6236 9.3521 152 927717.868 2.949 + 31 92 61 153 Pm -70648.003 9.063 8221.1536 0.0592 B- 1912.0559 9.0829 152 924156.252 9.729 + 29 91 62 153 Sm -n -72560.059 1.025 8228.5373 0.0067 B- 807.4073 0.7063 152 922103.576 1.100 + 27 90 63 153 Eu -73367.466 1.171 8228.7011 0.0077 B- -484.5225 0.7150 152 921236.789 1.257 + 25 89 64 153 Gd -72882.944 1.002 8220.4209 0.0066 B- -1569.3340 3.8444 152 921756.945 1.075 + 23 88 65 153 Tb -71313.610 3.947 8205.0504 0.0258 B- -2170.4134 1.9335 152 923441.694 4.237 + 21 87 66 153 Dy -69143.197 4.001 8185.7514 0.0262 B- -4131.1229 6.1571 152 925771.729 4.295 + 19 86 67 153 Ho -a -65012.074 5.066 8153.6372 0.0331 B- -4545.3918 9.8899 152 930206.671 5.438 + 17 85 68 153 Er -60466.682 9.285 8118.8154 0.0607 B- -6494.0723 12.8812 152 935086.350 9.967 + 15 84 69 153 Tm -53972.610 11.979 8071.2571 0.0783 B- -6813# 201# 152 942058.023 12.860 + 13 83 70 153 Yb x -47160# 200# 8022# 1# B- -8784# 250# 152 949372# 215# + 11 82 71 153 Lu +a -38375.462 150.017 7959.0882 0.9805 B- -11075# 335# 152 958802.248 161.050 + 9 81 72 153 Hf x -27300# 300# 7882# 2# B- * 152 970692# 322# +0 42 98 56 154 Ba x -32920# 500# 8001# 3# B- 8610# 583# 153 964659# 537# + 40 97 57 154 La x -41530# 300# 8051# 2# B- 10690# 361# 153 955416# 322# + 38 96 58 154 Ce x -52220# 200# 8116# 1# B- 5640# 224# 153 943940# 215# + 36 95 59 154 Pr + -57859.602 100.005 8147.2994 0.6494 B- 7720.0000 100.0000 153 937885.165 107.360 + 34 94 60 154 Nd x -65579.602 1.025 8192.3491 0.0067 B- 2687.0000 25.0000 153 929597.404 1.100 + 32 93 61 154 Pm - -68266.602 25.021 8204.7170 0.1625 B- 4188.9614 25.0550 153 926712.791 26.861 + 30 92 62 154 Sm -72455.564 1.305 8226.8379 0.0085 B- -717.1969 1.1019 153 922215.756 1.400 + 28 91 63 154 Eu -71738.367 1.188 8217.1006 0.0077 B- 1967.9913 0.7535 153 922985.699 1.275 + 26 90 64 154 Gd -73706.358 0.994 8224.7996 0.0065 B- -3549.6514 45.2983 153 920872.974 1.066 + 24 89 65 154 Tb - -70156.707 45.309 8196.6697 0.2942 B- 237.3080 45.9008 153 924683.681 48.641 + 22 88 66 154 Dy -70394.015 7.431 8193.1305 0.0483 B- -5754.6363 10.1785 153 924428.920 7.977 + 20 87 67 154 Ho -a -64639.378 8.216 8150.6825 0.0534 B- -2034.4045 9.4621 153 930606.776 8.820 + 18 86 68 154 Er -62604.974 4.961 8132.3919 0.0322 B- -8177.8316 14.9113 153 932790.799 5.325 + 16 85 69 154 Tm -a -54427.142 14.412 8074.2090 0.0936 B- -4495.0495 13.9528 153 941570.062 15.471 + 14 84 70 154 Yb -49932.093 17.281 8039.9402 0.1122 B- -10265# 201# 153 946395.696 18.551 + 12 83 71 154 Lu +a -39667# 201# 7968# 1# B- -6937# 361# 153 957416# 216# + 10 82 72 154 Hf x -32730# 300# 7918# 2# B- * 153 964863# 322# +0 41 98 57 155 La x -37930# 400# 8028# 3# B- 9850# 500# 154 959280# 429# + 39 97 58 155 Ce x -47780# 300# 8087# 2# B- 7635# 300# 154 948706# 322# + 37 96 59 155 Pr -55415.335 17.198 8131.0398 0.1110 B- 6868.4609 19.4725 154 940509.193 18.462 + 35 95 60 155 Nd -62283.796 9.154 8170.3050 0.0591 B- 4656.2095 10.2781 154 933135.598 9.826 + 33 94 61 155 Pm -66940.006 4.719 8195.2977 0.0304 B- 3251.1999 4.9024 154 928136.951 5.065 + 31 93 62 155 Sm -n -70191.206 1.332 8211.2258 0.0086 B- 1627.1314 1.2016 154 924646.645 1.429 + 29 92 63 155 Eu -71818.337 1.252 8216.6760 0.0081 B- 251.9612 0.8682 154 922899.847 1.343 + 27 91 64 155 Gd -72070.298 0.983 8213.2541 0.0063 B- -819.8588 9.7884 154 922629.356 1.055 + 25 90 65 155 Tb + -71250.439 9.830 8202.9173 0.0634 B- -2094.5000 1.8974 154 923509.511 10.552 + 23 89 66 155 Dy -69155.939 9.645 8184.3570 0.0622 B- -3116.1405 16.5887 154 925758.049 10.354 + 21 88 67 155 Ho -66039.799 17.470 8159.2055 0.1127 B- -3830.6268 18.4730 154 929103.363 18.754 + 19 87 68 155 Er -a -62209.172 6.074 8129.4444 0.0392 B- -5583.2509 11.5109 154 933215.710 6.520 + 17 86 69 155 Tm -a -56625.921 9.921 8088.3760 0.0640 B- -6123.3072 19.3388 154 939209.576 10.651 + 15 85 70 155 Yb -a -50502.614 16.600 8043.8234 0.1071 B- -7957.5578 25.4153 154 945783.216 17.820 + 13 84 71 155 Lu -42545.056 19.245 7987.4369 0.1242 B- -8235# 301# 154 954326.005 20.660 + 11 83 72 155 Hf x -34310# 300# 7929# 2# B- -10322# 424# 154 963167# 322# + 9 82 73 155 Ta -p -23988# 300# 7858# 2# B- * 154 974248# 322# +0 42 99 57 156 La x -33050# 400# 7997# 3# B- 11769# 500# 155 964519# 429# + 40 98 58 156 Ce x -44820# 300# 8068# 2# B- 6630# 300# 155 951884# 322# + 38 97 59 156 Pr x -51449.307 1.025 8105.2337 0.0066 B- 8752.8229 1.6585 155 944766.900 1.100 + 36 96 60 156 Nd x -60202.130 1.304 8156.3265 0.0084 B- 3964.7175 1.7642 155 935370.358 1.400 + 34 95 61 156 Pm -64166.847 1.188 8176.7263 0.0076 B- 5193.8878 8.6044 155 931114.059 1.275 + 32 94 62 156 Sm -69360.735 8.522 8205.0054 0.0546 B- 722.1090 7.9025 155 925538.191 9.148 + 30 93 63 156 Eu -70082.844 3.532 8204.6192 0.0226 B- 2452.4891 3.4083 155 924762.976 3.791 + 28 92 64 156 Gd -72535.333 0.983 8215.3253 0.0063 B- -2444.3230 3.6774 155 922130.120 1.054 + 26 91 65 156 Tb -70091.010 3.768 8194.6415 0.0242 B- 438.3762 3.6789 155 924754.209 4.044 + 24 90 66 156 Dy -70529.386 0.988 8192.4366 0.0063 B- -4990.9836 38.4111 155 924283.593 1.060 + 22 89 67 156 Ho - -65538.403 38.424 8155.4280 0.2463 B- -1326.7201 45.6391 155 929641.634 41.249 + 20 88 68 156 Er -64211.683 24.629 8141.9084 0.1579 B- -7377.2657 26.7099 155 931065.926 26.440 + 18 87 69 156 Tm -56834.417 14.279 8089.6032 0.0915 B- -3568.8794 12.5484 155 938985.746 15.328 + 16 86 70 156 Yb -53265.538 9.308 8061.7107 0.0597 B- -9565.9880 54.9162 155 942817.096 9.992 + 14 85 71 156 Lu -a -43699.550 54.122 7995.3752 0.3469 B- -5880.0352 139.6908 155 953086.606 58.102 + 12 84 72 156 Hf -37819.514 149.740 7952.6676 0.9599 B- -11819# 335# 155 959399.083 160.752 + 10 83 73 156 Ta -p -26001# 300# 7872# 2# B- * 155 972087# 322# +0 43 100 57 157 La x -29070# 300# 7972# 2# B- 10860# 500# 156 968792# 322# + 41 99 58 157 Ce x -39930# 400# 8037# 3# B- 8504# 400# 156 957133# 429# + 39 98 59 157 Pr x -48434.806 3.167 8085.8170 0.0202 B- 8059.3109 3.8207 156 948003.100 3.400 + 37 97 60 157 Nd -56494.117 2.137 8132.1671 0.0136 B- 5802.9994 7.3246 156 939351.074 2.294 + 35 96 61 157 Pm -62297.116 7.006 8164.1458 0.0446 B- 4380.5376 8.2650 156 933121.298 7.521 + 33 95 62 157 Sm -66677.654 4.434 8187.0642 0.0282 B- 2781.4807 6.1191 156 928418.598 4.759 + 31 94 63 157 Eu -69459.134 4.234 8199.7975 0.0270 B- 1364.7614 4.1973 156 925432.556 4.545 + 29 93 64 157 Gd -70823.896 0.977 8203.5072 0.0062 B- -60.0473 0.2972 156 923967.424 1.048 + 27 92 65 157 Tb -70763.848 1.018 8198.1416 0.0065 B- -1339.1791 5.1297 156 924031.888 1.092 + 25 91 66 157 Dy -69424.669 5.154 8184.6287 0.0328 B- -2591.8068 23.7839 156 925469.555 5.532 + 23 90 67 157 Ho -66832.862 23.469 8163.1373 0.1495 B- -3419.2146 33.6675 156 928251.974 25.194 + 21 89 68 157 Er -63413.648 26.505 8136.3757 0.1688 B- -4704.3690 38.5152 156 931922.652 28.454 + 19 88 69 157 Tm x -58709.279 27.945 8101.4285 0.1780 B- -5289.3667 29.9971 156 936973.000 30.000 + 17 87 70 157 Yb -53419.912 10.905 8062.7551 0.0695 B- -6980.0942 14.2406 156 942651.368 11.706 + 15 86 71 157 Lu -46439.818 12.074 8013.3128 0.0769 B- -7585# 201# 156 950144.807 12.961 + 13 85 72 157 Hf -a -38855# 200# 7960# 1# B- -9259# 250# 156 958288# 215# + 11 84 73 157 Ta IT -29595.948 150.052 7896.0608 0.9557 B- -9906# 427# 156 968227.445 161.087 + 9 83 74 157 W x -19690# 400# 7828# 3# B- * 156 978862# 429# +0 42 100 58 158 Ce x -36540# 400# 8015# 3# B- 7610# 500# 157 960773# 429# + 40 99 59 158 Pr x -44150# 300# 8059# 2# B- 9685# 300# 157 952603# 322# + 38 98 60 158 Nd x -53835.123 1.304 8114.9529 0.0083 B- 5271.0196 1.5776 157 942205.620 1.400 + 36 97 61 158 Pm -59106.143 0.888 8143.3622 0.0056 B- 6145.7062 4.8634 157 936546.948 0.953 + 34 96 62 158 Sm -65251.849 4.782 8177.3075 0.0303 B- 2018.6123 5.1146 157 929949.262 5.133 + 32 95 63 158 Eu -67270.461 2.032 8185.1320 0.0129 B- 3419.5081 2.2547 157 927782.192 2.181 + 30 94 64 158 Gd -70689.969 0.976 8201.8229 0.0062 B- -1219.0862 0.9799 157 924111.200 1.048 + 28 93 65 158 Tb -69470.883 1.268 8189.1556 0.0080 B- 936.2686 2.4750 157 925419.942 1.360 + 26 92 66 158 Dy -70407.152 2.337 8190.1298 0.0148 B- -4219.7555 27.0048 157 924414.817 2.509 + 24 91 67 158 Ho - -66187.396 27.106 8158.4709 0.1716 B- -883.5812 37.0236 157 928944.910 29.099 + 22 90 68 158 Er -65303.815 25.219 8147.9270 0.1596 B- -6600.6151 31.3411 157 929893.474 27.074 + 20 89 69 158 Tm -58703.200 25.219 8101.1994 0.1596 B- -2693.5796 26.4499 157 936979.525 27.074 + 18 88 70 158 Yb -56009.620 7.973 8079.1999 0.0505 B- -8797.4201 16.8655 157 939871.202 8.559 + 16 87 71 158 Lu -a -47212.200 15.125 8018.5685 0.0957 B- -5109.8010 14.9373 157 949315.620 16.236 + 14 86 72 158 Hf -42102.399 17.494 7981.2764 0.1107 B- -10984# 201# 157 954801.217 18.780 + 12 85 73 158 Ta +a -31118# 201# 7907# 1# B- -7426# 361# 157 966593# 215# + 10 84 74 158 W -a -23693# 300# 7855# 2# B- * 157 974565# 322# +0 43 101 58 159 Ce x -31340# 500# 7983# 3# B- 9430# 640# 158 966355# 537# + 41 100 59 159 Pr x -40770# 400# 8037# 3# B- 8954# 401# 158 956232# 429# + 39 99 60 159 Nd x -49724.007 29.808 8088.8224 0.1875 B- 6830.3441 31.4529 158 946619.085 32.000 + 37 98 61 159 Pm -56554.351 10.039 8126.8601 0.0631 B- 5653.4982 11.6438 158 939286.409 10.777 + 35 97 62 159 Sm -62207.849 5.934 8157.4963 0.0373 B- 3835.5363 7.3211 158 933217.130 6.370 + 33 96 63 159 Eu -66043.386 4.320 8176.6987 0.0272 B- 2518.4717 4.3657 158 929099.512 4.637 + 31 95 64 159 Gd -68561.857 0.980 8187.6177 0.0062 B- 970.7242 0.7495 158 926395.822 1.051 + 29 94 65 159 Tb -69532.582 1.103 8188.8025 0.0069 B- -365.3613 1.1573 158 925353.707 1.184 + 27 93 66 159 Dy -69167.220 1.439 8181.5842 0.0091 B- -1837.6000 2.6833 158 925745.938 1.544 + 25 92 67 159 Ho - -67329.620 3.045 8165.1066 0.0192 B- -2768.5000 2.0000 158 927718.683 3.268 + 23 91 68 159 Er - -64561.120 3.643 8142.7742 0.0229 B- -3990.7162 28.1813 158 930690.790 3.910 + 21 90 69 159 Tm x -60570.404 27.945 8112.7549 0.1758 B- -4736.8869 33.0155 158 934975.000 30.000 + 19 89 70 159 Yb x -55833.517 17.582 8078.0428 0.1106 B- -6124.9081 41.5648 158 940060.257 18.874 + 17 88 71 159 Lu x -49708.609 37.663 8034.6009 0.2369 B- -6856.0030 41.2456 158 946635.615 40.433 + 15 87 72 159 Hf -a -42852.606 16.813 7986.5610 0.1057 B- -8413.4492 25.8909 158 953995.837 18.049 + 13 86 73 159 Ta IT -34439.157 19.689 7928.7258 0.1238 B- -9005# 301# 158 963028.046 21.137 + 11 85 74 159 W -a -25434# 300# 7867# 2# B- -10629# 427# 158 972696# 322# + 9 84 75 159 Re IT -14805# 305# 7795# 2# B- * 158 984106# 327# +0 42 101 59 160 Pr x -36200# 400# 8009# 2# B- 10525# 402# 159 961138# 429# + 40 100 60 160 Nd x -46724.515 46.575 8069.9662 0.2911 B- 6170.1238 46.6198 159 949839.172 50.000 + 38 99 61 160 Pm x -52894.639 2.049 8103.6398 0.0128 B- 7338.5338 2.8330 159 943215.272 2.200 + 36 98 62 160 Sm x -60233.172 1.956 8144.6159 0.0122 B- 3260.2763 2.1547 159 935337.032 2.100 + 34 97 63 160 Eu x -63493.449 0.904 8160.1030 0.0057 B- 4448.6112 1.4417 159 931836.982 0.970 + 32 96 64 160 Gd -67942.060 1.123 8183.0171 0.0070 B- -105.5863 1.0207 159 927061.202 1.206 + 30 95 65 160 Tb -67836.474 1.110 8177.4676 0.0069 B- 1835.9516 1.1011 159 927174.553 1.191 + 28 94 66 160 Dy -69672.425 0.700 8184.0526 0.0044 B- -3290.0000 15.0000 159 925203.578 0.751 + 26 93 67 160 Ho - -66382.425 15.016 8158.6004 0.0939 B- -318.2488 28.5197 159 928735.538 16.120 + 24 92 68 160 Er -66064.176 24.246 8151.7217 0.1515 B- -5763.1395 39.1333 159 929077.193 26.029 + 22 91 69 160 Tm -60301.037 32.686 8110.8124 0.2043 B- -2137.8101 33.1447 159 935264.177 35.089 + 20 90 70 160 Yb x -58163.227 5.496 8092.5614 0.0343 B- -7893.2846 57.0863 159 937559.210 5.900 + 18 89 71 160 Lu x -50269.942 56.821 8038.3387 0.3551 B- -4331.1951 57.6165 159 946033.000 61.000 + 16 88 72 160 Hf -45938.747 9.540 8006.3791 0.0596 B- -10115.0475 55.1472 159 950682.728 10.241 + 14 87 73 160 Ta -a -35823.700 54.316 7938.2704 0.3395 B- -6494.6267 139.8413 159 961541.678 58.310 + 12 86 74 160 W -29329.073 149.810 7892.7893 0.9363 B- -12451# 335# 159 968513.946 160.828 + 10 85 75 160 Re -a -16878# 300# 7810# 2# B- * 159 981880# 322# +0 43 102 59 161 Pr x -32490# 500# 7986# 3# B- 9741# 640# 160 965121# 537# + 41 101 60 161 Nd x -42230# 400# 8042# 2# B- 7856# 400# 160 954664# 429# + 39 100 61 161 Pm x -50086.589 9.035 8085.9977 0.0561 B- 6585.4546 11.3187 160 946229.837 9.700 + 37 99 62 161 Sm -56672.043 6.817 8122.0418 0.0423 B- 5119.5577 12.4147 160 939160.062 7.318 + 35 98 63 161 Eu -61791.601 10.400 8148.9810 0.0646 B- 3714.5406 10.5074 160 933663.991 11.164 + 33 97 64 161 Gd -n -65506.142 1.504 8167.1934 0.0093 B- 1955.6357 1.4402 160 929676.267 1.614 + 31 96 65 161 Tb -67461.778 1.218 8174.4809 0.0076 B- 593.7166 1.2010 160 927576.806 1.308 + 29 95 66 161 Dy -68055.494 0.697 8173.3093 0.0043 B- -859.2003 2.1368 160 926939.425 0.748 + 27 94 67 161 Ho -67196.294 2.151 8163.1134 0.0134 B- -1994.9954 9.0041 160 927861.815 2.309 + 25 93 68 161 Er +n -65201.298 8.774 8145.8628 0.0545 B- -3302.5839 29.2899 160 930003.530 9.419 + 23 92 69 161 Tm x -61898.715 27.945 8120.4906 0.1736 B- -4064.4665 31.7640 160 933549.000 30.000 + 21 91 70 161 Yb x -57834.248 15.101 8090.3861 0.0938 B- -5271.8989 31.7640 160 937912.384 16.211 + 19 90 71 161 Lu x -52562.349 27.945 8052.7821 0.1736 B- -6246.5319 36.4805 160 943572.000 30.000 + 17 89 72 161 Hf -46315.817 23.450 8009.1245 0.1457 B- -7537.2421 33.7278 160 950277.927 25.174 + 15 88 73 161 Ta +a -38778.575 24.381 7957.4500 0.1514 B- -8272# 202# 160 958369.489 26.174 + 13 87 74 161 W -a -30507# 200# 7901# 1# B- -9664# 250# 160 967249# 215# + 11 86 75 161 Re -20842.820 149.905 7836.3292 0.9311 B- -10647# 427# 160 977624.313 160.930 + 9 85 76 161 Os -a -10196# 400# 7765# 2# B- * 160 989054# 429# +0 42 102 60 162 Nd x -39010# 400# 8022# 2# B- 7030# 500# 161 958121# 429# + 40 101 61 162 Pm x -46040# 300# 8061# 2# B- 8339# 300# 161 950574# 322# + 38 100 62 162 Sm -54379.053 3.523 8107.5745 0.0218 B- 4343.8905 3.7605 161 941621.687 3.782 + 36 99 63 162 Eu -58722.944 1.314 8129.5593 0.0081 B- 5557.7761 4.1748 161 936958.329 1.410 + 34 98 64 162 Gd -nn -64280.720 3.963 8159.0373 0.0245 B- 1598.8278 4.4611 161 930991.812 4.254 + 32 97 65 162 Tb x -65879.548 2.049 8164.0773 0.0127 B- 2301.6217 2.1640 161 929275.400 2.200 + 30 96 66 162 Dy -68181.169 0.695 8173.4555 0.0043 B- -2140.6068 3.0926 161 926804.507 0.746 + 28 95 67 162 Ho -66040.563 3.102 8155.4126 0.0192 B- 293.6478 3.1069 161 929102.543 3.330 + 26 94 68 162 Er -66334.210 0.756 8152.3959 0.0047 B- -4856.7282 26.0475 161 928787.299 0.811 + 24 93 69 162 Tm - -61477.482 26.058 8117.5868 0.1609 B- -1656.3190 30.1127 161 934001.211 27.974 + 22 92 70 162 Yb x -59821.163 15.103 8102.5333 0.0932 B- -6989.4042 76.5406 161 935779.342 16.213 + 20 91 71 162 Lu x -52831.759 75.036 8054.5596 0.4632 B- -3663.3333 75.5679 161 943282.776 80.554 + 18 90 72 162 Hf -49168.426 8.952 8027.1171 0.0553 B- -9387.0211 63.8938 161 947215.526 9.610 + 16 89 73 162 Ta -a -39781.405 63.322 7964.3432 0.3909 B- -5782.1880 63.3235 161 957292.907 67.979 + 14 88 74 162 W -33999.217 17.657 7923.8214 0.1090 B- -11546# 201# 161 963500.341 18.955 + 12 87 75 162 Re +a -22453# 201# 7848# 1# B- -7953# 361# 161 975896# 215# + 10 86 76 162 Os -a -14500# 300# 7794# 2# B- * 161 984434# 322# +0 43 103 60 163 Nd x -34080# 500# 7992# 3# B- 8880# 640# 162 963414# 537# + 41 102 61 163 Pm x -42960# 400# 8042# 2# B- 7640# 400# 162 953881# 429# + 39 101 62 163 Sm x -50599.612 7.359 8084.1653 0.0451 B- 5974.2073 7.4141 162 945679.085 7.900 + 37 100 63 163 Eu x -56573.819 0.904 8116.0172 0.0056 B- 4814.7720 1.2046 162 939265.510 0.970 + 35 99 64 163 Gd -61388.591 0.797 8140.7560 0.0049 B- 3207.1628 4.1374 162 934096.640 0.855 + 33 98 65 163 Tb +p -64595.754 4.060 8155.6322 0.0249 B- 1785.1041 4.0006 162 930653.609 4.358 + 31 97 66 163 Dy -66380.858 0.693 8161.7840 0.0043 B- -2.8309 0.0222 162 928737.221 0.744 + 29 96 67 163 Ho -66378.027 0.693 8156.9670 0.0043 B- -1210.6141 4.5755 162 928740.260 0.744 + 27 95 68 163 Er -65167.413 4.628 8144.7403 0.0284 B- -2439.0000 3.0000 162 930039.908 4.967 + 25 94 69 163 Tm - -62728.413 5.515 8124.9774 0.0338 B- -3434.5345 16.0687 162 932658.282 5.920 + 23 93 70 163 Yb x -59293.878 15.105 8099.1069 0.0927 B- -4502.4636 31.7657 162 936345.406 16.215 + 21 92 71 163 Lu x -54791.415 27.945 8066.6848 0.1714 B- -5522.0944 37.9611 162 941179.000 30.000 + 19 91 72 163 Hf -49269.320 25.693 8028.0072 0.1576 B- -6734.6864 45.9217 162 947107.211 27.582 + 17 90 73 163 Ta -a -42534.634 38.061 7981.8905 0.2335 B- -7626.1952 69.7301 162 954337.194 40.860 + 15 89 74 163 W -a -34908.439 58.426 7930.3043 0.3584 B- -8906.1859 61.2953 162 962524.251 62.722 + 13 88 75 163 Re +a -26002.253 18.534 7870.8655 0.1137 B- -9666# 301# 162 972085.434 19.897 + 11 87 76 163 Os -a -16336# 300# 7807# 2# B- -11026# 500# 162 982462# 322# + 9 86 77 163 Ir x -5310# 400# 7734# 2# B- * 162 994299# 429# +0 42 103 61 164 Pm x -38360# 400# 8014# 2# B- 9565# 400# 163 958819# 429# + 40 102 62 164 Sm x -47925.314 4.099 8067.7803 0.0250 B- 5306.8315 4.5907 163 948550.061 4.400 + 38 101 63 164 Eu -53232.146 2.068 8095.3686 0.0126 B- 6461.5416 2.2969 163 942852.943 2.219 + 36 100 64 164 Gd -59693.688 1.000 8129.9978 0.0061 B- 2411.2959 2.1143 163 935916.193 1.073 + 34 99 65 164 Tb x -62104.983 1.863 8139.9304 0.0114 B- 3862.6653 1.9884 163 933327.561 2.000 + 32 98 66 164 Dy -65967.649 0.695 8158.7129 0.0042 B- -987.1315 1.3710 163 929180.819 0.746 + 30 97 67 164 Ho -64980.517 1.390 8147.9234 0.0085 B- 962.0559 1.3756 163 930240.548 1.492 + 28 96 68 164 Er -65942.573 0.704 8149.0191 0.0043 B- -4033.6302 25.0113 163 929207.739 0.755 + 26 95 69 164 Tm -61908.943 25.006 8119.6534 0.1525 B- -896.7722 29.2135 163 933538.019 26.845 + 24 94 70 164 Yb x -61012.171 15.106 8109.4149 0.0921 B- -6369.7952 31.7666 163 934500.743 16.217 + 22 93 71 164 Lu x -54642.376 27.945 8065.8043 0.1704 B- -2824.0194 32.1083 163 941339.000 30.000 + 20 92 72 164 Hf -51818.356 15.812 8043.8142 0.0964 B- -8535.5511 32.1083 163 944370.709 16.975 + 18 91 73 164 Ta x -43282.805 27.945 7986.9978 0.1704 B- -5047.2500 29.5717 163 953534.000 30.000 + 16 90 74 164 W -38235.555 9.673 7951.4515 0.0590 B- -10763.1138 55.4055 163 958952.445 10.384 + 14 89 75 164 Re -a -27472.441 54.555 7881.0523 0.3326 B- -7047.7180 140.0330 163 970507.122 58.566 + 12 88 76 164 Os -20424.723 149.903 7833.3080 0.9140 B- -12941# 350# 163 978073.158 160.927 + 10 87 77 164 Ir -a -7483# 316# 7750# 2# B- * 163 991966# 339# +0 43 104 61 165 Pm x -34670# 500# 7992# 3# B- 8840# 640# 164 962780# 537# + 41 103 62 165 Sm x -43510# 400# 8041# 2# B- 7219# 400# 164 953290# 429# + 39 102 63 165 Eu -50729.103 5.213 8080.0529 0.0316 B- 5796.6788 5.3733 164 945540.070 5.596 + 37 101 64 165 Gd -56525.782 1.304 8110.4428 0.0079 B- 4063.0674 2.0189 164 939317.080 1.400 + 35 100 65 165 Tb -60588.849 1.541 8130.3259 0.0093 B- 3023.4392 1.6915 164 934955.198 1.654 + 33 99 66 165 Dy -n -63612.289 0.697 8143.9083 0.0042 B- 1285.7287 0.7502 164 931709.402 0.748 + 31 98 67 165 Ho -64898.017 0.786 8146.9591 0.0048 B- -376.6648 0.9575 164 930329.116 0.844 + 29 97 68 165 Er -64521.353 0.918 8139.9348 0.0056 B- -1591.3282 1.4891 164 930733.482 0.985 + 27 96 69 165 Tm -62930.024 1.658 8125.5489 0.0101 B- -2634.6364 26.5907 164 932441.843 1.779 + 25 95 70 165 Yb -60295.388 26.539 8104.8399 0.1608 B- -3853.1403 35.4324 164 935270.241 28.490 + 23 94 71 165 Lu -56442.248 26.539 8076.7460 0.1608 B- -4806.7350 38.5387 164 939406.758 28.490 + 21 93 72 165 Hf x -51635.513 27.945 8042.8728 0.1694 B- -5787.6410 31.0668 164 944567.000 30.000 + 19 92 73 165 Ta -45847.872 13.573 8003.0547 0.0823 B- -6986.5555 29.1133 164 950780.287 14.571 + 17 91 74 165 W -38861.316 25.756 7955.9704 0.1561 B- -8201.9627 34.9116 164 958280.663 27.649 + 15 90 75 165 Re +a -30659.353 23.593 7901.5201 0.1430 B- -8913# 202# 164 967085.831 25.328 + 13 89 76 165 Os -a -21747# 200# 7843# 1# B- -10151# 255# 164 976654# 215# + 11 88 77 165 Ir IT -11595# 158# 7776# 1# B- -11277# 430# 164 987552# 170# + 9 87 78 165 Pt -a -318# 400# 7703# 2# B- * 164 999658# 429# +0 42 104 62 166 Sm x -40450# 400# 8023# 2# B- 6299# 412# 165 956575# 429# + 40 103 63 166 Eu + -46749# 100# 8056# 1# B- 7622# 100# 165 949813# 107# + 38 102 64 166 Gd x -54370.926 1.584 8097.2260 0.0095 B- 3437.8515 2.1558 165 941630.413 1.700 + 36 101 65 166 Tb -57808.778 1.463 8113.2230 0.0088 B- 4775.6930 1.6690 165 937939.727 1.570 + 34 100 66 166 Dy -n -62584.471 0.804 8137.2793 0.0048 B- 485.8684 0.8502 165 932812.810 0.862 + 32 99 67 166 Ho -63070.339 0.786 8135.4933 0.0047 B- 1853.8057 0.7792 165 932291.209 0.844 + 30 98 68 166 Er -64924.145 0.334 8141.9479 0.0020 B- -3037.6667 11.5470 165 930301.067 0.358 + 28 97 69 166 Tm - -61886.478 11.552 8118.9357 0.0696 B- -292.7714 13.5069 165 933562.136 12.401 + 26 96 70 166 Yb +nn -61593.706 7.001 8112.4591 0.0422 B- -5572.7197 30.6189 165 933876.439 7.515 + 24 95 71 166 Lu x -56020.987 29.808 8074.1756 0.1796 B- -2161.9978 40.8585 165 939859.000 32.000 + 22 94 72 166 Hf x -53858.989 27.945 8056.4386 0.1683 B- -7761.2089 39.5199 165 942180.000 30.000 + 20 93 73 166 Ta x -46097.780 27.945 8004.9714 0.1683 B- -4210.3092 29.5036 165 950512.000 30.000 + 18 92 74 166 W -41887.471 9.463 7974.8951 0.0570 B- -10050.1358 88.7072 165 955031.952 10.159 + 16 91 75 166 Re -a -31837.335 88.242 7909.6392 0.5316 B- -6405.8090 88.3046 165 965821.216 94.731 + 14 90 76 166 Os -25431.526 17.966 7866.3371 0.1082 B- -12126# 201# 165 972698.135 19.287 + 12 89 77 166 Ir -p -13306# 201# 7789# 1# B- -8523# 361# 165 985716# 215# + 10 88 78 166 Pt -a -4783# 300# 7733# 2# B- * 165 994866# 322# +0 43 105 62 167 Sm x -35330# 500# 7992# 3# B- 8440# 640# 166 962072# 537# + 41 104 63 167 Eu x -43770# 400# 8038# 2# B- 7006# 400# 166 953011# 429# + 39 103 64 167 Gd -50775.732 5.213 8075.5428 0.0312 B- 5107.3505 5.5584 166 945490.012 5.596 + 37 102 65 167 Tb -55883.082 1.929 8101.4410 0.0116 B- 4028.3686 4.4459 166 940007.046 2.071 + 35 101 66 167 Dy x -59911.451 4.005 8120.8782 0.0240 B- 2368.0076 6.5549 166 935682.415 4.300 + 33 100 67 167 Ho p2n -62279.459 5.189 8130.3732 0.0311 B- 1009.7971 5.1890 166 933140.254 5.570 + 31 99 68 167 Er -63289.256 0.286 8131.7352 0.0017 B- -746.1392 1.2633 166 932056.192 0.306 + 29 98 69 167 Tm -62543.117 1.258 8122.5826 0.0075 B- -1953.2162 3.7968 166 932857.206 1.350 + 27 97 70 167 Yb -60589.900 3.960 8106.2020 0.0237 B- -3063.6190 37.4696 166 934954.069 4.251 + 25 96 71 167 Lu x -57526.281 37.260 8083.1722 0.2231 B- -4058.5198 46.5747 166 938243.000 40.000 + 23 95 72 167 Hf x -53467.761 27.945 8054.1850 0.1673 B- -5116.6971 39.5199 166 942600.000 30.000 + 21 94 73 167 Ta x -48351.064 27.945 8018.8614 0.1673 B- -6257.8523 33.6262 166 948093.000 30.000 + 19 93 74 167 W -42093.212 18.703 7976.7045 0.1120 B- -7259# 44# 166 954811.080 20.078 + 17 92 75 167 Re +a -34834# 40# 7929# 0# B- -8335# 90# 166 962604# 43# + 15 91 76 167 Os -a -26498.860 80.892 7873.9557 0.4844 B- -9426.4121 82.9464 166 971552.304 86.841 + 13 90 77 167 Ir -17072.448 18.346 7812.8254 0.1099 B- -10319# 307# 166 981671.973 19.694 + 11 89 78 167 Pt -a -6753# 306# 7746# 2# B- * 166 992750# 329# +0 44 106 62 168 Sm x -31640# 300# 7971# 2# B- 7610# 500# 167 966033# 322# + 42 105 63 168 Eu x -39250# 400# 8012# 2# B- 8899# 500# 167 957863# 429# + 40 104 64 168 Gd x -48150# 300# 8060# 2# B- 4631# 300# 167 948309# 322# + 38 103 65 168 Tb x -52781.181 4.192 8082.7980 0.0250 B- 5777.2167 140.0696 167 943337.074 4.500 + 36 102 66 168 Dy +pp -58558.398 140.007 8112.5293 0.8334 B- 1500.8333 143.1849 167 937134.977 150.303 + 34 101 67 168 Ho + -60059.231 30.001 8116.8061 0.1786 B- 2930.0000 30.0000 167 935523.766 32.207 + 32 100 68 168 Er -62989.231 0.262 8129.5897 0.0016 B- -1676.8526 1.6858 167 932378.282 0.280 + 30 99 69 168 Tm -61312.379 1.677 8114.9516 0.0100 B- 267.4880 1.6782 167 934178.457 1.800 + 28 98 70 168 Yb -61579.867 0.093 8111.8870 0.0006 B- -4507.0351 37.9735 167 933891.297 0.100 + 26 97 71 168 Lu -57072.832 37.973 8080.4026 0.2260 B- -1712.2740 47.1476 167 938729.798 40.766 + 24 96 72 168 Hf x -55360.557 27.945 8065.5536 0.1663 B- -6966.6444 39.5199 167 940568.000 30.000 + 22 95 73 168 Ta x -48393.913 27.945 8019.4287 0.1663 B- -3500.9828 30.9307 167 948047.000 30.000 + 20 94 74 168 W -44892.930 13.259 7993.9327 0.0789 B- -9098.0411 33.5515 167 951805.459 14.233 + 18 93 75 168 Re -a -35794.889 30.821 7935.1208 0.1835 B- -5799.8944 32.3727 167 961572.607 33.087 + 16 92 76 168 Os -29994.995 9.903 7895.9408 0.0589 B- -11328.7644 56.0975 167 967799.050 10.631 + 14 91 77 168 Ir -a -18666.230 55.216 7823.8509 0.3287 B- -7656.1526 140.3258 167 979960.978 59.277 + 12 90 78 168 Pt -a -11010.078 149.934 7773.6217 0.8925 B- -13540# 427# 167 988180.196 160.960 + 10 89 79 168 Au x 2530# 400# 7688# 2# B- * 168 002716# 429# +0 43 106 63 169 Eu x -35660# 500# 7991# 3# B- 8230# 640# 168 961717# 537# + 41 105 64 169 Gd x -43890# 400# 8035# 2# B- 6590# 500# 168 952882# 429# + 39 104 65 169 Tb x -50480# 300# 8069# 2# B- 5116# 425# 168 945807# 322# + 37 103 66 169 Dy + -55596.010 300.669 8094.7566 1.7791 B- 3200.0000 300.0000 168 940315.231 322.781 + 35 102 67 169 Ho +p -58796.010 20.048 8109.0622 0.1186 B- 2125.1534 20.0483 168 936879.890 21.522 + 33 101 68 169 Er -n -60921.163 0.304 8117.0078 0.0018 B- 353.4910 0.7729 168 934598.444 0.326 + 31 100 69 169 Tm -61274.654 0.738 8114.4702 0.0044 B- -899.1270 0.7563 168 934218.956 0.792 + 29 99 70 169 Yb -n -60375.527 0.178 8104.5206 0.0011 B- -2293.0000 3.0000 168 935184.208 0.191 + 27 98 71 169 Lu - -58082.527 3.005 8086.3233 0.0178 B- -3365.6321 28.1060 168 937645.845 3.226 + 25 97 72 169 Hf x -54716.895 27.945 8061.7791 0.1654 B- -4426.4600 39.5199 168 941259.000 30.000 + 23 96 73 169 Ta x -50290.435 27.945 8030.9577 0.1654 B- -5372.5686 31.9246 168 946011.000 30.000 + 21 95 74 169 W -44917.866 15.436 7994.5381 0.0913 B- -6508.6195 19.1703 168 951778.689 16.571 + 19 94 75 169 Re +a -38409.247 11.369 7951.3963 0.0673 B- -7686.2626 28.3218 168 958765.979 12.204 + 17 93 76 169 Os -a -30722.984 25.940 7901.2862 0.1535 B- -8629.5684 34.8557 168 967017.521 27.847 + 15 92 77 169 Ir +a -22093.416 23.307 7845.5944 0.1379 B- -9629# 202# 168 976281.743 25.020 + 13 91 78 169 Pt -a -12464# 200# 7784# 1# B- -10676# 359# 168 986619# 215# + 11 90 79 169 Au x -1788# 298# 7716# 2# B- * 168 998080# 320# +0 44 107 63 170 Eu x -30860# 500# 7963# 3# B- 9989# 707# 169 966870# 537# + 42 106 64 170 Gd x -40850# 500# 8017# 3# B- 5860# 583# 169 956146# 537# + 40 105 65 170 Tb x -46710# 300# 8047# 2# B- 7000# 361# 169 949855# 322# + 38 104 66 170 Dy x -53710# 200# 8084# 1# B- 2528# 206# 169 942340# 215# + 36 103 67 170 Ho + -56237.514 50.019 8093.7902 0.2942 B- 3870.0000 50.0000 169 939626.548 53.697 + 34 102 68 170 Er -60107.514 1.387 8111.9529 0.0082 B- -312.1997 1.7852 169 935471.933 1.488 + 32 101 69 170 Tm -59795.314 0.732 8105.5144 0.0043 B- 968.6148 0.7319 169 935807.093 0.785 + 30 100 70 170 Yb -60763.929 0.010 8106.6101 0.0003 B- -3457.6950 16.8430 169 934767.242 0.011 + 28 99 71 170 Lu - -57306.234 16.843 8081.6686 0.0991 B- -1052.3734 32.6282 169 938479.230 18.081 + 26 98 72 170 Hf x -56253.860 27.945 8070.8762 0.1644 B- -6116.1903 39.5199 169 939609.000 30.000 + 24 97 73 170 Ta x -50137.670 27.945 8030.2965 0.1644 B- -2846.8656 30.9035 169 946175.000 30.000 + 22 96 74 170 W -47290.804 13.195 8008.9482 0.0776 B- -8386.8083 17.4557 169 949231.235 14.165 + 20 95 75 170 Re -38903.996 11.427 7955.0120 0.0672 B- -4978.3046 15.0274 169 958234.844 12.267 + 18 94 76 170 Os -33925.692 9.759 7921.1258 0.0574 B- -10743# 102# 169 963579.273 10.476 + 16 93 77 170 Ir -a -23182# 101# 7853# 1# B- -6883# 102# 169 975113# 109# + 14 92 78 170 Pt -16299.202 18.246 7808.2365 0.1073 B- -12596# 202# 169 982502.087 19.588 + 12 91 79 170 Au -p -3703# 201# 7730# 1# B- -9119# 362# 169 996024# 216# + 10 90 80 170 Hg -a 5415# 302# 7671# 2# B- * 170 005814# 324# +0 43 107 64 171 Gd x -36210# 500# 7990# 3# B- 7560# 640# 170 961127# 537# + 41 106 65 171 Tb x -43770# 400# 8030# 2# B- 6240# 447# 170 953011# 429# + 39 105 66 171 Dy x -50010# 200# 8062# 1# B- 4508# 633# 170 946312# 215# + 37 104 67 171 Ho + -54517.822 600.002 8083.6021 3.5088 B- 3200.0000 600.0000 170 941472.713 644.128 + 35 103 68 171 Er -57717.822 1.408 8097.7404 0.0082 B- 1492.4490 1.0788 170 938037.372 1.511 + 33 102 69 171 Tm -59210.271 0.972 8101.8931 0.0057 B- 96.5468 0.9715 170 936435.162 1.043 + 31 101 70 171 Yb -59306.818 0.013 8097.8826 0.0003 B- -1478.3526 1.8621 170 936331.515 0.013 + 29 100 71 171 Lu -57828.465 1.862 8084.6621 0.0109 B- -2397.1144 28.9363 170 937918.591 1.999 + 27 99 72 171 Hf x -55431.351 28.876 8066.0687 0.1689 B- -3711.0725 40.1840 170 940492.000 31.000 + 25 98 73 171 Ta x -51720.279 27.945 8039.7914 0.1634 B- -4634.1832 39.5199 170 944476.000 30.000 + 23 97 74 171 W x -47086.095 27.945 8008.1158 0.1634 B- -5835.8106 39.5199 170 949451.000 30.000 + 21 96 75 171 Re x -41250.285 27.945 7969.4131 0.1634 B- -6953.0469 33.3748 170 955716.000 30.000 + 19 95 76 171 Os -34297.238 18.247 7924.1769 0.1067 B- -7885.2079 42.5749 170 963180.402 19.589 + 17 94 77 171 Ir -a -26412.030 38.466 7873.4895 0.2249 B- -8945.4613 89.6251 170 971645.520 41.295 + 15 93 78 171 Pt -a -17466.569 80.951 7816.6017 0.4734 B- -9904.2655 83.5586 170 981248.868 86.904 + 13 92 79 171 Au -p -7562.303 20.713 7754.1069 0.1211 B- -10901# 307# 170 991881.533 22.236 + 11 91 80 171 Hg -a 3339# 307# 7686# 2# B- * 171 003585# 329# +0 44 108 64 172 Gd x -32970# 300# 7972# 2# B- 6720# 583# 171 964605# 322# + 42 107 65 172 Tb x -39690# 500# 8006# 3# B- 8070# 583# 171 957391# 537# + 40 106 66 172 Dy x -47760# 300# 8049# 2# B- 3724# 358# 171 948728# 322# + 38 105 67 172 Ho x -51484# 196# 8066# 1# B- 4999# 196# 171 944730# 210# + 36 104 68 172 Er -56482.578 3.962 8090.4052 0.0230 B- 890.9756 4.5418 171 939363.461 4.253 + 34 103 69 172 Tm -57373.554 5.481 8091.0367 0.0319 B- 1881.9024 5.4814 171 938406.959 5.884 + 32 102 70 172 Yb -59255.456 0.014 8097.4295 0.0003 B- -2519.3805 2.3360 171 936386.654 0.014 + 30 101 71 172 Lu -56736.076 2.336 8078.2334 0.0136 B- -333.8443 24.5396 171 939091.320 2.507 + 28 100 72 172 Hf x -56402.232 24.428 8071.7439 0.1420 B- -5072.2490 37.1167 171 939449.716 26.224 + 26 99 73 172 Ta x -51329.983 27.945 8037.7056 0.1625 B- -2232.7914 39.5199 171 944895.000 30.000 + 24 98 74 172 W x -49097.191 27.945 8020.1757 0.1625 B- -7530.3525 45.2323 171 947292.000 30.000 + 22 97 75 172 Re -41566.839 35.568 7971.8460 0.2068 B- -4323.1979 37.7890 171 955376.165 38.183 + 20 96 76 172 Os -37243.641 12.766 7942.1626 0.0742 B- -9864.2673 34.8263 171 960017.309 13.704 + 18 95 77 172 Ir -a -27379.373 32.402 7880.2637 0.1884 B- -6272.7035 34.0232 171 970607.035 34.785 + 16 94 78 172 Pt -21106.670 10.376 7839.2460 0.0603 B- -11788.6592 57.1082 171 977341.059 11.139 + 14 93 79 172 Au -a -9318.011 56.158 7766.1587 0.3265 B- -8256.6495 140.8350 171 989996.704 60.287 + 12 92 80 172 Hg -a -1061.361 150.062 7713.6064 0.8725 B- * 171 998860.581 161.098 +0 43 108 65 173 Tb x -36510# 500# 7988# 3# B- 7230# 640# 172 960805# 537# + 41 107 66 173 Dy x -43740# 400# 8026# 2# B- 5610# 499# 172 953043# 429# + 39 106 67 173 Ho x -49351# 298# 8054# 2# B- 4304# 357# 172 947020# 320# + 37 105 68 173 Er x -53654# 196# 8074# 1# B- 2602# 196# 172 942400# 210# + 35 104 69 173 Tm p2n -56256.067 4.400 8084.4633 0.0254 B- 1295.1669 4.4000 172 939606.630 4.723 + 33 103 70 173 Yb -57551.234 0.011 8087.4276 0.0003 B- -670.2201 1.5674 172 938216.211 0.012 + 31 102 71 173 Lu -56881.014 1.567 8079.0312 0.0091 B- -1469.2244 27.9887 172 938935.722 1.682 + 29 101 72 173 Hf x -55411.790 27.945 8066.0164 0.1615 B- -3015.2464 39.5199 172 940513.000 30.000 + 27 100 73 173 Ta x -52396.543 27.945 8044.0650 0.1615 B- -3669.1553 39.5199 172 943750.000 30.000 + 25 99 74 173 W x -48727.388 27.945 8018.3337 0.1615 B- -5173.5182 39.5199 172 947689.000 30.000 + 23 98 75 173 Re x -43553.870 27.945 7983.9068 0.1615 B- -6115.6196 31.6968 172 953243.000 30.000 + 21 97 76 173 Os -37438.250 14.959 7944.0341 0.0865 B- -7169.7944 18.2998 172 959808.387 16.059 + 19 96 77 173 Ir -30268.456 10.542 7898.0680 0.0609 B- -8331.6974 64.3014 172 967505.477 11.316 + 17 95 78 173 Pt -a -21936.758 63.431 7845.3856 0.3667 B- -9104.7415 67.3903 172 976449.922 68.096 + 15 94 79 173 Au +a -12832.017 22.783 7788.2348 0.1317 B- -10171# 202# 172 986224.263 24.458 + 13 93 80 173 Hg -a -2661# 201# 7725# 1# B- * 172 997143# 215# +0 44 109 65 174 Tb x -31970# 500# 7963# 3# B- 9160# 707# 173 965679# 537# + 42 108 66 174 Dy x -41130# 500# 8011# 3# B- 4739# 583# 173 955845# 537# + 40 107 67 174 Ho x -45870# 300# 8034# 2# B- 6080# 423# 173 950757# 322# + 38 106 68 174 Er x -51949# 298# 8064# 2# B- 1915# 301# 173 944230# 320# + 36 105 69 174 Tm + -53864.521 44.721 8070.6432 0.2570 B- 3080.0000 44.7214 173 942174.061 48.010 + 34 104 70 174 Yb -56944.521 0.011 8083.8481 0.0003 B- -1374.2287 1.5675 173 938867.545 0.011 + 32 103 71 174 Lu -55570.292 1.567 8071.4540 0.0090 B- 274.2911 2.1686 173 940342.840 1.682 + 30 102 72 174 Hf -55844.583 2.259 8068.5341 0.0130 B- -4103.8117 28.0360 173 940048.377 2.425 + 28 101 73 174 Ta x -51740.771 27.945 8040.4528 0.1606 B- -1513.6779 39.5199 173 944454.000 30.000 + 26 100 74 174 W x -50227.093 27.945 8027.2572 0.1606 B- -6553.9925 39.5199 173 946079.000 30.000 + 24 99 75 174 Re x -43673.101 27.945 7985.0944 0.1606 B- -3677.7177 29.7667 173 953115.000 30.000 + 22 98 76 174 Os -39995.383 10.254 7959.4618 0.0589 B- -9209.4466 15.2008 173 957063.192 11.008 + 20 97 77 174 Ir +a -30785.937 11.221 7902.0377 0.0645 B- -5468.3293 15.2578 173 966949.939 12.046 + 18 96 78 174 Pt -a -25317.608 10.338 7866.1143 0.0594 B- -11259# 102# 173 972820.431 11.098 + 16 95 79 174 Au -a -14058# 102# 7797# 1# B- -7417# 102# 173 984908# 109# + 14 94 80 174 Hg -a -6641.017 19.211 7749.7851 0.1104 B- * 173 992870.575 20.623 +0 43 109 66 175 Dy x -36730# 500# 7986# 3# B- 6570# 640# 174 960569# 537# + 41 108 67 175 Ho x -43300# 400# 8019# 2# B- 5352# 566# 174 953516# 429# + 39 107 68 175 Er x -48652# 401# 8045# 2# B- 3659# 404# 174 947770# 430# + 37 106 69 175 Tm + -52310.556 50.000 8061.7673 0.2857 B- 2385.0000 50.0000 174 943842.310 53.677 + 35 105 70 175 Yb -54695.556 0.071 8070.9253 0.0005 B- 470.1219 1.2068 174 941281.907 0.076 + 33 104 71 175 Lu -55165.678 1.207 8069.1412 0.0069 B- -683.9154 1.9516 174 940777.211 1.295 + 31 103 72 175 Hf -54481.763 2.283 8060.7625 0.0130 B- -2073.1103 28.0379 174 941511.424 2.450 + 29 102 73 175 Ta x -52408.653 27.945 8044.4456 0.1597 B- -2775.8524 39.5199 174 943737.000 30.000 + 27 101 74 175 W x -49632.800 27.945 8024.1130 0.1597 B- -4344.4885 39.5199 174 946717.000 30.000 + 25 100 75 175 Re x -45288.312 27.945 7994.8168 0.1597 B- -5182.9513 30.3243 174 951381.000 30.000 + 23 99 76 175 Os -40105.360 11.775 7960.7294 0.0673 B- -6710.8496 17.0887 174 956945.126 12.640 + 21 98 77 175 Ir -33394.511 12.384 7917.9112 0.0708 B- -7685.8265 22.3572 174 964149.519 13.295 + 19 97 78 175 Pt -25708.684 18.614 7869.5216 0.1064 B- -8304.9980 42.8203 174 972400.593 19.982 + 17 96 79 175 Au -a -17403.686 38.563 7817.5939 0.2204 B- -9434.2436 89.7876 174 981316.375 41.399 + 15 95 80 175 Hg -a -7969.443 81.085 7759.2134 0.4633 B- * 174 991444.451 87.047 +0 44 110 66 176 Dy x -33610# 500# 7969# 3# B- 5780# 707# 175 963918# 537# + 42 109 67 176 Ho x -39390# 500# 7997# 3# B- 7241# 641# 175 957713# 537# + 40 108 68 176 Er x -46631# 401# 8034# 2# B- 2741# 413# 175 949940# 430# + 38 107 69 176 Tm + -49371.322 100.000 8045.1214 0.5682 B- 4120.0000 100.0000 175 946997.707 107.354 + 36 106 70 176 Yb -53491.322 0.014 8064.0853 0.0003 B- -108.9895 1.2124 175 942574.706 0.015 + 34 105 71 176 Lu -53382.333 1.212 8059.0209 0.0069 B- 1194.0947 0.8744 175 942691.711 1.301 + 32 104 72 176 Hf -54576.428 1.482 8061.3604 0.0084 B- -3211.0484 30.7750 175 941409.797 1.591 + 30 103 73 176 Ta x -51365.379 30.739 8038.6706 0.1747 B- -723.7709 41.5430 175 944857.000 33.000 + 28 102 74 176 W x -50641.608 27.945 8030.1131 0.1588 B- -5578.7182 39.5199 175 945634.000 30.000 + 26 101 75 176 Re x -45062.890 27.945 7993.9707 0.1588 B- -2931.7058 30.0134 175 951623.000 30.000 + 24 100 76 176 Os -42131.184 10.949 7972.8681 0.0622 B- -8249.2618 13.6110 175 954770.315 11.754 + 22 99 77 176 Ir -33881.923 8.085 7921.5522 0.0459 B- -4948.0041 15.0657 175 963626.261 8.679 + 20 98 78 176 Pt -28933.918 12.712 7888.9934 0.0722 B- -10412.9516 35.5363 175 968938.162 13.647 + 18 97 79 176 Au -a -18520.967 33.185 7825.3837 0.1885 B- -6736.3283 34.9978 175 980116.925 35.625 + 16 96 80 176 Hg -11784.639 11.118 7782.6640 0.0632 B- -12369.3668 83.7993 175 987348.670 11.936 + 14 95 81 176 Tl -p 584.728 83.058 7707.9383 0.4719 B- * 176 000627.731 89.166 +0 43 110 67 177 Ho x -36280# 500# 7980# 3# B- 6578# 709# 176 961052# 537# + 41 109 68 177 Er x -42858# 503# 8013# 3# B- 4711# 541# 176 953990# 540# + 39 108 69 177 Tm x -47570# 200# 8035# 1# B- 3417# 200# 176 948932# 215# + 37 107 70 177 Yb -n -50986.404 0.220 8049.9741 0.0013 B- 1397.4983 1.2406 176 945263.846 0.236 + 35 106 71 177 Lu -52383.903 1.221 8053.4495 0.0069 B- 496.8425 0.7921 176 943763.570 1.310 + 33 105 72 177 Hf -52880.745 1.410 8051.8365 0.0080 B- -1166.0000 3.0000 176 943230.187 1.514 + 31 104 73 177 Ta - -51714.745 3.315 8040.8289 0.0187 B- -2013.0144 28.1408 176 944481.940 3.558 + 29 103 74 177 W x -49701.731 27.945 8025.0359 0.1579 B- -3432.5558 39.5199 176 946643.000 30.000 + 27 102 75 177 Re x -46269.175 27.945 8001.2229 0.1579 B- -4312.7271 31.5349 176 950328.000 30.000 + 25 101 76 177 Os +a -41956.448 14.613 7972.4371 0.0826 B- -5909.0234 24.5763 176 954957.902 15.687 + 23 100 77 177 Ir x -36047.425 19.760 7934.6328 0.1116 B- -6676.9880 24.8010 176 961301.500 21.213 + 21 99 78 177 Pt -29370.437 14.988 7892.4896 0.0847 B- -7824.7003 17.9991 176 968469.541 16.090 + 19 98 79 177 Au -21545.736 9.968 7843.8623 0.0563 B- -8769.9135 85.3061 176 976869.701 10.700 + 17 97 80 177 Hg -a -12775.823 84.722 7789.8947 0.4787 B- -9435.7198 87.4322 176 986284.590 90.952 + 15 96 81 177 Tl IT -3340.103 21.628 7732.1655 0.1222 B- * 176 996414.252 23.218 +0 44 111 67 178 Ho x -32130# 500# 7957# 3# B- 8130# 778# 177 965507# 537# + 42 110 68 178 Er x -40260# 596# 7999# 3# B- 3980# 667# 177 956779# 640# + 40 109 69 178 Tm x -44240# 300# 8017# 2# B- 5437# 300# 177 952506# 322# + 38 108 70 178 Yb -49677.139 6.588 8042.7386 0.0370 B- 660.7415 6.9617 177 946669.400 7.072 + 36 107 71 178 Lu -50337.881 2.251 8042.0554 0.0127 B- 2097.4851 2.0569 177 945960.065 2.416 + 34 106 72 178 Hf -52435.366 1.415 8049.4438 0.0080 B- -1837# 52# 177 943708.322 1.519 + 32 105 73 178 Ta IT -50598# 52# 8035# 0# B- -191# 50# 177 945680# 56# + 30 104 74 178 W - -50407.066 15.199 8029.2584 0.0854 B- -4753.6082 31.8106 177 945885.791 16.316 + 28 103 75 178 Re x -45653.457 27.945 7998.1576 0.1570 B- -2109.2143 31.0925 177 950989.000 30.000 + 26 102 76 178 Os -43544.243 13.632 7981.9128 0.0766 B- -7289.9295 23.2390 177 953253.334 14.634 + 24 101 77 178 Ir -36254.314 18.821 7936.5630 0.1057 B- -4256.8282 21.3752 177 961079.395 20.204 + 22 100 78 178 Pt -31997.486 10.133 7908.2530 0.0569 B- -9694.4567 14.4108 177 965649.288 10.878 + 20 99 79 178 Au x -22303.029 10.246 7849.3946 0.0576 B- -5987.6832 14.8566 177 976056.714 11.000 + 18 98 80 178 Hg -a -16315.346 10.758 7811.3607 0.0604 B- -11702# 103# 177 982484.756 11.548 + 16 97 81 178 Tl -a -4613# 102# 7741# 1# B- -8187# 103# 177 995047# 110# + 14 96 82 178 Pb -a 3573.371 23.184 7690.8359 0.1302 B- * 178 003836.171 24.889 +0 43 111 68 179 Er x -36080# 500# 7976# 3# B- 5821# 640# 178 961267# 537# + 41 110 69 179 Tm x -41900# 400# 8004# 2# B- 4739# 447# 178 955018# 429# + 39 109 70 179 Yb x -46640# 200# 8026# 1# B- 2419# 200# 178 949930# 215# + 37 108 71 179 Lu -49059.013 5.150 8035.0744 0.0288 B- 1404.0231 5.0672 178 947332.985 5.528 + 35 107 72 179 Hf -50463.036 1.416 8038.5474 0.0079 B- -105.5801 0.4088 178 945825.705 1.520 + 33 106 73 179 Ta -50357.456 1.466 8033.5869 0.0082 B- -1062.2093 14.5197 178 945939.050 1.574 + 31 105 74 179 W -49295.247 14.573 8023.2821 0.0814 B- -2710.9347 26.8021 178 947079.378 15.644 + 29 104 75 179 Re -46584.312 24.639 8003.7666 0.1376 B- -3564.1747 29.1116 178 949989.686 26.450 + 27 103 76 179 Os -43020.137 15.505 7979.4844 0.0866 B- -4938.4182 18.3271 178 953815.985 16.645 + 25 102 77 179 Ir -38081.719 9.771 7947.5248 0.0546 B- -5813.5920 12.6133 178 959117.594 10.489 + 23 101 78 179 Pt -32268.127 7.977 7910.6759 0.0446 B- -7279.5556 14.1567 178 965358.742 8.563 + 21 100 79 179 Au -24988.572 11.696 7865.6374 0.0653 B- -8055.6480 30.4559 178 973173.666 12.555 + 19 99 80 179 Hg -16932.924 28.121 7816.2631 0.1571 B- -8663.2918 47.7998 178 981821.759 30.188 + 17 98 81 179 Tl -a -8269.632 38.653 7763.4942 0.2159 B- -10321.2401 89.9571 178 991122.185 41.495 + 15 97 82 179 Pb -a 2051.608 81.229 7701.4630 0.4538 B- * 179 002202.492 87.203 +0 44 112 68 180 Er x -33180# 500# 7960# 3# B- 4990# 640# 179 964380# 537# + 42 111 69 180 Tm x -38170# 400# 7983# 2# B- 6550# 500# 179 959023# 429# + 40 110 70 180 Yb x -44720# 300# 8016# 2# B- 1956# 308# 179 951991# 322# + 38 109 71 180 Lu + -46676.476 70.725 8022.0394 0.3929 B- 3103.0000 70.7107 179 949890.744 75.926 + 36 108 72 180 Hf -49779.476 1.421 8034.9319 0.0079 B- -845.8453 2.3472 179 946559.537 1.525 + 34 107 73 180 Ta +n -48933.631 2.068 8025.8864 0.0115 B- 702.6122 2.3590 179 947467.589 2.219 + 32 106 74 180 W -49636.243 1.439 8025.4434 0.0080 B- -3798.8793 21.4404 179 946713.304 1.545 + 30 105 75 180 Re x -45837.364 21.392 7999.9922 0.1188 B- -1481.1659 26.5482 179 950791.568 22.965 + 28 104 76 180 Os -44356.198 15.722 7987.4171 0.0873 B- -6378.6679 26.8021 179 952381.665 16.878 + 26 103 77 180 Ir x -37977.530 21.706 7947.6337 0.1206 B- -3547.6546 23.9205 179 959229.446 23.302 + 24 102 78 180 Pt -34429.875 10.051 7923.5781 0.0558 B- -8804.2290 11.1207 179 963038.010 10.790 + 22 101 79 180 Au -25625.646 4.759 7870.3194 0.0264 B- -5375.1330 13.5105 179 972489.738 5.108 + 20 100 80 180 Hg -20250.513 12.645 7836.1111 0.0702 B- -10860.0750 71.0509 179 978260.180 13.574 + 18 99 81 180 Tl -a -9390.438 69.917 7771.4310 0.3884 B- -7449.3696 71.0069 179 989918.950 75.058 + 16 98 82 180 Pb -a -1941.069 12.395 7725.6993 0.0689 B- * 179 997916.177 13.306 +0 43 112 69 181 Tm x -35440# 500# 7969# 3# B- 5649# 582# 180 961954# 537# + 41 111 70 181 Yb x -41088# 298# 7996# 2# B- 3709# 324# 180 955890# 320# + 39 110 71 181 Lu x -44797.414 125.752 8011.9301 0.6948 B- 2605.5435 125.7598 180 951908.000 135.000 + 37 109 72 181 Hf -n -47402.958 1.423 8022.0030 0.0079 B- 1036.1061 1.9298 180 949110.834 1.527 + 35 108 73 181 Ta -48439.064 1.576 8023.4050 0.0087 B- -205.1193 1.9495 180 947998.528 1.692 + 33 107 74 181 W -n -48233.945 1.448 8017.9494 0.0080 B- -1716.5331 12.6289 180 948218.733 1.554 + 31 106 75 181 Re 4n -46517.412 12.549 8004.1434 0.0693 B- -2967.4438 28.2755 180 950061.507 13.471 + 29 105 76 181 Os -43549.968 25.338 7983.4263 0.1400 B- -4086.9327 25.8756 180 953247.188 27.201 + 27 104 77 181 Ir +a -39463.035 5.245 7956.5242 0.0290 B- -5081.5379 14.6597 180 957634.691 5.631 + 25 103 78 181 Pt -34381.497 13.689 7924.1271 0.0756 B- -6510.3575 24.2164 180 963089.946 14.695 + 23 102 79 181 Au -a -27871.140 19.976 7883.8359 0.1104 B- -7210.0126 25.2123 180 970079.102 21.445 + 21 101 80 181 Hg -20661.127 15.382 7839.6792 0.0850 B- -7862.3780 17.8730 180 977819.368 16.513 + 19 100 81 181 Tl -12798.749 9.102 7791.9183 0.0503 B- -9688.1182 85.5227 180 986259.978 9.771 + 17 99 82 181 Pb -a -3110.631 85.037 7734.0704 0.4698 B- * 180 996660.600 91.290 +0 44 113 69 182 Tm x -31490# 500# 7948# 3# B- 7410# 640# 181 966194# 537# + 42 112 70 182 Yb x -38900# 400# 7984# 2# B- 2870# 447# 181 958239# 429# + 40 111 71 182 Lu x -41770# 200# 7996# 1# B- 4280# 200# 181 955158# 215# + 38 110 72 182 Hf -nn -46049.636 6.166 8014.8381 0.0339 B- 381.0486 6.3027 181 950563.684 6.619 + 36 109 73 182 Ta -46430.685 1.578 8012.6332 0.0087 B- 1815.4592 1.5276 181 950154.612 1.693 + 34 108 74 182 W -48246.144 0.745 8018.3096 0.0041 B- -2800.0000 101.9804 181 948205.636 0.799 + 32 107 75 182 Re IT -45446.144 101.983 7998.6264 0.5603 B- -837.0348 104.2757 181 951211.560 109.483 + 30 106 76 182 Os -44609.109 21.745 7989.7287 0.1195 B- -5557.4266 30.2074 181 952110.154 23.344 + 28 105 77 182 Ir -39051.682 20.967 7954.8948 0.1152 B- -2883.2620 24.7202 181 958076.296 22.509 + 26 104 78 182 Pt -36168.420 13.095 7934.7541 0.0719 B- -7864.4447 22.8812 181 961171.605 14.057 + 24 103 79 182 Au -28303.976 18.764 7887.2442 0.1031 B- -4727.0905 21.1645 181 969614.433 20.143 + 22 102 80 182 Hg -23576.885 9.790 7856.9726 0.0538 B- -10249.6721 15.4687 181 974689.173 10.510 + 20 101 81 182 Tl -a -13327.213 11.976 7796.3571 0.0658 B- -6502.6567 17.0151 181 985692.649 12.856 + 18 100 82 182 Pb -a -6824.556 12.086 7756.3296 0.0664 B- * 181 992673.537 12.975 +0 43 113 70 183 Yb x -35000# 400# 7963# 2# B- 4716# 408# 182 962426# 429# + 41 112 71 183 Lu x -39716.114 80.108 7984.8125 0.4378 B- 3567.4325 85.5564 182 957363.000 86.000 + 39 111 72 183 Hf + -43283.547 30.042 8000.0315 0.1642 B- 2010.0000 30.0000 182 953533.203 32.251 + 37 110 73 183 Ta -n -45293.547 1.590 8006.7400 0.0087 B- 1072.1161 1.5405 182 951375.380 1.707 + 35 109 74 183 W -46365.663 0.743 8008.3234 0.0041 B- -556.0000 8.0000 182 950224.416 0.798 + 33 108 75 183 Re - -45809.663 8.034 8001.0101 0.0439 B- -2145.9028 50.4129 182 950821.306 8.625 + 31 107 76 183 Os -43663.760 49.769 7985.0087 0.2720 B- -3461.6215 52.8061 182 953125.028 53.428 + 29 106 77 183 Ir -40202.138 24.672 7961.8176 0.1348 B- -4428.9417 28.4743 182 956841.231 26.486 + 27 105 78 183 Pt -35773.197 14.216 7933.3406 0.0777 B- -5581.7092 17.0554 182 961595.895 15.261 + 25 104 79 183 Au -30191.488 9.423 7898.5644 0.0515 B- -6386.8322 11.7891 182 967588.106 10.116 + 23 103 80 183 Hg -23804.655 7.084 7859.3885 0.0387 B- -7217.3941 11.7158 182 974444.652 7.604 + 21 102 81 183 Tl -16587.261 9.331 7815.6741 0.0510 B- -9007.2534 30.4442 182 982192.843 10.017 + 19 101 82 183 Pb -a -7580.008 28.979 7762.1790 0.1584 B- * 182 991862.527 31.110 +0 44 114 70 184 Yb x -32600# 503# 7951# 3# B- 3700# 541# 183 965002# 540# + 42 113 71 184 Lu x -36300# 200# 7967# 1# B- 5199# 204# 183 961030# 215# + 40 112 72 184 Hf + -41499.453 39.706 7990.7228 0.2158 B- 1340.0000 30.0000 183 955448.507 42.625 + 38 111 73 184 Ta + -42839.453 26.010 7993.7535 0.1414 B- 2866.0000 26.0000 183 954009.958 27.923 + 36 110 74 184 W -45705.453 0.738 8005.0777 0.0040 B- -1485.6333 4.1971 183 950933.180 0.792 + 34 109 75 184 Re -44219.819 4.276 7992.7517 0.0232 B- 32.7460 4.1387 183 952528.073 4.590 + 32 108 76 184 Os -44252.565 0.829 7988.6778 0.0045 B- -4641.7101 27.9571 183 952492.919 0.890 + 30 107 77 184 Ir x -39610.855 27.945 7959.1992 0.1519 B- -2278.3688 31.5957 183 957476.000 30.000 + 28 106 78 184 Pt -37332.486 14.744 7942.5649 0.0801 B- -7013.7724 26.7122 183 959921.929 15.828 + 26 105 79 184 Au -a -30318.714 22.275 7900.1947 0.1211 B- -3973.9269 24.2296 183 967451.523 23.912 + 24 104 80 184 Hg -26344.787 9.535 7874.3454 0.0518 B- -9461.4321 13.8254 183 971717.709 10.235 + 22 103 81 184 Tl -16883.355 10.012 7818.6727 0.0544 B- -5831.7688 16.2517 183 981874.973 10.747 + 20 102 82 184 Pb -11051.586 12.802 7782.7264 0.0696 B- -12306# 123# 183 988135.634 13.743 + 18 101 83 184 Bi -a 1254# 122# 7712# 1# B- * 184 001347# 131# +0 45 115 70 185 Yb x -28480# 500# 7929# 3# B- 5480# 583# 184 969425# 537# + 43 114 71 185 Lu x -33960# 300# 7955# 2# B- 4359# 307# 184 963542# 322# + 41 113 72 185 Hf x -38319.804 64.273 7973.9711 0.3474 B- 3074.5667 65.8147 184 958862.000 69.000 + 39 112 73 185 Ta + -41394.371 14.161 7986.3615 0.0765 B- 1993.5000 14.1421 184 955561.317 15.202 + 37 111 74 185 W -43387.871 0.739 7992.9083 0.0040 B- 431.1764 0.6616 184 953421.206 0.793 + 35 110 75 185 Re -43819.047 0.820 7991.0101 0.0044 B- -1013.1393 0.4190 184 952958.320 0.879 + 33 109 76 185 Os -42805.908 0.832 7981.3047 0.0045 B- -2470.3505 27.9572 184 954045.969 0.893 + 31 108 77 185 Ir x -40335.558 27.945 7963.7226 0.1511 B- -3647.4137 38.0554 184 956698.000 30.000 + 29 107 78 185 Pt -36688.144 25.832 7939.7779 0.1396 B- -4829.9942 25.9635 184 960613.659 27.731 + 27 106 79 185 Au x -31858.150 2.608 7909.4410 0.0141 B- -5674.4989 13.8859 184 965798.871 2.800 + 25 105 80 185 Hg -26183.651 13.639 7874.5391 0.0737 B- -6425.9062 24.7674 184 971890.696 14.641 + 23 104 81 185 Tl IT -19757.745 20.674 7835.5756 0.1118 B- -8216.5333 26.2493 184 978789.189 22.194 + 21 103 82 185 Pb -a -11541.211 16.175 7786.9330 0.0874 B- -9305# 83# 184 987610.000 17.364 + 19 102 83 185 Bi IT -2236# 81# 7732# 0# B- * 184 997600# 87# +0 44 115 71 186 Lu x -30320# 400# 7936# 2# B- 6104# 403# 185 967450# 429# + 42 114 72 186 Hf x -36424.214 51.232 7964.3032 0.2754 B- 2183.3883 78.9063 185 960897.000 55.000 + 40 113 73 186 Ta + -38607.602 60.012 7971.8357 0.3226 B- 3901.0000 60.0000 185 958553.036 64.425 + 38 112 74 186 W -42508.602 1.213 7988.6026 0.0065 B- -581.2819 1.2386 185 954365.140 1.302 + 36 111 75 186 Re -41927.320 0.820 7981.2713 0.0044 B- 1072.7114 0.8337 185 954989.172 0.880 + 34 110 76 186 Os -43000.032 0.761 7982.8324 0.0041 B- -3827.6813 16.5430 185 953837.569 0.816 + 32 109 77 186 Ir x -39172.350 16.526 7958.0473 0.0888 B- -1307.9030 27.3122 185 957946.754 17.740 + 30 108 78 186 Pt -37864.447 21.745 7946.8094 0.1169 B- -6149.5913 30.2074 185 959350.845 23.344 + 28 107 79 186 Au -31714.856 20.967 7909.5409 0.1127 B- -3175.7972 23.9866 185 965952.703 22.509 + 26 106 80 186 Hg -28539.059 11.650 7888.2605 0.0626 B- -8656.1190 23.7974 185 969362.061 12.507 + 24 105 81 186 Tl -19882.940 20.751 7837.5161 0.1116 B- -5202.0427 23.4877 185 978654.787 22.276 + 22 104 82 186 Pb -a -14680.897 11.004 7805.3420 0.0592 B- -11535.3999 20.2118 185 984239.409 11.813 + 20 103 83 186 Bi -a -3145.497 16.954 7739.1175 0.0911 B- -7247.0279 24.9305 185 996623.169 18.200 + 18 102 84 186 Po -a 4101.531 18.278 7695.9488 0.0983 B- * 186 004403.174 19.622 +0 45 116 71 187 Lu x -27770# 400# 7923# 2# B- 5230# 447# 186 970188# 429# + 43 115 72 187 Hf x -33000# 200# 7947# 1# B- 3896# 208# 186 964573# 215# + 41 114 73 187 Ta x -36895.550 55.890 7963.2123 0.2989 B- 3008.4937 55.9028 186 960391.000 60.000 + 39 113 74 187 W -39904.044 1.213 7975.1168 0.0065 B- 1312.5048 1.1219 186 957161.249 1.302 + 37 112 75 187 Re -41216.548 0.737 7977.9519 0.0039 B- 2.4667 0.0016 186 955752.217 0.791 + 35 111 76 187 Os -41219.015 0.737 7973.7814 0.0039 B- -1669.6385 27.9545 186 955749.569 0.791 + 33 110 77 187 Ir x -39549.377 27.945 7960.6692 0.1494 B- -2864.0151 36.8802 186 957542.000 30.000 + 31 109 78 187 Pt -36685.361 24.067 7941.1699 0.1287 B- -3656.5811 27.4478 186 960616.646 25.837 + 29 108 79 187 Au -33028.780 22.499 7917.4323 0.1203 B- -4910.2713 25.9171 186 964542.147 24.153 + 27 107 80 187 Hg -28118.509 12.864 7886.9905 0.0688 B- -5673.9170 15.1746 186 969813.540 13.810 + 25 106 81 187 Tl -22444.592 8.048 7852.4650 0.0430 B- -7457.6370 9.5248 186 975904.740 8.640 + 23 105 82 187 Pb -14986.955 5.094 7808.4010 0.0272 B- -8603.6798 11.2268 186 983910.842 5.468 + 21 104 83 187 Bi -a -6383.275 10.005 7758.2083 0.0535 B- -9207.0832 34.1302 186 993147.272 10.740 + 19 103 84 187 Po -a 2823.808 32.631 7704.7889 0.1745 B- * 187 003031.482 35.030 +0 46 117 71 188 Lu x -23820# 400# 7903# 2# B- 7009# 500# 187 974428# 429# + 44 116 72 188 Hf x -30830# 300# 7936# 2# B- 3080# 361# 187 966903# 322# + 42 115 73 188 Ta x -33910# 200# 7948# 1# B- 4758# 200# 187 963596# 215# + 40 114 74 188 W + -38667.880 3.089 7969.0532 0.0164 B- 349.0000 3.0000 187 958488.325 3.316 + 38 113 75 188 Re -n -39016.880 0.738 7966.7481 0.0039 B- 2120.4209 0.1520 187 958113.658 0.792 + 36 112 76 188 Os -41137.301 0.734 7973.8656 0.0039 B- -2792.3457 9.4164 187 955837.292 0.788 + 34 111 77 188 Ir -38344.955 9.423 7954.8512 0.0501 B- -523.9860 8.6863 187 958834.999 10.116 + 32 110 78 188 Pt -37820.970 5.305 7947.9027 0.0282 B- -5449.6549 5.9528 187 959397.521 5.694 + 30 109 79 188 Au x -32371.315 2.701 7914.7537 0.0144 B- -2172.9634 7.3046 187 965247.966 2.900 + 28 108 80 188 Hg -30198.351 6.787 7899.0340 0.0361 B- -7861.9485 30.6643 187 967580.738 7.285 + 26 107 81 188 Tl x -22336.403 29.904 7853.0537 0.1591 B- -4525.3784 31.5712 187 976020.886 32.103 + 24 106 82 188 Pb -a -17811.024 10.124 7824.8211 0.0539 B- -10616.2241 15.0824 187 980879.079 10.868 + 22 105 83 188 Bi -a -7194.800 11.179 7764.1904 0.0595 B- -6650.4226 22.8861 187 992276.064 12.001 + 20 104 84 188 Po -a -544.378 19.970 7724.6544 0.1062 B- * 187 999415.586 21.438 +0 45 117 72 189 Hf x -27150# 300# 7917# 2# B- 4809# 361# 188 970853# 322# + 43 116 73 189 Ta x -31960# 200# 7938# 1# B- 3850# 283# 188 965690# 215# + 41 115 74 189 W + -35809# 200# 7954# 1# B- 2170# 200# 188 961557# 215# + 39 114 75 189 Re +p -37979.097 8.191 7961.8105 0.0433 B- 1007.7049 8.1671 188 959227.764 8.793 + 37 113 76 189 Os -38986.802 0.666 7963.0029 0.0035 B- -537.1494 12.5630 188 958145.949 0.715 + 35 112 77 189 Ir -38449.652 12.576 7956.0214 0.0665 B- -1980.2470 13.6363 188 958722.602 13.500 + 33 111 78 189 Pt -36469.405 10.090 7941.4045 0.0534 B- -2887.4471 22.4737 188 960848.485 10.832 + 31 110 79 189 Au x -33581.958 20.081 7921.9876 0.1063 B- -3955.5800 37.4009 188 963948.286 21.558 + 29 109 80 189 Hg -29626.378 31.553 7896.9192 0.1669 B- -5010.2727 32.6434 188 968194.776 33.873 + 27 108 81 189 Tl -24616.105 8.368 7866.2704 0.0443 B- -6772.0862 16.3636 188 973573.525 8.983 + 25 107 82 189 Pb -17844.019 14.062 7826.2999 0.0744 B- -7779.3555 25.1498 188 980843.658 15.096 + 23 106 83 189 Bi -a -10064.664 20.851 7780.9999 0.1103 B- -8642.6682 30.3542 188 989195.139 22.384 + 21 105 84 189 Po -a -1421.996 22.059 7731.1321 0.1167 B- * 188 998473.425 23.681 +0 46 118 72 190 Hf x -24800# 400# 7905# 2# B- 3920# 447# 189 973376# 429# + 44 117 73 190 Ta x -28720# 200# 7922# 1# B- 5649# 203# 189 969168# 215# + 42 116 74 190 W -34368.832 35.391 7947.5031 0.1863 B- 1214.1824 35.5545 189 963103.542 37.993 + 40 115 75 190 Re -35583.015 4.870 7949.7759 0.0256 B- 3124.8105 4.7864 189 961800.064 5.227 + 38 114 76 190 Os -38707.825 0.650 7962.1047 0.0034 B- -1954.2108 1.2131 189 958445.442 0.697 + 36 113 77 190 Ir +n -36753.614 1.370 7947.7017 0.0072 B- 552.8893 1.2822 189 960543.374 1.470 + 34 112 78 190 Pt -37306.504 0.657 7946.4941 0.0035 B- -4472.9637 3.5086 189 959949.823 0.705 + 32 111 79 190 Au x -32833.540 3.447 7918.8345 0.0181 B- -1462.9150 16.2760 189 964751.746 3.700 + 30 110 80 190 Hg -31370.625 15.907 7907.0174 0.0837 B- -7004.3892 17.4819 189 966322.250 17.076 + 28 109 81 190 Tl +a -24366.236 7.252 7866.0345 0.0382 B- -3949.6288 14.4634 189 973841.771 7.784 + 26 108 82 190 Pb -a -20416.607 12.514 7841.1294 0.0659 B- -9820.7014 24.4226 189 978081.872 13.434 + 24 107 83 190 Bi -a -10595.906 20.973 7785.3239 0.1104 B- -6033.1975 24.7615 189 988624.828 22.515 + 22 106 84 190 Po -a -4562.708 13.163 7749.4526 0.0693 B- * 189 995101.731 14.131 +0 45 118 73 191 Ta x -26520# 300# 7911# 2# B- 4657# 303# 190 971530# 322# + 43 117 74 191 W x -31176.176 41.917 7931.4359 0.2195 B- 3174.2318 43.1556 190 966531.000 45.000 + 41 116 75 191 Re +p -34350.408 10.264 7943.9588 0.0537 B- 2044.8311 10.2443 190 963123.322 11.019 + 39 115 76 191 Os -36395.239 0.659 7950.5687 0.0035 B- 313.5873 1.1410 190 960928.105 0.707 + 37 114 77 191 Ir -36708.826 1.310 7948.1144 0.0069 B- -1010.4903 3.6360 190 960591.455 1.406 + 35 113 78 191 Pt -35698.336 4.127 7938.7279 0.0216 B- -1900.4257 6.4260 190 961676.261 4.430 + 33 112 79 191 Au -33797.910 4.926 7924.6819 0.0258 B- -3206.0616 22.7103 190 963716.452 5.288 + 31 111 80 191 Hg -30591.849 22.280 7903.8002 0.1167 B- -4308.8981 23.4609 190 967158.301 23.918 + 29 110 81 191 Tl +a -26282.951 7.349 7877.1445 0.0385 B- -5991.7073 9.8864 190 971784.093 7.889 + 27 109 82 191 Pb -20291.243 6.613 7841.6782 0.0346 B- -7051.8922 9.9895 190 978216.455 7.099 + 25 108 83 191 Bi -13239.351 7.487 7800.6613 0.0392 B- -8170.6205 10.3201 190 985786.972 8.037 + 23 107 84 191 Po -5068.731 7.103 7753.7871 0.0372 B- -8932.6440 17.5997 190 994558.494 7.624 + 21 106 85 191 At -a 3863.913 16.103 7702.9233 0.0843 B- * 191 004148.081 17.287 +0 46 119 73 192 Ta x -23100# 400# 7894# 2# B- 6520# 447# 191 975201# 429# + 44 118 74 192 W x -29620# 200# 7924# 1# B- 1969# 212# 191 968202# 215# + 42 117 75 192 Re x -31588.828 70.794 7930.2389 0.3687 B- 4293.4750 70.8314 191 966088.000 76.000 + 40 116 76 192 Os -35882.303 2.314 7948.5260 0.0121 B- -1046.6722 2.3962 191 961478.765 2.484 + 38 115 77 192 Ir -34835.631 1.314 7938.9999 0.0068 B- 1452.8946 2.2739 191 962602.414 1.410 + 36 114 78 192 Pt -36288.525 2.570 7942.4923 0.0134 B- -3516.3415 15.6174 191 961042.667 2.758 + 34 113 79 192 Au - -32772.184 15.827 7920.1033 0.0824 B- -760.7028 22.1777 191 964817.615 16.991 + 32 112 80 192 Hg x -32011.481 15.537 7912.0666 0.0809 B- -6139.2324 35.2767 191 965634.263 16.679 + 30 111 81 192 Tl x -25872.249 31.671 7876.0167 0.1650 B- -3320.4029 32.1843 191 972225.000 34.000 + 28 110 82 192 Pb -22551.846 5.726 7854.6482 0.0298 B- -9017.3089 30.6518 191 975789.598 6.147 + 26 109 83 192 Bi -a -13534.537 30.112 7803.6084 0.1568 B- -5468.0534 31.9348 191 985470.077 32.326 + 24 108 84 192 Po -a -8066.483 10.634 7771.0542 0.0554 B- -10992.2252 29.8328 191 991340.274 11.416 + 22 107 85 192 At -a 2925.742 27.873 7709.7283 0.1452 B- * 192 003140.912 29.922 +0 47 120 73 193 Ta x -20810# 400# 7883# 2# B- 5380# 447# 192 977660# 429# + 45 119 74 193 W x -26190# 200# 7907# 1# B- 4042# 204# 192 971884# 215# + 43 118 75 193 Re x -30231.641 39.123 7923.9378 0.2027 B- 3162.7597 39.1915 192 967545.000 42.000 + 41 117 76 193 Os -33394.401 2.320 7936.2716 0.0120 B- 1141.9038 2.4000 192 964149.637 2.490 + 39 116 77 193 Ir -34536.305 1.327 7938.1346 0.0069 B- -56.6276 0.2997 192 962923.753 1.425 + 37 115 78 193 Pt -34479.677 1.359 7933.7875 0.0070 B- -1074.8477 8.7676 192 962984.546 1.458 + 35 114 79 193 Au -33404.829 8.674 7924.1648 0.0449 B- -2342.6641 14.3702 192 964138.442 9.311 + 33 113 80 193 Hg -31062.165 15.505 7907.9730 0.0803 B- -3584.9466 16.8938 192 966653.395 16.645 + 31 112 81 193 Tl x -27477.218 6.707 7885.3445 0.0348 B- -5247.9637 12.2808 192 970501.994 7.200 + 29 111 82 193 Pb -22229.255 10.288 7854.0994 0.0533 B- -6344.6913 12.7761 192 976135.914 11.044 + 27 110 83 193 Bi -15884.563 7.576 7817.1718 0.0393 B- -7559.2614 16.3874 192 982947.220 8.132 + 25 109 84 193 Po -a -8325.302 14.531 7773.9510 0.0753 B- -8257.9789 26.0594 192 991062.421 15.599 + 23 108 85 193 At -a -67.323 21.632 7727.1099 0.1121 B- -9110.2435 33.1444 192 999927.725 23.222 + 21 107 86 193 Rn -a 9042.920 25.112 7675.8530 0.1301 B- * 193 009707.973 26.958 +0 48 121 73 194 Ta x -17130# 500# 7865# 3# B- 7280# 583# 193 981610# 537# + 46 120 74 194 W x -24410# 300# 7899# 2# B- 2850# 361# 193 973795# 322# + 44 119 75 194 Re x -27260# 200# 7909# 1# B- 5175# 200# 193 970735# 215# + 42 118 76 194 Os + -32435.176 2.403 7932.0232 0.0124 B- 96.6000 2.0000 193 965179.407 2.579 + 40 117 77 194 Ir -n -32531.776 1.332 7928.4885 0.0069 B- 2228.3252 1.2569 193 965075.703 1.429 + 38 116 78 194 Pt -34760.101 0.496 7935.9420 0.0026 B- -2548.1518 2.1174 193 962683.498 0.532 + 36 115 79 194 Au +3n -32211.950 2.118 7918.7744 0.0109 B- -27.9978 3.5809 193 965419.051 2.273 + 34 114 80 194 Hg x -32183.952 2.888 7914.5974 0.0149 B- -5246.4542 14.2677 193 965449.108 3.100 + 32 113 81 194 Tl x -26937.498 13.972 7883.5211 0.0720 B- -2729.6315 22.3433 193 971081.408 15.000 + 30 112 82 194 Pb -24207.866 17.435 7865.4181 0.0899 B- -8184.8462 18.2094 193 974011.788 18.717 + 28 111 83 194 Bi +a -16023.020 5.252 7819.1955 0.0271 B- -5018.4029 13.9386 193 982798.581 5.638 + 26 110 84 194 Po -a -11004.617 12.911 7789.2947 0.0666 B- -10288.1273 26.8153 193 988186.058 13.860 + 24 109 85 194 At -a -716.490 23.502 7732.2304 0.1211 B- -6441.1134 28.8079 193 999230.816 25.230 + 22 108 86 194 Rn -a 5724.624 16.659 7694.9961 0.0859 B- * 194 006145.636 17.884 +0 47 121 74 195 W x -20740# 300# 7881# 2# B- 4820# 424# 194 977735# 322# + 45 120 75 195 Re x -25560# 300# 7901# 2# B- 3951# 305# 194 972560# 322# + 43 119 76 195 Os x -29511.596 55.890 7917.7449 0.2866 B- 2180.7220 55.9055 194 968318.000 60.000 + 41 118 77 195 Ir -n -31692.318 1.333 7924.9160 0.0068 B- 1101.5601 1.2637 194 965976.898 1.431 + 39 117 78 195 Pt -32793.878 0.503 7926.5530 0.0026 B- -226.8175 0.9998 194 964794.325 0.540 + 37 116 79 195 Au -32567.061 1.119 7921.3778 0.0057 B- -1553.7190 23.1562 194 965037.823 1.201 + 35 115 80 195 Hg -31013.342 23.142 7909.3980 0.1187 B- -2858.0499 25.6707 194 966705.809 24.843 + 33 114 81 195 Tl -28155.292 11.126 7890.7293 0.0571 B- -4417.2524 12.2333 194 969774.052 11.944 + 31 113 82 195 Pb -23738.039 5.088 7864.0647 0.0261 B- -5712.4729 7.3370 194 974516.167 5.461 + 29 112 83 195 Bi -18025.567 5.287 7830.7579 0.0271 B- -6908.9121 8.0284 194 980648.759 5.675 + 27 111 84 195 Po -11116.655 6.042 7791.3155 0.0310 B- -7646.3554 11.3199 194 988065.781 6.486 + 25 110 85 195 At -a -3470.299 9.573 7748.0914 0.0491 B- -8520.5842 52.5650 194 996274.480 10.276 + 23 109 86 195 Rn -a 5050.285 51.686 7700.3841 0.2651 B- * 195 005421.703 55.487 +0 48 122 74 196 W x -18740# 400# 7872# 2# B- 3620# 500# 195 979882# 429# + 46 121 75 196 Re x -22360# 300# 7886# 2# B- 5918# 303# 195 975996# 322# + 44 120 76 196 Os +pp -28277.123 40.055 7912.2301 0.2044 B- 1158.3989 55.4951 195 969643.261 43.000 + 42 119 77 196 Ir + -29435.522 38.414 7914.1487 0.1960 B- 3209.0164 38.4111 195 968399.669 41.239 + 40 118 78 196 Pt -32644.538 0.510 7926.5297 0.0026 B- -1505.8204 2.9605 195 964954.648 0.547 + 38 117 79 196 Au -31138.718 2.962 7914.8553 0.0151 B- 687.2263 3.1176 195 966571.213 3.179 + 36 116 80 196 Hg -31825.944 2.946 7914.3700 0.0150 B- -4329.3455 12.4627 195 965833.445 3.163 + 34 115 81 196 Tl x -27496.598 12.109 7888.2900 0.0618 B- -2148.3639 14.3556 195 970481.189 13.000 + 32 114 82 196 Pb -25348.234 7.710 7873.3374 0.0393 B- -7339.2020 25.6160 195 972787.552 8.277 + 30 113 83 196 Bi x -18009.032 24.428 7831.9009 0.1246 B- -4540.3012 25.0142 195 980666.509 26.224 + 28 112 84 196 Po -13468.731 5.383 7804.7445 0.0275 B- -9555.5564 30.7105 195 985540.722 5.778 + 26 111 85 196 At -a -3913.175 30.235 7752.0001 0.1543 B- -5888.3439 33.3417 195 995799.034 32.458 + 24 110 86 196 Rn -a 1975.169 14.054 7717.9660 0.0717 B- * 196 002120.431 15.087 +0 49 123 74 197 W x -14870# 400# 7853# 2# B- 5480# 500# 196 984036# 429# + 47 122 75 197 Re x -20350# 300# 7877# 2# B- 4729# 361# 196 978153# 322# + 45 121 76 197 Os x -25080# 200# 7897# 1# B- 3185# 201# 196 973076# 215# + 43 120 77 197 Ir +p -28264.123 20.110 7909.0003 0.1021 B- 2155.6519 20.1061 196 969657.217 21.588 + 41 119 78 197 Pt -30419.775 0.536 7915.9714 0.0027 B- 719.9769 0.5022 196 967343.030 0.575 + 39 118 79 197 Au -31139.751 0.542 7915.6548 0.0028 B- -599.5206 3.2022 196 966570.103 0.581 + 37 117 80 197 Hg -30540.231 3.207 7908.6402 0.0163 B- -2186.0092 13.9478 196 967213.715 3.442 + 35 116 81 197 Tl +a -28354.222 13.575 7893.5725 0.0689 B- -3608.8367 14.3969 196 969560.492 14.573 + 33 115 82 197 Pb -24745.385 4.804 7871.2822 0.0244 B- -5058.1894 9.6190 196 973434.737 5.157 + 31 114 83 197 Bi +a -19687.196 8.333 7841.6348 0.0423 B- -6294.1172 12.9103 196 978864.927 8.946 + 29 113 84 197 Po -13393.078 9.861 7805.7136 0.0501 B- -7037.8235 12.6871 196 985621.939 10.585 + 27 112 85 197 At -6355.255 7.983 7766.0174 0.0405 B- -7865.6231 18.0538 196 993177.353 8.570 + 25 111 86 197 Rn -a 1510.368 16.193 7722.1190 0.0822 B- -8743.5996 58.7110 197 001621.446 17.383 + 23 110 87 197 Fr -a 10253.968 56.434 7673.7640 0.2865 B- * 197 011008.086 60.584 +0 48 123 75 198 Re x -16990# 400# 7861# 2# B- 6610# 447# 197 981760# 429# + 46 122 76 198 Os x -23600# 200# 7890# 1# B- 2110# 283# 197 974664# 215# + 44 121 77 198 Ir x -25710# 200# 7897# 1# B- 4194# 200# 197 972399# 215# + 42 120 78 198 Pt -29904.018 2.100 7914.1512 0.0106 B- -323.2251 2.0595 197 967896.718 2.254 + 40 119 79 198 Au -29580.793 0.540 7908.5675 0.0027 B- 1373.5226 0.4905 197 968243.714 0.579 + 38 118 80 198 Hg -30954.315 0.458 7911.5532 0.0023 B- -3425.5625 7.5590 197 966769.177 0.491 + 36 117 81 198 Tl x -27528.753 7.545 7890.3011 0.0381 B- -1461.3103 11.5537 197 970446.669 8.100 + 34 116 82 198 Pb -26067.443 8.750 7878.9695 0.0442 B- -6693.5916 28.9259 197 972015.450 9.393 + 32 115 83 198 Bi -19373.851 27.571 7841.2123 0.1392 B- -3900.5727 32.6152 197 979201.316 29.598 + 30 114 84 198 Po -15473.278 17.424 7817.5611 0.0880 B- -8764.5316 18.1013 197 983388.753 18.705 + 28 113 85 198 At -6708.747 4.904 7769.3446 0.0248 B- -5478.4271 14.2879 197 992797.864 5.265 + 26 112 86 198 Rn -a -1230.320 13.420 7737.7245 0.0678 B- -10808.0177 33.8991 197 998679.197 14.406 + 24 111 87 198 Fr -a 9577.698 31.130 7679.1873 0.1572 B- * 198 010282.081 33.419 +0 49 124 75 199 Re x -14730# 400# 7850# 2# B- 5541# 447# 198 984187# 429# + 47 123 76 199 Os x -20270# 200# 7874# 1# B- 4128# 204# 198 978239# 215# + 45 122 77 199 Ir p-2n -24398.534 41.054 7891.2066 0.2063 B- 2990.1656 41.0030 198 973807.097 44.073 + 43 121 78 199 Pt -n -27388.700 2.159 7902.3011 0.0109 B- 1705.0525 2.1201 198 970597.022 2.317 + 41 120 79 199 Au -29093.752 0.542 7906.9379 0.0027 B- 452.3142 0.6126 198 968766.573 0.581 + 39 119 80 199 Hg -29546.066 0.526 7905.2794 0.0027 B- -1486.6695 27.9498 198 968280.994 0.564 + 37 118 81 199 Tl x -28059.397 27.945 7893.8773 0.1404 B- -2827.6624 28.7653 198 969877.000 30.000 + 35 117 82 199 Pb +a -25231.734 6.821 7875.7366 0.0343 B- -4434.1181 12.6179 198 972912.620 7.322 + 33 116 83 199 Bi -20797.616 10.615 7849.5232 0.0533 B- -5558.7875 11.9224 198 977672.841 11.395 + 31 115 84 199 Po -a -15238.829 5.429 7817.6582 0.0273 B- -6415.4515 7.6464 198 983640.445 5.828 + 29 114 85 199 At -8823.377 5.384 7781.4883 0.0271 B- -7263.5308 9.0686 198 990527.715 5.780 + 27 113 86 199 Rn -a -1559.846 7.297 7741.0568 0.0367 B- -8331.2349 15.5446 198 998325.436 7.833 + 25 112 87 199 Fr -a 6771.388 13.726 7695.2599 0.0690 B- * 199 007269.384 14.734 +0 48 124 76 200 Os x -18550# 300# 7867# 1# B- 3020# 358# 199 980086# 322# + 46 123 77 200 Ir x -21570# 196# 7878# 1# B- 5030# 197# 199 976844# 210# + 44 122 78 200 Pt -nn -26599.178 20.110 7899.1986 0.1006 B- 640.9158 33.4386 199 971444.609 21.588 + 42 121 79 200 Au -27240.094 26.717 7898.4915 0.1336 B- 2263.1737 26.7188 199 970756.558 28.681 + 40 120 80 200 Hg -29503.267 0.530 7905.8956 0.0027 B- -2456.0403 5.7346 199 968326.941 0.568 + 38 119 81 200 Tl - -27047.227 5.759 7889.7037 0.0288 B- -796.3695 11.5360 199 970963.608 6.182 + 36 118 82 200 Pb -26250.858 10.008 7881.8101 0.0500 B- -5880.2841 24.8094 199 971818.546 10.744 + 34 117 83 200 Bi +a -20370.574 22.701 7848.4969 0.1135 B- -3428.8901 23.9327 199 978131.290 24.370 + 32 116 84 200 Po -16941.683 7.579 7827.4407 0.0379 B- -7953.7897 25.6119 199 981812.355 8.136 + 30 115 85 200 At -a -8987.894 24.465 7783.7601 0.1223 B- -4987.4394 25.1411 199 990351.099 26.264 + 28 114 86 200 Rn -a -4000.454 5.792 7754.9111 0.0290 B- -10134.0327 31.0688 199 995705.335 6.217 + 26 113 87 200 Fr -a 6133.578 30.524 7700.3292 0.1526 B- * 200 006584.666 32.769 +0 49 125 76 201 Os x -14840# 300# 7849# 1# B- 5000# 361# 200 984069# 322# + 47 124 77 201 Ir x -19840# 200# 7870# 1# B- 3901# 206# 200 978701# 215# + 45 123 78 201 Pt + -23740.705 50.103 7885.8337 0.2493 B- 2660.0000 50.0000 200 974513.305 53.788 + 43 122 79 201 Au -26400.705 3.218 7895.1752 0.0160 B- 1261.8237 3.1471 200 971657.678 3.455 + 41 121 80 201 Hg -27662.529 0.712 7897.5607 0.0036 B- -481.7508 14.1815 200 970303.054 0.763 + 39 120 81 201 Tl -27180.778 14.185 7891.2717 0.0706 B- -1909.7458 18.5299 200 970820.235 15.228 + 37 119 82 201 Pb -25271.033 13.747 7877.8782 0.0684 B- -3842.0269 18.3637 200 972870.431 14.758 + 35 118 83 201 Bi +a -21429.006 12.177 7854.8713 0.0606 B- -4907.8397 13.1377 200 976995.017 13.072 + 33 117 84 201 Po -16521.166 4.942 7826.5619 0.0246 B- -5731.7247 9.5606 200 982263.799 5.305 + 31 116 85 201 At +a -10789.441 8.184 7794.1536 0.0407 B- -6682.0288 13.0163 200 988417.058 8.786 + 29 115 86 201 Rn -a -4107.413 10.121 7757.0174 0.0504 B- -7695.9856 13.5972 200 995590.511 10.865 + 27 114 87 201 Fr -a 3588.573 9.080 7714.8367 0.0452 B- -8348.2439 22.2391 201 003852.491 9.747 + 25 113 88 201 Ra -a 11936.817 20.301 7669.4108 0.1010 B- * 201 012814.699 21.794 +0 50 126 76 202 Os x -12530# 400# 7839# 2# B- 4110# 500# 201 986548# 429# + 48 125 77 202 Ir x -16640# 300# 7855# 1# B- 6052# 301# 201 982136# 322# + 46 124 78 202 Pt x -22692.128 25.150 7881.5609 0.1245 B- 1660.8540 34.2759 201 975639.000 27.000 + 44 123 79 202 Au x -24352.982 23.287 7885.9100 0.1153 B- 2992.3278 23.2980 201 973856.000 25.000 + 42 122 80 202 Hg -27345.310 0.705 7896.8505 0.0035 B- -1364.8906 1.8348 201 970643.604 0.757 + 40 121 81 202 Tl -25980.419 1.838 7886.2206 0.0091 B- -39.8110 4.1863 201 972108.874 1.972 + 38 120 82 202 Pb -25940.608 3.796 7882.1505 0.0188 B- -5189.7539 14.5070 201 972151.613 4.075 + 36 119 83 202 Bi -20750.854 14.002 7852.5857 0.0693 B- -2809.2850 16.4660 201 977723.042 15.032 + 34 118 84 202 Po -17941.569 8.670 7834.8053 0.0429 B- -7346.4628 28.9311 201 980738.934 9.307 + 32 117 85 202 At -10595.106 27.601 7794.5637 0.1366 B- -4320.5458 32.6924 201 988625.686 29.631 + 30 116 86 202 Rn -a -6274.561 17.520 7769.3018 0.0867 B- -9376.0984 18.5296 201 993263.982 18.808 + 28 115 87 202 Fr -a 3101.538 6.033 7719.0125 0.0299 B- -5973.3620 16.1841 202 003329.637 6.476 + 26 114 88 202 Ra -a 9074.900 15.018 7685.5684 0.0743 B- * 202 009742.305 16.122 +0 51 127 76 203 Os x -7270# 400# 7814# 2# B- 7100# 565# 202 992195# 429# + 49 126 77 203 Ir x -14370# 400# 7845# 2# B- 5140# 447# 202 984573# 429# + 47 125 78 203 Pt x -19510# 200# 7867# 1# B- 3633# 200# 202 979055# 215# + 45 124 79 203 Au -23143.444 3.083 7880.8650 0.0152 B- 2125.7592 3.4514 202 975154.492 3.309 + 43 123 80 203 Hg -25269.203 1.630 7887.4828 0.0080 B- 492.1062 1.2247 202 972872.396 1.750 + 41 122 81 203 Tl -25761.309 1.171 7886.0530 0.0058 B- -974.8265 6.4609 202 972344.098 1.257 + 39 121 82 203 Pb -24786.483 6.554 7877.3970 0.0323 B- -3261.5896 14.3559 202 973390.617 7.036 + 37 120 83 203 Bi +a -21524.893 12.778 7857.4762 0.0629 B- -4214.0744 13.5942 202 976892.077 13.717 + 35 119 84 203 Po -17310.819 4.640 7832.8632 0.0229 B- -5148.2116 11.5921 202 981416.072 4.981 + 33 118 85 203 At -12162.607 10.623 7803.6487 0.0523 B- -5978.5623 12.1098 202 986942.904 11.404 + 31 117 86 203 Rn -a -6184.045 5.815 7770.3437 0.0286 B- -7060.4572 8.5231 202 993361.155 6.242 + 29 116 87 203 Fr 876.412 6.232 7731.7092 0.0307 B- -7724.9182 11.5191 203 000940.867 6.689 + 27 115 88 203 Ra -a 8601.331 9.688 7689.8015 0.0477 B- * 203 009233.907 10.400 +0 50 127 77 204 Ir x -9570# 400# 7823# 2# B- 8050# 447# 203 989726# 429# + 48 126 78 204 Pt x -17620# 200# 7859# 1# B- 2770# 283# 203 981084# 215# + 46 125 79 204 Au + -20390# 200# 7868# 1# B- 4300# 200# 203 978110# 215# + 44 124 80 204 Hg -24690.148 0.498 7885.5455 0.0025 B- -344.0781 1.1876 203 973494.037 0.534 + 42 123 81 204 Tl -24346.070 1.154 7880.0238 0.0057 B- 763.7453 0.1768 203 973863.420 1.238 + 40 122 82 204 Pb -25109.815 1.147 7879.9326 0.0056 B- -4463.8883 9.2480 203 973043.506 1.231 + 38 121 83 204 Bi +a -20645.927 9.180 7854.2157 0.0450 B- -2304.8814 13.6253 203 977835.687 9.854 + 36 120 84 204 Po -18341.045 10.071 7839.0823 0.0494 B- -6465.7939 24.8047 203 980310.078 10.811 + 34 119 85 204 At -11875.252 22.668 7803.5522 0.1111 B- -3905.1360 23.8592 203 987251.393 24.335 + 32 118 86 204 Rn -7970.115 7.444 7780.5743 0.0365 B- -8577.4239 25.6840 203 991443.729 7.991 + 30 117 87 204 Fr -a 607.308 24.581 7734.6931 0.1205 B- -5453.7889 26.1514 204 000651.972 26.389 + 28 116 88 204 Ra -a 6061.097 8.924 7704.1238 0.0437 B- * 204 006506.855 9.580 +0 51 128 77 205 Ir x -5600# 500# 7805# 2# B- 7220# 583# 204 993988# 537# + 49 127 78 205 Pt x -12820# 300# 7836# 1# B- 5750# 361# 204 986237# 322# + 47 126 79 205 Au x -18570# 200# 7860# 1# B- 3717# 200# 204 980064# 215# + 45 125 80 205 Hg -22287.719 3.655 7874.7325 0.0178 B- 1533.0836 3.7238 204 976073.151 3.923 + 43 124 81 205 Tl -23820.802 1.239 7878.3946 0.0060 B- -50.6402 0.5033 204 974427.318 1.330 + 41 123 82 205 Pb -23770.162 1.145 7874.3313 0.0056 B- -2704.5927 4.8196 204 974481.682 1.228 + 39 122 83 205 Bi -21065.569 4.808 7857.3218 0.0235 B- -3544.1710 11.1458 204 977385.182 5.161 + 37 121 84 205 Po -17521.398 10.059 7836.2168 0.0491 B- -4536.8793 15.6996 204 981190.006 10.798 + 35 120 85 205 At +a -12984.519 12.055 7810.2694 0.0588 B- -5274.7547 13.0777 204 986060.546 12.941 + 33 119 86 205 Rn -7709.764 5.080 7780.7226 0.0248 B- -6399.9479 9.3288 204 991723.228 5.453 + 31 118 87 205 Fr x -1309.816 7.824 7745.6870 0.0382 B- -7113.6693 24.0784 204 998593.854 8.399 + 29 117 88 205 Ra -a 5803.853 22.772 7707.1698 0.1111 B- -8302.8357 63.5402 205 006230.692 24.446 + 27 116 89 205 Ac -a 14106.689 59.320 7662.8519 0.2894 B- * 205 015144.152 63.682 +0 50 128 78 206 Pt x -9240# 300# 7820# 1# B- 4950# 424# 205 990080# 322# + 48 127 79 206 Au x -14190# 300# 7840# 1# B- 6755# 301# 205 984766# 322# + 46 126 80 206 Hg +a -20945.728 20.441 7869.1723 0.0992 B- 1307.5659 20.4100 205 977513.837 21.943 + 44 125 81 206 Tl -22253.293 1.286 7871.7219 0.0062 B- 1532.2128 0.6117 205 976110.108 1.380 + 42 124 82 206 Pb -23785.506 1.144 7875.3620 0.0056 B- -3757.3057 7.5461 205 974465.210 1.228 + 40 123 83 206 Bi - -20028.201 7.632 7853.3249 0.0371 B- -1839.5323 8.6005 205 978498.843 8.193 + 38 122 84 206 Po -a -18188.668 4.012 7840.5973 0.0195 B- -5749.2803 14.1099 205 980473.662 4.306 + 36 121 85 206 At -12439.388 13.529 7808.8904 0.0657 B- -3306.4697 16.0227 205 986645.768 14.523 + 34 120 86 206 Rn -9132.918 8.591 7789.0417 0.0417 B- -7886.0592 29.1075 205 990195.409 9.223 + 32 119 87 206 Fr -1246.859 27.811 7746.9621 0.1350 B- -4812.4721 33.1318 205 998661.441 29.856 + 30 118 88 206 Ra -a 3565.613 18.008 7719.8028 0.0874 B- -9919.1406 67.5328 206 003827.842 19.332 + 28 117 89 206 Ac -a 13484.754 65.088 7667.8538 0.3160 B- * 206 014476.477 69.874 +0 51 129 78 207 Pt x -4140# 400# 7797# 2# B- 6501# 500# 206 995556# 429# + 49 128 79 207 Au x -10640# 300# 7824# 1# B- 5847# 301# 206 988577# 322# + 47 127 80 207 Hg x -16487.446 29.808 7848.6112 0.1440 B- 4546.9906 30.3000 206 982300.000 32.000 + 45 126 81 207 Tl -21034.436 5.439 7866.7979 0.0263 B- 1417.5323 5.4024 206 977418.605 5.839 + 43 125 82 207 Pb -22451.968 1.147 7869.8664 0.0055 B- -2397.4140 2.1175 206 975896.821 1.231 + 41 124 83 207 Bi -20054.554 2.397 7854.5053 0.0116 B- -2908.8541 6.6140 206 978470.551 2.573 + 39 123 84 207 Po -17145.700 6.659 7836.6734 0.0322 B- -3918.2186 14.0754 206 981593.334 7.148 + 37 122 85 207 At +a -13227.482 12.406 7813.9653 0.0599 B- -4592.7400 13.2815 206 985799.715 13.318 + 35 121 86 207 Rn -8634.742 4.742 7787.9987 0.0229 B- -5785.7211 18.1857 206 990730.224 5.090 + 33 120 87 207 Fr -2849.021 17.557 7756.2689 0.0848 B- -6363.0084 60.8726 206 996941.450 18.847 + 31 119 88 207 Ra -a 3513.988 58.286 7721.7503 0.2816 B- -7632.2404 81.0004 207 003772.420 62.572 + 29 118 89 207 Ac -a 11146.228 56.248 7681.1001 0.2717 B- * 207 011965.967 60.384 +0 52 130 78 208 Pt x -500# 400# 7780# 2# B- 5410# 500# 207 999463# 429# + 50 129 79 208 Au x -5910# 300# 7803# 1# B- 7355# 302# 207 993655# 322# + 48 128 80 208 Hg x -13265.408 30.739 7834.1914 0.1478 B- 3484.7131 30.7951 207 985759.000 33.000 + 46 127 81 208 Tl +a -16750.121 1.854 7847.1835 0.0089 B- 4998.3984 1.6693 207 982018.006 1.989 + 44 126 82 208 Pb -21748.519 1.148 7867.4530 0.0055 B- -2878.3680 2.0127 207 976652.005 1.232 + 42 125 83 208 Bi +n -18870.151 2.305 7849.8534 0.0111 B- -1400.9438 2.3787 207 979742.060 2.474 + 40 124 84 208 Po -17469.207 1.672 7839.3568 0.0080 B- -4999.3061 9.0736 207 981246.035 1.795 + 38 123 85 208 At +a -12469.901 8.921 7811.5604 0.0429 B- -2814.5118 13.5215 207 986613.011 9.577 + 36 122 86 208 Rn -9655.389 10.163 7794.2678 0.0489 B- -6990.4614 15.4656 207 989634.513 10.910 + 34 121 87 208 Fr -2664.928 11.657 7756.8985 0.0560 B- -4392.8615 14.7413 207 997139.082 12.514 + 32 120 88 208 Ra -a 1727.934 9.023 7732.0177 0.0434 B- -9032.9208 65.1111 208 001855.012 9.686 + 30 119 89 208 Ac -a 10760.854 64.483 7684.8289 0.3100 B- -5927.1868 71.9264 208 011552.251 69.225 + 28 118 90 208 Th -a 16688.041 31.865 7652.5716 0.1532 B- * 208 017915.348 34.208 +0 51 130 79 209 Au x -2230# 400# 7786# 2# B- 6380# 427# 208 997606# 429# + 49 129 80 209 Hg x -8610# 150# 7813# 1# B- 5035# 150# 208 990757# 161# + 47 128 81 209 Tl +a -13644.793 6.110 7833.3979 0.0292 B- 3969.7809 6.2115 208 985351.713 6.559 + 45 127 82 209 Pb -17614.574 1.747 7848.6488 0.0084 B- 644.0152 1.1462 208 981089.978 1.875 + 43 126 83 209 Bi -18258.589 1.365 7847.9869 0.0065 B- -1892.5741 1.5635 208 980398.599 1.465 + 41 125 84 209 Po -a -16366.015 1.778 7835.1882 0.0085 B- -3482.2417 4.9599 208 982430.361 1.909 + 39 124 85 209 At -12883.773 4.745 7814.7835 0.0227 B- -3942.7237 11.0298 208 986168.701 5.094 + 37 123 86 209 Rn -8941.049 9.960 7792.1755 0.0477 B- -5158.9051 15.2153 208 990401.389 10.692 + 35 122 87 209 Fr -3782.144 11.503 7763.7485 0.0550 B- -5640.3845 12.8549 208 995939.701 12.349 + 33 121 88 209 Ra -a 1858.240 5.747 7733.0177 0.0275 B- -6986.6464 56.1409 209 001994.902 6.169 + 31 120 89 209 Ac -a 8844.887 55.846 7695.8455 0.2672 B- -7550# 117# 209 009495.375 59.953 + 29 119 90 209 Th IT 16395# 103# 7656# 0# B- * 209 017601# 111# +0 52 131 79 210 Au x 2680# 400# 7764# 2# B- 7980# 447# 210 002877# 429# + 50 130 80 210 Hg x -5300# 200# 7799# 1# B- 3947# 201# 209 994310# 215# + 48 129 81 210 Tl +a -9246.996 11.603 7813.5890 0.0553 B- 5481.4334 11.5610 209 990072.942 12.456 + 46 128 82 210 Pb -14728.429 1.448 7835.9656 0.0069 B- 63.4758 0.4992 209 984188.381 1.554 + 44 127 83 210 Bi -14791.905 1.364 7832.5424 0.0065 B- 1161.1549 0.7662 209 984120.237 1.463 + 42 126 84 210 Po -15953.060 1.146 7834.3462 0.0055 B- -3980.9605 7.6101 209 982873.686 1.230 + 40 125 85 210 At -a -11972.099 7.695 7811.6638 0.0366 B- -2367.3352 8.9225 209 987147.423 8.261 + 38 124 86 210 Rn -a -9604.764 4.557 7796.6653 0.0217 B- -6261.2558 14.1720 209 989688.862 4.892 + 36 123 87 210 Fr -3343.508 13.420 7763.1243 0.0639 B- -3786.3467 16.2633 209 996410.596 14.407 + 34 122 88 210 Ra -a 442.839 9.193 7741.3687 0.0438 B- -8321.2403 62.8832 210 000475.406 9.868 + 32 121 89 210 Ac 8764.079 62.208 7698.0182 0.2962 B- -5295.4420 65.0180 210 009408.625 66.782 + 30 120 90 210 Th -a 14059.521 18.909 7669.0764 0.0900 B- * 210 015093.515 20.299 +0 51 131 80 211 Hg x -390# 200# 7777# 1# B- 5688# 205# 210 999581# 215# + 49 130 81 211 Tl x -6077.999 41.917 7799.7915 0.1987 B- 4415.0129 41.9781 210 993475.000 45.000 + 47 129 82 211 Pb -10493.012 2.260 7817.0079 0.0107 B- 1366.1041 5.4713 210 988735.288 2.426 + 45 128 83 211 Bi -11859.116 5.442 7819.7745 0.0258 B- 573.3763 5.4297 210 987268.715 5.842 + 43 127 84 211 Po -a -12432.492 1.255 7818.7842 0.0060 B- -785.3012 2.5385 210 986653.171 1.347 + 41 126 85 211 At -a -11647.191 2.729 7811.3545 0.0129 B- -2891.8615 6.8937 210 987496.226 2.929 + 39 125 86 211 Rn -a -8755.330 6.813 7793.9412 0.0323 B- -4615.0152 13.7862 210 990600.767 7.314 + 37 124 87 211 Fr -4140.314 11.991 7768.3613 0.0568 B- -4972.1844 12.9786 210 995555.189 12.872 + 35 123 88 211 Ra 831.870 4.966 7741.0887 0.0235 B- -6311.6152 53.9818 211 000893.049 5.331 + 33 122 89 211 Ac 7143.485 53.753 7707.4680 0.2548 B- -6732.9111 101.4758 211 007668.846 57.706 + 31 121 90 211 Th -a 13876.396 86.070 7671.8506 0.4079 B- -8175.8296 110.6091 211 014896.923 92.399 + 29 120 91 211 Pa -a 22052.226 69.472 7629.3948 0.3293 B- * 211 023674.036 74.581 +0 52 132 80 212 Hg x 3020# 300# 7762# 1# B- 4571# 361# 212 003242# 322# + 50 131 81 212 Tl +a -1551# 200# 7780# 1# B- 5998# 200# 211 998335# 215# + 48 130 82 212 Pb -7548.929 1.840 7804.3203 0.0087 B- 569.0133 1.8246 211 991895.891 1.975 + 46 129 83 212 Bi -8117.943 1.853 7803.3140 0.0087 B- 2251.4656 1.6671 211 991285.030 1.989 + 44 128 84 212 Po -10369.408 1.153 7810.2438 0.0054 B- -1741.2596 2.1066 211 988867.982 1.237 + 42 127 85 212 At -a -8628.149 2.385 7798.3400 0.0113 B- 31.0705 3.5927 211 990737.301 2.559 + 40 126 86 212 Rn -a -8659.219 3.110 7794.7963 0.0147 B- -5143.2210 9.3064 211 990703.946 3.338 + 38 125 87 212 Fr -3515.998 8.775 7766.8455 0.0414 B- -3317.2355 13.4939 211 996225.420 9.419 + 36 124 88 212 Ra -198.763 10.254 7747.5078 0.0484 B- -7498.3626 24.1666 211 999786.619 11.007 + 34 123 89 212 Ac 7299.600 21.883 7708.4479 0.1032 B- -4811.2864 24.1055 212 007836.442 23.492 + 32 122 90 212 Th -a 12110.886 10.109 7682.0628 0.0477 B- -9485.6366 88.1858 212 013001.570 10.852 + 30 121 91 212 Pa -a 21596.523 87.604 7633.6289 0.4132 B- * 212 023184.819 94.047 +0 53 133 80 213 Hg x 8200# 300# 7739# 1# B- 6416# 301# 213 008803# 322# + 51 132 81 213 Tl x 1783.811 27.013 7765.4311 0.1268 B- 4987.4088 27.8941 213 001915.000 29.000 + 49 131 82 213 Pb +a -3203.598 6.954 7785.1732 0.0326 B- 2028.0730 8.3708 212 996560.796 7.465 + 47 130 83 213 Bi -5231.671 5.082 7791.0217 0.0239 B- 1421.8481 5.4898 212 994383.570 5.455 + 45 129 84 213 Po -6653.519 3.053 7794.0240 0.0143 B- -73.9972 5.4646 212 992857.154 3.277 + 43 128 85 213 At -a -6579.522 4.898 7790.0036 0.0230 B- -883.5727 5.7243 212 992936.593 5.258 + 41 127 86 213 Rn -a -5695.949 3.370 7782.1824 0.0158 B- -2141.7493 5.6996 212 993885.147 3.618 + 39 126 87 213 Fr -3554.199 4.707 7768.4543 0.0221 B- -3899.7568 10.8862 212 996184.410 5.053 + 37 125 88 213 Ra 345.557 9.818 7746.4726 0.0461 B- -5795.4721 15.2463 213 000370.971 10.540 + 35 124 89 213 Ac 6141.029 11.665 7715.5908 0.0548 B- -5979.0781 14.8635 213 006592.665 12.522 + 33 123 90 213 Th -a 12120.108 9.217 7683.8470 0.0433 B- -7534.0866 57.9078 213 013011.470 9.895 + 31 122 91 213 Pa -a 19654.194 57.170 7644.8027 0.2684 B- * 213 021099.644 61.374 +0 54 134 80 214 Hg x 11770# 400# 7724# 2# B- 5306# 445# 214 012636# 429# + 52 133 81 214 Tl x 6465# 196# 7745# 1# B- 6648# 196# 214 006940# 210# + 50 132 82 214 Pb -183.019 1.969 7772.3955 0.0092 B- 1017.7611 11.2559 213 999803.521 2.114 + 48 131 83 214 Bi -1200.780 11.209 7773.4955 0.0524 B- 3269.1925 11.1649 213 998710.909 12.033 + 46 130 84 214 Po -4469.972 1.449 7785.1163 0.0068 B- -1090.8208 3.7750 213 995201.287 1.556 + 44 129 85 214 At -3379.151 3.982 7776.3632 0.0186 B- 940.5125 9.8827 213 996372.331 4.274 + 42 128 86 214 Rn -a -4319.664 9.187 7777.1023 0.0429 B- -3361.3369 12.4238 213 995362.650 9.862 + 40 127 87 214 Fr -a -958.327 8.519 7757.7393 0.0398 B- -1051.0675 9.9879 213 998971.193 9.145 + 38 126 88 214 Ra -a 92.740 5.250 7749.1719 0.0245 B- -6340.5313 14.5317 214 000099.560 5.636 + 36 125 89 214 Ac 6433.272 13.551 7715.8874 0.0633 B- -4261.6599 17.2389 214 006906.400 14.547 + 34 124 90 214 Th -a 10694.932 10.661 7692.3173 0.0498 B- -8764.9630 81.9051 214 011481.480 11.445 + 32 123 91 214 Pa -a 19459.895 81.208 7647.7037 0.3795 B- * 214 020891.055 87.180 +0 55 135 80 215 Hg x 17110# 400# 7701# 2# B- 7079# 500# 215 018368# 429# + 53 134 81 215 Tl x 10030# 300# 7730# 1# B- 5688# 305# 215 010768# 322# + 51 133 82 215 Pb +a 4342.245 52.685 7752.7381 0.2450 B- 2712.9729 52.9848 215 004661.591 56.560 + 49 132 83 215 Bi 1629.272 5.624 7761.7177 0.0262 B- 2171.0426 5.5297 215 001749.095 6.037 + 47 131 84 215 Po -541.771 2.120 7768.1768 0.0099 B- 714.8128 6.6491 214 999418.385 2.276 + 45 130 85 215 At -a -1256.583 6.629 7767.8627 0.0308 B- -87.5935 8.9062 214 998651.002 7.116 + 43 129 86 215 Rn -a -1168.990 6.090 7763.8164 0.0283 B- -1487.1274 9.1890 214 998745.037 6.538 + 41 128 87 215 Fr -a 318.137 7.066 7753.2607 0.0329 B- -2213.8573 9.7691 215 000341.534 7.585 + 39 127 88 215 Ra -a 2531.995 7.201 7739.3249 0.0335 B- -3498.5554 14.3395 215 002718.208 7.730 + 37 126 89 215 Ac -a 6030.550 12.406 7719.4137 0.0577 B- -4890.8833 13.9296 215 006474.061 13.318 + 35 125 90 215 Th -a 10921.434 6.335 7693.0266 0.0295 B- -6883.1037 82.6932 215 011724.640 6.800 + 33 124 91 215 Pa -a 17804.537 82.450 7657.3733 0.3835 B- -7084.7747 132.8246 215 019113.955 88.513 + 31 123 92 215 U -a 24889.312 104.136 7620.7821 0.4844 B- * 215 026719.774 111.794 +0 56 136 80 216 Hg x 20920# 400# 7685# 2# B- 6050# 500# 216 022459# 429# + 54 135 81 216 Tl x 14870# 300# 7709# 1# B- 7361# 361# 216 015964# 322# + 52 134 82 216 Pb x 7510# 200# 7740# 1# B- 1636# 201# 216 008062# 215# + 50 133 83 216 Bi x 5873.988 11.178 7743.4996 0.0518 B- 4091.6520 11.3243 216 006305.985 12.000 + 48 132 84 216 Po 1782.336 1.815 7758.8205 0.0084 B- -474.3423 3.5713 216 001913.416 1.948 + 46 131 85 216 At -a 2256.678 3.575 7753.0024 0.0166 B- 2003.3657 6.6383 216 002422.643 3.837 + 44 130 86 216 Rn -a 253.312 5.768 7758.6553 0.0267 B- -2717.7096 6.9366 216 000271.942 6.192 + 42 129 87 216 Fr -a 2971.022 4.174 7742.4513 0.0193 B- -320.4441 8.8904 216 003189.523 4.480 + 40 128 88 216 Ra -a 3291.466 8.004 7737.3458 0.0371 B- -4858.2701 12.2147 216 003533.534 8.592 + 38 127 89 216 Ac 8149.736 9.230 7711.2319 0.0427 B- -2148.8006 14.4375 216 008749.101 9.908 + 36 126 90 216 Th -a 10298.537 11.104 7697.6617 0.0514 B- -7525.2616 27.0327 216 011055.933 11.920 + 34 125 91 216 Pa -a 17823.799 24.647 7659.2006 0.1141 B- -5242.6308 37.3721 216 019134.633 26.459 + 32 124 92 216 U -a 23066.429 28.093 7631.3072 0.1301 B- * 216 024762.829 30.158 +0 55 136 81 217 Tl x 18660# 400# 7693# 2# B- 6399# 500# 217 020032# 429# + 53 135 82 217 Pb x 12260# 300# 7719# 1# B- 3530# 300# 217 013162# 322# + 51 134 83 217 Bi x 8729.963 17.698 7731.8491 0.0816 B- 2846.5103 18.8695 217 009372.000 19.000 + 49 133 84 217 Po +a 5883.452 6.544 7741.3614 0.0302 B- 1488.8543 7.9791 217 006316.145 7.025 + 47 132 85 217 At 4394.598 5.001 7744.6172 0.0230 B- 736.0320 6.1505 217 004717.794 5.368 + 45 131 86 217 Rn -a 3658.566 4.198 7744.4037 0.0193 B- -656.0967 7.5383 217 003927.632 4.506 + 43 130 87 217 Fr -a 4314.663 6.531 7737.7750 0.0301 B- -1574.8729 9.4723 217 004631.980 7.011 + 41 129 88 217 Ra -a 5889.536 7.047 7726.9122 0.0325 B- -2812.7853 13.2129 217 006322.676 7.564 + 39 128 89 217 Ac -a 8702.321 11.223 7710.3448 0.0517 B- -3503.4590 15.4454 217 009342.325 12.048 + 37 127 90 217 Th -a 12205.780 10.614 7690.5945 0.0489 B- -4848.9680 16.3966 217 013103.443 11.394 + 35 126 91 217 Pa -a 17054.748 12.498 7664.6438 0.0576 B- -5916# 81# 217 018309.024 13.417 + 33 125 92 217 U -a 22971# 81# 7634# 0# B- * 217 024660# 86# +0 56 137 81 218 Tl x 23710# 400# 7672# 2# B- 8081# 500# 218 025454# 429# + 54 136 82 218 Pb x 15630# 300# 7705# 1# B- 2414# 301# 218 016779# 322# + 52 135 83 218 Bi x 13216.038 27.013 7712.8280 0.1239 B- 4859.3866 27.0849 218 014188.000 29.000 + 50 134 84 218 Po 8356.652 1.967 7731.5300 0.0090 B- 256.4334 11.5490 218 008971.234 2.112 + 48 133 85 218 At -a 8100.218 11.503 7729.1175 0.0528 B- 2882.8048 11.6054 218 008695.941 12.349 + 46 132 86 218 Rn 5217.413 2.316 7738.7527 0.0106 B- -1842.0267 4.4418 218 005601.123 2.486 + 44 131 87 218 Fr -a 7059.440 4.235 7726.7143 0.0194 B- 413.8838 10.5603 218 007578.620 4.546 + 42 130 88 218 Ra -a 6645.556 9.807 7725.0241 0.0450 B- -4205.2887 58.4224 218 007134.297 10.528 + 40 129 89 218 Ac -a 10850.845 57.616 7702.1450 0.2643 B- -1515.9019 58.5648 218 011648.860 61.853 + 38 128 90 218 Th -a 12366.747 10.516 7691.6026 0.0482 B- -6282.8212 20.7132 218 013276.248 11.289 + 36 127 91 218 Pa -a 18649.568 17.846 7659.1935 0.0819 B- -3245.0869 22.5042 218 020021.133 19.158 + 34 126 92 218 U -a 21894.655 13.714 7640.7191 0.0629 B- * 218 023504.877 14.722 +0 55 137 82 219 Pb x 20620# 400# 7684# 2# B- 4300# 447# 219 022136# 429# + 53 136 83 219 Bi x 16320# 200# 7700# 1# B- 3638# 201# 219 017520# 215# + 51 135 84 219 Po x 12681.361 15.835 7713.3340 0.0723 B- 2285.3395 16.1628 219 013614.000 17.000 + 49 134 85 219 At 10396.021 3.237 7720.1970 0.0148 B- 1566.6838 2.9473 219 011160.587 3.474 + 47 133 86 219 Rn 8829.337 2.100 7723.7784 0.0096 B- 212.3984 6.8938 219 009478.683 2.254 + 45 132 87 219 Fr -a 8616.939 6.874 7721.1759 0.0314 B- -776.9137 9.5906 219 009250.664 7.380 + 43 131 88 219 Ra -a 9393.853 6.814 7714.0560 0.0311 B- -2175.7005 51.9016 219 010084.715 7.315 + 41 130 89 219 Ac -a 11569.553 51.477 7700.5489 0.2351 B- -2893.2268 76.3627 219 012420.425 55.263 + 39 129 90 219 Th -a 14462.780 56.460 7683.7655 0.2578 B- -4120.4434 89.7010 219 015526.432 60.611 + 37 128 91 219 Pa -a 18583.223 69.705 7661.3783 0.3183 B- -4712.7298 70.9693 219 019949.909 74.831 + 35 127 92 219 U -a 23295.953 13.338 7636.2867 0.0609 B- -6140.9976 92.9309 219 025009.233 14.319 + 33 126 93 219 Np -a 29436.951 91.969 7604.6732 0.4199 B- * 219 031601.865 98.732 +0 56 138 82 220 Pb x 24130# 400# 7670# 2# B- 3171# 500# 220 025905# 429# + 54 137 83 220 Bi x 20960# 300# 7681# 1# B- 5696# 300# 220 022501# 322# + 52 136 84 220 Po x 15263.462 17.698 7703.2244 0.0804 B- 887.7139 22.5491 220 016386.000 19.000 + 50 135 85 220 At x 14375.748 13.972 7703.7033 0.0635 B- 3763.7550 14.0896 220 015433.000 15.000 + 48 134 86 220 Rn 10611.994 1.814 7717.2552 0.0082 B- -870.3384 4.0256 220 011392.443 1.947 + 46 133 87 220 Fr -a 11482.332 4.028 7709.7430 0.0183 B- 1210.2406 8.4809 220 012326.789 4.324 + 44 132 88 220 Ra -a 10272.091 7.595 7711.6879 0.0345 B- -3471.6640 9.6266 220 011027.542 8.153 + 42 131 89 220 Ac -a 13743.755 6.129 7692.3515 0.0279 B- -945.7825 14.9144 220 014754.527 6.579 + 40 130 90 220 Th -a 14689.538 13.687 7684.4964 0.0622 B- -5588.8595 20.0508 220 015769.866 14.693 + 38 129 91 220 Pa -a 20278.397 14.655 7655.5364 0.0666 B- -2735# 102# 220 021769.753 15.732 + 36 128 92 220 U -a 23013# 101# 7640# 0# B- -7462# 105# 220 024706# 108# + 34 127 93 220 Np -a 30475.022 30.718 7602.0758 0.1396 B- * 220 032716.280 32.977 +0 55 138 83 221 Bi x 24200# 300# 7668# 1# B- 4426# 301# 221 025980# 322# + 53 137 84 221 Po x 19773.757 19.561 7684.4814 0.0885 B- 2991.0276 24.0390 221 021228.000 21.000 + 51 136 85 221 At x 16782.729 13.972 7694.4754 0.0632 B- 2311.3750 15.0957 221 018017.000 15.000 + 49 135 86 221 Rn +a 14471.354 5.714 7701.3941 0.0259 B- 1194.1032 7.2312 221 015535.637 6.134 + 47 134 87 221 Fr 13277.251 4.886 7703.2572 0.0221 B- 313.3741 6.3858 221 014253.714 5.245 + 45 133 88 221 Ra -a 12963.877 4.630 7701.1352 0.0210 B- -1567.1715 57.0591 221 013917.293 4.970 + 43 132 89 221 Ac -a 14531.048 56.901 7690.5039 0.2575 B- -2408.8773 57.4376 221 015599.721 61.086 + 41 131 90 221 Th -a 16939.926 7.994 7676.0640 0.0362 B- -3435.0112 59.9069 221 018185.757 8.582 + 39 130 91 221 Pa -a 20374.937 59.380 7656.9809 0.2687 B- -4145.0590 93.4311 221 021873.393 63.746 + 37 129 92 221 U -a 24519.996 72.135 7634.6849 0.3264 B- -5390# 213# 221 026323.297 77.440 + 35 128 93 221 Np x 29910# 200# 7607# 1# B- -6019# 361# 221 032110# 215# + 33 127 94 221 Pu x 35930# 300# 7576# 1# B- * 221 038572# 322# +0 56 139 83 222 Bi x 28950# 300# 7648# 1# B- 6464# 303# 222 031079# 322# + 54 138 84 222 Po x 22486.268 40.054 7674.0054 0.1804 B- 1533.2393 43.0709 222 024140.000 43.000 + 52 137 85 222 At x 20953.028 15.835 7677.3878 0.0713 B- 4581.0714 15.9542 222 022494.000 17.000 + 50 136 86 222 Rn 16371.957 1.944 7694.4991 0.0088 B- -6.1461 7.7013 222 017576.017 2.086 + 48 135 87 222 Fr x 16378.103 7.452 7690.9474 0.0336 B- 2057.8980 8.6816 222 017582.615 8.000 + 46 134 88 222 Ra 14320.205 4.454 7696.6931 0.0201 B- -2301.5922 6.2737 222 015373.371 4.781 + 44 133 89 222 Ac -a 16621.797 4.699 7682.8015 0.0212 B- -581.2415 11.1289 222 017844.232 5.044 + 42 132 90 222 Th -a 17203.039 10.216 7676.6592 0.0460 B- -4861.3220 87.1915 222 018468.220 10.966 + 40 131 91 222 Pa -a 22064.361 86.606 7651.2373 0.3901 B- -2208.4729 101.0129 222 023687.064 92.975 + 38 130 92 222 U -a 24272.834 51.994 7637.7651 0.2342 B- -7001.8072 64.4300 222 026057.957 55.817 + 36 129 93 222 Np -a 31274.641 38.051 7602.7013 0.1714 B- -3785# 302# 222 033574.706 40.849 + 34 128 94 222 Pu x 35060# 300# 7582# 1# B- * 222 037638# 322# +0 57 140 83 223 Bi x 32240# 400# 7636# 2# B- 5161# 445# 223 034611# 429# + 55 139 84 223 Po x 27079# 196# 7655# 1# B- 3651# 196# 223 029070# 210# + 53 138 85 223 At x 23428.008 13.972 7668.0557 0.0627 B- 3038.2698 16.0129 223 025151.000 15.000 + 51 137 86 223 Rn 20389.738 7.822 7678.1720 0.0351 B- 2007.4091 8.0568 223 021889.283 8.397 + 49 136 87 223 Fr 18382.329 1.931 7683.6655 0.0087 B- 1149.0844 0.8476 223 019734.241 2.073 + 47 135 88 223 Ra 17233.245 2.090 7685.3101 0.0094 B- -591.8099 6.9657 223 018500.648 2.243 + 45 134 89 223 Ac -a 17825.055 6.947 7679.1479 0.0312 B- -1560.3471 10.4712 223 019135.982 7.457 + 43 133 90 223 Th -a 19385.402 7.943 7668.6426 0.0356 B- -2952.2124 76.0305 223 020811.083 8.527 + 41 132 91 223 Pa -a 22337.614 75.632 7651.8957 0.3392 B- -3707.6637 95.9225 223 023980.414 81.193 + 39 131 92 223 U -a 26045.278 59.054 7631.7611 0.2648 B- -4613.3046 101.7520 223 027960.754 63.396 + 37 130 93 223 Np -a 30658.583 82.863 7607.5654 0.3716 B- -5462# 311# 223 032913.340 88.956 + 35 129 94 223 Pu x 36121# 300# 7580# 1# B- -6579# 424# 223 038777# 322# + 33 128 95 223 Am x 42700# 300# 7547# 1# B- * 223 045840# 322# +0 58 141 83 224 Bi x 37070# 400# 7616# 2# B- 7159# 445# 224 039796# 429# + 56 140 84 224 Po x 29910# 196# 7644# 1# B- 2199# 197# 224 032110# 210# + 54 139 85 224 At x 27711.018 22.356 7650.7354 0.0998 B- 5265.9197 24.4153 224 029749.000 24.000 + 52 138 86 224 Rn 22445.098 9.814 7670.7514 0.0438 B- 696.4840 14.8750 224 024095.803 10.536 + 50 137 87 224 Fr x 21748.614 11.178 7670.3680 0.0499 B- 2922.7819 11.3237 224 023348.096 12.000 + 48 136 88 224 Ra 18825.832 1.811 7679.9236 0.0081 B- -1408.3152 4.0869 224 020210.361 1.944 + 46 135 89 224 Ac -a 20234.148 4.089 7670.1438 0.0183 B- 238.5672 10.3428 224 021722.249 4.389 + 44 134 90 224 Th -a 19995.581 9.604 7667.7162 0.0429 B- -3866.7705 12.1339 224 021466.137 10.310 + 42 133 91 224 Pa -a 23862.351 7.587 7646.9612 0.0339 B- -1880.3393 16.9711 224 025617.286 8.145 + 40 132 92 224 U -a 25742.690 15.261 7635.0742 0.0681 B- -6289.5572 32.7036 224 027635.913 16.383 + 38 131 93 224 Np 32032.248 28.925 7603.5032 0.1291 B- -3248# 301# 224 034388.030 31.052 + 36 130 94 224 Pu x 35280# 300# 7586# 1# B- -7980# 500# 224 037875# 322# + 34 129 95 224 Am x 43260# 400# 7546# 2# B- * 224 046442# 429# +0 57 141 84 225 Po x 34580# 300# 7626# 1# B- 4280# 424# 225 037123# 322# + 55 140 85 225 At x 30300# 300# 7641# 1# B- 3765# 300# 225 032528# 322# + 53 139 86 225 Rn 26534.143 11.140 7654.3581 0.0495 B- 2713.5412 16.3492 225 028485.572 11.958 + 51 138 87 225 Fr 23820.602 11.967 7662.9412 0.0532 B- 1827.5584 12.1574 225 025572.466 12.847 + 49 137 88 225 Ra 21993.044 2.596 7667.5866 0.0115 B- 355.7386 5.0067 225 023610.502 2.786 + 47 136 89 225 Ac 21637.305 4.758 7665.6906 0.0211 B- -672.8878 6.6576 225 023228.601 5.107 + 45 135 90 225 Th -a 22310.193 5.093 7659.2229 0.0226 B- -2046.4473 82.0038 225 023950.975 5.467 + 43 134 91 225 Pa -a 24356.640 81.867 7646.6504 0.3639 B- -3015.3610 82.4514 225 026147.927 87.887 + 41 133 92 225 U -a 27372.001 9.934 7629.7717 0.0442 B- -4246.0969 92.1491 225 029385.050 10.664 + 39 132 93 225 Np -a 31618.098 91.618 7607.4231 0.4072 B- -4682# 314# 225 033943.422 98.355 + 37 131 94 225 Pu x 36300# 300# 7583# 1# B- -6090# 500# 225 038970# 322# + 35 130 95 225 Am x 42390# 400# 7553# 2# B- * 225 045508# 429# +0 58 142 84 226 Po x 37549# 401# 7614# 2# B- 2889# 500# 226 040310# 430# + 56 141 85 226 At x 34660# 300# 7624# 1# B- 5913# 300# 226 037209# 322# + 54 140 86 226 Rn 28747.194 10.477 7646.4108 0.0464 B- 1226.6542 12.1895 226 030861.380 11.247 + 52 139 87 226 Fr 27520.539 6.230 7648.3768 0.0276 B- 3852.9638 6.5215 226 029544.512 6.688 + 50 138 88 226 Ra 23667.576 1.927 7661.9636 0.0085 B- -641.6252 3.2730 226 025408.186 2.068 + 48 137 89 226 Ac 24309.201 3.100 7655.6628 0.0137 B- 1111.5517 4.5626 226 026096.999 3.327 + 46 136 90 226 Th 23197.649 4.481 7657.1195 0.0198 B- -2835.9504 11.9702 226 024903.699 4.810 + 44 135 91 226 Pa -a 26033.600 11.213 7641.1093 0.0496 B- -1295.1978 15.6747 226 027948.217 12.037 + 42 134 92 226 U -a 27328.797 11.071 7631.9166 0.0490 B- -5488.0792 102.6485 226 029338.669 11.884 + 40 133 93 226 Np -a 32816.877 102.063 7604.1714 0.4516 B- -2813# 225# 226 035230.364 109.568 + 38 132 94 226 Pu x 35630# 200# 7588# 1# B- -7340# 361# 226 038250# 215# + 36 131 95 226 Am x 42970# 300# 7552# 1# B- * 226 046130# 322# +0 59 143 84 227 Po x 42281# 401# 7596# 2# B- 4850# 500# 227 045390# 430# + 57 142 85 227 At x 37430# 300# 7613# 1# B- 4544# 300# 227 040183# 322# + 55 141 86 227 Rn 32885.835 14.091 7630.0508 0.0621 B- 3203.3894 15.2755 227 035304.393 15.127 + 53 140 87 227 Fr 29682.445 5.898 7640.7162 0.0260 B- 2504.9813 6.2112 227 031865.413 6.332 + 51 139 88 227 Ra -n 27177.464 1.946 7648.3048 0.0086 B- 1327.9489 2.2622 227 029176.205 2.089 + 49 138 89 227 Ac 25849.515 1.926 7650.7084 0.0085 B- 44.7559 0.8297 227 027750.594 2.068 + 47 137 90 227 Th 25804.759 2.088 7647.4591 0.0092 B- -1025.6117 7.2815 227 027702.546 2.241 + 45 136 91 227 Pa -a 26830.371 7.263 7639.4945 0.0320 B- -2214.6629 11.1118 227 028803.586 7.797 + 43 135 92 227 U -a 29045.034 8.510 7626.2918 0.0375 B- -3533.9848 77.4417 227 031181.124 9.136 + 41 134 93 227 Np -a 32579.018 76.989 7607.2771 0.3392 B- -4191# 126# 227 034975.012 82.651 + 39 133 94 227 Pu x 36770# 100# 7585# 0# B- -5410# 224# 227 039474# 107# + 37 132 95 227 Am x 42180# 200# 7558# 1# B- * 227 045282# 215# +0 58 143 85 228 At x 41880# 400# 7596# 2# B- 6637# 400# 228 044960# 429# + 56 142 86 228 Rn 35243.466 17.677 7621.6457 0.0775 B- 1859.2451 18.9157 228 037835.415 18.977 + 54 141 87 228 Fr 33384.221 6.732 7626.3689 0.0295 B- 4444.0270 7.0210 228 035839.433 7.226 + 52 140 88 228 Ra +a 28940.194 1.995 7642.4289 0.0088 B- 45.5402 0.6344 228 031068.574 2.141 + 50 139 89 228 Ac - 28894.654 2.093 7639.1973 0.0092 B- 2123.7545 2.6446 228 031019.685 2.247 + 48 138 90 228 Th 26770.899 1.806 7645.0807 0.0079 B- -2152.6993 4.3399 228 028739.741 1.938 + 46 137 91 228 Pa -a 28923.599 4.340 7632.2076 0.0190 B- -296.4020 14.0858 228 031050.758 4.659 + 44 136 92 228 U -a 29220.001 13.474 7627.4763 0.0591 B- -4605# 101# 228 031368.959 14.465 + 42 135 93 228 Np -a 33825# 100# 7604# 0# B- -2283# 103# 228 036313# 108# + 40 134 94 228 Pu -a 36107.809 23.352 7590.4039 0.1024 B- -6742# 202# 228 038763.325 25.069 + 38 133 95 228 Am x 42850# 200# 7557# 1# B- * 228 046001# 215# +0 59 144 85 229 At x 44890# 400# 7585# 2# B- 5527# 400# 229 048191# 429# + 57 143 86 229 Rn x 39362.400 13.041 7605.6227 0.0569 B- 3694.1465 13.9670 229 042257.272 14.000 + 55 142 87 229 Fr 35668.253 5.001 7618.3380 0.0218 B- 3106.2907 16.2305 229 038291.443 5.368 + 53 141 88 229 Ra x 32561.963 15.441 7628.4862 0.0674 B- 1872.0266 19.6229 229 034956.703 16.576 + 51 140 89 229 Ac x 30689.936 12.109 7633.2446 0.0529 B- 1104.4191 12.3458 229 032947.000 13.000 + 49 139 90 229 Th 29585.517 2.404 7634.6510 0.0105 B- -311.3310 3.7152 229 031761.357 2.581 + 47 138 91 229 Pa 29896.848 3.280 7629.8752 0.0143 B- -1313.7716 6.6554 229 032095.585 3.521 + 45 137 92 229 U -a 31210.620 5.938 7620.7218 0.0259 B- -2590.7577 101.3342 229 033505.976 6.374 + 43 136 93 229 Np -a 33801.378 101.177 7605.9921 0.4418 B- -3593.5462 117.9433 229 036287.269 108.618 + 41 135 94 229 Pu -a 37394.924 60.633 7586.8834 0.2648 B- -4785.4899 122.4147 229 040145.099 65.092 + 39 134 95 229 Am -a 42180.414 106.348 7562.5697 0.4644 B- * 229 045282.534 114.169 +0 58 144 86 230 Rn x 42170# 200# 7595# 1# B- 2683# 200# 230 045271# 215# + 56 143 87 230 Fr 39486.769 6.541 7603.7052 0.0284 B- 4970.4627 12.1984 230 042390.787 7.022 + 54 142 88 230 Ra x 34516.306 10.296 7621.9144 0.0448 B- 677.9196 18.8884 230 037054.776 11.053 + 52 141 89 230 Ac x 33838.386 15.835 7621.4604 0.0689 B- 2975.8745 15.8815 230 036327.000 17.000 + 50 140 90 230 Th 30862.512 1.209 7630.9974 0.0053 B- -1311.0313 2.8334 230 033132.267 1.297 + 48 139 91 230 Pa 32173.543 3.038 7621.8958 0.0132 B- 558.5262 4.5919 230 034539.717 3.261 + 46 138 92 230 U -a 31615.017 4.509 7620.9227 0.0196 B- -3621.5986 55.1683 230 033940.114 4.841 + 44 137 93 230 Np -a 35236.615 55.007 7601.7751 0.2392 B- -1695.5543 56.8505 230 037828.060 59.051 + 42 136 94 230 Pu -a 36932.170 14.451 7591.0016 0.0628 B- -5940# 144# 230 039648.313 15.514 + 40 135 95 230 Am -a 42872# 143# 7562# 1# B- * 230 046025# 153# +0 59 145 86 231 Rn x 46550# 300# 7579# 1# B- 4469# 300# 231 049973# 322# + 57 144 87 231 Fr x 42080.575 7.731 7594.5009 0.0335 B- 3864.0868 13.7495 231 045175.353 8.300 + 55 143 88 231 Ra 38216.488 11.370 7607.8418 0.0492 B- 2453.6351 17.3014 231 041027.085 12.206 + 53 142 89 231 Ac x 35762.853 13.041 7615.0768 0.0565 B- 1947.0425 13.0976 231 038393.000 14.000 + 51 141 90 231 Th 33815.811 1.217 7620.1188 0.0053 B- 391.4727 1.4598 231 036302.764 1.306 + 49 140 91 231 Pa 33424.338 1.771 7618.4267 0.0077 B- -381.6138 2.0325 231 035882.500 1.901 + 47 139 92 231 U -a 33805.952 2.670 7613.3879 0.0116 B- -1817.7347 51.1839 231 036292.180 2.866 + 45 138 93 231 Np -a 35623.686 51.154 7602.1321 0.2214 B- -2684.8905 55.6931 231 038243.598 54.916 + 43 137 94 231 Pu -a 38308.577 22.061 7587.1224 0.0955 B- -4101# 301# 231 041125.946 23.683 + 41 136 95 231 Am x 42410# 300# 7566# 1# B- -4860# 424# 231 045529# 322# + 39 135 96 231 Cm x 47270# 300# 7542# 1# B- * 231 050746# 322# +0 58 145 87 232 Fr x 46072.834 13.972 7579.3481 0.0602 B- 5575.8791 16.7023 232 049461.219 15.000 + 56 144 88 232 Ra 40496.955 9.151 7600.0099 0.0394 B- 1342.5322 15.9313 232 043475.267 9.823 + 54 143 89 232 Ac x 39154.423 13.041 7602.4245 0.0562 B- 3707.7131 13.1181 232 042034.000 14.000 + 52 142 90 232 Th 35446.710 1.421 7615.0338 0.0061 B- -499.8388 7.7338 232 038053.606 1.525 + 50 141 91 232 Pa + 35946.549 7.645 7609.5072 0.0330 B- 1337.1034 7.4278 232 038590.205 8.206 + 48 140 92 232 U 34609.445 1.808 7611.8984 0.0078 B- -2750# 100# 232 037154.765 1.941 + 46 139 93 232 Np - 37359# 100# 7597# 0# B- -1001# 101# 232 040107# 107# + 44 138 94 232 Pu -a 38360.915 16.885 7588.9839 0.0728 B- -5059# 300# 232 041182.133 18.126 + 42 137 95 232 Am x 43420# 300# 7564# 1# B- -2913# 361# 232 046613# 322# + 40 136 96 232 Cm -a 46333# 201# 7548# 1# B- * 232 049740# 216# +0 59 146 87 233 Fr x 48920.052 19.561 7569.2398 0.0840 B- 4585.9906 21.3694 233 052517.833 21.000 + 57 145 88 233 Ra 44334.062 8.603 7585.5644 0.0369 B- 3026.0244 15.6228 233 047594.570 9.235 + 55 144 89 233 Ac x 41308.037 13.041 7595.1939 0.0560 B- 2576.3950 13.1184 233 044346.000 14.000 + 53 143 90 233 Th 38731.642 1.424 7602.8937 0.0061 B- 1242.2320 1.1224 233 041580.126 1.528 + 51 142 91 233 Pa 37489.410 1.336 7604.8675 0.0057 B- 570.2993 1.9750 233 040246.535 1.433 + 49 141 92 233 U 36919.111 2.254 7603.9574 0.0097 B- -1029.4197 51.0050 233 039634.294 2.420 + 47 140 93 233 Np -a 37948.531 50.981 7596.1816 0.2188 B- -2103.3047 74.3811 233 040739.421 54.729 + 45 139 94 233 Pu -a 40051.836 54.178 7583.7968 0.2325 B- -3233# 126# 233 042997.411 58.162 + 43 138 95 233 Am -a 43285# 114# 7567# 0# B- -4008# 140# 233 046468# 123# + 41 137 96 233 Cm -a 47293.340 81.095 7546.0020 0.3480 B- -5478# 247# 233 050771.485 87.059 + 39 136 97 233 Bk -a 52771# 233# 7519# 1# B- * 233 056652# 250# +0 58 146 88 234 Ra x 46930.629 8.383 7576.5439 0.0358 B- 2089.4348 16.2945 234 050382.100 9.000 + 56 145 89 234 Ac x 44841.195 13.972 7582.1297 0.0597 B- 4228.2364 14.2103 234 048139.000 15.000 + 54 144 90 234 Th +a 40612.958 2.589 7596.8557 0.0111 B- 274.0882 3.1716 234 043599.801 2.779 + 52 143 91 234 Pa IT 40338.870 4.094 7594.6837 0.0175 B- 2193.9105 3.9998 234 043305.555 4.395 + 50 142 92 234 U 38144.959 1.129 7600.7160 0.0048 B- -1809.8462 8.3205 234 040950.296 1.212 + 48 141 93 234 Np - 39954.806 8.397 7589.6382 0.0359 B- -395.1807 10.7522 234 042893.245 9.014 + 46 140 94 234 Pu -a 40349.986 6.798 7584.6061 0.0291 B- -4112# 160# 234 043317.489 7.298 + 44 139 95 234 Am -a 44462# 160# 7564# 1# B- -2261# 161# 234 047731# 172# + 42 138 96 234 Cm -a 46722.411 17.078 7550.6868 0.0730 B- -6673# 154# 234 050158.568 18.333 + 40 137 97 234 Bk -a 53395# 153# 7519# 1# B- * 234 057322# 164# +0 59 147 88 235 Ra x 51130# 300# 7561# 1# B- 3773# 300# 235 054890# 322# + 57 146 89 235 Ac x 47357.160 13.972 7573.5051 0.0595 B- 3339.4064 19.1127 235 050840.000 15.000 + 55 145 90 235 Th x 44017.754 13.041 7584.3862 0.0555 B- 1728.8531 19.1127 235 047255.000 14.000 + 53 144 91 235 Pa x 42288.901 13.972 7588.4139 0.0595 B- 1370.1184 14.0169 235 045399.000 15.000 + 51 143 92 235 U 40918.782 1.116 7590.9151 0.0048 B- -124.2619 0.8524 235 043928.117 1.198 + 49 142 93 235 Np 41043.044 1.388 7587.0571 0.0059 B- -1139.3021 20.4992 235 044061.518 1.490 + 47 141 94 235 Pu -a 42182.346 20.521 7578.8799 0.0873 B- -2442.2558 56.5932 235 045284.609 22.030 + 45 140 95 235 Am -a 44624.602 52.780 7565.1582 0.2246 B- -3389# 115# 235 047906.478 56.661 + 43 139 96 235 Cm -a 48013# 102# 7547# 0# B- -4757# 413# 235 051545# 110# + 41 138 97 235 Bk x 52770# 401# 7524# 2# B- * 235 056651# 430# +0 58 147 89 236 Ac x 51220.998 38.191 7559.2423 0.1618 B- 4965.7951 40.6669 236 054988.000 41.000 + 56 146 90 236 Th x 46255.203 13.972 7576.9688 0.0592 B- 921.2477 19.7600 236 049657.000 15.000 + 54 145 91 236 Pa x 45333.955 13.972 7577.5573 0.0592 B- 2889.3730 14.0166 236 048668.000 15.000 + 52 144 92 236 U 42444.582 1.112 7586.4854 0.0047 B- -933.5116 50.4152 236 045566.130 1.193 + 50 143 93 236 Np IT 43378.094 50.421 7579.2148 0.2136 B- 476.5854 50.3887 236 046568.296 54.129 + 48 142 94 236 Pu 42901.508 1.810 7577.9192 0.0077 B- -3139# 119# 236 046056.661 1.942 + 46 141 95 236 Am -a 46041# 119# 7561# 1# B- -1812# 120# 236 049427# 127# + 44 140 96 236 Cm -a 47852.820 17.635 7550.3090 0.0747 B- -5689# 361# 236 051372.112 18.931 + 42 139 97 236 Bk -a 53542# 361# 7523# 2# B- * 236 057479# 387# +0 59 148 89 237 Ac x 54020# 400# 7550# 2# B- 4065# 400# 237 057993# 429# + 57 147 90 237 Th x 49955.097 15.835 7563.4433 0.0668 B- 2427.4736 20.5140 237 053629.000 17.000 + 55 146 91 237 Pa x 47527.624 13.041 7570.3847 0.0550 B- 2137.4905 13.0962 237 051023.000 14.000 + 53 145 92 237 U 45390.133 1.202 7576.1026 0.0051 B- 518.5338 0.5200 237 048728.309 1.290 + 51 144 93 237 Np 44871.599 1.120 7574.9895 0.0047 B- -220.0630 1.2944 237 048171.640 1.201 + 49 143 94 237 Pu 45091.662 1.697 7570.7599 0.0072 B- -1478# 59# 237 048407.888 1.821 + 47 142 95 237 Am -a 46570# 59# 7561# 0# B- -2677# 95# 237 049995# 64# + 45 141 96 237 Cm -a 49247.151 74.399 7546.6241 0.3139 B- -3963# 242# 237 052868.988 79.870 + 43 140 97 237 Bk -a 53210# 230# 7527# 1# B- -4728# 250# 237 057123# 247# + 41 139 98 237 Cf -a 57938.255 97.347 7503.3507 0.4107 B- * 237 062199.272 104.506 +0 58 148 90 238 Th +a 52525# 283# 7555# 1# B- 1631# 284# 238 056388# 304# + 56 147 91 238 Pa x 50894.043 15.835 7558.3449 0.0665 B- 3586.3111 15.9056 238 054637.000 17.000 + 54 146 92 238 U 47307.732 1.492 7570.1262 0.0063 B- -146.8652 1.2006 238 050786.936 1.601 + 52 145 93 238 Np -n 47454.597 1.137 7566.2220 0.0048 B- 1291.4491 0.4573 238 050944.603 1.220 + 50 144 94 238 Pu 46163.148 1.138 7568.3611 0.0048 B- -2258.2731 58.9005 238 049558.175 1.221 + 48 143 95 238 Am -a 48421.421 58.911 7555.5853 0.2475 B- -1023.7818 60.1587 238 051982.531 63.243 + 46 142 96 238 Cm -a 49445.203 12.234 7547.9966 0.0514 B- -4771# 256# 238 053081.606 13.133 + 44 141 97 238 Bk -a 54216# 256# 7525# 1# B- -3061# 393# 238 058204# 275# + 42 140 98 238 Cf x 57278# 298# 7509# 1# B- * 238 061490# 320# +0 59 149 90 239 Th x 56500# 400# 7540# 2# B- 3162# 445# 239 060655# 429# + 57 148 91 239 Pa x 53337# 196# 7550# 1# B- 2765# 196# 239 057260# 210# + 55 147 92 239 U -n 50572.668 1.502 7558.5624 0.0063 B- 1261.6634 1.4935 239 054291.989 1.612 + 53 146 93 239 Np 49311.005 1.310 7560.5680 0.0055 B- 722.7849 0.9304 239 052937.538 1.406 + 51 145 94 239 Pu 48588.220 1.112 7560.3187 0.0047 B- -802.1402 1.6635 239 052161.596 1.194 + 49 144 95 239 Am -a 49390.360 1.982 7553.6891 0.0083 B- -1756.6021 150.0740 239 053022.729 2.127 + 47 143 96 239 Cm -a 51146.962 150.070 7543.0659 0.6279 B- -3103# 256# 239 054908.519 161.107 + 45 142 97 239 Bk -a 54250# 207# 7527# 1# B- -3952# 239# 239 058239# 222# + 43 141 98 239 Cf -a 58202# 120# 7507# 1# B- -5429# 323# 239 062482# 129# + 41 140 99 239 Es x 63630# 300# 7481# 1# B- * 239 068310# 322# +0 58 149 91 240 Pa x 57010# 200# 7537# 1# B- 4295# 200# 240 061203# 215# + 56 148 92 240 U 52715.497 2.553 7551.7705 0.0106 B- 399.2685 17.0830 240 056592.411 2.740 + 54 147 93 240 Np 52316.229 17.032 7550.1743 0.0710 B- 2190.9095 17.0151 240 056163.778 18.284 + 52 146 94 240 Pu 50125.319 1.105 7556.0433 0.0046 B- -1384.7902 13.7882 240 053811.740 1.186 + 50 145 95 240 Am +n 51510.110 13.832 7547.0136 0.0576 B- -214.1127 13.8967 240 055298.374 14.849 + 48 144 96 240 Cm 51724.222 1.905 7542.8617 0.0079 B- -3940# 150# 240 055528.233 2.045 + 46 143 97 240 Bk - 55664# 150# 7523# 1# B- -2324# 151# 240 059758# 161# + 44 142 98 240 Cf -a 57988.719 18.034 7510.2400 0.0751 B- -6237# 366# 240 062253.447 19.360 + 42 141 99 240 Es -a 64225# 366# 7481# 2# B- * 240 068949# 393# +0 59 150 91 241 Pa x 59740# 300# 7528# 1# B- 3543# 358# 241 064134# 322# + 57 149 92 241 U x 56197# 196# 7539# 1# B- 1882# 220# 241 060330# 210# + 55 148 93 241 Np + 54315.115 100.006 7544.0426 0.4150 B- 1360.0000 100.0000 241 058309.671 107.360 + 53 147 94 241 Pu 52955.115 1.105 7546.4395 0.0046 B- 20.7799 0.1658 241 056849.651 1.186 + 51 146 95 241 Am 52934.335 1.113 7543.2795 0.0046 B- -767.4346 1.1685 241 056827.343 1.195 + 49 145 96 241 Cm 53701.770 1.607 7536.8488 0.0067 B- -2279# 165# 241 057651.218 1.725 + 47 144 97 241 Bk +a 55981# 165# 7524# 1# B- -3346# 235# 241 060098# 178# + 45 143 98 241 Cf -a 59327# 167# 7507# 1# B- -4567# 285# 241 063690# 180# + 43 142 99 241 Es -a 63893# 231# 7485# 1# B- -5327# 379# 241 068592# 248# + 41 141 100 241 Fm x 69220# 300# 7459# 1# B- * 241 074311# 322# +0 58 150 92 242 U +a 58620# 201# 7532# 1# B- 1203# 283# 242 062931# 215# + 56 149 93 242 Np + 57416.876 200.004 7533.4042 0.8265 B- 2700.0000 200.0000 242 061639.548 214.712 + 54 148 94 242 Pu 54716.876 1.245 7541.3284 0.0052 B- -751.1373 0.7080 242 058740.979 1.336 + 52 147 95 242 Am -n 55468.014 1.118 7534.9917 0.0046 B- 664.3145 0.4143 242 059547.358 1.199 + 50 146 96 242 Cm 54803.699 1.141 7534.5040 0.0047 B- -2948# 135# 242 058834.187 1.224 + 48 145 97 242 Bk IT 57752# 135# 7519# 1# B- -1635# 135# 242 061999# 144# + 46 144 98 242 Cf -a 59386.982 12.892 7509.0991 0.0533 B- -5414# 257# 242 063754.544 13.840 + 44 143 99 242 Es -a 64801# 257# 7483# 1# B- -3598# 476# 242 069567# 276# + 42 142 100 242 Fm x 68400# 401# 7465# 2# B- * 242 073430# 430# +0 59 151 92 243 U x 62480# 300# 7518# 1# B- 2674# 302# 243 067075# 322# + 57 150 93 243 Np IT 59806# 32# 7526# 0# B- 2051# 32# 243 064204# 34# + 55 149 94 243 Pu 57754.561 2.542 7531.0087 0.0105 B- 579.5559 2.6216 243 062002.068 2.728 + 53 148 95 243 Am 57175.005 1.388 7530.1742 0.0057 B- -6.9302 1.5692 243 061379.889 1.490 + 51 147 96 243 Cm -a 57181.936 1.496 7526.9261 0.0062 B- -1507.6936 4.5065 243 061387.329 1.605 + 49 146 97 243 Bk -a 58689.629 4.524 7517.5021 0.0186 B- -2300# 181# 243 063005.905 4.856 + 47 145 98 243 Cf -a 60990# 181# 7505# 1# B- -3757# 275# 243 065475# 194# + 45 144 99 243 Es -a 64747# 207# 7486# 1# B- -4569# 245# 243 069508# 222# + 43 143 100 243 Fm -a 69316# 130# 7464# 1# B- * 243 074414# 140# +0 58 151 93 244 Np x 63240# 100# 7514# 0# B- 3434# 100# 244 067891# 107# + 56 150 94 244 Pu 59806.021 2.346 7524.8154 0.0096 B- -73.1143 2.6856 244 064204.401 2.518 + 54 149 95 244 Am + 59879.135 1.491 7521.3095 0.0061 B- 1427.3000 1.0000 244 064282.892 1.600 + 52 148 96 244 Cm -a 58451.835 1.106 7523.9527 0.0045 B- -2261.9902 14.3567 244 062750.622 1.187 + 50 147 97 244 Bk -a 60713.825 14.399 7511.4759 0.0590 B- -764.2709 14.5724 244 065178.969 15.457 + 48 146 98 244 Cf 61478.096 2.617 7505.1373 0.0107 B- -4547# 181# 244 065999.447 2.809 + 46 145 99 244 Es -a 66026# 181# 7483# 1# B- -2938# 271# 244 070881# 195# + 44 144 100 244 Fm -a 68964# 201# 7468# 1# B- -6634# 425# 244 074036# 216# + 42 143 101 244 Md -a 75597# 374# 7438# 2# B- * 244 081157# 402# +0 59 152 93 245 Np x 65850# 200# 7506# 1# B- 2672# 201# 245 070693# 215# + 57 151 94 245 Pu -n 63178.173 13.620 7513.2822 0.0556 B- 1277.7559 13.7334 245 067824.554 14.621 + 55 150 95 245 Am +a 61900.417 1.886 7515.3043 0.0077 B- 895.8929 1.5491 245 066452.827 2.024 + 53 149 96 245 Cm 61004.524 1.149 7515.7677 0.0047 B- -809.2519 1.4964 245 065491.047 1.233 + 51 148 97 245 Bk -a 61813.776 1.792 7509.2714 0.0073 B- -1571.3755 2.5861 245 066359.814 1.923 + 49 147 98 245 Cf 63385.151 2.428 7499.6644 0.0099 B- -2930# 165# 245 068046.755 2.606 + 47 146 99 245 Es IT 66315# 165# 7485# 1# B- -3877# 256# 245 071192# 178# + 45 145 100 245 Fm -a 70192# 195# 7465# 1# B- -5133# 325# 245 075354# 210# + 43 144 101 245 Md -a 75325# 260# 7441# 1# B- * 245 080864# 279# +0 58 152 94 246 Pu 65394.772 14.985 7506.5401 0.0609 B- 401# 14# 246 070204.172 16.087 + 56 151 95 246 Am IT 64994# 18# 7505# 0# B- 2377# 18# 246 069774# 19# + 54 150 96 246 Cm 62616.912 1.525 7511.4716 0.0062 B- -1350.0000 60.0000 246 067222.016 1.637 + 52 149 97 246 Bk - 63966.912 60.019 7502.8035 0.2440 B- -123.3159 60.0198 246 068671.300 64.433 + 50 148 98 246 Cf 64090.228 1.514 7499.1220 0.0062 B- -3728.5741 89.9373 246 068803.685 1.625 + 48 147 99 246 Es 67818.802 89.925 7480.7849 0.3655 B- -2372.3848 90.9577 246 072806.474 96.538 + 46 146 100 246 Fm -a 70191.187 13.670 7467.9608 0.0556 B- -5924# 260# 246 075353.334 14.675 + 44 145 101 246 Md -a 76115# 260# 7441# 1# B- * 246 081713# 279# +0 59 153 94 247 Pu x 69210# 200# 7493# 1# B- 2057# 224# 247 074300# 215# + 57 152 95 247 Am + 67153# 100# 7499# 0# B- 1620# 100# 247 072092# 107# + 55 151 96 247 Cm 65533.105 3.797 7501.9318 0.0154 B- 43.5841 6.3245 247 070352.678 4.076 + 53 150 97 247 Bk -a 65489.521 5.189 7498.9408 0.0210 B- -619.8711 15.2376 247 070305.889 5.570 + 51 149 98 247 Cf +a 66109.392 14.327 7493.2638 0.0580 B- -2469.0006 24.1495 247 070971.348 15.380 + 49 148 99 247 Es +a 68578.393 19.441 7480.1005 0.0787 B- -3094# 182# 247 073621.929 20.870 + 47 147 100 247 Fm +a 71672# 181# 7464# 1# B- -4263# 275# 247 076944# 194# + 45 146 101 247 Md -a 75936# 207# 7444# 1# B- * 247 081520# 223# +0 58 153 95 248 Am + 70563# 200# 7487# 1# B- 3170# 200# 248 075752# 215# + 56 152 96 248 Cm 67392.748 2.358 7496.7291 0.0095 B- -738.3049 50.0026 248 072349.086 2.531 + 54 151 97 248 Bk +a 68131.053 50.058 7490.5975 0.2018 B- 893.1015 50.3143 248 073141.689 53.739 + 52 150 98 248 Cf -a 67237.951 5.121 7491.0440 0.0207 B- -3061# 53# 248 072182.905 5.497 + 50 149 99 248 Es -a 70299# 52# 7476# 0# B- -1599# 53# 248 075469# 56# + 48 148 100 248 Fm 71897.793 8.497 7465.9451 0.0343 B- -5050# 184# 248 077185.451 9.122 + 46 147 101 248 Md -a 76948# 184# 7442# 1# B- -3741# 290# 248 082607# 198# + 44 146 102 248 No -a 80689# 224# 7424# 1# B- * 248 086623# 241# +0 59 154 95 249 Am x 73104# 298# 7479# 1# B- 2353# 298# 249 078480# 320# + 57 153 96 249 Cm -n 70750.696 2.371 7485.5510 0.0095 B- 904.3630 2.5934 249 075953.992 2.545 + 55 152 97 249 Bk + 69846.333 1.248 7486.0410 0.0050 B- 123.6000 0.4000 249 074983.118 1.339 + 53 151 98 249 Cf 69722.733 1.182 7483.3954 0.0048 B- -1452# 30# 249 074850.428 1.269 + 51 150 99 249 Es -a 71175# 30# 7474# 0# B- -2344# 31# 249 076409# 32# + 49 149 100 249 Fm 73519.143 6.212 7461.8649 0.0249 B- -3661.8091 164.5418 249 078926.042 6.668 + 47 148 101 249 Md 77180.952 164.425 7444.0169 0.6603 B- -4606# 324# 249 082857.155 176.516 + 45 147 102 249 No -a 81787# 279# 7422# 1# B- * 249 087802# 300# +0 58 154 96 250 Cm -nn 72989.588 10.274 7478.9385 0.0411 B- 37.5820 10.6414 250 078357.541 11.029 + 56 153 97 250 Bk +a 72952.006 2.898 7475.9594 0.0116 B- 1781.6696 2.4561 250 078317.195 3.110 + 54 152 98 250 Cf -a 71170.336 1.538 7479.9567 0.0062 B- -2055# 100# 250 076404.494 1.650 + 52 151 99 250 Es - 73225# 100# 7469# 0# B- -847# 100# 250 078611# 107# + 50 150 100 250 Fm 74072.193 7.888 7462.0905 0.0316 B- -4326.9476 91.2615 250 079519.765 8.468 + 48 149 101 250 Md 78399.140 90.920 7441.6533 0.3637 B- -3167# 220# 250 084164.934 97.606 + 46 148 102 250 No -a 81566# 200# 7426# 1# B- * 250 087565# 215# +0 59 155 96 251 Cm + 76647.981 22.698 7466.7233 0.0904 B- 1420.0000 20.0000 251 082284.988 24.367 + 57 154 97 251 Bk + 75227.981 10.734 7469.2637 0.0428 B- 1093.0000 10.0000 251 080760.555 11.523 + 55 153 98 251 Cf -a 74134.981 3.901 7470.5014 0.0155 B- -376.5660 6.4677 251 079587.171 4.187 + 53 152 99 251 Es -a 74511.547 5.288 7465.8842 0.0211 B- -1447.2610 15.2387 251 079991.431 5.676 + 51 151 100 251 Fm 75958.808 14.292 7457.0013 0.0569 B- -3007.9406 23.7108 251 081545.130 15.342 + 49 150 101 251 Md +a 78966.749 18.919 7441.9005 0.0754 B- -3882# 182# 251 084774.287 20.310 + 47 149 102 251 No IT 82849# 181# 7423# 1# B- -4981# 270# 251 088942# 194# + 45 148 103 251 Lr x 87830# 200# 7400# 1# B- * 251 094289# 215# +0 60 156 96 252 Cm x 79056# 298# 7460# 1# B- 521# 359# 252 084870# 320# + 58 155 97 252 Bk + 78535# 200# 7459# 1# B- 2500# 200# 252 084310# 215# + 56 154 98 252 Cf -a 76034.610 2.358 7465.3474 0.0094 B- -1260.0000 50.0000 252 081626.507 2.531 + 54 153 99 252 Es - 77294.610 50.056 7457.2428 0.1986 B- 477.9998 50.3220 252 082979.173 53.736 + 52 152 100 252 Fm -a 76816.611 5.221 7456.0351 0.0207 B- -3650.5075 91.4356 252 082466.019 5.604 + 50 151 101 252 Md x 80467.118 91.286 7438.4444 0.3622 B- -2404.2523 91.7581 252 086385.000 98.000 + 48 150 102 252 No 82871.370 9.292 7425.7992 0.0369 B- -5666# 185# 252 088966.070 9.975 + 46 149 103 252 Lr -a 88537# 185# 7400# 1# B- * 252 095048# 198# +0 59 156 97 253 Bk -a 80929# 359# 7451# 1# B- 1627# 359# 253 086880# 385# + 57 155 98 253 Cf -a 79301.562 4.257 7454.8297 0.0168 B- 291.0753 4.3850 253 085133.723 4.570 + 55 154 99 253 Es -a 79010.486 1.249 7452.8879 0.0049 B- -335.0623 1.0782 253 084821.241 1.341 + 53 153 100 253 Fm -a 79345.549 1.549 7448.4712 0.0061 B- -1827# 31# 253 085180.945 1.662 + 51 152 101 253 Md -a 81173# 31# 7438# 0# B- -3186# 32# 253 087143# 34# + 49 151 102 253 No 84358.696 6.912 7422.4719 0.0273 B- -4164.7752 164.6791 253 090562.780 7.420 + 47 150 103 253 Lr 88523.471 164.534 7402.9180 0.6503 B- -5118# 442# 253 095033.850 176.634 + 45 149 104 253 Rf -a 93642# 410# 7380# 2# B- * 253 100528# 440# +0 60 157 97 254 Bk x 84393# 298# 7440# 1# B- 3052# 298# 254 090600# 320# + 58 156 98 254 Cf -a 81341.395 11.462 7449.2259 0.0451 B- -652.7561 11.8014 254 087323.575 12.304 + 56 155 99 254 Es -a 81994.151 2.936 7443.5759 0.0116 B- 1091.6300 2.2858 254 088024.337 3.152 + 54 154 100 254 Fm -a 80902.521 1.843 7444.7936 0.0073 B- -2550# 100# 254 086852.424 1.978 + 52 153 101 254 Md - 83453# 100# 7432# 0# B- -1271# 100# 254 089590# 107# + 50 152 102 254 No 84723.312 9.658 7423.5909 0.0380 B- -4922.5753 91.8208 254 090954.211 10.367 + 48 151 103 254 Lr -a 89645.887 91.312 7401.1306 0.3595 B- -3555# 298# 254 096238.813 98.026 + 46 150 104 254 Rf -a 93201# 283# 7384# 1# B- * 254 100055# 304# +0 59 157 98 255 Cf + 84809# 200# 7438# 1# B- 720# 200# 255 091046# 215# + 57 156 99 255 Es -a 84089.237 10.817 7437.8216 0.0424 B- 288.7717 10.1024 255 090273.504 11.612 + 55 155 100 255 Fm -a 83800.465 3.934 7435.8860 0.0154 B- -1041.6037 6.7172 255 089963.495 4.223 + 53 154 101 255 Md -a 84842.069 5.567 7428.7333 0.0218 B- -1969.8648 15.1096 255 091081.702 5.976 + 51 153 102 255 No 86811.934 14.047 7417.9403 0.0551 B- -3135.3716 22.5952 255 093196.439 15.079 + 49 152 103 255 Lr x 89947.305 17.698 7402.5767 0.0694 B- -4382# 182# 255 096562.399 19.000 + 47 151 104 255 Rf -a 94329# 181# 7382# 1# B- -5265# 336# 255 101267# 194# + 45 150 105 255 Db -a 99595# 283# 7359# 1# B- * 255 106919# 304# +0 60 158 98 256 Cf -a 87041# 314# 7432# 1# B- -144# 330# 256 093442# 338# + 58 157 99 256 Es + 87185# 100# 7428# 0# B- 1700# 100# 256 093597# 107# + 56 156 100 256 Fm -a 85484.796 3.020 7431.7888 0.0118 B- -1971# 124# 256 091771.699 3.241 + 54 155 101 256 Md IT 87456# 124# 7421# 0# B- -367# 124# 256 093888# 133# + 52 154 102 256 No -a 87823.046 7.548 7416.5429 0.0295 B- -3923.5573 83.2459 256 094281.912 8.103 + 50 153 103 256 Lr x 91746.603 82.903 7398.1605 0.3238 B- -2475.3893 84.8025 256 098494.024 89.000 + 48 152 104 256 Rf -a 94221.992 17.848 7385.4349 0.0697 B- -6076# 188# 256 101151.464 19.160 + 46 151 105 256 Db -a 100298# 187# 7359# 1# B- * 256 107674# 201# +0 59 158 99 257 Es -a 89403# 411# 7422# 2# B- 813# 411# 257 095979# 441# + 57 157 100 257 Fm -a 88590.137 4.350 7422.1942 0.0169 B- -402.3347 4.5748 257 095105.419 4.669 + 55 156 101 257 Md -a 88992.472 1.569 7417.5845 0.0061 B- -1254.5923 6.1695 257 095537.343 1.683 + 53 155 102 257 No -a 90247.064 6.197 7409.6587 0.0241 B- -2418# 45# 257 096884.203 6.652 + 51 154 103 257 Lr -a 92665# 44# 7397# 0# B- -3201# 45# 257 099480# 47# + 49 153 104 257 Rf -a 95866.389 10.817 7381.7053 0.0421 B- -4287.8969 164.9888 257 102916.796 11.612 + 47 152 105 257 Db 100154.285 164.634 7361.9767 0.6406 B- * 257 107520.042 176.741 +0 60 159 99 258 Es x 92702# 401# 7412# 2# B- 2276# 448# 258 099520# 430# + 58 158 100 258 Fm -a 90426# 200# 7418# 1# B- -1264# 200# 258 097077# 215# + 56 157 101 258 Md -a 91690.350 3.474 7409.6615 0.0135 B- 213# 100# 258 098433.634 3.729 + 54 156 102 258 No -a 91477# 100# 7407# 0# B- -3304# 143# 258 098205# 107# + 52 155 103 258 Lr -a 94782# 102# 7392# 0# B- -1562# 103# 258 101753# 109# + 50 154 104 258 Rf -a 96344.338 16.104 7382.5257 0.0624 B- -5163.3651 93.2584 258 103429.895 17.288 + 48 153 105 258 Db -a 101507.703 91.857 7359.4803 0.3560 B- -3788# 423# 258 108972.995 98.613 + 46 152 106 258 Sg -a 105296# 413# 7342# 2# B- * 258 113040# 443# +0 59 159 100 259 Fm -a 93704# 283# 7407# 1# B- 140# 300# 259 100596# 304# + 57 158 101 259 Md -a 93564# 101# 7405# 0# B- -515# 101# 259 100445# 108# + 55 157 102 259 No -a 94079.381 6.362 7399.9714 0.0246 B- -1771# 71# 259 100998.364 6.829 + 53 156 103 259 Lr -a 95851# 71# 7390# 0# B- -2516# 101# 259 102900# 76# + 51 155 104 259 Rf -a 98367# 72# 7377# 0# B- -3624# 92# 259 105601# 78# + 49 154 105 259 Db -a 101991.021 56.685 7360.3626 0.2189 B- -4528# 190# 259 109491.859 60.854 + 47 153 106 259 Sg -a 106519# 181# 7340# 1# B- * 259 114353# 194# +0 60 160 100 260 Fm -a 95766# 435# 7402# 2# B- -784# 537# 260 102809# 467# + 58 159 101 260 Md -a 96550# 316# 7396# 1# B- 940# 374# 260 103650# 339# + 56 158 102 260 No -a 95610# 200# 7397# 1# B- -2667# 236# 260 102641# 215# + 54 157 103 260 Lr -a 98277# 125# 7383# 0# B- -871# 236# 260 105504# 134# + 52 156 104 260 Rf -a 99148# 200# 7377# 1# B- -4525# 221# 260 106440# 215# + 50 155 105 260 Db -a 103673# 93# 7357# 0# B- -2875# 95# 260 111297# 100# + 48 154 106 260 Sg -a 106547.495 20.536 7342.5632 0.0790 B- -6576# 197# 260 114383.435 22.045 + 46 153 107 260 Bh -a 113123# 196# 7314# 1# B- * 260 121443# 211# +0 59 160 101 261 Md -a 98578# 509# 7391# 2# B- 123# 547# 261 105828# 546# + 57 159 102 261 No -a 98455# 200# 7388# 1# B- -1102# 283# 261 105696# 215# + 55 158 103 261 Lr -a 99557# 200# 7381# 1# B- -1761# 211# 261 106879# 215# + 53 157 104 261 Rf -a 101318.233 65.663 7371.3858 0.2516 B- -2990# 128# 261 108769.591 70.492 + 51 156 105 261 Db -a 104308# 110# 7357# 0# B- -3697# 112# 261 111979# 118# + 49 155 106 261 Sg -a 108005.004 18.494 7339.7710 0.0709 B- -5074.4052 180.7519 261 115948.135 19.853 + 47 154 107 261 Bh -a 113079.410 179.803 7317.3313 0.6889 B- * 261 121395.733 193.026 +0 60 161 101 262 Md -a 101667# 448# 7382# 2# B- 1566# 575# 262 109144# 481# + 58 160 102 262 No -a 100101# 361# 7385# 1# B- -2004# 412# 262 107463# 387# + 56 159 103 262 Lr -a 102105# 200# 7374# 1# B- -287# 300# 262 109615# 215# + 54 158 104 262 Rf -a 102392# 224# 7370# 1# B- -3861# 265# 262 109923# 240# + 52 157 105 262 Db -a 106253# 143# 7352# 1# B- -2116# 145# 262 114067# 154# + 50 156 106 262 Sg -a 108369.072 22.167 7341.1736 0.0846 B- -5883.0463 95.6774 262 116338.978 23.797 + 48 155 107 262 Bh -a 114252.119 93.074 7315.7331 0.3552 B- * 262 122654.688 99.919 +0 59 161 102 263 No -a 103129# 490# 7376# 2# B- -540# 539# 263 110714# 526# + 57 160 103 263 Lr -a 103669# 224# 7371# 1# B- -1087# 271# 263 111293# 240# + 55 159 104 263 Rf -a 104757# 153# 7364# 1# B- -2353# 227# 263 112461# 164# + 53 158 105 263 Db -a 107110# 168# 7352# 1# B- -3085# 193# 263 114987# 180# + 51 157 106 263 Sg -a 110195# 95# 7337# 0# B- -4301# 320# 263 118299# 101# + 49 156 107 263 Bh -a 114496# 305# 7318# 1# B- -5182# 363# 263 122916# 328# + 47 155 108 263 Hs -a 119678# 197# 7295# 1# B- * 263 128479# 212# +0 60 162 102 264 No -a 105011# 591# 7371# 2# B- -1364# 734# 264 112734# 634# + 58 161 103 264 Lr -a 106375# 436# 7363# 2# B- 300# 566# 264 114198# 468# + 56 160 104 264 Rf -a 106075# 361# 7361# 1# B- -3187# 431# 264 113876# 387# + 54 159 105 264 Db -a 109262# 236# 7346# 1# B- -1521# 368# 264 117297# 253# + 52 158 106 264 Sg -a 110783# 283# 7338# 1# B- -5175# 334# 264 118930# 304# + 50 157 107 264 Bh -a 115958# 177# 7315# 1# B- -3605# 180# 264 124486# 190# + 48 156 108 264 Hs -a 119563.165 28.881 7298.3762 0.1094 B- * 264 128356.330 31.005 +0 59 162 103 265 Lr -a 108233# 547# 7359# 2# B- -457# 655# 265 116193# 587# + 57 161 104 265 Rf -a 108690# 361# 7354# 1# B- -1692# 424# 265 116683# 387# + 55 160 105 265 Db -a 110382# 224# 7345# 1# B- -2412# 263# 265 118500# 240# + 53 159 106 265 Sg -a 112794# 139# 7333# 1# B- -3601# 277# 265 121089# 149# + 51 158 107 265 Bh -a 116395# 239# 7316# 1# B- -4505# 240# 265 124955# 257# + 49 157 108 265 Hs -a 120900.245 23.958 7296.2474 0.0904 B- -5724# 439# 265 129791.744 25.719 + 47 156 109 265 Mt -a 126624# 439# 7272# 2# B- * 265 135937# 471# +0 60 163 103 266 Lr -a 111662# 539# 7349# 2# B- 1526# 679# 266 119874# 579# + 58 162 104 266 Rf -a 110136# 412# 7351# 2# B- -2604# 500# 266 118236# 443# + 56 161 105 266 Db -a 112740# 283# 7339# 1# B- -877# 374# 266 121032# 304# + 54 160 106 266 Sg -a 113617# 245# 7332# 1# B- -4487# 294# 266 121973# 263# + 52 159 107 266 Bh -a 118104# 163# 7313# 1# B- -3036# 165# 266 126790# 175# + 50 158 108 266 Hs -a 121139.675 27.106 7298.2611 0.1019 B- -6533.0066 100.2087 266 130048.783 29.099 + 48 157 109 266 Mt -a 127672.681 96.473 7270.7598 0.3627 B- * 266 137062.253 103.568 +0 59 163 104 267 Rf -a 113444# 575# 7342# 2# B- -570# 686# 267 121787# 617# + 57 162 105 267 Db -a 114014# 374# 7337# 1# B- -1792# 457# 267 122399# 402# + 55 161 106 267 Sg -a 115806# 261# 7327# 1# B- -2958# 371# 267 124323# 281# + 53 160 107 267 Bh -a 118765# 263# 7313# 1# B- -3893# 279# 267 127499# 282# + 51 159 108 267 Hs -a 122658# 95# 7295# 0# B- -5133# 512# 267 131678# 102# + 49 158 109 267 Mt -a 127791# 503# 7273# 2# B- -6089# 543# 267 137189# 540# + 47 157 110 267 Ds -a 133880# 204# 7248# 1# B- * 267 143726# 219# +0 60 164 104 268 Rf -a 115476# 662# 7337# 2# B- -1584# 848# 268 123968# 711# + 58 163 105 268 Db -a 117060# 529# 7328# 2# B- 260# 707# 268 125669# 568# + 56 162 106 268 Sg -a 116800# 469# 7326# 2# B- -3907# 605# 268 125389# 504# + 54 161 107 268 Bh -a 120707# 382# 7309# 1# B- -2261# 486# 268 129584# 410# + 52 160 108 268 Hs -a 122968# 300# 7297# 1# B- -6183# 380# 268 132011# 322# + 50 159 109 268 Mt -a 129151# 233# 7271# 1# B- -4497# 381# 268 138649# 250# + 48 158 110 268 Ds -a 133648# 301# 7252# 1# B- * 268 143477# 324# +0 59 164 105 269 Db -a 119148# 624# 7323# 2# B- -544# 724# 269 127911# 669# + 57 163 106 269 Sg -a 119692# 368# 7318# 1# B- -1785# 525# 269 128495# 395# + 55 162 107 269 Bh -a 121477# 374# 7309# 1# B- -3016# 396# 269 130411# 402# + 53 161 108 269 Hs -a 124493# 131# 7294# 0# B- -4807# 338# 269 133649# 141# + 51 160 109 269 Mt -a 129300# 312# 7274# 1# B- -5535# 313# 269 138809# 335# + 49 159 110 269 Ds -a 134834.671 31.403 7250.1551 0.1167 B- * 269 144750.965 33.712 +0 60 165 105 270 Db -a 122397# 575# 7314# 2# B- 966# 735# 270 131399# 617# + 58 164 106 270 Sg -a 121431# 458# 7314# 2# B- -2799# 547# 270 130362# 492# + 56 163 107 270 Bh -a 124230# 299# 7301# 1# B- -882# 388# 270 133366# 320# + 54 162 108 270 Hs -a 125112# 248# 7295# 1# B- -5597# 313# 270 134313# 266# + 52 161 109 270 Mt -a 130709# 191# 7271# 1# B- -3973# 195# 270 140322# 205# + 50 160 110 270 Ds -a 134681.584 39.275 7253.7634 0.1455 B- * 270 144586.620 42.163 +0 59 165 106 271 Sg -a 124617# 591# 7305# 2# B- -1242# 705# 271 133782# 634# + 57 164 107 271 Bh -a 125859# 384# 7298# 1# B- -1832# 473# 271 135115# 412# + 55 163 108 271 Hs -a 127691# 276# 7288# 1# B- -3409# 430# 271 137082# 296# + 53 162 109 271 Mt -a 131100# 330# 7273# 1# B- -4853# 344# 271 140741# 354# + 51 161 110 271 Ds -a 135952# 97# 7252# 0# B- * 271 145951# 104# +0 60 166 106 272 Sg -a 126520# 692# 7301# 3# B- -2267# 873# 272 135825# 743# + 58 165 107 272 Bh -a 128787# 532# 7290# 2# B- -217# 737# 272 138259# 571# + 56 164 108 272 Hs -a 129004# 510# 7286# 2# B- -4477# 704# 272 138492# 547# + 54 163 109 272 Mt -a 133481# 485# 7267# 2# B- -2601# 645# 272 143298# 521# + 52 162 110 272 Ds -a 136083# 424# 7255# 2# B- -6690# 484# 272 146091# 456# + 50 161 111 272 Rg -a 142773# 233# 7227# 1# B- * 272 153273# 251# +0 61 167 106 273 Sg x 129920# 400# 7292# 1# B- -763# 767# 273 139475# 429# + 59 166 107 273 Bh -a 130683# 655# 7286# 2# B- -1084# 754# 273 140294# 703# + 57 165 108 273 Hs -a 131767# 374# 7279# 1# B- -3015# 565# 273 141458# 401# + 55 164 109 273 Mt -a 134782# 424# 7265# 2# B- -3503# 447# 273 144695# 455# + 53 163 110 273 Ds -a 138285# 142# 7250# 1# B- -4600# 424# 273 148455# 152# + 51 162 111 273 Rg -a 142885# 400# 7230# 1# B- * 273 153393# 429# +0 60 167 107 274 Bh -a 133762# 578# 7278# 2# B- 356# 744# 274 143599# 620# + 58 166 108 274 Hs -a 133406# 469# 7276# 2# B- -3843# 602# 274 143217# 504# + 56 165 109 274 Mt -a 137249# 377# 7259# 1# B- -1948# 542# 274 147343# 404# + 54 164 110 274 Ds -a 139197# 389# 7249# 1# B- -5415# 442# 274 149434# 418# + 52 163 111 274 Rg -a 144612# 209# 7227# 1# B- * 274 155247# 225# +0 61 168 107 275 Bh x 135780# 600# 7273# 2# B- -712# 844# 275 145766# 644# + 59 167 108 275 Hs -a 136492# 593# 7268# 2# B- -2275# 709# 275 146530# 637# + 57 166 109 275 Mt -a 138767# 387# 7257# 1# B- -2899# 516# 275 148972# 416# + 55 165 110 275 Ds -a 141666# 340# 7243# 1# B- -3729# 561# 275 152085# 366# + 53 164 111 275 Rg -a 145395# 446# 7227# 2# B- * 275 156088# 479# +0 62 169 107 276 Bh x 138950# 600# 7265# 2# B- 765# 937# 276 149169# 644# + 60 168 108 276 Hs -a 138185# 720# 7265# 3# B- -3127# 895# 276 148348# 773# + 58 167 109 276 Mt -a 141312# 532# 7250# 2# B- -1227# 764# 276 151705# 571# + 56 166 110 276 Ds -a 142539# 548# 7243# 2# B- -4847# 834# 276 153022# 588# + 54 165 111 276 Rg -a 147386# 629# 7223# 2# B- -2974# 804# 276 158226# 675# + 52 164 112 276 Cn x 150360# 500# 7209# 2# B- * 276 161418# 537# +0 63 170 107 277 Bh x 141100# 600# 7260# 2# B- -275# 748# 277 151477# 644# + 61 169 108 277 Hs -a 141375# 447# 7256# 2# B- -1633# 799# 277 151772# 480# + 59 168 109 277 Mt -a 143008# 662# 7247# 2# B- -2084# 770# 277 153525# 711# + 57 167 110 277 Ds -a 145092# 392# 7237# 1# B- -3315# 611# 277 155763# 421# + 55 166 111 277 Rg -a 148407# 469# 7222# 2# B- -3925# 493# 277 159322# 504# + 53 165 112 277 Cn -a 152332# 153# 7205# 1# B- * 277 163535# 165# +0 64 171 107 278 Bh x 144370# 400# 7251# 1# B- 1150# 500# 278 154988# 429# + 62 170 108 278 Hs x 143220# 300# 7252# 1# B- -2547# 652# 278 153753# 322# + 60 169 109 278 Mt -a 145767# 579# 7240# 2# B- -484# 771# 278 156487# 621# + 58 168 110 278 Ds -a 146251# 510# 7236# 2# B- -4270# 641# 278 157007# 548# + 56 167 111 278 Rg -a 150521# 389# 7218# 1# B- -2321# 585# 278 161590# 417# + 54 166 112 278 Cn -a 152842# 438# 7206# 2# B- -6188# 491# 278 164083# 470# + 52 165 113 278 Nh -a 159030# 224# 7181# 1# B- * 278 170725# 240# +0 63 171 108 279 Hs x 146500# 600# 7243# 2# B- -1085# 900# 279 157274# 644# + 61 170 109 279 Mt -a 147585# 671# 7237# 2# B- -1439# 903# 279 158439# 720# + 59 169 110 279 Ds -a 149024# 605# 7229# 2# B- -2697# 737# 279 159984# 649# + 57 168 111 279 Rg -a 151721# 422# 7216# 2# B- -3299# 578# 279 162880# 453# + 55 167 112 279 Cn -a 155021# 395# 7202# 1# B- -4439# 718# 279 166422# 424# + 53 166 113 279 Nh x 159460# 600# 7183# 2# B- * 279 171187# 644# +0 64 172 108 280 Hs x 148420# 600# 7239# 2# B- -2090# 848# 280 159335# 644# + 62 171 109 280 Mt x 150510# 600# 7229# 2# B- 190# 958# 280 161579# 644# + 60 170 110 280 Ds -a 150320# 748# 7227# 3# B- -3566# 918# 280 161375# 803# + 58 169 111 280 Rg -a 153886# 532# 7212# 2# B- -1768# 789# 280 165204# 571# + 56 168 112 280 Cn -a 155654# 583# 7202# 2# B- -5585# 707# 280 167102# 626# + 54 167 113 280 Nh x 161240# 400# 7180# 1# B- * 280 173098# 429# +0 63 172 109 281 Mt x 152400# 600# 7225# 2# B- -873# 776# 281 163608# 644# + 61 171 110 281 Ds -a 153273# 493# 7220# 2# B- -2060# 918# 281 164545# 529# + 59 170 111 281 Rg -a 155333# 774# 7209# 3# B- -2614# 870# 281 166757# 831# + 57 169 112 281 Cn -a 157947# 397# 7197# 1# B- -3863# 498# 281 169563# 427# + 55 168 113 281 Nh x 161810# 300# 7181# 1# B- * 281 173710# 322# +0 64 173 109 282 Mt -a 155455# 447# 7218# 2# B- 665# 538# 282 166888# 480# + 62 172 110 282 Ds x 154790# 300# 7217# 1# B- -2952# 660# 282 166174# 322# + 60 171 111 282 Rg -a 157742# 588# 7204# 2# B- -1084# 804# 282 169343# 631# + 58 170 112 282 Cn -a 158826# 548# 7197# 2# B- -4903# 678# 282 170507# 588# + 56 169 113 282 Nh -a 163729# 400# 7177# 1# B- * 282 175770# 430# +0 63 173 110 283 Ds x 157830# 500# 7210# 2# B- -1550# 843# 283 169437# 537# + 61 172 111 283 Rg -a 159380# 678# 7201# 2# B- -1957# 916# 283 171101# 728# + 59 171 112 283 Cn -a 161337# 615# 7192# 2# B- -3226# 754# 283 173202# 660# + 57 170 113 283 Nh -a 164563# 437# 7177# 2# B- * 283 176666# 469# +0 64 174 110 284 Ds x 159460# 500# 7207# 2# B- -2510# 707# 284 171187# 537# + 62 173 111 284 Rg x 161970# 500# 7195# 2# B- -445# 912# 284 173882# 537# + 60 172 112 284 Cn -a 162415# 762# 7191# 3# B- -4176# 931# 284 174360# 819# + 58 171 113 284 Nh -a 166591# 533# 7173# 2# B- -2188# 845# 284 178843# 573# + 56 170 114 284 Fl -a 168779# 656# 7163# 2# B- * 284 181192# 704# +0 63 174 111 285 Rg x 163730# 600# 7192# 2# B- -1357# 785# 285 175771# 644# + 61 173 112 285 Cn -a 165086# 507# 7185# 2# B- -2682# 926# 285 177227# 544# + 59 172 113 285 Nh -a 167768# 775# 7172# 3# B- -3164# 874# 285 180106# 832# + 57 171 114 285 Fl -a 170932# 404# 7159# 1# B- * 285 183503# 433# +0 64 175 111 286 Rg -a 166510# 458# 7185# 2# B- 61# 836# 286 178756# 492# + 62 174 112 286 Cn x 166450# 700# 7183# 2# B- -3507# 915# 286 178691# 751# + 60 173 113 286 Nh -a 169957# 590# 7168# 2# B- -1649# 806# 286 182456# 634# + 58 172 114 286 Fl -a 171606# 549# 7159# 2# B- * 286 184226# 590# +0 63 175 112 287 Cn x 169370# 700# 7176# 2# B- -2085# 995# 287 181826# 751# + 61 174 113 287 Nh -a 171455# 707# 7166# 2# B- -2474# 939# 287 184064# 759# + 59 173 114 287 Fl -a 173929# 617# 7155# 2# B- -3819# 759# 287 186720# 663# + 57 172 115 287 Mc -a 177748# 443# 7139# 2# B- * 287 190820# 475# +0 64 176 112 288 Cn x 170930# 700# 7174# 2# B- -3039# 989# 288 183501# 751# + 62 175 113 288 Nh x 173970# 700# 7160# 2# B- -947# 1035# 288 186764# 751# + 60 174 114 288 Fl -a 174917# 763# 7154# 3# B- -4749# 932# 288 187781# 819# + 58 173 115 288 Mc -a 179666# 536# 7135# 2# B- * 288 192879# 575# +0 63 176 113 289 Nh x 175550# 500# 7158# 2# B- -1915# 715# 289 188461# 537# + 61 175 114 289 Fl -a 177465# 511# 7149# 2# B- -3217# 929# 289 190517# 548# + 59 174 115 289 Mc -a 180683# 776# 7135# 3# B- -3774# 925# 289 193971# 834# + 57 173 116 289 Lv -a 184457# 503# 7119# 2# B- * 289 198023# 540# +0 64 177 113 290 Nh -a 178315# 469# 7152# 2# B- -416# 843# 290 191429# 503# + 62 176 114 290 Fl -a 178731# 700# 7147# 2# B- -4061# 917# 290 191875# 752# + 60 175 115 290 Mc -a 182792# 592# 7131# 2# B- -2236# 809# 290 196235# 635# + 58 174 116 290 Lv -a 185028# 552# 7120# 2# B- * 290 198635# 593# +0 63 177 114 291 Fl x 181500# 700# 7141# 2# B- -2680# 1015# 291 194848# 751# + 61 176 115 291 Mc -a 184180# 735# 7129# 3# B- -3064# 964# 291 197725# 789# + 59 175 116 291 Lv -a 187244# 623# 7116# 2# B- -4409# 863# 291 201014# 669# + 57 174 117 291 Ts -a 191653# 597# 7098# 2# B- * 291 205748# 640# +0 62 177 115 292 Mc x 186600# 700# 7124# 2# B- -1533# 1035# 292 200323# 751# + 60 176 116 292 Lv -a 188133# 763# 7116# 3# B- -5488# 1014# 292 201969# 819# + 58 175 117 292 Ts -a 193621# 669# 7095# 2# B- * 292 207861# 718# +0 61 177 116 293 Lv -a 190568# 515# 7111# 2# B- -3860# 933# 293 204583# 553# + 59 176 117 293 Ts -a 194428# 778# 7095# 3# B- -4374# 1053# 293 208727# 835# + 57 175 118 293 Og -a 198802# 709# 7078# 2# B- * 293 213423# 761# +0 60 177 117 294 Ts -a 196397# 593# 7092# 2# B- -2923# 811# 294 210840# 637# + 58 176 118 294 Og -a 199320# 553# 7079# 2# B- * 294 213979# 594# +0 59 177 118 295 Og -a 201369# 655# 7076# 2# B- * 295 216178# 703# diff --git a/openmc/data/multipole.py b/openmc/data/multipole.py index 508c76ac431..dd14e0d1945 100644 --- a/openmc/data/multipole.py +++ b/openmc/data/multipole.py @@ -1,14 +1,12 @@ from numbers import Real from math import exp, erf, pi, sqrt from copy import deepcopy -import warnings import os import h5py import pickle import numpy as np from scipy.signal import find_peaks -import matplotlib.pyplot as plt import openmc.checkvalue as cv from ..exceptions import DataError @@ -196,9 +194,8 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, test_xs_ref[i] = np.interp(test_energy, energy, ce_xs[i]) if log: - print(" energy: {:.3e} to {:.3e} eV ({} points)".format( - energy[0], energy[-1], ne)) - print(" error tolerance: rtol={}, atol={}".format(rtol, atol)) + print(f" energy: {energy[0]:.3e} to {energy[-1]:.3e} eV ({ne} points)") + print(f" error tolerance: rtol={rtol}, atol={atol}") # transform xs (sigma) and energy (E) to f (sigma*E) and s (sqrt(E)) to be # compatible with the multipole representation @@ -232,8 +229,8 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, orders = list(range(lowest_order, highest_order + 1, 2)) if log: - print("Found {} peaks".format(n_peaks)) - print("Fitting orders from {} to {}".format(orders[0], orders[-1])) + print(f"Found {n_peaks} peaks") + print(f"Fitting orders from {orders[0]} to {orders[-1]}") # perform VF with increasing orders found_ideal = False @@ -241,7 +238,7 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, best_quality = best_ratio = -np.inf for i, order in enumerate(orders): if log: - print("Order={}({}/{})".format(order, i, len(orders))) + print(f"Order={order}({i}/{len(orders)})") # initial guessed poles poles_r = np.linspace(s[0], s[-1], order//2) poles = poles_r + poles_r*0.01j @@ -251,7 +248,7 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, # fitting iteration for i_vf in range(n_vf_iter): if log >= DETAILED_LOGGING: - print("VF iteration {}/{}".format(i_vf + 1, n_vf_iter)) + print(f"VF iteration {i_vf + 1}/{n_vf_iter}") # call vf poles, residues, cf, f_fit, rms = vf.vectfit(f, s, poles, weight) @@ -270,7 +267,7 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, # re-calculate residues if poles changed if n_real_poles > 0: if log >= DETAILED_LOGGING: - print(" # real poles: {}".format(n_real_poles)) + print(f" # real poles: {n_real_poles}") new_poles, residues, cf, f_fit, rms = \ vf.vectfit(f, s, new_poles, weight, skip_pole=True) @@ -298,10 +295,10 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, quality = -np.inf if log >= DETAILED_LOGGING: - print(" # poles: {}".format(new_poles.size)) - print(" Max relative error: {:.3f}%".format(maxre*100)) - print(" Satisfaction: {:.1f}%, {:.1f}%".format(ratio*100, ratio2*100)) - print(" Quality: {:.2f}".format(quality)) + print(f" # poles: {new_poles.size}") + print(f" Max relative error: {maxre * 100:.3f}%") + print(f" Satisfaction: {ratio * 100:.1f}%, {ratio2 * 100:.1f}%") + print(f" Quality: {quality:.2f}") if quality > best_quality: if log >= DETAILED_LOGGING: @@ -356,7 +353,7 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, mp_residues = np.concatenate((best_residues[:, real_idx], best_residues[:, conj_idx]*2), axis=1)/1j if log: - print("Final number of poles: {}".format(mp_poles.size)) + print(f"Final number of poles: {mp_poles.size}") if path_out: if not os.path.exists(path_out): @@ -364,6 +361,7 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, for i, mt in enumerate(mts): if not test_xs_ref[i].any(): continue + import matplotlib.pyplot as plt fig, ax1 = plt.subplots() lns1 = ax1.loglog(test_energy, test_xs_ref[i], 'g', label="ACE xs") lns2 = ax1.loglog(test_energy, best_test_xs[i], 'b', label="VF xs") @@ -379,14 +377,14 @@ def _vectfit_xs(energy, ce_xs, mts, rtol=1e-3, atol=1e-5, orders=None, ax2.set_ylabel('relative error', color='r') ax2.tick_params('y', colors='r') - plt.title("MT {} vector fitted with {} poles".format(mt, mp_poles.size)) + plt.title(f"MT {mt} vector fitted with {mp_poles.size} poles") fig.tight_layout() fig_file = os.path.join(path_out, "{:.0f}-{:.0f}_MT{}.png".format( energy[0], energy[-1], mt)) plt.savefig(fig_file) plt.close() if log: - print("Saved figure: {}".format(fig_file)) + print(f"Saved figure: {fig_file}") return (mp_poles, mp_residues) @@ -424,7 +422,7 @@ def vectfit_nuclide(endf_file, njoy_error=5e-4, vf_pieces=None, # make 0K ACE data using njoy if log: - print("Running NJOY to get 0K point-wise data (error={})...".format(njoy_error)) + print(f"Running NJOY to get 0K point-wise data (error={njoy_error})...") nuc_ce = IncidentNeutron.from_njoy(endf_file, temperatures=[0.0], error=njoy_error, broadr=False, heatr=False, purr=False) @@ -478,9 +476,8 @@ def vectfit_nuclide(endf_file, njoy_error=5e-4, vf_pieces=None, mts = [2, 27] if log: - print(" MTs: {}".format(mts)) - print(" Energy range: {:.3e} to {:.3e} eV ({} points)".format( - E_min, E_max, n_points)) + print(f" MTs: {mts}") + print(f" Energy range: {E_min:.3e} to {E_max:.3e} eV ({n_points} points)") # ====================================================================== # PERFORM VECTOR FITTING @@ -501,7 +498,7 @@ def vectfit_nuclide(endf_file, njoy_error=5e-4, vf_pieces=None, # VF piece by piece for i_piece in range(vf_pieces): if log: - print("Vector fitting piece {}/{}...".format(i_piece + 1, vf_pieces)) + print(f"Vector fitting piece {i_piece + 1}/{vf_pieces}...") # start E of this piece e_bound = (sqrt(E_min) + piece_width*(i_piece-0.5))**2 if i_piece == 0 or sqrt(alpha*e_bound) < 4.0: @@ -535,12 +532,12 @@ def vectfit_nuclide(endf_file, njoy_error=5e-4, vf_pieces=None, if not os.path.exists(path_out): os.makedirs(path_out) if not mp_filename: - mp_filename = "{}_mp.pickle".format(nuc_ce.name) + mp_filename = f"{nuc_ce.name}_mp.pickle" mp_filename = os.path.join(path_out, mp_filename) with open(mp_filename, 'wb') as f: pickle.dump(mp_data, f) if log: - print("Dumped multipole data to file: {}".format(mp_filename)) + print(f"Dumped multipole data to file: {mp_filename}") return mp_data @@ -606,9 +603,8 @@ def _windowing(mp_data, n_cf, rtol=1e-3, atol=1e-5, n_win=None, spacing=None, if log: print("Windowing:") - print(" config: # windows={}, spacing={}, CF order={}".format( - n_win, spacing, n_cf)) - print(" error tolerance: rtol={}, atol={}".format(rtol, atol)) + print(f" config: # windows={n_win}, spacing={spacing}, CF order={n_cf}") + print(f" error tolerance: rtol={rtol}, atol={atol}") # sort poles (and residues) by the real component of the pole for ip in range(n_pieces): @@ -624,7 +620,7 @@ def _windowing(mp_data, n_cf, rtol=1e-3, atol=1e-5, n_win=None, spacing=None, win_data = [] for iw in range(n_win): if log >= DETAILED_LOGGING: - print("Processing window {}/{}...".format(iw + 1, n_win)) + print(f"Processing window {iw + 1}/{n_win}...") # inner window boundaries inbegin = sqrt(E_min) + spacing * iw @@ -659,7 +655,7 @@ def _windowing(mp_data, n_cf, rtol=1e-3, atol=1e-5, n_win=None, spacing=None, lp = rp = center_pole_ind while True: if log >= DETAILED_LOGGING: - print("Trying poles {} to {}".format(lp, rp)) + print(f"Trying poles {lp} to {rp}") # calculate the cross sections contributed by the windowed poles if rp > lp: @@ -748,12 +744,12 @@ class WindowedMultipole(EqualityMixin): Parameters ---------- name : str - Name of the nuclide using the GND naming convention + Name of the nuclide using the GNDS naming convention Attributes ---------- name : str - Name of the nuclide using the GND naming convention + Name of the nuclide using the GNDS naming convention spacing : float The width of each window in sqrt(E)-space. For example, the frst window will end at (sqrt(E_min) + spacing)**2 and the second window at @@ -800,6 +796,11 @@ def __init__(self, name): def name(self): return self._name + @name.setter + def name(self, name): + cv.check_type('name', name, str) + self._name = name + @property def fit_order(self): return self.curvefit.shape[1] - 1 @@ -824,39 +825,6 @@ def poles_per_window(self): def spacing(self): return self._spacing - @property - def sqrtAWR(self): - return self._sqrtAWR - - @property - def E_min(self): - return self._E_min - - @property - def E_max(self): - return self._E_max - - @property - def data(self): - return self._data - - @property - def windows(self): - return self._windows - - @property - def broaden_poly(self): - return self._broaden_poly - - @property - def curvefit(self): - return self._curvefit - - @name.setter - def name(self, name): - cv.check_type('name', name, str) - self._name = name - @spacing.setter def spacing(self, spacing): if spacing is not None: @@ -864,6 +832,10 @@ def spacing(self, spacing): cv.check_greater_than('spacing', spacing, 0.0, equality=False) self._spacing = spacing + @property + def sqrtAWR(self): + return self._sqrtAWR + @sqrtAWR.setter def sqrtAWR(self, sqrtAWR): if sqrtAWR is not None: @@ -871,6 +843,10 @@ def sqrtAWR(self, sqrtAWR): cv.check_greater_than('sqrtAWR', sqrtAWR, 0.0, equality=False) self._sqrtAWR = sqrtAWR + @property + def E_min(self): + return self._E_min + @E_min.setter def E_min(self, E_min): if E_min is not None: @@ -878,6 +854,10 @@ def E_min(self, E_min): cv.check_greater_than('E_min', E_min, 0.0, equality=True) self._E_min = E_min + @property + def E_max(self): + return self._E_max + @E_max.setter def E_max(self, E_max): if E_max is not None: @@ -885,6 +865,10 @@ def E_max(self, E_max): cv.check_greater_than('E_max', E_max, 0.0, equality=False) self._E_max = E_max + @property + def data(self): + return self._data + @data.setter def data(self, data): if data is not None: @@ -900,6 +884,10 @@ def data(self, data): raise TypeError('Multipole data arrays must be complex dtype') self._data = data + @property + def windows(self): + return self._windows + @windows.setter def windows(self, windows): if windows is not None: @@ -911,6 +899,10 @@ def windows(self, windows): ' dtype') self._windows = windows + @property + def broaden_poly(self): + return self._broaden_poly + @broaden_poly.setter def broaden_poly(self, broaden_poly): if broaden_poly is not None: @@ -922,6 +914,10 @@ def broaden_poly(self, broaden_poly): ' dtype') self._broaden_poly = broaden_poly + @property + def curvefit(self): + return self._curvefit + @curvefit.setter def curvefit(self, curvefit): if curvefit is not None: @@ -1109,7 +1105,7 @@ def from_multipole(cls, mp_data, search=None, log=False, **kwargs): for n_w in np.unique(np.linspace(n_win_min, n_win_max, 20, dtype=int)): for n_cf in range(10, 1, -1): if log: - print("Testing N_win={} N_cf={}".format(n_w, n_cf)) + print(f"Testing N_win={n_w} N_cf={n_cf}") # update arguments dictionary kwargs.update(n_win=n_w, n_cf=n_cf) @@ -1154,8 +1150,8 @@ def _evaluate(self, E, T): Returns ------- 3-tuple of Real - Total, absorption, and fission microscopic cross sections at the - given energy and temperature. + Scattering, absorption, and fission microscopic cross sections + at the given energy and temperature. """ @@ -1170,10 +1166,11 @@ def _evaluate(self, E, T): sqrtE = sqrt(E) invE = 1.0 / E - # Locate us. The i_window calc omits a + 1 present in F90 because of - # the 1-based vs. 0-based indexing. Similarly startw needs to be - # decreased by 1. endw does not need to be decreased because - # range(startw, endw) does not include endw. + # Locate us. The i_window calc omits a + 1 present from the legacy + # Fortran version of OpenMC because of the 1-based vs. 0-based + # indexing. Similarly startw needs to be decreased by 1. endw does + # not need to be decreased because range(startw, endw) does not include + # endw. i_window = min(self.n_windows - 1, int(np.floor((sqrtE - sqrt(self.E_min)) / self.spacing))) startw = self.windows[i_window, 0] - 1 @@ -1248,8 +1245,8 @@ def __call__(self, E, T): Returns ------- 3-tuple of Real or 3-tuple of numpy.ndarray - Total, absorption, and fission microscopic cross sections at the - given energy and temperature. + Scattering, absorption, and fission microscopic cross sections + at the given energy and temperature. """ @@ -1274,7 +1271,7 @@ def export_to_hdf5(self, path, mode='a', libver='earliest'): # Open file and write version. with h5py.File(str(path), mode, libver=libver) as f: - f.attrs['filetype'] = np.string_('data_wmp') + f.attrs['filetype'] = np.bytes_('data_wmp') f.attrs['version'] = np.array(WMP_VERSION) g = f.create_group(self.name) diff --git a/openmc/data/nbody.py b/openmc/data/nbody.py index 4db9934b953..ec1ac25c0fd 100644 --- a/openmc/data/nbody.py +++ b/openmc/data/nbody.py @@ -43,18 +43,6 @@ def __init__(self, total_mass, n_particles, atomic_weight_ratio, q_value): def total_mass(self): return self._total_mass - @property - def n_particles(self): - return self._n_particles - - @property - def atomic_weight_ratio(self): - return self._atomic_weight_ratio - - @property - def q_value(self): - return self._q_value - @total_mass.setter def total_mass(self, total_mass): name = 'N-body phase space total mass' @@ -62,6 +50,10 @@ def total_mass(self, total_mass): cv.check_greater_than(name, total_mass, 0.) self._total_mass = total_mass + @property + def n_particles(self): + return self._n_particles + @n_particles.setter def n_particles(self, n_particles): name = 'N-body phase space number of particles' @@ -69,6 +61,10 @@ def n_particles(self, n_particles): cv.check_greater_than(name, n_particles, 0) self._n_particles = n_particles + @property + def atomic_weight_ratio(self): + return self._atomic_weight_ratio + @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): name = 'N-body phase space atomic weight ratio' @@ -76,6 +72,10 @@ def atomic_weight_ratio(self, atomic_weight_ratio): cv.check_greater_than(name, atomic_weight_ratio, 0.0) self._atomic_weight_ratio = atomic_weight_ratio + @property + def q_value(self): + return self._q_value + @q_value.setter def q_value(self, q_value): name = 'N-body phase space Q value' @@ -91,7 +91,7 @@ def to_hdf5(self, group): HDF5 group to write to """ - group.attrs['type'] = np.string_('nbody') + group.attrs['type'] = np.bytes_('nbody') group.attrs['total_mass'] = self.total_mass group.attrs['n_particles'] = self.n_particles group.attrs['atomic_weight_ratio'] = self.atomic_weight_ratio diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 47ebfabf83b..894be187178 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -1,4 +1,3 @@ -from collections import OrderedDict from collections.abc import Mapping, MutableMapping from io import StringIO from math import log10 @@ -44,7 +43,7 @@ class IncidentNeutron(EqualityMixin): Parameters ---------- name : str - Name of the nuclide using the GND naming convention + Name of the nuclide using the GNDS naming convention atomic_number : int Number of protons in the target nucleus mass_number : int @@ -75,8 +74,8 @@ class IncidentNeutron(EqualityMixin): Metastable state of the target nucleus. A value of zero indicates ground state. name : str - Name of the nuclide using the GND naming convention - reactions : collections.OrderedDict + Name of the nuclide using the GNDS naming convention + reactions : dict Contains the cross sections, secondary angle and energy distributions, and other associated data for each reaction. The keys are the MT values and the values are Reaction objects. @@ -107,7 +106,7 @@ def __init__(self, name, atomic_number, mass_number, metastable, self.kTs = kTs self.energy = {} self._fission_energy = None - self.reactions = OrderedDict() + self.reactions = {} self._urr = {} self._resonances = None @@ -123,10 +122,10 @@ def __getitem__(self, mt): if len(mts) > 0: return self._get_redundant_reaction(mt, mts) else: - raise KeyError('No reaction with MT={}.'.format(mt)) + raise KeyError(f'No reaction with MT={mt}.') def __repr__(self): - return "".format(self.name) + return f"" def __iter__(self): return iter(self.reactions.values()) @@ -135,54 +134,14 @@ def __iter__(self): def name(self): return self._name - @property - def atomic_number(self): - return self._atomic_number - - @property - def mass_number(self): - return self._mass_number - - @property - def metastable(self): - return self._metastable - - @property - def atomic_weight_ratio(self): - return self._atomic_weight_ratio - - @property - def fission_energy(self): - return self._fission_energy - - @property - def reactions(self): - return self._reactions - - @property - def resonances(self): - return self._resonances - - @property - def resonance_covariance(self): - return self._resonance_covariance - - @property - def urr(self): - return self._urr - - @property - def temperatures(self): - return ["{}K".format(int(round(kT / K_BOLTZMANN))) for kT in self.kTs] - @name.setter def name(self, name): cv.check_type('name', name, str) self._name = name @property - def atomic_symbol(self): - return ATOMIC_SYMBOL[self.atomic_number] + def atomic_number(self): + return self._atomic_number @atomic_number.setter def atomic_number(self, atomic_number): @@ -190,46 +149,78 @@ def atomic_number(self, atomic_number): cv.check_greater_than('atomic number', atomic_number, 0, True) self._atomic_number = atomic_number + @property + def mass_number(self): + return self._mass_number + @mass_number.setter def mass_number(self, mass_number): cv.check_type('mass number', mass_number, Integral) cv.check_greater_than('mass number', mass_number, 0, True) self._mass_number = mass_number + @property + def metastable(self): + return self._metastable + @metastable.setter def metastable(self, metastable): cv.check_type('metastable', metastable, Integral) cv.check_greater_than('metastable', metastable, 0, True) self._metastable = metastable + @property + def atomic_weight_ratio(self): + return self._atomic_weight_ratio + @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): cv.check_type('atomic weight ratio', atomic_weight_ratio, Real) cv.check_greater_than('atomic weight ratio', atomic_weight_ratio, 0.0) self._atomic_weight_ratio = atomic_weight_ratio + @property + def fission_energy(self): + return self._fission_energy + @fission_energy.setter def fission_energy(self, fission_energy): cv.check_type('fission energy release', fission_energy, FissionEnergyRelease) self._fission_energy = fission_energy + @property + def reactions(self): + return self._reactions + @reactions.setter def reactions(self, reactions): cv.check_type('reactions', reactions, Mapping) self._reactions = reactions + @property + def resonances(self): + return self._resonances + @resonances.setter def resonances(self, resonances): cv.check_type('resonances', resonances, res.Resonances) self._resonances = resonances + @property + def resonance_covariance(self): + return self._resonance_covariance + @resonance_covariance.setter def resonance_covariance(self, resonance_covariance): cv.check_type('resonance covariance', resonance_covariance, res_cov.ResonanceCovariances) self._resonance_covariance = resonance_covariance + @property + def urr(self): + return self._urr + @urr.setter def urr(self, urr): cv.check_type('probability table dictionary', urr, MutableMapping) @@ -238,6 +229,14 @@ def urr(self, urr): cv.check_type('probability tables', value, ProbabilityTables) self._urr = urr + @property + def temperatures(self): + return [f"{int(round(kT / K_BOLTZMANN))}K" for kT in self.kTs] + + @property + def atomic_symbol(self): + return ATOMIC_SYMBOL[self.atomic_number] + def add_temperature_from_ace(self, ace_or_filename, metastable_scheme='nndc'): """Append data from an ACE file at a different temperature. @@ -262,7 +261,7 @@ def add_temperature_from_ace(self, ace_or_filename, metastable_scheme='nndc'): # Check if temprature already exists strT = data.temperatures[0] if strT in self.temperatures: - warn('Cross sections at T={} already exist.'.format(strT)) + warn(f'Cross sections at T={strT} already exist.') return # Check that name matches @@ -426,7 +425,7 @@ def export_to_hdf5(self, path, mode='a', libver='earliest'): # Open file and write version with h5py.File(str(path), mode, libver=libver) as f: - f.attrs['filetype'] = np.string_('data_neutron') + f.attrs['filetype'] = np.bytes_('data_neutron') f.attrs['version'] = np.array(HDF5_VERSION) # Write basic data @@ -462,7 +461,7 @@ def export_to_hdf5(self, path, mode='a', libver='earliest'): if not (photon_rx or rx.mt in keep_mts): continue - rx_group = rxs_group.create_group('reaction_{:03}'.format(rx.mt)) + rx_group = rxs_group.create_group(f'reaction_{rx.mt:03}') rx.to_hdf5(rx_group) # Write total nu data if available @@ -594,7 +593,7 @@ def from_ace(cls, ace_or_filename, metastable_scheme='nndc'): zaid, xs = ace.name.split('.') if not xs.endswith('c'): raise TypeError( - "{} is not a continuous-energy neutron ACE table.".format(ace)) + f"{ace} is not a continuous-energy neutron ACE table.") name, element, Z, mass_number, metastable = \ get_metadata(int(zaid), metastable_scheme) @@ -733,9 +732,9 @@ def from_endf(cls, ev_or_filename, covariance=False): # Determine name element = ATOMIC_SYMBOL[atomic_number] if metastable > 0: - name = '{}{}_m{}'.format(element, mass_number, metastable) + name = f'{element}{mass_number}_m{metastable}' else: - name = '{}{}'.format(element, mass_number) + name = f'{element}{mass_number}' # Instantiate incident neutron data data = cls(name, atomic_number, mass_number, metastable, @@ -868,16 +867,15 @@ def get_file3_xs(ev, mt, E): heatr_evals = get_evaluations(kwargs["heatr"]) heatr_local_evals = get_evaluations(kwargs["heatr"] + "_local") - for ev, ev_local in zip(heatr_evals, heatr_local_evals): - temp = "{}K".format(round(ev.target["temperature"])) + for ev, ev_local, temp in zip(heatr_evals, heatr_local_evals, data.temperatures): # Get total KERMA (originally from ACE file) and energy grid kerma = data.reactions[301].xs[temp] E = kerma.x if f is not None: # Replace fission KERMA with (EFR + EB)*sigma_f - fission = data.reactions[18].xs[temp] + fission = data[18].xs[temp] kerma_fission = get_file3_xs(ev, 318, E) kerma.y = kerma.y - kerma_fission + ( f.fragments(E) + f.betas(E)) * fission(E) diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index 0ef77695b53..c1dcbab17f5 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -5,95 +5,74 @@ from subprocess import Popen, PIPE, STDOUT, CalledProcessError import tempfile from pathlib import Path +import warnings from . import endf +import openmc.data -# For a given MAT number, give a name for the ACE table and a list of ZAID -# identifiers. This is based on Appendix C in the ENDF manual. +# For a given material, give a name for the ACE table and a list of ZAID +# identifiers. ThermalTuple = namedtuple('ThermalTuple', ['name', 'zaids', 'nmix']) _THERMAL_DATA = { - 1: ThermalTuple('hh2o', [1001], 1), - 2: ThermalTuple('parah', [1001], 1), - 3: ThermalTuple('orthoh', [1001], 1), - 5: ThermalTuple('hyh2', [1001], 1), - 7: ThermalTuple('hzrh', [1001], 1), - 8: ThermalTuple('hcah2', [1001], 1), - 10: ThermalTuple('hice', [1001], 1), - 11: ThermalTuple('dd2o', [1002], 1), - 12: ThermalTuple('parad', [1002], 1), - 13: ThermalTuple('orthod', [1002], 1), - 14: ThermalTuple('dice', [1002], 1), - 26: ThermalTuple('be', [4009], 1), - 27: ThermalTuple('bebeo', [4009], 1), - 28: ThermalTuple('bebe2c', [4009], 1), - 30: ThermalTuple('graph', [6000, 6012, 6013], 1), - 31: ThermalTuple('grph10', [6000, 6012, 6013], 1), - 32: ThermalTuple('grph30', [6000, 6012, 6013], 1), - 33: ThermalTuple('lch4', [1001], 1), - 34: ThermalTuple('sch4', [1001], 1), - 35: ThermalTuple('sch4p2', [1001], 1), - 37: ThermalTuple('hch2', [1001], 1), - 38: ThermalTuple('mesi00', [1001], 1), - 39: ThermalTuple('lucite', [1001], 1), - 40: ThermalTuple('benz', [1001, 6000, 6012], 2), - 42: ThermalTuple('tol00', [1001], 1), - 43: ThermalTuple('sisic', [14028, 14029, 14030], 1), - 44: ThermalTuple('csic', [6000, 6012, 6013], 1), - 45: ThermalTuple('ouo2', [8016, 8017, 8018], 1), - 46: ThermalTuple('obeo', [8016, 8017, 8018], 1), - 47: ThermalTuple('sio2-a', [8016, 8017, 8018, 14028, 14029, 14030], 3), - 48: ThermalTuple('osap00', [92238], 1), - 49: ThermalTuple('sio2-b', [8016, 8017, 8018, 14028, 14029, 14030], 3), - 50: ThermalTuple('oice', [8016, 8017, 8018], 1), - 51: ThermalTuple('od2o', [8016, 8017, 8018], 1), - 52: ThermalTuple('mg24', [12024], 1), - 53: ThermalTuple('al27', [13027], 1), - 55: ThermalTuple('yyh2', [39089], 1), - 56: ThermalTuple('fe56', [26056], 1), - 58: ThermalTuple('zrzrh', [40000, 40090, 40091, 40092, 40094, 40096], 1), - 59: ThermalTuple('si00', [14028], 1), - 60: ThermalTuple('asap00', [13027], 1), - 71: ThermalTuple('n-un', [7014, 7015], 1), - 72: ThermalTuple('u-un', [92238], 1), - 75: ThermalTuple('uuo2', [8016, 8017, 8018], 1), + 'c_Al27': ThermalTuple('al27', [13027], 1), + 'c_Al_in_Al2O3': ThermalTuple('asap00', [13027], 1), + 'c_Be': ThermalTuple('be', [4009], 1), + 'c_Be_in_BeO': ThermalTuple('bebeo', [4009], 1), + 'c_Be_in_Be2C': ThermalTuple('bebe2c', [4009], 1), + 'c_Be_in_FLiBe': ThermalTuple('beflib', [4009], 1), + 'c_C6H6': ThermalTuple('benz', [1001, 6000, 6012], 2), + 'c_C_in_SiC': ThermalTuple('csic', [6000, 6012, 6013], 1), + 'c_Ca_in_CaH2': ThermalTuple('cacah2', [20040, 20042, 20043, 20044, 20046, 20048], 1), + 'c_D_in_D2O': ThermalTuple('dd2o', [1002], 1), + 'c_D_in_D2O_solid': ThermalTuple('dice', [1002], 1), + 'c_F_in_FLiBe': ThermalTuple('fflibe', [9019], 1), + 'c_Fe56': ThermalTuple('fe56', [26056], 1), + 'c_Graphite': ThermalTuple('graph', [6000, 6012, 6013], 1), + 'c_Graphite_10p': ThermalTuple('grph10', [6000, 6012, 6013], 1), + 'c_Graphite_30p': ThermalTuple('grph30', [6000, 6012, 6013], 1), + 'c_H_in_C5O2H8': ThermalTuple('lucite', [1001], 1), + 'c_H_in_CaH2': ThermalTuple('hcah2', [1001], 1), + 'c_H_in_CH2': ThermalTuple('hch2', [1001], 1), + 'c_H_in_CH4_liquid': ThermalTuple('lch4', [1001], 1), + 'c_H_in_CH4_solid': ThermalTuple('sch4', [1001], 1), + 'c_H_in_CH4_solid_phase_II': ThermalTuple('sch4p2', [1001], 1), + 'c_H_in_H2O': ThermalTuple('hh2o', [1001], 1), + 'c_H_in_H2O_solid': ThermalTuple('hice', [1001], 1), + 'c_H_in_HF': ThermalTuple('hhf', [1001], 1), + 'c_H_in_Mesitylene': ThermalTuple('mesi00', [1001], 1), + 'c_H_in_ParaffinicOil': ThermalTuple('hparaf', [1001], 1), + 'c_H_in_Toluene': ThermalTuple('tol00', [1001], 1), + 'c_H_in_UH3': ThermalTuple('huh3', [1001], 1), + 'c_H_in_YH2': ThermalTuple('hyh2', [1001], 1), + 'c_H_in_ZrH': ThermalTuple('hzrh', [1001], 1), + 'c_H_in_ZrH2': ThermalTuple('hzrh2', [1001], 1), + 'c_H_in_ZrHx': ThermalTuple('hzrhx', [1001], 1), + 'c_Li_in_FLiBe': ThermalTuple('liflib', [3006, 3007], 1), + 'c_Mg24': ThermalTuple('mg24', [12024], 1), + 'c_N_in_UN': ThermalTuple('n-un', [7014, 7015], 1), + 'c_O_in_Al2O3': ThermalTuple('osap00', [8016, 8017, 8018], 1), + 'c_O_in_BeO': ThermalTuple('obeo', [8016, 8017, 8018], 1), + 'c_O_in_D2O': ThermalTuple('od2o', [8016, 8017, 8018], 1), + 'c_O_in_H2O_solid': ThermalTuple('oice', [8016, 8017, 8018], 1), + 'c_O_in_UO2': ThermalTuple('ouo2', [8016, 8017, 8018], 1), + 'c_ortho_D': ThermalTuple('orthod', [1002], 1), + 'c_ortho_H': ThermalTuple('orthoh', [1001], 1), + 'c_para_D': ThermalTuple('parad', [1002], 1), + 'c_para_H': ThermalTuple('parah', [1001], 1), + 'c_Si28': ThermalTuple('si00', [14028], 1), + 'c_Si_in_SiC': ThermalTuple('sisic', [14028, 14029, 14030], 1), + 'c_SiO2_alpha': ThermalTuple('sio2-a', [8016, 8017, 8018, 14028, 14029, 14030], 3), + 'c_SiO2_beta': ThermalTuple('sio2-b', [8016, 8017, 8018, 14028, 14029, 14030], 3), + 'c_U_in_UN': ThermalTuple('u-un', [92233, 92234, 92235, 92236, 92238], 1), + 'c_U_in_UO2': ThermalTuple('uuo2', [92233, 92234, 92235, 92236, 92238], 1), + 'c_Y_in_YH2': ThermalTuple('yyh2', [39089], 1), + 'c_Zr_in_ZrH': ThermalTuple('zrzrh', [40000, 40090, 40091, 40092, 40094, 40096], 1), + 'c_Zr_in_ZrH2': ThermalTuple('zrzrh2', [40000, 40090, 40091, 40092, 40094, 40096], 1), + 'c_Zr_in_ZrHx': ThermalTuple('zrzrhx', [40000, 40090, 40091, 40092, 40094, 40096], 1), } -def _get_thermal_data(ev, mat): - """Return appropriate ThermalTuple, accounting for bugs.""" - - # JEFF assigns MAT=59 to Ca in CaH2 (which is supposed to be silicon). - if ev.info['library'][0] == 'JEFF': - if ev.material == 59: - if 'CaH2' in ''.join(ev.info['description']): - zaids = [20040, 20042, 20043, 20044, 20046, 20048] - return ThermalTuple('cacah2', zaids, 1) - - # Before ENDF/B-VIII.0, crystalline graphite was MAT=31 - if ev.info['library'] != ('ENDF/B', 8, 0): - if ev.material == 31: - return _THERMAL_DATA[30] - - # ENDF/B incorrectly assigns MAT numbers for UO2 - # - # Material | ENDF Manual | VII.0 | VII.1 | VIII.0 - # ---------|-------------|-------|-------|------- - # O in UO2 | 45 | 75 | 75 | 75 - # U in UO2 | 75 | 76 | 48 | 48 - if ev.info['library'][0] == 'ENDF/B': - if ev.material == 75: - return _THERMAL_DATA[45] - version = ev.info['library'][1:] - if version in ((7, 1), (8, 0)) and ev.material == 48: - return _THERMAL_DATA[75] - if version == (7, 0) and ev.material == 76: - return _THERMAL_DATA[75] - - # If not a problematic material, use the dictionary as is - return _THERMAL_DATA[mat] - - _TEMPLATE_RECONR = """ reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% {nendf} {npendf} @@ -148,7 +127,7 @@ def _get_thermal_data(ev, mat): 1 0 1 .{ext} / '{library}: {zsymam} at {temperature}'/ {mat} {temperature} -1 1/ +1 1 {ismooth}/ / """ @@ -170,7 +149,7 @@ def _get_thermal_data(ev, mat): {nendf} {nthermal_acer_in} 0 {nace} {ndir} 2 0 1 .{ext}/ '{library}: {zsymam_thermal} processed by NJOY'/ -{mat} {temperature} '{data.name}' / +{mat} {temperature} '{data.name}' {nza} / {zaids} / 222 64 {mt_elastic} {elastic_type} {data.nmix} {energy_max} {iwt}/ """ @@ -209,7 +188,7 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False, with tempfile.TemporaryDirectory() as tmpdir: # Copy evaluations to appropriates 'tapes' for tape_num, filename in tapein.items(): - tmpfilename = os.path.join(tmpdir, 'tape{}'.format(tape_num)) + tmpfilename = os.path.join(tmpdir, f'tape{tape_num}') shutil.copy(str(filename), tmpfilename) # Start up NJOY process @@ -237,7 +216,7 @@ def run(commands, tapein, tapeout, input_filename=None, stdout=False, # Copy output files back to original directory for tape_num, filename in tapeout.items(): - tmpfilename = os.path.join(tmpdir, 'tape{}'.format(tape_num)) + tmpfilename = os.path.join(tmpdir, f'tape{tape_num}') if os.path.isfile(tmpfilename): shutil.move(tmpfilename, str(filename)) @@ -269,7 +248,8 @@ def make_pendf(filename, pendf='pendf', error=0.001, stdout=False): def make_ace(filename, temperatures=None, acer=True, xsdir=None, output_dir=None, pendf=False, error=0.001, broadr=True, - heatr=True, gaspr=True, purr=True, evaluation=None, **kwargs): + heatr=True, gaspr=True, purr=True, evaluation=None, + smoothing=True, **kwargs): """Generate incident neutron ACE file from an ENDF file File names can be passed to @@ -319,6 +299,8 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, evaluation : openmc.data.endf.Evaluation, optional If the ENDF file contains multiple material evaluations, this argument indicates which evaluation should be used. + smoothing : bool, optional + If the smoothing option (ACER card 6) is on (True) or off (False). **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -335,7 +317,7 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, else: output_dir = Path(output_dir) if not output_dir.is_dir(): - raise IOError("{} is not a directory".format(output_dir)) + raise IOError(f"{output_dir} is not a directory") ev = evaluation if evaluation is not None else endf.Evaluation(filename) mat = ev.material @@ -401,17 +383,18 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, # acer if acer: + ismooth = int(smoothing) nacer_in = nlast for i, temperature in enumerate(temperatures): # Extend input with an ACER run for each temperature nace = nacer_in + 1 + 2*i ndir = nace + 1 - ext = '{:02}'.format(i + 1) + ext = f'{i + 1:02}' commands += _TEMPLATE_ACER.format(**locals()) # Indicate tapes to save for each ACER run - tapeout[nace] = output_dir / "ace_{:.1f}".format(temperature) - tapeout[ndir] = output_dir / "xsdir_{:.1f}".format(temperature) + tapeout[nace] = output_dir / f"ace_{temperature:.1f}" + tapeout[ndir] = output_dir / f"xsdir_{temperature:.1f}" commands += 'stop\n' run(commands, tapein, tapeout, **kwargs) @@ -421,7 +404,7 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, with ace.open('w') as ace_file, xsdir.open('w') as xsdir_file: for temperature in temperatures: # Get contents of ACE file - text = (output_dir / "ace_{:.1f}".format(temperature)).read_text() + text = (output_dir / f"ace_{temperature:.1f}").read_text() # If the target is metastable, make sure that ZAID in the ACE # file reflects this by adding 400 @@ -434,18 +417,19 @@ def make_ace(filename, temperatures=None, acer=True, xsdir=None, ace_file.write(text) # Concatenate into destination xsdir file - xsdir_in = output_dir / "xsdir_{:.1f}".format(temperature) + xsdir_in = output_dir / f"xsdir_{temperature:.1f}" xsdir_file.write(xsdir_in.read_text()) # Remove ACE/xsdir files for each temperature for temperature in temperatures: - (output_dir / "ace_{:.1f}".format(temperature)).unlink() - (output_dir / "xsdir_{:.1f}".format(temperature)).unlink() + (output_dir / f"ace_{temperature:.1f}").unlink() + (output_dir / f"xsdir_{temperature:.1f}").unlink() def make_ace_thermal(filename, filename_thermal, temperatures=None, ace='ace', xsdir=None, output_dir=None, error=0.001, - iwt=2, evaluation=None, evaluation_thermal=None, **kwargs): + iwt=2, evaluation=None, evaluation_thermal=None, + table_name=None, zaids=None, nmix=None, **kwargs): """Generate thermal scattering ACE file from ENDF files Parameters @@ -476,6 +460,12 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, evaluation_thermal : openmc.data.endf.Evaluation, optional If the ENDF thermal scattering sublibrary file contains multiple material evaluations, this argument indicates which evaluation to use. + table_name : str, optional + Name to assign to ACE table + zaids : list of int, optional + ZAIDs that the thermal scattering data applies to + nmix : int, optional + Number of atom types in mixed moderator **kwargs Keyword arguments passed to :func:`openmc.data.njoy.run` @@ -490,7 +480,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, else: output_dir = Path(output_dir) if not output_dir.is_dir(): - raise IOError("{} is not a directory".format(output_dir)) + raise IOError(f"{output_dir} is not a directory") ev = evaluation if evaluation is not None else endf.Evaluation(filename) mat = ev.material @@ -499,11 +489,23 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, ev_thermal = (evaluation_thermal if evaluation_thermal is not None else endf.Evaluation(filename_thermal)) mat_thermal = ev_thermal.material - zsymam_thermal = ev_thermal.target['zsymam'] + zsymam_thermal = ev_thermal.target['zsymam'].strip() - # Determine name, isotopes based on MAT number - data = _get_thermal_data(ev_thermal, mat_thermal) - zaids = ' '.join(str(zaid) for zaid in data.zaids[:3]) + # Determine name, isotopes, and number of atom types + if table_name and zaids and nmix: + data = ThermalTuple(table_name, zaids, nmix) + else: + with warnings.catch_warnings(record=True) as w: + proper_name = openmc.data.get_thermal_name(zsymam_thermal) + if w: + raise RuntimeError( + f"Thermal scattering material {zsymam_thermal} not " + "recognized. Please contact OpenMC developers at " + "https://openmc.discourse.group.") + data = _THERMAL_DATA[proper_name] + + zaids = ' '.join(str(zaid) for zaid in data.zaids) + nza = len(data.zaids) # Determine name of library library = '{}-{}.{}'.format(*ev_thermal.info['library']) @@ -579,12 +581,12 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, # Extend input with an ACER run for each temperature nace = nthermal_acer_in + 1 + 2*i ndir = nace + 1 - ext = '{:02}'.format(i + 1) + ext = f'{i + 1:02}' commands += _THERMAL_TEMPLATE_ACER.format(**locals()) # Indicate tapes to save for each ACER run - tapeout[nace] = output_dir / "ace_{:.1f}".format(temperature) - tapeout[ndir] = output_dir / "xsdir_{:.1f}".format(temperature) + tapeout[nace] = output_dir / f"ace_{temperature:.1f}" + tapeout[ndir] = output_dir / f"xsdir_{temperature:.1f}" commands += 'stop\n' run(commands, tapein, tapeout, **kwargs) @@ -593,13 +595,13 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, with ace.open('w') as ace_file, xsdir.open('w') as xsdir_file: # Concatenate ACE and xsdir files together for temperature in temperatures: - ace_in = output_dir / "ace_{:.1f}".format(temperature) + ace_in = output_dir / f"ace_{temperature:.1f}" ace_file.write(ace_in.read_text()) - xsdir_in = output_dir / "xsdir_{:.1f}".format(temperature) + xsdir_in = output_dir / f"xsdir_{temperature:.1f}" xsdir_file.write(xsdir_in.read_text()) # Remove ACE/xsdir files for each temperature for temperature in temperatures: - (output_dir / "ace_{:.1f}".format(temperature)).unlink() - (output_dir / "xsdir_{:.1f}".format(temperature)).unlink() + (output_dir / f"ace_{temperature:.1f}").unlink() + (output_dir / f"xsdir_{temperature:.1f}").unlink() diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 48ecc3748ce..c9d51f06238 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -1,4 +1,3 @@ -from collections import OrderedDict from collections.abc import Mapping, Callable from copy import deepcopy from io import StringIO @@ -13,7 +12,7 @@ import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -from . import HDF5_VERSION +from . import HDF5_VERSION, HDF5_VERSION_MAJOR from .ace import Table, get_metadata, get_table from .data import ATOMIC_SYMBOL, EV_PER_MEV from .endf import Evaluation, get_head_record, get_tab1_record, get_list_record @@ -143,6 +142,8 @@ class AtomicRelaxation(EqualityMixin): Dictionary indicating the number of electrons in a subshell when neutral (values) for given subshells (keys). The subshells should be given as strings, e.g., 'K', 'L1', 'L2', etc. + subshells : list + List of subshells as strings, e.g. ``['K', 'L1', ...]`` transitions : pandas.DataFrame Dictionary indicating allowed transitions and their probabilities (values) for given subshells (keys). The subshells should be given as @@ -166,18 +167,6 @@ def __init__(self, binding_energy, num_electrons, transitions): def binding_energy(self): return self._binding_energy - @property - def num_electrons(self): - return self._num_electrons - - @property - def subshells(self): - return list(sorted(self.binding_energy.keys())) - - @property - def transitions(self): - return self._transitions - @binding_energy.setter def binding_energy(self, binding_energy): cv.check_type('binding energies', binding_energy, Mapping) @@ -187,6 +176,10 @@ def binding_energy(self, binding_energy): cv.check_greater_than('binding energy', energy, 0.0, True) self._binding_energy = binding_energy + @property + def num_electrons(self): + return self._num_electrons + @num_electrons.setter def num_electrons(self, num_electrons): cv.check_type('number of electrons', num_electrons, Mapping) @@ -196,6 +189,14 @@ def num_electrons(self, num_electrons): cv.check_greater_than('number of electrons', num, 0.0, True) self._num_electrons = num_electrons + @property + def subshells(self): + return list(sorted(self.binding_energy.keys())) + + @property + def transitions(self): + return self._transitions + @transitions.setter def transitions(self, transitions): cv.check_type('transitions', transitions, Mapping) @@ -430,7 +431,7 @@ class IncidentPhoton(EqualityMixin): the projection of the electron momentum on the scattering vector, :math:`p_z` for each subshell). Note that subshell occupancies may not match the atomic relaxation data. - reactions : collections.OrderedDict + reactions : dict Contains the cross sections for each photon reaction. The keys are MT values and the values are instances of :class:`PhotonReaction`. @@ -439,7 +440,7 @@ class IncidentPhoton(EqualityMixin): def __init__(self, atomic_number): self.atomic_number = atomic_number self._atomic_relaxation = None - self.reactions = OrderedDict() + self.reactions = {} self.compton_profiles = {} self.bremsstrahlung = {} @@ -450,10 +451,10 @@ def __getitem__(self, mt): if mt in self.reactions: return self.reactions[mt] else: - raise KeyError('No reaction with MT={}.'.format(mt)) + raise KeyError(f'No reaction with MT={mt}.') def __repr__(self): - return "".format(self.name) + return f"" def __iter__(self): return iter(self.reactions.values()) @@ -462,26 +463,26 @@ def __iter__(self): def atomic_number(self): return self._atomic_number - @property - def atomic_relaxation(self): - return self._atomic_relaxation - - @property - def name(self): - return ATOMIC_SYMBOL[self.atomic_number] - @atomic_number.setter def atomic_number(self, atomic_number): cv.check_type('atomic number', atomic_number, Integral) cv.check_greater_than('atomic number', atomic_number, 0, True) self._atomic_number = atomic_number + @property + def atomic_relaxation(self): + return self._atomic_relaxation + @atomic_relaxation.setter def atomic_relaxation(self, atomic_relaxation): cv.check_type('atomic relaxation data', atomic_relaxation, AtomicRelaxation) self._atomic_relaxation = atomic_relaxation + @property + def name(self): + return ATOMIC_SYMBOL[self.atomic_number] + @classmethod def from_ace(cls, ace_or_filename): """Generate incident photon data from an ACE table @@ -507,18 +508,18 @@ def from_ace(cls, ace_or_filename): # Get atomic number based on name of ACE table zaid, xs = ace.name.split('.') if not xs.endswith('p'): - raise TypeError("{} is not a photoatomic transport ACE table.".format(ace)) + raise TypeError(f"{ace} is not a photoatomic transport ACE table.") Z = get_metadata(int(zaid))[2] # Read each reaction data = cls(Z) - for mt in (502, 504, 515, 522, 525): + for mt in (502, 504, 517, 522, 525): data.reactions[mt] = PhotonReaction.from_ace(ace, mt) # Get heating cross sections [eV-barn] from factors [eV per collision] # by multiplying with total xs data.reactions[525].xs.y *= sum([data.reactions[mt].xs.y for mt in - (502, 504, 515, 522)]) + (502, 504, 517, 522)]) # Compton profiles n_shell = ace.nxs[5] @@ -637,7 +638,7 @@ def from_endf(cls, photoatomic, relaxation=None): with h5py.File(filename, 'r') as f: _COMPTON_PROFILES['pz'] = f['pz'][()] for i in range(1, 101): - group = f['{:03}'.format(i)] + group = f[f'{i:03}'] num_electrons = group['num_electrons'][()] binding_energy = group['binding_energy'][()]*EV_PER_MEV J = group['J'][()] @@ -712,7 +713,7 @@ def from_hdf5(cls, group_or_filename): # Check for necessary reactions for mt in (502, 504, 522): - assert mt in data, "Reaction {} not found".format(mt) + assert mt in data, f"Reaction {mt} not found" # Read atomic relaxation data.atomic_relaxation = AtomicRelaxation.from_hdf5(group['subshells']) @@ -763,7 +764,7 @@ def export_to_hdf5(self, path, mode='a', libver='earliest'): """ with h5py.File(str(path), mode, libver=libver) as f: # Write filetype and version - f.attrs['filetype'] = np.string_('data_photon') + f.attrs['filetype'] = np.bytes_('data_photon') if 'version' not in f.attrs: f.attrs['version'] = np.array(HDF5_VERSION) @@ -835,7 +836,7 @@ def _add_bremsstrahlung(self): filename = os.path.join(os.path.dirname(__file__), 'density_effect.h5') with h5py.File(filename, 'r') as f: for i in range(1, 101): - group = f['{:03}'.format(i)] + group = f[f'{i:03}'] _BREMSSTRAHLUNG[i] = { 'I': group.attrs['I'], 'num_electrons': group['num_electrons'][()], @@ -923,44 +924,43 @@ def __init__(self, mt): def __repr__(self): if self.mt in _REACTION_NAME: - return "".format( - self.mt, _REACTION_NAME[self.mt][0]) + return f"" else: - return "".format(self.mt) + return f"" @property def anomalous_real(self): return self._anomalous_real - @property - def anomalous_imag(self): - return self._anomalous_imag - - @property - def scattering_factor(self): - return self._scattering_factor - - @property - def xs(self): - return self._xs - @anomalous_real.setter def anomalous_real(self, anomalous_real): cv.check_type('real part of anomalous scattering factor', anomalous_real, Callable) self._anomalous_real = anomalous_real + @property + def anomalous_imag(self): + return self._anomalous_imag + @anomalous_imag.setter def anomalous_imag(self, anomalous_imag): cv.check_type('imaginary part of anomalous scattering factor', anomalous_imag, Callable) self._anomalous_imag = anomalous_imag + @property + def scattering_factor(self): + return self._scattering_factor + @scattering_factor.setter def scattering_factor(self, scattering_factor): cv.check_type('scattering factor', scattering_factor, Callable) self._scattering_factor = scattering_factor + @property + def xs(self): + return self._xs + @xs.setter def xs(self, xs): cv.check_type('reaction cross section', xs, Callable) @@ -998,7 +998,7 @@ def from_ace(cls, ace, mt): elif mt == 504: # Incoherent scattering idx = ace.jxs[1] + n - elif mt == 515: + elif mt == 517: # Pair production idx = ace.jxs[1] + 4*n elif mt == 522: @@ -1019,6 +1019,9 @@ def from_ace(cls, ace, mt): else: nonzero = (xs != 0.0) xs[nonzero] = np.exp(xs[nonzero]) + + # Replace zero elements to small non-zero to enable log-log + xs[~nonzero] = np.exp(-500.0) rx.xs = Tabulated1D(energy, xs, [n], [5]) # Get form factors for incoherent/coherent scattering diff --git a/openmc/data/product.py b/openmc/data/product.py index a6b2fd89e5c..88c83b81fd4 100644 --- a/openmc/data/product.py +++ b/openmc/data/product.py @@ -61,55 +61,55 @@ def __repr__(self): def applicability(self): return self._applicability - @property - def decay_rate(self): - return self._decay_rate - - @property - def distribution(self): - return self._distribution - - @property - def emission_mode(self): - return self._emission_mode - - @property - def particle(self): - return self._particle - - @property - def yield_(self): - return self._yield - @applicability.setter def applicability(self, applicability): cv.check_type('product distribution applicability', applicability, Iterable, Tabulated1D) self._applicability = applicability + @property + def decay_rate(self): + return self._decay_rate + @decay_rate.setter def decay_rate(self, decay_rate): cv.check_type('product decay rate', decay_rate, Real) cv.check_greater_than('product decay rate', decay_rate, 0.0, True) self._decay_rate = decay_rate + @property + def distribution(self): + return self._distribution + @distribution.setter def distribution(self, distribution): cv.check_type('product angle-energy distribution', distribution, Iterable, AngleEnergy) self._distribution = distribution + @property + def emission_mode(self): + return self._emission_mode + @emission_mode.setter def emission_mode(self, emission_mode): cv.check_value('product emission mode', emission_mode, ('prompt', 'delayed', 'total')) self._emission_mode = emission_mode + @property + def particle(self): + return self._particle + @particle.setter def particle(self, particle): cv.check_type('product particle type', particle, str) self._particle = particle + @property + def yield_(self): + return self._yield + @yield_.setter def yield_(self, yield_): cv.check_type('product yield', yield_, Function1D) @@ -124,8 +124,8 @@ def to_hdf5(self, group): HDF5 group to write to """ - group.attrs['particle'] = np.string_(self.particle) - group.attrs['emission_mode'] = np.string_(self.emission_mode) + group.attrs['particle'] = np.bytes_(self.particle) + group.attrs['emission_mode'] = np.bytes_(self.emission_mode) if self.decay_rate > 0.0: group.attrs['decay_rate'] = self.decay_rate @@ -135,7 +135,7 @@ def to_hdf5(self, group): # Write applicability/distribution group.attrs['n_distribution'] = len(self.distribution) for i, d in enumerate(self.distribution): - dgroup = group.create_group('distribution_{}'.format(i)) + dgroup = group.create_group(f'distribution_{i}') if self.applicability: self.applicability[i].to_hdf5(dgroup, 'applicability') d.to_hdf5(dgroup) @@ -170,7 +170,7 @@ def from_hdf5(cls, group): distribution = [] applicability = [] for i in range(n_distribution): - dgroup = group['distribution_{}'.format(i)] + dgroup = group[f'distribution_{i}'] if 'applicability' in dgroup: applicability.append(Tabulated1D.from_hdf5( dgroup['applicability'])) diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index 5e4287f16ef..8f90d2de471 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -56,13 +56,13 @@ 301: 'heating', 444: 'damage-energy', 649: '(n,pc)', 699: '(n,dc)', 749: '(n,tc)', 799: '(n,3Hec)', 849: '(n,ac)', 891: '(n,2nc)', 901: 'heating-local'} -REACTION_NAME.update({i: '(n,n{})'.format(i - 50) for i in range(51, 91)}) -REACTION_NAME.update({i: '(n,p{})'.format(i - 600) for i in range(600, 649)}) -REACTION_NAME.update({i: '(n,d{})'.format(i - 650) for i in range(650, 699)}) -REACTION_NAME.update({i: '(n,t{})'.format(i - 700) for i in range(700, 749)}) -REACTION_NAME.update({i: '(n,3He{})'.format(i - 750) for i in range(750, 799)}) -REACTION_NAME.update({i: '(n,a{})'.format(i - 800) for i in range(800, 849)}) -REACTION_NAME.update({i: '(n,2n{})'.format(i - 875) for i in range(875, 891)}) +REACTION_NAME.update({i: f'(n,n{i - 50})' for i in range(51, 91)}) +REACTION_NAME.update({i: f'(n,p{i - 600})' for i in range(600, 649)}) +REACTION_NAME.update({i: f'(n,d{i - 650})' for i in range(650, 699)}) +REACTION_NAME.update({i: f'(n,t{i - 700})' for i in range(700, 749)}) +REACTION_NAME.update({i: f'(n,3He{i - 750})' for i in range(750, 799)}) +REACTION_NAME.update({i: f'(n,a{i - 800})' for i in range(800, 849)}) +REACTION_NAME.update({i: f'(n,2n{i - 875})' for i in range(875, 891)}) REACTION_MT = {name: mt for mt, name in REACTION_NAME.items()} REACTION_MT['fission'] = 18 @@ -80,6 +80,14 @@ def _get_products(ev, mt): mt : int The MT value of the reaction to get products for + Raises + ------ + IOError + When the Kalbach-Mann systematics is used, but the product + is not defined in the 'center-of-mass' system. The breakup logic + is not implemented which can lead to this error being raised while + the definition of the product is correct. + Returns ------- products : list of openmc.data.Product @@ -101,7 +109,6 @@ def _get_products(ev, mt): za = int(params[0]) awr = params[1] - lip = params[2] law = params[3] if za == 0: @@ -112,7 +119,7 @@ def _get_products(ev, mt): p = Product('electron') else: Z, A = divmod(za, 1000) - p = Product('{}{}'.format(ATOMIC_SYMBOL[Z], A)) + p = Product(f'{ATOMIC_SYMBOL[Z]}{A}') p.yield_ = yield_ @@ -141,7 +148,26 @@ def _get_products(ev, mt): if lang == 1: p.distribution = [CorrelatedAngleEnergy.from_endf(file_obj)] elif lang == 2: - p.distribution = [KalbachMann.from_endf(file_obj)] + # Products need to be described in the center-of-mass system + product_center_of_mass = False + if reference_frame == 'center-of-mass': + product_center_of_mass = True + elif reference_frame == 'light-heavy': + product_center_of_mass = (awr <= 4.0) + # TODO: 'breakup' logic not implemented + + if product_center_of_mass is False: + raise IOError( + "Kalbach-Mann representation must be defined in the " + "'center-of-mass' system" + ) + + zat = ev.target["atomic_number"] * 1000 + ev.target["mass_number"] + projectile_mass = ev.projectile["mass"] + p.distribution = [KalbachMann.from_endf(file_obj, + za, + zat, + projectile_mass)] elif law == 2: # Discrete two-body scattering @@ -528,12 +554,12 @@ def _get_activation_products(ev, rx): Z, A = divmod(items[2], 1000) excited_state = items[3] - # Get GND name for product + # Get GNDS name for product symbol = ATOMIC_SYMBOL[Z] if excited_state > 0: - name = '{}{}_e{}'.format(symbol, A, excited_state) + name = f'{symbol}{A}_e{excited_state}' else: - name = '{}{}'.format(symbol, A) + name = f'{symbol}{A}' p = Product(name) if mf == 9: @@ -630,8 +656,7 @@ def _get_photon_products_ace(ace, rx): photon.yield_ = Tabulated1D(energy, yield_) else: - raise ValueError("MFTYPE must be 12, 13, 16. Got {0}".format( - mftype)) + raise ValueError(f"MFTYPE must be 12, 13, 16. Got {mftype}") # ================================================================== # Photon energy distribution @@ -820,60 +845,60 @@ def __init__(self, mt): def __repr__(self): if self.mt in REACTION_NAME: - return "".format(self.mt, REACTION_NAME[self.mt]) + return f"" else: - return "".format(self.mt) + return f"" @property def center_of_mass(self): return self._center_of_mass - @property - def redundant(self): - return self._redundant - - @property - def q_value(self): - return self._q_value - - @property - def products(self): - return self._products - - @property - def derived_products(self): - return self._derived_products - - @property - def xs(self): - return self._xs - @center_of_mass.setter def center_of_mass(self, center_of_mass): cv.check_type('center of mass', center_of_mass, (bool, np.bool_)) self._center_of_mass = center_of_mass + @property + def redundant(self): + return self._redundant + @redundant.setter def redundant(self, redundant): cv.check_type('redundant', redundant, (bool, np.bool_)) self._redundant = redundant + @property + def q_value(self): + return self._q_value + @q_value.setter def q_value(self, q_value): cv.check_type('Q value', q_value, Real) self._q_value = q_value + @property + def products(self): + return self._products + @products.setter def products(self, products): cv.check_type('reaction products', products, Iterable, Product) self._products = products + @property + def derived_products(self): + return self._derived_products + @derived_products.setter def derived_products(self, derived_products): cv.check_type('reaction derived products', derived_products, Iterable, Product) self._derived_products = derived_products + @property + def xs(self): + return self._xs + @xs.setter def xs(self, xs): cv.check_type('reaction cross section dictionary', xs, MutableMapping) @@ -894,9 +919,9 @@ def to_hdf5(self, group): group.attrs['mt'] = self.mt if self.mt in REACTION_NAME: - group.attrs['label'] = np.string_(REACTION_NAME[self.mt]) + group.attrs['label'] = np.bytes_(REACTION_NAME[self.mt]) else: - group.attrs['label'] = np.string_(self.mt) + group.attrs['label'] = np.bytes_(self.mt) group.attrs['Q_value'] = self.q_value group.attrs['center_of_mass'] = 1 if self.center_of_mass else 0 group.attrs['redundant'] = 1 if self.redundant else 0 @@ -907,7 +932,7 @@ def to_hdf5(self, group): threshold_idx = getattr(self.xs[T], '_threshold_idx', 0) dset.attrs['threshold_idx'] = threshold_idx for i, p in enumerate(self.products): - pgroup = group.create_group('product_{}'.format(i)) + pgroup = group.create_group(f'product_{i}') p.to_hdf5(pgroup) @classmethod @@ -959,7 +984,7 @@ def from_hdf5(cls, group, energy): # Read reaction products for i in range(n_product): - pgroup = group['product_{}'.format(i)] + pgroup = group[f'product_{i}'] rx.products.append(Product.from_hdf5(pgroup)) return rx diff --git a/openmc/data/reconstruct.pyx b/openmc/data/reconstruct.pyx index f63a155b15d..cd0bbc38b95 100644 --- a/openmc/data/reconstruct.pyx +++ b/openmc/data/reconstruct.pyx @@ -299,8 +299,8 @@ def reconstruct_slbw(slbw, double E): # Determine shift and penetration at modified energy if slbw._competitive[i]: Ex = E + slbw.q_value[l]*(A + 1)/A - rhoc = slbw.channel_radius[l](Ex) - rhochat = slbw.scattering_radius[l](Ex) + rhoc = k*slbw.channel_radius[l](Ex) + rhochat = k*slbw.scattering_radius[l](Ex) P_c, S_c = penetration_shift(l, rhoc) if Ex < 0: P_c = 0 diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index 7d27ea7cc3c..31e230df588 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -46,6 +46,12 @@ def __iter__(self): def ranges(self): return self._ranges + @ranges.setter + def ranges(self, ranges): + cv.check_type('resonance ranges', ranges, MutableSequence) + self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', + ranges) + @property def resolved(self): resolved_ranges = [r for r in self.ranges @@ -65,12 +71,6 @@ def unresolved(self): else: return None - @ranges.setter - def ranges(self, ranges): - cv.check_type('resonance ranges', ranges, MutableSequence) - self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', - ranges) - @classmethod def from_endf(cls, ev): """Generate resonance data from an ENDF evaluation. @@ -93,9 +93,8 @@ def from_endf(cls, ev): n_isotope = items[4] # Number of isotopes ranges = [] - for iso in range(n_isotope): + for _ in range(n_isotope): items = get_cont_record(file_obj) - abundance = items[1] fission_widths = (items[3] == 1) # fission widths are given? n_ranges = items[4] # number of resonance energy ranges @@ -424,14 +423,12 @@ def _prepare_resonances(self): # Determine penetration and shift corresponding to resonance energy k = wave_number(A, E) rho = k*self.channel_radius[l](E) - rhohat = k*self.scattering_radius[l](E) p[i], s[i] = penetration_shift(l, rho) # Determine penetration at modified energy for competitive reaction if gx > 0: Ex = E + self.q_value[l]*(A + 1)/A rho = k*self.channel_radius[l](Ex) - rhohat = k*self.scattering_radius[l](Ex) px[i], sx[i] = penetration_shift(l, rho) else: px[i] = sx[i] = 0.0 @@ -680,7 +677,6 @@ def _prepare_resonances(self): # Determine penetration and shift corresponding to resonance energy k = wave_number(A, E) rho = k*self.channel_radius[l](E) - rhohat = k*self.scattering_radius[l](E) p[i], s[i] = penetration_shift(l, rho) df['p'] = p @@ -834,7 +830,7 @@ def from_endf(cls, ev, file_obj, items): elif mt == 102: columns.append('captureWidth') else: - columns.append('width (MT={})'.format(mt)) + columns.append(f'width (MT={mt})') # Create Pandas dataframe with resonance parameters parameters = pd.DataFrame.from_records(records, columns=columns) @@ -900,7 +896,7 @@ def __init__(self, spin, parity, channels, parameters): self.parameters = parameters def __repr__(self): - return ''.format(self.spin, self.parity) + return f'' class Unresolved(ResonanceRange): diff --git a/openmc/data/resonance_covariance.py b/openmc/data/resonance_covariance.py index 9e80e52f2c0..7096570449c 100644 --- a/openmc/data/resonance_covariance.py +++ b/openmc/data/resonance_covariance.py @@ -93,10 +93,8 @@ def from_endf(cls, ev, resonances): n_isotope = items[4] # Number of isotopes ranges = [] - for iso in range(n_isotope): + for _ in range(n_isotope): items = endf.get_cont_record(file_obj) - abundance = items[1] - fission_widths = (items[3] == 1) # Flag for fission widths n_ranges = items[4] # Number of resonance energy ranges for j in range(n_ranges): @@ -241,14 +239,14 @@ def sample(self, n_samples): samples = [] # Handling MLBW/SLBW sampling + rng = np.random.default_rng() if formalism == 'mlbw' or formalism == 'slbw': params = ['energy', 'neutronWidth', 'captureWidth', 'fissionWidth', 'competitiveWidth'] param_list = params[:mpar] mean_array = parameters[param_list].values mean = mean_array.flatten() - par_samples = np.random.multivariate_normal(mean, cov, - size=n_samples) + par_samples = rng.multivariate_normal(mean, cov, size=n_samples) spin = parameters['J'].values l_value = parameters['L'].values for sample in par_samples: @@ -279,8 +277,7 @@ def sample(self, n_samples): param_list = params[:mpar] mean_array = parameters[param_list].values mean = mean_array.flatten() - par_samples = np.random.multivariate_normal(mean, cov, - size=n_samples) + par_samples = rng.multivariate_normal(mean, cov, size=n_samples) spin = parameters['J'].values l_value = parameters['L'].values for sample in par_samples: @@ -378,7 +375,6 @@ def from_endf(cls, ev, file_obj, items, resonance): # Other scatter radius parameters items = endf.get_cont_record(file_obj) - target_spin = items[0] lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form nls = items[4] # number of l-values @@ -387,8 +383,6 @@ def from_endf(cls, ev, file_obj, items, resonance): items = endf.get_cont_record(file_obj) # Number of short range type resonance covariances num_short_range = items[4] - # Number of long range type resonance covariances - num_long_range = items[5] # Read resonance widths, J values, etc records = [] @@ -421,7 +415,6 @@ def from_endf(cls, ev, file_obj, items, resonance): # compact correlations elif lcomp == 2: items, values = endf.get_list_record(file_obj) - mean = items num_res = items[5] energy = values[0::12] spin = values[1::12] @@ -613,20 +606,14 @@ def from_endf(cls, ev, file_obj, items, resonance): # Other scatter radius parameters items = endf.get_cont_record(file_obj) - target_spin = items[0] lcomp = items[3] # Flag for compatibility 0, 1, 2 - 2 is compact form - nls = items[4] # Number of l-values # Build covariance matrix for General Resolved Resonance Formats if lcomp == 1: items = endf.get_cont_record(file_obj) # Number of short range type resonance covariances num_short_range = items[4] - # Number of long range type resonance covariances - num_long_range = items[5] # Read resonance widths, J values, etc - channel_radius = {} - scattering_radius = {} records = [] for i in range(num_short_range): items, values = endf.get_list_record(file_obj) diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index d0adbc4fe7b..f5841d9c90b 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -19,68 +19,78 @@ from .data import K_BOLTZMANN, ATOMIC_SYMBOL, EV_PER_MEV, isotopes from .ace import Table, get_table, Library from .angle_energy import AngleEnergy -from .function import Tabulated1D, Function1D +from .function import Tabulated1D, Function1D, Sum from .njoy import make_ace_thermal from .thermal_angle_energy import (CoherentElasticAE, IncoherentElasticAE, IncoherentElasticAEDiscrete, IncoherentInelasticAEDiscrete, - IncoherentInelasticAE) + IncoherentInelasticAE, MixedElasticAE) _THERMAL_NAMES = { - 'c_Al27': ('al', 'al27', 'al-27'), - 'c_Al_in_Sapphire': ('asap00', 'asap'), - 'c_Be': ('be', 'be-metal', 'be-met', 'be00'), + 'c_Al27': ('al', 'al27', 'al-27', '13-al- 27'), + 'c_Al_in_Al2O3': ('asap00', 'asap', 'al(al2o3)'), + 'c_Be': ('be', 'be-metal', 'be-met', 'be00', 'be-metal', 'be metal', '4-be'), 'c_BeO': ('beo',), - 'c_Be_in_BeO': ('bebeo', 'be-beo', 'be-o', 'be/o', 'bbeo00'), + 'c_Be_in_BeO': ('bebeo', 'be-beo', 'be-o', 'be/o', 'bbeo00', 'be(beo)'), 'c_Be_in_Be2C': ('bebe2c',), - 'c_C6H6': ('benz', 'c6h6'), - 'c_C_in_SiC': ('csic', 'c-sic'), - 'c_Ca_in_CaH2': ('cah', 'cah00', 'cacah2'), - 'c_D_in_D2O': ('dd2o', 'd-d2o', 'hwtr', 'hw', 'dhw00'), + 'c_Be_in_FLiBe': ('beflib', 'be(flibe)'), + 'c_C6H6': ('benz', 'c6h6', 'benzine'), + 'c_C_in_SiC': ('csic', 'c-sic', 'c(3c-sic)'), + 'c_Ca_in_CaH2': ('cah', 'cah00', 'cacah2', 'ca(cah2)'), + 'c_D_in_D2O': ('dd2o', 'd-d2o', 'hwtr', 'hw', 'dhw00', 'd(d2o)'), 'c_D_in_D2O_ice': ('dice',), - 'c_Fe56': ('fe', 'fe56', 'fe-56'), - 'c_Graphite': ('graph', 'grph', 'gr', 'gr00'), - 'c_Graphite_10p': ('grph10',), - 'c_Graphite_30p': ('grph30',), - 'c_H_in_CaH2': ('hcah2', 'hca00'), - 'c_H_in_CH2': ('hch2', 'poly', 'pol', 'h-poly', 'pol00'), - 'c_H_in_CH4_liquid': ('lch4', 'lmeth'), - 'c_H_in_CH4_solid': ('sch4', 'smeth'), + 'c_F_in_FLiBe': ('fflibe', 'f(flibe)'), + 'c_Fe56': ('fe', 'fe56', 'fe-56', '26-fe- 56'), + 'c_Graphite': ('graph', 'grph', 'gr', 'gr00', 'graphite'), + 'c_Graphite_10p': ('grph10', '10p graphit'), + 'c_Graphite_30p': ('grph30', '30p graphit'), + 'c_H_in_C5O2H8': ('lucite', 'c5o2h8', 'h-luci', 'h(lucite)'), + 'c_H_in_CaH2': ('hcah2', 'hca00', 'h(cah2)'), + 'c_H_in_CH2': ('hch2', 'poly', 'pol', 'h-poly', 'pol00', 'h(ch2)'), + 'c_H_in_CH4_liquid': ('lch4', 'lmeth', 'l-ch4'), + 'c_H_in_CH4_solid': ('sch4', 'smeth', 's-ch4'), 'c_H_in_CH4_solid_phase_II': ('sch4p2',), - 'c_H_in_H2O': ('hh2o', 'h-h2o', 'lwtr', 'lw', 'lw00'), - 'c_H_in_H2O_solid': ('hice', 'h-ice', 'ice00'), - 'c_H_in_C5O2H8': ('lucite', 'c5o2h8', 'h-luci'), - 'c_H_in_Mesitylene': ('mesi00', 'mesi'), - 'c_H_in_Toluene': ('tol00', 'tol'), - 'c_H_in_YH2': ('hyh2', 'h-yh2'), - 'c_H_in_ZrH': ('hzrh', 'h-zrh', 'h-zr', 'h/zr', 'hzr', 'hzr00'), - 'c_Mg24': ('mg', 'mg24', 'mg00'), - 'c_O_in_Sapphire': ('osap00', 'osap'), - 'c_O_in_BeO': ('obeo', 'o-beo', 'o-be', 'o/be', 'obeo00'), - 'c_O_in_D2O': ('od2o', 'o-d2o', 'ohw00'), - 'c_O_in_H2O_ice': ('oice', 'o-ice'), - 'c_O_in_UO2': ('ouo2', 'o-uo2', 'o2-u', 'o2/u', 'ouo200'), - 'c_N_in_UN': ('n-un',), - 'c_ortho_D': ('orthod', 'orthoD', 'dortho', 'od200', 'ortod'), - 'c_ortho_H': ('orthoh', 'orthoH', 'hortho', 'oh200', 'ortoh'), - 'c_Si28': ('si00', 'sili'), - 'c_Si_in_SiC': ('sisic', 'si-sic'), - 'c_SiO2_alpha': ('sio2', 'sio2a'), - 'c_SiO2_beta': ('sio2b',), - 'c_para_D': ('parad', 'paraD', 'dpara', 'pd200'), - 'c_para_H': ('parah', 'paraH', 'hpara', 'ph200'), - 'c_U_in_UN': ('u-un',), - 'c_U_in_UO2': ('uuo2', 'u-uo2', 'u-o2', 'u/o2', 'uuo200'), - 'c_Y_in_YH2': ('yyh2', 'y-yh2'), - 'c_Zr_in_ZrH': ('zrzrh', 'zr-zrh', 'zr-h', 'zr/h') + 'c_H_in_H2O': ('hh2o', 'h-h2o', 'lwtr', 'lw', 'lw00', 'h(h2o)'), + 'c_H_in_H2O_solid': ('hice', 'h-ice', 'ice00', 'h(ice-ih)', 'h(ice)'), + 'c_H_in_HF': ('hhf', 'h(hf)'), + 'c_H_in_Mesitylene': ('mesi00', 'mesi', 'mesi-phii'), + 'c_H_in_ParaffinicOil': ('hparaf', 'h(paraffin'), + 'c_H_in_Toluene': ('tol00', 'tol', 'tolue-phii'), + 'c_H_in_UH3': ('huh3', 'h(uh3)'), + 'c_H_in_YH2': ('hyh2', 'h-yh2', 'h(yh2)'), + 'c_H_in_ZrH': ('hzrh', 'h-zrh', 'h-zr', 'h/zr', 'hzr', 'hzr00', 'h(zrh)'), + 'c_H_in_ZrH2': ('hzrh2', 'h(zrh2)'), + 'c_H_in_ZrHx': ('hzrhx', 'h(zrhx)'), + 'c_Li_in_FLiBe': ('liflib', 'li(flibe)'), + 'c_Mg24': ('mg', 'mg24', 'mg00', '24-mg'), + 'c_N_in_UN': ('n-un', 'n(un)', 'n(un) l'), + 'c_O_in_Al2O3': ('osap00', 'osap', 'o(al2o3)'), + 'c_O_in_BeO': ('obeo', 'o-beo', 'o-be', 'o/be', 'obeo00', 'o(beo)'), + 'c_O_in_D2O': ('od2o', 'o-d2o', 'ohw00', 'o(d2o)'), + 'c_O_in_H2O_solid': ('oice', 'o-ice', 'o(ice-ih)'), + 'c_O_in_UO2': ('ouo2', 'o-uo2', 'o2-u', 'o2/u', 'ouo200', 'o(uo2)'), + 'c_ortho_D': ('orthod', 'orthoD', 'dortho', 'od200', 'ortod', 'ortho-d'), + 'c_ortho_H': ('orthoh', 'orthoH', 'hortho', 'oh200', 'ortoh', 'ortho-h'), + 'c_para_D': ('parad', 'paraD', 'dpara', 'pd200', 'para-d'), + 'c_para_H': ('parah', 'paraH', 'hpara', 'ph200', 'para-h'), + 'c_Si28': ('si00', 'sili', 'si'), + 'c_Si_in_SiC': ('sisic', 'si-sic', 'si(3c-sic)'), + 'c_SiO2_alpha': ('sio2', 'sio2a', 'sio2alpha'), + 'c_SiO2_beta': ('sio2b', 'sio2beta'), + 'c_U_in_UN': ('u-un', 'u(un)', 'u(un) l'), + 'c_U_in_UO2': ('uuo2', 'u-uo2', 'u-o2', 'u/o2', 'uuo200', 'u(uo2)'), + 'c_Y_in_YH2': ('yyh2', 'y-yh2', 'y(yh2)'), + 'c_Zr_in_ZrH': ('zrzrh', 'zr-zrh', 'zr-h', 'zr/h', 'zr(zrh)'), + 'c_Zr_in_ZrH2': ('zrzrh2', 'zr(zrh2)'), + 'c_Zr_in_ZrHx': ('zrzrhx', 'zr(zrhx)'), } def _temperature_str(T): # round() normally returns an int when called with a single argument, but # numpy floats overload rounding to return another float - return "{}K".format(int(round(T))) + return f"{int(round(T))}K" def get_thermal_name(name): @@ -94,7 +104,7 @@ def get_thermal_name(name): Returns ------- str - GND-format thermal scattering name + GNDS-format thermal scattering name """ if name in _THERMAL_NAMES: @@ -183,15 +193,15 @@ def __len__(self): def bragg_edges(self): return self._bragg_edges - @property - def factors(self): - return self._factors - @bragg_edges.setter def bragg_edges(self, bragg_edges): cv.check_type('Bragg edges', bragg_edges, Iterable, Real) self._bragg_edges = np.asarray(bragg_edges) + @property + def factors(self): + return self._factors + @factors.setter def factors(self, factors): cv.check_type('structure factor cumulative sums', factors, @@ -211,7 +221,7 @@ def to_hdf5(self, group, name): """ dataset = group.create_dataset(name, data=np.vstack( [self.bragg_edges, self.factors])) - dataset.attrs['type'] = np.string_(type(self).__name__) + dataset.attrs['type'] = np.bytes_(type(self).__name__) @classmethod def from_hdf5(cls, dataset): @@ -284,7 +294,7 @@ def to_hdf5(self, group, name): """ data = np.array([self.bound_xs, self.debye_waller]) dataset = group.create_dataset(name, data=data) - dataset.attrs['type'] = np.string_(type(self).__name__) + dataset.attrs['type'] = np.bytes_(type(self).__name__) @classmethod def from_hdf5(cls, dataset): @@ -386,7 +396,7 @@ class ThermalScattering(EqualityMixin): Parameters ---------- name : str - Name of the material using GND convention, e.g. c_H_in_H2O + Name of the material using GNDS convention, e.g. c_H_in_H2O atomic_weight_ratio : float Atomic mass ratio of the target nuclide. kTs : Iterable of float @@ -405,7 +415,7 @@ class ThermalScattering(EqualityMixin): Inelastic scattering cross section derived in the incoherent approximation name : str - Name of the material using GND convention, e.g. c_H_in_H2O + Name of the material using GNDS convention, e.g. c_H_in_H2O temperatures : Iterable of str List of string representations the temperatures of the target nuclide in the data set. The temperatures are strings of the temperature, @@ -429,7 +439,7 @@ def __init__(self, name, atomic_weight_ratio, energy_max, kTs): def __repr__(self): if hasattr(self, 'name'): - return "".format(self.name) + return f"" else: return "" @@ -454,7 +464,7 @@ def export_to_hdf5(self, path, mode='a', libver='earliest'): """ # Open file and write version with h5py.File(str(path), mode, libver=libver) as f: - f.attrs['filetype'] = np.string_('data_thermal') + f.attrs['filetype'] = np.bytes_('data_thermal') f.attrs['version'] = np.array(HDF5_VERSION) # Write basic data @@ -481,7 +491,7 @@ def add_temperature_from_ace(self, ace_or_filename, name=None): ACE table to read from. If given as a string, it is assumed to be the filename for the ACE file. name : str - GND-conforming name of the material, e.g. c_H_in_H2O. If none is + GNDS-conforming name of the material, e.g. c_H_in_H2O. If none is passed, the appropriate name is guessed based on the name of the ACE table. @@ -496,7 +506,7 @@ def add_temperature_from_ace(self, ace_or_filename, name=None): # Check if temprature already exists strT = data.temperatures[0] if strT in self.temperatures: - warn('S(a,b) data at T={} already exists.'.format(strT)) + warn(f'S(a,b) data at T={strT} already exists.') return # Check that name matches @@ -586,7 +596,7 @@ def from_ace(cls, ace_or_filename, name=None): ACE table to read from. If given as a string, it is assumed to be the filename for the ACE file. name : str - GND-conforming name of the material, e.g. c_H_in_H2O. If none is + GNDS-conforming name of the material, e.g. c_H_in_H2O. If none is passed, the appropriate name is guessed based on the name of the ACE table. @@ -604,8 +614,9 @@ def from_ace(cls, ace_or_filename, name=None): # Get new name that is GND-consistent ace_name, xs = ace.name.split('.') if not xs.endswith('t'): - raise TypeError("{} is not a thermal scattering ACE table.".format(ace)) - name = get_thermal_name(ace_name) + raise TypeError(f"{ace} is not a thermal scattering ACE table.") + if name is None: + name = get_thermal_name(ace_name) # Assign temperature to the running list kTs = [ace.temperature*EV_PER_MEV] @@ -659,12 +670,50 @@ def from_ace(cls, ace_or_filename, name=None): mu_i = [] for j in range(n_energy_out[i]): mu = ace.xss[idx + 4:idx + 4 + n_mu] + # The equiprobable angles produced by NJOY are not always + # sorted. This is problematic when the smearing algorithm + # is applied when sampling the angles. We sort the angles + # here, because they are equiprobable, so the order + # doesn't matter. + mu.sort() + + # Older versions of NJOY had a bug, and the discrete + # scattering angles could sometimes be less than -1 or + # greater than 1. We check for this here, and warn users. + if mu[0] < -1. or mu[-1] > 1.: + warn('S(a,b) scattering angle for incident energy index ' + f'{i} and exit energy index {j} outside of the ' + 'interval [-1, 1].') + p_mu = 1. / n_mu * np.ones(n_mu) mu_ij = Discrete(mu, p_mu) mu_ij.c = np.cumsum(p_mu) mu_i.append(mu_ij) idx += 3 + n_mu + # Check if the CDF for the outgoing energy distribution starts + # at 0. For NJOY and FRENDY evaluations, this is never the case, + # and can very rarely lead to negative energies when sampling + # the outgoing energy. From Eq. 7.6 of the ENDF manual, we can + # add an outgoing energy 0 eV that has a PDF of 0 (and of + # course, a CDF of 0 as well). + if eout_i.c[0] > 0.: + eout_i.x = np.insert(eout_i.x, 0, 0.) + eout_i.p = np.insert(eout_i.p, 0, 0.) + eout_i.c = np.insert(eout_i.c, 0, 0.) + + # For this added outgoing energy (of 0 eV) we add a set of + # isotropic discrete angles. + dmu = 2. / n_mu + mu = np.linspace(-1. + 0.5*dmu, 1. - 0.5*dmu, n_mu) + p_mu = 1. / n_mu * np.ones(n_mu) + mu_0 = Discrete(mu, p_mu) + mu_0.c = np.cumsum(p_mu) + mu_i.insert(0, mu_0) + # We don't worry about renormalizing the outgoing energy PDF/CDF + # after this manipulation, because it never seems to be + # normalized to begin with (at least with NJOY). + energy_out.append(eout_i) mu_out.append(mu_i) @@ -683,29 +732,53 @@ def from_ace(cls, ace_or_filename, name=None): # Incoherent/coherent elastic scattering cross section idx = ace.jxs[4] - n_mu = ace.nxs[6] + 1 if idx != 0: - n_energy = int(ace.xss[idx]) - energy = ace.xss[idx + 1: idx + 1 + n_energy]*EV_PER_MEV - P = ace.xss[idx + 1 + n_energy: idx + 1 + 2 * n_energy] - - if ace.nxs[5] == 4: + if ace.nxs[5] in (4, 5): # Coherent elastic - xs = CoherentElastic(energy, P*EV_PER_MEV) - distribution = CoherentElasticAE(xs) + n_energy = int(ace.xss[idx]) + energy = ace.xss[idx + 1: idx + 1 + n_energy]*EV_PER_MEV + P = ace.xss[idx + 1 + n_energy: idx + 1 + 2 * n_energy] + coherent_xs = CoherentElastic(energy, P*EV_PER_MEV) + coherent_dist = CoherentElasticAE(coherent_xs) # Coherent elastic shouldn't have angular distributions listed + n_mu = ace.nxs[6] + 1 assert n_mu == 0 - else: - # Incoherent elastic - xs = Tabulated1D(energy, P) + + if ace.nxs[5] in (3, 5): + # Incoherent elastic scattering -- first determine if both + # incoherent and coherent are present (mixed) + mixed = (ace.nxs[5] == 5) + + # Get cross section values + idx = ace.jxs[7] if mixed else ace.jxs[4] + n_energy = int(ace.xss[idx]) + energy = ace.xss[idx + 1: idx + 1 + n_energy]*EV_PER_MEV + values = ace.xss[idx + 1 + n_energy: idx + 1 + 2 * n_energy] + + incoherent_xs = Tabulated1D(energy, values) # Angular distribution + n_mu = (ace.nxs[8] if mixed else ace.nxs[6]) + 1 assert n_mu > 0 - idx = ace.jxs[6] + idx = ace.jxs[9] if mixed else ace.jxs[6] mu_out = ace.xss[idx:idx + n_energy * n_mu] mu_out.shape = (n_energy, n_mu) - distribution = IncoherentElasticAEDiscrete(mu_out) + incoherent_dist = IncoherentElasticAEDiscrete(mu_out) + + if ace.nxs[5] == 3: + xs = incoherent_xs + distribution = incoherent_dist + elif ace.nxs[5] == 4: + xs = coherent_xs + distribution = coherent_dist + else: + # Create mixed cross section -- note that coherent must come + # first due to assumption on C++ side + xs = Sum([coherent_xs, incoherent_xs]) + + # Create mixed distribution + distribution = MixedElasticAE(coherent_dist, incoherent_dist) table.elastic = ThermalScatteringReaction({T: xs}, {T: distribution}) @@ -773,9 +846,10 @@ def from_njoy(cls, filename, filename_thermal, temperatures=None, # Create instance from ACE tables within library lib = Library(kwargs['ace']) - data = cls.from_ace(lib.tables[0]) + name = kwargs.get('table_name') + data = cls.from_ace(lib.tables[0], name=name) for table in lib.tables[1:]: - data.add_temperature_from_ace(table) + data.add_temperature_from_ace(table, name=name) # Load ENDF data to replace incoherent elastic if use_endf_data: @@ -790,7 +864,7 @@ def from_njoy(cls, filename, filename_thermal, temperatures=None, # Replace ACE data with ENDF data rx, rx_endf = data.elastic, data_endf.elastic for t in temperatures: - if isinstance(rx_endf.xs[t], IncoherentElastic): + if isinstance(rx_endf.xs[t], (IncoherentElastic, Sum)): rx.xs[t] = rx_endf.xs[t] rx.distribution[t] = rx_endf.distribution[t] @@ -820,20 +894,14 @@ def from_endf(cls, ev_or_filename): # Read coherent/incoherent elastic data elastic = None if (7, 2) in ev.section: - xs = {} - distribution = {} - - file_obj = StringIO(ev.section[7, 2]) - lhtr = endf.get_head_record(file_obj)[2] - if lhtr == 1: - # coherent elastic - + # Define helper functions to avoid duplication + def get_coherent_elastic(file_obj): # Get structure factor at first temperature params, S = endf.get_tab1_record(file_obj) strT = _temperature_str(params[0]) n_temps = params[2] bragg_edges = S.x - xs[strT] = CoherentElastic(bragg_edges, S.y) + xs = {strT: CoherentElastic(bragg_edges, S.y)} distribution = {strT: CoherentElasticAE(xs[strT])} # Get structure factor for subsequent temperatures @@ -842,15 +910,34 @@ def from_endf(cls, ev_or_filename): strT = _temperature_str(params[0]) xs[strT] = CoherentElastic(bragg_edges, S) distribution[strT] = CoherentElasticAE(xs[strT]) + return xs, distribution - elif lhtr == 2: - # incoherent elastic + def get_incoherent_elastic(file_obj): params, W = endf.get_tab1_record(file_obj) bound_xs = params[0] + xs = {} + distribution = {} for T, debye_waller in zip(W.x, W.y): strT = _temperature_str(T) xs[strT] = IncoherentElastic(bound_xs, debye_waller) distribution[strT] = IncoherentElasticAE(debye_waller) + return xs, distribution + + file_obj = StringIO(ev.section[7, 2]) + lhtr = endf.get_head_record(file_obj)[2] + if lhtr == 1: + # coherent elastic + xs, distribution = get_coherent_elastic(file_obj) + elif lhtr == 2: + # incoherent elastic + xs, distribution = get_incoherent_elastic(file_obj) + elif lhtr == 3: + # mixed coherent / incoherent elastic + xs_c, dist_c = get_coherent_elastic(file_obj) + xs_i, dist_i = get_incoherent_elastic(file_obj) + assert sorted(xs_c) == sorted(xs_i) + xs = {T: Sum([xs_c[T], xs_i[T]]) for T in xs_c} + distribution = {T: MixedElasticAE(dist_c[T], dist_i[T]) for T in dist_c} elastic = ThermalScatteringReaction(xs, distribution) diff --git a/openmc/data/thermal_angle_energy.py b/openmc/data/thermal_angle_energy.py index 05393e7bb79..0dd2a0b7a51 100644 --- a/openmc/data/thermal_angle_energy.py +++ b/openmc/data/thermal_angle_energy.py @@ -2,6 +2,7 @@ from .angle_energy import AngleEnergy from .correlated import CorrelatedAngleEnergy +import openmc.data class CoherentElasticAE(AngleEnergy): @@ -42,8 +43,28 @@ def to_hdf5(self, group): HDF5 group to write to """ - group.attrs['type'] = np.string_('coherent_elastic') - group['coherent_xs'] = group.parent['xs'] + group.attrs['type'] = np.bytes_('coherent_elastic') + self.coherent_xs.to_hdf5(group, 'coherent_xs') + + @classmethod + def from_hdf5(cls, group): + """Generate coherent elastic distribution from HDF5 data + + .. versionadded:: 0.13.1 + + Parameters + ---------- + group : h5py.Group + HDF5 group to read from + + Returns + ------- + openmc.data.CoherentElasticAE + Coherent elastic distribution + + """ + coherent_xs = openmc.data.CoherentElastic.from_hdf5(group['coherent_xs']) + return cls(coherent_xs) class IncoherentElasticAE(AngleEnergy): @@ -83,7 +104,7 @@ def to_hdf5(self, group): HDF5 group to write to """ - group.attrs['type'] = np.string_('incoherent_elastic') + group.attrs['type'] = np.bytes_('incoherent_elastic') group.create_dataset('debye_waller', data=self.debye_waller) @classmethod @@ -101,7 +122,7 @@ def from_hdf5(cls, group): Incoherent elastic distribution """ - return cls(group['debye_waller']) + return cls(group['debye_waller'][()]) class IncoherentElasticAEDiscrete(AngleEnergy): @@ -125,7 +146,7 @@ def to_hdf5(self, group): HDF5 group to write to """ - group.attrs['type'] = np.string_('incoherent_elastic_discrete') + group.attrs['type'] = np.bytes_('incoherent_elastic_discrete') group.create_dataset('mu_out', data=self.mu_out) @classmethod @@ -182,7 +203,7 @@ def to_hdf5(self, group): HDF5 group to write to """ - group.attrs['type'] = np.string_('incoherent_inelastic_discrete') + group.attrs['type'] = np.bytes_('incoherent_inelastic_discrete') group.create_dataset('energy_out', data=self.energy_out) group.create_dataset('mu_out', data=self.mu_out) group.create_dataset('skewed', data=self.skewed) @@ -210,3 +231,62 @@ def from_hdf5(cls, group): class IncoherentInelasticAE(CorrelatedAngleEnergy): _name = 'incoherent_inelastic' + + +class MixedElasticAE(AngleEnergy): + """Secondary distribution for mixed coherent/incoherent thermal elastic + + .. versionadded:: 0.13.1 + + Parameters + ---------- + coherent : AngleEnergy + Secondary distribution for coherent elastic scattering + incoherent : AngleEnergy + Secondary distribution for incoherent elastic scattering + + Attributes + ---------- + coherent : AngleEnergy + Secondary distribution for coherent elastic scattering + incoherent : AngleEnergy + Secondary distribution for incoherent elastic scattering + + """ + def __init__(self, coherent, incoherent): + self.coherent = coherent + self.incoherent = incoherent + + def to_hdf5(self, group): + """Write mixed elastic distribution to an HDF5 group + + Parameters + ---------- + group : h5py.Group + HDF5 group to write to + + """ + group.attrs['type'] = np.bytes_('mixed_elastic') + coherent_group = group.create_group('coherent') + self.coherent.to_hdf5(coherent_group) + incoherent_group = group.create_group('incoherent') + self.incoherent.to_hdf5(incoherent_group) + + @classmethod + def from_hdf5(cls, group): + """Generate mixed thermal elastic distribution from HDF5 data + + Parameters + ---------- + group : h5py.Group + HDF5 group to read from + + Returns + ------- + openmc.data.MixedElasticAE + Mixed thermal elastic distribution + + """ + coherent = AngleEnergy.from_hdf5(group['coherent']) + incoherent = AngleEnergy.from_hdf5(group['incoherent']) + return cls(coherent, incoherent) diff --git a/openmc/data/uncorrelated.py b/openmc/data/uncorrelated.py index 0361c9b37a3..141007b70a9 100644 --- a/openmc/data/uncorrelated.py +++ b/openmc/data/uncorrelated.py @@ -38,16 +38,16 @@ def __init__(self, angle=None, energy=None): def angle(self): return self._angle - @property - def energy(self): - return self._energy - @angle.setter def angle(self, angle): cv.check_type('uncorrelated angle distribution', angle, AngleDistribution) self._angle = angle + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('uncorrelated energy distribution', energy, @@ -63,7 +63,7 @@ def to_hdf5(self, group): HDF5 group to write to """ - group.attrs['type'] = np.string_('uncorrelated') + group.attrs['type'] = np.bytes_('uncorrelated') if self.angle is not None: angle_group = group.create_group('angle') self.angle.to_hdf5(angle_group) diff --git a/openmc/data/urr.py b/openmc/data/urr.py index 53961a50acb..f129c98f811 100644 --- a/openmc/data/urr.py +++ b/openmc/data/urr.py @@ -79,51 +79,51 @@ def __init__(self, energy, table, interpolation, inelastic_flag=-1, def absorption_flag(self): return self._absorption_flag - @property - def energy(self): - return self._energy - - @property - def inelastic_flag(self): - return self._inelastic_flag - - @property - def interpolation(self): - return self._interpolation - - @property - def multiply_smooth(self): - return self._multiply_smooth - - @property - def table(self): - return self._table - @absorption_flag.setter def absorption_flag(self, absorption_flag): cv.check_type('absorption flag', absorption_flag, Integral) self._absorption_flag = absorption_flag + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('probability table energies', energy, Iterable, Real) self._energy = energy + @property + def inelastic_flag(self): + return self._inelastic_flag + @inelastic_flag.setter def inelastic_flag(self, inelastic_flag): cv.check_type('inelastic flag', inelastic_flag, Integral) self._inelastic_flag = inelastic_flag + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_value('interpolation', interpolation, [2, 5]) self._interpolation = interpolation + @property + def multiply_smooth(self): + return self._multiply_smooth + @multiply_smooth.setter def multiply_smooth(self, multiply_smooth): cv.check_type('multiply by smooth', multiply_smooth, bool) self._multiply_smooth = multiply_smooth + @property + def table(self): + return self._table + @table.setter def table(self, table): cv.check_type('probability tables', table, np.ndarray) diff --git a/openmc/deplete/__init__.py b/openmc/deplete/__init__.py index 00b29e3196f..8a9509e9009 100644 --- a/openmc/deplete/__init__.py +++ b/openmc/deplete/__init__.py @@ -4,26 +4,19 @@ A depletion front-end tool. """ -import sys -from unittest.mock import Mock - -from .dummy_comm import DummyCommunicator - -try: - from mpi4py import MPI - comm = MPI.COMM_WORLD -except ImportError: - MPI = Mock() - comm = DummyCommunicator() from .nuclide import * from .chain import * -from .operator import * +from .openmc_operator import * +from .coupled_operator import * +from .independent_operator import * +from .microxs import * from .reaction_rates import * from .atom_number import * +from .stepresult import * from .results import * -from .results_list import * from .integrators import * +from .transfer_rates import * from . import abc from . import cram from . import helpers diff --git a/openmc/deplete/_matrix_funcs.py b/openmc/deplete/_matrix_funcs.py index a606d739f72..c7f7df76fbd 100644 --- a/openmc/deplete/_matrix_funcs.py +++ b/openmc/deplete/_matrix_funcs.py @@ -77,4 +77,4 @@ def leqi_f4(chain, inputs, fission_yields=None): return (-dt ** 2 / (12 * dt_l * (dt + dt_l)) * f1 + (dt ** 2 + 2 * dt * dt_l + dt_l ** 2) / (12 * dt_l * (dt + dt_l)) * f2 - + (4 * dt * dt_l + 5 * dt_l ** 2) / (12 * dt_l * (dt + dt_l)) * f3) + + (4 * dt + 5 * dt_l) / (12 * (dt + dt_l)) * f3) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 7dca301f7ec..5d9b8a2403b 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -1,43 +1,45 @@ -"""function module. +"""abc module. -This module contains the Operator class, which is then passed to an integrator -to run a full depletion simulation. +This module contains Abstract Base Classes for implementing operator, integrator, depletion system solver, and operator helper classes """ +from __future__ import annotations from abc import ABC, abstractmethod from collections import namedtuple, defaultdict from collections.abc import Iterable, Callable from copy import deepcopy from inspect import signature from numbers import Real, Integral -import os from pathlib import Path -import sys import time +from typing import Optional, Union, Sequence from warnings import warn -from numpy import nonzero, empty, asarray +import numpy as np from uncertainties import ufloat -from openmc.data import DataLibrary -from openmc.lib import MaterialFilter, Tally -from openmc.checkvalue import check_type, check_greater_than -from . import comm -from .results import Results +from openmc.checkvalue import check_type, check_greater_than, PathLike +from openmc.mpi import comm +from openmc.utility_funcs import change_directory +from openmc import Material +from .stepresult import StepResult from .chain import Chain -from .results_list import ResultsList +from .results import Results from .pool import deplete +from .reaction_rates import ReactionRates +from .transfer_rates import TransferRates __all__ = [ - "OperatorResult", "TransportOperator", "ReactionRateHelper", - "NormalizationHelper", "FissionYieldHelper", "TalliedFissionYieldHelper", + "OperatorResult", "TransportOperator", + "ReactionRateHelper", "NormalizationHelper", "FissionYieldHelper", "Integrator", "SIIntegrator", "DepSystemSolver", "add_params"] _SECONDS_PER_MINUTE = 60 _SECONDS_PER_HOUR = 60*60 _SECONDS_PER_DAY = 24*60*60 +_SECONDS_PER_JULIAN_YEAR = 365.25*24*60*60 OperatorResult = namedtuple('OperatorResult', ['k', 'rates']) OperatorResult.__doc__ = """\ @@ -66,77 +68,41 @@ class TransportOperator(ABC): operator that takes a vector of material compositions and returns an eigenvalue and reaction rates. This abstract class sets the requirements for such a transport operator. Users should instantiate - :class:`openmc.deplete.Operator` rather than this class. + :class:`openmc.deplete.CoupledOperator` or + :class:`openmc.deplete.IndependentOperator` rather than this class. Parameters ---------- - chain_file : str, optional - Path to the depletion chain XML file. Defaults to the file - listed under ``depletion_chain`` in - :envvar:`OPENMC_CROSS_SECTIONS` environment variable. + chain_file : str + Path to the depletion chain XML file fission_q : dict, optional Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. - dilute_initial : float, optional - Initial atom density [atoms/cm^3] to add for nuclides that are zero - in initial condition to ensure they exist in the decay chain. - Only done for nuclides with reaction rates. - Defaults to 1.0e3. - prev_results : ResultsList, optional + prev_results : Results, optional Results from a previous depletion calculation. Attributes ---------- - dilute_initial : float - Initial atom density [atoms/cm^3] to add for nuclides that are zero - in initial condition to ensure they exist in the decay chain. - Only done for nuclides with reaction rates. - prev_res : ResultsList or None + output_dir : pathlib.Path + Path to output directory to save results. + prev_res : Results or None Results from a previous depletion calculation. ``None`` if no results are to be used. + chain : openmc.deplete.Chain + The depletion chain information necessary to form matrices and tallies. + """ - def __init__(self, chain_file=None, fission_q=None, dilute_initial=1.0e3, - prev_results=None): - self.dilute_initial = dilute_initial + def __init__(self, chain_file, fission_q=None, prev_results=None): self.output_dir = '.' # Read depletion chain - if chain_file is None: - chain_file = os.environ.get("OPENMC_DEPLETE_CHAIN", None) - if chain_file is None: - data = DataLibrary.from_xml() - # search for depletion_chain path from end of list - for lib in reversed(data.libraries): - if lib['type'] == 'depletion_chain': - break - else: - raise IOError( - "No chain specified, either manually or " - "under depletion_chain in environment variable " - "OPENMC_CROSS_SECTIONS.") - chain_file = lib['path'] - else: - warn("Use of OPENMC_DEPLETE_CHAIN is deprecated in favor " - "of adding depletion_chain to OPENMC_CROSS_SECTIONS", - FutureWarning) self.chain = Chain.from_xml(chain_file, fission_q) if prev_results is None: self.prev_res = None else: - check_type("previous results", prev_results, ResultsList) + check_type("previous results", prev_results, Results) self.prev_res = prev_results - @property - def dilute_initial(self): - """Initial atom density for nuclides with zero initial concentration""" - return self._dilute_initial - - @dilute_initial.setter - def dilute_initial(self, value): - check_type("dilute_initial", value, Real) - check_greater_than("dilute_initial", value, 0.0, equality=True) - self._dilute_initial = value - @abstractmethod def __call__(self, vec, source_rate): """Runs a simulation. @@ -155,21 +121,6 @@ def __call__(self, vec, source_rate): """ - def __enter__(self): - # Save current directory and move to specific output directory - self._orig_dir = os.getcwd() - if not self.output_dir.exists(): - self.output_dir.mkdir() # exist_ok parameter is 3.5+ - - # In Python 3.6+, chdir accepts a Path directly - os.chdir(str(self.output_dir)) - - return self.initial_condition() - - def __exit__(self, exc_type, exc_value, traceback): - self.finalize() - os.chdir(self._orig_dir) - @property def output_dir(self): return self._output_dir @@ -209,7 +160,7 @@ def finalize(self): pass @abstractmethod - def write_bos_data(self, step): + def write_bos_data(self, step: int): """Document beginning of step data for a given step Called at the beginning of a depletion step and at @@ -234,9 +185,11 @@ class ReactionRateHelper(ABC): Parameters ---------- n_nucs : int - Number of burnable nuclides tracked by :class:`openmc.deplete.Operator` + Number of burnable nuclides tracked by + :class:`openmc.deplete.abc.TransportOperator` n_react : int - Number of reactions tracked by :class:`openmc.deplete.Operator` + Number of reactions tracked by + :class:`openmc.deplete.abc.TransportOperator` Attributes ---------- @@ -246,7 +199,7 @@ class ReactionRateHelper(ABC): def __init__(self, n_nucs, n_react): self._nuclides = None - self._results_cache = empty((n_nucs, n_react)) + self._results_cache = np.empty((n_nucs, n_react)) @abstractmethod def generate_tallies(self, materials, scores): @@ -263,7 +216,12 @@ def nuclides(self, nuclides): self._nuclides = nuclides @abstractmethod - def get_material_rates(self, mat_id, nuc_index, react_index): + def get_material_rates( + self, + mat_id: int, + nuc_index: Sequence[str], + react_index: Sequence[str] + ): """Return 2D array of [nuclide, reaction] reaction rates Parameters @@ -276,16 +234,15 @@ def get_material_rates(self, mat_id, nuc_index, react_index): Ordering of reactions """ - def divide_by_adens(self, number): - """Normalize reaction rates by number of nuclides + def divide_by_atoms(self, number: Sequence[float]): + """Normalize reaction rates by number of atoms Acts on the current material examined by :meth:`get_material_rates` Parameters ---------- number : iterable of float - Number density [atoms/b-cm] of each nuclide tracked in the - calculation. + Number of each nuclide in [atom] tracked in the calculation. Returns ------- @@ -294,7 +251,7 @@ def divide_by_adens(self, number): normalized by the number of nuclides """ - mask = nonzero(number) + mask = np.nonzero(number) results = self._results_cache for col in range(results.shape[1]): results[mask, col] /= number[mask] @@ -305,9 +262,9 @@ class NormalizationHelper(ABC): """Abstract class for obtaining normalization factor on tallies This helper class determines how reaction rates calculated by an instance of - :class:`openmc.deplete.Operator` should be normalized for the purpose of - constructing a burnup matrix. Based on the method chosen, the power or - source rate provided by the user, and reaction rates from a + :class:`openmc.deplete.abc.TransportOperator` should be normalized for the + purpose of constructing a burnup matrix. Based on the method chosen, the + power or source rate provided by the user, and reaction rates from a :class:`ReactionRateHelper`, this class will scale reaction rates to the correct values. @@ -315,7 +272,7 @@ class NormalizationHelper(ABC): ---------- nuclides : list of str All nuclides with desired reaction rates. Ordered to be - consistent with :class:`openmc.deplete.Operator` + consistent with :class:`openmc.deplete.abc.TransportOperator` """ @@ -326,12 +283,12 @@ def reset(self): """Reset state for normalization""" @abstractmethod - def prepare(self, chain_nucs, rate_index): + def prepare(self, chain_nucs: Sequence[str], rate_index: dict): """Perform work needed to obtain energy produced - This method is called prior to the transport simulations - in :meth:`openmc.deplete.Operator.initial_condition`. Only used for - energy-based normalization. + This method is called prior to calculating the reaction rates + in :meth:`openmc.deplete.abc.TransportOperator.initial_condition`. Only + used for energy-based normalization. Parameters ---------- @@ -365,7 +322,7 @@ def nuclides(self, nuclides): self._nuclides = nuclides @abstractmethod - def factor(self, source_rate): + def factor(self, source_rate: float): """Return normalization factor Parameters @@ -442,7 +399,7 @@ def weighted_yields(self, local_mat_index): def unpack(): """Unpack tally data prior to compute fission yields. - Called after a :meth:`openmc.deplete.Operator.__call__` + Called after a :meth:`openmc.deplete.abc.TransportOperator.__call__` routine during the normalization of reaction rates. Not necessary for all subclasses to implement, unless tallies @@ -463,26 +420,27 @@ def generate_tallies(materials, mat_indexes): mat_indexes : iterable of int Indices of tallied materials that will have their fission yields computed by this helper. Necessary as the - :class:`openmc.deplete.Operator` that uses this helper + :class:`openmc.deplete.CoupledOperator` that uses this helper may only burn a subset of all materials when running in parallel mode. """ - def update_tally_nuclides(self, nuclides): + def update_tally_nuclides(self, nuclides: Sequence[str]) -> list: """Return nuclides with non-zero densities and yield data Parameters ---------- nuclides : iterable of str Nuclides with non-zero densities from the - :class:`openmc.deplete.Operator` + :class:`openmc.deplete.abc.TransportOperator` Returns ------- nuclides : list of str - Union of nuclides that the :class:`openmc.deplete.Operator` - says have non-zero densities at this stage and those that - have yield data. Sorted by nuclide name + Union of nuclides that the + :class:`openmc.deplete.abc.TransportOperator` says have non-zero + densities at this stage and those that have yield data. Sorted by + nuclide name """ return sorted(self._chain_set & set(nuclides)) @@ -496,7 +454,7 @@ def from_operator(cls, operator, **kwargs): Parameters ---------- - operator : openmc.deplete.TransportOperator + operator : openmc.deplete.abc.TransportOperator Operator with a depletion chain kwargs: optional Additional keyword arguments to be used in constuction @@ -504,99 +462,6 @@ def from_operator(cls, operator, **kwargs): return cls(operator.chain.nuclides, **kwargs) -class TalliedFissionYieldHelper(FissionYieldHelper): - """Abstract class for computing fission yields with tallies - - Generates a basic fission rate tally in all burnable materials with - :meth:`generate_tallies`, and set nuclides to be tallied with - :meth:`update_tally_nuclides`. Subclasses will need to implement - :meth:`unpack` and :meth:`weighted_yields`. - - Parameters - ---------- - chain_nuclides : iterable of openmc.deplete.Nuclide - Nuclides tracked in the depletion chain. Not necessary - that all have yield data. - - Attributes - ---------- - constant_yields : dict of str to :class:`openmc.deplete.FissionYield` - Fission yields for all nuclides that only have one set of - fission yield data. Can be accessed as ``{parent: {product: yield}}`` - results : None or numpy.ndarray - Tally results shaped in a manner useful to this helper. - """ - - _upper_energy = 20.0e6 # upper energy for tallies - - def __init__(self, chain_nuclides): - super().__init__(chain_nuclides) - self._local_indexes = None - self._fission_rate_tally = None - self._tally_nucs = [] - self.results = None - - def generate_tallies(self, materials, mat_indexes): - """Construct the fission rate tally - - Parameters - ---------- - materials : iterable of :class:`openmc.lib.Material` - Materials to be used in :class:`openmc.lib.MaterialFilter` - mat_indexes : iterable of int - Indices of tallied materials that will have their fission - yields computed by this helper. Necessary as the - :class:`openmc.deplete.Operator` that uses this helper - may only burn a subset of all materials when running - in parallel mode. - """ - self._local_indexes = asarray(mat_indexes) - - # Tally group-wise fission reaction rates - self._fission_rate_tally = Tally() - self._fission_rate_tally.writable = False - self._fission_rate_tally.scores = ['fission'] - self._fission_rate_tally.filters = [MaterialFilter(materials)] - - def update_tally_nuclides(self, nuclides): - """Tally nuclides with non-zero density and multiple yields - - Must be run after :meth:`generate_tallies`. - - Parameters - ---------- - nuclides : iterable of str - Potential nuclides to be tallied, such as those with - non-zero density at this stage. - - Returns - ------- - nuclides : list of str - Union of input nuclides and those that have multiple sets - of yield data. Sorted by nuclide name - - Raises - ------ - AttributeError - If tallies not generated - """ - assert self._fission_rate_tally is not None, ( - "Run generate_tallies first") - overlap = set(self._chain_nuclides).intersection(set(nuclides)) - nuclides = sorted(overlap) - self._tally_nucs = [self._chain_nuclides[n] for n in nuclides] - self._fission_rate_tally.nuclides = nuclides - return nuclides - - @abstractmethod - def unpack(self): - """Unpack tallies after a transport run. - - Abstract because each subclass will need to arrange its - tally data. - """ - - def add_params(cls): cls.__doc__ += cls._params return cls @@ -610,7 +475,7 @@ class Integrator(ABC): _params = r""" Parameters ---------- - operator : openmc.deplete.TransportOperator + operator : openmc.deplete.abc.TransportOperator Operator to perform transport simulations timesteps : iterable of float or iterable of tuple Array of timesteps. Note that values are not cumulative. The units are @@ -628,16 +493,17 @@ class Integrator(ABC): power_density : float or iterable of float, optional Power density of the reactor in [W/gHM]. It is multiplied by initial heavy metal inventory to get total power if ``power`` - is not speficied. + is not specified. source_rates : float or iterable of float, optional - Source rate in [neutron/sec] for each interval in :attr:`timesteps` + Source rate in [neutron/sec] or neutron flux in [neutron/s-cm^2] for + each interval in :attr:`timesteps` .. versionadded:: 0.12.1 - timestep_units : {'s', 'min', 'h', 'd', 'MWd/kg'} + timestep_units : {'s', 'min', 'h', 'd', 'a', 'MWd/kg'} Units for values specified in the `timesteps` argument. 's' means - seconds, 'min' means minutes, 'h' means hours, and 'MWd/kg' indicates - that the values are given in burnup (MW-d of energy deposited per - kilogram of initial heavy metal). + seconds, 'min' means minutes, 'h' means hours, 'a' means Julian years + and 'MWd/kg' indicates that the values are given in burnup (MW-d of + energy deposited per kilogram of initial heavy metal). solver : str or callable, optional If a string, must be the name of the solver responsible for solving the Bateman equations. Current options are: @@ -649,10 +515,9 @@ class Integrator(ABC): :attr:`solver`. .. versionadded:: 0.12 - Attributes ---------- - operator : openmc.deplete.TransportOperator + operator : openmc.deplete.abc.TransportOperator Operator to perform transport simulations chain : openmc.deplete.Chain Depletion chain @@ -668,7 +533,7 @@ class Integrator(ABC): User-supplied functions are expected to have the following signature: ``solver(A, n0, t) -> n1`` where - * ``A`` is a :class:`scipy.sparse.csr_matrix` making up the + * ``A`` is a :class:`scipy.sparse.csc_matrix` making up the depletion matrix * ``n0`` is a 1-D :class:`numpy.ndarray` of initial compositions for a given material in atoms/cm3 @@ -676,12 +541,23 @@ class Integrator(ABC): * ``n1`` is a :class:`numpy.ndarray` of compositions at the next time step. Expected to be of the same shape as ``n0`` - .. versionadded:: 0.12 + transfer_rates : openmc.deplete.TransferRates + Instance of TransferRates class to perform continuous transfer during depletion + + .. versionadded:: 0.14.0 """ - def __init__(self, operator, timesteps, power=None, power_density=None, - source_rates=None, timestep_units='s', solver="cram48"): + def __init__( + self, + operator: TransportOperator, + timesteps: Sequence[float], + power: Optional[Union[float, Sequence[float]]] = None, + power_density: Optional[Union[float, Sequence[float]]] = None, + source_rates: Optional[Sequence[float]] = None, + timestep_units: str = 's', + solver: str = "cram48" + ): # Check number of stages previously used if operator.prev_res is not None: res = operator.prev_res[-1] @@ -740,16 +616,23 @@ def __init__(self, operator, timesteps, power=None, power_density=None, seconds.append(timestep*_SECONDS_PER_HOUR) elif unit in ('d', 'day'): seconds.append(timestep*_SECONDS_PER_DAY) + elif unit in ('a', 'year'): + seconds.append(timestep*_SECONDS_PER_JULIAN_YEAR) elif unit.lower() == 'mwd/kg': watt_days_per_kg = 1e6*timestep kilograms = 1e-3*operator.heavy_metal + if rate == 0.0: + raise ValueError("Cannot specify a timestep in [MWd/kg] when" + " the power is zero.") days = watt_days_per_kg * kilograms / rate seconds.append(days*_SECONDS_PER_DAY) else: - raise ValueError("Invalid timestep unit '{}'".format(unit)) + raise ValueError(f"Invalid timestep unit '{unit}'") + + self.timesteps = np.asarray(seconds) + self.source_rates = np.asarray(source_rates) - self.timesteps = asarray(seconds) - self.source_rates = asarray(source_rates) + self.transfer_rates = None if isinstance(solver, str): # Delay importing of cram module, which requires this file @@ -761,8 +644,7 @@ def __init__(self, operator, timesteps, power=None, power_density=None, self._solver = CRAM16 else: raise ValueError( - "Solver {} not understood. Expected 'cram48' or " - "'cram16'".format(solver)) + f"Solver {solver} not understood. Expected 'cram48' or 'cram16'") else: self.solver = solver @@ -774,14 +656,13 @@ def solver(self): def solver(self, func): if not isinstance(func, Callable): raise TypeError( - "Solver must be callable, not {}".format(type(func))) + f"Solver must be callable, not {type(func)}") try: sig = signature(func) except ValueError: # Guard against callables that aren't introspectable, e.g. # fortran functions wrapped by F2PY - warn("Could not determine arguments to {}. Proceeding " - "anyways".format(func)) + warn(f"Could not determine arguments to {func}. Proceeding anyways") self._solver = func return @@ -793,25 +674,33 @@ def solver(self, func): for ix, param in enumerate(sig.parameters.values()): if param.kind in {param.KEYWORD_ONLY, param.VAR_KEYWORD}: raise ValueError( - "Keyword arguments like {} at position {} are not " - "allowed".format(ix, param)) + f"Keyword arguments like {ix} at position {param} are not allowed") self._solver = func - def _timed_deplete(self, concs, rates, dt, matrix_func=None): + def _timed_deplete(self, n, rates, dt, matrix_func=None): start = time.time() results = deplete( - self._solver, self.chain, concs, rates, dt, matrix_func) + self._solver, self.chain, n, rates, dt, matrix_func, + self.transfer_rates) return time.time() - start, results @abstractmethod - def __call__(self, conc, rates, dt, source_rate, i): + def __call__( + self, + n: Sequence[np.ndarray], + rates: ReactionRates, + dt: float, + source_rate: float, + i: int + ): """Perform the integration across one time step Parameters ---------- - conc : numpy.ndarray - Initial concentrations for all nuclides in [atom] + n : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -825,7 +714,7 @@ def __call__(self, conc, rates, dt, source_rate, i): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - conc_list : list of numpy.ndarray + n_list : list of list of numpy.ndarray Concentrations at each of the intermediate points with the final concentration as the last element op_results : list of openmc.deplete.OperatorResult @@ -857,7 +746,7 @@ def _get_bos_data_from_operator(self, step_index, source_rate, bos_conc): self.operator.write_bos_data(step_index + self._i_res) return x, res - def _get_bos_data_from_restart(self, step_index, source_rate, bos_conc): + def _get_bos_data_from_restart(self, source_rate, bos_conc): """Get beginning of step concentrations, reaction rates from restart""" res = self.operator.prev_res[-1] # Depletion methods expect list of arrays @@ -866,7 +755,7 @@ def _get_bos_data_from_restart(self, step_index, source_rate, bos_conc): k = ufloat(res.k[0, 0], res.k[0, 1]) # Scale reaction rates by ratio of source rates - rates *= source_rate / res.source_rate[0] + rates *= source_rate / res.source_rate return bos_conc, OperatorResult(k, rates) def _get_start_data(self): @@ -875,7 +764,12 @@ def _get_start_data(self): return (self.operator.prev_res[-1].time[-1], len(self.operator.prev_res) - 1) - def integrate(self, final_step=True): + def integrate( + self, + final_step: bool = True, + output: bool = True, + path: PathLike = 'depletion_results.h5' + ): """Perform the entire depletion process across all steps Parameters @@ -885,30 +779,41 @@ def integrate(self, final_step=True): of the last timestep. .. versionadded:: 0.12.1 + output : bool, optional + Indicate whether to display information about progress + + .. versionadded:: 0.13.1 + path : PathLike + Path to file to write. Defaults to 'depletion_results.h5'. + .. versionadded:: 0.14.1 """ - with self.operator as conc: + with change_directory(self.operator.output_dir): + n = self.operator.initial_condition() t, self._i_res = self._get_start_data() for i, (dt, source_rate) in enumerate(self): + if output and comm.rank == 0: + print(f"[openmc.deplete] t={t} s, dt={dt} s, source={source_rate}") + # Solve transport equation (or obtain result from restart) if i > 0 or self.operator.prev_res is None: - conc, res = self._get_bos_data_from_operator(i, source_rate, conc) + n, res = self._get_bos_data_from_operator(i, source_rate, n) else: - conc, res = self._get_bos_data_from_restart(i, source_rate, conc) + n, res = self._get_bos_data_from_restart(source_rate, n) # Solve Bateman equations over time interval - proc_time, conc_list, res_list = self(conc, res.rates, dt, source_rate, i) + proc_time, n_list, res_list = self(n, res.rates, dt, source_rate, i) # Insert BOS concentration, transport results - conc_list.insert(0, conc) + n_list.insert(0, n) res_list.insert(0, res) # Remove actual EOS concentration for next step - conc = conc_list.pop() + n = n_list.pop() - Results.save(self.operator, conc_list, res_list, [t, t + dt], - source_rate, self._i_res + i, proc_time) + StepResult.save(self.operator, n_list, res_list, [t, t + dt], + source_rate, self._i_res + i, proc_time, path) t += dt @@ -916,11 +821,48 @@ def integrate(self, final_step=True): # source rate is passed to the transport operator (which knows to # just return zero reaction rates without actually doing a transport # solve) - res_list = [self.operator(conc, source_rate if final_step else 0.0)] - Results.save(self.operator, [conc], res_list, [t, t], - source_rate, self._i_res + len(self), proc_time) + if output and final_step and comm.rank == 0: + print(f"[openmc.deplete] t={t} (final operator evaluation)") + res_list = [self.operator(n, source_rate if final_step else 0.0)] + StepResult.save(self.operator, [n], res_list, [t, t], + source_rate, self._i_res + len(self), proc_time, path) self.operator.write_bos_data(len(self) + self._i_res) + self.operator.finalize() + + def add_transfer_rate( + self, + material: Union[str, int, Material], + components: Sequence[str], + transfer_rate: float, + transfer_rate_units: str = '1/s', + destination_material: Optional[Union[str, int, Material]] = None + ): + """Add transfer rates to depletable material. + + Parameters + ---------- + material : openmc.Material or str or int + Depletable material + components : list of str + List of strings of elements and/or nuclides that share transfer rate. + A transfer rate for a nuclide cannot be added to a material + alongside a transfer rate for its element and vice versa. + transfer_rate : float + Rate at which elements are transferred. A positive or negative values + set removal of feed rates, respectively. + destination_material : openmc.Material or str or int, Optional + Destination material to where nuclides get fed. + transfer_rate_units : {'1/s', '1/min', '1/h', '1/d', '1/a'} + Units for values specified in the transfer_rate argument. 's' means + seconds, 'min' means minutes, 'h' means hours, 'a' means Julian years. + + """ + if self.transfer_rates is None: + self.transfer_rates = TransferRates(self.operator, self.operator.model) + + self.transfer_rates.set_transfer_rate(material, components, transfer_rate, + transfer_rate_units, destination_material) @add_params class SIIntegrator(Integrator): @@ -933,8 +875,8 @@ class SIIntegrator(Integrator): _params = r""" Parameters ---------- - operator : openmc.deplete.TransportOperator - The operator object to simulate on. + operator : openmc.deplete.abc.TransportOperator + Operator to perform transport simulations timesteps : iterable of float or iterable of tuple Array of timesteps. Note that values are not cumulative. The units are specified by the `timestep_units` argument when `timesteps` is an @@ -951,9 +893,10 @@ class SIIntegrator(Integrator): power_density : float or iterable of float, optional Power density of the reactor in [W/gHM]. It is multiplied by initial heavy metal inventory to get total power if ``power`` - is not speficied. + is not specified. source_rates : float or iterable of float, optional - Source rate in [neutron/sec] for each interval in :attr:`timesteps` + Source rate in [neutron/sec] or neutron flux in [neutron/s-cm^2] for + each interval in :attr:`timesteps` .. versionadded:: 0.12.1 timestep_units : {'s', 'min', 'h', 'd', 'MWd/kg'} @@ -978,7 +921,7 @@ class SIIntegrator(Integrator): Attributes ---------- - operator : openmc.deplete.TransportOperator + operator : openmc.deplete.abc.TransportOperator Operator to perform transport simulations chain : openmc.deplete.Chain Depletion chain @@ -995,7 +938,7 @@ class SIIntegrator(Integrator): User-supplied functions are expected to have the following signature: ``solver(A, n0, t) -> n1`` where - * ``A`` is a :class:`scipy.sparse.csr_matrix` making up the + * ``A`` is a :class:`scipy.sparse.csc_matrix` making up the depletion matrix * ``n0`` is a 1-D :class:`numpy.ndarray` of initial compositions for a given material in atoms/cm3 @@ -1007,9 +950,17 @@ class SIIntegrator(Integrator): """ - def __init__(self, operator, timesteps, power=None, power_density=None, - source_rates=None, timestep_units='s', n_steps=10, - solver="cram48"): + def __init__( + self, + operator: TransportOperator, + timesteps: Sequence[float], + power: Optional[Union[float, Sequence[float]]] = None, + power_density: Optional[Union[float, Sequence[float]]] = None, + source_rates: Optional[Sequence[float]] = None, + timestep_units: str = 's', + n_steps: int = 10, + solver: str = "cram48" + ): check_type("n_steps", n_steps, Integral) check_greater_than("n_steps", n_steps, 0) super().__init__( @@ -1017,52 +968,72 @@ def __init__(self, operator, timesteps, power=None, power_density=None, timestep_units=timestep_units, solver=solver) self.n_steps = n_steps - def _get_bos_data_from_operator(self, step_index, step_power, bos_conc): + def _get_bos_data_from_operator(self, step_index, step_power, n_bos): reset_particles = False if step_index == 0 and hasattr(self.operator, "settings"): reset_particles = True self.operator.settings.particles *= self.n_steps inherited = super()._get_bos_data_from_operator( - step_index, step_power, bos_conc) + step_index, step_power, n_bos) if reset_particles: self.operator.settings.particles //= self.n_steps return inherited - def integrate(self): - """Perform the entire depletion process across all steps""" - with self.operator as conc: + def integrate( + self, + output: bool = True, + path: PathLike = "depletion_results.h5" + ): + """Perform the entire depletion process across all steps + + Parameters + ---------- + output : bool, optional + Indicate whether to display information about progress + path : PathLike + Path to file to write. Defaults to 'depletion_results.h5'. + + .. versionadded:: 0.14.1 + """ + with change_directory(self.operator.output_dir): + n = self.operator.initial_condition() t, self._i_res = self._get_start_data() for i, (dt, p) in enumerate(self): + if output: + print(f"[openmc.deplete] t={t} s, dt={dt} s, source={p}") + if i == 0: if self.operator.prev_res is None: - conc, res = self._get_bos_data_from_operator(i, p, conc) + n, res = self._get_bos_data_from_operator(i, p, n) else: - conc, res = self._get_bos_data_from_restart(i, p, conc) + n, res = self._get_bos_data_from_restart(p, n) else: # Pull rates, k from previous iteration w/o # re-running transport res = res_list[-1] # defined in previous i iteration - proc_time, conc_list, res_list = self(conc, res.rates, dt, p, i) + proc_time, n_list, res_list = self(n, res.rates, dt, p, i) # Insert BOS concentration, transport results - conc_list.insert(0, conc) + n_list.insert(0, n) res_list.insert(0, res) # Remove actual EOS concentration for next step - conc = conc_list.pop() + n = n_list.pop() - Results.save(self.operator, conc_list, res_list, [t, t + dt], - p, self._i_res + i, proc_time) + StepResult.save(self.operator, n_list, res_list, [t, t + dt], + p, self._i_res + i, proc_time, path) t += dt # No final simulation for SIE, use last iteration results - Results.save(self.operator, [conc], [res_list[-1]], [t, t], - p, self._i_res + len(self), proc_time) + StepResult.save(self.operator, [n], [res_list[-1]], [t, t], + p, self._i_res + len(self), proc_time, path) self.operator.write_bos_data(self._i_res + len(self)) + self.operator.finalize() + class DepSystemSolver(ABC): r"""Abstract class for solving depletion equations @@ -1083,8 +1054,8 @@ def __call__(self, A, n0, dt): Parameters ---------- - A : scipy.sparse.csr_matrix - Sparse transmutation matrix ``A[j, i]`` desribing rates at + A : scipy.sparse.csc_matrix + Sparse transmutation matrix ``A[j, i]`` describing rates at which isotope ``i`` transmutes to isotope ``j`` n0 : numpy.ndarray Initial compositions, typically given in number of atoms in some diff --git a/openmc/deplete/atom_number.py b/openmc/deplete/atom_number.py index e4982f872e8..b24c048cc92 100644 --- a/openmc/deplete/atom_number.py +++ b/openmc/deplete/atom_number.py @@ -2,10 +2,10 @@ An ndarray to store atom densities with string, integer, or slice indexing. """ -from collections import OrderedDict - import numpy as np +from openmc import Material + class AtomNumber: """Stores local material compositions (atoms of each nuclide). @@ -45,8 +45,8 @@ class AtomNumber: """ def __init__(self, local_mats, nuclides, volume, n_nuc_burn): - self.index_mat = OrderedDict((mat, i) for i, mat in enumerate(local_mats)) - self.index_nuc = OrderedDict((nuc, i) for i, nuc in enumerate(nuclides)) + self.index_mat = {mat: i for i, mat in enumerate(local_mats)} + self.index_nuc = {nuc: i for i, nuc in enumerate(nuclides)} self.volume = np.ones(len(local_mats)) for mat, val in volume.items(): @@ -58,6 +58,12 @@ def __init__(self, local_mats, nuclides, volume, n_nuc_burn): self.number = np.zeros((len(local_mats), len(nuclides))) + def _get_mat_index(self, mat): + """Helper method for getting material index""" + if isinstance(mat, Material): + mat = str(mat.id) + return self.index_mat[mat] if isinstance(mat, str) else mat + def __getitem__(self, pos): """Retrieves total atom number from AtomNumber. @@ -75,8 +81,7 @@ def __getitem__(self, pos): """ mat, nuc = pos - if isinstance(mat, str): - mat = self.index_mat[mat] + mat = self._get_mat_index(mat) if isinstance(nuc, str): nuc = self.index_nuc[nuc] @@ -96,8 +101,7 @@ def __setitem__(self, pos, val): """ mat, nuc = pos - if isinstance(mat, str): - mat = self.index_mat[mat] + mat = self._get_mat_index(mat) if isinstance(nuc, str): nuc = self.index_nuc[nuc] @@ -120,12 +124,29 @@ def burnable_nuclides(self): return [nuc for nuc, ind in self.index_nuc.items() if ind < self.n_nuc_burn] + def get_mat_volume(self, mat): + """Return material volume + + Parameters + ---------- + mat : str, int, openmc.Material, or slice + Material index. + + Returns + ------- + float + Material volume in [cm^3] + + """ + mat = self._get_mat_index(mat) + return self.volume[mat] + def get_atom_density(self, mat, nuc): - """Accesses atom density instead of total number. + """Return atom density of given material and nuclide Parameters ---------- - mat : str, int or slice + mat : str, int, openmc.Material or slice Material index. nuc : str, int or slice Nuclide index. @@ -136,19 +157,43 @@ def get_atom_density(self, mat, nuc): Density in [atom/cm^3] """ - if isinstance(mat, str): - mat = self.index_mat[mat] + mat = self._get_mat_index(mat) if isinstance(nuc, str): nuc = self.index_nuc[nuc] return self[mat, nuc] / self.volume[mat] + def get_atom_densities(self, mat, units='atom/b-cm'): + """Return atom densities for a given material + + Parameters + ---------- + mat : str, int, openmc.Material or slice + Material index. + units : {"atom/b-cm", "atom/cm3"}, optional + Units for the returned concentration. Default is ``"atom/b-cm"`` + + .. versionadded:: 0.13.1 + + Returns + ------- + dict + Dictionary mapping nuclides to atom densities + + """ + mat = self._get_mat_index(mat) + normalization = (1.0e-24 if units == 'atom/b-cm' else 1.0) / self.volume[mat] + return { + name: normalization * self[mat, nuc] + for name, nuc in self.index_nuc.items() + } + def set_atom_density(self, mat, nuc, val): """Sets atom density instead of total number. Parameters ---------- - mat : str, int or slice + mat : str, int, openmc.Material or slice Material index. nuc : str, int or slice Nuclide index. @@ -156,8 +201,7 @@ def set_atom_density(self, mat, nuc, val): Array of densities to set in [atom/cm^3] """ - if isinstance(mat, str): - mat = self.index_mat[mat] + mat = self._get_mat_index(mat) if isinstance(nuc, str): nuc = self.index_nuc[nuc] @@ -168,7 +212,7 @@ def get_mat_slice(self, mat): Parameters ---------- - mat : str, int or slice + mat : str, int, openmc.Material or slice Material index. Returns @@ -177,9 +221,7 @@ def get_mat_slice(self, mat): The slice requested in [atom]. """ - if isinstance(mat, str): - mat = self.index_mat[mat] - + mat = self._get_mat_index(mat) return self[mat, :self.n_nuc_burn] def set_mat_slice(self, mat, val): @@ -187,15 +229,13 @@ def set_mat_slice(self, mat, val): Parameters ---------- - mat : str, int or slice + mat : str, int, openmc.Material, or slice Material index. val : numpy.ndarray The slice to set in [atom] """ - if isinstance(mat, str): - mat = self.index_mat[mat] - + mat = self._get_mat_index(mat) self[mat, :self.n_nuc_burn] = val def set_density(self, total_density): diff --git a/openmc/deplete/chain.py b/openmc/deplete/chain.py index 0c39a92e3d2..1d383498052 100644 --- a/openmc/deplete/chain.py +++ b/openmc/deplete/chain.py @@ -8,120 +8,108 @@ from itertools import chain import math import re -from collections import OrderedDict, defaultdict, namedtuple +from collections import defaultdict, namedtuple from collections.abc import Mapping, Iterable from numbers import Real, Integral from warnings import warn -from openmc.checkvalue import check_type, check_greater_than -from openmc.data import gnd_name, zam -from .nuclide import FissionYieldDistribution - -# Try to use lxml if it is available. It preserves the order of attributes and -# provides a pretty-printer by default. If not available, -# use OpenMC function to pretty print. -try: - import lxml.etree as ET - _have_lxml = True -except ImportError: - import xml.etree.ElementTree as ET - _have_lxml = False +import lxml.etree as ET import scipy.sparse as sp +from openmc.checkvalue import check_type, check_greater_than +from openmc.data import gnds_name, zam +from .nuclide import FissionYieldDistribution, Nuclide import openmc.data -from openmc._xml import clean_indentation -from .nuclide import Nuclide, DecayTuple, ReactionTuple -# tuple of (possible MT values, (dA, dZ), secondaries) where dA is the change in -# the mass number and dZ is the change in the atomic number -ReactionInfo = namedtuple('ReactionInfo', ('mts', 'dadz', 'secondaries')) +# tuple of (possible MT values, secondaries) +ReactionInfo = namedtuple('ReactionInfo', ('mts', 'secondaries')) REACTIONS = { - '(n,2nd)': ReactionInfo({11}, (-3, -1), ('H2',)), - '(n,2n)': ReactionInfo(set(chain([16], range(875, 892))), (-1, 0), ()), - '(n,3n)': ReactionInfo({17}, (-2, 0), ()), - '(n,na)': ReactionInfo({22}, (-4, -2), ('He4',)), - '(n,n3a)': ReactionInfo({23}, (-12, -6), ('He4', 'He4', 'He4')), - '(n,2na)': ReactionInfo({24}, (-5, -2), ('He4',)), - '(n,3na)': ReactionInfo({25}, (-6, -2), ('He4',)), - '(n,np)': ReactionInfo({28}, (-1, -1), ('H1',)), - '(n,n2a)': ReactionInfo({29}, (-8, -4), ('He4', 'He4')), - '(n,2n2a)': ReactionInfo({30}, (-9, -4), ('He4', 'He4')), - '(n,nd)': ReactionInfo({32}, (-2, -1), ('H2',)), - '(n,nt)': ReactionInfo({33}, (-3, -1), ('H3',)), - '(n,n3He)': ReactionInfo({34}, (-3, -2), ('He3',)), - '(n,nd2a)': ReactionInfo({35}, (-10, -5), ('H2', 'He4', 'He4')), - '(n,nt2a)': ReactionInfo({36}, (-11, -5), ('H3', 'He4', 'He4')), - '(n,4n)': ReactionInfo({37}, (-3, 0), ()), - '(n,2np)': ReactionInfo({41}, (-2, -1), ('H1',)), - '(n,3np)': ReactionInfo({42}, (-3, -1), ('H1',)), - '(n,n2p)': ReactionInfo({44}, (-2, -2), ('H1', 'H1')), - '(n,npa)': ReactionInfo({45}, (-5, -3), ('H1', 'He4')), - '(n,gamma)': ReactionInfo({102}, (1, 0), ()), - '(n,p)': ReactionInfo(set(chain([103], range(600, 650))), (0, -1), ('H1',)), - '(n,d)': ReactionInfo(set(chain([104], range(650, 700))), (-1, -1), ('H2',)), - '(n,t)': ReactionInfo(set(chain([105], range(700, 750))), (-2, -1), ('H3',)), - '(n,3He)': ReactionInfo(set(chain([106], range(750, 800))), (-2, -2), ('He3',)), - '(n,a)': ReactionInfo(set(chain([107], range(800, 850))), (-3, -2), ('He4',)), - '(n,2a)': ReactionInfo({108}, (-7, -4), ('He4', 'He4')), - '(n,3a)': ReactionInfo({109}, (-11, -6), ('He4', 'He4', 'He4')), - '(n,2p)': ReactionInfo({111}, (-1, -2), ('H1', 'H1')), - '(n,pa)': ReactionInfo({112}, (-4, -3), ('H1', 'He4')), - '(n,t2a)': ReactionInfo({113}, (-10, -5), ('H3', 'He4', 'He4')), - '(n,d2a)': ReactionInfo({114}, (-9, -5), ('H2', 'He4', 'He4')), - '(n,pd)': ReactionInfo({115}, (-2, -2), ('H1', 'H2')), - '(n,pt)': ReactionInfo({116}, (-3, -2), ('H1', 'H3')), - '(n,da)': ReactionInfo({117}, (-5, -3), ('H2', 'He4')), - '(n,5n)': ReactionInfo({152}, (-4, 0), ()), - '(n,6n)': ReactionInfo({153}, (-5, 0), ()), - '(n,2nt)': ReactionInfo({154}, (-4, -1), ('H3',)), - '(n,ta)': ReactionInfo({155}, (-6, -3), ('H3', 'He4')), - '(n,4np)': ReactionInfo({156}, (-4, -1), ('H1',)), - '(n,3nd)': ReactionInfo({157}, (-4, -1), ('H2',)), - '(n,nda)': ReactionInfo({158}, (-6, -3), ('H2', 'He4')), - '(n,2npa)': ReactionInfo({159}, (-6, -3), ('H1', 'He4')), - '(n,7n)': ReactionInfo({160}, (-6, 0), ()), - '(n,8n)': ReactionInfo({161}, (-7, 0), ()), - '(n,5np)': ReactionInfo({162}, (-5, -1), ('H1',)), - '(n,6np)': ReactionInfo({163}, (-6, -1), ('H1',)), - '(n,7np)': ReactionInfo({164}, (-7, -1), ('H1',)), - '(n,4na)': ReactionInfo({165}, (-7, -2), ('He4',)), - '(n,5na)': ReactionInfo({166}, (-8, -2), ('He4',)), - '(n,6na)': ReactionInfo({167}, (-9, -2), ('He4',)), - '(n,7na)': ReactionInfo({168}, (-10, -2), ('He4',)), - '(n,4nd)': ReactionInfo({169}, (-5, -1), ('H2',)), - '(n,5nd)': ReactionInfo({170}, (-6, -1), ('H2',)), - '(n,6nd)': ReactionInfo({171}, (-7, -1), ('H2',)), - '(n,3nt)': ReactionInfo({172}, (-5, -1), ('H3',)), - '(n,4nt)': ReactionInfo({173}, (-6, -1), ('H3',)), - '(n,5nt)': ReactionInfo({174}, (-7, -1), ('H3',)), - '(n,6nt)': ReactionInfo({175}, (-8, -1), ('H3',)), - '(n,2n3He)': ReactionInfo({176}, (-4, -2), ('He3',)), - '(n,3n3He)': ReactionInfo({177}, (-5, -2), ('He3',)), - '(n,4n3He)': ReactionInfo({178}, (-6, -2), ('He3',)), - '(n,3n2p)': ReactionInfo({179}, (-4, -2), ('H1', 'H1')), - '(n,3n2a)': ReactionInfo({180}, (-10, -4), ('He4', 'He4')), - '(n,3npa)': ReactionInfo({181}, (-7, -3), ('H1', 'He4')), - '(n,dt)': ReactionInfo({182}, (-4, -2), ('H2', 'H3')), - '(n,npd)': ReactionInfo({183}, (-3, -2), ('H1', 'H2')), - '(n,npt)': ReactionInfo({184}, (-4, -2), ('H1', 'H3')), - '(n,ndt)': ReactionInfo({185}, (-5, -2), ('H2', 'H3')), - '(n,np3He)': ReactionInfo({186}, (-4, -3), ('H1', 'He3')), - '(n,nd3He)': ReactionInfo({187}, (-5, -3), ('H2', 'He3')), - '(n,nt3He)': ReactionInfo({188}, (-6, -3), ('H3', 'He3')), - '(n,nta)': ReactionInfo({189}, (-7, -3), ('H3', 'He4')), - '(n,2n2p)': ReactionInfo({190}, (-3, -2), ('H1', 'H1')), - '(n,p3He)': ReactionInfo({191}, (-4, -3), ('H1', 'He3')), - '(n,d3He)': ReactionInfo({192}, (-5, -3), ('H2', 'He3')), - '(n,3Hea)': ReactionInfo({193}, (-6, -4), ('He3', 'He4')), - '(n,4n2p)': ReactionInfo({194}, (-5, -2), ('H1', 'H1')), - '(n,4n2a)': ReactionInfo({195}, (-11, -4), ('He4', 'He4')), - '(n,4npa)': ReactionInfo({196}, (-8, -3), ('H1', 'He4')), - '(n,3p)': ReactionInfo({197}, (-2, -3), ('H1', 'H1', 'H1')), - '(n,n3p)': ReactionInfo({198}, (-3, -3), ('H1', 'H1', 'H1')), - '(n,3n2pa)': ReactionInfo({199}, (-8, -4), ('H1', 'H1', 'He4')), - '(n,5n2p)': ReactionInfo({200}, (-6, -2), ('H1', 'H1')), + '(n,2nd)': ReactionInfo({11}, ('H2',)), + '(n,2n)': ReactionInfo(set(chain([16], range(875, 892))), ()), + '(n,3n)': ReactionInfo({17}, ()), + '(n,na)': ReactionInfo({22}, ('He4',)), + '(n,n3a)': ReactionInfo({23}, ('He4', 'He4', 'He4')), + '(n,2na)': ReactionInfo({24}, ('He4',)), + '(n,3na)': ReactionInfo({25}, ('He4',)), + '(n,np)': ReactionInfo({28}, ('H1',)), + '(n,n2a)': ReactionInfo({29}, ('He4', 'He4')), + '(n,2n2a)': ReactionInfo({30}, ('He4', 'He4')), + '(n,nd)': ReactionInfo({32}, ('H2',)), + '(n,nt)': ReactionInfo({33}, ('H3',)), + '(n,n3He)': ReactionInfo({34}, ('He3',)), + '(n,nd2a)': ReactionInfo({35}, ('H2', 'He4', 'He4')), + '(n,nt2a)': ReactionInfo({36}, ('H3', 'He4', 'He4')), + '(n,4n)': ReactionInfo({37}, ()), + '(n,2np)': ReactionInfo({41}, ('H1',)), + '(n,3np)': ReactionInfo({42}, ('H1',)), + '(n,n2p)': ReactionInfo({44}, ('H1', 'H1')), + '(n,npa)': ReactionInfo({45}, ('H1', 'He4')), + '(n,gamma)': ReactionInfo({102}, ()), + '(n,p)': ReactionInfo(set(chain([103], range(600, 650))), ('H1',)), + '(n,d)': ReactionInfo(set(chain([104], range(650, 700))), ('H2',)), + '(n,t)': ReactionInfo(set(chain([105], range(700, 750))), ('H3',)), + '(n,3He)': ReactionInfo(set(chain([106], range(750, 800))), ('He3',)), + '(n,a)': ReactionInfo(set(chain([107], range(800, 850))), ('He4',)), + '(n,2a)': ReactionInfo({108}, ('He4', 'He4')), + '(n,3a)': ReactionInfo({109}, ('He4', 'He4', 'He4')), + '(n,2p)': ReactionInfo({111}, ('H1', 'H1')), + '(n,pa)': ReactionInfo({112}, ('H1', 'He4')), + '(n,t2a)': ReactionInfo({113}, ('H3', 'He4', 'He4')), + '(n,d2a)': ReactionInfo({114}, ('H2', 'He4', 'He4')), + '(n,pd)': ReactionInfo({115}, ('H1', 'H2')), + '(n,pt)': ReactionInfo({116}, ('H1', 'H3')), + '(n,da)': ReactionInfo({117}, ('H2', 'He4')), + '(n,5n)': ReactionInfo({152}, ()), + '(n,6n)': ReactionInfo({153}, ()), + '(n,2nt)': ReactionInfo({154}, ('H3',)), + '(n,ta)': ReactionInfo({155}, ('H3', 'He4')), + '(n,4np)': ReactionInfo({156}, ('H1',)), + '(n,3nd)': ReactionInfo({157}, ('H2',)), + '(n,nda)': ReactionInfo({158}, ('H2', 'He4')), + '(n,2npa)': ReactionInfo({159}, ('H1', 'He4')), + '(n,7n)': ReactionInfo({160}, ()), + '(n,8n)': ReactionInfo({161}, ()), + '(n,5np)': ReactionInfo({162}, ('H1',)), + '(n,6np)': ReactionInfo({163}, ('H1',)), + '(n,7np)': ReactionInfo({164}, ('H1',)), + '(n,4na)': ReactionInfo({165}, ('He4',)), + '(n,5na)': ReactionInfo({166}, ('He4',)), + '(n,6na)': ReactionInfo({167}, ('He4',)), + '(n,7na)': ReactionInfo({168}, ('He4',)), + '(n,4nd)': ReactionInfo({169}, ('H2',)), + '(n,5nd)': ReactionInfo({170}, ('H2',)), + '(n,6nd)': ReactionInfo({171}, ('H2',)), + '(n,3nt)': ReactionInfo({172}, ('H3',)), + '(n,4nt)': ReactionInfo({173}, ('H3',)), + '(n,5nt)': ReactionInfo({174}, ('H3',)), + '(n,6nt)': ReactionInfo({175}, ('H3',)), + '(n,2n3He)': ReactionInfo({176}, ('He3',)), + '(n,3n3He)': ReactionInfo({177}, ('He3',)), + '(n,4n3He)': ReactionInfo({178}, ('He3',)), + '(n,3n2p)': ReactionInfo({179}, ('H1', 'H1')), + '(n,3n2a)': ReactionInfo({180}, ('He4', 'He4')), + '(n,3npa)': ReactionInfo({181}, ('H1', 'He4')), + '(n,dt)': ReactionInfo({182}, ('H2', 'H3')), + '(n,npd)': ReactionInfo({183}, ('H1', 'H2')), + '(n,npt)': ReactionInfo({184}, ('H1', 'H3')), + '(n,ndt)': ReactionInfo({185}, ('H2', 'H3')), + '(n,np3He)': ReactionInfo({186}, ('H1', 'He3')), + '(n,nd3He)': ReactionInfo({187}, ('H2', 'He3')), + '(n,nt3He)': ReactionInfo({188}, ('H3', 'He3')), + '(n,nta)': ReactionInfo({189}, ('H3', 'He4')), + '(n,2n2p)': ReactionInfo({190}, ('H1', 'H1')), + '(n,p3He)': ReactionInfo({191}, ('H1', 'He3')), + '(n,d3He)': ReactionInfo({192}, ('H2', 'He3')), + '(n,3Hea)': ReactionInfo({193}, ('He3', 'He4')), + '(n,4n2p)': ReactionInfo({194}, ('H1', 'H1')), + '(n,4n2a)': ReactionInfo({195}, ('He4', 'He4')), + '(n,4npa)': ReactionInfo({196}, ('H1', 'He4')), + '(n,3p)': ReactionInfo({197}, ('H1', 'H1', 'H1')), + '(n,n3p)': ReactionInfo({198}, ('H1', 'H1', 'H1')), + '(n,3n2pa)': ReactionInfo({199}, ('H1', 'H1', 'He4')), + '(n,5n2p)': ReactionInfo({200}, ('H1', 'H1')), } __all__ = ["Chain", "REACTIONS"] @@ -133,14 +121,14 @@ def replace_missing(product, decay_data): Parameters ---------- product : str - Name of product in GND format, e.g. 'Y86_m1'. + Name of product in GNDS format, e.g. 'Y86_m1'. decay_data : dict Dictionary of decay data Returns ------- product : str - Replacement for missing product in GND format. + Replacement for missing product in GNDS format. """ # Determine atomic number, mass number, and metastable state @@ -153,7 +141,7 @@ def replace_missing(product, decay_data): # First check if ground state is available if state: - product = '{}{}'.format(symbol, A) + product = f'{symbol}{A}' # Find isotope with longest half-life half_life = 0.0 @@ -184,7 +172,7 @@ def replace_missing(product, decay_data): Z += 1 else: Z -= 1 - product = '{}{}'.format(openmc.data.ATOMIC_SYMBOL[Z], A) + product = f'{openmc.data.ATOMIC_SYMBOL[Z]}{A}' return product @@ -211,7 +199,7 @@ def replace_missing_fpy(actinide, fpy_data, decay_data): # Check if metastable state has data (e.g., Am242m) Z, A, m = zam(actinide) if m == 0: - metastable = gnd_name(Z, A, 1) + metastable = gnds_name(Z, A, 1) if metastable in fpy_data: return metastable @@ -220,7 +208,7 @@ def replace_missing_fpy(actinide, fpy_data, decay_data): while isotone in decay_data: Z += 1 A += 1 - isotone = gnd_name(Z, A, 0) + isotone = gnds_name(Z, A, 0) if isotone in fpy_data: return isotone @@ -229,7 +217,7 @@ def replace_missing_fpy(actinide, fpy_data, decay_data): while isotone in decay_data: Z -= 1 A -= 1 - isotone = gnd_name(Z, A, 0) + isotone = gnds_name(Z, A, 0) if isotone in fpy_data: return isotone @@ -244,9 +232,9 @@ class Chain: requires a list of ENDF incident neutron, decay, and neutron fission product yield sublibrary files. The depletion chain used during a depletion simulation is indicated by either an argument to - :class:`openmc.deplete.Operator` or through the - ``depletion_chain`` item in the :envvar:`OPENMC_CROSS_SECTIONS` - environment variable. + :class:`openmc.deplete.CoupledOperator` or + :class:`openmc.deplete.IndependentOperator`, or through + openmc.config['chain_file']. Attributes ---------- @@ -254,7 +242,7 @@ class Chain: Nuclides present in the chain. reactions : list of str Reactions that are tracked in the depletion chain - nuclide_dict : OrderedDict of str to int + nuclide_dict : dict of str to int Maps a nuclide name to an index in nuclides. fission_yields : None or iterable of dict List of effective fission yields for materials. Each dictionary @@ -270,7 +258,7 @@ class Chain: def __init__(self): self.nuclides = [] self.reactions = [] - self.nuclide_dict = OrderedDict() + self.nuclide_dict = {} self._fission_yields = None def __contains__(self, nuclide): @@ -355,7 +343,7 @@ def from_endf(cls, decay_files, fpy_files, neutron_files, reactions = {} for f in neutron_files: evaluation = openmc.data.endf.Evaluation(f) - name = evaluation.gnd_name + name = evaluation.gnds_name reactions[name] = {} for mf, mt, nc, mod in evaluation.reaction_list: if mf == 3: @@ -418,16 +406,18 @@ def from_endf(cls, decay_files, fpy_files, neutron_files, # Append decay mode nuclide.add_decay_mode(type_, target, br) + nuclide.sources = data.sources + fissionable = False if parent in reactions: reactions_available = set(reactions[parent].keys()) for name in transmutation_reactions: - mts, changes, _ = REACTIONS[name] + mts = REACTIONS[name].mts + delta_A, delta_Z = openmc.data.DADZ[name] if mts & reactions_available: - delta_A, delta_Z = changes A = data.nuclide['mass_number'] + delta_A Z = data.nuclide['atomic_number'] + delta_Z - daughter = '{}{}'.format(openmc.data.ATOMIC_SYMBOL[Z], A) + daughter = f'{openmc.data.ATOMIC_SYMBOL[Z]}{A}' if daughter not in decay_data: daughter = replace_missing(daughter, decay_data) @@ -493,7 +483,7 @@ def from_endf(cls, decay_files, fpy_files, neutron_files, if missing_daughter: print('The following decay modes have daughters with no decay data:') for mode in missing_daughter: - print(' {}'.format(mode)) + print(f' {mode}') print('') if missing_rx_product: @@ -505,7 +495,7 @@ def from_endf(cls, decay_files, fpy_files, neutron_files, if missing_fpy: print('The following fissionable nuclides have no fission product yields:') for parent, replacement in missing_fpy: - print(' {}, replaced with {}'.format(parent, replacement)) + print(f' {parent}, replaced with {replacement}') print('') if missing_fp: @@ -561,11 +551,7 @@ def export_to_xml(self, filename): root_elem.append(nuclide.to_xml_element()) tree = ET.ElementTree(root_elem) - if _have_lxml: - tree.write(str(filename), encoding='utf-8', pretty_print=True) - else: - clean_indentation(root_elem) - tree.write(str(filename), encoding='utf-8') + tree.write(str(filename), encoding='utf-8', pretty_print=True) def get_default_fission_yields(self): """Return fission yields at lowest incident neutron energy @@ -604,16 +590,19 @@ def form_matrix(self, rates, fission_yields=None): Returns ------- - scipy.sparse.csr_matrix + scipy.sparse.csc_matrix Sparse matrix representing depletion. See Also -------- :meth:`get_default_fission_yields` """ - matrix = defaultdict(float) reactions = set() + # Use DOK matrix as intermediate representation for matrix + n = len(self) + matrix = sp.dok_matrix((n, n)) + if fission_yields is None: fission_yields = self.get_default_fission_yields() @@ -626,15 +615,27 @@ def form_matrix(self, rates, fission_yields=None): # Gain from radioactive decay if nuc.n_decay_modes != 0: - for _, target, branching_ratio in nuc.decay_modes: - # Allow for total annihilation for debug purposes - if target is not None: - branch_val = branching_ratio * decay_constant + for decay_type, target, branching_ratio in nuc.decay_modes: + branch_val = branching_ratio * decay_constant - if branch_val != 0.0: + # Allow for total annihilation for debug purposes + if branch_val != 0.0: + if target is not None: k = self.nuclide_dict[target] matrix[k, i] += branch_val + # Produce alphas and protons from decay + if 'alpha' in decay_type: + k = self.nuclide_dict.get('He4') + if k is not None: + count = decay_type.count('alpha') + matrix[k, i] += count * branch_val + elif 'p' in decay_type: + k = self.nuclide_dict.get('H1') + if k is not None: + count = decay_type.count('p') + matrix[k, i] += count * branch_val + if nuc.name in rates.index_nuc: # Extract all reactions for this nuclide in this cell nuc_ind = rates.index_nuc[nuc.name] @@ -676,11 +677,71 @@ def form_matrix(self, rates, fission_yields=None): # Clear set of reactions reactions.clear() - # Use DOK matrix as intermediate representation, then convert to CSR and return + # Return CSC representation instead of DOK + return matrix.tocsc() + + def form_rr_term(self, tr_rates, mats): + """Function to form the transfer rate term matrices. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + tr_rates : openmc.deplete.TransferRates + Instance of openmc.deplete.TransferRates + mats : string or two-tuple of strings + Two cases are possible: + + 1) Material ID as string: + Nuclide transfer only. In this case the transfer rate terms will be + subtracted from the respective depletion matrix + + 2) Two-tuple of material IDs as strings: + Nuclide transfer from one material into another. + The pair is assumed to be + ``(destination_material, source_material)``, where + ``destination_material`` and ``source_material`` are the nuclide + receiving and losing materials, respectively. + The transfer rate terms get placed in the final matrix with indexing + position corresponding to the ID of the materials set. + + Returns + ------- + scipy.sparse.csc_matrix + Sparse matrix representing transfer term. + + """ + # Use DOK as intermediate representation n = len(self) - matrix_dok = sp.dok_matrix((n, n)) - dict.update(matrix_dok, matrix) - return matrix_dok.tocsr() + matrix = sp.dok_matrix((n, n)) + + for i, nuc in enumerate(self.nuclides): + elm = re.split(r'\d+', nuc.name)[0] + # Build transfer terms matrices + if isinstance(mats, str): + mat = mats + components = tr_rates.get_components(mat) + if elm in components: + matrix[i, i] = sum(tr_rates.get_transfer_rate(mat, elm)) + elif nuc.name in components: + matrix[i, i] = sum(tr_rates.get_transfer_rate(mat, nuc.name)) + else: + matrix[i, i] = 0.0 + #Build transfer terms matrices + elif isinstance(mats, tuple): + dest_mat, mat = mats + if dest_mat in tr_rates.get_destination_material(mat, elm): + dest_mat_idx = tr_rates.get_destination_material(mat, elm).index(dest_mat) + matrix[i, i] = tr_rates.get_transfer_rate(mat, elm)[dest_mat_idx] + elif dest_mat in tr_rates.get_destination_material(mat, nuc.name): + dest_mat_idx = tr_rates.get_destination_material(mat, nuc.name).index(dest_mat) + matrix[i, i] = tr_rates.get_transfer_rate(mat, nuc.name)[dest_mat_idx] + else: + matrix[i, i] = 0.0 + #Nothing else is allowed + + # Return CSC instead of DOK + return matrix.tocsc() def get_branch_ratios(self, reaction="(n,gamma)"): """Return a dictionary with reaction branching ratios @@ -812,8 +873,7 @@ def set_branch_ratios(self, branch_ratios, reaction="(n,gamma)", if len(indexes) == 0: if strict: raise AttributeError( - "Nuclide {} does not have {} reactions".format( - parent, reaction)) + f"Nuclide {parent} does not have {reaction} reactions") missing_reaction.add(parent) continue @@ -835,8 +895,7 @@ def set_branch_ratios(self, branch_ratios, reaction="(n,gamma)", if len(rxn_ix_map) == 0: raise IndexError( - "No {} reactions found in this {}".format( - reaction, self.__class__.__name__)) + f"No {reaction} reactions found in this {self.__class__.__name__}") if len(missing_parents) > 0: warn("The following nuclides were not found in {}: {}".format( @@ -847,14 +906,14 @@ def set_branch_ratios(self, branch_ratios, reaction="(n,gamma)", "{}".format(reaction, ", ".join(sorted(missing_reaction)))) if len(missing_products) > 0: - tail = ("{} -> {}".format(k, v) + tail = (f"{k} -> {v}" for k, v in sorted(missing_products.items())) warn("The following products were not found in the {} and " "parents were unmodified: \n{}".format( self.__class__.__name__, ", ".join(tail))) if len(bad_sums) > 0: - tail = ("{}: {:5.3f}".format(k, s) + tail = (f"{k}: {s:5.3f}" for k, s in sorted(bad_sums.items())) warn("The following parent nuclides were given {} branch ratios " "with a sum outside tolerance of 1 +/- {:5.3e}:\n{}".format( @@ -888,7 +947,7 @@ def set_branch_ratios(self, branch_ratios, reaction="(n,gamma)", ground_target = grounds.get(parent_name) if ground_target is None: pz, pa, pm = zam(parent_name) - ground_target = gnd_name(pz, pa + 1, 0) + ground_target = gnds_name(pz, pa + 1, 0) new_ratios[ground_target] = ground_br parent.add_reaction(reaction, ground_target, rxn_Q, ground_br) @@ -1021,6 +1080,7 @@ def reduce(self, initial_isotopes, level=None): new_nuclide = Nuclide(previous.name) new_nuclide.half_life = previous.half_life new_nuclide.decay_energy = previous.decay_energy + new_nuclide.sources = previous.sources.copy() if hasattr(previous, '_fpy'): new_nuclide._fpy = previous._fpy diff --git a/openmc/deplete/coupled_operator.py b/openmc/deplete/coupled_operator.py new file mode 100644 index 00000000000..acdcf467c57 --- /dev/null +++ b/openmc/deplete/coupled_operator.py @@ -0,0 +1,569 @@ +"""Transport-coupled transport operator for depletion. + +This module implements a transport operator coupled to OpenMC's transport solver +so that it can be used by depletion integrators. The implementation makes use of +the Python bindings to OpenMC's C API so that reading tally results and updating +material number densities is all done in-memory instead of through the +filesystem. + +""" + +import copy +from warnings import warn +from typing import Optional + +import numpy as np +from uncertainties import ufloat + +import openmc +from openmc.checkvalue import check_value +from openmc.data import DataLibrary +from openmc.exceptions import DataError +import openmc.lib +from openmc.mpi import comm +from .abc import OperatorResult +from .openmc_operator import OpenMCOperator +from .pool import _distribute +from .results import Results +from .helpers import ( + DirectReactionRateHelper, ChainFissionHelper, ConstantFissionYieldHelper, + FissionYieldCutoffHelper, AveragedFissionYieldHelper, EnergyScoreHelper, + SourceRateHelper, FluxCollapseHelper) + + +__all__ = ["CoupledOperator", "Operator", "OperatorResult"] + + +def _find_cross_sections(model: Optional[str] = None): + """Determine cross sections to use for depletion + + Parameters + ---------- + model : openmc.model.Model, optional + Reactor model + + """ + if model: + if model.materials and model.materials.cross_sections is not None: + # Prefer info from Model class if available + return model.materials.cross_sections + + # otherwise fallback to environment variable + cross_sections = openmc.config.get("cross_sections") + if cross_sections is None: + raise DataError( + "Cross sections were not specified in Model.materials and " + "openmc.config['cross_sections'] is not set." + ) + return cross_sections + + +def _get_nuclides_with_data(cross_sections): + """Loads cross_sections.xml file to find nuclides with neutron data + + Parameters + ---------- + cross_sections : str + Path to cross_sections.xml file + + Returns + ------- + nuclides : set of str + Set of nuclide names that have cross section data + + """ + nuclides = set() + data_lib = DataLibrary.from_xml(cross_sections) + for library in data_lib.libraries: + if library['type'] != 'neutron': + continue + for name in library['materials']: + if name not in nuclides: + nuclides.add(name) + + return nuclides + + +class CoupledOperator(OpenMCOperator): + """Transport-coupled transport operator. + + Instances of this class can be used to perform transport-coupled depletion + using OpenMC's transport solver. Normally, a user needn't call methods of + this class directly. Instead, an instance of this class is passed to an + integrator class, such as :class:`openmc.deplete.CECMIntegrator`. + + .. versionchanged:: 0.13.0 + The geometry and settings parameters have been replaced with a + model parameter that takes a :class:`~openmc.model.Model` object + + .. versionchanged:: 0.13.1 + Name changed from ``Operator`` to ``CoupledOperator`` + + Parameters + ---------- + model : openmc.model.Model + OpenMC model object + chain_file : str, optional + Path to the depletion chain XML file. Defaults to + ``openmc.config['chain_file']``. + prev_results : Results, optional + Results from a previous depletion calculation. If this argument is + specified, the depletion calculation will start from the latest state + in the previous results. + diff_burnable_mats : bool, optional + Whether to differentiate burnable materials with multiple instances. + Volumes are divided equally from the original material volume. + normalization_mode : {"energy-deposition", "fission-q", "source-rate"} + Indicate how tally results should be normalized. ``"energy-deposition"`` + computes the total energy deposited in the system and uses the ratio of + the power to the energy produced as a normalization factor. + ``"fission-q"`` uses the fission Q values from the depletion chain to + compute the total energy deposited. ``"source-rate"`` normalizes + tallies based on the source rate (for fixed source calculations). + fission_q : dict, optional + Dictionary of nuclides and their fission Q values [eV]. If not given, + values will be pulled from the ``chain_file``. Only applicable + if ``"normalization_mode" == "fission-q"`` + fission_yield_mode : {"constant", "cutoff", "average"} + Key indicating what fission product yield scheme to use. The + key determines what fission energy helper is used: + + * "constant": :class:`~openmc.deplete.helpers.ConstantFissionYieldHelper` + * "cutoff": :class:`~openmc.deplete.helpers.FissionYieldCutoffHelper` + * "average": :class:`~openmc.deplete.helpers.AveragedFissionYieldHelper` + + The documentation on these classes describe their methodology + and differences. Default: ``"constant"`` + fission_yield_opts : dict of str to option, optional + Optional arguments to pass to the helper determined by + ``fission_yield_mode``. Will be passed directly on to the + helper. Passing a value of None will use the defaults for + the associated helper. + reaction_rate_mode : {"direct", "flux"}, optional + Indicate how one-group reaction rates should be calculated. The "direct" + method tallies transmutation reaction rates directly. The "flux" method + tallies a multigroup flux spectrum and then collapses one-group reaction + rates after a transport solve (with an option to tally some reaction + rates directly). + + .. versionadded:: 0.12.1 + reaction_rate_opts : dict, optional + Keyword arguments that are passed to the reaction rate helper class. + When ``reaction_rate_mode`` is set to "flux", energy group boundaries + can be set using the "energies" key. See the + :class:`~openmc.deplete.helpers.FluxCollapseHelper` class for all + options. + + .. versionadded:: 0.12.1 + reduce_chain : bool, optional + If True, use :meth:`openmc.deplete.Chain.reduce` to reduce the + depletion chain up to ``reduce_chain_level``. + + .. versionadded:: 0.12 + reduce_chain_level : int, optional + Depth of the search when reducing the depletion chain. Only used + if ``reduce_chain`` evaluates to true. The default value of + ``None`` implies no limit on the depth. + + .. versionadded:: 0.12 + diff_volume_method : str + Specifies how the volumes of the new materials should be found. Default + is to 'divide equally' which divides the original material volume + equally between the new materials, 'match cell' sets the volume of the + material to volume of the cell they fill. + + .. versionadded:: 0.14.0 + + Attributes + ---------- + model : openmc.model.Model + OpenMC model object + output_dir : pathlib.Path + Path to output directory to save results. + round_number : bool + Whether or not to round output to OpenMC to 8 digits. + Useful in testing, as OpenMC is incredibly sensitive to exact values. + number : openmc.deplete.AtomNumber + Total number of atoms in simulation. + nuclides_with_data : set of str + A set listing all unique nuclides available from cross_sections.xml. + chain : openmc.deplete.Chain + The depletion chain information necessary to form matrices and tallies. + reaction_rates : openmc.deplete.ReactionRates + Reaction rates from the last operator step. + burnable_mats : list of str + All burnable material IDs + heavy_metal : float + Initial heavy metal inventory [g] + local_mats : list of str + All burnable material IDs being managed by a single process + prev_res : Results or None + Results from a previous depletion calculation. ``None`` if no + results are to be used. + cleanup_when_done : bool + Whether to finalize and clear the shared library memory when the + depletion operation is complete. Defaults to clearing the library. + """ + _fission_helpers = { + "average": AveragedFissionYieldHelper, + "constant": ConstantFissionYieldHelper, + "cutoff": FissionYieldCutoffHelper, + } + + def __init__(self, model, chain_file=None, prev_results=None, + diff_burnable_mats=False, diff_volume_method="divide equally", + normalization_mode="fission-q", fission_q=None, + fission_yield_mode="constant", fission_yield_opts=None, + reaction_rate_mode="direct", reaction_rate_opts=None, + reduce_chain=False, reduce_chain_level=None): + + # check for old call to constructor + if isinstance(model, openmc.Geometry): + msg = "As of version 0.13.0 openmc.deplete.CoupledOperator " \ + "requires an openmc.Model object rather than the " \ + "openmc.Geometry and openmc.Settings parameters. Please use " \ + "the geometry and settings objects passed here to create a " \ + " model with which to generate the transport Operator." + raise TypeError(msg) + + # Determine cross sections + cross_sections = _find_cross_sections(model) + + check_value('fission yield mode', fission_yield_mode, + self._fission_helpers.keys()) + check_value('normalization mode', normalization_mode, + ('energy-deposition', 'fission-q', 'source-rate')) + if normalization_mode != "fission-q": + if fission_q is not None: + warn("Fission Q dictionary will not be used") + fission_q = None + self.model = model + + # determine set of materials in the model + if not model.materials: + model.materials = openmc.Materials( + model.geometry.get_all_materials().values() + ) + + self.cleanup_when_done = True + + if reaction_rate_opts is None: + reaction_rate_opts = {} + if fission_yield_opts is None: + fission_yield_opts = {} + helper_kwargs = { + 'reaction_rate_mode': reaction_rate_mode, + 'normalization_mode': normalization_mode, + 'fission_yield_mode': fission_yield_mode, + 'reaction_rate_opts': reaction_rate_opts, + 'fission_yield_opts': fission_yield_opts + } + + # Records how many times the operator has been called + self._n_calls = 0 + + super().__init__( + materials=model.materials, + cross_sections=cross_sections, + chain_file=chain_file, + prev_results=prev_results, + diff_burnable_mats=diff_burnable_mats, + diff_volume_method=diff_volume_method, + fission_q=fission_q, + helper_kwargs=helper_kwargs, + reduce_chain=reduce_chain, + reduce_chain_level=reduce_chain_level) + + def _differentiate_burnable_mats(self): + """Assign distribmats for each burnable material""" + + self.model.differentiate_depletable_mats( + diff_volume_method=self.diff_volume_method + ) + + def _load_previous_results(self): + """Load results from a previous depletion simulation""" + # Reload volumes into geometry + self.prev_res[-1].transfer_volumes(self.model) + + # Store previous results in operator + # Distribute reaction rates according to those tracked + # on this process + if comm.size != 1: + prev_results = self.prev_res + self.prev_res = Results(filename=None) + mat_indexes = _distribute(range(len(self.burnable_mats))) + for res_obj in prev_results: + new_res = res_obj.distribute(self.local_mats, mat_indexes) + self.prev_res.append(new_res) + + def _get_nuclides_with_data(self, cross_sections): + """Loads cross_sections.xml file to find nuclides with neutron data + + Parameters + ---------- + cross_sections : str + Path to cross_sections.xml file + + Returns + ------- + nuclides : set of str + Set of nuclide names that have cross secton data + + """ + return _get_nuclides_with_data(cross_sections) + + def _get_helper_classes(self, helper_kwargs): + """Create the ``_rate_helper``, ``_normalization_helper``, and + ``_yield_helper`` objects. + + Parameters + ---------- + helper_kwargs : dict + Keyword arguments for helper classes + + """ + reaction_rate_mode = helper_kwargs['reaction_rate_mode'] + normalization_mode = helper_kwargs['normalization_mode'] + fission_yield_mode = helper_kwargs['fission_yield_mode'] + reaction_rate_opts = helper_kwargs['reaction_rate_opts'] + fission_yield_opts = helper_kwargs['fission_yield_opts'] + + # Get classes to assist working with tallies + if reaction_rate_mode == "direct": + self._rate_helper = DirectReactionRateHelper( + self.reaction_rates.n_nuc, self.reaction_rates.n_react) + elif reaction_rate_mode == "flux": + # Ensure energy group boundaries were specified + if 'energies' not in reaction_rate_opts: + raise ValueError( + "Energy group boundaries must be specified in the " + "reaction_rate_opts argument when reaction_rate_mode is" + "set to 'flux'.") + + self._rate_helper = FluxCollapseHelper( + self.reaction_rates.n_nuc, + self.reaction_rates.n_react, + **reaction_rate_opts + ) + else: + raise ValueError("Invalid reaction rate mode.") + + if normalization_mode == "fission-q": + self._normalization_helper = ChainFissionHelper() + elif normalization_mode == "energy-deposition": + score = "heating" if self.model.settings.photon_transport else "heating-local" + self._normalization_helper = EnergyScoreHelper(score) + else: + self._normalization_helper = SourceRateHelper() + + # Select and create fission yield helper + fission_helper = self._fission_helpers[fission_yield_mode] + self._yield_helper = fission_helper.from_operator( + self, **fission_yield_opts) + + def initial_condition(self): + """Performs final setup and returns initial condition. + + Returns + ------- + list of numpy.ndarray + Total density for initial conditions. + + """ + + # Create XML files + if comm.rank == 0: + self.model.geometry.export_to_xml() + self.model.settings.export_to_xml() + if self.model.plots: + self.model.plots.export_to_xml() + if self.model.tallies: + self.model.tallies.export_to_xml() + self._generate_materials_xml() + + # Initialize OpenMC library + comm.barrier() + if not openmc.lib.is_initialized: + openmc.lib.init(intracomm=comm) + + # Generate tallies in memory + materials = [openmc.lib.materials[int(i)] for i in self.burnable_mats] + + return super().initial_condition(materials) + + def _generate_materials_xml(self): + """Creates materials.xml from self.number. + + Due to uncertainty with how MPI interacts with OpenMC API, this + constructs the XML manually. The long term goal is to do this + through direct memory writing. + + """ + # Sort nuclides according to order in AtomNumber object + nuclides = list(self.number.nuclides) + for mat in self.materials: + mat._nuclides.sort(key=lambda x: nuclides.index(x[0])) + + self.materials.export_to_xml(nuclides_to_ignore=self._decay_nucs) + + def __call__(self, vec, source_rate): + """Runs a simulation. + + Simulation will abort under the following circumstances: + + 1) No energy is computed using OpenMC tallies. + + Parameters + ---------- + vec : list of numpy.ndarray + Total atoms to be used in function. + source_rate : float + Power in [W] or source rate in [neutron/sec] + + Returns + ------- + openmc.deplete.OperatorResult + Eigenvalue and reaction rates resulting from transport operator + + """ + # Reset results in OpenMC + openmc.lib.reset() + + # The timers are reset only if the operator has been called before. + # This is because we call this method after loading cross sections, and + # no transport has taken place yet. As a result, we only reset the + # timers after the first step so as to correctly report the time spent + # reading cross sections in the first depletion step, and from there + # correctly report all particle tracking rates in multistep depletion + # solvers. + if self._n_calls > 0: + openmc.lib.reset_timers() + + self._update_materials_and_nuclides(vec) + + # If the source rate is zero, return zero reaction rates without running + # a transport solve + if source_rate == 0.0: + rates = self.reaction_rates.copy() + rates.fill(0.0) + return OperatorResult(ufloat(0.0, 0.0), rates) + + # Run OpenMC + openmc.lib.run() + + # Extract results + rates = self._calculate_reaction_rates(source_rate) + + # Get k and uncertainty + keff = ufloat(*openmc.lib.keff()) + + op_result = OperatorResult(keff, rates) + + self._n_calls += 1 + + return copy.deepcopy(op_result) + + def _update_materials(self): + """Updates material compositions in OpenMC on all processes.""" + + for rank in range(comm.size): + number_i = comm.bcast(self.number, root=rank) + + for mat in number_i.materials: + nuclides = [] + densities = [] + for nuc in number_i.nuclides: + if nuc in self.nuclides_with_data: + val = 1.0e-24 * number_i.get_atom_density(mat, nuc) + + # If nuclide is zero, do not add to the problem. + if val > 0.0: + if self.round_number: + val_magnitude = np.floor(np.log10(val)) + val_scaled = val / 10**val_magnitude + val_round = round(val_scaled, 8) + + val = val_round * 10**val_magnitude + + nuclides.append(nuc) + densities.append(val) + else: + # Only output warnings if values are significantly + # negative. CRAM does not guarantee positive + # values. + if val < -1.0e-21: + print(f'WARNING: nuclide {nuc} in material' + f'{mat} is negative (density = {val}' + + ' atom/b-cm)') + + number_i[mat, nuc] = 0.0 + + # Update densities on C API side + mat_internal = openmc.lib.materials[int(mat)] + mat_internal.set_densities(nuclides, densities) + + # TODO Update densities on the Python side, otherwise the + # summary.h5 file contains densities at the first time step + + @staticmethod + def write_bos_data(step): + """Write a state-point file with beginning of step data + + Parameters + ---------- + step : int + Current depletion step including restarts + + """ + openmc.lib.statepoint_write( + f"openmc_simulation_n{step}.h5", + write_source=False) + + def finalize(self): + """Finalize a depletion simulation and release resources.""" + if self.cleanup_when_done: + openmc.lib.finalize() + + # The next few class variables and methods should be removed after one + # release cycle or so. For now, we will provide compatibility to + # accessing CoupledOperator.settings and CoupledOperator.geometry. In + # the future these should stay on the Model class. + + var_warning_msg = "The CoupledOperator.{0} variable should be \ +accessed through CoupledOperator.model.{0}." + geometry_warning_msg = var_warning_msg.format("geometry") + settings_warning_msg = var_warning_msg.format("settings") + + @property + def settings(self): + warn(self.settings_warning_msg, FutureWarning) + return self.model.settings + + @settings.setter + def settings(self, new_settings): + warn(self.settings_warning_msg, FutureWarning) + self.model.settings = new_settings + + @property + def geometry(self): + warn(self.geometry_warning_msg, FutureWarning) + return self.model.geometry + + @geometry.setter + def geometry(self, new_geometry): + warn(self.geometry_warning_msg, FutureWarning) + self.model.geometry = new_geometry + + +# Retain deprecated name for the time being +def Operator(*args, **kwargs): + # warn of name change + warn( + "The Operator(...) class has been renamed and will " + "be removed in a future version of OpenMC. Use " + "CoupledOperator(...) instead.", + FutureWarning + ) + return CoupledOperator(*args, **kwargs) diff --git a/openmc/deplete/cram.py b/openmc/deplete/cram.py index f5f80dfdc48..53de83bb68e 100644 --- a/openmc/deplete/cram.py +++ b/openmc/deplete/cram.py @@ -75,9 +75,9 @@ def __call__(self, A, n0, dt): Final compositions after ``dt`` """ - A = sp.csr_matrix(A * dt, dtype=np.float64) + A = dt * sp.csc_matrix(A, dtype=np.float64) y = n0.copy() - ident = sp.eye(A.shape[0]) + ident = sp.eye(A.shape[0], format='csc') for alpha, theta in zip(self.alpha, self.theta): y += 2*np.real(alpha*sla.spsolve(A - theta*ident, y)) return y * self.alpha0 diff --git a/openmc/deplete/helpers.py b/openmc/deplete/helpers.py index 6c3badc0904..f24b89868b8 100644 --- a/openmc/deplete/helpers.py +++ b/openmc/deplete/helpers.py @@ -1,7 +1,8 @@ """ -Class for normalizing fission energy deposition +Classes for collecting and calculating quantities for reaction rate operators """ import bisect +from abc import abstractmethod from collections import defaultdict from copy import deepcopy from itertools import product @@ -10,21 +11,115 @@ from numpy import dot, zeros, newaxis, asarray -from . import comm +from openmc.mpi import comm from openmc.checkvalue import check_type, check_greater_than from openmc.data import JOULE_PER_EV, REACTION_MT from openmc.lib import ( - Tally, MaterialFilter, EnergyFilter, EnergyFunctionFilter) + Tally, MaterialFilter, EnergyFilter, EnergyFunctionFilter, load_nuclide) import openmc.lib from .abc import ( - ReactionRateHelper, NormalizationHelper, FissionYieldHelper, - TalliedFissionYieldHelper) + ReactionRateHelper, NormalizationHelper, FissionYieldHelper) __all__ = ( "DirectReactionRateHelper", "ChainFissionHelper", "EnergyScoreHelper" - "SourceRateHelper", "ConstantFissionYieldHelper", "FissionYieldCutoffHelper", + "SourceRateHelper", "TalliedFissionYieldHelper", + "ConstantFissionYieldHelper", "FissionYieldCutoffHelper", "AveragedFissionYieldHelper", "FluxCollapseHelper") + +class TalliedFissionYieldHelper(FissionYieldHelper): + """Abstract class for computing fission yields with tallies + + Generates a basic fission rate tally in all burnable materials with + :meth:`generate_tallies`, and set nuclides to be tallied with + :meth:`update_tally_nuclides`. Subclasses will need to implement + :meth:`unpack` and :meth:`weighted_yields`. + + Parameters + ---------- + chain_nuclides : iterable of openmc.deplete.Nuclide + Nuclides tracked in the depletion chain. Not necessary + that all have yield data. + + Attributes + ---------- + constant_yields : dict of str to :class:`openmc.deplete.FissionYield` + Fission yields for all nuclides that only have one set of + fission yield data. Can be accessed as ``{parent: {product: yield}}`` + results : None or numpy.ndarray + Tally results shaped in a manner useful to this helper. + """ + + _upper_energy = 20.0e6 # upper energy for tallies + + def __init__(self, chain_nuclides): + super().__init__(chain_nuclides) + self._local_indexes = None + self._fission_rate_tally = None + self._tally_nucs = [] + self.results = None + + def generate_tallies(self, materials, mat_indexes): + """Construct the fission rate tally + + Parameters + ---------- + materials : iterable of :class:`openmc.lib.Material` + Materials to be used in :class:`openmc.lib.MaterialFilter` + mat_indexes : iterable of int + Indices of tallied materials that will have their fission + yields computed by this helper. Necessary as the + :class:`openmc.deplete.CoupledOperator` that uses this helper + may only burn a subset of all materials when running + in parallel mode. + """ + self._local_indexes = asarray(mat_indexes) + + # Tally group-wise fission reaction rates + self._fission_rate_tally = Tally() + self._fission_rate_tally.writable = False + self._fission_rate_tally.scores = ['fission'] + self._fission_rate_tally.filters = [MaterialFilter(materials)] + + def update_tally_nuclides(self, nuclides): + """Tally nuclides with non-zero density and multiple yields + + Must be run after :meth:`generate_tallies`. + + Parameters + ---------- + nuclides : iterable of str + Potential nuclides to be tallied, such as those with + non-zero density at this stage. + + Returns + ------- + nuclides : list of str + Union of input nuclides and those that have multiple sets + of yield data. Sorted by nuclide name + + Raises + ------ + AttributeError + If tallies not generated + """ + assert self._fission_rate_tally is not None, ( + "Run generate_tallies first") + overlap = set(self._chain_nuclides).intersection(set(nuclides)) + nuclides = sorted(overlap) + self._tally_nucs = [self._chain_nuclides[n] for n in nuclides] + self._fission_rate_tally.nuclides = nuclides + return nuclides + + @abstractmethod + def unpack(self): + """Unpack tallies after a transport run. + + Abstract because each subclass will need to arrange its + tally data. + """ + + # ------------------------------------- # Helpers for generating reaction rates # ------------------------------------- @@ -39,9 +134,11 @@ class DirectReactionRateHelper(ReactionRateHelper): Parameters ---------- n_nucs : int - Number of burnable nuclides tracked by :class:`openmc.deplete.Operator` + Number of burnable nuclides tracked by + :class:`openmc.deplete.CoupledOperator` n_react : int - Number of reactions tracked by :class:`openmc.deplete.Operator` + Number of reactions tracked by an instance of + :class:`openmc.deplete.CoupledOperator` Attributes ---------- @@ -63,34 +160,53 @@ def nuclides(self, nuclides): def generate_tallies(self, materials, scores): """Produce one-group reaction rate tally - Uses the :mod:`openmc.lib` to generate a tally - of relevant reactions across all burnable materials. + Uses the :mod:`openmc.lib` to generate a tally of relevant reactions + across all burnable materials. Parameters ---------- - materials : iterable of :class:`openmc.Material` - Burnable materials in the problem. Used to - construct a :class:`openmc.MaterialFilter` + materials : iterable of :class:`openmc.lib.Material` + Burnable materials in the problem. Used to construct a + :class:`openmc.lib.MaterialFilter` scores : iterable of str - Reaction identifiers, e.g. ``"(n, fission)"``, - ``"(n, gamma)"``, needed for the reaction rate tally. + Reaction identifiers, e.g. ``"(n, fission)"``, ``"(n, gamma)"``, + needed for the reaction rate tally. """ self._rate_tally = Tally() self._rate_tally.writable = False self._rate_tally.scores = scores self._rate_tally.filters = [MaterialFilter(materials)] + self._rate_tally.multiply_density = False + self._rate_tally_means_cache = None - def get_material_rates(self, mat_id, nuc_index, react_index): + @property + def rate_tally_means(self): + """The mean results of the tally of every material's reaction rates for this cycle + """ + # If the mean cache is empty, fill it once with this transport cycle's results + if self._rate_tally_means_cache is None: + self._rate_tally_means_cache = self._rate_tally.mean + return self._rate_tally_means_cache + + def reset_tally_means(self): + """Reset the cached mean rate tallies. + .. note:: + + This step must be performed after each transport cycle + """ + self._rate_tally_means_cache = None + + def get_material_rates(self, mat_index, nuc_index, rx_index): """Return an array of reaction rates for a material Parameters ---------- - mat_id : int - Unique ID for the requested material + mat_index : int + Index for the material nuc_index : iterable of int Index for each nuclide in :attr:`nuclides` in the desired reaction rate matrix - react_index : iterable of int + rx_index : iterable of int Index for each reaction scored in the tally Returns @@ -100,10 +216,9 @@ def get_material_rates(self, mat_id, nuc_index, react_index): reaction rates in this material """ self._results_cache.fill(0.0) - full_tally_res = self._rate_tally.mean[mat_id] - for i_tally, (i_nuc, i_react) in enumerate( - product(nuc_index, react_index)): - self._results_cache[i_nuc, i_react] = full_tally_res[i_tally] + full_tally_res = self.rate_tally_means[mat_index] + for i_tally, (i_nuc, i_rx) in enumerate(product(nuc_index, rx_index)): + self._results_cache[i_nuc, i_rx] = full_tally_res[i_tally] return self._results_cache @@ -123,9 +238,10 @@ class FluxCollapseHelper(ReactionRateHelper): Parameters ---------- n_nucs : int - Number of burnable nuclides tracked by :class:`openmc.deplete.Operator` + Number of burnable nuclides tracked by + :class:`openmc.deplete.CoupledOperator` n_react : int - Number of reactions tracked by :class:`openmc.deplete.Operator` + Number of reactions tracked by :class:`openmc.deplete.CoupledOperator` energies : iterable of float Energy group boundaries for flux spectrum in [eV] reactions : iterable of str @@ -152,6 +268,11 @@ def nuclides(self, nuclides): if self._reactions_direct and self._nuclides_direct is None: self._rate_tally.nuclides = nuclides + # Make sure nuclide data is loaded + for nuclide in self.nuclides: + if nuclide not in openmc.lib.nuclides: + openmc.lib.load_nuclide(nuclide) + def generate_tallies(self, materials, scores): """Produce multigroup flux spectrum tally @@ -181,6 +302,7 @@ def generate_tallies(self, materials, scores): EnergyFilter(self._energies) ] self._flux_tally.scores = ['flux'] + self._flux_tally_means_cache = None # Create reaction rate tally if self._reactions_direct: @@ -188,9 +310,43 @@ def generate_tallies(self, materials, scores): self._rate_tally.writable = False self._rate_tally.scores = self._reactions_direct self._rate_tally.filters = [MaterialFilter(materials)] + self._rate_tally.multiply_density = False + self._rate_tally_means_cache = None if self._nuclides_direct is not None: + # check if any direct tally nuclides are requested that are not + # already loaded with the materials. Load separately if so. + mat_nuclides = {n for mat in materials for n in mat.nuclides} + extra_nuclides = set(self._nuclides_direct) - mat_nuclides + for nuc in extra_nuclides: + load_nuclide(nuc) self._rate_tally.nuclides = self._nuclides_direct + @property + def rate_tally_means(self): + """The mean results of the tally of every material's reaction rates for this cycle + """ + # If the mean cache is empty, fill it once with this transport cycle's results + if self._rate_tally_means_cache is None: + self._rate_tally_means_cache = self._rate_tally.mean + return self._rate_tally_means_cache + + @property + def flux_tally_means(self): + # If the mean cache is empty, fill it once for this transport cycle's results + if self._flux_tally_means_cache is None: + self._flux_tally_means_cache = self._flux_tally.mean + return self._flux_tally_means_cache + + def reset_tally_means(self): + """Reset the cached mean rate and flux tallies. + .. note:: + + This step must be performed after each transport cycle + """ + self._flux_tally_means_cache = None + if self._reactions_direct: + self._rate_tally_means_cache = None + def get_material_rates(self, mat_index, nuc_index, react_index): """Return an array of reaction rates for a material @@ -215,24 +371,18 @@ def get_material_rates(self, mat_index, nuc_index, react_index): # Get flux for specified material shape = (len(self._materials), len(self._energies) - 1) - mean_value = self._flux_tally.mean.reshape(shape) + mean_value = self.flux_tally_means.reshape(shape) flux = mean_value[mat_index] # Get direct reaction rates if self._reactions_direct: nuclides_direct = self._rate_tally.nuclides shape = (len(nuclides_direct), len(self._reactions_direct)) - rx_rates = self._rate_tally.mean[mat_index].reshape(shape) + rx_rates = self.rate_tally_means[mat_index].reshape(shape) mat = self._materials[mat_index] - # Build nucname: density mapping to enable O(1) lookup in loop below - densities = dict(zip(mat.nuclides, mat.densities)) - for name, i_nuc in zip(self.nuclides, nuc_index): - # Determine density of nuclide - density = densities[name] - for mt, score, i_rx in zip(self._mts, self._scores, react_index): if score in self._reactions_direct and name in nuclides_direct: # Determine index in rx_rates @@ -247,8 +397,7 @@ def get_material_rates(self, mat_index, nuc_index, react_index): rate_per_nuc = nuc.collapse_rate( mt, mat.temperature, self._energies, flux) - # Multiply by density to get absolute reaction rate - self._results_cache[i_nuc, i_rx] = rate_per_nuc * density + self._results_cache[i_nuc, i_rx] = rate_per_nuc return self._results_cache @@ -291,7 +440,7 @@ class ChainFissionHelper(EnergyNormalizationHelper): ---------- nuclides : list of str All nuclides with desired reaction rates. Ordered to be - consistent with :class:`openmc.deplete.Operator` + consistent with :class:`openmc.deplete.CoupledOperator` energy : float Total energy [J/s/source neutron] produced in a transport simulation. Updated in the material iteration with :meth:`update`. @@ -445,7 +594,6 @@ def __init__(self, chain_nuclides, energy=0.0253): self._constant_yields[name] = yield_data continue # Specific energy not found, use closest energy - distances = [abs(energy - ene) for ene in nuc.yield_energies] min_E = min(nuc.yield_energies, key=lambda e: abs(e - energy)) self._constant_yields[name] = nuc.yield_data[min_E] @@ -458,7 +606,7 @@ def from_operator(cls, operator, **kwargs): Parameters ---------- - operator : openmc.deplete.TransportOperator + operator : openmc.deplete.abc.TransportOperator operator with a depletion chain kwargs: Additional keyword arguments to be used in construction @@ -516,7 +664,6 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper): Default: 0.0253 [eV] fast_energy : float, optional Energy of yield data corresponding to fast yields. - Default: 500 [kev] Attributes ---------- @@ -538,10 +685,10 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper): Array of fission rate fractions with shape ``(n_mats, 2, n_nucs)``. ``results[:, 0]`` corresponds to the fraction of all fissions - that occured below ``cutoff``. The number + that occurred below ``cutoff``. The number of materials in the first axis corresponds to the number of materials burned by the - :class:`openmc.deplete.Operator` + :class:`openmc.deplete.CoupledOperator` """ def __init__(self, chain_nuclides, n_bmats, cutoff=112.0, @@ -598,7 +745,7 @@ def from_operator(cls, operator, **kwargs): Parameters ---------- - operator : openmc.deplete.Operator + operator : openmc.deplete.CoupledOperator Operator with a chain and burnable materials kwargs: Additional keyword arguments to be used in construction @@ -624,7 +771,7 @@ def generate_tallies(self, materials, mat_indexes): mat_indexes : iterable of int Indices of tallied materials that will have their fission yields computed by this helper. Necessary as the - :class:`openmc.deplete.Operator` that uses this helper + :class:`openmc.deplete.CoupledOperator` that uses this helper may only burn a subset of all materials when running in parallel mode. """ @@ -694,7 +841,7 @@ def fast_yields(self): class AveragedFissionYieldHelper(TalliedFissionYieldHelper): r"""Class that computes fission yields based on average fission energy - Computes average energy at which fission events occured with + Computes average energy at which fission events occurred with .. math:: @@ -749,7 +896,7 @@ def generate_tallies(self, materials, mat_indexes): mat_indexes : iterable of int Indices of tallied materials that will have their fission yields computed by this helper. Necessary as the - :class:`openmc.deplete.Operator` that uses this helper + :class:`openmc.deplete.CoupledOperator` that uses this helper may only burn a subset of all materials when running in parallel mode. """ @@ -812,7 +959,7 @@ def weighted_yields(self, local_mat_index): Use the computed average energy of fission events to determine fission yields. If average energy is between two sets of yields, linearly - interpolate bewteen the two. + interpolate between the two. Otherwise take the closet set of yields. Parameters @@ -862,7 +1009,7 @@ def from_operator(cls, operator, **kwargs): Parameters ---------- - operator : openmc.deplete.TransportOperator + operator : openmc.deplete.CoupledOperator Operator with a depletion chain kwargs : Additional keyword arguments to be used in construction diff --git a/openmc/deplete/independent_operator.py b/openmc/deplete/independent_operator.py new file mode 100644 index 00000000000..250b94deb42 --- /dev/null +++ b/openmc/deplete/independent_operator.py @@ -0,0 +1,456 @@ +"""Transport-independent transport operator for depletion. + +This module implements a transport operator that runs independently of any +transport solver by using user-provided one-group cross sections. + +""" + +from __future__ import annotations +from collections.abc import Iterable +import copy +from typing import List, Set + +import numpy as np +from uncertainties import ufloat + +import openmc +from openmc.checkvalue import check_type +from openmc.mpi import comm +from .abc import ReactionRateHelper, OperatorResult +from .openmc_operator import OpenMCOperator +from .pool import _distribute +from .microxs import MicroXS +from .results import Results +from .helpers import ChainFissionHelper, ConstantFissionYieldHelper, SourceRateHelper + + +class IndependentOperator(OpenMCOperator): + """Transport-independent transport operator that uses one-group cross + sections to calculate reaction rates. + + Instances of this class can be used to perform depletion using one-group + cross sections and constant flux or constant power. Normally, a user needn't + call methods of this class directly. Instead, an instance of this class is + passed to an integrator class, such as + :class:`openmc.deplete.CECMIntegrator`. + + Note that passing an empty :class:`~openmc.deplete.MicroXS` instance to the + ``micro_xs`` argument allows a decay-only calculation to be run. + + .. versionadded:: 0.13.1 + + .. versionchanged:: 0.14.0 + Arguments updated to include list of fluxes and microscopic cross + sections. + + Parameters + ---------- + materials : openmc.Materials + Materials to deplete. + fluxes : list of numpy.ndarray + Flux in each group in [n-cm/src] for each domain + micros : list of MicroXS + Cross sections in [b] for each domain. If the + :class:`~openmc.deplete.MicroXS` object is empty, a decay-only + calculation will be run. + chain_file : str + Path to the depletion chain XML file. Defaults to + ``openmc.config['chain_file']``. + keff : 2-tuple of float, optional + keff eigenvalue and uncertainty from transport calculation. + Default is None. + prev_results : Results, optional + Results from a previous depletion calculation. + normalization_mode : {"fission-q", "source-rate"} + Indicate how reaction rates should be calculated. + ``"fission-q"`` uses the fission Q values from the depletion chain to + compute the flux based on the power. ``"source-rate"`` uses a the + source rate (assumed to be neutron flux) to calculate the + reaction rates. + fission_q : dict, optional + Dictionary of nuclides and their fission Q values [eV]. If not given, + values will be pulled from the ``chain_file``. Only applicable + if ``"normalization_mode" == "fission-q"``. + reduce_chain : bool, optional + If True, use :meth:`openmc.deplete.Chain.reduce` to reduce the + depletion chain up to ``reduce_chain_level``. + reduce_chain_level : int, optional + Depth of the search when reducing the depletion chain. Only used + if ``reduce_chain`` evaluates to true. The default value of + ``None`` implies no limit on the depth. + fission_yield_opts : dict of str to option, optional + Optional arguments to pass to the + :class:`openmc.deplete.helpers.FissionYieldHelper` object. Will be + passed directly on to the helper. Passing a value of None will use + the defaults for the associated helper. + + Attributes + ---------- + materials : openmc.Materials + All materials present in the model + cross_sections : MicroXS + Object containing one-group cross-sections in [cm^2]. + output_dir : pathlib.Path + Path to output directory to save results. + round_number : bool + Whether or not to round output to OpenMC to 8 digits. + Useful in testing, as OpenMC is incredibly sensitive to exact values. + number : openmc.deplete.AtomNumber + Total number of atoms in simulation. + nuclides_with_data : set of str + A set listing all unique nuclides available from cross_sections.xml. + chain : openmc.deplete.Chain + The depletion chain information necessary to form matrices and tallies. + reaction_rates : openmc.deplete.ReactionRates + Reaction rates from the last operator step. + burnable_mats : list of str + All burnable material IDs + heavy_metal : float + Initial heavy metal inventory [g] + local_mats : list of str + All burnable material IDs being managed by a single process + prev_res : Results or None + Results from a previous depletion calculation. ``None`` if no + results are to be used. + + """ + + def __init__(self, + materials, + fluxes, + micros, + chain_file=None, + keff=None, + normalization_mode='fission-q', + fission_q=None, + prev_results=None, + reduce_chain=False, + reduce_chain_level=None, + fission_yield_opts=None): + # Validate micro-xs parameters + check_type('materials', materials, openmc.Materials) + check_type('micros', micros, Iterable, MicroXS) + + if not (len(fluxes) == len(micros) == len(materials)): + msg = (f'The length of fluxes ({len(fluxes)}) should be equal to ' + f'the length of micros ({len(micros)}) and the length of ' + f'materials ({len(materials)}).') + raise ValueError(msg) + + if keff is not None: + check_type('keff', keff, tuple, float) + keff = ufloat(*keff) + + self._keff = keff + + if fission_yield_opts is None: + fission_yield_opts = {} + helper_kwargs = {'normalization_mode': normalization_mode, + 'fission_yield_opts': fission_yield_opts} + + # Sort fluxes and micros in same order that materials get sorted + index_sort = np.argsort([mat.id for mat in materials]) + fluxes = [fluxes[i] for i in index_sort] + micros = [micros[i] for i in index_sort] + + self.fluxes = fluxes + super().__init__( + materials=materials, + cross_sections=micros, + chain_file=chain_file, + prev_results=prev_results, + fission_q=fission_q, + helper_kwargs=helper_kwargs, + reduce_chain=reduce_chain, + reduce_chain_level=reduce_chain_level) + + @classmethod + def from_nuclides(cls, volume, nuclides, + flux, + micro_xs, + chain_file=None, + nuc_units='atom/b-cm', + keff=None, + normalization_mode='fission-q', + fission_q=None, + prev_results=None, + reduce_chain=False, + reduce_chain_level=None, + fission_yield_opts=None): + """ + Alternate constructor from a dictionary of nuclide concentrations + + volume : float + Volume of the material being depleted in [cm^3] + nuclides : dict of str to float + Dictionary with nuclide names as keys and nuclide concentrations as + values. + flux : numpy.ndarray + Flux in each group in [n-cm/src] + micro_xs : MicroXS + Cross sections in [b]. If the :class:`~openmc.deplete.MicroXS` + object is empty, a decay-only calculation will be run. + chain_file : str, optional + Path to the depletion chain XML file. Defaults to + ``openmc.config['chain_file']``. + nuc_units : {'atom/cm3', 'atom/b-cm'}, optional + Units for nuclide concentration. + keff : 2-tuple of float, optional + keff eigenvalue and uncertainty from transport calculation. + Default is None. + normalization_mode : {"fission-q", "source-rate"} + Indicate how reaction rates should be calculated. + ``"fission-q"`` uses the fission Q values from the depletion + chain to compute the flux based on the power. ``"source-rate"`` uses + the source rate (assumed to be neutron flux) to calculate the + reaction rates. + fission_q : dict, optional + Dictionary of nuclides and their fission Q values [eV]. If not + given, values will be pulled from the ``chain_file``. Only + applicable if ``"normalization_mode" == "fission-q"``. + prev_results : Results, optional + Results from a previous depletion calculation. + reduce_chain : bool, optional + If True, use :meth:`openmc.deplete.Chain.reduce` to reduce the + depletion chain up to ``reduce_chain_level``. Default is False. + reduce_chain_level : int, optional + Depth of the search when reducing the depletion chain. Only used + if ``reduce_chain`` evaluates to true. The default value of + ``None`` implies no limit on the depth. + fission_yield_opts : dict of str to option, optional + Optional arguments to pass to the + :class:`openmc.deplete.helpers.FissionYieldHelper` class. Will be + passed directly on to the helper. Passing a value of None will use + the defaults for the associated helper. + + """ + check_type('nuclides', nuclides, dict, str) + materials = cls._consolidate_nuclides_to_material(nuclides, nuc_units, volume) + fluxes = [flux] + micros = [micro_xs] + return cls(materials, + fluxes, + micros, + chain_file, + keff=keff, + normalization_mode=normalization_mode, + fission_q=fission_q, + prev_results=prev_results, + reduce_chain=reduce_chain, + reduce_chain_level=reduce_chain_level, + fission_yield_opts=fission_yield_opts) + + @staticmethod + def _consolidate_nuclides_to_material(nuclides, nuc_units, volume): + """Puts nuclide list into an openmc.Materials object. + + """ + openmc.reset_auto_ids() + mat = openmc.Material() + if nuc_units == 'atom/b-cm': + for nuc, conc in nuclides.items(): + mat.add_nuclide(nuc, conc) + elif nuc_units == 'atom/cm3': + for nuc, conc in nuclides.items(): + mat.add_nuclide(nuc, conc * 1e-24) # convert to at/b-cm + else: + raise ValueError(f"Unit '{nuc_units}' is invalid.") + + mat.volume = volume + mat.depletable = True + + return openmc.Materials([mat]) + + def _load_previous_results(self): + """Load results from a previous depletion simulation""" + # Reload volumes into geometry + model = openmc.Model(materials=self.materials) + self.prev_res[-1].transfer_volumes(model) + self.materials = model.materials + + # Store previous results in operator + # Distribute reaction rates according to those tracked + # on this process + if comm.size != 1: + prev_results = self.prev_res + self.prev_res = Results() + mat_indexes = _distribute(range(len(self.burnable_mats))) + for res_obj in prev_results: + new_res = res_obj.distribute(self.local_mats, mat_indexes) + self.prev_res.append(new_res) + + def _get_nuclides_with_data(self, cross_sections: List[MicroXS]) -> Set[str]: + """Finds nuclides with cross section data""" + return set(cross_sections[0].nuclides) + + class _IndependentRateHelper(ReactionRateHelper): + """Class for generating one-group reaction rates with flux and + one-group cross sections. + + This class does not generate tallies, and instead stores cross sections + for each nuclide and transmutation reaction relevant for a depletion + calculation. The reaction rate is calculated by multiplying the flux by + the cross sections. + + Parameters + ---------- + op : openmc.deplete.IndependentOperator + Reference to the object encapsulate _IndependentRateHelper. + We pass this so we don't have to duplicate the + :attr:`IndependentOperator.number` object. + + Attributes + ---------- + nuc_ind_map : dict of int to str + Dictionary mapping the nuclide index to nuclide name + rx_ind_map : dict of int to str + Dictionary mapping reaction index to reaction name + + """ + + def __init__(self, op: IndependentOperator): + rates = op.reaction_rates + super().__init__(rates.n_nuc, rates.n_react) + + self.nuc_ind_map = {ind: nuc for nuc, ind in rates.index_nuc.items()} + self.rx_ind_map = {ind: rxn for rxn, ind in rates.index_rx.items()} + self._op = op + + def generate_tallies(self, materials, scores): + """Unused in this case""" + pass + + def reset_tally_means(self): + """Unused in this case""" + pass + + def get_material_rates(self, mat_index, nuc_index, react_index): + """Return 2D array of [nuclide, reaction] reaction rates + + Parameters + ---------- + mat_index : int + Index for the material + nuc_index : list of str + Ordering of desired nuclides + react_index : list of str + Ordering of reactions + """ + self._results_cache.fill(0.0) + + # Get flux and microscopic cross sections from operator + flux = self._op.fluxes[mat_index] + xs = self._op.cross_sections[mat_index] + + for i_nuc in nuc_index: + nuc = self.nuc_ind_map[i_nuc] + for i_rx in react_index: + rx = self.rx_ind_map[i_rx] + + # Determine reaction rate by multiplying xs in [b] by flux + # in [n-cm/src] to give [(reactions/src)*b-cm/atom] + self._results_cache[i_nuc, i_rx] = (xs[nuc, rx] * flux).sum() + + return self._results_cache + + def _get_helper_classes(self, helper_kwargs): + """Get helper classes for calculating reaction rates and fission yields + + Parameters + ---------- + helper_kwargs : dict + Keyword arguments for helper classes + + """ + + normalization_mode = helper_kwargs['normalization_mode'] + fission_yield_opts = helper_kwargs['fission_yield_opts'] + + self._rate_helper = self._IndependentRateHelper(self) + if normalization_mode == "fission-q": + self._normalization_helper = ChainFissionHelper() + else: + self._normalization_helper = SourceRateHelper() + + # Select and create fission yield helper + fission_helper = ConstantFissionYieldHelper + self._yield_helper = fission_helper.from_operator( + self, **fission_yield_opts) + + def initial_condition(self): + """Performs final setup and returns initial condition. + + Returns + ------- + list of numpy.ndarray + Total density for initial conditions. + """ + + # Return number density vector + return super().initial_condition(self.materials) + + def __call__(self, vec, source_rate): + """Obtain the reaction rates + + Parameters + ---------- + vec : list of numpy.ndarray + Total atoms to be used in function. + source_rate : float + Power in [W] or flux in [neutron/cm^2-s] + + Returns + ------- + openmc.deplete.OperatorResult + Eigenvalue and reaction rates resulting from transport operator + + """ + + self._update_materials_and_nuclides(vec) + + # If the source rate is zero, return zero reaction rates + if source_rate == 0.0: + rates = self.reaction_rates.copy() + rates.fill(0.0) + return OperatorResult(ufloat(0.0, 0.0), rates) + + rates = self._calculate_reaction_rates(source_rate) + keff = self._keff + + op_result = OperatorResult(keff, rates) + return copy.deepcopy(op_result) + + def _update_materials(self): + """Updates material compositions in OpenMC on all processes.""" + + for rank in range(comm.size): + number_i = comm.bcast(self.number, root=rank) + + for mat in number_i.materials: + nuclides = [] + densities = [] + for nuc in number_i.nuclides: + if nuc in self.nuclides_with_data: + val = 1.0e-24 * number_i.get_atom_density(mat, nuc) + + # If nuclide is zero, do not add to the problem. + if val > 0.0: + if self.round_number: + val_magnitude = np.floor(np.log10(val)) + val_scaled = val / 10**val_magnitude + val_round = round(val_scaled, 8) + + val = val_round * 10**val_magnitude + + nuclides.append(nuc) + densities.append(val) + else: + # Only output warnings if values are significantly + # negative. CRAM does not guarantee positive + # values. + if val < -1.0e-21: + print(f'WARNING: nuclide {nuc} in material' + f'{mat} is negative (density = {val}' + + ' atom/b-cm)') + number_i[mat, nuc] = 0.0 diff --git a/openmc/deplete/integrators.py b/openmc/deplete/integrators.py index fbf43a808e9..a877c4900f6 100644 --- a/openmc/deplete/integrators.py +++ b/openmc/deplete/integrators.py @@ -21,21 +21,19 @@ class PredictorIntegrator(Integrator): mathematically defined as: .. math:: - \begin{aligned} - y' &= A(y, t) y(t) \\ - A_p &= A(y_n, t_n) \\ - y_{n+1} &= \text{expm}(A_p h) y_n - \end{aligned} + \mathbf{n}_{i+1} = \exp\left(h\mathbf{A}(\mathbf{n}_i) \right) \mathbf{n}_i + """ _num_stages = 1 - def __call__(self, conc, rates, dt, source_rate, _i=None): + def __call__(self, n, rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - conc : numpy.ndarray - Initial concentrations for all nuclides in [atom] + n : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -49,15 +47,15 @@ def __call__(self, conc, rates, dt, source_rate, _i=None): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - conc_list : list of numpy.ndarray + n_list : list of list of numpy.ndarray Concentrations at end of interval op_results : empty list - Kept for consistency with API. No intermediate calls to - operator with predictor + Kept for consistency with API. No intermediate calls to operator + with predictor """ - proc_time, conc_end = self._timed_deplete(conc, rates, dt) - return proc_time, [conc_end], [] + proc_time, n_end = self._timed_deplete(n, rates, dt) + return proc_time, [n_end], [] @add_params @@ -72,22 +70,22 @@ class CECMIntegrator(Integrator): .. math:: \begin{aligned} - y' &= A(y, t) y(t) \\ - A_p &= A(y_n, t_n) \\ - y_m &= \text{expm}(A_p h/2) y_n \\ - A_c &= A(y_m, t_n + h/2) \\ - y_{n+1} &= \text{expm}(A_c h) y_n + \mathbf{n}_{i+1/2} &= \exp \left (\frac{h}{2}\mathbf{A}(\mathbf{n}_i) + \right) \mathbf{n}_i \\ + \mathbf{n}_{i+1} &= \exp \left(h \mathbf{A}(\mathbf{n}_{i+1/2}) \right) + \mathbf{n}_i. \end{aligned} """ _num_stages = 2 - def __call__(self, conc, rates, dt, source_rate, _i=None): + def __call__(self, n, rates, dt, source_rate, _i=None): """Integrate using CE/CM Parameters ---------- - conc : numpy.ndarray - Initial concentrations for all nuclides in [atom] + n : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -101,21 +99,21 @@ def __call__(self, conc, rates, dt, source_rate, _i=None): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - conc_list : list of numpy.ndarray + n_list : list of list of numpy.ndarray Concentrations at each of the intermediate points with the final concentration as the last element op_results : list of openmc.deplete.OperatorResult Eigenvalue and reaction rates from transport simulations """ - # deplete across first half of inteval - time0, x_middle = self._timed_deplete(conc, rates, dt / 2) - res_middle = self.operator(x_middle, source_rate) + # deplete across first half of interval + time0, n_middle = self._timed_deplete(n, rates, dt / 2) + res_middle = self.operator(n_middle, source_rate) # deplete across entire interval with BOS concentrations, # MOS reaction rates - time1, x_end = self._timed_deplete(conc, res_middle.rates, dt) + time1, n_end = self._timed_deplete(n, res_middle.rates, dt) - return time0 + time1, [x_middle, x_end], [res_middle] + return time0 + time1, [n_middle, n_end], [res_middle] @add_params @@ -128,26 +126,30 @@ class CF4Integrator(Integrator): .. math:: \begin{aligned} - F_1 &= h A(y_0) \\ - y_1 &= \text{expm}(1/2 F_1) y_0 \\ - F_2 &= h A(y_1) \\ - y_2 &= \text{expm}(1/2 F_2) y_0 \\ - F_3 &= h A(y_2) \\ - y_3 &= \text{expm}(-1/2 F_1 + F_3) y_1 \\ - F_4 &= h A(y_3) \\ - y_4 &= \text{expm}( 1/4 F_1 + 1/6 F_2 + 1/6 F_3 - 1/12 F_4) - \text{expm}(-1/12 F_1 + 1/6 F_2 + 1/6 F_3 + 1/4 F_4) y_0 + \mathbf{A}_1 &= h\mathbf{A}(\mathbf{n}_i) \\ + \hat{\mathbf{n}}_1 &= \exp \left ( \frac{\mathbf{A}_1}{2} \right ) \mathbf{n}_i \\ + \mathbf{A}_2 &= h\mathbf{A}(\hat{\mathbf{n}}_1) \\ + \hat{\mathbf{n}}_2 &= \exp \left ( \frac{\mathbf{A}_2}{2} \right ) \mathbf{n}_i \\ + \mathbf{A}_3 &= h \mathbf{A}(\hat{\mathbf{n}}_2) \\ + \hat{\mathbf{n}}_3 &= \exp \left ( -\frac{\mathbf{A}_1}{2} + \mathbf{A}_3 + \right ) \hat{\mathbf{n}}_1 \\ + \mathbf{A}_4 &= h\mathbf{A}(\hat{\mathbf{n}}_3) \\ + \mathbf{n}_{i+1} &= \exp \left ( \frac{\mathbf{A}_1}{4} + \frac{\mathbf{A}_2}{6} + + \frac{\mathbf{A}_3}{6} - \frac{\mathbf{A}_4}{12} \right ) + \exp \left ( -\frac{\mathbf{A}_1}{12} + \frac{\mathbf{A}_2}{6} + + \frac{\mathbf{A}_3}{6} + \frac{\mathbf{A}_4}{4} \right ) \mathbf{n}_i. \end{aligned} """ _num_stages = 4 - def __call__(self, bos_conc, bos_rates, dt, source_rate, _i=None): + def __call__(self, n_bos, bos_rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - bos_conc : numpy.ndarray - Initial concentrations for all nuclides in [atom] + n_bos : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. bos_rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -161,7 +163,7 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, _i=None): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - conc_list : list of numpy.ndarray + n_list : list of numpy.ndarray Concentrations at each of the intermediate points with the final concentration as the last element op_results : list of openmc.deplete.OperatorResult @@ -169,30 +171,30 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, _i=None): simulations """ # Step 1: deplete with matrix 1/2*A(y0) - time1, conc_eos1 = self._timed_deplete( - bos_conc, bos_rates, dt, matrix_func=cf4_f1) - res1 = self.operator(conc_eos1, source_rate) + time1, n_eos1 = self._timed_deplete( + n_bos, bos_rates, dt, matrix_func=cf4_f1) + res1 = self.operator(n_eos1, source_rate) # Step 2: deplete with matrix 1/2*A(y1) - time2, conc_eos2 = self._timed_deplete( - bos_conc, res1.rates, dt, matrix_func=cf4_f1) - res2 = self.operator(conc_eos2, source_rate) + time2, n_eos2 = self._timed_deplete( + n_bos, res1.rates, dt, matrix_func=cf4_f1) + res2 = self.operator(n_eos2, source_rate) # Step 3: deplete with matrix -1/2*A(y0)+A(y2) list_rates = list(zip(bos_rates, res2.rates)) - time3, conc_eos3 = self._timed_deplete( - conc_eos1, list_rates, dt, matrix_func=cf4_f2) - res3 = self.operator(conc_eos3, source_rate) + time3, n_eos3 = self._timed_deplete( + n_eos1, list_rates, dt, matrix_func=cf4_f2) + res3 = self.operator(n_eos3, source_rate) # Step 4: deplete with two matrix exponentials list_rates = list(zip(bos_rates, res1.rates, res2.rates, res3.rates)) - time4, conc_inter = self._timed_deplete( - bos_conc, list_rates, dt, matrix_func=cf4_f3) - time5, conc_eos5 = self._timed_deplete( - conc_inter, list_rates, dt, matrix_func=cf4_f4) + time4, n_inter = self._timed_deplete( + n_bos, list_rates, dt, matrix_func=cf4_f3) + time5, n_eos5 = self._timed_deplete( + n_inter, list_rates, dt, matrix_func=cf4_f4) return (time1 + time2 + time3 + time4 + time5, - [conc_eos1, conc_eos2, conc_eos3, conc_eos5], + [n_eos1, n_eos2, n_eos3, n_eos5], [res1, res2, res3]) @@ -208,23 +210,24 @@ class CELIIntegrator(Integrator): .. math:: \begin{aligned} - y' &= A(y, t) y(t) \\ - A_0 &= A(y_n, t_n) \\ - y_p &= \text{expm}(h A_0) y_n \\ - A_1 &= A(y_p, t_n + h) \\ - y_{n+1} &= \text{expm}(\frac{h}{12} A_0 + \frac{5h}{12} A1) - \text{expm}(\frac{5h}{12} A_0 + \frac{h}{12} A1) y_n + \mathbf{n}_{i+1}^p &= \exp \left ( h \mathbf{A}(\mathbf{n}_i ) \right ) + \mathbf{n}_i \\ + \mathbf{n}_{i+1} &= \exp \left( \frac{h}{12} \mathbf{A}(\mathbf{n}_i) + + \frac{5h}{12} \mathbf{A}(\mathbf{n}_{i+1}^p) \right) + \exp \left( \frac{5h}{12} \mathbf{A}(\mathbf{n}_i) + + \frac{h}{12} \mathbf{A}(\mathbf{n}_{i+1}^p) \right) \mathbf{n}_i. \end{aligned} """ _num_stages = 2 - def __call__(self, bos_conc, rates, dt, source_rate, _i=None): + def __call__(self, n_bos, rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - bos_conc : numpy.ndarray - Initial concentrations for all nuclides in [atom] + n_bos : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -238,7 +241,7 @@ def __call__(self, bos_conc, rates, dt, source_rate, _i=None): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - conc_list : list of numpy.ndarray + n_list : list of list of numpy.ndarray Concentrations at each of the intermediate points with the final concentration as the last element op_results : list of openmc.deplete.OperatorResult @@ -246,19 +249,19 @@ def __call__(self, bos_conc, rates, dt, source_rate, _i=None): simulation """ # deplete to end using BOS rates - proc_time, conc_ce = self._timed_deplete(bos_conc, rates, dt) - res_ce = self.operator(conc_ce, source_rate) + proc_time, n_ce = self._timed_deplete(n_bos, rates, dt) + res_ce = self.operator(n_ce, source_rate) # deplete using two matrix exponentials list_rates = list(zip(rates, res_ce.rates)) - time_le1, conc_inter = self._timed_deplete( - bos_conc, list_rates, dt, matrix_func=celi_f1) + time_le1, n_inter = self._timed_deplete( + n_bos, list_rates, dt, matrix_func=celi_f1) - time_le2, conc_end = self._timed_deplete( - conc_inter, list_rates, dt, matrix_func=celi_f2) + time_le2, n_end = self._timed_deplete( + n_inter, list_rates, dt, matrix_func=celi_f2) - return proc_time + time_le1 + time_le1, [conc_ce, conc_end], [res_ce] + return proc_time + time_le1 + time_le1, [n_ce, n_end], [res_ce] @add_params @@ -270,25 +273,27 @@ class EPCRK4Integrator(Integrator): .. math:: \begin{aligned} - F_1 &= h A(y_0) \\ - y_1 &= \text{expm}(1/2 F_1) y_0 \\ - F_2 &= h A(y_1) \\ - y_2 &= \text{expm}(1/2 F_2) y_0 \\ - F_3 &= h A(y_2) \\ - y_3 &= \text{expm}(F_3) y_0 \\ - F_4 &= h A(y_3) \\ - y_4 &= \text{expm}(1/6 F_1 + 1/3 F_2 + 1/3 F_3 + 1/6 F_4) y_0 + \mathbf{A}_1 &= h\mathbf{A}(\mathbf{n}_i) \\ + \hat{\mathbf{n}}_1 &= \exp \left ( \frac{\mathbf{A}_1}{2} \right ) \mathbf{n}_i \\ + \mathbf{A}_2 &= h\mathbf{A}(\hat{\mathbf{n}}_1) \\ + \hat{\mathbf{n}}_2 &= \exp \left ( \frac{\mathbf{A}_2}{2} \right ) \mathbf{n}_i \\ + \mathbf{A}_3 &= h \mathbf{A}(\hat{\mathbf{n}}_2) \\ + \hat{\mathbf{n}}_3 &= \exp \left ( \mathbf{A}_3 \right ) \mathbf{n}_i \\ + \mathbf{A}_4 &= h\mathbf{A}(\hat{\mathbf{n}}_3) \\ + \mathbf{n}_{i+1} &= \exp \left ( \frac{\mathbf{A}_1}{6} + \frac{\mathbf{A}_2}{3} + + \frac{\mathbf{A}_3}{3} + \frac{\mathbf{A}_4}{6} \right ) \mathbf{n}_i. \end{aligned} """ _num_stages = 4 - def __call__(self, conc, rates, dt, source_rate, _i=None): + def __call__(self, n, rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - conc : numpy.ndarray - Initial concentrations for all nuclides in [atom] + n : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -302,7 +307,7 @@ def __call__(self, conc, rates, dt, source_rate, _i=None): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - conc_list : list of numpy.ndarray + n_list : list of list of numpy.ndarray Concentrations at each of the intermediate points with the final concentration as the last element op_results : list of openmc.deplete.OperatorResult @@ -311,26 +316,22 @@ def __call__(self, conc, rates, dt, source_rate, _i=None): """ # Step 1: deplete with matrix A(y0) / 2 - time1, conc1 = self._timed_deplete( - conc, rates, dt, matrix_func=rk4_f1) - res1 = self.operator(conc1, source_rate) + time1, n1 = self._timed_deplete(n, rates, dt, matrix_func=rk4_f1) + res1 = self.operator(n1, source_rate) # Step 2: deplete with matrix A(y1) / 2 - time2, conc2 = self._timed_deplete( - conc, res1.rates, dt, matrix_func=rk4_f1) - res2 = self.operator(conc2, source_rate) + time2, n2 = self._timed_deplete(n, res1.rates, dt, matrix_func=rk4_f1) + res2 = self.operator(n2, source_rate) # Step 3: deplete with matrix A(y2) - time3, conc3 = self._timed_deplete(conc, res2.rates, dt) - res3 = self.operator(conc3, source_rate) + time3, n3 = self._timed_deplete(n, res2.rates, dt) + res3 = self.operator(n3, source_rate) # Step 4: deplete with matrix built from weighted rates list_rates = list(zip(rates, res1.rates, res2.rates, res3.rates)) - time4, conc4 = self._timed_deplete( - conc, list_rates, dt, matrix_func=rk4_f4) + time4, n4 = self._timed_deplete(n, list_rates, dt, matrix_func=rk4_f4) - return (time1 + time2 + time3 + time4, [conc1, conc2, conc3, conc4], - [res1, res2, res3]) + return (time1 + time2 + time3 + time4, [n1, n2, n3, n4], [res1, res2, res3]) @add_params @@ -345,34 +346,37 @@ class LEQIIntegrator(Integrator): .. math:: \begin{aligned} - y' &= A(y, t) y(t) \\ - A_{last} &= A(y_{n-1}, t_n - h_1) \\ - A_0 &= A(y_n, t_n) \\ - F_1 &= \frac{-h_2^2}{12h_1} A_{last} + \frac{h_2(6h_1+h_2)}{12h_1} A_0 \\ - F_2 &= \frac{-5h_2^2}{12h_1} A_{last} + \frac{h_2(6h_1+5h_2)}{12h_1} A_0 \\ - y_p &= \text{expm}(F_2) \text{expm}(F_1) y_n \\ - A_1 &= A(y_p, t_n + h_2) \\ - F_3 &= \frac{-h_2^3}{12 h_1 (h_1 + h_2)} A_{last} + - \frac{h_2 (5 h_1^2 + 6 h_2 h_1 + h_2^2)}{12 h_1 (h_1 + h_2)} A_0 + - \frac{h_2 h_1)}{12 (h_1 + h_2)} A_1 \\ - F_4 &= \frac{-h_2^3}{12 h_1 (h_1 + h_2)} A_{last} + - \frac{h_2 (h_1^2 + 2 h_2 h_1 + h_2^2)}{12 h_1 (h_1 + h_2)} A_0 + - \frac{h_2 (5 h_1^2 + 4 h_2 h_1)}{12 h_1 (h_1 + h_2)} A_1 \\ - y_{n+1} &= \text{expm}(F_4) \text{expm}(F_3) y_n + \mathbf{A}_{-1} &= \mathbf{A}(\mathbf{n}_{i-1}) \\ + \mathbf{A}_0 &= \mathbf{A}(\mathbf{n}_i) \\ + \mathbf{F}_1 &= \frac{-h_i}{12h_{i-1}} \mathbf{A}_{-1} + \frac{6h_{i-1} + + h_i}{12h_{i-1}} \mathbf{A}_0 \\ + \mathbf{F}_2 &= \frac{-5h_i}{12h_{i-1}} \mathbf{A}_{-1} + \frac{6h_{i-1} + + 5h_i}{12h_{i-1}} \mathbf{A}_0 \\ + \mathbf{n}_{i+1}^p &= \exp (h_i \mathbf{F}_1) \exp(h_i \mathbf{F}_2) + \mathbf{n}_i \\ + \mathbf{A}_1 &= \mathbf{A}(\mathbf{n}_{i+1}^p) \\ + \mathbf{F}_3 &= \frac{-h_i^2}{12 h_{i-1} (h_{i-1} + h_i)} \mathbf{A}_{-1} + + \frac{5 h_{i-1}^2 + 6 h_i h_{i-1} + h_i^2}{12 h_{i-1} (h_{i-1} + + h_i)} \mathbf{A}_0 + \frac{h_{i-1}}{12 (h_{i-1} + h_i)} \mathbf{A}_1 \\ + \mathbf{F}_4 &= \frac{-h_i^2}{12 h_{i-1} (h_{i-1} + h_i)} \mathbf{A}_{-1} + + \frac{h_{i-1}^2 + 2 h_i h_{i-1} + h_i^2}{12 h_{i-1} (h_{i-1} + h_i)} + \mathbf{A}_0 + \frac{5 h_{i-1} + 4 h_i}{12 (h_{i-1} + h_i)} \mathbf{A}_1 \\ + \mathbf{n}_{i+1} &= \exp(h_i \mathbf{F}_4) \exp(h_i \mathbf{F}_3) \mathbf{n}_i \end{aligned} It is initialized using the CE/LI algorithm. """ _num_stages = 2 - def __call__(self, bos_conc, bos_rates, dt, source_rate, i): + def __call__(self, n_bos, bos_rates, dt, source_rate, i): """Perform the integration across one time step Parameters ---------- - conc : numpy.ndarray - Initial concentrations for all nuclides in [atom] - rates : openmc.deplete.ReactionRates + n_bos : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. + bos_rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float Time in [s] for the entire depletion interval @@ -385,7 +389,7 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, i): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - conc_list : list of numpy.ndarray + n_list : list of list of numpy.ndarray Concentrations at each of the intermediate points with the final concentration as the last element op_results : list of openmc.deplete.OperatorResult @@ -396,7 +400,7 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, i): if self._i_res < 1: # need at least previous transport solution self._prev_rates = bos_rates return CELIIntegrator.__call__( - self, bos_conc, bos_rates, dt, source_rate, i) + self, n_bos, bos_rates, dt, source_rate, i) prev_res = self.operator.prev_res[-2] prev_dt = self.timesteps[i] - prev_res.time[0] self._prev_rates = prev_res.rates[0] @@ -404,32 +408,32 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, i): prev_dt = self.timesteps[i - 1] # Remaining LE/QI - bos_res = self.operator(bos_conc, source_rate) + bos_res = self.operator(n_bos, source_rate) le_inputs = list(zip( self._prev_rates, bos_res.rates, repeat(prev_dt), repeat(dt))) - time1, conc_inter = self._timed_deplete( - bos_conc, le_inputs, dt, matrix_func=leqi_f1) - time2, conc_eos0 = self._timed_deplete( - conc_inter, le_inputs, dt, matrix_func=leqi_f2) + time1, n_inter = self._timed_deplete( + n_bos, le_inputs, dt, matrix_func=leqi_f1) + time2, n_eos0 = self._timed_deplete( + n_inter, le_inputs, dt, matrix_func=leqi_f2) - res_inter = self.operator(conc_eos0, source_rate) + res_inter = self.operator(n_eos0, source_rate) qi_inputs = list(zip( self._prev_rates, bos_res.rates, res_inter.rates, repeat(prev_dt), repeat(dt))) - time3, conc_inter = self._timed_deplete( - bos_conc, qi_inputs, dt, matrix_func=leqi_f3) - time4, conc_eos1 = self._timed_deplete( - conc_inter, qi_inputs, dt, matrix_func=leqi_f4) + time3, n_inter = self._timed_deplete( + n_bos, qi_inputs, dt, matrix_func=leqi_f3) + time4, n_eos1 = self._timed_deplete( + n_inter, qi_inputs, dt, matrix_func=leqi_f4) # store updated rates self._prev_rates = copy.deepcopy(bos_res.rates) return ( - time1 + time2 + time3 + time4, [conc_eos0, conc_eos1], + time1 + time2 + time3 + time4, [n_eos0, n_eos1], [bos_res, res_inter]) @@ -446,13 +450,14 @@ class SICELIIntegrator(SIIntegrator): """ _num_stages = 2 - def __call__(self, bos_conc, bos_rates, dt, source_rate, _i=None): + def __call__(self, n_bos, bos_rates, dt, source_rate, _i=None): """Perform the integration across one time step Parameters ---------- - bos_conc : numpy.ndarray - Initial bos_concentrations for all nuclides in [atom] + n_bos : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. bos_rates : openmc.deplete.ReactionRates Reaction rates from operator dt : float @@ -466,19 +471,19 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, _i=None): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - bos_conc_list : list of numpy.ndarray + n_bos_list : list of list of numpy.ndarray Concentrations at each of the intermediate points with - the final bos_concentration as the last element + the final concentration as the last element op_results : list of openmc.deplete.OperatorResult Eigenvalue and reaction rates from intermediate transport simulations """ - proc_time, eos_conc = self._timed_deplete(bos_conc, bos_rates, dt) - inter_conc = copy.deepcopy(eos_conc) + proc_time, n_eos = self._timed_deplete(n_bos, bos_rates, dt) + n_inter = copy.deepcopy(n_eos) # Begin iteration for j in range(self.n_steps + 1): - inter_res = self.operator(inter_conc, source_rate) + inter_res = self.operator(n_inter, source_rate) if j <= 1: res_bar = copy.deepcopy(inter_res) @@ -488,14 +493,14 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, _i=None): res_bar = OperatorResult(k, rates) list_rates = list(zip(bos_rates, res_bar.rates)) - time1, inter_conc = self._timed_deplete( - bos_conc, list_rates, dt, matrix_func=celi_f1) - time2, inter_conc = self._timed_deplete( - inter_conc, list_rates, dt, matrix_func=celi_f2) + time1, n_inter = self._timed_deplete( + n_bos, list_rates, dt, matrix_func=celi_f1) + time2, n_inter = self._timed_deplete( + n_inter, list_rates, dt, matrix_func=celi_f2) proc_time += time1 + time2 # end iteration - return proc_time, [eos_conc, inter_conc], [res_bar] + return proc_time, [n_eos, n_inter], [res_bar] @add_params @@ -511,14 +516,14 @@ class SILEQIIntegrator(SIIntegrator): """ _num_stages = 2 - def __call__(self, bos_conc, bos_rates, dt, source_rate, i): + def __call__(self, n_bos, bos_rates, dt, source_rate, i): """Perform the integration across one time step Parameters ---------- - bos_conc : list of numpy.ndarray - Initial concentrations for all nuclides in [atom] for - all depletable materials + n_bos : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. bos_rates : list of openmc.deplete.ReactionRates Reaction rates from operator for all depletable materials dt : float @@ -532,7 +537,7 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, i): ------- proc_time : float Time spent in CRAM routines for all materials in [s] - conc_list : list of numpy.ndarray + n_list : list of list of numpy.ndarray Concentrations at each of the intermediate points with the final concentration as the last element op_results : list of openmc.deplete.OperatorResult @@ -544,7 +549,7 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, i): self._prev_rates = bos_rates # Perform CELI for initial steps return SICELIIntegrator.__call__( - self, bos_conc, bos_rates, dt, source_rate, i) + self, n_bos, bos_rates, dt, source_rate, i) prev_res = self.operator.prev_res[-2] prev_dt = self.timesteps[i] - prev_res.time[0] self._prev_rates = prev_res.rates[0] @@ -554,16 +559,16 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, i): # Perform remaining LE/QI inputs = list(zip(self._prev_rates, bos_rates, repeat(prev_dt), repeat(dt))) - proc_time, inter_conc = self._timed_deplete( - bos_conc, inputs, dt, matrix_func=leqi_f1) - time1, eos_conc = self._timed_deplete( - inter_conc, inputs, dt, matrix_func=leqi_f2) + proc_time, n_inter = self._timed_deplete( + n_bos, inputs, dt, matrix_func=leqi_f1) + time1, n_eos = self._timed_deplete( + n_inter, inputs, dt, matrix_func=leqi_f2) proc_time += time1 - inter_conc = copy.deepcopy(eos_conc) + n_inter = copy.deepcopy(n_eos) for j in range(self.n_steps + 1): - inter_res = self.operator(inter_conc, source_rate) + inter_res = self.operator(n_inter, source_rate) if j <= 1: res_bar = copy.deepcopy(inter_res) @@ -574,10 +579,22 @@ def __call__(self, bos_conc, bos_rates, dt, source_rate, i): inputs = list(zip(self._prev_rates, bos_rates, res_bar.rates, repeat(prev_dt), repeat(dt))) - time1, inter_conc = self._timed_deplete( - bos_conc, inputs, dt, matrix_func=leqi_f3) - time2, inter_conc = self._timed_deplete( - inter_conc, inputs, dt, matrix_func=leqi_f4) + time1, n_inter = self._timed_deplete( + n_bos, inputs, dt, matrix_func=leqi_f3) + time2, n_inter = self._timed_deplete( + n_inter, inputs, dt, matrix_func=leqi_f4) proc_time += time1 + time2 - return proc_time, [eos_conc, inter_conc], [res_bar] + return proc_time, [n_eos, n_inter], [res_bar] + + +integrator_by_name = { + 'cecm': CECMIntegrator, + 'predictor': PredictorIntegrator, + 'cf4': CF4Integrator, + 'epc_rk4': EPCRK4Integrator, + 'si_celi': SICELIIntegrator, + 'si_leqi': SILEQIIntegrator, + 'celi': CELIIntegrator, + 'leqi': LEQIIntegrator +} diff --git a/openmc/deplete/microxs.py b/openmc/deplete/microxs.py new file mode 100644 index 00000000000..497a5284a1d --- /dev/null +++ b/openmc/deplete/microxs.py @@ -0,0 +1,374 @@ +"""MicroXS module + +A class for storing microscopic cross section data that can be used with the +IndependentOperator class for depletion. +""" + +from __future__ import annotations +from tempfile import TemporaryDirectory +from typing import List, Tuple, Iterable, Optional, Union, Sequence + +import pandas as pd +import numpy as np + +from openmc.checkvalue import check_type, check_value, check_iterable_type, PathLike +from openmc.exceptions import DataError +from openmc.utility_funcs import change_directory +from openmc import StatePoint +from openmc.mgxs import GROUP_STRUCTURES +from openmc.data import REACTION_MT +import openmc +from .chain import Chain, REACTIONS +from .coupled_operator import _find_cross_sections, _get_nuclides_with_data +import openmc.lib + +_valid_rxns = list(REACTIONS) +_valid_rxns.append('fission') +_valid_rxns.append('damage-energy') + + +def _resolve_chain_file_path(chain_file: str): + if chain_file is None: + chain_file = openmc.config.get('chain_file') + if 'chain_file' not in openmc.config: + raise DataError( + "No depletion chain specified and could not find depletion " + "chain in openmc.config['chain_file']" + ) + return chain_file + + +def get_microxs_and_flux( + model: openmc.Model, + domains, + nuclides: Optional[Iterable[str]] = None, + reactions: Optional[Iterable[str]] = None, + energies: Optional[Union[Iterable[float], str]] = None, + chain_file: Optional[PathLike] = None, + run_kwargs=None + ) -> Tuple[List[np.ndarray], List[MicroXS]]: + """Generate a microscopic cross sections and flux from a Model + + .. versionadded:: 0.14.0 + + Parameters + ---------- + model : openmc.Model + OpenMC model object. Must contain geometry, materials, and settings. + domains : list of openmc.Material or openmc.Cell or openmc.Universe, or openmc.MeshBase + Domains in which to tally reaction rates. + nuclides : list of str + Nuclides to get cross sections for. If not specified, all burnable + nuclides from the depletion chain file are used. + reactions : list of str + Reactions to get cross sections for. If not specified, all neutron + reactions listed in the depletion chain file are used. + energies : iterable of float or str + Energy group boundaries in [eV] or the name of the group structure + chain_file : str, optional + Path to the depletion chain XML file that will be used in depletion + simulation. Used to determine cross sections for materials not + present in the inital composition. Defaults to + ``openmc.config['chain_file']``. + run_kwargs : dict, optional + Keyword arguments passed to :meth:`openmc.Model.run` + + Returns + ------- + list of numpy.ndarray + Flux in each group in [n-cm/src] for each domain + list of MicroXS + Cross section data in [b] for each domain + + """ + # Save any original tallies on the model + original_tallies = model.tallies + + # Determine what reactions and nuclides are available in chain + chain_file = _resolve_chain_file_path(chain_file) + chain = Chain.from_xml(chain_file) + if reactions is None: + reactions = chain.reactions + if not nuclides: + cross_sections = _find_cross_sections(model) + nuclides_with_data = _get_nuclides_with_data(cross_sections) + nuclides = [nuc.name for nuc in chain.nuclides + if nuc.name in nuclides_with_data] + + # Set up the reaction rate and flux tallies + if energies is None: + energy_filter = openmc.EnergyFilter([0.0, 100.0e6]) + elif isinstance(energies, str): + energy_filter = openmc.EnergyFilter.from_group_structure(energies) + else: + energy_filter = openmc.EnergyFilter(energies) + if isinstance(domains, openmc.MeshBase): + domain_filter = openmc.MeshFilter(domains) + elif isinstance(domains[0], openmc.Material): + domain_filter = openmc.MaterialFilter(domains) + elif isinstance(domains[0], openmc.Cell): + domain_filter = openmc.CellFilter(domains) + elif isinstance(domains[0], openmc.Universe): + domain_filter = openmc.UniverseFilter(domains) + else: + raise ValueError(f"Unsupported domain type: {type(domains[0])}") + + rr_tally = openmc.Tally(name='MicroXS RR') + rr_tally.filters = [domain_filter, energy_filter] + rr_tally.nuclides = nuclides + rr_tally.multiply_density = False + rr_tally.scores = reactions + + flux_tally = openmc.Tally(name='MicroXS flux') + flux_tally.filters = [domain_filter, energy_filter] + flux_tally.scores = ['flux'] + model.tallies = openmc.Tallies([rr_tally, flux_tally]) + + # create temporary run + with TemporaryDirectory() as temp_dir: + if run_kwargs is None: + run_kwargs = {} + else: + run_kwargs = dict(run_kwargs) + run_kwargs.setdefault('cwd', temp_dir) + statepoint_path = model.run(**run_kwargs) + + with StatePoint(statepoint_path) as sp: + rr_tally = sp.tallies[rr_tally.id] + rr_tally._read_results() + flux_tally = sp.tallies[flux_tally.id] + flux_tally._read_results() + + # Get reaction rates and flux values + reaction_rates = rr_tally.get_reshaped_data() # (domains, groups, nuclides, reactions) + flux = flux_tally.get_reshaped_data() # (domains, groups, 1, 1) + + # Make energy groups last dimension + reaction_rates = np.moveaxis(reaction_rates, 1, -1) # (domains, nuclides, reactions, groups) + flux = np.moveaxis(flux, 1, -1) # (domains, 1, 1, groups) + + # Divide RR by flux to get microscopic cross sections + xs = np.empty_like(reaction_rates) # (domains, nuclides, reactions, groups) + d, _, _, g = np.nonzero(flux) + xs[d, ..., g] = reaction_rates[d, ..., g] / flux[d, :, :, g] + + # Reset tallies + model.tallies = original_tallies + + # Create lists where each item corresponds to one domain + fluxes = list(flux.squeeze((1, 2))) + micros = [MicroXS(xs_i, nuclides, reactions) for xs_i in xs] + return fluxes, micros + + +class MicroXS: + """Microscopic cross section data for use in transport-independent depletion. + + .. versionadded:: 0.13.1 + + .. versionchanged:: 0.14.0 + Class was heavily refactored and no longer subclasses pandas.DataFrame. + + Parameters + ---------- + data : numpy.ndarray of floats + 3D array containing microscopic cross section values for each + nuclide, reaction, and energy group. Cross section values are assumed to + be in [b], and indexed by [nuclide, reaction, energy group] + nuclides : list of str + List of nuclide symbols for that have data for at least one + reaction. + reactions : list of str + List of reactions. All reactions must match those in + :data:`openmc.deplete.chain.REACTIONS` + + """ + def __init__(self, data: np.ndarray, nuclides: List[str], reactions: List[str]): + # Validate inputs + if data.shape[:2] != (len(nuclides), len(reactions)): + raise ValueError( + f'Nuclides list of length {len(nuclides)} and ' + f'reactions array of length {len(reactions)} do not ' + f'match dimensions of data array of shape {data.shape}') + check_iterable_type('nuclides', nuclides, str) + check_iterable_type('reactions', reactions, str) + check_type('data', data, np.ndarray, expected_iter_type=float) + for reaction in reactions: + check_value('reactions', reaction, _valid_rxns) + + self.data = data + self.nuclides = nuclides + self.reactions = reactions + self._index_nuc = {nuc: i for i, nuc in enumerate(nuclides)} + self._index_rx = {rx: i for i, rx in enumerate(reactions)} + + @classmethod + def from_multigroup_flux( + cls, + energies: Union[Sequence[float], str], + multigroup_flux: Sequence[float], + chain_file: Optional[PathLike] = None, + temperature: float = 293.6, + nuclides: Optional[Sequence[str]] = None, + reactions: Optional[Sequence[str]] = None, + **init_kwargs: dict, + ) -> MicroXS: + """Generated microscopic cross sections from a known flux. + + The size of the MicroXS matrix depends on the chain file and cross + sections available. MicroXS entry will be 0 if the nuclide cross section + is not found. + + .. versionadded:: 0.14.1 + + Parameters + ---------- + energies : iterable of float or str + Energy group boundaries in [eV] or the name of the group structure + multi_group_flux : iterable of float + Energy-dependent multigroup flux values + chain_file : str, optional + Path to the depletion chain XML file that will be used in depletion + simulation. Defaults to ``openmc.config['chain_file']``. + temperature : int, optional + Temperature for cross section evaluation in [K]. + nuclides : list of str, optional + Nuclides to get cross sections for. If not specified, all burnable + nuclides from the depletion chain file are used. + reactions : list of str, optional + Reactions to get cross sections for. If not specified, all neutron + reactions listed in the depletion chain file are used. + **init_kwargs : dict + Keyword arguments passed to :func:`openmc.lib.init` + + Returns + ------- + MicroXS + """ + + check_type("temperature", temperature, (int, float)) + # if energy is string then use group structure of that name + if isinstance(energies, str): + energies = GROUP_STRUCTURES[energies] + else: + # if user inputs energies check they are ascending (low to high) as + # some depletion codes use high energy to low energy. + if not np.all(np.diff(energies) > 0): + raise ValueError('Energy group boundaries must be in ascending order') + + # check dimension consistency + if len(multigroup_flux) != len(energies) - 1: + raise ValueError('Length of flux array should be len(energies)-1') + + chain_file_path = _resolve_chain_file_path(chain_file) + chain = Chain.from_xml(chain_file_path) + + cross_sections = _find_cross_sections(model=None) + nuclides_with_data = _get_nuclides_with_data(cross_sections) + + # If no nuclides were specified, default to all nuclides from the chain + if not nuclides: + nuclides = chain.nuclides + nuclides = [nuc.name for nuc in nuclides] + + # Get reaction MT values. If no reactions specified, default to the + # reactions available in the chain file + if reactions is None: + reactions = chain.reactions + mts = [REACTION_MT[name] for name in reactions] + + # Normalize multigroup flux + multigroup_flux = np.asarray(multigroup_flux) + multigroup_flux /= multigroup_flux.sum() + + # Create 2D array for microscopic cross sections + microxs_arr = np.zeros((len(nuclides), len(mts))) + + # Create a material with all nuclides + mat_all_nucs = openmc.Material() + for nuc in nuclides: + if nuc in nuclides_with_data: + mat_all_nucs.add_nuclide(nuc, 1.0) + mat_all_nucs.set_density("atom/b-cm", 1.0) + + # Create simple model containing the above material + surf1 = openmc.Sphere(boundary_type="vacuum") + surf1_cell = openmc.Cell(fill=mat_all_nucs, region=-surf1) + model = openmc.Model() + model.geometry = openmc.Geometry([surf1_cell]) + model.settings = openmc.Settings( + particles=1, batches=1, output={'summary': False}) + + with change_directory(tmpdir=True): + # Export model within temporary directory + model.export_to_model_xml() + + with openmc.lib.run_in_memory(**init_kwargs): + # For each nuclide and reaction, compute the flux-averaged + # cross section + for nuc_index, nuc in enumerate(nuclides): + if nuc not in nuclides_with_data: + continue + lib_nuc = openmc.lib.nuclides[nuc] + for mt_index, mt in enumerate(mts): + xs = lib_nuc.collapse_rate( + mt, temperature, energies, multigroup_flux + ) + microxs_arr[nuc_index, mt_index] = xs + + return cls(microxs_arr, nuclides, reactions) + + @classmethod + def from_csv(cls, csv_file, **kwargs): + """Load data from a comma-separated values (csv) file. + + Parameters + ---------- + csv_file : str + Relative path to csv-file containing microscopic cross section + data. Cross section values are assumed to be in [b] + **kwargs : dict + Keyword arguments to pass to :func:`pandas.read_csv()`. + + Returns + ------- + MicroXS + + """ + if 'float_precision' not in kwargs: + kwargs['float_precision'] = 'round_trip' + + df = pd.read_csv(csv_file, **kwargs) + df.set_index(['nuclides', 'reactions', 'groups'], inplace=True) + nuclides = list(df.index.unique(level='nuclides')) + reactions = list(df.index.unique(level='reactions')) + groups = list(df.index.unique(level='groups')) + shape = (len(nuclides), len(reactions), len(groups)) + data = df.values.reshape(shape) + return cls(data, nuclides, reactions) + + def __getitem__(self, index): + nuc, rx = index + i_nuc = self._index_nuc[nuc] + i_rx = self._index_rx[rx] + return self.data[i_nuc, i_rx] + + def to_csv(self, *args, **kwargs): + """Write data to a comma-separated values (csv) file + + Parameters + ---------- + *args + Positional arguments passed to :meth:`pandas.DataFrame.to_csv` + **kwargs + Keyword arguments passed to :meth:`pandas.DataFrame.to_csv` + + """ + groups = self.data.shape[2] + multi_index = pd.MultiIndex.from_product( + [self.nuclides, self.reactions, range(1, groups + 1)], + names=['nuclides', 'reactions', 'groups'] + ) + df = pd.DataFrame({'xs': self.data.flatten()}, index=multi_index) + df.to_csv(*args, **kwargs) + diff --git a/openmc/deplete/nuclide.py b/openmc/deplete/nuclide.py index edba9748c7e..60e3e5317f1 100644 --- a/openmc/deplete/nuclide.py +++ b/openmc/deplete/nuclide.py @@ -1,4 +1,4 @@ -"""Nuclide module. +"""Nuclide module.xml.etree.Ele Contains the per-nuclide components of a depletion chain. """ @@ -8,14 +8,12 @@ from collections import namedtuple, defaultdict from warnings import warn from numbers import Real -try: - import lxml.etree as ET -except ImportError: - import xml.etree.ElementTree as ET -from numpy import empty, searchsorted +import lxml.etree as ET +import numpy as np from openmc.checkvalue import check_type +from openmc.stats import Univariate __all__ = [ "DecayTuple", "ReactionTuple", "Nuclide", "FissionYield", @@ -81,7 +79,7 @@ class Nuclide: Parameters ---------- name : str, optional - GND name of this nuclide, e.g. ``"He4"``, ``"Am242_m1"`` + GNDS name of this nuclide, e.g. ``"He4"``, ``"Am242_m1"`` Attributes ---------- @@ -101,6 +99,9 @@ class Nuclide: reactions : list of openmc.deplete.ReactionTuple Reaction information. Each element of the list is a named tuple with attribute 'type', 'target', 'Q', and 'branching_ratio'. + sources : dict + Dictionary mapping particle type as string to energy distribution of + decay source represented as :class:`openmc.stats.Univariate` yield_data : FissionYieldDistribution or None Fission product yields at tabulated energies for this nuclide. Can be treated as a nested dictionary ``{energy: {product: yield}}`` @@ -120,9 +121,16 @@ def __init__(self, name=None): # Reaction paths self.reactions = [] + # Decay sources + self.sources = {} + # Neutron fission yields, if present self._yield_data = None + def __repr__(self): + n_modes, n_rx = self.n_decay_modes, self.n_reaction_paths + return f"" + @property def n_decay_modes(self): return len(self.decay_modes) @@ -201,9 +209,9 @@ def from_xml(cls, element, root=None, fission_q=None): Parameters ---------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element to read nuclide data from - root : xml.etree.ElementTree.Element, optional + root : lxml.etree._Element, optional Root XML element for chain file (only used when fission product yields are borrowed from another parent) fission_q : None or float @@ -233,6 +241,12 @@ def from_xml(cls, element, root=None, fission_q=None): branching_ratio = float(decay_elem.get('branching_ratio')) nuc.decay_modes.append(DecayTuple(d_type, target, branching_ratio)) + # Check for sources + for src_elem in element.iter('source'): + particle = src_elem.get('particle') + distribution = Univariate.from_xml_element(src_elem) + nuc.sources[particle] = distribution + # Check for reaction paths for reaction_elem in element.iter('reaction'): r_type = reaction_elem.get('type') @@ -261,7 +275,7 @@ def from_xml(cls, element, root=None, fission_q=None): if parent is not None: assert root is not None fpy_elem = root.find( - './/nuclide[@name="{}"]/neutron_fission_yields'.format(parent) + f'.//nuclide[@name="{parent}"]/neutron_fission_yields' ) if fpy_elem is None: raise ValueError( @@ -280,7 +294,7 @@ def to_xml_element(self): Returns ------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element to write nuclide data to """ @@ -294,9 +308,17 @@ def to_xml_element(self): for mode_type, daughter, br in self.decay_modes: mode_elem = ET.SubElement(elem, 'decay') mode_elem.set('type', mode_type) - mode_elem.set('target', daughter or "Nothing") + if daughter: + mode_elem.set('target', daughter) mode_elem.set('branching_ratio', str(br)) + # Write decay sources + if self.sources: + for particle, source in self.sources.items(): + src_elem = source.to_xml_element('source') + src_elem.set('particle', particle) + elem.append(src_elem) + elem.set('reactions', str(len(self.reactions))) for rx, daughter, Q, br in self.reactions: rx_elem = ET.SubElement(elem, 'reaction') @@ -391,7 +413,7 @@ def validate(self, strict=True, quiet=False, tolerance=1e-4): continue msg = msg_func( name=self.name, actual=sum_br, expected=1.0, tol=tolerance, - prop="{} reaction branch ratios".format(rxn_type)) + prop=f"{rxn_type} reaction branch ratios") if strict: raise ValueError(msg) elif quiet: @@ -408,7 +430,7 @@ def validate(self, strict=True, quiet=False, tolerance=1e-4): msg = msg_func( name=self.name, actual=sum_yield, expected=2.0, tol=tolerance, - prop="fission yields (E = {:7.4e} eV)".format(energy)) + prop=f"fission yields (E = {energy:7.4e} eV)") if strict: raise ValueError(msg) elif quiet: @@ -465,7 +487,7 @@ def __init__(self, fission_yields): shared_prod = set.union(*(set(x) for x in fission_yields.values())) ordered_prod = sorted(shared_prod) - yield_matrix = empty((len(energies), len(shared_prod))) + yield_matrix = np.empty((len(energies), len(shared_prod))) for g_index, energy in enumerate(energies): prod_map = fission_yields[energy] @@ -498,7 +520,7 @@ def from_xml_element(cls, element): Parameters ---------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element to pull fission yield data from Returns @@ -520,7 +542,7 @@ def to_xml_element(self, root): Parameters ---------- - root : xml.etree.ElementTree.Element + root : lxml.etree._Element Element to write distribution data to """ for energy, yield_obj in self.items(): @@ -555,7 +577,7 @@ def restrict_products(self, possible_products): return None products = sorted(overlap) - indices = searchsorted(self.products, products) + indices = np.searchsorted(self.products, products) # coerce back to dictionary to pass back to __init__ new_yields = {} @@ -673,8 +695,12 @@ def __rmul__(self, scalar): return self * scalar def __repr__(self): - return "<{} containing {} products and yields>".format( - self.__class__.__name__, len(self)) + return f"<{self.__class__.__name__} containing {len(self)} products and yields>" + + def __deepcopy__(self, memo): + result = FissionYield(self.products, self.yields.copy()) + memo[id(self)] = result + return result # Avoid greedy numpy operations like np.float64 * fission_yield # converting this to an array on the fly. Force __rmul__ and diff --git a/openmc/deplete/openmc_operator.py b/openmc/deplete/openmc_operator.py new file mode 100644 index 00000000000..ad7a3924b7e --- /dev/null +++ b/openmc/deplete/openmc_operator.py @@ -0,0 +1,577 @@ +"""OpenMC transport operator + +This module implements functions shared by both OpenMC transport-coupled and +transport-independent transport operators. + +""" + +from abc import abstractmethod +from warnings import warn +from typing import List, Tuple, Dict + +import numpy as np + +import openmc +from openmc.checkvalue import check_value +from openmc.exceptions import DataError +from openmc.mpi import comm +from .abc import TransportOperator, OperatorResult +from .atom_number import AtomNumber +from .reaction_rates import ReactionRates +from .pool import _distribute + +__all__ = ["OpenMCOperator", "OperatorResult"] + + +class OpenMCOperator(TransportOperator): + """Abstract class holding OpenMC-specific functions for running + depletion calculations. + + Specific classes for running transport-coupled or transport-independent + depletion calculations are implemented as subclasses of OpenMCOperator. + + Parameters + ---------- + materials : openmc.Materials + List of all materials in the model + cross_sections : str or list of MicroXS + Path to continuous energy cross section library, or list of objects + containing cross sections. + chain_file : str, optional + Path to the depletion chain XML file. Defaults to + openmc.config['chain_file']. + prev_results : Results, optional + Results from a previous depletion calculation. If this argument is + specified, the depletion calculation will start from the latest state + in the previous results. + diff_burnable_mats : bool, optional + Whether to differentiate burnable materials with multiple instances. + fission_q : dict, optional + Dictionary of nuclides and their fission Q values [eV]. + helper_kwargs : dict + Keyword arguments for helper classes + reduce_chain : bool, optional + If True, use :meth:`openmc.deplete.Chain.reduce()` to reduce the + depletion chain up to ``reduce_chain_level``. + reduce_chain_level : int, optional + Depth of the search when reducing the depletion chain. Only used + if ``reduce_chain`` evaluates to true. The default value of + ``None`` implies no limit on the depth. + + diff_volume_method : str + Specifies how the volumes of the new materials should be found. Default + is to 'divide equally' which divides the original material volume + equally between the new materials, 'match cell' sets the volume of the + material to volume of the cell they fill. + + .. versionadded:: 0.14.0 + + Attributes + ---------- + materials : openmc.Materials + All materials present in the model + cross_sections : str or list of MicroXS + Path to continuous energy cross section library, or list of objects + containing cross sections. + output_dir : pathlib.Path + Path to output directory to save results. + round_number : bool + Whether or not to round output to OpenMC to 8 digits. + Useful in testing, as OpenMC is incredibly sensitive to exact values. + number : openmc.deplete.AtomNumber + Total number of atoms in simulation. + nuclides_with_data : set of str + A set listing all unique nuclides available from cross_sections.xml. + chain : openmc.deplete.Chain + The depletion chain information necessary to form matrices and tallies. + reaction_rates : openmc.deplete.ReactionRates + Reaction rates from the last operator step. + burnable_mats : list of str + All burnable material IDs + heavy_metal : float + Initial heavy metal inventory [g] + local_mats : list of str + All burnable material IDs being managed by a single process + prev_res : Results or None + Results from a previous depletion calculation. ``None`` if no + results are to be used. + + """ + + def __init__( + self, + materials=None, + cross_sections=None, + chain_file=None, + prev_results=None, + diff_burnable_mats=False, + diff_volume_method='divide equally', + fission_q=None, + helper_kwargs=None, + reduce_chain=False, + reduce_chain_level=None): + + # If chain file was not specified, try to get it from global config + if chain_file is None: + chain_file = openmc.config.get('chain_file') + if chain_file is None: + raise DataError( + "No depletion chain specified and could not find depletion " + "chain in openmc.config['chain_file']" + ) + + super().__init__(chain_file, fission_q, prev_results) + self.round_number = False + self.materials = materials + self.cross_sections = cross_sections + + check_value('diff volume method', diff_volume_method, + {'divide equally', 'match cell'}) + self.diff_volume_method = diff_volume_method + + # Reduce the chain to only those nuclides present + if reduce_chain: + init_nuclides = set() + for material in self.materials: + if not material.depletable: + continue + for name, _dens_percent, _dens_type in material.nuclides: + init_nuclides.add(name) + + self.chain = self.chain.reduce(init_nuclides, reduce_chain_level) + + if diff_burnable_mats: + self._differentiate_burnable_mats() + + # Determine which nuclides have cross section data + # This nuclides variables contains every nuclides + # for which there is an entry in the micro_xs parameter + openmc.reset_auto_ids() + + self.nuclides_with_data = self._get_nuclides_with_data( + self.cross_sections) + + # Select nuclides with data that are also in the chain + self._burnable_nucs = [nuc.name for nuc in self.chain.nuclides + if nuc.name in self.nuclides_with_data] + + # Select nuclides without data that are also in the chain + self._decay_nucs = [nuc.name for nuc in self.chain.nuclides + if nuc.name not in self.nuclides_with_data] + + self.burnable_mats, volumes, all_nuclides = self._get_burnable_mats() + self.local_mats = _distribute(self.burnable_mats) + + self._mat_index_map = { + lm: self.burnable_mats.index(lm) for lm in self.local_mats} + + if self.prev_res is not None: + self._load_previous_results() + + # Extract number densities from the geometry / previous depletion run + self._extract_number(self.local_mats, + volumes, + all_nuclides, + self.prev_res) + + # Create reaction rates array + self.reaction_rates = ReactionRates( + self.local_mats, self._burnable_nucs, self.chain.reactions) + + self._get_helper_classes(helper_kwargs) + + def _differentiate_burnable_mats(self): + """Assign distribmats for each burnable material""" + pass + + def _get_burnable_mats(self) -> Tuple[List[str], Dict[str, float], List[str]]: + """Determine depletable materials, volumes, and nuclides + + Returns + ------- + burnable_mats : list of str + list of burnable material IDs + volume : dict of str to float + Volume of each material in [cm^3] + nuclides : list of str + Nuclides in order of how they'll appear in the simulation. + + """ + + burnable_mats = set() + model_nuclides = set() + volume = {} + + self.heavy_metal = 0.0 + + # Iterate once through the geometry to get dictionaries + for mat in self.materials: + for nuclide in mat.get_nuclides(): + if nuclide in self.nuclides_with_data or self._decay_nucs: + model_nuclides.add(nuclide) + else: + msg = (f"Nuclilde {nuclide} in material {mat.id} is not " + "present in the depletion chain and has no cross " + "section data.") + warn(msg) + if mat.depletable: + burnable_mats.add(str(mat.id)) + if mat.volume is None: + if mat.name is None: + msg = ("Volume not specified for depletable material " + f"with ID={mat.id}.") + else: + msg = ("Volume not specified for depletable material " + f"with ID={mat.id} Name={mat.name}.") + raise RuntimeError(msg) + volume[str(mat.id)] = mat.volume + self.heavy_metal += mat.fissionable_mass + + # Make sure there are burnable materials + if not burnable_mats: + raise RuntimeError( + "No depletable materials were found in the model.") + + # Sort the sets + burnable_mats = sorted(burnable_mats, key=int) + model_nuclides = sorted(model_nuclides) + + # Construct a global nuclide dictionary, burned first + nuclides = list(self.chain.nuclide_dict) + for nuc in model_nuclides: + if nuc not in nuclides: + nuclides.append(nuc) + return burnable_mats, volume, nuclides + + def _load_previous_results(self): + """Load results from a previous depletion simulation""" + pass + + @abstractmethod + def _get_nuclides_with_data(self, cross_sections): + """Find nuclides with cross section data + + Parameters + ---------- + cross_sections : str or pandas.DataFrame + Path to continuous energy cross section library, or object + containing one-group cross-sections. + + Returns + ------- + nuclides : set of str + Set of nuclide names that have cross secton data + + """ + + def _extract_number(self, local_mats, volume, all_nuclides, prev_res=None): + """Construct AtomNumber using geometry + + Parameters + ---------- + local_mats : list of str + Material IDs to be managed by this process + volume : dict of str to float + Volumes for the above materials in [cm^3] + all_nuclides : list of str + Nuclides to be used in the simulation. + prev_res : Results, optional + Results from a previous depletion calculation + + """ + self.number = AtomNumber(local_mats, all_nuclides, volume, len(self.chain)) + + # Now extract and store the number densities + # From the geometry if no previous depletion results + if prev_res is None: + for mat in self.materials: + if str(mat.id) in local_mats: + self._set_number_from_mat(mat) + + # Else from previous depletion results + else: + for mat in self.materials: + if str(mat.id) in local_mats: + self._set_number_from_results(mat, prev_res) + + def _set_number_from_mat(self, mat): + """Extracts material and number densities from openmc.Material + + Parameters + ---------- + mat : openmc.Material + The material to read from + + """ + mat_id = str(mat.id) + + for nuclide, atom_per_bcm in mat.get_nuclide_atom_densities().items(): + atom_per_cc = atom_per_bcm * 1.0e24 + self.number.set_atom_density(mat_id, nuclide, atom_per_cc) + + def _set_number_from_results(self, mat, prev_res): + """Extracts material nuclides and number densities. + + If the nuclide concentration's evolution is tracked, the densities come + from depletion results. Else, densities are extracted from the geometry + in the summary. + + Parameters + ---------- + mat : openmc.Material + The material to read from + prev_res : Results + Results from a previous depletion calculation + + """ + mat_id = str(mat.id) + + # Get nuclide lists from geometry and depletion results + depl_nuc = prev_res[-1].index_nuc + geom_nuc_densities = mat.get_nuclide_atom_densities() + + # Merge lists of nuclides, with the same order for every calculation + geom_nuc_densities.update(depl_nuc) + + for nuclide, atom_per_bcm in geom_nuc_densities.items(): + if nuclide in depl_nuc: + concentration = prev_res.get_atoms(mat_id, nuclide)[1][-1] + volume = prev_res[-1].volume[mat_id] + atom_per_cc = concentration / volume + else: + atom_per_cc = atom_per_bcm * 1.0e24 + + self.number.set_atom_density(mat_id, nuclide, atom_per_cc) + + @abstractmethod + def _get_helper_classes(self, helper_kwargs): + """Create the ``_rate_helper``, ``_normalization_helper``, and + ``_yield_helper`` objects. + + Parameters + ---------- + helper_kwargs : dict + Keyword arguments for helper classes + + """ + + def initial_condition(self, materials): + """Performs final setup and returns initial condition. + + Parameters + ---------- + materials : list of openmc.lib.Material + list of materials + + Returns + ------- + list of numpy.ndarray + Total density for initial conditions. + + """ + + self._rate_helper.generate_tallies(materials, self.chain.reactions) + self._normalization_helper.prepare( + self.chain.nuclides, self.reaction_rates.index_nuc) + # Tell fission yield helper what materials this process is + # responsible for + self._yield_helper.generate_tallies( + materials, tuple(sorted(self._mat_index_map.values()))) + + # Return number density vector + return list(self.number.get_mat_slice(np.s_[:])) + + def _update_materials_and_nuclides(self, vec): + """Update the number density, material compositions, and nuclide + lists in helper objects + + Parameters + ---------- + vec : list of numpy.ndarray + Total atoms. + + """ + + # Update the number densities regardless of the source rate + self.number.set_density(vec) + self._update_materials() + + # Prevent OpenMC from complaining about re-creating tallies + openmc.reset_auto_ids() + + # Update tally nuclides data in preparation for transport solve + nuclides = self._get_reaction_nuclides() + self._rate_helper.nuclides = nuclides + self._normalization_helper.nuclides = nuclides + self._yield_helper.update_tally_nuclides(nuclides) + + @abstractmethod + def _update_materials(self): + """Updates material compositions in OpenMC on all processes.""" + + def write_bos_data(self, step): + """Document beginning of step data for a given step + + Called at the beginning of a depletion step and at + the final point in the simulation. + + Parameters + ---------- + step : int + Current depletion step including restarts + """ + # Since we aren't running a transport simulation, we simply pass + pass + + def _get_reaction_nuclides(self): + """Determine nuclides that should be tallied for reaction rates. + + This method returns a list of all nuclides that have cross section data + and are listed in the depletion chain. Technically, we should count + nuclides that may not appear in the depletion chain because we still + need to get the fission reaction rate for these nuclides in order to + normalize power, but that is left as a future exercise. + + Returns + ------- + list of str + Nuclides with reaction rates + + """ + nuc_set = set() + + # Create the set of all nuclides in the decay chain in materials marked + # for burning in which the number density is greater than zero. + for nuc in self.number.nuclides: + if nuc in self.nuclides_with_data: + nuc_set.add(nuc) + + # Communicate which nuclides have nonzeros to rank 0 + if comm.rank == 0: + for i in range(1, comm.size): + nuc_newset = comm.recv(source=i, tag=i) + nuc_set |= nuc_newset + else: + comm.send(nuc_set, dest=0, tag=comm.rank) + + if comm.rank == 0: + # Sort nuclides in the same order as self.number + nuc_list = [nuc for nuc in self.number.nuclides + if nuc in nuc_set] + else: + nuc_list = None + + # Store list of nuclides on each process + nuc_list = comm.bcast(nuc_list) + return [nuc for nuc in nuc_list if nuc in self.chain] + + def _calculate_reaction_rates(self, source_rate): + """Unpack tallies from OpenMC and return an operator result + + This method uses OpenMC's C API bindings to determine the k-effective + value and reaction rates from the simulation. The reaction rates are + normalized by a helper class depending on the method being used. + + Parameters + ---------- + source_rate : float + Power in [W] or source rate in [neutron/sec] + + Returns + ------- + rates : openmc.deplete.ReactionRates + Reaction rates for nuclides + + """ + rates = self.reaction_rates + rates.fill(0.0) + + # Extract reaction nuclides + rxn_nuclides = self._rate_helper.nuclides + + # Form fast map + nuc_ind = [rates.index_nuc[nuc] for nuc in rxn_nuclides] + rx_ind = [rates.index_rx[react] for react in self.chain.reactions] + + # Keep track of energy produced from all reactions in eV per source + # particle + self._normalization_helper.reset() + self._yield_helper.unpack() + + # Store fission yield dictionaries + fission_yields = [] + + # Create arrays to store fission Q values, reaction rates, and nuclide + # numbers, zeroed out in material iteration + number = np.empty(rates.n_nuc) + + fission_ind = rates.index_rx.get("fission") + + # Reset the cached material reaction rates tallies + self._rate_helper.reset_tally_means() + + # Extract results + for i, mat in enumerate(self.local_mats): + # Get tally index + mat_index = self._mat_index_map[mat] + + # Zero out reaction rates and nuclide numbers + number.fill(0.0) + + # Get new number densities + for nuc, i_nuc_results in zip(rxn_nuclides, nuc_ind): + number[i_nuc_results] = self.number[mat, nuc] + + # Get microscopic reaction rates in [(reactions/src)*b-cm/atom]. 2D + # array with shape (nuclides, reactions). + tally_rates = self._rate_helper.get_material_rates( + mat_index, nuc_ind, rx_ind) + + # Compute fission yields for this material + fission_yields.append(self._yield_helper.weighted_yields(i)) + + # Accumulate energy from fission + volume_b_cm = 1e24 * self.number.get_mat_volume(mat) + if fission_ind is not None: + atom_per_bcm = number / volume_b_cm + fission_rates = tally_rates[:, fission_ind] * atom_per_bcm + self._normalization_helper.update(fission_rates) + + # Divide by [b-cm] to get [(reactions/src)/atom] + rates[i] = tally_rates / volume_b_cm + + # Scale reaction rates to obtain units of [(reactions/sec)/atom] + rates *= self._normalization_helper.factor(source_rate) + + # Store new fission yields on the chain + self.chain.fission_yields = fission_yields + + return rates + + def get_results_info(self): + """Returns volume list, material lists, and nuc lists. + + Returns + ------- + volume : dict of str float + Volumes corresponding to materials in full_burn_dict + nuc_list : list of str + A list of all nuclide names. Used for sorting the simulation. + burn_list : list of int + A list of all material IDs to be burned. Used for sorting the simulation. + full_burn_list : list + List of all burnable material IDs + + """ + nuc_list = self.number.burnable_nuclides + burn_list = self.local_mats + + volume = {} + for i, mat in enumerate(burn_list): + volume[mat] = self.number.volume[i] + + # Combine volume dictionaries across processes + volume_list = comm.allgather(volume) + volume = {k: v for d in volume_list for k, v in d.items()} + + return volume, nuc_list, burn_list, self.burnable_mats diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py deleted file mode 100644 index 0e5cc9efa31..00000000000 --- a/openmc/deplete/operator.py +++ /dev/null @@ -1,810 +0,0 @@ -"""OpenMC transport operator - -This module implements a transport operator for OpenMC so that it can be used by -depletion integrators. The implementation makes use of the Python bindings to -OpenMC's C API so that reading tally results and updating material number -densities is all done in-memory instead of through the filesystem. - -""" - -import copy -from collections import OrderedDict -import os -import xml.etree.ElementTree as ET -from warnings import warn -from pathlib import Path - -import numpy as np -from uncertainties import ufloat - -import openmc -from openmc.checkvalue import check_value -import openmc.lib -from . import comm -from .abc import TransportOperator, OperatorResult -from .atom_number import AtomNumber -from .reaction_rates import ReactionRates -from .results_list import ResultsList -from .helpers import ( - DirectReactionRateHelper, ChainFissionHelper, ConstantFissionYieldHelper, - FissionYieldCutoffHelper, AveragedFissionYieldHelper, EnergyScoreHelper, - SourceRateHelper, FluxCollapseHelper) - - -__all__ = ["Operator", "OperatorResult"] - - -def _distribute(items): - """Distribute items across MPI communicator - - Parameters - ---------- - items : list - List of items of distribute - - Returns - ------- - list - Items assigned to process that called - - """ - min_size, extra = divmod(len(items), comm.size) - j = 0 - for i in range(comm.size): - chunk_size = min_size + int(i < extra) - if comm.rank == i: - return items[j:j + chunk_size] - j += chunk_size - - -class Operator(TransportOperator): - """OpenMC transport operator for depletion. - - Instances of this class can be used to perform depletion using OpenMC as the - transport operator. Normally, a user needn't call methods of this class - directly. Instead, an instance of this class is passed to an integrator - class, such as :class:`openmc.deplete.CECMIntegrator`. - - Parameters - ---------- - geometry : openmc.Geometry - OpenMC geometry object - settings : openmc.Settings - OpenMC Settings object - chain_file : str, optional - Path to the depletion chain XML file. Defaults to the file - listed under ``depletion_chain`` in - :envvar:`OPENMC_CROSS_SECTIONS` environment variable. - prev_results : ResultsList, optional - Results from a previous depletion calculation. If this argument is - specified, the depletion calculation will start from the latest state - in the previous results. - diff_burnable_mats : bool, optional - Whether to differentiate burnable materials with multiple instances. - Volumes are divided equally from the original material volume. - Default: False. - normalization_mode : {"energy-deposition", "fission-q", "source-rate"} - Indicate how tally results should be normalized. ``"energy-deposition"`` - computes the total energy deposited in the system and uses the ratio of - the power to the energy produced as a normalization factor. - ``"fission-q"`` uses the fission Q values from the depletion chain to - compute the total energy deposited. ``"source-rate"`` normalizes - tallies based on the source rate (for fixed source calculations). - fission_q : dict, optional - Dictionary of nuclides and their fission Q values [eV]. If not given, - values will be pulled from the ``chain_file``. Only applicable - if ``"normalization_mode" == "fission-q"`` - dilute_initial : float, optional - Initial atom density [atoms/cm^3] to add for nuclides that are zero - in initial condition to ensure they exist in the decay chain. - Only done for nuclides with reaction rates. - Defaults to 1.0e3. - fission_yield_mode : {"constant", "cutoff", "average"} - Key indicating what fission product yield scheme to use. The - key determines what fission energy helper is used: - - * "constant": :class:`~openmc.deplete.helpers.ConstantFissionYieldHelper` - * "cutoff": :class:`~openmc.deplete.helpers.FissionYieldCutoffHelper` - * "average": :class:`~openmc.deplete.helpers.AveragedFissionYieldHelper` - - The documentation on these classes describe their methodology - and differences. Default: ``"constant"`` - fission_yield_opts : dict of str to option, optional - Optional arguments to pass to the helper determined by - ``fission_yield_mode``. Will be passed directly on to the - helper. Passing a value of None will use the defaults for - the associated helper. - reaction_rate_mode : {"direct", "flux"}, optional - Indicate how one-group reaction rates should be calculated. The "direct" - method tallies transmutation reaction rates directly. The "flux" method - tallies a multigroup flux spectrum and then collapses one-group reaction - rates after a transport solve (with an option to tally some reaction - rates directly). - - .. versionadded:: 0.12.1 - reaction_rate_opts : dict, optional - Keyword arguments that are passed to the reaction rate helper class. - When ``reaction_rate_mode`` is set to "flux", energy group boundaries - can be set using the "energies" key. See the - :class:`~openmc.deplete.helpers.FluxCollapseHelper` class for all - options. - - .. versionadded:: 0.12.1 - reduce_chain : bool, optional - If True, use :meth:`openmc.deplete.Chain.reduce` to reduce the - depletion chain up to ``reduce_chain_level``. Default is False. - - .. versionadded:: 0.12 - reduce_chain_level : int, optional - Depth of the search when reducing the depletion chain. Only used - if ``reduce_chain`` evaluates to true. The default value of - ``None`` implies no limit on the depth. - - .. versionadded:: 0.12 - - Attributes - ---------- - geometry : openmc.Geometry - OpenMC geometry object - settings : openmc.Settings - OpenMC settings object - dilute_initial : float - Initial atom density [atoms/cm^3] to add for nuclides that - are zero in initial condition to ensure they exist in the decay - chain. Only done for nuclides with reaction rates. - output_dir : pathlib.Path - Path to output directory to save results. - round_number : bool - Whether or not to round output to OpenMC to 8 digits. - Useful in testing, as OpenMC is incredibly sensitive to exact values. - number : openmc.deplete.AtomNumber - Total number of atoms in simulation. - nuclides_with_data : set of str - A set listing all unique nuclides available from cross_sections.xml. - chain : openmc.deplete.Chain - The depletion chain information necessary to form matrices and tallies. - reaction_rates : openmc.deplete.ReactionRates - Reaction rates from the last operator step. - burnable_mats : list of str - All burnable material IDs - heavy_metal : float - Initial heavy metal inventory [g] - local_mats : list of str - All burnable material IDs being managed by a single process - prev_res : ResultsList or None - Results from a previous depletion calculation. ``None`` if no - results are to be used. - diff_burnable_mats : bool - Whether to differentiate burnable materials with multiple instances - """ - _fission_helpers = { - "average": AveragedFissionYieldHelper, - "constant": ConstantFissionYieldHelper, - "cutoff": FissionYieldCutoffHelper, - } - - def __init__(self, geometry, settings, chain_file=None, prev_results=None, - diff_burnable_mats=False, normalization_mode="fission-q", - fission_q=None, dilute_initial=1.0e3, - fission_yield_mode="constant", fission_yield_opts=None, - reaction_rate_mode="direct", reaction_rate_opts=None, - reduce_chain=False, reduce_chain_level=None): - check_value('fission yield mode', fission_yield_mode, - self._fission_helpers.keys()) - check_value('normalization mode', normalization_mode, - ('energy-deposition', 'fission-q', 'source-rate')) - if normalization_mode != "fission-q": - if fission_q is not None: - warn("Fission Q dictionary will not be used") - fission_q = None - super().__init__(chain_file, fission_q, dilute_initial, prev_results) - self.round_number = False - self.settings = settings - self.geometry = geometry - self.diff_burnable_mats = diff_burnable_mats - - # Reduce the chain before we create more materials - if reduce_chain: - all_isotopes = set() - for material in geometry.get_all_materials().values(): - if not material.depletable: - continue - for name, _dens_percent, _dens_type in material.nuclides: - all_isotopes.add(name) - self.chain = self.chain.reduce(all_isotopes, reduce_chain_level) - - # Differentiate burnable materials with multiple instances - if self.diff_burnable_mats: - self._differentiate_burnable_mats() - - # Clear out OpenMC, create task lists, distribute - openmc.reset_auto_ids() - self.burnable_mats, volume, nuclides = self._get_burnable_mats() - self.local_mats = _distribute(self.burnable_mats) - - # Generate map from local materials => material index - self._mat_index_map = { - lm: self.burnable_mats.index(lm) for lm in self.local_mats} - - if self.prev_res is not None: - # Reload volumes into geometry - prev_results[-1].transfer_volumes(geometry) - - # Store previous results in operator - # Distribute reaction rates according to those tracked - # on this process - if comm.size == 1: - self.prev_res = prev_results - else: - self.prev_res = ResultsList() - mat_indexes = _distribute(range(len(self.burnable_mats))) - for res_obj in prev_results: - new_res = res_obj.distribute(self.local_mats, mat_indexes) - self.prev_res.append(new_res) - - # Determine which nuclides have incident neutron data - self.nuclides_with_data = self._get_nuclides_with_data() - - # Select nuclides with data that are also in the chain - self._burnable_nucs = [nuc.name for nuc in self.chain.nuclides - if nuc.name in self.nuclides_with_data] - - # Extract number densities from the geometry / previous depletion run - self._extract_number(self.local_mats, volume, nuclides, self.prev_res) - - # Create reaction rates array - self.reaction_rates = ReactionRates( - self.local_mats, self._burnable_nucs, self.chain.reactions) - - # Get classes to assist working with tallies - if reaction_rate_mode == "direct": - self._rate_helper = DirectReactionRateHelper( - self.reaction_rates.n_nuc, self.reaction_rates.n_react) - elif reaction_rate_mode == "flux": - if reaction_rate_opts is None: - reaction_rate_opts = {} - - # Ensure energy group boundaries were specified - if 'energies' not in reaction_rate_opts: - raise ValueError( - "Energy group boundaries must be specified in the " - "reaction_rate_opts argument when reaction_rate_mode is" - "set to 'flux'.") - - self._rate_helper = FluxCollapseHelper( - self.reaction_rates.n_nuc, - self.reaction_rates.n_react, - **reaction_rate_opts - ) - else: - raise ValueError("Invalid reaction rate mode.") - - if normalization_mode == "fission-q": - self._normalization_helper = ChainFissionHelper() - elif normalization_mode == "energy-deposition": - score = "heating" if settings.photon_transport else "heating-local" - self._normalization_helper = EnergyScoreHelper(score) - else: - self._normalization_helper = SourceRateHelper() - - # Select and create fission yield helper - fission_helper = self._fission_helpers[fission_yield_mode] - fission_yield_opts = ( - {} if fission_yield_opts is None else fission_yield_opts) - self._yield_helper = fission_helper.from_operator( - self, **fission_yield_opts) - - def __call__(self, vec, source_rate): - """Runs a simulation. - - Simulation will abort under the following circumstances: - - 1) No energy is computed using OpenMC tallies. - - Parameters - ---------- - vec : list of numpy.ndarray - Total atoms to be used in function. - source_rate : float - Power in [W] or source rate in [neutron/sec] - - Returns - ------- - openmc.deplete.OperatorResult - Eigenvalue and reaction rates resulting from transport operator - - """ - # Reset results in OpenMC - openmc.lib.reset() - - # If the source rate is zero, return zero reaction rates without running - # a transport solve - if source_rate == 0.0: - rates = self.reaction_rates.copy() - rates.fill(0.0) - return OperatorResult(ufloat(0.0, 0.0), rates) - - # Prevent OpenMC from complaining about re-creating tallies - openmc.reset_auto_ids() - - # Update status - self.number.set_density(vec) - - # Update material compositions and tally nuclides - self._update_materials() - nuclides = self._get_tally_nuclides() - self._rate_helper.nuclides = nuclides - self._normalization_helper.nuclides = nuclides - self._yield_helper.update_tally_nuclides(nuclides) - - # Run OpenMC - openmc.lib.run() - openmc.lib.reset_timers() - - # Extract results - op_result = self._unpack_tallies_and_normalize(source_rate) - - return copy.deepcopy(op_result) - - @staticmethod - def write_bos_data(step): - """Write a state-point file with beginning of step data - - Parameters - ---------- - step : int - Current depletion step including restarts - """ - openmc.lib.statepoint_write( - "openmc_simulation_n{}.h5".format(step), - write_source=False) - - def _differentiate_burnable_mats(self): - """Assign distribmats for each burnable material - - """ - - # Count the number of instances for each cell and material - self.geometry.determine_paths(instances_only=True) - - # Extract all burnable materials which have multiple instances - distribmats = set( - [mat for mat in self.geometry.get_all_materials().values() - if mat.depletable and mat.num_instances > 1]) - - for mat in distribmats: - if mat.volume is None: - raise RuntimeError("Volume not specified for depletable " - "material with ID={}.".format(mat.id)) - mat.volume /= mat.num_instances - - if distribmats: - # Assign distribmats to cells - for cell in self.geometry.get_all_material_cells().values(): - if cell.fill in distribmats: - mat = cell.fill - cell.fill = [mat.clone() - for i in range(cell.num_instances)] - - def _get_burnable_mats(self): - """Determine depletable materials, volumes, and nuclides - - Returns - ------- - burnable_mats : list of str - List of burnable material IDs - volume : OrderedDict of str to float - Volume of each material in [cm^3] - nuclides : list of str - Nuclides in order of how they'll appear in the simulation. - - """ - - burnable_mats = set() - model_nuclides = set() - volume = OrderedDict() - - self.heavy_metal = 0.0 - - # Iterate once through the geometry to get dictionaries - for mat in self.geometry.get_all_materials().values(): - for nuclide in mat.get_nuclides(): - model_nuclides.add(nuclide) - if mat.depletable: - burnable_mats.add(str(mat.id)) - if mat.volume is None: - raise RuntimeError("Volume not specified for depletable " - "material with ID={}.".format(mat.id)) - volume[str(mat.id)] = mat.volume - self.heavy_metal += mat.fissionable_mass - - # Make sure there are burnable materials - if not burnable_mats: - raise RuntimeError( - "No depletable materials were found in the model.") - - # Sort the sets - burnable_mats = sorted(burnable_mats, key=int) - model_nuclides = sorted(model_nuclides) - - # Construct a global nuclide dictionary, burned first - nuclides = list(self.chain.nuclide_dict) - for nuc in model_nuclides: - if nuc not in nuclides: - nuclides.append(nuc) - - return burnable_mats, volume, nuclides - - def _extract_number(self, local_mats, volume, nuclides, prev_res=None): - """Construct AtomNumber using geometry - - Parameters - ---------- - local_mats : list of str - Material IDs to be managed by this process - volume : OrderedDict of str to float - Volumes for the above materials in [cm^3] - nuclides : list of str - Nuclides to be used in the simulation. - prev_res : ResultsList, optional - Results from a previous depletion calculation - - """ - self.number = AtomNumber(local_mats, nuclides, volume, len(self.chain)) - - if self.dilute_initial != 0.0: - for nuc in self._burnable_nucs: - self.number.set_atom_density(np.s_[:], nuc, self.dilute_initial) - - # Now extract and store the number densities - # From the geometry if no previous depletion results - if prev_res is None: - for mat in self.geometry.get_all_materials().values(): - if str(mat.id) in local_mats: - self._set_number_from_mat(mat) - - # Else from previous depletion results - else: - for mat in self.geometry.get_all_materials().values(): - if str(mat.id) in local_mats: - self._set_number_from_results(mat, prev_res) - - def _set_number_from_mat(self, mat): - """Extracts material and number densities from openmc.Material - - Parameters - ---------- - mat : openmc.Material - The material to read from - - """ - mat_id = str(mat.id) - - for nuclide, density in mat.get_nuclide_atom_densities().values(): - number = density * 1.0e24 - self.number.set_atom_density(mat_id, nuclide, number) - - def _set_number_from_results(self, mat, prev_res): - """Extracts material nuclides and number densities. - - If the nuclide concentration's evolution is tracked, the densities come - from depletion results. Else, densities are extracted from the geometry - in the summary. - - Parameters - ---------- - mat : openmc.Material - The material to read from - prev_res : ResultsList - Results from a previous depletion calculation - - """ - mat_id = str(mat.id) - - # Get nuclide lists from geometry and depletion results - depl_nuc = prev_res[-1].nuc_to_ind - geom_nuc_densities = mat.get_nuclide_atom_densities() - - # Merge lists of nuclides, with the same order for every calculation - geom_nuc_densities.update(depl_nuc) - - for nuclide in geom_nuc_densities.keys(): - if nuclide in depl_nuc: - concentration = prev_res.get_atoms(mat_id, nuclide)[1][-1] - volume = prev_res[-1].volume[mat_id] - number = concentration / volume - else: - density = geom_nuc_densities[nuclide][1] - number = density * 1.0e24 - - self.number.set_atom_density(mat_id, nuclide, number) - - def initial_condition(self): - """Performs final setup and returns initial condition. - - Returns - ------- - list of numpy.ndarray - Total density for initial conditions. - """ - - # Create XML files - if comm.rank == 0: - self.geometry.export_to_xml() - self.settings.export_to_xml() - self._generate_materials_xml() - - # Initialize OpenMC library - comm.barrier() - openmc.lib.init(intracomm=comm) - - # Generate tallies in memory - materials = [openmc.lib.materials[int(i)] - for i in self.burnable_mats] - self._rate_helper.generate_tallies(materials, self.chain.reactions) - self._normalization_helper.prepare( - self.chain.nuclides, self.reaction_rates.index_nuc) - # Tell fission yield helper what materials this process is - # responsible for - self._yield_helper.generate_tallies( - materials, tuple(sorted(self._mat_index_map.values()))) - - # Return number density vector - return list(self.number.get_mat_slice(np.s_[:])) - - def finalize(self): - """Finalize a depletion simulation and release resources.""" - openmc.lib.finalize() - - def _update_materials(self): - """Updates material compositions in OpenMC on all processes.""" - - for rank in range(comm.size): - number_i = comm.bcast(self.number, root=rank) - - for mat in number_i.materials: - nuclides = [] - densities = [] - for nuc in number_i.nuclides: - if nuc in self.nuclides_with_data: - val = 1.0e-24 * number_i.get_atom_density(mat, nuc) - - # If nuclide is zero, do not add to the problem. - if val > 0.0: - if self.round_number: - val_magnitude = np.floor(np.log10(val)) - val_scaled = val / 10**val_magnitude - val_round = round(val_scaled, 8) - - val = val_round * 10**val_magnitude - - nuclides.append(nuc) - densities.append(val) - else: - # Only output warnings if values are significantly - # negative. CRAM does not guarantee positive values. - if val < -1.0e-21: - print("WARNING: nuclide ", nuc, " in material ", mat, - " is negative (density = ", val, " at/barn-cm)") - number_i[mat, nuc] = 0.0 - - # Update densities on C API side - mat_internal = openmc.lib.materials[int(mat)] - mat_internal.set_densities(nuclides, densities) - - #TODO Update densities on the Python side, otherwise the - # summary.h5 file contains densities at the first time step - - def _generate_materials_xml(self): - """Creates materials.xml from self.number. - - Due to uncertainty with how MPI interacts with OpenMC API, this - constructs the XML manually. The long term goal is to do this - through direct memory writing. - - """ - materials = openmc.Materials(self.geometry.get_all_materials() - .values()) - - # Sort nuclides according to order in AtomNumber object - nuclides = list(self.number.nuclides) - for mat in materials: - mat._nuclides.sort(key=lambda x: nuclides.index(x[0])) - - # Grab the cross sections tag from the existing file - mfile = Path("materials.xml") - if mfile.exists(): - tree = ET.parse(str(mfile)) - xs = tree.find('cross_sections') - if xs is not None: - materials.cross_sections = xs.text - - materials.export_to_xml() - - def _get_tally_nuclides(self): - """Determine nuclides that should be tallied for reaction rates. - - This method returns a list of all nuclides that have neutron data and - are listed in the depletion chain. Technically, we should tally nuclides - that may not appear in the depletion chain because we still need to get - the fission reaction rate for these nuclides in order to normalize - power, but that is left as a future exercise. - - Returns - ------- - list of str - Tally nuclides - - """ - nuc_set = set() - - # Create the set of all nuclides in the decay chain in materials marked - # for burning in which the number density is greater than zero. - for nuc in self.number.nuclides: - if nuc in self.nuclides_with_data: - if np.sum(self.number[:, nuc]) > 0.0: - nuc_set.add(nuc) - - # Communicate which nuclides have nonzeros to rank 0 - if comm.rank == 0: - for i in range(1, comm.size): - nuc_newset = comm.recv(source=i, tag=i) - nuc_set |= nuc_newset - else: - comm.send(nuc_set, dest=0, tag=comm.rank) - - if comm.rank == 0: - # Sort nuclides in the same order as self.number - nuc_list = [nuc for nuc in self.number.nuclides - if nuc in nuc_set] - else: - nuc_list = None - - # Store list of tally nuclides on each process - nuc_list = comm.bcast(nuc_list) - return [nuc for nuc in nuc_list if nuc in self.chain] - - def _unpack_tallies_and_normalize(self, source_rate): - """Unpack tallies from OpenMC and return an operator result - - This method uses OpenMC's C API bindings to determine the k-effective - value and reaction rates from the simulation. The reaction rates are - normalized by a helper class depending on the method being used. - - Parameters - ---------- - source_rate : float - Power in [W] or source rate in [neutron/sec] - - Returns - ------- - openmc.deplete.OperatorResult - Eigenvalue and reaction rates resulting from transport operator - - """ - rates = self.reaction_rates - rates.fill(0.0) - - # Get k and uncertainty - k_combined = ufloat(*openmc.lib.keff()) - - # Extract tally bins - nuclides = self._rate_helper.nuclides - - # Form fast map - nuc_ind = [rates.index_nuc[nuc] for nuc in nuclides] - react_ind = [rates.index_rx[react] for react in self.chain.reactions] - - # Keep track of energy produced from all reactions in eV per source - # particle - self._normalization_helper.reset() - self._yield_helper.unpack() - - # Store fission yield dictionaries - fission_yields = [] - - # Create arrays to store fission Q values, reaction rates, and nuclide - # numbers, zeroed out in material iteration - number = np.empty(rates.n_nuc) - - fission_ind = rates.index_rx.get("fission") - - # Extract results - for i, mat in enumerate(self.local_mats): - # Get tally index - mat_index = self._mat_index_map[mat] - - # Zero out reaction rates and nuclide numbers - number.fill(0.0) - - # Get new number densities - for nuc, i_nuc_results in zip(nuclides, nuc_ind): - number[i_nuc_results] = self.number[mat, nuc] - - tally_rates = self._rate_helper.get_material_rates( - mat_index, nuc_ind, react_ind) - - # Compute fission yields for this material - fission_yields.append(self._yield_helper.weighted_yields(i)) - - # Accumulate energy from fission - if fission_ind is not None: - self._normalization_helper.update(tally_rates[:, fission_ind]) - - # Divide by total number and store - rates[i] = self._rate_helper.divide_by_adens(number) - - # Scale reaction rates to obtain units of reactions/sec - rates *= self._normalization_helper.factor(source_rate) - - # Store new fission yields on the chain - self.chain.fission_yields = fission_yields - - return OperatorResult(k_combined, rates) - - def _get_nuclides_with_data(self): - """Loads a cross_sections.xml file to find participating nuclides. - - This allows for nuclides that are important in the decay chain but not - important neutronically, or have no cross section data. - """ - - # Reads cross_sections.xml to create a dictionary containing - # participating (burning and not just decaying) nuclides. - - try: - filename = os.environ["OPENMC_CROSS_SECTIONS"] - except KeyError: - filename = None - - nuclides = set() - - try: - tree = ET.parse(filename) - except Exception: - if filename is None: - msg = "No cross_sections.xml specified in materials." - else: - msg = 'Cross section file "{}" is invalid.'.format(filename) - raise IOError(msg) - - root = tree.getroot() - for nuclide_node in root.findall('library'): - mats = nuclide_node.get('materials') - if not mats: - continue - for name in mats.split(): - # Make a burn list of the union of nuclides in cross_sections.xml - # and nuclides in depletion chain. - if name not in nuclides: - nuclides.add(name) - - return nuclides - - def get_results_info(self): - """Returns volume list, material lists, and nuc lists. - - Returns - ------- - volume : dict of str float - Volumes corresponding to materials in full_burn_dict - nuc_list : list of str - A list of all nuclide names. Used for sorting the simulation. - burn_list : list of int - A list of all material IDs to be burned. Used for sorting the simulation. - full_burn_list : list - List of all burnable material IDs - - """ - nuc_list = self.number.burnable_nuclides - burn_list = self.local_mats - - volume = {} - for i, mat in enumerate(burn_list): - volume[mat] = self.number.volume[i] - - # Combine volume dictionaries across processes - volume_list = comm.allgather(volume) - volume = {k: v for d in volume_list for k, v in d.items()} - - return volume, nuc_list, burn_list, self.burnable_mats diff --git a/openmc/deplete/pool.py b/openmc/deplete/pool.py index 8360ef602ab..27ecaa4dd8b 100644 --- a/openmc/deplete/pool.py +++ b/openmc/deplete/pool.py @@ -5,62 +5,162 @@ from itertools import repeat, starmap from multiprocessing import Pool +from scipy.sparse import bmat +import numpy as np + +from openmc.mpi import comm # Configurable switch that enables / disables the use of # multiprocessing routines during depletion USE_MULTIPROCESSING = True +# Allow user to override the number of worker processes to use for depletion +# calculations +NUM_PROCESSES = None + +def _distribute(items): + """Distribute items across MPI communicator + + Parameters + ---------- + items : list + List of items of distribute -def deplete(func, chain, x, rates, dt, matrix_func=None): + Returns + ------- + list + Items assigned to process that called + + """ + min_size, extra = divmod(len(items), comm.size) + j = 0 + for i in range(comm.size): + chunk_size = min_size + int(i < extra) + if comm.rank == i: + return items[j:j + chunk_size] + j += chunk_size + +def deplete(func, chain, n, rates, dt, matrix_func=None, transfer_rates=None, + *matrix_args): """Deplete materials using given reaction rates for a specified time Parameters ---------- func : callable - Function to use to get new compositions. Expected to have the - signature ``func(A, n0, t) -> n1`` + Function to use to get new compositions. Expected to have the signature + ``func(A, n0, t) -> n1`` chain : openmc.deplete.Chain Depletion chain - x : list of numpy.ndarray - Atom number vectors for each material + n : list of numpy.ndarray + List of atom number arrays for each material. Each array in the list + contains the number of [atom] of each nuclide. rates : openmc.deplete.ReactionRates Reaction rates (from transport operator) dt : float Time in [s] to deplete for maxtrix_func : callable, optional - Function to form the depletion matrix after calling - ``matrix_func(chain, rates, fission_yields)``, where - ``fission_yields = {parent: {product: yield_frac}}`` - Expected to return the depletion matrix required by + Function to form the depletion matrix after calling ``matrix_func(chain, + rates, fission_yields)``, where ``fission_yields = {parent: {product: + yield_frac}}`` Expected to return the depletion matrix required by ``func`` + transfer_rates : openmc.deplete.TransferRates, Optional + Object to perform continuous reprocessing. + + .. versionadded:: 0.14.0 + matrix_args: Any, optional + Additional arguments passed to matrix_func Returns ------- - x_result : list of numpy.ndarray - Updated atom number vectors for each material + n_result : list of numpy.ndarray + Updated list of atom number arrays for each material. Each array in the + list contains the number of [atom] of each nuclide. """ fission_yields = chain.fission_yields if len(fission_yields) == 1: fission_yields = repeat(fission_yields[0]) - elif len(fission_yields) != len(x): + elif len(fission_yields) != len(n): raise ValueError( "Number of material fission yield distributions {} is not " "equal to the number of compositions {}".format( - len(fission_yields), len(x))) + len(fission_yields), len(n))) if matrix_func is None: matrices = map(chain.form_matrix, rates, fission_yields) else: - matrices = map(matrix_func, repeat(chain), rates, fission_yields) + matrices = map(matrix_func, repeat(chain), rates, fission_yields, + *matrix_args) + + if transfer_rates is not None: + # Calculate transfer rate terms as diagonal matrices + transfers = map(chain.form_rr_term, repeat(transfer_rates), + transfer_rates.local_mats) + # Subtract transfer rate terms from Bateman matrices + matrices = [matrix - transfer for (matrix, transfer) in zip(matrices, + transfers)] + + if len(transfer_rates.index_transfer) > 0: + # Gather all on comm.rank 0 + matrices = comm.gather(matrices) + n = comm.gather(n) + + if comm.rank == 0: + # Expand lists + matrices = [elm for matrix in matrices for elm in matrix] + n = [n_elm for n_mat in n for n_elm in n_mat] + + # Calculate transfer rate terms as diagonal matrices + transfer_pair = { + mat_pair: chain.form_rr_term(transfer_rates, mat_pair) + for mat_pair in transfer_rates.index_transfer + } + + # Combine all matrices together in a single matrix of matrices + # to be solved in one go + n_rows = n_cols = len(transfer_rates.burnable_mats) + rows = [] + for row in range(n_rows): + cols = [] + for col in range(n_cols): + mat_pair = (transfer_rates.burnable_mats[row], + transfer_rates.burnable_mats[col]) + if row == col: + # Fill the diagonals with the Bateman matrices + cols.append(matrices[row]) + elif mat_pair in transfer_rates.index_transfer: + # Fill the off-diagonals with the transfer pair matrices + cols.append(transfer_pair[mat_pair]) + else: + cols.append(None) + + rows.append(cols) + matrix = bmat(rows) + + # Concatenate vectors of nuclides in one + n_multi = np.concatenate(n) + n_result = func(matrix, n_multi, dt) + + # Split back the nuclide vector result into the original form + n_result = np.split(n_result, np.cumsum([len(i) for i in n])[:-1]) + + else: + n_result = None + + # Braodcast result to other ranks + n_result = comm.bcast(n_result) + # Distribute results across MPI + n_result = _distribute(n_result) + + return n_result - inputs = zip(matrices, x, repeat(dt)) + inputs = zip(matrices, n, repeat(dt)) if USE_MULTIPROCESSING: - with Pool() as pool: - x_result = list(pool.starmap(func, inputs)) + with Pool(NUM_PROCESSES) as pool: + n_result = list(pool.starmap(func, inputs)) else: - x_result = list(starmap(func, inputs)) + n_result = list(starmap(func, inputs)) - return x_result + return n_result diff --git a/openmc/deplete/reaction_rates.py b/openmc/deplete/reaction_rates.py index 299f1133f62..4aaf829a9a5 100644 --- a/openmc/deplete/reaction_rates.py +++ b/openmc/deplete/reaction_rates.py @@ -2,6 +2,8 @@ An ndarray to store reaction rates with string, integer, or slice indexing. """ +from typing import Dict + import numpy as np @@ -29,11 +31,11 @@ class ReactionRates(np.ndarray): Attributes ---------- - index_mat : OrderedDict of str to int + index_mat : dict of str to int A dictionary mapping material ID as string to index. - index_nuc : OrderedDict of str to int + index_nuc : dict of str to int A dictionary mapping nuclide name as string to index. - index_rx : OrderedDict of str to int + index_rx : dict of str to int A dictionary mapping reaction name as string to index. n_mat : int Number of materials. @@ -51,6 +53,10 @@ class ReactionRates(np.ndarray): # the __array_finalize__ method (discussed here: # https://docs.scipy.org/doc/numpy/user/basics.subclassing.html) + index_mat: Dict[str, int] + index_nuc: Dict[str, int] + index_rx: Dict[str, int] + def __new__(cls, local_mats, nuclides, reactions, from_results=False): # Create appropriately-sized zeroed-out ndarray shape = (len(local_mats), len(nuclides), len(reactions)) diff --git a/openmc/deplete/results.py b/openmc/deplete/results.py index ce8331e8251..2e537a1b735 100644 --- a/openmc/deplete/results.py +++ b/openmc/deplete/results.py @@ -1,511 +1,620 @@ -"""The results module. - -Contains results generation and saving capabilities. -""" - -from collections import OrderedDict -import copy +import numbers +import bisect +import math +import typing # required to prevent typing.Union namespace overwriting Union +from typing import Iterable, Optional, Tuple, List +from warnings import warn import h5py import numpy as np -from . import comm, MPI -from .reaction_rates import ReactionRates +from .stepresult import StepResult, VERSION_RESULTS +import openmc.checkvalue as cv +from openmc.data import atomic_mass, AVOGADRO +from openmc.data.library import DataLibrary +from openmc.material import Material, Materials +from openmc.exceptions import DataError +from openmc.checkvalue import PathLike + +__all__ = ["Results", "ResultsList"] + + +def _get_time_as(seconds: float, units: str) -> float: + """Converts the time in seconds to time in different units -VERSION_RESULTS = (1, 1) + Parameters + ---------- + seconds : float + The time to convert expressed in seconds + units : {"s", "min", "h", "d", "a"} + The units to convert time into. Available options are seconds ``"s"``, + minutes ``"min"``, hours ``"h"`` days ``"d"``, Julian years ``"a"`` + + """ + if units == "a": + return seconds / (60 * 60 * 24 * 365.25) # 365.25 due to the leap year + if units == "d": + return seconds / (60 * 60 * 24) + elif units == "h": + return seconds / (60 * 60) + elif units == "min": + return seconds / 60 + else: + return seconds -__all__ = ["Results"] +class Results(list): + """Results from a depletion simulation + The :class:`Results` class acts as a list that stores the results from + each depletion step and provides extra methods for interrogating these + results. -class Results: - """Output of a depletion run + .. versionchanged:: 0.13.1 + Name changed from ``ResultsList`` to ``Results`` - Attributes + Parameters ---------- - k : list of (float, float) - Eigenvalue and uncertainty for each substep. - time : list of float - Time at beginning, end of step, in seconds. - source_rate : float - Source rate during timestep in [W] or [neutron/sec] - n_mat : int - Number of mats. - n_nuc : int - Number of nuclides. - rates : list of ReactionRates - The reaction rates for each substep. - volume : OrderedDict of str to float - Dictionary mapping mat id to volume. - mat_to_ind : OrderedDict of str to int - A dictionary mapping mat ID as string to index. - nuc_to_ind : OrderedDict of str to int - A dictionary mapping nuclide name as string to index. - mat_to_hdf5_ind : OrderedDict of str to int - A dictionary mapping mat ID as string to global index. - n_hdf5_mats : int - Number of materials in entire geometry. - n_stages : int - Number of stages in simulation. - data : numpy.ndarray - Atom quantity, stored by stage, mat, then by nuclide. - proc_time: int - Average time spent depleting a material across all - materials and processes + filename : str, optional + Path to depletion result file """ - def __init__(self): - self.k = None - self.time = None - self.source_rate = None - self.rates = None - self.volume = None - self.proc_time = None + def __init__(self, filename='depletion_results.h5'): + data = [] + if filename is not None: + with h5py.File(str(filename), "r") as fh: + cv.check_filetype_version(fh, 'depletion results', VERSION_RESULTS[0]) - self.mat_to_ind = None - self.nuc_to_ind = None - self.mat_to_hdf5_ind = None + # Get number of results stored + n = fh["number"][...].shape[0] - self.data = None + for i in range(n): + data.append(StepResult.from_hdf5(fh, i)) + super().__init__(data) - def __getitem__(self, pos): - """Retrieves an item from results. + + @classmethod + def from_hdf5(cls, filename: PathLike): + """Load in depletion results from a previous file Parameters ---------- - pos : tuple - A three-length tuple containing a stage index, mat index and a nuc - index. All can be integers or slices. The second two can be - strings corresponding to their respective dictionary. + filename : str + Path to depletion result file Returns ------- - float - The atoms for stage, mat, nuc + Results + New instance of depletion results """ - stage, mat, nuc = pos - if isinstance(mat, str): - mat = self.mat_to_ind[mat] - if isinstance(nuc, str): - nuc = self.nuc_to_ind[nuc] - - return self.data[stage, mat, nuc] - - def __setitem__(self, pos, val): - """Sets an item from results. + warn( + "The ResultsList.from_hdf5(...) method is no longer necessary and will " + "be removed in a future version of OpenMC. Use Results(...) instead.", + FutureWarning + ) + return cls(filename) + + def get_activity( + self, + mat: typing.Union[Material, str], + units: str = "Bq/cm3", + by_nuclide: bool = False, + volume: Optional[float] = None + ) -> Tuple[np.ndarray, typing.Union[np.ndarray, List[dict]]]: + """Get activity of material over time. + + .. versionadded:: 0.14.0 Parameters ---------- - pos : tuple - A three-length tuple containing a stage index, mat index and a nuc - index. All can be integers or slices. The second two can be - strings corresponding to their respective dictionary. + mat : openmc.Material, str + Material object or material id to evaluate + units : {'Bq', 'Bq/g', 'Bq/cm3'} + Specifies the type of activity to return, options include total + activity [Bq], specific [Bq/g] or volumetric activity [Bq/cm3]. + by_nuclide : bool + Specifies if the activity should be returned for the material as a + whole or per nuclide. Default is False. + volume : float, optional + Volume of the material. If not passed, defaults to using the + :attr:`Material.volume` attribute. - val : float - The value to set data to. + Returns + ------- + times : numpy.ndarray + Array of times in [s] + activities : numpy.ndarray or List[dict] + Array of total activities if by_nuclide = False (default) + or list of dictionaries of activities by nuclide if + by_nuclide = True. """ - stage, mat, nuc = pos - if isinstance(mat, str): - mat = self.mat_to_ind[mat] - if isinstance(nuc, str): - nuc = self.nuc_to_ind[nuc] - - self.data[stage, mat, nuc] = val - - @property - def n_mat(self): - return len(self.mat_to_ind) + if isinstance(mat, Material): + mat_id = str(mat.id) + elif isinstance(mat, str): + mat_id = mat + else: + raise TypeError('mat should be of type openmc.Material or str') - @property - def n_nuc(self): - return len(self.nuc_to_ind) + times = np.empty_like(self, dtype=float) + if by_nuclide: + activities = [None] * len(self) + else: + activities = np.empty_like(self, dtype=float) - @property - def n_hdf5_mats(self): - return len(self.mat_to_hdf5_ind) + # Evaluate activity for each depletion time + for i, result in enumerate(self): + times[i] = result.time[0] + activities[i] = result.get_material(mat_id).get_activity(units, by_nuclide, volume) - @property - def n_stages(self): - return self.data.shape[0] + return times, activities - def allocate(self, volume, nuc_list, burn_list, full_burn_list, stages): - """Allocates memory of Results. + def get_atoms( + self, + mat: typing.Union[Material, str], + nuc: str, + nuc_units: str = "atoms", + time_units: str = "s" + ) -> Tuple[np.ndarray, np.ndarray]: + """Get number of nuclides over time from a single material Parameters ---------- - volume : dict of str float - Volumes corresponding to materials in full_burn_dict - nuc_list : list of str - A list of all nuclide names. Used for sorting the simulation. - burn_list : list of int - A list of all mat IDs to be burned. Used for sorting the simulation. - full_burn_list : list of str - List of all burnable material IDs - stages : int - Number of stages in simulation. - - """ - self.volume = copy.deepcopy(volume) - self.nuc_to_ind = {nuc: i for i, nuc in enumerate(nuc_list)} - self.mat_to_ind = {mat: i for i, mat in enumerate(burn_list)} - self.mat_to_hdf5_ind = {mat: i for i, mat in enumerate(full_burn_list)} + mat : openmc.Material, str + Material object or material id to evaluate + nuc : str + Nuclide name to evaluate + nuc_units : {"atoms", "atom/b-cm", "atom/cm3"}, optional + Units for the returned concentration. Default is ``"atoms"`` - # Create storage array - self.data = np.zeros((stages, self.n_mat, self.n_nuc)) + .. versionadded:: 0.12 + time_units : {"s", "min", "h", "d", "a"}, optional + Units for the returned time array. Default is ``"s"`` to + return the value in seconds. Other options are minutes ``"min"``, + hours ``"h"``, days ``"d"``, and Julian years ``"a"``. - def distribute(self, local_materials, ranges): - """Create a new object containing data for distributed materials - - Parameters - ---------- - local_materials : iterable of str - Materials for this process - ranges : iterable of int - Slice-like object indicating indicies of ``local_materials`` - in the material dimension of :attr:`data` and each element - in :attr:`rates` + .. versionadded:: 0.12 Returns ------- - Results - New results object + times : numpy.ndarray + Array of times in units of ``time_units`` + concentrations : numpy.ndarray + Concentration of specified nuclide in units of ``nuc_units`` + """ - new = Results() - new.volume = {lm: self.volume[lm] for lm in local_materials} - new.mat_to_ind = {mat: idx for (idx, mat) in enumerate(local_materials)} - - # Direct transfer - direct_attrs = ("time", "k", "source_rate", "nuc_to_ind", - "mat_to_hdf5_ind", "proc_time") - for attr in direct_attrs: - setattr(new, attr, getattr(self, attr)) - # Get applicable slice of data - new.data = self.data[:, ranges] - new.rates = [r[ranges] for r in self.rates] - return new - - def export_to_hdf5(self, filename, step): - """Export results to an HDF5 file + cv.check_value("time_units", time_units, {"s", "d", "min", "h", "a"}) + cv.check_value("nuc_units", nuc_units, + {"atoms", "atom/b-cm", "atom/cm3"}) + + if isinstance(mat, Material): + mat_id = str(mat.id) + elif isinstance(mat, str): + mat_id = mat + else: + raise TypeError('mat should be of type openmc.Material or str') + times = np.empty_like(self, dtype=float) + concentrations = np.empty_like(self, dtype=float) + + # Evaluate value in each region + for i, result in enumerate(self): + times[i] = result.time[0] + concentrations[i] = result[0, mat_id, nuc] + + # Unit conversions + times = _get_time_as(times, time_units) + if nuc_units != "atoms": + # Divide by volume to get density + concentrations /= self[0].volume[mat_id] + if nuc_units == "atom/b-cm": + # 1 barn = 1e-24 cm^2 + concentrations *= 1e-24 + + return times, concentrations + + def get_decay_heat( + self, + mat: typing.Union[Material, str], + units: str = "W", + by_nuclide: bool = False, + volume: Optional[float] = None + ) -> Tuple[np.ndarray, typing.Union[np.ndarray, List[dict]]]: + """Get decay heat of material over time. + + .. versionadded:: 0.14.0 Parameters ---------- - filename : str - The filename to write to - step : int - What step is this? + mat : openmc.Material, str + Material object or material id to evaluate. + units : {'W', 'W/g', 'W/cm3'} + Specifies the units of decay heat to return. Options include total + heat [W], specific [W/g] or volumetric heat [W/cm3]. + by_nuclide : bool + Specifies if the decay heat should be returned for the material as a + whole or per nuclide. Default is False. + volume : float, optional + Volume of the material. If not passed, defaults to using the + :attr:`Material.volume` attribute. + Returns + ------- + times : numpy.ndarray + Array of times in [s] + decay_heat : numpy.ndarray or List[dict] + Array of total decay heat values if by_nuclide = False (default) + or list of dictionaries of decay heat values by nuclide if + by_nuclide = True. """ - # Write new file if first time step, else add to existing file - kwargs = {'mode': "w" if step == 0 else "a"} - - if h5py.get_config().mpi and comm.size > 1: - # Write results in parallel - kwargs['driver'] = 'mpio' - kwargs['comm'] = comm - with h5py.File(filename, **kwargs) as handle: - self._to_hdf5(handle, step, parallel=True) + + if isinstance(mat, Material): + mat_id = str(mat.id) + elif isinstance(mat, str): + mat_id = mat else: - # Gather results at root process - all_results = comm.gather(self) + raise TypeError('mat should be of type openmc.Material or str') - # Only root process writes results - if comm.rank == 0: - with h5py.File(filename, **kwargs) as handle: - for res in all_results: - res._to_hdf5(handle, step, parallel=False) + times = np.empty_like(self, dtype=float) + if by_nuclide: + decay_heat = [None] * len(self) + else: + decay_heat = np.empty_like(self, dtype=float) - def _write_hdf5_metadata(self, handle): - """Writes result metadata in HDF5 file + # Evaluate decay heat for each depletion time + for i, result in enumerate(self): + times[i] = result.time[0] + decay_heat[i] = result.get_material(mat_id).get_decay_heat( + units, by_nuclide, volume) - Parameters - ---------- - handle : h5py.File or h5py.Group - An hdf5 file or group type to store this in. + return times, decay_heat - """ - # Create and save the 5 dictionaries: - # quantities - # self.mat_to_ind -> self.volume (TODO: support for changing volumes) - # self.nuc_to_ind - # reactions - # self.rates[0].nuc_to_ind (can be different from above, above is superset) - # self.rates[0].react_to_ind - # these are shared by every step of the simulation, and should be deduplicated. + def get_mass(self, + mat: typing.Union[Material, str], + nuc: str, + mass_units: str = "g", + time_units: str = "s" + ) -> Tuple[np.ndarray, np.ndarray]: + """Get mass of nuclides over time from a single material - # Store concentration mat and nuclide dictionaries (along with volumes) + .. versionadded:: 0.14.0 - handle.attrs['version'] = np.array(VERSION_RESULTS) - handle.attrs['filetype'] = np.string_('depletion results') + Parameters + ---------- + mat : openmc.Material, str + Material object or material id to evaluate + nuc : str + Nuclide name to evaluate + mass_units : {"g", "g/cm3", "kg"}, optional + Units for the returned mass. + time_units : {"s", "min", "h", "d", "a"}, optional + Units for the returned time array. Default is ``"s"`` to + return the value in seconds. Other options are minutes ``"min"``, + hours ``"h"``, days ``"d"``, and Julian years ``"a"``. - mat_list = sorted(self.mat_to_hdf5_ind, key=int) - nuc_list = sorted(self.nuc_to_ind) - rxn_list = sorted(self.rates[0].index_rx) + Returns + ------- + times : numpy.ndarray + Array of times in units of ``time_units`` + mass : numpy.ndarray + Mass of specified nuclide in units of ``mass_units`` - n_mats = self.n_hdf5_mats - n_nuc_number = len(nuc_list) - n_nuc_rxn = len(self.rates[0].index_nuc) - n_rxn = len(rxn_list) - n_stages = self.n_stages + """ + cv.check_value("mass_units", mass_units, {"g", "g/cm3", "kg"}) - mat_group = handle.create_group("materials") + if isinstance(mat, Material): + mat_id = str(mat.id) + elif isinstance(mat, str): + mat_id = mat + else: + raise TypeError('mat should be of type openmc.Material or str') - for mat in mat_list: - mat_single_group = mat_group.create_group(mat) - mat_single_group.attrs["index"] = self.mat_to_hdf5_ind[mat] - mat_single_group.attrs["volume"] = self.volume[mat] + times, atoms = self.get_atoms(mat, nuc, time_units=time_units) - nuc_group = handle.create_group("nuclides") + mass = atoms * atomic_mass(nuc) / AVOGADRO - for nuc in nuc_list: - nuc_single_group = nuc_group.create_group(nuc) - nuc_single_group.attrs["atom number index"] = self.nuc_to_ind[nuc] - if nuc in self.rates[0].index_nuc: - nuc_single_group.attrs["reaction rate index"] = self.rates[0].index_nuc[nuc] + # Unit conversions + if mass_units == "g/cm3": + # Divide by volume to get density + mass /= self[0].volume[mat_id] + elif mass_units == "kg": + mass /= 1e3 - rxn_group = handle.create_group("reactions") + return times, mass - for rxn in rxn_list: - rxn_single_group = rxn_group.create_group(rxn) - rxn_single_group.attrs["index"] = self.rates[0].index_rx[rxn] + def get_reaction_rate( + self, + mat: typing.Union[Material, str], + nuc: str, + rx: str + ) -> Tuple[np.ndarray, np.ndarray]: + """Get reaction rate in a single material/nuclide over time - # Construct array storage + Parameters + ---------- + mat : openmc.Material, str + Material object or material id to evaluate + nuc : str + Nuclide name to evaluate + rx : str + Reaction rate to evaluate - handle.create_dataset("number", (1, n_stages, n_mats, n_nuc_number), - maxshape=(None, n_stages, n_mats, n_nuc_number), - chunks=(1, 1, n_mats, n_nuc_number), - dtype='float64') + Returns + ------- + times : numpy.ndarray + Array of times in [s] + rates : numpy.ndarray + Array of reaction rates - handle.create_dataset("reaction rates", (1, n_stages, n_mats, n_nuc_rxn, n_rxn), - maxshape=(None, n_stages, n_mats, n_nuc_rxn, n_rxn), - chunks=(1, 1, n_mats, n_nuc_rxn, n_rxn), - dtype='float64') + """ + times = np.empty_like(self, dtype=float) + rates = np.empty_like(self, dtype=float) - handle.create_dataset("eigenvalues", (1, n_stages, 2), - maxshape=(None, n_stages, 2), dtype='float64') + if isinstance(mat, Material): + mat_id = str(mat.id) + elif isinstance(mat, str): + mat_id = mat + else: + raise TypeError('mat should be of type openmc.Material or str') - handle.create_dataset("time", (1, 2), maxshape=(None, 2), dtype='float64') + # Evaluate value in each region + for i, result in enumerate(self): + times[i] = result.time[0] + rates[i] = result.rates[0].get(mat_id, nuc, rx) * result[0, mat, nuc] - handle.create_dataset("source_rate", (1, n_stages), maxshape=(None, n_stages), - dtype='float64') + return times, rates - handle.create_dataset( - "depletion time", (1,), maxshape=(None,), - dtype="float64") + def get_keff(self, time_units: str = 's') -> Tuple[np.ndarray, np.ndarray]: + """Evaluates the eigenvalue from a results list. - def _to_hdf5(self, handle, index, parallel=False): - """Converts results object into an hdf5 object. + .. versionadded:: 0.13.1 Parameters ---------- - handle : h5py.File or h5py.Group - An HDF5 file or group type to store this in. - index : int - What step is this? - parallel : bool - Being called with parallel HDF5? + time_units : {"s", "d", "min", "h", "a"}, optional + Desired units for the times array. Options are seconds ``"s"``, + minutes ``"min"``, hours ``"h"``, days ``"d"``, and Julian years + ``"a"``. - """ - if "/number" not in handle: - if parallel: - comm.barrier() - self._write_hdf5_metadata(handle) - - if parallel: - comm.barrier() - - # Grab handles - number_dset = handle["/number"] - rxn_dset = handle["/reaction rates"] - eigenvalues_dset = handle["/eigenvalues"] - time_dset = handle["/time"] - source_rate_dset = handle["/source_rate"] - proc_time_dset = handle["/depletion time"] - - # Get number of results stored - number_shape = list(number_dset.shape) - number_results = number_shape[0] - - new_shape = index + 1 - - if number_results < new_shape: - # Extend first dimension by 1 - number_shape[0] = new_shape - number_dset.resize(number_shape) - - rxn_shape = list(rxn_dset.shape) - rxn_shape[0] = new_shape - rxn_dset.resize(rxn_shape) - - eigenvalues_shape = list(eigenvalues_dset.shape) - eigenvalues_shape[0] = new_shape - eigenvalues_dset.resize(eigenvalues_shape) - - time_shape = list(time_dset.shape) - time_shape[0] = new_shape - time_dset.resize(time_shape) - - source_rate_shape = list(source_rate_dset.shape) - source_rate_shape[0] = new_shape - source_rate_dset.resize(source_rate_shape) - - proc_shape = list(proc_time_dset.shape) - proc_shape[0] = new_shape - proc_time_dset.resize(proc_shape) - - # If nothing to write, just return - if len(self.mat_to_ind) == 0: - return - - # Add data - # Note, for the last step, self.n_stages = 1, even if n_stages != 1. - n_stages = self.n_stages - inds = [self.mat_to_hdf5_ind[mat] for mat in self.mat_to_ind] - low = min(inds) - high = max(inds) - for i in range(n_stages): - number_dset[index, i, low:high+1] = self.data[i] - rxn_dset[index, i, low:high+1] = self.rates[i] - if comm.rank == 0: - eigenvalues_dset[index, i] = self.k[i] - if comm.rank == 0: - time_dset[index] = self.time - source_rate_dset[index] = self.source_rate - if self.proc_time is not None: - proc_time_dset[index] = ( - self.proc_time / (comm.size * self.n_hdf5_mats) - ) - - @classmethod - def from_hdf5(cls, handle, step): - """Loads results object from HDF5. + Returns + ------- + times : numpy.ndarray + Array of times in specified units + eigenvalues : numpy.ndarray + k-eigenvalue at each time. Column 0 + contains the eigenvalue, while column + 1 contains the associated uncertainty - Parameters - ---------- - handle : h5py.File or h5py.Group - An HDF5 file or group type to load from. - step : int - Index for depletion step """ - results = cls() - - # Grab handles - number_dset = handle["/number"] - eigenvalues_dset = handle["/eigenvalues"] - time_dset = handle["/time"] - if "source_rate" in handle: - source_rate_dset = handle["/source_rate"] - else: - # Older versions used "power" instead of "source_rate" - source_rate_dset = handle["/power"] - - results.data = number_dset[step, :, :, :] - results.k = eigenvalues_dset[step, :] - results.time = time_dset[step, :] - results.source_rate = source_rate_dset[step, :] + cv.check_value("time_units", time_units, {"s", "d", "min", "h", "a"}) - if "depletion time" in handle: - proc_time_dset = handle["/depletion time"] - if step < proc_time_dset.shape[0]: - results.proc_time = proc_time_dset[step] + times = np.empty_like(self, dtype=float) + eigenvalues = np.empty((len(self), 2), dtype=float) - if results.proc_time is None: - results.proc_time = np.array([np.nan]) + # Get time/eigenvalue at each point + for i, result in enumerate(self): + times[i] = result.time[0] + eigenvalues[i] = result.k[0] - # Reconstruct dictionaries - results.volume = OrderedDict() - results.mat_to_ind = OrderedDict() - results.nuc_to_ind = OrderedDict() - rxn_nuc_to_ind = OrderedDict() - rxn_to_ind = OrderedDict() + # Convert time units if necessary + times = _get_time_as(times, time_units) + return times, eigenvalues - for mat, mat_handle in handle["/materials"].items(): - vol = mat_handle.attrs["volume"] - ind = mat_handle.attrs["index"] + def get_eigenvalue(self, time_units: str = 's') -> Tuple[np.ndarray, np.ndarray]: + warn("The get_eigenvalue(...) function has been renamed get_keff and " + "will be removed in a future version of OpenMC.", FutureWarning) + return self.get_keff(time_units) - results.volume[mat] = vol - results.mat_to_ind[mat] = ind + def get_depletion_time(self) -> np.ndarray: + """Return an array of the average time to deplete a material - for nuc, nuc_handle in handle["/nuclides"].items(): - ind_atom = nuc_handle.attrs["atom number index"] - results.nuc_to_ind[nuc] = ind_atom + .. note:: + The return value will have one fewer values than several other + methods, such as :meth:`get_keff`, because no depletion is performed + at the final transport stage. - if "reaction rate index" in nuc_handle.attrs: - rxn_nuc_to_ind[nuc] = nuc_handle.attrs["reaction rate index"] - - for rxn, rxn_handle in handle["/reactions"].items(): - rxn_to_ind[rxn] = rxn_handle.attrs["index"] - - results.rates = [] - # Reconstruct reactions - for i in range(results.n_stages): - rate = ReactionRates(results.mat_to_ind, rxn_nuc_to_ind, rxn_to_ind, True) + Returns + ------- + times : numpy.ndarray + Vector of average time to deplete a single material + across all processes and materials. - rate[:] = handle["/reaction rates"][step, i, :, :, :] - results.rates.append(rate) + """ + times = np.empty(len(self) - 1) + # Need special logic because the predictor + # writes EOS values for step i as BOS values + # for step i+1 + # The first proc_time may be zero + if self[0].proc_time > 0.0: + items = self[:-1] + else: + items = self[1:] + for ix, res in enumerate(items): + times[ix] = res.proc_time + return times - return results + def get_times(self, time_units: str = "d") -> np.ndarray: + """Return the points in time that define the depletion schedule - @staticmethod - def save(op, x, op_results, t, source_rate, step_ind, proc_time=None): - """Creates and writes depletion results to disk + .. versionadded:: 0.12.1 Parameters ---------- - op : openmc.deplete.TransportOperator - The operator used to generate these results. - x : list of list of numpy.array - The prior x vectors. Indexed [i][cell] using the above equation. - op_results : list of openmc.deplete.OperatorResult - Results of applying transport operator - t : list of float - Time indices. - source_rate : float - Source rate during time step in [W] or [neutron/sec] - step_ind : int - Step index. - proc_time : float or None - Total process time spent depleting materials. This may - be process-dependent and will be reduced across MPI - processes. + time_units : {"s", "d", "min", "h", "a"}, optional + Return the vector in these units. Default is to + convert to days ``"d"``. Other options are seconds ``"s"``, minutes + ``"min"``, hours ``"h"``, days ``"d"``, and Julian years ``"a"``. + + Returns + ------- + numpy.ndarray + 1-D vector of time points """ - # Get indexing terms - vol_dict, nuc_list, burn_list, full_burn_list = op.get_results_info() + cv.check_value("time_units", time_units, {"s", "d", "min", "h", "a"}) - stages = len(x) + times = np.fromiter( + (r.time[0] for r in self), + dtype=self[0].time.dtype, + count=len(self), + ) - # Create results - results = Results() - results.allocate(vol_dict, nuc_list, burn_list, full_burn_list, stages) + return _get_time_as(times, time_units) - n_mat = len(burn_list) + def get_step_where( + self, time, time_units: str = "d", atol: float = 1e-6, rtol: float = 1e-3 + ) -> int: + """Return the index closest to a given point in time - for i in range(stages): - for mat_i in range(n_mat): - results[i, mat_i, :] = x[i][mat_i] + In the event ``time`` lies exactly between two points, the + lower index will be returned. It is possible that the index + will be at most one past the point in time requested, but only + according to tolerances requested. - results.k = [(r.k.nominal_value, r.k.std_dev) for r in op_results] - results.rates = [r.rates for r in op_results] - results.time = t - results.source_rate = source_rate - results.proc_time = proc_time - if results.proc_time is not None: - results.proc_time = comm.reduce(proc_time, op=MPI.SUM) + Passing ``atol=math.inf`` and ``rtol=math.inf`` will return + the closest index to the requested point. - results.export_to_hdf5("depletion_results.h5", step_ind) + .. versionadded:: 0.12.1 - def transfer_volumes(self, geometry): - """Transfers volumes from depletion results to geometry + Parameters + ---------- + time : float + Desired point in time + time_units : {"s", "d", "min", "h", "a"}, optional + Units on ``time``. Default: days ``"d"``. Other options are seconds + ``"s"``, minutes ``"min"``, hours ``"h"`` and Julian years ``"a"``. + atol : float, optional + Absolute tolerance (in ``time_units``) if ``time`` is not + found. + rtol : float, optional + Relative tolerance if ``time`` is not found. + + Returns + ------- + int + + """ + cv.check_type("time", time, numbers.Real) + cv.check_type("atol", atol, numbers.Real) + cv.check_type("rtol", rtol, numbers.Real) + + times = self.get_times(time_units) + + if times[0] < time < times[-1]: + ix = bisect.bisect_left(times, time) + if ix == times.size: + ix -= 1 + # Bisection will place us either directly on the point + # or one-past the first value less than time + elif time - times[ix - 1] <= times[ix] - time: + ix -= 1 + elif times[0] >= time: + ix = 0 + elif time >= times[-1]: + ix = times.size - 1 + + if math.isclose(time, times[ix], rel_tol=rtol, abs_tol=atol): + return ix + + closest = min(times, key=lambda t: abs(time - t)) + raise ValueError( + f"A value of {time} {time_units} was not found given absolute and " + f"relative tolerances {atol} and {rtol}. Closest time is {closest} " + f"{time_units}." + ) + + def export_to_materials( + self, + burnup_index: int, + nuc_with_data: Optional[Iterable[str]] = None, + path: PathLike = 'materials.xml' + ) -> Materials: + """Return openmc.Materials object based on results at a given step + + .. versionadded:: 0.12.1 Parameters ---------- - geometry : OpenMC geometry to be used in a depletion restart - calculation + burn_index : int + Index of burnup step to evaluate. See also: get_step_where for + obtaining burnup step indices from other data such as the time. + nuc_with_data : Iterable of str, optional + Nuclides to include in resulting materials. + This can be specified if not all nuclides appearing in + depletion results have associated neutron cross sections, and + as such cannot be used in subsequent transport calculations. + If not provided, nuclides from the cross_sections element of + materials.xml will be used. If that element is not present, + nuclides from openmc.config['cross_sections'] will be used. + path : PathLike + Path to materials XML file to read. Defaults to 'materials.xml'. + + .. versionadded:: 0.13.3 + Returns + ------- + mat_file : Materials + A modified Materials instance containing depleted material data + and original isotopic compositions of non-depletable materials """ - for cell in geometry.get_all_material_cells().values(): - for material in cell.get_all_materials().values(): - if material.depletable: - material.volume = self.volume[str(material.id)] + result = self[burnup_index] + + # Only materials found in the original materials.xml file will be + # updated. If for some reason you have modified OpenMC to produce + # new materials as depletion takes place, this method will not + # work as expected and leave out that material. + mat_file = Materials.from_xml(path) + + # Only nuclides with valid transport data will be written to + # the new materials XML file. The precedence of nuclides to select + # is first ones provided as a kwarg here, then ones specified + # in the materials.xml file if provided, then finally from + # openmc.config['cross_sections']. + if nuc_with_data: + cv.check_iterable_type('nuclide names', nuc_with_data, str) + available_cross_sections = nuc_with_data + else: + # select cross_sections.xml file to use + if mat_file.cross_sections: + this_library = DataLibrary.from_xml(path=mat_file.cross_sections) + else: + this_library = DataLibrary.from_xml() + + # Find neutron libraries we have access to + available_cross_sections = set() + for lib in this_library.libraries: + if lib['type'] == 'neutron': + available_cross_sections.update(lib['materials']) + if not available_cross_sections: + raise DataError('No neutron libraries found in cross_sections.xml') + + # Overwrite material definitions, if they can be found in the depletion + # results, and save them to the new depleted xml file. + for mat in mat_file: + mat_id = str(mat.id) + if mat_id in result.index_mat: + mat.volume = result.volume[mat_id] + + # Change density of all nuclides in material to atom/b-cm + atoms_per_barn_cm = mat.get_nuclide_atom_densities() + for nuc, value in atoms_per_barn_cm.items(): + mat.remove_nuclide(nuc) + mat.add_nuclide(nuc, value) + mat.set_density('sum') + + # For nuclides in chain that have cross sections, replace + # density in original material with new density from results + for nuc in result.index_nuc: + if nuc not in available_cross_sections: + continue + atoms = result[0, mat_id, nuc] + if atoms > 0.0: + atoms_per_barn_cm = 1e-24 * atoms / mat.volume + mat.remove_nuclide(nuc) # Replace if it's there + mat.add_nuclide(nuc, atoms_per_barn_cm) + + return mat_file + + +# Retain deprecated name for the time being +ResultsList = Results diff --git a/openmc/deplete/results_list.py b/openmc/deplete/results_list.py deleted file mode 100644 index 2dc486feb35..00000000000 --- a/openmc/deplete/results_list.py +++ /dev/null @@ -1,373 +0,0 @@ -import numbers -import bisect -import math - -import h5py -import numpy as np - -from .results import Results, VERSION_RESULTS -import openmc.checkvalue as cv -from openmc.data.library import DataLibrary -from openmc.material import Material, Materials -from openmc.exceptions import DataError, InvalidArgumentError - -__all__ = ["ResultsList"] - - -class ResultsList(list): - """A list of openmc.deplete.Results objects - - It is recommended to use :meth:`from_hdf5` over - direct creation. - """ - - @classmethod - def from_hdf5(cls, filename): - """Load in depletion results from a previous file - - Parameters - ---------- - filename : str - Path to depletion result file - - Returns - ------- - new : ResultsList - New instance of depletion results - """ - with h5py.File(str(filename), "r") as fh: - cv.check_filetype_version(fh, 'depletion results', VERSION_RESULTS[0]) - new = cls() - - # Get number of results stored - n = fh["number"][...].shape[0] - - for i in range(n): - new.append(Results.from_hdf5(fh, i)) - return new - - def get_atoms(self, mat, nuc, nuc_units="atoms", time_units="s"): - """Get number of nuclides over time from a single material - - .. note:: - Initial values for some isotopes that do not appear in - initial concentrations may be non-zero, depending on the - value of :class:`openmc.deplete.Operator` ``dilute_initial``. - The :class:`openmc.deplete.Operator` adds isotopes according - to this setting, which can be set to zero. - - Parameters - ---------- - mat : str - Material name to evaluate - nuc : str - Nuclide name to evaluate - nuc_units : {"atoms", "atom/b-cm", "atom/cm3"}, optional - Units for the returned concentration. Default is ``"atoms"`` - - .. versionadded:: 0.12 - time_units : {"s", "min", "h", "d"}, optional - Units for the returned time array. Default is ``"s"`` to - return the value in seconds. - - .. versionadded:: 0.12 - - Returns - ------- - times : numpy.ndarray - Array of times in units of ``time_units`` - concentrations : numpy.ndarray - Concentration of specified nuclide in units of ``nuc_units`` - - """ - cv.check_value("time_units", time_units, {"s", "d", "min", "h"}) - cv.check_value("nuc_units", nuc_units, - {"atoms", "atom/b-cm", "atom/cm3"}) - - times = np.empty_like(self, dtype=float) - concentrations = np.empty_like(self, dtype=float) - - # Evaluate value in each region - for i, result in enumerate(self): - times[i] = result.time[0] - concentrations[i] = result[0, mat, nuc] - - # Unit conversions - if time_units == "d": - times /= (60 * 60 * 24) - elif time_units == "h": - times /= (60 * 60) - elif time_units == "min": - times /= 60 - - if nuc_units != "atoms": - # Divide by volume to get density - concentrations /= self[0].volume[mat] - if nuc_units == "atom/b-cm": - # 1 barn = 1e-24 cm^2 - concentrations *= 1e-24 - - return times, concentrations - - def get_reaction_rate(self, mat, nuc, rx): - """Get reaction rate in a single material/nuclide over time - - .. note:: - - Initial values for some isotopes that do not appear in - initial concentrations may be non-zero, depending on the - value of :class:`openmc.deplete.Operator` ``dilute_initial`` - The :class:`openmc.deplete.Operator` adds isotopes according - to this setting, which can be set to zero. - - Parameters - ---------- - mat : str - Material name to evaluate - nuc : str - Nuclide name to evaluate - rx : str - Reaction rate to evaluate - - Returns - ------- - times : numpy.ndarray - Array of times in [s] - rates : numpy.ndarray - Array of reaction rates - - """ - times = np.empty_like(self, dtype=float) - rates = np.empty_like(self, dtype=float) - - # Evaluate value in each region - for i, result in enumerate(self): - times[i] = result.time[0] - rates[i] = result.rates[0].get(mat, nuc, rx) * result[0, mat, nuc] - - return times, rates - - def get_eigenvalue(self): - """Evaluates the eigenvalue from a results list. - - Returns - ------- - times : numpy.ndarray - Array of times in [s] - eigenvalues : numpy.ndarray - k-eigenvalue at each time. Column 0 - contains the eigenvalue, while column - 1 contains the associated uncertainty - - """ - times = np.empty_like(self, dtype=float) - eigenvalues = np.empty((len(self), 2), dtype=float) - - # Get time/eigenvalue at each point - for i, result in enumerate(self): - times[i] = result.time[0] - eigenvalues[i] = result.k[0] - - return times, eigenvalues - - def get_depletion_time(self): - """Return an array of the average time to deplete a material - - .. note:: - - Will have one fewer row than number of other methods, - like :meth:`get_eigenvalues`, because no depletion - is performed at the final transport stage - - Returns - ------- - times : numpy.ndarray - Vector of average time to deplete a single material - across all processes and materials. - - """ - times = np.empty(len(self) - 1) - # Need special logic because the predictor - # writes EOS values for step i as BOS values - # for step i+1 - # The first proc_time may be zero - if self[0].proc_time > 0.0: - items = self[:-1] - else: - items = self[1:] - for ix, res in enumerate(items): - times[ix] = res.proc_time - return times - - def get_times(self, time_units="d") -> np.ndarray: - """Return the points in time that define the depletion schedule - - - .. versionadded:: 0.12.1 - - Parameters - ---------- - time_units : {"s", "d", "h", "min"}, optional - Return the vector in these units. Default is to - convert to days - - Returns - ------- - numpy.ndarray - 1-D vector of time points - - """ - cv.check_type("time_units", time_units, str) - - times = np.fromiter( - (r.time[0] for r in self), - dtype=self[0].time.dtype, - count=len(self), - ) - - if time_units == "d": - times /= (60 * 60 * 24) - elif time_units == "h": - times /= (60 * 60) - elif time_units == "min": - times /= 60 - elif time_units != "s": - raise ValueError( - 'Unable to set "time_units" to {} since it is not ' - 'in ("s", "d", "min", "h")'.format(time_units) - ) - return times - - def get_step_where( - self, time, time_units="d", atol=1e-6, rtol=1e-3 - ) -> int: - """Return the index closest to a given point in time - - In the event ``time`` lies exactly between two points, the - lower index will be returned. It is possible that the index - will be at most one past the point in time requested, but only - according to tolerances requested. - - Passing ``atol=math.inf`` and ``rtol=math.inf`` will return - the closest index to the requested point. - - - .. versionadded:: 0.12.1 - - Parameters - ---------- - time : float - Desired point in time - time_units : {"s", "d", "min", "h"}, optional - Units on ``time``. Default: days - atol : float, optional - Absolute tolerance (in ``time_units``) if ``time`` is not - found. - rtol : float, optional - Relative tolerance if ``time`` is not found. - - Returns - ------- - int - - """ - cv.check_type("time", time, numbers.Real) - cv.check_type("atol", atol, numbers.Real) - cv.check_type("rtol", rtol, numbers.Real) - - times = self.get_times(time_units) - - if times[0] < time < times[-1]: - ix = bisect.bisect_left(times, time) - if ix == times.size: - ix -= 1 - # Bisection will place us either directly on the point - # or one-past the first value less than time - elif time - times[ix - 1] <= times[ix] - time: - ix -= 1 - elif times[0] >= time: - ix = 0 - elif time >= times[-1]: - ix = times.size - 1 - - if math.isclose(time, times[ix], rel_tol=rtol, abs_tol=atol): - return ix - - raise ValueError( - "A value of {} {} was not found given absolute and " - "relative tolerances {} and {}.".format( - time, time_units, atol, rtol) - ) - - def export_to_materials(self, burnup_index, nuc_with_data=None) -> Materials: - """Return openmc.Materials object based on results at a given step - - .. versionadded:: 0.12.1 - - Parameters - ---------- - burn_index : int - Index of burnup step to evaluate. See also: get_step_where for - obtaining burnup step indices from other data such as the time. - nuc_with_data : Iterable of str, optional - Nuclides to include in resulting materials. - This can be specified if not all nuclides appearing in - depletion results have associated neutron cross sections, and - as such cannot be used in subsequent transport calculations. - If not provided, nuclides from the cross_sections element of - materials.xml will be used. If that element is not present, - nuclides from OPENMC_CROSS_SECTIONS will be used. - - Returns - ------- - mat_file : Materials - A modified Materials instance containing depleted material data - and original isotopic compositions of non-depletable materials - """ - result = self[burnup_index] - - # Only materials found in the original materials.xml file will be - # updated. If for some reason you have modified OpenMC to produce - # new materials as depletion takes place, this method will not - # work as expected and leave out that material. - mat_file = Materials.from_xml("materials.xml") - - # Only nuclides with valid transport data will be written to - # the new materials XML file. The precedence of nuclides to select - # is first ones provided as a kwarg here, then ones specified - # in the materials.xml file if provided, then finally from - # the environment variable OPENMC_CROSS_SECTIONS. - if nuc_with_data: - cv.check_iterable_type('nuclide names', nuc_with_data, str) - available_cross_sections = nuc_with_data - else: - # select cross_sections.xml file to use - if mat_file.cross_sections: - this_library = DataLibrary.from_xml(path=mat_file.cross_sections) - else: - this_library = DataLibrary.from_xml() - - # Find neutron libraries we have access to - available_cross_sections = set() - for lib in this_library.libraries: - if lib['type'] == 'neutron': - available_cross_sections.update(lib['materials']) - if not available_cross_sections: - raise DataError('No neutron libraries found in cross_sections.xml') - - # Overwrite material definitions, if they can be found in the depletion - # results, and save them to the new depleted xml file. - for mat in mat_file: - mat_id = str(mat.id) - if mat_id in result.mat_to_ind: - mat.volume = result.volume[mat_id] - for nuc in result.nuc_to_ind: - if nuc not in available_cross_sections: - continue - atoms = result[0, mat_id, nuc] - if atoms > 0.0: - atoms_per_barn_cm = 1e-24 * atoms / mat.volume - mat.remove_nuclide(nuc) # Replace if it's there - mat.add_nuclide(nuc, atoms_per_barn_cm) - - return mat_file diff --git a/openmc/deplete/stepresult.py b/openmc/deplete/stepresult.py new file mode 100644 index 00000000000..9cf33898f3b --- /dev/null +++ b/openmc/deplete/stepresult.py @@ -0,0 +1,591 @@ +"""The stepresult module. + +Contains capabilities for generating and saving results of a single depletion +timestep. +""" + +import copy +import warnings +from pathlib import Path + +import h5py +import numpy as np + +import openmc +from openmc.mpi import comm, MPI +from openmc.checkvalue import PathLike +from .reaction_rates import ReactionRates + +VERSION_RESULTS = (1, 1) + + +__all__ = ["StepResult"] + + +class StepResult: + """Result of a single depletion timestep + + .. versionchanged:: 0.13.1 + Name changed from ``Results`` to ``StepResult`` + + Attributes + ---------- + k : list of (float, float) + Eigenvalue and uncertainty for each substep. + time : list of float + Time at beginning, end of step, in seconds. + source_rate : float + Source rate during timestep in [W] or [neutron/sec] + n_mat : int + Number of mats. + n_nuc : int + Number of nuclides. + rates : list of ReactionRates + The reaction rates for each substep. + volume : dict of str to float + Dictionary mapping mat id to volume. + index_mat : dict of str to int + A dictionary mapping mat ID as string to index. + index_nuc : dict of str to int + A dictionary mapping nuclide name as string to index. + mat_to_hdf5_ind : dict of str to int + A dictionary mapping mat ID as string to global index. + n_hdf5_mats : int + Number of materials in entire geometry. + n_stages : int + Number of stages in simulation. + data : numpy.ndarray + Atom quantity, stored by stage, mat, then by nuclide. + proc_time : int + Average time spent depleting a material across all + materials and processes + + """ + def __init__(self): + self.k = None + self.time = None + self.source_rate = None + self.rates = None + self.volume = None + self.proc_time = None + + self.index_mat = None + self.index_nuc = None + self.mat_to_hdf5_ind = None + + self.data = None + + def __repr__(self): + t = self.time[0] + dt = self.time[1] - self.time[0] + return f"" + + def __getitem__(self, pos): + """Retrieves an item from results. + + Parameters + ---------- + pos : tuple + A three-length tuple containing a stage index, mat index and a nuc + index. All can be integers or slices. The second two can be + strings corresponding to their respective dictionary. + + Returns + ------- + float + The atoms for stage, mat, nuc + + """ + stage, mat, nuc = pos + if isinstance(mat, openmc.Material): + mat = str(mat.id) + if isinstance(mat, str): + mat = self.index_mat[mat] + if isinstance(nuc, str): + nuc = self.index_nuc[nuc] + + return self.data[stage, mat, nuc] + + def __setitem__(self, pos, val): + """Sets an item from results. + + Parameters + ---------- + pos : tuple + A three-length tuple containing a stage index, mat index and a nuc + index. All can be integers or slices. The second two can be + strings corresponding to their respective dictionary. + + val : float + The value to set data to. + + """ + stage, mat, nuc = pos + if isinstance(mat, str): + mat = self.index_mat[mat] + if isinstance(nuc, str): + nuc = self.index_nuc[nuc] + + self.data[stage, mat, nuc] = val + + @property + def n_mat(self): + return len(self.index_mat) + + @property + def n_nuc(self): + return len(self.index_nuc) + + @property + def n_hdf5_mats(self): + return len(self.mat_to_hdf5_ind) + + @property + def n_stages(self): + return self.data.shape[0] + + def allocate(self, volume, nuc_list, burn_list, full_burn_list, stages): + """Allocate memory for depletion step data + + Parameters + ---------- + volume : dict of str float + Volumes corresponding to materials in full_burn_dict + nuc_list : list of str + A list of all nuclide names. Used for sorting the simulation. + burn_list : list of int + A list of all mat IDs to be burned. Used for sorting the simulation. + full_burn_list : list of str + List of all burnable material IDs + stages : int + Number of stages in simulation. + + """ + self.volume = copy.deepcopy(volume) + self.index_nuc = {nuc: i for i, nuc in enumerate(nuc_list)} + self.index_mat = {mat: i for i, mat in enumerate(burn_list)} + self.mat_to_hdf5_ind = {mat: i for i, mat in enumerate(full_burn_list)} + + # Create storage array + self.data = np.zeros((stages, self.n_mat, self.n_nuc)) + + def distribute(self, local_materials, ranges): + """Create a new object containing data for distributed materials + + Parameters + ---------- + local_materials : iterable of str + Materials for this process + ranges : iterable of int + Slice-like object indicating indicies of ``local_materials`` + in the material dimension of :attr:`data` and each element + in :attr:`rates` + + Returns + ------- + StepResult + New results object + """ + new = StepResult() + new.volume = {lm: self.volume[lm] for lm in local_materials} + new.index_mat = {mat: idx for (idx, mat) in enumerate(local_materials)} + + # Direct transfer + direct_attrs = ("time", "k", "source_rate", "index_nuc", + "mat_to_hdf5_ind", "proc_time") + for attr in direct_attrs: + setattr(new, attr, getattr(self, attr)) + # Get applicable slice of data + new.data = self.data[:, ranges] + new.rates = [r[ranges] for r in self.rates] + return new + + def get_material(self, mat_id): + """Return material object for given depleted composition + + .. versionadded:: 0.13.2 + + Parameters + ---------- + mat_id : str + Material ID as a string + + Returns + ------- + openmc.Material + Equivalent material + + Raises + ------ + KeyError + If specified material ID is not found in the StepResult + + """ + with warnings.catch_warnings(): + warnings.simplefilter('ignore', openmc.IDWarning) + material = openmc.Material(material_id=int(mat_id)) + try: + vol = self.volume[mat_id] + except KeyError as e: + raise KeyError( + f'mat_id {mat_id} not found in StepResult. Available mat_id ' + f'values are {list(self.volume.keys())}' + ) from e + for nuc, _ in sorted(self.index_nuc.items(), key=lambda x: x[1]): + atoms = self[0, mat_id, nuc] + if atoms < 0.0: + continue + atom_per_bcm = atoms / vol * 1e-24 + material.add_nuclide(nuc, atom_per_bcm) + material.volume = vol + return material + + def export_to_hdf5(self, filename, step): + """Export results to an HDF5 file + + Parameters + ---------- + filename : str + The filename to write to + step : int + What step is this? + + """ + # Write new file if first time step, else add to existing file + kwargs = {'mode': "w" if step == 0 else "a"} + + if h5py.get_config().mpi and comm.size > 1: + # Write results in parallel + kwargs['driver'] = 'mpio' + kwargs['comm'] = comm + with h5py.File(filename, **kwargs) as handle: + self._to_hdf5(handle, step, parallel=True) + else: + # Gather results at root process + all_results = comm.gather(self) + + # Only root process writes results + if comm.rank == 0: + with h5py.File(filename, **kwargs) as handle: + for res in all_results: + res._to_hdf5(handle, step, parallel=False) + + def _write_hdf5_metadata(self, handle): + """Writes result metadata in HDF5 file + + Parameters + ---------- + handle : h5py.File or h5py.Group + An hdf5 file or group type to store this in. + + """ + # Create and save the 5 dictionaries: + # quantities + # self.index_mat -> self.volume (TODO: support for changing volumes) + # self.index_nuc + # reactions + # self.rates[0].index_nuc (can be different from above, above is superset) + # self.rates[0].index_rx + # these are shared by every step of the simulation, and should be deduplicated. + + # Store concentration mat and nuclide dictionaries (along with volumes) + + handle.attrs['version'] = np.array(VERSION_RESULTS) + handle.attrs['filetype'] = np.bytes_('depletion results') + + mat_list = sorted(self.mat_to_hdf5_ind, key=int) + nuc_list = sorted(self.index_nuc) + rxn_list = sorted(self.rates[0].index_rx) + + n_mats = self.n_hdf5_mats + n_nuc_number = len(nuc_list) + n_nuc_rxn = len(self.rates[0].index_nuc) + n_rxn = len(rxn_list) + n_stages = self.n_stages + + mat_group = handle.create_group("materials") + + for mat in mat_list: + mat_single_group = mat_group.create_group(mat) + mat_single_group.attrs["index"] = self.mat_to_hdf5_ind[mat] + mat_single_group.attrs["volume"] = self.volume[mat] + + nuc_group = handle.create_group("nuclides") + + for nuc in nuc_list: + nuc_single_group = nuc_group.create_group(nuc) + nuc_single_group.attrs["atom number index"] = self.index_nuc[nuc] + if nuc in self.rates[0].index_nuc: + nuc_single_group.attrs["reaction rate index"] = self.rates[0].index_nuc[nuc] + + rxn_group = handle.create_group("reactions") + + for rxn in rxn_list: + rxn_single_group = rxn_group.create_group(rxn) + rxn_single_group.attrs["index"] = self.rates[0].index_rx[rxn] + + # Construct array storage + + handle.create_dataset("number", (1, n_stages, n_mats, n_nuc_number), + maxshape=(None, n_stages, n_mats, n_nuc_number), + chunks=(1, 1, n_mats, n_nuc_number), + dtype='float64') + + if n_nuc_rxn > 0 and n_rxn > 0: + handle.create_dataset("reaction rates", (1, n_stages, n_mats, n_nuc_rxn, n_rxn), + maxshape=(None, n_stages, n_mats, n_nuc_rxn, n_rxn), + chunks=(1, 1, n_mats, n_nuc_rxn, n_rxn), + dtype='float64') + + handle.create_dataset("eigenvalues", (1, n_stages, 2), + maxshape=(None, n_stages, 2), dtype='float64') + + handle.create_dataset("time", (1, 2), maxshape=(None, 2), dtype='float64') + + handle.create_dataset("source_rate", (1, n_stages), maxshape=(None, n_stages), + dtype='float64') + + handle.create_dataset( + "depletion time", (1,), maxshape=(None,), + dtype="float64") + + def _to_hdf5(self, handle, index, parallel=False): + """Converts results object into an hdf5 object. + + Parameters + ---------- + handle : h5py.File or h5py.Group + An HDF5 file or group type to store this in. + index : int + What step is this? + parallel : bool + Being called with parallel HDF5? + + """ + if "/number" not in handle: + if parallel: + comm.barrier() + self._write_hdf5_metadata(handle) + + if parallel: + comm.barrier() + + # Grab handles + number_dset = handle["/number"] + has_reactions = ("reaction rates" in handle) + if has_reactions: + rxn_dset = handle["/reaction rates"] + eigenvalues_dset = handle["/eigenvalues"] + time_dset = handle["/time"] + source_rate_dset = handle["/source_rate"] + proc_time_dset = handle["/depletion time"] + + # Get number of results stored + number_shape = list(number_dset.shape) + number_results = number_shape[0] + + new_shape = index + 1 + + if number_results < new_shape: + # Extend first dimension by 1 + number_shape[0] = new_shape + number_dset.resize(number_shape) + + if has_reactions: + rxn_shape = list(rxn_dset.shape) + rxn_shape[0] = new_shape + rxn_dset.resize(rxn_shape) + + eigenvalues_shape = list(eigenvalues_dset.shape) + eigenvalues_shape[0] = new_shape + eigenvalues_dset.resize(eigenvalues_shape) + + time_shape = list(time_dset.shape) + time_shape[0] = new_shape + time_dset.resize(time_shape) + + source_rate_shape = list(source_rate_dset.shape) + source_rate_shape[0] = new_shape + source_rate_dset.resize(source_rate_shape) + + proc_shape = list(proc_time_dset.shape) + proc_shape[0] = new_shape + proc_time_dset.resize(proc_shape) + + # If nothing to write, just return + if len(self.index_mat) == 0: + return + + # Add data + # Note, for the last step, self.n_stages = 1, even if n_stages != 1. + n_stages = self.n_stages + inds = [self.mat_to_hdf5_ind[mat] for mat in self.index_mat] + low = min(inds) + high = max(inds) + for i in range(n_stages): + number_dset[index, i, low:high+1] = self.data[i] + if has_reactions: + rxn_dset[index, i, low:high+1] = self.rates[i] + if comm.rank == 0: + eigenvalues_dset[index, i] = self.k[i] + if comm.rank == 0: + time_dset[index] = self.time + source_rate_dset[index] = self.source_rate + if self.proc_time is not None: + proc_time_dset[index] = ( + self.proc_time / (comm.size * self.n_hdf5_mats) + ) + + @classmethod + def from_hdf5(cls, handle, step): + """Loads results object from HDF5. + + Parameters + ---------- + handle : h5py.File or h5py.Group + An HDF5 file or group type to load from. + step : int + Index for depletion step + """ + results = cls() + + # Grab handles + number_dset = handle["/number"] + eigenvalues_dset = handle["/eigenvalues"] + time_dset = handle["/time"] + if "source_rate" in handle: + source_rate_dset = handle["/source_rate"] + else: + # Older versions used "power" instead of "source_rate" + source_rate_dset = handle["/power"] + + results.data = number_dset[step, :, :, :] + results.k = eigenvalues_dset[step, :] + results.time = time_dset[step, :] + results.source_rate = source_rate_dset[step, 0] + + if "depletion time" in handle: + proc_time_dset = handle["/depletion time"] + if step < proc_time_dset.shape[0]: + results.proc_time = proc_time_dset[step] + + if results.proc_time is None: + results.proc_time = np.array([np.nan]) + + # Reconstruct dictionaries + results.volume = {} + results.index_mat = {} + results.index_nuc = {} + rxn_nuc_to_ind = {} + rxn_to_ind = {} + + for mat, mat_handle in handle["/materials"].items(): + vol = mat_handle.attrs["volume"] + ind = mat_handle.attrs["index"] + + results.volume[mat] = vol + results.index_mat[mat] = ind + + for nuc, nuc_handle in handle["/nuclides"].items(): + ind_atom = nuc_handle.attrs["atom number index"] + results.index_nuc[nuc] = ind_atom + + if "reaction rate index" in nuc_handle.attrs: + rxn_nuc_to_ind[nuc] = nuc_handle.attrs["reaction rate index"] + + for rxn, rxn_handle in handle["/reactions"].items(): + rxn_to_ind[rxn] = rxn_handle.attrs["index"] + + results.rates = [] + # Reconstruct reactions + for i in range(results.n_stages): + rate = ReactionRates(results.index_mat, rxn_nuc_to_ind, rxn_to_ind, True) + + if "reaction rates" in handle: + rate[:] = handle["/reaction rates"][step, i, :, :, :] + results.rates.append(rate) + + return results + + @staticmethod + def save(op, x, op_results, t, source_rate, step_ind, proc_time=None, + path: PathLike = "depletion_results.h5"): + """Creates and writes depletion results to disk + + Parameters + ---------- + op : openmc.deplete.abc.TransportOperator + The operator used to generate these results. + x : list of list of numpy.array + The prior x vectors. Indexed [i][cell] using the above equation. + op_results : list of openmc.deplete.OperatorResult + Results of applying transport operator + t : list of float + Time indices. + source_rate : float + Source rate during time step in [W] or [neutron/sec] + step_ind : int + Step index. + proc_time : float or None + Total process time spent depleting materials. This may + be process-dependent and will be reduced across MPI + processes. + + path : PathLike + Path to file to write. Defaults to 'depletion_results.h5'. + + .. versionadded:: 0.14.0 + """ + # Get indexing terms + vol_dict, nuc_list, burn_list, full_burn_list = op.get_results_info() + + stages = len(x) + + # Create results + results = StepResult() + results.allocate(vol_dict, nuc_list, burn_list, full_burn_list, stages) + + n_mat = len(burn_list) + + for i in range(stages): + for mat_i in range(n_mat): + results[i, mat_i, :] = x[i][mat_i] + + ks = [] + for r in op_results: + if isinstance(r.k, type(None)): + ks += [(None, None)] + else: + ks += [(r.k.nominal_value, r.k.std_dev)] + results.k = ks + results.rates = [r.rates for r in op_results] + results.time = t + results.source_rate = source_rate + results.proc_time = proc_time + if results.proc_time is not None: + results.proc_time = comm.reduce(proc_time, op=MPI.SUM) + + if not Path(path).is_file(): + Path(path).parent.mkdir(parents=True, exist_ok=True) + results.export_to_hdf5(path, step_ind) + + def transfer_volumes(self, model): + """Transfers volumes from depletion results to geometry + + Parameters + ---------- + model : OpenMC model to be used in a depletion restart + calculation + + """ + + if not model.materials: + materials = openmc.Materials( + model.geometry.get_all_materials().values() + ) + else: + materials = model.materials + + for material in materials: + if material.depletable: + material.volume = self.volume[str(material.id)] diff --git a/openmc/deplete/transfer_rates.py b/openmc/deplete/transfer_rates.py new file mode 100644 index 00000000000..01c9b2e3534 --- /dev/null +++ b/openmc/deplete/transfer_rates.py @@ -0,0 +1,229 @@ +from numbers import Real +import re + +from openmc.checkvalue import check_type, check_value +from openmc import Material +from openmc.data import ELEMENT_SYMBOL + + +class TransferRates: + """Class for defining continuous removals and feeds. + + Molten Salt Reactors (MSRs) benefit from continuous reprocessing, + which removes fission products and feeds fresh fuel into the system. MSRs + inspired the development of this class. + + An instance of this class can be passed directly to an instance of one of + the :class:`openmc.deplete.Integrator` classes. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + operator : openmc.TransportOperator + Depletion operator + model : openmc.Model + OpenMC model containing materials and geometry. If using + :class:`openmc.deplete.CoupledOperator`, the model must also contain + a :class:`opnemc.Settings` object. + + Attributes + ---------- + burnable_mats : list of str + All burnable material IDs. + local_mats : list of str + All burnable material IDs being managed by a single process + transfer_rates : dict of str to dict + Container of transfer rates, components (elements and/or nuclides) and + destination material + index_transfer : Set of pair of str + Pair of strings needed to build final matrix (destination_material, mat) + """ + + def __init__(self, operator, model): + + self.materials = model.materials + self.burnable_mats = operator.burnable_mats + self.local_mats = operator.local_mats + + #initialize transfer rates container dict + self.transfer_rates = {mat: {} for mat in self.burnable_mats} + self.index_transfer = set() + + def _get_material_id(self, val): + """Helper method for getting material id from Material obj or name. + + Parameters + ---------- + val : openmc.Material or str or int representing material name/id + + Returns + ------- + material_id : str + + """ + if isinstance(val, Material): + check_value('Depeletable Material', str(val.id), self.burnable_mats) + val = val.id + + elif isinstance(val, str): + if val.isnumeric(): + check_value('Material ID', str(val), self.burnable_mats) + else: + check_value('Material name', val, + [mat.name for mat in self.materials if mat.depletable]) + val = [mat.id for mat in self.materials if mat.name == val][0] + + elif isinstance(val, int): + check_value('Material ID', str(val), self.burnable_mats) + + return str(val) + + def get_transfer_rate(self, material, component): + """Return transfer rate for given material and element. + + Parameters + ---------- + material : openmc.Material or str or int + Depletable material + component : str + Element or nuclide to get transfer rate value + + Returns + ------- + transfer_rate : list of floats + Transfer rate values + + """ + material_id = self._get_material_id(material) + check_type('component', component, str) + return [i[0] for i in self.transfer_rates[material_id][component]] + + def get_destination_material(self, material, component): + """Return destination material for given material and + component, if defined. + + Parameters + ---------- + material : openmc.Material or str or int + Depletable material + component : str + Element or nuclide that gets transferred to another material. + + Returns + ------- + destination_material_id : list of str + Depletable material ID to where the element or nuclide gets + transferred + + """ + material_id = self._get_material_id(material) + check_type('component', component, str) + if component in self.transfer_rates[material_id]: + return [i[1] for i in self.transfer_rates[material_id][component]] + else: + return [] + + def get_components(self, material): + """Extract removing elements and/or nuclides for a given material + + Parameters + ---------- + material : openmc.Material or str or int + Depletable material + + Returns + ------- + elements : list + List of elements and nuclides where transfer rates exist + + """ + material_id = self._get_material_id(material) + if material_id in self.transfer_rates: + return self.transfer_rates[material_id].keys() + + def set_transfer_rate(self, material, components, transfer_rate, + transfer_rate_units='1/s', destination_material=None): + """Set element and/or nuclide transfer rates in a depletable material. + + Parameters + ---------- + material : openmc.Material or str or int + Depletable material + components : list of str + List of strings of elements and/or nuclides that share transfer rate. + Cannot add transfer rates for nuclides to a material where a + transfer rate for its element is specified and vice versa. + transfer_rate : float + Rate at which elements and/or nuclides are transferred. A positive or + negative value corresponds to a removal or feed rate, respectively. + destination_material : openmc.Material or str or int, Optional + Destination material to where nuclides get fed. + transfer_rate_units : {'1/s', '1/min', '1/h', '1/d', '1/a'} + Units for values specified in the transfer_rate argument. 's' for + seconds, 'min' for minutes, 'h' for hours, 'a' for Julian years. + + """ + material_id = self._get_material_id(material) + check_type('transfer_rate', transfer_rate, Real) + check_type('components', components, list, expected_iter_type=str) + + if destination_material is not None: + destination_material_id = self._get_material_id(destination_material) + if len(self.burnable_mats) > 1: + check_value('destination_material', str(destination_material_id), + self.burnable_mats) + else: + raise ValueError('Transfer to material ' + f'{destination_material_id} is set, but there ' + 'is only one depletable material') + else: + destination_material_id = None + + if transfer_rate_units in ('1/s', '1/sec'): + unit_conv = 1 + elif transfer_rate_units in ('1/min', '1/minute'): + unit_conv = 60 + elif transfer_rate_units in ('1/h', '1/hr', '1/hour'): + unit_conv = 60*60 + elif transfer_rate_units in ('1/d', '1/day'): + unit_conv = 24*60*60 + elif transfer_rate_units in ('1/a', '1/year'): + unit_conv = 365.25*24*60*60 + else: + raise ValueError('Invalid transfer rate unit ' + f'"{transfer_rate_units}"') + + for component in components: + current_components = self.transfer_rates[material_id].keys() + split_component = re.split(r'\d+', component) + element = split_component[0] + if element not in ELEMENT_SYMBOL.values(): + raise ValueError(f'{component} is not a valid nuclide or ' + 'element.') + else: + if len(split_component) == 1: + element_nucs = [c for c in current_components + if re.match(component + r'\d', c)] + if len(element_nucs) > 0: + nuc_str = ", ".join(element_nucs) + raise ValueError('Cannot add transfer rate for element ' + f'{component} to material {material_id} ' + f'with transfer rate(s) for nuclide(s) ' + f'{nuc_str}.') + + else: + if element in current_components: + raise ValueError('Cannot add transfer rate for nuclide ' + f'{component} to material {material_id} ' + f'where element {element} already has ' + 'a transfer rate.') + + if component in self.transfer_rates[material_id]: + self.transfer_rates[material_id][component].append( + (transfer_rate / unit_conv, destination_material_id)) + else: + self.transfer_rates[material_id][component] = [ + (transfer_rate / unit_conv, destination_material_id)] + if destination_material_id is not None: + self.index_transfer.add((destination_material_id, material_id)) diff --git a/openmc/deplete/dummy_comm.py b/openmc/dummy_comm.py similarity index 100% rename from openmc/deplete/dummy_comm.py rename to openmc/dummy_comm.py diff --git a/openmc/element.py b/openmc/element.py index 2eacaf867d0..082bee5226d 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -1,10 +1,11 @@ -from collections import OrderedDict -import os import re -from xml.etree import ElementTree as ET +import warnings + +import lxml.etree as ET import openmc.checkvalue as cv -from openmc.data import NATURAL_ABUNDANCE, atomic_mass, \ +import openmc +from openmc.data import NATURAL_ABUNDANCE, atomic_mass, zam, \ isotopes as natural_isotopes @@ -40,10 +41,10 @@ def expand(self, percent, percent_type, enrichment=None, cross_sections=None): """Expand natural element into its naturally-occurring isotopes. - An optional cross_sections argument or the :envvar:`OPENMC_CROSS_SECTIONS` - environment variable is used to specify a cross_sections.xml file. - If the cross_sections.xml file is found, the element is expanded only - into the isotopes/nuclides present in cross_sections.xml. If no + An optional cross_sections argument or the ``cross_sections`` + configuration value is used to specify a cross_sections.xml file. If the + cross_sections.xml file is found, the element is expanded only into the + isotopes/nuclides present in cross_sections.xml. If no cross_sections.xml file is found, the element is expanded based on its naturally occurring isotopes. @@ -54,12 +55,13 @@ def expand(self, percent, percent_type, enrichment=None, percent_type : {'ao', 'wo'} 'ao' for atom percent and 'wo' for weight percent enrichment : float, optional - Enrichment of an enrichment_taget nuclide in percent (ao or wo). - If enrichment_taget is not supplied then it is enrichment for U235 - in weight percent. For example, input 4.95 for 4.95 weight percent + Enrichment of an enrichment_target nuclide in percent (ao or wo). If + enrichment_target is not supplied then it is enrichment for U235 in + weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). enrichment_target: str, optional - Single nuclide name to enrich from a natural composition (e.g., 'O16') + Single nuclide name to enrich from a natural composition (e.g., + 'O16') .. versionadded:: 0.12 enrichment_type: {'ao', 'wo'}, optional @@ -82,8 +84,8 @@ def expand(self, percent, percent_type, enrichment=None, ValueError No data is available for any of natural isotopes of the element ValueError - If only some natural isotopes are available in the cross-section data - library and the element is not O, W, or Ta + If only some natural isotopes are available in the cross-section + data library and the element is not O, W, or Ta ValueError If a non-naturally-occurring isotope is requested ValueError @@ -101,8 +103,8 @@ def expand(self, percent, percent_type, enrichment=None, `ORNL/CSD/TM-244 `_ is used to calculate the weight fractions of U234, U235, U236, and U238. Namely, the weight fraction of U234 and U236 are taken to be 0.89% and 0.46%, - respectively, of the U235 weight fraction. The remainder of the - isotopic weight is assigned to U238. + respectively, of the U235 weight fraction. The remainder of the isotopic + weight is assigned to U238. When the `enrichment` argument is specified with `enrichment_target`, a general enrichment procedure is used for elements composed of exactly @@ -122,13 +124,17 @@ def expand(self, percent, percent_type, enrichment=None, # Get the nuclides present in nature natural_nuclides = {name for name, abundance in natural_isotopes(self)} + # Issue warning if no existing nuclides + if len(natural_nuclides) == 0: + warnings.warn(f"No naturally occurring isotopes found for {self}.") + # Create dict to store the expanded nuclides and abundances - abundances = OrderedDict() + abundances = {} - # If cross_sections is None, get the cross sections from the - # OPENMC_CROSS_SECTIONS environment variable + # If cross_sections is None, get the cross sections from the global + # configuration if cross_sections is None: - cross_sections = os.environ.get('OPENMC_CROSS_SECTIONS') + cross_sections = openmc.config.get('cross_sections') # If a cross_sections library is present, check natural nuclides # against the nuclides in the library @@ -146,10 +152,10 @@ def expand(self, percent, percent_type, enrichment=None, # and sort to avoid different ordering between Python 2 and 3. mutual_nuclides = natural_nuclides.intersection(library_nuclides) absent_nuclides = natural_nuclides.difference(mutual_nuclides) - mutual_nuclides = sorted(list(mutual_nuclides)) - absent_nuclides = sorted(list(absent_nuclides)) + mutual_nuclides = sorted(mutual_nuclides, key=zam) + absent_nuclides = sorted(absent_nuclides, key=zam) - # If all naturally ocurring isotopes are present in the library, + # If all naturally occurring isotopes are present in the library, # add them based on their abundance if len(absent_nuclides) == 0: for nuclide in mutual_nuclides: @@ -162,10 +168,9 @@ def expand(self, percent, percent_type, enrichment=None, abundances[self + '0'] = 1.0 elif len(mutual_nuclides) == 0: - msg = ('Unable to expand element {} because the cross ' + msg = (f'Unable to expand element {self} because the cross ' 'section library provided does not contain any of ' - 'the natural isotopes for that element.' - .format(self)) + 'the natural isotopes for that element.') raise ValueError(msg) # If some naturally occurring isotopes are in the library, add them. @@ -195,7 +200,7 @@ def expand(self, percent, percent_type, enrichment=None, # If a cross_section library is not present, expand the element into # its natural nuclides else: - for nuclide in natural_nuclides: + for nuclide in sorted(natural_nuclides, key=zam): abundances[nuclide] = NATURAL_ABUNDANCE[nuclide] # Modify mole fractions if enrichment provided @@ -205,7 +210,7 @@ def expand(self, percent, percent_type, enrichment=None, # Check that the element is Uranium if self.name != 'U': msg = ('Enrichment procedure for Uranium was requested, ' - 'but the isotope is {} not U'.format(self)) + f'but the isotope is {self} not U') raise ValueError(msg) # Check that enrichment_type is not 'ao' @@ -243,9 +248,8 @@ def expand(self, percent, percent_type, enrichment=None, # Check if it is two-isotope mixture if len(abundances) != 2: - msg = ('Element {} does not consist of two naturally-occurring ' - 'isotopes. Please enter isotopic abundances manually.' - .format(self)) + msg = (f'Element {self} does not consist of two naturally-occurring ' + 'isotopes. Please enter isotopic abundances manually.') raise ValueError(msg) # Check if the target nuclide is present in the mixture @@ -279,7 +283,7 @@ def expand(self, percent, percent_type, enrichment=None, tail_fraction = 1.0 - enrichment / 100.0 # Enrich all nuclides - # Do bogus operation for enrichment target but overwrite immediatly + # Do bogus operation for enrichment target but overwrite immediately # to avoid if statement in the loop for nuclide, fraction in abundances.items(): abundances[nuclide] = tail_fraction * fraction / non_enriched diff --git a/openmc/examples.py b/openmc/examples.py index 3b73d043ffc..fc94b8b528e 100644 --- a/openmc/examples.py +++ b/openmc/examples.py @@ -76,8 +76,10 @@ def pwr_pin_cell(): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( - [-pitch/2, -pitch/2, -1], [pitch/2, pitch/2, 1], only_fissionable=True)) + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Box([-pitch/2, -pitch/2, -1], [pitch/2, pitch/2, 1]), + constraints={'fissionable': True} + ) plot = openmc.Plot.from_geometry(model.geometry) plot.pixels = (300, 300) @@ -415,7 +417,7 @@ def pwr_core(): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-160, -160, -183], [160, 160, 183])) plot = openmc.Plot() @@ -527,8 +529,10 @@ def pwr_assembly(): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( - [-pitch/2, -pitch/2, -1], [pitch/2, pitch/2, 1], only_fissionable=True)) + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Box([-pitch/2, -pitch/2, -1], [pitch/2, pitch/2, 1]), + constraints={'fissionable': True} + ) plot = openmc.Plot() plot.origin = (0.0, 0.0, 0) @@ -629,7 +633,7 @@ def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5'): INF = 1000. bounds = [0., -INF, -INF, rads[0], INF, INF] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.source = openmc.source.Source(space=uniform_dist) + settings_file.source = openmc.IndependentSource(space=uniform_dist) settings_file.output = {'summary': False} diff --git a/openmc/executor.py b/openmc/executor.py index 008290c1818..aacc48b3fac 100644 --- a/openmc/executor.py +++ b/openmc/executor.py @@ -1,8 +1,95 @@ from collections.abc import Iterable from numbers import Integral +import os import subprocess import openmc +from .plots import _get_plot_image + + +def _process_CLI_arguments(volume=False, geometry_debug=False, particles=None, + plot=False, restart_file=None, threads=None, + tracks=False, event_based=None, + openmc_exec='openmc', mpi_args=None, path_input=None): + """Converts user-readable flags in to command-line arguments to be run with + the OpenMC executable via subprocess. + + Parameters + ---------- + volume : bool, optional + Run in stochastic volume calculation mode. Defaults to False. + geometry_debug : bool, optional + Turn on geometry debugging during simulation. Defaults to False. + particles : int, optional + Number of particles to simulate per generation. + plot : bool, optional + Run in plotting mode. Defaults to False. + restart_file : str or PathLike + Path to restart file to use + threads : int, optional + Number of OpenMP threads. If OpenMC is compiled with OpenMP threading + enabled, the default is implementation-dependent but is usually equal + to the number of hardware threads available (or a value set by the + :envvar:`OMP_NUM_THREADS` environment variable). + tracks : bool, optional + Enables the writing of particles tracks. The number of particle + tracks written to tracks.h5 is limited to 1000 unless + Settings.max_tracks is set. Defaults to False. + event_based : None or bool, optional + Turns on event-based parallelism if True. If None, the value in + the Settings will be used. + openmc_exec : str, optional + Path to OpenMC executable. Defaults to 'openmc'. + mpi_args : list of str, optional + MPI execute command and any additional MPI arguments to pass, + e.g., ['mpiexec', '-n', '8']. + path_input : str or PathLike + Path to a single XML file or a directory containing XML files for the + OpenMC executable to read. + + .. versionadded:: 0.13.0 + + Returns + ------- + args : Iterable of str + The runtime flags converted to CLI arguments of the OpenMC executable + + """ + + args = [openmc_exec] + + if volume: + args.append('--volume') + + if isinstance(particles, Integral) and particles > 0: + args += ['-n', str(particles)] + + if isinstance(threads, Integral) and threads > 0: + args += ['-s', str(threads)] + + if geometry_debug: + args.append('-g') + + if event_based is not None: + if event_based: + args.append('-e') + + if isinstance(restart_file, (str, os.PathLike)): + args += ['-r', str(restart_file)] + + if tracks: + args.append('-t') + + if plot: + args.append('-p') + + if mpi_args is not None: + args = mpi_args + args + + if path_input is not None: + args += [path_input] + + return args def _run(args, output, cwd): @@ -38,7 +125,7 @@ def _run(args, output, cwd): raise RuntimeError(error_msg) -def plot_geometry(output=True, openmc_exec='openmc', cwd='.'): +def plot_geometry(output=True, openmc_exec='openmc', cwd='.', path_input=None): """Run OpenMC in plotting mode Parameters @@ -49,6 +136,11 @@ def plot_geometry(output=True, openmc_exec='openmc', cwd='.'): Path to OpenMC executable cwd : str, optional Path to working directory to run in + path_input : str + Path to a single XML file or a directory containing XML files for the + OpenMC executable to read. + + .. versionadded:: 0.13.3 Raises ------ @@ -56,15 +148,19 @@ def plot_geometry(output=True, openmc_exec='openmc', cwd='.'): If the `openmc` executable returns a non-zero status """ - _run([openmc_exec, '-p'], output, cwd) + args = [openmc_exec, '-p'] + if path_input is not None: + args += [path_input] + _run(args, output, cwd) -def plot_inline(plots, openmc_exec='openmc', cwd='.', convert_exec='convert'): +def plot_inline(plots, openmc_exec='openmc', cwd='.', path_input=None): """Display plots inline in a Jupyter notebook. - This function requires that you have a program installed to convert PPM - files to PNG files. Typically, that would be `ImageMagick - `_ which includes a `convert` command. + .. versionchanged:: 0.13.0 + The *convert_exec* argument was removed since OpenMC now produces + .png images directly. + Parameters ---------- @@ -74,8 +170,11 @@ def plot_inline(plots, openmc_exec='openmc', cwd='.', convert_exec='convert'): Path to OpenMC executable cwd : str, optional Path to working directory to run in - convert_exec : str, optional - Command that can convert PPM files into PNG files + path_input : str + Path to a single XML file or a directory containing XML files for the + OpenMC executable to read. + + .. versionadded:: 0.13.3 Raises ------ @@ -83,32 +182,25 @@ def plot_inline(plots, openmc_exec='openmc', cwd='.', convert_exec='convert'): If the `openmc` executable returns a non-zero status """ - from IPython.display import Image, display + from IPython.display import display if not isinstance(plots, Iterable): plots = [plots] # Create plots.xml - openmc.Plots(plots).export_to_xml() + openmc.Plots(plots).export_to_xml(cwd) # Run OpenMC in geometry plotting mode - plot_geometry(False, openmc_exec, cwd) + plot_geometry(False, openmc_exec, cwd, path_input) - images = [] if plots is not None: - for p in plots: - if p.filename is not None: - ppm_file = '{}.ppm'.format(p.filename) - else: - ppm_file = 'plot_{}.ppm'.format(p.id) - png_file = ppm_file.replace('.ppm', '.png') - subprocess.check_call([convert_exec, ppm_file, png_file]) - images.append(Image(png_file)) + images = [_get_plot_image(p, cwd) for p in plots] display(*images) def calculate_volumes(threads=None, output=True, cwd='.', - openmc_exec='openmc', mpi_args=None): + openmc_exec='openmc', mpi_args=None, + path_input=None): """Run stochastic volume calculations in OpenMC. This function runs OpenMC in stochastic volume calculation mode. To specify @@ -126,8 +218,8 @@ def calculate_volumes(threads=None, output=True, cwd='.', ---------- threads : int, optional Number of OpenMP threads. If OpenMC is compiled with OpenMP threading - enabled, the default is implementation-dependent but is usually equal to - the number of hardware threads available (or a value set by the + enabled, the default is implementation-dependent but is usually equal + to the number of hardware threads available (or a value set by the :envvar:`OMP_NUM_THREADS` environment variable). output : bool, optional Capture OpenMC output from standard out @@ -135,10 +227,14 @@ def calculate_volumes(threads=None, output=True, cwd='.', Path to OpenMC executable. Defaults to 'openmc'. mpi_args : list of str, optional MPI execute command and any additional MPI arguments to pass, - e.g. ['mpiexec', '-n', '8']. + e.g., ['mpiexec', '-n', '8']. cwd : str, optional Path to working directory to run in. Defaults to the current working directory. + path_input : str or PathLike + Path to a single XML file or a directory containing XML files for the + OpenMC executable to read. + Raises ------ @@ -150,19 +246,18 @@ def calculate_volumes(threads=None, output=True, cwd='.', openmc.VolumeCalculation """ - args = [openmc_exec, '--volume'] - if isinstance(threads, Integral) and threads > 0: - args += ['-s', str(threads)] - if mpi_args is not None: - args = mpi_args + args + args = _process_CLI_arguments(volume=True, threads=threads, + openmc_exec=openmc_exec, mpi_args=mpi_args, + path_input=path_input) _run(args, output, cwd) def run(particles=None, threads=None, geometry_debug=False, restart_file=None, tracks=False, output=True, cwd='.', - openmc_exec='openmc', mpi_args=None, event_based=False): + openmc_exec='openmc', mpi_args=None, event_based=False, + path_input=None): """Run an OpenMC simulation. Parameters @@ -176,10 +271,12 @@ def run(particles=None, threads=None, geometry_debug=False, :envvar:`OMP_NUM_THREADS` environment variable). geometry_debug : bool, optional Turn on geometry debugging during simulation. Defaults to False. - restart_file : str, optional + restart_file : str or PathLike Path to restart file to use tracks : bool, optional - Write tracks for all particles. Defaults to False. + Enables the writing of particles tracks. The number of particle tracks + written to tracks.h5 is limited to 1000 unless Settings.max_tracks is + set. Defaults to False. output : bool Capture OpenMC output from standard out cwd : str, optional @@ -188,40 +285,30 @@ def run(particles=None, threads=None, geometry_debug=False, openmc_exec : str, optional Path to OpenMC executable. Defaults to 'openmc'. mpi_args : list of str, optional - MPI execute command and any additional MPI arguments to pass, - e.g. ['mpiexec', '-n', '8']. + MPI execute command and any additional MPI arguments to pass, e.g., + ['mpiexec', '-n', '8']. event_based : bool, optional Turns on event-based parallelism, instead of default history-based .. versionadded:: 0.12 + path_input : str or PathLike + Path to a single XML file or a directory containing XML files for the + OpenMC executable to read. + + .. versionadded:: 0.13.3 + Raises ------ RuntimeError If the `openmc` executable returns a non-zero status """ - args = [openmc_exec] - - if isinstance(particles, Integral) and particles > 0: - args += ['-n', str(particles)] - if isinstance(threads, Integral) and threads > 0: - args += ['-s', str(threads)] - - if geometry_debug: - args.append('-g') - - if event_based: - args.append('-e') - - if isinstance(restart_file, str): - args += ['-r', restart_file] - - if tracks: - args.append('-t') - - if mpi_args is not None: - args = mpi_args + args + args = _process_CLI_arguments( + volume=False, geometry_debug=geometry_debug, particles=particles, + restart_file=restart_file, threads=threads, tracks=tracks, + event_based=event_based, openmc_exec=openmc_exec, mpi_args=mpi_args, + path_input=path_input) _run(args, output, cwd) diff --git a/openmc/filter.py b/openmc/filter.py index e0cedd6bf24..e005140eeb3 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -1,11 +1,12 @@ +from __future__ import annotations from abc import ABCMeta -from collections import OrderedDict from collections.abc import Iterable import hashlib from itertools import product from numbers import Real, Integral -from xml.etree import ElementTree as ET +import warnings +import lxml.etree as ET import numpy as np import pandas as pd @@ -15,15 +16,16 @@ from .material import Material from .mixin import IDManagerMixin from .surface import Surface -from .universe import Universe +from .universe import UniverseBase +from ._xml import get_text _FILTER_TYPES = ( 'universe', 'material', 'cell', 'cellborn', 'surface', 'mesh', 'energy', 'energyout', 'mu', 'polar', 'azimuthal', 'distribcell', 'delayedgroup', - 'energyfunction', 'cellfrom', 'legendre', 'spatiallegendre', + 'energyfunction', 'cellfrom', 'materialfrom', 'legendre', 'spatiallegendre', 'sphericalharmonics', 'zernike', 'zernikeradial', 'particle', 'cellinstance', - 'collision' + 'collision', 'time' ) _CURRENT_NAMES = ( @@ -88,7 +90,7 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): ---------- bins : Integral or Iterable of Integral or Iterable of Real The bins for the filter. This takes on different meaning for different - filters. See the docstrings for sublcasses of this filter or the online + filters. See the docstrings for subclasses of this filter or the online documentation for more details. filter_id : int Unique identifier for the filter @@ -101,6 +103,8 @@ class Filter(IDManagerMixin, metaclass=FilterMeta): Unique identifier for the filter num_bins : Integral The number of filter bins + shape : tuple + The shape of the filter """ @@ -176,7 +180,7 @@ def from_hdf5(cls, group, **kwargs): filter_id = int(group.name.split('/')[-1].lstrip('filter ')) # If the HDF5 'type' variable matches this class's short_name, then - # there is no overriden from_hdf5 method. Pass the bins to __init__. + # there is no overridden from_hdf5 method. Pass the bins to __init__. if group['type'][()].decode() == cls.short_name.lower(): out = cls(group['bins'][()], filter_id=filter_id) out._num_bins = group['n_bins'][()] @@ -204,6 +208,10 @@ def bins(self, bins): def num_bins(self): return len(self.bins) + @property + def shape(self): + return (self.num_bins,) + def check_bins(self, bins): """Make sure given bins are valid for this filter. @@ -221,7 +229,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ @@ -231,9 +239,45 @@ def to_xml_element(self): subelement = ET.SubElement(element, 'bins') subelement.text = ' '.join(str(b) for b in self.bins) - return element + @classmethod + def from_xml_element(cls, elem, **kwargs): + """Generate a filter from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + **kwargs + Keyword arguments (e.g., mesh information) + + Returns + ------- + openmc.Filter + Filter object + + """ + filter_type = elem.get('type') + if filter_type is None: + filter_type = elem.find('type').text + + # If the filter type matches this class's short_name, then + # there is no overridden from_xml_element method + if filter_type == cls.short_name.lower(): + # Get bins from element -- the default here works for any filters + # that just store a list of bins that can be represented as integers + filter_id = int(elem.get('id')) + bins = [int(x) for x in get_text(elem, 'bins').split()] + return cls(bins, filter_id=filter_id) + + # Search through all subclasses and find the one matching the HDF5 + # 'type'. Call that class's from_hdf5 method + for subclass in cls._recursive_subclasses(): + if filter_type == subclass.short_name.lower(): + return subclass.from_xml_element(elem, **kwargs) + + def can_merge(self, other): """Determine if filter can be merged with another. @@ -266,8 +310,7 @@ def merge(self, other): """ if not self.can_merge(other): - msg = 'Unable to merge "{0}" with "{1}" '.format( - type(self), type(other)) + msg = f'Unable to merge "{type(self)}" with "{type(other)}"' raise ValueError(msg) # Merge unique filter bins @@ -326,8 +369,8 @@ def get_bin_index(self, filter_bin): """ if filter_bin not in self.bins: - msg = 'Unable to get the bin index for Filter since "{0}" ' \ - 'is not one of the bins'.format(filter_bin) + msg = ('Unable to get the bin index for Filter since ' + f'"{filter_bin}" is not one of the bins') raise ValueError(msg) if isinstance(self.bins, np.ndarray): @@ -404,12 +447,12 @@ def check_bins(self, bins): class UniverseFilter(WithIDFilter): - """Bins tally event locations based on the Universe they occured in. + """Bins tally event locations based on the Universe they occurred in. Parameters ---------- - bins : openmc.Universe, int, or iterable thereof - The Universes to tally. Either openmc.Universe objects or their + bins : openmc.UniverseBase, int, or iterable thereof + The Universes to tally. Either :class:`openmc.UniverseBase` objects or their Integral ID numbers can be used. filter_id : int Unique identifier for the filter @@ -417,23 +460,47 @@ class UniverseFilter(WithIDFilter): Attributes ---------- bins : Iterable of Integral - openmc.Universe IDs. + openmc.UniverseBase IDs. id : int Unique identifier for the filter num_bins : Integral The number of filter bins """ - expected_type = Universe + expected_type = UniverseBase class MaterialFilter(WithIDFilter): - """Bins tally event locations based on the Material they occured in. + """Bins tally event locations based on the Material they occurred in. + + Parameters + ---------- + bins : openmc.Material, Integral, or iterable thereof + The material(s) to tally. Either :class:`openmc.Material` objects or their + Integral ID numbers can be used. + filter_id : int + Unique identifier for the filter + + Attributes + ---------- + bins : Iterable of Integral + openmc.Material IDs. + id : int + Unique identifier for the filter + num_bins : Integral + The number of filter bins + + """ + expected_type = Material + + +class MaterialFromFilter(WithIDFilter): + """Bins tally event locations based on the Material they occurred in. Parameters ---------- bins : openmc.Material, Integral, or iterable thereof - The Materials to tally. Either openmc.Material objects or their + The material(s) to tally. Either :class:`openmc.Material` objects or their Integral ID numbers can be used. filter_id : int Unique identifier for the filter @@ -452,12 +519,12 @@ class MaterialFilter(WithIDFilter): class CellFilter(WithIDFilter): - """Bins tally event locations based on the Cell they occured in. + """Bins tally event locations based on the Cell they occurred in. Parameters ---------- bins : openmc.Cell, int, or iterable thereof - The cells to tally. Either openmc.Cell objects or their ID numbers can + The cells to tally. Either :class:`openmc.Cell` objects or their ID numbers can be used. filter_id : int Unique identifier for the filter @@ -476,20 +543,20 @@ class CellFilter(WithIDFilter): class CellFromFilter(WithIDFilter): - """Bins tally on which Cell the neutron came from. + """Bins tally on which cell the particle came from. Parameters ---------- bins : openmc.Cell, Integral, or iterable thereof - The Cell(s) to tally. Either openmc.Cell objects or their - Integral ID numbers can be used. + The cell(s) to tally. Either :class:`openmc.Cell` objects or their + integral ID numbers can be used. filter_id : int Unique identifier for the filter Attributes ---------- bins : Integral or Iterable of Integral - openmc.Cell IDs. + Cell IDs. id : int Unique identifier for the filter num_bins : Integral @@ -499,21 +566,21 @@ class CellFromFilter(WithIDFilter): expected_type = Cell -class CellbornFilter(WithIDFilter): - """Bins tally events based on which Cell the neutron was born in. +class CellBornFilter(WithIDFilter): + """Bins tally events based on which cell the particle was born in. Parameters ---------- bins : openmc.Cell, Integral, or iterable thereof - The birth Cells to tally. Either openmc.Cell objects or their - Integral ID numbers can be used. + The birth cells to tally. Either :class:`openmc.Cell` objects or their + integral ID numbers can be used. filter_id : int Unique identifier for the filter Attributes ---------- bins : Iterable of Integral - openmc.Cell IDs. + Cell IDs. id : int Unique identifier for the filter num_bins : Integral @@ -523,6 +590,14 @@ class CellbornFilter(WithIDFilter): expected_type = Cell +# Temporary alias for CellbornFilter +def CellbornFilter(*args, **kwargs): + warnings.warn('The name of "CellbornFilter" has changed to ' + '"CellBornFilter". "CellbornFilter" will be ' + 'removed in the future.', FutureWarning) + return CellBornFilter(*args, **kwargs) + + class CellInstanceFilter(Filter): """Bins tally events based on which cell instance a particle is in. @@ -538,7 +613,7 @@ class CellInstanceFilter(Filter): bins : iterable of 2-tuples or numpy.ndarray The cell instances to tally, given as 2-tuples. For the first value in the tuple, either openmc.Cell objects or their integral ID numbers can - be used. + be used. The second value indicates the cell instance. filter_id : int Unique identifier for the filter @@ -611,7 +686,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ @@ -623,6 +698,13 @@ def to_xml_element(self): subelement.text = ' '.join(str(i) for i in self.bins.ravel()) return element + @classmethod + def from_xml_element(cls, elem, **kwargs): + filter_id = int(elem.get('id')) + bins = [int(x) for x in get_text(elem, 'bins').split()] + cell_instances = list(zip(bins[::2], bins[1::2])) + return cls(cell_instances, filter_id=filter_id) + class SurfaceFilter(WithIDFilter): """Filters particles by surface crossing @@ -662,8 +744,8 @@ class ParticleFilter(Filter): Attributes ---------- - bins : Iterable of Integral - The Particles to tally + bins : iterable of str + The particles to tally id : int Unique identifier for the filter num_bins : Integral @@ -699,9 +781,15 @@ def from_hdf5(cls, group, **kwargs): filter_id = int(group.name.split('/')[-1].lstrip('filter ')) return cls(particles, filter_id=filter_id) + @classmethod + def from_xml_element(cls, elem, **kwargs): + filter_id = int(elem.get('id')) + bins = get_text(elem, 'bins').split() + return cls(bins, filter_id=filter_id) + class MeshFilter(Filter): - """Bins tally event locations onto a regular, rectangular mesh. + """Bins tally event locations by mesh elements. Parameters ---------- @@ -717,8 +805,8 @@ class MeshFilter(Filter): id : int Unique identifier for the filter translation : Iterable of float - This array specifies a vector that is used to translate (shift) - the mesh for this filter + This array specifies a vector that is used to translate (shift) the mesh + for this filter bins : list of tuple A list of mesh indices for each filter bin, e.g. [(1, 1, 1), (2, 1, 1), ...] @@ -759,7 +847,6 @@ def from_hdf5(cls, group, **kwargs): mesh_obj = kwargs['meshes'][mesh_id] filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - out = cls(mesh_obj, filter_id=filter_id) translation = group.get('translation') @@ -777,13 +864,19 @@ def mesh(self, mesh): cv.check_type('filter mesh', mesh, openmc.MeshBase) self._mesh = mesh if isinstance(mesh, openmc.UnstructuredMesh): - if mesh.volumes is None: - self.bins = [] - else: + if mesh.has_statepoint_data: self.bins = list(range(len(mesh.volumes))) + else: + self.bins = [] else: self.bins = list(mesh.indices) + @property + def shape(self): + if isinstance(self, MeshSurfaceFilter): + return (self.num_bins,) + return self.mesh.dimension + @property def translation(self): return self._translation @@ -833,7 +926,7 @@ def get_pandas_dataframe(self, data_size, stride, **kwargs): filter_dict = {} # Append mesh ID as outermost index of multi-index - mesh_key = 'mesh {}'.format(self.mesh.id) + mesh_key = f'mesh {self.mesh.id}' # Find mesh dimensions - use 3D indices for simplicity n_dim = len(self.mesh.dimension) @@ -868,7 +961,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ @@ -878,9 +971,49 @@ def to_xml_element(self): element.set('translation', ' '.join(map(str, self.translation))) return element + @classmethod + def from_xml_element(cls, elem: ET.Element, **kwargs) -> MeshFilter: + mesh_id = int(get_text(elem, 'bins')) + mesh_obj = kwargs['meshes'][mesh_id] + filter_id = int(elem.get('id')) + out = cls(mesh_obj, filter_id=filter_id) + + translation = elem.get('translation') + if translation: + out.translation = [float(x) for x in translation.split()] + return out + + +class MeshBornFilter(MeshFilter): + """Filter events by the mesh cell a particle originated from. + + Parameters + ---------- + mesh : openmc.MeshBase + The mesh object that events will be tallied onto + filter_id : int + Unique identifier for the filter + + Attributes + ---------- + mesh : openmc.MeshBase + The mesh object that events will be tallied onto + id : int + Unique identifier for the filter + translation : Iterable of float + This array specifies a vector that is used to translate (shift) + the mesh for this filter + bins : list of tuple + A list of mesh indices for each filter bin, e.g. [(1, 1, 1), (2, 1, 1), + ...] + num_bins : Integral + The number of filter bins + + """ + class MeshSurfaceFilter(MeshFilter): - """Filter events by surface crossings on a regular, rectangular mesh. + """Filter events by surface crossings on a mesh. Parameters ---------- @@ -891,8 +1024,6 @@ class MeshSurfaceFilter(MeshFilter): Attributes ---------- - bins : Integral - The mesh ID mesh : openmc.MeshBase The mesh object that events will be tallied onto translation : Iterable of float @@ -901,10 +1032,8 @@ class MeshSurfaceFilter(MeshFilter): id : int Unique identifier for the filter bins : list of tuple - A list of mesh indices / surfaces for each filter bin, e.g. [(1, 1, 'x-min out'), (1, 1, 'x-min in'), ...] - num_bins : Integral The number of filter bins @@ -955,7 +1084,7 @@ def get_pandas_dataframe(self, data_size, stride, **kwargs): filter_dict = {} # Append mesh ID as outermost index of multi-index - mesh_key = 'mesh {}'.format(self.mesh.id) + mesh_key = f'mesh {self.mesh.id}' # Find mesh dimensions - use 3D indices for simplicity n_surfs = 4 * len(self.mesh.dimension) @@ -1020,35 +1149,12 @@ def __init__(self, bins, filter_id=None): self.bins = np.asarray(bins) self.id = filter_id - def __repr__(self): - string = type(self).__name__ + '\n' - string += '{: <16}=\t{}\n'.format('\tValues', self.bins) - string += '{: <16}=\t{}\n'.format('\tID', self.id) - return string - - @Filter.bins.setter - def bins(self, bins): - Filter.bins.__set__(self, np.asarray(bins)) - def check_bins(self, bins): for x in bins: # Values should be integers cv.check_type('filter value', x, Integral) cv.check_greater_than('filter value', x, 0, equality=True) - def to_xml_element(self): - """Return XML Element representing the Filter. - - Returns - ------- - element : xml.etree.ElementTree.Element - XML element containing filter data - - """ - element = super().to_xml_element() - element[0].text = ' '.join(str(x) for x in self.bins) - return element - class RealFilter(Filter): """Tally modifier that describes phase-space and other characteristics @@ -1106,14 +1212,14 @@ def check_bins(self, bins): # Make sure that each tuple has values that are increasing if v1 < v0: - raise ValueError('Values {} and {} appear to be out of order' - .format(v0, v1)) + raise ValueError(f'Values {v0} and {v1} appear to be out of ' + 'order') for pair0, pair1 in zip(bins[:-1], bins[1:]): # Successive pairs should be ordered if pair1[1] < pair0[1]: - raise ValueError('Values {} and {} appear to be out of order' - .format(pair1[1], pair0[1])) + raise ValueError(f'Values {pair1[1]} and {pair0[1]} appear to ' + 'be out of order') def can_merge(self, other): if type(self) is not type(other): @@ -1130,8 +1236,7 @@ def can_merge(self, other): def merge(self, other): if not self.can_merge(other): - msg = 'Unable to merge "{0}" with "{1}" ' \ - 'filters'.format(type(self), type(other)) + msg = f'Unable to merge "{type(self)}" with "{type(other)}" filters' raise ValueError(msg) # Merge unique filter bins @@ -1169,8 +1274,8 @@ def is_subset(self, other): def get_bin_index(self, filter_bin): i = np.where(self.bins[:, 1] == filter_bin[1])[0] if len(i) == 0: - msg = 'Unable to get the bin index for Filter since "{0}" ' \ - 'is not one of the bins'.format(filter_bin) + msg = ('Unable to get the bin index for Filter since ' + f'"{filter_bin}" is not one of the bins') raise ValueError(msg) else: return i[0] @@ -1216,7 +1321,7 @@ def get_pandas_dataframe(self, data_size, stride, **kwargs): # Add the new energy columns to the DataFrame. if hasattr(self, 'units'): - units = ' [{}]'.format(self.units) + units = f' [{self.units}]' else: units = '' @@ -1230,7 +1335,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ @@ -1238,6 +1343,12 @@ def to_xml_element(self): element[0].text = ' '.join(str(x) for x in self.values) return element + @classmethod + def from_xml_element(cls, elem, **kwargs): + filter_id = int(elem.get('id')) + bins = [float(x) for x in get_text(elem, 'bins').split()] + return cls(bins, filter_id=filter_id) + class EnergyFilter(RealFilter): """Bins tally events based on incident particle energy. @@ -1266,6 +1377,10 @@ class EnergyFilter(RealFilter): """ units = 'eV' + def __init__(self, values, filter_id=None): + cv.check_length('values', values, 2) + super().__init__(values, filter_id) + def get_bin_index(self, filter_bin): # Use lower energy bound to find index for RealFilters deltas = np.abs(self.bins[:, 1] - filter_bin[1]) / filter_bin[1] @@ -1273,8 +1388,8 @@ def get_bin_index(self, filter_bin): if min_delta < 1E-3: return deltas.argmin() else: - msg = 'Unable to get the bin index for Filter since "{0}" ' \ - 'is not one of the bins'.format(filter_bin) + msg = ('Unable to get the bin index for Filter since ' + f'"{filter_bin}" is not one of the bins') raise ValueError(msg) def check_bins(self, bins): @@ -1283,6 +1398,67 @@ def check_bins(self, bins): cv.check_greater_than('filter value', v0, 0., equality=True) cv.check_greater_than('filter value', v1, 0., equality=True) + def get_tabular(self, values, **kwargs): + """Create a tabulated distribution based on tally results with an energy filter + + This method provides an easy way to create a distribution in energy + (e.g., a source spectrum) based on tally results that were obtained from + using an :class:`~openmc.EnergyFilter`. + + .. versionadded:: 0.13.3 + + Parameters + ---------- + values : iterable of float + Array of numeric values, typically from a tally result + **kwargs + Keyword arguments passed to :class:`openmc.stats.Tabular` + + Returns + ------- + openmc.stats.Tabular + Tabular distribution with histogram interpolation + """ + + probabilities = np.array(values, dtype=float) + probabilities /= probabilities.sum() + + # Determine probability per eV, adding extra 0 at the end since it is a histogram + probability_per_ev = probabilities / np.diff(self.values) + probability_per_ev = np.append(probability_per_ev, 0.0) + + kwargs.setdefault('interpolation', 'histogram') + return openmc.stats.Tabular(self.values, probability_per_ev, **kwargs) + + @property + def lethargy_bin_width(self): + """Calculates the base 10 log width of energy bins which is useful when + plotting the normalized flux. + + Returns + ------- + numpy.array + Array of bin widths + """ + return np.log10(self.bins[:, 1]/self.bins[:, 0]) + + @classmethod + def from_group_structure(cls, group_structure): + """Construct an EnergyFilter instance from a standard group structure. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + group_structure : str + Name of the group structure. Must be a valid key of + openmc.mgxs.GROUP_STRUCTURES dictionary. + + """ + + cv.check_value('group_structure', group_structure, openmc.mgxs.GROUP_STRUCTURES.keys()) + return cls(openmc.mgxs.GROUP_STRUCTURES[group_structure.upper()]) + class EnergyoutFilter(EnergyFilter): """Bins tally events based on outgoing particle energy. @@ -1310,6 +1486,52 @@ class EnergyoutFilter(EnergyFilter): """ +class TimeFilter(RealFilter): + """Bins tally events based on the particle's time. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + values : iterable of float + A list of values for which each successive pair constitutes a range of + time in [s] for a single bin + filter_id : int + Unique identifier for the filter + + Attributes + ---------- + values : numpy.ndarray + An array of values for which each successive pair constitutes a range of + time in [s] for a single bin + id : int + Unique identifier for the filter + bins : numpy.ndarray + An array of shape (N, 2) where each row is a pair of time in [s] + for a single filter bin + num_bins : int + The number of filter bins + + """ + units = 's' + + def get_bin_index(self, filter_bin): + # Use lower energy bound to find index for RealFilters + deltas = np.abs(self.bins[:, 1] - filter_bin[1]) / filter_bin[1] + min_delta = np.min(deltas) + if min_delta < 1e-3: + return deltas.argmin() + else: + msg = ('Unable to get the bin index for Filter since ' + f'"{filter_bin}" is not one of the bins') + raise ValueError(msg) + + def check_bins(self, bins): + super().check_bins(bins) + for v0, v1 in bins: + cv.check_greater_than('filter value', v0, 0., equality=True) + cv.check_greater_than('filter value', v1, 0., equality=True) + def _path_to_levels(path): """Convert distribcell path to list of levels @@ -1409,6 +1631,11 @@ def num_bins(self): def paths(self): return self._paths + @paths.setter + def paths(self, paths): + cv.check_iterable_type('paths', paths, str) + self._paths = paths + @Filter.bins.setter def bins(self, bins): # Format the bins as a 1D numpy array. @@ -1416,8 +1643,8 @@ def bins(self, bins): # Make sure there is only 1 bin. if not len(bins) == 1: - msg = 'Unable to add bins "{0}" to a DistribcellFilter since ' \ - 'only a single distribcell can be used per tally'.format(bins) + msg = (f'Unable to add bins "{bins}" to a DistribcellFilter since ' + 'only a single distribcell can be used per tally') raise ValueError(msg) # Check the type and extract the id, if necessary. @@ -1427,11 +1654,6 @@ def bins(self, bins): self._bins = bins - @paths.setter - def paths(self, paths): - cv.check_iterable_type('paths', paths, str) - self._paths = paths - def can_merge(self, other): # Distribcell filters cannot have more than one bin return False @@ -1508,10 +1730,10 @@ def get_pandas_dataframe(self, data_size, stride, **kwargs): num_levels = len(paths[0]) for i_level in range(num_levels): # Use level key as first index in Pandas Multi-index column - level_key = 'level {}'.format(i_level + 1) + level_key = f'level {i_level + 1}' # Create a dictionary for this level for Pandas Multi-index - level_dict = OrderedDict() + level_dict = {} # Use the first distribcell path to determine if level # is a universe/cell or lattice level @@ -1580,7 +1802,7 @@ def get_pandas_dataframe(self, data_size, stride, **kwargs): # Concatenate with DataFrame of distribcell instance IDs if level_df is not None: level_df = level_df.dropna(axis=1, how='all') - level_df = level_df.astype(np.int) + level_df = level_df.astype(int) df = pd.concat([level_df, df], axis=1) return df @@ -1760,6 +1982,9 @@ class EnergyFunctionFilter(Filter): A grid of energy values in [eV] y : iterable of Real A grid of interpolant values in [eV] + interpolation : str + Interpolation scheme: {'histogram', 'linear-linear', 'linear-log', + 'log-linear', 'log-log', 'quadratic', 'cubic'} filter_id : int Unique identifier for the filter @@ -1769,6 +1994,9 @@ class EnergyFunctionFilter(Filter): A grid of energy values in [eV] y : iterable of Real A grid of interpolant values in [eV] + interpolation : str + Interpolation scheme: {'histogram', 'linear-linear', 'linear-log', + 'log-linear', 'log-log', 'quadratic', 'cubic'} id : int Unique identifier for the filter num_bins : Integral @@ -1776,14 +2004,25 @@ class EnergyFunctionFilter(Filter): """ - def __init__(self, energy, y, filter_id=None): + # keys selected to match those in function.py where possible + # skip 6 b/c ENDF-6 reserves this value for + # "special one-dimensional interpolation law" + INTERPOLATION_SCHEMES = {1: 'histogram', 2: 'linear-linear', + 3: 'linear-log', 4: 'log-linear', + 5: 'log-log', 7: 'quadratic', + 8: 'cubic'} + + def __init__(self, energy, y, interpolation='linear-linear', filter_id=None): self.energy = energy self.y = y self.id = filter_id + self.interpolation = interpolation def __eq__(self, other): if type(self) is not type(other): return False + elif not self.interpolation == other.interpolation: + return False elif not all(self.energy == other.energy): return False else: @@ -1817,12 +2056,14 @@ def __hash__(self): string = type(self).__name__ + '\n' string += '{: <16}=\t{}\n'.format('\tEnergy', self.energy) string += '{: <16}=\t{}\n'.format('\tInterpolant', self.y) + string += '{: <16}=\t{}\n'.format('\tInterpolation', self.interpolation) return hash(string) def __repr__(self): string = type(self).__name__ + '\n' string += '{: <16}=\t{}\n'.format('\tEnergy', self.energy) string += '{: <16}=\t{}\n'.format('\tInterpolant', self.y) + string += '{: <16}=\t{}\n'.format('\tInterpolation', self.interpolation) string += '{: <16}=\t{}\n'.format('\tID', self.id) return string @@ -1834,10 +2075,16 @@ def from_hdf5(cls, group, **kwargs): + group['type'][()].decode() + " instead") energy = group['energy'][()] - y = group['y'][()] + y_grp = group['y'] + y = y_grp[()] filter_id = int(group.name.split('/')[-1].lstrip('filter ')) - return cls(energy, y, filter_id=filter_id) + out = cls(energy, y, filter_id=filter_id) + if 'interpolation' in y_grp.attrs: + out.interpolation = \ + cls.INTERPOLATION_SCHEMES[y_grp.attrs['interpolation'][()]] + + return out @classmethod def from_tabulated1d(cls, tab1d): @@ -1859,27 +2106,16 @@ def from_tabulated1d(cls, tab1d): if tab1d.n_regions > 1: raise ValueError('Only Tabulated1Ds with a single interpolation ' 'region are supported') - if tab1d.interpolation[0] != 2: - raise ValueError('Only linear-linar Tabulated1Ds are supported') - - return cls(tab1d.x, tab1d.y) + interpolation_val = tab1d.interpolation[0] + if interpolation_val not in cls.INTERPOLATION_SCHEMES.keys(): + raise ValueError('Only histogram, linear-linear, linear-log, log-linear, and ' + 'log-log Tabulated1Ds are supported') + return cls(tab1d.x, tab1d.y, cls.INTERPOLATION_SCHEMES[interpolation_val]) @property def energy(self): return self._energy - @property - def y(self): - return self._y - - @property - def bins(self): - raise AttributeError('EnergyFunctionFilters have no bins.') - - @property - def num_bins(self): - return 1 - @energy.setter def energy(self, energy): # Format the bins as a 1D numpy array. @@ -1892,6 +2128,10 @@ def energy(self, energy): self._energy = energy + @property + def y(self): + return self._y + @y.setter def y(self, y): # Format the bins as a 1D numpy array. @@ -1902,16 +2142,41 @@ def y(self, y): self._y = y + @property + def interpolation(self): + return self._interpolation + + @interpolation.setter + def interpolation(self, val): + cv.check_type('interpolation', val, str) + cv.check_value('interpolation', val, self.INTERPOLATION_SCHEMES.values()) + + if val == 'quadratic' and len(self.energy) < 3: + raise ValueError('Quadratic interpolation requires 3 or more values.') + + if val == 'cubic' and len(self.energy) < 4: + raise ValueError('Cubic interpolation requires 3 or more values.') + + self._interpolation = val + + @property + def bins(self): + raise AttributeError('EnergyFunctionFilters have no bins.') + @bins.setter def bins(self, bins): raise RuntimeError('EnergyFunctionFilters have no bins.') + @property + def num_bins(self): + return 1 + def to_xml_element(self): """Return XML Element representing the Filter. Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ @@ -1925,8 +2190,21 @@ def to_xml_element(self): subelement = ET.SubElement(element, 'y') subelement.text = ' '.join(str(y) for y in self.y) + subelement = ET.SubElement(element, 'interpolation') + subelement.text = self.interpolation + return element + @classmethod + def from_xml_element(cls, elem, **kwargs): + filter_id = int(elem.get('id')) + energy = [float(x) for x in get_text(elem, 'energy').split()] + y = [float(x) for x in get_text(elem, 'y').split()] + out = cls(energy, y, filter_id=filter_id) + if elem.find('interpolation') is not None: + out.interpolation = elem.find('interpolation').text + return out + def can_merge(self, other): return False diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index c26d5437b38..f8e677578f1 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -1,5 +1,6 @@ from numbers import Integral, Real -from xml.etree import ElementTree as ET + +import lxml.etree as ET import openmc.checkvalue as cv from . import Filter @@ -33,7 +34,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Legendre filter data """ @@ -46,6 +47,40 @@ def to_xml_element(self): return element + @classmethod + def from_xml_element(cls, elem, **kwargs): + filter_id = int(elem.get('id')) + order = int(elem.find('order').text) + return cls(order, filter_id=filter_id) + + def merge(self, other): + """Merge this filter with another. + + This overrides the behavior of the parent Filter class, since its + merging technique is to take the union of the set of bins of each + filter. That technique does not apply to expansion filters, since the + argument should be the maximum filter order rather than the list of all + bins. + + Parameters + ---------- + other : openmc.Filter + Filter to merge with + + Returns + ------- + merged_filter : openmc.Filter + Filter resulting from the merge + + """ + + if not self.can_merge(other): + msg = f'Unable to merge "{type(self)}" with "{type(other)}"' + raise ValueError(msg) + + # Create a new filter with these bins and a new auto-generated ID + return type(self)(max(self.order, other.order)) + class LegendreFilter(ExpansionFilter): r"""Score Legendre expansion moments up to specified order. @@ -85,7 +120,7 @@ def __repr__(self): @ExpansionFilter.order.setter def order(self, order): ExpansionFilter.order.__set__(self, order) - self.bins = ['P{}'.format(i) for i in range(order + 1)] + self.bins = [f'P{i}' for i in range(order + 1)] @classmethod def from_hdf5(cls, group, **kwargs): @@ -164,7 +199,7 @@ def __repr__(self): @ExpansionFilter.order.setter def order(self, order): ExpansionFilter.order.__set__(self, order) - self.bins = ['P{}'.format(i) for i in range(order + 1)] + self.bins = [f'P{i}' for i in range(order + 1)] @property def axis(self): @@ -212,7 +247,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Legendre filter data """ @@ -226,6 +261,15 @@ def to_xml_element(self): return element + @classmethod + def from_xml_element(cls, elem, **kwargs): + filter_id = int(elem.get('id')) + order = int(elem.find('order').text) + axis = elem.find('axis').text + minimum = float(elem.find('min').text) + maximum = float(elem.find('max').text) + return cls(order, axis, minimum, maximum, filter_id=filter_id) + class SphericalHarmonicsFilter(ExpansionFilter): r"""Score spherical harmonic expansion moments up to specified order. @@ -275,7 +319,7 @@ def __repr__(self): @ExpansionFilter.order.setter def order(self, order): ExpansionFilter.order.__set__(self, order) - self.bins = ['Y{},{}'.format(n, m) + self.bins = [f'Y{n},{m}' for n in range(order + 1) for m in range(-n, n + 1)] @@ -308,7 +352,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing spherical harmonics filter data """ @@ -316,6 +360,14 @@ def to_xml_element(self): element.set('cosine', self.cosine) return element + @classmethod + def from_xml_element(cls, elem, **kwargs): + filter_id = int(elem.get('id')) + order = int(elem.find('order').text) + filter = cls(order, filter_id=filter_id) + filter.cosine = elem.get('cosine') + return filter + class ZernikeFilter(ExpansionFilter): r"""Score Zernike expansion moments in space up to specified order. @@ -358,7 +410,7 @@ class ZernikeFilter(ExpansionFilter): x-coordinate of center of circle for normalization y : float y-coordinate of center of circle for normalization - r : int or None + r : float Radius of circle for normalization Attributes @@ -369,7 +421,7 @@ class ZernikeFilter(ExpansionFilter): x-coordinate of center of circle for normalization y : float y-coordinate of center of circle for normalization - r : int or None + r : float Radius of circle for normalization id : int Unique identifier for the filter @@ -401,7 +453,7 @@ def __repr__(self): @ExpansionFilter.order.setter def order(self, order): ExpansionFilter.order.__set__(self, order) - self.bins = ['Z{},{}'.format(n, m) + self.bins = [f'Z{n},{m}' for n in range(order + 1) for m in range(-n, n + 1, 2)] @@ -450,7 +502,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Zernike filter data """ @@ -464,6 +516,15 @@ def to_xml_element(self): return element + @classmethod + def from_xml_element(cls, elem, **kwargs): + filter_id = int(elem.get('id')) + order = int(elem.find('order').text) + x = float(elem.find('x').text) + y = float(elem.find('y').text) + r = float(elem.find('r').text) + return cls(order, x, y, r, filter_id=filter_id) + class ZernikeRadialFilter(ZernikeFilter): r"""Score the :math:`m = 0` (radial variation only) Zernike moments up to @@ -499,7 +560,7 @@ class ZernikeRadialFilter(ZernikeFilter): x-coordinate of center of circle for normalization y : float y-coordinate of center of circle for normalization - r : int or None + r : float Radius of circle for normalization Attributes @@ -510,7 +571,7 @@ class ZernikeRadialFilter(ZernikeFilter): x-coordinate of center of circle for normalization y : float y-coordinate of center of circle for normalization - r : int or None + r : float Radius of circle for normalization id : int Unique identifier for the filter @@ -522,4 +583,4 @@ class ZernikeRadialFilter(ZernikeFilter): @ExpansionFilter.order.setter def order(self, order): ExpansionFilter.order.__set__(self, order) - self.bins = ['Z{},0'.format(n) for n in range(0, order+1, 2)] + self.bins = [f'Z{n},0' for n in range(0, order+1, 2)] diff --git a/openmc/geometry.py b/openmc/geometry.py index e7d981d7b8a..175cef2bf37 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -1,12 +1,18 @@ -from collections import OrderedDict, defaultdict -from collections.abc import Iterable +from __future__ import annotations +import os +import typing +from collections import defaultdict from copy import deepcopy +from collections.abc import Iterable from pathlib import Path -from xml.etree import ElementTree as ET +import warnings +import lxml.etree as ET + +import numpy as np import openmc import openmc._xml as xml -from .checkvalue import check_type +from .checkvalue import check_type, check_less_than, check_greater_than, PathLike class Geometry: @@ -14,25 +20,37 @@ class Geometry: Parameters ---------- - root : openmc.Universe or Iterable of openmc.Cell, optional + root : openmc.UniverseBase or Iterable of openmc.Cell, optional Root universe which contains all others, or an iterable of cells that should be used to create a root universe. Attributes ---------- - root_universe : openmc.Universe + root_universe : openmc.UniverseBase Root universe which contains all others - bounding_box : 2-tuple of numpy.array + bounding_box : openmc.BoundingBox Lower-left and upper-right coordinates of an axis-aligned bounding box of the universe. + merge_surfaces : bool + Whether to remove redundant surfaces when the geometry is exported. + surface_precision : int + Number of decimal places to round to for comparing the coefficients of + surfaces for considering them topologically equivalent. """ - def __init__(self, root=None): + def __init__( + self, + root: typing.Optional[openmc.UniverseBase] = None, + merge_surfaces: bool = False, + surface_precision: int = 10 + ): self._root_universe = None self._offsets = {} + self.merge_surfaces = merge_surfaces + self.surface_precision = surface_precision if root is not None: - if isinstance(root, openmc.Universe): + if isinstance(root, openmc.UniverseBase): self.root_universe = root else: univ = openmc.Universe() @@ -41,18 +59,38 @@ def __init__(self, root=None): self._root_universe = univ @property - def root_universe(self): + def root_universe(self) -> openmc.UniverseBase: return self._root_universe - @property - def bounding_box(self): - return self.root_universe.bounding_box - @root_universe.setter def root_universe(self, root_universe): - check_type('root universe', root_universe, openmc.Universe) + check_type('root universe', root_universe, openmc.UniverseBase) self._root_universe = root_universe + @property + def bounding_box(self) -> np.ndarray: + return self.root_universe.bounding_box + + @property + def merge_surfaces(self) -> bool: + return self._merge_surfaces + + @merge_surfaces.setter + def merge_surfaces(self, merge_surfaces): + check_type('merge surfaces', merge_surfaces, bool) + self._merge_surfaces = merge_surfaces + + @property + def surface_precision(self) -> int: + return self._surface_precision + + @surface_precision.setter + def surface_precision(self, surface_precision): + check_type('surface precision', surface_precision, int) + check_less_than('surface_precision', surface_precision, 16) + check_greater_than('surface_precision', surface_precision, 0) + self._surface_precision = surface_precision + def add_volume_information(self, volume_calc): """Add volume information from a stochastic volume calculation. @@ -75,34 +113,54 @@ def add_volume_information(self, volume_calc): if universe.id in volume_calc.volumes: universe.add_volume_information(volume_calc) - def export_to_xml(self, path='geometry.xml', remove_surfs=False): - """Export geometry to an XML file. + def to_xml_element(self, remove_surfs=False) -> ET.Element: + """Creates a 'geometry' element to be written to an XML file. Parameters ---------- - path : str - Path to file to write. Defaults to 'geometry.xml'. remove_surfs : bool Whether or not to remove redundant surfaces from the geometry when exporting - .. versionadded:: 0.12 - """ # Find and remove redundant surfaces from the geometry if remove_surfs: + warnings.warn("remove_surfs kwarg will be deprecated soon, please " + "set the Geometry.merge_surfaces attribute instead.") + self.merge_surfaces = True + + if self.merge_surfaces: self.remove_redundant_surfaces() # Create XML representation - root_element = ET.Element("geometry") - self.root_universe.create_xml_subelement(root_element, memo=set()) + element = ET.Element("geometry") + self.root_universe.create_xml_subelement(element, memo=set()) # Sort the elements in the file - root_element[:] = sorted(root_element, key=lambda x: ( + element[:] = sorted(element, key=lambda x: ( x.tag, int(x.get('id')))) # Clean the indentation in the file to be user-readable - xml.clean_indentation(root_element) + xml.clean_indentation(element) + xml.reorder_attributes(element) # TODO: Remove when support is Python 3.8+ + + return element + + def export_to_xml(self, path='geometry.xml', remove_surfs=False): + """Export geometry to an XML file. + + Parameters + ---------- + path : str + Path to file to write. Defaults to 'geometry.xml'. + remove_surfs : bool + Whether or not to remove redundant surfaces from the geometry when + exporting + + .. versionadded:: 0.12 + + """ + root_element = self.to_xml_element(remove_surfs) # Check if path is a directory p = Path(path) @@ -110,18 +168,17 @@ def export_to_xml(self, path='geometry.xml', remove_surfs=False): p /= 'geometry.xml' # Write the XML Tree to the geometry.xml file - xml.reorder_attributes(root_element) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') @classmethod - def from_xml(cls, path='geometry.xml', materials=None): - """Generate geometry from XML file + def from_xml_element(cls, elem, materials=None) -> Geometry: + """Generate geometry from an XML element Parameters ---------- - path : str, optional - Path to geometry XML file + elem : lxml.etree._Element + XML element materials : openmc.Materials or None Materials used to assign to cells. If None, an attempt is made to generate it from the materials.xml file. @@ -132,6 +189,11 @@ def from_xml(cls, path='geometry.xml', materials=None): Geometry object """ + mats = dict() + if materials is not None: + mats.update({str(m.id): m for m in materials}) + mats['void'] = None + # Helper function for keeping a cache of Universe instances universes = {} def get_universe(univ_id): @@ -140,13 +202,10 @@ def get_universe(univ_id): universes[univ_id] = univ return universes[univ_id] - tree = ET.parse(path) - root = tree.getroot() - # Get surfaces surfaces = {} periodic = {} - for surface in root.findall('surface'): + for surface in elem.findall('surface'): s = openmc.Surface.from_xml_element(surface) surfaces[s.id] = s @@ -159,20 +218,25 @@ def get_universe(univ_id): for s1, s2 in periodic.items(): surfaces[s1].periodic_surface = surfaces[s2] + # Add any DAGMC universes + for e in elem.findall('dagmc_universe'): + dag_univ = openmc.DAGMCUniverse.from_xml_element(e) + universes[dag_univ.id] = dag_univ + # Dictionary that maps each universe to a list of cells/lattices that - # contain it (needed to determine which universe is the root) + # contain it (needed to determine which universe is the elem) child_of = defaultdict(list) - for elem in root.findall('lattice'): - lat = openmc.RectLattice.from_xml_element(elem, get_universe) + for e in elem.findall('lattice'): + lat = openmc.RectLattice.from_xml_element(e, get_universe) universes[lat.id] = lat if lat.outer is not None: child_of[lat.outer].append(lat) for u in lat.universes.ravel(): child_of[u].append(lat) - for elem in root.findall('hex_lattice'): - lat = openmc.HexLattice.from_xml_element(elem, get_universe) + for e in elem.findall('hex_lattice'): + lat = openmc.HexLattice.from_xml_element(e, get_universe) universes[lat.id] = lat if lat.outer is not None: child_of[lat.outer].append(lat) @@ -186,15 +250,8 @@ def get_universe(univ_id): for u in ring: child_of[u].append(lat) - # Create dictionary to easily look up materials - if materials is None: - filename = Path(path).parent / 'materials.xml' - materials = openmc.Materials.from_xml(str(filename)) - mats = {str(m.id): m for m in materials} - mats['void'] = None - - for elem in root.findall('cell'): - c = openmc.Cell.from_xml_element(elem, surfaces, mats, get_universe) + for e in elem.findall('cell'): + c = openmc.Cell.from_xml_element(e, surfaces, mats, get_universe) if c.fill_type in ('universe', 'lattice'): child_of[c.fill].append(c) @@ -206,7 +263,43 @@ def get_universe(univ_id): else: raise ValueError('Error determining root universe.') - def find(self, point): + @classmethod + def from_xml( + cls, + path: PathLike = 'geometry.xml', + materials: typing.Optional[typing.Union[PathLike, 'openmc.Materials']] = 'materials.xml' + ) -> Geometry: + """Generate geometry from XML file + + Parameters + ---------- + path : PathLike, optional + Path to geometry XML file + materials : openmc.Materials or PathLike + Materials used to assign to cells. If PathLike, an attempt is made + to generate materials from the provided xml file. + + Returns + ------- + openmc.Geometry + Geometry object + + """ + + # Using str and os.PathLike here to avoid error when using just the imported PathLike + # TypeError: Subscripted generics cannot be used with class and instance checks + check_type('materials', materials, (str, os.PathLike, openmc.Materials)) + + if isinstance(materials, (str, os.PathLike)): + materials = openmc.Materials.from_xml(materials) + + parser = ET.XMLParser(huge_tree=True) + tree = ET.parse(path, parser=parser) + root = tree.getroot() + + return cls.from_xml_element(root, materials) + + def find(self, point) -> list: """Find cells/universes/lattices which contain a given point Parameters @@ -223,7 +316,7 @@ def find(self, point): """ return self.root_universe.find(point) - def get_instances(self, paths): + def get_instances(self, paths) -> typing.Union[int, typing.List[int]]: """Return the instance number(s) for a cell/material in a geometry path. The instance numbers are used as indices into distributed @@ -270,41 +363,55 @@ def get_instances(self, paths): return indices if return_list else indices[0] - def get_all_cells(self): + def get_all_cells(self) -> typing.Dict[int, openmc.Cell]: """Return all cells in the geometry. Returns ------- - collections.OrderedDict + dict Dictionary mapping cell IDs to :class:`openmc.Cell` instances """ if self.root_universe is not None: return self.root_universe.get_all_cells(memo=set()) else: - return OrderedDict() + return {} - def get_all_universes(self): + def get_all_universes(self) -> typing.Dict[int, openmc.Universe]: """Return all universes in the geometry. Returns ------- - collections.OrderedDict + dict Dictionary mapping universe IDs to :class:`openmc.Universe` instances """ - universes = OrderedDict() + universes = {} universes[self.root_universe.id] = self.root_universe universes.update(self.root_universe.get_all_universes()) return universes - def get_all_materials(self): + def get_all_nuclides(self) -> typing.List[str]: + """Return all nuclides within the geometry. + + Returns + ------- + list + Sorted list of all nuclides in materials appearing in the geometry + + """ + all_nuclides = set() + for material in self.get_all_materials().values(): + all_nuclides |= set(material.get_nuclides()) + return sorted(all_nuclides) + + def get_all_materials(self) -> typing.Dict[int, openmc.Material]: """Return all materials within the geometry. Returns ------- - collections.OrderedDict + dict Dictionary mapping material IDs to :class:`openmc.Material` instances @@ -312,19 +419,19 @@ def get_all_materials(self): if self.root_universe is not None: return self.root_universe.get_all_materials(memo=set()) else: - return OrderedDict() + return {} - def get_all_material_cells(self): + def get_all_material_cells(self) -> typing.Dict[int, openmc.Cell]: """Return all cells filled by a material Returns ------- - collections.OrderedDict + dict Dictionary mapping cell IDs to :class:`openmc.Cell` instances that are filled with materials or distributed materials. """ - material_cells = OrderedDict() + material_cells = {} for cell in self.get_all_cells().values(): if cell.fill_type in ('material', 'distribmat'): @@ -333,7 +440,7 @@ def get_all_material_cells(self): return material_cells - def get_all_material_universes(self): + def get_all_material_universes(self) -> typing.Dict[int, openmc.Universe]: """Return all universes having at least one material-filled cell. This method can be used to find universes that have at least one cell @@ -341,12 +448,12 @@ def get_all_material_universes(self): Returns ------- - collections.OrderedDict + dict Dictionary mapping universe IDs to :class:`openmc.Universe` instances with at least one material-filled cell """ - material_universes = OrderedDict() + material_universes = {} for universe in self.get_all_universes().values(): for cell in universe.cells.values(): @@ -356,16 +463,16 @@ def get_all_material_universes(self): return material_universes - def get_all_lattices(self): + def get_all_lattices(self) -> typing.Dict[int, openmc.Lattice]: """Return all lattices defined Returns ------- - collections.OrderedDict + dict Dictionary mapping lattice IDs to :class:`openmc.Lattice` instances """ - lattices = OrderedDict() + lattices = {} for cell in self.get_all_cells().values(): if cell.fill_type == 'lattice': @@ -374,52 +481,30 @@ def get_all_lattices(self): return lattices - def get_all_surfaces(self): + def get_all_surfaces(self) -> typing.Dict[int, openmc.Surface]: """ Return all surfaces used in the geometry Returns ------- - collections.OrderedDict + dict Dictionary mapping surface IDs to :class:`openmc.Surface` instances """ - surfaces = OrderedDict() + surfaces = {} for cell in self.get_all_cells().values(): if cell.region is not None: surfaces = cell.region.get_surfaces(surfaces) return surfaces - def get_redundant_surfaces(self): - """Return all of the topologically redundant surface IDs - - .. versionadded:: 0.12 - - Returns - ------- - dict - Dictionary whose keys are the ID of a redundant surface and whose - values are the topologically equivalent :class:`openmc.Surface` - that should replace it. - - """ - tally = defaultdict(list) - for surf in self.get_all_surfaces().values(): - coeffs = tuple(surf._coefficients[k] for k in surf._coeff_keys) - key = (surf._type,) + coeffs - tally[key].append(surf) - return {replace.id: keep - for keep, *redundant in tally.values() - for replace in redundant} - - def _get_domains_by_name(self, name, case_sensitive, matching, domain_type): + def _get_domains_by_name(self, name, case_sensitive, matching, domain_type) -> list: if not case_sensitive: name = name.lower() domains = [] - func = getattr(self, 'get_all_{}s'.format(domain_type)) + func = getattr(self, f'get_all_{domain_type}s') for domain in func().values(): domain_name = domain.name if case_sensitive else domain.name.lower() if domain_name == name: @@ -430,7 +515,9 @@ def _get_domains_by_name(self, name, case_sensitive, matching, domain_type): domains.sort(key=lambda x: x.id) return domains - def get_materials_by_name(self, name, case_sensitive=False, matching=False): + def get_materials_by_name( + self, name, case_sensitive=False, matching=False + ) -> typing.List[openmc.Material]: """Return a list of materials with matching names. Parameters @@ -451,7 +538,9 @@ def get_materials_by_name(self, name, case_sensitive=False, matching=False): """ return self._get_domains_by_name(name, case_sensitive, matching, 'material') - def get_cells_by_name(self, name, case_sensitive=False, matching=False): + def get_cells_by_name( + self, name, case_sensitive=False, matching=False + ) -> typing.List[openmc.Cell]: """Return a list of cells with matching names. Parameters @@ -472,7 +561,34 @@ def get_cells_by_name(self, name, case_sensitive=False, matching=False): """ return self._get_domains_by_name(name, case_sensitive, matching, 'cell') - def get_cells_by_fill_name(self, name, case_sensitive=False, matching=False): + def get_surfaces_by_name( + self, name, case_sensitive=False, matching=False + ) -> typing.List[openmc.Surface]: + """Return a list of surfaces with matching names. + + .. versionadded:: 0.13.3 + + Parameters + ---------- + name : str + The name to search match + case_sensitive : bool + Whether to distinguish upper and lower case letters in each + surface's name (default is False) + matching : bool + Whether the names must match completely (default is False) + + Returns + ------- + list of openmc.Surface + Surfaces matching the queried name + + """ + return self._get_domains_by_name(name, case_sensitive, matching, 'surface') + + def get_cells_by_fill_name( + self, name, case_sensitive=False, matching=False + ) -> typing.List[openmc.Cell]: """Return a list of cells with fills with matching names. Parameters @@ -517,7 +633,9 @@ def get_cells_by_fill_name(self, name, case_sensitive=False, matching=False): return sorted(cells, key=lambda x: x.id) - def get_universes_by_name(self, name, case_sensitive=False, matching=False): + def get_universes_by_name( + self, name, case_sensitive=False, matching=False + ) -> typing.List[openmc.Universe]: """Return a list of universes with matching names. Parameters @@ -538,7 +656,9 @@ def get_universes_by_name(self, name, case_sensitive=False, matching=False): """ return self._get_domains_by_name(name, case_sensitive, matching, 'universe') - def get_lattices_by_name(self, name, case_sensitive=False, matching=False): + def get_lattices_by_name( + self, name, case_sensitive=False, matching=False + ) -> typing.List[openmc.Lattice]: """Return a list of lattices with matching names. Parameters @@ -559,17 +679,43 @@ def get_lattices_by_name(self, name, case_sensitive=False, matching=False): """ return self._get_domains_by_name(name, case_sensitive, matching, 'lattice') - def remove_redundant_surfaces(self): - """Remove redundant surfaces from the geometry""" + def remove_redundant_surfaces(self) -> typing.Dict[int, openmc.Surface]: + """Remove and return all of the redundant surfaces. + + Uses surface_precision attribute of Geometry instance for rounding and + comparing surface coefficients. + + .. versionadded:: 0.12 + Returns + ------- + redundant_surfaces + Dictionary whose keys are the ID of a redundant surface and whose + values are the topologically equivalent :class:`openmc.Surface` + that should replace it. + + """ # Get redundant surfaces - redundant_surfaces = self.get_redundant_surfaces() + redundancies = defaultdict(list) + for surf in self.get_all_surfaces().values(): + coeffs = tuple(round(surf._coefficients[k], + self.surface_precision) + for k in surf._coeff_keys) + key = (surf._type, surf._boundary_type) + coeffs + redundancies[key].append(surf) + + redundant_surfaces = {replace.id: keep + for keep, *redundant in redundancies.values() + for replace in redundant} + + if redundant_surfaces: + # Iterate through all cells contained in the geometry + for cell in self.get_all_cells().values(): + # Recursively remove redundant surfaces from regions + if cell.region: + cell.region.remove_redundant_surfaces(redundant_surfaces) - # Iterate through all cells contained in the geometry - for cell in self.get_all_cells().values(): - # Recursively remove redundant surfaces from regions - if cell.region: - cell.region.remove_redundant_surfaces(redundant_surfaces) + return redundant_surfaces def determine_paths(self, instances_only=False): """Determine paths through CSG tree for cells and materials. @@ -596,10 +742,69 @@ def determine_paths(self, instances_only=False): # Recursively traverse the CSG tree to count all cell instances self.root_universe._determine_paths(instances_only=instances_only) - def clone(self): + def clone(self) -> Geometry: """Create a copy of this geometry with new unique IDs for all of its enclosed materials, surfaces, cells, universes and lattices.""" clone = deepcopy(self) clone.root_universe = self.root_universe.clone() return clone + + def plot(self, *args, **kwargs): + """Display a slice plot of the geometry. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + origin : iterable of float + Coordinates at the origin of the plot. If left as None then the + bounding box center will be used to attempt to ascertain the origin. + Defaults to (0, 0, 0) if the bounding box is not finite + width : iterable of float + Width of the plot in each basis direction. If left as none then the + bounding box width will be used to attempt to ascertain the plot + width. Defaults to (10, 10) if the bounding box is not finite + pixels : Iterable of int or int + If iterable of ints provided, then this directly sets the number of + pixels to use in each basis direction. If int provided, then this + sets the total number of pixels in the plot and the number of pixels + in each basis direction is calculated from this total and the image + aspect ratio. + basis : {'xy', 'xz', 'yz'} + The basis directions for the plot + color_by : {'cell', 'material'} + Indicate whether the plot should be colored by cell or by material + colors : dict + Assigns colors to specific materials or cells. Keys are instances of + :class:`Cell` or :class:`Material` and values are RGB 3-tuples, RGBA + 4-tuples, or strings indicating SVG color names. Red, green, blue, + and alpha should all be floats in the range [0.0, 1.0], for + example:: + + # Make water blue + water = openmc.Cell(fill=h2o) + universe.plot(..., colors={water: (0., 0., 1.)) + seed : int + Seed for the random number generator + openmc_exec : str + Path to OpenMC executable. + axes : matplotlib.Axes + Axes to draw to + legend : bool + Whether a legend showing material or cell names should be drawn + legend_kwargs : dict + Keyword arguments passed to :func:`matplotlib.pyplot.legend`. + outline : bool + Whether outlines between color boundaries should be drawn + axis_units : {'km', 'm', 'cm', 'mm'} + Units used on the plot axis + **kwargs + Keyword arguments passed to :func:`matplotlib.pyplot.imshow` + Returns + ------- + matplotlib.axes.Axes + Axes containing resulting image + """ + + return self.root_universe.plot(*args, **kwargs) diff --git a/openmc/lattice.py b/openmc/lattice.py index 252fbf32741..40b97f6cf5c 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -1,12 +1,11 @@ from abc import ABC -from collections import OrderedDict from collections.abc import Iterable from copy import deepcopy from math import sqrt, floor from numbers import Real import types -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np import openmc @@ -34,16 +33,16 @@ class Lattice(IDManagerMixin, ABC): Name of the lattice pitch : Iterable of float Pitch of the lattice in each direction in cm - outer : openmc.Universe + outer : openmc.UniverseBase A universe to fill all space outside the lattice - universes : Iterable of Iterable of openmc.Universe + universes : Iterable of Iterable of openmc.UniverseBase A two-or three-dimensional list/array of universes filling each element of the lattice """ next_id = 1 - used_ids = openmc.Universe.used_ids + used_ids = openmc.UniverseBase.used_ids def __init__(self, lattice_id=None, name=''): # Initialize Lattice class attributes @@ -57,18 +56,6 @@ def __init__(self, lattice_id=None, name=''): def name(self): return self._name - @property - def pitch(self): - return self._pitch - - @property - def outer(self): - return self._outer - - @property - def universes(self): - return self._universes - @name.setter def name(self, name): if name is not None: @@ -77,11 +64,23 @@ def name(self, name): else: self._name = '' + @property + def pitch(self): + return self._pitch + + @property + def outer(self): + return self._outer + @outer.setter def outer(self, outer): - cv.check_type('outer universe', outer, openmc.Universe) + cv.check_type('outer universe', outer, openmc.UniverseBase) self._outer = outer + @property + def universes(self): + return self._universes + @staticmethod def from_hdf5(group, universes): """Create lattice from HDF5 group @@ -92,7 +91,7 @@ def from_hdf5(group, universes): Group in HDF5 file universes : dict Dictionary mapping universe IDs to instances of - :class:`openmc.Universe`. + :class:`openmc.UniverseBase`. Returns ------- @@ -106,29 +105,29 @@ def from_hdf5(group, universes): elif lattice_type == 'hexagonal': return openmc.HexLattice.from_hdf5(group, universes) else: - raise ValueError('Unkown lattice type: {}'.format(lattice_type)) + raise ValueError(f'Unknown lattice type: {lattice_type}') def get_unique_universes(self): """Determine all unique universes in the lattice Returns ------- - universes : collections.OrderedDict + universes : dict Dictionary whose keys are universe IDs and values are - :class:`openmc.Universe` instances + :class:`openmc.UniverseBase` instances """ - univs = OrderedDict() + univs = {} for k in range(len(self._universes)): for j in range(len(self._universes[k])): - if isinstance(self._universes[k][j], openmc.Universe): + if isinstance(self._universes[k][j], openmc.UniverseBase): u = self._universes[k][j] univs[u._id] = u else: for i in range(len(self._universes[k][j])): u = self._universes[k][j][i] - assert isinstance(u, openmc.Universe) + assert isinstance(u, openmc.UniverseBase) univs[u._id] = u if self.outer is not None: @@ -164,12 +163,12 @@ def get_all_cells(self, memo=None): Returns ------- - cells : collections.OrderedDict + cells : dict Dictionary whose keys are cell IDs and values are :class:`Cell` instances """ - cells = OrderedDict() + cells = {} if memo and self in memo: return cells @@ -189,13 +188,13 @@ def get_all_materials(self, memo=None): Returns ------- - materials : collections.OrderedDict + materials : dict Dictionary whose keys are material IDs and values are :class:`Material` instances """ - materials = OrderedDict() + materials = {} # Append all Cells in each Cell in the Universe to the dictionary cells = self.get_all_cells(memo) @@ -209,7 +208,7 @@ def get_all_universes(self): Returns ------- - universes : collections.OrderedDict + universes : dict Dictionary whose keys are universe IDs and values are :class:`Universe` instances @@ -217,7 +216,7 @@ def get_all_universes(self): # Initialize a dictionary of all Universes contained by the Lattice # in each nested Universe level - all_universes = OrderedDict() + all_universes = {} # Get all unique Universes contained in each of the lattice cells unique_universes = self.get_unique_universes() @@ -246,7 +245,7 @@ def get_universe(self, idx): Returns ------- - openmc.Universe + openmc.UniverseBase Universe with given indices """ @@ -370,9 +369,9 @@ class RectLattice(Lattice): pitch : Iterable of float Pitch of the lattice in the x, y, and (if applicable) z directions in cm. - outer : openmc.Universe + outer : openmc.UniverseBase A universe to fill all space outside the lattice - universes : Iterable of Iterable of openmc.Universe + universes : Iterable of Iterable of openmc.UniverseBase A two- or three-dimensional list/array of universes filling each element of the lattice. The first dimension corresponds to the z-direction (if applicable), the second dimension corresponds to the y-direction, and @@ -416,7 +415,7 @@ def __repr__(self): # Lattice nested Universe IDs for i, universe in enumerate(np.ravel(self._universes)): - string += '{} '.format(universe._id) + string += f'{universe._id} ' # Add a newline character every time we reach end of row of cells if (i + 1) % self.shape[0] == 0: @@ -460,6 +459,12 @@ def _natural_indices(self): def lower_left(self): return self._lower_left + @lower_left.setter + def lower_left(self, lower_left): + cv.check_type('lattice lower left corner', lower_left, Iterable, Real) + cv.check_length('lattice lower left corner', lower_left, 2, 3) + self._lower_left = lower_left + @property def ndim(self): if self.pitch is not None: @@ -472,12 +477,6 @@ def ndim(self): def shape(self): return self._universes.shape[::-1] - @lower_left.setter - def lower_left(self, lower_left): - cv.check_type('lattice lower left corner', lower_left, Iterable, Real) - cv.check_length('lattice lower left corner', lower_left, 2, 3) - self._lower_left = lower_left - @Lattice.pitch.setter def pitch(self, pitch): cv.check_type('lattice pitch', pitch, Iterable, Real) @@ -488,7 +487,7 @@ def pitch(self, pitch): @Lattice.universes.setter def universes(self, universes): - cv.check_iterable_type('lattice universes', universes, openmc.Universe, + cv.check_iterable_type('lattice universes', universes, openmc.UniverseBase, min_depth=2, max_depth=3) self._universes = np.asarray(universes) @@ -633,11 +632,11 @@ def discretize(self, strategy="degenerate", cv.check_value('strategy', strategy, ('degenerate', 'lns')) cv.check_type('universes_to_ignore', universes_to_ignore, Iterable, - openmc.Universe) + openmc.UniverseBase) cv.check_type('materials_to_clone', materials_to_clone, Iterable, openmc.Material) cv.check_type('lattice_neighbors', lattice_neighbors, Iterable, - openmc.Universe) + openmc.UniverseBase) cv.check_value('number of lattice_neighbors', len(lattice_neighbors), (0, 8)) cv.check_type('key', key, types.FunctionType) @@ -833,7 +832,7 @@ def create_xml_subelement(self, xml_element, memo=None): Parameters ---------- - xml_element : xml.etree.ElementTree.Element + xml_element : lxml.etree._Element XML element to be added to memo : set or None @@ -852,6 +851,10 @@ def create_xml_subelement(self, xml_element, memo=None): if memo is not None: memo.add(self) + # Make sure universes have been assigned + if self.universes is None: + raise ValueError(f"Lattice {self.id} does not have universes assigned.") + lattice_subelement = ET.Element("lattice") lattice_subelement.set("id", str(self._id)) @@ -865,7 +868,7 @@ def create_xml_subelement(self, xml_element, memo=None): # Export the Lattice outer Universe (if specified) if self._outer is not None: outer = ET.SubElement(lattice_subelement, "outer") - outer.text = '{0}'.format(self._outer._id) + outer.text = str(self._outer._id) self._outer.create_xml_subelement(xml_element, memo) # Export Lattice cell dimensions @@ -876,7 +879,7 @@ def create_xml_subelement(self, xml_element, memo=None): lower_left = ET.SubElement(lattice_subelement, "lower_left") lower_left.text = ' '.join(map(str, self._lower_left)) - # Export the Lattice nested Universe IDs - column major for Fortran + # Export the Lattice nested Universe IDs universe_ids = '\n' # 3D Lattices @@ -887,7 +890,7 @@ def create_xml_subelement(self, xml_element, memo=None): universe = self._universes[z][y][x] # Append Universe ID to the Lattice XML subelement - universe_ids += '{0} '.format(universe._id) + universe_ids += f'{universe._id} ' # Create XML subelement for this Universe universe.create_xml_subelement(xml_element, memo) @@ -905,7 +908,7 @@ def create_xml_subelement(self, xml_element, memo=None): universe = self._universes[y][x] # Append Universe ID to Lattice XML subelement - universe_ids += '{0} '.format(universe._id) + universe_ids += f'{universe._id} ' # Create XML subelement for this Universe universe.create_xml_subelement(xml_element, memo) @@ -928,7 +931,7 @@ def from_xml_element(cls, elem, get_universe): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element `` element get_universe : function Function returning universe (defined in @@ -969,7 +972,7 @@ def from_hdf5(cls, group, universes): Group in HDF5 file universes : dict Dictionary mapping universe IDs to instances of - :class:`openmc.Universe`. + :class:`openmc.UniverseBase`. Returns ------- @@ -995,7 +998,7 @@ def from_hdf5(cls, group, universes): lattice.outer = universes[outer] # Build array of Universe pointers for the Lattice - uarray = np.empty(universe_ids.shape, dtype=openmc.Universe) + uarray = np.empty(universe_ids.shape, dtype=openmc.UniverseBase) for z in range(universe_ids.shape[0]): for y in range(universe_ids.shape[1]): @@ -1050,9 +1053,9 @@ class HexLattice(Lattice): Pitch of the lattice in cm. The first item in the iterable specifies the pitch in the radial direction and, if the lattice is 3D, the second item in the iterable specifies the pitch in the axial direction. - outer : openmc.Universe + outer : openmc.UniverseBase A universe to fill all space outside the lattice - universes : Nested Iterable of openmc.Universe + universes : Nested Iterable of openmc.UniverseBase A two- or three-dimensional list/array of universes filling each element of the lattice. Each sub-list corresponds to one ring of universes and should be ordered from outermost ring to innermost ring. The universes @@ -1124,6 +1127,11 @@ def num_rings(self): def orientation(self): return self._orientation + @orientation.setter + def orientation(self, orientation): + cv.check_value('orientation', orientation.lower(), ('x', 'y')) + self._orientation = orientation.lower() + @property def num_axial(self): return self._num_axial @@ -1132,6 +1140,12 @@ def num_axial(self): def center(self): return self._center + @center.setter + def center(self, center): + cv.check_type('lattice center', center, Iterable, Real) + cv.check_length('lattice center', center, 2, 3) + self._center = center + @property def indices(self): if self.num_axial is None: @@ -1169,18 +1183,7 @@ def _natural_indices(self): @property def ndim(self): - return 2 if isinstance(self.universes[0][0], openmc.Universe) else 3 - - @center.setter - def center(self, center): - cv.check_type('lattice center', center, Iterable, Real) - cv.check_length('lattice center', center, 2, 3) - self._center = center - - @orientation.setter - def orientation(self, orientation): - cv.check_value('orientation', orientation.lower(), ('x', 'y')) - self._orientation = orientation.lower() + return 2 if isinstance(self.universes[0][0], openmc.UniverseBase) else 3 @Lattice.pitch.setter def pitch(self, pitch): @@ -1192,7 +1195,7 @@ def pitch(self, pitch): @Lattice.universes.setter def universes(self, universes): - cv.check_iterable_type('lattice universes', universes, openmc.Universe, + cv.check_iterable_type('lattice universes', universes, openmc.UniverseBase, min_depth=2, max_depth=3) self._universes = universes @@ -1215,7 +1218,7 @@ def universes(self, universes): for rings in self._universes: if len(rings) != self._num_rings: msg = 'HexLattice ID={0:d} has an inconsistent number of ' \ - 'rings per axial positon'.format(self._id) + 'rings per axial position'.format(self._id) raise ValueError(msg) else: @@ -1432,7 +1435,7 @@ def create_xml_subelement(self, xml_element, memo=None): # Export the Lattice outer Universe (if specified) if self._outer is not None: outer = ET.SubElement(lattice_subelement, "outer") - outer.text = '{0}'.format(self._outer._id) + outer.text = str(self._outer._id) self._outer.create_xml_subelement(xml_element, memo) lattice_subelement.set("n_rings", str(self._num_rings)) @@ -1448,6 +1451,8 @@ def create_xml_subelement(self, xml_element, memo=None): center.text = ' '.join(map(str, self._center)) # Export the Lattice nested Universe IDs. + if self.universes is None: + raise ValueError(f"Lattice {self.id} does not have universes assigned.") # 3D Lattices if self._num_axial is not None: @@ -1496,7 +1501,7 @@ def from_xml_element(cls, elem, get_universe): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element `` element get_universe : function Function returning universe (defined in @@ -1846,7 +1851,7 @@ def _show_indices_y(num_rings): largest_index = 6*(num_rings - 1) n_digits_index = len(str(largest_index)) n_digits_ring = len(str(num_rings - 1)) - str_form = '({{:{}}},{{:{}}})'.format(n_digits_ring, n_digits_index) + str_form = f'({{:{n_digits_ring}}},{{:{n_digits_index}}})' pad = ' '*(n_digits_index + n_digits_ring + 3) # Initialize the list for each row. @@ -1951,7 +1956,7 @@ def _show_indices_x(num_rings): largest_index = 6*(num_rings - 1) n_digits_index = len(str(largest_index)) n_digits_ring = len(str(num_rings - 1)) - str_form = '({{:{}}},{{:{}}})'.format(n_digits_ring, n_digits_index) + str_form = f'({{:{n_digits_ring}}},{{:{n_digits_index}}})' pad = ' '*(n_digits_index + n_digits_ring + 3) # Initialize the list for each row. @@ -2046,12 +2051,12 @@ def from_hdf5(cls, group, universes): Group in HDF5 file universes : dict Dictionary mapping universe IDs to instances of - :class:`openmc.Universe`. + :class:`openmc.UniverseBase`. Returns ------- - openmc.RectLattice - Rectangular lattice + openmc.HexLattice + Hexagonal lattice """ n_rings = group['n_rings'][()] diff --git a/openmc/lib/__init__.py b/openmc/lib/__init__.py index 82dc92ba483..42d77944146 100644 --- a/openmc/lib/__init__.py +++ b/openmc/lib/__init__.py @@ -28,7 +28,7 @@ if os.environ.get('READTHEDOCS', None) != 'True': # Open shared library _filename = pkg_resources.resource_filename( - __name__, 'libopenmc.{}'.format(_suffix)) + __name__, f'libopenmc.{_suffix}') _dll = CDLL(_filename) else: # For documentation builds, we don't actually have the shared library @@ -42,12 +42,22 @@ def _dagmc_enabled(): return c_bool.in_dll(_dll, "DAGMC_ENABLED").value +def _ncrystal_enabled(): + return c_bool.in_dll(_dll, "NCRYSTAL_ENABLED").value + def _coord_levels(): return c_int.in_dll(_dll, "n_coord_levels").value def _libmesh_enabled(): return c_bool.in_dll(_dll, "LIBMESH_ENABLED").value +def _mcpl_enabled(): + return c_bool.in_dll(_dll, "MCPL_ENABLED").value + +def _uwuw_enabled(): + return c_bool.in_dll(_dll, "UWUW_ENABLED").value + + from .error import * from .core import * from .nuclide import * @@ -59,3 +69,9 @@ def _libmesh_enabled(): from .settings import settings from .math import * from .plot import * +from .weight_windows import * + +# Flag to denote whether or not openmc.lib.init has been called +# TODO: Establish and use a flag in the C++ code to represent the status of the +# openmc_init and openmc_finalize methods +is_initialized = False diff --git a/openmc/lib/cell.py b/openmc/lib/cell.py index c69d1e2a402..971a24cba91 100644 --- a/openmc/lib/cell.py +++ b/openmc/lib/cell.py @@ -1,7 +1,7 @@ import sys from collections.abc import Mapping, Iterable -from ctypes import c_int, c_int32, c_double, c_char_p, POINTER, c_bool +from ctypes import c_int, c_int32, c_double, c_char_p, POINTER, c_bool, c_size_t from weakref import WeakValueDictionary import numpy as np @@ -11,6 +11,8 @@ from .core import _FortranObjectWithID from .error import _error_handler from .material import Material +from ..bounding_box import BoundingBox + __all__ = ['Cell', 'cells'] @@ -25,6 +27,9 @@ c_int32, POINTER(c_int), POINTER(POINTER(c_int32)), POINTER(c_int32)] _dll.openmc_cell_get_fill.restype = c_int _dll.openmc_cell_get_fill.errcheck = _error_handler +_dll.openmc_cell_get_num_instances.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_cell_get_num_instances.restype = c_int +_dll.openmc_cell_get_num_instances.errcheck = _error_handler _dll.openmc_cell_get_temperature.argtypes = [ c_int32, POINTER(c_int32), POINTER(c_double)] _dll.openmc_cell_get_temperature.restype = c_int @@ -32,6 +37,13 @@ _dll.openmc_cell_get_name.argtypes = [c_int32, POINTER(c_char_p)] _dll.openmc_cell_get_name.restype = c_int _dll.openmc_cell_get_name.errcheck = _error_handler +_dll.openmc_cell_get_translation.argtypes = [c_int32, POINTER(c_double)] +_dll.openmc_cell_get_translation.restype = c_int +_dll.openmc_cell_get_translation.errcheck = _error_handler +_dll.openmc_cell_get_rotation.argtypes = [c_int32, POINTER(c_double), + POINTER(c_size_t)] +_dll.openmc_cell_get_rotation.restype = c_int +_dll.openmc_cell_get_rotation.errcheck = _error_handler _dll.openmc_cell_set_name.argtypes = [c_int32, c_char_p] _dll.openmc_cell_set_name.restype = c_int _dll.openmc_cell_set_name.errcheck = _error_handler @@ -46,6 +58,13 @@ c_int32, c_double, POINTER(c_int32), c_bool] _dll.openmc_cell_set_temperature.restype = c_int _dll.openmc_cell_set_temperature.errcheck = _error_handler +_dll.openmc_cell_set_translation.argtypes = [c_int32, POINTER(c_double)] +_dll.openmc_cell_set_translation.restype = c_int +_dll.openmc_cell_set_translation.errcheck = _error_handler +_dll.openmc_cell_set_rotation.argtypes = [ + c_int32, POINTER(c_double), c_size_t] +_dll.openmc_cell_set_rotation.restype = c_int +_dll.openmc_cell_set_rotation.errcheck = _error_handler _dll.openmc_get_cell_index.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_cell_index.restype = c_int _dll.openmc_get_cell_index.errcheck = _error_handler @@ -78,6 +97,21 @@ class Cell(_FortranObjectWithID): ---------- id : int ID of the cell + fill : openmc.lib.Material or list of openmc.lib.Material + Indicates what the region of space is filled with + name : str + Name of the cell + num_instances : int + Number of unique cell instances + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the cell + translation : Iterable of float + 3-D coordinates of the translation vector + rotation : Iterable of float + The rotation matrix or angles of the universe filling the cell. This + can either be a fully specified 3 x 3 rotation matrix or an Iterable + of length 3 with the angles in degrees about the x, y, and z axes, + respectively. """ __instances = WeakValueDictionary() @@ -159,6 +193,12 @@ def fill(self, fill): indices = (c_int32*1)(-1) _dll.openmc_cell_set_fill(self._index, 0, 1, indices) + @property + def num_instances(self): + n = c_int32() + _dll.openmc_cell_get_num_instances(self._index, n) + return n.value + def get_temperature(self, instance=None): """Get the temperature of a cell @@ -196,6 +236,48 @@ def set_temperature(self, T, instance=None, set_contained=False): _dll.openmc_cell_set_temperature(self._index, T, instance, set_contained) + @property + def translation(self): + translation = np.zeros(3) + _dll.openmc_cell_get_translation( + self._index, translation.ctypes.data_as(POINTER(c_double))) + return translation + + @translation.setter + def translation(self, translation_vec): + vector = np.asarray(translation_vec, dtype=float) + _dll.openmc_cell_set_translation( + self._index, vector.ctypes.data_as(POINTER(c_double))) + + @property + def rotation(self): + rotation_data = np.zeros(12) + rot_size = c_size_t() + + _dll.openmc_cell_get_rotation( + self._index, rotation_data.ctypes.data_as(POINTER(c_double)), + rot_size) + rot_size = rot_size.value + + if rot_size == 9: + return rotation_data[:rot_size].shape(3, 3) + elif rot_size in (0, 12): + # If size is 0, rotation_data[9:] will be zeros. This indicates no + # rotation and is the most straightforward way to always return + # an iterable of floats + return rotation_data[9:] + else: + raise ValueError( + f'Invalid size of rotation matrix: {rot_size}') + + @rotation.setter + def rotation(self, rotation_data): + flat_rotation = np.asarray(rotation_data, dtype=float).flatten() + + _dll.openmc_cell_set_rotation( + self._index, flat_rotation.ctypes.data_as(POINTER(c_double)), + c_size_t(len(flat_rotation))) + @property def bounding_box(self): inf = sys.float_info.max @@ -209,7 +291,8 @@ def bounding_box(self): llc[llc == -inf] = -np.inf urc[urc == -inf] = -np.inf - return llc, urc + return BoundingBox(llc, urc) + class _CellMapping(Mapping): def __getitem__(self, key): diff --git a/openmc/lib/core.py b/openmc/lib/core.py index e740e28699a..a9a549fa05a 100644 --- a/openmc/lib/core.py +++ b/openmc/lib/core.py @@ -1,20 +1,26 @@ from contextlib import contextmanager from ctypes import (c_bool, c_int, c_int32, c_int64, c_double, c_char_p, - c_char, POINTER, Structure, c_void_p, create_string_buffer) + c_char, POINTER, Structure, c_void_p, create_string_buffer, + c_uint64, c_size_t) import sys +import os +from random import getrandbits import numpy as np from numpy.ctypeslib import as_array from . import _dll from .error import _error_handler +from openmc.checkvalue import PathLike import openmc.lib +import openmc class _SourceSite(Structure): _fields_ = [('r', c_double*3), ('u', c_double*3), ('E', c_double), + ('time', c_double), ('wgt', c_double), ('delayed_group', c_int), ('surf_id', c_int), @@ -62,7 +68,13 @@ class _SourceSite(Structure): _dll.openmc_next_batch.restype = c_int _dll.openmc_next_batch.errcheck = _error_handler _dll.openmc_plot_geometry.restype = c_int -_dll.openmc_plot_geometry.restype = _error_handler +_dll.openmc_plot_geometry.errcheck = _error_handler +_dll.openmc_properties_export.argtypes = [c_char_p] +_dll.openmc_properties_export.restype = c_int +_dll.openmc_properties_export.errcheck = _error_handler +_dll.openmc_properties_import.argtypes = [c_char_p] +_dll.openmc_properties_import.restype = c_int +_dll.openmc_properties_import.errcheck = _error_handler _dll.openmc_run.restype = c_int _dll.openmc_run.errcheck = _error_handler _dll.openmc_reset.restype = c_int @@ -83,11 +95,18 @@ class _SourceSite(Structure): _dll.openmc_statepoint_write.argtypes = [c_char_p, POINTER(c_bool)] _dll.openmc_statepoint_write.restype = c_int _dll.openmc_statepoint_write.errcheck = _error_handler +_dll.openmc_statepoint_load.argtypes = [c_char_p] +_dll.openmc_statepoint_load.restype = c_int +_dll.openmc_statepoint_load.errcheck = _error_handler +_dll.openmc_statepoint_write.restype = c_int +_dll.openmc_statepoint_write.errcheck = _error_handler _dll.openmc_global_bounding_box.argtypes = [POINTER(c_double), POINTER(c_double)] _dll.openmc_global_bounding_box.restype = c_int _dll.openmc_global_bounding_box.errcheck = _error_handler - +_dll.openmc_sample_external_source.argtypes = [c_size_t, POINTER(c_uint64), POINTER(_SourceSite)] +_dll.openmc_sample_external_source.restype = c_int +_dll.openmc_sample_external_source.errcheck = _error_handler def global_bounding_box(): """Calculate a global bounding box for the model""" @@ -103,9 +122,22 @@ def global_bounding_box(): return llc, urc -def calculate_volumes(): - """Run stochastic volume calculation""" - _dll.openmc_calculate_volumes() + +def calculate_volumes(output=True): + """Run stochastic volume calculation + + .. versionchanged:: 0.13.0 + The *output* argument was added. + + Parameters + ---------- + output : bool, optional + Whether or not to show output. Defaults to showing output + + """ + + with quiet_dll(output): + _dll.openmc_calculate_volumes() def current_batch(): @@ -120,9 +152,82 @@ def current_batch(): return c_int.in_dll(_dll, 'current_batch').value +def export_properties(filename=None, output=True): + """Export physical properties. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + filename : str or None + Filename to export properties to (defaults to "properties.h5") + output : bool, optional + Whether or not to show output. Defaults to showing output + + See Also + -------- + openmc.lib.import_properties + + """ + if filename is not None: + filename = c_char_p(filename.encode()) + + with quiet_dll(output): + _dll.openmc_properties_export(filename) + + +def export_weight_windows(filename="weight_windows.h5", output=True): + """Export weight windows. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + filename : PathLike or None + Filename to export weight windows to + output : bool, optional + Whether or not to show output. + + See Also + -------- + openmc.lib.import_weight_windows + + """ + if filename is not None: + filename = c_char_p(str(filename).encode()) + + with quiet_dll(output): + _dll.openmc_weight_windows_export(filename) + + +def import_weight_windows(filename='weight_windows.h5', output=True): + """Import weight windows. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + filename : PathLike or None + Filename to import weight windows from + output : bool, optional + Whether or not to show output. + + See Also + -------- + openmc.lib.export_weight_windows + + """ + if filename is not None: + filename = c_char_p(str(filename).encode()) + + with quiet_dll(output): + _dll.openmc_weight_windows_import(filename) + + def finalize(): """Finalize simulation and free memory""" _dll.openmc_finalize() + openmc.lib.is_initialized = False def find_cell(xyz): @@ -178,15 +283,38 @@ def hard_reset(): _dll.openmc_hard_reset() -def init(args=None, intracomm=None): +def import_properties(filename): + """Import physical properties. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + filename : str + Filename to import properties from + + See Also + -------- + openmc.lib.export_properties + + """ + _dll.openmc_properties_import(filename.encode()) + + +def init(args=None, intracomm=None, output=True): """Initialize OpenMC + .. versionchanged:: 0.13.0 + The *output* argument was added. + Parameters ---------- - args : list of str + args : list of str, optional Command-line arguments - intracomm : mpi4py.MPI.Intracomm or None + intracomm : mpi4py.MPI.Intracomm or None, optional MPI intracommunicator + output : bool, optional + Whether or not to show output. Defaults to showing output """ if args is not None: @@ -212,7 +340,9 @@ def init(args=None, intracomm=None): address = MPI._addressof(intracomm) intracomm = c_void_p(address) - _dll.openmc_init(argc, argv, intracomm) + with quiet_dll(output): + _dll.openmc_init(argc, argv, intracomm) + openmc.lib.is_initialized = True def is_statepoint_batch(): @@ -302,9 +432,20 @@ def next_batch(): return status.value -def plot_geometry(): - """Plot geometry""" - _dll.openmc_plot_geometry() +def plot_geometry(output=True): + """Plot geometry + + .. versionchanged:: 0.13.0 + The *output* argument was added. + + Parameters + ---------- + output : bool, optional + Whether or not to show output. Defaults to showing output + """ + + with quiet_dll(output): + _dll.openmc_plot_geometry() def reset(): @@ -317,9 +458,59 @@ def reset_timers(): _dll.openmc_reset_timers() -def run(): - """Run simulation""" - _dll.openmc_run() +def run(output=True): + """Run simulation + + .. versionchanged:: 0.13.0 + The *output* argument was added. + + Parameters + ---------- + output : bool, optional + Whether or not to show output. Defaults to showing output + """ + + with quiet_dll(output): + _dll.openmc_run() + + +def sample_external_source(n_samples=1, prn_seed=None): + """Sample external source + + .. versionadded:: 0.13.1 + + Parameters + ---------- + n_samples : int + Number of samples + prn_seed : int + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. + + Returns + ------- + list of openmc.SourceParticle + List of samples source particles + + """ + if n_samples <= 0: + raise ValueError("Number of samples must be positive") + if prn_seed is None: + prn_seed = getrandbits(63) + + # Call into C API to sample source + sites_array = (_SourceSite * n_samples)() + _dll.openmc_sample_external_source(c_size_t(n_samples), c_uint64(prn_seed), sites_array) + + # Convert to list of SourceParticle and return + return [ + openmc.SourceParticle( + r=site.r, u=site.u, E=site.E, time=site.time, wgt=site.wgt, + delayed_group=site.delayed_group, surf_id=site.surf_id, + particle=openmc.ParticleType(site.particle) + ) + for site in sites_array + ] def simulation_init(): @@ -382,6 +573,19 @@ def statepoint_write(filename=None, write_source=True): _dll.openmc_statepoint_write(filename, c_bool(write_source)) +def statepoint_load(filename: PathLike): + """Load a statepoint file. + + Parameters + ---------- + filename : path-like + Path to the statepoint to load. + + """ + filename = c_char_p(str(filename).encode()) + _dll.openmc_statepoint_load(filename) + + @contextmanager def run_in_memory(**kwargs): """Provides context manager for calling OpenMC shared library functions. @@ -425,7 +629,7 @@ def __set__(self, instance, value): class _FortranObject: def __repr__(self): - return "{}[{}]".format(type(self).__name__, self._index) + return f"<{type(self).__name__}(index={self._index})>" class _FortranObjectWithID(_FortranObject): @@ -435,3 +639,49 @@ def __init__(self, uid=None, new=True, index=None): # assigned. If the array index of the object is out of bounds, an # OutOfBoundsError will be raised here by virtue of referencing self.id self.id + + def __repr__(self): + return f"<{type(self).__name__}(id={self.id})>" + + +@contextmanager +def quiet_dll(output=True): + """This context manager allows us to suppress standard output from DLLs + + Parameters + ---------- + output : bool + Denotes whether the output should be displayed (True) or not (False) + + .. versionadded:: 0.13.0 + + """ + + # This contextmanager is modified from that provided here: + # https://stackoverflow.com/a/14797594 + + if output: + yield + else: + sys.stdout.flush() + # Save the initial file descriptor states + initial_stdout = sys.stdout + initial_stdout_fno = os.dup(sys.stdout.fileno()) + # Get a garbage descriptor so we can throw away output + devnull = os.open(os.devnull, os.O_WRONLY) + + # Get the current stdout stream and make a duplicate of it + new_stdout = os.dup(1) + # Copy the garbage output to the stdout stream + os.dup2(devnull, 1) + os.close(devnull) + # Now point stdout to the re-defined stdout + sys.stdout = os.fdopen(new_stdout, 'w') + + try: + yield + finally: + # Now we just clean up after ourselves and reset the streams + sys.stdout = initial_stdout + sys.stdout.flush() + os.dup2(initial_stdout_fno, 1) diff --git a/openmc/lib/error.py b/openmc/lib/error.py index 89e7b6e3903..dbe08e1ef8b 100644 --- a/openmc/lib/error.py +++ b/openmc/lib/error.py @@ -37,5 +37,5 @@ def errcode(s): warn(msg) elif err < 0: if not msg: - msg = "Unknown error encountered (code {}).".format(err) + msg = f"Unknown error encountered (code {err})." raise exc.OpenMCError(msg) diff --git a/openmc/lib/filter.py b/openmc/lib/filter.py index 5d2231cc2e8..340c2fa3448 100644 --- a/openmc/lib/filter.py +++ b/openmc/lib/filter.py @@ -7,6 +7,8 @@ from numpy.ctypeslib import as_array from openmc.exceptions import AllocationError, InvalidIDError +from openmc.data.function import INTERPOLATION_SCHEME +from openmc import ParticleType from . import _dll from .core import _FortranObjectWithID from .error import _error_handler @@ -16,9 +18,10 @@ __all__ = [ 'Filter', 'AzimuthalFilter', 'CellFilter', 'CellbornFilter', 'CellfromFilter', - 'CellInstanceFilter', 'CollisionFilter', 'DistribcellFilter', 'DelayedGroupFilter', - 'EnergyFilter', 'EnergyoutFilter', 'EnergyFunctionFilter', 'LegendreFilter', - 'MaterialFilter', 'MeshFilter', 'MeshSurfaceFilter', 'MuFilter', 'ParticleFilter', + 'CellInstanceFilter', 'CollisionFilter', 'DistribcellFilter', 'DelayedGroupFilter', + 'EnergyFilter', 'EnergyoutFilter', 'EnergyFunctionFilter', 'LegendreFilter', + 'MaterialFilter', 'MaterialFromFilter', 'MeshFilter', 'MeshBornFilter', + 'MeshSurfaceFilter', 'MuFilter', 'ParticleFilter', 'PolarFilter', 'SphericalHarmonicsFilter', 'SpatialLegendreFilter', 'SurfaceFilter', 'UniverseFilter', 'ZernikeFilter', 'ZernikeRadialFilter', 'filters' ] @@ -47,9 +50,18 @@ _dll.openmc_energyfunc_filter_get_y.errcheck = _error_handler _dll.openmc_energyfunc_filter_get_y.argtypes = [ c_int32, POINTER(c_size_t), POINTER(POINTER(c_double))] +_dll.openmc_energyfunc_filter_get_interpolation.resttpe = c_int +_dll.openmc_energyfunc_filter_get_interpolation.errcheck = _error_handler +_dll.openmc_energyfunc_filter_get_interpolation.argtypes = [c_int32, POINTER(c_int)] +_dll.openmc_energyfunc_filter_set_interpolation.resttpe = c_int +_dll.openmc_energyfunc_filter_set_interpolation.errcheck = _error_handler +_dll.openmc_energyfunc_filter_set_interpolation.argtypes = [c_int32, c_char_p] _dll.openmc_filter_get_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_filter_get_id.restype = c_int _dll.openmc_filter_get_id.errcheck = _error_handler +_dll.openmc_filter_get_num_bins.argtypes = [c_int32, POINTER(c_int)] +_dll.openmc_filter_get_num_bins.restype = c_int +_dll.openmc_filter_get_num_bins.errchck = _error_handler _dll.openmc_filter_get_type.argtypes = [c_int32, c_char_p] _dll.openmc_filter_get_type.restype = c_int _dll.openmc_filter_get_type.errcheck = _error_handler @@ -78,18 +90,36 @@ _dll.openmc_mesh_filter_set_mesh.argtypes = [c_int32, c_int32] _dll.openmc_mesh_filter_set_mesh.restype = c_int _dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler -_dll.openmc_meshsurface_filter_get_mesh.argtypes = [c_int32, POINTER(c_int32)] -_dll.openmc_meshsurface_filter_get_mesh.restype = c_int -_dll.openmc_meshsurface_filter_get_mesh.errcheck = _error_handler -_dll.openmc_meshsurface_filter_set_mesh.argtypes = [c_int32, c_int32] -_dll.openmc_meshsurface_filter_set_mesh.restype = c_int -_dll.openmc_meshsurface_filter_set_mesh.errcheck = _error_handler _dll.openmc_mesh_filter_get_translation.argtypes = [c_int32, POINTER(c_double*3)] _dll.openmc_mesh_filter_get_translation.restype = c_int _dll.openmc_mesh_filter_get_translation.errcheck = _error_handler _dll.openmc_mesh_filter_set_translation.argtypes = [c_int32, POINTER(c_double*3)] _dll.openmc_mesh_filter_set_translation.restype = c_int _dll.openmc_mesh_filter_set_translation.errcheck = _error_handler +_dll.openmc_meshborn_filter_get_mesh.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_meshborn_filter_get_mesh.restype = c_int +_dll.openmc_meshborn_filter_get_mesh.errcheck = _error_handler +_dll.openmc_meshborn_filter_set_mesh.argtypes = [c_int32, c_int32] +_dll.openmc_meshborn_filter_set_mesh.restype = c_int +_dll.openmc_meshborn_filter_set_mesh.errcheck = _error_handler +_dll.openmc_meshborn_filter_get_translation.argtypes = [c_int32, POINTER(c_double*3)] +_dll.openmc_meshborn_filter_get_translation.restype = c_int +_dll.openmc_meshborn_filter_get_translation.errcheck = _error_handler +_dll.openmc_meshborn_filter_set_translation.argtypes = [c_int32, POINTER(c_double*3)] +_dll.openmc_meshborn_filter_set_translation.restype = c_int +_dll.openmc_meshborn_filter_set_translation.errcheck = _error_handler +_dll.openmc_meshsurface_filter_get_mesh.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_meshsurface_filter_get_mesh.restype = c_int +_dll.openmc_meshsurface_filter_get_mesh.errcheck = _error_handler +_dll.openmc_meshsurface_filter_set_mesh.argtypes = [c_int32, c_int32] +_dll.openmc_meshsurface_filter_set_mesh.restype = c_int +_dll.openmc_meshsurface_filter_set_mesh.errcheck = _error_handler +_dll.openmc_meshsurface_filter_get_translation.argtypes = [c_int32, POINTER(c_double*3)] +_dll.openmc_meshsurface_filter_get_translation.restype = c_int +_dll.openmc_meshsurface_filter_get_translation.errcheck = _error_handler +_dll.openmc_meshsurface_filter_set_translation.argtypes = [c_int32, POINTER(c_double*3)] +_dll.openmc_meshsurface_filter_set_translation.restype = c_int +_dll.openmc_meshsurface_filter_set_translation.errcheck = _error_handler _dll.openmc_new_filter.argtypes = [c_char_p, POINTER(c_int32)] _dll.openmc_new_filter.restype = c_int _dll.openmc_new_filter.errcheck = _error_handler @@ -113,7 +143,6 @@ _dll.openmc_zernike_filter_set_order.errcheck = _error_handler _dll.tally_filters_size.restype = c_size_t - class Filter(_FortranObjectWithID): __instances = WeakValueDictionary() @@ -156,6 +185,12 @@ def id(self): def id(self, filter_id): _dll.openmc_filter_set_id(self._index, filter_id) + @property + def n_bins(self): + n = c_int() + _dll.openmc_filter_get_num_bins(self._index, n) + return n.value + class EnergyFilter(Filter): filter_type = 'energy' @@ -247,6 +282,8 @@ def set_data(self, energy, y): Independent variable for the interpolation y : numpy.ndarray Dependent variable for the interpolation + interpolation : {'histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log', 'quadratic', 'cubic'} + Interpolation scheme """ energy_array = np.asarray(energy) y_array = np.asarray(y) @@ -264,6 +301,17 @@ def energy(self): def y(self): return self._get_attr(_dll.openmc_energyfunc_filter_get_y) + @property + def interpolation(self) -> str: + interp = c_int() + _dll.openmc_energyfunc_filter_get_interpolation(self._index, interp) + return INTERPOLATION_SCHEME[interp.value] + + @interpolation.setter + def interpolation(self, interp: str): + interp_ptr = c_char_p(interp.encode()) + _dll.openmc_energyfunc_filter_set_interpolation(self._index, interp_ptr) + def _get_attr(self, cfunc): array_p = POINTER(c_double)() n = c_size_t() @@ -313,7 +361,39 @@ def bins(self, materials): _dll.openmc_material_filter_set_bins(self._index, n, bins) +class MaterialFromFilter(Filter): + filter_type = 'materialfrom' + + class MeshFilter(Filter): + """Mesh filter stored internally. + + This class exposes a Mesh filter that is stored internally in the OpenMC + library. To obtain a view of a Mesh filter with a given ID, use the + :data:`openmc.lib.filters` mapping. + + Parameters + ---------- + mesh : openmc.lib.Mesh + Mesh to use for the filter + uid : int or None + Unique ID of the Mesh filter + new : bool + When `index` is None, this argument controls whether a new object is + created or a view of an existing object is returned. + index : int + Index in the `filters` array. + + Attributes + ---------- + filter_type : str + Type of filter + mesh : openmc.lib.Mesh + Mesh used for the filter + translation : Iterable of float + 3-D coordinates of the translation vector + + """ filter_type = 'mesh' def __init__(self, mesh=None, uid=None, new=True, index=None): @@ -342,7 +422,92 @@ def translation(self, translation): _dll.openmc_mesh_filter_set_translation(self._index, (c_double*3)(*translation)) +class MeshBornFilter(Filter): + """MeshBorn filter stored internally. + + This class exposes a MeshBorn filter that is stored internally in the OpenMC + library. To obtain a view of a MeshBorn filter with a given ID, use the + :data:`openmc.lib.filters` mapping. + + Parameters + ---------- + mesh : openmc.lib.Mesh + Mesh to use for the filter + uid : int or None + Unique ID of the MeshBorn filter + new : bool + When `index` is None, this argument controls whether a new object is + created or a view of an existing object is returned. + index : int + Index in the `filters` array. + + Attributes + ---------- + filter_type : str + Type of filter + mesh : openmc.lib.Mesh + Mesh used for the filter + translation : Iterable of float + 3-D coordinates of the translation vector + + """ + filter_type = 'meshborn' + + def __init__(self, mesh=None, uid=None, new=True, index=None): + super().__init__(uid, new, index) + if mesh is not None: + self.mesh = mesh + + @property + def mesh(self): + index_mesh = c_int32() + _dll.openmc_meshborn_filter_get_mesh(self._index, index_mesh) + return _get_mesh(index_mesh.value) + + @mesh.setter + def mesh(self, mesh): + _dll.openmc_meshborn_filter_set_mesh(self._index, mesh._index) + + @property + def translation(self): + translation = (c_double*3)() + _dll.openmc_meshborn_filter_get_translation(self._index, translation) + return tuple(translation) + + @translation.setter + def translation(self, translation): + _dll.openmc_meshborn_filter_set_translation(self._index, (c_double*3)(*translation)) + + class MeshSurfaceFilter(Filter): + """MeshSurface filter stored internally. + + This class exposes a MeshSurface filter that is stored internally in the + OpenMC library. To obtain a view of a MeshSurface filter with a given ID, + use the :data:`openmc.lib.filters` mapping. + + Parameters + ---------- + mesh : openmc.lib.Mesh + Mesh to use for the filter + uid : int or None + Unique ID of the MeshSurface filter + new : bool + When `index` is None, this argument controls whether a new object is + created or a view of an existing object is returned. + index : int + Index in the `filters` array. + + Attributes + ---------- + filter_type : str + Type of filter + mesh : openmc.lib.Mesh + Mesh used for the filter + translation : Iterable of float + 3-D coordinates of the translation vector + + """ filter_type = 'meshsurface' def __init__(self, mesh=None, uid=None, new=True, index=None): @@ -363,12 +528,12 @@ def mesh(self, mesh): @property def translation(self): translation = (c_double*3)() - _dll.openmc_mesh_filter_get_translation(self._index, translation) + _dll.openmc_meshsurface_filter_get_translation(self._index, translation) return tuple(translation) @translation.setter def translation(self, translation): - _dll.openmc_mesh_filter_set_translation(self._index, (c_double*3)(*translation)) + _dll.openmc_meshsurface_filter_set_translation(self._index, (c_double*3)(*translation)) class MuFilter(Filter): @@ -378,6 +543,13 @@ class MuFilter(Filter): class ParticleFilter(Filter): filter_type = 'particle' + @property + def bins(self): + particle_i = np.zeros((self.n_bins,), dtype=c_int) + _dll.openmc_particle_filter_get_bins( + self._index, particle_i.ctypes.data_as(POINTER(c_int))) + return [ParticleType(i) for i in particle_i] + class PolarFilter(Filter): filter_type = 'polar' @@ -465,7 +637,9 @@ class ZernikeRadialFilter(ZernikeFilter): 'energyfunction': EnergyFunctionFilter, 'legendre': LegendreFilter, 'material': MaterialFilter, + 'materialfrom': MaterialFromFilter, 'mesh': MeshFilter, + 'meshborn': MeshBornFilter, 'meshsurface': MeshSurfaceFilter, 'mu': MuFilter, 'particle': ParticleFilter, diff --git a/openmc/lib/material.py b/openmc/lib/material.py index 6f80abb5e29..0ed8932da8f 100644 --- a/openmc/lib/material.py +++ b/openmc/lib/material.py @@ -1,5 +1,5 @@ from collections.abc import Mapping -from ctypes import c_int, c_int32, c_double, c_char_p, POINTER, c_size_t +from ctypes import c_bool, c_int, c_int32, c_double, c_char_p, POINTER, c_size_t from weakref import WeakValueDictionary import numpy as np @@ -60,6 +60,12 @@ _dll.openmc_material_set_volume.argtypes = [c_int32, c_double] _dll.openmc_material_set_volume.restype = c_int _dll.openmc_material_set_volume.errcheck = _error_handler +_dll.openmc_material_get_depletable.argtypes = [c_int32, POINTER(c_bool)] +_dll.openmc_material_get_depletable.restype = c_int +_dll.openmc_material_get_depletable.errcheck = _error_handler +_dll.openmc_material_set_depletable.argtypes = [c_int32, c_bool] +_dll.openmc_material_set_depletable.restype = c_int +_dll.openmc_material_set_depletable.errcheck = _error_handler _dll.n_materials.argtypes = [] _dll.n_materials.restype = c_size_t @@ -89,6 +95,8 @@ class Material(_FortranObjectWithID): List of nuclides in the material densities : numpy.ndarray Array of densities in atom/b-cm + depletable : bool + Whether this material is marked as depletable name : str Name of the material temperature : float @@ -170,18 +178,18 @@ def volume(self, volume): _dll.openmc_material_set_volume(self._index, volume) @property - def nuclides(self): - return self._get_densities()[0] - return nuclides + def depletable(self): + depletable = c_bool() + _dll.openmc_material_get_depletable(self._index, depletable) + return depletable.value + + @depletable.setter + def depletable(self, depletable): + _dll.openmc_material_set_depletable(self._index, depletable) @property - def density(self): - density = c_double() - try: - _dll.openmc_material_get_density(self._index, density) - except OpenMCError: - return None - return density.value + def nuclides(self): + return self._get_densities()[0] @property def densities(self): @@ -224,6 +232,29 @@ def add_nuclide(self, name, density): """ _dll.openmc_material_add_nuclide(self._index, name.encode(), density) + def get_density(self, units='atom/b-cm'): + """Get density of a material. + + Parameters + ---------- + units : {'atom/b-cm', 'g/cm3'} + Units for density + + Returns + ------- + float + Density in requested units + + """ + if units == 'atom/b-cm': + return self.densities.sum() + elif units == 'g/cm3': + density = c_double() + _dll.openmc_material_get_density(self._index, density) + return density.value + else: + raise ValueError("Units must be 'atom/b-cm' or 'g/cm3'") + def set_density(self, density, units='atom/b-cm'): """Set density of a material. diff --git a/openmc/lib/math.py b/openmc/lib/math.py index bdb09b2d1fa..029f1c4c9ff 100644 --- a/openmc/lib/math.py +++ b/openmc/lib/math.py @@ -1,12 +1,11 @@ from ctypes import c_int, c_double, POINTER, c_uint64 +from random import getrandbits import numpy as np from numpy.ctypeslib import ndpointer from . import _dll -from random import getrandbits - _dll.t_percentile.restype = c_double _dll.t_percentile.argtypes = [c_double, c_int] @@ -104,7 +103,7 @@ def evaluate_legendre(data, x): """ data_arr = np.array(data, dtype=np.float64) - return _dll.evaluate_legendre(len(data), + return _dll.evaluate_legendre(len(data)-1, data_arr.ctypes.data_as(POINTER(c_double)), x) @@ -200,7 +199,8 @@ def rotate_angle(uvw0, mu, phi, prn_seed=None): phi : float Azimuthal angle; if None, one will be sampled uniformly prn_seed : int - PRNG seed; if None, one will be generated randomly + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. Returns ------- @@ -232,7 +232,8 @@ def maxwell_spectrum(T, prn_seed=None): T : float Spectrum parameter prn_seed : int - PRNG seed; if None, one will be generated randomly + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. Returns ------- @@ -240,10 +241,10 @@ def maxwell_spectrum(T, prn_seed=None): Sampled outgoing energy """ - + if prn_seed is None: prn_seed = getrandbits(63) - + return _dll.maxwell_spectrum(T, c_uint64(prn_seed)) @@ -257,7 +258,8 @@ def watt_spectrum(a, b, prn_seed=None): b : float Spectrum parameter b prn_seed : int - PRNG seed; if None, one will be generated randomly + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. Returns ------- @@ -265,7 +267,7 @@ def watt_spectrum(a, b, prn_seed=None): Sampled outgoing energy """ - + if prn_seed is None: prn_seed = getrandbits(63) @@ -282,7 +284,8 @@ def normal_variate(mean_value, std_dev, prn_seed=None): std_dev : float Standard deviation of the normal distribution prn_seed : int - PRNG seed; if None, one will be generated randomly + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. Returns ------- @@ -290,7 +293,7 @@ def normal_variate(mean_value, std_dev, prn_seed=None): Sampled outgoing normally distributed value """ - + if prn_seed is None: prn_seed = getrandbits(63) diff --git a/openmc/lib/mesh.py b/openmc/lib/mesh.py index dc528573acb..4da7baba771 100644 --- a/openmc/lib/mesh.py +++ b/openmc/lib/mesh.py @@ -1,6 +1,8 @@ from collections.abc import Mapping -from ctypes import (c_int, c_int32, c_char_p, c_double, POINTER, - create_string_buffer) +from ctypes import (c_int, c_int32, c_char_p, c_double, POINTER, Structure, + create_string_buffer, c_uint64, c_size_t) +from random import getrandbits +from typing import Optional, List, Tuple, Sequence from weakref import WeakValueDictionary import numpy as np @@ -10,8 +12,21 @@ from . import _dll from .core import _FortranObjectWithID from .error import _error_handler +from .material import Material +from .plot import _Position + +__all__ = [ + 'Mesh', 'RegularMesh', 'RectilinearMesh', 'CylindricalMesh', + 'SphericalMesh', 'UnstructuredMesh', 'meshes' +] + + +class _MaterialVolume(Structure): + _fields_ = [ + ("material", c_int32), + ("volume", c_double) + ] -__all__ = ['RegularMesh', 'RectilinearMesh', 'meshes'] # Mesh functions _dll.openmc_extend_meshes.argtypes = [c_int32, c_char_p, POINTER(c_int32), @@ -24,6 +39,22 @@ _dll.openmc_mesh_set_id.argtypes = [c_int32, c_int32] _dll.openmc_mesh_set_id.restype = c_int _dll.openmc_mesh_set_id.errcheck = _error_handler +_dll.openmc_mesh_get_n_elements.argtypes = [c_int32, POINTER(c_size_t)] +_dll.openmc_mesh_get_n_elements.restype = c_int +_dll.openmc_mesh_get_n_elements.errcheck = _error_handler +_dll.openmc_mesh_get_volumes.argtypes = [c_int32, POINTER(c_double)] +_dll.openmc_mesh_get_volumes.restype = c_int +_dll.openmc_mesh_get_volumes.errcheck = _error_handler +_dll.openmc_mesh_material_volumes.argtypes = [ + c_int32, c_int, c_int, c_int, POINTER(_MaterialVolume), + POINTER(c_int), POINTER(c_uint64)] +_dll.openmc_mesh_material_volumes.restype = c_int +_dll.openmc_mesh_material_volumes.errcheck = _error_handler +_dll.openmc_mesh_get_plot_bins.argtypes = [ + c_int32, _Position, _Position, c_int, POINTER(c_int), POINTER(c_int32) +] +_dll.openmc_mesh_get_plot_bins.restype = c_int +_dll.openmc_mesh_get_plot_bins.errcheck = _error_handler _dll.openmc_get_mesh_index.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_mesh_index.restype = c_int _dll.openmc_get_mesh_index.errcheck = _error_handler @@ -56,6 +87,26 @@ _dll.openmc_regular_mesh_set_params.restype = c_int _dll.openmc_regular_mesh_set_params.errcheck = _error_handler +_dll.openmc_cylindrical_mesh_get_grid.argtypes = [c_int32, + POINTER(POINTER(c_double)), POINTER(c_int), POINTER(POINTER(c_double)), + POINTER(c_int), POINTER(POINTER(c_double)), POINTER(c_int)] +_dll.openmc_cylindrical_mesh_get_grid.restype = c_int +_dll.openmc_cylindrical_mesh_get_grid.errcheck = _error_handler +_dll.openmc_cylindrical_mesh_set_grid.argtypes = [c_int32, POINTER(c_double), + c_int, POINTER(c_double), c_int, POINTER(c_double), c_int] +_dll.openmc_cylindrical_mesh_set_grid.restype = c_int +_dll.openmc_cylindrical_mesh_set_grid.errcheck = _error_handler + +_dll.openmc_spherical_mesh_get_grid.argtypes = [c_int32, + POINTER(POINTER(c_double)), POINTER(c_int), POINTER(POINTER(c_double)), + POINTER(c_int), POINTER(POINTER(c_double)), POINTER(c_int)] +_dll.openmc_spherical_mesh_get_grid.restype = c_int +_dll.openmc_spherical_mesh_get_grid.errcheck = _error_handler +_dll.openmc_spherical_mesh_set_grid.argtypes = [c_int32, POINTER(c_double), + c_int, POINTER(c_double), c_int, POINTER(c_double), c_int] +_dll.openmc_spherical_mesh_set_grid.restype = c_int +_dll.openmc_spherical_mesh_set_grid.errcheck = _error_handler + class Mesh(_FortranObjectWithID): """Base class to represent mesh objects @@ -103,6 +154,114 @@ def id(self): def id(self, mesh_id): _dll.openmc_mesh_set_id(self._index, mesh_id) + @property + def n_elements(self) -> int: + n = c_size_t() + _dll.openmc_mesh_get_n_elements(self._index, n) + return n.value + + @property + def volumes(self) -> np.ndarray: + volumes = np.empty((self.n_elements,)) + _dll.openmc_mesh_get_volumes( + self._index, volumes.ctypes.data_as(POINTER(c_double))) + return volumes + + def material_volumes( + self, + n_samples: int = 10_000, + prn_seed: Optional[int] = None + ) -> List[List[Tuple[Material, float]]]: + """Determine volume of materials in each mesh element + + .. versionadded:: 0.14.1 + + Parameters + ---------- + n_samples : int + Number of samples in each mesh element + prn_seed : int + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. + + Returns + ------- + List of tuple of (material, volume) for each mesh element. Void volume + is represented by having a value of None in the first element of a + tuple. + + """ + if n_samples <= 0: + raise ValueError("Number of samples must be positive") + if prn_seed is None: + prn_seed = getrandbits(63) + prn_seed = c_uint64(prn_seed) + + # Preallocate space for MaterialVolume results + size = 16 + result = (_MaterialVolume * size)() + + hits = c_int() # Number of materials hit in a given element + volumes = [] + for i_element in range(self.n_elements): + while True: + try: + _dll.openmc_mesh_material_volumes( + self._index, n_samples, i_element, size, result, hits, prn_seed) + except AllocationError: + # Increase size of result array and try again + size *= 2 + result = (_MaterialVolume * size)() + else: + # If no error, break out of loop + break + + volumes.append([ + (Material(index=r.material), r.volume) + for r in result[:hits.value] + ]) + return volumes + + def get_plot_bins( + self, + origin: Sequence[float], + width: Sequence[float], + basis: str, + pixels: Sequence[int] + ) -> np.ndarray: + """Get mesh bin indices for a rasterized plot. + + .. versionadded:: 0.14.1 + + Parameters + ---------- + origin : iterable of float + Origin of the plotting view. Should have length 3. + width : iterable of float + Width of the plotting view. Should have length 2. + basis : {'xy', 'xz', 'yz'} + Plotting basis. + pixels : iterable of int + Number of pixels in each direction. Should have length 2. + + Returns + ------- + 2D numpy array with mesh bin indices corresponding to each pixel within + the plotting view. + + """ + origin = _Position(*origin) + width = _Position(*width) + basis = {'xy': 1, 'xz': 2, 'yz': 3}[basis] + pixel_array = (c_int*2)(*pixels) + img_data = np.zeros((pixels[1], pixels[0]), dtype=np.dtype('int32')) + + _dll.openmc_mesh_get_plot_bins( + self._index, origin, width, basis, pixel_array, + img_data.ctypes.data_as(POINTER(c_int32)) + ) + return img_data + class RegularMesh(Mesh): """RegularMesh stored internally. @@ -130,6 +289,10 @@ class RegularMesh(Mesh): are given, it is assumed that the mesh is an x-y mesh. width : numpy.ndarray The width of mesh cells in each direction. + n_elements : int + Total number of mesh elements. + volumes : numpy.ndarray + Volume of each mesh element in [cm^3] """ mesh_type = 'regular' @@ -212,6 +375,10 @@ class RectilinearMesh(Mesh): The upper-right corner of the structrued mesh. width : numpy.ndarray The width of mesh cells in each direction. + n_elements : int + Total number of mesh elements. + volumes : numpy.ndarray + Volume of each mesh element in [cm^3] """ mesh_type = 'rectilinear' @@ -265,6 +432,18 @@ def _get_parameters(self): return (lower_left, upper_right, dimension, width) def set_grid(self, x_grid, y_grid, z_grid): + """Set grid values + + Parameters + ---------- + x_grid : iterable of float + Mesh boundary points along the x-axis + y_grid : iterable of float + Mesh boundary points along the y-axis + z_grid : iterable of float + Mesh boundary points along the z-axis + + """ nx = len(x_grid) x_grid = (c_double*nx)(*x_grid) ny = len(y_grid) @@ -275,9 +454,222 @@ def set_grid(self, x_grid, y_grid, z_grid): ny, z_grid, nz) +class CylindricalMesh(Mesh): + """CylindricalMesh stored internally. + + This class exposes a mesh that is stored internally in the OpenMC + library. To obtain a view of a mesh with a given ID, use the + :data:`openmc.lib.meshes` mapping. + + Parameters + ---------- + index : int + Index in the `meshes` array. + + Attributes + ---------- + id : int + ID of the mesh + dimension : iterable of int + The number of mesh cells in each direction. + lower_left : numpy.ndarray + The lower-left corner of the structured mesh. + upper_right : numpy.ndarray + The upper-right corner of the structrued mesh. + width : numpy.ndarray + The width of mesh cells in each direction. + n_elements : int + Total number of mesh elements. + volumes : numpy.ndarray + Volume of each mesh element in [cm^3] + + """ + mesh_type = 'cylindrical' + + def __init__(self, uid=None, new=True, index=None): + super().__init__(uid, new, index) + + @property + def lower_left(self): + return self._get_parameters()[0] + + @property + def upper_right(self): + return self._get_parameters()[1] + + @property + def dimension(self): + return self._get_parameters()[2] + + @property + def width(self): + return self._get_parameters()[3] + + def _get_parameters(self): + gx = POINTER(c_double)() + nx = c_int() + gy = POINTER(c_double)() + ny = c_int() + gz = POINTER(c_double)() + nz = c_int() + # Call C API to get grid parameters + _dll.openmc_cylindrical_mesh_get_grid(self._index, gx, nx, gy, ny, gz, + nz) + + # Convert grid parameters to Numpy arrays + grid_x = as_array(gx, (nx.value,)) + grid_y = as_array(gy, (ny.value,)) + grid_z = as_array(gz, (nz.value,)) + + # Calculate lower_left, upper_right, width, and dimension from grid + lower_left = np.array((grid_x[0], grid_y[0], grid_z[0])) + upper_right = np.array((grid_x[-1], grid_y[-1], grid_z[-1])) + dimension = np.array((nx.value - 1, ny.value - 1, nz.value - 1)) + width = np.zeros(list(dimension) + [3]) + + for i, diff_x in enumerate(np.diff(grid_x)): + for j, diff_y in enumerate(np.diff(grid_y)): + for k, diff_z in enumerate(np.diff(grid_z)): + width[i, j, k, :] = diff_x, diff_y, diff_z + + return (lower_left, upper_right, dimension, width) + + def set_grid(self, r_grid, phi_grid, z_grid): + """Set grid values + + Parameters + ---------- + r_grid : iterable of float + Mesh boundary points along the r-axis + phi_grid : Iterable of float + Mesh boundary points along the phi-axis + z_grid : Iterable of float + Mesh boundary points along the z-axis + + """ + nr = len(r_grid) + r_grid = (c_double*nr)(*r_grid) + nphi = len(phi_grid) + phi_grid = (c_double*nphi)(*phi_grid) + nz = len(z_grid) + z_grid = (c_double*nz)(*z_grid) + _dll.openmc_cylindrical_mesh_set_grid(self._index, r_grid, nr, phi_grid, + nphi, z_grid, nz) + + +class SphericalMesh(Mesh): + """SphericalMesh stored internally. + + This class exposes a mesh that is stored internally in the OpenMC + library. To obtain a view of a mesh with a given ID, use the + :data:`openmc.lib.meshes` mapping. + + Parameters + ---------- + index : int + Index in the `meshes` array. + + Attributes + ---------- + id : int + ID of the mesh + dimension : iterable of int + The number of mesh cells in each direction. + lower_left : numpy.ndarray + The lower-left corner of the structured mesh. + upper_right : numpy.ndarray + The upper-right corner of the structrued mesh. + width : numpy.ndarray + The width of mesh cells in each direction. + n_elements : int + Total number of mesh elements. + volumes : numpy.ndarray + Volume of each mesh element in [cm^3] + + """ + mesh_type = 'spherical' + + def __init__(self, uid=None, new=True, index=None): + super().__init__(uid, new, index) + + @property + def lower_left(self): + return self._get_parameters()[0] + + @property + def upper_right(self): + return self._get_parameters()[1] + + @property + def dimension(self): + return self._get_parameters()[2] + + @property + def width(self): + return self._get_parameters()[3] + + def _get_parameters(self): + gx = POINTER(c_double)() + nx = c_int() + gy = POINTER(c_double)() + ny = c_int() + gz = POINTER(c_double)() + nz = c_int() + # Call C API to get grid parameters + _dll.openmc_spherical_mesh_get_grid(self._index, gx, nx, gy, ny, gz, + nz) + + # Convert grid parameters to Numpy arrays + grid_x = as_array(gx, (nx.value,)) + grid_y = as_array(gy, (ny.value,)) + grid_z = as_array(gz, (nz.value,)) + + # Calculate lower_left, upper_right, width, and dimension from grid + lower_left = np.array((grid_x[0], grid_y[0], grid_z[0])) + upper_right = np.array((grid_x[-1], grid_y[-1], grid_z[-1])) + dimension = np.array((nx.value - 1, ny.value - 1, nz.value - 1)) + width = np.zeros(list(dimension) + [3]) + + for i, diff_x in enumerate(np.diff(grid_x)): + for j, diff_y in enumerate(np.diff(grid_y)): + for k, diff_z in enumerate(np.diff(grid_z)): + width[i, j, k, :] = diff_x, diff_y, diff_z + + return (lower_left, upper_right, dimension, width) + + def set_grid(self, r_grid, theta_grid, phi_grid): + """Set grid values + + Parameters + ---------- + r_grid : iterable of float + Mesh boundary points along the r-axis + theta_grid : Iterable of float + Mesh boundary points along the theta-axis + phi_grid : Iterable of float + Mesh boundary points along the phi-axis + + """ + nr = len(r_grid) + r_grid = (c_double*nr)(*r_grid) + ntheta = len(theta_grid) + theta_grid = (c_double*ntheta)(*theta_grid) + nphi = len(phi_grid) + phi_grid = (c_double*nphi)(*phi_grid) + _dll.openmc_spherical_mesh_set_grid(self._index, r_grid, nr, theta_grid, + ntheta, phi_grid, nphi) + + +class UnstructuredMesh(Mesh): + pass + + _MESH_TYPE_MAP = { 'regular': RegularMesh, - 'rectilinear': RectilinearMesh + 'rectilinear': RectilinearMesh, + 'cylindrical': CylindricalMesh, + 'spherical': SphericalMesh, + 'unstructured': UnstructuredMesh } diff --git a/openmc/lib/nuclide.py b/openmc/lib/nuclide.py index 399bb346520..8078882cf35 100644 --- a/openmc/lib/nuclide.py +++ b/openmc/lib/nuclide.py @@ -91,7 +91,7 @@ def collapse_rate(self, MT, temperature, energy, flux): energy : iterable of float Energy group boundaries in [eV] flux : iterable of float - Flux in each energt group (not normalized per eV) + Flux in each energy group (not normalized per eV) Returns ------- diff --git a/openmc/lib/plot.py b/openmc/lib/plot.py index c51000e0de4..d9863667641 100644 --- a/openmc/lib/plot.py +++ b/openmc/lib/plot.py @@ -31,7 +31,7 @@ def __getitem__(self, idx): elif idx == 2: return self.z else: - raise IndexError("{} index is invalid for _Position".format(idx)) + raise IndexError(f"{idx} index is invalid for _Position") def __setitem__(self, idx, val): if idx == 0: @@ -41,10 +41,10 @@ def __setitem__(self, idx, val): elif idx == 2: self.z = val else: - raise IndexError("{} index is invalid for _Position".format(idx)) + raise IndexError(f"{idx} index is invalid for _Position") def __repr__(self): - return "({}, {}, {})".format(self.x, self.y, self.z) + return f"({self.x}, {self.y}, {self.z})" class _PlotBase(Structure): @@ -96,14 +96,28 @@ def __init__(self): def origin(self): return self.origin_ + @origin.setter + def origin(self, origin): + self.origin_.x = origin[0] + self.origin_.y = origin[1] + self.origin_.z = origin[2] + @property def width(self): return self.width_.x + @width.setter + def width(self, width): + self.width_.x = width + @property def height(self): return self.width_.y + @height.setter + def height(self, height): + self.width_.y = height + @property def basis(self): if self.basis_ == 1: @@ -113,7 +127,7 @@ def basis(self): elif self.basis_ == 3: return 'yz' - raise ValueError("Plot basis {} is invalid".format(self.basis_)) + raise ValueError(f"Plot basis {self.basis_} is invalid") @basis.setter def basis(self, basis): @@ -121,7 +135,7 @@ def basis(self, basis): valid_bases = ('xy', 'xz', 'yz') basis = basis.lower() if basis not in valid_bases: - raise ValueError("{} is not a valid plot basis.".format(basis)) + raise ValueError(f"{basis} is not a valid plot basis.") if basis == 'xy': self.basis_ = 1 @@ -134,25 +148,36 @@ def basis(self, basis): if isinstance(basis, int): valid_bases = (1, 2, 3) if basis not in valid_bases: - raise ValueError("{} is not a valid plot basis.".format(basis)) + raise ValueError(f"{basis} is not a valid plot basis.") self.basis_ = basis return - raise ValueError("{} of type {} is an" - " invalid plot basis".format(basis, type(basis))) + raise ValueError(f"{basis} of type {type(basis)} is an invalid plot basis") @property def h_res(self): return self.pixels_[0] + @h_res.setter + def h_res(self, h_res): + self.pixels_[0] = h_res + @property def v_res(self): return self.pixels_[1] + @v_res.setter + def v_res(self, v_res): + self.pixels_[1] = v_res + @property def level(self): return int(self.level_) + @level.setter + def level(self, level): + self.level_ = level + @property def color_overlaps(self): return self.color_overlaps_ @@ -161,32 +186,6 @@ def color_overlaps(self): def color_overlaps(self, color_overlaps): self.color_overlaps_ = color_overlaps - @origin.setter - def origin(self, origin): - self.origin_.x = origin[0] - self.origin_.y = origin[1] - self.origin_.z = origin[2] - - @width.setter - def width(self, width): - self.width_.x = width - - @height.setter - def height(self, height): - self.width_.y = height - - @h_res.setter - def h_res(self, h_res): - self.pixels_[0] = h_res - - @v_res.setter - def v_res(self, v_res): - self.pixels_[1] = v_res - - @level.setter - def level(self, level): - self.level_ = level - @property def color_overlaps(self): return self.color_overlaps_ @@ -199,14 +198,14 @@ def __repr__(self): out_str = ["-----", "Plot:", "-----", - "Origin: {}".format(self.origin), - "Width: {}".format(self.width), - "Height: {}".format(self.height), - "Basis: {}".format(self.basis), - "HRes: {}".format(self.h_res), - "VRes: {}".format(self.v_res), - "Color Overlaps: {}".format(self.color_overlaps), - "Level: {}".format(self.level)] + f"Origin: {self.origin}", + f"Width: {self.width}", + f"Height: {self.height}", + f"Basis: {self.basis}", + f"HRes: {self.h_res}", + f"VRes: {self.v_res}", + f"Color Overlaps: {self.color_overlaps}", + f"Level: {self.level}"] return '\n'.join(out_str) @@ -228,11 +227,12 @@ def id_map(plot): Returns ------- id_map : numpy.ndarray - A NumPy array with shape (vertical pixels, horizontal pixels, 2) of - OpenMC property ids with dtype int32 + A NumPy array with shape (vertical pixels, horizontal pixels, 3) of + OpenMC property ids with dtype int32. The last dimension of the array + contains, in order, cell IDs, cell instances, and material IDs. """ - img_data = np.zeros((plot.v_res, plot.h_res, 2), + img_data = np.zeros((plot.v_res, plot.h_res, 3), dtype=np.dtype('int32')) _dll.openmc_id_map(plot, img_data.ctypes.data_as(POINTER(c_int32))) return img_data diff --git a/openmc/lib/settings.py b/openmc/lib/settings.py index 1eab4aa8a4f..062670ef843 100644 --- a/openmc/lib/settings.py +++ b/openmc/lib/settings.py @@ -34,6 +34,8 @@ class _Settings: restart_run = _DLLGlobal(c_bool, 'restart_run') run_CE = _DLLGlobal(c_bool, 'run_CE') verbosity = _DLLGlobal(c_int, 'verbosity') + event_based = _DLLGlobal(c_bool, 'event_based') + weight_windows_on = _DLLGlobal(c_bool, 'weight_windows_on') @property def run_mode(self): @@ -51,11 +53,11 @@ def run_mode(self, mode): current_idx.value = idx break else: - raise ValueError('Invalid run mode: {}'.format(mode)) + raise ValueError(f'Invalid run mode: {mode}') @property def path_statepoint(self): - path = c_char_p.in_dll(_dll, 'path_statepoint').value + path = c_char_p.in_dll(_dll, 'path_statepoint_c').value return path.decode() @property diff --git a/openmc/lib/tally.py b/openmc/lib/tally.py index df28cb5dcac..d0b34aedc26 100644 --- a/openmc/lib/tally.py +++ b/openmc/lib/tally.py @@ -39,6 +39,9 @@ c_int32, POINTER(POINTER(c_int32)), POINTER(c_size_t)] _dll.openmc_tally_get_filters.restype = c_int _dll.openmc_tally_get_filters.errcheck = _error_handler +_dll.openmc_tally_get_multiply_density.argtypes = [c_int32, POINTER(c_bool)] +_dll.openmc_tally_get_multiply_density.restype = c_int +_dll.openmc_tally_get_multiply_density.errcheck = _error_handler _dll.openmc_tally_get_n_realizations.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_get_n_realizations.restype = c_int _dll.openmc_tally_get_n_realizations.errcheck = _error_handler @@ -75,6 +78,9 @@ _dll.openmc_tally_set_id.argtypes = [c_int32, c_int32] _dll.openmc_tally_set_id.restype = c_int _dll.openmc_tally_set_id.errcheck = _error_handler +_dll.openmc_tally_set_multiply_density.argtypes = [c_int32, c_bool] +_dll.openmc_tally_set_multiply_density.restype = c_int +_dll.openmc_tally_set_multiply_density.errcheck = _error_handler _dll.openmc_tally_set_nuclides.argtypes = [c_int32, c_int, POINTER(c_char_p)] _dll.openmc_tally_set_nuclides.restype = c_int _dll.openmc_tally_set_nuclides.errcheck = _error_handler @@ -87,6 +93,9 @@ _dll.openmc_tally_set_writable.argtypes = [c_int32, c_bool] _dll.openmc_tally_set_writable.restype = c_int _dll.openmc_tally_set_writable.errcheck = _error_handler +_dll.openmc_remove_tally.argtypes = [c_int32] +_dll.openmc_remove_tally.restype = c_int +_dll.openmc_remove_tally.errcheck = _error_handler _dll.tallies_size.restype = c_size_t @@ -95,13 +104,13 @@ -5: 'absorption', -6: 'fission', -7: 'nu-fission', -8: 'kappa-fission', -9: 'current', -10: 'events', -11: 'delayed-nu-fission', -12: 'prompt-nu-fission', -13: 'inverse-velocity', -14: 'fission-q-prompt', - -15: 'fission-q-recoverable', -16: 'decay-rate' + -15: 'fission-q-recoverable', -16: 'decay-rate', -17: 'pulse-height' } _ESTIMATORS = { 0: 'analog', 1: 'tracklength', 2: 'collision' } _TALLY_TYPES = { - 0: 'volume', 1: 'mesh-surface', 2: 'surface' + 0: 'volume', 1: 'mesh-surface', 2: 'surface', 3: 'pulse-height' } @@ -171,6 +180,10 @@ class Tally(_FortranObjectWithID): List of tally filters mean : numpy.ndarray An array containing the sample mean for each bin + multiply_density : bool + Whether reaction rates should be multiplied by atom density + + .. versionadded:: 0.14.0 nuclides : list of str List of nuclides to score results for num_realizations : int @@ -218,6 +231,10 @@ def active(self): _dll.openmc_tally_get_active(self._index, active) return active.value + @active.setter + def active(self, active): + _dll.openmc_tally_set_active(self._index, active) + @property def type(self): type = c_int32() @@ -238,10 +255,6 @@ def estimator(self): def estimator(self, estimator): _dll.openmc_tally_set_estimator(self._index, estimator.encode()) - @active.setter - def active(self, active): - _dll.openmc_tally_set_active(self._index, active) - @property def id(self): tally_id = c_int32() @@ -267,6 +280,30 @@ def filters(self, filters): _dll.openmc_tally_set_filters(self._index, n, indices) + def find_filter(self, filter_type): + """ + Returns the first instance of a filter matching the specified type + + Parameters + ---------- + filter_type : subclass of openmc.lib.Filter + The filter type to match when retrieving a filter instance + + Returns + ------- + filter : openmc.lib.Filter + The filter instance matching the input filter type + + Raises + ------ + ValueError if a filter instance matching the input filter type cannot be found. + """ + for filter in self.filters: + if isinstance(filter, filter_type): + return filter + + raise ValueError(f'No filter of type {filter_type} on tally {self.id}') + @property def mean(self): n = self.num_realizations @@ -360,6 +397,16 @@ def writable(self): def writable(self, writable): _dll.openmc_tally_set_writable(self._index, writable) + @property + def multiply_density(self): + multiply_density = c_bool() + _dll.openmc_tally_get_multiply_density(self._index, multiply_density) + return multiply_density.value + + @multiply_density.setter + def multiply_density(self, multiply_density): + _dll.openmc_tally_set_multiply_density(self._index, multiply_density) + def reset(self): """Reset results and num_realizations of tally""" _dll.openmc_tally_reset(self._index) @@ -405,4 +452,8 @@ def __len__(self): def __repr__(self): return repr(dict(self)) + def __delitem__(self, key): + """Delete a tally from tally vector and remove the ID,index pair from tally""" + _dll.openmc_remove_tally(self[key]._index) + tallies = _TallyMapping() diff --git a/openmc/lib/weight_windows.py b/openmc/lib/weight_windows.py new file mode 100644 index 00000000000..d92f019179f --- /dev/null +++ b/openmc/lib/weight_windows.py @@ -0,0 +1,395 @@ +from collections.abc import Mapping +from ctypes import c_double, c_int, c_int32, c_char_p, c_size_t, POINTER +from weakref import WeakValueDictionary + +import numpy as np +from numpy.ctypeslib import as_array + +from openmc import ParticleType +from openmc.exceptions import AllocationError, InvalidIDError +from . import _dll +from .core import _FortranObjectWithID +from .error import _error_handler +from .filter import EnergyFilter, MeshFilter, ParticleFilter +from .mesh import _get_mesh +from .mesh import meshes + + +__all__ = ['WeightWindows', 'weight_windows'] + +_dll.openmc_extend_weight_windows.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)] + +_dll.openmc_weight_windows_update_magic.argtypes = 2*[c_int32] + [c_char_p] + 2*[c_double] +_dll.openmc_weight_windows_update_magic.restype = c_int +_dll.openmc_weight_windows_update_magic.errcheck = _error_handler + +_dll.openmc_weight_windows_size.restype = c_size_t + +_dll.openmc_get_weight_windows_index.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_weight_windows_index.restype = c_int +_dll.openmc_get_weight_windows_index.errcheck = _error_handler + +_dll.openmc_weight_windows_get_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_weight_windows_get_id.restype = c_int +_dll.openmc_weight_windows_get_id.errcheck = _error_handler + +_dll.openmc_weight_windows_set_id.argtypes = [c_int32, c_int32] +_dll.openmc_weight_windows_set_id.restype = c_int +_dll.openmc_weight_windows_set_id.errcheck = _error_handler + +_dll.openmc_weight_windows_set_mesh.argtypes = [c_int32, c_int32] +_dll.openmc_weight_windows_set_mesh.restype = c_int +_dll.openmc_weight_windows_set_mesh.errcheck = _error_handler + +_dll.openmc_weight_windows_get_mesh.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_weight_windows_get_mesh.restype = c_int +_dll.openmc_weight_windows_get_mesh.errcheck = _error_handler + +_dll.openmc_weight_windows_set_energy_bounds.argtypes = [c_int32, POINTER(c_double), c_size_t] +_dll.openmc_weight_windows_set_energy_bounds.restype = c_int +_dll.openmc_weight_windows_set_energy_bounds.errcheck = _error_handler + +_dll.openmc_weight_windows_get_energy_bounds.argtypes = [c_int32, POINTER(POINTER(c_double)), POINTER(c_size_t)] +_dll.openmc_weight_windows_get_energy_bounds.restype = c_int +_dll.openmc_weight_windows_get_energy_bounds.errcheck = _error_handler + +_dll.openmc_weight_windows_set_particle.argtypes = [c_int32, c_int] +_dll.openmc_weight_windows_set_particle.restype = c_int +_dll.openmc_weight_windows_set_particle.errcheck = _error_handler + +_dll.openmc_weight_windows_get_particle.argtypes = [c_int32, POINTER(c_int)] +_dll.openmc_weight_windows_get_particle.restype = c_int +_dll.openmc_weight_windows_get_particle.errcheck = _error_handler + +_dll.openmc_weight_windows_set_bounds.argtypes = [c_int32, POINTER(c_double), POINTER(c_double), c_size_t] +_dll.openmc_weight_windows_set_bounds.restype = c_int +_dll.openmc_weight_windows_set_bounds.errcheck = _error_handler + +_dll.openmc_weight_windows_get_bounds.argtypes = [c_int32, POINTER(POINTER(c_double)), POINTER(POINTER(c_double)), POINTER(c_size_t)] +_dll.openmc_weight_windows_get_bounds.restype = c_int +_dll.openmc_weight_windows_get_bounds.errcheck = _error_handler + +_dll.openmc_weight_windows_get_survival_ratio.argtypes = [c_int32, POINTER(c_double)] +_dll.openmc_weight_windows_get_survival_ratio.restype = c_int +_dll.openmc_weight_windows_get_survival_ratio.errcheck = _error_handler + +_dll.openmc_weight_windows_set_survival_ratio.argtypes = [c_int32, c_double] +_dll.openmc_weight_windows_set_survival_ratio.restype = c_int +_dll.openmc_weight_windows_set_survival_ratio.errcheck = _error_handler + +_dll.openmc_weight_windows_get_max_lower_bound_ratio.argtypes = [c_int32, POINTER(c_double)] +_dll.openmc_weight_windows_get_max_lower_bound_ratio.restype = c_int +_dll.openmc_weight_windows_get_max_lower_bound_ratio.errcheck = _error_handler + +_dll.openmc_weight_windows_set_max_lower_bound_ratio.argtypes = [c_int32, c_double] +_dll.openmc_weight_windows_set_max_lower_bound_ratio.restype = c_int +_dll.openmc_weight_windows_set_max_lower_bound_ratio.errcheck = _error_handler + +_dll.openmc_weight_windows_get_weight_cutoff.argtypes = [c_int32, POINTER(c_double)] +_dll.openmc_weight_windows_get_weight_cutoff.restype = c_int +_dll.openmc_weight_windows_get_weight_cutoff.errcheck = _error_handler + +_dll.openmc_weight_windows_set_weight_cutoff.argtypes = [c_int32, c_double] +_dll.openmc_weight_windows_set_weight_cutoff.restype = c_int +_dll.openmc_weight_windows_set_weight_cutoff.errcheck = _error_handler + +_dll.openmc_weight_windows_get_max_split.argtypes = [c_int32, POINTER(c_int)] +_dll.openmc_weight_windows_get_max_split.restype = c_int +_dll.openmc_weight_windows_get_max_split.errcheck = _error_handler + +_dll.openmc_weight_windows_set_max_split.argtypes = [c_int32, c_int] +_dll.openmc_weight_windows_set_max_split.restype = c_int +_dll.openmc_weight_windows_set_max_split.errcheck = _error_handler + + +class WeightWindows(_FortranObjectWithID): + """WeightWindows stored internally. + + This class exposes a weight windows object that is stored internally in the + OpenMC library. To obtain a view of a weight windows object with a given ID, + use the :data:`openmc.lib.weight_windows` mapping. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + id : int or None + Unique ID of the weight windows + new : bool + When `index` is None, this argument controls whether a new object is + created or a view of an existing object is returned. + index : int or None + Index in the `weight_windows` array. + + Attributes + ---------- + id : int + ID of the weight windows object + mesh : openmc.lib.Mesh + Mesh used for the weight windows + particle : openmc.ParticleType + The particle type to which these weight windows apply + energy_bounds : numpy.ndarray + The energy bounds for the weight windows + bounds : numpy.ndarray + The weight window bounds + """ + __instances = WeakValueDictionary() + + def __new__(cls, id=None, new=True, index=None): + mapping = weight_windows + + if index is None: + if new: + # Determine ID to assign + if id is None: + id = max(mapping, default=0) + 1 + else: + if id in mapping: + raise AllocationError(f'A weight windows object with ID={id} ' + 'has already been allocated.') + + index = c_int32() + _dll.openmc_extend_weight_windows(1, index, None) + index = index.value + else: + index = mapping[id]._index + + if index not in cls.__instances: + instance = super().__new__(cls) + instance._index = index + if id is not None: + instance.id = id + cls.__instances[index] = instance + + return cls.__instances[index] + + @property + def id(self): + ww_id = c_int32() + _dll.openmc_weight_windows_get_id(self._index, ww_id) + return ww_id.value + + @id.setter + def id(self, ww_id): + _dll.openmc_weight_windows_set_id(self._index, ww_id) + + @property + def mesh(self): + mesh_idx = c_int32() + _dll.openmc_weight_windows_get_mesh(self._index, mesh_idx) + return _get_mesh(mesh_idx.value) + + @mesh.setter + def mesh(self, mesh): + _dll.openmc_weight_windows_set_mesh( + weight_windows[self.id]._index, meshes[mesh.id]._index) + + @property + def energy_bounds(self): + data = POINTER(c_double)() + n = c_size_t() + _dll.openmc_weight_windows_get_energy_bounds(self._index, data, n) + return as_array(data, (n.value,)) + + @energy_bounds.setter + def energy_bounds(self, e_bounds): + e_bounds_arr = np.asarray(e_bounds, dtype=float) + e_bounds_ptr = e_bounds_arr.ctypes.data_as(POINTER(c_double)) + _dll.openmc_weight_windows_set_energy_bounds( + self._index, e_bounds_ptr, e_bounds_arr.size) + + @property + def particle(self): + val = c_int() + _dll.openmc_weight_windows_get_particle(self._index, val) + return ParticleType(val.value) + + @particle.setter + def particle(self, p): + if isinstance(p, str): + p = ParticleType.from_string(p) + else: + p = ParticleType(p) + _dll.openmc_weight_windows_set_particle(self._index, int(p)) + + @property + def bounds(self): + upper = POINTER(c_double)() + lower = POINTER(c_double)() + size = c_size_t() + _dll.openmc_weight_windows_get_bounds(self._index, lower, upper, size) + lower_arr = as_array(lower, (size.value,)) + upper_arr = as_array(upper, (size.value,)) + return (lower_arr, upper_arr) + + @bounds.setter + def bounds(self, bounds): + lower = np.asarray(bounds[0]) + upper = np.asarray(bounds[1]) + + lower_p = lower.ctypes.data_as(POINTER(c_double)) + upper_p = upper.ctypes.data_as(POINTER(c_double)) + + _dll.openmc_weight_windows_set_bounds(self._index, lower_p, upper_p, lower.size) + + @property + def survival_ratio(self): + ratio = c_double() + _dll.openmc_weight_windows_get_survival_ratio(self._index, ratio) + return ratio.value + + @survival_ratio.setter + def survival_ratio(self, ratio): + _dll.openmc_weight_windows_set_survival_ratio(self._index, ratio) + + @property + def max_lower_bound_ratio(self): + lb_ratio = c_double() + _dll.openmc_weight_windows_get_max_lower_bound_ratio(self._index, lb_ratio) + return lb_ratio.value + + @max_lower_bound_ratio.setter + def max_lower_bound_ratio(self, lb_ratio): + _dll.openmc_weight_windows_set_max_lower_bound_ratio(self._index, lb_ratio) + + @property + def weight_cutoff(self): + cutoff = c_double() + _dll.openmc_weight_windows_get_weight_cutoff(self._index, cutoff) + return cutoff.value + + @weight_cutoff.setter + def weight_cutoff(self, cutoff): + _dll.openmc_weight_windows_set_weight_cutoff(self._index, cutoff) + + @property + def max_split(self): + max_split = c_int() + _dll.openmc_weight_windows_get_max_split(self._index, max_split) + return max_split.value + + @max_split.setter + def max_split(self, max_split): + _dll.openmc_weight_windows_set_max_split(self._index, max_split) + + def update_magic(self, tally, value='mean', threshold=1.0, ratio=5.0): + """Update weight window values using the MAGIC method + + Reference: https://inis.iaea.org/search/48022314 + + Parameters + ---------- + tally : openmc.lib.Tally object + The tally used to update weight window information + value : str + Value type used to generate weight windows. One of {'mean', 'rel_err'}. + threshold : float + Threshold for relative error of results used to generate weight window bounds + ratio : float + Ratio of the lower to upper weight window bounds + + """ + _dll.openmc_weight_windows_update_magic(self._index, + tally._index, + c_char_p(value.encode()), + threshold, + ratio) + + @classmethod + def from_tally(cls, tally, particle=ParticleType.NEUTRON): + """Create an instance of the WeightWindows class based on the specified tally. + + Parameters + ---------- + tally : openmc.lib.Tally + The tally used to create the WeightWindows instance. + particle : openmc.ParticleType or str, optional + The particle type to use for the WeightWindows instance. Should be + specified as an instance of ParticleType or as a string with a value of + 'neutron' or 'photon'. + + Returns + ------- + WeightWindows + The WeightWindows instance created from the specified tally. + + Raises + ------ + ValueError + If the particle parameter is not an instance of ParticleType or a string. + ValueError + If the particle parameter is not a valid particle type (i.e., not 'neutron' + or 'photon'). + ValueError + If the specified particle is not included in the bins of the ParticleFilter + of the tally. + ValueError + If the tally does not have a MeshFilter. + """ + # do some checks on particle value + if not isinstance(particle, (ParticleType, str)): + raise ValueError(f"Parameter 'particle' must be {ParticleType} or one of ('neutron', 'photon').") + + # convert particle type if needed + if isinstance(particle, str): + particle = ParticleType.from_string(particle) + + if particle not in (ParticleType.NEUTRON, ParticleType.PHOTON): + raise ValueError('Weight windows can only be applied for neutrons or photons') + + try: + particle_filter = tally.find_filter(ParticleFilter) + except ValueError: + particle_filter = None + + # ensure that the tally won't filter out the specified particle + if particle_filter is not None and particle not in particle_filter.bins: + raise ValueError(f'Specified tally for weight windows (Tally {tally.id})' + f' does not track the requested particle: "{particle}"') + + # tally must have a mesh filter + mesh_filter = tally.find_filter(MeshFilter) + + # create a new weight windows instance + out = cls() + + # set mesh and particle + out.mesh = mesh_filter.mesh + out.particle = particle + + # set energy bounds if needed + try: + energy_filter = tally.find_filter(EnergyFilter) + except ValueError: + energy_filter = None + + if energy_filter is not None: + out.energy_bounds = energy_filter.bins + + return out + + +class _WeightWindowsMapping(Mapping): + def __getitem__(self, key): + index = c_int32() + try: + _dll.openmc_get_weight_windows_index(key, index) + except (AllocationError, InvalidIDError) as e: + raise KeyError(str(e)) + return WeightWindows(index=index.value) + + def __iter__(self): + for i in range(len(self)): + yield WeightWindows(index=i).id + + def __len__(self): + return _dll.openmc_weight_windows_size() + + def __repr__(self): + return repr(dict(self)) + + def __delitem__(self): + raise NotImplementedError("WeightWindows object remove not implemented") + +weight_windows = _WeightWindowsMapping() diff --git a/openmc/material.py b/openmc/material.py index c6a8e6f44af..6edc372161c 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -1,19 +1,25 @@ -from collections import OrderedDict, defaultdict, namedtuple, Counter +from __future__ import annotations +from collections import defaultdict, namedtuple, Counter from collections.abc import Iterable from copy import deepcopy from numbers import Real from pathlib import Path import re +import typing # imported separately as py3.8 requires typing.Iterable import warnings -from xml.etree import ElementTree as ET +from typing import Optional, List, Union, Dict +import lxml.etree as ET import numpy as np +import h5py import openmc import openmc.data import openmc.checkvalue as cv from ._xml import clean_indentation, reorder_attributes from .mixin import IDManagerMixin +from openmc.checkvalue import PathLike +from openmc.stats import Univariate, Discrete, Mixture # Units for density supported by OpenMC @@ -29,9 +35,11 @@ class Material(IDManagerMixin): To create a material, one should create an instance of this class, add nuclides or elements with :meth:`Material.add_nuclide` or - `Material.add_element`, respectively, and set the total material density - with `Material.set_density()`. The material can then be assigned to a cell - using the :attr:`Cell.fill` attribute. + :meth:`Material.add_element`, respectively, and set the total material + density with :meth:`Material.set_density()`. Alternatively, you can use + :meth:`Material.add_components()` to pass a dictionary containing all the + component information. The material can then be assigned to a cell using the + :attr:`Cell.fill` attribute. Parameters ---------- @@ -85,6 +93,10 @@ class Material(IDManagerMixin): fissionable_mass : float Mass of fissionable nuclides in the material in [g]. Requires that the :attr:`volume` attribute is set. + ncrystal_cfg : str + NCrystal configuration string + + .. versionadded:: 0.13.3 """ @@ -104,6 +116,7 @@ def __init__(self, material_id=None, name='', temperature=None): self._volume = None self._atoms = {} self._isotropic = [] + self._ncrystal_cfg = None # A list of tuples (nuclide, percent, percent type) self._nuclides = [] @@ -115,17 +128,23 @@ def __init__(self, material_id=None, name='', temperature=None): # If specified, a list of table names self._sab = [] - def __repr__(self): + def __repr__(self) -> str: string = 'Material\n' string += '{: <16}=\t{}\n'.format('\tID', self._id) string += '{: <16}=\t{}\n'.format('\tName', self._name) string += '{: <16}=\t{}\n'.format('\tTemperature', self._temperature) string += '{: <16}=\t{}'.format('\tDensity', self._density) - string += ' [{}]\n'.format(self._density_units) + string += f' [{self._density_units}]\n' + + string += '{: <16}=\t{} [cm^3]\n'.format('\tVolume', self._volume) + string += '{: <16}=\t{}\n'.format('\tDepletable', self._depletable) string += '{: <16}\n'.format('\tS(a,b) Tables') + if self._ncrystal_cfg: + string += '{: <16}=\t{}\n'.format('\tNCrystal conf', self._ncrystal_cfg) + for sab in self._sab: string += '{: <16}=\t{}\n'.format('\tS(a,b)', sab) @@ -133,7 +152,7 @@ def __repr__(self): for nuclide, percent, percent_type in self._nuclides: string += '{: <16}'.format('\t{}'.format(nuclide)) - string += '=\t{: <12} [{}]\n'.format(percent, percent_type) + string += f'=\t{percent: <12} [{percent_type}]\n' if self._macroscopic is not None: string += '{: <16}\n'.format('\tMacroscopic Data') @@ -142,34 +161,55 @@ def __repr__(self): return string @property - def name(self): + def name(self) -> Optional[str]: return self._name + @name.setter + def name(self, name: Optional[str]): + if name is not None: + cv.check_type(f'name for Material ID="{self._id}"', + name, str) + self._name = name + else: + self._name = '' + @property - def temperature(self): + def temperature(self) -> Optional[float]: return self._temperature + @temperature.setter + def temperature(self, temperature: Optional[Real]): + cv.check_type(f'Temperature for Material ID="{self._id}"', + temperature, (Real, type(None))) + self._temperature = temperature + @property - def density(self): + def density(self) -> Optional[float]: return self._density @property - def density_units(self): + def density_units(self) -> str: return self._density_units @property - def depletable(self): + def depletable(self) -> bool: return self._depletable + @depletable.setter + def depletable(self, depletable: bool): + cv.check_type(f'Depletable flag for Material ID="{self._id}"', + depletable, bool) + self._depletable = depletable + @property - def paths(self): + def paths(self) -> List[str]: if self._paths is None: raise ValueError('Material instance paths have not been determined. ' 'Call the Geometry.determine_paths() method.') return self._paths @property - def num_instances(self): + def num_instances(self) -> int: if self._num_instances is None: raise ValueError( 'Number of material instances have not been determined. Call ' @@ -177,15 +217,21 @@ def num_instances(self): return self._num_instances @property - def nuclides(self): + def nuclides(self) -> List[namedtuple]: return self._nuclides @property - def isotropic(self): + def isotropic(self) -> List[str]: return self._isotropic + @isotropic.setter + def isotropic(self, isotropic: typing.Iterable[str]): + cv.check_iterable_type('Isotropic scattering nuclides', isotropic, + str) + self._isotropic = list(isotropic) + @property - def average_molar_mass(self): + def average_molar_mass(self) -> float: # Using the sum of specified atomic or weight amounts as a basis, sum # the mass and moles of the material mass = 0. @@ -202,56 +248,97 @@ def average_molar_mass(self): return mass / moles @property - def volume(self): + def volume(self) -> Optional[float]: return self._volume - @name.setter - def name(self, name): - if name is not None: - cv.check_type('name for Material ID="{}"'.format(self._id), - name, str) - self._name = name - else: - self._name = '' - - @temperature.setter - def temperature(self, temperature): - cv.check_type('Temperature for Material ID="{}"'.format(self._id), - temperature, (Real, type(None))) - self._temperature = temperature - - @depletable.setter - def depletable(self, depletable): - cv.check_type('Depletable flag for Material ID="{}"'.format(self.id), - depletable, bool) - self._depletable = depletable - @volume.setter - def volume(self, volume): + def volume(self, volume: Real): if volume is not None: cv.check_type('material volume', volume, Real) self._volume = volume - @isotropic.setter - def isotropic(self, isotropic): - cv.check_iterable_type('Isotropic scattering nuclides', isotropic, - str) - self._isotropic = list(isotropic) + @property + def ncrystal_cfg(self) -> Optional[str]: + return self._ncrystal_cfg @property - def fissionable_mass(self): + def fissionable_mass(self) -> float: if self.volume is None: raise ValueError("Volume must be set in order to determine mass.") density = 0.0 - for nuc, atoms_per_cc in self.get_nuclide_atom_densities().values(): + for nuc, atoms_per_bcm in self.get_nuclide_atom_densities().items(): Z = openmc.data.zam(nuc)[0] if Z >= 90: - density += 1e24 * atoms_per_cc * openmc.data.atomic_mass(nuc) \ + density += 1e24 * atoms_per_bcm * openmc.data.atomic_mass(nuc) \ / openmc.data.AVOGADRO return density*self.volume + @property + def decay_photon_energy(self) -> Optional[Univariate]: + warnings.warn( + "The 'decay_photon_energy' property has been replaced by the " + "get_decay_photon_energy() method and will be removed in a future " + "version.", FutureWarning) + return self.get_decay_photon_energy(0.0) + + def get_decay_photon_energy( + self, + clip_tolerance: float = 1e-6, + units: str = 'Bq', + volume: Optional[float] = None + ) -> Optional[Univariate]: + r"""Return energy distribution of decay photons from unstable nuclides. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + clip_tolerance : float + Maximum fraction of :math:`\sum_i x_i p_i` for discrete + distributions that will be discarded. + units : {'Bq', 'Bq/g', 'Bq/cm3'} + Specifies the units on the integral of the distribution. + volume : float, optional + Volume of the material. If not passed, defaults to using the + :attr:`Material.volume` attribute. + + Returns + ------- + Decay photon energy distribution. The integral of this distribution is + the total intensity of the photon source in the requested units. + + """ + cv.check_value('units', units, {'Bq', 'Bq/g', 'Bq/cm3'}) + if units == 'Bq': + multiplier = volume if volume is not None else self.volume + if multiplier is None: + raise ValueError("volume must be specified if units='Bq'") + elif units == 'Bq/cm3': + multiplier = 1 + elif units == 'Bq/g': + multiplier = 1.0 / self.get_mass_density() + + dists = [] + probs = [] + for nuc, atoms_per_bcm in self.get_nuclide_atom_densities().items(): + source_per_atom = openmc.data.decay_photon_energy(nuc) + if source_per_atom is not None: + dists.append(source_per_atom) + probs.append(1e24 * atoms_per_bcm * multiplier) + + # If no photon sources, exit early + if not dists: + return None + + # Get combined distribution, clip low-intensity values in discrete spectra + combined = openmc.data.combine_distributions(dists, probs) + if isinstance(combined, (Discrete, Mixture)): + combined.clip(clip_tolerance, inplace=True) + + return combined + @classmethod - def from_hdf5(cls, group): + def from_hdf5(cls, group: h5py.Group) -> Material: """Create material from HDF5 group Parameters @@ -305,6 +392,66 @@ def from_hdf5(cls, group): return material + @classmethod + def from_ncrystal(cls, cfg, **kwargs) -> Material: + """Create material from NCrystal configuration string. + + Density, temperature, and material composition, and (ultimately) thermal + neutron scattering will be automatically be provided by NCrystal based + on this string. The name and material_id parameters are simply passed on + to the Material constructor. + + .. versionadded:: 0.13.3 + + Parameters + ---------- + cfg : str + NCrystal configuration string + **kwargs + Keyword arguments passed to :class:`openmc.Material` + + Returns + ------- + openmc.Material + Material instance + + """ + + import NCrystal + nc_mat = NCrystal.createInfo(cfg) + + def openmc_natabund(Z): + #nc_mat.getFlattenedComposition might need natural abundancies. + #This call-back function is used so NCrystal can flatten composition + #using OpenMC's natural abundancies. In practice this function will + #only get invoked in the unlikely case where a material is specified + #by referring both to natural elements and specific isotopes of the + #same element. + elem_name = openmc.data.ATOMIC_SYMBOL[Z] + return [ + (int(iso_name[len(elem_name):]), abund) + for iso_name, abund in openmc.data.isotopes(elem_name) + ] + + flat_compos = nc_mat.getFlattenedComposition( + preferNaturalElements=True, naturalAbundProvider=openmc_natabund) + + # Create the Material + material = cls(temperature=nc_mat.getTemperature(), **kwargs) + + for Z, A_vals in flat_compos: + elemname = openmc.data.ATOMIC_SYMBOL[Z] + for A, frac in A_vals: + if A: + material.add_nuclide(f'{elemname}{A}', frac) + else: + material.add_element(elemname, frac) + + material.set_density('g/cm3', nc_mat.getDensity()) + material._ncrystal_cfg = NCrystal.normaliseCfg(cfg) + + return material + def add_volume_information(self, volume_calc): """Add volume information to a material. @@ -320,12 +467,11 @@ def add_volume_information(self, volume_calc): self._atoms = volume_calc.atoms[self.id] else: raise ValueError('No volume information found for material ID={}.' - .format(self.id)) + .format(self.id)) else: - raise ValueError('No volume information found for material ID={}.' - .format(self.id)) + raise ValueError(f'No volume information found for material ID={self.id}.') - def set_density(self, units, density=None): + def set_density(self, units: str, density: Optional[float] = None): """Set the density of the material Parameters @@ -353,11 +499,11 @@ def set_density(self, units, density=None): '"sum" unit'.format(self.id) raise ValueError(msg) - cv.check_type('the density for Material ID="{}"'.format(self.id), + cv.check_type(f'the density for Material ID="{self.id}"', density, Real) self._density = density - def add_nuclide(self, nuclide, percent, percent_type='ao'): + def add_nuclide(self, nuclide: str, percent: float, percent_type: str = 'ao'): """Add a nuclide to the material Parameters @@ -379,6 +525,9 @@ def add_nuclide(self, nuclide, percent, percent_type='ao'): 'macroscopic data-set has already been added'.format(self._id) raise ValueError(msg) + if self._ncrystal_cfg is not None: + raise ValueError("Cannot add nuclides to NCrystal material") + # If nuclide name doesn't look valid, give a warning try: Z, _, _ = openmc.data.zam(nuclide) @@ -391,7 +540,54 @@ def add_nuclide(self, nuclide, percent, percent_type='ao'): self._nuclides.append(NuclideTuple(nuclide, percent, percent_type)) - def remove_nuclide(self, nuclide): + def add_components(self, components: dict, percent_type: str = 'ao'): + """ Add multiple elements or nuclides to a material + + .. versionadded:: 0.13.1 + + Parameters + ---------- + components : dict of str to float or dict + Dictionary mapping element or nuclide names to their atom or weight + percent. To specify enrichment of an element, the entry of + ``components`` for that element must instead be a dictionary + containing the keyword arguments as well as a value for + ``'percent'`` + percent_type : {'ao', 'wo'} + 'ao' for atom percent and 'wo' for weight percent + + Examples + -------- + >>> mat = openmc.Material() + >>> components = {'Li': {'percent': 1.0, + >>> 'enrichment': 60.0, + >>> 'enrichment_target': 'Li7'}, + >>> 'Fl': 1.0, + >>> 'Be6': 0.5} + >>> mat.add_components(components) + + """ + + for component, params in components.items(): + cv.check_type('component', component, str) + if isinstance(params, Real): + params = {'percent': params} + + else: + cv.check_type('params', params, dict) + if 'percent' not in params: + raise ValueError("An entry in the dictionary does not have " + "a required key: 'percent'") + + params['percent_type'] = percent_type + + # check if nuclide + if not component.isalpha(): + self.add_nuclide(component, **params) + else: + self.add_element(component, **params) + + def remove_nuclide(self, nuclide: str): """Remove a nuclide from the material Parameters @@ -407,7 +603,26 @@ def remove_nuclide(self, nuclide): if nuclide == nuc.name: self.nuclides.remove(nuc) - def add_macroscopic(self, macroscopic): + def remove_element(self, element): + """Remove an element from the material + + .. versionadded:: 0.13.1 + + Parameters + ---------- + element : str + Element to remove + + """ + cv.check_type('element', element, str) + + # If the Material contains the element, delete it + for nuc in reversed(self.nuclides): + element_name = re.split(r'\d+', nuc.name)[0] + if element_name == element: + self.nuclides.remove(nuc) + + def add_macroscopic(self, macroscopic: str): """Add a macroscopic to the material. This will also set the density of the material to 1.0, unless it has been otherwise set, as a default for Macroscopic cross sections. @@ -443,13 +658,13 @@ def add_macroscopic(self, macroscopic): # Generally speaking, the density for a macroscopic object will # be 1.0. Therefore, lets set density to 1.0 so that the user - # doesnt need to set it unless its needed. + # doesn't need to set it unless its needed. # Of course, if the user has already set a value of density, # then we will not override it. if self._density is None: self.set_density('macro', 1.0) - def remove_macroscopic(self, macroscopic): + def remove_macroscopic(self, macroscopic: str): """Remove a macroscopic from the material Parameters @@ -468,8 +683,11 @@ def remove_macroscopic(self, macroscopic): if macroscopic == self._macroscopic: self._macroscopic = None - def add_element(self, element, percent, percent_type='ao', enrichment=None, - enrichment_target=None, enrichment_type=None): + def add_element(self, element: str, percent: float, percent_type: str = 'ao', + enrichment: Optional[float] = None, + enrichment_target: Optional[str] = None, + enrichment_type: Optional[str] = None, + cross_sections: Optional[str] = None): """Add a natural element to the material Parameters @@ -482,8 +700,8 @@ def add_element(self, element, percent, percent_type='ao', enrichment=None, 'ao' for atom percent and 'wo' for weight percent. Defaults to atom percent. enrichment : float, optional - Enrichment of an enrichment_taget nuclide in percent (ao or wo). - If enrichment_taget is not supplied then it is enrichment for U235 + Enrichment of an enrichment_target nuclide in percent (ao or wo). + If enrichment_target is not supplied then it is enrichment for U235 in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). @@ -496,6 +714,8 @@ def add_element(self, element, percent, percent_type='ao', enrichment=None, Default is: 'ao' for two-isotope enrichment; 'wo' for U enrichment .. versionadded:: 0.12 + cross_sections : str, optional + Location of cross_sections.xml file. Notes ----- @@ -514,25 +734,26 @@ def add_element(self, element, percent, percent_type='ao', enrichment=None, raise ValueError("Element name should be given by the " "element's symbol or name, e.g., 'Zr', 'zirconium'") + if self._ncrystal_cfg is not None: + raise ValueError("Cannot add elements to NCrystal material") + # Allow for element identifier to be given as a symbol or name if len(element) > 2: el = element.lower() element = openmc.data.ELEMENT_SYMBOL.get(el) if element is None: - msg = 'Element name "{}" not recognised'.format(el) + msg = f'Element name "{el}" not recognised' raise ValueError(msg) else: if element[0].islower(): - msg = 'Element name "{}" should start with an uppercase ' \ - 'letter'.format(element) + msg = f'Element name "{element}" should start with an uppercase letter' raise ValueError(msg) if len(element) == 2 and element[1].isupper(): - msg = 'Element name "{}" should end with a lowercase ' \ - 'letter'.format(element) + msg = f'Element name "{element}" should end with a lowercase letter' raise ValueError(msg) # skips the first entry of ATOMIC_SYMBOL which is n for neutron if element not in list(openmc.data.ATOMIC_SYMBOL.values())[1:]: - msg = 'Element name "{}" not recognised'.format(element) + msg = f'Element name "{element}" not recognised' raise ValueError(msg) if self._macroscopic is not None: @@ -571,11 +792,14 @@ def add_element(self, element, percent, percent_type='ao', enrichment=None, percent_type, enrichment, enrichment_target, - enrichment_type): + enrichment_type, + cross_sections): self.add_nuclide(*nuclide) - def add_elements_from_formula(self, formula, percent_type='ao', enrichment=None, - enrichment_target=None, enrichment_type=None): + def add_elements_from_formula(self, formula: str, percent_type: str = 'ao', + enrichment: Optional[float] = None, + enrichment_target: Optional[str] = None, + enrichment_type: Optional[str] = None): """Add a elements from a chemical formula to the material. .. versionadded:: 0.12 @@ -620,12 +844,11 @@ def add_elements_from_formula(self, formula, percent_type='ao', enrichment=None, for token in row: if token.isalpha(): if token == "n" or token not in openmc.data.ATOMIC_NUMBER: - msg = 'Formula entry {} not an element symbol.' \ - .format(token) + msg = f'Formula entry {token} not an element symbol.' raise ValueError(msg) elif token not in ['(', ')', ''] and not token.isdigit(): msg = 'Formula must be made from a sequence of ' \ - 'element symbols, integers, and backets. ' \ + 'element symbols, integers, and brackets. ' \ '{} is not an allowable entry.'.format(token) raise ValueError(msg) @@ -672,7 +895,7 @@ def add_elements_from_formula(self, formula, percent_type='ao', enrichment=None, else: self.add_element(element, percent, percent_type) - def add_s_alpha_beta(self, name, fraction=1.0): + def add_s_alpha_beta(self, name: str, fraction: float = 1.0): r"""Add an :math:`S(\alpha,\beta)` table to the material Parameters @@ -700,19 +923,12 @@ def add_s_alpha_beta(self, name, fraction=1.0): cv.check_type('S(a,b) fraction', fraction, Real) cv.check_greater_than('S(a,b) fraction', fraction, 0.0, True) cv.check_less_than('S(a,b) fraction', fraction, 1.0, True) - - new_name = openmc.data.get_thermal_name(name) - if new_name != name: - msg = 'OpenMC S(a,b) tables follow the GND naming convention. ' \ - 'Table "{}" is being renamed as "{}".'.format(name, new_name) - warnings.warn(msg) - - self._sab.append((new_name, fraction)) + self._sab.append((name, fraction)) def make_isotropic_in_lab(self): self.isotropic = [x.name for x in self._nuclides] - def get_elements(self): + def get_elements(self) -> List[str]: """Returns all elements in the material .. versionadded:: 0.12 @@ -726,18 +942,37 @@ def get_elements(self): return sorted({re.split(r'(\d+)', i)[0] for i in self.get_nuclides()}) - def get_nuclides(self): - """Returns all nuclides in the material + def get_nuclides(self, element: Optional[str] = None) -> List[str]: + """Returns a list of all nuclides in the material, if the element + argument is specified then just nuclides of that element are returned. + + Parameters + ---------- + element : str + Specifies the element to match when searching through the nuclides + + .. versionadded:: 0.13.2 Returns ------- nuclides : list of str List of nuclide names - """ - return [x.name for x in self._nuclides] - def get_nuclide_densities(self): + matching_nuclides = [] + if element: + for nuclide in self._nuclides: + if re.split(r'(\d+)', nuclide.name)[0] == element: + if nuclide.name not in matching_nuclides: + matching_nuclides.append(nuclide.name) + else: + for nuclide in self._nuclides: + if nuclide.name not in matching_nuclides: + matching_nuclides.append(nuclide.name) + + return matching_nuclides + + def get_nuclide_densities(self) -> Dict[str, tuple]: """Returns all nuclides in the material and their densities Returns @@ -748,23 +983,34 @@ def get_nuclide_densities(self): """ - # keep ordered dictionary for testing purposes - nuclides = OrderedDict() + nuclides = {} for nuclide in self._nuclides: nuclides[nuclide.name] = nuclide return nuclides - def get_nuclide_atom_densities(self): - """Returns all nuclides in the material and their atomic densities in - units of atom/b-cm + def get_nuclide_atom_densities(self, nuclide: Optional[str] = None) -> Dict[str, float]: + """Returns one or all nuclides in the material and their atomic + densities in units of atom/b-cm + + .. versionchanged:: 0.13.1 + The values in the dictionary were changed from a tuple containing + the nuclide name and the density to just the density. + + Parameters + ---------- + nuclides : str, optional + Nuclide for which atom density is desired. If not specified, the + atom density for each nuclide in the material is given. + + .. versionadded:: 0.13.2 Returns ------- nuclides : dict - Dictionary whose keys are nuclide names and values are tuples of - (nuclide, density in atom/b-cm) + Dictionary whose keys are nuclide names and values are densities in + [atom/b-cm] """ @@ -781,7 +1027,7 @@ def get_nuclide_atom_densities(self): elif self.density_units == 'atom/b-cm': density = self.density elif self.density_units == 'atom/cm3' or self.density_units == 'atom/cc': - density = 1.E-24 * self.density + density = 1.e-24 * self.density # For ease of processing split out nuc, nuc_density, # and nuc_density_type into separate arrays @@ -789,10 +1035,10 @@ def get_nuclide_atom_densities(self): nuc_densities = [] nuc_density_types = [] - for nuclide in self.nuclides: - nucs.append(nuclide.name) - nuc_densities.append(nuclide.percent) - nuc_density_types.append(nuclide.percent_type) + for nuc in self.nuclides: + nucs.append(nuc.name) + nuc_densities.append(nuc.percent) + nuc_density_types.append(nuc.percent_type) nucs = np.array(nucs) nuc_densities = np.array(nuc_densities) @@ -817,18 +1063,144 @@ def get_nuclide_atom_densities(self): # Convert the mass density to an atom density if not density_in_atom: - density = -density / self.average_molar_mass * 1.E-24 \ + density = -density / self.average_molar_mass * 1.e-24 \ * openmc.data.AVOGADRO nuc_densities = density * nuc_densities - nuclides = OrderedDict() + nuclides = {} for n, nuc in enumerate(nucs): - nuclides[nuc] = (nuc, nuc_densities[n]) + if nuclide is None or nuclide == nuc: + nuclides[nuc] = nuc_densities[n] return nuclides - def get_mass_density(self, nuclide=None): + def get_activity(self, units: str = 'Bq/cm3', by_nuclide: bool = False, + volume: Optional[float] = None) -> Union[Dict[str, float], float]: + """Returns the activity of the material or for each nuclide in the + material in units of [Bq], [Bq/g] or [Bq/cm3]. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + units : {'Bq', 'Bq/g', 'Bq/cm3'} + Specifies the type of activity to return, options include total + activity [Bq], specific [Bq/g] or volumetric activity [Bq/cm3]. + Default is volumetric activity [Bq/cm3]. + by_nuclide : bool + Specifies if the activity should be returned for the material as a + whole or per nuclide. Default is False. + volume : float, optional + Volume of the material. If not passed, defaults to using the + :attr:`Material.volume` attribute. + + .. versionadded:: 0.13.3 + + Returns + ------- + typing.Union[dict, float] + If by_nuclide is True then a dictionary whose keys are nuclide + names and values are activity is returned. Otherwise the activity + of the material is returned as a float. + """ + + cv.check_value('units', units, {'Bq', 'Bq/g', 'Bq/cm3'}) + cv.check_type('by_nuclide', by_nuclide, bool) + + if units == 'Bq': + multiplier = volume if volume is not None else self.volume + elif units == 'Bq/cm3': + multiplier = 1 + elif units == 'Bq/g': + multiplier = 1.0 / self.get_mass_density() + + activity = {} + for nuclide, atoms_per_bcm in self.get_nuclide_atom_densities().items(): + inv_seconds = openmc.data.decay_constant(nuclide) + activity[nuclide] = inv_seconds * 1e24 * atoms_per_bcm * multiplier + + return activity if by_nuclide else sum(activity.values()) + + def get_decay_heat(self, units: str = 'W', by_nuclide: bool = False, + volume: Optional[float] = None) -> Union[Dict[str, float], float]: + """Returns the decay heat of the material or for each nuclide in the + material in units of [W], [W/g] or [W/cm3]. + + .. versionadded:: 0.13.3 + + Parameters + ---------- + units : {'W', 'W/g', 'W/cm3'} + Specifies the units of decay heat to return. Options include total + heat [W], specific [W/g] or volumetric heat [W/cm3]. + Default is total heat [W]. + by_nuclide : bool + Specifies if the decay heat should be returned for the material as a + whole or per nuclide. Default is False. + volume : float, optional + Volume of the material. If not passed, defaults to using the + :attr:`Material.volume` attribute. + + .. versionadded:: 0.13.3 + + Returns + ------- + Union[dict, float] + If `by_nuclide` is True then a dictionary whose keys are nuclide + names and values are decay heat is returned. Otherwise the decay heat + of the material is returned as a float. + """ + + cv.check_value('units', units, {'W', 'W/g', 'W/cm3'}) + cv.check_type('by_nuclide', by_nuclide, bool) + + if units == 'W': + multiplier = volume if volume is not None else self.volume + elif units == 'W/cm3': + multiplier = 1 + elif units == 'W/g': + multiplier = 1.0 / self.get_mass_density() + + decayheat = {} + for nuclide, atoms_per_bcm in self.get_nuclide_atom_densities().items(): + decay_erg = openmc.data.decay_energy(nuclide) + inv_seconds = openmc.data.decay_constant(nuclide) + decay_erg *= openmc.data.JOULE_PER_EV + decayheat[nuclide] = inv_seconds * decay_erg * 1e24 * atoms_per_bcm * multiplier + + return decayheat if by_nuclide else sum(decayheat.values()) + + def get_nuclide_atoms(self, volume: Optional[float] = None) -> Dict[str, float]: + """Return number of atoms of each nuclide in the material + + .. versionadded:: 0.13.1 + + Parameters + ---------- + volume : float, optional + Volume of the material. If not passed, defaults to using the + :attr:`Material.volume` attribute. + + .. versionadded:: 0.13.3 + + Returns + ------- + dict + Dictionary whose keys are nuclide names and values are number of + atoms present in the material. + + """ + if volume is None: + volume = self.volume + if volume is None: + raise ValueError("Volume must be set in order to determine atoms.") + atoms = {} + for nuclide, atom_per_bcm in self.get_nuclide_atom_densities().items(): + atoms[nuclide] = 1.0e24 * atom_per_bcm * volume + return atoms + + def get_mass_density(self, nuclide: Optional[str] = None) -> float: """Return mass density of one or all nuclides Parameters @@ -844,14 +1216,13 @@ def get_mass_density(self, nuclide=None): """ mass_density = 0.0 - for nuc, atoms_per_cc in self.get_nuclide_atom_densities().values(): - if nuclide is None or nuclide == nuc: - density_i = 1e24 * atoms_per_cc * openmc.data.atomic_mass(nuc) \ - / openmc.data.AVOGADRO - mass_density += density_i + for nuc, atoms_per_bcm in self.get_nuclide_atom_densities(nuclide=nuclide).items(): + density_i = 1e24 * atoms_per_bcm * openmc.data.atomic_mass(nuc) \ + / openmc.data.AVOGADRO + mass_density += density_i return mass_density - def get_mass(self, nuclide=None): + def get_mass(self, nuclide: Optional[str] = None, volume: Optional[float] = None) -> float: """Return mass of one or all nuclides. Note that this method requires that the :attr:`Material.volume` has @@ -862,6 +1233,12 @@ def get_mass(self, nuclide=None): nuclides : str, optional Nuclide for which mass is desired. If not specified, the density for the entire material is given. + volume : float, optional + Volume of the material. If not passed, defaults to using the + :attr:`Material.volume` attribute. + + .. versionadded:: 0.13.3 + Returns ------- @@ -869,11 +1246,13 @@ def get_mass(self, nuclide=None): Mass of the nuclide/material in [g] """ - if self.volume is None: + if volume is None: + volume = self.volume + if volume is None: raise ValueError("Volume must be set in order to determine mass.") - return self.volume*self.get_mass_density(nuclide) + return volume*self.get_mass_density(nuclide) - def clone(self, memo=None): + def clone(self, memo: Optional[dict] = None) -> Material: """Create a copy of this material with a new unique ID. Parameters @@ -912,7 +1291,7 @@ def clone(self, memo=None): return memo[self] - def _get_nuclide_xml(self, nuclide): + def _get_nuclide_xml(self, nuclide: NuclideTuple) -> ET.Element: xml_element = ET.Element("nuclide") xml_element.set("name", nuclide.name) @@ -923,29 +1302,37 @@ def _get_nuclide_xml(self, nuclide): return xml_element - def _get_macroscopic_xml(self, macroscopic): + def _get_macroscopic_xml(self, macroscopic: str) -> ET.Element: xml_element = ET.Element("macroscopic") xml_element.set("name", macroscopic) return xml_element - def _get_nuclides_xml(self, nuclides): + def _get_nuclides_xml( + self, nuclides: typing.Iterable[NuclideTuple], + nuclides_to_ignore: Optional[typing.Iterable[str]] = None)-> List[ET.Element]: xml_elements = [] - for nuclide in nuclides: - xml_elements.append(self._get_nuclide_xml(nuclide)) + + # Remove any nuclides to ignore from the XML export + if nuclides_to_ignore: + nuclides = [nuclide for nuclide in nuclides if nuclide.name not in nuclides_to_ignore] + + xml_elements = [self._get_nuclide_xml(nuclide) for nuclide in nuclides] + return xml_elements - def to_xml_element(self, cross_sections=None): + def to_xml_element( + self, nuclides_to_ignore: Optional[typing.Iterable[str]] = None) -> ET.Element: """Return XML representation of the material Parameters ---------- - cross_sections : str - Path to an XML cross sections listing file + nuclides_to_ignore : list of str + Nuclides to ignore when exporting to XML. Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing material data """ @@ -963,6 +1350,14 @@ def to_xml_element(self, cross_sections=None): if self._volume: element.set("volume", str(self._volume)) + if self._ncrystal_cfg: + if self._sab: + raise ValueError("NCrystal materials are not compatible with S(a,b).") + if self._macroscopic is not None: + raise ValueError("NCrystal materials are not compatible with macroscopic cross sections.") + + element.set("cfg", str(self._ncrystal_cfg)) + # Create temperature XML subelement if self.temperature is not None: element.set("temperature", str(self.temperature)) @@ -974,12 +1369,12 @@ def to_xml_element(self, cross_sections=None): subelement.set("value", str(self._density)) subelement.set("units", self._density_units) else: - raise ValueError('Density has not been set for material {}!' - .format(self.id)) + raise ValueError(f'Density has not been set for material {self.id}!') if self._macroscopic is None: # Create nuclide XML subelements - subelements = self._get_nuclides_xml(self._nuclides) + subelements = self._get_nuclides_xml(self._nuclides, + nuclides_to_ignore=nuclides_to_ignore) for subelement in subelements: element.append(subelement) else: @@ -1001,7 +1396,8 @@ def to_xml_element(self, cross_sections=None): return element @classmethod - def mix_materials(cls, materials, fracs, percent_type='ao', name=None): + def mix_materials(cls, materials, fracs: typing.Iterable[float], + percent_type: str = 'ao', name: Optional[str] = None) -> Material: """Mix materials together based on atom, weight, or volume fractions .. versionadded:: 0.12 @@ -1071,7 +1467,7 @@ def mix_materials(cls, materials, fracs, percent_type='ao', name=None): nuclides_per_cc = defaultdict(float) mass_per_cc = defaultdict(float) for mat, wgt in zip(materials, wgts): - for nuc, atoms_per_bcm in mat.get_nuclide_atom_densities().values(): + for nuc, atoms_per_bcm in mat.get_nuclide_atom_densities().items(): nuc_per_cc = wgt*1.e24*atoms_per_bcm nuclides_per_cc[nuc] += nuc_per_cc mass_per_cc[nuc] += nuc_per_cc*openmc.data.atomic_mass(nuc) / \ @@ -1079,7 +1475,7 @@ def mix_materials(cls, materials, fracs, percent_type='ao', name=None): # Create the new material with the desired name if name is None: - name = '-'.join(['{}({})'.format(m.name, f) for m, f in + name = '-'.join([f'{m.name}({f})' for m, f in zip(materials, fracs)]) new_mat = openmc.Material(name=name) @@ -1092,19 +1488,19 @@ def mix_materials(cls, materials, fracs, percent_type='ao', name=None): new_density = np.sum([dens for dens in mass_per_cc.values()]) new_mat.set_density('g/cm3', new_density) - # If any of the involved materials is depletable, the new material is + # If any of the involved materials is depletable, the new material is # depletable new_mat.depletable = any(mat.depletable for mat in materials) return new_mat @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element) -> Material: """Generate material from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -1114,6 +1510,11 @@ def from_xml_element(cls, elem): """ mat_id = int(elem.get('id')) + # Add NCrystal material from cfg string + if "cfg" in elem.attrib: + cfg = elem.get("cfg") + return Material.from_ncrystal(cfg, material_id=mat_id) + mat = cls(mat_id) mat.name = elem.get('name') @@ -1158,9 +1559,8 @@ class Materials(cv.CheckedList): """Collection of Materials used for an OpenMC simulation. This class corresponds directly to the materials.xml input file. It can be - thought of as a normal Python list where each member is a - :class:`Material`. It behaves like a list as the following example - demonstrates: + thought of as a normal Python list where each member is a :class:`Material`. + It behaves like a list as the following example demonstrates: >>> fuel = openmc.Material() >>> clad = openmc.Material() @@ -1173,13 +1573,16 @@ class Materials(cv.CheckedList): ---------- materials : Iterable of openmc.Material Materials to add to the collection - cross_sections : str + + Attributes + ---------- + cross_sections : str or path-like Indicates the path to an XML cross section listing file (usually named cross_sections.xml). If it is not set, the :envvar:`OPENMC_CROSS_SECTIONS` environment variable will be used for - continuous-energy calculations and - :envvar:`OPENMC_MG_CROSS_SECTIONS` will be used for multi-group - calculations to find the path to the HDF5 cross section file. + continuous-energy calculations and :envvar:`OPENMC_MG_CROSS_SECTIONS` + will be used for multi-group calculations to find the path to the HDF5 + cross section file. """ @@ -1191,13 +1594,13 @@ def __init__(self, materials=None): self += materials @property - def cross_sections(self): + def cross_sections(self) -> Optional[Path]: return self._cross_sections @cross_sections.setter def cross_sections(self, cross_sections): - cv.check_type('cross sections', cross_sections, str) - self._cross_sections = cross_sections + if cross_sections is not None: + self._cross_sections = Path(cross_sections) def append(self, material): """Append material to collection @@ -1210,7 +1613,7 @@ def append(self, material): """ super().append(material) - def insert(self, index, material): + def insert(self, index: int, material): """Insert material before index Parameters @@ -1227,13 +1630,69 @@ def make_isotropic_in_lab(self): for material in self: material.make_isotropic_in_lab() - def export_to_xml(self, path='materials.xml'): + def _write_xml(self, file, header=True, level=0, spaces_per_level=2, + trailing_indent=True, nuclides_to_ignore=None): + """Writes XML content of the materials to an open file handle. + + Parameters + ---------- + file : IOTextWrapper + Open file handle to write content into. + header : bool + Whether or not to write the XML header + level : int + Indentation level of materials element + spaces_per_level : int + Number of spaces per indentation + trailing_indentation : bool + Whether or not to write a trailing indentation for the materials element + nuclides_to_ignore : list of str + Nuclides to ignore when exporting to XML. + + """ + indentation = level*spaces_per_level*' ' + # Write the header and the opening tag for the root element. + if header: + file.write("\n") + file.write(indentation+'\n') + + # Write the element. + if self.cross_sections is not None: + element = ET.Element('cross_sections') + element.text = str(self.cross_sections) + clean_indentation(element, level=level+1) + element.tail = element.tail.strip(' ') + file.write((level+1)*spaces_per_level*' ') + reorder_attributes(element) # TODO: Remove when support is Python 3.8+ + file.write(ET.tostring(element, encoding="unicode")) + + # Write the elements. + for material in sorted(self, key=lambda x: x.id): + element = material.to_xml_element(nuclides_to_ignore=nuclides_to_ignore) + clean_indentation(element, level=level+1) + element.tail = element.tail.strip(' ') + file.write((level+1)*spaces_per_level*' ') + reorder_attributes(element) # TODO: Remove when support is Python 3.8+ + file.write(ET.tostring(element, encoding="unicode")) + + # Write the closing tag for the root element. + file.write(indentation+'\n') + + # Write a trailing indentation for the next element + # at this level if needed + if trailing_indent: + file.write(indentation) + + def export_to_xml(self, path: PathLike = 'materials.xml', + nuclides_to_ignore: Optional[typing.Iterable[str]] = None): """Export material collection to an XML file. Parameters ---------- path : str Path to file to write. Defaults to 'materials.xml'. + nuclides_to_ignore : list of str + Nuclides to ignore when exporting to XML. """ # Check if path is a directory @@ -1246,41 +1705,16 @@ def export_to_xml(self, path='materials.xml'): # one go. with open(str(p), 'w', encoding='utf-8', errors='xmlcharrefreplace') as fh: - - # Write the header and the opening tag for the root element. - fh.write("\n") - fh.write('\n') - - # Write the element. - if self._cross_sections is not None: - element = ET.Element('cross_sections') - element.text = str(self._cross_sections) - clean_indentation(element, level=1) - element.tail = element.tail.strip(' ') - fh.write(' ') - reorder_attributes(element) # TODO: Remove when support is Python 3.8+ - ET.ElementTree(element).write(fh, encoding='unicode') - - # Write the elements. - for material in sorted(self, key=lambda x: x.id): - element = material.to_xml_element(self.cross_sections) - clean_indentation(element, level=1) - element.tail = element.tail.strip(' ') - fh.write(' ') - reorder_attributes(element) # TODO: Remove when support is Python 3.8+ - ET.ElementTree(element).write(fh, encoding='unicode') - - # Write the closing tag for the root element. - fh.write('\n') + self._write_xml(fh, nuclides_to_ignore=nuclides_to_ignore) @classmethod - def from_xml(cls, path='materials.xml'): + def from_xml_element(cls, elem) -> Materials: """Generate materials collection from XML file Parameters ---------- - path : str, optional - Path to materials XML file + elem : lxml.etree._Element + XML element Returns ------- @@ -1288,17 +1722,35 @@ def from_xml(cls, path='materials.xml'): Materials collection """ - tree = ET.parse(path) - root = tree.getroot() - # Generate each material materials = cls() - for material in root.findall('material'): + for material in elem.findall('material'): materials.append(Material.from_xml_element(material)) # Check for cross sections settings - xs = tree.find('cross_sections') + xs = elem.find('cross_sections') if xs is not None: materials.cross_sections = xs.text return materials + + @classmethod + def from_xml(cls, path: PathLike = 'materials.xml') -> Materials: + """Generate materials collection from XML file + + Parameters + ---------- + path : str + Path to materials XML file + + Returns + ------- + openmc.Materials + Materials collection + + """ + parser = ET.XMLParser(huge_tree=True) + tree = ET.parse(path, parser=parser) + root = tree.getroot() + + return cls.from_xml_element(root) diff --git a/openmc/mesh.py b/openmc/mesh.py index 7ef18b1ceb9..8777da32554 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -1,13 +1,23 @@ -from abc import ABC -from collections.abc import Iterable -from numbers import Real, Integral +from __future__ import annotations +import typing import warnings -from xml.etree import ElementTree as ET - +from abc import ABC, abstractmethod +from collections.abc import Iterable +from functools import wraps +from math import pi, sqrt, atan2 +from numbers import Integral, Real +from pathlib import Path +import tempfile +from typing import Optional, Sequence, Tuple, List + +import h5py +import lxml.etree as ET import numpy as np -import openmc.checkvalue as cv import openmc +import openmc.checkvalue as cv +from openmc.checkvalue import PathLike +from openmc.utility_funcs import change_directory from ._xml import get_text from .mixin import IDManagerMixin from .surface import _BOUNDARY_TYPES @@ -29,13 +39,17 @@ class MeshBase(IDManagerMixin, ABC): Unique identifier for the mesh name : str Name of the mesh - + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. + indices : Iterable of tuple + An iterable of mesh indices for each mesh element, e.g. [(1, 1, 1), (2, 1, 1), ...] """ next_id = 1 used_ids = set() - def __init__(self, mesh_id=None, name=''): + def __init__(self, mesh_id: Optional[int] = None, name: str = ''): # Initialize Mesh class attributes self.id = mesh_id self.name = name @@ -45,22 +59,36 @@ def name(self): return self._name @name.setter - def name(self, name): + def name(self, name: str): if name is not None: - cv.check_type('name for mesh ID="{0}"'.format(self._id), - name, str) + cv.check_type(f'name for mesh ID="{self._id}"', name, str) self._name = name else: self._name = '' + @property + def bounding_box(self) -> openmc.BoundingBox: + return openmc.BoundingBox(self.lower_left, self.upper_right) + + @property + @abstractmethod + def indices(self): + pass + def __repr__(self): string = type(self).__name__ + '\n' string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) return string + def _volume_dim_check(self): + if self.n_dimension != 3 or \ + any([d == 0 for d in self.dimension]): + raise RuntimeError(f'Mesh {self.id} is not 3D. ' + 'Volumes cannot be provided.') + @classmethod - def from_hdf5(cls, group): + def from_hdf5(cls, group: h5py.Group): """Create mesh from HDF5 group Parameters @@ -80,13 +108,485 @@ def from_hdf5(cls, group): return RegularMesh.from_hdf5(group) elif mesh_type == 'rectilinear': return RectilinearMesh.from_hdf5(group) + elif mesh_type == 'cylindrical': + return CylindricalMesh.from_hdf5(group) + elif mesh_type == 'spherical': + return SphericalMesh.from_hdf5(group) elif mesh_type == 'unstructured': return UnstructuredMesh.from_hdf5(group) else: raise ValueError('Unrecognized mesh type: "' + mesh_type + '"') + @classmethod + def from_xml_element(cls, elem: ET.Element): + """Generates a mesh from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.MeshBase + an openmc mesh object + + """ + mesh_type = get_text(elem, 'type') + + if mesh_type == 'regular' or mesh_type is None: + return RegularMesh.from_xml_element(elem) + elif mesh_type == 'rectilinear': + return RectilinearMesh.from_xml_element(elem) + elif mesh_type == 'cylindrical': + return CylindricalMesh.from_xml_element(elem) + elif mesh_type == 'spherical': + return SphericalMesh.from_xml_element(elem) + elif mesh_type == 'unstructured': + return UnstructuredMesh.from_xml_element(elem) + else: + raise ValueError(f'Unrecognized mesh type "{mesh_type}" found.') + + def get_homogenized_materials( + self, + model: openmc.Model, + n_samples: int = 10_000, + prn_seed: Optional[int] = None, + **kwargs + ) -> List[openmc.Material]: + """Generate homogenized materials over each element in a mesh. + + .. versionadded:: 0.14.1 + + Parameters + ---------- + model : openmc.Model + Model containing materials to be homogenized and the associated + geometry. + n_samples : int + Number of samples in each mesh element. + prn_seed : int, optional + Pseudorandom number generator (PRNG) seed; if None, one will be + generated randomly. + **kwargs + Keyword-arguments passed to :func:`openmc.lib.init`. + + Returns + ------- + list of openmc.Material + Homogenized material in each mesh element + + """ + import openmc.lib + + with change_directory(tmpdir=True): + # In order to get mesh into model, we temporarily replace the + # tallies with a single mesh tally using the current mesh + original_tallies = model.tallies + new_tally = openmc.Tally() + new_tally.filters = [openmc.MeshFilter(self)] + new_tally.scores = ['flux'] + model.tallies = [new_tally] + + # Export model to XML + model.export_to_model_xml() + + # Get material volume fractions + openmc.lib.init(**kwargs) + mesh = openmc.lib.tallies[new_tally.id].filters[0].mesh + mat_volume_by_element = [ + [ + (mat.id if mat is not None else None, volume) + for mat, volume in mat_volume_list + ] + for mat_volume_list in mesh.material_volumes(n_samples, prn_seed) + ] + openmc.lib.finalize() + + # Restore original tallies + model.tallies = original_tallies + + # Create homogenized material for each element + materials = model.geometry.get_all_materials() + homogenized_materials = [] + for mat_volume_list in mat_volume_by_element: + material_ids, volumes = [list(x) for x in zip(*mat_volume_list)] + total_volume = sum(volumes) + + # Check for void material and remove + try: + index_void = material_ids.index(None) + except ValueError: + pass + else: + material_ids.pop(index_void) + volumes.pop(index_void) + + # Compute volume fractions + volume_fracs = np.array(volumes) / total_volume + + # Get list of materials and mix 'em up! + mats = [materials[uid] for uid in material_ids] + homogenized_mat = openmc.Material.mix_materials( + mats, volume_fracs, 'vo' + ) + homogenized_mat.volume = total_volume + homogenized_materials.append(homogenized_mat) + + return homogenized_materials + + +class StructuredMesh(MeshBase): + """A base class for structured mesh functionality + + Parameters + ---------- + mesh_id : int + Unique identifier for the mesh + name : str + Name of the mesh + + Attributes + ---------- + id : int + Unique identifier for the mesh + name : str + Name of the mesh + + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + @property + @abstractmethod + def dimension(self): + pass + + @property + @abstractmethod + def n_dimension(self): + pass + + @property + @abstractmethod + def _grids(self): + pass + + @property + def vertices(self): + """Return coordinates of mesh vertices in Cartesian coordinates. Also + see :meth:`CylindricalMesh.vertices_cylindrical` and + :meth:`SphericalMesh.vertices_spherical` for coordinates in other coordinate + systems. + + Returns + ------- + vertices : numpy.ndarray + Returns a numpy.ndarray representing the coordinates of the mesh + vertices with a shape equal to (dim1 + 1, ..., dimn + 1, ndim). X, Y, Z values + can be unpacked with xx, yy, zz = np.rollaxis(mesh.vertices, -1). + + """ + return self._generate_vertices(*self._grids) + + @staticmethod + def _generate_vertices(i_grid, j_grid, k_grid): + """Returns an array with shape (i_grid.size, j_grid.size, k_grid.size, 3) + containing the corner vertices of mesh elements. + """ + return np.stack(np.meshgrid(i_grid, j_grid, k_grid, indexing='ij'), axis=-1) + + @staticmethod + def _generate_edge_midpoints(grids): + """Generates the midpoints of mesh element edges for each dimension of the mesh. + + Parameters + ---------- + grids : numpy.ndarray + The vertex grids along each dimension of the mesh. + + Returns + ------- + midpoint_grids : list of numpy.ndarray + The edge midpoints for the i, j, and k midpoints of each element in + i, j, k ordering. The shapes of the resulting grids are + [(ni-1, nj, nk, 3), (ni, nj-1, nk, 3), (ni, nj, nk-1, 3)] + """ + # generate a set of edge midpoints for each dimension + midpoint_grids = [] + # generate the element edge midpoints in order s.t. + # the epxected element ordering is preserved with respect to the corner vertices + + # each grid is comprised of the mid points for one dimension and the + # corner vertices of the other two + for dims in ((0, 1, 2), (1, 0, 2), (2, 0, 1)): + # compute the midpoints along the last dimension + midpoints = grids[dims[0]][:-1] + 0.5 * np.diff(grids[dims[0]]) + + coords = (midpoints, grids[dims[1]], grids[dims[2]]) + + i_grid, j_grid, k_grid = [coords[dims.index(i)] for i in range(3)] + + # re-use the generate vertices method to create the full mesh grid + # transpose to get (i, j, k) ordering of the gridpoints + midpoint_grid = StructuredMesh._generate_vertices(i_grid, j_grid, k_grid) + midpoint_grids.append(midpoint_grid) + + return midpoint_grids + + @property + def midpoint_vertices(self): + """Create vertices that lie on the midpoint of element edges + """ + # generate edge midpoints needed for curvilinear element definition + midpoint_vertices = self._generate_edge_midpoints(self._grids) + + # convert each of the midpoint grids to cartesian coordinates + for vertices in midpoint_vertices: + self._convert_to_cartesian(vertices, self.origin) + + return midpoint_vertices + + @property + def centroids(self): + """Return coordinates of mesh element centroids. + + Returns + ------- + centroids : numpy.ndarray + Returns a numpy.ndarray representing the mesh element centroid + coordinates with a shape equal to (dim1, ..., dimn, ndim). X, + Y, Z values can be unpacked with xx, yy, zz = + np.rollaxis(mesh.centroids, -1). + """ + ndim = self.n_dimension + # this line ensures that the vertices aren't adjusted by the origin or + # converted to the Cartesian system for cylindrical and spherical meshes + vertices = StructuredMesh.vertices.fget(self) + s0 = (slice(0, -1),)*ndim + (slice(None),) + s1 = (slice(1, None),)*ndim + (slice(None),) + return (vertices[s0] + vertices[s1]) / 2 + + @property + def num_mesh_cells(self): + return np.prod(self.dimension) + + def write_data_to_vtk(self, + filename: PathLike, + datasets: Optional[dict] = None, + volume_normalization: bool = True, + curvilinear: bool = False): + """Creates a VTK object of the mesh + + Parameters + ---------- + filename : str + Name of the VTK file to write. + datasets : dict + Dictionary whose keys are the data labels + and values are the data sets. + volume_normalization : bool, optional + Whether or not to normalize the data by + the volume of the mesh elements. + curvilinear : bool + Whether or not to write curvilinear elements. Only applies to + ``SphericalMesh`` and ``CylindricalMesh``. + + Raises + ------ + ValueError + When the size of a dataset doesn't match the number of mesh cells + + Returns + ------- + vtk.StructuredGrid or vtk.UnstructuredGrid + a VTK grid object representing the mesh + """ + import vtk + from vtk.util import numpy_support as nps + + # check that the data sets are appropriately sized + if datasets is not None: + self._check_vtk_datasets(datasets) + + # write linear elements using a structured grid + if not curvilinear or isinstance(self, (RegularMesh, RectilinearMesh)): + vtk_grid = self._create_vtk_structured_grid() + writer = vtk.vtkStructuredGridWriter() + # write curvilinear elements using an unstructured grid + else: + vtk_grid = self._create_vtk_unstructured_grid() + writer = vtk.vtkUnstructuredGridWriter() + + if datasets is not None: + # maintain a list of the datasets as added + # to the VTK arrays to ensure they persist + # in memory until the file is written + datasets_out = [] + for label, dataset in datasets.items(): + dataset = np.asarray(dataset).flatten() + datasets_out.append(dataset) + + if volume_normalization: + dataset /= self.volumes.T.flatten() + + dataset_array = vtk.vtkDoubleArray() + dataset_array.SetName(label) + dataset_array.SetArray(nps.numpy_to_vtk(dataset), + dataset.size, + True) + vtk_grid.GetCellData().AddArray(dataset_array) + + writer.SetFileName(str(filename)) + writer.SetInputData(vtk_grid) + writer.Write() + + return vtk_grid + + def _create_vtk_structured_grid(self): + """Create a structured grid -class RegularMesh(MeshBase): + Returns + ------- + vtk.vtkStructuredGrid + a VTK structured grid object representing the mesh + """ + import vtk + from vtk.util import numpy_support as nps + + vtkPts = vtk.vtkPoints() + vtkPts.SetData(nps.numpy_to_vtk(np.swapaxes(self.vertices, 0, 2).reshape(-1, 3), deep=True)) + vtk_grid = vtk.vtkStructuredGrid() + vtk_grid.SetPoints(vtkPts) + vtk_grid.SetDimensions(*[dim + 1 for dim in self.dimension]) + + return vtk_grid + + def _create_vtk_unstructured_grid(self): + """Create an unstructured grid of curvilinear elements + representing the mesh + + Returns + ------- + vtk.vtkUnstructuredGrid + a VTK unstructured grid object representing the mesh + """ + import vtk + from vtk.util import numpy_support as nps + + corner_vertices = np.swapaxes(self.vertices, 0, 2).reshape(-1, 3) + + vtkPts = vtk.vtkPoints() + vtk_grid = vtk.vtkUnstructuredGrid() + vtk_grid.SetPoints(vtkPts) + # add corner vertices to the point set for the unstructured grid + # only insert unique points, we'll get their IDs in the point set to + # define element connectivity later + vtkPts.SetData(nps.numpy_to_vtk(np.unique(corner_vertices, axis=0), deep=True)) + + # create a locator to assist with duplicate points + locator = vtk.vtkPointLocator() + locator.SetDataSet(vtk_grid) + locator.AutomaticOn() # autmoatically adds points to locator + locator.InitPointInsertion(vtkPts, vtkPts.GetBounds()) + locator.BuildLocator() + + # this function is used to add new points to the unstructured + # grid. It will return an existing point ID if the point is alread present + def _insert_point(pnt): + result = locator.IsInsertedPoint(pnt) + if result == -1: + point_id = vtkPts.InsertNextPoint(pnt) + locator.InsertPoint(point_id, pnt) + return point_id + else: + return result + + # Add all points to the unstructured grid, maintaining a flat list of IDs as we go ### + + # flat array storing point IDs for a given vertex + # in the grid + point_ids = [] + + # add element corner vertices to array + for pnt in corner_vertices: + point_ids.append(_insert_point(pnt)) + + # get edge midpoints and add them to the + # list of point IDs + midpoint_vertices = self.midpoint_vertices + for edge_grid in midpoint_vertices: + for pnt in np.swapaxes(edge_grid, 0, 2).reshape(-1, 3): + point_ids.append(_insert_point(pnt)) + + # determine how many elements in each dimension + # and how many points in each grid + n_elem = np.asarray(self.dimension) + n_pnts = n_elem + 1 + + # create hexes and set points for corner + # vertices + for i, j, k in self.indices: + # handle indices indexed from one + i -= 1 + j -= 1 + k -= 1 + + # create a new vtk hex + hex = vtk.vtkQuadraticHexahedron() + + # set connectivity the hex corners + for n, (di, dj, dk) in enumerate(_HEX_VERTEX_CONN): + # compute flat index into the point ID list based on i, j, k + # of the vertex + flat_idx = np.ravel_multi_index((i+di, j+dj, k+dk), n_pnts, order='F') + # set corner vertices + hex.GetPointIds().SetId(n, point_ids[flat_idx]) + + # set connectivity of the hex midpoints + n_midpoint_vertices = [v.size // 3 for v in midpoint_vertices] + for n, (dim, (di, dj, dk)) in enumerate(_HEX_MIDPOINT_CONN): + # initial offset for corner vertices and midpoint dimension + flat_idx = corner_vertices.shape[0] + sum(n_midpoint_vertices[:dim]) + # generate a flat index into the table of point IDs + midpoint_shape = midpoint_vertices[dim].shape[:-1] + flat_idx += np.ravel_multi_index((i+di, j+dj, k+dk), + midpoint_shape, + order='F') + # set hex midpoint connectivity + hex.GetPointIds().SetId(_N_HEX_VERTICES + n, point_ids[flat_idx]) + + # add the hex to the grid + vtk_grid.InsertNextCell(hex.GetCellType(), hex.GetPointIds()) + + return vtk_grid + + def _check_vtk_datasets(self, datasets: dict): + """Perform some basic checks that the datasets are valid for this mesh + + Parameters + ---------- + datasets : dict + Dictionary whose keys are the data labels + and values are the data sets. + + """ + for label, dataset in datasets.items(): + errmsg = ( + f"The size of the dataset '{label}' ({dataset.size}) should be" + f" equal to the number of mesh cells ({self.num_mesh_cells})" + ) + if isinstance(dataset, np.ndarray): + if not dataset.size == self.num_mesh_cells: + raise ValueError(errmsg) + else: + if len(dataset) == self.num_mesh_cells: + raise ValueError(errmsg) + cv.check_type('data label', label, str) + + +class RegularMesh(StructuredMesh): """A regular Cartesian mesh in one, two, or three dimensions Parameters @@ -103,15 +603,18 @@ class RegularMesh(MeshBase): name : str Name of the mesh dimension : Iterable of int - The number of mesh cells in each direction. + The number of mesh cells in each direction (x, y, z). n_dimension : int Number of mesh dimensions. lower_left : Iterable of float The lower-left corner of the structured mesh. If only two coordinate are given, it is assumed that the mesh is an x-y mesh. upper_right : Iterable of float - The upper-right corner of the structrued mesh. If only two coordinate + The upper-right corner of the structured mesh. If only two coordinate are given, it is assumed that the mesh is an x-y mesh. + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. width : Iterable of float The width of mesh cells in each direction. indices : Iterable of tuple @@ -120,7 +623,7 @@ class RegularMesh(MeshBase): """ - def __init__(self, mesh_id=None, name=''): + def __init__(self, mesh_id: Optional[int] = None, name: str = ''): super().__init__(mesh_id, name) self._dimension = None @@ -130,7 +633,13 @@ def __init__(self, mesh_id=None, name=''): @property def dimension(self): - return self._dimension + return tuple(self._dimension) + + @dimension.setter + def dimension(self, dimension: typing.Iterable[int]): + cv.check_type('mesh dimension', dimension, Iterable, Integral) + cv.check_length('mesh dimension', dimension, 1, 3) + self._dimension = dimension @property def n_dimension(self): @@ -143,17 +652,76 @@ def n_dimension(self): def lower_left(self): return self._lower_left + @lower_left.setter + def lower_left(self, lower_left: typing.Iterable[Real]): + cv.check_type('mesh lower_left', lower_left, Iterable, Real) + cv.check_length('mesh lower_left', lower_left, 1, 3) + self._lower_left = lower_left + + if self.upper_right is not None and any(np.isclose(self.upper_right, lower_left)): + raise ValueError("Mesh cannot have zero thickness in any dimension") + @property def upper_right(self): - return self._upper_right + if self._upper_right is not None: + return self._upper_right + elif self._width is not None: + if self._lower_left is not None and self._dimension is not None: + ls = self._lower_left + ws = self._width + dims = self._dimension + return [l + w * d for l, w, d in zip(ls, ws, dims)] + + @upper_right.setter + def upper_right(self, upper_right: typing.Iterable[Real]): + cv.check_type('mesh upper_right', upper_right, Iterable, Real) + cv.check_length('mesh upper_right', upper_right, 1, 3) + self._upper_right = upper_right + + if self._width is not None: + self._width = None + warnings.warn("Unsetting width attribute.") + + if self.lower_left is not None and any(np.isclose(self.lower_left, upper_right)): + raise ValueError("Mesh cannot have zero thickness in any dimension") @property def width(self): - return self._width + if self._width is not None: + return self._width + elif self._upper_right is not None: + if self._lower_left is not None and self._dimension is not None: + us = self._upper_right + ls = self._lower_left + dims = self._dimension + return [(u - l) / d for u, l, d in zip(us, ls, dims)] + + @width.setter + def width(self, width: typing.Iterable[Real]): + cv.check_type('mesh width', width, Iterable, Real) + cv.check_length('mesh width', width, 1, 3) + self._width = width + + if self._upper_right is not None: + self._upper_right = None + warnings.warn("Unsetting upper_right attribute.") @property - def num_mesh_cells(self): - return np.prod(self._dimension) + def volumes(self): + """Return Volumes for every mesh cell + + Returns + ------- + volumes : numpy.ndarray + Volumes + + """ + self._volume_dim_check() + return np.full(self.dimension, np.prod(self.width)) + + @property + def total_volume(self): + return np.prod(self.dimension) * np.prod(self.width) @property def indices(self): @@ -173,54 +741,64 @@ def indices(self): nx, = self.dimension return ((x,) for x in range(1, nx + 1)) - @dimension.setter - def dimension(self, dimension): - cv.check_type('mesh dimension', dimension, Iterable, Integral) - cv.check_length('mesh dimension', dimension, 1, 3) - self._dimension = dimension - - @lower_left.setter - def lower_left(self, lower_left): - cv.check_type('mesh lower_left', lower_left, Iterable, Real) - cv.check_length('mesh lower_left', lower_left, 1, 3) - self._lower_left = lower_left - - @upper_right.setter - def upper_right(self, upper_right): - cv.check_type('mesh upper_right', upper_right, Iterable, Real) - cv.check_length('mesh upper_right', upper_right, 1, 3) - self._upper_right = upper_right - - @width.setter - def width(self, width): - cv.check_type('mesh width', width, Iterable, Real) - cv.check_length('mesh width', width, 1, 3) - self._width = width + @property + def _grids(self): + ndim = len(self._dimension) + if ndim == 3: + x0, y0, z0 = self.lower_left + x1, y1, z1 = self.upper_right + nx, ny, nz = self.dimension + xarr = np.linspace(x0, x1, nx + 1) + yarr = np.linspace(y0, y1, ny + 1) + zarr = np.linspace(z0, z1, nz + 1) + return (xarr, yarr, zarr) + elif ndim == 2: + x0, y0 = self.lower_left + x1, y1 = self.upper_right + nx, ny = self.dimension + xarr = np.linspace(x0, x1, nx + 1) + yarr = np.linspace(y0, y1, ny + 1) + return (xarr, yarr) + else: + nx, = self.dimension + x0, = self.lower_left + x1, = self.upper_right + return (np.linspace(x0, x1, nx + 1),) def __repr__(self): string = super().__repr__() string += '{0: <16}{1}{2}\n'.format('\tDimensions', '=\t', self.n_dimension) - string += '{0: <16}{1}{2}\n'.format('\tMesh Cells', '=\t', self._dimension) - string += '{0: <16}{1}{2}\n'.format('\tWidth', '=\t', self._lower_left) - string += '{0: <16}{1}{2}\n'.format('\tOrigin', '=\t', self._upper_right) - string += '{0: <16}{1}{2}\n'.format('\tPixels', '=\t', self._width) + string += '{0: <16}{1}{2}\n'.format('\tVoxels', '=\t', self._dimension) + string += '{0: <16}{1}{2}\n'.format('\tLower left', '=\t', self._lower_left) + string += '{0: <16}{1}{2}\n'.format('\tUpper Right', '=\t', self._upper_right) + string += '{0: <16}{1}{2}\n'.format('\tWidth', '=\t', self._width) return string @classmethod - def from_hdf5(cls, group): + def from_hdf5(cls, group: h5py.Group): mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) # Read and assign mesh properties mesh = cls(mesh_id) mesh.dimension = group['dimension'][()] mesh.lower_left = group['lower_left'][()] - mesh.upper_right = group['upper_right'][()] - mesh.width = group['width'][()] + if 'width' in group: + mesh.width = group['width'][()] + elif 'upper_right' in group: + mesh.upper_right = group['upper_right'][()] + else: + raise IOError('Invalid mesh: must have one of "upper_right" or "width"') return mesh @classmethod - def from_rect_lattice(cls, lattice, division=1, mesh_id=None, name=''): + def from_rect_lattice( + cls, + lattice: 'openmc.RectLattice', + division: int = 1, + mesh_id: Optional[int] = None, + name: str = '' + ): """Create mesh from an existing rectangular lattice Parameters @@ -246,19 +824,62 @@ def from_rect_lattice(cls, lattice, division=1, mesh_id=None, name=''): shape = np.array(lattice.shape) width = lattice.pitch*shape - mesh = cls(mesh_id, name) + mesh = cls(mesh_id=mesh_id, name=name) mesh.lower_left = lattice.lower_left mesh.upper_right = lattice.lower_left + width mesh.dimension = shape*division return mesh + @classmethod + def from_domain( + cls, + domain: typing.Union['openmc.Cell', 'openmc.Region', 'openmc.Universe', 'openmc.Geometry'], + dimension: Sequence[int] = (10, 10, 10), + mesh_id: Optional[int] = None, + name: str = '' + ): + """Create mesh from an existing openmc cell, region, universe or + geometry by making use of the objects bounding box property. + + Parameters + ---------- + domain : {openmc.Cell, openmc.Region, openmc.Universe, openmc.Geometry} + The object passed in will be used as a template for this mesh. The + bounding box of the property of the object passed will be used to + set the lower_left and upper_right and of the mesh instance + dimension : Iterable of int + The number of mesh cells in each direction (x, y, z). + mesh_id : int + Unique identifier for the mesh + name : str + Name of the mesh + + Returns + ------- + openmc.RegularMesh + RegularMesh instance + + """ + cv.check_type( + "domain", + domain, + (openmc.Cell, openmc.Region, openmc.Universe, openmc.Geometry), + ) + + mesh = cls(mesh_id=mesh_id, name=name) + mesh.lower_left = domain.bounding_box[0] + mesh.upper_right = domain.bounding_box[1] + mesh.dimension = dimension + + return mesh + def to_xml_element(self): """Return XML representation of the mesh Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing mesh data """ @@ -276,7 +897,6 @@ def to_xml_element(self): if self._upper_right is not None: subelement = ET.SubElement(element, "upper_right") subelement.text = ' '.join(map(str, self._upper_right)) - if self._width is not None: subelement = ET.SubElement(element, "width") subelement.text = ' '.join(map(str, self._width)) @@ -284,12 +904,12 @@ def to_xml_element(self): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate mesh from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -299,7 +919,7 @@ def from_xml_element(cls, elem): """ mesh_id = int(get_text(elem, 'id')) - mesh = cls(mesh_id) + mesh = cls(mesh_id=mesh_id) mesh_type = get_text(elem, 'type') if mesh_type is not None: @@ -323,7 +943,7 @@ def from_xml_element(cls, elem): return mesh - def build_cells(self, bc=None): + def build_cells(self, bc: Optional[str] = None): """Generates a lattice of universes with the same dimensionality as the mesh object. The individual cells/universes produced will not have material definitions applied and so downstream code @@ -358,7 +978,7 @@ def build_cells(self, bc=None): for entry in bc: cv.check_value('bc', entry, _BOUNDARY_TYPES) - n_dim = len(self.dimension) + n_dim = self.n_dimension # Build the cell which will contain the lattice xplanes = [openmc.XPlane(self.lower_left[0], boundary_type=bc[0]), @@ -455,7 +1075,7 @@ def Mesh(*args, **kwargs): return RegularMesh(*args, **kwargs) -class RectilinearMesh(MeshBase): +class RectilinearMesh(StructuredMesh): """A 3D rectilinear Cartesian mesh Parameters @@ -472,22 +1092,25 @@ class RectilinearMesh(MeshBase): name : str Name of the mesh dimension : Iterable of int - The number of mesh cells in each direction. + The number of mesh cells in each direction (x, y, z). n_dimension : int Number of mesh dimensions (always 3 for a RectilinearMesh). - x_grid : Iterable of float - Mesh boundary points along the x-axis. - y_grid : Iterable of float - Mesh boundary points along the y-axis. - z_grid : Iterable of float - Mesh boundary points along the z-axis. + x_grid : numpy.ndarray + 1-D array of mesh boundary points along the x-axis. + y_grid : numpy.ndarray + 1-D array of mesh boundary points along the y-axis. + z_grid : numpy.ndarray + 1-D array of mesh boundary points along the z-axis. indices : Iterable of tuple An iterable of mesh indices for each mesh element, e.g. [(1, 1, 1), (2, 1, 1), ...] + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. """ - def __init__(self, mesh_id=None, name=''): + def __init__(self, mesh_id: int = None, name: str = ''): super().__init__(mesh_id, name) self._x_grid = None @@ -508,78 +1131,134 @@ def n_dimension(self): def x_grid(self): return self._x_grid + @x_grid.setter + def x_grid(self, grid): + cv.check_type('mesh x_grid', grid, Iterable, Real) + self._x_grid = np.asarray(grid, dtype=float) + @property def y_grid(self): return self._y_grid + @y_grid.setter + def y_grid(self, grid): + cv.check_type('mesh y_grid', grid, Iterable, Real) + self._y_grid = np.asarray(grid, dtype=float) + @property def z_grid(self): return self._z_grid + @z_grid.setter + def z_grid(self, grid): + cv.check_type('mesh z_grid', grid, Iterable, Real) + self._z_grid = np.asarray(grid, dtype=float) + @property - def indices(self): - nx = len(self.x_grid) - 1 - ny = len(self.y_grid) - 1 + def _grids(self): + return (self.x_grid, self.y_grid, self.z_grid) + + @property + def lower_left(self): + return np.array([self.x_grid[0], self.y_grid[0], self.z_grid[0]]) + + @property + def upper_right(self): + return np.array([self.x_grid[-1], self.y_grid[-1], self.z_grid[-1]]) + + @property + def volumes(self): + """Return Volumes for every mesh cell + + Returns + ------- + volumes : numpy.ndarray + Volumes + + """ + self._volume_dim_check() + V_x = np.diff(self.x_grid) + V_y = np.diff(self.y_grid) + V_z = np.diff(self.z_grid) + + return np.multiply.outer(np.outer(V_x, V_y), V_z) + + @property + def total_volume(self): + return np.sum(self.volumes) + + @property + def indices(self): + nx = len(self.x_grid) - 1 + ny = len(self.y_grid) - 1 nz = len(self.z_grid) - 1 return ((x, y, z) for z in range(1, nz + 1) for y in range(1, ny + 1) for x in range(1, nx + 1)) - @x_grid.setter - def x_grid(self, grid): - cv.check_type('mesh x_grid', grid, Iterable, Real) - self._x_grid = grid - - @y_grid.setter - def y_grid(self, grid): - cv.check_type('mesh y_grid', grid, Iterable, Real) - self._y_grid = grid - - @z_grid.setter - def z_grid(self, grid): - cv.check_type('mesh z_grid', grid, Iterable, Real) - self._z_grid = grid - def __repr__(self): fmt = '{0: <16}{1}{2}\n' string = super().__repr__() string += fmt.format('\tDimensions', '=\t', self.n_dimension) - x_grid_str = str(self._x_grid) if not self._x_grid else len(self._x_grid) + x_grid_str = str(self._x_grid) if self._x_grid is None else len(self._x_grid) string += fmt.format('\tN X pnts:', '=\t', x_grid_str) - if self._x_grid: + if self._x_grid is not None: string += fmt.format('\tX Min:', '=\t', self._x_grid[0]) string += fmt.format('\tX Max:', '=\t', self._x_grid[-1]) - y_grid_str = str(self._y_grid) if not self._y_grid else len(self._y_grid) + y_grid_str = str(self._y_grid) if self._y_grid is None else len(self._y_grid) string += fmt.format('\tN Y pnts:', '=\t', y_grid_str) - if self._y_grid: + if self._y_grid is not None: string += fmt.format('\tY Min:', '=\t', self._y_grid[0]) string += fmt.format('\tY Max:', '=\t', self._y_grid[-1]) - z_grid_str = str(self._z_grid) if not self._z_grid else len(self._z_grid) + z_grid_str = str(self._z_grid) if self._z_grid is None else len(self._z_grid) string += fmt.format('\tN Z pnts:', '=\t', z_grid_str) - if self._z_grid: + if self._z_grid is not None: string += fmt.format('\tZ Min:', '=\t', self._z_grid[0]) string += fmt.format('\tZ Max:', '=\t', self._z_grid[-1]) return string @classmethod - def from_hdf5(cls, group): + def from_hdf5(cls, group: h5py.Group): mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) # Read and assign mesh properties - mesh = cls(mesh_id) + mesh = cls(mesh_id=mesh_id) mesh.x_grid = group['x_grid'][()] mesh.y_grid = group['y_grid'][()] mesh.z_grid = group['z_grid'][()] return mesh + @classmethod + def from_xml_element(cls, elem: ET.Element): + """Generate a rectilinear mesh from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.RectilinearMesh + Rectilinear mesh object + + """ + mesh_id = int(get_text(elem, 'id')) + mesh = cls(mesh_id=mesh_id) + mesh.x_grid = [float(x) for x in get_text(elem, 'x_grid').split()] + mesh.y_grid = [float(y) for y in get_text(elem, 'y_grid').split()] + mesh.z_grid = [float(z) for z in get_text(elem, 'z_grid').split()] + + return mesh + def to_xml_element(self): """Return XML representation of the mesh Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing mesh data """ @@ -600,6 +1279,749 @@ def to_xml_element(self): return element +class CylindricalMesh(StructuredMesh): + """A 3D cylindrical mesh + + Parameters + ---------- + r_grid : numpy.ndarray + 1-D array of mesh boundary points along the r-axis + Requirement is r >= 0. + z_grid : numpy.ndarray + 1-D array of mesh boundary points along the z-axis relative to the + origin. + phi_grid : numpy.ndarray + 1-D array of mesh boundary points along the phi-axis in radians. + The default value is [0, 2π], i.e. the full phi range. + origin : numpy.ndarray + 1-D array of length 3 the (x,y,z) origin of the mesh in + cartesian coordinates + mesh_id : int + Unique identifier for the mesh + name : str + Name of the mesh + + Attributes + ---------- + id : int + Unique identifier for the mesh + name : str + Name of the mesh + dimension : Iterable of int + The number of mesh cells in each direction (r_grid, phi_grid, z_grid). + n_dimension : int + Number of mesh dimensions (always 3 for a CylindricalMesh). + r_grid : numpy.ndarray + 1-D array of mesh boundary points along the r-axis. + Requirement is r >= 0. + phi_grid : numpy.ndarray + 1-D array of mesh boundary points along the phi-axis in radians. + The default value is [0, 2π], i.e. the full phi range. + z_grid : numpy.ndarray + 1-D array of mesh boundary points along the z-axis relative to the + origin. + origin : numpy.ndarray + 1-D array of length 3 the (x,y,z) origin of the mesh in + cartesian coordinates + indices : Iterable of tuple + An iterable of mesh indices for each mesh element, e.g. [(1, 1, 1), + (2, 1, 1), ...] + lower_left : Iterable of float + The lower-left corner of the structured mesh. If only two coordinate + are given, it is assumed that the mesh is an x-y mesh. + upper_right : Iterable of float + The upper-right corner of the structured mesh. If only two coordinate + are given, it is assumed that the mesh is an x-y mesh. + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. + + """ + + def __init__( + self, + r_grid: Sequence[float], + z_grid: Sequence[float], + phi_grid: Sequence[float] = (0, 2*pi), + origin: Sequence[float] = (0., 0., 0.), + mesh_id: Optional[int] = None, + name: str = '', + ): + super().__init__(mesh_id, name) + + self.r_grid = r_grid + self.phi_grid = phi_grid + self.z_grid = z_grid + self.origin = origin + + @property + def dimension(self): + return (len(self.r_grid) - 1, + len(self.phi_grid) - 1, + len(self.z_grid) - 1) + + @property + def n_dimension(self): + return 3 + + @property + def origin(self): + return self._origin + + @origin.setter + def origin(self, coords): + cv.check_type('mesh origin', coords, Iterable, Real) + cv.check_length("mesh origin", coords, 3) + self._origin = np.asarray(coords) + + @property + def r_grid(self): + return self._r_grid + + @r_grid.setter + def r_grid(self, grid): + cv.check_type('mesh r_grid', grid, Iterable, Real) + self._r_grid = np.asarray(grid, dtype=float) + + @property + def phi_grid(self): + return self._phi_grid + + @phi_grid.setter + def phi_grid(self, grid): + cv.check_type('mesh phi_grid', grid, Iterable, Real) + self._phi_grid = np.asarray(grid, dtype=float) + + @property + def z_grid(self): + return self._z_grid + + @z_grid.setter + def z_grid(self, grid): + cv.check_type('mesh z_grid', grid, Iterable, Real) + self._z_grid = np.asarray(grid, dtype=float) + + @property + def _grids(self): + return (self.r_grid, self.phi_grid, self.z_grid) + + @property + def indices(self): + nr, np, nz = self.dimension + np = len(self.phi_grid) - 1 + nz = len(self.z_grid) - 1 + return ((r, p, z) + for z in range(1, nz + 1) + for p in range(1, np + 1) + for r in range(1, nr + 1)) + + @property + def lower_left(self): + return np.array(( + self.origin[0] - self.r_grid[-1], + self.origin[1] - self.r_grid[-1], + self.origin[2] + self.z_grid[0] + )) + + @property + def upper_right(self): + return np.array(( + self.origin[0] + self.r_grid[-1], + self.origin[1] + self.r_grid[-1], + self.origin[2] + self.z_grid[-1] + )) + + def __repr__(self): + fmt = '{0: <16}{1}{2}\n' + string = super().__repr__() + string += fmt.format('\tDimensions', '=\t', self.n_dimension) + string += fmt.format('\tOrigin', '=\t', self.origin) + r_grid_str = str(self._r_grid) if self._r_grid is None else len(self._r_grid) + string += fmt.format('\tN R pnts:', '=\t', r_grid_str) + if self._r_grid is not None: + string += fmt.format('\tR Min:', '=\t', self._r_grid[0]) + string += fmt.format('\tR Max:', '=\t', self._r_grid[-1]) + phi_grid_str = str(self._phi_grid) if self._phi_grid is None else len(self._phi_grid) + string += fmt.format('\tN Phi pnts:', '=\t', phi_grid_str) + if self._phi_grid is not None: + string += fmt.format('\tPhi Min:', '=\t', self._phi_grid[0]) + string += fmt.format('\tPhi Max:', '=\t', self._phi_grid[-1]) + z_grid_str = str(self._z_grid) if self._z_grid is None else len(self._z_grid) + string += fmt.format('\tN Z pnts:', '=\t', z_grid_str) + if self._z_grid is not None: + string += fmt.format('\tZ Min:', '=\t', self._z_grid[0]) + string += fmt.format('\tZ Max:', '=\t', self._z_grid[-1]) + return string + + def get_indices_at_coords( + self, + coords: Sequence[float] + ) -> Tuple[int, int, int]: + """Finds the index of the mesh voxel at the specified x,y,z coordinates. + + Parameters + ---------- + coords : Sequence[float] + The x, y, z axis coordinates + + Returns + ------- + Tuple[int, int, int] + The r, phi, z indices + + """ + r_value_from_origin = sqrt((coords[0]-self.origin[0])**2 + (coords[1]-self.origin[1])**2) + + if r_value_from_origin < self.r_grid[0] or r_value_from_origin > self.r_grid[-1]: + raise ValueError( + f'The specified x, y ({coords[0]}, {coords[1]}) combine to give an r value of ' + f'{r_value_from_origin} from the origin of {self.origin}.which ' + f'is outside the origin absolute r grid values {self.r_grid}.' + ) + + r_index = np.searchsorted(self.r_grid, r_value_from_origin) - 1 + + z_grid_values = np.array(self.z_grid) + self.origin[2] + + if coords[2] < z_grid_values[0] or coords[2] > z_grid_values[-1]: + raise ValueError( + f'The specified z value ({coords[2]}) from the z origin of ' + f'{self.origin[-1]} is outside of the absolute z grid range {z_grid_values}.' + ) + + z_index = np.argmax(z_grid_values > coords[2]) - 1 + + delta_x = coords[0] - self.origin[0] + delta_y = coords[1] - self.origin[1] + # atan2 returns values in -pi to +pi range + phi_value = atan2(delta_y, delta_x) + if delta_x < 0 and delta_y < 0: + # returned phi_value anticlockwise and negative + phi_value += 2 * pi + if delta_x > 0 and delta_y < 0: + # returned phi_value anticlockwise and negative + phi_value += 2 * pi + + phi_grid_values = np.array(self.phi_grid) + + if phi_value < phi_grid_values[0] or phi_value > phi_grid_values[-1]: + raise ValueError( + f'The phi value ({phi_value}) resulting from the specified x, y ' + f'values is outside of the absolute phi grid range {phi_grid_values}.' + ) + phi_index = np.argmax(phi_grid_values > phi_value) - 1 + + return (r_index, phi_index, z_index) + + @classmethod + def from_hdf5(cls, group: h5py.Group): + mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) + + # Read and assign mesh properties + mesh = cls( + mesh_id=mesh_id, + r_grid = group['r_grid'][()], + phi_grid = group['phi_grid'][()], + z_grid = group['z_grid'][()], + ) + if 'origin' in group: + mesh.origin = group['origin'][()] + + return mesh + + @classmethod + def from_domain( + cls, + domain: typing.Union['openmc.Cell', 'openmc.Region', 'openmc.Universe', 'openmc.Geometry'], + dimension: Sequence[int] = (10, 10, 10), + mesh_id: Optional[int] = None, + phi_grid_bounds: Sequence[float] = (0.0, 2*pi), + name: str = '' + ): + """Creates a regular CylindricalMesh from an existing openmc domain. + + Parameters + ---------- + domain : openmc.Cell or openmc.Region or openmc.Universe or openmc.Geometry + The object passed in will be used as a template for this mesh. The + bounding box of the property of the object passed will be used to + set the r_grid, z_grid ranges. + dimension : Iterable of int + The number of equally spaced mesh cells in each direction (r_grid, + phi_grid, z_grid) + mesh_id : int + Unique identifier for the mesh + phi_grid_bounds : numpy.ndarray + Mesh bounds points along the phi-axis in radians. The default value + is (0, 2π), i.e., the full phi range. + name : str + Name of the mesh + + Returns + ------- + openmc.CylindricalMesh + CylindricalMesh instance + + """ + cv.check_type( + "domain", + domain, + (openmc.Cell, openmc.Region, openmc.Universe, openmc.Geometry), + ) + + # loaded once to avoid recalculating bounding box + cached_bb = domain.bounding_box + max_bounding_box_radius = max( + [ + cached_bb[0][0], + cached_bb[0][1], + cached_bb[1][0], + cached_bb[1][1], + ] + ) + r_grid = np.linspace( + 0, + max_bounding_box_radius, + num=dimension[0]+1 + ) + phi_grid = np.linspace( + phi_grid_bounds[0], + phi_grid_bounds[1], + num=dimension[1]+1 + ) + z_grid = np.linspace( + cached_bb[0][2], + cached_bb[1][2], + num=dimension[2]+1 + ) + origin = (cached_bb.center[0], cached_bb.center[1], z_grid[0]) + + # make z-grid relative to the origin + z_grid -= origin[2] + + mesh = cls( + r_grid=r_grid, + z_grid=z_grid, + phi_grid=phi_grid, + mesh_id=mesh_id, + name=name, + origin=origin + ) + + return mesh + + def to_xml_element(self): + """Return XML representation of the mesh + + Returns + ------- + element : lxml.etree._Element + XML element containing mesh data + + """ + + element = ET.Element("mesh") + element.set("id", str(self._id)) + element.set("type", "cylindrical") + + subelement = ET.SubElement(element, "r_grid") + subelement.text = ' '.join(map(str, self.r_grid)) + + subelement = ET.SubElement(element, "phi_grid") + subelement.text = ' '.join(map(str, self.phi_grid)) + + subelement = ET.SubElement(element, "z_grid") + subelement.text = ' '.join(map(str, self.z_grid)) + + subelement = ET.SubElement(element, "origin") + subelement.text = ' '.join(map(str, self.origin)) + + return element + + @classmethod + def from_xml_element(cls, elem: ET.Element): + """Generate a cylindrical mesh from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.CylindricalMesh + Cylindrical mesh object + + """ + + mesh_id = int(get_text(elem, 'id')) + mesh = cls( + r_grid = [float(x) for x in get_text(elem, "r_grid").split()], + phi_grid = [float(x) for x in get_text(elem, "phi_grid").split()], + z_grid = [float(x) for x in get_text(elem, "z_grid").split()], + origin = [float(x) for x in get_text(elem, "origin", default=[0., 0., 0.]).split()], + mesh_id=mesh_id, + ) + + return mesh + + @property + def volumes(self): + """Return Volumes for every mesh cell + + Returns + ------- + volumes : Iterable of float + Volumes + + """ + self._volume_dim_check() + V_r = np.diff(np.asarray(self.r_grid)**2 / 2) + V_p = np.diff(self.phi_grid) + V_z = np.diff(self.z_grid) + + return np.multiply.outer(np.outer(V_r, V_p), V_z) + + @property + def vertices(self): + warnings.warn('Cartesian coordinates are returned from this property as of version 0.14.0') + return self._convert_to_cartesian(self.vertices_cylindrical, self.origin) + + @property + def vertices_cylindrical(self): + """Returns vertices of the mesh in cylindrical coordinates. + """ + return super().vertices + + @property + def centroids(self): + warnings.warn('Cartesian coordinates are returned from this property as of version 0.14.0') + return self._convert_to_cartesian(self.centroids_cylindrical, self.origin) + + @property + def centroids_cylindrical(self): + """Returns centroids of the mesh in cylindrical coordinates. + """ + return super().centroids + + @staticmethod + def _convert_to_cartesian(arr, origin: Sequence[float]): + """Converts an array with r, phi, z values in the last dimension (shape (..., 3)) + to Cartesian coordinates. + """ + x = arr[..., 0] * np.cos(arr[..., 1]) + origin[0] + y = arr[..., 0] * np.sin(arr[..., 1]) + origin[1] + arr[..., 0] = x + arr[..., 1] = y + arr[..., 2] += origin[2] + return arr + + +class SphericalMesh(StructuredMesh): + """A 3D spherical mesh + + Parameters + ---------- + r_grid : numpy.ndarray + 1-D array of mesh boundary points along the r-axis. + Requirement is r >= 0. + phi_grid : numpy.ndarray + 1-D array of mesh boundary points along the phi-axis in radians. + The default value is [0, 2π], i.e. the full phi range. + theta_grid : numpy.ndarray + 1-D array of mesh boundary points along the theta-axis in radians. + The default value is [0, π], i.e. the full theta range. + origin : numpy.ndarray + 1-D array of length 3 the (x,y,z) origin of the mesh in + cartesian coordinates + mesh_id : int + Unique identifier for the mesh + name : str + Name of the mesh + + Attributes + ---------- + id : int + Unique identifier for the mesh + name : str + Name of the mesh + dimension : Iterable of int + The number of mesh cells in each direction (r_grid, + theta_grid, phi_grid). + n_dimension : int + Number of mesh dimensions (always 3 for a SphericalMesh). + r_grid : numpy.ndarray + 1-D array of mesh boundary points along the r-axis. + Requirement is r >= 0. + theta_grid : numpy.ndarray + 1-D array of mesh boundary points along the theta-axis in radians. + The default value is [0, π], i.e. the full theta range. + phi_grid : numpy.ndarray + 1-D array of mesh boundary points along the phi-axis in radians. + The default value is [0, 2π], i.e. the full phi range. + origin : numpy.ndarray + 1-D array of length 3 the (x,y,z) origin of the mesh in + cartesian coordinates + indices : Iterable of tuple + An iterable of mesh indices for each mesh element, e.g. [(1, 1, 1), + (2, 1, 1), ...] + lower_left : numpy.ndarray + The lower-left corner of the structured mesh. If only two coordinate + are given, it is assumed that the mesh is an x-y mesh. + upper_right : numpy.ndarray + The upper-right corner of the structured mesh. If only two coordinate + are given, it is assumed that the mesh is an x-y mesh. + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. + + """ + + def __init__( + self, + r_grid: Sequence[float], + phi_grid: Sequence[float] = (0, 2*pi), + theta_grid: Sequence[float] = (0, pi), + origin: Sequence[float] = (0., 0., 0.), + mesh_id: Optional[int] = None, + name: str = '', + ): + super().__init__(mesh_id, name) + + self.r_grid = r_grid + self.theta_grid = theta_grid + self.phi_grid = phi_grid + self.origin = origin + + @property + def dimension(self): + return (len(self.r_grid) - 1, + len(self.theta_grid) - 1, + len(self.phi_grid) - 1) + + @property + def n_dimension(self): + return 3 + + @property + def origin(self): + return self._origin + + @origin.setter + def origin(self, coords): + cv.check_type('mesh origin', coords, Iterable, Real) + cv.check_length("mesh origin", coords, 3) + self._origin = np.asarray(coords, dtype=float) + + @property + def r_grid(self): + return self._r_grid + + @r_grid.setter + def r_grid(self, grid): + cv.check_type('mesh r_grid', grid, Iterable, Real) + self._r_grid = np.asarray(grid, dtype=float) + + @property + def theta_grid(self): + return self._theta_grid + + @theta_grid.setter + def theta_grid(self, grid): + cv.check_type('mesh theta_grid', grid, Iterable, Real) + self._theta_grid = np.asarray(grid, dtype=float) + + @property + def phi_grid(self): + return self._phi_grid + + @phi_grid.setter + def phi_grid(self, grid): + cv.check_type('mesh phi_grid', grid, Iterable, Real) + self._phi_grid = np.asarray(grid, dtype=float) + + @property + def _grids(self): + return (self.r_grid, self.theta_grid, self.phi_grid) + + @property + def indices(self): + nr, nt, np = self.dimension + nt = len(self.theta_grid) - 1 + np = len(self.phi_grid) - 1 + return ((r, t, p) + for p in range(1, np + 1) + for t in range(1, nt + 1) + for r in range(1, nr + 1)) + + @property + def lower_left(self): + r = self.r_grid[-1] + return np.array((self.origin[0] - r, self.origin[1] - r, self.origin[2] - r)) + + @property + def upper_right(self): + r = self.r_grid[-1] + return np.array((self.origin[0] + r, self.origin[1] + r, self.origin[2] + r)) + + def __repr__(self): + fmt = '{0: <16}{1}{2}\n' + string = super().__repr__() + string += fmt.format('\tDimensions', '=\t', self.n_dimension) + string += fmt.format('\tOrigin', '=\t', self.origin) + r_grid_str = str(self._r_grid) if self._r_grid is None else len(self._r_grid) + string += fmt.format('\tN R pnts:', '=\t', r_grid_str) + if self._r_grid is not None: + string += fmt.format('\tR Min:', '=\t', self._r_grid[0]) + string += fmt.format('\tR Max:', '=\t', self._r_grid[-1]) + theta_grid_str = str(self._theta_grid) if self._theta_grid is None else len(self._theta_grid) + string += fmt.format('\tN Theta pnts:', '=\t', theta_grid_str) + if self._theta_grid is not None: + string += fmt.format('\tTheta Min:', '=\t', self._theta_grid[0]) + string += fmt.format('\tTheta Max:', '=\t', self._theta_grid[-1]) + phi_grid_str = str(self._phi_grid) if self._phi_grid is None else len(self._phi_grid) + string += fmt.format('\tN Phi pnts:', '=\t', phi_grid_str) + if self._phi_grid is not None: + string += fmt.format('\tPhi Min:', '=\t', self._phi_grid[0]) + string += fmt.format('\tPhi Max:', '=\t', self._phi_grid[-1]) + return string + + @classmethod + def from_hdf5(cls, group: h5py.Group): + mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) + + # Read and assign mesh properties + mesh = cls( + r_grid = group['r_grid'][()], + theta_grid = group['theta_grid'][()], + phi_grid = group['phi_grid'][()], + mesh_id=mesh_id, + ) + if 'origin' in group: + mesh.origin = group['origin'][()] + + return mesh + + def to_xml_element(self): + """Return XML representation of the mesh + + Returns + ------- + element : lxml.etree._Element + XML element containing mesh data + + """ + + element = ET.Element("mesh") + element.set("id", str(self._id)) + element.set("type", "spherical") + + subelement = ET.SubElement(element, "r_grid") + subelement.text = ' '.join(map(str, self.r_grid)) + + subelement = ET.SubElement(element, "theta_grid") + subelement.text = ' '.join(map(str, self.theta_grid)) + + subelement = ET.SubElement(element, "phi_grid") + subelement.text = ' '.join(map(str, self.phi_grid)) + + subelement = ET.SubElement(element, "origin") + subelement.text = ' '.join(map(str, self.origin)) + + return element + + @classmethod + def from_xml_element(cls, elem: ET.Element): + """Generate a spherical mesh from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.SphericalMesh + Spherical mesh object + + """ + mesh_id = int(get_text(elem, 'id')) + mesh = cls( + mesh_id=mesh_id, + r_grid = [float(x) for x in get_text(elem, "r_grid").split()], + theta_grid = [float(x) for x in get_text(elem, "theta_grid").split()], + phi_grid = [float(x) for x in get_text(elem, "phi_grid").split()], + origin = [float(x) for x in get_text(elem, "origin", default=[0., 0., 0.]).split()], + ) + + return mesh + + @property + def volumes(self): + """Return Volumes for every mesh cell + + Returns + ------- + volumes : Iterable of float + Volumes + + """ + self._volume_dim_check() + V_r = np.diff(np.asarray(self.r_grid)**3 / 3) + V_t = np.diff(-np.cos(self.theta_grid)) + V_p = np.diff(self.phi_grid) + + return np.multiply.outer(np.outer(V_r, V_t), V_p) + + @property + def vertices(self): + warnings.warn('Cartesian coordinates are returned from this property as of version 0.14.0') + return self._convert_to_cartesian(self.vertices_spherical, self.origin) + + @property + def vertices_spherical(self): + """Returns vertices of the mesh in cylindrical coordinates. + """ + return super().vertices + + @property + def centroids(self): + warnings.warn('Cartesian coordinates are returned from this property as of version 0.14.0') + return self._convert_to_cartesian(self.centroids_spherical, self.origin) + + @property + def centroids_spherical(self): + """Returns centroids of the mesh in cylindrical coordinates. + """ + return super().centroids + + + @staticmethod + def _convert_to_cartesian(arr, origin: Sequence[float]): + """Converts an array with r, theta, phi values in the last dimension (shape (..., 3)) + to Cartesian coordinates. + """ + r_xy = arr[..., 0] * np.sin(arr[..., 1]) + x = r_xy * np.cos(arr[..., 2]) + y = r_xy * np.sin(arr[..., 2]) + z = arr[..., 0] * np.cos(arr[..., 1]) + arr[..., 0] = x + origin[0] + arr[..., 1] = y + origin[1] + arr[..., 2] = z + origin[2] + return arr + + +def require_statepoint_data(func): + @wraps(func) + def wrapper(self: UnstructuredMesh, *args, **kwargs): + if not self._has_statepoint_data: + raise AttributeError(f'The "{func.__name__}" property requires ' + 'information about this mesh to be loaded ' + 'from a statepoint file.') + return func(self, *args, **kwargs) + return wrapper + + class UnstructuredMesh(MeshBase): """A 3D unstructured mesh @@ -610,14 +2032,21 @@ class UnstructuredMesh(MeshBase): Parameters ---------- - filename : str + filename : str or pathlib.Path Location of the unstructured mesh file + library : {'moab', 'libmesh'} + Mesh library used for the unstructured mesh tally mesh_id : int Unique identifier for the mesh name : str Name of the mesh - size : int - Number of elements in the unstructured mesh + length_multiplier: float + Constant multiplier to apply to mesh coordinates + options : str, optional + Special options that control spatial search data structures used. This + is currently only used to set `parameters + `_ for MOAB's AdaptiveKDTree. If + None, OpenMC internally uses a default of "MAX_DEPTH=20;PLANE_SET=2;". Attributes ---------- @@ -627,26 +2056,61 @@ class UnstructuredMesh(MeshBase): Name of the mesh filename : str Name of the file containing the unstructured mesh - library : str + length_multiplier: float + Multiplicative factor to apply to mesh coordinates + library : {'moab', 'libmesh'} Mesh library used for the unstructured mesh tally + options : str + Special options that control spatial search data structures used. This + is currently only used to set `parameters + `_ for MOAB's AdaptiveKDTree. If + None, OpenMC internally uses a default of "MAX_DEPTH=20;PLANE_SET=2;". output : bool - Indicates whether or not automatic tally output should - be generated for this mesh + Indicates whether or not automatic tally output should be generated for + this mesh volumes : Iterable of float Volumes of the unstructured mesh elements + centroids : numpy.ndarray + Centroids of the mesh elements with array shape (n_elements, 3) + + vertices : numpy.ndarray + Coordinates of the mesh vertices with array shape (n_elements, 3) + + .. versionadded:: 0.13.1 + connectivity : numpy.ndarray + Connectivity of the elements with array shape (n_elements, 8) + + .. versionadded:: 0.13.1 + element_types : Iterable of integers + Mesh element types + + .. versionadded:: 0.13.1 total_volume : float Volume of the unstructured mesh in total - centroids : Iterable of tuple - An iterable of element centroid coordinates, e.g. [(0.0, 0.0, 0.0), - (1.0, 1.0, 1.0), ...] + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the mesh as defined by the upper-right and + lower-left coordinates. + """ - def __init__(self, filename, library, mesh_id=None, name=''): + + _UNSUPPORTED_ELEM = -1 + _LINEAR_TET = 0 + _LINEAR_HEX = 1 + + def __init__(self, filename: PathLike, library: str, mesh_id: Optional[int] = None, + name: str = '', length_multiplier: float = 1.0, + options: Optional[str] = None): super().__init__(mesh_id, name) self.filename = filename self._volumes = None - self._centroids = None + self._n_elements = None + self._conectivity = None + self._vertices = None self.library = library - self._output = True + self._output = False + self.length_multiplier = length_multiplier + self.options = options + self._has_statepoint_data = False @property def filename(self): @@ -654,7 +2118,7 @@ def filename(self): @filename.setter def filename(self, filename): - cv.check_type('Unstructured Mesh filename', filename, str) + cv.check_type('Unstructured Mesh filename', filename, (str, Path)) self._filename = filename @property @@ -662,16 +2126,26 @@ def library(self): return self._library @library.setter - def library(self, lib): + def library(self, lib: str): cv.check_value('Unstructured mesh library', lib, ('moab', 'libmesh')) self._library = lib @property + def options(self) -> Optional[str]: + return self._options + + @options.setter + def options(self, options: Optional[str]): + cv.check_type('options', options, (str, type(None))) + self._options = options + + @property + @require_statepoint_data def size(self): return self._size @size.setter - def size(self, size): + def size(self, size: int): cv.check_type("Unstructured mesh size", size, Integral) self._size = size @@ -680,53 +2154,146 @@ def output(self): return self._output @output.setter - def output(self, val): + def output(self, val: bool): cv.check_type("Unstructured mesh output value", val, bool) self._output = val @property + @require_statepoint_data def volumes(self): + """Return Volumes for every mesh cell if + populated by a StatePoint file + + Returns + ------- + volumes : numpy.ndarray + Volumes + + """ return self._volumes @volumes.setter - def volumes(self, volumes): + def volumes(self, volumes: typing.Iterable[Real]): cv.check_type("Unstructured mesh volumes", volumes, Iterable, Real) self._volumes = volumes @property + @require_statepoint_data def total_volume(self): return np.sum(self.volumes) @property + @require_statepoint_data + def vertices(self): + return self._vertices + + @property + @require_statepoint_data + def connectivity(self): + return self._connectivity + + @property + @require_statepoint_data + def element_types(self): + return self._element_types + + @property + @require_statepoint_data def centroids(self): - return self._centroids + return np.array([self.centroid(i) for i in range(self.n_elements)]) @property + @require_statepoint_data def n_elements(self): - if self._centroids is None: + if self._n_elements is None: raise RuntimeError("No information about this mesh has " "been loaded from a statepoint file.") - return len(self._centroids) + return self._n_elements + + @n_elements.setter + def n_elements(self, val: int): + cv.check_type('Number of elements', val, Integral) + self._n_elements = val + + @property + def length_multiplier(self): + return self._length_multiplier - @centroids.setter - def centroids(self, centroids): - cv.check_type("Unstructured mesh centroids", centroids, - Iterable, Real) - self._centroids = centroids + @length_multiplier.setter + def length_multiplier(self, length_multiplier): + cv.check_type("Unstructured mesh length multiplier", + length_multiplier, + Real) + self._length_multiplier = length_multiplier + + @property + def dimension(self): + return (self.n_elements,) + + @property + def n_dimension(self): + return 3 + + @property + @require_statepoint_data + def indices(self): + return [(i,) for i in range(self.n_elements)] + + @property + def has_statepoint_data(self) -> bool: + return self._has_statepoint_data def __repr__(self): string = super().__repr__() string += '{: <16}=\t{}\n'.format('\tFilename', self.filename) - string += '{: <16}=\t{}\n'.format('\tMesh Library', self.mesh_lib) + string += '{: <16}=\t{}\n'.format('\tMesh Library', self.library) + if self.length_multiplier != 1.0: + string += '{: <16}=\t{}\n'.format('\tLength multiplier', + self.length_multiplier) + if self.options is not None: + string += '{: <16}=\t{}\n'.format('\tOptions', self.options) return string - def write_data_to_vtk(self, filename, datasets, volume_normalization=True): - """Map data to the unstructured mesh element centroids - to create a VTK point-cloud dataset. + @property + @require_statepoint_data + def lower_left(self): + return self.vertices.min(axis=0) + + @property + @require_statepoint_data + def upper_right(self): + return self.vertices.max(axis=0) + + @require_statepoint_data + def centroid(self, bin: int): + """Return the vertex averaged centroid of an element Parameters ---------- - filename : str + bin : int + Bin ID for the returned centroid + + Returns + ------- + numpy.ndarray + x, y, z values of the element centroid + + """ + conn = self.connectivity[bin] + # remove invalid connectivity values + conn = conn[conn >= 0] + coords = self.vertices[conn] + return coords.mean(axis=0) + + def write_vtk_mesh(self, **kwargs): + """Map data to unstructured VTK mesh elements. + + .. deprecated:: 0.13 + Use :func:`UnstructuredMesh.write_data_to_vtk` instead. + + Parameters + ---------- + filename : str or pathlib.Path Name of the VTK file to write. datasets : dict Dictionary whose keys are the data labels @@ -735,88 +2302,130 @@ def write_data_to_vtk(self, filename, datasets, volume_normalization=True): Whether or not to normalize the data by the volume of the mesh elements """ + warnings.warn( + "The 'UnstructuredMesh.write_vtk_mesh' method has been renamed " + "to 'write_data_to_vtk' and will be removed in a future version " + " of OpenMC.", FutureWarning + ) + self.write_data_to_vtk(**kwargs) + + def write_data_to_vtk( + self, + filename: Optional[PathLike] = None, + datasets: Optional[dict] = None, + volume_normalization: bool = True + ): + """Map data to unstructured VTK mesh elements. + Parameters + ---------- + filename : str or pathlib.Path + Name of the VTK file to write + datasets : dict + Dictionary whose keys are the data labels + and values are numpy appropriately sized arrays + of the data + volume_normalization : bool + Whether or not to normalize the data by the + volume of the mesh elements + """ import vtk - from vtk.util import numpy_support as vtk_npsup + from vtk.util import numpy_support as nps - if self.centroids is None: - raise RuntimeError("No centroid information is present on this " - "unstructured mesh. Please load this " - "information from a relevant statepoint file.") + if self.connectivity is None or self.vertices is None: + raise RuntimeError('This mesh has not been ' + 'loaded from a statepoint file.') - if self.volumes is None and volume_normalization: - raise RuntimeError("No volume data is present on this " - "unstructured mesh. Please load the " - " mesh information from a statepoint file.") + if filename is None: + filename = f'mesh_{self.id}.vtk' - # check that the data sets are appropriately sized - for label, dataset in datasets.items(): - if isinstance(dataset, np.ndarray): - assert dataset.size == self.n_elements - else: - assert len(dataset) == self.n_elements - cv.check_type('label', label, str) - - # create data arrays for the cells/points - cell_dim = 1 - vertices = vtk.vtkCellArray() - points = vtk.vtkPoints() - - for centroid in self.centroids: - # create a point for each centroid - point_id = points.InsertNextPoint(centroid) - # create a cell of type "Vertex" for each point - cell_id = vertices.InsertNextCell(cell_dim, (point_id,)) - - # create a VTK data object - poly_data = vtk.vtkPolyData() - poly_data.SetPoints(points) - poly_data.SetVerts(vertices) - - # strange VTK nuance: - # data must be held in some container - # until the vtk file is written - data_holder = [] - - # create VTK arrays for each of - # the data sets - for label, dataset in datasets.items(): - dataset = np.asarray(dataset).flatten() + writer = vtk.vtkUnstructuredGridWriter() - if volume_normalization: - dataset /= self.volumes.flatten() + writer.SetFileName(str(filename)) - array = vtk.vtkDoubleArray() - array.SetName(label) - array.SetNumberOfComponents(1) - array.SetArray(vtk_npsup.numpy_to_vtk(dataset), - dataset.size, - True) + grid = vtk.vtkUnstructuredGrid() - data_holder.append(dataset) - poly_data.GetPointData().AddArray(array) + vtk_pnts = vtk.vtkPoints() + vtk_pnts.SetData(nps.numpy_to_vtk(self.vertices)) + grid.SetPoints(vtk_pnts) - # set filename - if not filename.endswith(".vtk"): - filename += ".vtk" + n_skipped = 0 + for elem_type, conn in zip(self.element_types, self.connectivity): + if elem_type == self._LINEAR_TET: + elem = vtk.vtkTetra() + elif elem_type == self._LINEAR_HEX: + elem = vtk.vtkHexahedron() + elif elem_type == self._UNSUPPORTED_ELEM: + n_skipped += 1 + else: + raise RuntimeError(f'Invalid element type {elem_type} found') + for i, c in enumerate(conn): + if c == -1: + break + elem.GetPointIds().SetId(i, c) + + grid.InsertNextCell(elem.GetCellType(), elem.GetPointIds()) + + if n_skipped > 0: + warnings.warn(f'{n_skipped} elements were not written because ' + 'they are not of type linear tet/hex') + + # check that datasets are the correct size + datasets_out = [] + if datasets is not None: + for name, data in datasets.items(): + if data.shape != self.dimension: + raise ValueError(f'Cannot apply dataset "{name}" with ' + f'shape {data.shape} to mesh {self.id} ' + f'with dimensions {self.dimension}') + + if volume_normalization: + for name, data in datasets.items(): + if np.issubdtype(data.dtype, np.integer): + warnings.warn(f'Integer data set "{name}" will ' + 'not be volume-normalized.') + continue + data /= self.volumes + + # add data to the mesh + for name, data in datasets.items(): + datasets_out.append(data) + arr = vtk.vtkDoubleArray() + arr.SetName(name) + arr.SetNumberOfTuples(data.size) + + for i in range(data.size): + arr.SetTuple1(i, data.flat[i]) + grid.GetCellData().AddArray(arr) + + writer.SetInputData(grid) - writer = vtk.vtkGenericDataObjectWriter() - writer.SetFileName(filename) - writer.SetInputData(poly_data) writer.Write() @classmethod - def from_hdf5(cls, group): + def from_hdf5(cls, group: h5py.Group): mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) filename = group['filename'][()].decode() library = group['library'][()].decode() + if 'options' in group.attrs: + options = group.attrs['options'].decode() + else: + options = None - mesh = cls(filename, library, mesh_id=mesh_id) + mesh = cls(filename=filename, library=library, mesh_id=mesh_id, options=options) + mesh._has_statepoint_data = True vol_data = group['volumes'][()] - centroids = group['centroids'][()] mesh.volumes = np.reshape(vol_data, (vol_data.shape[0],)) - mesh.centroids = np.reshape(centroids, (vol_data.shape[0], 3)) - mesh.size = mesh.volumes.size + mesh.n_elements = mesh.volumes.size + + vertices = group['vertices'][()] + mesh._vertices = vertices.reshape((-1, 3)) + connectivity = group['connectivity'][()] + mesh._connectivity = connectivity.reshape((-1, 8)) + mesh._element_types = group['element_types'][()] + + if 'length_multiplier' in group: + mesh.length_multiplier = group['length_multiplier'][()] return mesh @@ -825,7 +2434,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing mesh data """ @@ -834,18 +2443,23 @@ def to_xml_element(self): element.set("id", str(self._id)) element.set("type", "unstructured") element.set("library", self._library) + if self.options is not None: + element.set('options', self.options) subelement = ET.SubElement(element, "filename") - subelement.text = self.filename + subelement.text = str(self.filename) + + if self._length_multiplier != 1.0: + element.set("length_multiplier", str(self.length_multiplier)) return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate unstructured mesh object from XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -856,5 +2470,60 @@ def from_xml_element(cls, elem): mesh_id = int(get_text(elem, 'id')) filename = get_text(elem, 'filename') library = get_text(elem, 'library') + length_multiplier = float(get_text(elem, 'length_multiplier', 1.0)) + options = elem.get('options') - return cls(filename, library, mesh_id) + return cls(filename, library, mesh_id, '', length_multiplier, options) + + +def _read_meshes(elem): + """Generate dictionary of meshes from a given XML node + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + dict + A dictionary with mesh IDs as keys and openmc.MeshBase + instanaces as values + """ + out = {} + for mesh_elem in elem.findall('mesh'): + mesh = MeshBase.from_xml_element(mesh_elem) + out[mesh.id] = mesh + + return out + + +# hexahedron element connectivity +# lower-k connectivity offsets +_HEX_VERTEX_CONN = ((0, 0, 0), + (1, 0, 0), + (1, 1, 0), + (0, 1, 0)) +# upper-k connectivity offsets +_HEX_VERTEX_CONN += ((0, 0, 1), + (1, 0, 1), + (1, 1, 1), + (0, 1, 1)) + +_N_HEX_VERTICES = 8 + +# lower-k connectivity offsets +_HEX_MIDPOINT_CONN = ((0, (0, 0, 0)), + (1, (1, 0, 0)), + (0, (0, 1, 0)), + (1, (0, 0, 0))) +# upper-k connectivity offsets +_HEX_MIDPOINT_CONN += ((0, (0, 0, 1)), + (1, (1, 0, 1)), + (0, (0, 1, 1)), + (1, (0, 0, 1))) +# mid-plane k connectivity +_HEX_MIDPOINT_CONN += ((2, (0, 0, 0)), + (2, (1, 0, 0)), + (2, (1, 1, 0)), + (2, (0, 1, 0))) diff --git a/openmc/mgxs/__init__.py b/openmc/mgxs/__init__.py index 00b6440507d..4f12a8fb42c 100644 --- a/openmc/mgxs/__init__.py +++ b/openmc/mgxs/__init__.py @@ -13,16 +13,27 @@ - "XMAS-172_" designed for LWR analysis ([SAR1990]_, [SAN2004]_) - "SHEM-361_" designed for LWR analysis to eliminate self-shielding calculations of thermal resonances ([HFA2005]_, [SAN2007]_, [HEB2008]_) +- "SCALE-X" (where X is 44 which is designed for criticality analysis + and 252 is designed for thermal reactors) for the SCALE code suite + ([ZAL1999]_ and [REARDEN2013]_) +- "MPACT-X" (where X is 51 (PWR), 60 (BWR), 69 (Magnox)) from the MPACT_ reactor + physics code ([KIM2019]_ and [KIM2020]_) +- "ECCO-1968_" designed for fine group reactor cell calculations for fast, + intermediate and thermal reactor applications ([SAR1990]_) - activation_ energy group structures "VITAMIN-J-42", "VITAMIN-J-175", "TRIPOLI-315", "CCFE-709_" and "UKAEA-1102_" .. _CASMO: https://www.studsvik.com/SharepointFiles/CASMO-5%20Development%20and%20Applications.pdf +.. _SCALE44: https://www-nds.iaea.org/publications/indc/indc-czr-0001.pdf +.. _SCALE252: https://oecd-nea.org/science/wpncs/amct/workingarea/meeting2013/EGAMCT2013_08.pdf +.. _MPACT: https://vera.ornl.gov/mpact/ .. _XMAS-172: https://www-nds.iaea.org/wimsd/energy.htm .. _SHEM-361: https://www.polymtl.ca/merlin/downloads/FP214.pdf .. _activation: https://fispact.ukaea.uk/wiki/Keyword:GETXS .. _VITAMIN-J-42: https://www.oecd-nea.org/dbdata/nds_jefreports/jefreport-10.pdf .. _CCFE-709: https://fispact.ukaea.uk/wiki/CCFE-709_group_structure .. _UKAEA-1102: https://fispact.ukaea.uk/wiki/UKAEA-1102_group_structure +.. _ECCO-1968: http://serpent.vtt.fi/mediawiki/index.php/ECCO_1968-group_structure .. [SAR1990] Sartori, E., OECD/NEA Data Bank: Standard Energy Group Structures of Cross Section Libraries for Reactor Shielding, Reactor Cell and Fusion Neutronics Applications: VITAMIN-J, ECCO-33, ECCO-2000 and XMAS JEF/DOC-315 @@ -41,6 +52,19 @@ .. [HEB2008] Hébert, Alain & Santamarina, Alain. (2008). Refinement of the Santamarina-Hfaiedh energy mesh between 22.5 eV and 11.4 keV. International Conference on the Physics of Reactors 2008, PHYSOR 08. 2. 929-938. +.. [ZAL1999] K. Záleský and L. Marková (1999), Assessment of Nuclear Data Needs + for Broad-Group SCALE Library Related to VVER Spent Fuel Applications, IAEA. SCALE44_. +.. [REARDEN2013] B. T. Rearden, M. E. Dunn, D. Wiarda, C. Celik, K. Bekar, + M. L. Williams, D. E. Peplow, M. A. Jessee, C. M. Perfetti, + I. C. Gauld, W. A. Wieselquist, J. P. Lefebvre, R. A. Lefebvre, + W. J. Marshall, A. B. Thompson, F. Havluj, S. E. Skutnik, + K. J. Dugan. (2013). Overview of SCALE 6.2. OECD. SCALE252_. +.. [KIM2019] Kim, K.S., Williams, M., Wiarda, D., & Clarno, K. (2019). Development + of the multigroup cross section library for the CASL neutronics simulator MPACT: + Method and procedure. Annals of Nuclear Energy, 133. pp. 46-58. +.. [KIM2020] Kim, K.S., Ade, B., & Luciano, N. (2020). Development + of the MPACT 69-group Library for Magnox Reactor Analysis using VERA. + Proceedings of International Conference on Physics of Reactors PHYSOR2020. """ GROUP_STRUCTURES['CASMO-2'] = np.array([ @@ -68,6 +92,35 @@ 1.33e6, 1.34e6, 1.5e6, 1.66e6, 2.e6, 2.5e6, 3.e6, 3.5e6, 4.e6, 4.5e6, 5.e6, 5.5e6, 6.e6, 6.5e6, 7.e6, 7.5e6, 8.e6, 10.e6, 12.e6, 14.e6, 20.e6, 30.e6, 50.e6]) +GROUP_STRUCTURES['SCALE-44'] = np.array([1e-5, 3.e-3, 7.5e-3, 1.e-2, 2.53e-2, + 3.e-2, 4.e-2, 5e-2, 7.e-2, 1.e-1, 1.5e-1, 2.e-1, 2.25e-1, 2.5e-1, 2.75e-1, + 3.25e-1, 3.5e-1, 3.75e-1, 4.e-1, 6.25e-1, 1., 1.77, 3., 4.75, 6., 8.1, + 1.e1, 3.e1, 1.e2, 5.5e2, 3.e3, 1.7e4, 2.5e4, 1.e5, 4.e5, 9.e5, 1.4e6, + 1.85e6, 2.354e6, 2.479e6, 3.e6, 4.8e6, 6.434e6, 8.1873e6, 2.e7]) +GROUP_STRUCTURES['MPACT-51'] = np.array([ + 0., 1.e-2, 3.e-2, 4.e-2, 6.e-2, 8.e-2, 1.e-1, 1.5e-1, 2.e-1, 2.75e-1, + 3.5e-1, 5.e-1, 6.25e-1, 7.5e-1, 9.25e-1, 9.75e-1, 1.010, 1.080, 1.130, + 1.175, 1.250, 1.450, 1.860, 2.470, 3.730, 4.700, 5.000, 5.400, 6.250, + 7.150, 8.100, 1.19e+1, 1.44e+1, 3.e+1, 4.83e+1, 7.6e+1, 1.43e+2, 3.05e+2, + 9.5e+2, 2.25e+3, 9.5e+3, 2.e+4, 5.e+4, 7.3e+4, 2.e+5, 4.92e+5, 8.2e+5, + 1.356e+6, 2.354e+6, 4.304e+6, 6.434e+6, 2.e+7]) +GROUP_STRUCTURES['MPACT-60'] = np.array([ + 0., 1.e-2, 3.e-2, 4.e-2, 6.e-2, 8.e-2, 1.e-1, 1.5e-1, 2.e-1, 2.75e-1, + 3.5e-1, 5.e-1, 6.25e-1, 7.5e-1, 9.25e-1, 9.75e-1, 1.01, 1.08, 1.13, + 1.175, 1.25, 1.45, 1.86, 2.47, 3.73, 4.7, 5., 5.4, 6.25, 7.15, 8.1, + 1.19e+1, 1.44e+1, 3.e+1, 4.83e+1, 7.6e+1, 1.43e+2, 2.095e+2, 3.05e+2, + 6.7e+2, 9.5e+2, 1.55e+3, 2.25e+3, 3.9e+3, 9.5e+3, 1.3e+4, 2.e+4, 3.e+4, + 5.e+4, 7.3e+4, 1.283e+5, 2.e+5, 3.3e+5, 4.92e+5, 6.7e+5, 8.2e+5, 1.356e+6, + 2.354e+6, 4.304e+6, 6.434e+6, 2.e+7]) +GROUP_STRUCTURES['MPACT-69'] = np.array([ + 0., 1.e-2, 3.e-2, 4.e-2, 6.e-2, 8.e-2, 9.e-2, 1.e-1, 1.25e-1, 1.5e-1, + 1.75e-1, 2.e-1, 2.25e-1, 2.5e-1, 2.75e-1, 3.e-1, 3.25e-1, 3.5e-1, 3.75e-1, + 4.e-1, 4.5e-1, 5.e-1, 5.5e-1, 6.e-1, 6.25e-1, 6.5e-1, 7.5e-1, 8.5e-1, + 9.25e-1, 9.75e-1, 1.01, 1.08, 1.13, 1.175, 1.25, 1.45, 1.86, 2.47, 3., + 3.73, 4.7, 5., 5.4, 6.25, 7.15, 8.1, 1.e+1, 1.19e+1, 1.44e+1, 3.e+1, + 4.83e+1, 7.6e+1, 1.43e+2, 3.05e+2, 5.5e+2, 9.5e+2, 2.25e+3, 3.9e+3, 9.5e+3, + 2.e+4, 5.e+4, 7.3e+4, 2.e+5, 4.92e+5, 8.2e+5, 1.356e+6, 2.354e+6, 4.304e+6, + 6.434e+6, 2.e+7]) GROUP_STRUCTURES['CASMO-70'] = np.array([ 0., 5.e-3, 1.e-2, 1.5e-2, 2.e-2, 2.5e-2, 3.e-2, 3.5e-2, 4.2e-2, 5.e-2, 5.8e-2, 6.7e-2, 8.e-2, 1.e-1, 1.4e-1, 1.8e-1, 2.2e-1, @@ -145,7 +198,35 @@ 1.1052e7, 1.1618e7, 1.2214e7, 1.2523e7, 1.2840e7, 1.3499e7, 1.3840e7, 1.4191e7, 1.4550e7, 1.4918e7, 1.5683e7, 1.6487e7, 1.6905e7, 1.7332e7, 1.9640e7]) -GROUP_STRUCTURES['TRIPOLI-315,'] = np.array([ +GROUP_STRUCTURES['SCALE-252'] = np.array([ + 0., 1.e-4, 5.e-4, 7.5e-4, 1.e-3, 1.2e-3, 1.5e-3, 2.e-3, 2.5e-3, 3.e-3, + 4.e-3, 5.e-3, 7.5e-3, 1.e-2, 2.53e-2, 3.e-2, 4.e-2, 5.e-2, 6.e-2, 7.e-2, + 8.e-2, 9.e-2, 1.e-1, 1.25e-1, 1.5e-1, 1.75e-1, 2.e-1, 2.25e-1, 2.5e-1, + 2.75e-1, 3.e-1, 3.25e-1, 3.5e-1, 3.75e-1, 4.e-1, 4.5e-1, 5.e-1, 5.5e-1, + 6.e-1, 6.25e-1, 6.5e-1, 7.e-1, 7.5e-1, 8.e-1, 8.5e-1, 9.e-1, 9.25e-1, + 9.5e-1, 9.75e-1, 1., 1.01, 1.02, 1.03, 1.04, 1.05, 1.06, 1.07, 1.08, 1.09, + 1.1, 1.11, 1.12, 1.13, 1.14, 1.15, 1.175, 1.2, 1.225, 1.25, 1.3, 1.35, 1.4, + 1.45, 1.5, 1.59, 1.68, 1.77, 1.86, 1.94, 2., 2.12, 2.21, 2.3, 2.38, 2.47, + 2.57, 2.67, 2.77, 2.87, 2.97, 3., 3.1, 3.2, 3.5, 3.73, 4.1, 4.7, 5., 5.4, + 6., 6.25, 6.5, 6.75, 6.875, 7., 7.15, 8.1, 9.1, 1.e+1, 1.15e+1, 1.19e+1, + 1.29e+1, 1.44e+1, 1.6e+1, 1.7e+1, 1.85e+1, 1.94e+1, 2.e+1, 2.05e+1, + 2.12e+1, 2.175e+1, 2.25e+1, 2.5e+1, 2.75e+1, 3.e+1, 3.125e+1, 3.175e+1, + 3.325e+1, 3.375e+1, 3.5e+1, 3.55e+1, 3.6e+1, 3.7e+1, 3.713e+1, 3.727e+1, + 3.763e+1, 3.8e+1, 3.91e+1, 3.96e+1, 4.1e+1, 4.24e+1, 4.4e+1, 4.52e+1, + 4.83e+1, 5.06e+1, 5.34e+1, 5.8e+1, 6.1e+1, 6.3e+1, 6.5e+1, 6.75e+1, 7.2e+1, + 7.6e+1, 8.e+1, 8.17e+1, 9.e+1, 9.7e+1, 1.012e+2, 1.05e+2, 1.08e+2, 1.13e+2, + 1.16e+2, 1.175e+2, 1.19e+2, 1.22e+2, 1.43e+2, 1.7e+2, 1.8e+2, 1.877e+2, + 1.885e+2, 1.915e+2, 1.93e+2, 2.02e+2, 2.074e+2, 2.095e+2, 2.2e+2, 2.4e+2, + 2.85e+2, 3.05e+2, 5.5e+2, 6.7e+2, 6.83e+2, 9.5e+2, 1.15e+3, 1.5e+3, + 1.55e+3, 1.8e+3, 2.2e+3, 2.25e+3, 2.5e+3, 3.e+3, 3.74e+3, 3.9e+3, 5.7e+3, + 8.03e+3, 9.5e+3, 1.3e+4, 1.7e+4, 2.e+4, 3.e+4, 4.5e+4, 5.e+4, 5.2e+4, + 6.e+4, 7.3e+4, 7.5e+4, 8.2e+4, 8.5e+4, 1.e+5, 1.283e+5, 1.49e+5, 2.e+5, + 2.7e+5, 3.3e+5, 4.e+5, 4.2e+5, 4.4e+5, 4.7e+5, 4.92e+5, 5.5e+5, 5.73e+5, + 6.e+5, 6.7e+5, 6.79e+5, 7.5e+5, 8.2e+5, 8.611e+5, 8.75e+5, 9.e+5, 9.2e+5, + 1.01e+6, 1.1e+6, 1.2e+6, 1.25e+6, 1.317e+6, 1.356e+6, 1.4e+6, 1.5e+6, + 1.85e+6, 2.354e+6, 2.479e+6, 3.e+6, 4.304e+6, 4.8e+6, 6.434e+6, 8.187e+6, + 1.e+7, 1.284e+7, 1.384e+7, 1.455e+7, 1.568e+7, 1.733e+7, 2.e+7]) +GROUP_STRUCTURES['TRIPOLI-315'] = np.array([ 1.0e-5, 1.1e-4, 3.000e-3, 5.500e-3, 1.000e-2, 1.500e-2, 2.000e-2, 3.000e-2, 3.200e-2, 3.238e-2, 4.300e-2, 5.900e-2, 7.700e-2, 9.500e-2, 1.000e-1, 1.150e-1, 1.340e-1, 1.600e-1, 1.890e-1, 2.200e-1, 2.480e-1, 2.825e-1, @@ -630,3 +711,329 @@ 5.7544e8, 6.0256e8, 6.3096e8, 6.6069e8, 6.9183e8, 7.2444e8, 7.5858e8, 7.9433e8, 8.3176e8, 8.7096e8, 9.1201e8, 9.5499e8, 1.e9]) +GROUP_STRUCTURES['ECCO-1968'] = np.array([ + 1.00001e-5, 3.00000e-3, 5.00000e-3, 6.90000e-3, 1.00000e-2, 1.50000e-2, + 2.00000e-2, 2.50000e-2, 3.00000e-2, 3.50000e-2, 4.20000e-2, 5.00000e-2, + 5.80000e-2, 6.70000e-2, 7.70000e-2, 8.00000e-2, 9.50000e-2, 1.00000e-1, + 1.15000e-1, 1.34000e-1, 1.40000e-1, 1.46370e-1, 1.53030e-1, 1.60000e-1, + 1.69710e-1, 1.80000e-1, 1.89000e-1, 1.98810e-1, 2.09140e-1, 2.20000e-1, + 2.33580e-1, 2.48000e-1, 2.63510e-1, 2.80000e-1, 3.00000e-1, 3.14500e-1, + 3.20000e-1, 3.34660e-1, 3.50000e-1, 3.69930e-1, 3.91000e-1, 4.00000e-1, + 4.13990e-1, 4.33000e-1, 4.49680e-1, 4.67010e-1, 4.85000e-1, 5.00000e-1, + 5.19620e-1, 5.31580e-1, 5.40000e-1, 5.66960e-1, 5.95280e-1, 6.25000e-1, + 6.53150e-1, 6.82560e-1, 7.05000e-1, 7.41550e-1, 7.80000e-1, 7.90000e-1, + 8.19450e-1, 8.50000e-1, 8.60000e-1, 8.76425e-1, 9.10000e-1, 9.30000e-1, + 9.50000e-1, 9.72000e-1, 9.86000e-1, 9.96000e-1, + 1.020000, 1.035000, 1.045000, 1.071000, 1.080000, 1.097000, 1.110000, + 1.123000, 1.150000, 1.170000, 1.202060, 1.235000, 1.267080, 1.300000, + 1.337500, 1.370000, 1.404560, 1.440000, 1.475000, 1.500000, 1.544340, + 1.590000, 1.629510, 1.670000, 1.711970, 1.755000, 1.797000, 1.840000, + 1.855390, 1.884460, 1.930000, 1.974490, 2.020000, 2.059610, 2.100000, + 2.130000, 2.185310, 2.242050, 2.300270, 2.360000, 2.382370, 2.421710, + 2.485030, 2.550000, 2.600000, 2.659320, 2.720000, 2.767920, 2.837990, + 2.909830, 2.983490, 3.059020, 3.137330, 3.217630, 3.300000, 3.380750, + 3.466330, 3.554080, 3.644050, 3.736300, 3.830880, 3.927860, 4.000000, + 4.129250, 4.233782, 4.340961, 4.450853, 4.563526, 4.679053, 4.797503, + 4.918953, 5.043477, 5.085681, 5.128239, 5.171153, 5.214426, 5.258061, + 5.302061, 5.346430, 5.391169, 5.436284, 5.481775, 5.527647, 5.573904, + 5.620547, 5.667581, 5.715008, 5.762832, 5.811056, 5.859684, 5.908719, + 5.958164, 6.008022, 6.058298, 6.108995, 6.160116, 6.211665, 6.263645, + 6.316060, 6.368914, 6.422210, 6.475952, 6.530144, 6.584789, 6.639892, + 6.695455, 6.751484, 6.807981, 6.864952, 6.922399, 6.980326, 7.038739, + 7.097640, 7.157034, 7.216925, 7.277317, 7.338215, 7.399622, 7.461544, + 7.523983, 7.586945, 7.650434, 7.714454, 7.779009, 7.844105, 7.909746, + 7.975936, 8.042680, 8.109982, 8.177848, 8.246281, 8.315287, 8.384871, + 8.455037, 8.525790, 8.597135, 8.669077, 8.741621, 8.814772, 8.888536, + 8.962916, 9.037919, 9.113550, 9.189814, 9.266715, 9.344261, 9.422455, + 9.501303, 9.580812, 9.660985, 9.741830, 9.823351, 9.905554, 9.988446, + 1.007203e1, 1.015631e1, 1.024130e1, 1.032701e1, 1.041342e1, 1.050056e1, + 1.058843e1, 1.067704e1, 1.076639e1, 1.085648e1, 1.094733e1, 1.103894e1, + 1.113132e1, 1.122446e1, 1.131839e1, 1.141311e1, 1.150861e1, 1.160492e1, + 1.170203e1, 1.179995e1, 1.189870e1, 1.199827e1, 1.209867e1, 1.219991e1, + 1.230201e1, 1.240495e1, 1.250876e1, 1.261343e1, 1.271898e1, 1.282542e1, + 1.293274e1, 1.304097e1, 1.315010e1, 1.326014e1, 1.337110e1, 1.348299e1, + 1.359582e1, 1.370959e1, 1.382431e1, 1.394000e1, 1.405665e1, 1.417428e1, + 1.429289e1, 1.441250e1, 1.453310e1, 1.465472e1, 1.477735e1, 1.490101e1, + 1.502570e1, 1.515144e1, 1.527823e1, 1.540608e1, 1.553500e1, 1.566500e1, + 1.579609e1, 1.592827e1, 1.606156e1, 1.619597e1, 1.633150e1, 1.646816e1, + 1.660597e1, 1.674493e1, 1.688506e1, 1.702635e1, 1.716883e1, 1.731250e1, + 1.745738e1, 1.760346e1, 1.775077e1, 1.789931e1, 1.804910e1, 1.820013e1, + 1.835244e1, 1.850601e1, 1.866087e1, 1.881703e1, 1.897449e1, 1.913328e1, + 1.929339e1, 1.945484e1, 1.961764e1, 1.978180e1, 1.994734e1, 2.011426e1, + 2.028258e1, 2.045231e1, 2.062345e1, 2.079603e1, 2.097006e1, 2.114554e1, + 2.132249e1, 2.150092e1, 2.168084e1, 2.186227e1, 2.204522e1, 2.222969e1, + 2.241572e1, 2.260329e1, 2.279244e1, 2.298317e1, 2.317550e1, 2.336944e1, + 2.356499e1, 2.376219e1, 2.396104e1, 2.416154e1, 2.436373e1, 2.456761e1, + 2.477320e1, 2.498050e1, 2.518954e1, 2.540033e1, 2.561289e1, 2.582722e1, + 2.604335e1, 2.626128e1, 2.648104e1, 2.670264e1, 2.692609e1, 2.715141e1, + 2.737862e1, 2.760773e1, 2.783875e1, 2.807171e1, 2.830662e1, 2.854349e1, + 2.878235e1, 2.902320e1, 2.926607e1, 2.951098e1, 2.975793e1, 3.000695e1, + 3.025805e1, 3.051126e1, 3.076658e1, 3.102404e1, 3.128365e1, 3.154544e1, + 3.180942e1, 3.207560e1, 3.234401e1, 3.261467e1, 3.288760e1, 3.316281e1, + 3.344032e1, 3.372015e1, 3.400233e1, 3.428686e1, 3.457378e1, 3.486310e1, + 3.515484e1, 3.544902e1, 3.574566e1, 3.604479e1, 3.634642e1, 3.665057e1, + 3.695727e1, 3.726653e1, 3.757838e1, 3.789285e1, 3.820994e1, 3.852969e1, + 3.885211e1, 3.917723e1, 3.950507e1, 3.983565e1, 4.016900e1, 4.050514e1, + 4.084410e1, 4.118589e1, 4.153054e1, 4.187807e1, 4.222851e1, 4.258189e1, + 4.293822e1, 4.329753e1, 4.365985e1, 4.402521e1, 4.439361e1, 4.476511e1, + 4.513971e1, 4.551744e1, 4.589834e1, 4.628243e1, 4.666972e1, 4.706026e1, + 4.745407e1, 4.785117e1, 4.825160e1, 4.865538e1, 4.906253e1, 4.947309e1, + 4.988709e1, 5.030456e1, 5.072551e1, 5.114999e1, 5.157802e1, 5.200963e1, + 5.244486e1, 5.288373e1, 5.332626e1, 5.377251e1, 5.422248e1, 5.467623e1, + 5.513376e1, 5.559513e1, 5.606036e1, 5.652948e1, 5.700253e1, 5.747954e1, + 5.796053e1, 5.844556e1, 5.893464e1, 5.942781e1, 5.992511e1, 6.042657e1, + 6.093223e1, 6.144212e1, 6.195628e1, 6.247474e1, 6.299754e1, 6.352471e1, + 6.405630e1, 6.459233e1, 6.513285e1, 6.567789e1, 6.622749e1, 6.678169e1, + 6.734053e1, 6.790405e1, 6.847228e1, 6.904527e1, 6.962305e1, 7.020566e1, + 7.079316e1, 7.138556e1, 7.198293e1, 7.258529e1, 7.319270e1, 7.380518e1, + 7.442280e1, 7.504558e1, 7.567357e1, 7.630682e1, 7.694537e1, 7.758926e1, + 7.823854e1, 7.889325e1, 7.955344e1, 8.021915e1, 8.089044e1, 8.156734e1, + 8.224991e1, 8.293819e1, 8.363223e1, 8.433208e1, 8.503778e1, 8.574939e1, + 8.646695e1, 8.719052e1, 8.792015e1, 8.865588e1, 8.939776e1, 9.014586e1, + 9.090021e1, 9.166088e1, 9.242791e1, 9.320136e1, 9.398128e1, 9.476773e1, + 9.556076e1, 9.636043e1, 9.716679e1, 9.797990e1, 9.879981e1, 9.962658e1, + 1.004603e2, 1.013009e2, 1.021486e2, 1.030034e2, 1.038654e2, 1.047345e2, + 1.056110e2, 1.064947e2, 1.073859e2, 1.082845e2, 1.091907e2, 1.101044e2, + 1.110258e2, 1.119548e2, 1.128917e2, 1.138364e2, 1.147890e2, 1.157496e2, + 1.167182e2, 1.176949e2, 1.186798e2, 1.196729e2, 1.206744e2, 1.216842e2, + 1.227024e2, 1.237292e2, 1.247646e2, 1.258087e2, 1.268615e2, 1.279231e2, + 1.289935e2, 1.300730e2, 1.311615e2, 1.322590e2, 1.333658e2, 1.344818e2, + 1.356072e2, 1.367420e2, 1.378862e2, 1.390401e2, 1.402036e2, 1.413768e2, + 1.425599e2, 1.437529e2, 1.449558e2, 1.461688e2, 1.473920e2, 1.486254e2, + 1.498691e2, 1.511232e2, 1.523879e2, 1.536631e2, 1.549489e2, 1.562456e2, + 1.575531e2, 1.588715e2, 1.602010e2, 1.615415e2, 1.628933e2, 1.642565e2, + 1.656310e2, 1.670170e2, 1.684146e2, 1.698239e2, 1.712451e2, 1.726781e2, + 1.741231e2, 1.755802e2, 1.770494e2, 1.785310e2, 1.800250e2, 1.815315e2, + 1.830505e2, 1.845823e2, 1.861269e2, 1.876845e2, 1.892551e2, 1.908388e2, + 1.924358e2, 1.940461e2, 1.956699e2, 1.973073e2, 1.989584e2, 2.006233e2, + 2.023021e2, 2.039950e2, 2.057021e2, 2.074234e2, 2.091592e2, 2.109095e2, + 2.126744e2, 2.144541e2, 2.162487e2, 2.180583e2, 2.198830e2, 2.217230e2, + 2.235784e2, 2.254494e2, 2.273360e2, 2.292384e2, 2.311567e2, 2.330910e2, + 2.350416e2, 2.370084e2, 2.389917e2, 2.409917e2, 2.430083e2, 2.450418e2, + 2.470924e2, 2.491601e2, 2.512451e2, 2.533476e2, 2.554676e2, 2.576054e2, + 2.597611e2, 2.619348e2, 2.641267e2, 2.663370e2, 2.685657e2, 2.708131e2, + 2.730793e2, 2.753645e2, 2.776688e2, 2.799924e2, 2.823354e2, 2.846980e2, + 2.870804e2, 2.894827e2, 2.919052e2, 2.943479e2, 2.968110e2, 2.992948e2, + 3.017993e2, 3.043248e2, 3.068715e2, 3.094394e2, 3.120288e2, 3.146399e2, + 3.172729e2, 3.199279e2, 3.226051e2, 3.253047e2, 3.280269e2, 3.307719e2, + 3.335398e2, 3.363309e2, 3.391454e2, 3.419834e2, 3.448452e2, 3.477309e2, + 3.506408e2, 3.535750e2, 3.565338e2, 3.595173e2, 3.625258e2, 3.655595e2, + 3.686185e2, 3.717032e2, 3.748137e2, 3.779502e2, 3.811129e2, 3.843021e2, + 3.875180e2, 3.907608e2, 3.940308e2, 3.973281e2, 4.006530e2, 4.040057e2, + 4.073865e2, 4.107955e2, 4.142332e2, 4.176995e2, 4.211949e2, 4.247195e2, + 4.282736e2, 4.318575e2, 4.354713e2, 4.391154e2, 4.427900e2, 4.464953e2, + 4.502317e2, 4.539993e2, 4.577984e2, 4.616294e2, 4.654923e2, 4.693877e2, + 4.733156e2, 4.772763e2, 4.812703e2, 4.852976e2, 4.893587e2, 4.934537e2, + 4.975830e2, 5.017468e2, 5.059455e2, 5.101793e2, 5.144486e2, 5.187536e2, + 5.230946e2, 5.274719e2, 5.318859e2, 5.363368e2, 5.408249e2, 5.453506e2, + 5.499142e2, 5.545160e2, 5.591563e2, 5.638354e2, 5.685536e2, 5.733114e2, + 5.781089e2, 5.829466e2, 5.878248e2, 5.927438e2, 5.977040e2, 6.027057e2, + 6.077492e2, 6.128350e2, 6.179633e2, 6.231345e2, 6.283489e2, 6.336071e2, + 6.389092e2, 6.442557e2, 6.496469e2, 6.550832e2, 6.605651e2, 6.660928e2, + 6.716668e2, 6.772874e2, 6.829550e2, 6.886701e2, 6.944330e2, 7.002441e2, + 7.061038e2, 7.120126e2, 7.179709e2, 7.239790e2, 7.300373e2, 7.361464e2, + 7.423066e2, 7.485183e2, 7.547820e2, 7.610981e2, 7.674671e2, 7.738894e2, + 7.803654e2, 7.868957e2, 7.934805e2, 8.001205e2, 8.068160e2, 8.135676e2, + 8.203756e2, 8.272407e2, 8.341631e2, 8.411435e2, 8.481824e2, 8.552801e2, + 8.624372e2, 8.696542e2, 8.769316e2, 8.842699e2, 8.916696e2, 8.991312e2, + 9.066553e2, 9.142423e2, 9.218928e2, 9.296074e2, 9.373865e2, 9.452307e2, + 9.531405e2, 9.611165e2, 9.691593e2, 9.772694e2, 9.854473e2, 9.936937e2, + 1.002009e3, 1.010394e3, 1.018849e3, 1.027375e3, 1.035972e3, 1.044641e3, + 1.053383e3, 1.062198e3, 1.071087e3, 1.080050e3, 1.089088e3, 1.098201e3, + 1.107391e3, 1.116658e3, 1.126002e3, 1.135425e3, 1.144926e3, 1.154507e3, + 1.164168e3, 1.173910e3, 1.183734e3, 1.193639e3, 1.203628e3, 1.213700e3, + 1.223857e3, 1.234098e3, 1.244425e3, 1.254839e3, 1.265339e3, 1.275928e3, + 1.286605e3, 1.297372e3, 1.308228e3, 1.319176e3, 1.330215e3, 1.341346e3, + 1.352571e3, 1.363889e3, 1.375303e3, 1.386811e3, 1.398416e3, 1.410118e3, + 1.421919e3, 1.433817e3, 1.445816e3, 1.457915e3, 1.470115e3, 1.482417e3, + 1.494822e3, 1.507331e3, 1.519944e3, 1.532663e3, 1.545489e3, 1.558422e3, + 1.571463e3, 1.584613e3, 1.597874e3, 1.611245e3, 1.624728e3, 1.638324e3, + 1.652034e3, 1.665858e3, 1.679798e3, 1.693855e3, 1.708030e3, 1.722323e3, + 1.736735e3, 1.751268e3, 1.765923e3, 1.780701e3, 1.795602e3, 1.810628e3, + 1.825780e3, 1.841058e3, 1.856464e3, 1.871999e3, 1.887665e3, 1.903461e3, + 1.919389e3, 1.935451e3, 1.951647e3, 1.967979e3, 1.984447e3, 2.001053e3, + 2.017798e3, 2.034684e3, 2.051710e3, 2.068879e3, 2.086192e3, 2.103650e3, + 2.121253e3, 2.139004e3, 2.156904e3, 2.174953e3, 2.193153e3, 2.211506e3, + 2.230012e3, 2.248673e3, 2.267490e3, 2.286465e3, 2.305599e3, 2.324892e3, + 2.344347e3, 2.363965e3, 2.383747e3, 2.403695e3, 2.423809e3, 2.444092e3, + 2.464545e3, 2.485168e3, 2.505965e3, 2.526935e3, 2.548081e3, 2.569403e3, + 2.590904e3, 2.612586e3, 2.634448e3, 2.656494e3, 2.678723e3, 2.701139e3, + 2.723743e3, 2.746536e3, 2.769519e3, 2.792695e3, 2.816065e3, 2.839630e3, + 2.863392e3, 2.887354e3, 2.911515e3, 2.935879e3, 2.960447e3, 2.985221e3, + 3.010202e3, 3.035391e3, 3.060792e3, 3.086405e3, 3.112233e3, 3.138276e3, + 3.164538e3, 3.191019e3, 3.217722e3, 3.244649e3, 3.271800e3, 3.299179e3, + 3.326787e3, 3.354626e3, 3.382698e3, 3.411005e3, 3.439549e3, 3.468332e3, + 3.497355e3, 3.526622e3, 3.556133e3, 3.585891e3, 3.615898e3, 3.646157e3, + 3.676668e3, 3.707435e3, 3.738460e3, 3.769744e3, 3.801290e3, 3.833099e3, + 3.865175e3, 3.897520e3, 3.930135e3, 3.963023e3, 3.996186e3, 4.029627e3, + 4.063347e3, 4.097350e3, 4.131637e3, 4.166211e3, 4.201075e3, 4.236230e3, + 4.271679e3, 4.307425e3, 4.343471e3, 4.379817e3, 4.416468e3, 4.453426e3, + 4.490693e3, 4.528272e3, 4.566165e3, 4.604375e3, 4.642906e3, 4.681758e3, + 4.720936e3, 4.760441e3, 4.800277e3, 4.840447e3, 4.880952e3, 4.921797e3, + 4.962983e3, 5.004514e3, 5.046393e3, 5.088622e3, 5.131204e3, 5.174143e3, + 5.217441e3, 5.261101e3, 5.305127e3, 5.349521e3, 5.394287e3, 5.439427e3, + 5.484945e3, 5.530844e3, 5.577127e3, 5.623797e3, 5.670858e3, 5.718312e3, + 5.766164e3, 5.814416e3, 5.863072e3, 5.912135e3, 5.961609e3, 6.011496e3, + 6.061802e3, 6.112528e3, 6.163678e3, 6.215257e3, 6.267267e3, 6.319712e3, + 6.372597e3, 6.425924e3, 6.479697e3, 6.533920e3, 6.588597e3, 6.643731e3, + 6.699327e3, 6.755388e3, 6.811918e3, 6.868921e3, 6.926401e3, 6.984362e3, + 7.042809e3, 7.101744e3, 7.161172e3, 7.221098e3, 7.281525e3, 7.342458e3, + 7.403901e3, 7.465858e3, 7.528334e3, 7.591332e3, 7.654857e3, 7.718914e3, + 7.783507e3, 7.848641e3, 7.914319e3, 7.980548e3, 8.047330e3, 8.114671e3, + 8.182576e3, 8.251049e3, 8.320095e3, 8.389719e3, 8.459926e3, 8.530719e3, + 8.602106e3, 8.674090e3, 8.746676e3, 8.819869e3, 8.893675e3, 8.968099e3, + 9.043145e3, 9.118820e3, 9.195127e3, 9.272074e3, 9.349664e3, 9.427903e3, + 9.506797e3, 9.586352e3, 9.666572e3, 9.747463e3, 9.829031e3, 9.911282e3, + 9.994221e3, 1.007785e4, 1.016219e4, 1.024723e4, 1.033298e4, 1.041944e4, + 1.050664e4, 1.059456e4, 1.068321e4, 1.077261e4, 1.086276e4, 1.095366e4, + 1.104532e4, 1.113775e4, 1.123095e4, 1.132494e4, 1.141970e4, 1.151527e4, + 1.161163e4, 1.170880e4, 1.180678e4, 1.190558e4, 1.200521e4, 1.210567e4, + 1.220697e4, 1.230912e4, 1.241212e4, 1.251599e4, 1.262073e4, 1.272634e4, + 1.283283e4, 1.294022e4, 1.304851e4, 1.315770e4, 1.326780e4, 1.337883e4, + 1.349079e4, 1.360368e4, 1.371752e4, 1.383231e4, 1.394806e4, 1.406478e4, + 1.418247e4, 1.430116e4, 1.442083e4, 1.454151e4, 1.466319e4, 1.478590e4, + 1.490963e4, 1.503439e4, 1.516020e4, 1.528706e4, 1.541499e4, 1.554398e4, + 1.567406e4, 1.580522e4, 1.593748e4, 1.607085e4, 1.620533e4, 1.634094e4, + 1.647768e4, 1.661557e4, 1.675461e4, 1.689482e4, 1.703620e4, 1.717876e4, + 1.732251e4, 1.746747e4, 1.761364e4, 1.776104e4, 1.790966e4, 1.805953e4, + 1.821066e4, 1.836305e4, 1.851671e4, 1.867166e4, 1.882791e4, 1.898547e4, + 1.914434e4, 1.930454e4, 1.946608e4, 1.962898e4, 1.979324e4, 1.995887e4, + 2.012589e4, 2.029431e4, 2.046413e4, 2.063538e4, 2.080806e4, 2.098218e4, + 2.115777e4, 2.133482e4, 2.151335e4, 2.169338e4, 2.187491e4, 2.205796e4, + 2.224255e4, 2.242868e4, 2.261636e4, 2.280562e4, 2.299646e4, 2.318890e4, + 2.338295e4, 2.357862e4, 2.377593e4, 2.397489e4, 2.417552e4, 2.437782e4, + 2.458182e4, 2.478752e4, 2.499495e4, 2.520411e4, 2.541502e4, 2.562770e4, + 2.584215e4, 2.605841e4, 2.627647e4, 2.649635e4, 2.671808e4, 2.694166e4, + 2.700000e4, 2.716711e4, 2.739445e4, 2.762369e4, 2.785485e4, 2.808794e4, + 2.832299e4, 2.850000e4, 2.856000e4, 2.879899e4, 2.903999e4, 2.928300e4, + 2.952804e4, 2.977514e4, 3.002430e4, 3.027555e4, 3.052890e4, 3.078437e4, + 3.104198e4, 3.130174e4, 3.156368e4, 3.182781e4, 3.209415e4, 3.236272e4, + 3.263353e4, 3.290662e4, 3.318198e4, 3.345965e4, 3.373965e4, 3.402199e4, + 3.430669e4, 3.459377e4, 3.488326e4, 3.517517e4, 3.546952e4, 3.576633e4, + 3.606563e4, 3.636743e4, 3.667176e4, 3.697864e4, 3.728808e4, 3.760011e4, + 3.791476e4, 3.823203e4, 3.855196e4, 3.887457e4, 3.919988e4, 3.952791e4, + 3.985869e4, 4.019223e4, 4.052857e4, 4.086771e4, 4.120970e4, 4.155455e4, + 4.190229e4, 4.225293e4, 4.260651e4, 4.296305e4, 4.332257e4, 4.368510e4, + 4.405066e4, 4.441928e4, 4.479099e4, 4.516581e4, 4.554376e4, 4.592488e4, + 4.630919e4, 4.669671e4, 4.708747e4, 4.748151e4, 4.787884e4, 4.827950e4, + 4.868351e4, 4.909090e4, 4.950170e4, 4.991594e4, 5.033364e4, 5.075484e4, + 5.117957e4, 5.160785e4, 5.203971e4, 5.247518e4, 5.291430e4, 5.335710e4, + 5.380360e4, 5.425384e4, 5.470784e4, 5.516564e4, 5.562728e4, 5.609278e4, + 5.656217e4, 5.703549e4, 5.751277e4, 5.799405e4, 5.847935e4, 5.896871e4, + 5.946217e4, 5.995976e4, 6.046151e4, 6.096747e4, 6.147765e4, 6.199211e4, + 6.251086e4, 6.303396e4, 6.356144e4, 6.409333e4, 6.462968e4, 6.517051e4, + 6.571586e4, 6.626579e4, 6.682031e4, 6.737947e4, 6.794331e4, 6.851187e4, + 6.908519e4, 6.966330e4, 7.024626e4, 7.083409e4, 7.142684e4, 7.202455e4, + 7.262726e4, 7.323502e4, 7.384786e4, 7.446583e4, 7.508897e4, 7.571733e4, + 7.635094e4, 7.698986e4, 7.763412e4, 7.828378e4, 7.893887e4, 7.950000e4, + 7.959944e4, 8.026554e4, 8.093721e4, 8.161451e4, 8.229747e4, 8.250000e4, + 8.298615e4, 8.368059e4, 8.438084e4, 8.508695e4, 8.579897e4, 8.651695e4, + 8.724094e4, 8.797098e4, 8.870714e4, 8.944945e4, 9.019798e4, 9.095277e4, + 9.171388e4, 9.248135e4, 9.325525e4, 9.403563e4, 9.482253e4, 9.561602e4, + 9.641615e4, 9.722297e4, 9.803655e4, 9.885694e4, 9.968419e4, 1.005184e5, + 1.013595e5, 1.022077e5, 1.030630e5, 1.039254e5, 1.047951e5, 1.056720e5, + 1.065563e5, 1.074480e5, 1.083471e5, 1.092538e5, 1.101681e5, 1.110900e5, + 1.120196e5, 1.129570e5, 1.139022e5, 1.148554e5, 1.158165e5, 1.167857e5, + 1.177629e5, 1.187484e5, 1.197421e5, 1.207441e5, 1.217545e5, 1.227734e5, + 1.238008e5, 1.248368e5, 1.258814e5, 1.269348e5, 1.279970e5, 1.290681e5, + 1.301482e5, 1.312373e5, 1.323355e5, 1.334429e5, 1.345596e5, 1.356856e5, + 1.368210e5, 1.379660e5, 1.391205e5, 1.402847e5, 1.414586e5, 1.426423e5, + 1.438360e5, 1.450396e5, 1.462533e5, 1.474772e5, 1.487113e5, 1.499558e5, + 1.512106e5, 1.524760e5, 1.537519e5, 1.550385e5, 1.563359e5, 1.576442e5, + 1.589634e5, 1.602936e5, 1.616349e5, 1.629875e5, 1.643514e5, 1.657268e5, + 1.671136e5, 1.685120e5, 1.699221e5, 1.713441e5, 1.727779e5, 1.742237e5, + 1.756817e5, 1.771518e5, 1.786342e5, 1.801291e5, 1.816364e5, 1.831564e5, + 1.846891e5, 1.862346e5, 1.877930e5, 1.893645e5, 1.909491e5, 1.925470e5, + 1.941583e5, 1.957830e5, 1.974214e5, 1.990734e5, 2.007393e5, 2.024191e5, + 2.041130e5, 2.058210e5, 2.075434e5, 2.092801e5, 2.110314e5, 2.127974e5, + 2.145781e5, 2.163737e5, 2.181844e5, 2.200102e5, 2.218512e5, 2.237077e5, + 2.255797e5, 2.274674e5, 2.293709e5, 2.312903e5, 2.332258e5, 2.351775e5, + 2.371455e5, 2.391299e5, 2.411310e5, 2.431488e5, 2.451835e5, 2.472353e5, + 2.493042e5, 2.513904e5, 2.534941e5, 2.556153e5, 2.577544e5, 2.599113e5, + 2.620863e5, 2.642794e5, 2.664910e5, 2.687210e5, 2.709697e5, 2.732372e5, + 2.755237e5, 2.778293e5, 2.801543e5, 2.824986e5, 2.848626e5, 2.872464e5, + 2.896501e5, 2.920740e5, 2.945181e5, 2.969826e5, 2.972000e5, 2.985000e5, + 2.994678e5, 3.019738e5, 3.045008e5, 3.070489e5, 3.096183e5, 3.122093e5, + 3.148219e5, 3.174564e5, 3.201129e5, 3.227916e5, 3.254928e5, 3.282166e5, + 3.309631e5, 3.337327e5, 3.365254e5, 3.393415e5, 3.421812e5, 3.450446e5, + 3.479320e5, 3.508435e5, 3.537795e5, 3.567399e5, 3.597252e5, 3.627354e5, + 3.657708e5, 3.688317e5, 3.719181e5, 3.750304e5, 3.781687e5, 3.813333e5, + 3.845243e5, 3.877421e5, 3.909868e5, 3.942586e5, 3.975578e5, 4.008846e5, + 4.042393e5, 4.076220e5, 4.110331e5, 4.144727e5, 4.179410e5, 4.214384e5, + 4.249651e5, 4.285213e5, 4.321072e5, 4.357231e5, 4.393693e5, 4.430460e5, + 4.467535e5, 4.504920e5, 4.542618e5, 4.580631e5, 4.618963e5, 4.657615e5, + 4.696591e5, 4.735892e5, 4.775523e5, 4.815485e5, 4.855782e5, 4.896416e5, + 4.937390e5, 4.978707e5, 5.020369e5, 5.062381e5, 5.104743e5, 5.147461e5, + 5.190535e5, 5.233971e5, 5.277769e5, 5.321934e5, 5.366469e5, 5.411377e5, + 5.456660e5, 5.502322e5, 5.548366e5, 5.594796e5, 5.641614e5, 5.688824e5, + 5.736429e5, 5.784432e5, 5.832837e5, 5.881647e5, 5.930866e5, 5.980496e5, + 6.030542e5, 6.081006e5, 6.131893e5, 6.183206e5, 6.234948e5, 6.287123e5, + 6.339734e5, 6.392786e5, 6.446282e5, 6.500225e5, 6.554620e5, 6.609470e5, + 6.664779e5, 6.720551e5, 6.776790e5, 6.833499e5, 6.890683e5, 6.948345e5, + 7.006490e5, 7.065121e5, 7.124243e5, 7.183860e5, 7.243976e5, 7.304594e5, + 7.365720e5, 7.427358e5, 7.489511e5, 7.552184e5, 7.615382e5, 7.679109e5, + 7.743369e5, 7.808167e5, 7.873507e5, 7.939393e5, 8.005831e5, 8.072825e5, + 8.140380e5, 8.208500e5, 8.277190e5, 8.346455e5, 8.416299e5, 8.486728e5, + 8.557746e5, 8.629359e5, 8.701570e5, 8.774387e5, 8.847812e5, 8.921852e5, + 8.996511e5, 9.071795e5, 9.147709e5, 9.224259e5, 9.301449e5, 9.379285e5, + 9.457772e5, 9.536916e5, 9.616723e5, 9.697197e5, 9.778344e5, 9.860171e5, + 9.942682e5, 1.002588e6, 1.010978e6, 1.019438e6, 1.027969e6, 1.036571e6, + 1.045245e6, 1.053992e6, 1.062812e6, 1.071706e6, 1.080674e6, 1.089717e6, + 1.098836e6, 1.108032e6, 1.117304e6, 1.126654e6, 1.136082e6, 1.145588e6, + 1.155175e6, 1.164842e6, 1.174589e6, 1.184418e6, 1.194330e6, 1.204324e6, + 1.214402e6, 1.224564e6, 1.234812e6, 1.245145e6, 1.255564e6, 1.266071e6, + 1.276666e6, 1.287349e6, 1.298122e6, 1.308985e6, 1.319938e6, 1.330984e6, + 1.342122e6, 1.353353e6, 1.364678e6, 1.376098e6, 1.387613e6, 1.399225e6, + 1.410934e6, 1.422741e6, 1.434646e6, 1.446652e6, 1.458758e6, 1.470965e6, + 1.483274e6, 1.495686e6, 1.508202e6, 1.520823e6, 1.533550e6, 1.546383e6, + 1.559323e6, 1.572372e6, 1.585530e6, 1.598797e6, 1.612176e6, 1.625667e6, + 1.639271e6, 1.652989e6, 1.666821e6, 1.680770e6, 1.694834e6, 1.709017e6, + 1.723318e6, 1.737739e6, 1.752281e6, 1.766944e6, 1.781731e6, 1.796640e6, + 1.811675e6, 1.826835e6, 1.842122e6, 1.857538e6, 1.873082e6, 1.888756e6, + 1.904561e6, 1.920499e6, 1.936570e6, 1.952776e6, 1.969117e6, 1.985595e6, + 2.002210e6, 2.018965e6, 2.035860e6, 2.052897e6, 2.070076e6, 2.087398e6, + 2.104866e6, 2.122480e6, 2.140241e6, 2.158151e6, 2.176211e6, 2.194421e6, + 2.212785e6, 2.231302e6, 2.249973e6, 2.268802e6, 2.287787e6, 2.306932e6, + 2.326237e6, 2.345703e6, 2.365332e6, 2.385126e6, 2.405085e6, 2.425211e6, + 2.445505e6, 2.465970e6, 2.486605e6, 2.507414e6, 2.528396e6, 2.549554e6, + 2.570889e6, 2.592403e6, 2.614096e6, 2.635971e6, 2.658030e6, 2.680272e6, + 2.702701e6, 2.725318e6, 2.748124e6, 2.771121e6, 2.794310e6, 2.817693e6, + 2.841272e6, 2.865048e6, 2.889023e6, 2.913199e6, 2.937577e6, 2.962159e6, + 2.986947e6, 3.011942e6, 3.037147e6, 3.062562e6, 3.088190e6, 3.114032e6, + 3.140091e6, 3.166368e6, 3.192864e6, 3.219583e6, 3.246525e6, 3.273692e6, + 3.301087e6, 3.328711e6, 3.356566e6, 3.384654e6, 3.412978e6, 3.441538e6, + 3.470337e6, 3.499377e6, 3.528661e6, 3.558189e6, 3.587965e6, 3.617989e6, + 3.648265e6, 3.678794e6, 3.709579e6, 3.740621e6, 3.771924e6, 3.803488e6, + 3.835316e6, 3.867410e6, 3.899773e6, 3.932407e6, 3.965314e6, 3.998497e6, + 4.031957e6, 4.065697e6, 4.099719e6, 4.134026e6, 4.168620e6, 4.203504e6, + 4.238679e6, 4.274149e6, 4.309916e6, 4.345982e6, 4.382350e6, 4.419022e6, + 4.456001e6, 4.493290e6, 4.530890e6, 4.568805e6, 4.607038e6, 4.645590e6, + 4.684465e6, 4.723666e6, 4.763194e6, 4.803053e6, 4.843246e6, 4.883775e6, + 4.924643e6, 4.965853e6, 5.007408e6, 5.049311e6, 5.091564e6, 5.134171e6, + 5.177135e6, 5.220458e6, 5.264143e6, 5.308195e6, 5.352614e6, 5.397406e6, + 5.442572e6, 5.488116e6, 5.534042e6, 5.580351e6, 5.627049e6, 5.674137e6, + 5.721619e6, 5.769498e6, 5.817778e6, 5.866462e6, 5.915554e6, 5.965056e6, + 6.014972e6, 6.065307e6, 6.116062e6, 6.167242e6, 6.218851e6, 6.270891e6, + 6.323367e6, 6.376282e6, 6.429639e6, 6.483443e6, 6.537698e6, 6.592406e6, + 6.647573e6, 6.703200e6, 6.759294e6, 6.815857e6, 6.872893e6, 6.930406e6, + 6.988401e6, 7.046881e6, 7.105850e6, 7.165313e6, 7.225274e6, 7.285736e6, + 7.346704e6, 7.408182e6, 7.470175e6, 7.532687e6, 7.595721e6, 7.659283e6, + 7.723377e6, 7.788008e6, 7.853179e6, 7.918896e6, 7.985162e6, 8.051983e6, + 8.119363e6, 8.187308e6, 8.255820e6, 8.324906e6, 8.394570e6, 8.464817e6, + 8.535652e6, 8.607080e6, 8.679105e6, 8.751733e6, 8.824969e6, 8.898818e6, + 8.973284e6, 9.048374e6, 9.124092e6, 9.200444e6, 9.277435e6, 9.355070e6, + 9.433354e6, 9.512294e6, 9.591895e6, 9.672161e6, 9.753099e6, 9.834715e6, + 9.917013e6, 1.000000e7, 1.008368e7, 1.016806e7, 1.025315e7, 1.033895e7, + 1.042547e7, 1.051271e7, 1.060068e7, 1.068939e7, 1.077884e7, 1.086904e7, + 1.095999e7, 1.105171e7, 1.114419e7, 1.123745e7, 1.133148e7, 1.142631e7, + 1.152193e7, 1.161834e7, 1.171557e7, 1.181360e7, 1.191246e7, 1.201215e7, + 1.211267e7, 1.221403e7, 1.231624e7, 1.241930e7, 1.252323e7, 1.262802e7, + 1.273370e7, 1.284025e7, 1.294770e7, 1.305605e7, 1.316531e7, 1.327548e7, + 1.338657e7, 1.349859e7, 1.361155e7, 1.372545e7, 1.384031e7, 1.395612e7, + 1.407291e7, 1.419068e7, 1.430943e7, 1.442917e7, 1.454991e7, 1.467167e7, + 1.479444e7, 1.491825e7, 1.504309e7, 1.516897e7, 1.529590e7, 1.542390e7, + 1.555297e7, 1.568312e7, 1.581436e7, 1.594670e7, 1.608014e7, 1.621470e7, + 1.635039e7, 1.648721e7, 1.662518e7, 1.676430e7, 1.690459e7, 1.704605e7, + 1.718869e7, 1.733253e7, 1.747757e7, 1.762383e7, 1.777131e7, 1.792002e7, + 1.806998e7, 1.822119e7, 1.837367e7, 1.852742e7, 1.868246e7, 1.883880e7, + 1.899644e7, 1.915541e7, 1.931570e7, 1.947734e7, 1.964033e7]) diff --git a/openmc/mgxs/groups.py b/openmc/mgxs/groups.py index f26218e031f..182402ed7fc 100644 --- a/openmc/mgxs/groups.py +++ b/openmc/mgxs/groups.py @@ -5,30 +5,36 @@ import numpy as np import openmc.checkvalue as cv +import openmc.mgxs class EnergyGroups: - """An energy groups structure used for multi-group cross-sections. + """An energy group structure used for multigroup cross-sections. Parameters ---------- - group_edges : Iterable of Real - The energy group boundaries [eV] + group_edges : Iterable of float or str + The energy group boundaries in [eV] or the name of the group structure + (Must be a valid key in the openmc.mgxs.GROUP_STRUCTURES dictionary). + + .. versionchanged:: 0.14.0 + Changed to allow a string specifying the group structure name. Attributes ---------- - group_edges : Iterable of Real - The energy group boundaries [eV] + group_edges : np.ndarray + The energy group boundaries in [eV] num_groups : int The number of energy groups """ - def __init__(self, group_edges=None): - self._group_edges = None + def __init__(self, group_edges): + if isinstance(group_edges, str): + self._name = group_edges.upper() + group_edges = openmc.mgxs.GROUP_STRUCTURES[self._name] - if group_edges is not None: - self.group_edges = group_edges + self.group_edges = group_edges def __deepcopy__(self, memo): existing = memo.get(id(self)) @@ -59,20 +65,26 @@ def __eq__(self, other): def __hash__(self): return hash(tuple(self.group_edges)) + def __repr__(self): + if hasattr(self, '_name'): + return f"" + else: + return f"" + @property def group_edges(self): return self._group_edges - @property - def num_groups(self): - return len(self.group_edges) - 1 - @group_edges.setter def group_edges(self, edges): cv.check_type('group edges', edges, Iterable, Real) cv.check_greater_than('number of group edges', len(edges), 1) self._group_edges = np.array(edges) + @property + def num_groups(self): + return len(self.group_edges) - 1 + def get_group(self, energy): """Returns the energy group in which the given energy resides. @@ -164,7 +176,7 @@ def get_group_indices(self, groups='all'): if groups == 'all': return np.arange(self.num_groups) else: - indices = np.zeros(len(groups), dtype=np.int) + indices = np.zeros(len(groups), dtype=int) for i, group in enumerate(groups): cv.check_greater_than('group', group, 0) @@ -226,10 +238,7 @@ def get_condensed_groups(self, coarse_groups): group_edges = np.sort(group_edges) # Create a new condensed EnergyGroups object - condensed_groups = EnergyGroups() - condensed_groups.group_edges = group_edges - - return condensed_groups + return EnergyGroups(group_edges) def can_merge(self, other): """Determine if energy groups can be merged with another. diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 5c70720334f..12a4630bdc4 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -1,4 +1,3 @@ -from collections import OrderedDict from collections.abc import Iterable import copy from numbers import Integral @@ -72,13 +71,18 @@ class Library: Number of equi-width polar angle bins for angle discretization num_azimuthal : Integral Number of equi-width azimuthal angle bins for angle discretization + nuclides : Iterable of str or 'sum' + The optional user-specified nuclides for which to compute cross + sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides + are not specified by the user, all nuclides in the domain + are included. estimator : str or None The tally estimator used to compute multi-group cross sections. If None, the default for each MGXS type is used. tally_trigger : openmc.Trigger An (optional) tally precision trigger given to each tally used to compute the cross section - all_mgxs : collections.OrderedDict + all_mgxs : dict MGXS objects keyed by domain ID and cross section type sp_filename : str The filename of the statepoint with tally data used to the @@ -107,13 +111,14 @@ def __init__(self, geometry, by_nuclide=False, self._energy_groups = None self._num_polar = 1 self._num_azimuthal = 1 + self._nuclides = None self._num_delayed_groups = 0 self._correction = 'P0' self._scatter_format = 'legendre' self._legendre_order = 0 self._histogram_bins = 16 self._tally_trigger = None - self._all_mgxs = OrderedDict() + self._all_mgxs = {} self._sp_filename = None self._keff = None self._sparse = False @@ -145,6 +150,7 @@ def __deepcopy__(self, memo): clone._energy_groups = copy.deepcopy(self.energy_groups, memo) clone._num_polar = self.num_polar clone._num_azimuthal = self.num_azimuthal + clone._nuclides = self._nuclides clone._num_delayed_groups = self.num_delayed_groups clone._tally_trigger = copy.deepcopy(self.tally_trigger, memo) clone._all_mgxs = copy.deepcopy(self.all_mgxs) @@ -152,9 +158,9 @@ def __deepcopy__(self, memo): clone._keff = self._keff clone._sparse = self.sparse - clone._all_mgxs = OrderedDict() + clone._all_mgxs = {} for domain in self.domains: - clone.all_mgxs[domain.id] = OrderedDict() + clone.all_mgxs[domain.id] = {} for mgxs_type in self.mgxs_types: mgxs = copy.deepcopy(self.all_mgxs[domain.id][mgxs_type]) clone.all_mgxs[domain.id][mgxs_type] = mgxs @@ -171,110 +177,24 @@ def __deepcopy__(self, memo): def geometry(self): return self._geometry - @property - def name(self): - return self._name - - @property - def mgxs_types(self): - return self._mgxs_types - - @property - def by_nuclide(self): - return self._by_nuclide - - @property - def domain_type(self): - return self._domain_type - - @property - def domains(self): - if self._domains == 'all': - if self.domain_type == 'material': - return list(self.geometry.get_all_materials().values()) - elif self.domain_type == 'cell': - return list(self.geometry.get_all_cells().values()) - elif self.domain_type in 'distribcell': - return list(self.geometry.get_all_material_cells().values()) - elif self.domain_type == 'universe': - return list(self.geometry.get_all_universes().values()) - elif self.domain_type == 'mesh': - raise ValueError('Unable to get domains for Mesh domain type') - else: - raise ValueError('Unable to get domains without a domain type') - else: - return self._domains - - @property - def energy_groups(self): - return self._energy_groups - - @property - def num_delayed_groups(self): - return self._num_delayed_groups - - @property - def num_polar(self): - return self._num_polar - - @property - def num_azimuthal(self): - return self._num_azimuthal - - @property - def correction(self): - return self._correction - - @property - def scatter_format(self): - return self._scatter_format - - @property - def legendre_order(self): - return self._legendre_order - - @property - def histogram_bins(self): - return self._histogram_bins - - @property - def tally_trigger(self): - return self._tally_trigger - - @property - def estimator(self): - return self._estimator - - @property - def num_groups(self): - return self.energy_groups.num_groups - - @property - def all_mgxs(self): - return self._all_mgxs - - @property - def sp_filename(self): - return self._sp_filename - - @property - def keff(self): - return self._keff - - @property - def sparse(self): - return self._sparse - @geometry.setter def geometry(self, geometry): cv.check_type('geometry', geometry, openmc.Geometry) self._geometry = geometry + @property + def name(self): + return self._name + @name.setter def name(self, name): cv.check_type('name', name, str) self._name = name + @property + def mgxs_types(self): + return self._mgxs_types + @mgxs_types.setter def mgxs_types(self, mgxs_types): all_mgxs_types = openmc.mgxs.MGXS_TYPES + openmc.mgxs.MDGXS_TYPES + \ @@ -288,6 +208,10 @@ def mgxs_types(self, mgxs_types): cv.check_value('mgxs_type', mgxs_type, all_mgxs_types) self._mgxs_types = mgxs_types + @property + def by_nuclide(self): + return self._by_nuclide + @by_nuclide.setter def by_nuclide(self, by_nuclide): cv.check_type('by_nuclide', by_nuclide, bool) @@ -298,6 +222,10 @@ def by_nuclide(self, by_nuclide): self._by_nuclide = by_nuclide + @property + def domain_type(self): + return self._domain_type + @domain_type.setter def domain_type(self, domain_type): cv.check_value('domain type', domain_type, openmc.mgxs.DOMAIN_TYPES) @@ -308,6 +236,24 @@ def domain_type(self, domain_type): self._domain_type = domain_type + @property + def domains(self): + if self._domains == 'all': + if self.domain_type == 'material': + return list(self.geometry.get_all_materials().values()) + elif self.domain_type == 'cell': + return list(self.geometry.get_all_cells().values()) + elif self.domain_type in 'distribcell': + return list(self.geometry.get_all_material_cells().values()) + elif self.domain_type == 'universe': + return list(self.geometry.get_all_universes().values()) + elif self.domain_type == 'mesh': + raise ValueError('Unable to get domains for Mesh domain type') + else: + raise ValueError('Unable to get domains without a domain type') + else: + return self._domains + @domains.setter def domains(self, domains): @@ -347,11 +293,28 @@ def domains(self, domains): self._domains = list(domains) + @property + def nuclides(self): + return self._nuclides + + @nuclides.setter + def nuclides(self, nuclides): + cv.check_iterable_type('nuclides', nuclides, str) + self._nuclides = nuclides + + @property + def energy_groups(self): + return self._energy_groups + @energy_groups.setter def energy_groups(self, energy_groups): cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) self._energy_groups = energy_groups + @property + def num_delayed_groups(self): + return self._num_delayed_groups + @num_delayed_groups.setter def num_delayed_groups(self, num_delayed_groups): @@ -361,18 +324,30 @@ def num_delayed_groups(self, num_delayed_groups): equality=True) self._num_delayed_groups = num_delayed_groups + @property + def num_polar(self): + return self._num_polar + @num_polar.setter def num_polar(self, num_polar): cv.check_type('num_polar', num_polar, Integral) cv.check_greater_than('num_polar', num_polar, 0) self._num_polar = num_polar + @property + def num_azimuthal(self): + return self._num_azimuthal + @num_azimuthal.setter def num_azimuthal(self, num_azimuthal): cv.check_type('num_azimuthal', num_azimuthal, Integral) cv.check_greater_than('num_azimuthal', num_azimuthal, 0) self._num_azimuthal = num_azimuthal + @property + def correction(self): + return self._correction + @correction.setter def correction(self, correction): cv.check_value('correction', correction, ('P0', None)) @@ -390,6 +365,10 @@ def correction(self, correction): self._correction = correction + @property + def scatter_format(self): + return self._scatter_format + @scatter_format.setter def scatter_format(self, scatter_format): cv.check_value('scatter_format', scatter_format, @@ -403,6 +382,10 @@ def scatter_format(self, scatter_format): self._scatter_format = scatter_format + @property + def legendre_order(self): + return self._legendre_order + @legendre_order.setter def legendre_order(self, legendre_order): cv.check_type('legendre_order', legendre_order, Integral) @@ -424,6 +407,10 @@ def legendre_order(self, legendre_order): self._legendre_order = legendre_order + @property + def histogram_bins(self): + return self._histogram_bins + @histogram_bins.setter def histogram_bins(self, histogram_bins): cv.check_type('histogram_bins', histogram_bins, Integral) @@ -443,16 +430,44 @@ def histogram_bins(self, histogram_bins): self._histogram_bins = histogram_bins + @property + def tally_trigger(self): + return self._tally_trigger + @tally_trigger.setter def tally_trigger(self, tally_trigger): cv.check_type('tally trigger', tally_trigger, openmc.Trigger) self._tally_trigger = tally_trigger + @property + def estimator(self): + return self._estimator + @estimator.setter def estimator(self, estimator): cv.check_value('estimator', estimator, ESTIMATOR_TYPES) self._estimator = estimator + @property + def num_groups(self): + return self.energy_groups.num_groups + + @property + def all_mgxs(self): + return self._all_mgxs + + @property + def sp_filename(self): + return self._sp_filename + + @property + def keff(self): + return self._keff + + @property + def sparse(self): + return self._sparse + @sparse.setter def sparse(self, sparse): """Convert tally data from NumPy arrays to SciPy list of lists (LIL) @@ -487,7 +502,7 @@ def build_library(self): # Initialize MGXS for each domain and mgxs type and store in dictionary for domain in self.domains: - self.all_mgxs[domain.id] = OrderedDict() + self.all_mgxs[domain.id] = {} for mgxs_type in self.mgxs_types: if mgxs_type in openmc.mgxs.MDGXS_TYPES: mgxs = openmc.mgxs.MDGXS.get_mgxs( @@ -524,6 +539,20 @@ def build_library(self): mgxs.legendre_order = self.legendre_order mgxs.histogram_bins = self.histogram_bins + if self.by_nuclide: + try: + domain_nuclides = domain.get_nuclides() + except AttributeError: + domain_nuclides = None + if self.nuclides: + if domain_nuclides: + mgxs.nuclides = [ + nuclide for nuclide in self.nuclides + if nuclide in domain_nuclides + ] + ["total"] + else: + mgxs.nuclides = self.nuclides + self.all_mgxs[domain.id][mgxs_type] = mgxs def add_to_tallies_file(self, tallies_file, merge=True): @@ -590,10 +619,10 @@ def load_from_statepoint(self, statepoint): self._sp_filename = statepoint._f.filename self._geometry = statepoint.summary.geometry - self._nuclides = statepoint.summary.nuclides + self._atomic_weight_ratios = statepoint.summary.nuclides if statepoint.run_mode == 'eigenvalue': - self._keff = statepoint.k_combined.n + self._keff = statepoint.keff.n # Load tallies for each MGXS for each domain and mgxs type for domain in self.domains: @@ -656,7 +685,7 @@ def get_mgxs(self, domain, mgxs_type): # Check that requested domain is included in library if mgxs_type not in self.mgxs_types: - msg = 'Unable to find MGXS type "{0}"'.format(mgxs_type) + msg = f'Unable to find MGXS type "{mgxs_type}"' raise ValueError(msg) return self.all_mgxs[domain_id][mgxs_type] @@ -872,7 +901,7 @@ def dump_to_file(self, filename='mgxs', directory='mgxs'): if not os.path.exists(directory): os.makedirs(directory) - full_filename = os.path.join(directory, '{}.pkl'.format(filename)) + full_filename = os.path.join(directory, f'{filename}.pkl') full_filename = full_filename.replace(' ', '-') # Load and return pickled Library object @@ -1005,7 +1034,7 @@ def get_xsdata(self, domain, xsdata_name, nuclide='total', xs_type='macro', xsdata.num_azimuthal = self.num_azimuthal if nuclide != 'total': - xsdata.atomic_weight_ratio = self._nuclides[nuclide] + xsdata.atomic_weight_ratio = self._atomic_weight_ratios[nuclide] if subdomain is None: subdomain = 'all' diff --git a/openmc/mgxs/mdgxs.py b/openmc/mgxs/mdgxs.py index 7a139c7f87d..b95a4fbc0eb 100644 --- a/openmc/mgxs/mdgxs.py +++ b/openmc/mgxs/mdgxs.py @@ -1,4 +1,3 @@ -from collections import OrderedDict import copy import itertools from numbers import Integral @@ -21,7 +20,7 @@ 'delayed-nu-fission matrix' ) -# Maximum number of delayed groups, from src/constants.F90 +# Maximum number of delayed groups, from include/openmc/constants.h MAX_DELAYED_GROUPS = 8 @@ -90,7 +89,7 @@ class MDGXS(MGXS): the multi-group cross section estimator : {'tracklength', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section rxn_rate_tally : openmc.Tally Derived tally for the reaction rate tally used in the numerator to @@ -110,7 +109,7 @@ class MDGXS(MGXS): being tracked. This is unity if the by_nuclide attribute is False. nuclides : Iterable of str or 'sum' The optional user-specified nuclides for which to compute cross - sections (e.g., 'U-238', 'O-16'). If by_nuclide is True but nuclides + sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides are not specified by the user, all nuclides in the spatial domain are included. This attribute is 'sum' if by_nuclide is false. sparse : bool @@ -120,8 +119,11 @@ class MDGXS(MGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ @@ -158,7 +160,7 @@ def __deepcopy__(self, memo): clone._sparse = self.sparse clone._derived = self.derived - clone._tallies = OrderedDict() + clone._tallies = {} for tally_type, tally in self.tallies.items(): clone.tallies[tally_type] = copy.deepcopy(tally, memo) @@ -184,13 +186,6 @@ def _dont_squeeze(self): def delayed_groups(self): return self._delayed_groups - @property - def num_delayed_groups(self): - if self.delayed_groups is None: - return 1 - else: - return len(self.delayed_groups) - @delayed_groups.setter def delayed_groups(self, delayed_groups): @@ -207,6 +202,13 @@ def delayed_groups(self, delayed_groups): self._delayed_groups = delayed_groups + @property + def num_delayed_groups(self): + if self.delayed_groups is None: + return 1 + else: + return len(self.delayed_groups) + @property def filters(self): @@ -214,7 +216,7 @@ def filters(self): group_edges = self.energy_groups.group_edges energy_filter = openmc.EnergyFilter(group_edges) - if self.delayed_groups != None: + if self.delayed_groups is not None: delayed_filter = openmc.DelayedGroupFilter(self.delayed_groups) filters = [[energy_filter], [delayed_filter, energy_filter]] else: @@ -303,7 +305,7 @@ def get_xs(self, groups='all', subdomains='all', nuclides='all', subdomains : Iterable of Integral or 'all' Subdomain IDs of interest. Defaults to 'all'. nuclides : Iterable of str or 'all' or 'sum' - A list of nuclide name strings (e.g., ['U-235', 'U-238']). The + A list of nuclide name strings (e.g., ['U235', 'U238']). The special string 'all' will return the cross sections for all nuclides in the spatial domain. The special string 'sum' will return the cross section summed over all nuclides. Defaults to 'all'. @@ -453,7 +455,7 @@ def get_slice(self, nuclides=[], groups=[], delayed_groups=[]): ---------- nuclides : list of str A list of nuclide name strings - (e.g., ['U-235', 'U-238']; default is []) + (e.g., ['U235', 'U238']; default is []) groups : list of int A list of energy group indices starting at 1 for the high energies (e.g., [1, 2, 3]; default is []) @@ -565,7 +567,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): Defaults to 'all'. nuclides : Iterable of str or 'all' or 'sum' The nuclides of the cross-sections to include in the report. This - may be a list of nuclide name strings (e.g., ['U-235', 'U-238']). + may be a list of nuclide name strings (e.g., ['U235', 'U238']). The special string 'all' will report the cross sections for all nuclides in the spatial domain. The special string 'sum' will report the cross sections summed over all nuclides. Defaults to 'all'. @@ -583,7 +585,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=np.int) + subdomains = np.arange(self.num_subdomains, dtype=int) elif self.domain_type == 'mesh': xyz = [range(1, x + 1) for x in self.domain.dimension] subdomains = list(itertools.product(*xyz)) @@ -605,12 +607,12 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): # Build header for string with type and domain info string = 'Multi-Delayed-Group XS\n' - string += '{0: <16}=\t{1}\n'.format('\tReaction Type', self.rxn_type) + string += '{0: <16}=\t{1}\n'.format('\tReaction Type', self.mgxs_type) string += '{0: <16}=\t{1}\n'.format('\tDomain Type', self.domain_type) string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) + xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' # If cross section data has not been computed, only print string header if self.tallies is None: @@ -639,7 +641,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): string += '{0: <16}=\t{1}\n'.format('\tNuclide', nuclide) # Add the cross section header - string += '{0: <16}\n'.format(xs_header) + string += f'{xs_header: <16}\n' for delayed_group in self.delayed_groups: @@ -741,9 +743,9 @@ def export_xs_data(self, filename='mgxs', directory='mgxs', df.to_csv(filename + '.csv', index=False) elif format == 'excel': if self.domain_type == 'mesh': - df.to_excel(filename + '.xls') + df.to_excel(filename + '.xlsx') else: - df.to_excel(filename + '.xls', index=False) + df.to_excel(filename + '.xlsx', index=False) elif format == 'pickle': df.to_pickle(filename + '.pkl') elif format == 'latex': @@ -782,7 +784,7 @@ def get_pandas_dataframe(self, groups='all', nuclides='all', Energy groups of interest. Defaults to 'all'. nuclides : Iterable of str or 'all' or 'sum' The nuclides of the cross-sections to include in the dataframe. This - may be a list of nuclide name strings (e.g., ['U-235', 'U-238']). + may be a list of nuclide name strings (e.g., ['U235', 'U238']). The special string 'all' will include the cross sections for all nuclides in the spatial domain. The special string 'sum' will include the cross sections summed over all nuclides. Defaults @@ -873,7 +875,7 @@ def get_pandas_dataframe(self, groups='all', nuclides='all', # Sort the dataframe by domain type id (e.g., distribcell id) and # energy groups such that data is from fast to thermal if self.domain_type == 'mesh': - mesh_str = 'mesh {0}'.format(self.domain.id) + mesh_str = f'mesh {self.domain.id}' df.sort_values(by=[(mesh_str, 'x'), (mesh_str, 'y'), (mesh_str, 'z')] + columns, inplace=True) else: @@ -969,7 +971,7 @@ class ChiDelayed(MDGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`ChiDelayed.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -990,7 +992,7 @@ class ChiDelayed(MDGXS): being tracked. This is unity if the by_nuclide attribute is False. nuclides : Iterable of str or 'sum' The optional user-specified nuclides for which to compute cross - sections (e.g., 'U-238', 'O-16'). If by_nuclide is True but nuclides + sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides are not specified by the user, all nuclides in the spatial domain are included. This attribute is 'sum' if by_nuclide is false. sparse : bool @@ -1000,14 +1002,17 @@ class ChiDelayed(MDGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ # Store whether or not the number density should be removed for microscopic - # values of this data; since this chi data is normalized to 1.0, the - # data should not be divided by the number density + # values of this data; since this chi data is normalized to 1.0, the + # data should not be divided by the number density _divide_by_density = False def __init__(self, domain=None, domain_type=None, energy_groups=None, @@ -1107,7 +1112,7 @@ def get_slice(self, nuclides=[], groups=[], delayed_groups=[]): ---------- nuclides : list of str A list of nuclide name strings - (e.g., ['U-235', 'U-238']; default is []) + (e.g., ['U235', 'U238']; default is []) groups : list of Integral A list of energy group indices starting at 1 for the high energies (e.g., [1, 2, 3]; default is []) @@ -1241,7 +1246,7 @@ def get_xs(self, groups='all', subdomains='all', nuclides='all', subdomains : Iterable of Integral or 'all' Subdomain IDs of interest. Defaults to 'all'. nuclides : Iterable of str or 'all' or 'sum' - A list of nuclide name strings (e.g., ['U-235', 'U-238']). The + A list of nuclide name strings (e.g., ['U235', 'U238']). The special string 'all' will return the cross sections for all nuclides in the spatial domain. The special string 'sum' will return the cross section summed over all nuclides. Defaults to 'all'. @@ -1485,7 +1490,7 @@ class DelayedNuFissionXS(MDGXS): the multi-group cross section estimator : {'tracklength', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`DelayedNuFissionXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -1506,7 +1511,7 @@ class DelayedNuFissionXS(MDGXS): being tracked. This is unity if the by_nuclide attribute is False. nuclides : Iterable of str or 'sum' The optional user-specified nuclides for which to compute cross - sections (e.g., 'U-238', 'O-16'). If by_nuclide is True but nuclides + sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides are not specified by the user, all nuclides in the spatial domain are included. This attribute is 'sum' if by_nuclide is false. sparse : bool @@ -1516,8 +1521,11 @@ class DelayedNuFissionXS(MDGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ @@ -1621,7 +1629,7 @@ class Beta(MDGXS): the multi-group cross section estimator : {'tracklength', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`Beta.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -1642,7 +1650,7 @@ class Beta(MDGXS): being tracked. This is unity if the by_nuclide attribute is False. nuclides : Iterable of str or 'sum' The optional user-specified nuclides for which to compute cross - sections (e.g., 'U-238', 'O-16'). If by_nuclide is True but nuclides + sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides are not specified by the user, all nuclides in the spatial domain are included. This attribute is 'sum' if by_nuclide is false. sparse : bool @@ -1652,8 +1660,11 @@ class Beta(MDGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ @@ -1811,7 +1822,7 @@ class DecayRate(MDGXS): the multi-group cross section estimator : {'tracklength', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`DecayRate.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -1832,7 +1843,7 @@ class DecayRate(MDGXS): being tracked. This is unity if the by_nuclide attribute is False. nuclides : Iterable of str or 'sum' The optional user-specified nuclides for which to compute cross - sections (e.g., 'U-238', 'O-16'). If by_nuclide is True but nuclides + sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides are not specified by the user, all nuclides in the spatial domain are included. This attribute is 'sum' if by_nuclide is false. sparse : bool @@ -1842,8 +1853,11 @@ class DecayRate(MDGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ @@ -1870,9 +1884,6 @@ def tally_keys(self): @property def filters(self): - # Create the non-domain specific Filters for the Tallies - group_edges = self.energy_groups.group_edges - if self.delayed_groups is not None: delayed_filter = openmc.DelayedGroupFilter(self.delayed_groups) filters = [[delayed_filter], [delayed_filter]] @@ -1935,7 +1946,7 @@ def get_xs(self, subdomains='all', nuclides='all', subdomains : Iterable of Integral or 'all' Subdomain IDs of interest. Defaults to 'all'. nuclides : Iterable of str or 'all' or 'sum' - A list of nuclide name strings (e.g., ['U-235', 'U-238']). The + A list of nuclide name strings (e.g., ['U235', 'U238']). The special string 'all' will return the cross sections for all nuclides in the spatial domain. The special string 'sum' will return the cross section summed over all nuclides. Defaults to 'all'. @@ -2122,7 +2133,7 @@ class MatrixMDGXS(MDGXS): the multi-group cross section estimator : {'tracklength', 'collision', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section rxn_rate_tally : openmc.Tally Derived tally for the reaction rate tally used in the numerator to @@ -2152,8 +2163,11 @@ class MatrixMDGXS(MDGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ @@ -2455,7 +2469,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=np.int) + subdomains = np.arange(self.num_subdomains, dtype=int) elif self.domain_type == 'mesh': xyz = [range(1, x + 1) for x in self.domain.dimension] subdomains = list(itertools.product(*xyz)) @@ -2477,12 +2491,12 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): # Build header for string with type and domain info string = 'Multi-Delayed-Group XS\n' - string += '{0: <16}=\t{1}\n'.format('\tReaction Type', self.rxn_type) + string += '{0: <16}=\t{1}\n'.format('\tReaction Type', self.mgxs_type) string += '{0: <16}=\t{1}\n'.format('\tDomain Type', self.domain_type) string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) + xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' # If cross section data has not been computed, only print string header if self.tallies is None: @@ -2518,7 +2532,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): string += '{: <16}=\t{}\n'.format('\tNuclide', nuclide) # Build header for cross section type - string += '{: <16}\n'.format(xs_header) + string += f'{xs_header: <16}\n' if self.delayed_groups is not None: @@ -2717,7 +2731,7 @@ class DelayedNuFissionMatrixXS(MatrixMDGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`DelayedNuFissionXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -2738,7 +2752,7 @@ class DelayedNuFissionMatrixXS(MatrixMDGXS): being tracked. This is unity if the by_nuclide attribute is False. nuclides : Iterable of str or 'sum' The optional user-specified nuclides for which to compute cross - sections (e.g., 'U-238', 'O-16'). If by_nuclide is True but nuclides + sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides are not specified by the user, all nuclides in the spatial domain are included. This attribute is 'sum' if by_nuclide is false. sparse : bool @@ -2748,8 +2762,11 @@ class DelayedNuFissionMatrixXS(MatrixMDGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ @@ -2759,6 +2776,6 @@ def __init__(self, domain=None, domain_type=None, energy_groups=None, super().__init__(domain, domain_type, energy_groups, delayed_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = 'delayed-nu-fission' - self._hdf5_key = 'delayed-nu-fission matrix' + self._mgxs_type = 'delayed-nu-fission matrix' self._estimator = 'analog' self._valid_estimators = ['analog'] diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 89b223a3540..588b6f64e2a 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -1,4 +1,3 @@ -from collections import OrderedDict import copy from numbers import Integral import os @@ -20,6 +19,7 @@ 'transport', 'nu-transport', 'absorption', + 'reduced absorption', 'capture', 'fission', 'nu-fission', @@ -147,6 +147,11 @@ def _df_column_convert_to_bin(df, current_name, new_name, values_to_bin, df.rename(columns={current_name: new_name}, inplace=True) +def add_params(cls): + cls.__doc__ += cls._params + return cls + +@add_params class MGXS: """An abstract multi-group cross section for some energy group structure within some spatial domain. @@ -157,6 +162,9 @@ class MGXS: .. note:: Users should instantiate the subclasses of this abstract class. + """ + + _params = """ Parameters ---------- domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh @@ -207,7 +215,7 @@ class MGXS: the multi-group cross section estimator : {'tracklength', 'collision', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section rxn_rate_tally : openmc.Tally Derived tally for the reaction rate tally used in the numerator to @@ -237,8 +245,11 @@ class MGXS: Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ @@ -266,7 +277,7 @@ def __init__(self, domain=None, domain_type=None, self._sparse = False self._loaded_sp = False self._derived = False - self._hdf5_key = None + self._mgxs_type = None self._valid_estimators = ESTIMATOR_TYPES self.name = name @@ -305,9 +316,9 @@ def __deepcopy__(self, memo): clone._sparse = self.sparse clone._loaded_sp = self._loaded_sp clone._derived = self.derived - clone._hdf5_key = self._hdf5_key + clone._mgxs_type = self._mgxs_type - clone._tallies = OrderedDict() + clone._tallies = {} for tally_type, tally in self.tallies.items(): clone.tallies[tally_type] = copy.deepcopy(tally, memo) @@ -441,6 +452,11 @@ def _dont_squeeze(self): def name(self): return self._name + @name.setter + def name(self, name): + cv.check_type('name', name, str) + self._name = name + @property def rxn_type(self): return self._rxn_type @@ -449,30 +465,78 @@ def rxn_type(self): def by_nuclide(self): return self._by_nuclide + @by_nuclide.setter + def by_nuclide(self, by_nuclide): + cv.check_type('by_nuclide', by_nuclide, bool) + self._by_nuclide = by_nuclide + @property def domain(self): return self._domain + @domain.setter + def domain(self, domain): + cv.check_type('domain', domain, _DOMAINS) + self._domain = domain + + # Assign a domain type + if self.domain_type is None: + if isinstance(domain, openmc.Material): + self._domain_type = 'material' + elif isinstance(domain, openmc.Cell): + self._domain_type = 'cell' + elif isinstance(domain, openmc.Universe): + self._domain_type = 'universe' + elif isinstance(domain, openmc.RegularMesh): + self._domain_type = 'mesh' + @property def domain_type(self): return self._domain_type + @domain_type.setter + def domain_type(self, domain_type): + cv.check_value('domain type', domain_type, DOMAIN_TYPES) + self._domain_type = domain_type + @property def energy_groups(self): return self._energy_groups + @energy_groups.setter + def energy_groups(self, energy_groups): + cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) + self._energy_groups = energy_groups + @property def num_polar(self): return self._num_polar + @num_polar.setter + def num_polar(self, num_polar): + cv.check_type('num_polar', num_polar, Integral) + cv.check_greater_than('num_polar', num_polar, 0) + self._num_polar = num_polar + @property def num_azimuthal(self): return self._num_azimuthal + @num_azimuthal.setter + def num_azimuthal(self, num_azimuthal): + cv.check_type('num_azimuthal', num_azimuthal, Integral) + cv.check_greater_than('num_azimuthal', num_azimuthal, 0) + self._num_azimuthal = num_azimuthal + @property def tally_trigger(self): return self._tally_trigger + @tally_trigger.setter + def tally_trigger(self, tally_trigger): + cv.check_type('tally trigger', tally_trigger, openmc.Trigger) + self._tally_trigger = tally_trigger + @property def num_groups(self): return self.energy_groups.num_groups @@ -499,6 +563,11 @@ def tally_keys(self): def estimator(self): return self._estimator + @estimator.setter + def estimator(self, estimator): + cv.check_value('estimator', estimator, self._valid_estimators) + self._estimator = estimator + @property def tallies(self): @@ -506,7 +575,7 @@ def tallies(self): if self._tallies is None: # Initialize a collection of Tallies - self._tallies = OrderedDict() + self._tallies ={} # Create a domain Filter object filter_type = _DOMAIN_TO_FILTER[self.domain_type] @@ -573,6 +642,31 @@ def xs_tally(self): def sparse(self): return self._sparse + @sparse.setter + def sparse(self, sparse): + """Convert tally data from NumPy arrays to SciPy list of lists (LIL) + sparse matrices, and vice versa. + + This property may be used to reduce the amount of data in memory during + tally data processing. The tally data will be stored as SciPy LIL + matrices internally within the Tally object. All tally data access + properties and methods will return data as a dense NumPy array. + + """ + + cv.check_type('sparse', sparse, bool) + + # Sparsify or densify the derived MGXS tallies and the base tallies + if self._xs_tally: + self.xs_tally.sparse = sparse + if self._rxn_rate_tally: + self.rxn_rate_tally.sparse = sparse + + for tally_name in self.tallies: + self.tallies[tally_name].sparse = sparse + + self._sparse = sparse + @property def num_subdomains(self): if self.domain_type.startswith('sum('): @@ -600,6 +694,11 @@ def nuclides(self): else: return ['sum'] + @nuclides.setter + def nuclides(self, nuclides): + cv.check_iterable_type('nuclides', nuclides, str) + self._nuclides = nuclides + @property def loaded_sp(self): return self._loaded_sp @@ -609,100 +708,12 @@ def derived(self): return self._derived @property - def hdf5_key(self): - if self._hdf5_key is not None: - return self._hdf5_key + def mgxs_type(self): + if self._mgxs_type is not None: + return self._mgxs_type else: return self._rxn_type - @name.setter - def name(self, name): - cv.check_type('name', name, str) - self._name = name - - @by_nuclide.setter - def by_nuclide(self, by_nuclide): - cv.check_type('by_nuclide', by_nuclide, bool) - self._by_nuclide = by_nuclide - - @nuclides.setter - def nuclides(self, nuclides): - cv.check_iterable_type('nuclides', nuclides, str) - self._nuclides = nuclides - - @estimator.setter - def estimator(self, estimator): - cv.check_value('estimator', estimator, self._valid_estimators) - self._estimator = estimator - - @domain.setter - def domain(self, domain): - cv.check_type('domain', domain, _DOMAINS) - self._domain = domain - - # Assign a domain type - if self.domain_type is None: - if isinstance(domain, openmc.Material): - self._domain_type = 'material' - elif isinstance(domain, openmc.Cell): - self._domain_type = 'cell' - elif isinstance(domain, openmc.Universe): - self._domain_type = 'universe' - elif isinstance(domain, openmc.RegularMesh): - self._domain_type = 'mesh' - - @domain_type.setter - def domain_type(self, domain_type): - cv.check_value('domain type', domain_type, DOMAIN_TYPES) - self._domain_type = domain_type - - @energy_groups.setter - def energy_groups(self, energy_groups): - cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) - self._energy_groups = energy_groups - - @num_polar.setter - def num_polar(self, num_polar): - cv.check_type('num_polar', num_polar, Integral) - cv.check_greater_than('num_polar', num_polar, 0) - self._num_polar = num_polar - - @num_azimuthal.setter - def num_azimuthal(self, num_azimuthal): - cv.check_type('num_azimuthal', num_azimuthal, Integral) - cv.check_greater_than('num_azimuthal', num_azimuthal, 0) - self._num_azimuthal = num_azimuthal - - @tally_trigger.setter - def tally_trigger(self, tally_trigger): - cv.check_type('tally trigger', tally_trigger, openmc.Trigger) - self._tally_trigger = tally_trigger - - @sparse.setter - def sparse(self, sparse): - """Convert tally data from NumPy arrays to SciPy list of lists (LIL) - sparse matrices, and vice versa. - - This property may be used to reduce the amount of data in memory during - tally data processing. The tally data will be stored as SciPy LIL - matrices internally within the Tally object. All tally data access - properties and methods will return data as a dense NumPy array. - - """ - - cv.check_type('sparse', sparse, bool) - - # Sparsify or densify the derived MGXS tallies and the base tallies - if self._xs_tally: - self.xs_tally.sparse = sparse - if self._rxn_rate_tally: - self.rxn_rate_tally.sparse = sparse - - for tally_name in self.tallies: - self.tallies[tally_name].sparse = sparse - - self._sparse = sparse - @staticmethod def get_mgxs(mgxs_type, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, @@ -761,6 +772,8 @@ def get_mgxs(mgxs_type, domain=None, domain_type=None, mgxs = TransportXS(domain, domain_type, energy_groups, nu=True) elif mgxs_type == 'absorption': mgxs = AbsorptionXS(domain, domain_type, energy_groups) + elif mgxs_type == 'reduced absorption': + mgxs = ReducedAbsorptionXS(domain, domain_type, energy_groups) elif mgxs_type == 'capture': mgxs = CaptureXS(domain, domain_type, energy_groups) elif mgxs_type == 'fission': @@ -813,6 +826,8 @@ def get_mgxs(mgxs_type, domain=None, domain_type=None, elif mgxs_type in ARBITRARY_MATRIX_TYPES: mgxs = ArbitraryMatrixXS(mgxs_type, domain, domain_type, energy_groups) + else: + raise ValueError(f"Unknown MGXS type: {mgxs_type}") mgxs.by_nuclide = by_nuclide mgxs.name = name @@ -902,20 +917,20 @@ def get_nuclide_densities(self, nuclides='all'): # Sum the atomic number densities for all nuclides if nuclides == 'sum': nuclides = self.get_nuclides() - densities = np.zeros(1, dtype=np.float) + densities = np.zeros(1, dtype=float) for nuclide in nuclides: densities[0] += self.get_nuclide_density(nuclide) # Tabulate the atomic number densities for all nuclides elif nuclides == 'all': nuclides = self.get_nuclides() - densities = np.zeros(self.num_nuclides, dtype=np.float) + densities = np.zeros(self.num_nuclides, dtype=float) for i, nuclide in enumerate(nuclides): densities[i] += self.get_nuclide_density(nuclide) # Tabulate the atomic number densities for each specified nuclide else: - densities = np.zeros(len(nuclides), dtype=np.float) + densities = np.zeros(len(nuclides), dtype=float) for i, nuclide in enumerate(nuclides): densities[i] = self.get_nuclide_density(nuclide) @@ -1412,7 +1427,7 @@ def get_subdomain_avg_xs(self, subdomains='all'): filter_bins=subdomains) avg_xs.tallies[tally_type] = tally_avg - avg_xs._domain_type = 'sum({0})'.format(self.domain_type) + avg_xs._domain_type = f'sum({self.domain_type})' avg_xs.sparse = self.sparse return avg_xs @@ -1463,7 +1478,7 @@ def _get_homogenized_mgxs(self, other_mgxs, denom_score='flux'): # Clone this MGXS to initialize the homogenized version homogenized_mgxs = copy.deepcopy(self) homogenized_mgxs._derived = True - name = 'hom({}, '.format(self.domain.name) + name = f'hom({self.domain.name}, ' # Get the domain filter filter_type = _DOMAIN_TO_FILTER[self.domain_type] @@ -1490,7 +1505,7 @@ def _get_homogenized_mgxs(self, other_mgxs, denom_score='flux'): denom_tally += other_denom_tally # Update the name for the homogenzied MGXS - name += '{}, '.format(mgxs.domain.name) + name += f'{mgxs.domain.name}, ' # Set the properties of the homogenized MGXS homogenized_mgxs._rxn_rate_tally = rxn_rate_tally @@ -1674,7 +1689,7 @@ def merge(self, other): merged_mgxs.nuclides = self.nuclides + other.nuclides # Null base tallies but merge reaction rate and cross section tallies - merged_mgxs._tallies = OrderedDict() + merged_mgxs._tallies ={} merged_mgxs._rxn_rate_tally = self.rxn_rate_tally.merge(other.rxn_rate_tally) merged_mgxs._xs_tally = self.xs_tally.merge(other.xs_tally) @@ -1704,7 +1719,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=np.int) + subdomains = np.arange(self.num_subdomains, dtype=int) elif self.domain_type == 'mesh': subdomains = list(self.domain.indices) else: @@ -1725,12 +1740,12 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): # Build header for string with type and domain info string = 'Multi-Group XS\n' - string += '{0: <16}=\t{1}\n'.format('\tReaction Type', self.rxn_type) + string += '{0: <16}=\t{1}\n'.format('\tReaction Type', self.mgxs_type) string += '{0: <16}=\t{1}\n'.format('\tDomain Type', self.domain_type) string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) + xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' # If cross section data has not been computed, only print string header if self.tallies is None: @@ -1758,7 +1773,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): string += '{0: <16}=\t{1}\n'.format('\tNuclide', nuclide) # Build header for cross section type - string += '{0: <16}\n'.format(xs_header) + string += f'{xs_header: <16}\n' template = '{0: <12}Group {1} [{2: <10} - {3: <10}eV]:\t' average_xs = self.get_xs(nuclides=[nuclide], @@ -1871,7 +1886,7 @@ def build_hdf5_store(self, filename='mgxs.h5', directory='mgxs', if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=np.int) + subdomains = np.arange(self.num_subdomains, dtype=int) elif self.domain_type == 'sum(distribcell)': domain_filter = self.xs_tally.find_filter('sum(distribcell)') subdomains = domain_filter.bins @@ -1884,7 +1899,7 @@ def build_hdf5_store(self, filename='mgxs.h5', directory='mgxs', if self.by_nuclide: if nuclides == 'all': nuclides = self.get_nuclides() - densities = np.zeros(len(nuclides), dtype=np.float) + densities = np.zeros(len(nuclides), dtype=float) elif nuclides == 'sum': nuclides = ['sum'] else: @@ -1912,7 +1927,7 @@ def build_hdf5_store(self, filename='mgxs.h5', directory='mgxs', subdomain_group = domain_group # Create a separate HDF5 group for this cross section - rxn_group = subdomain_group.require_group(self.hdf5_key) + rxn_group = subdomain_group.require_group(self.mgxs_type) # Create a separate HDF5 group for each nuclide for j, nuclide in enumerate(nuclides): @@ -1986,9 +2001,9 @@ def export_xs_data(self, filename='mgxs', directory='mgxs', df.to_csv(filename + '.csv', index=False) elif format == 'excel': if self.domain_type == 'mesh': - df.to_excel(filename + '.xls') + df.to_excel(filename + '.xlsx') else: - df.to_excel(filename + '.xls', index=False) + df.to_excel(filename + '.xlsx', index=False) elif format == 'pickle': df.to_pickle(filename + '.pkl') elif format == 'latex': @@ -2116,7 +2131,7 @@ def get_pandas_dataframe(self, groups='all', nuclides='all', # Sort the dataframe by domain type id (e.g., distribcell id) and # energy groups such that data is from fast to thermal if self.domain_type == 'mesh': - mesh_str = 'mesh {0}'.format(self.domain.id) + mesh_str = f'mesh {self.domain.id}' df.sort_values(by=[(mesh_str, 'x'), (mesh_str, 'y'), (mesh_str, 'z')] + columns, inplace=True) else: @@ -2145,6 +2160,7 @@ def get_units(self, xs_type='macro'): return 'cm^-1' if xs_type == 'macro' else 'barns' +@add_params class MatrixMGXS(MGXS): """An abstract multi-group cross section for some energy group structure within some spatial domain. This class is specifically intended for @@ -2158,99 +2174,16 @@ class MatrixMGXS(MGXS): .. note:: Users should instantiate the subclasses of this abstract class. - Parameters - ---------- - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin - - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., 'total', 'nu-fission', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : {'tracklength', 'collision', 'analog'} - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file) and the number of mesh cells for - 'mesh' domain types. - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store - - """ - @property - def _dont_squeeze(self): - """Create a tuple of axes which should not be removed during the get_xs - process - """ - if self.num_polar > 1 or self.num_azimuthal > 1: - return (0, 1, 3, 4) - else: - return (1, 2) + """ + @property + def _dont_squeeze(self): + """Create a tuple of axes which should not be removed during the get_xs + process + """ + if self.num_polar > 1 or self.num_azimuthal > 1: + return (0, 1, 3, 4) + else: + return (1, 2) @property def filters(self): @@ -2513,7 +2446,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=np.int) + subdomains = np.arange(self.num_subdomains, dtype=int) elif self.domain_type == 'mesh': subdomains = list(self.domain.indices) else: @@ -2534,12 +2467,12 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): # Build header for string with type and domain info string = 'Multi-Group XS\n' - string += '{0: <16}=\t{1}\n'.format('\tReaction Type', self.rxn_type) + string += '{0: <16}=\t{1}\n'.format('\tReaction Type', self.mgxs_type) string += '{0: <16}=\t{1}\n'.format('\tDomain Type', self.domain_type) string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) + xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' # If cross section data has not been computed, only print string header if self.tallies is None: @@ -2575,7 +2508,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): string += '{0: <16}=\t{1}\n'.format('\tNuclide', nuclide) # Build header for cross section type - string += '{0: <16}\n'.format(xs_header) + string += f'{xs_header: <16}\n' template = '{0: <12}Group {1} -> Group {2}:\t\t' average_xs = self.get_xs(nuclides=[nuclide], @@ -2625,6 +2558,7 @@ def print_xs(self, subdomains='all', nuclides='all', xs_type='macro'): print(string) +@add_params class TotalXS(MGXS): r"""A total multi-group cross section. @@ -2651,95 +2585,11 @@ class TotalXS(MGXS): \sigma_t (r, E) \psi (r, E, \Omega)}{\int_{r \in V} dr \int_{4\pi} d\Omega \int_{E_g}^{E_{g-1}} dE \; \psi (r, E, \Omega)}. - Parameters - ---------- - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin - - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., 'total', 'nu-fission', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : {'tracklength', 'collision', 'analog'} - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section. The keys - are strings listed in the :attr:`TotalXS.tally_keys` property and values - are instances of :class:`openmc.Tally`. - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file). - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store - """ - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = 'total' @@ -2839,7 +2689,7 @@ class TransportXS(MGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`TransportXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -2870,14 +2720,17 @@ class TransportXS(MGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ - def __init__(self, domain=None, domain_type=None, groups=None, nu=False, + def __init__(self, domain=None, domain_type=None, energy_groups=None, nu=False, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) # Use tracklength estimators for the total MGXS term, and @@ -3077,7 +2930,7 @@ class DiffusionCoefficient(TransportXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`TransportXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -3108,14 +2961,17 @@ class DiffusionCoefficient(TransportXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ - def __init__(self, domain=None, domain_type=None, groups=None, nu=False, + def __init__(self, domain=None, domain_type=None, energy_groups=None, nu=False, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super(DiffusionCoefficient, self).__init__(domain, domain_type, groups, + super(DiffusionCoefficient, self).__init__(domain, domain_type, energy_groups, nu, by_nuclide, name, num_polar, num_azimuthal) if not nu: @@ -3127,7 +2983,7 @@ def __init__(self, domain=None, domain_type=None, groups=None, nu=False, @property def rxn_rate_tally(self): if self._rxn_rate_tally is None: - # Switch EnergyoutFilter to EnergyFilter + # Switch EnergyoutFilter to EnergyFilter. p1_tally = self.tallies['scatter-1'] old_filt = p1_tally.filters[-2] new_filt = openmc.EnergyFilter(old_filt.values) @@ -3139,17 +2995,8 @@ def rxn_rate_tally(self): squeeze=True) p1_tally._scores = ['scatter-1'] - # Compute total cross section - total_xs = self.tallies['total'] / self.tallies['flux (tracklength)'] - - # Compute transport correction term - trans_corr = self.tallies['scatter-1'] / self.tallies['flux (analog)'] - - # Compute the diffusion coefficient - transport = total_xs - trans_corr - dif_coef = transport**(-1) / 3.0 - - self._rxn_rate_tally = dif_coef * self.tallies['flux (tracklength)'] + transport = self.tallies['total'] - p1_tally + self._rxn_rate_tally = transport**(-1) / 3.0 self._rxn_rate_tally.sparse = self.sparse return self._rxn_rate_tally @@ -3162,13 +3009,34 @@ def xs_tally(self): 'not been loaded from a statepoint' raise ValueError(msg) - self._xs_tally = self.rxn_rate_tally / self.tallies['flux (tracklength)'] - self._compute_xs() + # Switch EnergyoutFilter to EnergyFilter + # If 'scatter-1' is not in tallies, it is because the transport correction has + # already occurred on this MGXS in another function or in a previous call to this function. + if 'scatter-1' in self.tallies: + p1_tally = self.tallies['scatter-1'] + old_filt = p1_tally.filters[-2] + new_filt = openmc.EnergyFilter(old_filt.values) + p1_tally.filters[-2] = new_filt + + p1_tally = p1_tally.get_slice(filters=[openmc.LegendreFilter], + filter_bins=[('P1',)],squeeze=True) + p1_tally._scores = ['scatter-1'] + total_xs = self.tallies['total'] / self.tallies['flux (tracklength)'] + trans_corr = p1_tally / self.tallies['flux (analog)'] + transport = total_xs - trans_corr + diff_coef = transport**(-1) / 3.0 + self._xs_tally = diff_coef + self._compute_xs() + + else: + self._xs_tally = self.tallies[self._rxn_type] / self.tallies['flux (tracklength)'] + self._compute_xs() return self._xs_tally def get_condensed_xs(self, coarse_groups): """Construct an energy-condensed version of this cross section. + Parameters ---------- coarse_groups : openmc.mgxs.EnergyGroups @@ -3178,6 +3046,7 @@ def get_condensed_xs(self, coarse_groups): ------- MGXS A new MGXS condensed to the group structure of interest + """ cv.check_type('coarse_groups', coarse_groups, EnergyGroups) @@ -3191,36 +3060,36 @@ def get_condensed_xs(self, coarse_groups): # Clone this MGXS to initialize the condensed version condensed_xs = copy.deepcopy(self) - if self._rxn_rate_tally is None: - + # If 'scatter-1' is not in tallies, it is because the transport correction has + # already occurred on this MGXS in another function or in a previous call to this function. + if 'scatter-1' in self.tallies: p1_tally = self.tallies['scatter-1'] old_filt = p1_tally.filters[-2] new_filt = openmc.EnergyFilter(old_filt.values) p1_tally.filters[-2] = new_filt - - # Slice Legendre expansion filter and change name of score p1_tally = p1_tally.get_slice(filters=[openmc.LegendreFilter], - filter_bins=[('P1',)], - squeeze=True) + filter_bins=[('P1',)], + squeeze=True) p1_tally._scores = ['scatter-1'] - - total = self.tallies['total'] / self.tallies['flux (tracklength)'] + total_xs = self.tallies['total'] / self.tallies['flux (tracklength)'] trans_corr = p1_tally / self.tallies['flux (analog)'] - transport = (total - trans_corr) - dif_coef = transport**(-1) / 3.0 - dif_coef *= self.tallies['flux (tracklength)'] + transport = total_xs - trans_corr + diff_coef = transport**(-1) / 3.0 + diff_coef *= self.tallies['flux (tracklength)'] + flux_tally = condensed_xs.tallies['flux (tracklength)'] + condensed_xs._tallies = {} + condensed_xs._tallies[self._rxn_type] = diff_coef + condensed_xs._tallies['flux (tracklength)'] = flux_tally + condensed_xs._rxn_rate_tally = diff_coef + condensed_xs._xs_tally = None + condensed_xs._sparse = False + condensed_xs._energy_groups = coarse_groups else: - dif_coef = self.rxn_rate_tally - - flux_tally = condensed_xs.tallies['flux (tracklength)'] - condensed_xs._tallies = OrderedDict() - condensed_xs._tallies[self._rxn_type] = dif_coef - condensed_xs._tallies['flux (tracklength)'] = flux_tally - condensed_xs._rxn_rate_tally = dif_coef - condensed_xs._xs_tally = None - condensed_xs._sparse = False - condensed_xs._energy_groups = coarse_groups + condensed_xs._rxn_rate_tally = None + condensed_xs._xs_tally = None + condensed_xs._sparse = False + condensed_xs._energy_groups = coarse_groups # Build energy indices to sum across energy_indices = [] @@ -3245,16 +3114,17 @@ def get_condensed_xs(self, coarse_groups): # Sum across all applicable fine energy group filters for i, tally_filter in enumerate(tally.filters): - if not isinstance(tally_filter, - (openmc.EnergyFilter, - openmc.EnergyoutFilter)): + if not isinstance(tally_filter, (openmc.EnergyFilter, + openmc.EnergyoutFilter)): continue - elif len(tally_filter.bins) != len(fine_edges): + elif len(tally_filter.bins) != len(fine_edges) - 1: continue - elif not np.allclose(tally_filter.bins, fine_edges): + elif not np.allclose(tally_filter.bins[:, 0], fine_edges[:-1]): continue else: - tally_filter.bins = coarse_groups.group_edges + cedge = coarse_groups.group_edges + tally_filter.values = cedge + tally_filter.bins = np.vstack((cedge[:-1], cedge[1:])).T mean = np.add.reduceat(mean, energy_indices, axis=i) std_dev = np.add.reduceat(std_dev**2, energy_indices, axis=i) @@ -3272,7 +3142,7 @@ def get_condensed_xs(self, coarse_groups): condensed_xs.sparse = self.sparse return condensed_xs - +@add_params class AbsorptionXS(MGXS): r"""An absorption multi-group cross section. @@ -3303,115 +3173,28 @@ class AbsorptionXS(MGXS): \sigma_a (r, E) \psi (r, E, \Omega)}{\int_{r \in V} dr \int_{4\pi} d\Omega \int_{E_g}^{E_{g-1}} dE \; \psi (r, E, \Omega)}. - Parameters - ---------- - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin - - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., 'total', 'nu-fission', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : {'tracklength', 'collision', 'analog'} - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section. The keys - are strings listed in the :attr:`AbsorptionXS.tally_keys` property and - values are instances of :class:`openmc.Tally`. - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file) and the number of mesh cells for - 'mesh' domain types. - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store - """ - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = 'absorption' -class CaptureXS(MGXS): - r"""A capture multi-group cross section. +@add_params +class ReducedAbsorptionXS(MGXS): + r"""A reduced absorption multi-group cross section. - The neutron capture reaction rate is defined as the difference between - OpenMC's 'absorption' and 'fission' reaction rate score types. This includes - not only radiative capture, but all forms of neutron disappearance aside - from fission (i.e., MT > 100). + The reduced absorption reaction rate is defined as the difference between + absorption and the production of neutrons due to (n,xn) reactions. This class can be used for both OpenMC input generation and tally data post-processing to compute spatially-homogenized and energy-integrated - multi-group capture cross sections for multi-group neutronics - calculations. At a minimum, one needs to set the - :attr:`CaptureXS.energy_groups` and :attr:`CaptureXS.domain` - properties. Tallies for the flux and appropriate reaction rates over the - specified domain are generated automatically via the + multi-group capture cross sections for multi-group neutronics calculations. + At a minimum, one needs to set the :attr:`CaptureXS.energy_groups` and + :attr:`CaptureXS.domain` properties. Tallies for the flux and appropriate + reaction rates over the specified domain are generated automatically via the :attr:`CaptureXS.tallies` property, which can then be appended to a :class:`openmc.Tallies` instance. @@ -3421,104 +3204,81 @@ class CaptureXS(MGXS): can then be obtained from the :attr:`CaptureXS.xs_tally` property. For a spatial domain :math:`V` and energy group :math:`[E_g,E_{g-1}]`, the - capture cross section is calculated as: + reduced absorption cross section is calculated as: .. math:: \frac{\int_{r \in V} dr \int_{4\pi} d\Omega \int_{E_g}^{E_{g-1}} dE \; - \left [ \sigma_a (r, E) \psi (r, E, \Omega) - \sigma_f (r, E) \psi (r, E, - \Omega) \right ]}{\int_{r \in V} dr \int_{4\pi} d\Omega - \int_{E_g}^{E_{g-1}} dE \; \psi (r, E, \Omega)}. + \left(\sigma_a (r, E) - \sigma_{n,2n}(r,E) - 2\sigma_{n,3n}(r,E) - + 3\sigma_{n,4n}(r,E) \right) \psi (r, E, \Omega)}{\int_{r \in V} dr + \int_{4\pi} d\Omega \int_{E_g}^{E_{g-1}} dE \; \psi (r, E, \Omega)}. - Parameters - ---------- - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin + .. versionadded:: 0.13.1 - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., 'total', 'nu-fission', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : {'tracklength', 'collision', 'analog'} - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section. The keys - are strings listed in the :attr:`CaptureXS.tally_keys` property and - values are instances of :class:`openmc.Tally`. - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file). - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + """ + + def __init__(self, domain=None, domain_type=None, energy_groups=None, + by_nuclide=False, name='', num_polar=1, num_azimuthal=1): + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, + num_polar, num_azimuthal) + self._rxn_type = 'reduced absorption' + + @property + def scores(self): + return ['flux', 'absorption', '(n,2n)', '(n,3n)', '(n,4n)'] + + @property + def rxn_rate_tally(self): + if self._rxn_rate_tally is None: + self._rxn_rate_tally = ( + self.tallies['absorption'] + - self.tallies['(n,2n)'] + - 2*self.tallies['(n,3n)'] + - 3*self.tallies['(n,4n)'] + ) + self._rxn_rate_tally.sparse = self.sparse + return self._rxn_rate_tally + + +@add_params +class CaptureXS(MGXS): + r"""A capture multi-group cross section. + + The neutron capture reaction rate is defined as the difference between + OpenMC's 'absorption' and 'fission' reaction rate score types. This includes + not only radiative capture, but all forms of neutron disappearance aside + from fission (i.e., MT > 100). + + This class can be used for both OpenMC input generation and tally data + post-processing to compute spatially-homogenized and energy-integrated + multi-group capture cross sections for multi-group neutronics + calculations. At a minimum, one needs to set the + :attr:`CaptureXS.energy_groups` and :attr:`CaptureXS.domain` + properties. Tallies for the flux and appropriate reaction rates over the + specified domain are generated automatically via the + :attr:`CaptureXS.tallies` property, which can then be appended to a + :class:`openmc.Tallies` instance. + + For post-processing, the :meth:`MGXS.load_from_statepoint` will pull in the + necessary data to compute multi-group cross sections from a + :class:`openmc.StatePoint` instance. The derived multi-group cross section + can then be obtained from the :attr:`CaptureXS.xs_tally` property. + + For a spatial domain :math:`V` and energy group :math:`[E_g,E_{g-1}]`, the + capture cross section is calculated as: + + .. math:: + + \frac{\int_{r \in V} dr \int_{4\pi} d\Omega \int_{E_g}^{E_{g-1}} dE \; + \left [ \sigma_a (r, E) \psi (r, E, \Omega) - \sigma_f (r, E) \psi (r, E, + \Omega) \right ]}{\int_{r \in V} dr \int_{4\pi} d\Omega + \int_{E_g}^{E_{g-1}} dE \; \psi (r, E, \Omega)}. """ - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = 'capture' @@ -3633,7 +3393,7 @@ class FissionXS(MGXS): the multi-group cross section estimator : {'tracklength', 'collision', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`FissionXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -3664,15 +3424,18 @@ class FissionXS(MGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ - def __init__(self, domain=None, domain_type=None, groups=None, nu=False, + def __init__(self, domain=None, domain_type=None, energy_groups=None, nu=False, prompt=False, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._nu = False self._prompt = False @@ -3689,10 +3452,6 @@ def __deepcopy__(self, memo): def nu(self): return self._nu - @property - def prompt(self): - return self._prompt - @nu.setter def nu(self, nu): cv.check_type('nu', nu, bool) @@ -3705,6 +3464,10 @@ def nu(self, nu): else: self._rxn_type = 'prompt-nu-fission' + @property + def prompt(self): + return self._prompt + @prompt.setter def prompt(self, prompt): cv.check_type('prompt', prompt, bool) @@ -3718,6 +3481,7 @@ def prompt(self, prompt): self._rxn_type = 'prompt-nu-fission' +@add_params class KappaFissionXS(MGXS): r"""A recoverable fission energy production rate multi-group cross section. @@ -3751,95 +3515,11 @@ class KappaFissionXS(MGXS): \kappa\sigma_f (r, E) \psi (r, E, \Omega)}{\int_{r \in V} dr \int_{4\pi} d\Omega \int_{E_g}^{E_{g-1}} dE \; \psi (r, E, \Omega)}. - Parameters - ---------- - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin - - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., 'total', 'nu-fission', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : {'tracklength', 'collision', 'analog'} - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section. The keys - are strings listed in the :attr:`KappaFissionXS.tally_keys` property and - values are instances of :class:`openmc.Tally`. - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file). - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store - """ - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = 'kappa-fission' @@ -3932,7 +3612,7 @@ class ScatterXS(MGXS): the multi-group cross section estimator : {'tracklength', 'collision', 'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`ScatterXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -3963,15 +3643,18 @@ class ScatterXS(MGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1, nu=False): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self.nu = nu @@ -3996,6 +3679,7 @@ def nu(self, nu): self._valid_estimators = ['analog'] +@add_params class ArbitraryXS(MGXS): r"""A multi-group cross section for an arbitrary reaction type. @@ -4024,102 +3708,17 @@ class ArbitraryXS(MGXS): where :math:`\sigma_X` is the requested reaction type of interest. - Parameters - ---------- - rxn_type : str - Reaction type (e.g., '(n,2n)', '(n,Xt)', etc.) - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin - - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., '(n,2n)', '(n,Xt)', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : {'tracklength', 'collision', 'analog'} - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section. The keys - are strings listed in the :attr:`TotalXS.tally_keys` property and values - are instances of :class:`openmc.Tally`. - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file). - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store - """ - def __init__(self, rxn_type, domain=None, domain_type=None, groups=None, + def __init__(self, rxn_type, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): cv.check_value("rxn_type", rxn_type, ARBITRARY_VECTOR_TYPES) - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = rxn_type +@add_params class ArbitraryMatrixXS(MatrixMGXS): r"""A multi-group matrix cross section for an arbitrary reaction type. @@ -4155,100 +3754,13 @@ class ArbitraryMatrixXS(MatrixMGXS): where :math:`\sigma_X` is the requested reaction type of interest. - Parameters - ---------- - rxn_type : str - Reaction type (e.g., '(n,2n)', '(n,nta)', etc.). Valid names have - neutrons as a product. - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin - - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., 'total', 'nu-fission', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : 'analog' - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section. The keys - are strings listed in the :attr:`NuFissionMatrixXS.tally_keys` - property and values are instances of :class:`openmc.Tally`. - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file). - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store - """ - def __init__(self, rxn_type, domain=None, domain_type=None, groups=None, + def __init__(self, rxn_type, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): cv.check_value("rxn_type", rxn_type, ARBITRARY_MATRIX_TYPES) - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = rxn_type.split(" ")[0] self._estimator = 'analog' @@ -4410,7 +3922,7 @@ class ScatterMatrixXS(MatrixMGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`ScatterMatrixXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -4441,15 +3953,18 @@ class ScatterMatrixXS(MatrixMGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1, nu=False): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._formulation = 'simple' self._correction = 'P0' @@ -4490,26 +4005,115 @@ def _dont_squeeze(self): def formulation(self): return self._formulation + @formulation.setter + def formulation(self, formulation): + cv.check_value('formulation', formulation, ('simple', 'consistent')) + self._formulation = formulation + + if self.formulation == 'simple': + self._valid_estimators = ['analog'] + if not self.nu: + self._mgxs_type = 'scatter matrix' + else: + self._mgxs_type = 'nu-scatter matrix' + else: + self._valid_estimators = ['tracklength'] + if not self.nu: + self._mgxs_type = 'consistent scatter matrix' + else: + self._mgxs_type = 'consistent nu-scatter matrix' + @property def correction(self): return self._correction + @correction.setter + def correction(self, correction): + cv.check_value('correction', correction, ('P0', None)) + + if self.scatter_format == SCATTER_LEGENDRE: + if correction == 'P0' and self.legendre_order > 0: + msg = 'The P0 correction will be ignored since the ' \ + 'scattering order {} is greater than '\ + 'zero'.format(self.legendre_order) + warnings.warn(msg) + elif self.scatter_format == SCATTER_HISTOGRAM: + msg = 'The P0 correction will be ignored since the ' \ + 'scatter format is set to histogram' + warnings.warn(msg) + + self._correction = correction + @property def scatter_format(self): return self._scatter_format - @property - def legendre_order(self): - return self._legendre_order + @scatter_format.setter + def scatter_format(self, scatter_format): + cv.check_value('scatter_format', scatter_format, MU_TREATMENTS) + self._scatter_format = scatter_format + + @property + def legendre_order(self): + return self._legendre_order + + @legendre_order.setter + def legendre_order(self, legendre_order): + cv.check_type('legendre_order', legendre_order, Integral) + cv.check_greater_than('legendre_order', legendre_order, 0, + equality=True) + cv.check_less_than('legendre_order', legendre_order, _MAX_LEGENDRE, + equality=True) + + if self.scatter_format == SCATTER_LEGENDRE: + if self.correction == 'P0' and legendre_order > 0: + msg = 'The P0 correction will be ignored since the ' \ + 'scattering order {} is greater than '\ + 'zero'.format(legendre_order) + warnings.warn(msg, RuntimeWarning) + self.correction = None + elif self.scatter_format == SCATTER_HISTOGRAM: + msg = 'The legendre order will be ignored since the ' \ + 'scatter format is set to histogram' + warnings.warn(msg) + + self._legendre_order = legendre_order @property def histogram_bins(self): return self._histogram_bins + @histogram_bins.setter + def histogram_bins(self, histogram_bins): + cv.check_type('histogram_bins', histogram_bins, Integral) + cv.check_greater_than('histogram_bins', histogram_bins, 0) + + self._histogram_bins = histogram_bins + @property def nu(self): return self._nu + @nu.setter + def nu(self, nu): + cv.check_type('nu', nu, bool) + self._nu = nu + + if self.formulation == 'simple': + if not nu: + self._rxn_type = 'scatter' + self._mgxs_type = 'scatter matrix' + else: + self._rxn_type = 'nu-scatter' + self._mgxs_type = 'nu-scatter matrix' + else: + if not nu: + self._rxn_type = 'scatter' + self._mgxs_type = 'consistent scatter matrix' + else: + self._rxn_type = 'nu-scatter' + self._mgxs_type = 'consistent nu-scatter matrix' + @property def scores(self): @@ -4791,95 +4395,6 @@ def xs_tally(self): return self._xs_tally - @nu.setter - def nu(self, nu): - cv.check_type('nu', nu, bool) - self._nu = nu - - if self.formulation == 'simple': - if not nu: - self._rxn_type = 'scatter' - self._hdf5_key = 'scatter matrix' - else: - self._rxn_type = 'nu-scatter' - self._hdf5_key = 'nu-scatter matrix' - else: - if not nu: - self._rxn_type = 'scatter' - self._hdf5_key = 'consistent scatter matrix' - else: - self._rxn_type = 'nu-scatter' - self._hdf5_key = 'consistent nu-scatter matrix' - - @formulation.setter - def formulation(self, formulation): - cv.check_value('formulation', formulation, ('simple', 'consistent')) - self._formulation = formulation - - if self.formulation == 'simple': - self._valid_estimators = ['analog'] - if not self.nu: - self._hdf5_key = 'scatter matrix' - else: - self._hdf5_key = 'nu-scatter matrix' - else: - self._valid_estimators = ['tracklength'] - if not self.nu: - self._hdf5_key = 'consistent scatter matrix' - else: - self._hdf5_key = 'consistent nu-scatter matrix' - - @correction.setter - def correction(self, correction): - cv.check_value('correction', correction, ('P0', None)) - - if self.scatter_format == SCATTER_LEGENDRE: - if correction == 'P0' and self.legendre_order > 0: - msg = 'The P0 correction will be ignored since the ' \ - 'scattering order {} is greater than '\ - 'zero'.format(self.legendre_order) - warnings.warn(msg) - elif self.scatter_format == SCATTER_HISTOGRAM: - msg = 'The P0 correction will be ignored since the ' \ - 'scatter format is set to histogram' - warnings.warn(msg) - - self._correction = correction - - @scatter_format.setter - def scatter_format(self, scatter_format): - cv.check_value('scatter_format', scatter_format, MU_TREATMENTS) - self._scatter_format = scatter_format - - @legendre_order.setter - def legendre_order(self, legendre_order): - cv.check_type('legendre_order', legendre_order, Integral) - cv.check_greater_than('legendre_order', legendre_order, 0, - equality=True) - cv.check_less_than('legendre_order', legendre_order, _MAX_LEGENDRE, - equality=True) - - if self.scatter_format == SCATTER_LEGENDRE: - if self.correction == 'P0' and legendre_order > 0: - msg = 'The P0 correction will be ignored since the ' \ - 'scattering order {} is greater than '\ - 'zero'.format(legendre_order) - warnings.warn(msg, RuntimeWarning) - self.correction = None - elif self.scatter_format == SCATTER_HISTOGRAM: - msg = 'The legendre order will be ignored since the ' \ - 'scatter format is set to histogram' - warnings.warn(msg) - - self._legendre_order = legendre_order - - @histogram_bins.setter - def histogram_bins(self, histogram_bins): - cv.check_type('histogram_bins', histogram_bins, Integral) - cv.check_greater_than('histogram_bins', histogram_bins, 0) - - self._histogram_bins = histogram_bins - def load_from_statepoint(self, statepoint): """Extracts tallies in an OpenMC StatePoint with the data needed to compute multi-group cross sections. @@ -4961,7 +4476,7 @@ def get_slice(self, nuclides=[], in_groups=[], out_groups=[], slice_xs.legendre_order = legendre_order # Slice the scattering tally - filter_bins = [tuple(['P{}'.format(i) + filter_bins = [tuple([f'P{i}' for i in range(self.legendre_order + 1)])] slice_xs.tallies[self.rxn_type] = \ slice_xs.tallies[self.rxn_type].get_slice( @@ -5098,7 +4613,7 @@ def get_xs(self, in_groups='all', out_groups='all', cv.check_less_than( 'moment', moment, self.legendre_order, equality=True) filters.append(openmc.LegendreFilter) - filter_bins.append(('P{}'.format(moment),)) + filter_bins.append((f'P{moment}',)) num_angle_bins = 1 else: num_angle_bins = self.legendre_order + 1 @@ -5269,7 +4784,7 @@ def print_xs(self, subdomains='all', nuclides='all', if not isinstance(subdomains, str): cv.check_iterable_type('subdomains', subdomains, Integral) elif self.domain_type == 'distribcell': - subdomains = np.arange(self.num_subdomains, dtype=np.int) + subdomains = np.arange(self.num_subdomains, dtype=int) elif self.domain_type == 'mesh': subdomains = list(self.domain.indices) else: @@ -5289,9 +4804,9 @@ def print_xs(self, subdomains='all', nuclides='all', cv.check_value('xs_type', xs_type, ['macro', 'micro']) if self.correction != 'P0' and self.scatter_format == SCATTER_LEGENDRE: - rxn_type = '{0} (P{1})'.format(self.rxn_type, moment) + rxn_type = f'{self.mgxs_type} (P{moment})' else: - rxn_type = self.rxn_type + rxn_type = self.mgxs_type # Build header for string with type and domain info string = 'Multi-Group XS\n' @@ -5300,7 +4815,7 @@ def print_xs(self, subdomains='all', nuclides='all', string += '{0: <16}=\t{1}\n'.format('\tDomain ID', self.domain.id) # Generate the header for an individual XS - xs_header = '\tCross Sections [{0}]:'.format(self.get_units(xs_type)) + xs_header = f'\tCross Sections [{self.get_units(xs_type)}]:' # If cross section data has not been computed, only print string header if self.tallies is None: @@ -5336,7 +4851,7 @@ def print_xs(self, subdomains='all', nuclides='all', string += '{0: <16}=\t{1}\n'.format('\tNuclide', nuclide) # Build header for cross section type - string += '{0: <16}\n'.format(xs_header) + string += f'{xs_header: <16}\n' average_xs = self.get_xs(nuclides=[nuclide], subdomains=[subdomain], @@ -5387,149 +4902,65 @@ def print_groups_and_histogram(avg_xs, err_xs, num_groups, pol_low, pol_high = pol_bins[pol: pol + 2] for azi in range(len(azi_bins) - 1): azi_low, azi_high = azi_bins[azi: azi + 2] - string += \ - '\t\tPolar Angle: [{0:5f} - {1:5f}]'.format( - pol_low, pol_high) + \ - '\tAzimuthal Angle: [{0:5f} - {1:5f}]'.format( - azi_low, azi_high) + '\n' - string += print_groups_and_histogram( - average_xs[pol, azi, ...], - rel_err_xs[pol, azi, ...], self.num_groups, - num_mu_bins) - string += '\n' - else: - string += print_groups_and_histogram( - average_xs, rel_err_xs, self.num_groups, num_mu_bins) - string += '\n' - string += '\n' - string += '\n' - - print(string) - - -class MultiplicityMatrixXS(MatrixMGXS): - r"""The scattering multiplicity matrix. - - This class can be used for both OpenMC input generation and tally data - post-processing to compute spatially-homogenized and energy-integrated - multi-group cross sections for multi-group neutronics calculations. At a - minimum, one needs to set the :attr:`MultiplicityMatrixXS.energy_groups` and - :attr:`MultiplicityMatrixXS.domain` properties. Tallies for the flux and - appropriate reaction rates over the specified domain are generated - automatically via the :attr:`MultiplicityMatrixXS.tallies` property, which - can then be appended to a :class:`openmc.Tallies` instance. - - For post-processing, the :meth:`MGXS.load_from_statepoint` will pull in the - necessary data to compute multi-group cross sections from a - :class:`openmc.StatePoint` instance. The derived multi-group cross section - can then be obtained from the :attr:`MultiplicityMatrixXS.xs_tally` - property. - - For a spatial domain :math:`V`, incoming energy group - :math:`[E_{g'},E_{g'-1}]`, and outgoing energy group :math:`[E_g,E_{g-1}]`, - the multiplicity is calculated as: - - .. math:: - - \begin{aligned} - \langle \upsilon \sigma_{s,g'\rightarrow g} \phi \rangle &= \int_{r \in - D} dr \int_{4\pi} d\Omega' \int_{E_{g'}}^{E_{g'-1}} dE' \int_{4\pi} - d\Omega \int_{E_g}^{E_{g-1}} dE \; \sum_i \upsilon_i \sigma_i (r, E' \rightarrow - E, \Omega' \cdot \Omega) \psi(r, E', \Omega') \\ - \langle \sigma_{s,g'\rightarrow g} \phi \rangle &= \int_{r \in - D} dr \int_{4\pi} d\Omega' \int_{E_{g'}}^{E_{g'-1}} dE' \int_{4\pi} - d\Omega \int_{E_g}^{E_{g-1}} dE \; \sum_i \upsilon_i \sigma_i (r, E' \rightarrow - E, \Omega' \cdot \Omega) \psi(r, E', \Omega') \\ - \upsilon_{g'\rightarrow g} &= \frac{\langle \upsilon - \sigma_{s,g'\rightarrow g} \rangle}{\langle \sigma_{s,g'\rightarrow g} - \rangle} - \end{aligned} - - where :math:`\upsilon_i` is the multiplicity for the :math:`i`-th reaction. - - Parameters - ---------- - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin - - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., 'total', 'nu-fission', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : 'analog' - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section. The keys - are strings listed in the :attr:`MultiplicityMatrixXS.tally_keys` - property and values are instances of :class:`openmc.Tally`. - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file). - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + string += \ + f'\t\tPolar Angle: [{pol_low:5f} - {pol_high:5f}]' + \ + '\tAzimuthal Angle: [{0:5f} - {1:5f}]'.format( + azi_low, azi_high) + '\n' + string += print_groups_and_histogram( + average_xs[pol, azi, ...], + rel_err_xs[pol, azi, ...], self.num_groups, + num_mu_bins) + string += '\n' + else: + string += print_groups_and_histogram( + average_xs, rel_err_xs, self.num_groups, num_mu_bins) + string += '\n' + string += '\n' + string += '\n' + + print(string) + + +@add_params +class MultiplicityMatrixXS(MatrixMGXS): + r"""The scattering multiplicity matrix. + + This class can be used for both OpenMC input generation and tally data + post-processing to compute spatially-homogenized and energy-integrated + multi-group cross sections for multi-group neutronics calculations. At a + minimum, one needs to set the :attr:`MultiplicityMatrixXS.energy_groups` and + :attr:`MultiplicityMatrixXS.domain` properties. Tallies for the flux and + appropriate reaction rates over the specified domain are generated + automatically via the :attr:`MultiplicityMatrixXS.tallies` property, which + can then be appended to a :class:`openmc.Tallies` instance. + + For post-processing, the :meth:`MGXS.load_from_statepoint` will pull in the + necessary data to compute multi-group cross sections from a + :class:`openmc.StatePoint` instance. The derived multi-group cross section + can then be obtained from the :attr:`MultiplicityMatrixXS.xs_tally` + property. + + For a spatial domain :math:`V`, incoming energy group + :math:`[E_{g'},E_{g'-1}]`, and outgoing energy group :math:`[E_g,E_{g-1}]`, + the multiplicity is calculated as: + + .. math:: + + \begin{aligned} + \langle \upsilon \sigma_{s,g'\rightarrow g} \phi \rangle &= \int_{r \in + D} dr \int_{4\pi} d\Omega' \int_{E_{g'}}^{E_{g'-1}} dE' \int_{4\pi} + d\Omega \int_{E_g}^{E_{g-1}} dE \; \sum_i \upsilon_i \sigma_i (r, E' \rightarrow + E, \Omega' \cdot \Omega) \psi(r, E', \Omega') \\ + \langle \sigma_{s,g'\rightarrow g} \phi \rangle &= \int_{r \in + D} dr \int_{4\pi} d\Omega' \int_{E_{g'}}^{E_{g'-1}} dE' \int_{4\pi} + d\Omega \int_{E_g}^{E_{g-1}} dE \; \sum_i \upsilon_i \sigma_i (r, E' \rightarrow + E, \Omega' \cdot \Omega) \psi(r, E', \Omega') \\ + \upsilon_{g'\rightarrow g} &= \frac{\langle \upsilon + \sigma_{s,g'\rightarrow g} \rangle}{\langle \sigma_{s,g'\rightarrow g} + \rangle} + \end{aligned} + + where :math:`\upsilon_i` is the multiplicity for the :math:`i`-th reaction. """ @@ -5539,9 +4970,9 @@ class MultiplicityMatrixXS(MatrixMGXS): # for microscopic data _divide_by_density = False - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = 'multiplicity matrix' self._estimator = 'analog' @@ -5582,6 +5013,7 @@ def xs_tally(self): return self._xs_tally +@add_params class ScatterProbabilityMatrix(MatrixMGXS): r"""The group-to-group scattering probability matrix. @@ -5620,90 +5052,6 @@ class ScatterProbabilityMatrix(MatrixMGXS): \sigma_{s,g'} \phi \rangle} \end{aligned} - Parameters - ---------- - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin - - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., 'total', 'nu-fission', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : 'analog' - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section. The keys - are strings listed in the :attr:`ScatterProbabilityMatrix.tally_keys` - property and values are instances of :class:`openmc.Tally`. - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file). - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U238', 'O16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store - """ # Store whether or not the number density should be removed for microscopic @@ -5711,12 +5059,12 @@ class ScatterProbabilityMatrix(MatrixMGXS): # to 1.0, this density division is not necessary _divide_by_density = False - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = 'scatter' - self._hdf5_key = 'scatter probability matrix' + self._mgxs_type = 'scatter probability matrix' self._estimator = 'analog' self._valid_estimators = ['analog'] @@ -5843,7 +5191,7 @@ class NuFissionMatrixXS(MatrixMGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`NuFissionMatrixXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -5874,22 +5222,25 @@ class NuFissionMatrixXS(MatrixMGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1, prompt=False): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) if not prompt: self._rxn_type = 'nu-fission' - self._hdf5_key = 'nu-fission matrix' + self._mgxs_type = 'nu-fission matrix' else: self._rxn_type = 'prompt-nu-fission' - self._hdf5_key = 'prompt-nu-fission matrix' + self._mgxs_type = 'prompt-nu-fission matrix' self._estimator = 'analog' self._valid_estimators = ['analog'] self.prompt = prompt @@ -6001,7 +5352,7 @@ class Chi(MGXS): the multi-group cross section estimator : 'analog' The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`Chi.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -6032,8 +5383,11 @@ class Chi(MGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ @@ -6042,15 +5396,11 @@ class Chi(MGXS): # data should not be divided by the number density _divide_by_density = False - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, prompt=False, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) - if not prompt: - self._rxn_type = 'chi' - else: - self._rxn_type = 'chi-prompt' self._estimator = 'analog' self._valid_estimators = ['analog'] self.prompt = prompt @@ -6064,6 +5414,17 @@ def __deepcopy__(self, memo): def prompt(self): return self._prompt + @prompt.setter + def prompt(self, prompt): + cv.check_type('prompt', prompt, bool) + self._prompt = prompt + if not self.prompt: + self._rxn_type = 'chi' + self._mgxs_type = 'chi' + else: + self._rxn_type = 'chi-prompt' + self._mgxs_type = 'chi-prompt' + @property def _dont_squeeze(self): """Create a tuple of axes which should not be removed during the get_xs @@ -6120,17 +5481,6 @@ def xs_tally(self): return self._xs_tally - @prompt.setter - def prompt(self, prompt): - cv.check_type('prompt', prompt, bool) - self._prompt = prompt - if not self.prompt: - self._rxn_type = 'nu-fission' - self._hdf5_key = 'chi' - else: - self._rxn_type = 'prompt-nu-fission' - self._hdf5_key = 'chi-prompt' - def get_homogenized_mgxs(self, other_mgxs): """Construct a homogenized mgxs with other MGXS objects. @@ -6448,6 +5798,7 @@ def get_units(self, xs_type='macro'): return '%' +@add_params class InverseVelocity(MGXS): r"""An inverse velocity multi-group cross section. @@ -6477,91 +5828,6 @@ class InverseVelocity(MGXS): \frac{\psi (r, E, \Omega)}{v (r, E)}}{\int_{r \in V} dr \int_{4\pi} d\Omega \int_{E_g}^{E_{g-1}} dE \; \psi (r, E, \Omega)} - Parameters - ---------- - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - The domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - The domain type for spatial homogenization - groups : openmc.mgxs.EnergyGroups - The energy group structure for energy condensation - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - name : str, optional - Name of the multi-group cross section. Used as a label to identify - tallies in OpenMC 'tallies.xml' file. - num_polar : Integral, optional - Number of equi-width polar angle bins for angle discretization; - defaults to one bin - num_azimuthal : Integral, optional - Number of equi-width azimuthal angle bins for angle discretization; - defaults to one bin - - Attributes - ---------- - name : str, optional - Name of the multi-group cross section - rxn_type : str - Reaction type (e.g., 'total', 'nu-fission', etc.) - by_nuclide : bool - If true, computes cross sections for each nuclide in domain - domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh - Domain for spatial homogenization - domain_type : {'material', 'cell', 'distribcell', 'universe', 'mesh'} - Domain type for spatial homogenization - energy_groups : openmc.mgxs.EnergyGroups - Energy group structure for energy condensation - num_polar : Integral - Number of equi-width polar angle bins for angle discretization - num_azimuthal : Integral - Number of equi-width azimuthal angle bins for angle discretization - tally_trigger : openmc.Trigger - An (optional) tally precision trigger given to each tally used to - compute the cross section - scores : list of str - The scores in each tally used to compute the multi-group cross section - filters : list of openmc.Filter - The filters in each tally used to compute the multi-group cross section - tally_keys : list of str - The keys into the tallies dictionary for each tally used to compute - the multi-group cross section - estimator : {'tracklength', 'collision', 'analog'} - The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict - OpenMC tallies needed to compute the multi-group cross section. The keys - are strings listed in the :attr:`InverseVelocity.tally_keys` property - and values are instances of :class:`openmc.Tally`. - rxn_rate_tally : openmc.Tally - Derived tally for the reaction rate tally used in the numerator to - compute the multi-group cross section. This attribute is None - unless the multi-group cross section has been computed. - xs_tally : openmc.Tally - Derived tally for the multi-group cross section. This attribute - is None unless the multi-group cross section has been computed. - num_subdomains : int - The number of subdomains is unity for 'material', 'cell' and 'universe' - domain types. This is equal to the number of cell instances - for 'distribcell' domain types (it is equal to unity prior to loading - tally data from a statepoint file) and the number of mesh cells for - 'mesh' domain types. - num_nuclides : int - The number of nuclides for which the multi-group cross section is - being tracked. This is unity if the by_nuclide attribute is False. - nuclides : Iterable of str or 'sum' - The optional user-specified nuclides for which to compute cross - sections (e.g., 'U-238', 'O-16'). If by_nuclide is True but nuclides - are not specified by the user, all nuclides in the spatial domain - are included. This attribute is 'sum' if by_nuclide is false. - sparse : bool - Whether or not the MGXS' tallies use SciPy's LIL sparse matrix format - for compressed data storage - loaded_sp : bool - Whether or not a statepoint file has been loaded with tally data - derived : bool - Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store - """ # Store whether or not the number density should be removed for microscopic @@ -6570,9 +5836,9 @@ class InverseVelocity(MGXS): # values _divide_by_density = False - def __init__(self, domain=None, domain_type=None, groups=None, + def __init__(self, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, num_azimuthal=1): - super().__init__(domain, domain_type, groups, by_nuclide, name, + super().__init__(domain, domain_type, energy_groups, by_nuclide, name, num_polar, num_azimuthal) self._rxn_type = 'inverse-velocity' @@ -6654,7 +5920,7 @@ class MeshSurfaceMGXS(MGXS): the multi-group cross section estimator : {'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section rxn_rate_tally : openmc.Tally Derived tally for the reaction rate tally used in the numerator to @@ -6678,8 +5944,11 @@ class MeshSurfaceMGXS(MGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ def __init__(self, domain=None, domain_type=None, energy_groups=None, @@ -6697,10 +5966,6 @@ def scores(self): def domain(self): return self._domain - @property - def domain_type(self): - return self._domain_type - @domain.setter def domain(self, domain): cv.check_type('domain', domain, openmc.RegularMesh) @@ -6710,6 +5975,10 @@ def domain(self, domain): if self.domain_type is None: self._domain_type = 'mesh' + @property + def domain_type(self): + return self._domain_type + @domain_type.setter def domain_type(self, domain_type): cv.check_value('domain type', domain_type, 'mesh') @@ -6956,7 +6225,7 @@ def get_pandas_dataframe(self, groups='all', nuclides='all', if 'group out' in df: df = df[df['group out'].isin(groups)] - mesh_str = 'mesh {0}'.format(self.domain.id) + mesh_str = f'mesh {self.domain.id}' col_key = (mesh_str, 'surf') surfaces = df.pop(col_key) df.insert(len(self.domain.dimension), col_key, surfaces) @@ -7038,7 +6307,7 @@ class Current(MeshSurfaceMGXS): the multi-group cross section estimator : {'analog'} The tally estimator used to compute the multi-group cross section - tallies : collections.OrderedDict + tallies : dict OpenMC tallies needed to compute the multi-group cross section. The keys are strings listed in the :attr:`TotalXS.tally_keys` property and values are instances of :class:`openmc.Tally`. @@ -7064,12 +6333,15 @@ class Current(MeshSurfaceMGXS): Whether or not a statepoint file has been loaded with tally data derived : bool Whether or not the MGXS is merged from one or more other MGXS - hdf5_key : str - The key used to index multi-group cross sections in an HDF5 data store + mgxs_type : str + The name of this MGXS type, to be used when printing and + indexing in an HDF5 data store + + .. versionadded:: 0.13.1 """ def __init__(self, domain=None, domain_type=None, - groups=None, by_nuclide=False, name=''): + energy_groups=None, by_nuclide=False, name=''): super(Current, self).__init__(domain, domain_type, - groups, by_nuclide, name) + energy_groups, by_nuclide, name) self._rxn_type = 'current' diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 00a155142f8..642da83d170 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -1,6 +1,5 @@ import copy from numbers import Real, Integral -import os import h5py import numpy as np @@ -261,22 +260,62 @@ def __deepcopy__(self, memo): def name(self): return self._name + @name.setter + def name(self, name): + + check_type('name for XSdata', name, str) + self._name = name + @property def energy_groups(self): return self._energy_groups + @energy_groups.setter + def energy_groups(self, energy_groups): + + check_type('energy_groups', energy_groups, openmc.mgxs.EnergyGroups) + if energy_groups.group_edges is None: + msg = 'Unable to assign an EnergyGroups object ' \ + 'with uninitialized group edges' + raise ValueError(msg) + + self._energy_groups = energy_groups + @property def num_delayed_groups(self): return self._num_delayed_groups + @num_delayed_groups.setter + def num_delayed_groups(self, num_delayed_groups): + + check_type('num_delayed_groups', num_delayed_groups, Integral) + check_less_than('num_delayed_groups', num_delayed_groups, + openmc.mgxs.MAX_DELAYED_GROUPS, equality=True) + check_greater_than('num_delayed_groups', num_delayed_groups, 0, + equality=True) + self._num_delayed_groups = num_delayed_groups + @property def representation(self): return self._representation + @representation.setter + def representation(self, representation): + + check_value('representation', representation, _REPRESENTATIONS) + self._representation = representation + @property def atomic_weight_ratio(self): return self._atomic_weight_ratio + @atomic_weight_ratio.setter + def atomic_weight_ratio(self, atomic_weight_ratio): + + check_type('atomic_weight_ratio', atomic_weight_ratio, Real) + check_greater_than('atomic_weight_ratio', atomic_weight_ratio, 0.0) + self._atomic_weight_ratio = atomic_weight_ratio + @property def fissionable(self): return self._fissionable @@ -285,22 +324,55 @@ def fissionable(self): def temperatures(self): return self._temperatures + @temperatures.setter + def temperatures(self, temperatures): + + check_iterable_type('temperatures', temperatures, Real) + self._temperatures = np.array(temperatures) + @property def scatter_format(self): return self._scatter_format + @scatter_format.setter + def scatter_format(self, scatter_format): + + check_value('scatter_format', scatter_format, _SCATTER_TYPES) + self._scatter_format = scatter_format + @property def order(self): return self._order + @order.setter + def order(self, order): + + check_type('order', order, Integral) + check_greater_than('order', order, 0, equality=True) + self._order = order + @property def num_polar(self): return self._num_polar + @num_polar.setter + def num_polar(self, num_polar): + + check_type('num_polar', num_polar, Integral) + check_greater_than('num_polar', num_polar, 0) + self._num_polar = num_polar + @property def num_azimuthal(self): return self._num_azimuthal + @num_azimuthal.setter + def num_azimuthal(self, num_azimuthal): + + check_type('num_azimuthal', num_azimuthal, Integral) + check_greater_than('num_azimuthal', num_azimuthal, 0) + self._num_azimuthal = num_azimuthal + @property def total(self): return self._total @@ -402,82 +474,9 @@ def xs_shapes(self): return self._xs_shapes - @name.setter - def name(self, name): - - check_type('name for XSdata', name, str) - self._name = name - - @energy_groups.setter - def energy_groups(self, energy_groups): - - check_type('energy_groups', energy_groups, openmc.mgxs.EnergyGroups) - if energy_groups.group_edges is None: - msg = 'Unable to assign an EnergyGroups object ' \ - 'with uninitialized group edges' - raise ValueError(msg) - - self._energy_groups = energy_groups - - @num_delayed_groups.setter - def num_delayed_groups(self, num_delayed_groups): - - check_type('num_delayed_groups', num_delayed_groups, Integral) - check_less_than('num_delayed_groups', num_delayed_groups, - openmc.mgxs.MAX_DELAYED_GROUPS, equality=True) - check_greater_than('num_delayed_groups', num_delayed_groups, 0, - equality=True) - self._num_delayed_groups = num_delayed_groups - - @representation.setter - def representation(self, representation): - - check_value('representation', representation, _REPRESENTATIONS) - self._representation = representation - - @atomic_weight_ratio.setter - def atomic_weight_ratio(self, atomic_weight_ratio): - - check_type('atomic_weight_ratio', atomic_weight_ratio, Real) - check_greater_than('atomic_weight_ratio', atomic_weight_ratio, 0.0) - self._atomic_weight_ratio = atomic_weight_ratio - - @temperatures.setter - def temperatures(self, temperatures): - - check_iterable_type('temperatures', temperatures, Real) - self._temperatures = np.array(temperatures) - - @scatter_format.setter - def scatter_format(self, scatter_format): - - check_value('scatter_format', scatter_format, _SCATTER_TYPES) - self._scatter_format = scatter_format - - @order.setter - def order(self, order): - - check_type('order', order, Integral) - check_greater_than('order', order, 0, equality=True) - self._order = order - - @num_polar.setter - def num_polar(self, num_polar): - - check_type('num_polar', num_polar, Integral) - check_greater_than('num_polar', num_polar, 0) - self._num_polar = num_polar - - @num_azimuthal.setter - def num_azimuthal(self, num_azimuthal): - - check_type('num_azimuthal', num_azimuthal, Integral) - check_greater_than('num_azimuthal', num_azimuthal, 0) - self._num_azimuthal = num_azimuthal - def add_temperature(self, temperature): """This method re-sizes the attributes of this XSdata object so that it - can accomodate an additional temperature. Note that the set_* methods + can accommodate an additional temperature. Note that the set_* methods will still need to be executed. Parameters @@ -1965,7 +1964,7 @@ def to_hdf5(self, file): grp.attrs['fissionable'] = self.fissionable if self.representation is not None: - grp.attrs['representation'] = np.string_(self.representation) + grp.attrs['representation'] = np.bytes_(self.representation) if self.representation == REPRESENTATION_ANGLE: if self.num_azimuthal is not None: grp.attrs['num_azimuthal'] = self.num_azimuthal @@ -1973,9 +1972,9 @@ def to_hdf5(self, file): if self.num_polar is not None: grp.attrs['num_polar'] = self.num_polar - grp.attrs['scatter_shape'] = np.string_("[G][G'][Order]") + grp.attrs['scatter_shape'] = np.bytes_("[G][G'][Order]") if self.scatter_format is not None: - grp.attrs['scatter_format'] = np.string_(self.scatter_format) + grp.attrs['scatter_format'] = np.bytes_(self.scatter_format) if self.order is not None: grp.attrs['order'] = self.order @@ -2331,23 +2330,15 @@ def __deepcopy__(self, memo): def energy_groups(self): return self._energy_groups - @property - def num_delayed_groups(self): - return self._num_delayed_groups - - @property - def xsdatas(self): - return self._xsdatas - - @property - def names(self): - return [xsdata.name for xsdata in self.xsdatas] - @energy_groups.setter def energy_groups(self, energy_groups): check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) self._energy_groups = energy_groups + @property + def num_delayed_groups(self): + return self._num_delayed_groups + @num_delayed_groups.setter def num_delayed_groups(self, num_delayed_groups): check_type('num_delayed_groups', num_delayed_groups, Integral) @@ -2357,6 +2348,14 @@ def num_delayed_groups(self, num_delayed_groups): openmc.mgxs.MAX_DELAYED_GROUPS, equality=True) self._num_delayed_groups = num_delayed_groups + @property + def xsdatas(self): + return self._xsdatas + + @property + def names(self): + return [xsdata.name for xsdata in self.xsdatas] + def add_xsdata(self, xsdata): """Add an XSdata entry to the file. @@ -2368,8 +2367,8 @@ def add_xsdata(self, xsdata): """ if not isinstance(xsdata, XSdata): - msg = 'Unable to add a non-XSdata "{0}" to the ' \ - 'MGXSLibrary instance'.format(xsdata) + msg = f'Unable to add a non-XSdata "{xsdata}" to the ' \ + 'MGXSLibrary instance' raise ValueError(msg) if xsdata.energy_groups != self._energy_groups: @@ -2404,8 +2403,8 @@ def remove_xsdata(self, xsdata): """ if not isinstance(xsdata, XSdata): - msg = 'Unable to remove a non-XSdata "{0}" from the ' \ - 'MGXSLibrary instance'.format(xsdata) + msg = f'Unable to remove a non-XSdata "{xsdata}" from the ' \ + 'MGXSLibrary instance' raise ValueError(msg) self._xsdatas.remove(xsdata) @@ -2517,7 +2516,7 @@ def export_to_hdf5(self, filename='mgxs.h5', libver='earliest'): # Create and write to the HDF5 file file = h5py.File(filename, "w", libver=libver) - file.attrs['filetype'] = np.string_(_FILETYPE_MGXS_LIBRARY) + file.attrs['filetype'] = np.bytes_(_FILETYPE_MGXS_LIBRARY) file.attrs['version'] = [_VERSION_MGXS_LIBRARY, 0] file.attrs['energy_groups'] = self.energy_groups.num_groups file.attrs['delayed_groups'] = self.num_delayed_groups @@ -2536,8 +2535,7 @@ def from_hdf5(cls, filename=None): ---------- filename : str, optional Name of HDF5 file containing MGXS data. Default is None. - If not provided, the value of the OPENMC_MG_CROSS_SECTIONS - environmental variable will be used + If not provided, openmc.config['mg_cross_sections'] will be used. Returns ------- @@ -2545,15 +2543,14 @@ def from_hdf5(cls, filename=None): Multi-group cross section data object. """ - # If filename is None, get the cross sections from the - # OPENMC_CROSS_SECTIONS environment variable + # If filename is None, get the cross sections from openmc.config if filename is None: - filename = os.environ.get('OPENMC_MG_CROSS_SECTIONS') + filename = openmc.config.get('mg_cross_sections') # Check to make sure there was an environmental variable. if filename is None: - raise ValueError("Either path or OPENMC_MG_CROSS_SECTIONS " - "environmental variable must be set") + raise ValueError("Either path or openmc.config['mg_cross_sections']" + "must be set") check_type('filename', filename, str) file = h5py.File(filename, 'r') diff --git a/openmc/mixin.py b/openmc/mixin.py index dc2e91f51a1..31c26ec7603 100644 --- a/openmc/mixin.py +++ b/openmc/mixin.py @@ -14,8 +14,11 @@ class EqualityMixin: def __eq__(self, other): if isinstance(other, type(self)): for key, value in self.__dict__.items(): - if not np.array_equal(value, other.__dict__.get(key)): - return False + if isinstance(value, np.ndarray): + if not np.array_equal(value, other.__dict__.get(key)): + return False + else: + return value == other.__dict__.get(key) else: return False @@ -60,11 +63,10 @@ def id(self, uid): cls.used_ids.add(cls.next_id) else: name = cls.__name__ - cv.check_type('{} ID'.format(name), uid, Integral) - cv.check_greater_than('{} ID'.format(name), uid, 0, equality=True) + cv.check_type(f'{name} ID', uid, Integral) + cv.check_greater_than(f'{name} ID', uid, 0, equality=True) if uid in cls.used_ids: - msg = 'Another {} instance already exists with id={}.'.format( - name, uid) + msg = f'Another {name} instance already exists with id={uid}.' warn(msg, IDWarning) else: cls.used_ids.add(uid) diff --git a/openmc/model/funcs.py b/openmc/model/funcs.py index 53f3a4b2abb..41aa920eae7 100644 --- a/openmc/model/funcs.py +++ b/openmc/model/funcs.py @@ -1,16 +1,12 @@ from collections.abc import Iterable -from functools import partial from math import sqrt -from numbers import Real from operator import attrgetter from warnings import warn -from openmc import ( - XPlane, YPlane, Plane, ZCylinder, Cylinder, XCylinder, - YCylinder, Universe, Cell) -from ..checkvalue import ( - check_type, check_value, check_length, check_less_than, - check_iterable_type) +from openmc import Cylinder, Universe, Cell +from .surface_composite import RectangularPrism, HexagonalPrism +from ..checkvalue import (check_type, check_value, check_length, + check_less_than, check_iterable_type) import openmc.data @@ -111,271 +107,26 @@ def borated_water(boron_ppm, temperature=293., pressure=0.1013, temp_unit='K', return out -def rectangular_prism(width, height, axis='z', origin=(0., 0.), - boundary_type='transmission', corner_radius=0.): - """Get an infinite rectangular prism from four planar surfaces. - - .. versionchanged:: 0.11 - This function was renamed from `get_rectangular_prism` to - `rectangular_prism`. - - Parameters - ---------- - width: float - Prism width in units of cm. The width is aligned with the y, x, - or x axes for prisms parallel to the x, y, or z axis, respectively. - height: float - Prism height in units of cm. The height is aligned with the z, z, - or y axes for prisms parallel to the x, y, or z axis, respectively. - axis : {'x', 'y', 'z'} - Axis with which the infinite length of the prism should be aligned. - Defaults to 'z'. - origin: Iterable of two floats - Origin of the prism. The two floats correspond to (y,z), (x,z) or - (x,y) for prisms parallel to the x, y or z axis, respectively. - Defaults to (0., 0.). - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'} - Boundary condition that defines the behavior for particles hitting the - surfaces comprising the rectangular prism (default is 'transmission'). - corner_radius: float - Prism corner radius in units of cm. Defaults to 0. - - Returns - ------- - openmc.Region - The inside of a rectangular prism - - """ - - check_type('width', width, Real) - check_type('height', height, Real) - check_type('corner_radius', corner_radius, Real) - check_value('axis', axis, ['x', 'y', 'z']) - check_type('origin', origin, Iterable, Real) - - # Define function to create a plane on given axis - def plane(axis, name, value): - cls = globals()['{}Plane'.format(axis.upper())] - return cls(name='{} {}'.format(name, axis), - boundary_type=boundary_type, - **{axis + '0': value}) - - if axis == 'x': - x1, x2 = 'y', 'z' - elif axis == 'y': - x1, x2 = 'x', 'z' - else: - x1, x2 = 'x', 'y' - - # Get cylinder class corresponding to given axis - cyl = globals()['{}Cylinder'.format(axis.upper())] - - # Create rectangular region - min_x1 = plane(x1, 'minimum', -width/2 + origin[0]) - max_x1 = plane(x1, 'maximum', width/2 + origin[0]) - min_x2 = plane(x2, 'minimum', -height/2 + origin[1]) - max_x2 = plane(x2, 'maximum', height/2 + origin[1]) - if boundary_type == 'periodic': - min_x1.periodic_surface = max_x1 - min_x2.periodic_surface = max_x2 - prism = +min_x1 & -max_x1 & +min_x2 & -max_x2 - - # Handle rounded corners if given - if corner_radius > 0.: - if boundary_type == 'periodic': - raise ValueError('Periodic boundary conditions not permitted when ' - 'rounded corners are used.') - - args = {'R': corner_radius, 'boundary_type': boundary_type} - - args[x1 + '0'] = origin[0] - width/2 + corner_radius - args[x2 + '0'] = origin[1] - height/2 + corner_radius - x1_min_x2_min = cyl(name='{} min {} min'.format(x1, x2), **args) - - args[x1 + '0'] = origin[0] - width/2 + corner_radius - args[x2 + '0'] = origin[1] - height/2 + corner_radius - x1_min_x2_min = cyl(name='{} min {} min'.format(x1, x2), **args) - - args[x1 + '0'] = origin[0] - width/2 + corner_radius - args[x2 + '0'] = origin[1] + height/2 - corner_radius - x1_min_x2_max = cyl(name='{} min {} max'.format(x1, x2), **args) - args[x1 + '0'] = origin[0] + width/2 - corner_radius - args[x2 + '0'] = origin[1] - height/2 + corner_radius - x1_max_x2_min = cyl(name='{} max {} min'.format(x1, x2), **args) - args[x1 + '0'] = origin[0] + width/2 - corner_radius - args[x2 + '0'] = origin[1] + height/2 - corner_radius - x1_max_x2_max = cyl(name='{} max {} max'.format(x1, x2), **args) - - x1_min = plane(x1, 'min', -width/2 + origin[0] + corner_radius) - x1_max = plane(x1, 'max', width/2 + origin[0] - corner_radius) - x2_min = plane(x2, 'min', -height/2 + origin[1] + corner_radius) - x2_max = plane(x2, 'max', height/2 + origin[1] - corner_radius) - - corners = (+x1_min_x2_min & -x1_min & -x2_min) | \ - (+x1_min_x2_max & -x1_min & +x2_max) | \ - (+x1_max_x2_min & +x1_max & -x2_min) | \ - (+x1_max_x2_max & +x1_max & +x2_max) - - prism = prism & ~corners - - return prism - - -def get_rectangular_prism(*args, **kwargs): - warn("get_rectangular_prism(...) has been renamed rectangular_prism(...). " - "Future versions of OpenMC will not accept get_rectangular_prism.", - FutureWarning) - return rectangular_prism(*args, **kwargs) +def rectangular_prism(width, height, axis='z', origin=(0., 0.), + boundary_type='transmission', corner_radius=0.): + warn("The rectangular_prism(...) function has been replaced by the " + "RectangularPrism(...) class. Future versions of OpenMC will not " + "accept rectangular_prism.", FutureWarning) + return -RectangularPrism( + width=width, height=height, axis=axis, origin=origin, + boundary_type=boundary_type, corner_radius=corner_radius) def hexagonal_prism(edge_length=1., orientation='y', origin=(0., 0.), boundary_type='transmission', corner_radius=0.): - """Create a hexagon region from six surface planes. - - .. versionchanged:: 0.11 - This function was renamed from `get_hexagonal_prism` to - `hexagonal_prism`. - - Parameters - ---------- - edge_length : float - Length of a side of the hexagon in cm - orientation : {'x', 'y'} - An 'x' orientation means that two sides of the hexagon are parallel to - the x-axis and a 'y' orientation means that two sides of the hexagon are - parallel to the y-axis. - origin: Iterable of two floats - Origin of the prism. Defaults to (0., 0.). - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'} - Boundary condition that defines the behavior for particles hitting the - surfaces comprising the hexagonal prism (default is 'transmission'). - corner_radius: float - Prism corner radius in units of cm. Defaults to 0. - - Returns - ------- - openmc.Region - The inside of a hexagonal prism - - """ - - l = edge_length - x, y = origin - - if orientation == 'y': - right = XPlane(x + sqrt(3.)/2*l, boundary_type=boundary_type) - left = XPlane(x - sqrt(3.)/2*l, boundary_type=boundary_type) - c = sqrt(3.)/3. - - # y = -x/sqrt(3) + a - upper_right = Plane(a=c, b=1., d=l+x*c+y, boundary_type=boundary_type) - - # y = x/sqrt(3) + a - upper_left = Plane(a=-c, b=1., d=l-x*c+y, boundary_type=boundary_type) - - # y = x/sqrt(3) - a - lower_right = Plane(a=-c, b=1., d=-l-x*c+y, boundary_type=boundary_type) - - # y = -x/sqrt(3) - a - lower_left = Plane(a=c, b=1., d=-l+x*c+y, boundary_type=boundary_type) - - prism = -right & +left & -upper_right & -upper_left & \ - +lower_right & +lower_left - - if boundary_type == 'periodic': - right.periodic_surface = left - upper_right.periodic_surface = lower_left - lower_right.periodic_surface = upper_left - - elif orientation == 'x': - top = YPlane(y0=y + sqrt(3.)/2*l, boundary_type=boundary_type) - bottom = YPlane(y0=y - sqrt(3.)/2*l, boundary_type=boundary_type) - c = sqrt(3.) - - # y = -sqrt(3)*(x - a) - upper_right = Plane(a=c, b=1., d=c*l+x*c+y, boundary_type=boundary_type) - - # y = sqrt(3)*(x + a) - lower_right = Plane(a=-c, b=1., d=-c*l-x*c+y, - boundary_type=boundary_type) - - # y = -sqrt(3)*(x + a) - lower_left = Plane(a=c, b=1., d=-c*l+x*c+y, boundary_type=boundary_type) - - # y = sqrt(3)*(x + a) - upper_left = Plane(a=-c, b=1., d=c*l-x*c+y, boundary_type=boundary_type) - - prism = -top & +bottom & -upper_right & +lower_right & \ - +lower_left & -upper_left - - if boundary_type == 'periodic': - top.periodic_surface = bottom - upper_right.periodic_surface = lower_left - lower_right.periodic_surface = upper_left - - # Handle rounded corners if given - if corner_radius > 0.: - if boundary_type == 'periodic': - raise ValueError('Periodic boundary conditions not permitted when ' - 'rounded corners are used.') - - c = sqrt(3.)/2 - t = l - corner_radius/c - - # Cylinder with corner radius and boundary type pre-applied - cyl1 = partial(ZCylinder, r=corner_radius, boundary_type=boundary_type) - cyl2 = partial(ZCylinder, r=corner_radius/(2*c), - boundary_type=boundary_type) - - if orientation == 'x': - x_min_y_min_in = cyl1(name='x min y min in', x0=x-t/2, y0=y-c*t) - x_min_y_max_in = cyl1(name='x min y max in', x0=x+t/2, y0=y-c*t) - x_max_y_min_in = cyl1(name='x max y min in', x0=x-t/2, y0=y+c*t) - x_max_y_max_in = cyl1(name='x max y max in', x0=x+t/2, y0=y+c*t) - x_min_in = cyl1(name='x min in', x0=x-t, y0=y) - x_max_in = cyl1(name='x max in', x0=x+t, y0=y) - - x_min_y_min_out = cyl2(name='x min y min out', x0=x-l/2, y0=y-c*l) - x_min_y_max_out = cyl2(name='x min y max out', x0=x+l/2, y0=y-c*l) - x_max_y_min_out = cyl2(name='x max y min out', x0=x-l/2, y0=y+c*l) - x_max_y_max_out = cyl2(name='x max y max out', x0=x+l/2, y0=y+c*l) - x_min_out = cyl2(name='x min out', x0=x-l, y0=y) - x_max_out = cyl2(name='x max out', x0=x+l, y0=y) - - corners = (+x_min_y_min_in & -x_min_y_min_out | - +x_min_y_max_in & -x_min_y_max_out | - +x_max_y_min_in & -x_max_y_min_out | - +x_max_y_max_in & -x_max_y_max_out | - +x_min_in & -x_min_out | - +x_max_in & -x_max_out) - - elif orientation == 'y': - x_min_y_min_in = cyl1(name='x min y min in', x0=x-c*t, y0=y-t/2) - x_min_y_max_in = cyl1(name='x min y max in', x0=x-c*t, y0=y+t/2) - x_max_y_min_in = cyl1(name='x max y min in', x0=x+c*t, y0=y-t/2) - x_max_y_max_in = cyl1(name='x max y max in', x0=x+c*t, y0=y+t/2) - y_min_in = cyl1(name='y min in', x0=x, y0=y-t) - y_max_in = cyl1(name='y max in', x0=x, y0=y+t) - - x_min_y_min_out = cyl2(name='x min y min out', x0=x-c*l, y0=y-l/2) - x_min_y_max_out = cyl2(name='x min y max out', x0=x-c*l, y0=y+l/2) - x_max_y_min_out = cyl2(name='x max y min out', x0=x+c*l, y0=y-l/2) - x_max_y_max_out = cyl2(name='x max y max out', x0=x+c*l, y0=y+l/2) - y_min_out = cyl2(name='y min out', x0=x, y0=y-l) - y_max_out = cyl2(name='y max out', x0=x, y0=y+l) - - corners = (+x_min_y_min_in & -x_min_y_min_out | - +x_min_y_max_in & -x_min_y_max_out | - +x_max_y_min_in & -x_max_y_min_out | - +x_max_y_max_in & -x_max_y_max_out | - +y_min_in & -y_min_out | - +y_max_in & -y_max_out) - - prism = prism & ~corners - - return prism + warn("The hexagonal_prism(...) function has been replaced by the " + "HexagonalPrism(...) class. Future versions of OpenMC will not " + "accept hexagonal_prism.", FutureWarning) + return -HexagonalPrism( + edge_length=edge_length, orientation=orientation, origin=origin, + boundary_type=boundary_type, corner_radius=corner_radius) def get_hexagonal_prism(*args, **kwargs): @@ -462,16 +213,15 @@ def pin(surfaces, items, subdivisions=None, divide_vols=True, check_iterable_type("surfaces", surfaces[1:], surf_type) # Check for increasing radii and equal centers - if surf_type is ZCylinder: + if surf_type is openmc.ZCylinder: center_getter = attrgetter("x0", "y0") - elif surf_type is YCylinder: + elif surf_type is openmc.YCylinder: center_getter = attrgetter("x0", "z0") - elif surf_type is XCylinder: + elif surf_type is openmc.XCylinder: center_getter = attrgetter("z0", "y0") else: raise TypeError( - "Not configured to interpret {} surfaces".format( - surf_type.__name__)) + f"Not configured to interpret {surf_type.__name__} surfaces") centers = set() prev_rad = 0 diff --git a/openmc/model/model.py b/openmc/model/model.py index 7d6acb281ce..2160c97e6cc 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -1,9 +1,23 @@ +from __future__ import annotations from collections.abc import Iterable +from functools import lru_cache +import os from pathlib import Path -import time +from numbers import Integral +from tempfile import NamedTemporaryFile +import warnings +from typing import Optional, Dict + +import h5py +import lxml.etree as ET import openmc -from openmc.checkvalue import check_type, check_value +import openmc._xml as xml +from openmc.dummy_comm import DummyCommunicator +from openmc.executor import _process_CLI_arguments +from openmc.checkvalue import check_type, check_value, PathLike +from openmc.exceptions import InvalidIDError +from openmc.utility_funcs import change_directory class Model: @@ -11,11 +25,15 @@ class Model: This class can be used to store instances of :class:`openmc.Geometry`, :class:`openmc.Materials`, :class:`openmc.Settings`, - :class:`openmc.Tallies`, :class:`openmc.Plots`, and :class:`openmc.CMFD`, - thus making a complete model. The :meth:`Model.export_to_xml` method will - export XML files for all attributes that have been set. If the - :meth:`Model.materials` attribute is not set, it will attempt to create a - ``materials.xml`` file based on all materials appearing in the geometry. + :class:`openmc.Tallies`, and :class:`openmc.Plots`, thus making a complete + model. The :meth:`Model.export_to_xml` method will export XML files for all + attributes that have been set. If the :attr:`Model.materials` attribute is + not set, it will attempt to create a ``materials.xml`` file based on all + materials appearing in the geometry. + + .. versionchanged:: 0.13.0 + The model information can now be loaded in to OpenMC directly via + openmc.lib Parameters ---------- @@ -65,30 +83,18 @@ def __init__(self, geometry=None, materials=None, settings=None, self.plots = plots @property - def geometry(self): + def geometry(self) -> Optional[openmc.Geometry]: return self._geometry - @property - def materials(self): - return self._materials - - @property - def settings(self): - return self._settings - - @property - def tallies(self): - return self._tallies - - @property - def plots(self): - return self._plots - @geometry.setter def geometry(self, geometry): check_type('geometry', geometry, openmc.Geometry) self._geometry = geometry + @property + def materials(self) -> Optional[openmc.Materials]: + return self._materials + @materials.setter def materials(self, materials): check_type('materials', materials, Iterable, openmc.Material) @@ -99,11 +105,19 @@ def materials(self, materials): for mat in materials: self._materials.append(mat) + @property + def settings(self) -> Optional[openmc.Settings]: + return self._settings + @settings.setter def settings(self, settings): check_type('settings', settings, openmc.Settings) self._settings = settings + @property + def tallies(self) -> Optional[openmc.Tallies]: + return self._tallies + @tallies.setter def tallies(self, tallies): check_type('tallies', tallies, Iterable, openmc.Tally) @@ -114,6 +128,10 @@ def tallies(self, tallies): for tally in tallies: self._tallies.append(tally) + @property + def plots(self) -> Optional[openmc.Plots]: + return self._plots + @plots.setter def plots(self, plots): check_type('plots', plots, Iterable, openmc.Plot) @@ -124,63 +142,305 @@ def plots(self, plots): for plot in plots: self._plots.append(plot) - def deplete(self, timesteps, chain_file=None, method='cecm', - fission_q=None, **kwargs): + @property + def is_initialized(self) -> bool: + try: + import openmc.lib + return openmc.lib.is_initialized + except ImportError: + return False + + @property + @lru_cache(maxsize=None) + def _materials_by_id(self) -> dict: + """Dictionary mapping material ID --> material""" + if self.materials: + mats = self.materials + else: + mats = self.geometry.get_all_materials().values() + return {mat.id: mat for mat in mats} + + @property + @lru_cache(maxsize=None) + def _cells_by_id(self) -> dict: + """Dictionary mapping cell ID --> cell""" + cells = self.geometry.get_all_cells() + return {cell.id: cell for cell in cells.values()} + + @property + @lru_cache(maxsize=None) + def _cells_by_name(self) -> Dict[int, openmc.Cell]: + # Get the names maps, but since names are not unique, store a set for + # each name key. In this way when the user requests a change by a name, + # the change will be applied to all of the same name. + result = {} + for cell in self.geometry.get_all_cells().values(): + if cell.name not in result: + result[cell.name] = set() + result[cell.name].add(cell) + return result + + @property + @lru_cache(maxsize=None) + def _materials_by_name(self) -> Dict[int, openmc.Material]: + if self.materials is None: + mats = self.geometry.get_all_materials().values() + else: + mats = self.materials + result = {} + for mat in mats: + if mat.name not in result: + result[mat.name] = set() + result[mat.name].add(mat) + return result + + @classmethod + def from_xml(cls, geometry='geometry.xml', materials='materials.xml', + settings='settings.xml', tallies='tallies.xml', + plots='plots.xml') -> Model: + """Create model from existing XML files + + Parameters + ---------- + geometry : str + Path to geometry.xml file + materials : str + Path to materials.xml file + settings : str + Path to settings.xml file + tallies : str + Path to tallies.xml file + + .. versionadded:: 0.13.0 + plots : str + Path to plots.xml file + + .. versionadded:: 0.13.0 + + Returns + ------- + openmc.model.Model + Model created from XML files + + """ + materials = openmc.Materials.from_xml(materials) + geometry = openmc.Geometry.from_xml(geometry, materials) + settings = openmc.Settings.from_xml(settings) + tallies = openmc.Tallies.from_xml(tallies) if Path(tallies).exists() else None + plots = openmc.Plots.from_xml(plots) if Path(plots).exists() else None + return cls(geometry, materials, settings, tallies, plots) + + @classmethod + def from_model_xml(cls, path='model.xml'): + """Create model from single XML file + + .. versionadded:: 0.13.3 + + Parameters + ---------- + path : str or PathLike + Path to model.xml file + """ + parser = ET.XMLParser(huge_tree=True) + tree = ET.parse(path, parser=parser) + root = tree.getroot() + + model = cls() + + meshes = {} + model.settings = openmc.Settings.from_xml_element(root.find('settings'), meshes) + model.materials = openmc.Materials.from_xml_element(root.find('materials')) + model.geometry = openmc.Geometry.from_xml_element(root.find('geometry'), model.materials) + + if root.find('tallies') is not None: + model.tallies = openmc.Tallies.from_xml_element(root.find('tallies'), meshes) + + if root.find('plots') is not None: + model.plots = openmc.Plots.from_xml_element(root.find('plots')) + + return model + + def init_lib(self, threads=None, geometry_debug=False, restart_file=None, + tracks=False, output=True, event_based=None, intracomm=None): + """Initializes the model in memory via the C API + + .. versionadded:: 0.13.0 + + Parameters + ---------- + threads : int, optional + Number of OpenMP threads. If OpenMC is compiled with OpenMP + threading enabled, the default is implementation-dependent but is + usually equal to the number of hardware threads available + (or a value set by the :envvar:`OMP_NUM_THREADS` environment + variable). + geometry_debug : bool, optional + Turn on geometry debugging during simulation. Defaults to False. + restart_file : str, optional + Path to restart file to use + tracks : bool, optional + Enables the writing of particles tracks. The number of particle + tracks written to tracks.h5 is limited to 1000 unless + Settings.max_tracks is set. Defaults to False. + output : bool + Capture OpenMC output from standard out + event_based : None or bool, optional + Turns on event-based parallelism if True. If None, the value in + the Settings will be used. + intracomm : mpi4py.MPI.Intracomm or None, optional + MPI intracommunicator + """ + + import openmc.lib + + # TODO: right now the only way to set most of the above parameters via + # the C API are at initialization time despite use-cases existing to + # set them for individual runs. For now this functionality is exposed + # where it exists (here in init), but in the future the functionality + # should be exposed so that it can be accessed via model.run(...) + + args = _process_CLI_arguments( + volume=False, geometry_debug=geometry_debug, + restart_file=restart_file, threads=threads, tracks=tracks, + event_based=event_based) + # Args adds the openmc_exec command in the first entry; remove it + args = args[1:] + + self.finalize_lib() + + # The Model object needs to be aware of the communicator so it can + # use it in certain cases, therefore lets store the communicator + if intracomm is not None: + self._intracomm = intracomm + else: + self._intracomm = DummyCommunicator() + + if self._intracomm.rank == 0: + self.export_to_xml() + self._intracomm.barrier() + + # We cannot pass DummyCommunicator to openmc.lib.init so pass instead + # the user-provided intracomm which will either be None or an mpi4py + # communicator + openmc.lib.init(args=args, intracomm=intracomm, output=output) + + def finalize_lib(self): + """Finalize simulation and free memory allocated for the C API + + .. versionadded:: 0.13.0 + + """ + + import openmc.lib + + openmc.lib.finalize() + + def deplete(self, timesteps, method='cecm', final_step=True, + operator_kwargs=None, directory='.', output=True, + **integrator_kwargs): """Deplete model using specified timesteps/power + .. versionchanged:: 0.13.0 + The *final_step*, *operator_kwargs*, *directory*, and *output* + arguments were added. + Parameters ---------- timesteps : iterable of float Array of timesteps in units of [s]. Note that values are not cumulative. - chain_file : str, optional - Path to the depletion chain XML file. Defaults to the chain - found under the ``depletion_chain`` in the - :envvar:`OPENMC_CROSS_SECTIONS` environment variable if it exists. - method : str - Integration method used for depletion (e.g., 'cecm', 'predictor') - fission_q : dict, optional - Dictionary of nuclides and their fission Q values [eV]. - If not given, values will be pulled from the ``chain_file``. - **kwargs - Keyword arguments passed to integration function (e.g., - :func:`openmc.deplete.integrator.cecm`) - - """ - # Import the depletion module. This is done here rather than the module - # header to delay importing openmc.lib (through openmc.deplete) which - # can be tough to install properly. + method : str, optional + Integration method used for depletion (e.g., 'cecm', 'predictor'). + Defaults to 'cecm'. + final_step : bool, optional + Indicate whether or not a transport solve should be run at the end + of the last timestep. Defaults to running this transport solve. + operator_kwargs : dict + Keyword arguments passed to the depletion operator initializer + (e.g., :func:`openmc.deplete.Operator`) + directory : str, optional + Directory to write XML files to. If it doesn't exist already, it + will be created. Defaults to the current working directory + output : bool + Capture OpenMC output from standard out + integrator_kwargs : dict + Remaining keyword arguments passed to the depletion Integrator + initializer (e.g., :func:`openmc.deplete.integrator.cecm`). + + """ + + if operator_kwargs is None: + op_kwargs = {} + elif isinstance(operator_kwargs, dict): + op_kwargs = operator_kwargs + else: + raise ValueError("operator_kwargs must be a dict or None") + + # Import openmc.deplete here so the Model can be used even if the + # shared library is unavailable. import openmc.deplete as dep - # Create OpenMC transport operator - op = dep.Operator( - self.geometry, self.settings, chain_file, - fission_q=fission_q, - ) + # Store whether or not the library was initialized when we started + started_initialized = self.is_initialized + + with change_directory(directory): + with openmc.lib.quiet_dll(output): + # TODO: Support use of IndependentOperator too + depletion_operator = dep.CoupledOperator(self, **op_kwargs) - # Perform depletion - check_value('method', method, ('cecm', 'predictor', 'cf4', 'epc_rk4', - 'si_celi', 'si_leqi', 'celi', 'leqi')) - getattr(dep.integrator, method)(op, timesteps, **kwargs) + # Tell depletion_operator.finalize NOT to clear C API memory when + # it is done + depletion_operator.cleanup_when_done = False - def export_to_xml(self, directory='.'): - """Export model to XML files. + # Set up the integrator + check_value('method', method, + dep.integrators.integrator_by_name.keys()) + integrator_class = dep.integrators.integrator_by_name[method] + integrator = integrator_class(depletion_operator, timesteps, + **integrator_kwargs) + + # Now perform the depletion + with openmc.lib.quiet_dll(output): + integrator.integrate(final_step) + + # Now make the python Materials match the C API material data + for mat_id, mat in self._materials_by_id.items(): + if mat.depletable: + # Get the C data + c_mat = openmc.lib.materials[mat_id] + nuclides, densities = c_mat._get_densities() + # And now we can remove isotopes and add these ones in + mat.nuclides.clear() + for nuc, density in zip(nuclides, densities): + mat.add_nuclide(nuc, density) + mat.set_density('atom/b-cm', sum(densities)) + + # If we didnt start intialized, we should cleanup after ourselves + if not started_initialized: + depletion_operator.cleanup_when_done = True + depletion_operator.finalize() + + def export_to_xml(self, directory='.', remove_surfs=False): + """Export model to separate XML files. Parameters ---------- directory : str Directory to write XML files to. If it doesn't exist already, it will be created. + remove_surfs : bool + Whether or not to remove redundant surfaces from the geometry when + exporting. + .. versionadded:: 0.13.1 """ # Create directory if required d = Path(directory) if not d.is_dir(): - d.mkdir(parents=True) + d.mkdir(parents=True, exist_ok=True) self.settings.export_to_xml(d) - if not self.settings.dagmc: - self.geometry.export_to_xml(d) + self.geometry.export_to_xml(d, remove_surfs=remove_surfs) # If a materials collection was specified, export it. Otherwise, look # for all materials in the geometry and use that to automatically build @@ -197,44 +457,610 @@ def export_to_xml(self, directory='.'): if self.plots: self.plots.export_to_xml(d) - def run(self, **kwargs): - """Creates the XML files, runs OpenMC, and returns the path to the last - statepoint file generated. + def export_to_model_xml(self, path='model.xml', remove_surfs=False): + """Export model to a single XML file. + + .. versionadded:: 0.13.3 + + Parameters + ---------- + path : str or PathLike + Location of the XML file to write (default is 'model.xml'). Can be a + directory or file path. + remove_surfs : bool + Whether or not to remove redundant surfaces from the geometry when + exporting. + + """ + xml_path = Path(path) + # if the provided path doesn't end with the XML extension, assume the + # input path is meant to be a directory. If the directory does not + # exist, create it and place a 'model.xml' file there. + if not str(xml_path).endswith('.xml'): + if not xml_path.exists(): + xml_path.mkdir(parents=True, exist_ok=True) + elif not xml_path.is_dir(): + raise FileExistsError(f"File exists and is not a directory: '{xml_path}'") + xml_path /= 'model.xml' + # if this is an XML file location and the file's parent directory does + # not exist, create it before continuing + elif not xml_path.parent.exists(): + xml_path.parent.mkdir(parents=True, exist_ok=True) + + if remove_surfs: + warnings.warn("remove_surfs kwarg will be deprecated soon, please " + "set the Geometry.merge_surfaces attribute instead.") + self.geometry.merge_surfaces = True + + # provide a memo to track which meshes have been written + mesh_memo = set() + settings_element = self.settings.to_xml_element(mesh_memo) + geometry_element = self.geometry.to_xml_element() + + xml.clean_indentation(geometry_element, level=1) + xml.clean_indentation(settings_element, level=1) + + # If a materials collection was specified, export it. Otherwise, look + # for all materials in the geometry and use that to automatically build + # a collection. + if self.materials: + materials = self.materials + else: + materials = openmc.Materials(self.geometry.get_all_materials() + .values()) + + with open(xml_path, 'w', encoding='utf-8', errors='xmlcharrefreplace') as fh: + # write the XML header + fh.write("\n") + fh.write("\n") + # Write the materials collection to the open XML file first. + # This will write the XML header also + materials._write_xml(fh, False, level=1) + # Write remaining elements as a tree + fh.write(ET.tostring(geometry_element, encoding="unicode")) + fh.write(ET.tostring(settings_element, encoding="unicode")) + + if self.tallies: + tallies_element = self.tallies.to_xml_element(mesh_memo) + xml.clean_indentation(tallies_element, level=1, trailing_indent=self.plots) + fh.write(ET.tostring(tallies_element, encoding="unicode")) + if self.plots: + plots_element = self.plots.to_xml_element() + xml.clean_indentation(plots_element, level=1, trailing_indent=False) + fh.write(ET.tostring(plots_element, encoding="unicode")) + fh.write("\n") + + def import_properties(self, filename): + """Import physical properties + + .. versionchanged:: 0.13.0 + This method now updates values as loaded in memory with the C API + + Parameters + ---------- + filename : str + Path to properties HDF5 file + + See Also + -------- + openmc.lib.export_properties + + """ + import openmc.lib + + cells = self.geometry.get_all_cells() + materials = self.geometry.get_all_materials() + + with h5py.File(filename, 'r') as fh: + cells_group = fh['geometry/cells'] + + # Make sure number of cells matches + n_cells = fh['geometry'].attrs['n_cells'] + if n_cells != len(cells): + raise ValueError("Number of cells in properties file doesn't " + "match current model.") + + # Update temperatures for cells filled with materials + for name, group in cells_group.items(): + cell_id = int(name.split()[1]) + cell = cells[cell_id] + if cell.fill_type in ('material', 'distribmat'): + temperature = group['temperature'][()] + cell.temperature = temperature + if self.is_initialized: + lib_cell = openmc.lib.cells[cell_id] + if temperature.size > 1: + for i, T in enumerate(temperature): + lib_cell.set_temperature(T, i) + else: + lib_cell.set_temperature(temperature[0]) + + # Make sure number of materials matches + mats_group = fh['materials'] + n_cells = mats_group.attrs['n_materials'] + if n_cells != len(materials): + raise ValueError("Number of materials in properties file " + "doesn't match current model.") + + # Update material densities + for name, group in mats_group.items(): + mat_id = int(name.split()[1]) + atom_density = group.attrs['atom_density'] + materials[mat_id].set_density('atom/b-cm', atom_density) + if self.is_initialized: + C_mat = openmc.lib.materials[mat_id] + C_mat.set_density(atom_density, 'atom/b-cm') + + def run(self, particles=None, threads=None, geometry_debug=False, + restart_file=None, tracks=False, output=True, cwd='.', + openmc_exec='openmc', mpi_args=None, event_based=None, + export_model_xml=True, **export_kwargs): + """Run OpenMC + + If the C API has been initialized, then the C API is used, otherwise, + this method creates the XML files and runs OpenMC via a system call. In + both cases this method returns the path to the last statepoint file + generated. .. versionchanged:: 0.12 Instead of returning the final k-effective value, this function now returns the path to the final statepoint written. + .. versionchanged:: 0.13.0 + This method can utilize the C API for execution + Parameters ---------- - **kwargs - Keyword arguments passed to :func:`openmc.run` + particles : int, optional + Number of particles to simulate per generation. + threads : int, optional + Number of OpenMP threads. If OpenMC is compiled with OpenMP + threading enabled, the default is implementation-dependent but is + usually equal to the number of hardware threads available (or a + value set by the :envvar:`OMP_NUM_THREADS` environment variable). + geometry_debug : bool, optional + Turn on geometry debugging during simulation. Defaults to False. + restart_file : str or PathLike + Path to restart file to use + tracks : bool, optional + Enables the writing of particles tracks. The number of particle + tracks written to tracks.h5 is limited to 1000 unless + Settings.max_tracks is set. Defaults to False. + output : bool, optional + Capture OpenMC output from standard out + cwd : PathLike, optional + Path to working directory to run in. Defaults to the current working + directory. + openmc_exec : str, optional + Path to OpenMC executable. Defaults to 'openmc'. + mpi_args : list of str, optional + MPI execute command and any additional MPI arguments to pass, e.g. + ['mpiexec', '-n', '8']. + event_based : None or bool, optional + Turns on event-based parallelism if True. If None, the value in the + Settings will be used. + export_model_xml : bool, optional + Exports a single model.xml file rather than separate files. Defaults + to True. + + .. versionadded:: 0.13.3 + **export_kwargs + Keyword arguments passed to either :meth:`Model.export_to_model_xml` + or :meth:`Model.export_to_xml`. Returns ------- Path - Path to the last statepoint written by this run - (None if no statepoint was written) + Path to the last statepoint written by this run (None if no + statepoint was written) """ - self.export_to_xml() - - # Setting tstart here ensures we don't pick up any pre-existing statepoint - # files in the output directory - tstart = time.time() + # Setting tstart here ensures we don't pick up any pre-existing + # statepoint files in the output directory -- just in case there are + # differences between the system clock and the filesystem, we get the + # time of a just-created temporary file + with NamedTemporaryFile() as fp: + tstart = Path(fp.name).stat().st_mtime last_statepoint = None - openmc.run(**kwargs) + # Operate in the provided working directory + with change_directory(cwd): + if self.is_initialized: + # Handle the run options as applicable + # First dont allow ones that must be set via init + for arg_name, arg, default in zip( + ['threads', 'geometry_debug', 'restart_file', 'tracks'], + [threads, geometry_debug, restart_file, tracks], + [None, False, None, False] + ): + if arg != default: + msg = f"{arg_name} must be set via Model.is_initialized(...)" + raise ValueError(msg) - # Get output directory and return the last statepoint written by this run - if self.settings.output and 'path' in self.settings.output: - output_dir = Path(self.settings.output['path']) - else: - output_dir = Path.cwd() - for sp in output_dir.glob('statepoint.*.h5'): - mtime = sp.stat().st_mtime - if mtime >= tstart: # >= allows for poor clock resolution - tstart = mtime - last_statepoint = sp + init_particles = openmc.lib.settings.particles + if particles is not None: + if isinstance(particles, Integral) and particles > 0: + openmc.lib.settings.particles = particles + + init_event_based = openmc.lib.settings.event_based + if event_based is not None: + openmc.lib.settings.event_based = event_based + + # Then run using the C API + openmc.lib.run(output) + + # Reset changes for the openmc.run kwargs handling + openmc.lib.settings.particles = init_particles + openmc.lib.settings.event_based = init_event_based + + else: + # Then run via the command line + if export_model_xml: + self.export_to_model_xml(**export_kwargs) + else: + self.export_to_xml(**export_kwargs) + path_input = export_kwargs.get("path", None) + openmc.run(particles, threads, geometry_debug, restart_file, + tracks, output, Path('.'), openmc_exec, mpi_args, + event_based, path_input) + + # Get output directory and return the last statepoint written + if self.settings.output and 'path' in self.settings.output: + output_dir = Path(self.settings.output['path']) + else: + output_dir = Path.cwd() + for sp in output_dir.glob('statepoint.*.h5'): + mtime = sp.stat().st_mtime + if mtime >= tstart: # >= allows for poor clock resolution + tstart = mtime + last_statepoint = sp return last_statepoint + + def calculate_volumes(self, threads=None, output=True, cwd='.', + openmc_exec='openmc', mpi_args=None, + apply_volumes=True): + """Runs an OpenMC stochastic volume calculation and, if requested, + applies volumes to the model + + .. versionadded:: 0.13.0 + + Parameters + ---------- + threads : int, optional + Number of OpenMP threads. If OpenMC is compiled with OpenMP + threading enabled, the default is implementation-dependent but is + usually equal to the number of hardware threads available (or a + value set by the :envvar:`OMP_NUM_THREADS` environment variable). + This currenty only applies to the case when not using the C API. + output : bool, optional + Capture OpenMC output from standard out + openmc_exec : str, optional + Path to OpenMC executable. Defaults to 'openmc'. + This only applies to the case when not using the C API. + mpi_args : list of str, optional + MPI execute command and any additional MPI arguments to pass, + e.g. ['mpiexec', '-n', '8']. + This only applies to the case when not using the C API. + cwd : str, optional + Path to working directory to run in. Defaults to the current + working directory. + apply_volumes : bool, optional + Whether apply the volume calculation results from this calculation + to the model. Defaults to applying the volumes. + """ + + if len(self.settings.volume_calculations) == 0: + # Then there is no volume calculation specified + raise ValueError("The Settings.volume_calculations attribute must" + " be specified before executing this method!") + + with change_directory(cwd): + if self.is_initialized: + if threads is not None: + msg = "Threads must be set via Model.is_initialized(...)" + raise ValueError(msg) + if mpi_args is not None: + msg = "The MPI environment must be set otherwise such as" \ + "with the call to mpi4py" + raise ValueError(msg) + + # Compute the volumes + openmc.lib.calculate_volumes(output) + + else: + self.export_to_xml() + openmc.calculate_volumes(threads=threads, output=output, + openmc_exec=openmc_exec, + mpi_args=mpi_args) + + # Now we apply the volumes + if apply_volumes: + # Load the results and add them to the model + for i, vol_calc in enumerate(self.settings.volume_calculations): + vol_calc.load_results(f"volume_{i + 1}.h5") + # First add them to the Python side + if vol_calc.domain_type == "material" and self.materials: + for material in self.materials: + if material.id in vol_calc.volumes: + material.add_volume_information(vol_calc) + else: + self.geometry.add_volume_information(vol_calc) + + # And now repeat for the C API + if self.is_initialized and vol_calc.domain_type == 'material': + # Then we can do this in the C API + for domain_id in vol_calc.ids: + openmc.lib.materials[domain_id].volume = \ + vol_calc.volumes[domain_id].n + + def plot_geometry(self, output=True, cwd='.', openmc_exec='openmc'): + """Creates plot images as specified by the Model.plots attribute + + .. versionadded:: 0.13.0 + + Parameters + ---------- + output : bool, optional + Capture OpenMC output from standard out + cwd : str, optional + Path to working directory to run in. Defaults to the current + working directory. + openmc_exec : str, optional + Path to OpenMC executable. Defaults to 'openmc'. + This only applies to the case when not using the C API. + + """ + + if len(self.plots) == 0: + # Then there is no volume calculation specified + raise ValueError("The Model.plots attribute must be specified " + "before executing this method!") + + with change_directory(cwd): + if self.is_initialized: + # Compute the volumes + openmc.lib.plot_geometry(output) + else: + self.export_to_xml() + openmc.plot_geometry(output=output, openmc_exec=openmc_exec) + + def _change_py_lib_attribs(self, names_or_ids, value, obj_type, + attrib_name, density_units='atom/b-cm'): + # Method to do the same work whether it is a cell or material and + # a temperature or volume + check_type('names_or_ids', names_or_ids, Iterable, (Integral, str)) + check_type('obj_type', obj_type, str) + obj_type = obj_type.lower() + check_value('obj_type', obj_type, ('material', 'cell')) + check_value('attrib_name', attrib_name, + ('temperature', 'volume', 'density', 'rotation', + 'translation')) + # The C API only allows setting density units of atom/b-cm and g/cm3 + check_value('density_units', density_units, ('atom/b-cm', 'g/cm3')) + # The C API has no way to set cell volume or material temperature + # so lets raise exceptions as needed + if obj_type == 'cell' and attrib_name == 'volume': + raise NotImplementedError( + 'Setting a Cell volume is not supported!') + if obj_type == 'material' and attrib_name == 'temperature': + raise NotImplementedError( + 'Setting a material temperature is not supported!') + + # And some items just dont make sense + if obj_type == 'cell' and attrib_name == 'density': + raise ValueError('Cannot set a Cell density!') + if obj_type == 'material' and attrib_name in ('rotation', + 'translation'): + raise ValueError('Cannot set a material rotation/translation!') + + # Set the + if obj_type == 'cell': + by_name = self._cells_by_name + by_id = self._cells_by_id + if self.is_initialized: + obj_by_id = openmc.lib.cells + else: + by_name = self._materials_by_name + by_id = self._materials_by_id + if self.is_initialized: + obj_by_id = openmc.lib.materials + # Get the list of ids to use if converting from names and accepting + # only values that have actual ids + ids = [] + for name_or_id in names_or_ids: + if isinstance(name_or_id, Integral): + if name_or_id in by_id: + ids.append(int(name_or_id)) + else: + cap_obj = obj_type.capitalize() + msg = f'{cap_obj} ID {name_or_id} " \ + "is not present in the model!' + raise InvalidIDError(msg) + elif isinstance(name_or_id, str): + if name_or_id in by_name: + # Then by_name[name_or_id] is a list so we need to add all + # entries + ids.extend([obj.id for obj in by_name[name_or_id]]) + else: + cap_obj = obj_type.capitalize() + msg = f'{cap_obj} {name_or_id} " \ + "is not present in the model!' + raise InvalidIDError(msg) + + # Now perform the change to both python and C API + for id_ in ids: + obj = by_id[id_] + if attrib_name == 'density': + obj.set_density(density_units, value) + else: + setattr(obj, attrib_name, value) + # Next lets keep what is in C API memory up to date as well + if self.is_initialized: + lib_obj = obj_by_id[id_] + if attrib_name == 'density': + lib_obj.set_density(value, density_units) + elif attrib_name == 'temperature': + lib_obj.set_temperature(value) + else: + setattr(lib_obj, attrib_name, value) + + def rotate_cells(self, names_or_ids, vector): + """Rotate the identified cell(s) by the specified rotation vector. + The rotation is only applied to cells filled with a universe. + + .. note:: If applying this change to a name that is not unique, then + the change will be applied to all objects of that name. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + names_or_ids : Iterable of str or int + The cell names (if str) or id (if int) that are to be translated + or rotated. This parameter can include a mix of names and ids. + vector : Iterable of float + The rotation vector of length 3 to apply. This array specifies the + angles in degrees about the x, y, and z axes, respectively. + + """ + + self._change_py_lib_attribs(names_or_ids, vector, 'cell', 'rotation') + + def translate_cells(self, names_or_ids, vector): + """Translate the identified cell(s) by the specified translation vector. + The translation is only applied to cells filled with a universe. + + .. note:: If applying this change to a name that is not unique, then + the change will be applied to all objects of that name. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + names_or_ids : Iterable of str or int + The cell names (if str) or id (if int) that are to be translated + or rotated. This parameter can include a mix of names and ids. + vector : Iterable of float + The translation vector of length 3 to apply. This array specifies + the x, y, and z dimensions of the translation. + + """ + + self._change_py_lib_attribs(names_or_ids, vector, 'cell', + 'translation') + + def update_densities(self, names_or_ids, density, density_units='atom/b-cm'): + """Update the density of a given set of materials to a new value + + .. note:: If applying this change to a name that is not unique, then + the change will be applied to all objects of that name. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + names_or_ids : Iterable of str or int + The material names (if str) or id (if int) that are to be updated. + This parameter can include a mix of names and ids. + density : float + The density to apply in the units specified by `density_units` + density_units : {'atom/b-cm', 'g/cm3'}, optional + Units for `density`. Defaults to 'atom/b-cm' + + """ + + self._change_py_lib_attribs(names_or_ids, density, 'material', + 'density', density_units) + + def update_cell_temperatures(self, names_or_ids, temperature): + """Update the temperature of a set of cells to the given value + + .. note:: If applying this change to a name that is not unique, then + the change will be applied to all objects of that name. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + names_or_ids : Iterable of str or int + The cell names (if str) or id (if int) that are to be updated. + This parameter can include a mix of names and ids. + temperature : float + The temperature to apply in units of Kelvin + + """ + + self._change_py_lib_attribs(names_or_ids, temperature, 'cell', + 'temperature') + + def update_material_volumes(self, names_or_ids, volume): + """Update the volume of a set of materials to the given value + + .. note:: If applying this change to a name that is not unique, then + the change will be applied to all objects of that name. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + names_or_ids : Iterable of str or int + The material names (if str) or id (if int) that are to be updated. + This parameter can include a mix of names and ids. + volume : float + The volume to apply in units of cm^3 + + """ + + self._change_py_lib_attribs(names_or_ids, volume, 'material', 'volume') + + def differentiate_depletable_mats(self, diff_volume_method: str): + """Assign distribmats for each depletable material + + .. versionadded:: 0.14.0 + + Parameters + ---------- + diff_volume_method : str + Specifies how the volumes of the new materials should be found. + Default is to 'divide equally' which divides the original material + volume equally between the new materials, 'match cell' sets the + volume of the material to volume of the cell they fill. + """ + # Count the number of instances for each cell and material + self.geometry.determine_paths(instances_only=True) + + # Extract all depletable materials which have multiple instances + distribmats = set( + [mat for mat in self.materials + if mat.depletable and mat.num_instances > 1]) + + if diff_volume_method == 'divide equally': + for mat in distribmats: + if mat.volume is None: + raise RuntimeError("Volume not specified for depletable " + f"material with ID={mat.id}.") + mat.volume /= mat.num_instances + + if distribmats: + # Assign distribmats to cells + for cell in self.geometry.get_all_material_cells().values(): + if cell.fill in distribmats: + mat = cell.fill + if diff_volume_method == 'divide equally': + cell.fill = [mat.clone() for _ in range(cell.num_instances)] + elif diff_volume_method == 'match cell': + for _ in range(cell.num_instances): + cell.fill = mat.clone() + if not cell.volume: + raise ValueError( + f"Volume of cell ID={cell.id} not specified. " + "Set volumes of cells prior to using " + "diff_volume_method='match cell'." + ) + cell.fill.volume = cell.volume + + if self.materials is not None: + self.materials = openmc.Materials( + self.geometry.get_all_materials().values() + ) diff --git a/openmc/model/surface_composite.py b/openmc/model/surface_composite.py index 09a3c0170f2..6f9123311fb 100644 --- a/openmc/model/surface_composite.py +++ b/openmc/model/surface_composite.py @@ -1,8 +1,19 @@ from abc import ABC, abstractmethod +from collections.abc import Iterable from copy import copy +from functools import partial +from math import sqrt, pi, sin, cos, isclose +from numbers import Real +import warnings +import operator +from typing import Sequence + +import numpy as np +from scipy.spatial import ConvexHull, Delaunay import openmc -from openmc.checkvalue import check_greater_than, check_value +from openmc.checkvalue import (check_greater_than, check_value, check_less_than, + check_iterable_type, check_length, check_type) class CompositeSurface(ABC): @@ -35,7 +46,7 @@ def boundary_type(self, boundary_type): getattr(self, name).boundary_type = boundary_type def __repr__(self): - return "<{} at 0x{:x}>".format(type(self).__name__, id(self)) + return f"<{type(self).__name__} at 0x{id(self):x}>" @property @abstractmethod @@ -43,12 +54,305 @@ def _surface_names(self): """Iterable of attribute names corresponding to underlying surfaces.""" @abstractmethod - def __pos__(self): + def __neg__(self) -> openmc.Region: + """Return the negative half-space of the composite surface.""" + + def __pos__(self) -> openmc.Region: """Return the positive half-space of the composite surface.""" + return ~(-self) + + +class CylinderSector(CompositeSurface): + """Infinite cylindrical sector composite surface. + + A cylinder sector is composed of two cylindrical and two planar surfaces. + The cylindrical surfaces are concentric, and the planar surfaces intersect + the central axis of the cylindrical surfaces. + + This class acts as a proper surface, meaning that unary `+` and `-` + operators applied to it will produce a half-space. The negative + side is defined to be the region inside of the cylinder sector. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + r1 : float + Inner radius of sector. Must be less than r2. + r2 : float + Outer radius of sector. Must be greater than r1. + theta1 : float + Clockwise-most bound of sector in degrees. Assumed to be in the + counterclockwise direction with respect to the first basis axis + (+y, +z, or +x). Must be less than :attr:`theta2`. + theta2 : float + Counterclockwise-most bound of sector in degrees. Assumed to be in the + counterclockwise direction with respect to the first basis axis + (+y, +z, or +x). Must be greater than :attr:`theta1`. + center : iterable of float + Coordinate for central axes of cylinders in the (y, z), (z, x), or (x, y) + basis. Defaults to (0,0). + axis : {'x', 'y', 'z'} + Central axis of the cylinders defining the inner and outer surfaces of + the sector. Defaults to 'z'. + **kwargs : dict + Keyword arguments passed to the :class:`Cylinder` and + :class:`Plane` constructors. + + Attributes + ---------- + outer_cyl : openmc.ZCylinder, openmc.YCylinder, or openmc.XCylinder + Outer cylinder surface. + inner_cyl : openmc.ZCylinder, openmc.YCylinder, or openmc.XCylinder + Inner cylinder surface. + plane1 : openmc.Plane + Plane at angle :math:`\\theta_1` relative to the first basis axis. + plane2 : openmc.Plane + Plane at angle :math:`\\theta_2` relative to the first basis axis. + + """ + + _surface_names = ('outer_cyl', 'inner_cyl', 'plane1', 'plane2') + + def __init__(self, + r1, + r2, + theta1, + theta2, + center=(0.,0.), + axis='z', + **kwargs): + + if r2 <= r1: + raise ValueError('r2 must be greater than r1.') + + if theta2 <= theta1: + raise ValueError('theta2 must be greater than theta1.') + + phi1 = pi / 180 * theta1 + phi2 = pi / 180 * theta2 + + # Coords for axis-perpendicular planes + p1 = np.array([0., 0., 1.]) + + p2_plane1 = np.array([r1 * cos(phi1), r1 * sin(phi1), 0.]) + p3_plane1 = np.array([r2 * cos(phi1), r2 * sin(phi1), 0.]) + + p2_plane2 = np.array([r1 * cos(phi2), r1 * sin(phi2), 0.]) + p3_plane2 = np.array([r2 * cos(phi2), r2 * sin(phi2), 0.]) + + points = [p1, p2_plane1, p3_plane1, p2_plane2, p3_plane2] + if axis == 'z': + coord_map = [0, 1, 2] + self.inner_cyl = openmc.ZCylinder(*center, r1, **kwargs) + self.outer_cyl = openmc.ZCylinder(*center, r2, **kwargs) + elif axis == 'y': + coord_map = [1, 2, 0] + self.inner_cyl = openmc.YCylinder(*center, r1, **kwargs) + self.outer_cyl = openmc.YCylinder(*center, r2, **kwargs) + elif axis == 'x': + coord_map = [2, 0, 1] + self.inner_cyl = openmc.XCylinder(*center, r1, **kwargs) + self.outer_cyl = openmc.XCylinder(*center, r2, **kwargs) + + for p in points: + p[:] = p[coord_map] + + self.plane1 = openmc.Plane.from_points(p1, p2_plane1, p3_plane1, + **kwargs) + self.plane2 = openmc.Plane.from_points(p1, p2_plane2, p3_plane2, + **kwargs) + + @classmethod + def from_theta_alpha(cls, + r1, + r2, + theta, + alpha, + center = (0.,0.), + axis='z', + **kwargs): + r"""Alternate constructor for :class:`CylinderSector`. Returns a + :class:`CylinderSector` object based on a central angle :math:`\theta` + and an angular offset :math:`\alpha`. Note that + :math:`\theta_1 = \alpha` and :math:`\theta_2 = \alpha + \theta`. + + Parameters + ---------- + r1 : float + Inner radius of sector. Must be less than r2. + r2 : float + Outer radius of sector. Must be greater than r1. + theta : float + Central angle, :math:`\theta`, of the sector in degrees. Must be + greater that 0 and less than 360. + alpha : float + Angular offset, :math:`\alpha`, of sector in degrees. + The offset is in the counter-clockwise direction + with respect to the first basis axis (+y, +z, or +x). Note that + negative values translate to an offset in the clockwise direction. + center : iterable of float + Coordinate for central axes of cylinders in the (y, z), (z, x), or (x, y) + basis. Defaults to (0,0). + axis : {'x', 'y', 'z'} + Central axis of the cylinders defining the inner and outer surfaces + of the sector. Defaults to 'z'. + **kwargs : dict + Keyword arguments passed to the :class:`Cylinder` and + :class:`Plane` constructors. + + Returns + ------- + CylinderSector + CylinderSector with the given central angle at the given + offset. + """ + if theta >= 360. or theta <= 0: + raise ValueError('theta must be less than 360 and greater than 0.') + + theta1 = alpha + theta2 = alpha + theta + + return cls(r1, r2, theta1, theta2, center=center, axis=axis, **kwargs) - @abstractmethod def __neg__(self): - """Return the negative half-space of the composite surface.""" + return -self.outer_cyl & +self.inner_cyl & -self.plane1 & +self.plane2 + + def __pos__(self): + return +self.outer_cyl | -self.inner_cyl | +self.plane1 | -self.plane2 + + +class IsogonalOctagon(CompositeSurface): + r"""Infinite isogonal octagon composite surface + + An isogonal octagon is composed of eight planar surfaces. The prism is + parallel to the x, y, or z axis. The remaining two axes (y and z, z and x, + or x and y) serve as a basis for constructing the surfaces. Two surfaces + are parallel to the first basis axis, two surfaces are parallel + to the second basis axis, and the remaining four surfaces intersect both + basis axes at 45 degree angles. + + This class acts as a proper surface, meaning that unary `+` and `-` + operators applied to it will produce a half-space. The negative side is + defined to be the region inside of the octogonal prism. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + center : iterable of float + Coordinate for the central axis of the octagon in the + (y, z), (z, x), or (x, y) basis. + r1 : float + Half-width of octagon across its basis axis-parallel sides in units + of cm. Must be less than :math:`r_2\sqrt{2}`. + r2 : float + Half-width of octagon across its basis axis intersecting sides in + units of cm. Must be less than than :math:`r_1\sqrt{2}`. + axis : {'x', 'y', 'z'} + Central axis of octagon. Defaults to 'z' + **kwargs + Keyword arguments passed to underlying plane classes + + Attributes + ---------- + top : openmc.ZPlane, openmc.XPlane, or openmc.YPlane + Top planar surface of octagon + bottom : openmc.ZPlane, openmc.XPlane, or openmc.YPlane + Bottom planar surface of octagon + right : openmc.YPlane, openmc.ZPlane, or openmc.XPlane + Right planar surface of octagon + left : openmc.YPlane, openmc.ZPlane, or openmc.XPlane + Left planar surface of octagon + upper_right : openmc.Plane + Upper right planar surface of octagon + lower_right : openmc.Plane + Lower right planar surface of octagon + lower_left : openmc.Plane + Lower left planar surface of octagon + upper_left : openmc.Plane + Upper left planar surface of octagon + + """ + + _surface_names = ('top', 'bottom', + 'upper_right', 'lower_left', + 'right', 'left', + 'lower_right', 'upper_left') + + def __init__(self, center, r1, r2, axis='z', **kwargs): + c1, c2 = center + + # Coords for axis-perpendicular planes + ctop = c1 + r1 + cbottom = c1 - r1 + + cright = c2 + r1 + cleft = c2 - r1 + + # Side lengths + if r2 > r1 * sqrt(2): + raise ValueError('r2 is greater than sqrt(2) * r1. Octagon' + + ' may be erroneous.') + if r1 > r2 * sqrt(2): + raise ValueError('r1 is greater than sqrt(2) * r2. Octagon' + + ' may be erroneous.') + + L_basis_ax = (r2 * sqrt(2) - r1) + + # Coords for quadrant planes + p1_ur = np.array([L_basis_ax, r1, 0.]) + p2_ur = np.array([r1, L_basis_ax, 0.]) + p3_ur = np.array([r1, L_basis_ax, 1.]) + + p1_lr = np.array([r1, -L_basis_ax, 0.]) + p2_lr = np.array([L_basis_ax, -r1, 0.]) + p3_lr = np.array([L_basis_ax, -r1, 1.]) + + points = [p1_ur, p2_ur, p3_ur, p1_lr, p2_lr, p3_lr] + + # Orientation specific variables + if axis == 'z': + coord_map = [0, 1, 2] + self.top = openmc.YPlane(ctop, **kwargs) + self.bottom = openmc.YPlane(cbottom, **kwargs) + self.right = openmc.XPlane(cright, **kwargs) + self.left = openmc.XPlane(cleft, **kwargs) + elif axis == 'y': + coord_map = [1, 2, 0] + self.top = openmc.XPlane(ctop, **kwargs) + self.bottom = openmc.XPlane(cbottom, **kwargs) + self.right = openmc.ZPlane(cright, **kwargs) + self.left = openmc.ZPlane(cleft, **kwargs) + elif axis == 'x': + coord_map = [2, 0, 1] + self.top = openmc.ZPlane(ctop, **kwargs) + self.bottom = openmc.ZPlane(cbottom, **kwargs) + self.right = openmc.YPlane(cright, **kwargs) + self.left = openmc.YPlane(cleft, **kwargs) + + # Put our coordinates in (x,y,z) order + for p in points: + p[:] = p[coord_map] + + self.upper_right = openmc.Plane.from_points(p1_ur, p2_ur, p3_ur, + **kwargs) + self.lower_right = openmc.Plane.from_points(p1_lr, p2_lr, p3_lr, + **kwargs) + self.lower_left = openmc.Plane.from_points(-p1_ur, -p2_ur, -p3_ur, + **kwargs) + self.upper_left = openmc.Plane.from_points(-p1_lr, -p2_lr, -p3_lr, + **kwargs) + + def __neg__(self): + return -self.top & +self.bottom & -self.right & +self.left & \ + +self.upper_right & +self.lower_right & -self.lower_left & \ + -self.upper_left + + def __pos__(self): + return +self.top | -self.bottom | +self.right | -self.left | \ + -self.upper_right | -self.lower_right | +self.lower_left | \ + +self.upper_left class RightCircularCylinder(CompositeSurface): @@ -72,6 +376,10 @@ class RightCircularCylinder(CompositeSurface): Radius of the cylinder axis : {'x', 'y', 'z'} Axis of the cylinder + upper_fillet_radius : float + Upper edge fillet radius in [cm]. + lower_fillet_radius : float + Lower edge fillet radius in [cm]. **kwargs Keyword arguments passed to underlying cylinder and plane classes @@ -83,33 +391,173 @@ class RightCircularCylinder(CompositeSurface): Bottom planar surface of the cylinder top : openmc.Plane Top planar surface of the cylinder + upper_fillet_torus : openmc.Torus + Surface that creates the filleted edge for the upper end of the + cylinder. Only present if :attr:`upper_fillet_radius` is set. + upper_fillet_cylinder : openmc.Cylinder + Surface that bounds :attr:`upper_fillet_torus` radially. Only present + if :attr:`upper_fillet_radius` is set. + upper_fillet_plane : openmc.Plane + Surface that bounds :attr:`upper_fillet_torus` axially. Only present if + :attr:`upper_fillet_radius` is set. + lower_fillet_torus : openmc.Torus + Surface that creates the filleted edge for the lower end of the + cylinder. Only present if :attr:`lower_fillet_radius` is set. + lower_fillet_cylinder : openmc.Cylinder + Surface that bounds :attr:`lower_fillet_torus` radially. Only present + if :attr:`lower_fillet_radius` is set. + lower_fillet_plane : openmc.Plane + Surface that bounds :attr:`lower_fillet_torus` axially. Only present if + :attr:`lower_fillet_radius` is set. """ _surface_names = ('cyl', 'bottom', 'top') - def __init__(self, center_base, height, radius, axis='z', **kwargs): + def __init__(self, center_base, height, radius, axis='z', + upper_fillet_radius=0., lower_fillet_radius=0., **kwargs): cx, cy, cz = center_base check_greater_than('cylinder height', height, 0.0) check_greater_than('cylinder radius', radius, 0.0) check_value('cylinder axis', axis, ('x', 'y', 'z')) + check_type('upper_fillet_radius', upper_fillet_radius, float) + check_less_than('upper_fillet_radius', upper_fillet_radius, + radius, equality=True) + check_type('lower_fillet_radius', lower_fillet_radius, float) + check_less_than('lower_fillet_radius', lower_fillet_radius, + radius, equality=True) + if axis == 'x': self.cyl = openmc.XCylinder(y0=cy, z0=cz, r=radius, **kwargs) self.bottom = openmc.XPlane(x0=cx, **kwargs) self.top = openmc.XPlane(x0=cx + height, **kwargs) + x1, x2 = 'y', 'z' + axcoord, axcoord1, axcoord2 = 0, 1, 2 elif axis == 'y': self.cyl = openmc.YCylinder(x0=cx, z0=cz, r=radius, **kwargs) self.bottom = openmc.YPlane(y0=cy, **kwargs) self.top = openmc.YPlane(y0=cy + height, **kwargs) + x1, x2 = 'x', 'z' + axcoord, axcoord1, axcoord2 = 1, 0, 2 elif axis == 'z': self.cyl = openmc.ZCylinder(x0=cx, y0=cy, r=radius, **kwargs) self.bottom = openmc.ZPlane(z0=cz, **kwargs) self.top = openmc.ZPlane(z0=cz + height, **kwargs) + x1, x2 = 'x', 'y' + axcoord, axcoord1, axcoord2 = 2, 0, 1 + + def _create_fillet_objects(axis_args, height, center_base, radius, fillet_radius, pos='upper'): + axis, x1, x2, axcoord, axcoord1, axcoord2 = axis_args + fillet_ext = height / 2 - fillet_radius + sign = 1 + if pos == 'lower': + sign = -1 + coord = center_base[axcoord] + (height / 2) + sign * fillet_ext + + # cylinder + cyl_name = f'{pos}_min' + cylinder_args = { + x1 + '0': center_base[axcoord1], + x2 + '0': center_base[axcoord2], + 'r': radius - fillet_radius + } + cls = getattr(openmc, f'{axis.upper()}Cylinder') + cyl = cls(name=f'{cyl_name} {axis}', **cylinder_args) + + #torus + tor_name = f'{axis} {pos}' + tor_args = { + 'a': radius - fillet_radius, + 'b': fillet_radius, + 'c': fillet_radius, + x1 + '0': center_base[axcoord1], + x2 + '0': center_base[axcoord2], + axis + '0': coord + } + cls = getattr(openmc, f'{axis.upper()}Torus') + torus = cls(name=tor_name, **tor_args) + + # plane + p_name = f'{pos} ext' + p_args = {axis + '0': coord} + cls = getattr(openmc, f'{axis.upper()}Plane') + plane = cls(name=p_name, **p_args) + + return cyl, torus, plane + + if upper_fillet_radius > 0. or lower_fillet_radius > 0.: + if 'boundary_type' in kwargs: + if kwargs['boundary_type'] == 'periodic': + raise ValueError('Periodic boundary conditions not permitted when ' + 'rounded corners are used.') + + axis_args = (axis, x1, x2, axcoord, axcoord1, axcoord2) + if upper_fillet_radius > 0.: + cylinder, torus, plane = _create_fillet_objects( + axis_args, height, center_base, radius, upper_fillet_radius) + self.upper_fillet_cylinder = cylinder + self.upper_fillet_torus = torus + self.upper_fillet_plane = plane + self._surface_names += ('upper_fillet_cylinder', + 'upper_fillet_torus', + 'upper_fillet_plane') + + if lower_fillet_radius > 0.: + cylinder, torus, plane = _create_fillet_objects( + axis_args, height, center_base, radius, lower_fillet_radius, + pos='lower' + ) + self.lower_fillet_cylinder = cylinder + self.lower_fillet_torus = torus + self.lower_fillet_plane = plane + + self._surface_names += ('lower_fillet_cylinder', + 'lower_fillet_torus', + 'lower_fillet_plane') + + def _get_fillet(self): + upper_fillet = self._get_upper_fillet() + lower_fillet = self._get_lower_fillet() + has_upper_fillet = upper_fillet is not None + has_lower_fillet = lower_fillet is not None + if has_lower_fillet and has_upper_fillet: + fillet = lower_fillet | upper_fillet + elif has_upper_fillet and not has_lower_fillet: + fillet = upper_fillet + elif not has_upper_fillet and has_lower_fillet: + fillet = lower_fillet + else: + fillet = None + return fillet + + def _get_upper_fillet(self): + has_upper_fillet = hasattr(self, 'upper_fillet_plane') + if has_upper_fillet: + upper_fillet = +self.upper_fillet_cylinder & +self.upper_fillet_torus & +self.upper_fillet_plane + else: + upper_fillet = None + return upper_fillet + + def _get_lower_fillet(self): + has_lower_fillet = hasattr(self, 'lower_fillet_plane') + if has_lower_fillet: + lower_fillet = +self.lower_fillet_cylinder & +self.lower_fillet_torus & -self.lower_fillet_plane + else: + lower_fillet = None + return lower_fillet def __neg__(self): - return -self.cyl & +self.bottom & -self.top + prism = -self.cyl & +self.bottom & -self.top + fillet = self._get_fillet() + if fillet is not None: + prism = prism & ~fillet + return prism def __pos__(self): - return +self.cyl | -self.bottom | +self.top + prism = +self.cyl | -self.bottom | +self.top + fillet = self._get_fillet() + if fillet is not None: + prism = prism | fillet + return prism class RectangularParallelepiped(CompositeSurface): @@ -160,16 +608,16 @@ def __init__(self, xmin, xmax, ymin, ymax, zmin, zmax, **kwargs): self.zmax = openmc.ZPlane(z0=zmax, **kwargs) def __neg__(self): - return +self.xmin & -self.xmax & +self.ymin & -self.ymax & +self.zmin & -self.zmax + return -self.xmax & +self.xmin & -self.ymax & +self.ymin & -self.zmax & +self.zmin def __pos__(self): - return -self.xmin | +self.xmax | -self.ymin | +self.ymax | -self.zmin | +self.zmax + return +self.xmax | -self.xmin | +self.ymax | -self.ymin | +self.zmax | -self.zmin class XConeOneSided(CompositeSurface): """One-sided cone parallel the x-axis - A one-sided cone is composed of a normal cone surface and an "ambiguity" + A one-sided cone is composed of a normal cone surface and a "disambiguation" surface that eliminates the ambiguity as to which region of space is included. This class acts as a proper surface, meaning that unary `+` and `-` operators applied to it will produce a half-space. The negative side is @@ -186,7 +634,9 @@ class XConeOneSided(CompositeSurface): z0 : float, optional z-coordinate of the apex. Defaults to 0. r2 : float, optional - Parameter related to the aperature. Defaults to 1. + Parameter related to the aperture [:math:`\\rm cm^2`]. + It can be interpreted as the increase in the radius squared per cm along + the cone's axis of revolution. up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -199,7 +649,7 @@ class XConeOneSided(CompositeSurface): cone : openmc.XCone Regular two-sided cone plane : openmc.XPlane - Ambiguity surface + Disambiguation surface up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -227,7 +677,7 @@ def __pos__(self): class YConeOneSided(CompositeSurface): """One-sided cone parallel the y-axis - A one-sided cone is composed of a normal cone surface and an "ambiguity" + A one-sided cone is composed of a normal cone surface and a "disambiguation" surface that eliminates the ambiguity as to which region of space is included. This class acts as a proper surface, meaning that unary `+` and `-` operators applied to it will produce a half-space. The negative side is @@ -244,7 +694,9 @@ class YConeOneSided(CompositeSurface): z0 : float, optional z-coordinate of the apex. Defaults to 0. r2 : float, optional - Parameter related to the aperature. Defaults to 1. + Parameter related to the aperture [:math:`\\rm cm^2`]. + It can be interpreted as the increase in the radius squared per cm along + the cone's axis of revolution. up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -257,7 +709,7 @@ class YConeOneSided(CompositeSurface): cone : openmc.YCone Regular two-sided cone plane : openmc.YPlane - Ambiguity surface + Disambiguation surface up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -279,7 +731,7 @@ def __init__(self, x0=0., y0=0., z0=0., r2=1., up=True, **kwargs): class ZConeOneSided(CompositeSurface): """One-sided cone parallel the z-axis - A one-sided cone is composed of a normal cone surface and an "ambiguity" + A one-sided cone is composed of a normal cone surface and a "disambiguation" surface that eliminates the ambiguity as to which region of space is included. This class acts as a proper surface, meaning that unary `+` and `-` operators applied to it will produce a half-space. The negative side is @@ -296,7 +748,9 @@ class ZConeOneSided(CompositeSurface): z0 : float, optional z-coordinate of the apex. Defaults to 0. r2 : float, optional - Parameter related to the aperature. Defaults to 1. + Parameter related to the aperture [:math:`\\rm cm^2`]. + It can be interpreted as the increase in the radius squared per cm along + the cone's axis of revolution. up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -309,7 +763,7 @@ class ZConeOneSided(CompositeSurface): cone : openmc.ZCone Regular two-sided cone plane : openmc.ZPlane - Ambiguity surface + Disambiguation surface up : bool Whether to select the side of the cone that extends to infinity in the positive direction of the coordinate axis (the positive half-space of @@ -326,3 +780,837 @@ def __init__(self, x0=0., y0=0., z0=0., r2=1., up=True, **kwargs): __neg__ = XConeOneSided.__neg__ __pos__ = XConeOneSided.__pos__ + + +class Polygon(CompositeSurface): + """Polygon formed from a path of closed points. + + .. versionadded:: 0.13.3 + + Parameters + ---------- + points : np.ndarray + An Nx2 array of points defining the vertices of the polygon. + basis : {'rz', 'xy', 'yz', 'xz'}, optional + 2D basis set for the polygon. The polygon is two dimensional and has + infinite extent in the third (unspecified) dimension. For example, the + 'xy' basis produces a polygon with infinite extent in the +/- z + direction. For the 'rz' basis the phi extent is infinite, thus forming + an axisymmetric surface. + + Attributes + ---------- + points : np.ndarray + An Nx2 array of points defining the vertices of the polygon. + basis : {'rz', 'xy', 'yz', 'xz'} + 2D basis set for the polygon. + regions : list of openmc.Region + A list of :class:`openmc.Region` objects, one for each of the convex polygons + formed during the decomposition of the input polygon. + region : openmc.Union + The union of all the regions comprising the polygon. + """ + + def __init__(self, points, basis='rz'): + check_value('basis', basis, ('xy', 'yz', 'xz', 'rz')) + self._basis = basis + + # Create a constrained triangulation of the validated points. + # The constrained triangulation is set to the _tri attribute + self._constrain_triangulation(self._validate_points(points)) + + # Decompose the polygon into groups of simplices forming convex subsets + # and get the sets of (surface, operator) pairs defining the polygon + self._surfsets = self._decompose_polygon_into_convex_sets() + + # Set surface names as required by CompositeSurface protocol + surfnames = [] + i = 0 + for surfset in self._surfsets: + for surf, op, on_boundary in surfset: + if on_boundary: + setattr(self, f'surface_{i}', surf) + surfnames.append(f'surface_{i}') + i += 1 + self._surfnames = tuple(surfnames) + + # Generate a list of regions whose union represents the polygon. + regions = [] + for surfs_ops in self._surfsets: + regions.append([op(surf) for surf, op, _ in surfs_ops]) + self._regions = [openmc.Intersection(regs) for regs in regions] + + # Create the union of all the convex subsets + self._region = openmc.Union(self._regions) + + def __neg__(self): + return self._region + + @property + def _surface_names(self): + return self._surfnames + + @CompositeSurface.boundary_type.setter + def boundary_type(self, boundary_type): + if boundary_type != 'transmission': + warnings.warn("Setting boundary_type to a value other than " + "'transmission' on Polygon composite surfaces can " + "result in unintended behavior. Please use the " + "regions property of the Polygon to generate " + "individual openmc.Cell objects to avoid unwanted " + "behavior.") + for name in self._surface_names: + getattr(self, name).boundary_type = boundary_type + + @property + def points(self): + return self._tri.points + + @property + def basis(self): + return self._basis + + @property + def _normals(self): + """Generate the outward normal unit vectors for the polygon.""" + # Rotation matrix for 90 degree clockwise rotation (-90 degrees about z + # axis for an 'xy' basis). + rotation = np.array([[0., 1.], [-1., 0.]]) + # Get the unit vectors that point from one point in the polygon to the + # next given that they are ordered counterclockwise and that the final + # point is connected to the first point + tangents = np.diff(self.points, axis=0, append=[self.points[0, :]]) + tangents /= np.linalg.norm(tangents, axis=-1, keepdims=True) + # Rotate the tangent vectors clockwise by 90 degrees, which for a + # counter-clockwise ordered polygon will produce the outward normal + # vectors. + return rotation.dot(tangents.T).T + + @property + def _equations(self): + normals = self._normals + equations = np.empty((normals.shape[0], 3)) + equations[:, :2] = normals + equations[:, 2] = -np.sum(normals*self.points, axis=-1) + return equations + + @property + def regions(self): + return self._regions + + @property + def region(self): + return self._region + + def _validate_points(self, points): + """Ensure the closed path defined by points does not intersect and is + oriented counter-clockwise. + + Parameters + ---------- + points : np.ndarray (Nx2) + An Nx2 array of coordinate pairs describing the vertices. + + Returns + ------- + ordered_points : the input points ordered counter-clockwise + """ + points = np.asarray(points, dtype=float) + check_iterable_type('points', points, float, min_depth=2, max_depth=2) + check_length('points', points[0, :], 2, 2) + + # If the last point is the same as the first, remove it and make sure + # there are still at least 3 points for a valid polygon. + if np.allclose(points[0, :], points[-1, :]): + points = points[:-1, :] + check_length('points', points, 3) + + if len(points) != len(np.unique(points, axis=0)): + raise ValueError('Duplicate points were detected in the Polygon input') + + # Order the points counter-clockwise (necessary for offset method) + # Calculates twice the signed area of the polygon using the "Shoelace + # Formula" https://en.wikipedia.org/wiki/Shoelace_formula + # If signed area is positive the curve is oriented counter-clockwise. + # If the signed area is negative the curve is oriented clockwise. + xpts, ypts = points.T + if np.sum(ypts*(np.roll(xpts, 1) - np.roll(xpts, -1))) < 0: + points = points[::-1, :] + + # Check if polygon is self-intersecting by comparing edges pairwise + n = len(points) + for i in range(n): + p0 = points[i, :] + p1 = points[(i + 1) % n, :] + for j in range(i + 1, n): + p2 = points[j, :] + p3 = points[(j + 1) % n, :] + # Compute orientation of p0 wrt p2->p3 line segment + cp0 = np.cross(p3-p0, p2-p0) + # Compute orientation of p1 wrt p2->p3 line segment + cp1 = np.cross(p3-p1, p2-p1) + # Compute orientation of p2 wrt p0->p1 line segment + cp2 = np.cross(p1-p2, p0-p2) + # Compute orientation of p3 wrt p0->p1 line segment + cp3 = np.cross(p1-p3, p0-p3) + + # Group cross products in an array and find out how many are 0 + cross_products = np.array([[cp0, cp1], [cp2, cp3]]) + cps_near_zero = np.isclose(cross_products, 0).astype(int) + num_zeros = np.sum(cps_near_zero) + + # Topologies of 2 finite line segments categorized by the number + # of zero-valued cross products: + # + # 0: No 3 points lie on the same line + # 1: 1 point lies on the same line defined by the other line + # segment, but is not coincident with either of the points + # 2: 2 points are coincident, but the line segments are not + # collinear which guarantees no intersection + # 3: not possible, except maybe floating point issues? + # 4: Both line segments are collinear, simply need to check if + # they overlap or not + # adapted from algorithm linked below and modified to only + # consider intersections on the interior of line segments as + # proper intersections: i.e. segments sharing end points do not + # count as intersections. + # https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ + + if num_zeros == 0: + # If the orientations of p0 and p1 have opposite signs + # and the orientations of p2 and p3 have opposite signs + # then there is an intersection. + if all(np.prod(cross_products, axis=-1) < 0): + raise ValueError('Polygon cannot be self-intersecting') + continue + + elif num_zeros == 1: + # determine which line segment has 2 out of the 3 collinear + # points + idx = np.argwhere(np.sum(cps_near_zero, axis=-1) == 0) + if np.prod(cross_products[idx, :]) < 0: + raise ValueError('Polygon cannot be self-intersecting') + continue + + elif num_zeros == 2: + continue + + elif num_zeros == 3: + warnings.warn('Unclear if Polygon is self-intersecting') + continue + + else: + # All 4 cross products are zero + # Determine number of unique points, x span and y span for + # both line segments + xmin1, xmax1 = min(p0[0], p1[0]), max(p0[0], p1[0]) + ymin1, ymax1 = min(p0[1], p1[1]), max(p0[1], p1[1]) + xmin2, xmax2 = min(p2[0], p3[0]), max(p2[0], p3[0]) + ymin2, ymax2 = min(p2[1], p3[1]), max(p2[1], p3[1]) + xlap = xmin1 < xmax2 and xmin2 < xmax1 + ylap = ymin1 < ymax2 and ymin2 < ymax1 + if xlap or ylap: + raise ValueError('Polygon cannot be self-intersecting') + continue + + return points + + def _constrain_triangulation(self, points, depth=0): + """Generate a constrained triangulation by ensuring all edges of the + Polygon are contained within the simplices. + + Parameters + ---------- + points : np.ndarray (Nx2) + An Nx2 array of coordinate pairs describing the vertices. These + points represent a planar straight line graph. + + Returns + ------- + None + """ + # Only attempt the triangulation up to 5 times. + if depth > 4: + raise RuntimeError('Could not create a valid triangulation after 5' + ' attempts') + + tri = Delaunay(points, qhull_options='QJ') + # Loop through the boundary edges of the polygon. If an edge is not + # included in the triangulation, break it into two line segments. + n = len(points) + new_pts = [] + for i, j in zip(range(n), range(1, n + 1)): + # If both vertices of any edge are not found in any simplex, insert + # a new point between them. + if not any([i in s and j % n in s for s in tri.simplices]): + newpt = (points[i, :] + points[j % n, :]) / 2 + new_pts.append((j, newpt)) + + # If all the edges are included in the triangulation set it, otherwise + # try again with additional points inserted on offending edges. + if not new_pts: + self._tri = tri + else: + for i, pt in new_pts[::-1]: + points = np.insert(points, i, pt, axis=0) + self._constrain_triangulation(points, depth=depth + 1) + + def _group_simplices(self, neighbor_map, group=None): + """Generate a convex grouping of simplices. + + Parameters + ---------- + neighbor_map : dict + A map whose keys are simplex indices for simplices inside the polygon + and whose values are a list of simplex indices that neighbor this + simplex and are also inside the polygon. + group : list + A list of simplex indices that comprise the current convex group. + + Returns + ------- + group : list + The list of simplex indices that comprise the complete convex group. + """ + # If neighbor_map is empty there's nothing left to do + if not neighbor_map: + return group + # If group is empty, grab the next simplex in the dictionary and recurse + if group is None: + # Start with smallest neighbor lists + sidx = sorted(neighbor_map.items(), key=lambda item: len(item[1]))[0][0] + return self._group_simplices(neighbor_map, group=[sidx]) + # Otherwise use the last simplex in the group + else: + sidx = group[-1] + # Remove current simplex from dictionary since it is in a group + neighbors = neighbor_map.pop(sidx, []) + # For each neighbor check if it is part of the same convex + # hull as the rest of the group. If yes, recurse. If no, continue on. + for n in neighbors: + if n in group or neighbor_map.get(n) is None: + continue + test_group = group + [n] + test_point_idx = np.unique(self._tri.simplices[test_group, :]) + test_points = self.points[test_point_idx] + test_hull = ConvexHull(test_points, qhull_options='Qc') + pts_on_hull = len(test_hull.vertices) + len(test_hull.coplanar) + # If test_points are convex (including coplanar) keep adding to + # this group + if len(test_points) == pts_on_hull: + group = self._group_simplices(neighbor_map, group=test_group) + return group + + def _get_convex_hull_surfs(self, qhull): + """Generate a list of surfaces given by a set of linear equations + + Parameters + ---------- + qhull : scipy.spatial.ConvexHull + A ConvexHull object representing the sub-region of the polygon. + + Returns + ------- + surfs_ops : list of (surface, operator) tuples + + """ + basis = self.basis + boundary_eqns = self._equations + # Collect surface/operator pairs such that the intersection of the + # regions defined by these pairs is the inside of the polygon. + surfs_ops = [] + # hull facet equation: dx*x + dy*y + c = 0 + for dx, dy, c in qhull.equations: + # check if this facet is on the boundary of the polygon + facet_eq = np.array([dx, dy, c]) + on_boundary = any([np.allclose(facet_eq, eq) for eq in boundary_eqns]) + # Check if the facet is horizontal + if isclose(dx, 0, abs_tol=1e-8): + if basis in ('xz', 'yz', 'rz'): + surf = openmc.ZPlane(z0=-c/dy) + else: + surf = openmc.YPlane(y0=-c/dy) + # if (0, 1).(dx, dy) < 0 we want positive halfspace instead + op = operator.pos if dy < 0 else operator.neg + # Check if the facet is vertical + elif isclose(dy, 0, abs_tol=1e-8): + if basis in ('xy', 'xz'): + surf = openmc.XPlane(x0=-c/dx) + elif basis == 'yz': + surf = openmc.YPlane(y0=-c/dx) + else: + surf = openmc.ZCylinder(r=-c/dx) + # if (1, 0).(dx, dy) < 0 we want positive halfspace instead + op = operator.pos if dx < 0 else operator.neg + # Otherwise the facet is at an angle + else: + op = operator.neg + if basis == 'xy': + surf = openmc.Plane(a=dx, b=dy, d=-c) + elif basis == 'yz': + surf = openmc.Plane(b=dx, c=dy, d=-c) + elif basis == 'xz': + surf = openmc.Plane(a=dx, c=dy, d=-c) + else: + y0 = -c/dy + r2 = dy**2 / dx**2 + # Check if the *slope* of the facet is positive. If dy/dx < 0 + # then we want up to be True for the one-sided cones. + up = dy / dx < 0 + surf = openmc.model.ZConeOneSided(z0=y0, r2=r2, up=up) + # if (1, -1).(dx, dy) < 0 for up cones we want positive halfspace + # if (1, 1).(dx, dy) < 0 for down cones we want positive halfspace + # otherwise we keep the negative halfspace operator + if (up and dx - dy < 0) or (not up and dx + dy < 0): + op = operator.pos + + surfs_ops.append((surf, op, on_boundary)) + + return surfs_ops + + def _decompose_polygon_into_convex_sets(self): + """Decompose the Polygon into a set of convex polygons. + + Returns + ------- + surfsets : a list of lists of surface, operator pairs + """ + from matplotlib.path import Path + + # Get centroids of all the simplices and determine if they are inside + # the polygon defined by input vertices or not. + centroids = np.mean(self.points[self._tri.simplices], axis=1) + in_polygon = Path(self.points).contains_points(centroids) + self._in_polygon = in_polygon + + # Build a map with keys of simplex indices inside the polygon whose + # values are lists of that simplex's neighbors also inside the + # polygon + neighbor_map = {} + for i, nlist in enumerate(self._tri.neighbors): + if not in_polygon[i]: + continue + neighbor_map[i] = [n for n in nlist if in_polygon[n] and n >=0] + + # Get the groups of simplices forming convex polygons whose union + # comprises the full input polygon. While there are still simplices + # left in the neighbor map, group them together into convex sets. + groups = [] + while neighbor_map: + groups.append(self._group_simplices(neighbor_map)) + self._groups = groups + + # Generate lists of (surface, operator) pairs for each convex + # sub-region. + surfsets = [] + for group in groups: + # Find all the unique points in the convex group of simplices, + # generate the convex hull and find the resulting surfaces and + # unary operators that represent this convex subset of the polygon. + idx = np.unique(self._tri.simplices[group, :]) + qhull = ConvexHull(self.points[idx, :]) + surf_ops = self._get_convex_hull_surfs(qhull) + surfsets.append(surf_ops) + return surfsets + + def offset(self, distance): + """Offset this polygon by a set distance + + Parameters + ---------- + distance : float + The distance to offset the polygon by. Positive is outward + (expanding) and negative is inward (shrinking). + + Returns + ------- + offset_polygon : openmc.model.Polygon + """ + normals = np.insert(self._normals, 0, self._normals[-1, :], axis=0) + cos2theta = np.sum(normals[1:, :]*normals[:-1, :], axis=-1, keepdims=True) + costheta = np.cos(np.arccos(cos2theta) / 2) + nvec = (normals[1:, :] + normals[:-1, :]) + unit_nvec = nvec / np.linalg.norm(nvec, axis=-1, keepdims=True) + disp_vec = distance / costheta * unit_nvec + + return type(self)(self.points + disp_vec, basis=self.basis) + + +class CruciformPrism(CompositeSurface): + """Generalized cruciform prism + + This surface represents a prism parallel to an axis formed by planes at + multiple distances from the center. Equivalent to the 'gcross' derived + surface in Serpent. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + distances : iterable of float + A monotonically increasing (or decreasing) iterable of distances in [cm] + that form the planes of the generalized cruciform. + center : iterable of float + The center of the prism in the two non-parallel axes (e.g., (x, y) when + axis is 'z') in [cm] + axis : {'x', 'y', 'z'} + Axis to which the prism is parallel + **kwargs + Keyword arguments passed to underlying plane classes + + """ + + def __init__(self, distances, center=(0., 0.), axis='z', **kwargs): + x0, y0 = center + self.distances = distances + + if axis == 'x': + cls_horizontal = openmc.YPlane + cls_vertical = openmc.ZPlane + elif axis == 'y': + cls_horizontal = openmc.XPlane + cls_vertical = openmc.ZPlane + elif axis == 'z': + cls_horizontal = openmc.XPlane + cls_vertical = openmc.YPlane + else: + raise ValueError("axis must be 'x', 'y', or 'z'") + + # Create each planar surface + surfnames = [] + for i, d in enumerate(distances): + setattr(self, f'hmin{i}', cls_horizontal(x0 - d, **kwargs)) + setattr(self, f'hmax{i}', cls_horizontal(x0 + d, **kwargs)) + setattr(self, f'vmin{i}', cls_vertical(y0 - d, **kwargs)) + setattr(self, f'vmax{i}', cls_vertical(y0 + d, **kwargs)) + surfnames.extend([f'hmin{i}', f'hmax{i}', f'vmin{i}', f'vmax{i}']) + + # Set _surfnames to satisfy CompositeSurface protocol + self._surfnames = tuple(surfnames) + + @property + def _surface_names(self): + return self._surfnames + + @property + def distances(self): + return self._distances + + @distances.setter + def distances(self, values): + values = np.array(values, dtype=float) + # check for positive values + if not (values > 0).all(): + raise ValueError("distances must be positive") + # Check for monotonicity + if (values[1:] > values[:-1]).all() or (values[1:] < values[:-1]).all(): + self._distances = values + else: + raise ValueError("distances must be monotonic") + + def __neg__(self): + n = len(self.distances) + regions = [] + for i in range(n): + regions.append( + +getattr(self, f'hmin{i}') & + -getattr(self, f'hmax{i}') & + +getattr(self, f'vmin{n-1-i}') & + -getattr(self, f'vmax{n-1-i}') + ) + return openmc.Union(regions) + + +# Define function to create a plane on given axis +def _plane(axis, name, value, boundary_type='transmission', albedo=1.0): + cls = getattr(openmc, f'{axis.upper()}Plane') + return cls(value, name=f'{name} {axis}', + boundary_type=boundary_type, albedo=albedo) + + +class RectangularPrism(CompositeSurface): + """Infinite rectangular prism bounded by four planar surfaces. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + width : float + Prism width in units of [cm]. The width is aligned with the x, x, or z + axes for prisms parallel to the x, y, or z axis, respectively. + height : float + Prism height in units of [cm]. The height is aligned with the x, y, or z + axes for prisms parallel to the x, y, or z axis, respectively. + axis : {'x', 'y', 'z'} + Axis with which the infinite length of the prism should be aligned. + origin : Iterable of two floats + Origin of the prism. The two floats correspond to (y,z), (x,z) or (x,y) + for prisms parallel to the x, y or z axis, respectively. + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} + Boundary condition that defines the behavior for particles hitting the + surfaces comprising the rectangular prism. + albedo : float, optional + Albedo of the prism's surfaces as a ratio of particle weight after + interaction with the surface to the initial weight. Values must be + positive. Only applicable if the boundary type is 'reflective', + 'periodic', or 'white'. + corner_radius : float + Prism corner radius in units of [cm]. + + """ + _surface_names = ('min_x1', 'max_x1', 'min_x2', 'max_x2') + + def __init__( + self, + width: float, + height: float, + axis: str = 'z', + origin: Sequence[float] = (0., 0.), + boundary_type: str = 'transmission', + albedo: float = 1., + corner_radius: float = 0. + ): + check_type('width', width, Real) + check_type('height', height, Real) + check_type('albedo', albedo, Real) + check_type('corner_radius', corner_radius, Real) + check_value('axis', axis, ('x', 'y', 'z')) + check_type('origin', origin, Iterable, Real) + + if axis == 'x': + x1, x2 = 'y', 'z' + elif axis == 'y': + x1, x2 = 'x', 'z' + else: + x1, x2 = 'x', 'y' + + # Get cylinder class corresponding to given axis + cyl = getattr(openmc, f'{axis.upper()}Cylinder') + + # Create container for boundary arguments + bc_args = {'boundary_type': boundary_type, 'albedo': albedo} + + # Create rectangular region + self.min_x1 = _plane(x1, 'minimum', -width/2 + origin[0], **bc_args) + self.max_x1 = _plane(x1, 'maximum', width/2 + origin[0], **bc_args) + self.min_x2 = _plane(x2, 'minimum', -height/2 + origin[1], **bc_args) + self.max_x2 = _plane(x2, 'maximum', height/2 + origin[1], **bc_args) + if boundary_type == 'periodic': + self.min_x1.periodic_surface = self.max_x1 + self.min_x2.periodic_surface = self.max_x2 + + # Handle rounded corners if given + if corner_radius > 0.: + if boundary_type == 'periodic': + raise ValueError('Periodic boundary conditions not permitted when ' + 'rounded corners are used.') + + args = {'r': corner_radius, 'boundary_type': boundary_type, 'albedo': albedo} + + args[x1 + '0'] = origin[0] - width/2 + corner_radius + args[x2 + '0'] = origin[1] - height/2 + corner_radius + self.x1_min_x2_min = cyl(name=f'{x1} min {x2} min', **args) + + args[x1 + '0'] = origin[0] - width/2 + corner_radius + args[x2 + '0'] = origin[1] + height/2 - corner_radius + self.x1_min_x2_max = cyl(name=f'{x1} min {x2} max', **args) + + args[x1 + '0'] = origin[0] + width/2 - corner_radius + args[x2 + '0'] = origin[1] - height/2 + corner_radius + self.x1_max_x2_min = cyl(name=f'{x1} max {x2} min', **args) + + args[x1 + '0'] = origin[0] + width/2 - corner_radius + args[x2 + '0'] = origin[1] + height/2 - corner_radius + self.x1_max_x2_max = cyl(name=f'{x1} max {x2} max', **args) + + self.x1_min = _plane(x1, 'min', -width/2 + origin[0] + corner_radius, + **bc_args) + self.x1_max = _plane(x1, 'max', width/2 + origin[0] - corner_radius, + **bc_args) + self.x2_min = _plane(x2, 'min', -height/2 + origin[1] + corner_radius, + **bc_args) + self.x2_max = _plane(x2, 'max', height/2 + origin[1] - corner_radius, + **bc_args) + self._surface_names += ( + 'x1_min_x2_min', 'x1_min_x2_max', 'x1_max_x2_min', + 'x1_max_x2_max', 'x1_min', 'x1_max', 'x2_min', 'x2_max' + ) + + def __neg__(self): + prism = +self.min_x1 & -self.max_x1 & +self.min_x2 & -self.max_x2 + + # Cut out corners if a corner radius was given + if hasattr(self, 'x1_min'): + corners = ( + (+self.x1_min_x2_min & -self.x1_min & -self.x2_min) | + (+self.x1_min_x2_max & -self.x1_min & +self.x2_max) | + (+self.x1_max_x2_min & +self.x1_max & -self.x2_min) | + (+self.x1_max_x2_max & +self.x1_max & +self.x2_max) + ) + prism &= ~corners + + return prism + + +class HexagonalPrism(CompositeSurface): + """Hexagonal prism comoposed of six planar surfaces + + .. versionadded:: 0.14.0 + + Parameters + ---------- + edge_length : float + Length of a side of the hexagon in [cm] + orientation : {'x', 'y'} + An 'x' orientation means that two sides of the hexagon are parallel to + the x-axis and a 'y' orientation means that two sides of the hexagon are + parallel to the y-axis. + origin : Iterable of two floats + Origin of the prism. + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} + Boundary condition that defines the behavior for particles hitting the + surfaces comprising the hexagonal prism. + albedo : float, optional + Albedo of the prism's surfaces as a ratio of particle weight after + interaction with the surface to the initial weight. Values must be + positive. Only applicable if the boundary type is 'reflective', + 'periodic', or 'white'. + corner_radius : float + Prism corner radius in units of [cm]. + + """ + _surface_names = ('plane_max', 'plane_min', 'upper_right', 'upper_left', + 'lower_right', 'lower_left') + + def __init__( + self, + edge_length: float = 1., + orientation: str = 'y', + origin: Sequence[float] = (0., 0.), + boundary_type: str = 'transmission', + albedo: float = 1., + corner_radius: float = 0. + ): + check_type('edge_length', edge_length, Real) + check_type('albedo', albedo, Real) + check_type('corner_radius', corner_radius, Real) + check_value('orientation', orientation, ('x', 'y')) + check_type('origin', origin, Iterable, Real) + + l = edge_length + x, y = origin + + # Create container for boundary arguments + bc_args = {'boundary_type': boundary_type, 'albedo': albedo} + + if orientation == 'y': + # Left and right planes + self.plane_max = openmc.XPlane(x + sqrt(3.)/2*l, **bc_args) + self.plane_min = openmc.XPlane(x - sqrt(3.)/2*l, **bc_args) + c = sqrt(3.)/3. + + # y = -x/sqrt(3) + a + self.upper_right = openmc.Plane(a=c, b=1., d=l+x*c+y, **bc_args) + + # y = x/sqrt(3) + a + self.upper_left = openmc.Plane(a=-c, b=1., d=l-x*c+y, **bc_args) + + # y = x/sqrt(3) - a + self.lower_right = openmc.Plane(a=-c, b=1., d=-l-x*c+y, **bc_args) + + # y = -x/sqrt(3) - a + self.lower_left = openmc.Plane(a=c, b=1., d=-l+x*c+y, **bc_args) + + elif orientation == 'x': + self.plane_max = openmc.YPlane(y + sqrt(3.)/2*l, **bc_args) + self.plane_min = openmc.YPlane(y - sqrt(3.)/2*l, **bc_args) + c = sqrt(3.) + + # Upper-right surface: y = -sqrt(3)*(x - a) + self.upper_right = openmc.Plane(a=c, b=1., d=c*l+x*c+y, **bc_args) + + # Lower-right surface: y = sqrt(3)*(x + a) + self.lower_right = openmc.Plane(a=-c, b=1., d=-c*l-x*c+y, **bc_args) + + # Lower-left surface: y = -sqrt(3)*(x + a) + self.lower_left = openmc.Plane(a=c, b=1., d=-c*l+x*c+y, **bc_args) + + # Upper-left surface: y = sqrt(3)*(x + a) + self.upper_left = openmc.Plane(a=-c, b=1., d=c*l-x*c+y, **bc_args) + + # Handle periodic boundary conditions + if boundary_type == 'periodic': + self.plane_min.periodic_surface = self.plane_max + self.upper_right.periodic_surface = self.lower_left + self.lower_right.periodic_surface = self.upper_left + + # Handle rounded corners if given + if corner_radius > 0.: + if boundary_type == 'periodic': + raise ValueError('Periodic boundary conditions not permitted ' + 'when rounded corners are used.') + + c = sqrt(3.)/2 + t = l - corner_radius/c + + # Cylinder with corner radius and boundary type pre-applied + cyl1 = partial(openmc.ZCylinder, r=corner_radius, **bc_args) + cyl2 = partial(openmc.ZCylinder, r=corner_radius/(2*c), **bc_args) + + if orientation == 'x': + self.x_min_y_min_in = cyl1(name='x min y min in', x0=x-t/2, y0=y-c*t) + self.x_min_y_max_in = cyl1(name='x min y max in', x0=x+t/2, y0=y-c*t) + self.x_max_y_min_in = cyl1(name='x max y min in', x0=x-t/2, y0=y+c*t) + self.x_max_y_max_in = cyl1(name='x max y max in', x0=x+t/2, y0=y+c*t) + self.min_in = cyl1(name='x min in', x0=x-t, y0=y) + self.max_in = cyl1(name='x max in', x0=x+t, y0=y) + + self.x_min_y_min_out = cyl2(name='x min y min out', x0=x-l/2, y0=y-c*l) + self.x_min_y_max_out = cyl2(name='x min y max out', x0=x+l/2, y0=y-c*l) + self.x_max_y_min_out = cyl2(name='x max y min out', x0=x-l/2, y0=y+c*l) + self.x_max_y_max_out = cyl2(name='x max y max out', x0=x+l/2, y0=y+c*l) + self.min_out = cyl2(name='x min out', x0=x-l, y0=y) + self.max_out = cyl2(name='x max out', x0=x+l, y0=y) + + elif orientation == 'y': + self.x_min_y_min_in = cyl1(name='x min y min in', x0=x-c*t, y0=y-t/2) + self.x_min_y_max_in = cyl1(name='x min y max in', x0=x-c*t, y0=y+t/2) + self.x_max_y_min_in = cyl1(name='x max y min in', x0=x+c*t, y0=y-t/2) + self.x_max_y_max_in = cyl1(name='x max y max in', x0=x+c*t, y0=y+t/2) + self.min_in = cyl1(name='y min in', x0=x, y0=y-t) + self.max_in = cyl1(name='y max in', x0=x, y0=y+t) + + self.x_min_y_min_out = cyl2(name='x min y min out', x0=x-c*l, y0=y-l/2) + self.x_min_y_max_out = cyl2(name='x min y max out', x0=x-c*l, y0=y+l/2) + self.x_max_y_min_out = cyl2(name='x max y min out', x0=x+c*l, y0=y-l/2) + self.x_max_y_max_out = cyl2(name='x max y max out', x0=x+c*l, y0=y+l/2) + self.min_out = cyl2(name='y min out', x0=x, y0=y-l) + self.max_out = cyl2(name='y max out', x0=x, y0=y+l) + + # Add to tuple of surface names + for s in ('in', 'out'): + self._surface_names += ( + f'x_min_y_min_{s}', f'x_min_y_max_{s}', + f'x_max_y_min_{s}', f'x_max_y_max_{s}', + f'min_{s}', f'max_{s}') + + def __neg__(self) -> openmc.Region: + prism = ( + -self.plane_max & +self.plane_min & + -self.upper_right & -self.upper_left & + +self.lower_right & +self.lower_left + ) + + # Cut out corners if a corner radius was given + if hasattr(self, 'min_in'): + corners = ( + +self.x_min_y_min_in & -self.x_min_y_min_out | + +self.x_min_y_max_in & -self.x_min_y_max_out | + +self.x_max_y_min_in & -self.x_max_y_min_out | + +self.x_max_y_max_in & -self.x_max_y_max_out | + +self.min_in & -self.min_out | + +self.max_in & -self.max_out + ) + prism &= ~corners + + return prism diff --git a/openmc/model/triso.py b/openmc/model/triso.py index f486482aab6..f344b8edd42 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -138,10 +138,20 @@ def __init__(self, sphere_radius, center=(0., 0., 0.)): def sphere_radius(self): return self._sphere_radius + @sphere_radius.setter + def sphere_radius(self, sphere_radius): + self._sphere_radius = float(sphere_radius) + self._limits = None + self._cell_length = None + @property def center(self): return self._center + @center.setter + def center(self, center): + self._center = center + @abstractproperty def limits(self): pass @@ -154,15 +164,6 @@ def cell_length(self): def volume(self): pass - @sphere_radius.setter - def sphere_radius(self, sphere_radius): - self._sphere_radius = float(sphere_radius) - self._limits = None - self._cell_length = None - - @center.setter - def center(self, center): - self._center = center def mesh_cell(self, p): """Calculate the index of the cell in a mesh overlaid on the domain in @@ -300,14 +301,32 @@ def __init__(self, width, depth, height, sphere_radius, center=(0., 0., 0.)): def width(self): return self._width + @width.setter + def width(self, width): + self._width = float(width) + self._limits = None + self._cell_length = None + @property def depth(self): return self._depth + @depth.setter + def depth(self, depth): + self._depth = float(depth) + self._limits = None + self._cell_length = None + @property def height(self): return self._height + @height.setter + def height(self, height): + self._height = float(height) + self._limits = None + self._cell_length = None + @property def limits(self): if self._limits is None: @@ -316,8 +335,13 @@ def limits(self): x, y, z = self.width/2, self.depth/2, self.height/2 self._limits = [[c[0] - x + r, c[1] - y + r, c[2] - z + r], [c[0] + x - r, c[1] + y - r, c[2] + z - r]] + return self._limits + @limits.setter + def limits(self, limits): + self._limits = limits + @property def cell_length(self): if self._cell_length is None: @@ -330,28 +354,6 @@ def cell_length(self): def volume(self): return self.width*self.depth*self.height - @width.setter - def width(self, width): - self._width = float(width) - self._limits = None - self._cell_length = None - - @depth.setter - def depth(self, depth): - self._depth = float(depth) - self._limits = None - self._cell_length = None - - @height.setter - def height(self, height): - self._height = float(height) - self._limits = None - self._cell_length = None - - @limits.setter - def limits(self, limits): - self._limits = limits - @classmethod def from_region(self, region, sphere_radius): check_type('region', region, openmc.Region) @@ -470,14 +472,31 @@ def __init__(self, length, radius, axis, sphere_radius, center=(0., 0., 0.)): def length(self): return self._length + @length.setter + def length(self, length): + self._length = float(length) + self._limits = None + self._cell_length = None + @property def radius(self): return self._radius + @radius.setter + def radius(self, radius): + self._radius = float(radius) + self._limits = None + self._cell_length = None + @property def axis(self): return self._axis + @axis.setter + def axis(self, axis): + self._axis = axis + self._shift = None + @property def shift(self): if self._shift is None: @@ -498,6 +517,10 @@ def limits(self): self._limits = [[z0 - z + r], [z0 + z - r, self.radius - r]] return self._limits + @limits.setter + def limits(self, limits): + self._limits = limits + @property def cell_length(self): if self._cell_length is None: @@ -513,27 +536,6 @@ def cell_length(self): def volume(self): return self.length*pi*self.radius**2 - @length.setter - def length(self, length): - self._length = float(length) - self._limits = None - self._cell_length = None - - @radius.setter - def radius(self, radius): - self._radius = float(radius) - self._limits = None - self._cell_length = None - - @axis.setter - def axis(self, axis): - self._axis = axis - self._shift = None - - @limits.setter - def limits(self, limits): - self._limits = limits - @classmethod def from_region(self, region, sphere_radius): check_type('region', region, openmc.Region) @@ -676,10 +678,21 @@ def __init__(self, radius, inner_radius, sphere_radius, def radius(self): return self._radius + @radius.setter + def radius(self, radius): + self._radius = float(radius) + self._limits = None + self._cell_length = None + @property def inner_radius(self): return self._inner_radius + @inner_radius.setter + def inner_radius(self, inner_radius): + self._inner_radius = float(inner_radius) + self._limits = None + @property def limits(self): if self._limits is None: @@ -691,6 +704,10 @@ def limits(self): self._limits = [[r_min], [r_max]] return self._limits + @limits.setter + def limits(self, limits): + self._limits = limits + @property def cell_length(self): if self._cell_length is None: @@ -703,21 +720,6 @@ def cell_length(self): def volume(self): return _volume_sphere(self.radius) - _volume_sphere(self.inner_radius) - @radius.setter - def radius(self, radius): - self._radius = float(radius) - self._limits = None - self._cell_length = None - - @inner_radius.setter - def inner_radius(self, inner_radius): - self._inner_radius = float(inner_radius) - self._limits = None - - @limits.setter - def limits(self, limits): - self._limits = limits - @classmethod def from_region(self, region, sphere_radius): check_type('region', region, openmc.Region) @@ -1206,7 +1208,7 @@ def update_rod_list(i): def pack_spheres(radius, region, pf=None, num_spheres=None, initial_pf=0.3, - contraction_rate=1.e-3, seed=1): + contraction_rate=1.e-3, seed=None): """Generate a random, non-overlapping configuration of spheres within a container. @@ -1235,7 +1237,7 @@ def pack_spheres(radius, region, pf=None, num_spheres=None, initial_pf=0.3, reached using a smaller contraction rate, but the algorithm will take longer to converge. seed : int, optional - RNG seed. + Pseudorandom number generator seed passed to :func:`random.seed` Returns ------ @@ -1278,7 +1280,8 @@ def pack_spheres(radius, region, pf=None, num_spheres=None, initial_pf=0.3, """ # Seed RNG - random.seed(seed) + if seed is not None: + random.seed(seed) # Create container with the correct shape based on the supplied region domain = None @@ -1310,14 +1313,13 @@ def pack_spheres(radius, region, pf=None, num_spheres=None, initial_pf=0.3, # Check packing fraction for close random packing if pf > MAX_PF_CRP: - raise ValueError('Packing fraction {0} is greater than the limit for ' - 'close random packing, {1}'.format(pf, MAX_PF_CRP)) + raise ValueError(f'Packing fraction {pf} is greater than the limit for ' + f'close random packing, {MAX_PF_CRP}') # Check packing fraction for random sequential packing if initial_pf > MAX_PF_RSP: - raise ValueError('Initial packing fraction {0} is greater than the ' - 'limit for random sequential packing, ' - '{1}'.format(initial_pf, MAX_PF_RSP)) + raise ValueError(f'Initial packing fraction {initial_pf} is greater than' + f'the limit for random sequential packing, {MAX_PF_RSP}') # Calculate the sphere radius used in the initial random sequential # packing from the initial packing fraction diff --git a/openmc/mpi.py b/openmc/mpi.py new file mode 100644 index 00000000000..cfc10c0d189 --- /dev/null +++ b/openmc/mpi.py @@ -0,0 +1,8 @@ +try: + from mpi4py import MPI + comm = MPI.COMM_WORLD +except ImportError: + from unittest.mock import Mock + MPI = Mock() + from openmc.dummy_comm import DummyCommunicator + comm = DummyCommunicator() diff --git a/openmc/nuclide.py b/openmc/nuclide.py index fcbfc2d6067..d5ae4bddbb4 100644 --- a/openmc/nuclide.py +++ b/openmc/nuclide.py @@ -26,8 +26,8 @@ def __new__(cls, name): if name.endswith('m'): name = name[:-1] + '_m1' - msg = 'OpenMC nuclides follow the GND naming convention. Nuclide ' \ - '"{}" is being renamed as "{}".'.format(orig_name, name) + msg = ('OpenMC nuclides follow the GNDS naming convention. ' + f'Nuclide "{orig_name}" is being renamed as "{name}".') warnings.warn(msg) return super().__new__(cls, name) diff --git a/openmc/openmoc_compatible.py b/openmc/openmoc_compatible.py index 1ae120df6f5..3fd54520ba5 100644 --- a/openmc/openmoc_compatible.py +++ b/openmc/openmoc_compatible.py @@ -193,9 +193,9 @@ def get_openmoc_surface(openmc_surface): openmoc_surface = openmoc.ZCylinder(x0, y0, R, surface_id, name) else: - msg = 'Unable to create an OpenMOC Surface from an OpenMC ' \ - 'Surface of type "{}" since it is not a compatible ' \ - 'Surface type in OpenMOC'.format(type(openmc_surface)) + msg = ('Unable to create an OpenMOC Surface from an OpenMC Surface of ' + f'type "{type(openmc_surface)}" since it is not a compatible ' + 'Surface type in OpenMOC') raise ValueError(msg) # Set the boundary condition for this Surface diff --git a/openmc/plots.py b/openmc/plots.py index f275a84818b..df4a7663310 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -1,16 +1,18 @@ from collections.abc import Iterable, Mapping -from numbers import Real, Integral +from numbers import Integral, Real from pathlib import Path -import subprocess -from xml.etree import ElementTree as ET +from typing import Optional +import h5py +import lxml.etree as ET import numpy as np import openmc import openmc.checkvalue as cv -from ._xml import clean_indentation, reorder_attributes -from .mixin import IDManagerMixin +from openmc.checkvalue import PathLike +from ._xml import clean_indentation, get_elem_tuple, reorder_attributes, get_text +from .mixin import IDManagerMixin _BASES = ['xy', 'xz', 'yz'] @@ -165,14 +167,94 @@ } -class Plot(IDManagerMixin): - """Definition of a finite region of space to be plotted. +def _get_plot_image(plot, cwd): + from IPython.display import Image - OpenMC is capable of generating two-dimensional slice plots and - three-dimensional voxel plots. Colors that are used in plots can be given as - RGB tuples, e.g. (255, 255, 255) would be white, or by a string indicating a - valid `SVG color `_. + # Make sure .png file was created + stem = plot.filename if plot.filename is not None else f'plot_{plot.id}' + png_file = Path(cwd) / f'{stem}.png' + if not png_file.exists(): + raise FileNotFoundError( + f"Could not find .png image for plot {plot.id}. Your version of " + "OpenMC may not be built against libpng.") + + return Image(str(png_file)) + + +def voxel_to_vtk(voxel_file: PathLike, output: PathLike = 'plot.vti'): + """Converts a voxel HDF5 file to a VTK file + .. versionadded:: 0.14.0 + + Parameters + ---------- + voxel_file : path-like + Path of the input h5 to convert + output : path-like + Path of the output vti file produced + + Returns + ------- + Path + Path of the .vti file produced + """ + + # imported vtk only if used as vtk is an option dependency + import vtk + + _min_version = (2, 0) + + # Read data from voxel file + with h5py.File(voxel_file, "r") as fh: + # check version + version = tuple(fh.attrs["version"]) + if version < _min_version: + old_version = ".".join(map(str, version)) + min_version = ".".join(map(str, _min_version)) + err_msg = ( + f"This voxel file's version is {old_version}. This function only " + f" supports voxel files with version {min_version} or higher. " + "Please generate a new voxel file using a newer version of OpenMC." + ) + raise ValueError(err_msg) + + dimension = fh.attrs["num_voxels"] + width = fh.attrs["voxel_width"] + lower_left = fh.attrs["lower_left"] + + nx, ny, nz = dimension + + grid = vtk.vtkImageData() + grid.SetDimensions(nx + 1, ny + 1, nz + 1) + grid.SetOrigin(*lower_left) + grid.SetSpacing(*width) + + # transpose data from OpenMC ordering (zyx) to VTK ordering (xyz) + # and flatten to 1-D array + h5data = fh["data"][...] + + data = vtk.vtkIntArray() + data.SetName("id") + # set the array using the h5data array + data.SetArray(h5data, h5data.size, True) + # add data to image grid + grid.GetCellData().AddArray(data) + + writer = vtk.vtkXMLImageDataWriter() + if vtk.vtkVersion.GetVTKMajorVersion() > 5: + writer.SetInputData(grid) + else: + writer.SetInput(grid) + if not output.endswith(".vti"): + output += ".vti" + writer.SetFileName(str(output)) + writer.Write() + + return output + + +class PlotBase(IDManagerMixin): + """ Parameters ---------- plot_id : int @@ -186,39 +268,29 @@ class Plot(IDManagerMixin): Unique identifier name : str Name of the plot - width : Iterable of float - Width of the plot in each basis direction pixels : Iterable of int - Number of pixels to use in each basis direction - origin : tuple or list of ndarray - Origin (center) of the plot - filename : + Number of pixels to use in each direction + filename : str Path to write the plot to color_by : {'cell', 'material'} Indicate whether the plot should be colored by cell or by material - type : {'slice', 'voxel'} - The type of the plot - basis : {'xy', 'xz', 'yz'} - The basis directions for the plot background : Iterable of int or str Color of the background - mask_components : Iterable of openmc.Cell or openmc.Material - The cells or materials to plot + mask_components : Iterable of openmc.Cell or openmc.Material or int + The cells or materials (or corresponding IDs) to mask mask_background : Iterable of int or str - Color to apply to all cells/materials not listed in mask_components + Color to apply to all cells/materials listed in mask_components show_overlaps : bool - Inidicate whether or not overlapping regions are shown + Indicate whether or not overlapping regions are shown overlap_color : Iterable of int or str Color to apply to overlapping regions colors : dict - Dictionary indicating that certain cells/materials (keys) should be - displayed with a particular color. + Dictionary indicating that certain cells/materials should be + displayed with a particular color. The keys can be of type + :class:`~openmc.Cell`, :class:`~openmc.Material`, or int (ID for a + cell/material). level : int Universe depth to plot at - meshlines : dict - Dictionary defining type, id, linewidth and color of a mesh to be - plotted on top of a plot - """ next_id = 1 @@ -228,13 +300,9 @@ def __init__(self, plot_id=None, name=''): # Initialize Plot class attributes self.id = plot_id self.name = name - self._width = [4.0, 4.0] self._pixels = [400, 400] - self._origin = [0., 0., 0.] self._filename = None self._color_by = 'cell' - self._type = 'slice' - self._basis = 'xy' self._background = None self._mask_components = None self._mask_background = None @@ -242,88 +310,19 @@ def __init__(self, plot_id=None, name=''): self._overlap_color = None self._colors = {} self._level = None - self._meshlines = None @property def name(self): return self._name - @property - def width(self): - return self._width - - @property - def pixels(self): - return self._pixels - - @property - def origin(self): - return self._origin - - @property - def filename(self): - return self._filename - - @property - def color_by(self): - return self._color_by - - @property - def type(self): - return self._type - - @property - def basis(self): - return self._basis - - @property - def background(self): - return self._background - - @property - def mask_components(self): - return self._mask_components - - @property - def mask_background(self): - return self._mask_background - - @property - def show_overlaps(self): - return self._show_overlaps - - @property - def overlap_color(self): - return self._overlap_color - - @property - def colors(self): - return self._colors - - @property - def level(self): - return self._level - - @property - def meshlines(self): - return self._meshlines - @name.setter def name(self, name): cv.check_type('plot name', name, str) self._name = name - @width.setter - def width(self, width): - cv.check_type('plot width', width, Iterable, Real) - cv.check_length('plot width', width, 2, 3) - self._width = width - - @origin.setter - def origin(self, origin): - cv.check_type('plot origin', origin, Iterable, Real) - cv.check_length('plot origin', origin, 3) - self._origin = origin + @property + def pixels(self): + return self._pixels @pixels.setter def pixels(self, pixels): @@ -333,101 +332,100 @@ def pixels(self, pixels): cv.check_greater_than('plot pixels', dim, 0) self._pixels = pixels + @property + def filename(self): + return self._filename + @filename.setter def filename(self, filename): cv.check_type('filename', filename, str) self._filename = filename + @property + def color_by(self): + return self._color_by + @color_by.setter def color_by(self, color_by): cv.check_value('plot color_by', color_by, ['cell', 'material']) self._color_by = color_by - @type.setter - def type(self, plottype): - cv.check_value('plot type', plottype, ['slice', 'voxel']) - self._type = plottype - - @basis.setter - def basis(self, basis): - cv.check_value('plot basis', basis, _BASES) - self._basis = basis + @property + def background(self): + return self._background @background.setter def background(self, background): self._check_color('plot background', background) self._background = background - @colors.setter - def colors(self, colors): - cv.check_type('plot colors', colors, Mapping) - for key, value in colors.items(): - cv.check_type('plot color key', key, (openmc.Cell, openmc.Material)) - self._check_color('plot color value', value) - self._colors = colors + @property + def mask_components(self): + return self._mask_components @mask_components.setter def mask_components(self, mask_components): cv.check_type('plot mask components', mask_components, Iterable, - (openmc.Cell, openmc.Material)) + (openmc.Cell, openmc.Material, Integral)) self._mask_components = mask_components + @property + def mask_background(self): + return self._mask_background + @mask_background.setter def mask_background(self, mask_background): self._check_color('plot mask background', mask_background) self._mask_background = mask_background + @property + def show_overlaps(self): + return self._show_overlaps + @show_overlaps.setter def show_overlaps(self, show_overlaps): - cv.check_type('Show overlaps flag for Plot ID="{}"'.format(self.id), + cv.check_type(f'Show overlaps flag for Plot ID="{self.id}"', show_overlaps, bool) self._show_overlaps = show_overlaps + @property + def overlap_color(self): + return self._overlap_color + @overlap_color.setter def overlap_color(self, overlap_color): self._check_color('plot overlap color', overlap_color) self._overlap_color = overlap_color + @property + def colors(self): + return self._colors + + @colors.setter + def colors(self, colors): + cv.check_type('plot colors', colors, Mapping) + for key, value in colors.items(): + cv.check_type('plot color key', key, + (openmc.Cell, openmc.Material, Integral)) + self._check_color('plot color value', value) + self._colors = colors + + @property + def level(self): + return self._level + @level.setter def level(self, plot_level): cv.check_type('plot level', plot_level, Integral) cv.check_greater_than('plot level', plot_level, 0, equality=True) self._level = plot_level - @meshlines.setter - def meshlines(self, meshlines): - cv.check_type('plot meshlines', meshlines, dict) - if 'type' not in meshlines: - msg = 'Unable to set the meshlines to "{}" which ' \ - 'does not have a "type" key'.format(meshlines) - raise ValueError(msg) - - elif meshlines['type'] not in ['tally', 'entropy', 'ufs', 'cmfd']: - msg = 'Unable to set the meshlines with ' \ - 'type "{}"'.format(meshlines['type']) - raise ValueError(msg) - - if 'id' in meshlines: - cv.check_type('plot meshlines id', meshlines['id'], Integral) - cv.check_greater_than('plot meshlines id', meshlines['id'], 0, - equality=True) - - if 'linewidth' in meshlines: - cv.check_type('plot mesh linewidth', meshlines['linewidth'], Integral) - cv.check_greater_than('plot mesh linewidth', meshlines['linewidth'], - 0, equality=True) - - if 'color' in meshlines: - self._check_color('plot meshlines color', meshlines['color']) - - self._meshlines = meshlines - @staticmethod def _check_color(err_string, color): cv.check_type(err_string, color, Iterable) if isinstance(color, str): if color.lower() not in _SVG_COLORS: - raise ValueError("'{}' is not a valid color.".format(color)) + raise ValueError(f"'{color}' is not a valid color.") else: cv.check_length(err_string, color, 3) for rgb in color: @@ -435,73 +433,11 @@ def _check_color(err_string, color): cv.check_greater_than('RGB component', rgb, 0, True) cv.check_less_than('RGB component', rgb, 256) - def __repr__(self): - string = 'Plot\n' - string += '{: <16}=\t{}\n'.format('\tID', self._id) - string += '{: <16}=\t{}\n'.format('\tName', self._name) - string += '{: <16}=\t{}\n'.format('\tFilename', self._filename) - string += '{: <16}=\t{}\n'.format('\tType', self._type) - string += '{: <16}=\t{}\n'.format('\tBasis', self._basis) - string += '{: <16}=\t{}\n'.format('\tWidth', self._width) - string += '{: <16}=\t{}\n'.format('\tOrigin', self._origin) - string += '{: <16}=\t{}\n'.format('\tPixels', self._pixels) - string += '{: <16}=\t{}\n'.format('\tColor by', self._color_by) - string += '{: <16}=\t{}\n'.format('\tBackground', self._background) - string += '{: <16}=\t{}\n'.format('\tMask components', - self._mask_components) - string += '{: <16}=\t{}\n'.format('\tMask background', - self._mask_background) - string += '{: <16}=\t{}\n'.format('\tOverlap Color', - self._overlap_color) - string += '{: <16}=\t{}\n'.format('\tColors', self._colors) - string += '{: <16}=\t{}\n'.format('\tLevel', self._level) - string += '{: <16}=\t{}\n'.format('\tMeshlines', self._meshlines) - return string - - @classmethod - def from_geometry(cls, geometry, basis='xy', slice_coord=0.): - """Return plot that encompasses a geometry. - - Parameters - ---------- - geometry : openmc.Geometry - The geometry to base the plot off of - basis : {'xy', 'xz', 'yz'} - The basis directions for the plot - slice_coord : float - The level at which the slice plot should be plotted. For example, if - the basis is 'xy', this would indicate the z value used in the - origin. - - """ - cv.check_type('geometry', geometry, openmc.Geometry) - cv.check_value('basis', basis, _BASES) - - # Decide which axes to keep - if basis == 'xy': - pick_index = (0, 1) - slice_index = 2 - elif basis == 'yz': - pick_index = (1, 2) - slice_index = 0 - elif basis == 'xz': - pick_index = (0, 2) - slice_index = 1 - - # Get lower-left and upper-right coordinates for desired axes - lower_left, upper_right = geometry.bounding_box - lower_left = lower_left[np.array(pick_index)] - upper_right = upper_right[np.array(pick_index)] - - if np.any(np.isinf((lower_left, upper_right))): - raise ValueError('The geometry does not appear to be bounded ' - 'in the {} plane.'.format(basis)) - - plot = cls() - plot.origin = np.insert((lower_left + upper_right)/2, - slice_index, slice_coord) - plot.width = upper_right - lower_left - return plot + # Helper function that returns the domain ID given either a + # Cell/Material object or the domain ID itself + @staticmethod + def _get_id(domain): + return domain if isinstance(domain, Integral) else domain.id def colorize(self, geometry, seed=1): """Generate a color scheme for each domain in the plot. @@ -529,15 +465,266 @@ def colorize(self, geometry, seed=1): domains = geometry.get_all_cells().values() # Set the seed for the random number generator - np.random.seed(seed) + rng = np.random.RandomState(seed) # Generate random colors for each feature for domain in domains: - self.colors[domain] = np.random.randint(0, 256, (3,)) + self.colors[domain] = rng.randint(0, 256, (3,)) - def highlight_domains(self, geometry, domains, seed=1, - alpha=0.5, background='gray'): - """Use alpha compositing to highlight one or more domains in the plot. + def to_xml_element(self): + """Save common plot attributes to XML element + + Returns + ------- + element : lxml.etree._Element + XML element containing plot data + + """ + + element = ET.Element("plot") + element.set("id", str(self._id)) + if len(self._name) > 0: + element.set("name", str(self.name)) + if self._filename is not None: + element.set("filename", self._filename) + element.set("color_by", self._color_by) + + subelement = ET.SubElement(element, "pixels") + subelement.text = ' '.join(map(str, self._pixels)) + + if self._background is not None: + subelement = ET.SubElement(element, "background") + color = self._background + if isinstance(color, str): + color = _SVG_COLORS[color.lower()] + subelement.text = ' '.join(str(x) for x in color) + + if self._mask_components is not None: + subelement = ET.SubElement(element, "mask") + subelement.set("components", ' '.join( + str(PlotBase._get_id(d)) for d in self._mask_components)) + color = self._mask_background + if color is not None: + if isinstance(color, str): + color = _SVG_COLORS[color.lower()] + subelement.set("background", ' '.join( + str(x) for x in color)) + + if self._level is not None: + subelement = ET.SubElement(element, "level") + subelement.text = str(self._level) + + return element + + +class Plot(PlotBase): + """Definition of a finite region of space to be plotted. + + OpenMC is capable of generating two-dimensional slice plots, or + three-dimensional voxel or projection plots. Colors that are used in plots can be given as + RGB tuples, e.g. (255, 255, 255) would be white, or by a string indicating a + valid `SVG color `_. + + Parameters + ---------- + plot_id : int + Unique identifier for the plot + name : str + Name of the plot + + Attributes + ---------- + id : int + Unique identifier + name : str + Name of the plot + pixels : Iterable of int + Number of pixels to use in each direction + filename : str + Path to write the plot to + color_by : {'cell', 'material'} + Indicate whether the plot should be colored by cell or by material + background : Iterable of int or str + Color of the background + mask_components : Iterable of openmc.Cell or openmc.Material or int + The cells or materials (or corresponding IDs) to mask + mask_background : Iterable of int or str + Color to apply to all cells/materials listed in mask_components + show_overlaps : bool + Indicate whether or not overlapping regions are shown + overlap_color : Iterable of int or str + Color to apply to overlapping regions + colors : dict + Dictionary indicating that certain cells/materials should be + displayed with a particular color. The keys can be of type + :class:`~openmc.Cell`, :class:`~openmc.Material`, or int (ID for a + cell/material). + level : int + Universe depth to plot at + width : Iterable of float + Width of the plot in each basis direction + origin : tuple or list of ndarray + Origin (center) of the plot + type : {'slice', 'voxel'} + The type of the plot + basis : {'xy', 'xz', 'yz'} + The basis directions for the plot + meshlines : dict + Dictionary defining type, id, linewidth and color of a mesh to be + plotted on top of a plot + + """ + + def __init__(self, plot_id=None, name=''): + super().__init__(plot_id, name) + self._width = [4.0, 4.0] + self._origin = [0., 0., 0.] + self._type = 'slice' + self._basis = 'xy' + self._meshlines = None + + @property + def width(self): + return self._width + + @width.setter + def width(self, width): + cv.check_type('plot width', width, Iterable, Real) + cv.check_length('plot width', width, 2, 3) + self._width = width + + @property + def origin(self): + return self._origin + + @origin.setter + def origin(self, origin): + cv.check_type('plot origin', origin, Iterable, Real) + cv.check_length('plot origin', origin, 3) + self._origin = origin + + @property + def type(self): + return self._type + + @type.setter + def type(self, plottype): + cv.check_value('plot type', plottype, ['slice', 'voxel']) + self._type = plottype + + @property + def basis(self): + return self._basis + + @basis.setter + def basis(self, basis): + cv.check_value('plot basis', basis, _BASES) + self._basis = basis + + @property + def meshlines(self): + return self._meshlines + + @meshlines.setter + def meshlines(self, meshlines): + cv.check_type('plot meshlines', meshlines, dict) + if 'type' not in meshlines: + msg = f'Unable to set the meshlines to "{meshlines}" which ' \ + 'does not have a "type" key' + raise ValueError(msg) + + elif meshlines['type'] not in ['tally', 'entropy', 'ufs', 'cmfd']: + msg = f"Unable to set the meshlines with type \"{meshlines['type']}\"" + raise ValueError(msg) + + if 'id' in meshlines: + cv.check_type('plot meshlines id', meshlines['id'], Integral) + cv.check_greater_than('plot meshlines id', meshlines['id'], 0, + equality=True) + + if 'linewidth' in meshlines: + cv.check_type('plot mesh linewidth', + meshlines['linewidth'], Integral) + cv.check_greater_than('plot mesh linewidth', meshlines['linewidth'], + 0, equality=True) + + if 'color' in meshlines: + self._check_color('plot meshlines color', meshlines['color']) + + self._meshlines = meshlines + + def __repr__(self): + string = 'Plot\n' + string += '{: <16}=\t{}\n'.format('\tID', self._id) + string += '{: <16}=\t{}\n'.format('\tName', self._name) + string += '{: <16}=\t{}\n'.format('\tFilename', self._filename) + string += '{: <16}=\t{}\n'.format('\tType', self._type) + string += '{: <16}=\t{}\n'.format('\tBasis', self._basis) + string += '{: <16}=\t{}\n'.format('\tWidth', self._width) + string += '{: <16}=\t{}\n'.format('\tOrigin', self._origin) + string += '{: <16}=\t{}\n'.format('\tPixels', self._pixels) + string += '{: <16}=\t{}\n'.format('\tColor by', self._color_by) + string += '{: <16}=\t{}\n'.format('\tBackground', self._background) + string += '{: <16}=\t{}\n'.format('\tMask components', + self._mask_components) + string += '{: <16}=\t{}\n'.format('\tMask background', + self._mask_background) + string += '{: <16}=\t{}\n'.format('\tOverlap Color', + self._overlap_color) + string += '{: <16}=\t{}\n'.format('\tColors', self._colors) + string += '{: <16}=\t{}\n'.format('\tLevel', self._level) + string += '{: <16}=\t{}\n'.format('\tMeshlines', self._meshlines) + return string + + @classmethod + def from_geometry(cls, geometry, basis='xy', slice_coord=0.): + """Return plot that encompasses a geometry. + + Parameters + ---------- + geometry : openmc.Geometry + The geometry to base the plot off of + basis : {'xy', 'xz', 'yz'} + The basis directions for the plot + slice_coord : float + The level at which the slice plot should be plotted. For example, if + the basis is 'xy', this would indicate the z value used in the + origin. + + """ + cv.check_type('geometry', geometry, openmc.Geometry) + cv.check_value('basis', basis, _BASES) + + # Decide which axes to keep + if basis == 'xy': + pick_index = (0, 1) + slice_index = 2 + elif basis == 'yz': + pick_index = (1, 2) + slice_index = 0 + elif basis == 'xz': + pick_index = (0, 2) + slice_index = 1 + + # Get lower-left and upper-right coordinates for desired axes + lower_left, upper_right = geometry.bounding_box + lower_left = lower_left[np.array(pick_index)] + upper_right = upper_right[np.array(pick_index)] + + if np.any(np.isinf((lower_left, upper_right))): + raise ValueError('The geometry does not appear to be bounded ' + f'in the {basis} plane.') + + plot = cls() + plot.origin = np.insert((lower_left + upper_right)/2, + slice_index, slice_coord) + plot.width = upper_right - lower_left + plot.basis = basis + return plot + + def highlight_domains(self, geometry, domains, seed=1, + alpha=0.5, background='gray'): + """Use alpha compositing to highlight one or more domains in the plot. This routine generates a color scheme and applies alpha compositing to make all domains except the highlighted ones appear partially @@ -552,9 +739,9 @@ def highlight_domains(self, geometry, domains, seed=1, seed : int The random number seed used to generate the color scheme alpha : float - The value between 0 and 1 to apply in alpha compisiting + The value between 0 and 1 to apply in alpha compositing background : 3-tuple of int or str - The background color to apply in alpha compisiting + The background color to apply in alpha compositing """ @@ -568,7 +755,7 @@ def highlight_domains(self, geometry, domains, seed=1, # Get a background (R,G,B) tuple to apply in alpha compositing if isinstance(background, str): if background.lower() not in _SVG_COLORS: - raise ValueError("'{}' is not a valid color.".format(background)) + raise ValueError(f"'{background}' is not a valid color.") background = _SVG_COLORS[background.lower()] # Generate a color scheme @@ -587,20 +774,16 @@ def highlight_domains(self, geometry, domains, seed=1, self._colors[domain] = (r, g, b) def to_xml_element(self): - """Return XML representation of the plot + """Return XML representation of the slice/voxel plot Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing plot data """ - element = ET.Element("plot") - element.set("id", str(self._id)) - if self._filename is not None: - element.set("filename", self._filename) - element.set("color_by", self._color_by) + element = super().to_xml_element() element.set("type", self._type) if self._type == 'slice': @@ -612,36 +795,15 @@ def to_xml_element(self): subelement = ET.SubElement(element, "width") subelement.text = ' '.join(map(str, self._width)) - subelement = ET.SubElement(element, "pixels") - subelement.text = ' '.join(map(str, self._pixels)) - - if self._background is not None: - subelement = ET.SubElement(element, "background") - color = self._background - if isinstance(color, str): - color = _SVG_COLORS[color.lower()] - subelement.text = ' '.join(str(x) for x in color) - if self._colors: for domain, color in sorted(self._colors.items(), - key=lambda x: x[0].id): + key=lambda x: PlotBase._get_id(x[0])): subelement = ET.SubElement(element, "color") - subelement.set("id", str(domain.id)) + subelement.set("id", str(PlotBase._get_id(domain))) if isinstance(color, str): color = _SVG_COLORS[color.lower()] subelement.set("rgb", ' '.join(str(x) for x in color)) - if self._mask_components is not None: - subelement = ET.SubElement(element, "mask") - subelement.set("components", ' '.join( - str(d.id) for d in self._mask_components)) - color = self._mask_background - if color is not None: - if isinstance(color, str): - color = _SVG_COLORS[color.lower()] - subelement.set("background", ' '.join( - str(x) for x in color)) - if self._show_overlaps: subelement = ET.SubElement(element, "show_overlaps") subelement.text = "true" @@ -653,33 +815,104 @@ def to_xml_element(self): subelement = ET.SubElement(element, "overlap_color") subelement.text = ' '.join(str(x) for x in color) - - if self._level is not None: - subelement = ET.SubElement(element, "level") - subelement.text = str(self._level) - if self._meshlines is not None: subelement = ET.SubElement(element, "meshlines") subelement.set("meshtype", self._meshlines['type']) - if self._meshlines['id'] is not None: + if 'id' in self._meshlines: subelement.set("id", str(self._meshlines['id'])) - if self._meshlines['linewidth'] is not None: + if 'linewidth' in self._meshlines: subelement.set("linewidth", str(self._meshlines['linewidth'])) - if self._meshlines['color'] is not None: + if 'color' in self._meshlines: subelement.set("color", ' '.join(map( str, self._meshlines['color']))) return element - def to_ipython_image(self, openmc_exec='openmc', cwd='.', - convert_exec='convert'): + @classmethod + def from_xml_element(cls, elem): + """Generate plot object from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.Plot + Plot object + + """ + plot_id = int(elem.get("id")) + name = get_text(elem, 'name', '') + plot = cls(plot_id, name) + if "filename" in elem.keys(): + plot.filename = elem.get("filename") + plot.color_by = elem.get("color_by") + plot.type = elem.get("type") + if plot.type == 'slice': + plot.basis = elem.get("basis") + + plot.origin = get_elem_tuple(elem, "origin", float) + plot.width = get_elem_tuple(elem, "width", float) + plot.pixels = get_elem_tuple(elem, "pixels") + plot._background = get_elem_tuple(elem, "background") + + # Set plot colors + colors = {} + for color_elem in elem.findall("color"): + uid = int(color_elem.get("id")) + colors[uid] = tuple([int(x) + for x in color_elem.get("rgb").split()]) + plot.colors = colors + + # Set masking information + mask_elem = elem.find("mask") + if mask_elem is not None: + plot.mask_components = [ + int(x) for x in mask_elem.get("components").split()] + background = mask_elem.get("background") + if background is not None: + plot.mask_background = tuple( + [int(x) for x in background.split()]) + + # show overlaps + overlap_elem = elem.find("show_overlaps") + if overlap_elem is not None: + plot.show_overlaps = (overlap_elem.text in ('true', '1')) + overlap_color = get_elem_tuple(elem, "overlap_color") + if overlap_color is not None: + plot.overlap_color = overlap_color + + # Set universe level + level = elem.find("level") + if level is not None: + plot.level = int(level.text) + + # Set meshlines + mesh_elem = elem.find("meshlines") + if mesh_elem is not None: + meshlines = {'type': mesh_elem.get('meshtype')} + if 'id' in mesh_elem.keys(): + meshlines['id'] = int(mesh_elem.get('id')) + if 'linewidth' in mesh_elem.keys(): + meshlines['linewidth'] = int(mesh_elem.get('linewidth')) + if 'color' in mesh_elem.keys(): + meshlines['color'] = tuple( + [int(x) for x in mesh_elem.get('color').split()] + ) + plot.meshlines = meshlines + + return plot + + def to_ipython_image(self, openmc_exec='openmc', cwd='.'): """Render plot as an image - This method runs OpenMC in plotting mode to produce a bitmap image which - is then converted to a .png file and loaded in as an - :class:`IPython.display.Image` object. As such, it requires that your - model geometry, materials, and settings have already been exported to - XML. + This method runs OpenMC in plotting mode to produce a .png file. + + .. versionchanged:: 0.13.0 + The *convert_exec* argument was removed since OpenMC now produces + .png images directly. Parameters ---------- @@ -687,8 +920,6 @@ def to_ipython_image(self, openmc_exec='openmc', cwd='.', Path to OpenMC executable cwd : str, optional Path to working directory to run in - convert_exec : str, optional - Command that can convert PPM files into PNG files Returns ------- @@ -696,31 +927,407 @@ def to_ipython_image(self, openmc_exec='openmc', cwd='.', Image generated """ - from IPython.display import Image - # Create plots.xml - Plots([self]).export_to_xml() + Plots([self]).export_to_xml(cwd) # Run OpenMC in geometry plotting mode openmc.plot_geometry(False, openmc_exec, cwd) - # Convert to .png - if self.filename is not None: - ppm_file = '{}.ppm'.format(self.filename) + # Return produced image + return _get_plot_image(self, cwd) + + def to_vtk(self, output: Optional[PathLike] = None, + openmc_exec: str = 'openmc', cwd: str = '.'): + """Render plot as an voxel image + + This method runs OpenMC in plotting mode to produce a .vti file. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + output : path-like + Path of the output .vti file produced + openmc_exec : str + Path to OpenMC executable + cwd : str, optional + Path to working directory to run in + + Returns + ------- + Path + Path of the .vti file produced + + """ + if self.type != 'voxel': + raise ValueError('Generating a VTK file only works for voxel plots') + + # Create plots.xml + Plots([self]).export_to_xml(cwd) + + # Run OpenMC in geometry plotting mode and produces a h5 file + openmc.plot_geometry(False, openmc_exec, cwd) + + stem = self.filename if self.filename is not None else f'plot_{self.id}' + h5_voxel_file = Path(cwd) / f'{stem}.h5' + if output is None: + output = h5_voxel_file.with_suffix('.vti') + + return voxel_to_vtk(h5_voxel_file, output) + + +class ProjectionPlot(PlotBase): + """Definition of a camera's view of OpenMC geometry + + Colors are defined in the same manner as the Plot class, but with the addition + of a coloring parameter resembling a macroscopic cross section in units of inverse + centimeters. The volume rendering technique is used to color regions of the model. + An infinite cross section denotes a fully opaque region, and zero represents a + transparent region which will expose the color of the regions behind it. + + The camera projection may either by orthographic or perspective. Perspective + projections are more similar to a pinhole camera, and orthographic projections + preserve parallel lines and distances. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + plot_id : int + Unique identifier for the plot + name : str + Name of the plot + + Attributes + ---------- + horizontal_field_of_view : float + Field of view horizontally, in units of degrees, defaults to 70. + camera_position : tuple or list of ndarray + Position of the camera in 3D space. Defaults to (1, 0, 0). + look_at : tuple or list of ndarray + The center of the camera's image points to this place in 3D space. + Set to (0, 0, 0) by default. + up : tuple or list of ndarray + Which way is up for the camera. Must not be parallel to the + line between look_at and camera_position. Set to (0, 0, 1) by default. + orthographic_width : float + If set to a nonzero value, an orthographic projection is used. + All rays traced from the orthographic pixel array travel in the + same direction. The width of the starting array must be specified, + unlike with the default perspective projection. The height of the + array is deduced from the ratio of pixel dimensions for the image. + Defaults to zero, i.e. using perspective projection. + wireframe_thickness : int + Line thickness employed for drawing wireframes around cells or + material regions. Can be set to zero for no wireframes at all. + Defaults to one pixel. + wireframe_color : tuple of ints + RGB color of the wireframe lines. Defaults to black. + wireframe_domains : iterable of either Material or Cells + If provided, the wireframe is only drawn around these. + If color_by is by material, it must be a list of materials, else cells. + xs : dict + A mapping from cell/material IDs to floats. The floating point values + are macroscopic cross sections influencing the volume rendering opacity + of each geometric region. Zero corresponds to perfect transparency, and + infinity equivalent to opaque. These must be set by the user, but default + values can be obtained using the set_transparent method. + """ + + def __init__(self, plot_id=None, name=''): + # Initialize Plot class attributes + super().__init__(plot_id, name) + self._horizontal_field_of_view = 70.0 + self._camera_position = (1.0, 0.0, 0.0) + self._look_at = (0.0, 0.0, 0.0) + self._up = (0.0, 0.0, 1.0) + self._orthographic_width = 0.0 + self._wireframe_thickness = 1 + self._wireframe_color = _SVG_COLORS['black'] + self._wireframe_domains = [] + self._xs = {} + + @property + def horizontal_field_of_view(self): + return self._horizontal_field_of_view + + @horizontal_field_of_view.setter + def horizontal_field_of_view(self, horizontal_field_of_view): + cv.check_type('plot horizontal field of view', horizontal_field_of_view, + Real) + assert horizontal_field_of_view > 0.0 + assert horizontal_field_of_view < 180.0 + self._horizontal_field_of_view = horizontal_field_of_view + + @property + def camera_position(self): + return self._camera_position + + @camera_position.setter + def camera_position(self, camera_position): + cv.check_type('plot camera position', camera_position, Iterable, Real) + cv.check_length('plot camera position', camera_position, 3) + self._camera_position = camera_position + + @property + def look_at(self): + return self._look_at + + @look_at.setter + def look_at(self, look_at): + cv.check_type('plot look at', look_at, Iterable, Real) + cv.check_length('plot look at', look_at, 3) + self._look_at = look_at + + @property + def up(self): + return self._up + + @up.setter + def up(self, up): + cv.check_type('plot up', up, Iterable, Real) + cv.check_length('plot up', up, 3) + self._up = up + + @property + def orthographic_width(self): + return self._orthographic_width + + @orthographic_width.setter + def orthographic_width(self, orthographic_width): + cv.check_type('plot orthographic width', orthographic_width, Real) + assert orthographic_width >= 0.0 + self._orthographic_width = orthographic_width + + @property + def wireframe_thickness(self): + return self._wireframe_thickness + + @wireframe_thickness.setter + def wireframe_thickness(self, wireframe_thickness): + cv.check_type('plot wireframe thickness', + wireframe_thickness, Integral) + assert wireframe_thickness >= 0 + self._wireframe_thickness = wireframe_thickness + + @property + def wireframe_color(self): + return self._wireframe_color + + @wireframe_color.setter + def wireframe_color(self, wireframe_color): + self._check_color('plot wireframe color', wireframe_color) + self._wireframe_color = wireframe_color + + @property + def wireframe_domains(self): + return self._wireframe_domains + + @wireframe_domains.setter + def wireframe_domains(self, wireframe_domains): + for region in wireframe_domains: + if self._color_by == 'material': + if not isinstance(region, openmc.Material): + raise Exception('Must provide a list of materials for \ + wireframe_region if color_by=Material') + else: + if not isinstance(region, openmc.Cell): + raise Exception('Must provide a list of cells for \ + wireframe_region if color_by=cell') + self._wireframe_domains = wireframe_domains + + @property + def xs(self): + return self._xs + + @xs.setter + def xs(self, xs): + cv.check_type('plot xs', xs, Mapping) + for key, value in xs.items(): + cv.check_type('plot xs key', key, (openmc.Cell, openmc.Material)) + cv.check_type('plot xs value', value, Real) + assert value >= 0.0 + self._xs = xs + + def set_transparent(self, geometry): + """Sets all volume rendering XS to zero for the model + + Parameters + ---------- + geometry : openmc.Geometry + The geometry for which the plot is defined + """ + + cv.check_type('geometry', geometry, openmc.Geometry) + + # Get collections of the domains which will be plotted + if self.color_by == 'material': + domains = geometry.get_all_materials().values() else: - ppm_file = 'plot_{}.ppm'.format(self.id) - png_file = ppm_file.replace('.ppm', '.png') - subprocess.check_call([convert_exec, ppm_file, png_file]) + domains = geometry.get_all_cells().values() + + # Generate random colors for each feature + for domain in domains: + self.xs[domain] = 0.0 + + def to_xml_element(self): + """Return XML representation of the projection plot + + Returns + ------- + element : lxml.etree._Element + XML element containing plot data + + """ - return Image(png_file) + element = super().to_xml_element() + element.set("type", "projection") + + subelement = ET.SubElement(element, "camera_position") + subelement.text = ' '.join(map(str, self._camera_position)) + + subelement = ET.SubElement(element, "look_at") + subelement.text = ' '.join(map(str, self._look_at)) + + subelement = ET.SubElement(element, "wireframe_thickness") + subelement.text = str(self._wireframe_thickness) + + subelement = ET.SubElement(element, "wireframe_color") + color = self._wireframe_color + if isinstance(color, str): + color = _SVG_COLORS[color.lower()] + subelement.text = ' '.join(str(x) for x in color) + + if self._wireframe_domains: + id_list = [x.id for x in self._wireframe_domains] + subelement = ET.SubElement(element, "wireframe_ids") + subelement.text = ' '.join([str(x) for x in id_list]) + + # note that this differs from the slice plot colors + # in that "xs" must also be specified + if self._colors: + for domain, color in sorted(self._colors.items(), + key=lambda x: x[0].id): + subelement = ET.SubElement(element, "color") + subelement.set("id", str(domain.id)) + if isinstance(color, str): + color = _SVG_COLORS[color.lower()] + subelement.set("rgb", ' '.join(str(x) for x in color)) + subelement.set("xs", str(self._xs[domain])) + + subelement = ET.SubElement(element, "horizontal_field_of_view") + subelement.text = str(self._horizontal_field_of_view) + + # do not need to write if orthographic_width == 0.0 + if self._orthographic_width > 0.0: + subelement = ET.SubElement(element, "orthographic_width") + subelement.text = str(self._orthographic_width) + + return element + + def __repr__(self): + string = 'Projection Plot\n' + string += '{: <16}=\t{}\n'.format('\tID', self._id) + string += '{: <16}=\t{}\n'.format('\tName', self._name) + string += '{: <16}=\t{}\n'.format('\tFilename', self._filename) + string += '{: <16}=\t{}\n'.format('\tHorizontal FOV', + self._horizontal_field_of_view) + string += '{: <16}=\t{}\n'.format('\tOrthographic width', + self._orthographic_width) + string += '{: <16}=\t{}\n'.format('\tWireframe thickness', + self._wireframe_thickness) + string += '{: <16}=\t{}\n'.format('\tWireframe color', + self._wireframe_color) + string += '{: <16}=\t{}\n'.format('\tWireframe domains', + self._wireframe_domains) + string += '{: <16}=\t{}\n'.format('\tCamera position', + self._camera_position) + string += '{: <16}=\t{}\n'.format('\tLook at', self._look_at) + string += '{: <16}=\t{}\n'.format('\tUp', self._up) + string += '{: <16}=\t{}\n'.format('\tPixels', self._pixels) + string += '{: <16}=\t{}\n'.format('\tColor by', self._color_by) + string += '{: <16}=\t{}\n'.format('\tBackground', self._background) + string += '{: <16}=\t{}\n'.format('\tColors', self._colors) + string += '{: <16}=\t{}\n'.format('\tTransparencies', self._xs) + string += '{: <16}=\t{}\n'.format('\tLevel', self._level) + return string + + @classmethod + def from_xml_element(cls, elem): + """Generate plot object from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.ProjectionPlot + ProjectionPlot object + + """ + plot_id = int(elem.get("id")) + plot = cls(plot_id) + if "filename" in elem.keys(): + plot.filename = elem.get("filename") + plot.color_by = elem.get("color_by") + plot.type = "projection" + + horizontal_fov = elem.find("horizontal_field_of_view") + if horizontal_fov is not None: + plot.horizontal_field_of_view = float(horizontal_fov.text) + + tmp = elem.find("orthographic_width") + if tmp is not None: + plot.orthographic_width = float(tmp) + + plot.pixels = get_elem_tuple(elem, "pixels") + plot.camera_position = get_elem_tuple(elem, "camera_position", float) + plot.look_at = get_elem_tuple(elem, "look_at", float) + + # Attempt to get wireframe thickness. May not be present + wireframe_thickness = elem.get("wireframe_thickness") + if wireframe_thickness: + plot.wireframe_thickness = int(wireframe_thickness) + wireframe_color = elem.get("wireframe_color") + if wireframe_color: + plot.wireframe_color = [int(item) for item in wireframe_color] + + # Set plot colors + colors = {} + xs = {} + for color_elem in elem.findall("color"): + uid = color_elem.get("id") + colors[uid] = get_elem_tuple(color_elem, "rgb") + xs[uid] = float(color_elem.get("xs")) + + # Set masking information + mask_elem = elem.find("mask") + if mask_elem is not None: + mask_components = [int(x) + for x in mask_elem.get("components").split()] + # TODO: set mask components (needs geometry information) + background = mask_elem.get("background") + if background is not None: + plot.mask_background = tuple( + [int(x) for x in background.split()]) + + # Set universe level + level = elem.find("level") + if level is not None: + plot.level = int(level.text) + + return plot class Plots(cv.CheckedList): """Collection of Plots used for an OpenMC simulation. This class corresponds directly to the plots.xml input file. It can be - thought of as a normal Python list where each member is a :class:`Plot`. It - behaves like a list as the following example demonstrates: + thought of as a normal Python list where each member is inherits from + :class:`PlotBase`. It behaves like a list as the following example + demonstrates: >>> xz_plot = openmc.Plot() >>> big_plot = openmc.Plot() @@ -731,13 +1338,13 @@ class Plots(cv.CheckedList): Parameters ---------- - plots : Iterable of openmc.Plot - Plots to add to the collection + plots : Iterable of openmc.Plot or openmc.ProjectionPlot + plots to add to the collection """ def __init__(self, plots=None): - super().__init__(Plot, 'plots collection') + super().__init__((Plot, ProjectionPlot), 'plots collection') self._plots_file = ET.Element("plots") if plots is not None: self += plots @@ -747,7 +1354,7 @@ def append(self, plot): Parameters ---------- - plot : openmc.Plot + plot : openmc.Plot or openmc.ProjectionPlot Plot to append """ @@ -785,7 +1392,6 @@ def colorize(self, geometry, seed=1): for plot in self: plot.colorize(geometry, seed) - def highlight_domains(self, geometry, domains, seed=1, alpha=0.5, background='gray'): """Use alpha compositing to highlight one or more domains in the plot. @@ -803,9 +1409,9 @@ def highlight_domains(self, geometry, domains, seed=1, seed : int The random number seed used to generate the color scheme alpha : float - The value between 0 and 1 to apply in alpha compisiting + The value between 0 and 1 to apply in alpha compositing background : 3-tuple of int or str - The background color to apply in alpha compisiting + The background color to apply in alpha compositing """ @@ -821,13 +1427,13 @@ def _create_plot_subelements(self): self._plots_file.append(xml_element) - def export_to_xml(self, path='plots.xml'): - """Export plot specifications to an XML file. + def to_xml_element(self): + """Create a 'plots' element to be written to an XML file. - Parameters - ---------- - path : str - Path to file to write. Defaults to 'plots.xml'. + Returns + ------- + element : lxml.etree._Element + XML element containing all plot elements """ # Reset xml element tree @@ -837,13 +1443,71 @@ def export_to_xml(self, path='plots.xml'): # Clean the indentation in the file to be user-readable clean_indentation(self._plots_file) + # TODO: Remove when support is Python 3.8+ + reorder_attributes(self._plots_file) + return self._plots_file + + def export_to_xml(self, path='plots.xml'): + """Export plot specifications to an XML file. + + Parameters + ---------- + path : str + Path to file to write. Defaults to 'plots.xml'. + + """ # Check if path is a directory p = Path(path) if p.is_dir(): p /= 'plots.xml' + self.to_xml_element() # Write the XML Tree to the plots.xml file - reorder_attributes(self._plots_file) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(self._plots_file) tree.write(str(p), xml_declaration=True, encoding='utf-8') + + @classmethod + def from_xml_element(cls, elem): + """Generate plots collection from XML file + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.Plots + Plots collection + + """ + # Generate each plot + plots = cls() + for e in elem.findall('plot'): + plot_type = e.get('type') + if plot_type == 'projection': + plots.append(ProjectionPlot.from_xml_element(e)) + else: + plots.append(Plot.from_xml_element(e)) + return plots + + @classmethod + def from_xml(cls, path='plots.xml'): + """Generate plots collection from XML file + + Parameters + ---------- + path : str, optional + Path to plots XML file + + Returns + ------- + openmc.Plots + Plots collection + + """ + parser = ET.XMLParser(huge_tree=True) + tree = ET.parse(path, parser=parser) + root = tree.getroot() + return cls.from_xml_element(root) diff --git a/openmc/plotter.py b/openmc/plotter.py index c6f069aa620..97ca5f92975 100644 --- a/openmc/plotter.py +++ b/openmc/plotter.py @@ -1,6 +1,5 @@ from itertools import chain from numbers import Integral, Real -import string import numpy as np @@ -53,18 +52,81 @@ _MAX_E = 20.e6 -def plot_xs(this, types, divisor_types=None, temperature=294., data_type=None, - axis=None, sab_name=None, ce_cross_sections=None, - mg_cross_sections=None, enrichment=None, plot_CE=True, orders=None, - divisor_orders=None, **kwargs): +ELEMENT_NAMES = list(openmc.data.ELEMENT_SYMBOL.values())[1:] + + +def _get_legend_label(this, type): + """Gets a label for the element or nuclide or material and reaction plotted""" + if isinstance(this, str): + if type in openmc.data.DADZ: + z, a, m = openmc.data.zam(this) + da, dz = openmc.data.DADZ[type] + gnds_name = openmc.data.gnds_name(z + dz, a + da, m) + return f'{this} {type} {gnds_name}' + return f'{this} {type}' + elif this.name == '': + return f'Material {this.id} {type}' + else: + return f'{this.name} {type}' + + +def _get_yaxis_label(reactions, divisor_types): + """Gets a y axis label for the type of data plotted""" + + heat_values = {"heating", "heating-local", "damage-energy"} + + # if all the types are heating a different stem and unit is needed + if all(set(value).issubset(heat_values) for value in reactions.values()): + stem = "Heating" + elif all(isinstance(item, str) for item in reactions.keys()): + for nuc_reactions in reactions.values(): + for reaction in nuc_reactions: + if reaction in heat_values: + raise TypeError( + "Mixture of heating and Microscopic reactions. " + "Invalid type for plotting" + ) + stem = "Microscopic" + elif all(isinstance(item, openmc.Material) for item in reactions.keys()): + stem = 'Macroscopic' + else: + msg = "Mixture of openmc.Material and elements/nuclides. Invalid type for plotting" + raise TypeError(msg) + + if divisor_types: + mid, units = "Data", "" + else: + mid = "Cross Section" + units = { + "Macroscopic": "[1/cm]", + "Microscopic": "[b]", + "Heating": "[eV-barn]", + }[stem] + + return f'{stem} {mid} {units}' + +def _get_title(reactions): + """Gets a title for the type of data plotted""" + if len(reactions) == 1: + this, = reactions + name = this.name if isinstance(this, openmc.Material) else this + return f'Cross Section Plot For {name}' + else: + return 'Cross Section Plot' + + +def plot_xs(reactions, divisor_types=None, temperature=294., axis=None, + sab_name=None, ce_cross_sections=None, mg_cross_sections=None, + enrichment=None, plot_CE=True, orders=None, divisor_orders=None, + energy_axis_units="eV", **kwargs): """Creates a figure of continuous-energy cross sections for this item. Parameters ---------- - this : str or openmc.Material - Object to source data from - types : Iterable of values of PLOT_TYPES - The type of cross sections to include in the plot. + reactions : dict + keys can be either a nuclide or element in string form or an + openmc.Material object. Values are the type of cross sections to + include in the plot. divisor_types : Iterable of values of PLOT_TYPES, optional Cross section types which will divide those produced by types before plotting. A type of 'unity' can be used to effectively not @@ -74,23 +136,18 @@ def plot_xs(this, types, divisor_types=None, temperature=294., data_type=None, temperature of 294K will be plotted. Note that the nearest temperature in the library for each nuclide will be used as opposed to using any interpolation. - data_type : {'nuclide', 'element', 'material', 'macroscopic'}, optional - Type of object to plot. If not specified, a guess is made based on the - `this` argument. axis : matplotlib.axes, optional A previously generated axis to use for plotting. If not specified, a new axis and figure will be generated. sab_name : str, optional - Name of S(a,b) library to apply to MT=2 data when applicable; only used - for items which are instances of openmc.Element or openmc.Nuclide + Name of S(a,b) library to apply to MT=2 data when applicable. ce_cross_sections : str, optional Location of cross_sections.xml file. Default is None. mg_cross_sections : str, optional Location of MGXS HDF5 Library file. Default is None. enrichment : float, optional Enrichment for U235 in weight percent. For example, input 4.95 for - 4.95 weight percent enriched U. Default is None. This is only used for - items which are instances of openmc.Element + 4.95 weight percent enriched U. Default is None. plot_CE : bool, optional Denotes whether or not continuous-energy will be plotted. Defaults to plotting the continuous-energy data. @@ -101,9 +158,13 @@ def plot_xs(this, types, divisor_types=None, temperature=294., data_type=None, multi-group data. divisor_orders : Iterable of Integral, optional Same as orders, but for divisor_types - **kwargs + **kwargs : All keyword arguments are passed to :func:`matplotlib.pyplot.figure`. + energy_axis_units : {'eV', 'keV', 'MeV'} + Units used on the plot energy axis + + .. versionadded:: 0.14.1 Returns ------- @@ -117,125 +178,108 @@ def plot_xs(this, types, divisor_types=None, temperature=294., data_type=None, import matplotlib.pyplot as plt cv.check_type("plot_CE", plot_CE, bool) + cv.check_value("energy_axis_units", energy_axis_units, {"eV", "keV", "MeV"}) - if data_type is None: - if isinstance(this, openmc.Nuclide): - data_type = 'nuclide' - elif isinstance(this, openmc.Element): - data_type = 'element' - elif isinstance(this, openmc.Material): - data_type = 'material' - elif isinstance(this, openmc.Macroscopic): - data_type = 'macroscopic' - elif isinstance(this, str): - if this[-1] in string.digits: - data_type = 'nuclide' - else: - data_type = 'element' - else: - raise TypeError("Invalid type for plotting") - - if plot_CE: - # Calculate for the CE cross sections - E, data = calculate_cexs(this, data_type, types, temperature, sab_name, - ce_cross_sections, enrichment) - if divisor_types: - cv.check_length('divisor types', divisor_types, len(types)) - Ediv, data_div = calculate_cexs(this, divisor_types, temperature, - sab_name, ce_cross_sections, - enrichment) - - # Create a new union grid, interpolate data and data_div on to that - # grid, and then do the actual division - Enum = E[:] - E = np.union1d(Enum, Ediv) - data_new = np.zeros((len(types), len(E))) - - for line in range(len(types)): - data_new[line, :] = \ - np.divide(np.interp(E, Enum, data[line, :]), - np.interp(E, Ediv, data_div[line, :])) - if divisor_types[line] != 'unity': - types[line] = types[line] + ' / ' + divisor_types[line] - data = data_new - else: - # Calculate for MG cross sections - E, data = calculate_mgxs(this, data_type, types, orders, temperature, - mg_cross_sections, ce_cross_sections, - enrichment) - - if divisor_types: - cv.check_length('divisor types', divisor_types, len(types)) - Ediv, data_div = calculate_mgxs(this, data_type, divisor_types, - divisor_orders, temperature, - mg_cross_sections, - ce_cross_sections, enrichment) - - # Perform the division - for line in range(len(types)): - data[line, :] /= data_div[line, :] - if divisor_types[line] != 'unity': - types[line] += ' / ' + divisor_types[line] + axis_scaling_factor = {"eV": 1.0, "keV": 1e-3, "MeV": 1e-6} # Generate the plot if axis is None: - fig, ax = plt.subplots() + fig, ax = plt.subplots(**kwargs) else: fig = None ax = axis + + all_types = [] + + for this, types in reactions.items(): + all_types = all_types + types + + if plot_CE: + cv.check_type("this", this, (str, openmc.Material)) + # Calculate for the CE cross sections + E, data = calculate_cexs(this, types, temperature, sab_name, + ce_cross_sections, enrichment) + if divisor_types: + cv.check_length('divisor types', divisor_types, len(types)) + Ediv, data_div = calculate_cexs(this, divisor_types, temperature, + sab_name, ce_cross_sections, + enrichment) + + # Create a new union grid, interpolate data and data_div on to that + # grid, and then do the actual division + Enum = E[:] + E = np.union1d(Enum, Ediv) + data_new = np.zeros((len(types), len(E))) + + for line in range(len(types)): + data_new[line, :] = \ + np.divide(np.interp(E, Enum, data[line, :]), + np.interp(E, Ediv, data_div[line, :])) + if divisor_types[line] != 'unity': + types[line] = types[line] + ' / ' + divisor_types[line] + data = data_new + else: + # Calculate for MG cross sections + E, data = calculate_mgxs(this, types, orders, temperature, + mg_cross_sections, ce_cross_sections, + enrichment) + + if divisor_types: + cv.check_length('divisor types', divisor_types, len(types)) + Ediv, data_div = calculate_mgxs(this, divisor_types, + divisor_orders, temperature, + mg_cross_sections, + ce_cross_sections, enrichment) + + # Perform the division + for line in range(len(types)): + data[line, :] /= data_div[line, :] + if divisor_types[line] != 'unity': + types[line] += ' / ' + divisor_types[line] + + E *= axis_scaling_factor[energy_axis_units] + + # Plot the data + for i in range(len(data)): + data[i, :] = np.nan_to_num(data[i, :]) + if np.sum(data[i, :]) > 0.: + ax.plot(E, data[i, :], label=_get_legend_label(this, types[i])) + # Set to loglog or semilogx depending on if we are plotting a data # type which we expect to vary linearly - if set(types).issubset(PLOT_TYPES_LINEAR): - plot_func = ax.semilogx + if set(all_types).issubset(PLOT_TYPES_LINEAR): + ax.set_xscale('log') + ax.set_yscale('linear') else: - plot_func = ax.loglog - - # Plot the data - for i in range(len(data)): - data[i, :] = np.nan_to_num(data[i, :]) - if np.sum(data[i, :]) > 0.: - plot_func(E, data[i, :], label=types[i]) + ax.set_xscale('log') + ax.set_yscale('log') - ax.set_xlabel('Energy [eV]') + ax.set_xlabel(f"Energy [{energy_axis_units}]") if plot_CE: - ax.set_xlim(_MIN_E, _MAX_E) + ax.set_xlim( + _MIN_E * axis_scaling_factor[energy_axis_units], + _MAX_E * axis_scaling_factor[energy_axis_units], + ) else: ax.set_xlim(E[-1], E[0]) - if divisor_types: - if data_type == 'nuclide': - ylabel = 'Nuclidic Microscopic Data' - elif data_type == 'element': - ylabel = 'Elemental Microscopic Data' - elif data_type == 'material' or data_type == 'macroscopic': - ylabel = 'Macroscopic Data' - else: - if data_type == 'nuclide': - ylabel = 'Microscopic Cross Section [b]' - elif data_type == 'element': - ylabel = 'Elemental Cross Section [b]' - elif data_type == 'material' or data_type == 'macroscopic': - ylabel = 'Macroscopic Cross Section [1/cm]' - ax.set_ylabel(ylabel) + + ax.set_ylabel(_get_yaxis_label(reactions, divisor_types)) ax.legend(loc='best') - name = this.name if data_type == 'material' else this - if len(types) > 1: - ax.set_title('Cross Sections for ' + name) - else: - ax.set_title('Cross Section for ' + name) + ax.set_title(_get_title(reactions)) return fig -def calculate_cexs(this, data_type, types, temperature=294., sab_name=None, - cross_sections=None, enrichment=None): + +def calculate_cexs(this, types, temperature=294., sab_name=None, + cross_sections=None, enrichment=None, ncrystal_cfg=None): """Calculates continuous-energy cross sections of a requested type. Parameters ---------- - this : {str, openmc.Nuclide, openmc.Element, openmc.Material} - Object to source data from - data_type : {'nuclide', 'element', 'material'} - Type of object to plot + this : str or openmc.Material + Object to source data from. Nuclides and elements should be input as a + str types : Iterable of values of PLOT_TYPES The type of cross sections to calculate temperature : float, optional @@ -251,6 +295,8 @@ def calculate_cexs(this, data_type, types, temperature=294., sab_name=None, Enrichment for U235 in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None (natural composition). + ncrystal_cfg : str, optional + Configuration string for NCrystal material. Returns ------- @@ -262,50 +308,44 @@ def calculate_cexs(this, data_type, types, temperature=294., sab_name=None, """ # Check types + cv.check_type('this', this, (str, openmc.Material)) cv.check_type('temperature', temperature, Real) if sab_name: cv.check_type('sab_name', sab_name, str) if enrichment: cv.check_type('enrichment', enrichment, Real) - if data_type == 'nuclide': - if isinstance(this, str): - nuc = openmc.Nuclide(this) - else: - nuc = this - energy_grid, xs = _calculate_cexs_nuclide(nuc, types, temperature, - sab_name, cross_sections) - # Convert xs (Iterable of Callable) to a grid of cross section values - # calculated on the points in energy_grid for consistency with the - # element and material functions. - data = np.zeros((len(types), len(energy_grid))) - for line in range(len(types)): - data[line, :] = xs[line](energy_grid) - elif data_type == 'element': - if isinstance(this, str): - elem = openmc.Element(this) + if isinstance(this, str): + if this in ELEMENT_NAMES: + energy_grid, data = _calculate_cexs_elem_mat( + this, types, temperature, cross_sections, sab_name, enrichment + ) else: - elem = this - energy_grid, data = _calculate_cexs_elem_mat(elem, types, temperature, - cross_sections, sab_name, - enrichment) - elif data_type == 'material': - cv.check_type('this', this, openmc.Material) + energy_grid, xs = _calculate_cexs_nuclide( + this, types, temperature, sab_name, cross_sections, + ncrystal_cfg + ) + + # Convert xs (Iterable of Callable) to a grid of cross section values + # calculated on the points in energy_grid for consistency with the + # element and material functions. + data = np.zeros((len(types), len(energy_grid))) + for line in range(len(types)): + data[line, :] = xs[line](energy_grid) + else: energy_grid, data = _calculate_cexs_elem_mat(this, types, temperature, cross_sections) - else: - raise TypeError("Invalid type") return energy_grid, data def _calculate_cexs_nuclide(this, types, temperature=294., sab_name=None, - cross_sections=None): + cross_sections=None, ncrystal_cfg=None): """Calculates continuous-energy cross sections of a requested type. Parameters ---------- - this : openmc.Nuclide + this : str Nuclide object to source data from types : Iterable of str or Integral The type of cross sections to calculate; values can either be those @@ -321,6 +361,8 @@ def _calculate_cexs_nuclide(this, types, temperature=294., sab_name=None, Name of S(a,b) library to apply to MT=2 data when applicable. cross_sections : str, optional Location of cross_sections.xml file. Default is None. + ncrystal_cfg : str, optional + Configuration string for NCrystal material. Returns ------- @@ -335,7 +377,7 @@ def _calculate_cexs_nuclide(this, types, temperature=294., sab_name=None, library = openmc.data.DataLibrary.from_xml(cross_sections) # Convert temperature to format needed for access in the library - strT = "{}K".format(int(round(temperature))) + strT = f"{int(round(temperature))}K" T = temperature # Now we can create the data sets to be plotted @@ -438,6 +480,19 @@ def _calculate_cexs_nuclide(this, types, temperature=294., sab_name=None, [sab_sum, nuc[mt].xs[nucT]], [sab_Emax]) funcs.append(pw_funcs) + elif ncrystal_cfg: + import NCrystal + nc_scatter = NCrystal.createScatter(ncrystal_cfg) + nc_func = nc_scatter.crossSectionNonOriented + nc_emax = 5 # eV # this should be obtained from NCRYSTAL_MAX_ENERGY + energy_grid = np.union1d(np.geomspace(min(energy_grid), + 1.1*nc_emax, + 1000),energy_grid) # NCrystal does not have + # an intrinsic energy grid + pw_funcs = openmc.data.Regions1D( + [nc_func, nuc[mt].xs[nucT]], + [nc_emax]) + funcs.append(pw_funcs) else: funcs.append(nuc[mt].xs[nucT]) elif mt in nuc: @@ -502,8 +557,8 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., Parameters ---------- - this : openmc.Material or openmc.Element - Object to source data from + this : openmc.Material or str + Object to source data from. Element can be input as str types : Iterable of values of PLOT_TYPES The type of cross sections to calculate temperature : float, optional @@ -540,26 +595,23 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., # Load the library library = openmc.data.DataLibrary.from_xml(cross_sections) + ncrystal_cfg = None if isinstance(this, openmc.Material): # Expand elements in to nuclides with atomic densities - nuclides = this.get_nuclide_atom_densities() - # For ease of processing split out the nuclide and its fraction - nuc_fractions = {nuclide[1][0]: nuclide[1][1] - for nuclide in nuclides.items()} + nuc_fractions = this.get_nuclide_atom_densities() # Create a dict of [nuclide name] = nuclide object to carry forward - # with a common nuclides format between openmc.Material and - # openmc.Element objects - nuclides = {nuclide[1][0]: nuclide[1][0] - for nuclide in nuclides.items()} + # with a common nuclides format between openmc.Material and Elements + nuclides = {nuclide: nuclide for nuclide in nuc_fractions} + # Add NCrystal cfg string if it exists + ncrystal_cfg = this.ncrystal_cfg else: # Expand elements in to nuclides with atomic densities - nuclides = this.expand(1., 'ao', enrichment=enrichment, + nuclides = openmc.Element(this).expand(1., 'ao', enrichment=enrichment, cross_sections=cross_sections) # For ease of processing split out the nuclide and its fraction nuc_fractions = {nuclide[0]: nuclide[1] for nuclide in nuclides} # Create a dict of [nuclide name] = nuclide object to carry forward - # with a common nuclides format between openmc.Material and - # openmc.Element objects + # with a common nuclides format between openmc.Material and Elements nuclides = {nuclide[0]: nuclide[0] for nuclide in nuclides} # Identify the nuclides which have S(a,b) data @@ -567,7 +619,7 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., for nuclide in nuclides.items(): sabs[nuclide[0]] = None if isinstance(this, openmc.Material): - for sab_name in this._sab: + for sab_name, _ in this._sab: sab = openmc.data.ThermalScattering.from_hdf5( library.get_by_material(sab_name, data_type='thermal')['path']) for nuc in sab.nuclides: @@ -587,8 +639,9 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., name = nuclide[0] nuc = nuclide[1] sab_tab = sabs[name] - temp_E, temp_xs = calculate_cexs(nuc, 'nuclide', types, T, sab_tab, - cross_sections) + temp_E, temp_xs = calculate_cexs(nuc, types, T, sab_tab, cross_sections, + ncrystal_cfg=ncrystal_cfg + ) E.append(temp_E) # Since the energy grids are different, store the cross sections as # a tabulated function so they can be calculated on any grid needed. @@ -615,7 +668,7 @@ def _calculate_cexs_elem_mat(this, types, temperature=294., return energy_grid, data -def calculate_mgxs(this, data_type, types, orders=None, temperature=294., +def calculate_mgxs(this, types, orders=None, temperature=294., cross_sections=None, ce_cross_sections=None, enrichment=None): """Calculates multi-group cross sections of a requested type. @@ -627,9 +680,7 @@ def calculate_mgxs(this, data_type, types, orders=None, temperature=294., Parameters ---------- this : str or openmc.Material - Object to source data from - data_type : {'nuclide', 'element', 'material', 'macroscopic'} - Type of object to plot + Object to source data from. Nuclides and elements can be input as a str types : Iterable of values of PLOT_TYPES_MGXS The type of cross sections to calculate orders : Iterable of Integral, optional @@ -645,7 +696,6 @@ def calculate_mgxs(this, data_type, types, orders=None, temperature=294., Location of MGXS HDF5 Library file. Default is None. ce_cross_sections : str, optional Location of continuous-energy cross_sections.xml file. Default is None. - This is used only for expanding an openmc.Element object passed as this enrichment : float, optional Enrichment for U235 in weight percent. For example, input 4.95 for 4.95 weight percent enriched U. Default is None @@ -669,13 +719,13 @@ def calculate_mgxs(this, data_type, types, orders=None, temperature=294., cv.check_type("cross_sections", cross_sections, str) library = openmc.MGXSLibrary.from_hdf5(cross_sections) - if data_type in ('nuclide', 'macroscopic'): - mgxs = _calculate_mgxs_nuc_macro(this, types, library, orders, - temperature) - elif data_type in ('element', 'material'): + if this in ELEMENT_NAMES or isinstance(this, openmc.Material): mgxs = _calculate_mgxs_elem_mat(this, types, library, orders, temperature, ce_cross_sections, enrichment) + elif isinstance(this, str): + mgxs = _calculate_mgxs_nuc_macro(this, types, library, orders, + temperature) else: raise TypeError("Invalid type") @@ -707,7 +757,7 @@ def _calculate_mgxs_nuc_macro(this, types, library, orders=None, Parameters ---------- - this : openmc.Nuclide or openmc.Macroscopic + this : str Object to source data from types : Iterable of str The type of cross sections to calculate; values can either be those @@ -828,8 +878,7 @@ def _calculate_mgxs_nuc_macro(this, types, library, orders=None, if order < shape[1]: data[i, :] = temp_data[:, order] else: - raise ValueError("{} not present in provided MGXS " - "library".format(this)) + raise ValueError(f"{this} not present in provided MGXS library") return data @@ -846,8 +895,8 @@ def _calculate_mgxs_elem_mat(this, types, library, orders=None, Parameters ---------- - this : openmc.Element or openmc.Material - Object to source data from + this : str or openmc.Material + Object to source data from. Elements can be input as a str types : Iterable of str The type of cross sections to calculate; values can either be those in openmc.PLOT_TYPES_MGXS @@ -883,20 +932,20 @@ def _calculate_mgxs_elem_mat(this, types, library, orders=None, else: T = temperature - # Check to see if we have nuclides/elements or a macrocopic object + # Check to see if we have nuclides/elements or a macroscopic object if this._macroscopic is not None: # We have macroscopics - nuclides = {this._macroscopic: (this._macroscopic, this.density)} + nuclides = {this._macroscopic: this.density} else: # Expand elements in to nuclides with atomic densities nuclides = this.get_nuclide_atom_densities() # For ease of processing split out nuc and nuc_density - nuc_fraction = [nuclide[1][1] for nuclide in nuclides.items()] + nuc_fraction = list(nuclides.values()) else: T = temperature # Expand elements in to nuclides with atomic densities - nuclides = this.expand(100., 'ao', enrichment=enrichment, + nuclides = openmc.Element(this).expand(100., 'ao', enrichment=enrichment, cross_sections=ce_cross_sections) # For ease of processing split out nuc and nuc_fractions diff --git a/openmc/polynomial.py b/openmc/polynomial.py index 718fc668c56..1259c61ca26 100644 --- a/openmc/polynomial.py +++ b/openmc/polynomial.py @@ -59,7 +59,7 @@ class ZernikeRadial(Polynomial): Domain of Zernike polynomials to be applied on. Default is 1. norm_coef : iterable of float The list of coefficients of each term in the polynomials after - normailization. + normalization. """ def __init__(self, coef, radius=1): @@ -106,7 +106,7 @@ class Zernike(Polynomial): Azimuthal of Zernike polynomial to be applied on. Default is 0. norm_coef : iterable of float The list of coefficients of each term in the polynomials after - normailization. + normalization. """ def __init__(self, coef, radius=1): super().__init__(coef) diff --git a/openmc/region.py b/openmc/region.py index 69273e5de96..f679129c1fc 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -1,11 +1,12 @@ from abc import ABC, abstractmethod -from collections import OrderedDict from collections.abc import MutableSequence from copy import deepcopy +import warnings import numpy as np -from .checkvalue import check_type +import openmc +from .bounding_box import BoundingBox class Region(ABC): @@ -17,6 +18,11 @@ class Region(ABC): respective classes are typically not instantiated directly but rather are created through operators of the Surface and Region classes. + Attributes + ---------- + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the region + """ def __and__(self, other): return Intersection((self, other)) @@ -31,6 +37,11 @@ def __invert__(self): def __contains__(self, point): pass + @property + @abstractmethod + def bounding_box(self) -> BoundingBox: + pass + @abstractmethod def __str__(self): pass @@ -46,17 +57,17 @@ def get_surfaces(self, surfaces=None): Parameters ---------- - surfaces: collections.OrderedDict, optional + surfaces : dict, optional Dictionary mapping surface IDs to :class:`openmc.Surface` instances Returns ------- - surfaces: collections.OrderedDict + surfaces : dict Dictionary mapping surface IDs to :class:`openmc.Surface` instances """ if surfaces is None: - surfaces = OrderedDict() + surfaces = {} for region in self: surfaces = region.get_surfaces(surfaces) return surfaces @@ -87,7 +98,7 @@ def from_expression(expression, surfaces): operators are union '|', intersection ' ', and complement '~'. For example, '(1 -2) | 3 ~(4 -5)'. surfaces : dict - Dictionary whose keys are suface IDs that appear in the Boolean + Dictionary whose keys are surface IDs that appear in the Boolean expression and whose values are Surface objects. """ @@ -104,7 +115,7 @@ def from_expression(expression, surfaces): while i < len(expression): if expression[i] in '()|~ ': # If special character appears immediately after a non-operator, - # create a token with the apporpriate half-space + # create a token with the appropriate half-space if i_start >= 0: j = int(expression[i_start:i]) if j < 0: @@ -112,18 +123,29 @@ def from_expression(expression, surfaces): else: tokens.append(+surfaces[abs(j)]) + # When an opening parenthesis appears after a non-operator, + # there's an implicit intersection operator between them + if expression[i] == '(': + tokens.append(' ') + if expression[i] in '()|~': # For everything other than intersection, add the operator # to the list of tokens tokens.append(expression[i]) + + # If two parentheses appear immediately adjacent to one + # another, we need an intersection between them + if expression[i:i+2] == ')(': + tokens.append(' ') else: # Find next non-space character while expression[i+1] == ' ': i += 1 - # If previous token is a halfspace or right parenthesis and next token - # is not a left parenthese or union operator, that implies that the - # whitespace is to be interpreted as an intersection operator + # If previous token is a halfspace or right parenthesis and + # next token is not a left parenthesis or union operator, + # that implies that the whitespace is to be interpreted as + # an intersection operator if (i_start >= 0 or tokens[-1] == ')') and \ expression[i+1] not in ')|': tokens.append(' ') @@ -132,8 +154,8 @@ def from_expression(expression, surfaces): else: # Check for invalid characters if expression[i] not in '-+0123456789': - raise SyntaxError("Invalid character '{}' in expression" - .format(expression[i])) + raise SyntaxError(f"Invalid character '{expression[i]}' in " + "expression") # If we haven't yet reached the start of a word, start one if i_start < 0: @@ -248,13 +270,18 @@ def clone(self, memo=None): clone[:] = [n.clone(memo) for n in self] return clone - def translate(self, vector, memo=None): + def translate(self, vector, inplace=False, memo=None): """Translate region in given direction Parameters ---------- vector : iterable of float Direction in which region should be translated + inplace : bool + Whether or not to return a region based on new surfaces or one based + on the original surfaces that have been modified. + + .. versionadded:: 0.13.1 memo : dict or None Dictionary used for memoization. This parameter is used internally and should not be specified by the user. @@ -268,7 +295,7 @@ def translate(self, vector, memo=None): if memo is None: memo = {} - return type(self)(n.translate(vector, memo) for n in self) + return type(self)(n.translate(vector, inplace, memo) for n in self) def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False, memo=None): @@ -297,7 +324,7 @@ def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False, :math:`\psi` about z. This corresponds to an x-y-z extrinsic rotation as well as a z-y'-x'' intrinsic rotation using Tait-Bryan angles :math:`(\phi, \theta, \psi)`. - inplace : boolean + inplace : bool Whether or not to return a new instance of Surface or to modify the coefficients of this Surface in place. Defaults to False. memo : dict or None @@ -314,6 +341,59 @@ def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False, return type(self)(n.rotate(rotation, pivot=pivot, order=order, inplace=inplace, memo=memo) for n in self) + def plot(self, *args, **kwargs): + """Display a slice plot of the region. + + .. versionadded:: 0.14.1 + + Parameters + ---------- + origin : iterable of float + Coordinates at the origin of the plot. If left as None then the + bounding box center will be used to attempt to ascertain the origin. + Defaults to (0, 0, 0) if the bounding box is not finite + width : iterable of float + Width of the plot in each basis direction. If left as none then the + bounding box width will be used to attempt to ascertain the plot + width. Defaults to (10, 10) if the bounding box is not finite + pixels : Iterable of int or int + If iterable of ints provided, then this directly sets the number of + pixels to use in each basis direction. If int provided, then this + sets the total number of pixels in the plot and the number of pixels + in each basis direction is calculated from this total and the image + aspect ratio. + basis : {'xy', 'xz', 'yz'} + The basis directions for the plot + seed : int + Seed for the random number generator + openmc_exec : str + Path to OpenMC executable. + axes : matplotlib.Axes + Axes to draw to + outline : bool + Whether outlines between color boundaries should be drawn + axis_units : {'km', 'm', 'cm', 'mm'} + Units used on the plot axis + **kwargs + Keyword arguments passed to :func:`matplotlib.pyplot.imshow` + + Returns + ------- + matplotlib.axes.Axes + Axes containing resulting image + + """ + for key in ('color_by', 'colors', 'legend', 'legend_kwargs'): + if key in kwargs: + warnings.warn(f"The '{key}' argument is present but won't be applied in a region plot") + + # Create cell while not perturbing use of autogenerated IDs + next_id = openmc.Cell.next_id + c = openmc.Cell(region=self) + openmc.Cell.used_ids.remove(c.id) + openmc.Cell.next_id = next_id + return c.plot(*args, **kwargs) + class Intersection(Region, MutableSequence): r"""Intersection of two or more regions. @@ -339,13 +419,16 @@ class Intersection(Region, MutableSequence): Attributes ---------- - bounding_box : tuple of numpy.array - Lower-left and upper-right coordinates of an axis-aligned bounding box + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the region """ def __init__(self, nodes): self._nodes = list(nodes) + for node in nodes: + if not isinstance(node, Region): + raise ValueError('Intersection operands must be of type Region') def __and__(self, other): new = Intersection(self) @@ -395,14 +478,11 @@ def __str__(self): return '(' + ' '.join(map(str, self)) + ')' @property - def bounding_box(self): - lower_left = np.array([-np.inf, -np.inf, -np.inf]) - upper_right = np.array([np.inf, np.inf, np.inf]) + def bounding_box(self) -> BoundingBox: + box = BoundingBox.infinite() for n in self: - lower_left_n, upper_right_n = n.bounding_box - lower_left[:] = np.maximum(lower_left, lower_left_n) - upper_right[:] = np.minimum(upper_right, upper_right_n) - return lower_left, upper_right + box &= n.bounding_box + return box class Union(Region, MutableSequence): @@ -427,13 +507,16 @@ class Union(Region, MutableSequence): Attributes ---------- - bounding_box : 2-tuple of numpy.array - Lower-left and upper-right coordinates of an axis-aligned bounding box + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the region """ def __init__(self, nodes): self._nodes = list(nodes) + for node in nodes: + if not isinstance(node, Region): + raise ValueError('Union operands must be of type Region') def __or__(self, other): new = Union(self) @@ -483,14 +566,12 @@ def __str__(self): return '(' + ' | '.join(map(str, self)) + ')' @property - def bounding_box(self): - lower_left = np.array([np.inf, np.inf, np.inf]) - upper_right = np.array([-np.inf, -np.inf, -np.inf]) + def bounding_box(self) -> BoundingBox: + bbox = BoundingBox(np.array([np.inf]*3), + np.array([-np.inf]*3)) for n in self: - lower_left_n, upper_right_n = n.bounding_box - lower_left[:] = np.minimum(lower_left, lower_left_n) - upper_right[:] = np.maximum(upper_right, upper_right_n) - return lower_left, upper_right + bbox |= n.bounding_box + return bbox class Complement(Region): @@ -517,8 +598,8 @@ class Complement(Region): ---------- node : openmc.Region Regions to take the complement of - bounding_box : tuple of numpy.array - Lower-left and upper-right coordinates of an axis-aligned bounding box + bounding_box : openmc.BoundingBox + Axis-aligned bounding box of the region """ @@ -550,11 +631,12 @@ def node(self): @node.setter def node(self, node): - check_type('node', node, Region) + if not isinstance(node, Region): + raise ValueError('Complement operand must be of type Region') self._node = node @property - def bounding_box(self): + def bounding_box(self) -> BoundingBox: # Use De Morgan's laws to distribute the complement operator so that it # only applies to surface half-spaces, thus allowing us to calculate the # bounding box in the usual recursive manner. @@ -573,17 +655,17 @@ def get_surfaces(self, surfaces=None): Parameters ---------- - surfaces: collections.OrderedDict, optional + surfaces : dict, optional Dictionary mapping surface IDs to :class:`openmc.Surface` instances Returns ------- - surfaces: collections.OrderedDict + surfaces : dict Dictionary mapping surface IDs to :class:`openmc.Surface` instances """ if surfaces is None: - surfaces = OrderedDict() + surfaces = {} for region in self.node: surfaces = region.get_surfaces(surfaces) return surfaces @@ -611,10 +693,10 @@ def clone(self, memo=None): clone.node = self.node.clone(memo) return clone - def translate(self, vector, memo=None): + def translate(self, vector, inplace=False, memo=None): if memo is None: memo = {} - return type(self)(self.node.translate(vector, memo)) + return type(self)(self.node.translate(vector, inplace, memo)) def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False, memo=None): diff --git a/openmc/search.py b/openmc/search.py index ee5dd1f0776..7f6b3b5b9a4 100644 --- a/openmc/search.py +++ b/openmc/search.py @@ -12,7 +12,7 @@ def _search_keff(guess, target, model_builder, model_args, print_iterations, - print_output, guesses, results): + run_args, guesses, results): """Function which will actually create our model, run the calculation, and obtain the result. This function will be passed to the root finding algorithm @@ -31,8 +31,8 @@ def _search_keff(guess, target, model_builder, model_args, print_iterations, print_iterations : bool Whether or not to print the guess and the resultant keff during the iteration process. - print_output : bool - Whether or not to print the OpenMC output during the iterations. + run_args : dict + Keyword arguments to pass to :meth:`openmc.Model.run`. guesses : Iterable of Real Running list of guesses thus far, to be updated during the execution of this function. @@ -51,9 +51,9 @@ def _search_keff(guess, target, model_builder, model_args, print_iterations, model = model_builder(guess, **model_args) # Run the model and obtain keff - sp_filepath = model.run(output=print_output) + sp_filepath = model.run(**run_args) with openmc.StatePoint(sp_filepath) as sp: - keff = sp.k_combined + keff = sp.keff # Record the history guesses.append(guess) @@ -70,7 +70,7 @@ def _search_keff(guess, target, model_builder, model_args, print_iterations, def search_for_keff(model_builder, initial_guess=None, target=1.0, bracket=None, model_args=None, tol=None, bracketed_method='bisect', print_iterations=False, - print_output=False, **kwargs): + run_args=None, **kwargs): """Function to perform a keff search by modifying a model parametrized by a single independent variable. @@ -102,9 +102,11 @@ def search_for_keff(model_builder, initial_guess=None, target=1.0, print_iterations : bool Whether or not to print the guess and the result during the iteration process. Defaults to False. - print_output : bool - Whether or not to print the OpenMC output during the iterations. - Defaults to False. + run_args : dict, optional + Keyword arguments to pass to :meth:`openmc.Model.run`. Defaults to no + arguments. + + .. versionadded:: 0.13.1 **kwargs All remaining keyword arguments are passed to the root-finding method. @@ -137,7 +139,10 @@ def search_for_keff(model_builder, initial_guess=None, target=1.0, cv.check_value('bracketed_method', bracketed_method, _SCALAR_BRACKETED_METHODS) cv.check_type('print_iterations', print_iterations, bool) - cv.check_type('print_output', print_output, bool) + if run_args is None: + run_args = {} + else: + cv.check_type('run_args', run_args, dict) cv.check_type('model_builder', model_builder, Callable) # Run the model builder function once to make sure it provides the correct @@ -188,7 +193,7 @@ def search_for_keff(model_builder, initial_guess=None, target=1.0, # Add information to be passed to the searching function args['args'] = (target, model_builder, model_args, print_iterations, - print_output, guesses, results) + run_args, guesses, results) # Create a new dictionary with the arguments from args and kwargs args.update(kwargs) diff --git a/openmc/settings.py b/openmc/settings.py index 615e6365aac..63124602908 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -1,13 +1,21 @@ -from collections.abc import Iterable, MutableSequence, Mapping +from collections.abc import Iterable, Mapping, MutableSequence from enum import Enum -from pathlib import Path -from numbers import Real, Integral -from xml.etree import ElementTree as ET +import itertools from math import ceil +from numbers import Integral, Real +from pathlib import Path +import typing # required to prevent typing.Union namespace overwriting Union +from typing import Optional + +import lxml.etree as ET import openmc.checkvalue as cv -from . import VolumeCalculation, Source, RegularMesh +from openmc.stats.multivariate import MeshSpatial +from . import (RegularMesh, SourceBase, MeshSource, IndependentSource, + VolumeCalculation, WeightWindows, WeightWindowGenerator) from ._xml import clean_indentation, get_text, reorder_attributes +from openmc.checkvalue import PathLike +from .mesh import _read_meshes class RunMode(Enum): @@ -24,6 +32,11 @@ class RunMode(Enum): class Settings: """Settings used for an OpenMC simulation. + Parameters + ---------- + **kwargs : dict, optional + Any keyword arguments are used to set attributes on the instance. + Attributes ---------- batches : int @@ -36,16 +49,16 @@ class Settings: create_fission_neutrons : bool Indicate whether fission neutrons should be created or not. cutoff : dict - Dictionary defining weight cutoff and energy cutoff. The dictionary may - have six keys, 'weight', 'weight_avg', 'energy_neutron', 'energy_photon', - 'energy_electron', and 'energy_positron'. Value for 'weight' + Dictionary defining weight cutoff, energy cutoff and time cutoff. The + dictionary may have ten keys, 'weight', 'weight_avg', 'energy_neutron', + 'energy_photon', 'energy_electron', 'energy_positron', 'time_neutron', + 'time_photon', 'time_electron', and 'time_positron'. Value for 'weight' should be a float indicating weight cutoff below which particle undergo Russian roulette. Value for 'weight_avg' should be a float indicating - weight assigned to particles that are not killed after Russian - roulette. Value of energy should be a float indicating energy in eV - below which particle type will be killed. - dagmc : bool - Indicate that a CAD-based DAGMC geometry will be used. + weight assigned to particles that are not killed after Russian roulette. + Value of energy should be a float indicating energy in eV below which + particle type will be killed. Value of time should be a float in + seconds. Particles will be killed exactly at the specified time. delayed_photon_scaling : bool Indicate whether to scale the fission photon yield by (EGP + EGD)/EGP where EGP is the energy release of prompt photons and EGD is the energy @@ -72,8 +85,9 @@ class Settings: Maximum number of lost particles .. versionadded:: 0.12 - rel_max_lost_particles : int - Maximum number of lost particles, relative to the total number of particles + rel_max_lost_particles : float + Maximum number of lost particles, relative to the total number of + particles .. versionadded:: 0.12 inactive : int @@ -96,8 +110,25 @@ class Settings: parallelism. .. versionadded:: 0.12 + max_particle_events : int + Maximum number of allowed particle events per source particle. + + .. versionadded:: 0.14.1 max_order : None or int Maximum scattering order to apply globally when in multi-group mode. + max_splits : int + Maximum number of times a particle can split during a history + + .. versionadded:: 0.13 + max_tracks : int + Maximum number of tracks written to a track file (per MPI process). + + .. versionadded:: 0.13.1 + max_write_lost_particles : int + Maximum number of particle restart files (per MPI process) to write for + lost particles. + + .. versionadded:: 0.14.0 no_reduce : bool Indicate that all user-defined and global tallies should not be reduced across processes in a parallel calculation. @@ -112,8 +143,22 @@ class Settings: Number of particles per generation photon_transport : bool Whether to use photon transport. + plot_seed : int + Initial seed for randomly generated plot colors. ptables : bool Determine whether probability tables are used. + random_ray : dict + Options for configuring the random ray solver. Acceptable keys are: + + :distance_inactive: + Indicates the total active distance in [cm] a ray should travel + :distance_active: + Indicates the total active distance in [cm] a ray should travel + :ray_source: + Starting ray distribution (must be uniform in space and angle) as + specified by a :class:`openmc.SourceBase` object. + + .. versionadded:: 0.14.1 resonance_scattering : dict Settings for resonance elastic scattering. Accepted keys are 'enable' (bool), 'method' (str), 'energy_min' (float), 'energy_max' (float), and @@ -121,15 +166,15 @@ class Settings: rejection correction) or 'rvs' (relative velocity sampling). If not specified, 'rvs' is the default method. The 'energy_min' and 'energy_max' values indicate the minimum and maximum energies above and - below which the resonance elastic scattering method is to be - applied. The 'nuclides' list indicates what nuclides the method should - be applied to. In its absence, the method will be applied to all - nuclides with 0 K elastic scattering data present. + below which the resonance elastic scattering method is to be applied. + The 'nuclides' list indicates what nuclides the method should be applied + to. In its absence, the method will be applied to all nuclides with 0 K + elastic scattering data present. run_mode : {'eigenvalue', 'fixed source', 'plot', 'volume', 'particle restart'} The type of calculation to perform (default is 'eigenvalue') seed : int Seed for the linear congruential pseudorandom number generator - source : Iterable of openmc.Source + source : Iterable of openmc.SourceBase Distribution of source sites in space, angle, and energy sourcepoint : dict Options for writing source points. Acceptable keys are: @@ -139,10 +184,11 @@ class Settings: :separate: bool indicating whether the source should be written as a separate file :write: bool indicating whether or not to write the source + :mcpl: bool indicating whether to write the source as an MCPL file statepoint : dict Options for writing state points. Acceptable keys are: - :batches: list of batches at which to write source + :batches: list of batches at which to write statepoint files surf_source_read : dict Options for reading surface source points. Acceptable keys are: @@ -152,17 +198,18 @@ class Settings: :surface_ids: List of surface ids at which crossing particles are to be banked (int) - :max_particles: Maximum number of particles to be banked on - surfaces per process (int) + :max_particles: Maximum number of particles to be banked on surfaces per + process (int) + :mcpl: Output in the form of an MCPL-file (bool) survival_biasing : bool Indicate whether survival biasing is to be used tabular_legendre : dict Determines if a multi-group scattering moment kernel expanded via Legendre polynomials is to be converted to a tabular distribution or - not. Accepted keys are 'enable' and 'num_points'. The value for - 'enable' is a bool stating whether the conversion to tabular is - performed; the value for 'num_points' sets the number of points to use - in the tabular distribution, should 'enable' be True. + not. Accepted keys are 'enable' and 'num_points'. The value for 'enable' + is a bool stating whether the conversion to tabular is performed; the + value for 'num_points' sets the number of points to use in the tabular + distribution, should 'enable' be True. temperature : dict Defines a default temperature and method for treating intermediate temperatures at which nuclear data doesn't exist. Accepted keys are @@ -170,18 +217,20 @@ class Settings: for 'default' should be a float representing the default temperature in Kelvin. The value for 'method' should be 'nearest' or 'interpolation'. If the method is 'nearest', 'tolerance' indicates a range of temperature - within which cross sections may be used. The value for 'range' should be - a pair a minimum and maximum temperatures which are used to indicate - that cross sections be loaded at all temperatures within the - range. 'multipole' is a boolean indicating whether or not the windowed - multipole method should be used to evaluate resolved resonance cross - sections. + within which cross sections may be used. If the method is + 'interpolation', 'tolerance' indicates the range of temperatures outside + of the available cross section temperatures where cross sections will + evaluate to the nearer bound. The value for 'range' should be a pair of + minimum and maximum temperatures which are used to indicate that cross + sections be loaded at all temperatures within the range. 'multipole' is + a boolean indicating whether or not the windowed multipole method should + be used to evaluate resolved resonance cross sections. trace : tuple or list Show detailed information about a single particle, indicated by three integers: the batch number, generation number, and particle number track : tuple or list Specify particles for which track files should be written. Each particle - is identified by a triplet with the batch number, generation number, and + is identified by a tuple with the batch number, generation number, and particle number. trigger_active : bool Indicate whether tally triggers are used @@ -192,23 +241,52 @@ class Settings: batches specified via ``batches`` is interpreted as the minimum number of batches ufs_mesh : openmc.RegularMesh - Mesh to be used for redistributing source sites via the uniform fision + Mesh to be used for redistributing source sites via the uniform fission site (UFS) method. verbosity : int Verbosity during simulation between 1 and 10. Verbosity levels are described in :ref:`verbosity`. volume_calculations : VolumeCalculation or iterable of VolumeCalculation Stochastic volume calculation specifications + weight_windows : WeightWindows or iterable of WeightWindows + Weight windows to use for variance reduction + + .. versionadded:: 0.13 + weight_window_checkpoints : dict + Indicates the checkpoints for weight window split/roulettes. Valid keys + include "collision" and "surface". Values must be of type bool. + .. versionadded:: 0.14.0 + weight_window_generators : WeightWindowGenerator or iterable of WeightWindowGenerator + Weight windows generation parameters to apply during simulation + + .. versionadded:: 0.14.0 + + create_delayed_neutrons : bool + Whether delayed neutrons are created in fission. + + .. versionadded:: 0.13.3 + weight_windows_on : bool + Whether weight windows are enabled + + .. versionadded:: 0.13 + + weight_windows_file: Pathlike + Path to a weight window file to load during simulation initialization + + .. versionadded::0.14.0 + write_initial_source : bool + Indicate whether to write the initial source distribution to file """ - def __init__(self): + def __init__(self, **kwargs): self._run_mode = RunMode.EIGENVALUE self._batches = None self._generations_per_batch = None self._inactive = None self._max_lost_particles = None self._rel_max_lost_particles = None + self._max_write_lost_particles = None self._particles = None self._keff_trigger = None @@ -217,11 +295,12 @@ def __init__(self): self._max_order = None # Source subelement - self._source = cv.CheckedList(Source, 'source distributions') + self._source = cv.CheckedList(SourceBase, 'source distributions') self._confidence_intervals = None self._electron_treatment = None self._photon_transport = None + self._plot_seed = None self._ptables = None self._seed = None self._survival_biasing = None @@ -265,241 +344,124 @@ def __init__(self): VolumeCalculation, 'volume calculations') self._create_fission_neutrons = None + self._create_delayed_neutrons = None self._delayed_photon_scaling = None self._material_cell_offsets = None self._log_grid_bins = None - self._dagmc = False - self._event_based = None self._max_particles_in_flight = None + self._max_particle_events = None + self._write_initial_source = None + self._weight_windows = cv.CheckedList(WeightWindows, 'weight windows') + self._weight_window_generators = cv.CheckedList(WeightWindowGenerator, 'weight window generators') + self._weight_windows_on = None + self._weight_windows_file = None + self._weight_window_checkpoints = {} + self._max_splits = None + self._max_tracks = None - @property - def run_mode(self): - return self._run_mode.value - - @property - def batches(self): - return self._batches - - @property - def generations_per_batch(self): - return self._generations_per_batch - - @property - def inactive(self): - return self._inactive - - @property - def max_lost_particles(self): - return self._max_lost_particles - - @property - def rel_max_lost_particles(self): - return self._rel_max_lost_particles - - @property - def particles(self): - return self._particles - - @property - def keff_trigger(self): - return self._keff_trigger - - @property - def energy_mode(self): - return self._energy_mode - - @property - def max_order(self): - return self._max_order - - @property - def source(self): - return self._source - - @property - def confidence_intervals(self): - return self._confidence_intervals - - @property - def electron_treatment(self): - return self._electron_treatment + self._random_ray = {} - @property - def ptables(self): - return self._ptables + for key, value in kwargs.items(): + setattr(self, key, value) @property - def photon_transport(self): - return self._photon_transport - - @property - def seed(self): - return self._seed - - @property - def survival_biasing(self): - return self._survival_biasing - - @property - def entropy_mesh(self): - return self._entropy_mesh - - @property - def trigger_active(self): - return self._trigger_active - - @property - def trigger_max_batches(self): - return self._trigger_max_batches - - @property - def trigger_batch_interval(self): - return self._trigger_batch_interval - - @property - def output(self): - return self._output - - @property - def sourcepoint(self): - return self._sourcepoint - - @property - def statepoint(self): - return self._statepoint - - @property - def surf_source_read(self): - return self._surf_source_read - - @property - def surf_source_write(self): - return self._surf_source_write - - @property - def no_reduce(self): - return self._no_reduce - - @property - def verbosity(self): - return self._verbosity - - @property - def tabular_legendre(self): - return self._tabular_legendre - - @property - def temperature(self): - return self._temperature - - @property - def trace(self): - return self._trace - - @property - def track(self): - return self._track - - @property - def cutoff(self): - return self._cutoff - - @property - def ufs_mesh(self): - return self._ufs_mesh - - @property - def resonance_scattering(self): - return self._resonance_scattering - - @property - def volume_calculations(self): - return self._volume_calculations - - @property - def create_fission_neutrons(self): - return self._create_fission_neutrons - - @property - def delayed_photon_scaling(self): - return self._delayed_photon_scaling - - @property - def material_cell_offsets(self): - return self._material_cell_offsets - - @property - def log_grid_bins(self): - return self._log_grid_bins - - @property - def dagmc(self): - return self._dagmc - - @property - def event_based(self): - return self._event_based - - @property - def max_particles_in_flight(self): - return self._max_particles_in_flight + def run_mode(self) -> str: + return self._run_mode.value @run_mode.setter - def run_mode(self, run_mode): + def run_mode(self, run_mode: str): cv.check_value('run mode', run_mode, {x.value for x in RunMode}) for mode in RunMode: if mode.value == run_mode: self._run_mode = mode + @property + def batches(self) -> int: + return self._batches + @batches.setter - def batches(self, batches): + def batches(self, batches: int): cv.check_type('batches', batches, Integral) cv.check_greater_than('batches', batches, 0) self._batches = batches + @property + def generations_per_batch(self) -> int: + return self._generations_per_batch + @generations_per_batch.setter - def generations_per_batch(self, generations_per_batch): + def generations_per_batch(self, generations_per_batch: int): cv.check_type('generations per patch', generations_per_batch, Integral) cv.check_greater_than('generations per batch', generations_per_batch, 0) self._generations_per_batch = generations_per_batch + @property + def inactive(self) -> int: + return self._inactive + @inactive.setter - def inactive(self, inactive): + def inactive(self, inactive: int): cv.check_type('inactive batches', inactive, Integral) cv.check_greater_than('inactive batches', inactive, 0, True) self._inactive = inactive + @property + def max_lost_particles(self) -> int: + return self._max_lost_particles + @max_lost_particles.setter - def max_lost_particles(self, max_lost_particles): + def max_lost_particles(self, max_lost_particles: int): cv.check_type('max_lost_particles', max_lost_particles, Integral) cv.check_greater_than('max_lost_particles', max_lost_particles, 0) self._max_lost_particles = max_lost_particles + @property + def rel_max_lost_particles(self) -> float: + return self._rel_max_lost_particles + @rel_max_lost_particles.setter - def rel_max_lost_particles(self, rel_max_lost_particles): + def rel_max_lost_particles(self, rel_max_lost_particles: float): cv.check_type('rel_max_lost_particles', rel_max_lost_particles, Real) cv.check_greater_than('rel_max_lost_particles', rel_max_lost_particles, 0) cv.check_less_than('rel_max_lost_particles', rel_max_lost_particles, 1) self._rel_max_lost_particles = rel_max_lost_particles + @property + def max_write_lost_particles(self) -> int: + return self._max_write_lost_particles + + @max_write_lost_particles.setter + def max_write_lost_particles(self, max_write_lost_particles: int): + cv.check_type('max_write_lost_particles', max_write_lost_particles, Integral) + cv.check_greater_than('max_write_lost_particles', max_write_lost_particles, 0) + self._max_write_lost_particles = max_write_lost_particles + + @property + def particles(self) -> int: + return self._particles + @particles.setter - def particles(self, particles): + def particles(self, particles: int): cv.check_type('particles', particles, Integral) cv.check_greater_than('particles', particles, 0) self._particles = particles + @property + def keff_trigger(self) -> dict: + return self._keff_trigger + @keff_trigger.setter - def keff_trigger(self, keff_trigger): + def keff_trigger(self, keff_trigger: dict): if not isinstance(keff_trigger, dict): - msg = 'Unable to set a trigger on keff from "{0}" which ' \ - 'is not a Python dictionary'.format(keff_trigger) + msg = f'Unable to set a trigger on keff from "{keff_trigger}" ' \ + 'which is not a Python dictionary' raise ValueError(msg) elif 'type' not in keff_trigger: - msg = 'Unable to set a trigger on keff from "{0}" which ' \ - 'does not have a "type" key'.format(keff_trigger) + msg = f'Unable to set a trigger on keff from "{keff_trigger}" ' \ + 'which does not have a "type" key' raise ValueError(msg) elif keff_trigger['type'] not in ['variance', 'std_dev', 'rel_err']: @@ -508,8 +470,8 @@ def keff_trigger(self, keff_trigger): raise ValueError(msg) elif 'threshold' not in keff_trigger: - msg = 'Unable to set a trigger on keff from "{0}" which ' \ - 'does not have a "threshold" key'.format(keff_trigger) + msg = f'Unable to set a trigger on keff from "{keff_trigger}" ' \ + 'which does not have a "threshold" key' raise ValueError(msg) elif not isinstance(keff_trigger['threshold'], Real): @@ -519,194 +481,264 @@ def keff_trigger(self, keff_trigger): self._keff_trigger = keff_trigger + @property + def energy_mode(self) -> str: + return self._energy_mode + @energy_mode.setter - def energy_mode(self, energy_mode): + def energy_mode(self, energy_mode: str): cv.check_value('energy mode', energy_mode, ['continuous-energy', 'multi-group']) self._energy_mode = energy_mode + @property + def max_order(self) -> int: + return self._max_order + @max_order.setter - def max_order(self, max_order): + def max_order(self, max_order: Optional[int]): if max_order is not None: cv.check_type('maximum scattering order', max_order, Integral) cv.check_greater_than('maximum scattering order', max_order, 0, True) self._max_order = max_order + @property + def source(self) -> typing.List[SourceBase]: + return self._source + @source.setter - def source(self, source): + def source(self, source: typing.Union[SourceBase, typing.Iterable[SourceBase]]): if not isinstance(source, MutableSequence): source = [source] - self._source = cv.CheckedList(Source, 'source distributions', source) - - @output.setter - def output(self, output): - cv.check_type('output', output, Mapping) - for key, value in output.items(): - cv.check_value('output key', key, ('summary', 'tallies', 'path')) - if key in ('summary', 'tallies'): - cv.check_type("output['{}']".format(key), value, bool) - else: - cv.check_type("output['path']", value, str) - self._output = output + self._source = cv.CheckedList(SourceBase, 'source distributions', source) - @verbosity.setter - def verbosity(self, verbosity): - cv.check_type('verbosity', verbosity, Integral) - cv.check_greater_than('verbosity', verbosity, 1, True) - cv.check_less_than('verbosity', verbosity, 10, True) - self._verbosity = verbosity - - @sourcepoint.setter - def sourcepoint(self, sourcepoint): - cv.check_type('sourcepoint options', sourcepoint, Mapping) - for key, value in sourcepoint.items(): - if key == 'batches': - cv.check_type('sourcepoint batches', value, Iterable, Integral) - for batch in value: - cv.check_greater_than('sourcepoint batch', batch, 0) - elif key == 'separate': - cv.check_type('sourcepoint separate', value, bool) - elif key == 'write': - cv.check_type('sourcepoint write', value, bool) - elif key == 'overwrite': - cv.check_type('sourcepoint overwrite', value, bool) - else: - raise ValueError("Unknown key '{}' encountered when setting " - "sourcepoint options.".format(key)) - self._sourcepoint = sourcepoint - - @statepoint.setter - def statepoint(self, statepoint): - cv.check_type('statepoint options', statepoint, Mapping) - for key, value in statepoint.items(): - if key == 'batches': - cv.check_type('statepoint batches', value, Iterable, Integral) - for batch in value: - cv.check_greater_than('statepoint batch', batch, 0) - else: - raise ValueError("Unknown key '{}' encountered when setting " - "statepoint options.".format(key)) - self._statepoint = statepoint - - @surf_source_read.setter - def surf_source_read(self, surf_source_read): - cv.check_type('surface source reading options', surf_source_read, Mapping) - for key, value in surf_source_read.items(): - cv.check_value('surface source reading key', key, - ('path')) - if key == 'path': - cv.check_type('path to surface source file', value, str) - self._surf_source_read = surf_source_read - - @surf_source_write.setter - def surf_source_write(self, surf_source_write): - cv.check_type('surface source writing options', surf_source_write, Mapping) - for key, value in surf_source_write.items(): - cv.check_value('surface source writing key', key, - ('surface_ids', 'max_particles')) - if key == 'surface_ids': - cv.check_type('surface ids for source banking', value, - Iterable, Integral) - for surf_id in value: - cv.check_greater_than('surface id for source banking', - surf_id, 0) - elif key == 'max_particles': - cv.check_type('maximum particle banks on surfaces per process', - value, Integral) - cv.check_greater_than('maximum particle banks on surfaces per process', - value, 0) - self._surf_source_write = surf_source_write + @property + def confidence_intervals(self) -> bool: + return self._confidence_intervals @confidence_intervals.setter - def confidence_intervals(self, confidence_intervals): + def confidence_intervals(self, confidence_intervals: bool): cv.check_type('confidence interval', confidence_intervals, bool) self._confidence_intervals = confidence_intervals + @property + def electron_treatment(self) -> str: + return self._electron_treatment + @electron_treatment.setter - def electron_treatment(self, electron_treatment): + def electron_treatment(self, electron_treatment: str): cv.check_value('electron treatment', electron_treatment, ['led', 'ttb']) self._electron_treatment = electron_treatment + @property + def ptables(self) -> bool: + return self._ptables + + @ptables.setter + def ptables(self, ptables: bool): + cv.check_type('probability tables', ptables, bool) + self._ptables = ptables + + @property + def photon_transport(self) -> bool: + return self._photon_transport + @photon_transport.setter - def photon_transport(self, photon_transport): + def photon_transport(self, photon_transport: bool): cv.check_type('photon transport', photon_transport, bool) self._photon_transport = photon_transport - @dagmc.setter - def dagmc(self, dagmc): - cv.check_type('dagmc geometry', dagmc, bool) - self._dagmc = dagmc + @property + def plot_seed(self): + return self._plot_seed - @ptables.setter - def ptables(self, ptables): - cv.check_type('probability tables', ptables, bool) - self._ptables = ptables + @plot_seed.setter + def plot_seed(self, seed): + cv.check_type('random plot color seed', seed, Integral) + cv.check_greater_than('random plot color seed', seed, 0) + self._plot_seed = seed + + @property + def seed(self) -> int: + return self._seed @seed.setter - def seed(self, seed): + def seed(self, seed: int): cv.check_type('random number generator seed', seed, Integral) cv.check_greater_than('random number generator seed', seed, 0) self._seed = seed + @property + def survival_biasing(self) -> bool: + return self._survival_biasing + @survival_biasing.setter - def survival_biasing(self, survival_biasing): + def survival_biasing(self, survival_biasing: bool): cv.check_type('survival biasing', survival_biasing, bool) self._survival_biasing = survival_biasing - @cutoff.setter - def cutoff(self, cutoff): - if not isinstance(cutoff, Mapping): - msg = 'Unable to set cutoff from "{0}" which is not a '\ - ' Python dictionary'.format(cutoff) - raise ValueError(msg) - for key in cutoff: - if key == 'weight': - cv.check_type('weight cutoff', cutoff[key], Real) - cv.check_greater_than('weight cutoff', cutoff[key], 0.0) - elif key == 'weight_avg': - cv.check_type('average survival weight', cutoff[key], Real) - cv.check_greater_than('average survival weight', - cutoff[key], 0.0) - elif key in ['energy_neutron', 'energy_photon', 'energy_electron', - 'energy_positron']: - cv.check_type('energy cutoff', cutoff[key], Real) - cv.check_greater_than('energy cutoff', cutoff[key], 0.0) + @property + def entropy_mesh(self) -> RegularMesh: + return self._entropy_mesh + + @entropy_mesh.setter + def entropy_mesh(self, entropy: RegularMesh): + cv.check_type('entropy mesh', entropy, RegularMesh) + self._entropy_mesh = entropy + + @property + def trigger_active(self) -> bool: + return self._trigger_active + + @trigger_active.setter + def trigger_active(self, trigger_active: bool): + cv.check_type('trigger active', trigger_active, bool) + self._trigger_active = trigger_active + + @property + def trigger_max_batches(self) -> int: + return self._trigger_max_batches + + @trigger_max_batches.setter + def trigger_max_batches(self, trigger_max_batches: int): + cv.check_type('trigger maximum batches', trigger_max_batches, Integral) + cv.check_greater_than('trigger maximum batches', trigger_max_batches, 0) + self._trigger_max_batches = trigger_max_batches + + @property + def trigger_batch_interval(self) -> int: + return self._trigger_batch_interval + + @trigger_batch_interval.setter + def trigger_batch_interval(self, trigger_batch_interval: int): + cv.check_type('trigger batch interval', trigger_batch_interval, Integral) + cv.check_greater_than('trigger batch interval', trigger_batch_interval, 0) + self._trigger_batch_interval = trigger_batch_interval + + @property + def output(self) -> dict: + return self._output + + @output.setter + def output(self, output: dict): + cv.check_type('output', output, Mapping) + for key, value in output.items(): + cv.check_value('output key', key, ('summary', 'tallies', 'path')) + if key in ('summary', 'tallies'): + cv.check_type(f"output['{key}']", value, bool) + else: + cv.check_type("output['path']", value, str) + self._output = output + + @property + def sourcepoint(self) -> dict: + return self._sourcepoint + + @sourcepoint.setter + def sourcepoint(self, sourcepoint: dict): + cv.check_type('sourcepoint options', sourcepoint, Mapping) + for key, value in sourcepoint.items(): + if key == 'batches': + cv.check_type('sourcepoint batches', value, Iterable, Integral) + for batch in value: + cv.check_greater_than('sourcepoint batch', batch, 0) + elif key == 'separate': + cv.check_type('sourcepoint separate', value, bool) + elif key == 'write': + cv.check_type('sourcepoint write', value, bool) + elif key == 'overwrite': + cv.check_type('sourcepoint overwrite', value, bool) + elif key == 'mcpl': + cv.check_type('sourcepoint mcpl', value, bool) + else: + raise ValueError(f"Unknown key '{key}' encountered when " + "setting sourcepoint options.") + self._sourcepoint = sourcepoint + + @property + def statepoint(self) -> dict: + return self._statepoint + + @statepoint.setter + def statepoint(self, statepoint: dict): + cv.check_type('statepoint options', statepoint, Mapping) + for key, value in statepoint.items(): + if key == 'batches': + cv.check_type('statepoint batches', value, Iterable, Integral) + for batch in value: + cv.check_greater_than('statepoint batch', batch, 0) else: - msg = 'Unable to set cutoff to "{0}" which is unsupported by '\ - 'OpenMC'.format(key) + raise ValueError(f"Unknown key '{key}' encountered when " + "setting statepoint options.") + self._statepoint = statepoint - self._cutoff = cutoff + @property + def surf_source_read(self) -> dict: + return self._surf_source_read - @entropy_mesh.setter - def entropy_mesh(self, entropy): - cv.check_type('entropy mesh', entropy, RegularMesh) - self._entropy_mesh = entropy + @surf_source_read.setter + def surf_source_read(self, surf_source_read: dict): + cv.check_type('surface source reading options', surf_source_read, Mapping) + for key, value in surf_source_read.items(): + cv.check_value('surface source reading key', key, + ('path')) + if key == 'path': + cv.check_type('path to surface source file', value, str) + self._surf_source_read = surf_source_read - @trigger_active.setter - def trigger_active(self, trigger_active): - cv.check_type('trigger active', trigger_active, bool) - self._trigger_active = trigger_active + @property + def surf_source_write(self) -> dict: + return self._surf_source_write - @trigger_max_batches.setter - def trigger_max_batches(self, trigger_max_batches): - cv.check_type('trigger maximum batches', trigger_max_batches, Integral) - cv.check_greater_than('trigger maximum batches', trigger_max_batches, 0) - self._trigger_max_batches = trigger_max_batches + @surf_source_write.setter + def surf_source_write(self, surf_source_write: dict): + cv.check_type('surface source writing options', surf_source_write, Mapping) + for key, value in surf_source_write.items(): + cv.check_value('surface source writing key', key, + ('surface_ids', 'max_particles', 'mcpl')) + if key == 'surface_ids': + cv.check_type('surface ids for source banking', value, + Iterable, Integral) + for surf_id in value: + cv.check_greater_than('surface id for source banking', + surf_id, 0) + elif key == 'max_particles': + cv.check_type('maximum particle banks on surfaces per process', + value, Integral) + cv.check_greater_than('maximum particle banks on surfaces per process', + value, 0) + elif key == 'mcpl': + cv.check_type('write to an MCPL-format file', value, bool) - @trigger_batch_interval.setter - def trigger_batch_interval(self, trigger_batch_interval): - cv.check_type('trigger batch interval', trigger_batch_interval, Integral) - cv.check_greater_than('trigger batch interval', trigger_batch_interval, 0) - self._trigger_batch_interval = trigger_batch_interval + self._surf_source_write = surf_source_write + + @property + def no_reduce(self) -> bool: + return self._no_reduce @no_reduce.setter - def no_reduce(self, no_reduce): + def no_reduce(self, no_reduce: bool): cv.check_type('no reduction option', no_reduce, bool) self._no_reduce = no_reduce + @property + def verbosity(self) -> int: + return self._verbosity + + @verbosity.setter + def verbosity(self, verbosity: int): + cv.check_type('verbosity', verbosity, Integral) + cv.check_greater_than('verbosity', verbosity, 1, True) + cv.check_less_than('verbosity', verbosity, 10, True) + self._verbosity = verbosity + + @property + def tabular_legendre(self) -> dict: + return self._tabular_legendre + @tabular_legendre.setter - def tabular_legendre(self, tabular_legendre): + def tabular_legendre(self, tabular_legendre: dict): cv.check_type('tabular_legendre settings', tabular_legendre, Mapping) for key, value in tabular_legendre.items(): cv.check_value('tabular_legendre key', key, @@ -718,8 +750,12 @@ def tabular_legendre(self, tabular_legendre): cv.check_greater_than('num_points tabular_legendre', value, 0) self._tabular_legendre = tabular_legendre + @property + def temperature(self) -> dict: + return self._temperature + @temperature.setter - def temperature(self, temperature): + def temperature(self, temperature: dict): cv.check_type('temperature settings', temperature, Mapping) for key, value in temperature.items(): @@ -742,8 +778,12 @@ def temperature(self, temperature): self._temperature = temperature + @property + def trace(self) -> typing.Iterable: + return self._trace + @trace.setter - def trace(self, trace): + def trace(self, trace: Iterable): cv.check_type('trace', trace, Iterable, Integral) cv.check_length('trace', trace, 3) cv.check_greater_than('trace batch', trace[0], 0) @@ -751,29 +791,71 @@ def trace(self, trace): cv.check_greater_than('trace particle', trace[2], 0) self._trace = trace + @property + def track(self) -> typing.Iterable[typing.Iterable[int]]: + return self._track + @track.setter - def track(self, track): - cv.check_type('track', track, Iterable, Integral) - if len(track) % 3 != 0: - msg = 'Unable to set the track to "{0}" since its length is ' \ - 'not a multiple of 3'.format(track) - raise ValueError(msg) - for t in zip(track[::3], track[1::3], track[2::3]): + def track(self, track: typing.Iterable[typing.Iterable[int]]): + cv.check_type('track', track, Iterable) + for t in track: + if len(t) != 3: + msg = f'Unable to set the track to "{t}" since its length is not 3' + raise ValueError(msg) cv.check_greater_than('track batch', t[0], 0) - cv.check_greater_than('track generation', t[0], 0) - cv.check_greater_than('track particle', t[0], 0) + cv.check_greater_than('track generation', t[1], 0) + cv.check_greater_than('track particle', t[2], 0) + cv.check_type('track batch', t[0], Integral) + cv.check_type('track generation', t[1], Integral) + cv.check_type('track particle', t[2], Integral) self._track = track + @property + def cutoff(self) -> dict: + return self._cutoff + + @cutoff.setter + def cutoff(self, cutoff: dict): + if not isinstance(cutoff, Mapping): + msg = f'Unable to set cutoff from "{cutoff}" which is not a '\ + 'Python dictionary' + raise ValueError(msg) + for key in cutoff: + if key == 'weight': + cv.check_type('weight cutoff', cutoff[key], Real) + cv.check_greater_than('weight cutoff', cutoff[key], 0.0) + elif key == 'weight_avg': + cv.check_type('average survival weight', cutoff[key], Real) + cv.check_greater_than('average survival weight', + cutoff[key], 0.0) + elif key in ['energy_neutron', 'energy_photon', 'energy_electron', + 'energy_positron']: + cv.check_type('energy cutoff', cutoff[key], Real) + cv.check_greater_than('energy cutoff', cutoff[key], 0.0) + else: + msg = f'Unable to set cutoff to "{key}" which is unsupported ' \ + 'by OpenMC' + + self._cutoff = cutoff + + @property + def ufs_mesh(self) -> RegularMesh: + return self._ufs_mesh + @ufs_mesh.setter - def ufs_mesh(self, ufs_mesh): + def ufs_mesh(self, ufs_mesh: RegularMesh): cv.check_type('UFS mesh', ufs_mesh, RegularMesh) cv.check_length('UFS mesh dimension', ufs_mesh.dimension, 3) cv.check_length('UFS mesh lower-left corner', ufs_mesh.lower_left, 3) cv.check_length('UFS mesh upper-right corner', ufs_mesh.upper_right, 3) self._ufs_mesh = ufs_mesh + @property + def resonance_scattering(self) -> dict: + return self._resonance_scattering + @resonance_scattering.setter - def resonance_scattering(self, res): + def resonance_scattering(self, res: dict): cv.check_type('resonance scattering settings', res, Mapping) keys = ('enable', 'method', 'energy_min', 'energy_max', 'nuclides') for key, value in res.items(): @@ -796,45 +878,197 @@ def resonance_scattering(self, res): Iterable, str) self._resonance_scattering = res + @property + def volume_calculations(self) -> typing.List[VolumeCalculation]: + return self._volume_calculations + @volume_calculations.setter - def volume_calculations(self, vol_calcs): + def volume_calculations( + self, vol_calcs: typing.Union[VolumeCalculation, typing.Iterable[VolumeCalculation]] + ): if not isinstance(vol_calcs, MutableSequence): vol_calcs = [vol_calcs] self._volume_calculations = cv.CheckedList( VolumeCalculation, 'stochastic volume calculations', vol_calcs) + @property + def create_fission_neutrons(self) -> bool: + return self._create_fission_neutrons + @create_fission_neutrons.setter - def create_fission_neutrons(self, create_fission_neutrons): + def create_fission_neutrons(self, create_fission_neutrons: bool): cv.check_type('Whether create fission neutrons', create_fission_neutrons, bool) self._create_fission_neutrons = create_fission_neutrons + @property + def create_delayed_neutrons(self) -> bool: + return self._create_delayed_neutrons + + @create_delayed_neutrons.setter + def create_delayed_neutrons(self, create_delayed_neutrons: bool): + cv.check_type('Whether create only prompt neutrons', + create_delayed_neutrons, bool) + self._create_delayed_neutrons = create_delayed_neutrons + + @property + def delayed_photon_scaling(self) -> bool: + return self._delayed_photon_scaling + @delayed_photon_scaling.setter - def delayed_photon_scaling(self, value): + def delayed_photon_scaling(self, value: bool): cv.check_type('delayed photon scaling', value, bool) self._delayed_photon_scaling = value + @property + def material_cell_offsets(self) -> bool: + return self._material_cell_offsets + + @material_cell_offsets.setter + def material_cell_offsets(self, value: bool): + cv.check_type('material cell offsets', value, bool) + self._material_cell_offsets = value + + @property + def log_grid_bins(self) -> int: + return self._log_grid_bins + + @log_grid_bins.setter + def log_grid_bins(self, log_grid_bins: int): + cv.check_type('log grid bins', log_grid_bins, Real) + cv.check_greater_than('log grid bins', log_grid_bins, 0) + self._log_grid_bins = log_grid_bins + + @property + def event_based(self) -> bool: + return self._event_based + @event_based.setter - def event_based(self, value): + def event_based(self, value: bool): cv.check_type('event based', value, bool) self._event_based = value + @property + def max_particles_in_flight(self) -> int: + return self._max_particles_in_flight + @max_particles_in_flight.setter - def max_particles_in_flight(self, value): + def max_particles_in_flight(self, value: int): cv.check_type('max particles in flight', value, Integral) cv.check_greater_than('max particles in flight', value, 0) self._max_particles_in_flight = value - @material_cell_offsets.setter - def material_cell_offsets(self, value): - cv.check_type('material cell offsets', value, bool) - self._material_cell_offsets = value + @property + def max_particle_events(self) -> int: + return self._max_particle_events - @log_grid_bins.setter - def log_grid_bins(self, log_grid_bins): - cv.check_type('log grid bins', log_grid_bins, Real) - cv.check_greater_than('log grid bins', log_grid_bins, 0) - self._log_grid_bins = log_grid_bins + @max_particle_events.setter + def max_particle_events(self, value: int): + cv.check_type('max particle events', value, Integral) + cv.check_greater_than('max particle events', value, 0) + self._max_particle_events = value + + @property + def write_initial_source(self) -> bool: + return self._write_initial_source + + @write_initial_source.setter + def write_initial_source(self, value: bool): + cv.check_type('write initial source', value, bool) + self._write_initial_source = value + + @property + def weight_windows(self) -> typing.List[WeightWindows]: + return self._weight_windows + + @weight_windows.setter + def weight_windows(self, value: typing.Union[WeightWindows, typing.Iterable[WeightWindows]]): + if not isinstance(value, MutableSequence): + value = [value] + self._weight_windows = cv.CheckedList(WeightWindows, 'weight windows', value) + + @property + def weight_windows_on(self) -> bool: + return self._weight_windows_on + + @weight_windows_on.setter + def weight_windows_on(self, value: bool): + cv.check_type('weight windows on', value, bool) + self._weight_windows_on = value + + @property + def weight_window_checkpoints(self) -> dict: + return self._weight_window_checkpoints + + @weight_window_checkpoints.setter + def weight_window_checkpoints(self, weight_window_checkpoints: dict): + for key in weight_window_checkpoints.keys(): + cv.check_value('weight_window_checkpoints', key, ('collision', 'surface')) + self._weight_window_checkpoints = weight_window_checkpoints + + @property + def max_splits(self) -> int: + return self._max_splits + + @max_splits.setter + def max_splits(self, value: int): + cv.check_type('maximum particle splits', value, Integral) + cv.check_greater_than('max particle splits', value, 0) + self._max_splits = value + + @property + def max_tracks(self) -> int: + return self._max_tracks + + @max_tracks.setter + def max_tracks(self, value: int): + cv.check_type('maximum particle tracks', value, Integral) + cv.check_greater_than('maximum particle tracks', value, 0, True) + self._max_tracks = value + + @property + def weight_windows_file(self) -> Optional[PathLike]: + return self._weight_windows_file + + @weight_windows_file.setter + def weight_windows_file(self, value: PathLike): + cv.check_type('weight windows file', value, (str, Path)) + self._weight_windows_file = value + + @property + def weight_window_generators(self) -> typing.List[WeightWindowGenerator]: + return self._weight_window_generators + + @weight_window_generators.setter + def weight_window_generators(self, wwgs): + if not isinstance(wwgs, MutableSequence): + wwgs = [wwgs] + self._weight_window_generators = cv.CheckedList(WeightWindowGenerator, 'weight window generators', wwgs) + + @property + def random_ray(self) -> dict: + return self._random_ray + + @random_ray.setter + def random_ray(self, random_ray: dict): + if not isinstance(random_ray, Mapping): + raise ValueError(f'Unable to set random_ray from "{random_ray}" ' + 'which is not a dict.') + for key in random_ray: + if key == 'distance_active': + cv.check_type('active ray length', random_ray[key], Real) + cv.check_greater_than('active ray length', random_ray[key], 0.0) + elif key == 'distance_inactive': + cv.check_type('inactive ray length', random_ray[key], Real) + cv.check_greater_than('inactive ray length', + random_ray[key], 0.0, True) + elif key == 'ray_source': + cv.check_type('random ray source', random_ray[key], SourceBase) + else: + raise ValueError(f'Unable to set random ray to "{key}" which is ' + 'unsupported by OpenMC') + + self._random_ray = random_ray def _create_run_mode_subelement(self, root): elem = ET.SubElement(root, "run_mode") @@ -865,6 +1099,11 @@ def _create_rel_max_lost_particles_subelement(self, root): element = ET.SubElement(root, "rel_max_lost_particles") element.text = str(self._rel_max_lost_particles) + def _create_max_write_lost_particles_subelement(self, root): + if self._max_write_lost_particles is not None: + element = ET.SubElement(root, "max_write_lost_particles") + element.text = str(self._max_write_lost_particles) + def _create_particles_subelement(self, root): if self._particles is not None: element = ET.SubElement(root, "particles") @@ -887,9 +1126,19 @@ def _create_max_order_subelement(self, root): element = ET.SubElement(root, "max_order") element.text = str(self._max_order) - def _create_source_subelement(self, root): + def _create_source_subelement(self, root, mesh_memo=None): for source in self.source: root.append(source.to_xml_element()) + if isinstance(source, IndependentSource) and isinstance(source.space, MeshSpatial): + path = f"./mesh[@id='{source.space.mesh.id}']" + if root.find(path) is None: + root.append(source.space.mesh.to_xml_element()) + if isinstance(source, MeshSource): + path = f"./mesh[@id='{source.mesh.id}']" + if root.find(path) is None: + root.append(source.mesh.to_xml_element()) + if mesh_memo is not None: + mesh_memo.add(source.mesh.id) def _create_volume_calcs_subelement(self, root): for calc in self.volume_calculations: @@ -940,6 +1189,10 @@ def _create_sourcepoint_subelement(self, root): subelement = ET.SubElement(element, "overwrite_latest") subelement.text = str(self._sourcepoint['overwrite']).lower() + if 'mcpl' in self._sourcepoint: + subelement = ET.SubElement(element, "mcpl") + subelement.text = str(self._sourcepoint['mcpl']).lower() + def _create_surf_source_read_subelement(self, root): if self._surf_source_read: element = ET.SubElement(root, "surf_source_read") @@ -957,6 +1210,9 @@ def _create_surf_source_write_subelement(self, root): if 'max_particles' in self._surf_source_write: subelement = ET.SubElement(element, "max_particles") subelement.text = str(self._surf_source_write['max_particles']) + if 'mcpl' in self._surf_source_write: + subelement = ET.SubElement(element, "mcpl") + subelement.text = str(self._surf_source_write['mcpl']).lower() def _create_confidence_intervals(self, root): if self._confidence_intervals is not None: @@ -973,6 +1229,11 @@ def _create_photon_transport_subelement(self, root): element = ET.SubElement(root, "photon_transport") element.text = str(self._photon_transport).lower() + def _create_plot_seed_subelement(self, root): + if self._plot_seed is not None: + element = ET.SubElement(root, "plot_seed") + element.text = str(self._plot_seed) + def _create_ptables_subelement(self, root): if self._ptables is not None: element = ET.SubElement(root, "ptables") @@ -995,25 +1256,35 @@ def _create_cutoff_subelement(self, root): subelement = ET.SubElement(element, key) subelement.text = str(value) - def _create_entropy_mesh_subelement(self, root): - if self.entropy_mesh is not None: - # use default heuristic for entropy mesh if not set by user - if self.entropy_mesh.dimension is None: - if self.particles is None: - raise RuntimeError("Number of particles must be set in order to " \ - "use entropy mesh dimension heuristic") - else: - n = ceil((self.particles / 20.0)**(1.0 / 3.0)) - d = len(self.entropy_mesh.lower_left) - self.entropy_mesh.dimension = (n,)*d - - # See if a element already exists -- if not, add it - path = "./mesh[@id='{}']".format(self.entropy_mesh.id) - if root.find(path) is None: - root.append(self.entropy_mesh.to_xml_element()) + def _create_entropy_mesh_subelement(self, root, mesh_memo=None): + if self.entropy_mesh is None: + return - subelement = ET.SubElement(root, "entropy_mesh") - subelement.text = str(self.entropy_mesh.id) + # use default heuristic for entropy mesh if not set by user + if self.entropy_mesh.dimension is None: + if self.particles is None: + raise RuntimeError("Number of particles must be set in order to " \ + "use entropy mesh dimension heuristic") + else: + n = ceil((self.particles / 20.0)**(1.0 / 3.0)) + d = len(self.entropy_mesh.lower_left) + self.entropy_mesh.dimension = (n,)*d + + # add mesh ID to this element + subelement = ET.SubElement(root, "entropy_mesh") + subelement.text = str(self.entropy_mesh.id) + + # If this mesh has already been written outside the + # settings element, skip writing it again + if mesh_memo and self.entropy_mesh.id in mesh_memo: + return + + # See if a element already exists -- if not, add it + path = f"./mesh[@id='{self.entropy_mesh.id}']" + if root.find(path) is None: + root.append(self.entropy_mesh.to_xml_element()) + if mesh_memo is not None: + mesh_memo.add(self.entropy_mesh.id) def _create_trigger_subelement(self, root): if self._trigger_active is not None: @@ -1046,8 +1317,7 @@ def _create_tabular_legendre_subelements(self, root): def _create_temperature_subelements(self, root): if self.temperature: for key, value in sorted(self.temperature.items()): - element = ET.SubElement(root, - "temperature_{}".format(key)) + element = ET.SubElement(root, f"temperature_{key}") if isinstance(value, bool): element.text = str(value).lower() elif key == 'range': @@ -1063,17 +1333,23 @@ def _create_trace_subelement(self, root): def _create_track_subelement(self, root): if self._track is not None: element = ET.SubElement(root, "track") - element.text = ' '.join(map(str, self._track)) + element.text = ' '.join(map(str, itertools.chain(*self._track))) - def _create_ufs_mesh_subelement(self, root): - if self.ufs_mesh is not None: - # See if a element already exists -- if not, add it - path = "./mesh[@id='{}']".format(self.ufs_mesh.id) - if root.find(path) is None: - root.append(self.ufs_mesh.to_xml_element()) + def _create_ufs_mesh_subelement(self, root, mesh_memo=None): + if self.ufs_mesh is None: + return - subelement = ET.SubElement(root, "ufs_mesh") - subelement.text = str(self.ufs_mesh.id) + subelement = ET.SubElement(root, "ufs_mesh") + subelement.text = str(self.ufs_mesh.id) + + if mesh_memo and self.ufs_mesh.id in mesh_memo: + return + + # See if a element already exists -- if not, add it + path = f"./mesh[@id='{self.ufs_mesh.id}']" + if root.find(path) is None: + root.append(self.ufs_mesh.to_xml_element()) + if mesh_memo is not None: mesh_memo.add(self.ufs_mesh.id) def _create_resonance_scattering_subelement(self, root): res = self.resonance_scattering @@ -1100,6 +1376,11 @@ def _create_create_fission_neutrons_subelement(self, root): elem = ET.SubElement(root, "create_fission_neutrons") elem.text = str(self._create_fission_neutrons).lower() + def _create_create_delayed_neutrons_subelement(self, root): + if self._create_delayed_neutrons is not None: + elem = ET.SubElement(root, "create_delayed_neutrons") + elem.text = str(self._create_delayed_neutrons).lower() + def _create_delayed_photon_scaling_subelement(self, root): if self._delayed_photon_scaling is not None: elem = ET.SubElement(root, "delayed_photon_scaling") @@ -1115,6 +1396,11 @@ def _create_max_particles_in_flight_subelement(self, root): elem = ET.SubElement(root, "max_particles_in_flight") elem.text = str(self._max_particles_in_flight).lower() + def _create_max_events_subelement(self, root): + if self._max_particle_events is not None: + elem = ET.SubElement(root, "max_particle_events") + elem.text = str(self._max_particle_events).lower() + def _create_material_cell_offsets_subelement(self, root): if self._material_cell_offsets is not None: elem = ET.SubElement(root, "material_cell_offsets") @@ -1125,10 +1411,87 @@ def _create_log_grid_bins_subelement(self, root): elem = ET.SubElement(root, "log_grid_bins") elem.text = str(self._log_grid_bins) - def _create_dagmc_subelement(self, root): - if self._dagmc: - elem = ET.SubElement(root, "dagmc") - elem.text = str(self._dagmc).lower() + def _create_write_initial_source_subelement(self, root): + if self._write_initial_source is not None: + elem = ET.SubElement(root, "write_initial_source") + elem.text = str(self._write_initial_source).lower() + + def _create_weight_windows_subelement(self, root, mesh_memo=None): + for ww in self._weight_windows: + # Add weight window information + root.append(ww.to_xml_element()) + + # if this mesh has already been written, + # skip writing the mesh element + if mesh_memo and ww.mesh.id in mesh_memo: + continue + + # See if a element already exists -- if not, add it + path = f"./mesh[@id='{ww.mesh.id}']" + if root.find(path) is None: + root.append(ww.mesh.to_xml_element()) + if mesh_memo is not None: + mesh_memo.add(ww.mesh.id) + + if self._weight_windows_on is not None: + elem = ET.SubElement(root, "weight_windows_on") + elem.text = str(self._weight_windows_on).lower() + + def _create_weight_window_generators_subelement(self, root, mesh_memo=None): + if not self.weight_window_generators: + return + elem = ET.SubElement(root, 'weight_window_generators') + for wwg in self.weight_window_generators: + elem.append(wwg.to_xml_element()) + + # ensure that mesh elements are created if needed + for wwg in self.weight_window_generators: + if mesh_memo is not None and wwg.mesh.id in mesh_memo: + continue + + root.append(wwg.mesh.to_xml_element()) + if mesh_memo is not None: + mesh_memo.add(wwg.mesh) + + def _create_weight_windows_file_element(self, root): + if self.weight_windows_file is not None: + element = ET.Element("weight_windows_file") + element.text = self.weight_windows_file + root.append(element) + + def _create_weight_window_checkpoints_subelement(self, root): + if not self._weight_window_checkpoints: + return + element = ET.SubElement(root, "weight_window_checkpoints") + + if 'collision' in self._weight_window_checkpoints: + subelement = ET.SubElement(element, "collision") + subelement.text = str(self._weight_window_checkpoints['collision']).lower() + + if 'surface' in self._weight_window_checkpoints: + subelement = ET.SubElement(element, "surface") + subelement.text = str(self._weight_window_checkpoints['surface']).lower() + + def _create_max_splits_subelement(self, root): + if self._max_splits is not None: + elem = ET.SubElement(root, "max_splits") + elem.text = str(self._max_splits) + + def _create_max_tracks_subelement(self, root): + if self._max_tracks is not None: + elem = ET.SubElement(root, "max_tracks") + elem.text = str(self._max_tracks) + + def _create_random_ray_subelement(self, root): + if self._random_ray: + element = ET.SubElement(root, "random_ray") + for key, value in self._random_ray.items(): + if key == 'ray_source' and isinstance(value, SourceBase): + source_element = value.to_xml_element() + element.append(source_element) + else: + subelement = ET.SubElement(element, key) + subelement.text = str(value) def _eigenvalue_from_xml_element(self, root): elem = root.find('eigenvalue') @@ -1139,6 +1502,7 @@ def _eigenvalue_from_xml_element(self, root): self._inactive_from_xml_element(elem) self._max_lost_particles_from_xml_element(elem) self._rel_max_lost_particles_from_xml_element(elem) + self._max_write_lost_particles_from_xml_element(elem) self._generations_per_batch_from_xml_element(elem) def _run_mode_from_xml_element(self, root): @@ -1171,6 +1535,11 @@ def _rel_max_lost_particles_from_xml_element(self, root): if text is not None: self.rel_max_lost_particles = float(text) + def _max_write_lost_particles_from_xml_element(self, root): + text = get_text(root, 'max_write_lost_particles') + if text is not None: + self.max_write_lost_particles = int(text) + def _generations_per_batch_from_xml_element(self, root): text = get_text(root, 'generations_per_batch') if text is not None: @@ -1183,9 +1552,17 @@ def _keff_trigger_from_xml_element(self, root): threshold = float(get_text(elem, 'threshold')) self.keff_trigger = {'type': trigger, 'threshold': threshold} - def _source_from_xml_element(self, root): + def _source_from_xml_element(self, root, meshes=None): for elem in root.findall('source'): - self.source.append(Source.from_xml_element(elem)) + src = SourceBase.from_xml_element(elem, meshes) + # add newly constructed source object to the list + self.source.append(src) + + def _volume_calcs_from_xml_element(self, root): + volume_elems = root.findall("volume_calc") + if volume_elems: + self.volume_calculations = [VolumeCalculation.from_xml_element(elem) + for elem in volume_elems] def _output_from_xml_element(self, root): elem = root.find('output') @@ -1208,10 +1585,10 @@ def _statepoint_from_xml_element(self, root): def _sourcepoint_from_xml_element(self, root): elem = root.find('source_point') if elem is not None: - for key in ('separate', 'write', 'overwrite_latest', 'batches'): + for key in ('separate', 'write', 'overwrite_latest', 'batches', 'mcpl'): value = get_text(elem, key) if value is not None: - if key in ('separate', 'write'): + if key in ('separate', 'write', 'mcpl'): value = value in ('true', '1') elif key == 'overwrite_latest': value = value in ('true', '1') @@ -1230,13 +1607,15 @@ def _surf_source_read_from_xml_element(self, root): def _surf_source_write_from_xml_element(self, root): elem = root.find('surf_source_write') if elem is not None: - for key in ('surface_ids', 'max_particles'): + for key in ('surface_ids', 'max_particles','mcpl'): value = get_text(elem, key) if value is not None: if key == 'surface_ids': value = [int(x) for x in value.split()] elif key in ('max_particles'): value = int(value) + elif key == 'mcpl': + value = value in ('true', '1') self.surf_source_write[key] = value def _confidence_intervals_from_xml_element(self, root): @@ -1264,6 +1643,11 @@ def _photon_transport_from_xml_element(self, root): if text is not None: self.photon_transport = text in ('true', '1') + def _plot_seed_from_xml_element(self, root): + text = get_text(root, 'plot_seed') + if text is not None: + self.plot_seed = int(text) + def _ptables_from_xml_element(self, root): text = get_text(root, 'ptables') if text is not None: @@ -1284,18 +1668,20 @@ def _cutoff_from_xml_element(self, root): if elem is not None: self.cutoff = {} for key in ('energy_neutron', 'energy_photon', 'energy_electron', - 'energy_positron', 'weight', 'weight_avg'): + 'energy_positron', 'weight', 'weight_avg', 'time_neutron', + 'time_photon', 'time_electron', 'time_positron'): value = get_text(elem, key) if value is not None: self.cutoff[key] = float(value) - def _entropy_mesh_from_xml_element(self, root): + def _entropy_mesh_from_xml_element(self, root, meshes): text = get_text(root, 'entropy_mesh') - if text is not None: - path = "./mesh[@id='{}']".format(int(text)) - elem = root.find(path) - if elem is not None: - self.entropy_mesh = RegularMesh.from_xml_element(elem) + if text is None: + return + mesh_id = int(text) + if mesh_id not in meshes: + raise ValueError(f'Could not locate mesh with ID "{mesh_id}"') + self.entropy_mesh = meshes[mesh_id] def _trigger_from_xml_element(self, root): elem = root.find('trigger') @@ -1352,15 +1738,17 @@ def _trace_from_xml_element(self, root): def _track_from_xml_element(self, root): text = get_text(root, 'track') if text is not None: - self.track = [int(x) for x in text.split()] + values = [int(x) for x in text.split()] + self.track = list(zip(values[::3], values[1::3], values[2::3])) - def _ufs_mesh_from_xml_element(self, root): + def _ufs_mesh_from_xml_element(self, root, meshes): text = get_text(root, 'ufs_mesh') - if text is not None: - path = "./mesh[@id='{}']".format(int(text)) - elem = root.find(path) - if elem is not None: - self.ufs_mesh = RegularMesh.from_xml_element(elem) + if text is None: + return + mesh_id = int(text) + if mesh_id not in meshes: + raise ValueError(f'Could not locate mesh with ID "{mesh_id}"') + self.ufs_mesh = meshes[mesh_id] def _resonance_scattering_from_xml_element(self, root): elem = root.find('resonance_scattering') @@ -1382,6 +1770,11 @@ def _create_fission_neutrons_from_xml_element(self, root): if text is not None: self.create_fission_neutrons = text in ('true', '1') + def _create_delayed_neutrons_from_xml_element(self, root): + text = get_text(root, 'create_delayed_neutrons') + if text is not None: + self.create_delayed_neutrons = text in ('true', '1') + def _delayed_photon_scaling_from_xml_element(self, root): text = get_text(root, 'delayed_photon_scaling') if text is not None: @@ -1397,6 +1790,11 @@ def _max_particles_in_flight_from_xml_element(self, root): if text is not None: self.max_particles_in_flight = int(text) + def _max_particle_events_from_xml_element(self, root): + text = get_text(root, 'max_particle_events') + if text is not None: + self.max_particle_events = int(text) + def _material_cell_offsets_from_xml_element(self, root): text = get_text(root, 'material_cell_offsets') if text is not None: @@ -1407,12 +1805,127 @@ def _log_grid_bins_from_xml_element(self, root): if text is not None: self.log_grid_bins = int(text) - def _dagmc_from_xml_element(self, root): - text = get_text(root, 'dagmc') + def _write_initial_source_from_xml_element(self, root): + text = get_text(root, 'write_initial_source') + if text is not None: + self.write_initial_source = text in ('true', '1') + + def _weight_window_generators_from_xml_element(self, root, meshes=None): + for elem in root.iter('weight_windows_generator'): + wwg = WeightWindowGenerator.from_xml_element(elem, meshes) + self.weight_window_generators.append(wwg) + + def _weight_windows_from_xml_element(self, root, meshes=None): + for elem in root.findall('weight_windows'): + ww = WeightWindows.from_xml_element(elem, meshes) + self.weight_windows.append(ww) + + text = get_text(root, 'weight_windows_on') + if text is not None: + self.weight_windows_on = text in ('true', '1') + + def _weight_window_checkpoints_from_xml_element(self, root): + elem = root.find('weight_window_checkpoints') + if elem is None: + return + for key in ('collision', 'surface'): + value = get_text(elem, key) + if value is not None: + value = value in ('true', '1') + self.weight_window_checkpoints[key] = value + + def _max_splits_from_xml_element(self, root): + text = get_text(root, 'max_splits') + if text is not None: + self.max_splits = int(text) + + def _max_tracks_from_xml_element(self, root): + text = get_text(root, 'max_tracks') if text is not None: - self.dagmc = text in ('true', '1') + self.max_tracks = int(text) + + def _random_ray_from_xml_element(self, root): + elem = root.find('random_ray') + if elem is not None: + self.random_ray = {} + for child in elem: + if child.tag in ('distance_inactive', 'distance_active'): + self.random_ray[child.tag] = float(child.text) + elif child.tag == 'source': + source = SourceBase.from_xml_element(child) + self.random_ray['ray_source'] = source + + def to_xml_element(self, mesh_memo=None): + """Create a 'settings' element to be written to an XML file. + + Parameters + ---------- + mesh_memo : set of ints + A set of mesh IDs to keep track of whether a mesh has already been written. + """ + # Reset xml element tree + element = ET.Element("settings") + + self._create_run_mode_subelement(element) + self._create_particles_subelement(element) + self._create_batches_subelement(element) + self._create_inactive_subelement(element) + self._create_max_lost_particles_subelement(element) + self._create_rel_max_lost_particles_subelement(element) + self._create_max_write_lost_particles_subelement(element) + self._create_generations_per_batch_subelement(element) + self._create_keff_trigger_subelement(element) + self._create_source_subelement(element, mesh_memo) + self._create_output_subelement(element) + self._create_statepoint_subelement(element) + self._create_sourcepoint_subelement(element) + self._create_surf_source_read_subelement(element) + self._create_surf_source_write_subelement(element) + self._create_confidence_intervals(element) + self._create_electron_treatment_subelement(element) + self._create_energy_mode_subelement(element) + self._create_max_order_subelement(element) + self._create_photon_transport_subelement(element) + self._create_plot_seed_subelement(element) + self._create_ptables_subelement(element) + self._create_seed_subelement(element) + self._create_survival_biasing_subelement(element) + self._create_cutoff_subelement(element) + self._create_entropy_mesh_subelement(element, mesh_memo) + self._create_trigger_subelement(element) + self._create_no_reduce_subelement(element) + self._create_verbosity_subelement(element) + self._create_tabular_legendre_subelements(element) + self._create_temperature_subelements(element) + self._create_trace_subelement(element) + self._create_track_subelement(element) + self._create_ufs_mesh_subelement(element, mesh_memo) + self._create_resonance_scattering_subelement(element) + self._create_volume_calcs_subelement(element) + self._create_create_fission_neutrons_subelement(element) + self._create_create_delayed_neutrons_subelement(element) + self._create_delayed_photon_scaling_subelement(element) + self._create_event_based_subelement(element) + self._create_max_particles_in_flight_subelement(element) + self._create_max_events_subelement(element) + self._create_material_cell_offsets_subelement(element) + self._create_log_grid_bins_subelement(element) + self._create_write_initial_source_subelement(element) + self._create_weight_windows_subelement(element, mesh_memo) + self._create_weight_window_generators_subelement(element, mesh_memo) + self._create_weight_windows_file_element(element) + self._create_weight_window_checkpoints_subelement(element) + self._create_max_splits_subelement(element) + self._create_max_tracks_subelement(element) + self._create_random_ray_subelement(element) + + # Clean the indentation in the file to be user-readable + clean_indentation(element) + reorder_attributes(element) # TODO: Remove when support is Python 3.8+ + + return element - def export_to_xml(self, path='settings.xml'): + def export_to_xml(self, path: PathLike = 'settings.xml'): """Export simulation settings to an XML file. Parameters @@ -1421,54 +1934,7 @@ def export_to_xml(self, path='settings.xml'): Path to file to write. Defaults to 'settings.xml'. """ - - # Reset xml element tree - root_element = ET.Element("settings") - - self._create_run_mode_subelement(root_element) - self._create_particles_subelement(root_element) - self._create_batches_subelement(root_element) - self._create_inactive_subelement(root_element) - self._create_max_lost_particles_subelement(root_element) - self._create_rel_max_lost_particles_subelement(root_element) - self._create_generations_per_batch_subelement(root_element) - self._create_keff_trigger_subelement(root_element) - self._create_source_subelement(root_element) - self._create_output_subelement(root_element) - self._create_statepoint_subelement(root_element) - self._create_sourcepoint_subelement(root_element) - self._create_surf_source_read_subelement(root_element) - self._create_surf_source_write_subelement(root_element) - self._create_confidence_intervals(root_element) - self._create_electron_treatment_subelement(root_element) - self._create_energy_mode_subelement(root_element) - self._create_max_order_subelement(root_element) - self._create_photon_transport_subelement(root_element) - self._create_ptables_subelement(root_element) - self._create_seed_subelement(root_element) - self._create_survival_biasing_subelement(root_element) - self._create_cutoff_subelement(root_element) - self._create_entropy_mesh_subelement(root_element) - self._create_trigger_subelement(root_element) - self._create_no_reduce_subelement(root_element) - self._create_verbosity_subelement(root_element) - self._create_tabular_legendre_subelements(root_element) - self._create_temperature_subelements(root_element) - self._create_trace_subelement(root_element) - self._create_track_subelement(root_element) - self._create_ufs_mesh_subelement(root_element) - self._create_resonance_scattering_subelement(root_element) - self._create_volume_calcs_subelement(root_element) - self._create_create_fission_neutrons_subelement(root_element) - self._create_delayed_photon_scaling_subelement(root_element) - self._create_event_based_subelement(root_element) - self._create_max_particles_in_flight_subelement(root_element) - self._create_material_cell_offsets_subelement(root_element) - self._create_log_grid_bins_subelement(root_element) - self._create_dagmc_subelement(root_element) - - # Clean the indentation in the file to be user-readable - clean_indentation(root_element) + root_element = self.to_xml_element() # Check if path is a directory p = Path(path) @@ -1476,18 +1942,21 @@ def export_to_xml(self, path='settings.xml'): p /= 'settings.xml' # Write the XML Tree to the settings.xml file - reorder_attributes(root_element) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') @classmethod - def from_xml(cls, path='settings.xml'): - """Generate settings from XML file + def from_xml_element(cls, elem, meshes=None): + """Generate settings from XML element Parameters ---------- - path : str, optional - Path to settings XML file + elem : lxml.etree._Element + XML element + meshes : dict or None + A dictionary with mesh IDs as keys and mesh instances as values that + have already been read from XML. Pre-existing meshes are used + and new meshes are added to when creating tally objects. Returns ------- @@ -1495,52 +1964,87 @@ def from_xml(cls, path='settings.xml'): Settings object """ - tree = ET.parse(path) - root = tree.getroot() + # read all meshes under the settings node and update + settings_meshes = _read_meshes(elem) + meshes = {} if meshes is None else meshes + meshes.update(settings_meshes) settings = cls() - settings._eigenvalue_from_xml_element(root) - settings._run_mode_from_xml_element(root) - settings._particles_from_xml_element(root) - settings._batches_from_xml_element(root) - settings._inactive_from_xml_element(root) - settings._max_lost_particles_from_xml_element(root) - settings._rel_max_lost_particles_from_xml_element(root) - settings._generations_per_batch_from_xml_element(root) - settings._keff_trigger_from_xml_element(root) - settings._source_from_xml_element(root) - settings._output_from_xml_element(root) - settings._statepoint_from_xml_element(root) - settings._sourcepoint_from_xml_element(root) - settings._surf_source_read_from_xml_element(root) - settings._surf_source_write_from_xml_element(root) - settings._confidence_intervals_from_xml_element(root) - settings._electron_treatment_from_xml_element(root) - settings._energy_mode_from_xml_element(root) - settings._max_order_from_xml_element(root) - settings._photon_transport_from_xml_element(root) - settings._ptables_from_xml_element(root) - settings._seed_from_xml_element(root) - settings._survival_biasing_from_xml_element(root) - settings._cutoff_from_xml_element(root) - settings._entropy_mesh_from_xml_element(root) - settings._trigger_from_xml_element(root) - settings._no_reduce_from_xml_element(root) - settings._verbosity_from_xml_element(root) - settings._tabular_legendre_from_xml_element(root) - settings._temperature_from_xml_element(root) - settings._trace_from_xml_element(root) - settings._track_from_xml_element(root) - settings._ufs_mesh_from_xml_element(root) - settings._resonance_scattering_from_xml_element(root) - settings._create_fission_neutrons_from_xml_element(root) - settings._delayed_photon_scaling_from_xml_element(root) - settings._event_based_from_xml_element(root) - settings._max_particles_in_flight_from_xml_element(root) - settings._material_cell_offsets_from_xml_element(root) - settings._log_grid_bins_from_xml_element(root) - settings._dagmc_from_xml_element(root) + settings._eigenvalue_from_xml_element(elem) + settings._run_mode_from_xml_element(elem) + settings._particles_from_xml_element(elem) + settings._batches_from_xml_element(elem) + settings._inactive_from_xml_element(elem) + settings._max_lost_particles_from_xml_element(elem) + settings._rel_max_lost_particles_from_xml_element(elem) + settings._max_write_lost_particles_from_xml_element(elem) + settings._generations_per_batch_from_xml_element(elem) + settings._keff_trigger_from_xml_element(elem) + settings._source_from_xml_element(elem, meshes) + settings._volume_calcs_from_xml_element(elem) + settings._output_from_xml_element(elem) + settings._statepoint_from_xml_element(elem) + settings._sourcepoint_from_xml_element(elem) + settings._surf_source_read_from_xml_element(elem) + settings._surf_source_write_from_xml_element(elem) + settings._confidence_intervals_from_xml_element(elem) + settings._electron_treatment_from_xml_element(elem) + settings._energy_mode_from_xml_element(elem) + settings._max_order_from_xml_element(elem) + settings._photon_transport_from_xml_element(elem) + settings._plot_seed_from_xml_element(elem) + settings._ptables_from_xml_element(elem) + settings._seed_from_xml_element(elem) + settings._survival_biasing_from_xml_element(elem) + settings._cutoff_from_xml_element(elem) + settings._entropy_mesh_from_xml_element(elem, meshes) + settings._trigger_from_xml_element(elem) + settings._no_reduce_from_xml_element(elem) + settings._verbosity_from_xml_element(elem) + settings._tabular_legendre_from_xml_element(elem) + settings._temperature_from_xml_element(elem) + settings._trace_from_xml_element(elem) + settings._track_from_xml_element(elem) + settings._ufs_mesh_from_xml_element(elem, meshes) + settings._resonance_scattering_from_xml_element(elem) + settings._create_fission_neutrons_from_xml_element(elem) + settings._create_delayed_neutrons_from_xml_element(elem) + settings._delayed_photon_scaling_from_xml_element(elem) + settings._event_based_from_xml_element(elem) + settings._max_particles_in_flight_from_xml_element(elem) + settings._max_particle_events_from_xml_element(elem) + settings._material_cell_offsets_from_xml_element(elem) + settings._log_grid_bins_from_xml_element(elem) + settings._write_initial_source_from_xml_element(elem) + settings._weight_windows_from_xml_element(elem, meshes) + settings._weight_window_generators_from_xml_element(elem, meshes) + settings._weight_window_checkpoints_from_xml_element(elem) + settings._max_splits_from_xml_element(elem) + settings._max_tracks_from_xml_element(elem) + settings._random_ray_from_xml_element(elem) # TODO: Get volume calculations - return settings + + @classmethod + def from_xml(cls, path: PathLike = 'settings.xml'): + """Generate settings from XML file + + .. versionadded:: 0.13.0 + + Parameters + ---------- + path : str, optional + Path to settings XML file + + Returns + ------- + openmc.Settings + Settings object + + """ + parser = ET.XMLParser(huge_tree=True) + tree = ET.parse(path, parser=parser) + root = tree.getroot() + meshes = _read_meshes(root) + return cls.from_xml_element(root, meshes) diff --git a/openmc/source.py b/openmc/source.py index 415aacd96c7..91318f8e9ad 100644 --- a/openmc/source.py +++ b/openmc/source.py @@ -1,19 +1,251 @@ -from enum import Enum +from __future__ import annotations +from abc import ABC, abstractmethod +from collections.abc import Iterable +from enum import IntEnum from numbers import Real -from xml.etree import ElementTree as ET +import warnings +import typing # imported separately as py3.8 requires typing.Iterable +# also required to prevent typing.Union namespace overwriting Union +from typing import Optional, Sequence, Dict, Any +import lxml.etree as ET import numpy as np import h5py +import openmc import openmc.checkvalue as cv +from openmc.checkvalue import PathLike from openmc.stats.multivariate import UnitSphere, Spatial from openmc.stats.univariate import Univariate from ._xml import get_text +from .mesh import MeshBase, StructuredMesh, UnstructuredMesh -class Source: +class SourceBase(ABC): + """Base class for external sources + + Parameters + ---------- + strength : float + Strength of the source + constraints : dict + Constraints on sampled source particles. Valid keys include 'domains', + 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. + For 'domains', the corresponding value is an iterable of + :class:`openmc.Cell`, :class:`openmc.Material`, or + :class:`openmc.Universe` for which sampled sites must be within. For + 'time_bounds' and 'energy_bounds', the corresponding value is a sequence + of floats giving the lower and upper bounds on time in [s] or energy in + [eV] that the sampled particle must be within. For 'fissionable', the + value is a bool indicating that only sites in fissionable material + should be accepted. The 'rejection_strategy' indicates what should + happen when a source particle is rejected: either 'resample' (pick a new + particle) or 'kill' (accept and terminate). + + Attributes + ---------- + type : {'independent', 'file', 'compiled', 'mesh'} + Indicator of source type. + strength : float + Strength of the source + constraints : dict + Constraints on sampled source particles. Valid keys include + 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', + 'fissionable', and 'rejection_strategy'. + + """ + + def __init__( + self, + strength: Optional[float] = 1.0, + constraints: Optional[Dict[str, Any]] = None + ): + self.strength = strength + self.constraints = constraints + + @property + def strength(self): + return self._strength + + @strength.setter + def strength(self, strength): + cv.check_type('source strength', strength, Real, none_ok=True) + if strength is not None: + cv.check_greater_than('source strength', strength, 0.0, True) + self._strength = strength + + @property + def constraints(self) -> Dict[str, Any]: + return self._constraints + + @constraints.setter + def constraints(self, constraints: Optional[Dict[str, Any]]): + self._constraints = {} + if constraints is None: + return + + for key, value in constraints.items(): + if key == 'domains': + cv.check_type('domains', value, Iterable, + (openmc.Cell, openmc.Material, openmc.Universe)) + if isinstance(value[0], openmc.Cell): + self._constraints['domain_type'] = 'cell' + elif isinstance(value[0], openmc.Material): + self._constraints['domain_type'] = 'material' + elif isinstance(value[0], openmc.Universe): + self._constraints['domain_type'] = 'universe' + self._constraints['domain_ids'] = [d.id for d in value] + elif key == 'time_bounds': + cv.check_type('time bounds', value, Iterable, Real) + self._constraints['time_bounds'] = tuple(value) + elif key == 'energy_bounds': + cv.check_type('energy bounds', value, Iterable, Real) + self._constraints['energy_bounds'] = tuple(value) + elif key == 'fissionable': + cv.check_type('fissionable', value, bool) + self._constraints['fissionable'] = value + elif key == 'rejection_strategy': + cv.check_value('rejection strategy', value, ('resample', 'kill')) + self._constraints['rejection_strategy'] = value + else: + raise ValueError('Unknown key in constraints dictionary: {key}') + + @abstractmethod + def populate_xml_element(self, element): + """Add necessary source information to an XML element + + Returns + ------- + element : lxml.etree._Element + XML element containing source data + + """ + + def to_xml_element(self) -> ET.Element: + """Return XML representation of the source + + Returns + ------- + element : xml.etree.ElementTree.Element + XML element containing source data + + """ + element = ET.Element("source") + element.set("type", self.type) + if self.strength is not None: + element.set("strength", str(self.strength)) + self.populate_xml_element(element) + constraints = self.constraints + if constraints: + constraints_elem = ET.SubElement(element, "constraints") + if "domain_ids" in constraints: + dt_elem = ET.SubElement(constraints_elem, "domain_type") + dt_elem.text = constraints["domain_type"] + id_elem = ET.SubElement(constraints_elem, "domain_ids") + id_elem.text = ' '.join(str(uid) for uid in constraints["domain_ids"]) + if "time_bounds" in constraints: + dt_elem = ET.SubElement(constraints_elem, "time_bounds") + dt_elem.text = ' '.join(str(t) for t in constraints["time_bounds"]) + if "energy_bounds" in constraints: + dt_elem = ET.SubElement(constraints_elem, "energy_bounds") + dt_elem.text = ' '.join(str(E) for E in constraints["energy_bounds"]) + if "fissionable" in constraints: + dt_elem = ET.SubElement(constraints_elem, "fissionable") + dt_elem.text = str(constraints["fissionable"]).lower() + if "rejection_strategy" in constraints: + dt_elem = ET.SubElement(constraints_elem, "rejection_strategy") + dt_elem.text = constraints["rejection_strategy"] + + return element + + @classmethod + def from_xml_element(cls, elem: ET.Element, meshes=None) -> SourceBase: + """Generate source from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict + Dictionary with mesh IDs as keys and openmc.MeshBase instances as + values + + Returns + ------- + openmc.SourceBase + Source generated from XML element + + """ + source_type = get_text(elem, 'type') + + if source_type is None: + # attempt to determine source type based on attributes + # for backward compatibility + if get_text(elem, 'file') is not None: + return FileSource.from_xml_element(elem) + elif get_text(elem, 'library') is not None: + return CompiledSource.from_xml_element(elem) + else: + return IndependentSource.from_xml_element(elem) + else: + if source_type == 'independent': + return IndependentSource.from_xml_element(elem, meshes) + elif source_type == 'compiled': + return CompiledSource.from_xml_element(elem) + elif source_type == 'file': + return FileSource.from_xml_element(elem) + elif source_type == 'mesh': + return MeshSource.from_xml_element(elem, meshes) + else: + raise ValueError(f'Source type {source_type} is not recognized') + + @staticmethod + def _get_constraints(elem: ET.Element) -> Dict[str, Any]: + # Find element containing constraints + constraints_elem = elem.find("constraints") + elem = constraints_elem if constraints_elem is not None else elem + + constraints = {} + domain_type = get_text(elem, "domain_type") + if domain_type is not None: + domain_ids = [int(x) for x in get_text(elem, "domain_ids").split()] + + # Instantiate some throw-away domains that are used by the + # constructor to assign IDs + with warnings.catch_warnings(): + warnings.simplefilter('ignore', openmc.IDWarning) + if domain_type == 'cell': + domains = [openmc.Cell(uid) for uid in domain_ids] + elif domain_type == 'material': + domains = [openmc.Material(uid) for uid in domain_ids] + elif domain_type == 'universe': + domains = [openmc.Universe(uid) for uid in domain_ids] + constraints['domains'] = domains + + time_bounds = get_text(elem, "time_bounds") + if time_bounds is not None: + constraints['time_bounds'] = [float(x) for x in time_bounds.split()] + + energy_bounds = get_text(elem, "energy_bounds") + if energy_bounds is not None: + constraints['energy_bounds'] = [float(x) for x in energy_bounds.split()] + + fissionable = get_text(elem, "fissionable") + if fissionable is not None: + constraints['fissionable'] = fissionable in ('true', '1') + + rejection_strategy = get_text(elem, "rejection_strategy") + if rejection_strategy is not None: + constraints['rejection_strategy'] = rejection_strategy + + return constraints + + +class IndependentSource(SourceBase): """Distribution of phase space coordinates for source sites. + .. versionadded:: 0.14.0 + Parameters ---------- space : openmc.stats.Spatial @@ -22,18 +254,31 @@ class Source: Angular distribution of source sites energy : openmc.stats.Univariate Energy distribution of source sites - filename : str - Source file from which sites should be sampled - library : str - Path to a custom source library - parameters : str - Parameters to be provided to the custom source library - - .. versionadded:: 0.12 + time : openmc.stats.Univariate + time distribution of source sites strength : float Strength of the source particle : {'neutron', 'photon'} Source particle type + domains : iterable of openmc.Cell, openmc.Material, or openmc.Universe + Domains to reject based on, i.e., if a sampled spatial location is not + within one of these domains, it will be rejected. + + .. deprecated:: 0.14.1 + Use the `constraints` argument instead. + constraints : dict + Constraints on sampled source particles. Valid keys include 'domains', + 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. + For 'domains', the corresponding value is an iterable of + :class:`openmc.Cell`, :class:`openmc.Material`, or + :class:`openmc.Universe` for which sampled sites must be within. For + 'time_bounds' and 'energy_bounds', the corresponding value is a sequence + of floats giving the lower and upper bounds on time in [s] or energy in + [eV] that the sampled particle must be within. For 'fissionable', the + value is a bool indicating that only sites in fissionable material + should be accepted. The 'rejection_strategy' indicates what should + happen when a source particle is rejected: either 'resample' (pick a new + particle) or 'kill' (accept and terminate). Attributes ---------- @@ -43,27 +288,46 @@ class Source: Angular distribution of source sites energy : openmc.stats.Univariate or None Energy distribution of source sites - file : str or None - Source file from which sites should be sampled - library : str or None - Path to a custom source library - parameters : str - Parameters to be provided to the custom source library + time : openmc.stats.Univariate or None + time distribution of source sites strength : float Strength of the source + type : str + Indicator of source type: 'independent' + + .. versionadded:: 0.14.0 + particle : {'neutron', 'photon'} Source particle type + constraints : dict + Constraints on sampled source particles. Valid keys include + 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', + 'fissionable', and 'rejection_strategy'. """ - def __init__(self, space=None, angle=None, energy=None, filename=None, - library=None, parameters=None, strength=1.0, particle='neutron'): + def __init__( + self, + space: Optional[openmc.stats.Spatial] = None, + angle: Optional[openmc.stats.UnitSphere] = None, + energy: Optional[openmc.stats.Univariate] = None, + time: Optional[openmc.stats.Univariate] = None, + strength: float = 1.0, + particle: str = 'neutron', + domains: Optional[Sequence[typing.Union[openmc.Cell, openmc.Material, openmc.Universe]]] = None, + constraints: Optional[Dict[str, Any]] = None + ): + if domains is not None: + warnings.warn("The 'domains' arguments has been replaced by the " + "'constraints' argument.", FutureWarning) + constraints = {'domains': domains} + + super().__init__(strength=strength, constraints=constraints) + self._space = None self._angle = None self._energy = None - self._file = None - self._library = None - self._parameters = None + self._time = None if space is not None: self.space = space @@ -71,123 +335,106 @@ def __init__(self, space=None, angle=None, energy=None, filename=None, self.angle = angle if energy is not None: self.energy = energy - if filename is not None: - self.file = filename - if library is not None: - self.library = library - if parameters is not None: - self.parameters = parameters - self.strength = strength + if time is not None: + self.time = time self.particle = particle @property - def file(self): - return self._file + def type(self) -> str: + return 'independent' - @property - def library(self): - return self._library + def __getattr__(self, name): + cls_names = {'file': 'FileSource', 'library': 'CompiledSource', + 'parameters': 'CompiledSource'} + if name in cls_names: + raise AttributeError( + f'The "{name}" attribute has been deprecated on the ' + f'IndependentSource class. Please use the {cls_names[name]} class.') + else: + super().__getattribute__(name) - @property - def parameters(self): - return self._parameters + def __setattr__(self, name, value): + if name in ('file', 'library', 'parameters'): + # Ensure proper AttributeError is thrown + getattr(self, name) + else: + super().__setattr__(name, value) @property def space(self): return self._space - @property - def angle(self): - return self._angle - - @property - def energy(self): - return self._energy - - @property - def strength(self): - return self._strength - - @property - def particle(self): - return self._particle - - @file.setter - def file(self, filename): - cv.check_type('source file', filename, str) - self._file = filename - - @library.setter - def library(self, library_name): - cv.check_type('library', library_name, str) - self._library = library_name - - @parameters.setter - def parameters(self, parameters_path): - cv.check_type('parameters', parameters_path, str) - self._parameters = parameters_path - @space.setter def space(self, space): cv.check_type('spatial distribution', space, Spatial) self._space = space + @property + def angle(self): + return self._angle + @angle.setter def angle(self, angle): cv.check_type('angular distribution', angle, UnitSphere) self._angle = angle + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('energy distribution', energy, Univariate) self._energy = energy - @strength.setter - def strength(self, strength): - cv.check_type('source strength', strength, Real) - cv.check_greater_than('source strength', strength, 0.0, True) - self._strength = strength + @property + def time(self): + return self._time + + @time.setter + def time(self, time): + cv.check_type('time distribution', time, Univariate) + self._time = time + + @property + def particle(self): + return self._particle @particle.setter def particle(self, particle): cv.check_value('source particle', particle, ['neutron', 'photon']) self._particle = particle - def to_xml_element(self): - """Return XML representation of the source + def populate_xml_element(self, element): + """Add necessary source information to an XML element Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ - element = ET.Element("source") - element.set("strength", str(self.strength)) - if self.particle != 'neutron': - element.set("particle", self.particle) - if self.file is not None: - element.set("file", self.file) - if self.library is not None: - element.set("library", self.library) - if self.parameters is not None: - element.set("parameters", self.parameters) + element.set("particle", self.particle) if self.space is not None: element.append(self.space.to_xml_element()) if self.angle is not None: element.append(self.angle.to_xml_element()) if self.energy is not None: element.append(self.energy.to_xml_element('energy')) - return element + if self.time is not None: + element.append(self.time.to_xml_element('time')) @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element, meshes=None) -> SourceBase: """Generate source from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element + meshes : dict + Dictionary with mesh IDs as keys and openmc.MeshBase instaces as + values Returns ------- @@ -195,7 +442,8 @@ def from_xml_element(cls, elem): Source generated from XML element """ - source = cls() + constraints = cls._get_constraints(elem) + source = cls(constraints=constraints) strength = get_text(elem, 'strength') if strength is not None: @@ -205,21 +453,9 @@ def from_xml_element(cls, elem): if particle is not None: source.particle = particle - filename = get_text(elem, 'file') - if filename is not None: - source.file = filename - - library = get_text(elem, 'library') - if library is not None: - source.library = library - - parameters = get_text(elem, 'parameters') - if parameters is not None: - source.parameters = parameters - space = elem.find('space') if space is not None: - source.space = Spatial.from_xml_element(space) + source.space = Spatial.from_xml_element(space, meshes) angle = elem.find('angle') if angle is not None: @@ -229,15 +465,478 @@ def from_xml_element(cls, elem): if energy is not None: source.energy = Univariate.from_xml_element(energy) + time = elem.find('time') + if time is not None: + source.time = Univariate.from_xml_element(time) + + return source + + +class MeshSource(SourceBase): + """A source with a spatial distribution over mesh elements + + This class represents a mesh-based source in which random positions are + uniformly sampled within mesh elements and each element can have independent + angle, energy, and time distributions. The element sampled is chosen based + on the relative strengths of the sources applied to the elements. The + strength of the mesh source as a whole is the sum of all source strengths + applied to the elements. + + .. versionadded:: 0.14.1 + + Parameters + ---------- + mesh : openmc.MeshBase + The mesh over which source sites will be generated. + sources : sequence of openmc.SourceBase + Sources for each element in the mesh. Sources must be specified as + either a 1-D array in the order of the mesh indices or a + multidimensional array whose shape matches the mesh shape. If spatial + distributions are set on any of the source objects, they will be ignored + during source site sampling. + constraints : dict + Constraints on sampled source particles. Valid keys include 'domains', + 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. + For 'domains', the corresponding value is an iterable of + :class:`openmc.Cell`, :class:`openmc.Material`, or + :class:`openmc.Universe` for which sampled sites must be within. For + 'time_bounds' and 'energy_bounds', the corresponding value is a sequence + of floats giving the lower and upper bounds on time in [s] or energy in + [eV] that the sampled particle must be within. For 'fissionable', the + value is a bool indicating that only sites in fissionable material + should be accepted. The 'rejection_strategy' indicates what should + happen when a source particle is rejected: either 'resample' (pick a new + particle) or 'kill' (accept and terminate). + + Attributes + ---------- + mesh : openmc.MeshBase + The mesh over which source sites will be generated. + sources : numpy.ndarray of openmc.SourceBase + Sources to apply to each element + strength : float + Strength of the source + type : str + Indicator of source type: 'mesh' + constraints : dict + Constraints on sampled source particles. Valid keys include + 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', + 'fissionable', and 'rejection_strategy'. + + """ + def __init__( + self, + mesh: MeshBase, + sources: Sequence[SourceBase], + constraints: Optional[Dict[str, Any]] = None, + ): + super().__init__(strength=None, constraints=constraints) + self.mesh = mesh + self.sources = sources + + @property + def type(self) -> str: + return "mesh" + + @property + def mesh(self) -> MeshBase: + return self._mesh + + @property + def strength(self) -> float: + return sum(s.strength for s in self.sources) + + @property + def sources(self) -> np.ndarray: + return self._sources + + @mesh.setter + def mesh(self, m): + cv.check_type('source mesh', m, MeshBase) + self._mesh = m + + @sources.setter + def sources(self, s): + cv.check_iterable_type('mesh sources', s, SourceBase, max_depth=3) + + s = np.asarray(s) + + if isinstance(self.mesh, StructuredMesh): + if s.size != self.mesh.num_mesh_cells: + raise ValueError( + f'The length of the source array ({s.size}) does not match ' + f'the number of mesh elements ({self.mesh.num_mesh_cells}).') + + # If user gave a multidimensional array, flatten in the order + # of the mesh indices + if s.ndim > 1: + s = s.ravel(order='F') + + elif isinstance(self.mesh, UnstructuredMesh): + if s.ndim > 1: + raise ValueError('Sources must be a 1-D array for unstructured mesh') + + self._sources = s + for src in self._sources: + if isinstance(src, IndependentSource) and src.space is not None: + warnings.warn('Some sources on the mesh have spatial ' + 'distributions that will be ignored at runtime.') + break + + @strength.setter + def strength(self, val): + if val is not None: + cv.check_type('mesh source strength', val, Real) + self.set_total_strength(val) + + def set_total_strength(self, strength: float): + """Scales the element source strengths based on a desired total strength. + + Parameters + ---------- + strength : float + Total source strength + + """ + current_strength = self.strength if self.strength != 0.0 else 1.0 + + for s in self.sources: + s.strength *= strength / current_strength + + def normalize_source_strengths(self): + """Update all element source strengths such that they sum to 1.0.""" + self.set_total_strength(1.0) + + def populate_xml_element(self, elem: ET.Element): + """Add necessary source information to an XML element + + Returns + ------- + element : lxml.etree._Element + XML element containing source data + + """ + elem.set("mesh", str(self.mesh.id)) + + # write in the order of mesh indices + for s in self.sources: + elem.append(s.to_xml_element()) + + @classmethod + def from_xml_element(cls, elem: ET.Element, meshes) -> openmc.MeshSource: + """ + Generate MeshSource from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict + A dictionary with mesh IDs as keys and openmc.MeshBase instances as + values + + Returns + ------- + openmc.MeshSource + MeshSource generated from the XML element + """ + mesh_id = int(get_text(elem, 'mesh')) + mesh = meshes[mesh_id] + + sources = [SourceBase.from_xml_element(e) for e in elem.iterchildren('source')] + constraints = cls._get_constraints(elem) + return cls(mesh, sources, constraints=constraints) + + +def Source(*args, **kwargs): + """ + A function for backward compatibility of sources. Will be removed in the + future. Please update to IndependentSource. + """ + warnings.warn("This class is deprecated in favor of 'IndependentSource'", FutureWarning) + return openmc.IndependentSource(*args, **kwargs) + + +class CompiledSource(SourceBase): + """A source based on a compiled shared library + + .. versionadded:: 0.14.0 + + Parameters + ---------- + library : str or None + Path to a compiled shared library + parameters : str + Parameters to be provided to the compiled shared library function + strength : float + Strength of the source + constraints : dict + Constraints on sampled source particles. Valid keys include 'domains', + 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. + For 'domains', the corresponding value is an iterable of + :class:`openmc.Cell`, :class:`openmc.Material`, or + :class:`openmc.Universe` for which sampled sites must be within. For + 'time_bounds' and 'energy_bounds', the corresponding value is a sequence + of floats giving the lower and upper bounds on time in [s] or energy in + [eV] that the sampled particle must be within. For 'fissionable', the + value is a bool indicating that only sites in fissionable material + should be accepted. The 'rejection_strategy' indicates what should + happen when a source particle is rejected: either 'resample' (pick a new + particle) or 'kill' (accept and terminate). + + Attributes + ---------- + library : str or None + Path to a compiled shared library + parameters : str + Parameters to be provided to the compiled shared library function + strength : float + Strength of the source + type : str + Indicator of source type: 'compiled' + constraints : dict + Constraints on sampled source particles. Valid keys include + 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', + 'fissionable', and 'rejection_strategy'. + + """ + def __init__( + self, + library: Optional[str] = None, + parameters: Optional[str] = None, + strength: float = 1.0, + constraints: Optional[Dict[str, Any]] = None + ) -> None: + super().__init__(strength=strength, constraints=constraints) + + self._library = None + if library is not None: + self.library = library + + self._parameters = None + if parameters is not None: + self.parameters = parameters + + @property + def type(self) -> str: + return "compiled" + + @property + def library(self) -> str: + return self._library + + @library.setter + def library(self, library_name): + cv.check_type('library', library_name, str) + self._library = library_name + + @property + def parameters(self) -> str: + return self._parameters + + @parameters.setter + def parameters(self, parameters_path): + cv.check_type('parameters', parameters_path, str) + self._parameters = parameters_path + + def populate_xml_element(self, element): + """Add necessary compiled source information to an XML element + + Returns + ------- + element : lxml.etree._Element + XML element containing source data + + """ + element.set("library", self.library) + + if self.parameters is not None: + element.set("parameters", self.parameters) + + @classmethod + def from_xml_element(cls, elem: ET.Element) -> openmc.CompiledSource: + """Generate a compiled source from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict + Dictionary with mesh IDs as keys and openmc.MeshBase instances as + values + + Returns + ------- + openmc.CompiledSource + Source generated from XML element + + """ + kwargs = {'constraints': cls._get_constraints(elem)} + kwargs['library'] = get_text(elem, 'library') + + source = cls(**kwargs) + + strength = get_text(elem, 'strength') + if strength is not None: + source.strength = float(strength) + + parameters = get_text(elem, 'parameters') + if parameters is not None: + source.parameters = parameters + return source -class ParticleType(Enum): +class FileSource(SourceBase): + """A source based on particles stored in a file + + .. versionadded:: 0.14.0 + + Parameters + ---------- + path : str or pathlib.Path + Path to the source file from which sites should be sampled + strength : float + Strength of the source (default is 1.0) + constraints : dict + Constraints on sampled source particles. Valid keys include 'domains', + 'time_bounds', 'energy_bounds', 'fissionable', and 'rejection_strategy'. + For 'domains', the corresponding value is an iterable of + :class:`openmc.Cell`, :class:`openmc.Material`, or + :class:`openmc.Universe` for which sampled sites must be within. For + 'time_bounds' and 'energy_bounds', the corresponding value is a sequence + of floats giving the lower and upper bounds on time in [s] or energy in + [eV] that the sampled particle must be within. For 'fissionable', the + value is a bool indicating that only sites in fissionable material + should be accepted. The 'rejection_strategy' indicates what should + happen when a source particle is rejected: either 'resample' (pick a new + particle) or 'kill' (accept and terminate). + + Attributes + ---------- + path : Pathlike + Source file from which sites should be sampled + strength : float + Strength of the source + type : str + Indicator of source type: 'file' + constraints : dict + Constraints on sampled source particles. Valid keys include + 'domain_type', 'domain_ids', 'time_bounds', 'energy_bounds', + 'fissionable', and 'rejection_strategy'. + + """ + + def __init__( + self, + path: Optional[PathLike] = None, + strength: float = 1.0, + constraints: Optional[Dict[str, Any]] = None + ): + super().__init__(strength=strength, constraints=constraints) + self._path = None + if path is not None: + self.path = path + + @property + def type(self) -> str: + return "file" + + @property + def path(self) -> PathLike: + return self._path + + @path.setter + def path(self, p: PathLike): + cv.check_type('source file', p, str) + self._path = p + + def populate_xml_element(self, element): + """Add necessary file source information to an XML element + + Returns + ------- + element : lxml.etree._Element + XML element containing source data + + """ + if self.path is not None: + element.set("file", self.path) + + @classmethod + def from_xml_element(cls, elem: ET.Element) -> openmc.FileSource: + """Generate file source from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict + Dictionary with mesh IDs as keys and openmc.MeshBase instances as + values + + Returns + ------- + openmc.FileSource + Source generated from XML element + + """ + kwargs = {'constraints': cls._get_constraints(elem)} + kwargs['path'] = get_text(elem, 'file') + strength = get_text(elem, 'strength') + if strength is not None: + kwargs['strength'] = float(strength) + + return cls(**kwargs) + + +class ParticleType(IntEnum): + """ + IntEnum class representing a particle type. Type + values mirror those found in the C++ class. + """ NEUTRON = 0 PHOTON = 1 ELECTRON = 2 POSITRON = 3 + @classmethod + def from_string(cls, value: str): + """ + Constructs a ParticleType instance from a string. + + Parameters + ---------- + value : str + The string representation of the particle type. + + Returns + ------- + The corresponding ParticleType instance. + """ + try: + return cls[value.upper()] + except KeyError: + raise ValueError(f"Invalid string for creation of {cls.__name__}: {value}") + + def __repr__(self) -> str: + """ + Returns a string representation of the ParticleType instance. + + Returns: + str: The lowercase name of the ParticleType instance. + """ + return self.name.lower() + + # needed for < Python 3.11 + def __str__(self) -> str: + return self.__repr__() + + # needed for <= 3.7, IntEnum will use the mixed-in type's `__format__` method otherwise + # this forces it to default to the standard object format, relying on __str__ under the hood + def __format__(self, spec): + return object.__format__(self, spec) + class SourceParticle: """Source particle @@ -253,6 +952,8 @@ class SourceParticle: Directional cosines E : float Energy of particle in [eV] + time : float + Time of particle in [s] wgt : float Weight of the particle delayed_group : int @@ -263,17 +964,32 @@ class SourceParticle: Type of the particle """ - def __init__(self, r=(0., 0., 0.), u=(0., 0., 1.), E=1.0e6, wgt=1.0, - delayed_group=0, surf_id=0, particle=ParticleType.NEUTRON): + def __init__( + self, + r: typing.Iterable[float] = (0., 0., 0.), + u: typing.Iterable[float] = (0., 0., 1.), + E: float = 1.0e6, + time: float = 0.0, + wgt: float = 1.0, + delayed_group: int = 0, + surf_id: int = 0, + particle: ParticleType = ParticleType.NEUTRON + ): + self.r = tuple(r) self.u = tuple(u) self.E = float(E) + self.time = float(time) self.wgt = float(wgt) self.delayed_group = delayed_group self.surf_id = surf_id self.particle = particle - def to_tuple(self): + def __repr__(self): + name = self.particle.name.lower() + return f'' + + def to_tuple(self) -> tuple: """Return source particle attributes as a tuple Returns @@ -282,11 +998,14 @@ def to_tuple(self): Source particle attributes """ - return (self.r, self.u, self.E, self.wgt, + return (self.r, self.u, self.E, self.time, self.wgt, self.delayed_group, self.surf_id, self.particle.value) -def write_source_file(source_particles, filename, **kwargs): +def write_source_file( + source_particles: typing.Iterable[SourceParticle], + filename: PathLike, **kwargs +): """Write a source file using a collection of source particles Parameters @@ -309,6 +1028,7 @@ def write_source_file(source_particles, filename, **kwargs): ('r', pos_dtype), ('u', pos_dtype), ('E', ' typing.List[SourceParticle]: + """Read a source file and return a list of source particles. + + .. versionadded:: 0.14.1 + + Parameters + ---------- + filename : str or path-like + Path to source file to read + + Returns + ------- + list of SourceParticle + Source particles read from file + + See Also + -------- + openmc.SourceParticle + + """ + with h5py.File(filename, 'r') as fh: + filetype = fh.attrs['filetype'] + arr = fh['source_bank'][...] + + if filetype != b'source': + raise ValueError(f'File {filename} is not a source file') + + source_particles = [] + for *params, particle in arr: + source_particles.append(SourceParticle(*params, ParticleType(particle))) + + return source_particles diff --git a/openmc/statepoint.py b/openmc/statepoint.py index 6e90bcaf7c6..f6df01bd4f1 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -11,7 +11,7 @@ import openmc import openmc.checkvalue as cv -_VERSION_STATEPOINT = 17 +_VERSION_STATEPOINT = 18 class StatePoint: @@ -63,6 +63,8 @@ class StatePoint: datatype has fields 'name', 'sum', 'sum_sq', 'mean', and 'std_dev'. k_combined : uncertainties.UFloat Combined estimator for k-effective + + .. deprecated:: 0.13.1 k_col_abs : float Cross-product of collision and absorption estimates of k-effective k_col_tra : float @@ -71,6 +73,10 @@ class StatePoint: Cross-product of absorption and tracklength estimates of k-effective k_generation : numpy.ndarray Estimate of k-effective for each batch/generation + keff : uncertainties.UFloat + Combined estimator for k-effective + + .. versionadded:: 0.13.1 meshes : dict Dictionary whose keys are mesh IDs and whose values are MeshBase objects n_batches : int @@ -153,9 +159,7 @@ def __enter__(self): return self def __exit__(self, *exc): - self._f.close() - if self._summary is not None: - self._summary._f.close() + self.close() @property def cmfd_on(self): @@ -262,12 +266,20 @@ def k_generation(self): return None @property - def k_combined(self): + def keff(self): if self.run_mode == 'eigenvalue': return ufloat(*self._f['k_combined'][()]) else: return None + @property + def k_combined(self): + warnings.warn( + "The 'k_combined' property has been renamed to 'keff' and will be " + "removed in a future version of OpenMC.", FutureWarning + ) + return self.keff + @property def k_col_abs(self): if self.run_mode == 'eigenvalue': @@ -355,6 +367,26 @@ def source_present(self): def sparse(self): return self._sparse + @sparse.setter + def sparse(self, sparse): + """Convert tally data from NumPy arrays to SciPy list of lists (LIL) + sparse matrices, and vice versa. + + This property may be used to reduce the amount of data in memory during + tally data processing. The tally data will be stored as SciPy LIL + matrices internally within each Tally object. All tally data access + properties and methods will return data as a dense NumPy array. + + """ + + cv.check_type('sparse', sparse, bool) + self._sparse = sparse + + # Update tally sparsities + if self._tallies_read: + for tally_id in self.tallies: + self.tallies[tally_id].sparse = self.sparse + @property def tallies(self): if self.tallies_present and not self._tallies_read: @@ -375,7 +407,7 @@ def tallies(self): # Iterate over all tallies for tally_id in tally_ids: - group = tallies_group['tally {}'.format(tally_id)] + group = tallies_group[f'tally {tally_id}'] # Check if tally is internal and therefore has no data if group.attrs.get("internal"): @@ -386,6 +418,10 @@ def tallies(self): tally._sp_filename = self._f.filename tally.name = group['name'][()].decode() if 'name' in group else '' + # Check if tally has multiply_density attribute + if "multiply_density" in group.attrs: + tally.multiply_density = group.attrs["multiply_density"].item() > 0 + # Read the number of realizations n_realizations = group['n_realizations'][()] @@ -403,8 +439,7 @@ def tallies(self): filter_ids = group['filters'][()] filters_group = self._f['tallies/filters'] for filter_id in filter_ids: - filter_group = filters_group['filter {}'.format( - filter_id)] + filter_group = filters_group[f'filter {filter_id}'] new_filter = openmc.Filter.from_hdf5( filter_group, meshes=self.meshes) tally.filters.append(new_filter) @@ -445,8 +480,7 @@ def tally_derivatives(self): # Create each derivative object and add it to the dictionary. for d_id in deriv_ids: - group = self._f['tallies/derivatives/derivative {}' - .format(d_id)] + group = self._f[f'tallies/derivatives/derivative {d_id}'] deriv = openmc.TallyDerivative(derivative_id=d_id) deriv.variable = group['independent variable'][()].decode() if deriv.variable == 'density': @@ -470,25 +504,13 @@ def version(self): def summary(self): return self._summary - @sparse.setter - def sparse(self, sparse): - """Convert tally data from NumPy arrays to SciPy list of lists (LIL) - sparse matrices, and vice versa. - - This property may be used to reduce the amount of data in memory during - tally data processing. The tally data will be stored as SciPy LIL - matrices internally within each Tally object. All tally data access - properties and methods will return data as a dense NumPy array. - + def close(self): + """Close the statepoint HDF5 file and the corresponding + summary HDF5 file if present. """ - - cv.check_type('sparse', sparse, bool) - self._sparse = sparse - - # Update tally sparsities - if self._tallies_read: - for tally_id in self.tallies: - self.tallies[tally_id].sparse = self.sparse + self._f.close() + if self._summary is not None: + self._summary._f.close() def add_volume_information(self, volume_calc): """Add volume information to the geometry within the file @@ -651,8 +673,8 @@ def link_with_summary(self, summary): return if not isinstance(summary, openmc.Summary): - msg = 'Unable to link statepoint with "{0}" which ' \ - 'is not a Summary object'.format(summary) + msg = f'Unable to link statepoint with "{summary}" which is not a' \ + 'Summary object' raise ValueError(msg) cells = summary.geometry.get_all_cells() diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index f33427c34dc..212083c3cff 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -1,14 +1,18 @@ +from __future__ import annotations +import typing from abc import ABC, abstractmethod from collections.abc import Iterable -from math import pi +from math import cos, pi from numbers import Real -from xml.etree import ElementTree as ET +from warnings import warn +import lxml.etree as ET import numpy as np import openmc.checkvalue as cv from .._xml import get_text -from .univariate import Univariate, Uniform +from ..mesh import MeshBase +from .univariate import PowerLaw, Uniform, Univariate class UnitSphere(ABC): @@ -101,15 +105,15 @@ def __init__(self, mu=None, phi=None, reference_uvw=(0., 0., 1.)): def mu(self): return self._mu - @property - def phi(self): - return self._phi - @mu.setter def mu(self, mu): cv.check_type('cosine of polar angle', mu, Univariate) self._mu = mu + @property + def phi(self): + return self._phi + @phi.setter def phi(self, phi): cv.check_type('azimuthal angle', phi, Univariate) @@ -120,7 +124,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing angular distribution data """ @@ -138,7 +142,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -148,9 +152,9 @@ def from_xml_element(cls, elem): """ mu_phi = cls() - params = get_text(elem, 'parameters') - if params is not None: - mu_phi.reference_uvw = [float(x) for x in params.split()] + uvw = get_text(elem, 'reference_uvw') + if uvw is not None: + mu_phi.reference_uvw = [float(x) for x in uvw.split()] mu_phi.mu = Univariate.from_xml_element(elem.find('mu')) mu_phi.phi = Univariate.from_xml_element(elem.find('phi')) return mu_phi @@ -167,7 +171,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing isotropic distribution data """ @@ -176,12 +180,12 @@ def to_xml_element(self): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate isotropic distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -208,8 +212,7 @@ class Monodirectional(UnitSphere): """ - - def __init__(self, reference_uvw=[1., 0., 0.]): + def __init__(self, reference_uvw: typing.Sequence[float] = [1., 0., 0.]): super().__init__(reference_uvw) def to_xml_element(self): @@ -217,7 +220,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing monodirectional distribution data """ @@ -228,12 +231,12 @@ def to_xml_element(self): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate monodirectional distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -243,9 +246,9 @@ def from_xml_element(cls, elem): """ monodirectional = cls() - params = get_text(elem, 'parameters') - if params is not None: - monodirectional.reference_uvw = [float(x) for x in params.split()] + uvw = get_text(elem, 'reference_uvw') + if uvw is not None: + monodirectional.reference_uvw = [float(x) for x in uvw.split()] return monodirectional @@ -262,7 +265,7 @@ def to_xml_element(self): @classmethod @abstractmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem, meshes=None): distribution = get_text(elem, 'type') if distribution == 'cartesian': return CartesianIndependent.from_xml_element(elem) @@ -274,6 +277,8 @@ def from_xml_element(cls, elem): return Box.from_xml_element(elem) elif distribution == 'point': return Point.from_xml_element(elem) + elif distribution == 'mesh': + return MeshSpatial.from_xml_element(elem, meshes) class CartesianIndependent(Spatial): @@ -302,7 +307,12 @@ class CartesianIndependent(Spatial): """ - def __init__(self, x, y, z): + def __init__( + self, + x: openmc.stats.Univariate, + y: openmc.stats.Univariate, + z: openmc.stats.Univariate + ): self.x = x self.y = y self.z = z @@ -311,24 +321,24 @@ def __init__(self, x, y, z): def x(self): return self._x - @property - def y(self): - return self._y - - @property - def z(self): - return self._z - @x.setter def x(self, x): cv.check_type('x coordinate', x, Univariate) self._x = x + @property + def y(self): + return self._y + @y.setter def y(self, y): cv.check_type('y coordinate', y, Univariate) self._y = y + @property + def z(self): + return self._z + @z.setter def z(self, z): cv.check_type('z coordinate', z, Univariate) @@ -339,7 +349,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing spatial distribution data """ @@ -351,12 +361,12 @@ def to_xml_element(self): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate spatial distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -375,19 +385,22 @@ class SphericalIndependent(Spatial): r"""Spatial distribution represented in spherical coordinates. This distribution allows one to specify coordinates whose :math:`r`, - :math:`\theta`, and :math:`\phi` components are sampled independently from - one another and centered on the coordinates (x0, y0, z0). + :math:`\theta`, and :math:`\phi` components are sampled independently + from one another and centered on the coordinates (x0, y0, z0). + + .. versionadded:: 0.12 - .. versionadded: 0.12 + .. versionchanged:: 0.13.1 + Accepts ``cos_theta`` instead of ``theta`` Parameters ---------- r : openmc.stats.Univariate Distribution of r-coordinates in a reference frame specified by the origin parameter - theta : openmc.stats.Univariate - Distribution of theta-coordinates (angle relative to the z-axis) in a - reference frame specified by the origin parameter + cos_theta : openmc.stats.Univariate + Distribution of the cosine of the theta-coordinates (angle relative to + the z-axis) in a reference frame specified by the origin parameter phi : openmc.stats.Univariate Distribution of phi-coordinates (azimuthal angle) in a reference frame specified by the origin parameter @@ -399,9 +412,9 @@ class SphericalIndependent(Spatial): ---------- r : openmc.stats.Univariate Distribution of r-coordinates in the local reference frame - theta : openmc.stats.Univariate - Distribution of theta-coordinates (angle relative to the z-axis) in the - local reference frame + cos_theta : openmc.stats.Univariate + Distribution of the cosine of the theta-coordinates (angle relative to + the z-axis) in the local reference frame phi : openmc.stats.Univariate Distribution of phi-coordinates (azimuthal angle) in the local reference frame @@ -411,9 +424,9 @@ class SphericalIndependent(Spatial): """ - def __init__(self, r, theta, phi, origin=(0.0, 0.0, 0.0)): + def __init__(self, r, cos_theta, phi, origin=(0.0, 0.0, 0.0)): self.r = r - self.theta = theta + self.cos_theta = cos_theta self.phi = phi self.origin = origin @@ -421,33 +434,33 @@ def __init__(self, r, theta, phi, origin=(0.0, 0.0, 0.0)): def r(self): return self._r - @property - def theta(self): - return self._theta - - @property - def phi(self): - return self._phi - - @property - def origin(self): - return self._origin - @r.setter def r(self, r): cv.check_type('r coordinate', r, Univariate) self._r = r - @theta.setter - def theta(self, theta): - cv.check_type('theta coordinate', theta, Univariate) - self._theta = theta + @property + def cos_theta(self): + return self._cos_theta + + @cos_theta.setter + def cos_theta(self, cos_theta): + cv.check_type('cos_theta coordinate', cos_theta, Univariate) + self._cos_theta = cos_theta + + @property + def phi(self): + return self._phi @phi.setter def phi(self, phi): cv.check_type('phi coordinate', phi, Univariate) self._phi = phi + @property + def origin(self): + return self._origin + @origin.setter def origin(self, origin): cv.check_type('origin coordinates', origin, Iterable, Real) @@ -459,25 +472,25 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing spatial distribution data """ element = ET.Element('space') element.set('type', 'spherical') element.append(self.r.to_xml_element('r')) - element.append(self.theta.to_xml_element('theta')) + element.append(self.cos_theta.to_xml_element('cos_theta')) element.append(self.phi.to_xml_element('phi')) element.set("origin", ' '.join(map(str, self.origin))) return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate spatial distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -487,10 +500,11 @@ def from_xml_element(cls, elem): """ r = Univariate.from_xml_element(elem.find('r')) - theta = Univariate.from_xml_element(elem.find('theta')) + cos_theta = Univariate.from_xml_element(elem.find('cos_theta')) phi = Univariate.from_xml_element(elem.find('phi')) origin = [float(x) for x in elem.get('origin').split()] - return cls(r, theta, phi, origin=origin) + return cls(r, cos_theta, phi, origin=origin) + class CylindricalIndependent(Spatial): r"""Spatial distribution represented in cylindrical coordinates. @@ -542,33 +556,33 @@ def __init__(self, r, phi, z, origin=(0.0, 0.0, 0.0)): def r(self): return self._r - @property - def phi(self): - return self._phi - - @property - def z(self): - return self._z - - @property - def origin(self): - return self._origin - @r.setter def r(self, r): cv.check_type('r coordinate', r, Univariate) self._r = r + @property + def phi(self): + return self._phi + @phi.setter def phi(self, phi): cv.check_type('phi coordinate', phi, Univariate) self._phi = phi + @property + def z(self): + return self._z + @z.setter def z(self, z): cv.check_type('z coordinate', z, Univariate) self._z = z + @property + def origin(self): + return self._origin + @origin.setter def origin(self, origin): cv.check_type('origin coordinates', origin, Iterable, Real) @@ -580,7 +594,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing spatial distribution data """ @@ -593,12 +607,12 @@ def to_xml_element(self): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate spatial distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -614,6 +628,134 @@ def from_xml_element(cls, elem): return cls(r, phi, z, origin=origin) +class MeshSpatial(Spatial): + """Spatial distribution for a mesh. + + This distribution specifies a mesh to sample over with source strengths + specified for each mesh element. + + .. versionadded:: 0.13.3 + + Parameters + ---------- + mesh : openmc.MeshBase + The mesh instance used for sampling + strengths : iterable of float, optional + An iterable of values that represents the weights of each element. If no + source strengths are specified, they will be equal for all mesh + elements. + volume_normalized : bool, optional + Whether or not the strengths will be multiplied by element volumes at + runtime. Default is True. + + Attributes + ---------- + mesh : openmc.MeshBase + The mesh instance used for sampling + strengths : numpy.ndarray or None + An array of source strengths for each mesh element + volume_normalized : bool + Whether or not the strengths will be multiplied by element volumes at + runtime. + """ + + def __init__(self, mesh, strengths=None, volume_normalized=True): + self.mesh = mesh + self.strengths = strengths + self.volume_normalized = volume_normalized + + @property + def mesh(self): + return self._mesh + + @mesh.setter + def mesh(self, mesh): + if mesh is not None: + cv.check_type('mesh instance', mesh, MeshBase) + self._mesh = mesh + + @property + def volume_normalized(self): + return self._volume_normalized + + @volume_normalized.setter + def volume_normalized(self, volume_normalized): + cv.check_type('Multiply strengths by element volumes', volume_normalized, bool) + self._volume_normalized = volume_normalized + + @property + def strengths(self): + return self._strengths + + @strengths.setter + def strengths(self, given_strengths): + if given_strengths is not None: + cv.check_type('strengths array passed in', given_strengths, Iterable, Real) + self._strengths = np.asarray(given_strengths, dtype=float).flatten() + else: + self._strengths = None + + @property + def num_strength_bins(self): + if self.strengths is None: + raise ValueError('Strengths are not set') + return self.strengths.size + + def to_xml_element(self): + """Return XML representation of the spatial distribution + + Returns + ------- + element : lxml.etree._Element + XML element containing spatial distribution data + + """ + element = ET.Element('space') + + element.set('type', 'mesh') + element.set("mesh_id", str(self.mesh.id)) + element.set("volume_normalized", str(self.volume_normalized)) + + if self.strengths is not None: + subelement = ET.SubElement(element, 'strengths') + subelement.text = ' '.join(str(e) for e in self.strengths) + + return element + + @classmethod + def from_xml_element(cls, elem, meshes): + """Generate spatial distribution from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict + A dictionary with mesh IDs as keys and openmc.MeshBase instances as + values + + Returns + ------- + openmc.stats.MeshSpatial + Spatial distribution generated from XML element + + """ + + mesh_id = int(elem.get('mesh_id')) + + # check if this mesh has been read in from another location already + if mesh_id not in meshes: + raise ValueError(f'Could not locate mesh with ID "{mesh_id}"') + + volume_normalized = elem.get("volume_normalized") + volume_normalized = get_text(elem, 'volume_normalized').lower() == 'true' + strengths = get_text(elem, 'strengths') + if strengths is not None: + strengths = [float(b) for b in get_text(elem, 'strengths').split()] + + return cls(meshes[mesh_id], strengths, volume_normalized) + + class Box(Spatial): """Uniform distribution of coordinates in a rectangular cuboid. @@ -627,6 +769,9 @@ class Box(Spatial): Whether spatial sites should only be accepted if they occur in fissionable materials + .. deprecated:: 0.14.1 + Use the `constraints` argument when defining a source object instead. + Attributes ---------- lower_left : Iterable of float @@ -637,10 +782,17 @@ class Box(Spatial): Whether spatial sites should only be accepted if they occur in fissionable materials - """ + .. deprecated:: 0.14.1 + Use the `constraints` argument when defining a source object instead. + """ - def __init__(self, lower_left, upper_right, only_fissionable=False): + def __init__( + self, + lower_left: typing.Sequence[float], + upper_right: typing.Sequence[float], + only_fissionable: bool = False + ): self.lower_left = lower_left self.upper_right = upper_right self.only_fissionable = only_fissionable @@ -649,37 +801,41 @@ def __init__(self, lower_left, upper_right, only_fissionable=False): def lower_left(self): return self._lower_left - @property - def upper_right(self): - return self._upper_right - - @property - def only_fissionable(self): - return self._only_fissionable - @lower_left.setter def lower_left(self, lower_left): cv.check_type('lower left coordinate', lower_left, Iterable, Real) cv.check_length('lower left coordinate', lower_left, 3) self._lower_left = lower_left + @property + def upper_right(self): + return self._upper_right + @upper_right.setter def upper_right(self, upper_right): cv.check_type('upper right coordinate', upper_right, Iterable, Real) cv.check_length('upper right coordinate', upper_right, 3) self._upper_right = upper_right + @property + def only_fissionable(self): + return self._only_fissionable + @only_fissionable.setter def only_fissionable(self, only_fissionable): cv.check_type('only fissionable', only_fissionable, bool) self._only_fissionable = only_fissionable + if only_fissionable: + warn("The 'only_fissionable' has been deprecated. Use the " + "'constraints' argument when defining a source instead.", + FutureWarning) def to_xml_element(self): """Return XML representation of the box distribution Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing box distribution data """ @@ -694,12 +850,12 @@ def to_xml_element(self): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate box distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -733,7 +889,7 @@ class Point(Spatial): """ - def __init__(self, xyz=(0., 0., 0.)): + def __init__(self, xyz: typing.Sequence[float] = (0., 0., 0.)): self.xyz = xyz @property @@ -751,7 +907,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing point distribution location """ @@ -762,12 +918,12 @@ def to_xml_element(self): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate point distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -778,3 +934,47 @@ def from_xml_element(cls, elem): """ xyz = [float(x) for x in get_text(elem, 'parameters').split()] return cls(xyz) + + +def spherical_uniform( + r_outer: float, + r_inner: float = 0.0, + thetas: typing.Sequence[float] = (0., pi), + phis: typing.Sequence[float] = (0., 2*pi), + origin: typing.Sequence[float] = (0., 0., 0.) + ): + """Return a uniform spatial distribution over a spherical shell. + + This function provides a uniform spatial distribution over a spherical + shell between `r_inner` and `r_outer`. Optionally, the range of angles + can be restricted by the `thetas` and `phis` arguments. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + r_outer : float + Outer radius of the spherical shell in [cm] + r_inner : float + Inner radius of the spherical shell in [cm] + thetas : iterable of float + Starting and ending theta coordinates (angle relative to + the z-axis) in radius in a reference frame centered at `origin` + phis : iterable of float + Starting and ending phi coordinates (azimuthal angle) in + radians in a reference frame centered at `origin` + origin: iterable of float + Coordinates (x0, y0, z0) of the center of the spherical + reference frame for the distribution. + + Returns + ------- + openmc.stats.SphericalIndependent + Uniform distribution over the spherical shell + """ + + r_dist = PowerLaw(r_inner, r_outer, 2) + cos_thetas_dist = Uniform(cos(thetas[1]), cos(thetas[0])) + phis_dist = Uniform(phis[0], phis[1]) + + return SphericalIndependent(r_dist, cos_thetas_dist, phis_dist, origin) diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index 4bbc5092778..a0e86c3f8f2 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -1,15 +1,21 @@ +from __future__ import annotations +import math +import typing from abc import ABC, abstractmethod +from collections import defaultdict from collections.abc import Iterable +from copy import deepcopy from numbers import Real -from xml.etree import ElementTree as ET +from warnings import warn +import lxml.etree as ET import numpy as np +from scipy.integrate import trapezoid import openmc.checkvalue as cv from .._xml import get_text from ..mixin import EqualityMixin - _INTERPOLATION_SCHEMES = [ 'histogram', 'linear-linear', @@ -42,6 +48,8 @@ def from_xml_element(cls, elem): return Discrete.from_xml_element(elem) elif distribution == 'uniform': return Uniform.from_xml_element(elem) + elif distribution == 'powerlaw': + return PowerLaw.from_xml_element(elem) elif distribution == 'maxwell': return Maxwell.from_xml_element(elem) elif distribution == 'watt': @@ -49,7 +57,9 @@ def from_xml_element(cls, elem): elif distribution == 'normal': return Normal.from_xml_element(elem) elif distribution == 'muir': - return Muir.from_xml_element(elem) + # Support older files where Muir had its own class + params = [float(x) for x in get_text(elem, 'parameters').split()] + return muir(*params) elif distribution == 'tabular': return Tabular.from_xml_element(elem) elif distribution == 'legendre': @@ -57,6 +67,36 @@ def from_xml_element(cls, elem): elif distribution == 'mixture': return Mixture.from_xml_element(elem) + @abstractmethod + def sample(n_samples: int = 1, seed: typing.Optional[int] = None): + """Sample the univariate distribution + + Parameters + ---------- + n_samples : int + Number of sampled values to generate + seed : int or None + Initial random number seed. + + Returns + ------- + numpy.ndarray + A 1-D array of sampled values + """ + pass + + def integral(self): + """Return integral of distribution + + .. versionadded:: 0.13.1 + + Returns + ------- + float + Integral of distribution + """ + return 1.0 + class Discrete(Univariate): """Distribution characterized by a probability mass function. @@ -74,9 +114,9 @@ class Discrete(Univariate): Attributes ---------- - x : Iterable of float + x : numpy.ndarray Values of the random variable - p : Iterable of float + p : numpy.ndarray Discrete probability for each value """ @@ -92,16 +132,16 @@ def __len__(self): def x(self): return self._x - @property - def p(self): - return self._p - @x.setter def x(self, x): if isinstance(x, Real): x = [x] cv.check_type('discrete values', x, Iterable, Real) - self._x = x + self._x = np.array(x, dtype=float) + + @property + def p(self): + return self._p @p.setter def p(self, p): @@ -110,7 +150,20 @@ def p(self, p): cv.check_type('discrete probabilities', p, Iterable, Real) for pk in p: cv.check_greater_than('discrete probability', pk, 0.0, True) - self._p = p + self._p = np.array(p, dtype=float) + + def cdf(self): + return np.insert(np.cumsum(self.p), 0, 0.0) + + def sample(self, n_samples=1, seed=None): + rng = np.random.RandomState(seed) + p = self.p / self.p.sum() + return rng.choice(self.x, n_samples, p=p) + + def normalize(self): + """Normalize the probabilities stored on the distribution""" + norm = sum(self.p) + self.p = [val / norm for val in self.p] def to_xml_element(self, element_name): """Return XML representation of the discrete distribution @@ -122,7 +175,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing discrete distribution data """ @@ -135,12 +188,12 @@ def to_xml_element(self, element_name): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate discrete distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -154,6 +207,111 @@ def from_xml_element(cls, elem): p = params[len(params)//2:] return cls(x, p) + @classmethod + def merge( + cls, + dists: typing.Sequence[Discrete], + probs: typing.Sequence[int] + ): + """Merge multiple discrete distributions into a single distribution + + .. versionadded:: 0.13.1 + + Parameters + ---------- + dists : iterable of openmc.stats.Discrete + Discrete distributions to combine + probs : iterable of float + Probability of each distribution + + Returns + ------- + openmc.stats.Discrete + Combined discrete distribution + + """ + if len(dists) != len(probs): + raise ValueError("Number of distributions and probabilities must match.") + + # Combine distributions accounting for duplicate x values + x_merged = set() + p_merged = defaultdict(float) + for dist, p_dist in zip(dists, probs): + for x, p in zip(dist.x, dist.p): + x_merged.add(x) + p_merged[x] += p*p_dist + + # Create values and probabilities as arrays + x_arr = np.array(sorted(x_merged)) + p_arr = np.array([p_merged[x] for x in x_arr]) + return cls(x_arr, p_arr) + + def integral(self): + """Return integral of distribution + + .. versionadded:: 0.13.1 + + Returns + ------- + float + Integral of discrete distribution + """ + return np.sum(self.p) + + def clip(self, tolerance: float = 1e-6, inplace: bool = False) -> Discrete: + r"""Remove low-importance points from discrete distribution. + + Given a probability mass function :math:`p(x)` with :math:`\{x_1, x_2, + x_3, \dots\}` the possible values of the random variable with + corresponding probabilities :math:`\{p_1, p_2, p_3, \dots\}`, this + function will remove any low-importance points such that :math:`\sum_i + x_i p_i` is preserved to within some threshold. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + tolerance : float + Maximum fraction of :math:`\sum_i x_i p_i` that will be discarded. + inplace : bool + Whether to modify the current object in-place or return a new one. + + Returns + ------- + Discrete distribution with low-importance points removed + + """ + cv.check_less_than("tolerance", tolerance, 1.0, equality=True) + cv.check_greater_than("tolerance", tolerance, 0.0, equality=True) + + # Determine (reversed) sorted order of probabilities + intensity = self.p * self.x + index_sort = np.argsort(intensity)[::-1] + + # Get probabilities in above order + sorted_intensity = intensity[index_sort] + + # Determine cumulative sum of probabilities + cumsum = np.cumsum(sorted_intensity) + cumsum /= cumsum[-1] + + # Find index which satisfies cutoff + index_cutoff = np.searchsorted(cumsum, 1.0 - tolerance) + + # Now get indices up to cutoff + new_indices = index_sort[:index_cutoff + 1] + new_indices.sort() + + # Create new discrete distribution + if inplace: + self.x = self.x[new_indices] + self.p = self.p[new_indices] + return self + else: + new_x = self.x[new_indices] + new_p = self.p[new_indices] + return type(self)(new_x, new_p) + class Uniform(Univariate): """Distribution with constant probability over a finite interval [a,b] @@ -174,7 +332,7 @@ class Uniform(Univariate): """ - def __init__(self, a=0.0, b=1.0): + def __init__(self, a: float = 0.0, b: float = 1.0): self.a = a self.b = b @@ -185,15 +343,15 @@ def __len__(self): def a(self): return self._a - @property - def b(self): - return self._b - @a.setter def a(self, a): cv.check_type('Uniform a', a, Real) self._a = a + @property + def b(self): + return self._b + @b.setter def b(self, b): cv.check_type('Uniform b', b, Real) @@ -205,7 +363,11 @@ def to_tabular(self): t.c = [0., 1.] return t - def to_xml_element(self, element_name): + def sample(self, n_samples=1, seed=None): + rng = np.random.RandomState(seed) + return rng.uniform(self.a, self.b, n_samples) + + def to_xml_element(self, element_name: str): """Return XML representation of the uniform distribution Parameters @@ -215,22 +377,22 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing uniform distribution data """ element = ET.Element(element_name) element.set("type", "uniform") - element.set("parameters", '{} {}'.format(self.a, self.b)) + element.set("parameters", f'{self.a} {self.b}') return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate uniform distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -243,6 +405,115 @@ def from_xml_element(cls, elem): return cls(*map(float, params)) +class PowerLaw(Univariate): + """Distribution with power law probability over a finite interval [a,b] + + The power law distribution has density function :math:`p(x) dx = c x^n dx`. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + a : float, optional + Lower bound of the sampling interval. Defaults to zero. + b : float, optional + Upper bound of the sampling interval. Defaults to unity. + n : float, optional + Power law exponent. Defaults to zero, which is equivalent to a uniform + distribution. + + Attributes + ---------- + a : float + Lower bound of the sampling interval + b : float + Upper bound of the sampling interval + n : float + Power law exponent + + """ + + def __init__(self, a: float = 0.0, b: float = 1.0, n: float = 0.): + self.a = a + self.b = b + self.n = n + + def __len__(self): + return 3 + + @property + def a(self): + return self._a + + @a.setter + def a(self, a): + cv.check_type('interval lower bound', a, Real) + self._a = a + + @property + def b(self): + return self._b + + @b.setter + def b(self, b): + cv.check_type('interval upper bound', b, Real) + self._b = b + + @property + def n(self): + return self._n + + @n.setter + def n(self, n): + cv.check_type('power law exponent', n, Real) + self._n = n + + def sample(self, n_samples=1, seed=None): + rng = np.random.RandomState(seed) + xi = rng.random(n_samples) + pwr = self.n + 1 + offset = self.a**pwr + span = self.b**pwr - offset + return np.power(offset + xi * span, 1/pwr) + + def to_xml_element(self, element_name: str): + """Return XML representation of the power law distribution + + Parameters + ---------- + element_name : str + XML element name + + Returns + ------- + element : lxml.etree._Element + XML element containing distribution data + + """ + element = ET.Element(element_name) + element.set("type", "powerlaw") + element.set("parameters", f'{self.a} {self.b} {self.n}') + return element + + @classmethod + def from_xml_element(cls, elem: ET.Element): + """Generate power law distribution from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.stats.PowerLaw + Distribution generated from XML element + + """ + params = get_text(elem, 'parameters').split() + return cls(*map(float, params)) + + class Maxwell(Univariate): r"""Maxwellian distribution in energy. @@ -278,7 +549,19 @@ def theta(self, theta): cv.check_greater_than('Maxwell temperature', theta, 0.0) self._theta = theta - def to_xml_element(self, element_name): + def sample(self, n_samples=1, seed=None): + rng = np.random.RandomState(seed) + return self.sample_maxwell(self.theta, n_samples, rng=rng) + + @staticmethod + def sample_maxwell(t, n_samples: int, rng=None): + if rng is None: + rng = np.random.default_rng() + r1, r2, r3 = rng.random((3, n_samples)) + c = np.cos(0.5 * np.pi * r3) + return -t * (np.log(r1) + np.log(r2) * c * c) + + def to_xml_element(self, element_name: str): """Return XML representation of the Maxwellian distribution Parameters @@ -288,7 +571,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Maxwellian distribution data """ @@ -298,12 +581,12 @@ def to_xml_element(self, element_name): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate Maxwellian distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -350,23 +633,30 @@ def __len__(self): def a(self): return self._a - @property - def b(self): - return self._b - @a.setter def a(self, a): cv.check_type('Watt a', a, Real) cv.check_greater_than('Watt a', a, 0.0) self._a = a + @property + def b(self): + return self._b + @b.setter def b(self, b): cv.check_type('Watt b', b, Real) cv.check_greater_than('Watt b', b, 0.0) self._b = b - def to_xml_element(self, element_name): + def sample(self, n_samples=1, seed=None): + rng = np.random.RandomState(seed) + w = Maxwell.sample_maxwell(self.a, n_samples, rng=rng) + u = rng.uniform(-1., 1., n_samples) + aab = self.a * self.a * self.b + return w + 0.25*aab + u*np.sqrt(aab*w) + + def to_xml_element(self, element_name: str): """Return XML representation of the Watt distribution Parameters @@ -376,22 +666,22 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Watt distribution data """ element = ET.Element(element_name) element.set("type", "watt") - element.set("parameters", '{} {}'.format(self.a, self.b)) + element.set("parameters", f'{self.a} {self.b}') return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate Watt distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -437,22 +727,26 @@ def __len__(self): def mean_value(self): return self._mean_value - @property - def std_dev(self): - return self._std_dev - @mean_value.setter def mean_value(self, mean_value): cv.check_type('Normal mean_value', mean_value, Real) self._mean_value = mean_value + @property + def std_dev(self): + return self._std_dev + @std_dev.setter def std_dev(self, std_dev): cv.check_type('Normal std_dev', std_dev, Real) cv.check_greater_than('Normal std_dev', std_dev, 0.0) self._std_dev = std_dev - def to_xml_element(self, element_name): + def sample(self, n_samples=1, seed=None): + rng = np.random.RandomState(seed) + return rng.normal(self.mean_value, self.std_dev, n_samples) + + def to_xml_element(self, element_name: str): """Return XML representation of the Normal distribution Parameters @@ -462,22 +756,22 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Watt distribution data """ element = ET.Element(element_name) element.set("type", "normal") - element.set("parameters", '{} {}'.format(self.mean_value, self.std_dev)) + element.set("parameters", f'{self.mean_value} {self.std_dev}') return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate Normal distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -490,110 +784,45 @@ def from_xml_element(cls, elem): return cls(*map(float, params)) -class Muir(Univariate): - """Muir energy spectrum. +def muir(e0: float, m_rat: float, kt: float): + """Generate a Muir energy spectrum + + The Muir energy spectrum is a normal distribution, but for convenience + reasons allows the user to specify three parameters to define the + distribution: the mean energy of particles ``e0``, the mass of reactants + ``m_rat``, and the ion temperature ``kt``. - The Muir energy spectrum is a Gaussian spectrum, but for - convenience reasons allows the user 3 parameters to define - the distribution, e0 the mean energy of particles, the mass - of reactants m_rat, and the ion temperature kt. + .. versionadded:: 0.13.2 Parameters ---------- e0 : float - Mean of the Muir distribution in units of eV + Mean of the Muir distribution in [eV] m_rat : float - Ratio of the sum of the masses of the reaction inputs to an - AMU + Ratio of the sum of the masses of the reaction inputs to 1 amu kt : float - Ion temperature for the Muir distribution in units of eV + Ion temperature for the Muir distribution in [eV] - Attributes - ---------- - e0 : float - Mean of the Muir distribution in units of eV - m_rat : float - Ratio of the sum of the masses of the reaction inputs to an - AMU - kt : float - Ion temperature for the Muir distribution in units of eV + Returns + ------- + openmc.stats.Normal + Corresponding normal distribution """ + # https://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-05411-MS + std_dev = math.sqrt(2 * e0 * kt / m_rat) + return Normal(e0, std_dev) - def __init__(self, e0=14.08e6, m_rat = 5., kt = 20000.): - self.e0 = e0 - self.m_rat = m_rat - self.kt = kt - - def __len__(self): - return 3 - - @property - def e0(self): - return self._e0 - - @property - def m_rat(self): - return self._m_rat - @property - def kt(self): - return self._kt - - @e0.setter - def e0(self, e0): - cv.check_type('Muir e0', e0, Real) - cv.check_greater_than('Muir e0', e0, 0.0) - self._e0 = e0 - - @m_rat.setter - def m_rat(self, m_rat): - cv.check_type('Muir m_rat', m_rat, Real) - cv.check_greater_than('Muir m_rat', m_rat, 0.0) - self._m_rat = m_rat - - @kt.setter - def kt(self, kt): - cv.check_type('Muir kt', kt, Real) - cv.check_greater_than('Muir kt', kt, 0.0) - self._kt = kt - - def to_xml_element(self, element_name): - """Return XML representation of the Watt distribution - - Parameters - ---------- - element_name : str - XML element name - - Returns - ------- - element : xml.etree.ElementTree.Element - XML element containing Watt distribution data - - """ - element = ET.Element(element_name) - element.set("type", "muir") - element.set("parameters", '{} {} {}'.format(self._e0, self._m_rat, self._kt)) - return element - - @classmethod - def from_xml_element(cls, elem): - """Generate Muir distribution from an XML element - - Parameters - ---------- - elem : xml.etree.ElementTree.Element - XML element - - Returns - ------- - openmc.stats.Muir - Muir distribution generated from XML element - - """ - params = get_text(elem, 'parameters').split() - return cls(*map(float, params)) +# Retain deprecated name for the time being +def Muir(*args, **kwargs): + # warn of name change + warn( + "The Muir(...) class has been replaced by the muir(...) function and " + "will be removed in a future version of OpenMC. Use muir(...) instead.", + FutureWarning + ) + return muir(*args, **kwargs) class Tabular(Univariate): @@ -617,9 +846,9 @@ class Tabular(Univariate): Attributes ---------- - x : Iterable of float + x : numpy.ndarray Tabulated values of the random variable - p : Iterable of float + p : numpy.ndarray Tabulated probabilities interpolation : {'histogram', 'linear-linear', 'linear-log', 'log-linear', 'log-log'}, optional Indicate whether the density function is constant between tabulated @@ -627,8 +856,13 @@ class Tabular(Univariate): """ - def __init__(self, x, p, interpolation='linear-linear', - ignore_negative=False): + def __init__( + self, + x: typing.Sequence[float], + p: typing.Sequence[float], + interpolation: str = 'linear-linear', + ignore_negative: bool = False + ): self._ignore_negative = ignore_negative self.x = x self.p = p @@ -641,18 +875,14 @@ def __len__(self): def x(self): return self._x - @property - def p(self): - return self._p - - @property - def interpolation(self): - return self._interpolation - @x.setter def x(self, x): cv.check_type('tabulated values', x, Iterable, Real) - self._x = x + self._x = np.array(x, dtype=float) + + @property + def p(self): + return self._p @p.setter def p(self, p): @@ -660,14 +890,132 @@ def p(self, p): if not self._ignore_negative: for pk in p: cv.check_greater_than('tabulated probability', pk, 0.0, True) - self._p = p + self._p = np.array(p, dtype=float) + + @property + def interpolation(self): + return self._interpolation @interpolation.setter def interpolation(self, interpolation): cv.check_value('interpolation', interpolation, _INTERPOLATION_SCHEMES) self._interpolation = interpolation - def to_xml_element(self, element_name): + def cdf(self): + c = np.zeros_like(self.x) + x = self.x + p = self.p + + if self.interpolation == 'histogram': + c[1:] = p[:-1] * np.diff(x) + elif self.interpolation == 'linear-linear': + c[1:] = 0.5 * (p[:-1] + p[1:]) * np.diff(x) + else: + raise NotImplementedError('Can only generate CDFs for tabular ' + 'distributions using histogram or ' + 'linear-linear interpolation') + + + return np.cumsum(c) + + def mean(self): + """Compute the mean of the tabular distribution""" + if self.interpolation == 'linear-linear': + mean = 0.0 + for i in range(1, len(self.x)): + y_min = self.p[i-1] + y_max = self.p[i] + x_min = self.x[i-1] + x_max = self.x[i] + + m = (y_max - y_min) / (x_max - x_min) + + exp_val = (1./3.) * m * (x_max**3 - x_min**3) + exp_val += 0.5 * m * x_min * (x_min**2 - x_max**2) + exp_val += 0.5 * y_min * (x_max**2 - x_min**2) + mean += exp_val + + elif self.interpolation == 'histogram': + x_l = self.x[:-1] + x_r = self.x[1:] + p_l = self.p[:-1] + mean = (0.5 * (x_l + x_r) * (x_r - x_l) * p_l).sum() + else: + raise NotImplementedError('Can only compute mean for tabular ' + 'distributions using histogram ' + 'or linear-linear interpolation.') + + # Normalize for when integral of distribution is not 1 + mean /= self.integral() + + return mean + + def normalize(self): + """Normalize the probabilities stored on the distribution""" + self.p /= self.cdf().max() + + def sample(self, n_samples: int = 1, seed: typing.Optional[int] = None): + rng = np.random.RandomState(seed) + xi = rng.random(n_samples) + + # always use normalized probabilities when sampling + cdf = self.cdf() + p = self.p / cdf.max() + cdf /= cdf.max() + + # get CDF bins that are above the + # sampled values + c_i = np.full(n_samples, cdf[0]) + cdf_idx = np.zeros(n_samples, dtype=int) + for i, val in enumerate(cdf[:-1]): + mask = xi > val + c_i[mask] = val + cdf_idx[mask] = i + + # get table values at each index where + # the random number is less than the next cdf + # entry + x_i = self.x[cdf_idx] + p_i = p[cdf_idx] + + if self.interpolation == 'histogram': + # mask where probability is greater than zero + pos_mask = p_i > 0.0 + # probabilities greater than zero are set proportional to the + # position of the random numebers in relation to the cdf value + p_i[pos_mask] = x_i[pos_mask] + (xi[pos_mask] - c_i[pos_mask]) \ + / p_i[pos_mask] + # probabilities smaller than zero are set to the random number value + p_i[~pos_mask] = x_i[~pos_mask] + + samples_out = p_i + + elif self.interpolation == 'linear-linear': + # get variable and probability values for the + # next entry + x_i1 = self.x[cdf_idx + 1] + p_i1 = p[cdf_idx + 1] + # compute slope between entries + m = (p_i1 - p_i) / (x_i1 - x_i) + # set values for zero slope + zero = m == 0.0 + m[zero] = x_i[zero] + (xi[zero] - c_i[zero]) / p_i[zero] + # set values for non-zero slope + non_zero = ~zero + quad = np.power(p_i[non_zero], 2) + 2.0 * m[non_zero] * (xi[non_zero] - c_i[non_zero]) + quad[quad < 0.0] = 0.0 + m[non_zero] = x_i[non_zero] + (np.sqrt(quad) - p_i[non_zero]) / m[non_zero] + samples_out = m + + else: + raise NotImplementedError('Can only sample tabular distributions ' + 'using histogram or ' + 'linear-linear interpolation') + + assert all(samples_out < self.x[-1]) + return samples_out + + def to_xml_element(self, element_name: str): """Return XML representation of the tabular distribution Parameters @@ -677,7 +1025,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing tabular distribution data """ @@ -691,12 +1039,12 @@ def to_xml_element(self, element_name): return element @classmethod - def from_xml_element(cls, elem): + def from_xml_element(cls, elem: ET.Element): """Generate tabular distribution from an XML element Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -711,6 +1059,24 @@ def from_xml_element(cls, elem): p = params[len(params)//2:] return cls(x, p, interpolation) + def integral(self): + """Return integral of distribution + + .. versionadded:: 0.13.1 + + Returns + ------- + float + Integral of tabular distrbution + """ + if self.interpolation == 'histogram': + return np.sum(np.diff(self.x) * self.p[:-1]) + elif self.interpolation == 'linear-linear': + return trapezoid(self.p, self.x) + else: + raise NotImplementedError( + f'integral() not supported for {self.inteprolation} interpolation') + class Legendre(Univariate): r"""Probability density given by a Legendre polynomial expansion @@ -730,7 +1096,7 @@ class Legendre(Univariate): """ - def __init__(self, coefficients): + def __init__(self, coefficients: typing.Sequence[float]): self.coefficients = coefficients self._legendre_poly = None @@ -754,6 +1120,9 @@ def coefficients(self): def coefficients(self, coefficients): self._coefficients = np.asarray(coefficients) + def sample(self, n_samples=1, seed=None): + raise NotImplementedError + def to_xml_element(self, element_name): raise NotImplementedError @@ -781,7 +1150,11 @@ class Mixture(Univariate): """ - def __init__(self, probability, distribution): + def __init__( + self, + probability: typing.Sequence[float], + distribution: typing.Sequence[Univariate] + ): self.probability = probability self.distribution = distribution @@ -792,10 +1165,6 @@ def __len__(self): def probability(self): return self._probability - @property - def distribution(self): - return self._distribution - @probability.setter def probability(self, probability): cv.check_type('mixture distribution probabilities', probability, @@ -805,15 +1174,194 @@ def probability(self, probability): p, 0.0, True) self._probability = probability + @property + def distribution(self): + return self._distribution + @distribution.setter def distribution(self, distribution): cv.check_type('mixture distribution components', distribution, Iterable, Univariate) self._distribution = distribution - def to_xml_element(self, element_name): - raise NotImplementedError + def cdf(self): + return np.insert(np.cumsum(self.probability), 0, 0.0) + + def sample(self, n_samples=1, seed=None): + rng = np.random.RandomState(seed) + + # Get probability of each distribution accounting for its intensity + p = np.array([prob*dist.integral() for prob, dist in + zip(self.probability, self.distribution)]) + p /= p.sum() + + # Sample from the distributions + idx = rng.choice(range(len(self.distribution)), n_samples, p=p) + + # Draw samples from the distributions sampled above + out = np.empty_like(idx, dtype=float) + for i in np.unique(idx): + n_dist_samples = np.count_nonzero(idx == i) + samples = self.distribution[i].sample(n_dist_samples) + out[idx == i] = samples + return out + + def normalize(self): + """Normalize the probabilities stored on the distribution""" + norm = sum(self.probability) + self.probability = [val / norm for val in self.probability] + + def to_xml_element(self, element_name: str): + """Return XML representation of the mixture distribution + + .. versionadded:: 0.13.0 + + Parameters + ---------- + element_name : str + XML element name + + Returns + ------- + element : lxml.etree._Element + XML element containing mixture distribution data + + """ + element = ET.Element(element_name) + element.set("type", "mixture") + + for p, d in zip(self.probability, self.distribution): + data = ET.SubElement(element, "pair") + data.set("probability", str(p)) + data.append(d.to_xml_element("dist")) + + return element @classmethod - def from_xml_element(cls, elem): - raise NotImplementedError + def from_xml_element(cls, elem: ET.Element): + """Generate mixture distribution from an XML element + + .. versionadded:: 0.13.0 + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.stats.Mixture + Mixture distribution generated from XML element + + """ + probability = [] + distribution = [] + for pair in elem.findall('pair'): + probability.append(float(get_text(pair, 'probability'))) + distribution.append(Univariate.from_xml_element(pair.find("dist"))) + + return cls(probability, distribution) + + def integral(self): + """Return integral of the distribution + + .. versionadded:: 0.13.1 + + Returns + ------- + float + Integral of the distribution + """ + return sum([ + p*dist.integral() + for p, dist in zip(self.probability, self.distribution) + ]) + + def clip(self, tolerance: float = 1e-6, inplace: bool = False) -> Mixture: + r"""Remove low-importance points from contained discrete distributions. + + Given a probability mass function :math:`p(x)` with :math:`\{x_1, x_2, + x_3, \dots\}` the possible values of the random variable with + corresponding probabilities :math:`\{p_1, p_2, p_3, \dots\}`, this + function will remove any low-importance points such that :math:`\sum_i + x_i p_i` is preserved to within some threshold. + + .. versionadded:: 0.14.0 + + Parameters + ---------- + tolerance : float + Maximum fraction of :math:`\sum_i x_i p_i` that will be discarded + for any discrete distributions within the mixture distribution. + inplace : bool + Whether to modify the current object in-place or return a new one. + + Returns + ------- + Discrete distribution with low-importance points removed + + """ + if inplace: + for dist in self.distribution: + if isinstance(dist, Discrete): + dist.clip(tolerance, inplace=True) + return self + else: + distribution = [ + dist.clip(tolerance) if isinstance(dist, Discrete) else dist + for dist in self.distribution + ] + return type(self)(self.probability, distribution) + + +def combine_distributions( + dists: typing.Sequence[Univariate], + probs: typing.Sequence[float] +): + """Combine distributions with specified probabilities + + This function can be used to combine multiple instances of + :class:`~openmc.stats.Discrete` and `~openmc.stats.Tabular`. Multiple + discrete distributions are merged into a single distribution and the + remainder of the distributions are put into a :class:`~openmc.stats.Mixture` + distribution. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + dists : iterable of openmc.stats.Univariate + Distributions to combine + probs : iterable of float + Probability (or intensity) of each distribution + + """ + # Get copy of distribution list so as not to modify the argument + dist_list = deepcopy(dists) + + # Get list of discrete/continuous distribution indices + discrete_index = [i for i, d in enumerate(dist_list) if isinstance(d, Discrete)] + cont_index = [i for i, d in enumerate(dist_list) if isinstance(d, Tabular)] + + # Apply probabilites to continuous distributions + for i in cont_index: + dist = dist_list[i] + dist.p *= probs[i] + + if discrete_index: + # Create combined discrete distribution + dist_discrete = [dist_list[i] for i in discrete_index] + discrete_probs = [probs[i] for i in discrete_index] + combined_dist = Discrete.merge(dist_discrete, discrete_probs) + + # Replace multiple discrete distributions with merged + for idx in reversed(discrete_index): + dist_list.pop(idx) + dist_list.append(combined_dist) + + # Combine discrete and continuous if present + if len(dist_list) > 1: + probs = [1.0]*len(dist_list) + dist_list[:] = [Mixture(probs, dist_list.copy())] + + return dist_list[0] diff --git a/openmc/summary.py b/openmc/summary.py index 63ed6651695..6423f8ce1d6 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -12,7 +12,12 @@ class Summary: - """Summary of geometry, materials, and tallies used in a simulation. + """Summary of model used in a simulation. + + Parameters + ---------- + filename : str or path-like + Path to file to load Attributes ---------- @@ -33,8 +38,9 @@ class Summary: """ def __init__(self, filename): + filename = str(filename) if not filename.endswith(('.h5', '.hdf5')): - msg = 'Unable to open "{0}" which is not an HDF5 summary file' + msg = f'Unable to open "{filename}" which is not an HDF5 summary file' raise ValueError(msg) self._f = h5py.File(filename, 'r') @@ -123,7 +129,9 @@ def _read_materials(self): def _read_surfaces(self): for group in self._f['geometry/surfaces'].values(): surface = openmc.Surface.from_hdf5(group) - self._fast_surfaces[surface.id] = surface + # surface may be None for DAGMC surfaces + if surface: + self._fast_surfaces[surface.id] = surface def _read_cells(self): @@ -176,7 +184,11 @@ def _read_cells(self): def _read_universes(self): for group in self._f['geometry/universes'].values(): - universe = openmc.Universe.from_hdf5(group, self._fast_cells) + geom_type = group.get('geom_type') + if geom_type and geom_type[()].decode() == 'dagmc': + universe = openmc.DAGMCUniverse.from_hdf5(group) + else: + universe = openmc.Universe.from_hdf5(group, self._fast_cells) self._fast_universes[universe.id] = universe def _read_lattices(self): @@ -228,4 +240,9 @@ def add_volume_information(self, volume_calc): Results from a stochastic volume calculation """ - self.geometry.add_volume_information(volume_calc) + if volume_calc.domain_type == "material" and self.materials: + for material in self.materials: + if material.id in volume_calc.volumes: + material.add_volume_information(volume_calc) + else: + self.geometry.add_volume_information(volume_calc) diff --git a/openmc/surface.py b/openmc/surface.py index d71e73788ef..806331024e2 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -1,20 +1,21 @@ from abc import ABC, abstractmethod -from collections import OrderedDict from collections.abc import Iterable from copy import deepcopy import math from numbers import Real -from xml.etree import ElementTree as ET from warnings import warn, catch_warnings, simplefilter +import lxml.etree as ET import numpy as np -from .checkvalue import check_type, check_value, check_length +from .checkvalue import check_type, check_value, check_length, check_greater_than from .mixin import IDManagerMixin, IDWarning from .region import Region, Intersection, Union +from .bounding_box import BoundingBox _BOUNDARY_TYPES = ['transmission', 'vacuum', 'reflective', 'periodic', 'white'] +_ALBEDO_BOUNDARIES = ['reflective', 'periodic', 'white'] _WARNING_UPPER = """\ "{}(...) accepts an argument named '{}', not '{}'. Future versions of OpenMC \ @@ -52,7 +53,7 @@ def __get__(self, instance, owner=None): def __set__(self, instance, value): if isinstance(self.value, Real): raise AttributeError('This coefficient is read-only') - check_type('{} coefficient'.format(self.value), value, Real) + check_type(f'{self.value} coefficient', value, Real) instance._coefficients[self.value] = value @@ -123,6 +124,10 @@ class Surface(IDManagerMixin, ABC): freely pass through the surface. Note that periodic boundary conditions can only be applied to x-, y-, and z-planes, and only axis-aligned periodicity is supported. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the surface. If not specified, the name will be the empty string. @@ -132,6 +137,8 @@ class Surface(IDManagerMixin, ABC): boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -147,10 +154,12 @@ class Surface(IDManagerMixin, ABC): used_ids = set() _atol = 1.e-12 - def __init__(self, surface_id=None, boundary_type='transmission', name=''): + def __init__(self, surface_id=None, boundary_type='transmission', + albedo=1., name=''): self.id = surface_id self.name = name self.boundary_type = boundary_type + self.albedo = albedo # A dictionary of the quadratic surface coefficients # Key - coefficient name @@ -165,16 +174,20 @@ def __pos__(self): def __repr__(self): string = 'Surface\n' - string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) - string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) - string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type) - string += '{0: <16}{1}{2}\n'.format('\tBoundary', '=\t', self._boundary_type) - - coefficients = '{0: <16}'.format('\tCoefficients') + '\n' + string += '{0: <20}{1}{2}\n'.format('\tID', '=\t', self._id) + string += '{0: <20}{1}{2}\n'.format('\tName', '=\t', self._name) + string += '{0: <20}{1}{2}\n'.format('\tType', '=\t', self._type) + string += '{0: <20}{1}{2}\n'.format('\tBoundary', '=\t', + self._boundary_type) + if (self._boundary_type in _ALBEDO_BOUNDARIES and + not math.isclose(self._albedo, 1.0)): + string += '{0: <20}{1}{2}\n'.format('\tBoundary Albedo', '=\t', + self._albedo) + + coefficients = '{0: <20}'.format('\tCoefficients') + '\n' for coeff in self._coefficients: - coefficients += '{0: <16}{1}{2}\n'.format( - coeff, '=\t', self._coefficients[coeff]) + coefficients += f'{coeff: <20}=\t{self._coefficients[coeff]}\n' string += coefficients @@ -184,18 +197,6 @@ def __repr__(self): def name(self): return self._name - @property - def type(self): - return self._type - - @property - def boundary_type(self): - return self._boundary_type - - @property - def coefficients(self): - return self._coefficients - @name.setter def name(self, name): if name is not None: @@ -204,12 +205,34 @@ def name(self, name): else: self._name = '' + @property + def type(self): + return self._type + + @property + def boundary_type(self): + return self._boundary_type + @boundary_type.setter def boundary_type(self, boundary_type): check_type('boundary type', boundary_type, str) check_value('boundary type', boundary_type, _BOUNDARY_TYPES) self._boundary_type = boundary_type + @property + def albedo(self): + return self._albedo + + @albedo.setter + def albedo(self, albedo): + check_type('albedo', albedo, Real) + check_greater_than('albedo', albedo, 0.0) + self._albedo = float(albedo) + + @property + def coefficients(self): + return self._coefficients + def bounding_box(self, side): """Determine an axis-aligned bounding box. @@ -233,8 +256,7 @@ def bounding_box(self, side): desired half-space """ - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) + return BoundingBox.infinite() def clone(self, memo=None): """Create a copy of this surface with a new unique ID. @@ -255,7 +277,7 @@ def clone(self, memo=None): if memo is None: memo = {} - # If no nemoize'd clone exists, instantiate one + # If no memoize'd clone exists, instantiate one if self not in memo: clone = deepcopy(self) clone.id = None @@ -336,9 +358,9 @@ def translate(self, vector, inplace=False): ---------- vector : iterable of float Direction in which surface should be translated - inplace : boolean + inplace : bool Whether or not to return a new instance of this Surface or to - modify the coefficients of this Surface. Defaults to False + modify the coefficients of this Surface. Returns ------- @@ -374,7 +396,7 @@ def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False): :math:`\psi` about z. This corresponds to an x-y-z extrinsic rotation as well as a z-y'-x'' intrinsic rotation using Tait-Bryan angles :math:`(\phi, \theta, \psi)`. - inplace : boolean + inplace : bool Whether or not to return a new instance of Surface or to modify the coefficients of this Surface in place. Defaults to False. @@ -390,7 +412,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ @@ -403,6 +425,9 @@ def to_xml_element(self): element.set("type", self._type) if self.boundary_type != 'transmission': element.set("boundary", self.boundary_type) + if (self.boundary_type in _ALBEDO_BOUNDARIES and + not math.isclose(self.albedo, 1.0)): + element.set("albedo", str(self.albedo)) element.set("coeffs", ' '.join([str(self._coefficients.setdefault(key, 0.0)) for key in self._coeff_keys])) @@ -414,7 +439,7 @@ def from_xml_element(elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -428,10 +453,13 @@ def from_xml_element(elem): surf_type = elem.get('type') cls = _SURFACE_CLASSES[surf_type] - # Determine ID, boundary type, coefficients + # Determine ID, boundary type, boundary albedo, coefficients kwargs = {} kwargs['surface_id'] = int(elem.get('id')) kwargs['boundary_type'] = elem.get('boundary', 'transmission') + if kwargs['boundary_type'] in _ALBEDO_BOUNDARIES: + kwargs['albedo'] = float(elem.get('albedo', 1.0)) + kwargs['name'] = elem.get('name') coeffs = [float(x) for x in elem.get('coeffs').split()] kwargs.update(dict(zip(cls._coeff_keys, coeffs))) @@ -453,13 +481,24 @@ def from_hdf5(group): """ + # If this is a DAGMC surface, do nothing for now + geom_type = group.get('geom_type') + if geom_type and geom_type[()].decode() == 'dagmc': + return + surface_id = int(group.name.split('/')[-1].lstrip('surface ')) name = group['name'][()].decode() if 'name' in group else '' - surf_type = group['type'][()].decode() + bc = group['boundary_type'][()].decode() + if 'albedo' in group: + bc_alb = float(group['albedo'][()].decode()) + else: + bc_alb = 1.0 coeffs = group['coefficients'][...] - kwargs = {'boundary_type': bc, 'name': name, 'surface_id': surface_id} + kwargs = {'boundary_type': bc, 'albedo': bc_alb, 'name': name, + 'surface_id': surface_id} + surf_type = group['type'][()].decode() cls = _SURFACE_CLASSES[surf_type] return cls(*coeffs, **kwargs) @@ -532,7 +571,7 @@ def bounding_box(self, side): else: ur = np.array([v if not np.isnan(v) else np.inf for v in vals]) - return (ll, ur) + return BoundingBox(ll, ur) def evaluate(self, point): """Evaluate the surface equation at a given point. @@ -561,9 +600,9 @@ def translate(self, vector, inplace=False): ---------- vector : iterable of float Direction in which surface should be translated - inplace : boolean + inplace : bool Whether or not to return a new instance of a Plane or to modify the - coefficients of this plane. Defaults to False + coefficients of this plane. Returns ------- @@ -601,7 +640,9 @@ def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False): # Compute new rotated coefficients a, b, c a, b, c = Rmat @ [a, b, c] - kwargs = {'boundary_type': surf.boundary_type, 'name': surf.name} + kwargs = {'boundary_type': surf.boundary_type, + 'albedo': surf.albedo, + 'name': surf.name} if inplace: kwargs['surface_id'] = surf.id @@ -614,7 +655,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ @@ -641,10 +682,14 @@ class Plane(PlaneMixin, Surface): The 'C' parameter for the plane. Defaults to 0. d : float, optional The 'D' parameter for the plane. Defaults to 0. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the plane. If not specified, the name will be the empty string. surface_id : int, optional @@ -661,9 +706,11 @@ class Plane(PlaneMixin, Surface): The 'C' parameter for the plane d : float The 'D' parameter for the plane - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight periodic_surface : openmc.Surface If a periodic boundary condition is used, the surface with which this one is periodic with @@ -730,16 +777,25 @@ def from_points(cls, p1, p2, p3, **kwargs): Plane Plane that passes through the three points + Raises + ------ + ValueError + If all three points lie along a line + """ # Convert to numpy arrays - p1 = np.asarray(p1) - p2 = np.asarray(p2) - p3 = np.asarray(p3) + p1 = np.asarray(p1, dtype=float) + p2 = np.asarray(p2, dtype=float) + p3 = np.asarray(p3, dtype=float) # Find normal vector to plane by taking cross product of two vectors # connecting p1->p2 and p1->p3 n = np.cross(p2 - p1, p3 - p1) + # Check for points along a line + if np.allclose(n, 0.): + raise ValueError("All three points appear to lie along a line.") + # The equation of the plane will by n·( - p1) = 0. Determine # coefficients a, b, c, and d based on that a, b, c = n @@ -753,12 +809,16 @@ class XPlane(PlaneMixin, Surface): Parameters ---------- x0 : float, optional - Location of the plane. Defaults to 0. + Location of the plane in [cm]. Defaults to 0. boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. Only axis-aligned periodicity is supported, i.e., x-planes can only be paired with x-planes. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the plane. If not specified, the name will be the empty string. surface_id : int, optional @@ -768,10 +828,12 @@ class XPlane(PlaneMixin, Surface): Attributes ---------- x0 : float - Location of the plane + Location of the plane in [cm] boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight periodic_surface : openmc.Surface If a periodic boundary condition is used, the surface with which this one is periodic with @@ -812,12 +874,16 @@ class YPlane(PlaneMixin, Surface): Parameters ---------- y0 : float, optional - Location of the plane + Location of the plane in [cm] boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. Only axis-aligned periodicity is - supported, i.e., x-planes can only be paired with x-planes. + supported, i.e., y-planes can only be paired with y-planes. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the plane. If not specified, the name will be the empty string. surface_id : int, optional @@ -827,10 +893,12 @@ class YPlane(PlaneMixin, Surface): Attributes ---------- y0 : float - Location of the plane + Location of the plane in [cm] boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight periodic_surface : openmc.Surface If a periodic boundary condition is used, the surface with which this one is periodic with @@ -871,12 +939,16 @@ class ZPlane(PlaneMixin, Surface): Parameters ---------- z0 : float, optional - Location of the plane. Defaults to 0. + Location of the plane in [cm]. Defaults to 0. boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. Only axis-aligned periodicity is - supported, i.e., x-planes can only be paired with x-planes. + supported, i.e., z-planes can only be paired with z-planes. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the plane. If not specified, the name will be the empty string. surface_id : int, optional @@ -886,10 +958,12 @@ class ZPlane(PlaneMixin, Surface): Attributes ---------- z0 : float - Location of the plane + Location of the plane in [cm] boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight periodic_surface : openmc.Surface If a periodic boundary condition is used, the surface with which this one is periodic with @@ -984,8 +1058,8 @@ def evaluate(self, point): Parameters ---------- point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. + The Cartesian coordinates, :math:`(x',y',z')`, in [cm] at which the + surface equation should be evaluated. Returns ------- @@ -1005,9 +1079,8 @@ def translate(self, vector, inplace=False): ---------- vector : iterable of float Direction in which surface should be translated - inplace : boolean + inplace : bool Whether to return a clone of the Surface or the Surface itself. - Defaults to False Returns ------- @@ -1046,7 +1119,7 @@ def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False): pivot = np.asarray(pivot) rotation = np.asarray(rotation, dtype=float) - # Allow rotaiton matrix to be passed in directly, otherwise build it + # Allow rotation matrix to be passed in directly, otherwise build it if rotation.ndim == 2: check_length('surface rotation', rotation.ravel(), 9) Rmat = rotation @@ -1062,7 +1135,8 @@ def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False): else: base_cls = type(tsurf)._virtual_base # Copy necessary surface attributes to new kwargs dictionary - kwargs = {'boundary_type': tsurf.boundary_type, 'name': tsurf.name} + kwargs = {'boundary_type': tsurf.boundary_type, + 'albedo': tsurf.albedo, 'name': tsurf.name} if inplace: kwargs['surface_id'] = tsurf.id kwargs.update({k: getattr(tsurf, k) for k in base_cls._coeff_keys}) @@ -1099,13 +1173,13 @@ class Cylinder(QuadricMixin, Surface): Parameters ---------- x0 : float, optional - x-coordinate for the origin of the Cylinder. Defaults to 0 + x-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 y0 : float, optional - y-coordinate for the origin of the Cylinder. Defaults to 0 + y-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 z0 : float, optional - z-coordinate for the origin of the Cylinder. Defaults to 0 + z-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 r : float, optional - Radius of the cylinder. Defaults to 1. + Radius of the cylinder in [cm]. Defaults to 1. dx : float, optional x-component of the vector representing the axis of the cylinder. Defaults to 0. @@ -1119,6 +1193,10 @@ class Cylinder(QuadricMixin, Surface): Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cylinder. If not specified, the name will be the empty string. @@ -1129,13 +1207,13 @@ class Cylinder(QuadricMixin, Surface): Attributes ---------- x0 : float - x-coordinate for the origin of the Cylinder + x-coordinate for the origin of the Cylinder in [cm] y0 : float - y-coordinate for the origin of the Cylinder + y-coordinate for the origin of the Cylinder in [cm] z0 : float - z-coordinate for the origin of the Cylinder + z-coordinate for the origin of the Cylinder in [cm] r : float - Radius of the cylinder + Radius of the cylinder in [cm] dx : float x-component of the vector representing the axis of the cylinder dy : float @@ -1145,6 +1223,8 @@ class Cylinder(QuadricMixin, Surface): boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1187,11 +1267,9 @@ def bounding_box(self, side): else -np.inf for xi, dxi in zip(self._origin, self._axis)] ur = [xi + r if np.isclose(dxi, 0., rtol=0., atol=self._atol) else np.inf for xi, dxi in zip(self._origin, self._axis)] - return (np.array(ll), np.array(ur)) - + return BoundingBox(np.array(ll), np.array(ur)) elif side == '+': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) + return BoundingBox.infinite() def _get_base_coeffs(self): # Get x, y, z coordinates of two points @@ -1234,9 +1312,9 @@ def from_points(cls, p1, p2, r=1., **kwargs): Parameters ---------- p1, p2 : 3-tuples - Points that pass through the plane, p1 will be used as (x0, y0, z0) + Points that pass through the cylinder axis. r : float, optional - Radius of the cylinder. Defaults to 1. + Radius of the cylinder in [cm]. Defaults to 1. kwargs : dict Keyword arguments passed to the :class:`Cylinder` constructor @@ -1260,7 +1338,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ @@ -1268,8 +1346,8 @@ def to_xml_element(self): # since the C++ layer doesn't support Cylinders right now with catch_warnings(): simplefilter('ignore', IDWarning) - kwargs = {'boundary_type': self.boundary_type, 'name': self.name, - 'surface_id': self.id} + kwargs = {'boundary_type': self.boundary_type, 'albedo': self.albedo, + 'name': self.name, 'surface_id': self.id} quad_rep = Quadric(*self._get_base_coeffs(), **kwargs) return quad_rep.to_xml_element() @@ -1281,15 +1359,19 @@ class XCylinder(QuadricMixin, Surface): Parameters ---------- y0 : float, optional - y-coordinate for the origin of the Cylinder. Defaults to 0 + y-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 z0 : float, optional - z-coordinate for the origin of the Cylinder. Defaults to 0 + z-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 r : float, optional - Radius of the cylinder. Defaults to 1. + Radius of the cylinder in [cm]. Defaults to 1. boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cylinder. If not specified, the name will be the empty string. @@ -1300,14 +1382,16 @@ class XCylinder(QuadricMixin, Surface): Attributes ---------- y0 : float - y-coordinate for the origin of the Cylinder + y-coordinate for the origin of the Cylinder in [cm] z0 : float - z-coordinate for the origin of the Cylinder + z-coordinate for the origin of the Cylinder in [cm] r : float - Radius of the cylinder + Radius of the cylinder in [cm] boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1353,11 +1437,12 @@ def _get_base_coeffs(self): def bounding_box(self, side): if side == '-': - return (np.array([-np.inf, self.y0 - self.r, self.z0 - self.r]), - np.array([np.inf, self.y0 + self.r, self.z0 + self.r])) + return BoundingBox( + np.array([-np.inf, self.y0 - self.r, self.z0 - self.r]), + np.array([np.inf, self.y0 + self.r, self.z0 + self.r]) + ) elif side == '+': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) + return BoundingBox.infinite() def evaluate(self, point): y = point[1] - self.y0 @@ -1372,15 +1457,19 @@ class YCylinder(QuadricMixin, Surface): Parameters ---------- x0 : float, optional - x-coordinate for the origin of the Cylinder. Defaults to 0 + x-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 z0 : float, optional - z-coordinate for the origin of the Cylinder. Defaults to 0 + z-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 r : float, optional - Radius of the cylinder. Defaults to 1. + Radius of the cylinder in [cm]. Defaults to 1. boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cylinder. If not specified, the name will be the empty string. @@ -1391,14 +1480,16 @@ class YCylinder(QuadricMixin, Surface): Attributes ---------- x0 : float - x-coordinate for the origin of the Cylinder + x-coordinate for the origin of the Cylinder in [cm] z0 : float - z-coordinate for the origin of the Cylinder + z-coordinate for the origin of the Cylinder in [cm] r : float - Radius of the cylinder + Radius of the cylinder in [cm] boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1444,11 +1535,12 @@ def _get_base_coeffs(self): def bounding_box(self, side): if side == '-': - return (np.array([self.x0 - self.r, -np.inf, self.z0 - self.r]), - np.array([self.x0 + self.r, np.inf, self.z0 + self.r])) + return BoundingBox( + np.array([self.x0 - self.r, -np.inf, self.z0 - self.r]), + np.array([self.x0 + self.r, np.inf, self.z0 + self.r]) + ) elif side == '+': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) + return BoundingBox.infinite() def evaluate(self, point): x = point[0] - self.x0 @@ -1463,15 +1555,19 @@ class ZCylinder(QuadricMixin, Surface): Parameters ---------- x0 : float, optional - x-coordinate for the origin of the Cylinder. Defaults to 0 + x-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 y0 : float, optional - y-coordinate for the origin of the Cylinder. Defaults to 0 + y-coordinate for the origin of the Cylinder in [cm]. Defaults to 0 r : float, optional - Radius of the cylinder. Defaults to 1. + Radius of the cylinder in [cm]. Defaults to 1. boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cylinder. If not specified, the name will be the empty string. @@ -1482,14 +1578,16 @@ class ZCylinder(QuadricMixin, Surface): Attributes ---------- x0 : float - x-coordinate for the origin of the Cylinder + x-coordinate for the origin of the Cylinder in [cm] y0 : float - y-coordinate for the origin of the Cylinder + y-coordinate for the origin of the Cylinder in [cm] r : float - Radius of the cylinder + Radius of the cylinder in [cm] boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1535,11 +1633,12 @@ def _get_base_coeffs(self): def bounding_box(self, side): if side == '-': - return (np.array([self.x0 - self.r, self.y0 - self.r, -np.inf]), - np.array([self.x0 + self.r, self.y0 + self.r, np.inf])) + return BoundingBox( + np.array([self.x0 - self.r, self.y0 - self.r, -np.inf]), + np.array([self.x0 + self.r, self.y0 + self.r, np.inf]) + ) elif side == '+': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) + return BoundingBox.infinite() def evaluate(self, point): x = point[0] - self.x0 @@ -1553,17 +1652,21 @@ class Sphere(QuadricMixin, Surface): Parameters ---------- x0 : float, optional - x-coordinate of the center of the sphere. Defaults to 0. + x-coordinate of the center of the sphere in [cm]. Defaults to 0. y0 : float, optional - y-coordinate of the center of the sphere. Defaults to 0. + y-coordinate of the center of the sphere in [cm]. Defaults to 0. z0 : float, optional - z-coordinate of the center of the sphere. Defaults to 0. + z-coordinate of the center of the sphere in [cm]. Defaults to 0. r : float, optional - Radius of the sphere. Defaults to 1. + Radius of the sphere in [cm]. Defaults to 1. boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the sphere. If not specified, the name will be the empty string. surface_id : int, optional @@ -1573,16 +1676,18 @@ class Sphere(QuadricMixin, Surface): Attributes ---------- x0 : float - x-coordinate of the center of the sphere + x-coordinate of the center of the sphere in [cm] y0 : float - y-coordinate of the center of the sphere + y-coordinate of the center of the sphere in [cm] z0 : float - z-coordinate of the center of the sphere + z-coordinate of the center of the sphere in [cm] r : float - Radius of the sphere + Radius of the sphere in [cm] boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1625,13 +1730,12 @@ def _get_base_coeffs(self): def bounding_box(self, side): if side == '-': - return (np.array([self.x0 - self.r, self.y0 - self.r, - self.z0 - self.r]), - np.array([self.x0 + self.r, self.y0 + self.r, - self.z0 + self.r])) + return BoundingBox( + np.array([self.x0 - self.r, self.y0 - self.r, self.z0 - self.r]), + np.array([self.x0 + self.r, self.y0 + self.r, self.z0 + self.r]) + ) elif side == '+': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) + return BoundingBox.infinite() def evaluate(self, point): x = point[0] - self.x0 @@ -1643,16 +1747,23 @@ def evaluate(self, point): class Cone(QuadricMixin, Surface): """A conical surface parallel to the x-, y-, or z-axis. + .. Note:: + This creates a double cone, which is two one-sided cones that meet at their apex. + For a one-sided cone see :class:`~openmc.model.XConeOneSided`, + :class:`~openmc.model.YConeOneSided`, and :class:`~openmc.model.ZConeOneSided`. + Parameters ---------- x0 : float, optional - x-coordinate of the apex. Defaults to 0. + x-coordinate of the apex in [cm]. Defaults to 0. y0 : float, optional - y-coordinate of the apex. Defaults to 0. + y-coordinate of the apex in [cm]. Defaults to 0. z0 : float, optional - z-coordinate of the apex. Defaults to 0. + z-coordinate of the apex in [cm]. Defaults to 0. r2 : float, optional - Parameter related to the aperature. Defaults to 1. + Parameter related to the aperture [:math:`\\rm cm^2`]. + It can be interpreted as the increase in the radius squared per cm along + the cone's axis of revolution. dx : float, optional x-component of the vector representing the axis of the cone. Defaults to 0. @@ -1669,19 +1780,24 @@ class Cone(QuadricMixin, Surface): Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. + name : str Name of the cone. If not specified, the name will be the empty string. Attributes ---------- x0 : float - x-coordinate of the apex + x-coordinate of the apex in [cm] y0 : float - y-coordinate of the apex + y-coordinate of the apex in [cm] z0 : float - z-coordinate of the apex + z-coordinate of the apex in [cm] r2 : float - Parameter related to the aperature + Parameter related to the aperature [cm^2] dx : float x-component of the vector representing the axis of the cone. dy : float @@ -1691,6 +1807,8 @@ class Cone(QuadricMixin, Surface): boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1739,7 +1857,7 @@ def _get_base_coeffs(self): # # (d*(r - p))^2 - (r - p)*(r - p)cos^2(theta) = 0 # - # where * is the dot product and the vector r is the evaulation point + # where * is the dot product and the vector r is the evaluation point # r = (x, y, z) # # The argument r2 for cones is actually tan^2(theta) so that @@ -1768,7 +1886,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ @@ -1776,7 +1894,9 @@ def to_xml_element(self): # since the C++ layer doesn't support Cones right now with catch_warnings(): simplefilter('ignore', IDWarning) - kwargs = {'boundary_type': self.boundary_type, 'name': self.name, + kwargs = {'boundary_type': self.boundary_type, + 'albedo': self.albedo, + 'name': self.name, 'surface_id': self.id} quad_rep = Quadric(*self._get_base_coeffs(), **kwargs) return quad_rep.to_xml_element() @@ -1786,20 +1906,30 @@ class XCone(QuadricMixin, Surface): """A cone parallel to the x-axis of the form :math:`(y - y_0)^2 + (z - z_0)^2 = r^2 (x - x_0)^2`. + .. Note:: + This creates a double cone, which is two one-sided cones that meet at their apex. + For a one-sided cone see :class:`~openmc.model.XConeOneSided`. + Parameters ---------- x0 : float, optional - x-coordinate of the apex. Defaults to 0. + x-coordinate of the apex in [cm]. Defaults to 0. y0 : float, optional - y-coordinate of the apex. Defaults to 0. + y-coordinate of the apex in [cm]. Defaults to 0. z0 : float, optional - z-coordinate of the apex. Defaults to 0. + z-coordinate of the apex in [cm]. Defaults to 0. r2 : float, optional - Parameter related to the aperature. Defaults to 1. + Parameter related to the aperture [:math:`\\rm cm^2`]. + It can be interpreted as the increase in the radius squared per cm along + the cone's axis of revolution. boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cone. If not specified, the name will be the empty string. surface_id : int, optional @@ -1809,16 +1939,18 @@ class XCone(QuadricMixin, Surface): Attributes ---------- x0 : float - x-coordinate of the apex + x-coordinate of the apex in [cm] y0 : float - y-coordinate of the apex + y-coordinate of the apex in [cm] z0 : float - z-coordinate of the apex + z-coordinate of the apex in [cm] r2 : float Parameter related to the aperature boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1875,20 +2007,30 @@ class YCone(QuadricMixin, Surface): """A cone parallel to the y-axis of the form :math:`(x - x_0)^2 + (z - z_0)^2 = r^2 (y - y_0)^2`. + .. Note:: + This creates a double cone, which is two one-sided cones that meet at their apex. + For a one-sided cone see :class:`~openmc.model.YConeOneSided`. + Parameters ---------- x0 : float, optional - x-coordinate of the apex. Defaults to 0. + x-coordinate of the apex in [cm]. Defaults to 0. y0 : float, optional - y-coordinate of the apex. Defaults to 0. + y-coordinate of the apex in [cm]. Defaults to 0. z0 : float, optional - z-coordinate of the apex. Defaults to 0. + z-coordinate of the apex in [cm]. Defaults to 0. r2 : float, optional - Parameter related to the aperature. Defaults to 1. + Parameter related to the aperture [:math:`\\rm cm^2`]. + It can be interpreted as the increase in the radius squared per cm along + the cone's axis of revolution. boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cone. If not specified, the name will be the empty string. surface_id : int, optional @@ -1898,16 +2040,18 @@ class YCone(QuadricMixin, Surface): Attributes ---------- x0 : float - x-coordinate of the apex + x-coordinate of the apex in [cm] y0 : float - y-coordinate of the apex + y-coordinate of the apex in [cm] z0 : float - z-coordinate of the apex + z-coordinate of the apex in [cm] r2 : float Parameter related to the aperature boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -1961,23 +2105,33 @@ def evaluate(self, point): class ZCone(QuadricMixin, Surface): - """A cone parallel to the x-axis of the form :math:`(x - x_0)^2 + (y - y_0)^2 = + """A cone parallel to the z-axis of the form :math:`(x - x_0)^2 + (y - y_0)^2 = r^2 (z - z_0)^2`. + .. Note:: + This creates a double cone, which is two one-sided cones that meet at their apex. + For a one-sided cone see :class:`~openmc.model.ZConeOneSided`. + Parameters ---------- x0 : float, optional - x-coordinate of the apex. Defaults to 0. + x-coordinate of the apex in [cm]. Defaults to 0. y0 : float, optional - y-coordinate of the apex. Defaults to 0. + y-coordinate of the apex in [cm]. Defaults to 0. z0 : float, optional - z-coordinate of the apex. Defaults to 0. + z-coordinate of the apex in [cm]. Defaults to 0. r2 : float, optional - Parameter related to the aperature. Defaults to 1. + Parameter related to the aperature [cm^2]. + This is the square of the radius of the cone 1 cm from. + This can also be treated as the square of the slope of the cone relative to its axis. boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the cone. If not specified, the name will be the empty string. surface_id : int, optional @@ -1987,16 +2141,18 @@ class ZCone(QuadricMixin, Surface): Attributes ---------- x0 : float - x-coordinate of the apex + x-coordinate of the apex in [cm] y0 : float - y-coordinate of the apex + y-coordinate of the apex in [cm] z0 : float - z-coordinate of the apex + z-coordinate of the apex in [cm] r2 : float Parameter related to the aperature boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -2057,10 +2213,14 @@ class Quadric(QuadricMixin, Surface): ---------- a, b, c, d, e, f, g, h, j, k : float, optional coefficients for the surface. All default to 0. - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional Boundary condition that defines the behavior for particles hitting the surface. Defaults to transmissive boundary condition where particles freely pass through the surface. + albedo : float, optional + Albedo of the surfaces as a ratio of particle weight after interaction + with the surface to the initial weight. Values must be positive. Only + applicable if the boundary type is 'reflective', 'periodic', or 'white'. name : str, optional Name of the surface. If not specified, the name will be the empty string. surface_id : int, optional @@ -2071,9 +2231,11 @@ class Quadric(QuadricMixin, Surface): ---------- a, b, c, d, e, f, g, h, j, k : float coefficients for the surface - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} Boundary condition that defines the behavior for particles hitting the surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight coefficients : dict Dictionary of surface coefficients id : int @@ -2111,6 +2273,304 @@ def _get_base_coeffs(self): return tuple(getattr(self, c) for c in self._coeff_keys) +class TorusMixin: + """A Mixin class implementing common functionality for torus surfaces""" + _coeff_keys = ('x0', 'y0', 'z0', 'a', 'b', 'c') + + def __init__(self, x0=0., y0=0., z0=0., a=0., b=0., c=0., **kwargs): + super().__init__(**kwargs) + for key, val in zip(self._coeff_keys, (x0, y0, z0, a, b, c)): + setattr(self, key, val) + + x0 = SurfaceCoefficient('x0') + y0 = SurfaceCoefficient('y0') + z0 = SurfaceCoefficient('z0') + a = SurfaceCoefficient('a') + b = SurfaceCoefficient('b') + c = SurfaceCoefficient('c') + + def translate(self, vector, inplace=False): + surf = self if inplace else self.clone() + surf.x0 += vector[0] + surf.y0 += vector[1] + surf.z0 += vector[2] + return surf + + def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False): + pivot = np.asarray(pivot) + rotation = np.asarray(rotation, dtype=float) + + # Allow rotation matrix to be passed in directly, otherwise build it + if rotation.ndim == 2: + check_length('surface rotation', rotation.ravel(), 9) + Rmat = rotation + else: + Rmat = get_rotation_matrix(rotation, order=order) + + # Only can handle trivial rotation matrices + close = np.isclose + if not np.all(close(Rmat, -1.0) | close(Rmat, 0.0) | close(Rmat, 1.0)): + raise NotImplementedError('Torus surfaces cannot handle generic rotations') + + # Translate surface to pivot + surf = self.translate(-pivot, inplace=inplace) + + # Determine "center" of torus and a point above it (along main axis) + center = [surf.x0, surf.y0, surf.z0] + above_center = center.copy() + index = ['x-torus', 'y-torus', 'z-torus'].index(surf._type) + above_center[index] += 1 + + # Compute new rotated torus center + center = Rmat @ center + + # Figure out which axis should be used after rotation + above_center = Rmat @ above_center + new_index = np.where(np.isclose(np.abs(above_center - center), 1.0))[0][0] + cls = [XTorus, YTorus, ZTorus][new_index] + + # Create rotated torus + kwargs = { + 'boundary_type': surf.boundary_type, + 'albedo': surf.albedo, + 'name': surf.name, + 'a': surf.a, 'b': surf.b, 'c': surf.c + } + if inplace: + kwargs['surface_id'] = surf.id + surf = cls(x0=center[0], y0=center[1], z0=center[2], **kwargs) + + return surf.translate(pivot, inplace=inplace) + + def _get_base_coeffs(self): + raise NotImplementedError + + +class XTorus(TorusMixin, Surface): + r"""A torus of the form :math:`(x - x_0)^2/B^2 + (\sqrt{(y - y_0)^2 + (z - + z_0)^2} - A)^2/C^2 - 1 = 0`. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + x0 : float + x-coordinate of the center of the axis of revolution in [cm] + y0 : float + y-coordinate of the center of the axis of revolution in [cm] + z0 : float + z-coordinate of the center of the axis of revolution in [cm] + a : float + Major radius of the torus in [cm] + b : float + Minor radius of the torus in [cm] (parallel to axis of revolution) + c : float + Minor radius of the torus in [cm] (perpendicular to axis of revolution) + kwargs : dict + Keyword arguments passed to the :class:`Surface` constructor + + Attributes + ---------- + x0 : float + x-coordinate of the center of the axis of revolution in [cm] + y0 : float + y-coordinate of the center of the axis of revolution in [cm] + z0 : float + z-coordinate of the center of the axis of revolution in [cm] + a : float + Major radius of the torus in [cm] + b : float + Minor radius of the torus in [cm] (parallel to axis of revolution) + c : float + Minor radius of the torus in [cm] (perpendicular to axis of revolution) + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} + Boundary condition that defines the behavior for particles hitting the + surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight + coefficients : dict + Dictionary of surface coefficients + id : int + Unique identifier for the surface + name : str + Name of the surface + type : str + Type of the surface + + """ + _type = 'x-torus' + + def evaluate(self, point): + x = point[0] - self.x0 + y = point[1] - self.y0 + z = point[2] - self.z0 + a = self.a + b = self.b + c = self.c + return (x*x)/(b*b) + (math.sqrt(y*y + z*z) - a)**2/(c*c) - 1 + + def bounding_box(self, side): + x0, y0, z0 = self.x0, self.y0, self.z0 + a, b, c = self.a, self.b, self.c + if side == '-': + return BoundingBox( + np.array([x0 - b, y0 - a - c, z0 - a - c]), + np.array([x0 + b, y0 + a + c, z0 + a + c]) + ) + elif side == '+': + return BoundingBox.infinite() + + +class YTorus(TorusMixin, Surface): + r"""A torus of the form :math:`(y - y_0)^2/B^2 + (\sqrt{(x - x_0)^2 + (z - + z_0)^2} - A)^2/C^2 - 1 = 0`. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + x0 : float + x-coordinate of the center of the axis of revolution in [cm] + y0 : float + y-coordinate of the center of the axis of revolution in [cm] + z0 : float + z-coordinate of the center of the axis of revolution in [cm] + a : float + Major radius of the torus in [cm] + b : float + Minor radius of the torus in [cm] (parallel to axis of revolution) + c : float + Minor radius of the torus in [cm] (perpendicular to axis of revolution) + kwargs : dict + Keyword arguments passed to the :class:`Surface` constructor + + Attributes + ---------- + x0 : float + x-coordinate of the center of the axis of revolution in [cm] + y0 : float + y-coordinate of the center of the axis of revolution in [cm] + z0 : float + z-coordinate of the center of the axis of revolution in [cm] + a : float + Major radius of the torus in [cm] + b : float + Minor radius of the torus in [cm] (parallel to axis of revolution) + c : float + Minor radius of the torus (perpendicular to axis of revolution) + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} + Boundary condition that defines the behavior for particles hitting the + surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight + coefficients : dict + Dictionary of surface coefficients + id : int + Unique identifier for the surface + name : str + Name of the surface + type : str + Type of the surface + + """ + _type = 'y-torus' + + def evaluate(self, point): + x = point[0] - self.x0 + y = point[1] - self.y0 + z = point[2] - self.z0 + a = self.a + b = self.b + c = self.c + return (y*y)/(b*b) + (math.sqrt(x*x + z*z) - a)**2/(c*c) - 1 + + def bounding_box(self, side): + x0, y0, z0 = self.x0, self.y0, self.z0 + a, b, c = self.a, self.b, self.c + if side == '-': + return BoundingBox( + np.array([x0 - a - c, y0 - b, z0 - a - c]), + np.array([x0 + a + c, y0 + b, z0 + a + c]) + ) + elif side == '+': + return BoundingBox.infinite() + + +class ZTorus(TorusMixin, Surface): + r"""A torus of the form :math:`(z - z_0)^2/B^2 + (\sqrt{(x - x_0)^2 + (y - + y_0)^2} - A)^2/C^2 - 1 = 0`. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + x0 : float + x-coordinate of the center of the axis of revolution in [cm] + y0 : float + y-coordinate of the center of the axis of revolution in [cm] + z0 : float + z-coordinate of the center of the axis of revolution in [cm] + a : float + Major radius of the torus in [cm] + b : float + Minor radius of the torus in [cm] (parallel to axis of revolution) + c : float + Minor radius of the torus in [cm] (perpendicular to axis of revolution) + kwargs : dict + Keyword arguments passed to the :class:`Surface` constructor + + Attributes + ---------- + x0 : float + x-coordinate of the center of the axis of revolution in [cm] + y0 : float + y-coordinate of the center of the axis of revolution in [cm] + z0 : float + z-coordinate of the center of the axis of revolution in [cm] + a : float + Major radius of the torus in [cm] + b : float + Minor radius of the torus in [cm] (parallel to axis of revolution) + c : float + Minor radius of the torus in [cm] (perpendicular to axis of revolution) + boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} + Boundary condition that defines the behavior for particles hitting the + surface. + albedo : float + Boundary albedo as a positive multiplier of particle weight + coefficients : dict + Dictionary of surface coefficients + id : int + Unique identifier for the surface + name : str + Name of the surface + type : str + Type of the surface + """ + + _type = 'z-torus' + + def evaluate(self, point): + x = point[0] - self.x0 + y = point[1] - self.y0 + z = point[2] - self.z0 + a = self.a + b = self.b + c = self.c + return (z*z)/(b*b) + (math.sqrt(x*x + y*y) - a)**2/(c*c) - 1 + + def bounding_box(self, side): + x0, y0, z0 = self.x0, self.y0, self.z0 + a, b, c = self.a, self.b, self.c + if side == '-': + return BoundingBox( + np.array([x0 - a - c, y0 - a - c, z0 - b]), + np.array([x0 + a + c, y0 + a + c, z0 + b]) + ) + elif side == '+': + return BoundingBox.infinite() + + class Halfspace(Region): """A positive or negative half-space region. @@ -2143,7 +2603,7 @@ class Halfspace(Region): Surface which divides Euclidean space. side : {'+', '-'} Indicates whether the positive or negative half-space is used. - bounding_box : tuple of numpy.ndarray + bounding_box : openmc.BoundingBox Lower-left and upper-right coordinates of an axis-aligned bounding box """ @@ -2217,17 +2677,17 @@ def get_surfaces(self, surfaces=None): Parameters ---------- - surfaces: collections.OrderedDict, optional + surfaces : dict, optional Dictionary mapping surface IDs to :class:`openmc.Surface` instances Returns ------- - surfaces: collections.OrderedDict + surfaces : dict Dictionary mapping surface IDs to :class:`openmc.Surface` instances """ if surfaces is None: - surfaces = OrderedDict() + surfaces = {} surfaces[self.surface.id] = self.surface return surfaces @@ -2271,7 +2731,7 @@ def clone(self, memo=None): clone.surface = self.surface.clone(memo) return clone - def translate(self, vector, memo=None): + def translate(self, vector, inplace=False, memo=None): """Translate half-space in given direction Parameters @@ -2293,7 +2753,7 @@ def translate(self, vector, memo=None): # If translated surface not in memo, add it key = (self.surface, tuple(vector)) if key not in memo: - memo[key] = self.surface.translate(vector) + memo[key] = self.surface.translate(vector, inplace) # Return translated half-space return type(self)(memo[key], self.side) @@ -2325,7 +2785,7 @@ def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False, :math:`\psi` about z. This corresponds to an x-y-z extrinsic rotation as well as a z-y'-x'' intrinsic rotation using Tait-Bryan angles :math:`(\phi, \theta, \psi)`. - inplace : boolean + inplace : bool Whether or not to return a new instance of Surface or to modify the coefficients of this Surface in place. Defaults to False. memo : dict or None @@ -2341,7 +2801,7 @@ def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False, memo = {} # If rotated surface not in memo, add it - key = (self.surface, tuple(rotation), tuple(pivot), order, inplace) + key = (self.surface, tuple(np.ravel(rotation)), tuple(pivot), order, inplace) if key not in memo: memo[key] = self.surface.rotate(rotation, pivot=pivot, order=order, inplace=inplace) @@ -2353,7 +2813,7 @@ def rotate(self, rotation, pivot=(0., 0., 0.), order='xyz', inplace=False, _SURFACE_CLASSES = {cls._type: cls for cls in Surface.__subclasses__()} -# Set virtual base classes for "casting" up the heirarchy +# Set virtual base classes for "casting" up the hierarchy Plane._virtual_base = Plane XPlane._virtual_base = Plane YPlane._virtual_base = Plane diff --git a/openmc/tallies.py b/openmc/tallies.py index 048bd99513c..04ae00b6a32 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -5,7 +5,7 @@ from numbers import Integral, Real import operator from pathlib import Path -from xml.etree import ElementTree as ET +import lxml.etree as ET import h5py import numpy as np @@ -14,8 +14,9 @@ import openmc import openmc.checkvalue as cv -from ._xml import clean_indentation, reorder_attributes +from ._xml import clean_indentation, reorder_attributes, get_text from .mixin import IDManagerMixin +from .mesh import MeshBase # The tally arithmetic product types. The tensor product performs the full @@ -53,9 +54,13 @@ class Tally(IDManagerMixin): Unique identifier for the tally name : str Name of the tally + multiply_density : bool + Whether reaction rates should be multiplied by atom density + + .. versionadded:: 0.14.0 filters : list of openmc.Filter List of specified filters for the tally - nuclides : list of openmc.Nuclide + nuclides : list of str List of nuclides to score results for scores : list of str List of defined scores, e.g. 'flux', 'fission', etc. @@ -110,6 +115,7 @@ def __init__(self, tally_id=None, name=''): self._estimator = None self._triggers = cv.CheckedList(openmc.Trigger, 'tally triggers') self._derivative = None + self._multiply_density = True self._num_realizations = 0 self._with_summary = False @@ -137,20 +143,68 @@ def __repr__(self): parts.append('{: <15}=\t{}'.format('Nuclides', nuclides)) parts.append('{: <15}=\t{}'.format('Scores', self.scores)) parts.append('{: <15}=\t{}'.format('Estimator', self.estimator)) + parts.append('{: <15}=\t{}'.format('Multiply dens.', self.multiply_density)) return '\n\t'.join(parts) @property def name(self): return self._name + @name.setter + def name(self, name): + cv.check_type('tally name', name, str, none_ok=True) + self._name = name + + @property + def multiply_density(self): + return self._multiply_density + + @multiply_density.setter + def multiply_density(self, value): + cv.check_type('multiply density', value, bool) + self._multiply_density = value + @property def filters(self): return self._filters + @filters.setter + def filters(self, filters): + cv.check_type('tally filters', filters, MutableSequence) + + # If the filter is already in the Tally, raise an error + visited_filters = set() + for f in filters: + if f in visited_filters: + msg = (f'Unable to add a duplicate filter "{f}" to Tally ' + f'ID="{self.id}" since duplicate filters are not ' + 'supported in the OpenMC Python API') + raise ValueError(msg) + visited_filters.add(f) + + self._filters = cv.CheckedList(_FILTER_CLASSES, 'tally filters', filters) + @property def nuclides(self): return self._nuclides + @nuclides.setter + def nuclides(self, nuclides): + cv.check_type('tally nuclides', nuclides, MutableSequence) + + # If the nuclide is already in the Tally, raise an error + visited_nuclides = set() + for nuc in nuclides: + if nuc in visited_nuclides: + msg = (f'Unable to add a duplicate nuclide "{nuc}" to Tally ID=' + f'"{self.id}" since duplicate nuclides are not supported ' + 'in the OpenMC Python API') + raise ValueError(msg) + visited_nuclides.add(nuc) + + self._nuclides = cv.CheckedList(_NUCLIDE_CLASSES, 'tally nuclides', + nuclides) + @property def num_nuclides(self): return len(self._nuclides) @@ -159,6 +213,33 @@ def num_nuclides(self): def scores(self): return self._scores + @scores.setter + def scores(self, scores): + cv.check_type('tally scores', scores, MutableSequence) + + visited_scores = set() + for i, score in enumerate(scores): + # If the score is already in the Tally, raise an error + if score in visited_scores: + msg = (f'Unable to add a duplicate score "{score}" to Tally ' + f'ID="{self.id}" since duplicate scores are not ' + 'supported in the OpenMC Python API') + raise ValueError(msg) + visited_scores.add(score) + + # If score is a string, strip whitespace + if isinstance(score, str): + # Check to see if scores are deprecated before storing + for deprecated in ['scatter-', 'nu-scatter-', 'scatter-p', + 'nu-scatter-p', 'scatter-y', 'nu-scatter-y', + 'flux-y', 'total-y']: + if score.strip().startswith(deprecated): + msg = score.strip() + ' is no longer supported.' + raise ValueError(msg) + scores[i] = score.strip() + + self._scores = cv.CheckedList(_SCORE_CLASSES, 'tally scores', scores) + @property def num_scores(self): return len(self._scores) @@ -183,18 +264,40 @@ def shape(self): def estimator(self): return self._estimator + @estimator.setter + def estimator(self, estimator): + cv.check_value('estimator', estimator, ESTIMATOR_TYPES) + self._estimator = estimator + @property def triggers(self): return self._triggers + @triggers.setter + def triggers(self, triggers): + cv.check_type('tally triggers', triggers, MutableSequence) + self._triggers = cv.CheckedList(openmc.Trigger, 'tally triggers', + triggers) + @property def num_realizations(self): return self._num_realizations + @num_realizations.setter + def num_realizations(self, num_realizations): + cv.check_type('number of realizations', num_realizations, Integral) + cv.check_greater_than('number of realizations', num_realizations, 0, True) + self._num_realizations = num_realizations + @property def with_summary(self): return self._with_summary + @with_summary.setter + def with_summary(self, with_summary): + cv.check_type('with_summary', with_summary, bool) + self._with_summary = with_summary + def _read_results(self): if self._results_read: return @@ -202,7 +305,7 @@ def _read_results(self): # Open the HDF5 statepoint file with h5py.File(self._sp_filename, 'r') as f: # Extract Tally data from the file - data = f['tallies/tally {}/results'.format(self.id)] + data = f[f'tallies/tally {self.id}/results'] sum_ = data[:, :, 0] sum_sq = data[:, :, 1] @@ -235,6 +338,11 @@ def sum(self): else: return self._sum + @sum.setter + def sum(self, sum): + cv.check_type('sum', sum, Iterable) + self._sum = sum + @property def sum_sq(self): if not self._sp_filename or self.derived: @@ -248,6 +356,11 @@ def sum_sq(self): else: return self._sum_sq + @sum_sq.setter + def sum_sq(self, sum_sq): + cv.check_type('sum_sq', sum_sq, Iterable) + self._sum_sq = sum_sq + @property def mean(self): if self._mean is None: @@ -294,6 +407,11 @@ def std_dev(self): def with_batch_statistics(self): return self._with_batch_statistics + @with_batch_statistics.setter + def with_batch_statistics(self, with_batch_statistics): + cv.check_type('with_batch_statistics', with_batch_statistics, bool) + self._with_batch_statistics = with_batch_statistics + @property def derived(self): return self._derived @@ -302,117 +420,15 @@ def derived(self): def derivative(self): return self._derivative - @property - def sparse(self): - return self._sparse - - @estimator.setter - def estimator(self, estimator): - cv.check_value('estimator', estimator, ESTIMATOR_TYPES) - self._estimator = estimator - - @triggers.setter - def triggers(self, triggers): - cv.check_type('tally triggers', triggers, MutableSequence) - self._triggers = cv.CheckedList(openmc.Trigger, 'tally triggers', - triggers) - - @name.setter - def name(self, name): - cv.check_type('tally name', name, str, none_ok=True) - self._name = name - @derivative.setter def derivative(self, deriv): cv.check_type('tally derivative', deriv, openmc.TallyDerivative, none_ok=True) self._derivative = deriv - @filters.setter - def filters(self, filters): - cv.check_type('tally filters', filters, MutableSequence) - - # If the filter is already in the Tally, raise an error - visited_filters = set() - for f in filters: - if f in visited_filters: - msg = 'Unable to add a duplicate filter "{}" to Tally ID="{}" ' \ - 'since duplicate filters are not supported in the OpenMC ' \ - 'Python API'.format(f, self.id) - raise ValueError(msg) - visited_filters.add(f) - - self._filters = cv.CheckedList(_FILTER_CLASSES, 'tally filters', filters) - - @nuclides.setter - def nuclides(self, nuclides): - cv.check_type('tally nuclides', nuclides, MutableSequence) - - # If the nuclide is already in the Tally, raise an error - visited_nuclides = set() - for nuc in nuclides: - if nuc in visited_nuclides: - msg = 'Unable to add a duplicate nuclide "{}" to Tally ID="{}" ' \ - 'since duplicate nuclides are not supported in the OpenMC ' \ - 'Python API'.format(nuc, self.id) - raise ValueError(msg) - visited_nuclides.add(nuc) - - self._nuclides = cv.CheckedList(_NUCLIDE_CLASSES, 'tally nuclides', - nuclides) - - @scores.setter - def scores(self, scores): - cv.check_type('tally scores', scores, MutableSequence) - - visited_scores = set() - for i, score in enumerate(scores): - # If the score is already in the Tally, raise an error - if score in visited_scores: - msg = 'Unable to add a duplicate score "{}" to Tally ID="{}" ' \ - 'since duplicate scores are not supported in the OpenMC ' \ - 'Python API'.format(score, self.id) - raise ValueError(msg) - visited_scores.add(score) - - # If score is a string, strip whitespace - if isinstance(score, str): - # Check to see if scores are deprecated before storing - for deprecated in ['scatter-', 'nu-scatter-', 'scatter-p', - 'nu-scatter-p', 'scatter-y', 'nu-scatter-y', - 'flux-y', 'total-y']: - if score.strip().startswith(deprecated): - msg = score.strip() + ' is no longer supported.' - raise ValueError(msg) - scores[i] = score.strip() - - self._scores = cv.CheckedList(_SCORE_CLASSES, 'tally scores', scores) - - @num_realizations.setter - def num_realizations(self, num_realizations): - cv.check_type('number of realizations', num_realizations, Integral) - cv.check_greater_than('number of realizations', num_realizations, 0, True) - self._num_realizations = num_realizations - - @with_summary.setter - def with_summary(self, with_summary): - cv.check_type('with_summary', with_summary, bool) - self._with_summary = with_summary - - @with_batch_statistics.setter - def with_batch_statistics(self, with_batch_statistics): - cv.check_type('with_batch_statistics', with_batch_statistics, bool) - self._with_batch_statistics = with_batch_statistics - - @sum.setter - def sum(self, sum): - cv.check_type('sum', sum, Iterable) - self._sum = sum - - @sum_sq.setter - def sum_sq(self, sum_sq): - cv.check_type('sum_sq', sum_sq, Iterable) - self._sum_sq = sum_sq + @property + def sparse(self): + return self._sparse @sparse.setter def sparse(self, sparse): @@ -467,8 +483,8 @@ def remove_score(self, score): """ if score not in self.scores: - msg = 'Unable to remove score "{}" from Tally ID="{}" since ' \ - 'the Tally does not contain this score'.format(score, self.id) + msg = f'Unable to remove score "{score}" from Tally ' \ + f'ID="{self.id}" since the Tally does not contain this score' raise ValueError(msg) self._scores.remove(score) @@ -484,8 +500,8 @@ def remove_filter(self, old_filter): """ if old_filter not in self.filters: - msg = 'Unable to remove filter "{}" from Tally ID="{}" since the ' \ - 'Tally does not contain this filter'.format(old_filter, self.id) + msg = f'Unable to remove filter "{old_filter}" from Tally ' \ + f'ID="{self.id}" since the Tally does not contain this filter' raise ValueError(msg) self._filters.remove(old_filter) @@ -501,8 +517,8 @@ def remove_nuclide(self, nuclide): """ if nuclide not in self.nuclides: - msg = 'Unable to remove nuclide "{}" from Tally ID="{}" since the ' \ - 'Tally does not contain this nuclide'.format(nuclide, self.id) + msg = f'Unable to remove nuclide "{nuclide}" from Tally ' \ + f'ID="{self.id}" since the Tally does not contain this nuclide' raise ValueError(msg) self._nuclides.remove(nuclide) @@ -684,8 +700,7 @@ def merge(self, other): """ if not self.can_merge(other): - msg = 'Unable to merge tally ID="{}" with "{}"'.format( - other.id, self.id) + msg = f'Unable to merge tally ID="{other.id}" with "{self.id}"' raise ValueError(msg) # Create deep copy of tally to return as merged tally @@ -815,7 +830,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing tally data """ @@ -829,6 +844,10 @@ def to_xml_element(self): if self.name != '': element.set("name", self.name) + # Multiply by density + if not self.multiply_density: + element.set("multiply_density", str(self.multiply_density).lower()) + # Optional Tally filters if len(self.filters) > 0: subelement = ET.SubElement(element, "filters") @@ -841,17 +860,12 @@ def to_xml_element(self): # Scores if len(self.scores) == 0: - msg = 'Unable to get XML for Tally ID="{}" since it does not ' \ - 'contain any scores'.format(self.id) + msg = f'Unable to get XML for Tally ID="{self.id}" since it does ' \ + 'not contain any scores' raise ValueError(msg) - else: - scores = '' - for score in self.scores: - scores += '{} '.format(score) - - subelement = ET.SubElement(element, "scores") - subelement.text = scores.rstrip(' ') + subelement = ET.SubElement(element, "scores") + subelement.text = ' '.join(str(x) for x in self.scores) # Tally estimator type if self.estimator is not None: @@ -860,7 +874,7 @@ def to_xml_element(self): # Optional Triggers for trigger in self.triggers: - trigger.get_trigger_xml(element) + element.append(trigger.to_xml_element()) # Optional derivatives if self.derivative is not None: @@ -869,6 +883,66 @@ def to_xml_element(self): return element + @classmethod + def from_xml_element(cls, elem, **kwargs): + """Generate tally object from an XML element + + .. versionadded:: 0.13.0 + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.Tally + Tally object + + """ + tally_id = int(elem.get('id')) + name = elem.get('name', '') + tally = cls(tally_id=tally_id, name=name) + + text = get_text(elem, 'multiply_density') + if text is not None: + tally.multiply_density = text in ('true', '1') + + # Read filters + filters_elem = elem.find('filters') + if filters_elem is not None: + filter_ids = [int(x) for x in filters_elem.text.split()] + tally.filters = [kwargs['filters'][uid] for uid in filter_ids] + + # Read nuclides + nuclides_elem = elem.find('nuclides') + if nuclides_elem is not None: + tally.nuclides = nuclides_elem.text.split() + + # Read scores + scores_elem = elem.find('scores') + if scores_elem is not None: + tally.scores = scores_elem.text.split() + + # Set estimator + estimator_elem = elem.find('estimator') + if estimator_elem is not None: + tally.estimator = estimator_elem.text + + # Read triggers + tally.triggers = [ + openmc.Trigger.from_xml_element(trigger_elem) + for trigger_elem in elem.findall('trigger') + ] + + # Read tally derivative + deriv_elem = elem.find('derivative') + if deriv_elem is not None: + deriv_id = int(deriv_elem.text) + tally.derivative = kwargs['derivatives'][deriv_id] + + return tally + def contains_filter(self, filter_type): """Looks for a filter in the tally that matches a specified type @@ -922,8 +996,8 @@ def find_filter(self, filter_type): return test_filter # If we did not find the Filter, throw an Exception - msg = 'Unable to find filter type "{}" in Tally ID="{}"'.format( - filter_type, self.id) + msg = f'Unable to find filter type "{filter_type}" in Tally ' \ + f'ID="{self.id}"' raise ValueError(msg) def get_nuclide_index(self, nuclide): @@ -958,8 +1032,8 @@ def get_nuclide_index(self, nuclide): if test_nuclide == nuclide: return i - msg = ('Unable to get the nuclide index for Tally since "{}" ' - 'is not one of the nuclides'.format(nuclide)) + msg = (f'Unable to get the nuclide index for Tally since "{nuclide}" ' + 'is not one of the nuclides') raise KeyError(msg) def get_score_index(self, score): @@ -987,8 +1061,8 @@ def get_score_index(self, score): score_index = self.scores.index(score) except ValueError: - msg = 'Unable to get the score index for Tally since "{}" ' \ - 'is not one of the scores'.format(score) + msg = f'Unable to get the score index for Tally since "{score}" ' \ + 'is not one of the scores' raise ValueError(msg) return score_index @@ -1042,23 +1116,11 @@ def get_filter_indices(self, filters=[], filter_bins=[]): for j, test_filter in enumerate(filters): if type(self_filter) is test_filter: bins = filter_bins[j] + indices = np.array([self_filter.get_bin_index(b) for b in bins]) break else: - # If not a user-requested Filter, get all bins - if isinstance(self_filter, openmc.DistribcellFilter): - # Create list of cell instance IDs for distribcell Filters - bins = list(range(self_filter.num_bins)) - - elif isinstance(self_filter, openmc.EnergyFunctionFilter): - # EnergyFunctionFilters don't have bins so just add a None - bins = [None] - - else: - # Create list of IDs for bins for all other filter types - bins = self_filter.bins + indices = np.arange(self_filter.num_bins) - # Add indices for each bin in this Filter to the list - indices = np.array([self_filter.get_bin_index(b) for b in bins]) filter_indices.append(indices) # Account for stride in each of the previous filters @@ -1122,9 +1184,9 @@ def get_score_indices(self, scores): for score in scores: if not isinstance(score, (str, openmc.CrossScore)): - msg = 'Unable to get score indices for score "{}" in Tally ' \ - 'ID="{}" since it is not a string or CrossScore'\ - .format(score, self.id) + msg = f'Unable to get score indices for score "{score}" in ' \ + f'ID="{self.id}" since it is not a string or CrossScore ' \ + 'Tally' raise ValueError(msg) # Determine the score indices from any of the requested scores @@ -1196,7 +1258,7 @@ def get_values(self, scores=[], filters=[], filter_bins=[], (value == 'rel_err' and self.mean is None) or \ (value == 'sum' and self.sum is None) or \ (value == 'sum_sq' and self.sum_sq is None): - msg = 'The Tally ID="{}" has no data to return'.format(self.id) + msg = f'The Tally ID="{self.id}" has no data to return' raise ValueError(msg) # Get filter, nuclide and score indices @@ -1219,9 +1281,9 @@ def get_values(self, scores=[], filters=[], filter_bins=[], elif value == 'sum_sq': data = self.sum_sq[indices] else: - msg = 'Unable to return results from Tally ID="{}" since the ' \ - 'the requested value "{}" is not \'mean\', \'std_dev\', ' \ - '\'rel_err\', \'sum\', or \'sum_sq\''.format(self.id, value) + msg = f'Unable to return results from Tally ID="{value}" since ' \ + f'the requested value "{self.id}" is not \'mean\', ' \ + '\'std_dev\', \'rel_err\', \'sum\', or \'sum_sq\'' raise LookupError(msg) return data @@ -1272,7 +1334,7 @@ def get_pandas_dataframe(self, filters=True, nuclides=True, scores=True, # Ensure that the tally has data if self.mean is None or self.std_dev is None: - msg = 'The Tally ID="{}" has no data to return'.format(self.id) + msg = f'The Tally ID="{self.id}" has no data to return' raise KeyError(msg) # Initialize a pandas dataframe for the tally data @@ -1299,7 +1361,7 @@ def get_pandas_dataframe(self, filters=True, nuclides=True, scores=True, nuclides.append(nuclide.name) elif isinstance(nuclide, openmc.AggregateNuclide): nuclides.append(nuclide.name) - column_name = '{}(nuclide)'.format(nuclide.aggregate_op) + column_name = f'{nuclide.aggregate_op}(nuclide)' else: nuclides.append(nuclide) @@ -1318,7 +1380,7 @@ def get_pandas_dataframe(self, filters=True, nuclides=True, scores=True, scores.append(str(score)) elif isinstance(score, openmc.AggregateScore): scores.append(score.name) - column_name = '{}(score)'.format(score.aggregate_op) + column_name = f'{score.aggregate_op}(score)' tile_factor = data_size / len(self.scores) df[column_name] = np.tile(scores, int(tile_factor)) @@ -1366,7 +1428,7 @@ def get_pandas_dataframe(self, filters=True, nuclides=True, scores=True, return df - def get_reshaped_data(self, value='mean'): + def get_reshaped_data(self, value='mean', expand_dims=False): """Returns an array of tally data with one dimension per filter. The tally data in OpenMC is stored as a 3D array with the dimensions @@ -1378,17 +1440,26 @@ def get_reshaped_data(self, value='mean'): This builds and returns a reshaped version of the tally data array with unique dimensions corresponding to each tally filter. For example, - suppose this tally has arrays of data with shape (8,5,5) corresponding - to two filters (2 and 4 bins, respectively), five nuclides and five + suppose this tally has arrays of data with shape (30,5,5) corresponding + to two filters (2 and 15 bins, respectively), five nuclides and five scores. This method will return a version of the data array with the - with a new shape of (2,4,5,5) such that the first two dimensions - correspond directly to the two filters with two and four bins. + with a new shape of (2,15,5,5) such that the first two dimensions + correspond directly to the two filters with two and fifteen bins. If + expand_dims is True and our filter above with 15 bins is an instance of + :class:`openmc.MeshFilter` with a shape of (3,5,1). The resulting tally + data array will have a new shape of (2,3,5,1,5,5). Parameters ---------- value : str A string for the type of value to return - 'mean' (default), 'std_dev', 'rel_err', 'sum', or 'sum_sq' are accepted + expand_dims : bool, optional + Whether or not to expand the dimensions of filters with multiple + dimensions. This will result in more than one dimension per filter + for the returned data array. + + .. versionadded:: 0.13.3 Returns ------- @@ -1400,12 +1471,32 @@ def get_reshaped_data(self, value='mean'): # Get the 3D array of data in filters, nuclides and scores data = self.get_values(value=value) - # Build a new array shape with one dimension per filter - new_shape = tuple(f.num_bins for f in self.filters) + # Build a new array shape with one dimension per filter or expand + # multidimensional filters if desired + new_shape = tuple() + idx0 = None + for i, f in enumerate(self.filters): + if expand_dims: + # Mesh filter indices are backwards so we need to flip them + if isinstance(f, openmc.MeshFilter): + fshape = f.shape[::-1] + new_shape += fshape + idx0, idx1 = i, i + len(fshape) - 1 + else: + new_shape += f.shape + else: + new_shape += (np.prod(f.shape),) + new_shape += (self.num_nuclides, self.num_scores) # Reshape the data with one dimension for each filter data = np.reshape(data, new_shape) + + # If we had a MeshFilter we should swap the axes to have the same shape + # for the data and the filter + if idx0 is not None: + data = np.swapaxes(data, idx0, idx1) + return data def hybrid_product(self, other, binary_op, filter_product=None, @@ -1487,8 +1578,8 @@ def hybrid_product(self, other, binary_op, filter_product=None, # Check that results have been read if not other.derived and other.sum is None: - msg = 'Unable to use tally arithmetic with Tally ID="{}" ' \ - 'since it does not contain any results.'.format(other.id) + msg = f'Unable to use tally arithmetic with Tally ' \ + f'ID="{other.id}" since it does not contain any results.' raise ValueError(msg) new_tally = Tally() @@ -1501,7 +1592,7 @@ def hybrid_product(self, other, binary_op, filter_product=None, # Construct a combined derived name from the two tally operands if self.name != '' and other.name != '': - new_name = '({} {} {})'.format(self.name, binary_op, other.name) + new_name = f'({self.name} {binary_op} {other.name})' new_tally.name = new_name # Query the mean and std dev so the tally data is read in from file @@ -1797,12 +1888,12 @@ def _swap_filters(self, filter1, filter2): if filter1 == filter2: return elif filter1 not in self.filters: - msg = 'Unable to swap "{}" filter1 in Tally ID="{}" since it ' \ - 'does not contain such a filter'.format(filter1.type, self.id) + msg = f'Unable to swap "{filter1.type}" filter1 in Tally ' \ + f'ID="{self.id}" since it does not contain such a filter' raise ValueError(msg) elif filter2 not in self.filters: - msg = 'Unable to swap "{}" filter2 in Tally ID="{}" since it ' \ - 'does not contain such a filter'.format(filter2.type, self.id) + msg = f'Unable to swap "{filter2.type}" filter2 in Tally ' \ + f'ID="{self.id}" since it does not contain such a filter' raise ValueError(msg) # Construct lists of tuples for the bins in each of the two filters @@ -1879,8 +1970,8 @@ def _swap_nuclides(self, nuclide1, nuclide2): # Check that results have been read if not self.derived and self.sum is None: - msg = 'Unable to use tally arithmetic with Tally ID="{}" ' \ - 'since it does not contain any results.'.format(self.id) + msg = f'Unable to use tally arithmetic with Tally ID="{self.id}" ' \ + 'since it does not contain any results.' raise ValueError(msg) cv.check_type('nuclide1', nuclide1, _NUCLIDE_CLASSES) @@ -1891,14 +1982,12 @@ def _swap_nuclides(self, nuclide1, nuclide2): msg = 'Unable to swap a nuclide with itself' raise ValueError(msg) elif nuclide1 not in self.nuclides: - msg = 'Unable to swap nuclide1 "{}" in Tally ID="{}" since it ' \ - 'does not contain such a nuclide'\ - .format(nuclide1.name, self.id) + msg = f'Unable to swap nuclide1 "{nuclide1.name}" in Tally ' \ + f'ID="{self.id}" since it does not contain such a nuclide' raise ValueError(msg) elif nuclide2 not in self.nuclides: - msg = 'Unable to swap "{}" nuclide2 in Tally ID="{}" since it ' \ - 'does not contain such a nuclide'\ - .format(nuclide2.name, self.id) + msg = f'Unable to swap "{nuclide2.name}" nuclide2 in Tally ' \ + f'ID="{self.id}" since it does not contain such a nuclide' raise ValueError(msg) # Swap the nuclides in the Tally @@ -2060,7 +2149,7 @@ def __add__(self, other): new_tally.sparse = self.sparse else: - msg = 'Unable to add "{}" to Tally ID="{}"'.format(other, self.id) + msg = f'Unable to add "{other}" to Tally ID="{self.id}"' raise ValueError(msg) return new_tally @@ -2131,7 +2220,7 @@ def __sub__(self, other): new_tally.sparse = self.sparse else: - msg = 'Unable to subtract "{}" from Tally ID="{}"'.format(other, self.id) + msg = f'Unable to subtract "{other}" from Tally ID="{self.id}"' raise ValueError(msg) return new_tally @@ -2202,7 +2291,7 @@ def __mul__(self, other): new_tally.sparse = self.sparse else: - msg = 'Unable to multiply Tally ID="{}" by "{}"'.format(self.id, other) + msg = f'Unable to multiply Tally ID="{self.id}" by "{other}"' raise ValueError(msg) return new_tally @@ -2273,7 +2362,7 @@ def __truediv__(self, other): new_tally.sparse = self.sparse else: - msg = 'Unable to divide Tally ID="{}" by "{}"'.format(self.id, other) + msg = f'Unable to divide Tally ID="{self.id}" by "{other}"' raise ValueError(msg) return new_tally @@ -2348,7 +2437,7 @@ def __pow__(self, power): new_tally.sparse = self.sparse else: - msg = 'Unable to raise Tally ID="{}" to power "{}"'.format(self.id, power) + msg = f'Unable to raise Tally ID="{self.id}" to power "{power}"' raise ValueError(msg) return new_tally @@ -2929,7 +3018,7 @@ def diagonalize_filter(self, new_filter, filter_position=-1): Returns ------- openmc.Tally - A new derived Tally with data diagaonalized along the new filter. + A new derived Tally with data diagonalized along the new filter. """ @@ -3016,8 +3105,7 @@ def append(self, tally, merge=False): """ if not isinstance(tally, Tally): - msg = 'Unable to add a non-Tally "{}" to the ' \ - 'Tallies instance'.format(tally) + msg = f'Unable to add a non-Tally "{tally}" to the Tallies instance' raise TypeError(msg) if merge: @@ -3082,17 +3170,17 @@ def _create_tally_subelements(self, root_element): for tally in self: root_element.append(tally.to_xml_element()) - def _create_mesh_subelements(self, root_element): - already_written = set() + def _create_mesh_subelements(self, root_element, memo=None): + already_written = memo if memo else set() for tally in self: for f in tally.filters: if isinstance(f, openmc.MeshFilter): - if f.mesh.id not in already_written: - if len(f.mesh.name) > 0: - root_element.append(ET.Comment(f.mesh.name)) - - root_element.append(f.mesh.to_xml_element()) - already_written.add(f.mesh.id) + if f.mesh.id in already_written: + continue + if len(f.mesh.name) > 0: + root_element.append(ET.Comment(f.mesh.name)) + root_element.append(f.mesh.to_xml_element()) + already_written.add(f.mesh.id) def _create_filter_subelements(self, root_element): already_written = dict() @@ -3118,6 +3206,21 @@ def _create_derivative_subelements(self, root_element): for d in derivs: root_element.append(d.to_xml_element()) + def to_xml_element(self, memo=None): + """Creates a 'tallies' element to be written to an XML file. + """ + element = ET.Element("tallies") + self._create_mesh_subelements(element, memo) + self._create_filter_subelements(element) + self._create_tally_subelements(element) + self._create_derivative_subelements(element) + + # Clean the indentation in the file to be user-readable + clean_indentation(element) + reorder_attributes(element) # TODO: Remove when support is Python 3.8+ + + return element + def export_to_xml(self, path='tallies.xml'): """Create a tallies.xml file that can be used for a simulation. @@ -3127,15 +3230,7 @@ def export_to_xml(self, path='tallies.xml'): Path to file to write. Defaults to 'tallies.xml'. """ - - root_element = ET.Element("tallies") - self._create_mesh_subelements(root_element) - self._create_filter_subelements(root_element) - self._create_tally_subelements(root_element) - self._create_derivative_subelements(root_element) - - # Clean the indentation in the file to be user-readable - clean_indentation(root_element) + root_element = self.to_xml_element() # Check if path is a directory p = Path(path) @@ -3143,6 +3238,72 @@ def export_to_xml(self, path='tallies.xml'): p /= 'tallies.xml' # Write the XML Tree to the tallies.xml file - reorder_attributes(root_element) # TODO: Remove when support is Python 3.8+ tree = ET.ElementTree(root_element) tree.write(str(p), xml_declaration=True, encoding='utf-8') + + @classmethod + def from_xml_element(cls, elem, meshes=None): + """Generate tallies from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict or None + A dictionary with mesh IDs as keys and mesh instances as values that + have already been read from XML. Pre-existing meshes are used + and new meshes are added to when creating tally objects. + + Returns + ------- + openmc.Tallies + Tallies object + + """ + # Read mesh elements + meshes = {} if meshes is None else meshes + for e in elem.findall('mesh'): + mesh = MeshBase.from_xml_element(e) + meshes[mesh.id] = mesh + + # Read filter elements + filters = {} + for e in elem.findall('filter'): + filter = openmc.Filter.from_xml_element(e, meshes=meshes) + filters[filter.id] = filter + + # Read derivative elements + derivatives = {} + for e in elem.findall('derivative'): + deriv = openmc.TallyDerivative.from_xml_element(e) + derivatives[deriv.id] = deriv + + # Read tally elements + tallies = [] + for e in elem.findall('tally'): + tally = openmc.Tally.from_xml_element( + e, filters=filters, derivatives=derivatives + ) + tallies.append(tally) + + return cls(tallies) + + @classmethod + def from_xml(cls, path='tallies.xml'): + """Generate tallies from XML file + + Parameters + ---------- + path : str, optional + Path to tallies XML file + + Returns + ------- + openmc.Tallies + Tallies object + + """ + parser = ET.XMLParser(huge_tree=True) + tree = ET.parse(path, parser=parser) + root = tree.getroot() + return cls.from_xml_element(root) diff --git a/openmc/tally_derivative.py b/openmc/tally_derivative.py index 125946197b2..ff918c1b3c6 100644 --- a/openmc/tally_derivative.py +++ b/openmc/tally_derivative.py @@ -1,5 +1,6 @@ from numbers import Integral -from xml.etree import ElementTree as ET + +import lxml.etree as ET import openmc.checkvalue as cv from .mixin import EqualityMixin, IDManagerMixin @@ -60,14 +61,6 @@ def __repr__(self): def variable(self): return self._variable - @property - def material(self): - return self._material - - @property - def nuclide(self): - return self._nuclide - @variable.setter def variable(self, var): if var is not None: @@ -76,12 +69,20 @@ def variable(self, var): ('density', 'nuclide_density', 'temperature')) self._variable = var + @property + def material(self): + return self._material + @material.setter def material(self, mat): if mat is not None: cv.check_type('derivative material', mat, Integral) self._material = mat + @property + def nuclide(self): + return self._nuclide + @nuclide.setter def nuclide(self, nuc): if nuc is not None: @@ -93,7 +94,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing derivative data """ @@ -105,3 +106,24 @@ def to_xml_element(self): if self.variable == 'nuclide_density': element.set("nuclide", self.nuclide) return element + + @classmethod + def from_xml_element(cls, elem): + """Generate tally derivative from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.TallyDerivative + Tally derivative object + + """ + derivative_id = int(elem.get("id")) + variable = elem.get("variable") + material = int(elem.get("material")) + nuclide = elem.get("nuclide") if variable == "nuclide_density" else None + return cls(derivative_id, variable, material, nuclide) diff --git a/openmc/tracks.py b/openmc/tracks.py new file mode 100644 index 00000000000..61e5a72442e --- /dev/null +++ b/openmc/tracks.py @@ -0,0 +1,346 @@ +from collections import namedtuple +from collections.abc import Sequence + +import h5py + +from .checkvalue import check_filetype_version +from .source import SourceParticle, ParticleType + +from pathlib import Path + +ParticleTrack = namedtuple('ParticleTrack', ['particle', 'states']) +ParticleTrack.__doc__ = """\ +Particle track information + +Parameters +---------- +particle : openmc.ParticleType + Type of the particle +states : numpy.ndarray + Structured array containing each state of the particle. The structured array + contains the following fields: ``r`` (position; each direction in [cm]), + ``u`` (direction), ``E`` (energy in [eV]), ``time`` (time in [s]), ``wgt`` + (weight), ``cell_id`` (cell ID) , ``cell_instance`` (cell instance), and + ``material_id`` (material ID). + +""" +def _particle_track_repr(self): + return f"" +ParticleTrack.__repr__ = _particle_track_repr + + +_VERSION_TRACK = 3 + + +def _identifier(dset_name): + """Return (batch, gen, particle) tuple given dataset name""" + _, batch, gen, particle = dset_name.split('_') + return (int(batch), int(gen), int(particle)) + + +class Track(Sequence): + """Tracks resulting from a single source particle + + This class stores information for all tracks resulting from a primary source + particle and any secondary particles that it created. The track for each + primary/secondary particle is stored in the :attr:`particle_tracks` + attribute. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + dset : h5py.Dataset + Dataset to read track data from + + Attributes + ---------- + identifier : tuple + Tuple of (batch, generation, particle number) + particle_tracks : list + List of tuples containing (particle type, array of track states) + sources : list + List of :class:`SourceParticle` representing each primary/secondary + particle + + """ + + def __init__(self, dset): + tracks = dset[()] + offsets = dset.attrs['offsets'] + particles = dset.attrs['particles'] + self.identifier = _identifier(dset.name) + + # Construct list of track histories + tracks_list = [] + for particle, start, end in zip(particles, offsets[:-1], offsets[1:]): + ptype = ParticleType(particle) + tracks_list.append(ParticleTrack(ptype, tracks[start:end])) + self.particle_tracks = tracks_list + + def __repr__(self): + return f'' + + def __getitem__(self, index): + return self.particle_tracks[index] + + def __len__(self): + return len(self.particle_tracks) + + def filter(self, particle=None, state_filter=None): + """Filter particle tracks by given criteria + + Parameters + ---------- + particle : {'neutron', 'photon', 'electron', 'positron'} + Matching particle type + state_filter : function + Function that takes a state (structured datatype) and returns a bool + depending on some criteria. + + Returns + ------- + Track + New instance with only matching :class:`openmc.ParticleTrack` objects + + Examples + -------- + Get all particle tracks for photons: + + >>> track.filter(particle='photon') + + Get all particle tracks that entered cell with ID=15: + + >>> track.filter(state_filter=lambda s: s['cell_id'] == 15) + + Get all particle tracks in entered material with ID=2: + + >>> track.filter(state_filter=lambda s: s['material_id'] == 2) + + See Also + -------- + openmc.ParticleTrack + + """ + matching = [] + for t in self: + # Check for matching particle + if particle is not None: + if t.particle.name.lower() != particle: + continue + + # Apply arbitrary state filter + match = True + if state_filter is not None: + for state in t.states: + if state_filter(state): + break + else: + match = False + + if match: + matching.append(t) + + # Return new Track instance with only matching particle tracks + track = type(self).__new__(type(self)) + track.identifier = self.identifier + track.particle_tracks = matching + return track + + def plot(self, axes=None): + """Produce a 3D plot of particle tracks + + Parameters + ---------- + axes : matplotlib.axes.Axes, optional + Axes for plot + + Returns + ------- + axes : matplotlib.axes.Axes + Axes for plot + + """ + import matplotlib.pyplot as plt + + # Setup axes is one wasn't passed + if axes is None: + fig = plt.figure() + ax = plt.axes(projection='3d') + ax.set_xlabel('x [cm]') + ax.set_ylabel('y [cm]') + ax.set_zlabel('z [cm]') + else: + ax = axes + + # Plot each particle track + for _, states in self: + r = states['r'] + ax.plot3D(r['x'], r['y'], r['z']) + + return ax + + @property + def sources(self): + sources = [] + for particle_track in self: + particle_type = ParticleType(particle_track.particle) + state = particle_track.states[0] + sources.append( + SourceParticle( + r=state['r'], u=state['u'], E=state['E'], + time=state['time'], wgt=state['wgt'], + particle=particle_type + ) + ) + return sources + + +class Tracks(list): + """Collection of particle tracks + + This class behaves like a list and can be indexed using the normal subscript + notation. Each element in the list is a :class:`openmc.Track` object. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + filepath : str or pathlib.Path + Path of file to load + + """ + + def __init__(self, filepath='tracks.h5'): + # Read data from track file + with h5py.File(filepath, 'r') as fh: + # Check filetype and version + check_filetype_version(fh, 'track', _VERSION_TRACK) + + for dset_name in sorted(fh, key=_identifier): + dset = fh[dset_name] + self.append(Track(dset)) + + def filter(self, particle=None, state_filter=None): + """Filter tracks by given criteria + + Parameters + ---------- + particle : {'neutron', 'photon', 'electron', 'positron'} + Matching particle type + state_filter : function + Function that takes a state (structured datatype) and returns a bool + depending on some criteria. + + Returns + ------- + Tracks + List of :class:`openmc.Track` objects + + See Also + -------- + openmc.Track.filter + + """ + # Create a new Tracks instance but avoid call to __init__ + matching = type(self).__new__(type(self)) + + # Append matching Track objects + for track in self: + if track.filter(particle, state_filter): + matching.append(track) + return matching + + def plot(self): + """Produce a 3D plot of particle tracks + + Returns + ------- + matplotlib.axes.Axes + Axes for plot + + """ + import matplotlib.pyplot as plt + fig = plt.figure() + ax = plt.axes(projection='3d') + ax.set_xlabel('x [cm]') + ax.set_ylabel('y [cm]') + ax.set_zlabel('z [cm]') + for track in self: + track.plot(ax) + return ax + + def write_to_vtk(self, filename=Path('tracks.vtp')): + """Creates a VTP file of the tracks + + Parameters + ---------- + filename : path-like + Name of the VTP file to write. + + Returns + ------- + vtk.vtkPolyData + the VTK vtkPolyData object produced + """ + + import vtk + + # Initialize data arrays and offset. + points = vtk.vtkPoints() + cells = vtk.vtkCellArray() + + point_offset = 0 + for particle in self: + for pt in particle.particle_tracks: + for state in pt.states: + points.InsertNextPoint(state['r']) + + # Create VTK line and assign points to line. + n = pt.states.size + line = vtk.vtkPolyLine() + line.GetPointIds().SetNumberOfIds(n) + for i in range(n): + line.GetPointIds().SetId(i, point_offset + i) + point_offset += n + + # Add line to cell array + cells.InsertNextCell(line) + + data = vtk.vtkPolyData() + data.SetPoints(points) + data.SetLines(cells) + + writer = vtk.vtkXMLPPolyDataWriter() + if vtk.vtkVersion.GetVTKMajorVersion() > 5: + writer.SetInputData(data) + else: + writer.SetInput(data) + writer.SetFileName(str(filename)) # SetFileName requires a string + writer.Write() + + return data + + @staticmethod + def combine(track_files, path='tracks.h5'): + """Combine multiple track files into a single track file + + Parameters + ---------- + track_files : list of path-like + Paths to track files to combine + path : path-like + Path of combined track file to create + + """ + with h5py.File(path, 'w') as h5_out: + for i, fname in enumerate(track_files): + with h5py.File(fname, 'r') as h5_in: + # Copy file attributes for first file + if i == 0: + h5_out.attrs['filetype'] = h5_in.attrs['filetype'] + h5_out.attrs['version'] = h5_in.attrs['version'] + + # Copy each 'track_*' dataset from input file + for dset in h5_in: + h5_in.copy(dset, h5_out) diff --git a/openmc/trigger.py b/openmc/trigger.py index 3b00ccd204b..79f5ea5af89 100644 --- a/openmc/trigger.py +++ b/openmc/trigger.py @@ -1,6 +1,7 @@ from collections.abc import Iterable from numbers import Real -from xml.etree import ElementTree as ET + +import lxml.etree as ET import openmc.checkvalue as cv from .mixin import EqualityMixin @@ -16,6 +17,12 @@ class Trigger(EqualityMixin): relative error of scores. threshold : float The threshold for the trigger type. + ignore_zeros : bool + Whether to allow zero tally bins to be ignored. Note that this option + can cause the trigger to fire prematurely if there are zero scores in + any bin at the first evaluation. + + .. versionadded:: 0.14.1 Attributes ---------- @@ -26,18 +33,22 @@ class Trigger(EqualityMixin): The threshold for the trigger type. scores : list of str Scores which should be checked against the trigger + ignore_zeros : bool + Whether to allow zero tally bins to be ignored. """ - def __init__(self, trigger_type, threshold): + def __init__(self, trigger_type: str, threshold: float, ignore_zeros: bool = False): self.trigger_type = trigger_type self.threshold = threshold + self.ignore_zeros = ignore_zeros self._scores = [] def __repr__(self): string = 'Trigger\n' string += '{: <16}=\t{}\n'.format('\tType', self._trigger_type) string += '{: <16}=\t{}\n'.format('\tThreshold', self._threshold) + string += '{: <16}=\t{}\n'.format('\tIgnore Zeros', self._ignore_zeros) string += '{: <16}=\t{}\n'.format('\tScores', self._scores) return string @@ -45,25 +56,34 @@ def __repr__(self): def trigger_type(self): return self._trigger_type - @property - def threshold(self): - return self._threshold - - @property - def scores(self): - return self._scores - @trigger_type.setter def trigger_type(self, trigger_type): cv.check_value('tally trigger type', trigger_type, ['variance', 'std_dev', 'rel_err']) self._trigger_type = trigger_type + @property + def threshold(self): + return self._threshold + @threshold.setter def threshold(self, threshold): cv.check_type('tally trigger threshold', threshold, Real) self._threshold = threshold + @property + def ignore_zeros(self): + return self._ignore_zeros + + @ignore_zeros.setter + def ignore_zeros(self, ignore_zeros): + cv.check_type('tally trigger ignores zeros', ignore_zeros, bool) + self._ignore_zeros = ignore_zeros + + @property + def scores(self): + return self._scores + @scores.setter def scores(self, scores): cv.check_type('trigger scores', scores, Iterable, str) @@ -74,18 +94,51 @@ def scores(self, scores): if score not in self._scores: self._scores.append(score) - def get_trigger_xml(self, element): + def to_xml_element(self): """Return XML representation of the trigger Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing trigger data """ - subelement = ET.SubElement(element, "trigger") - subelement.set("type", self._trigger_type) - subelement.set("threshold", str(self._threshold)) + element = ET.Element("trigger") + element.set("type", self._trigger_type) + element.set("threshold", str(self._threshold)) + if self._ignore_zeros: + element.set("ignore_zeros", "true") if len(self._scores) != 0: - subelement.set("scores", ' '.join(map(str, self._scores))) + element.set("scores", ' '.join(self._scores)) + return element + + @classmethod + def from_xml_element(cls, elem: ET.Element): + """Generate trigger object from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.Trigger + Trigger object + + """ + # Generate trigger object + trigger_type = elem.get("type") + threshold = float(elem.get("threshold")) + ignore_zeros = str(elem.get("ignore_zeros", "false")).lower() + # Try to convert to bool. Let Trigger error out on instantiation. + ignore_zeros = ignore_zeros in ('true', '1') + trigger = cls(trigger_type, threshold, ignore_zeros) + + # Add scores if present + scores = elem.get("scores") + if scores is not None: + trigger.scores = scores.split() + + return trigger diff --git a/openmc/universe.py b/openmc/universe.py index 2dfbf9cd750..2e86ab05a9b 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -1,18 +1,181 @@ -from collections import OrderedDict +import math +from abc import ABC, abstractmethod from collections.abc import Iterable -from copy import copy, deepcopy -from numbers import Real -import random +from numbers import Integral, Real +from pathlib import Path +from tempfile import TemporaryDirectory +import warnings +import h5py +import lxml.etree as ET import numpy as np import openmc import openmc.checkvalue as cv +from ._xml import get_text +from .checkvalue import check_type, check_value from .mixin import IDManagerMixin -from .plots import _SVG_COLORS +from .surface import _BOUNDARY_TYPES -class Universe(IDManagerMixin): +class UniverseBase(ABC, IDManagerMixin): + """A collection of cells that can be repeated. + + Attributes + ---------- + id : int + Unique identifier of the universe + name : str + Name of the universe + """ + + next_id = 1 + used_ids = set() + + def __init__(self, universe_id=None, name=''): + # Initialize Universe class attributes + self.id = universe_id + self.name = name + self._volume = None + self._atoms = {} + + # Keys - Cell IDs + # Values - Cells + self._cells = {} + + def __repr__(self): + string = 'Universe\n' + string += '{: <16}=\t{}\n'.format('\tID', self._id) + string += '{: <16}=\t{}\n'.format('\tName', self._name) + return string + + @property + def name(self): + return self._name + + @name.setter + def name(self, name): + if name is not None: + cv.check_type('universe name', name, str) + self._name = name + else: + self._name = '' + + @property + def volume(self): + return self._volume + + @volume.setter + def volume(self, volume): + if volume is not None: + cv.check_type('universe volume', volume, Real) + self._volume = volume + + def add_volume_information(self, volume_calc): + """Add volume information to a universe. + + Parameters + ---------- + volume_calc : openmc.VolumeCalculation + Results from a stochastic volume calculation + + """ + if volume_calc.domain_type == 'universe': + if self.id in volume_calc.volumes: + self._volume = volume_calc.volumes[self.id].n + self._atoms = volume_calc.atoms[self.id] + else: + raise ValueError( + 'No volume information found for this universe.') + else: + raise ValueError('No volume information found for this universe.') + + def get_all_universes(self): + """Return all universes that are contained within this one. + + Returns + ------- + universes : dict + Dictionary whose keys are universe IDs and values are + :class:`Universe` instances + + """ + # Append all Universes within each Cell to the dictionary + universes = {} + for cell in self.get_all_cells().values(): + universes.update(cell.get_all_universes()) + + return universes + + @abstractmethod + def create_xml_subelement(self, xml_element, memo=None): + """Add the universe xml representation to an incoming xml element + + Parameters + ---------- + xml_element : lxml.etree._Element + XML element to be added to + + memo : set or None + A set of object id's representing geometry entities already + written to the xml_element. This parameter is used internally + and should not be specified by users. + + Returns + ------- + None + + """ + + @abstractmethod + def _partial_deepcopy(self): + """Deepcopy all parameters of an openmc.UniverseBase object except its cells. + This should only be used from the openmc.UniverseBase.clone() context. + + """ + + def clone(self, clone_materials=True, clone_regions=True, memo=None): + """Create a copy of this universe with a new unique ID, and clones + all cells within this universe. + + Parameters + ---------- + clone_materials : bool + Whether to create separates copies of the materials filling cells + contained in this universe. + clone_regions : bool + Whether to create separates copies of the regions bounding cells + contained in this universe. + memo : dict or None + A nested dictionary of previously cloned objects. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + clone : openmc.Universe + The clone of this universe + + """ + if memo is None: + memo = {} + + # If no memoize'd clone exists, instantiate one + if self not in memo: + clone = self._partial_deepcopy() + + # Clone all cells for the universe clone + clone._cells = {} + for cell in self._cells.values(): + clone.add_cell(cell.clone(clone_materials, clone_regions, + memo)) + + # Memoize the clone + memo[self] = clone + + return memo[self] + + +class Universe(UniverseBase): """A collection of cells that can be repeated. Parameters @@ -31,55 +194,35 @@ class Universe(IDManagerMixin): Unique identifier of the universe name : str Name of the universe - cells : collections.OrderedDict + cells : dict Dictionary whose keys are cell IDs and values are :class:`Cell` instances volume : float Volume of the universe in cm^3. This can either be set manually or calculated in a stochastic volume calculation and added via the :meth:`Universe.add_volume_information` method. - bounding_box : 2-tuple of numpy.array + bounding_box : openmc.BoundingBox Lower-left and upper-right coordinates of an axis-aligned bounding box of the universe. """ - next_id = 1 - used_ids = set() - def __init__(self, universe_id=None, name='', cells=None): - # Initialize Cell class attributes - self.id = universe_id - self.name = name - self._volume = None - self._atoms = {} - - # Keys - Cell IDs - # Values - Cells - self._cells = OrderedDict() + super().__init__(universe_id, name) if cells is not None: self.add_cells(cells) def __repr__(self): - string = 'Universe\n' - string += '{: <16}=\t{}\n'.format('\tID', self._id) - string += '{: <16}=\t{}\n'.format('\tName', self._name) + string = super().__repr__() + string += '{: <16}=\t{}\n'.format('\tGeom', 'CSG') string += '{: <16}=\t{}\n'.format('\tCells', list(self._cells.keys())) return string - @property - def name(self): - return self._name - @property def cells(self): return self._cells - @property - def volume(self): - return self._volume - @property def bounding_box(self): regions = [c.region for c in self.cells.values() @@ -87,22 +230,7 @@ def bounding_box(self): if regions: return openmc.Union(regions).bounding_box else: - # Infinite bounding box - return openmc.Intersection([]).bounding_box - - @name.setter - def name(self, name): - if name is not None: - cv.check_type('universe name', name, str) - self._name = name - else: - self._name = '' - - @volume.setter - def volume(self, volume): - if volume is not None: - cv.check_type('universe volume', volume, Real) - self._volume = volume + return openmc.BoundingBox.infinite() @classmethod def from_hdf5(cls, group, cells): @@ -133,24 +261,6 @@ def from_hdf5(cls, group, cells): return universe - def add_volume_information(self, volume_calc): - """Add volume information to a universe. - - Parameters - ---------- - volume_calc : openmc.VolumeCalculation - Results from a stochastic volume calculation - - """ - if volume_calc.domain_type == 'universe': - if self.id in volume_calc.volumes: - self._volume = volume_calc.volumes[self.id].n - self._atoms = volume_calc.atoms[self.id] - else: - raise ValueError('No volume information found for this universe.') - else: - raise ValueError('No volume information found for this universe.') - def find(self, point): """Find cells/universes/lattices which contain a given point @@ -181,23 +291,34 @@ def find(self, point): return [self, cell] + cell.fill.find(p) return [] - def plot(self, origin=(0., 0., 0.), width=(1., 1.), pixels=(200, 200), + # default kwargs that are passed to plt.legend in the plot method below. + _default_legend_kwargs = {'bbox_to_anchor': ( + 1.05, 1), 'loc': 2, 'borderaxespad': 0.0} + + def plot(self, origin=None, width=None, pixels=40000, basis='xy', color_by='cell', colors=None, seed=None, + openmc_exec='openmc', axes=None, legend=False, axis_units='cm', + legend_kwargs=_default_legend_kwargs, outline=False, **kwargs): """Display a slice plot of the universe. - To display or save the plot, call :func:`matplotlib.pyplot.show` or - :func:`matplotlib.pyplot.savefig`. In a Jupyter notebook, enabling the - matplotlib inline backend will show the plot inline. - Parameters ---------- - origin : Iterable of float - Coordinates at the origin of the plot - width : Iterable of float - Width of the plot in each basis direction - pixels : Iterable of int - Number of pixels to use in each basis direction + origin : iterable of float + Coordinates at the origin of the plot. If left as None, + universe.bounding_box.center will be used to attempt to ascertain + the origin with infinite values being replaced by 0. + width : iterable of float + Width of the plot in each basis direction. If left as none then the + universe.bounding_box.width() will be used to attempt to + ascertain the plot width. Defaults to (10, 10) if the bounding_box + contains inf values + pixels : Iterable of int or int + If iterable of ints provided then this directly sets the number of + pixels to use in each basis direction. If int provided then this + sets the total number of pixels in the plot and the number of + pixels in each basis direction is calculated from this total and + the image aspect ratio. basis : {'xy', 'xz', 'yz'} The basis directions for the plot color_by : {'cell', 'material'} @@ -213,99 +334,191 @@ def plot(self, origin=(0., 0., 0.), width=(1., 1.), pixels=(200, 200), # Make water blue water = openmc.Cell(fill=h2o) universe.plot(..., colors={water: (0., 0., 1.)) - - seed : hashable object or None - Hashable object which is used to seed the random number generator - used to select colors. If None, the generator is seeded from the - current time. + seed : int + Seed for the random number generator + openmc_exec : str + Path to OpenMC executable. + axes : matplotlib.Axes + Axes to draw to + + .. versionadded:: 0.13.1 + legend : bool + Whether a legend showing material or cell names should be drawn + + .. versionadded:: 0.14.0 + legend_kwargs : dict + Keyword arguments passed to :func:`matplotlib.pyplot.legend`. + + .. versionadded:: 0.14.0 + outline : bool + Whether outlines between color boundaries should be drawn + + .. versionadded:: 0.14.0 + axis_units : {'km', 'm', 'cm', 'mm'} + Units used on the plot axis + + .. versionadded:: 0.14.0 **kwargs - All keyword arguments are passed to - :func:`matplotlib.pyplot.imshow`. + Keyword arguments passed to :func:`matplotlib.pyplot.imshow` Returns ------- - matplotlib.image.AxesImage - Resulting image + matplotlib.axes.Axes + Axes containing resulting image """ + import matplotlib.image as mpimg + import matplotlib.patches as mpatches import matplotlib.pyplot as plt - # Seed the random number generator - if seed is not None: - random.seed(seed) - - if colors is None: - # Create default dictionary if none supplied - colors = {} - else: - # Convert to RGBA if necessary - colors = copy(colors) - for obj, color in colors.items(): - if isinstance(color, str): - if color.lower() not in _SVG_COLORS: - raise ValueError("'{}' is not a valid color." - .format(color)) - colors[obj] = [x/255 for x in - _SVG_COLORS[color.lower()]] + [1.0] - elif len(color) == 3: - colors[obj] = list(color) + [1.0] - + # Determine extents of plot if basis == 'xy': - x_min = origin[0] - 0.5*width[0] - x_max = origin[0] + 0.5*width[0] - y_min = origin[1] - 0.5*width[1] - y_max = origin[1] + 0.5*width[1] + x, y = 0, 1 + xlabel, ylabel = f'x [{axis_units}]', f'y [{axis_units}]' elif basis == 'yz': - # The x-axis will correspond to physical y and the y-axis will - # correspond to physical z - x_min = origin[1] - 0.5*width[0] - x_max = origin[1] + 0.5*width[0] - y_min = origin[2] - 0.5*width[1] - y_max = origin[2] + 0.5*width[1] + x, y = 1, 2 + xlabel, ylabel = f'y [{axis_units}]', f'z [{axis_units}]' elif basis == 'xz': - # The y-axis will correspond to physical z - x_min = origin[0] - 0.5*width[0] - x_max = origin[0] + 0.5*width[0] - y_min = origin[2] - 0.5*width[1] - y_max = origin[2] + 0.5*width[1] - - # Determine locations to determine cells at - x_coords = np.linspace(x_min, x_max, pixels[0], endpoint=False) + \ - 0.5*(x_max - x_min)/pixels[0] - y_coords = np.linspace(y_max, y_min, pixels[1], endpoint=False) - \ - 0.5*(y_max - y_min)/pixels[1] - - # Initialize output image in RGBA format. Flip the pixels from - # traditional (x, y) to (y, x) used in graphics. - img = np.zeros((pixels[1], pixels[0], 4)) - for i, x in enumerate(x_coords): - for j, y in enumerate(y_coords): - if basis == 'xy': - path = self.find((x, y, origin[2])) - elif basis == 'yz': - path = self.find((origin[0], x, y)) - elif basis == 'xz': - path = self.find((x, origin[1], y)) - - if len(path) > 0: - try: - if color_by == 'cell': - obj = path[-1] - elif color_by == 'material': - if path[-1].fill_type == 'material': - obj = path[-1].fill - else: - continue - except AttributeError: - continue - if obj not in colors: - colors[obj] = (random.random(), random.random(), - random.random(), 1.0) - img[j, i, :] = colors[obj] - - # Display image - return plt.imshow(img, extent=(x_min, x_max, y_min, y_max), - interpolation='nearest', **kwargs) + x, y = 0, 2 + xlabel, ylabel = f'x [{axis_units}]', f'z [{axis_units}]' + + bb = self.bounding_box + # checks to see if bounding box contains -inf or inf values + if np.isinf(bb.extent[basis]).any(): + if origin is None: + origin = (0, 0, 0) + if width is None: + width = (10, 10) + else: + if origin is None: + # if nan values in the bb.center they get replaced with 0.0 + # this happens when the bounding_box contains inf values + with warnings.catch_warnings(): + warnings.simplefilter("ignore", RuntimeWarning) + origin = np.nan_to_num(bb.center) + if width is None: + bb_width = bb.width + x_width = bb_width['xyz'.index(basis[0])] + y_width = bb_width['xyz'.index(basis[1])] + width = (x_width, y_width) + + if isinstance(pixels, int): + aspect_ratio = width[0] / width[1] + pixels_y = math.sqrt(pixels / aspect_ratio) + pixels = (int(pixels / pixels_y), int(pixels_y)) + + axis_scaling_factor = {'km': 0.00001, 'm': 0.01, 'cm': 1, 'mm': 10} + + x_min = (origin[x] - 0.5*width[0]) * axis_scaling_factor[axis_units] + x_max = (origin[x] + 0.5*width[0]) * axis_scaling_factor[axis_units] + y_min = (origin[y] - 0.5*width[1]) * axis_scaling_factor[axis_units] + y_max = (origin[y] + 0.5*width[1]) * axis_scaling_factor[axis_units] + + with TemporaryDirectory() as tmpdir: + model = openmc.Model() + model.geometry = openmc.Geometry(self) + if seed is not None: + model.settings.plot_seed = seed + + # Determine whether any materials contains macroscopic data and if + # so, set energy mode accordingly + for mat in self.get_all_materials().values(): + if mat._macroscopic is not None: + model.settings.energy_mode = 'multi-group' + break + + # Create plot object matching passed arguments + plot = openmc.Plot() + plot.origin = origin + plot.width = width + plot.pixels = pixels + plot.basis = basis + plot.color_by = color_by + if colors is not None: + plot.colors = colors + model.plots.append(plot) + + # Run OpenMC in geometry plotting mode + model.plot_geometry(False, cwd=tmpdir, openmc_exec=openmc_exec) + + # Read image from file + img_path = Path(tmpdir) / f'plot_{plot.id}.png' + if not img_path.is_file(): + img_path = img_path.with_suffix('.ppm') + img = mpimg.imread(str(img_path)) + + # Create a figure sized such that the size of the axes within + # exactly matches the number of pixels specified + if axes is None: + px = 1/plt.rcParams['figure.dpi'] + fig, axes = plt.subplots() + axes.set_xlabel(xlabel) + axes.set_ylabel(ylabel) + params = fig.subplotpars + width = pixels[0]*px/(params.right - params.left) + height = pixels[1]*px/(params.top - params.bottom) + fig.set_size_inches(width, height) + + if outline: + # Combine R, G, B values into a single int + rgb = (img * 256).astype(int) + image_value = (rgb[..., 0] << 16) + \ + (rgb[..., 1] << 8) + (rgb[..., 2]) + + axes.contour( + image_value, + origin="upper", + colors="k", + linestyles="solid", + linewidths=1, + levels=np.unique(image_value), + extent=(x_min, x_max, y_min, y_max), + ) + + # add legend showing which colors represent which material + # or cell if that was requested + if legend: + if plot.colors == {}: + raise ValueError("Must pass 'colors' dictionary if you " + "are adding a legend via legend=True.") + + if color_by == "cell": + expected_key_type = openmc.Cell + else: + expected_key_type = openmc.Material + + patches = [] + for key, color in plot.colors.items(): + + if isinstance(key, int): + raise TypeError( + "Cannot use IDs in colors dict for auto legend.") + elif not isinstance(key, expected_key_type): + raise TypeError( + "Color dict key type does not match color_by") + + # this works whether we're doing cells or materials + label = key.name if key.name != '' else key.id + + # matplotlib takes RGB on 0-1 scale rather than 0-255. at + # this point PlotBase has already checked that 3-tuple + # based colors are already valid, so if the length is three + # then we know it just needs to be converted to the 0-1 + # format. + if len(color) == 3 and not isinstance(color, str): + scaled_color = ( + color[0]/255, color[1]/255, color[2]/255) + else: + scaled_color = color + + key_patch = mpatches.Patch(color=scaled_color, label=label) + patches.append(key_patch) + + axes.legend(handles=patches, **legend_kwargs) + + # Plot image and return the axes + axes.imshow(img, extent=(x_min, x_max, y_min, y_max), **kwargs) + return axes def add_cell(self, cell): """Add a cell to the universe. @@ -318,8 +531,8 @@ def add_cell(self, cell): """ if not isinstance(cell, openmc.Cell): - msg = 'Unable to add a Cell to Universe ID="{0}" since "{1}" is not ' \ - 'a Cell'.format(self._id, cell) + msg = f'Unable to add a Cell to Universe ID="{self._id}" since ' \ + f'"{cell}" is not a Cell' raise TypeError(msg) cell_id = cell.id @@ -338,8 +551,8 @@ def add_cells(self, cells): """ if not isinstance(cells, Iterable): - msg = 'Unable to add Cells to Universe ID="{0}" since "{1}" is not ' \ - 'iterable'.format(self._id, cells) + msg = f'Unable to add Cells to Universe ID="{self._id}" since ' \ + f'"{cells}" is not iterable' raise TypeError(msg) for cell in cells: @@ -356,8 +569,8 @@ def remove_cell(self, cell): """ if not isinstance(cell, openmc.Cell): - msg = 'Unable to remove a Cell from Universe ID="{0}" since "{1}" is ' \ - 'not a Cell'.format(self._id, cell) + msg = f'Unable to remove a Cell from Universe ID="{self._id}" ' \ + f'since "{cell}" is not a Cell' raise TypeError(msg) # If the Cell is in the Universe's list of Cells, delete it @@ -393,14 +606,14 @@ def get_nuclide_densities(self): Returns ------- - nuclides : collections.OrderedDict + nuclides : dict Dictionary whose keys are nuclide names and values are 2-tuples of (nuclide, density) """ - nuclides = OrderedDict() + nuclides = {} - if self._atoms is not None: + if self._atoms: volume = self.volume for name, atoms in self._atoms.items(): nuclide = openmc.Nuclide(name) @@ -409,9 +622,9 @@ def get_nuclide_densities(self): else: raise RuntimeError( 'Volume information is needed to calculate microscopic cross ' - 'sections for universe {}. This can be done by running a ' - 'stochastic volume calculation via the ' - 'openmc.VolumeCalculation object'.format(self.id)) + f'sections for universe {self.id}. This can be done by running ' + 'a stochastic volume calculation via the ' + 'openmc.VolumeCalculation object') return nuclides @@ -420,13 +633,13 @@ def get_all_cells(self, memo=None): Returns ------- - cells : collections.OrderedDict + cells : dict Dictionary whose keys are cell IDs and values are :class:`Cell` instances """ - cells = OrderedDict() + cells = {} if memo and self in memo: return cells @@ -448,13 +661,13 @@ def get_all_materials(self, memo=None): Returns ------- - materials : collections.OrderedDict + materials : dict Dictionary whose keys are material IDs and values are :class:`Material` instances """ - materials = OrderedDict() + materials = {} # Append all Cells in each Cell in the Universe to the dictionary cells = self.get_all_cells(memo) @@ -463,83 +676,7 @@ def get_all_materials(self, memo=None): return materials - def get_all_universes(self): - """Return all universes that are contained within this one. - - Returns - ------- - universes : collections.OrderedDict - Dictionary whose keys are universe IDs and values are - :class:`Universe` instances - - """ - # Append all Universes within each Cell to the dictionary - universes = OrderedDict() - for cell in self.get_all_cells().values(): - universes.update(cell.get_all_universes()) - - return universes - - def clone(self, clone_materials=True, clone_regions=True, memo=None): - """Create a copy of this universe with a new unique ID, and clones - all cells within this universe. - - Parameters - ---------- - clone_materials : bool - Whether to create separates copies of the materials filling cells - contained in this universe. - clone_regions : bool - Whether to create separates copies of the regions bounding cells - contained in this universe. - memo : dict or None - A nested dictionary of previously cloned objects. This parameter - is used internally and should not be specified by the user. - - Returns - ------- - clone : openmc.Universe - The clone of this universe - - """ - - if memo is None: - memo = {} - - # If no nemoize'd clone exists, instantiate one - if self not in memo: - clone = deepcopy(self) - clone.id = None - - # Clone all cells for the universe clone - clone._cells = OrderedDict() - for cell in self._cells.values(): - clone.add_cell(cell.clone(clone_materials, clone_regions, - memo)) - - # Memoize the clone - memo[self] = clone - - return memo[self] - def create_xml_subelement(self, xml_element, memo=None): - """Add the universe xml representation to an incoming xml element - - Parameters - ---------- - xml_element : xml.etree.ElementTree.Element - XML element to be added to - - memo : set or None - A set of object id's representing geometry entities already - written to the xml_element. This parameter is used internally - and should not be specified by users. - - Returns - ------- - None - - """ # Iterate over all Cells for cell in self._cells.values(): @@ -561,10 +698,10 @@ def _determine_paths(self, path='', instances_only=False): """Count the number of instances for each cell in the universe, and record the count in the :attr:`Cell.num_instances` properties.""" - univ_path = path + 'u{}'.format(self.id) + univ_path = path + f'u{self.id}' for cell in self.cells.values(): - cell_path = '{}->c{}'.format(univ_path, cell.id) + cell_path = f'{univ_path}->c{cell.id}' fill = cell._fill fill_type = cell.fill_type @@ -594,9 +731,377 @@ def _determine_paths(self, path='', instances_only=False): if mat is not None: mat._num_instances += 1 if not instances_only: - mat._paths.append('{}->m{}'.format(cell_path, mat.id)) + mat._paths.append(f'{cell_path}->m{mat.id}') # Append current path cell._num_instances += 1 if not instances_only: cell._paths.append(cell_path) + + def _partial_deepcopy(self): + """Clone all of the openmc.Universe object's attributes except for its cells, + as they are copied within the clone function. This should only to be + used within the openmc.UniverseBase.clone() context. + """ + clone = openmc.Universe(name=self.name) + clone.volume = self.volume + return clone + + +class DAGMCUniverse(UniverseBase): + """A reference to a DAGMC file to be used in the model. + + .. versionadded:: 0.13.0 + + Parameters + ---------- + filename : str + Path to the DAGMC file used to represent this universe. + universe_id : int, optional + Unique identifier of the universe. If not specified, an identifier will + automatically be assigned. + name : str, optional + Name of the universe. If not specified, the name is the empty string. + auto_geom_ids : bool + Set IDs automatically on initialization (True) or report overlaps in ID + space between CSG and DAGMC (False) + auto_mat_ids : bool + Set IDs automatically on initialization (True) or report overlaps in ID + space between OpenMC and UWUW materials (False) + + Attributes + ---------- + id : int + Unique identifier of the universe + name : str + Name of the universe + filename : str + Path to the DAGMC file used to represent this universe. + auto_geom_ids : bool + Set IDs automatically on initialization (True) or report overlaps in ID + space between CSG and DAGMC (False) + auto_mat_ids : bool + Set IDs automatically on initialization (True) or report overlaps in ID + space between OpenMC and UWUW materials (False) + bounding_box : openmc.BoundingBox + Lower-left and upper-right coordinates of an axis-aligned bounding box + of the universe. + + .. versionadded:: 0.13.1 + material_names : list of str + Return a sorted list of materials names that are contained within the + DAGMC h5m file. This is useful when naming openmc.Material() objects + as each material name present in the DAGMC h5m file must have a + matching openmc.Material() with the same name. + + .. versionadded:: 0.13.2 + n_cells : int + The number of cells in the DAGMC model. This is the number of cells at + runtime and accounts for the implicit complement whether or not is it + present in the DAGMC file. + + .. versionadded:: 0.13.2 + n_surfaces : int + The number of surfaces in the model. + + .. versionadded:: 0.13.2 + + """ + + def __init__(self, + filename, + universe_id=None, + name='', + auto_geom_ids=False, + auto_mat_ids=False): + super().__init__(universe_id, name) + # Initialize class attributes + self.filename = filename + self.auto_geom_ids = auto_geom_ids + self.auto_mat_ids = auto_mat_ids + + def __repr__(self): + string = super().__repr__() + string += '{: <16}=\t{}\n'.format('\tGeom', 'DAGMC') + string += '{: <16}=\t{}\n'.format('\tFile', self.filename) + return string + + @property + def bounding_box(self): + with h5py.File(self.filename) as dagmc_file: + coords = dagmc_file['tstt']['nodes']['coordinates'][()] + lower_left_corner = coords.min(axis=0) + upper_right_corner = coords.max(axis=0) + return openmc.BoundingBox(lower_left_corner, upper_right_corner) + + @property + def filename(self): + return self._filename + + @filename.setter + def filename(self, val): + cv.check_type('DAGMC filename', val, (Path, str)) + self._filename = val + + @property + def auto_geom_ids(self): + return self._auto_geom_ids + + @auto_geom_ids.setter + def auto_geom_ids(self, val): + cv.check_type('DAGMC automatic geometry ids', val, bool) + self._auto_geom_ids = val + + @property + def auto_mat_ids(self): + return self._auto_mat_ids + + @auto_mat_ids.setter + def auto_mat_ids(self, val): + cv.check_type('DAGMC automatic material ids', val, bool) + self._auto_mat_ids = val + + @property + def material_names(self): + dagmc_file_contents = h5py.File(self.filename) + material_tags_hex = dagmc_file_contents['/tstt/tags/NAME'].get( + 'values') + material_tags_ascii = [] + for tag in material_tags_hex: + candidate_tag = tag.tobytes().decode().replace('\x00', '') + # tags might be for temperature or reflective surfaces + if candidate_tag.startswith('mat:'): + # removes first 4 characters as openmc.Material name should be + # set without the 'mat:' part of the tag + material_tags_ascii.append(candidate_tag[4:]) + + return sorted(set(material_tags_ascii)) + + def get_all_cells(self, memo=None): + return {} + + def get_all_materials(self, memo=None): + return {} + + def _n_geom_elements(self, geom_type): + """ + Helper function for retrieving the number geometric entities in a DAGMC + file + + Parameters + ---------- + geom_type : str + The type of geometric entity to count. One of {'Volume', 'Surface'}. Returns + the runtime number of voumes in the DAGMC model (includes implicit complement). + + Returns + ------- + int + Number of geometry elements of the specified type + """ + cv.check_value('geometry type', geom_type, ('volume', 'surface')) + + def decode_str_tag(tag_val): + return tag_val.tobytes().decode().replace('\x00', '') + + dagmc_filepath = Path(self.filename).resolve() + with h5py.File(dagmc_filepath) as dagmc_file: + category_data = dagmc_file['tstt/tags/CATEGORY/values'] + category_strs = map(decode_str_tag, category_data) + n = sum([v == geom_type.capitalize() for v in category_strs]) + + # check for presence of an implicit complement in the file and + # increment the number of cells if it doesn't exist + if geom_type == 'volume': + name_data = dagmc_file['tstt/tags/NAME/values'] + name_strs = map(decode_str_tag, name_data) + if not sum(['impl_complement' in n for n in name_strs]): + n += 1 + return n + + @property + def n_cells(self): + return self._n_geom_elements('volume') + + @property + def n_surfaces(self): + return self._n_geom_elements('surface') + + def create_xml_subelement(self, xml_element, memo=None): + if memo and self in memo: + return + + if memo is not None: + memo.add(self) + + # Set xml element values + dagmc_element = ET.Element('dagmc_universe') + dagmc_element.set('id', str(self.id)) + + if self.auto_geom_ids: + dagmc_element.set('auto_geom_ids', 'true') + if self.auto_mat_ids: + dagmc_element.set('auto_mat_ids', 'true') + dagmc_element.set('filename', str(self.filename)) + xml_element.append(dagmc_element) + + def bounding_region( + self, + bounded_type: str = 'box', + boundary_type: str = 'vacuum', + starting_id: int = 10000, + padding_distance: float = 0. + ): + """Creates a either a spherical or box shaped bounding region around + the DAGMC geometry. + + .. versionadded:: 0.13.1 + + Parameters + ---------- + bounded_type : str + The type of bounding surface(s) to use when constructing the region. + Options include a single spherical surface (sphere) or a rectangle + made from six planes (box). + boundary_type : str + Boundary condition that defines the behavior for particles hitting + the surface. Defaults to vacuum boundary condition. Passed into the + surface construction. + starting_id : int + Starting ID of the surface(s) used in the region. For bounded_type + 'box', the next 5 IDs will also be used. Defaults to 10000 to reduce + the chance of an overlap of surface IDs with the DAGMC geometry. + padding_distance : float + Distance between the bounding region surfaces and the minimal + bounding box. Allows for the region to be larger than the DAGMC + geometry. + + Returns + ------- + openmc.Region + Region instance + """ + + check_type('boundary type', boundary_type, str) + check_value('boundary type', boundary_type, _BOUNDARY_TYPES) + check_type('starting surface id', starting_id, Integral) + check_type('bounded type', bounded_type, str) + check_value('bounded type', bounded_type, ('box', 'sphere')) + + bbox = self.bounding_box.expand(padding_distance, True) + + if bounded_type == 'sphere': + radius = np.linalg.norm(bbox.upper_right - bbox.center) + bounding_surface = openmc.Sphere( + surface_id=starting_id, + x0=bbox.center[0], + y0=bbox.center[1], + z0=bbox.center[2], + boundary_type=boundary_type, + r=radius, + ) + + return -bounding_surface + + if bounded_type == 'box': + # defines plane surfaces for all six faces of the bounding box + lower_x = openmc.XPlane(bbox[0][0], surface_id=starting_id) + upper_x = openmc.XPlane(bbox[1][0], surface_id=starting_id+1) + lower_y = openmc.YPlane(bbox[0][1], surface_id=starting_id+2) + upper_y = openmc.YPlane(bbox[1][1], surface_id=starting_id+3) + lower_z = openmc.ZPlane(bbox[0][2], surface_id=starting_id+4) + upper_z = openmc.ZPlane(bbox[1][2], surface_id=starting_id+5) + + region = +lower_x & -upper_x & +lower_y & -upper_y & +lower_z & -upper_z + + for surface in region.get_surfaces().values(): + surface.boundary_type = boundary_type + + return region + + def bounded_universe(self, bounding_cell_id=10000, **kwargs): + """Returns an openmc.Universe filled with this DAGMCUniverse and bounded + with a cell. Defaults to a box cell with a vacuum surface however this + can be changed using the kwargs which are passed directly to + DAGMCUniverse.bounding_region(). + + Parameters + ---------- + bounding_cell_id : int + The cell ID number to use for the bounding cell, defaults to 10000 to reduce + the chance of overlapping ID numbers with the DAGMC geometry. + + Returns + ------- + openmc.Universe + Universe instance + """ + bounding_cell = openmc.Cell( + fill=self, cell_id=bounding_cell_id, region=self.bounding_region(**kwargs)) + return openmc.Universe(cells=[bounding_cell]) + + @classmethod + def from_hdf5(cls, group): + """Create DAGMC universe from HDF5 group + + Parameters + ---------- + group : h5py.Group + Group in HDF5 file + + Returns + ------- + openmc.DAGMCUniverse + DAGMCUniverse instance + + """ + id = int(group.name.split('/')[-1].lstrip('universe ')) + fname = group['filename'][()].decode() + name = group['name'][()].decode() if 'name' in group else None + + out = cls(fname, universe_id=id, name=name) + + out.auto_geom_ids = bool(group.attrs['auto_geom_ids']) + out.auto_mat_ids = bool(group.attrs['auto_mat_ids']) + + return out + + @classmethod + def from_xml_element(cls, elem): + """Generate DAGMC universe from XML element + + Parameters + ---------- + elem : lxml.etree._Element + `` element + + Returns + ------- + openmc.DAGMCUniverse + DAGMCUniverse instance + + """ + id = int(get_text(elem, 'id')) + fname = get_text(elem, 'filename') + + out = cls(fname, universe_id=id) + + name = get_text(elem, 'name') + if name is not None: + out.name = name + + out.auto_geom_ids = bool(elem.get('auto_geom_ids')) + out.auto_mat_ids = bool(elem.get('auto_mat_ids')) + + return out + + def _partial_deepcopy(self): + """Clone all of the openmc.DAGMCUniverse object's attributes except for + its cells, as they are copied within the clone function. This should + only to be used within the openmc.UniverseBase.clone() context. + """ + clone = openmc.DAGMCUniverse(name=self.name, filename=self.filename) + clone.volume = self.volume + clone.auto_geom_ids = self.auto_geom_ids + clone.auto_mat_ids = self.auto_mat_ids + return clone diff --git a/openmc/utility_funcs.py b/openmc/utility_funcs.py new file mode 100644 index 00000000000..4eb307c9303 --- /dev/null +++ b/openmc/utility_funcs.py @@ -0,0 +1,38 @@ +from contextlib import contextmanager +import os +from pathlib import Path +from tempfile import TemporaryDirectory +from typing import Optional + +from .checkvalue import PathLike + +@contextmanager +def change_directory(working_dir: Optional[PathLike] = None, *, tmpdir: bool = False): + """Context manager for executing in a provided working directory + + Parameters + ---------- + working_dir : path-like + Directory to switch to. + tmpdir : bool + Whether to use a temporary directory instead of a specific working directory + + """ + orig_dir = Path.cwd() + + # Set up temporary directory if requested + if tmpdir: + tmp = TemporaryDirectory() + working_dir = tmp.name + elif working_dir is None: + raise ValueError('Must pass working_dir argument or specify tmpdir=True.') + + working_dir = Path(working_dir) + working_dir.mkdir(parents=True, exist_ok=True) + os.chdir(working_dir) + try: + yield + finally: + os.chdir(orig_dir) + if tmpdir: + tmp.cleanup() diff --git a/openmc/volume.py b/openmc/volume.py index 7a9ef173719..df19def1eac 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -1,16 +1,16 @@ -from collections import OrderedDict from collections.abc import Iterable, Mapping from numbers import Real, Integral -from xml.etree import ElementTree as ET import warnings +import h5py +import lxml.etree as ET import numpy as np import pandas as pd -import h5py from uncertainties import ufloat import openmc import openmc.checkvalue as cv +from openmc._xml import get_text _VERSION_VOLUME = 1 @@ -55,7 +55,7 @@ class VolumeCalculation: volumes : dict Dictionary mapping unique IDs of domains to estimated volumes in cm^3. threshold : float - Threshold for the maxmimum standard deviation of volumes. + Threshold for the maximum standard deviation of volumes. .. versionadded:: 0.12 trigger_type : {'variance', 'std_dev', 'rel_err'} @@ -101,10 +101,10 @@ def __init__(self, domains, samples, lower_left=None, upper_right=None): continue if (np.any(np.asarray(lower_left) > ll) or np.any(np.asarray(upper_right) < ur)): - warnings.warn( - "Specified bounding box is smaller than computed " - "bounding box for cell {}. Volume calculation may " - "be incorrect!".format(c.id)) + msg = ('Specified bounding box is smaller than ' + f'computed bounding box for cell {c.id}. Volume ' + 'calculation may be incorrect!') + warnings.warn(msg) self.lower_left = lower_left self.upper_right = upper_right @@ -121,67 +121,33 @@ def __init__(self, domains, samples, lower_left=None, upper_right=None): raise ValueError('Could not automatically determine bounding box ' 'for stochastic volume calculation.') + if np.isinf(self.lower_left).any() or np.isinf(self.upper_right).any(): + raise ValueError('Lower-left and upper-right bounding box ' + 'coordinates must be finite.') + @property def ids(self): return self._ids - @property - def samples(self): - return self._samples - - @property - def lower_left(self): - return self._lower_left - - @property - def upper_right(self): - return self._upper_right - - @property - def threshold(self): - return self._threshold - - @property - def trigger_type(self): - return self._trigger_type - - @property - def iterations(self): - return self._iterations - - @property - def domain_type(self): - return self._domain_type - - @property - def atoms(self): - return self._atoms - - @property - def volumes(self): - return self._volumes - - @property - def atoms_dataframe(self): - items = [] - columns = [self.domain_type.capitalize(), 'Nuclide', 'Atoms'] - for uid, atoms_dict in self.atoms.items(): - for name, atoms in atoms_dict.items(): - items.append((uid, name, atoms)) - - return pd.DataFrame.from_records(items, columns=columns) - @ids.setter def ids(self, ids): cv.check_type('domain IDs', ids, Iterable, Real) self._ids = ids + @property + def samples(self): + return self._samples + @samples.setter def samples(self, samples): cv.check_type('number of samples', samples, Integral) cv.check_greater_than('number of samples', samples, 0) self._samples = samples + @property + def lower_left(self): + return self._lower_left + @lower_left.setter def lower_left(self, lower_left): name = 'lower-left bounding box coordinates', @@ -189,6 +155,10 @@ def lower_left(self, lower_left): cv.check_length(name, lower_left, 3) self._lower_left = lower_left + @property + def upper_right(self): + return self._upper_right + @upper_right.setter def upper_right(self, upper_right): name = 'upper-right bounding box coordinates' @@ -196,6 +166,10 @@ def upper_right(self, upper_right): cv.check_length(name, upper_right, 3) self._upper_right = upper_right + @property + def threshold(self): + return self._threshold + @threshold.setter def threshold(self, threshold): name = 'volume std. dev. threshold' @@ -203,12 +177,20 @@ def threshold(self, threshold): cv.check_greater_than(name, threshold, 0.0) self._threshold = threshold + @property + def trigger_type(self): + return self._trigger_type + @trigger_type.setter def trigger_type(self, trigger_type): cv.check_value('tally trigger type', trigger_type, ('variance', 'std_dev', 'rel_err')) self._trigger_type = trigger_type + @property + def iterations(self): + return self._iterations + @iterations.setter def iterations(self, iterations): name = 'volume calculation iterations' @@ -216,25 +198,47 @@ def iterations(self, iterations): cv.check_greater_than(name, iterations, 0) self._iterations = iterations - @volumes.setter - def volumes(self, volumes): - cv.check_type('volumes', volumes, Mapping) - self._volumes = volumes + @property + def domain_type(self): + return self._domain_type + + @property + def atoms(self): + return self._atoms @atoms.setter def atoms(self, atoms): cv.check_type('atoms', atoms, Mapping) self._atoms = atoms + @property + def volumes(self): + return self._volumes + + @volumes.setter + def volumes(self, volumes): + cv.check_type('volumes', volumes, Mapping) + self._volumes = volumes + + @property + def atoms_dataframe(self): + items = [] + columns = [self.domain_type.capitalize(), 'Nuclide', 'Atoms'] + for uid, atoms_dict in self.atoms.items(): + for name, atoms in atoms_dict.items(): + items.append((uid, name, atoms)) + + return pd.DataFrame.from_records(items, columns=columns) + def set_trigger(self, threshold, trigger_type): - """Set a trigger on the voulme calculation + """Set a trigger on the volume calculation .. versionadded:: 0.12 Parameters ---------- threshold : float - Threshold for the maxmimum standard deviation of volumes + Threshold for the maximum standard deviation of volumes trigger_type : {'variance', 'std_dev', 'rel_err'} Value type used to halt volume calculation """ @@ -280,7 +284,7 @@ def from_hdf5(cls, filename): volumes[domain_id] = volume nucnames = group['nuclides'][()] atoms_ = group['atoms'][()] - atom_dict = OrderedDict() + atom_dict = {} for name_i, atoms_i in zip(nucnames, atoms_): atom_dict[name_i.decode()] = ufloat(*atoms_i) atoms[domain_id] = atom_dict @@ -332,7 +336,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing volume calculation data """ @@ -352,3 +356,51 @@ def to_xml_element(self): trigger_elem.set("type", self.trigger_type) trigger_elem.set("threshold", str(self.threshold)) return element + + @classmethod + def from_xml_element(cls, elem): + """Generate volume calculation object from an XML element + + .. versionadded:: 0.13.0 + + Parameters + ---------- + elem : lxml.etree._Element + XML element + + Returns + ------- + openmc.VolumeCalculation + Volume calculation object + + """ + domain_type = get_text(elem, "domain_type") + domain_ids = get_text(elem, "domain_ids").split() + ids = [int(x) for x in domain_ids] + samples = int(get_text(elem, "samples")) + lower_left = get_text(elem, "lower_left").split() + lower_left = tuple([float(x) for x in lower_left]) + upper_right = get_text(elem, "upper_right").split() + upper_right = tuple([float(x) for x in upper_right]) + + # Instantiate some throw-away domains that are used by the constructor + # to assign IDs + with warnings.catch_warnings(): + warnings.simplefilter('ignore', openmc.IDWarning) + if domain_type == 'cell': + domains = [openmc.Cell(uid) for uid in ids] + elif domain_type == 'material': + domains = [openmc.Material(uid) for uid in ids] + elif domain_type == 'universe': + domains = [openmc.Universe(uid) for uid in ids] + + vol = cls(domains, samples, lower_left, upper_right) + + # Check for trigger + trigger_elem = elem.find("threshold") + if trigger_elem is not None: + trigger_type = get_text(trigger_elem, "type") + threshold = float(get_text(trigger_elem, "threshold")) + vol.set_trigger(threshold, trigger_type) + + return vol diff --git a/openmc/weight_windows.py b/openmc/weight_windows.py new file mode 100644 index 00000000000..96f1db89282 --- /dev/null +++ b/openmc/weight_windows.py @@ -0,0 +1,941 @@ +from __future__ import annotations +from numbers import Real, Integral +from typing import Iterable, List, Optional, Dict, Sequence +import warnings + +import lxml.etree as ET +import numpy as np +import h5py + +import openmc +from openmc.filter import _PARTICLES +from openmc.mesh import MeshBase, RectilinearMesh, CylindricalMesh, SphericalMesh, UnstructuredMesh +import openmc.checkvalue as cv +from openmc.checkvalue import PathLike +from ._xml import get_text, clean_indentation +from .mixin import IDManagerMixin + + +class WeightWindows(IDManagerMixin): + """Mesh-based weight windows + + This class enables you to specify weight window parameters that are used in + a simulation. Multiple sets of weight windows can be defined for different + meshes and different particles. An iterable of :class:`WeightWindows` + instances can be assigned to the :attr:`openmc.Settings.weight_windows` + attribute, which is then exported to XML. + + Weight window lower/upper bounds are to be specified for each combination of + a mesh element and an energy bin. Thus the total number of bounds should be + equal to the product of the number of mesh bins and the number of energy + bins. + + .. versionadded:: 0.13 + + Parameters + ---------- + mesh : openmc.MeshBase + Mesh for the weight windows + lower_ww_bounds : Iterable of Real + A list of values for which each value is the lower bound of a weight + window + upper_ww_bounds : Iterable of Real + A list of values for which each value is the upper bound of a weight + window + upper_bound_ratio : float + Ratio of the lower to upper weight window bounds + energy_bounds : Iterable of Real + A list of values for which each successive pair constitutes a range of + energies in [eV] for a single bin. If no energy bins are provided, the + maximum and minimum energy for the data available at runtime. + particle_type : {'neutron', 'photon'} + Particle type the weight windows apply to + survival_ratio : float + Ratio of the survival weight to the lower weight window bound for + rouletting + max_lower_bound_ratio : float + Maximum allowed ratio of a particle's weight to the weight window's + lower bound. A factor will be applied to raise the weight window to be + lower than the particle's weight by a factor of max_lower_bound_ratio + during transport if exceeded. + max_split : int + Maximum allowable number of particles when splitting + weight_cutoff : float + Threshold below which particles will be terminated + id : int + Unique identifier for the weight window settings. If not specified, an + identifier will automatically be assigned. + + Attributes + ---------- + id : int + Unique identifier for the weight window settings. + mesh : openmc.MeshBase + Mesh for the weight windows with dimension (ni, nj, nk) + particle_type : str + Particle type the weight windows apply to + energy_bounds : Iterable of Real + A list of values for which each successive pair constitutes a range of + energies in [eV] for a single bin + num_energy_bins : int + Number of energy bins + lower_ww_bounds : numpy.ndarray of float + An array of values for which each value is the lower bound of a weight + window. Shape: (ni, nj, nk, num_energy_bins) for StructuredMesh; + (num_elements, num_energy_bins) for UnstructuredMesh + upper_ww_bounds : numpy.ndarray of float + An array of values for which each value is the upper bound of a weight + window. Shape: (ni, nj, nk, num_energy_bins) for StructuredMesh; + (num_elements, num_energy_bins) for UnstructuredMesh + survival_ratio : float + Ratio of the survival weight to the lower weight window bound for + rouletting + max_lower_bound_ratio: float + Maximum allowed ratio of a particle's weight to the weight window's + lower bound. (Default: 1.0) + max_split : int + Maximum allowable number of particles when splitting + weight_cutoff : float + Threshold below which particles will be terminated + + See Also + -------- + openmc.Settings + + """ + next_id = 1 + used_ids = set() + + def __init__( + self, + mesh: MeshBase, + lower_ww_bounds: Iterable[float], + upper_ww_bounds: Optional[Iterable[float]] = None, + upper_bound_ratio: Optional[float] = None, + energy_bounds: Optional[Iterable[Real]] = None, + particle_type: str = 'neutron', + survival_ratio: float = 3, + max_lower_bound_ratio: Optional[float] = None, + max_split: int = 10, + weight_cutoff: float = 1.e-38, + id: Optional[int] = None + ): + self.mesh = mesh + self.id = id + self.particle_type = particle_type + self._energy_bounds = None + if energy_bounds is not None: + self.energy_bounds = energy_bounds + self.lower_ww_bounds = lower_ww_bounds + + if upper_ww_bounds is not None and upper_bound_ratio: + raise ValueError("Exactly one of upper_ww_bounds and " + "upper_bound_ratio must be present.") + + if upper_ww_bounds is None and upper_bound_ratio is None: + raise ValueError("Exactly one of upper_ww_bounds and " + "upper_bound_ratio must be present.") + + if upper_bound_ratio: + self.upper_ww_bounds = [ + lb * upper_bound_ratio for lb in self.lower_ww_bounds + ] + + if upper_ww_bounds is not None: + self.upper_ww_bounds = upper_ww_bounds + + if len(self.lower_ww_bounds) != len(self.upper_ww_bounds): + raise ValueError('Size of the lower and upper weight ' + 'window bounds do not match') + + self.survival_ratio = survival_ratio + + self._max_lower_bound_ratio = None + if max_lower_bound_ratio is not None: + self.max_lower_bound_ratio = max_lower_bound_ratio + + self.max_split = max_split + self.weight_cutoff = weight_cutoff + + def __repr__(self) -> str: + string = type(self).__name__ + '\n' + string += '{: <16}=\t{}\n'.format('\tID', self._id) + string += '{: <16}=\t{}\n'.format('\tMesh', self.mesh) + string += '{: <16}=\t{}\n'.format('\tParticle Type', self._particle_type) + string += '{: <16}=\t{}\n'.format('\tEnergy Bounds', self._energy_bounds) + string += '{: <16}=\t{}\n'.format('\tMax lower bound ratio', self.max_lower_bound_ratio) + string += '{: <16}=\t{}\n'.format('\tLower WW Bounds', self._lower_ww_bounds) + string += '{: <16}=\t{}\n'.format('\tUpper WW Bounds', self._upper_ww_bounds) + string += '{: <16}=\t{}\n'.format('\tSurvival Ratio', self._survival_ratio) + string += '{: <16}=\t{}\n'.format('\tMax Split', self._max_split) + string += '{: <16}=\t{}\n'.format('\tWeight Cutoff', self._weight_cutoff) + return string + + def __eq__(self, other: WeightWindows) -> bool: + # ensure that `other` is a WeightWindows object + if not isinstance(other, WeightWindows): + return False + + # TODO: add ability to check mesh equality + + # check several attributes directly + attrs = ('particle_type', + 'survival_ratio', + 'max_lower_bound_ratio', + 'max_split', + 'weight_cutoff') + for attr in attrs: + if getattr(self, attr) != getattr(other, attr): + return False + + # save most expensive checks for last + if not np.array_equal(self.energy_bounds, other.energy_bounds): + return False + + if not np.array_equal(self.lower_ww_bounds, other.lower_ww_bounds): + return False + + if not np.array_equal(self.upper_ww_bounds, other.upper_ww_bounds): + return False + + return True + + @property + def mesh(self) -> MeshBase: + return self._mesh + + @mesh.setter + def mesh(self, mesh: MeshBase): + cv.check_type('Weight window mesh', mesh, MeshBase) + self._mesh = mesh + + @property + def particle_type(self) -> str: + return self._particle_type + + @particle_type.setter + def particle_type(self, pt: str): + cv.check_value('Particle type', pt, _PARTICLES) + self._particle_type = pt + + @property + def energy_bounds(self) -> Iterable[Real]: + return self._energy_bounds + + @energy_bounds.setter + def energy_bounds(self, bounds: Iterable[float]): + cv.check_type('Energy bounds', bounds, Iterable, Real) + self._energy_bounds = np.asarray(bounds) + + @property + def num_energy_bins(self) -> int: + if self.energy_bounds is None: + return 1 + return self.energy_bounds.size - 1 + + @property + def lower_ww_bounds(self) -> np.ndarray: + return self._lower_ww_bounds + + @lower_ww_bounds.setter + def lower_ww_bounds(self, bounds: Iterable[float]): + cv.check_iterable_type('Lower WW bounds', + bounds, + Real, + min_depth=1, + max_depth=4) + # reshape data according to mesh and energy bins + bounds = np.asarray(bounds) + if isinstance(self.mesh, UnstructuredMesh): + bounds = bounds.reshape(-1, self.num_energy_bins) + else: + bounds = bounds.reshape(*self.mesh.dimension, self.num_energy_bins) + self._lower_ww_bounds = bounds + + @property + def upper_ww_bounds(self) -> np.ndarray: + return self._upper_ww_bounds + + @upper_ww_bounds.setter + def upper_ww_bounds(self, bounds: Iterable[float]): + cv.check_iterable_type('Upper WW bounds', + bounds, + Real, + min_depth=1, + max_depth=4) + # reshape data according to mesh and energy bins + bounds = np.asarray(bounds) + if isinstance(self.mesh, UnstructuredMesh): + bounds = bounds.reshape(-1, self.num_energy_bins) + else: + bounds = bounds.reshape(*self.mesh.dimension, self.num_energy_bins) + self._upper_ww_bounds = bounds + + @property + def survival_ratio(self) -> float: + return self._survival_ratio + + @survival_ratio.setter + def survival_ratio(self, val: float): + cv.check_type('Survival ratio', val, Real) + cv.check_greater_than('Survival ratio', val, 1.0, True) + self._survival_ratio = val + + @property + def max_lower_bound_ratio(self) -> float: + return self._max_lower_bound_ratio + + @max_lower_bound_ratio.setter + def max_lower_bound_ratio(self, val: float): + cv.check_type('Maximum lower bound ratio', val, Real) + cv.check_greater_than('Maximum lower bound ratio', val, 1.0, equality=True) + self._max_lower_bound_ratio = val + + @property + def max_split(self) -> int: + return self._max_split + + @max_split.setter + def max_split(self, val: int): + cv.check_type('Max split', val, Integral) + self._max_split = val + + @property + def weight_cutoff(self) -> float: + return self._weight_cutoff + + @weight_cutoff.setter + def weight_cutoff(self, cutoff: float): + cv.check_type('Weight cutoff', cutoff, Real) + cv.check_greater_than('Weight cutoff', cutoff, 0.0, True) + self._weight_cutoff = cutoff + + def to_xml_element(self) -> ET.Element: + """Return an XML representation of the weight window settings + + Returns + ------- + element : lxml.etree._Element + XML element containing the weight window information + """ + element = ET.Element('weight_windows') + + element.set('id', str(self._id)) + + subelement = ET.SubElement(element, 'mesh') + subelement.text = str(self.mesh.id) + + subelement = ET.SubElement(element, 'particle_type') + subelement.text = self.particle_type + + subelement = ET.SubElement(element, 'energy_bounds') + subelement.text = ' '.join(str(e) for e in self.energy_bounds) + + subelement = ET.SubElement(element, 'lower_ww_bounds') + subelement.text = ' '.join(str(b) for b in self.lower_ww_bounds.ravel('F')) + + subelement = ET.SubElement(element, 'upper_ww_bounds') + subelement.text = ' '.join(str(b) for b in self.upper_ww_bounds.ravel('F')) + + subelement = ET.SubElement(element, 'survival_ratio') + subelement.text = str(self.survival_ratio) + + if self.max_lower_bound_ratio is not None: + subelement = ET.SubElement(element, 'max_lower_bound_ratio') + subelement.text = str(self.max_lower_bound_ratio) + + subelement = ET.SubElement(element, 'max_split') + subelement.text = str(self.max_split) + + subelement = ET.SubElement(element, 'weight_cutoff') + subelement.text = str(self.weight_cutoff) + + return element + + @classmethod + def from_xml_element(cls, elem: ET.Element, meshes: Dict[int, MeshBase]) -> WeightWindows: + """Generate weight window settings from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict + Dictionary mapping IDs to mesh objects + + Returns + ------- + openmc.WeightWindows + Weight windows object + """ + # Get mesh for weight windows + mesh_id = int(get_text(elem, 'mesh')) + if mesh_id not in meshes: + raise ValueError(f'Could not locate mesh with ID "{mesh_id}"') + mesh = meshes[mesh_id] + + # Read all other parameters + lower_ww_bounds = [float(l) for l in get_text(elem, 'lower_ww_bounds').split()] + upper_ww_bounds = [float(u) for u in get_text(elem, 'upper_ww_bounds').split()] + e_bounds = [float(b) for b in get_text(elem, 'energy_bounds').split()] + particle_type = get_text(elem, 'particle_type') + survival_ratio = float(get_text(elem, 'survival_ratio')) + + ww_shape = (len(e_bounds) - 1,) + mesh.dimension[::-1] + lower_ww_bounds = np.array(lower_ww_bounds).reshape(ww_shape).T + upper_ww_bounds = np.array(upper_ww_bounds).reshape(ww_shape).T + + max_lower_bound_ratio = None + if get_text(elem, 'max_lower_bound_ratio'): + max_lower_bound_ratio = float(get_text(elem, 'max_lower_bound_ratio')) + + max_split = int(get_text(elem, 'max_split')) + weight_cutoff = float(get_text(elem, 'weight_cutoff')) + id = int(get_text(elem, 'id')) + + return cls( + mesh=mesh, + lower_ww_bounds=lower_ww_bounds, + upper_ww_bounds=upper_ww_bounds, + energy_bounds=e_bounds, + particle_type=particle_type, + survival_ratio=survival_ratio, + max_lower_bound_ratio=max_lower_bound_ratio, + max_split=max_split, + weight_cutoff=weight_cutoff, + id=id + ) + + @classmethod + def from_hdf5(cls, group: h5py.Group, meshes: Dict[int, MeshBase]) -> WeightWindows: + """Create weight windows from HDF5 group + + Parameters + ---------- + group : h5py.Group + Group in HDF5 file + meshes : dict + Dictionary mapping IDs to mesh objects + + Returns + ------- + openmc.WeightWindows + A weight window object + """ + + id = int(group.name.split('/')[-1].lstrip('weight_windows')) + mesh_id = group['mesh'][()] + mesh = meshes[mesh_id] + + ptype = group['particle_type'][()].decode() + e_bounds = group['energy_bounds'][()] + # weight window bounds are stored with the shape (e, k, j, i) + # in C++ and HDF5 -- the opposite of how they are stored here + shape = (e_bounds.size - 1, *mesh.dimension[::-1]) + lower_ww_bounds = group['lower_ww_bounds'][()].reshape(shape).T + upper_ww_bounds = group['upper_ww_bounds'][()].reshape(shape).T + survival_ratio = group['survival_ratio'][()] + + max_lower_bound_ratio = None + if group.get('max_lower_bound_ratio') is not None: + max_lower_bound_ratio = group['max_lower_bound_ratio'][()] + + max_split = group['max_split'][()] + weight_cutoff = group['weight_cutoff'][()] + + return cls( + mesh=mesh, + lower_ww_bounds=lower_ww_bounds, + upper_ww_bounds=upper_ww_bounds, + energy_bounds=e_bounds, + particle_type=ptype, + survival_ratio=survival_ratio, + max_lower_bound_ratio=max_lower_bound_ratio, + max_split=max_split, + weight_cutoff=weight_cutoff, + id=id + ) + + +def wwinp_to_wws(path: PathLike) -> List[WeightWindows]: + """Create WeightWindows instances from a wwinp file + + .. versionadded:: 0.13.1 + + Parameters + ---------- + path : str or pathlib.Path + Path to the wwinp file + + Returns + ------- + list of openmc.WeightWindows + """ + + with open(path) as wwinp: + # BLOCK 1 + header = wwinp.readline().split(None, 4) + # read file type, time-dependence, number of + # particles, mesh type and problem identifier + _if, iv, ni, nr = [int(x) for x in header[:4]] + + # header value checks + if _if != 1: + raise ValueError(f'Found incorrect file type, if: {_if}') + + if iv > 1: + # read number of time bins for each particle, 'nt(1...ni)' + nt = np.fromstring(wwinp.readline(), sep=' ', dtype=int) + + # raise error if time bins are present for now + raise ValueError('Time-dependent weight windows ' + 'are not yet supported') + else: + nt = ni * [1] + + # read number of energy bins for each particle, 'ne(1...ni)' + ne = np.fromstring(wwinp.readline(), sep=' ', dtype=int) + + # read coarse mesh dimensions and lower left corner + mesh_description = np.fromstring(wwinp.readline(), sep=' ') + nfx, nfy, nfz = mesh_description[:3].astype(int) + xyz0 = mesh_description[3:] + + # read cylindrical and spherical mesh vectors if present + if nr == 16: + # read number of coarse bins + line_arr = np.fromstring(wwinp.readline(), sep=' ') + ncx, ncy, ncz = line_arr[:3].astype(int) + # read polar vector (x1, y1, z1) + xyz1 = line_arr[3:] + # read azimuthal vector (x2, y2, z2) + line_arr = np.fromstring(wwinp.readline(), sep=' ') + xyz2 = line_arr[:3] + + # oriented polar and azimuthal vectors aren't yet supported + if np.count_nonzero(xyz1) or np.count_nonzero(xyz2): + raise NotImplementedError('Custom sphere/cylinder orientations are not supported') + + # read geometry type + nwg = int(line_arr[-1]) + + elif nr == 10: + # read rectilinear data: + # number of coarse mesh bins and mesh type + ncx, ncy, ncz, nwg = \ + np.fromstring(wwinp.readline(), sep=' ').astype(int) + else: + raise RuntimeError(f'Invalid mesh description (nr) found: {nr}') + + # read BLOCK 2 and BLOCK 3 data into a single array + ww_data = np.fromstring(wwinp.read(), sep=' ') + + # extract mesh data from the ww_data array + start_idx = 0 + + # first values in the mesh definition arrays are the first + # coordinate of the grid + end_idx = start_idx + 1 + 3 * ncx + i0, i_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] + start_idx = end_idx + + end_idx = start_idx + 1 + 3 * ncy + j0, j_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] + start_idx = end_idx + + end_idx = start_idx + 1 + 3 * ncz + k0, k_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] + start_idx = end_idx + + # mesh consistency checks + if nr == 16 and nwg == 1 or nr == 10 and nwg != 1: + raise ValueError(f'Mesh description in header ({nr}) ' + f'does not match the mesh type ({nwg})') + + if nr == 10 and (xyz0 != (i0, j0, k0)).any(): + raise ValueError(f'Mesh origin in the header ({xyz0}) ' + f' does not match the origin in the mesh ' + f' description ({i0, j0, k0})') + + # create openmc mesh object + grids = [] + mesh_definition = [(i0, i_vals, nfx), (j0, j_vals, nfy), (k0, k_vals, nfz)] + for grid0, grid_vals, n_pnts in mesh_definition: + # file spec checks for the mesh definition + if (grid_vals[2::3] != 1.0).any(): + raise ValueError('One or more mesh ratio value, qx, ' + 'is not equal to one') + + s = int(grid_vals[::3].sum()) + if s != n_pnts: + raise ValueError(f'Sum of the fine bin entries, {s}, does ' + f'not match the number of fine bins, {n_pnts}') + + # extend the grid based on the next coarse bin endpoint, px + # and the number of fine bins in the coarse bin, sx + intervals = grid_vals.reshape(-1, 3) + coords = [grid0] + for sx, px, qx in intervals: + coords += np.linspace(coords[-1], px, int(sx + 1)).tolist()[1:] + + grids.append(np.array(coords)) + + if nwg == 1: + mesh = RectilinearMesh() + mesh.x_grid, mesh.y_grid, mesh.z_grid = grids + elif nwg == 2: + mesh = CylindricalMesh( + r_grid=grids[0], + z_grid=grids[1], + phi_grid=grids[2], + origin = xyz0, + ) + elif nwg == 3: + mesh = SphericalMesh( + r_grid=grids[0], + theta_grid=grids[1], + phi_grid=grids[2], + origin = xyz0 + ) + + # extract weight window values from array + wws = [] + for ne_i, nt_i, particle_type in zip(ne, nt, ('neutron', 'photon')): + # no information to read for this particle if + # either the energy bins or time bins are empty + if ne_i == 0 or nt_i == 0: + continue + + if iv > 1: + # time bins are parsed but unused for now + end_idx = start_idx + nt_i + time_bounds = ww_data[start_idx:end_idx] + np.insert(time_bounds, (0,), (0.0,)) + start_idx = end_idx + + # read energy boundaries + end_idx = start_idx + ne_i + energy_bounds = np.insert(ww_data[start_idx:end_idx], (0,), (0.0,)) + # convert from MeV to eV + energy_bounds *= 1e6 + start_idx = end_idx + + # read weight window values + end_idx = start_idx + (nfx * nfy * nfz) * nt_i * ne_i + + # read values and reshape according to ordering + # slowest to fastest: t, e, z, y, x + # reorder with transpose since our ordering is x, y, z, e, t + ww_shape = (nt_i, ne_i, nfz, nfy, nfx) + ww_values = ww_data[start_idx:end_idx].reshape(ww_shape).T + # Only use first time bin since we don't support time dependent weight + # windows yet. + ww_values = ww_values[:, :, :, :, 0] + start_idx = end_idx + + # create a weight window object + ww = WeightWindows(id=None, + mesh=mesh, + lower_ww_bounds=ww_values, + upper_bound_ratio=5.0, + energy_bounds=energy_bounds, + particle_type=particle_type) + wws.append(ww) + + return wws + + +class WeightWindowGenerator: + """Class passed to setting to govern weight window generation + using the OpenMC executable + + Parameters + ---------- + mesh : :class:`openmc.MeshBase` + Mesh used to represent the weight windows spatially + energy_bounds : Iterable of Real + A list of values for which each successive pair constitutes a range of + energies in [eV] for a single bin. If no energy bins are provided, the + maximum and minimum energy for the data available at runtime. + particle_type : {'neutron', 'photon'} + Particle type the weight windows apply to + method : {'magic'} + The weight window generation methodology applied during an update. Only + 'magic' is currently supported. + max_realizations : int + The upper limit for number of tally realizations when generating weight + windows. + update_interval : int + The number of tally realizations between updates. + on_the_fly : bool + Whether or not to apply weight windows on the fly. + + Attributes + ---------- + mesh : openmc.MeshBase + Mesh used to represent the weight windows spatially + energy_bounds : Iterable of Real + A list of values for which each successive pair constitutes a range of + energies in [eV] for a single bin + particle_type : {'neutron', 'photon'} + Particle type the weight windows apply to + method : {'magic'} + The weight window generation methodology applied during an update. Only + 'magic' is currently supported. + max_realizations : int + The upper limit for number of tally realizations when generating weight + windows. + update_interval : int + The number of tally realizations between updates. + update_parameters : dict + A set of parameters related to the update. + on_the_fly : bool + Whether or not to apply weight windows on the fly. + """ + + _MAGIC_PARAMS = {'value': str, 'threshold': float, 'ratio': float} + + def __init__( + self, + mesh: openmc.MeshBase, + energy_bounds: Optional[Sequence[float]] = None, + particle_type: str = 'neutron', + method: str = 'magic', + max_realizations: int = 1, + update_interval: int = 1, + on_the_fly: bool = True + ): + self._update_parameters = None + + self.mesh = mesh + self._energy_bounds = None + if energy_bounds is not None: + self.energy_bounds = energy_bounds + self.particle_type = particle_type + self.method = method + self.max_realizations = max_realizations + self.update_interval = update_interval + self.on_the_fly = on_the_fly + + def __repr__(self): + string = type(self).__name__ + '\n' + string += f'\t{"Mesh":<20}=\t{self.mesh.id}\n' + string += f'\t{"Particle:":<20}=\t{self.particle_type}\n' + string += f'\t{"Energy Bounds:":<20}=\t{self.energy_bounds}\n' + string += f'\t{"Method":<20}=\t{self.method}\n' + string += f'\t{"Max Realizations:":<20}=\t{self.max_realizations}\n' + string += f'\t{"Update Interval:":<20}=\t{self.update_interval}\n' + string += f'\t{"On The Fly:":<20}=\t{self.on_the_fly}\n' + if self.update_parameters is not None: + string += f'\t{"Update Parameters:":<20}\n\t\t\t{self.update_parameters}\n' + string + + return string + + @property + def mesh(self) -> openmc.MeshBase: + return self._mesh + + @mesh.setter + def mesh(self, m: openmc.MeshBase): + cv.check_type('mesh', m, openmc.MeshBase) + self._mesh = m + + @property + def energy_bounds(self) -> Iterable[Real]: + return self._energy_bounds + + @energy_bounds.setter + def energy_bounds(self, eb: Iterable[float]): + cv.check_type('energy bounds', eb, Iterable, Real) + self._energy_bounds = eb + + @property + def particle_type(self) -> str: + return self._particle_type + + @particle_type.setter + def particle_type(self, pt: str): + cv.check_value('particle type', pt, ('neutron', 'photon')) + self._particle_type = pt + + @property + def method(self) -> str: + return self._method + + @method.setter + def method(self, m: str): + cv.check_type('generation method', m, str) + cv.check_value('generation method', m, {'magic'}) + self._method = m + if self._update_parameters is not None: + try: + self._check_update_parameters() + except (TypeError, KeyError): + warnings.warn(f'Update parameters are invalid for the "{m}" method.') + + @property + def max_realizations(self) -> int: + return self._max_realizations + + @max_realizations.setter + def max_realizations(self, m: int): + cv.check_type('max tally realizations', m, Integral) + cv.check_greater_than('max tally realizations', m, 0) + self._max_realizations = m + + @property + def update_interval(self) -> int: + return self._update_interval + + @update_interval.setter + def update_interval(self, ui: int): + cv.check_type('update interval', ui, Integral) + cv.check_greater_than('update interval', ui , 0) + self._update_interval = ui + + @property + def update_parameters(self) -> dict: + return self._update_parameters + + def _check_update_parameters(self, params: dict): + if self.method == 'magic': + check_params = self._MAGIC_PARAMS + + for key, val in params.items(): + if key not in check_params: + raise ValueError(f'Invalid param "{key}" for {self.method} ' + 'weight window generation') + cv.check_type(f'weight window generation param: "{key}"', val, self._MAGIC_PARAMS[key]) + + @update_parameters.setter + def update_parameters(self, params: dict): + self._check_update_parameters(params) + self._update_parameters = params + + @property + def on_the_fly(self) -> bool: + return self._on_the_fly + + @on_the_fly.setter + def on_the_fly(self, otf: bool): + cv.check_type('on the fly generation', otf, bool) + self._on_the_fly = otf + + def _update_parameters_subelement(self, element: ET.Element): + if not self.update_parameters: + return + params_element = ET.SubElement(element, 'update_parameters') + for pname, value in self.update_parameters.items(): + param_element = ET.SubElement(params_element, pname) + param_element.text = str(value) + + @classmethod + def _sanitize_update_parameters(cls, method: str, update_parameters: dict): + """ + Attempt to convert update parameters to their appropriate types + + Parameters + ---------- + method : str + The update method for which these update parameters should comply + update_parameters : dict + The update parameters as-read from the XML node (keys: str, values: str) + """ + if method == 'magic': + check_params = cls._MAGIC_PARAMS + + for param, param_type in check_params.items(): + if param in update_parameters: + update_parameters[param] = param_type(update_parameters[param]) + + def to_xml_element(self): + """Creates a 'weight_window_generator' element to be written to an XML file. + """ + element = ET.Element('weight_windows_generator') + + mesh_elem = ET.SubElement(element, 'mesh') + mesh_elem.text = str(self.mesh.id) + if self.energy_bounds is not None: + subelement = ET.SubElement(element, 'energy_bounds') + subelement.text = ' '.join(str(e) for e in self.energy_bounds) + particle_elem = ET.SubElement(element, 'particle_type') + particle_elem.text = self.particle_type + realizations_elem = ET.SubElement(element, 'max_realizations') + realizations_elem.text = str(self.max_realizations) + update_interval_elem = ET.SubElement(element, 'update_interval') + update_interval_elem.text = str(self.update_interval) + otf_elem = ET.SubElement(element, 'on_the_fly') + otf_elem.text = str(self.on_the_fly).lower() + method_elem = ET.SubElement(element, 'method') + method_elem.text = self.method + if self.update_parameters is not None: + self._update_parameters_subelement(element) + + clean_indentation(element) + + return element + + @classmethod + def from_xml_element(cls, elem: ET.Element, meshes: dict) -> WeightWindowGenerator: + """ + Create a weight window generation object from an XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + meshes : dict + A dictionary with IDs as keys and openmc.MeshBase instances as values + + Returns + ------- + openmc.WeightWindowGenerator + """ + + mesh_id = int(get_text(elem, 'mesh')) + mesh = meshes[mesh_id] + + energy_bounds = [float(x) for x in get_text(elem, 'energy_bounds').split()] + particle_type = get_text(elem, 'particle_type') + + wwg = cls(mesh, energy_bounds, particle_type) + + wwg.max_realizations = int(get_text(elem, 'max_realizations')) + wwg.update_interval = int(get_text(elem, 'update_interval')) + wwg.on_the_fly = bool(get_text(elem, 'on_the_fly')) + wwg.method = get_text(elem, 'method') + + if elem.find('update_parameters') is not None: + update_parameters = {} + params_elem = elem.find('update_parameters') + for entry in params_elem: + update_parameters[entry.tag] = entry.text + + cls._sanitize_update_parameters(wwg.method, update_parameters) + wwg.update_parameters = update_parameters + + return wwg + +def hdf5_to_wws(path='weight_windows.h5'): + """Create WeightWindows instances from a weight windows HDF5 file + + .. versionadded:: 0.14.0 + + Parameters + ---------- + path : cv.PathLike + Path to the weight windows hdf5 file + + Returns + ------- + list of openmc.WeightWindows + """ + + with h5py.File(path) as h5_file: + # read in all of the meshes in the mesh node + meshes = {} + for mesh_group in h5_file['meshes']: + mesh = MeshBase.from_hdf5(h5_file['meshes'][mesh_group]) + meshes[mesh.id] = mesh + return [WeightWindows.from_hdf5(ww, meshes) for ww in h5_file['weight_windows'].values()] diff --git a/schemas.xml b/schemas.xml deleted file mode 100644 index 3e586ec6ac7..00000000000 --- a/schemas.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/scripts/openmc-ace-to-hdf5 b/scripts/openmc-ace-to-hdf5 index 3aeb95198e4..66ae7e2a948 100755 --- a/scripts/openmc-ace-to-hdf5 +++ b/scripts/openmc-ace-to-hdf5 @@ -28,103 +28,129 @@ import openmc.data from openmc.data.ace import TableType -class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, - argparse.RawDescriptionHelpFormatter): - pass - - -parser = argparse.ArgumentParser( - description=__doc__, - formatter_class=CustomFormatter -) -parser.add_argument('libraries', nargs='*', - help='ACE libraries to convert to HDF5') -parser.add_argument('-d', '--destination', type=Path, default=Path.cwd(), - help='Directory to create new library in') -parser.add_argument('-m', '--metastable', choices=['mcnp', 'nndc'], - default='nndc', - help='How to interpret ZAIDs for metastable nuclides') -parser.add_argument('--xsdir', help='MCNP xsdir file that lists ' - 'ACE libraries') -parser.add_argument('--xsdata', help='Serpent xsdata file that lists ' - 'ACE libraries') -parser.add_argument('--libver', choices=['earliest', 'latest'], - default='earliest', help="Output HDF5 versioning. Use " - "'earliest' for backwards compatibility or 'latest' for " - "performance") -args = parser.parse_args() - -if not args.destination.is_dir(): - args.destination.mkdir(parents=True, exist_ok=True) - -ace_libraries = [] -if args.xsdir is not None: - ace_libraries.extend(openmc.data.ace.get_libraries_from_xsdir(args.xsdir)) -elif args.xsdata is not None: - ace_libraries.extend(openmc.data.ace.get_libraries_from_xsdata(args.xsdata)) -else: - ace_libraries = [Path(lib) for lib in args.libraries] - -converted = {} -library = openmc.data.DataLibrary() - -for path in ace_libraries: - # Check that ACE library exists - if not os.path.exists(path): - warnings.warn("ACE library '{}' does not exist.".format(path)) - continue - - lib = openmc.data.ace.Library(path) - for table in lib.tables: - # Check type of the ACE table and determine appropriate class / - # conversion function - if table.data_type == TableType.NEUTRON_CONTINUOUS: - name = table.zaid - cls = openmc.data.IncidentNeutron - converter = partial(cls.from_ace, metastable_scheme=args.metastable) - elif table.data_type == TableType.THERMAL_SCATTERING: - # Adjust name to be the new thermal scattering name - name = openmc.data.get_thermal_name(table.zaid) - cls = openmc.data.ThermalScattering - converter = cls.from_ace - else: - print("Can't convert ACE table {}".format(table.name)) +def ace_to_hdf5(destination, xsdir, xsdata, libraries, metastable, libver): + + if not destination.is_dir(): + destination.mkdir(parents=True, exist_ok=True) + + ace_libraries = [] + if xsdir is not None: + ace_libraries.extend(openmc.data.ace.get_libraries_from_xsdir(xsdir)) + elif xsdata is not None: + ace_libraries.extend(openmc.data.ace.get_libraries_from_xsdata(xsdata)) + else: + ace_libraries = [Path(lib) for lib in libraries] + + converted = {} + library = openmc.data.DataLibrary() + + for path in ace_libraries: + # Check that ACE library exists + if not os.path.exists(path): + warnings.warn(f"ACE library '{path}' does not exist.") continue - if name not in converted: - try: - data = converter(table) - except Exception as e: - print('Failed to convert {}: {}'.format(table.name, e)) + lib = openmc.data.ace.Library(path) + for table in lib.tables: + # Check type of the ACE table and determine appropriate class / + # conversion function + if table.data_type == TableType.NEUTRON_CONTINUOUS: + name = table.zaid + cls = openmc.data.IncidentNeutron + converter = partial(cls.from_ace, metastable_scheme=metastable) + elif table.data_type == TableType.THERMAL_SCATTERING: + # Adjust name to be the new thermal scattering name + name = openmc.data.get_thermal_name(table.zaid) + cls = openmc.data.ThermalScattering + converter = cls.from_ace + else: + print(f"Can't convert ACE table {table.name}") continue - print('Converting {} (ACE) to {} (HDF5)'.format(table.name, data.name)) - - # Determine output filename - outfile = args.destination / (data.name.replace('.', '_') + '.h5') - data.export_to_hdf5(outfile, 'w', libver=args.libver) - - # Register with library - library.register_file(outfile) - - # Add nuclide to list - converted[name] = outfile - else: - # Read existing HDF5 file - data = cls.from_hdf5(converted[name]) - - # Add data for new temperature - try: - print('Converting {} (ACE) to {} (HDF5)' - .format(table.name, data.name)) - data.add_temperature_from_ace(table, args.metastable) - except Exception as e: - print('Failed to convert {}: {}'.format(table.name, e)) - continue - - # Re-export - data.export_to_hdf5(converted[name] + '_1', 'w', libver=args.libver) - os.rename(converted[name] + '_1', converted[name]) - -# Write cross_sections.xml -library.export_to_xml(args.destination / 'cross_sections.xml') + if name not in converted: + try: + data = converter(table) + except Exception as e: + print(f"Failed to convert {table.name}: {e}") + continue + + print(f"Converting {table.name} (ACE) to {data.name} (HDF5)") + + # Determine output filename + outfile = destination / (data.name.replace(".", "_") + ".h5") + data.export_to_hdf5(outfile, "w", libver=libver) + + # Register with library + library.register_file(outfile) + + # Add nuclide to list + converted[name] = outfile + else: + # Read existing HDF5 file + data = cls.from_hdf5(converted[name]) + + # Add data for new temperature + try: + print(f"Converting {table.name} (ACE) to {data.name} (HDF5)") + if table.data_type == TableType.NEUTRON_CONTINUOUS: + data.add_temperature_from_ace(table, metastable) + else: + data.add_temperature_from_ace(table) + except Exception as e: + print(f"Failed to convert {table.name}: {e}") + continue + + # Re-export + data.export_to_hdf5(converted[name], "w", libver=libver) + + # Write cross_sections.xml + library.export_to_xml(destination / "cross_sections.xml") + + +if __name__ == "__main__": + + class CustomFormatter( + argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter + ): + pass + + parser = argparse.ArgumentParser( + description=__doc__, formatter_class=CustomFormatter + ) + parser.add_argument("libraries", nargs="*", help="ACE libraries to convert to HDF5") + parser.add_argument( + "-d", + "--destination", + type=Path, + default=Path.cwd(), + help="Directory to create new library in", + ) + parser.add_argument( + "-m", + "--metastable", + choices=["mcnp", "nndc"], + default="nndc", + help="How to interpret ZAIDs for metastable nuclides", + ) + parser.add_argument("--xsdir", help="MCNP xsdir file that lists " "ACE libraries") + parser.add_argument( + "--xsdata", help="Serpent xsdata file that lists " "ACE libraries" + ) + parser.add_argument( + "--libver", + choices=["earliest", "latest"], + default="earliest", + help="Output HDF5 versioning. Use " + "'earliest' for backwards compatibility or 'latest' " + "for performance", + ) + args = parser.parse_args() + + ace_to_hdf5( + destination=args.destination, + xsdir=args.xsdir, + xsdata=args.xsdata, + libraries=args.libraries, + metastable=args.metastable, + libver=args.libver, + ) diff --git a/scripts/openmc-make-test-data b/scripts/openmc-make-test-data deleted file mode 100755 index 4d26db7fb06..00000000000 --- a/scripts/openmc-make-test-data +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env python3 - -""" -Download ENDF/B-VII.1 ENDF and ACE files from NNDC and WMP files from GitHub and -generate a full HDF5 library with incident neutron, incident photon, thermal -scattering data, and windowed multipole data. This data is used for OpenMC's -regression test suite. -""" - -import glob -import os -from pathlib import Path -import tarfile -import tempfile -from urllib.parse import urljoin -import zipfile - -import openmc.data -from openmc._utils import download - -base_ace = 'https://www.nndc.bnl.gov/endf/b7.1/aceFiles/' -base_endf = 'https://www.nndc.bnl.gov/endf/b7.1/zips/' -base_wmp = 'https://github.com/mit-crpg/WMP_Library/releases/download/v1.1/' -files = [ - (base_ace, 'ENDF-B-VII.1-neutron-293.6K.tar.gz', '9729a17eb62b75f285d8a7628ace1449'), - (base_ace, 'ENDF-B-VII.1-tsl.tar.gz', 'e17d827c92940a30f22f096d910ea186'), - (base_endf, 'ENDF-B-VII.1-neutrons.zip', 'e5d7f441fc4c92893322c24d1725e29c'), - (base_endf, 'ENDF-B-VII.1-photoat.zip', '5192f94e61f0b385cf536f448ffab4a4'), - (base_endf, 'ENDF-B-VII.1-atomic_relax.zip', 'fddb6035e7f2b6931e51a58fc754bd10'), - (base_wmp, 'WMP_Library_v1.1.tar.gz', '8523895928dd6ba63fba803e3a45d4f3') -] - - -def fix_zaid(table, old, new): - filename = os.path.join('tsl', table) - with open(filename, 'r') as fh: - text = fh.read() - text = text.replace(old, new, 1) - with open(filename, 'w') as fh: - fh.write(text) - -pwd = Path.cwd() -output_dir = pwd / 'nndc_hdf5' -os.makedirs('nndc_hdf5/photon', exist_ok=True) - -with tempfile.TemporaryDirectory() as tmpdir: - # Temporarily change dir - os.chdir(tmpdir) - - # ========================================================================= - # Download files from NNDC server - for base, fname, checksum in files: - download(urljoin(base, fname), checksum) - - # ========================================================================= - # EXTRACT FILES FROM TGZ - - for _, f, _ in files: - print('Extracting {}...'.format(f)) - path = Path(f) - if path.suffix == '.gz': - with tarfile.open(f, 'r') as tgz: - if 'tsl' in f: - tgz.extractall(path='tsl') - else: - tgz.extractall() - elif path.suffix == '.zip': - zipfile.ZipFile(f).extractall() - - # ========================================================================= - # FIX ZAID ASSIGNMENTS FOR VARIOUS S(A,B) TABLES - - print('Fixing ZAIDs for S(a,b) tables') - fix_zaid('bebeo.acer', '8016', ' 0') - fix_zaid('obeo.acer', '4009', ' 0') - - library = openmc.data.DataLibrary() - - # ========================================================================= - # INCIDENT NEUTRON DATA - - neutron_files = sorted(glob.glob('ENDF-B-VII.1-neutron-293.6K/*.ace')) - for f in neutron_files: - print('Converting {}...'.format(os.path.basename(f))) - data = openmc.data.IncidentNeutron.from_ace(f) - - # Check for fission energy release data on MF=1, MT=458 - endf_filename = 'neutrons/n-{:03}_{}_{:03}{}.endf'.format( - data.atomic_number, - data.atomic_symbol, - data.mass_number, - 'm{}'.format(data.metastable) if data.metastable else '' - ) - ev = openmc.data.endf.Evaluation(endf_filename) - if (1, 458) in ev.section: - endf_data = openmc.data.IncidentNeutron.from_endf(ev) - data.fission_energy = endf_data.fission_energy - - # Add 0K elastic scattering data for select nuclides - if data.name in ('U235', 'U238', 'Pu239'): - data.add_elastic_0K_from_endf(endf_filename) - - # Determine filename - outfile = output_dir / (data.name + '.h5') - data.export_to_hdf5(outfile, 'w', 'earliest') - - # Register with library - library.register_file(outfile) - - # ========================================================================= - # THERMAL SCATTERING DATA - - thermal_files = sorted(glob.glob('tsl/*.acer')) - for f in thermal_files: - print('Converting {}...'.format(os.path.basename(f))) - data = openmc.data.ThermalScattering.from_ace(f) - - # Determine filename - outfile = output_dir / (data.name + '.h5') - data.export_to_hdf5(outfile, 'w', 'earliest') - - # Register with library - library.register_file(outfile) - - # ========================================================================= - # INCIDENT PHOTON DATA - - for z in range(1, 101): - element = openmc.data.ATOMIC_SYMBOL[z] - print('Generating HDF5 file for Z={} ({})...'.format(z, element)) - - # Generate instance of IncidentPhoton - photo_file = Path('photoat') / 'photoat-{:03}_{}_000.endf'.format(z, element) - atom_file = Path('atomic_relax') / 'atom-{:03}_{}_000.endf'.format(z, element) - data = openmc.data.IncidentPhoton.from_endf(photo_file, atom_file) - - # Write HDF5 file and register it - outfile = output_dir / 'photon' / (element + '.h5') - data.export_to_hdf5(outfile, 'w', 'earliest') - library.register_file(outfile) - - # ========================================================================= - # WINDOWED MULTIPOLE DATA - - # Move data into output directory - os.rename('WMP_Library', str(output_dir / 'wmp')) - - # Add multipole data to library - for f in sorted(glob.glob('{}/wmp/*.h5'.format(output_dir))): - print('Registering WMP file {}...'.format(f)) - library.register_file(f) - - library.export_to_xml(output_dir / 'cross_sections.xml') - - # ========================================================================= - # CREATE TARBALL AND MOVE BACK - - print('Creating compressed archive...') - test_tar = pwd / 'nndc_hdf5_test.tar.xz' - with tarfile.open(str(test_tar), 'w:xz') as txz: - txz.add(output_dir) - - # Change back to original directory - os.chdir(str(pwd)) diff --git a/scripts/openmc-track-combine b/scripts/openmc-track-combine new file mode 100755 index 00000000000..f69f2151c68 --- /dev/null +++ b/scripts/openmc-track-combine @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 + +"""Combine multiple HDF5 particle track files.""" + +import argparse + +import openmc + + +def main(): + # Parse command-line arguments + parser = argparse.ArgumentParser( + description='Combine particle track files into a single .h5 file.') + parser.add_argument('input', metavar='IN', nargs='+', + help='Input HDF5 particle track filename(s).') + parser.add_argument('-o', '--out', metavar='OUT', default='tracks.h5', + help='Output HDF5 particle track file.') + + args = parser.parse_args() + openmc.Tracks.combine(args.input, args.out) + + +if __name__ == '__main__': + main() diff --git a/scripts/openmc-track-to-vtk b/scripts/openmc-track-to-vtk index 3c781d19ec7..82439bea738 100755 --- a/scripts/openmc-track-to-vtk +++ b/scripts/openmc-track-to-vtk @@ -4,20 +4,18 @@ """ -import os import argparse -import struct -import h5py +import openmc import vtk def _parse_args(): # Create argument parser. parser = argparse.ArgumentParser( - description='Convert particle track file to a .pvtp file.') - parser.add_argument('input', metavar='IN', type=str, nargs='+', - help='Input particle track data filename(s).') + description='Convert particle track file(s) to a .pvtp file.') + parser.add_argument('input', metavar='IN', type=str, + help='Input particle track data filename.') parser.add_argument('-o', '--out', metavar='OUT', type=str, dest='out', help='Output VTK poly data filename.') @@ -35,44 +33,9 @@ def main(): elif not args.out.endswith('.pvtp'): args.out += '.pvtp' - # Initialize data arrays and offset. - points = vtk.vtkPoints() - cells = vtk.vtkCellArray() - point_offset = 0 - for fname in args.input: - # Write coordinate values to points array. - track = h5py.File(fname) - n_particles = track.attrs['n_particles'] - n_coords = track.attrs['n_coords'] - coords = [] - for i in range(n_particles): - coords.append(track['coordinates_' + str(i + 1)][()]) - for j in range(n_coords[i]): - points.InsertNextPoint(coords[i][j,:]) - - for i in range(n_particles): - # Create VTK line and assign points to line. - line = vtk.vtkPolyLine() - line.GetPointIds().SetNumberOfIds(n_coords[i]) - for j in range(n_coords[i]): - line.GetPointIds().SetId(j, point_offset + j) - - # Add line to cell array - cells.InsertNextCell(line) - point_offset += n_coords[i] - - data = vtk.vtkPolyData() - data.SetPoints(points) - data.SetLines(cells) - - writer = vtk.vtkXMLPPolyDataWriter() - if vtk.vtkVersion.GetVTKMajorVersion() > 5: - writer.SetInputData(data) - else: - writer.SetInput(data) - writer.SetFileName(args.out) - writer.Write() - + # Write coordinate values to points array. + track_file = openmc.Tracks(args.input) + track_file.write_to_vtk(args.out) if __name__ == '__main__': main() diff --git a/scripts/openmc-update-inputs b/scripts/openmc-update-inputs index c47f888c837..2d49c0626e2 100755 --- a/scripts/openmc-update-inputs +++ b/scripts/openmc-update-inputs @@ -4,7 +4,6 @@ """ import argparse -from difflib import get_close_matches from itertools import chain from random import randint from shutil import move @@ -27,8 +26,8 @@ geometry.xml: Lattices containing 'outside' attributes/tags will be replaced will be renamed 'region'. materials.xml: Nuclide names will be changed from ACE aliases (e.g., Am-242m) to - HDF5/GND names (e.g., Am242_m1). Thermal scattering table names will be - changed from ACE aliases (e.g., HH2O) to HDF5/GND names (e.g., c_H_in_H2O). + HDF5/GNDS names (e.g., Am242_m1). Thermal scattering table names will be + changed from ACE aliases (e.g., HH2O) to HDF5/GNDS names (e.g., c_H_in_H2O). """ diff --git a/scripts/openmc-validate-xml b/scripts/openmc-validate-xml deleted file mode 100755 index f36ba2b5d3d..00000000000 --- a/scripts/openmc-validate-xml +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import glob -import lxml.etree as etree -from subprocess import call -from optparse import OptionParser - -# Command line parsing -parser = OptionParser() -parser.add_option('-r', '--relaxng-path', dest='relaxng', - help="Path to RelaxNG files.") -parser.add_option('-i', '--input-path', dest='inputs', default=os.getcwd(), - help="Path to OpenMC input files." ) -(options, args) = parser.parse_args() - -# Colored output -if sys.stdout.isatty(): - OK = '\033[92m' - FAIL = '\033[91m' - NOT_FOUND = '\033[93m' - ENDC = '\033[0m' - BOLD = '\033[1m' -else: - OK = '' - FAIL = '' - ENDC = '' - BOLD = '' - NOT_FOUND = '' - -# Get absolute paths -if options.relaxng is not None: - relaxng_path = os.path.abspath(options.relaxng) -if options.inputs is not None: - inputs_path = os.path.abspath(options.inputs) - -# Search for relaxng path if not set -if options.relaxng is None: - xml_validate_path = os.path.abspath(os.path.dirname(sys.argv[0])) - if "bin" in xml_validate_path: - relaxng_path = os.path.join(xml_validate_path, "..", "share", "relaxng") - elif os.path.join("src", "utils") in xml_validate_path: - relaxng_path = os.path.join(xml_validate_path, "..", "relaxng") - else: - raise Exception("Set RelaxNG path with -r command line option.") -if not os.path.exists(relaxng_path): - raise Exception("RelaxNG path: {0} does not exist, set with -r " - "command line option.".format(relaxng_path)) - -# Make sure there are .rng files in RelaxNG path -rng_files = glob.glob(os.path.join(relaxng_path, "*.rng")) -if len(rng_files) == 0: - raise Exception("No .rng files found in RelaxNG " - "path: {0}.".format(relaxng_path)) - -# Get list of xml input files -xml_files = glob.glob(os.path.join(inputs_path, "*.xml")) -if len(xml_files) == 0: - raise Exception("No .xml files found at input path: {0}" - ".".format(inputs_path)) - -# Begin loop around input files -for xml_file in xml_files: - - text = "Validating {0}".format(os.path.basename(xml_file)) - print(text + '.'*(30 - len(text)), end="") - - # Validate the XML file - try: - xml_tree = etree.parse(xml_file) - except etree.XMLSyntaxError as e: - print(BOLD + FAIL + '[XML ERROR]' + ENDC) - print(" {0}".format(e)) - continue - - # Get xml_filename prefix - xml_prefix = os.path.basename(xml_file) - xml_prefix = xml_prefix.split(".")[0] - - # Search for rng file - rng_file = os.path.join(relaxng_path, xml_prefix + ".rng") - if rng_file in rng_files: - - # read in RelaxNG - relaxng_doc = etree.parse(rng_file) - relaxng = etree.RelaxNG(relaxng_doc) - - # validate xml file again RelaxNG - try: - relaxng.assertValid(xml_tree) - print(BOLD + OK + '[VALID]' + ENDC) - except (etree.DocumentInvalid, TypeError) as e: - print(BOLD + FAIL + '[NOT VALID]' + ENDC) - print(" {0}".format(e)) - - # RNG file does not exist - else: - print(BOLD + NOT_FOUND + '[NO RELAXNG FOUND]' + ENDC) diff --git a/scripts/openmc-voxel-to-vtk b/scripts/openmc-voxel-to-vtk index 33251144fb6..3f59ffd4262 100755 --- a/scripts/openmc-voxel-to-vtk +++ b/scripts/openmc-voxel-to-vtk @@ -1,72 +1,22 @@ #!/usr/bin/env python3 -import struct -import sys from argparse import ArgumentParser -import numpy as np -import h5py -import vtk +import openmc -_min_version = (2, 0) - -def main(): +if __name__ == "__main__": # Process command line arguments - parser = ArgumentParser() - parser.add_argument('voxel_file', help='Path to voxel file') - parser.add_argument('-o', '--output', action='store', - default='plot', help='Path to output VTK file.') + parser = ArgumentParser('Converts a voxel HDF5 file to a VTK file') + parser.add_argument("voxel_file", help="Path to voxel h5 file") + parser.add_argument( + "-o", + "--output", + action="store", + default="plot", + help="Path to output VTK file.", + ) args = parser.parse_args() - - # Read data from voxel file - fh = h5py.File(args.voxel_file, 'r') - - # check version - version = tuple(fh.attrs['version']) - if version < _min_version: - old_version = ".".join(map(str,version)) - min_version = ".".join(map(str,_min_version)) - err_msg = "This voxel file's version is {}. This script " \ - "only supports voxel files with version {} or " \ - "higher. Please generate a new voxel file using " \ - "a newer version of OpenMC.".format(old_version, min_version) - raise ValueError(err_msg) - - dimension = fh.attrs['num_voxels'] - width = fh.attrs['voxel_width'] - lower_left = fh.attrs['lower_left'] - - nx, ny, nz = dimension - upper_right = lower_left + width*dimension - - grid = vtk.vtkImageData() - grid.SetDimensions(nx+1, ny+1, nz+1) - grid.SetOrigin(*lower_left) - grid.SetSpacing(*width) - - # transpose data from OpenMC ordering (zyx) to VTK ordering (xyz) - # and flatten to 1-D array print("Reading and translating data...") - h5data = fh['data'][...] - - data = vtk.vtkIntArray() - data.SetName("id") - # set the array using the h5data array - data.SetArray(h5data, h5data.size, True) - # add data to image grid - grid.GetCellData().AddArray(data) - - writer = vtk.vtkXMLImageDataWriter() - if vtk.vtkVersion.GetVTKMajorVersion() > 5: - writer.SetInputData(grid) - else: - writer.SetInput(grid) - if not args.output.endswith(".vti"): - args.output += ".vti" - writer.SetFileName(args.output) - print("Writing VTK file {}...".format(args.output)) - writer.Write() - -if __name__ == '__main__': - main() + openmc.voxel_to_vtk(args.voxel_file, args.output) + print(f"Written VTK file {args.output}...") diff --git a/setup.py b/setup.py index 02f3c08429a..a33037ad3e6 100755 --- a/setup.py +++ b/setup.py @@ -5,11 +5,7 @@ import numpy as np from setuptools import setup, find_packages -try: - from Cython.Build import cythonize - have_cython = True -except ImportError: - have_cython = False +from Cython.Build import cythonize # Determine shared library suffix @@ -29,16 +25,16 @@ 'packages': find_packages(exclude=['tests*']), 'scripts': glob.glob('scripts/openmc-*'), - # Data files and librarries + # Data files and libraries 'package_data': { 'openmc.lib': ['libopenmc.{}'.format(suffix)], - 'openmc.data': ['mass16.txt', 'BREMX.DAT', '*.h5'], + 'openmc.data': ['mass_1.mas20.txt', 'BREMX.DAT', 'half_life.json', '*.h5'], 'openmc.data.effective_dose': ['*.txt'] }, # Metadata 'author': 'The OpenMC Development Team', - 'author_email': 'openmc-dev@googlegroups.com', + 'author_email': 'openmc@anl.gov', 'description': 'OpenMC', 'url': 'https://openmc.org', 'download_url': 'https://github.com/openmc-dev/openmc/releases', @@ -57,33 +53,29 @@ 'Topic :: Scientific/Engineering' 'Programming Language :: C++', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', ], # Dependencies - 'python_requires': '>=3.5', + 'python_requires': '>=3.8', 'install_requires': [ 'numpy>=1.9', 'h5py', 'scipy', 'ipython', 'matplotlib', - 'pandas', 'lxml', 'uncertainties' + 'pandas', 'lxml', 'uncertainties', 'setuptools' ], 'extras_require': { 'depletion-mpi': ['mpi4py'], 'docs': ['sphinx', 'sphinxcontrib-katex', 'sphinx-numfig', 'jupyter', - 'sphinxcontrib-svg2pdfconverter', 'sphinx-rtd-theme', - 'nbsphinx'], - 'test': ['pytest', 'pytest-cov', 'colorama'], + 'sphinxcontrib-svg2pdfconverter', 'sphinx-rtd-theme'], + 'test': ['pytest', 'pytest-cov', 'colorama', 'openpyxl'], 'vtk': ['vtk'], }, + # Cython is used to add resonance reconstruction and fast float_endf + 'ext_modules': cythonize('openmc/data/*.pyx'), + 'include_dirs': [np.get_include()] } -# If Cython is present, add resonance reconstruction and fast float_endf -if have_cython: - kwargs.update({ - 'ext_modules': cythonize('openmc/data/*.pyx'), - 'include_dirs': [np.get_include()] - }) - setup(**kwargs) diff --git a/src/bank.cpp b/src/bank.cpp index d5d3647564b..8d00d544090 100644 --- a/src/bank.cpp +++ b/src/bank.cpp @@ -7,7 +7,6 @@ #include - namespace openmc { //============================================================================== @@ -20,10 +19,11 @@ vector source_bank; SharedArray surf_source_bank; -// The fission bank is allocated as a SharedArray, rather than a vector, as it will -// be shared by all threads in the simulation. It will be allocated to a fixed -// maximum capacity in the init_fission_bank() function. Then, Elements will be -// added to it by using SharedArray's special thread_safe_append() function. +// The fission bank is allocated as a SharedArray, rather than a vector, as it +// will be shared by all threads in the simulation. It will be allocated to a +// fixed maximum capacity in the init_fission_bank() function. Then, Elements +// will be added to it by using SharedArray's special thread_safe_append() +// function. SharedArray fission_bank; // Each entry in this vector corresponds to the number of progeny produced @@ -69,7 +69,7 @@ void sort_fission_bank() int64_t tmp = simulation::progeny_per_particle[0]; simulation::progeny_per_particle[0] = 0; for (int64_t i = 1; i < simulation::progeny_per_particle.size(); i++) { - int64_t value = simulation::progeny_per_particle[i-1] + tmp; + int64_t value = simulation::progeny_per_particle[i - 1] + tmp; tmp = simulation::progeny_per_particle[i]; simulation::progeny_per_particle[i] = value; } @@ -84,7 +84,8 @@ void sort_fission_bank() vector sorted_bank_holder; // If there is not enough space, allocate a temporary vector and point to it - if (simulation::fission_bank.size() > simulation::fission_bank.capacity() / 2) { + if (simulation::fission_bank.size() > + simulation::fission_bank.capacity() / 2) { sorted_bank_holder.resize(simulation::fission_bank.size()); sorted_bank = sorted_bank_holder.data(); } else { // otherwise, point sorted_bank to unused portion of the fission bank @@ -96,12 +97,16 @@ void sort_fission_bank() const auto& site = simulation::fission_bank[i]; int64_t offset = site.parent_id - 1 - simulation::work_index[mpi::rank]; int64_t idx = simulation::progeny_per_particle[offset] + site.progeny_id; + if (idx >= simulation::fission_bank.size()) { + fatal_error("Mismatch detected between sum of all particle progeny and " + "shared fission bank size."); + } sorted_bank[idx] = site; } // Copy sorted bank into the fission bank std::copy(sorted_bank, sorted_bank + simulation::fission_bank.size(), - simulation::fission_bank.data()); + simulation::fission_bank.data()); } //============================================================================== @@ -137,7 +142,7 @@ extern "C" int openmc_fission_bank(void** ptr, int64_t* n) return OPENMC_E_ALLOCATE; } else { *ptr = simulation::fission_bank.data(); - *n = simulation::fission_bank.size(); + *n = simulation::fission_bank.size(); return 0; } } diff --git a/src/boundary_condition.cpp b/src/boundary_condition.cpp index 884b06f8170..b58054dce8c 100644 --- a/src/boundary_condition.cpp +++ b/src/boundary_condition.cpp @@ -6,6 +6,7 @@ #include "openmc/constants.h" #include "openmc/error.h" +#include "openmc/random_ray/random_ray.h" #include "openmc/surface.h" namespace openmc { @@ -14,22 +15,34 @@ namespace openmc { // VacuumBC implementation //============================================================================== -void -VacuumBC::handle_particle(Particle& p, const Surface& surf) const +void VacuumBC::handle_particle(Particle& p, const Surface& surf) const { - p.cross_vacuum_bc(surf); + // Random ray and Monte Carlo need different treatments at vacuum BCs + if (settings::solver_type == SolverType::RANDOM_RAY) { + // Reflect ray off of the surface + ReflectiveBC().handle_particle(p, surf); + + // Set ray's angular flux spectrum to vacuum conditions (zero) + RandomRay* r = static_cast(&p); + std::fill(r->angular_flux_.begin(), r->angular_flux_.end(), 0.0); + + } else { + p.cross_vacuum_bc(surf); + } } //============================================================================== // ReflectiveBC implementation //============================================================================== -void -ReflectiveBC::handle_particle(Particle& p, const Surface& surf) const +void ReflectiveBC::handle_particle(Particle& p, const Surface& surf) const { Direction u = surf.reflect(p.r(), p.u(), &p); u /= u.norm(); + // Handle the effects of the surface albedo on the particle's weight. + BoundaryCondition::handle_albedo(p, surf); + p.cross_reflective_bc(surf, u); } @@ -37,12 +50,14 @@ ReflectiveBC::handle_particle(Particle& p, const Surface& surf) const // WhiteBC implementation //============================================================================== -void -WhiteBC::handle_particle(Particle& p, const Surface& surf) const +void WhiteBC::handle_particle(Particle& p, const Surface& surf) const { Direction u = surf.diffuse_reflect(p.r(), p.u(), p.current_seed()); u /= u.norm(); + // Handle the effects of the surface albedo on the particle's weight. + BoundaryCondition::handle_albedo(p, surf); + p.cross_reflective_bc(surf, u); } @@ -62,7 +77,8 @@ TranslationalPeriodicBC::TranslationalPeriodicBC(int i_surf, int j_surf) } else if (const auto* ptr = dynamic_cast(&surf1)) { } else if (const auto* ptr = dynamic_cast(&surf1)) { } else { - throw std::invalid_argument(fmt::format("Surface {} is an invalid type for " + throw std::invalid_argument(fmt::format( + "Surface {} is an invalid type for " "translational periodic BCs. Only planes are supported for these BCs.", surf1.id_)); } @@ -73,7 +89,8 @@ TranslationalPeriodicBC::TranslationalPeriodicBC(int i_surf, int j_surf) } else if (const auto* ptr = dynamic_cast(&surf2)) { } else if (const auto* ptr = dynamic_cast(&surf2)) { } else { - throw std::invalid_argument(fmt::format("Surface {} is an invalid type for " + throw std::invalid_argument(fmt::format( + "Surface {} is an invalid type for " "translational periodic BCs. Only planes are supported for these BCs.", surf2.id_)); } @@ -109,8 +126,8 @@ TranslationalPeriodicBC::TranslationalPeriodicBC(int i_surf, int j_surf) translation_ = u * (d2 - d1); } -void -TranslationalPeriodicBC::handle_particle(Particle& p, const Surface& surf) const +void TranslationalPeriodicBC::handle_particle( + Particle& p, const Surface& surf) const { // TODO: off-by-one on surface indices throughout this function. int i_particle_surf = std::abs(p.surface()) - 1; @@ -126,10 +143,14 @@ TranslationalPeriodicBC::handle_particle(Particle& p, const Surface& surf) const new_r = p.r() - translation_; new_surface = p.surface() > 0 ? i_surf_ + 1 : -(i_surf_ + 1); } else { - throw std::runtime_error("Called BoundaryCondition::handle_particle after " + throw std::runtime_error( + "Called BoundaryCondition::handle_particle after " "hitting a surface, but that surface is not recognized by the BC."); } + // Handle the effects of the surface albedo on the particle's weight. + BoundaryCondition::handle_albedo(p, surf); + // Pass the new location and surface to the particle. p.cross_periodic_bc(surf, new_r, p.u(), new_surface); } @@ -153,9 +174,11 @@ RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf) } else if (const auto* ptr = dynamic_cast(&surf1)) { surf1_is_xyplane = false; } else { - throw std::invalid_argument(fmt::format("Surface {} is an invalid type for " + throw std::invalid_argument(fmt::format( + "Surface {} is an invalid type for " "rotational periodic BCs. Only x-planes, y-planes, or general planes " - "(that are perpendicular to z) are supported for these BCs.", surf1.id_)); + "(that are perpendicular to z) are supported for these BCs.", + surf1.id_)); } // Check the type of the second surface @@ -167,9 +190,11 @@ RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf) } else if (const auto* ptr = dynamic_cast(&surf2)) { surf2_is_xyplane = false; } else { - throw std::invalid_argument(fmt::format("Surface {} is an invalid type for " + throw std::invalid_argument(fmt::format( + "Surface {} is an invalid type for " "rotational periodic BCs. Only x-planes, y-planes, or general planes " - "(that are perpendicular to z) are supported for these BCs.", surf2.id_)); + "(that are perpendicular to z) are supported for these BCs.", + surf2.id_)); } // Compute the surface normal vectors and make sure they are perpendicular @@ -177,26 +202,34 @@ RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf) Direction norm1 = surf1.normal({0, 0, 0}); Direction norm2 = surf2.normal({0, 0, 0}); if (std::abs(norm1.z) > FP_PRECISION) { - throw std::invalid_argument(fmt::format("Rotational periodic BCs are only " + throw std::invalid_argument(fmt::format( + "Rotational periodic BCs are only " "supported for rotations about the z-axis, but surface {} is not " - "perpendicular to the z-axis.", surf1.id_)); + "perpendicular to the z-axis.", + surf1.id_)); } if (std::abs(norm2.z) > FP_PRECISION) { - throw std::invalid_argument(fmt::format("Rotational periodic BCs are only " + throw std::invalid_argument(fmt::format( + "Rotational periodic BCs are only " "supported for rotations about the z-axis, but surface {} is not " - "perpendicular to the z-axis.", surf2.id_)); + "perpendicular to the z-axis.", + surf2.id_)); } // Make sure both surfaces intersect the origin if (std::abs(surf1.evaluate({0, 0, 0})) > FP_COINCIDENT) { - throw std::invalid_argument(fmt::format("Rotational periodic BCs are only " + throw std::invalid_argument(fmt::format( + "Rotational periodic BCs are only " "supported for rotations about the origin, but surface {} does not " - "intersect the origin.", surf1.id_)); + "intersect the origin.", + surf1.id_)); } if (std::abs(surf2.evaluate({0, 0, 0})) > FP_COINCIDENT) { - throw std::invalid_argument(fmt::format("Rotational periodic BCs are only " + throw std::invalid_argument(fmt::format( + "Rotational periodic BCs are only " "supported for rotations about the origin, but surface {} does not " - "intersect the origin.", surf2.id_)); + "intersect the origin.", + surf2.id_)); } // Compute the BC rotation angle. Here it is assumed that both surface @@ -212,14 +245,15 @@ RotationalPeriodicBC::RotationalPeriodicBC(int i_surf, int j_surf) // Warn the user if the angle does not evenly divide a circle double rem = std::abs(std::remainder((2 * PI / angle_), 1.0)); if (rem > FP_REL_PRECISION && rem < 1 - FP_REL_PRECISION) { - warning(fmt::format("Rotational periodic BC specified with a rotation " + warning(fmt::format( + "Rotational periodic BC specified with a rotation " "angle of {} degrees which does not evenly divide 360 degrees.", angle_ * 180 / PI)); } } -void -RotationalPeriodicBC::handle_particle(Particle& p, const Surface& surf) const +void RotationalPeriodicBC::handle_particle( + Particle& p, const Surface& surf) const { // TODO: off-by-one on surface indices throughout this function. int i_particle_surf = std::abs(p.surface()) - 1; @@ -236,7 +270,8 @@ RotationalPeriodicBC::handle_particle(Particle& p, const Surface& surf) const theta = -angle_; new_surface = p.surface() > 0 ? -(i_surf_ + 1) : i_surf_ + 1; } else { - throw std::runtime_error("Called BoundaryCondition::handle_particle after " + throw std::runtime_error( + "Called BoundaryCondition::handle_particle after " "hitting a surface, but that surface is not recognized by the BC."); } @@ -246,13 +281,12 @@ RotationalPeriodicBC::handle_particle(Particle& p, const Surface& surf) const double cos_theta = std::cos(theta); double sin_theta = std::sin(theta); Position new_r = { - cos_theta*r.x - sin_theta*r.y, - sin_theta*r.x + cos_theta*r.y, - r.z}; + cos_theta * r.x - sin_theta * r.y, sin_theta * r.x + cos_theta * r.y, r.z}; Direction new_u = { - cos_theta*u.x - sin_theta*u.y, - sin_theta*u.x + cos_theta*u.y, - u.z}; + cos_theta * u.x - sin_theta * u.y, sin_theta * u.x + cos_theta * u.y, u.z}; + + // Handle the effects of the surface albedo on the particle's weight. + BoundaryCondition::handle_albedo(p, surf); // Pass the new location, direction, and surface to the particle. p.cross_periodic_bc(surf, new_r, new_u, new_surface); diff --git a/src/bremsstrahlung.cpp b/src/bremsstrahlung.cpp index 099e0ca0c19..d22d6392ab8 100644 --- a/src/bremsstrahlung.cpp +++ b/src/bremsstrahlung.cpp @@ -47,30 +47,32 @@ void thick_target_bremsstrahlung(Particle& p, double* E_lost) auto n_e = data::ttb_e_grid.size(); // Find the lower bounding index of the incident electron energy - size_t j = lower_bound_index(data::ttb_e_grid.cbegin(), - data::ttb_e_grid.cend(), e); - if (j == n_e - 1) --j; + size_t j = + lower_bound_index(data::ttb_e_grid.cbegin(), data::ttb_e_grid.cend(), e); + if (j == n_e - 1) + --j; // Get the interpolation bounds double e_l = data::ttb_e_grid(j); - double e_r = data::ttb_e_grid(j+1); + double e_r = data::ttb_e_grid(j + 1); double y_l = mat->yield(j); - double y_r = mat->yield(j+1); + double y_r = mat->yield(j + 1); // Calculate the interpolation weight w_j+1 of the bremsstrahlung energy PDF // interpolated in log energy, which can be interpreted as the probability // of index j+1 - double f = (e - e_l)/(e_r - e_l); + double f = (e - e_l) / (e_r - e_l); // Get the photon number yield for the given energy using linear // interpolation on a log-log scale - double y = std::exp(y_l + (y_r - y_l)*f); + double y = std::exp(y_l + (y_r - y_l) * f); // Sample number of secondary bremsstrahlung photons int n = y + prn(p.current_seed()); *E_lost = 0.0; - if (n == 0) return; + if (n == 0) + return; // Sample index of the tabulated PDF in the energy grid, j or j+1 double c_max; @@ -83,8 +85,8 @@ void thick_target_bremsstrahlung(Particle& p, double* E_lost) double p_l = mat->pdf(i_e, i_e - 1); double p_r = mat->pdf(i_e, i_e); double c_l = mat->cdf(i_e, i_e - 1); - double a = std::log(p_r/p_l)/(e_r - e_l) + 1.0; - c_max = c_l + std::exp(e_l)*p_l/a*(std::exp(a*(e - e_l)) - 1.0); + double a = std::log(p_r / p_l) / (e_r - e_l) + 1.0; + c_max = c_l + std::exp(e_l) * p_l / a * (std::exp(a * (e - e_l)) - 1.0); } else { i_e = j; @@ -96,7 +98,7 @@ void thick_target_bremsstrahlung(Particle& p, double* E_lost) for (int i = 0; i < n; ++i) { // Generate a random number r and determine the index i for which // cdf(i) <= r*cdf,max <= cdf(i+1) - double c = prn(p.current_seed())*c_max; + double c = prn(p.current_seed()) * c_max; int i_w = lower_bound_index(&mat->cdf(i_e, 0), &mat->cdf(i_e, 0) + i_e, c); // Sample the photon energy @@ -105,8 +107,9 @@ void thick_target_bremsstrahlung(Particle& p, double* E_lost) double p_l = mat->pdf(i_e, i_w); double p_r = mat->pdf(i_e, i_w + 1); double c_l = mat->cdf(i_e, i_w); - double a = std::log(p_r/p_l)/(w_r - w_l) + 1.0; - double w = std::exp(w_l)*std::pow(a*(c - c_l)/(std::exp(w_l)*p_l) + 1.0, 1.0/a); + double a = std::log(p_r / p_l) / (w_r - w_l) + 1.0; + double w = std::exp(w_l) * + std::pow(a * (c - c_l) / (std::exp(w_l) * p_l) + 1.0, 1.0 / a); if (w > settings::energy_cutoff[photon]) { // Create secondary photon diff --git a/src/cell.cpp b/src/cell.cpp index 6b88a67803e..a46f05687eb 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include "openmc/capi.h" #include "openmc/constants.h" @@ -22,7 +22,6 @@ #include "openmc/material.h" #include "openmc/nuclide.h" #include "openmc/settings.h" -#include "openmc/surface.h" #include "openmc/xml_interface.h" namespace openmc { @@ -32,229 +31,92 @@ namespace openmc { //============================================================================== namespace model { - std::unordered_map cell_map; - vector> cells; +std::unordered_map cell_map; +vector> cells; - std::unordered_map universe_map; - vector> universes; } // namespace model //============================================================================== -//! Convert region specification string to integer tokens. -//! -//! The characters (, ), |, and ~ count as separate tokens since they represent -//! operators. +// Cell implementation //============================================================================== -vector tokenize(const std::string region_spec) +void Cell::set_rotation(const vector& rot) { - // Check for an empty region_spec first. - vector tokens; - if (region_spec.empty()) { - return tokens; - } - - // Parse all halfspaces and operators except for intersection (whitespace). - for (int i = 0; i < region_spec.size(); ) { - if (region_spec[i] == '(') { - tokens.push_back(OP_LEFT_PAREN); - i++; - - } else if (region_spec[i] == ')') { - tokens.push_back(OP_RIGHT_PAREN); - i++; - - } else if (region_spec[i] == '|') { - tokens.push_back(OP_UNION); - i++; - - } else if (region_spec[i] == '~') { - tokens.push_back(OP_COMPLEMENT); - i++; - - } else if (region_spec[i] == '-' || region_spec[i] == '+' - || std::isdigit(region_spec[i])) { - // This is the start of a halfspace specification. Iterate j until we - // find the end, then push-back everything between i and j. - int j = i + 1; - while (j < region_spec.size() && std::isdigit(region_spec[j])) {j++;} - tokens.push_back(std::stoi(region_spec.substr(i, j-i))); - i = j; - - } else if (std::isspace(region_spec[i])) { - i++; - - } else { - auto err_msg = fmt::format( - "Region specification contains invalid character, \"{}\"", region_spec[i]); - fatal_error(err_msg); - } + if (fill_ == C_NONE) { + fatal_error(fmt::format("Cannot apply a rotation to cell {}" + " because it is not filled with another universe", + id_)); } - // Add in intersection operators where a missing operator is needed. - int i = 0; - while (i < tokens.size()-1) { - bool left_compat {(tokens[i] < OP_UNION) || (tokens[i] == OP_RIGHT_PAREN)}; - bool right_compat {(tokens[i+1] < OP_UNION) - || (tokens[i+1] == OP_LEFT_PAREN) - || (tokens[i+1] == OP_COMPLEMENT)}; - if (left_compat && right_compat) { - tokens.insert(tokens.begin()+i+1, OP_INTERSECTION); - } - i++; + if (rot.size() != 3 && rot.size() != 9) { + fatal_error(fmt::format("Non-3D rotation vector applied to cell {}", id_)); } - return tokens; -} - -//============================================================================== -//! Convert infix region specification to Reverse Polish Notation (RPN) -//! -//! This function uses the shunting-yard algorithm. -//============================================================================== - -vector generate_rpn(int32_t cell_id, vector infix) -{ - vector rpn; - vector stack; - - for (int32_t token : infix) { - if (token < OP_UNION) { - // If token is not an operator, add it to output - rpn.push_back(token); - } else if (token < OP_RIGHT_PAREN) { - // Regular operators union, intersection, complement - while (stack.size() > 0) { - int32_t op = stack.back(); - - if (op < OP_RIGHT_PAREN && - ((token == OP_COMPLEMENT && token < op) || - (token != OP_COMPLEMENT && token <= op))) { - // While there is an operator, op, on top of the stack, if the token - // is left-associative and its precedence is less than or equal to - // that of op or if the token is right-associative and its precedence - // is less than that of op, move op to the output queue and push the - // token on to the stack. Note that only complement is - // right-associative. - rpn.push_back(op); - stack.pop_back(); - } else { - break; - } - } - - stack.push_back(token); - - } else if (token == OP_LEFT_PAREN) { - // If the token is a left parenthesis, push it onto the stack - stack.push_back(token); - - } else { - // If the token is a right parenthesis, move operators from the stack to - // the output queue until reaching the left parenthesis. - for (auto it = stack.rbegin(); *it != OP_LEFT_PAREN; it++) { - // If we run out of operators without finding a left parenthesis, it - // means there are mismatched parentheses. - if (it == stack.rend()) { - fatal_error(fmt::format( - "Mismatched parentheses in region specification for cell {}", cell_id)); - } - rpn.push_back(stack.back()); - stack.pop_back(); - } - - // Pop the left parenthesis. - stack.pop_back(); - } - } - - while (stack.size() > 0) { - int32_t op = stack.back(); - - // If the operator is a parenthesis it is mismatched. - if (op >= OP_RIGHT_PAREN) { - fatal_error(fmt::format( - "Mismatched parentheses in region specification for cell {}", cell_id)); - } - - rpn.push_back(stack.back()); - stack.pop_back(); - } - - return rpn; -} - -//============================================================================== -// Universe implementation -//============================================================================== - -void -Universe::to_hdf5(hid_t universes_group) const -{ - // Create a group for this universe. - auto group = create_group(universes_group, fmt::format("universe {}", id_)); - - // Write the contained cells. - if (cells_.size() > 0) { - vector cell_ids; - for (auto i_cell : cells_) cell_ids.push_back(model::cells[i_cell]->id_); - write_dataset(group, "cells", cell_ids); - } - - close_group(group); -} - -BoundingBox Universe::bounding_box() const { - BoundingBox bbox = {INFTY, -INFTY, INFTY, -INFTY, INFTY, -INFTY}; - if (cells_.size() == 0) { - return {}; + // Compute and store the rotation matrix. + rotation_.clear(); + rotation_.reserve(rot.size() == 9 ? 9 : 12); + if (rot.size() == 3) { + double phi = -rot[0] * PI / 180.0; + double theta = -rot[1] * PI / 180.0; + double psi = -rot[2] * PI / 180.0; + rotation_.push_back(std::cos(theta) * std::cos(psi)); + rotation_.push_back(-std::cos(phi) * std::sin(psi) + + std::sin(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::sin(phi) * std::sin(psi) + + std::cos(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::cos(theta) * std::sin(psi)); + rotation_.push_back(std::cos(phi) * std::cos(psi) + + std::sin(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(phi) * std::cos(psi) + + std::cos(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(theta)); + rotation_.push_back(std::sin(phi) * std::cos(theta)); + rotation_.push_back(std::cos(phi) * std::cos(theta)); + + // When user specifies angles, write them at end of vector + rotation_.push_back(rot[0]); + rotation_.push_back(rot[1]); + rotation_.push_back(rot[2]); } else { - for (const auto& cell : cells_) { - auto& c = model::cells[cell]; - bbox |= c->bounding_box(); - } + std::copy(rot.begin(), rot.end(), std::back_inserter(rotation_)); } - return bbox; } -//============================================================================== -// Cell implementation -//============================================================================== - -double -Cell::temperature(int32_t instance) const +double Cell::temperature(int32_t instance) const { if (sqrtkT_.size() < 1) { - throw std::runtime_error{"Cell temperature has not yet been set."}; + throw std::runtime_error {"Cell temperature has not yet been set."}; } if (instance >= 0) { - double sqrtkT = sqrtkT_.size() == 1 ? - sqrtkT_.at(0) : - sqrtkT_.at(instance); + double sqrtkT = sqrtkT_.size() == 1 ? sqrtkT_.at(0) : sqrtkT_.at(instance); return sqrtkT * sqrtkT / K_BOLTZMANN; } else { return sqrtkT_[0] * sqrtkT_[0] / K_BOLTZMANN; } } -void -Cell::set_temperature(double T, int32_t instance, bool set_contained) +void Cell::set_temperature(double T, int32_t instance, bool set_contained) { if (settings::temperature_method == TemperatureMethod::INTERPOLATION) { - if (T < data::temperature_min) { - throw std::runtime_error{"Temperature is below minimum temperature at " - "which data is available."}; - } else if (T > data::temperature_max) { - throw std::runtime_error{"Temperature is above maximum temperature at " - "which data is available."}; + if (T < (data::temperature_min - settings::temperature_tolerance)) { + throw std::runtime_error { + fmt::format("Temperature of {} K is below minimum temperature at " + "which data is available of {} K.", + T, data::temperature_min)}; + } else if (T > (data::temperature_max + settings::temperature_tolerance)) { + throw std::runtime_error { + fmt::format("Temperature of {} K is above maximum temperature at " + "which data is available of {} K.", + T, data::temperature_max)}; } } if (type_ == Fill::MATERIAL) { if (instance >= 0) { // If temperature vector is not big enough, resize it first - if (sqrtkT_.size() != n_instances_) sqrtkT_.resize(n_instances_, sqrtkT_[0]); + if (sqrtkT_.size() != n_instances_) + sqrtkT_.resize(n_instances_, sqrtkT_[0]); // Set temperature for the corresponding instance sqrtkT_.at(instance) = std::sqrt(K_BOLTZMANN * T); @@ -266,15 +128,17 @@ Cell::set_temperature(double T, int32_t instance, bool set_contained) } } else { if (!set_contained) { - throw std::runtime_error{fmt::format("Attempted to set the temperature of cell {} " - "which is not filled by a material.", id_)}; + throw std::runtime_error { + fmt::format("Attempted to set the temperature of cell {} " + "which is not filled by a material.", + id_)}; } - auto contained_cells = this->get_contained_cells(); + auto contained_cells = this->get_contained_cells(instance); for (const auto& entry : contained_cells) { auto& cell = model::cells[entry.first]; Expects(cell->type_ == Fill::MATERIAL); - auto& instances = entry.second; + auto& instances = entry.second; for (auto instance : instances) { cell->set_temperature(T, instance); } @@ -282,14 +146,119 @@ Cell::set_temperature(double T, int32_t instance, bool set_contained) } } +void Cell::export_properties_hdf5(hid_t group) const +{ + // Create a group for this cell. + auto cell_group = create_group(group, fmt::format("cell {}", id_)); + + // Write temperature in [K] for one or more cell instances + vector temps; + for (auto sqrtkT_val : sqrtkT_) + temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); + write_dataset(cell_group, "temperature", temps); + + close_group(cell_group); +} + +void Cell::import_properties_hdf5(hid_t group) +{ + auto cell_group = open_group(group, fmt::format("cell {}", id_)); + + // Read temperatures from file + vector temps; + read_dataset(cell_group, "temperature", temps); + + // Ensure number of temperatures makes sense + auto n_temps = temps.size(); + if (n_temps > 1 && n_temps != n_instances_) { + throw std::runtime_error(fmt::format( + "Number of temperatures for cell {} doesn't match number of instances", + id_)); + } + + // Modify temperatures for the cell + sqrtkT_.clear(); + sqrtkT_.resize(temps.size()); + for (gsl::index i = 0; i < temps.size(); ++i) { + this->set_temperature(temps[i], i); + } + + close_group(cell_group); +} + +void Cell::to_hdf5(hid_t cell_group) const +{ + + // Create a group for this cell. + auto group = create_group(cell_group, fmt::format("cell {}", id_)); + + if (!name_.empty()) { + write_string(group, "name", name_, false); + } + + write_dataset(group, "universe", model::universes[universe_]->id_); + + to_hdf5_inner(group); + + // Write fill information. + if (type_ == Fill::MATERIAL) { + write_dataset(group, "fill_type", "material"); + std::vector mat_ids; + for (auto i_mat : material_) { + if (i_mat != MATERIAL_VOID) { + mat_ids.push_back(model::materials[i_mat]->id_); + } else { + mat_ids.push_back(MATERIAL_VOID); + } + } + if (mat_ids.size() == 1) { + write_dataset(group, "material", mat_ids[0]); + } else { + write_dataset(group, "material", mat_ids); + } + + std::vector temps; + for (auto sqrtkT_val : sqrtkT_) + temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); + write_dataset(group, "temperature", temps); + + } else if (type_ == Fill::UNIVERSE) { + write_dataset(group, "fill_type", "universe"); + write_dataset(group, "fill", model::universes[fill_]->id_); + if (translation_ != Position(0, 0, 0)) { + write_dataset(group, "translation", translation_); + } + if (!rotation_.empty()) { + if (rotation_.size() == 12) { + std::array rot {rotation_[9], rotation_[10], rotation_[11]}; + write_dataset(group, "rotation", rot); + } else { + write_dataset(group, "rotation", rotation_); + } + } + + } else if (type_ == Fill::LATTICE) { + write_dataset(group, "fill_type", "lattice"); + write_dataset(group, "lattice", model::lattices[fill_]->id_); + } + + close_group(group); +} + //============================================================================== // CSGCell implementation //============================================================================== -CSGCell::CSGCell() {} // empty constructor +// default constructor +CSGCell::CSGCell() +{ + geom_type_ = GeometryType::CSG; +} CSGCell::CSGCell(pugi::xml_node cell_node) { + geom_type_ = GeometryType::CSG; + if (check_for_node(cell_node, "id")) { id_ = std::stoi(get_node_value(cell_node, "id")); } else { @@ -310,19 +279,21 @@ CSGCell::CSGCell(pugi::xml_node cell_node) bool fill_present = check_for_node(cell_node, "fill"); bool material_present = check_for_node(cell_node, "material"); if (!(fill_present || material_present)) { - fatal_error(fmt::format( - "Neither material nor fill was specified for cell {}", id_)); + fatal_error( + fmt::format("Neither material nor fill was specified for cell {}", id_)); } if (fill_present && material_present) { fatal_error(fmt::format("Cell {} has both a material and a fill specified; " - "only one can be specified per cell", id_)); + "only one can be specified per cell", + id_)); } if (fill_present) { fill_ = std::stoi(get_node_value(cell_node, "fill")); if (fill_ == universe_) { - fatal_error(fmt::format("Cell {} is filled with the same universe that" - "it is contained in.", id_)); + fatal_error(fmt::format("Cell {} is filled with the same universe that " + "it is contained in.", + id_)); } } else { fill_ = C_NONE; @@ -344,8 +315,8 @@ CSGCell::CSGCell(pugi::xml_node cell_node) } } } else { - fatal_error(fmt::format("An empty material element was specified for cell {}", - id_)); + fatal_error(fmt::format( + "An empty material element was specified for cell {}", id_)); } } @@ -358,7 +329,8 @@ CSGCell::CSGCell(pugi::xml_node cell_node) if (material_.size() == 0) { fatal_error(fmt::format( "Cell {} was specified with a temperature but no material. Temperature" - "specification is only valid for cells filled with a material.", id_)); + "specification is only valid for cells filled with a material.", + id_)); } // Make sure all temperatures are non-negative. @@ -381,334 +353,480 @@ CSGCell::CSGCell(pugi::xml_node cell_node) region_spec = get_node_value(cell_node, "region"); } - // Get a tokenized representation of the region specification. - region_ = tokenize(region_spec); - region_.shrink_to_fit(); - - // Convert user IDs to surface indices. - for (auto& r : region_) { - if (r < OP_UNION) { - const auto& it {model::surface_map.find(abs(r))}; - if (it == model::surface_map.end()) { - throw std::runtime_error{"Invalid surface ID " + std::to_string(abs(r)) - + " specified in region for cell " + std::to_string(id_) + "."}; - } - r = (r > 0) ? it->second + 1 : -(it->second + 1); - } - } - - // Convert the infix region spec to RPN. - rpn_ = generate_rpn(id_, region_); - - // Check if this is a simple cell. - simple_ = true; - for (int32_t token : rpn_) { - if ((token == OP_COMPLEMENT) || (token == OP_UNION)) { - simple_ = false; - break; - } - } - - // If this cell is simple, remove all the superfluous operator tokens. - if (simple_) { - size_t i0 = 0; - size_t i1 = 0; - while (i1 < rpn_.size()) { - if (rpn_[i1] < OP_UNION) { - rpn_[i0] = rpn_[i1]; - ++i0; - } - ++i1; - } - rpn_.resize(i0); - } - rpn_.shrink_to_fit(); + // Get a tokenized representation of the region specification and apply De + // Morgans law + Region region(region_spec, id_); + region_ = region; // Read the translation vector. if (check_for_node(cell_node, "translation")) { if (fill_ == C_NONE) { fatal_error(fmt::format("Cannot apply a translation to cell {}" - " because it is not filled with another universe", id_)); + " because it is not filled with another universe", + id_)); } auto xyz {get_node_array(cell_node, "translation")}; if (xyz.size() != 3) { - fatal_error(fmt::format( - "Non-3D translation vector applied to cell {}", id_)); + fatal_error( + fmt::format("Non-3D translation vector applied to cell {}", id_)); } translation_ = xyz; } // Read the rotation transform. if (check_for_node(cell_node, "rotation")) { - if (fill_ == C_NONE) { - fatal_error(fmt::format("Cannot apply a rotation to cell {}" - " because it is not filled with another universe", id_)); - } - auto rot {get_node_array(cell_node, "rotation")}; - if (rot.size() != 3 && rot.size() != 9) { - fatal_error(fmt::format( - "Non-3D rotation vector applied to cell {}", id_)); - } - - // Compute and store the rotation matrix. - rotation_.reserve(rot.size() == 9 ? 9 : 12); - if (rot.size() == 3) { - double phi = -rot[0] * PI / 180.0; - double theta = -rot[1] * PI / 180.0; - double psi = -rot[2] * PI / 180.0; - rotation_.push_back(std::cos(theta) * std::cos(psi)); - rotation_.push_back(-std::cos(phi) * std::sin(psi) - + std::sin(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::sin(phi) * std::sin(psi) - + std::cos(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::cos(theta) * std::sin(psi)); - rotation_.push_back(std::cos(phi) * std::cos(psi) - + std::sin(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(phi) * std::cos(psi) - + std::cos(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(theta)); - rotation_.push_back(std::sin(phi) * std::cos(theta)); - rotation_.push_back(std::cos(phi) * std::cos(theta)); - - // When user specifies angles, write them at end of vector - rotation_.push_back(rot[0]); - rotation_.push_back(rot[1]); - rotation_.push_back(rot[2]); - } else { - std::copy(rot.begin(), rot.end(), std::back_inserter(rotation_)); - } + set_rotation(rot); } } //============================================================================== -bool -CSGCell::contains(Position r, Direction u, int32_t on_surface) const +void CSGCell::to_hdf5_inner(hid_t group_id) const { - if (simple_) { - return contains_simple(r, u, on_surface); - } else { - return contains_complex(r, u, on_surface); - } + write_string(group_id, "geom_type", "csg", false); + write_string(group_id, "region", region_.str(), false); } //============================================================================== -std::pair -CSGCell::distance(Position r, Direction u, int32_t on_surface, Particle* p) const +vector::iterator CSGCell::find_left_parenthesis( + vector::iterator start, const vector& infix) { - double min_dist {INFTY}; - int32_t i_surf {std::numeric_limits::max()}; - - for (int32_t token : rpn_) { - // Ignore this token if it corresponds to an operator rather than a region. - if (token >= OP_UNION) continue; + // start search at zero + int parenthesis_level = 0; + auto it = start; + while (it != infix.begin()) { + // look at two tokens at a time + int32_t one = *it; + int32_t two = *(it - 1); - // Calculate the distance to this surface. - // Note the off-by-one indexing - bool coincident {std::abs(token) == std::abs(on_surface)}; - double d {model::surfaces[abs(token)-1]->distance(r, u, coincident)}; + // decrement parenthesis level if there are two adjacent surfaces + if (one < OP_UNION && two < OP_UNION) { + parenthesis_level--; + // increment if there are two adjacent operators + } else if (one >= OP_UNION && two >= OP_UNION) { + parenthesis_level++; + } - // Check if this distance is the new minimum. - if (d < min_dist) { - if (min_dist - d >= FP_PRECISION*min_dist) { - min_dist = d; - i_surf = -token; - } + // if the level gets to zero, return the position + if (parenthesis_level == 0) { + // move the iterator back one before leaving the loop + // so that all tokens in the parenthesis block are included + it--; + break; } - } - return {min_dist, i_surf}; + // continue loop, one token at a time + it--; + } + return it; } +//============================================================================== +// Region implementation //============================================================================== -void -CSGCell::to_hdf5(hid_t cell_group) const +Region::Region(std::string region_spec, int32_t cell_id) { - // Create a group for this cell. - auto group = create_group(cell_group, fmt::format("cell {}", id_)); - - if (!name_.empty()) { - write_string(group, "name", name_, false); - } + // Check if region_spec is not empty. + if (!region_spec.empty()) { + // Parse all halfspaces and operators except for intersection (whitespace). + for (int i = 0; i < region_spec.size();) { + if (region_spec[i] == '(') { + expression_.push_back(OP_LEFT_PAREN); + i++; + + } else if (region_spec[i] == ')') { + expression_.push_back(OP_RIGHT_PAREN); + i++; + + } else if (region_spec[i] == '|') { + expression_.push_back(OP_UNION); + i++; + + } else if (region_spec[i] == '~') { + expression_.push_back(OP_COMPLEMENT); + i++; + + } else if (region_spec[i] == '-' || region_spec[i] == '+' || + std::isdigit(region_spec[i])) { + // This is the start of a halfspace specification. Iterate j until we + // find the end, then push-back everything between i and j. + int j = i + 1; + while (j < region_spec.size() && std::isdigit(region_spec[j])) { + j++; + } + expression_.push_back(std::stoi(region_spec.substr(i, j - i))); + i = j; - write_dataset(group, "universe", model::universes[universe_]->id_); + } else if (std::isspace(region_spec[i])) { + i++; - // Write the region specification. - if (!region_.empty()) { - std::stringstream region_spec {}; - for (int32_t token : region_) { - if (token == OP_LEFT_PAREN) { - region_spec << " ("; - } else if (token == OP_RIGHT_PAREN) { - region_spec << " )"; - } else if (token == OP_COMPLEMENT) { - region_spec << " ~"; - } else if (token == OP_INTERSECTION) { - } else if (token == OP_UNION) { - region_spec << " |"; } else { - // Note the off-by-one indexing - auto surf_id = model::surfaces[abs(token)-1]->id_; - region_spec << " " << ((token > 0) ? surf_id : -surf_id); + auto err_msg = + fmt::format("Region specification contains invalid character, \"{}\"", + region_spec[i]); + fatal_error(err_msg); } } - write_string(group, "region", region_spec.str(), false); - } - // Write fill information. - if (type_ == Fill::MATERIAL) { - write_dataset(group, "fill_type", "material"); - vector mat_ids; - for (auto i_mat : material_) { - if (i_mat != MATERIAL_VOID) { - mat_ids.push_back(model::materials[i_mat]->id_); - } else { - mat_ids.push_back(MATERIAL_VOID); + // Add in intersection operators where a missing operator is needed. + int i = 0; + while (i < expression_.size() - 1) { + bool left_compat { + (expression_[i] < OP_UNION) || (expression_[i] == OP_RIGHT_PAREN)}; + bool right_compat {(expression_[i + 1] < OP_UNION) || + (expression_[i + 1] == OP_LEFT_PAREN) || + (expression_[i + 1] == OP_COMPLEMENT)}; + if (left_compat && right_compat) { + expression_.insert(expression_.begin() + i + 1, OP_INTERSECTION); } + i++; } - if (mat_ids.size() == 1) { - write_dataset(group, "material", mat_ids[0]); - } else { - write_dataset(group, "material", mat_ids); + + // Remove complement operators using DeMorgan's laws + auto it = std::find(expression_.begin(), expression_.end(), OP_COMPLEMENT); + while (it != expression_.end()) { + // Erase complement + expression_.erase(it); + + // Define stop given left parenthesis or not + auto stop = it; + if (*it == OP_LEFT_PAREN) { + int depth = 1; + do { + stop++; + if (*stop > OP_COMPLEMENT) { + if (*stop == OP_RIGHT_PAREN) { + depth--; + } else { + depth++; + } + } + } while (depth > 0); + it++; + } + + // apply DeMorgan's law to any surfaces/operators between these + // positions in the RPN + apply_demorgan(it, stop); + // update iterator position + it = std::find(expression_.begin(), expression_.end(), OP_COMPLEMENT); } - vector temps; - for (auto sqrtkT_val : sqrtkT_) - temps.push_back(sqrtkT_val * sqrtkT_val / K_BOLTZMANN); - write_dataset(group, "temperature", temps); + // Convert user IDs to surface indices. + for (auto& r : expression_) { + if (r < OP_UNION) { + const auto& it {model::surface_map.find(abs(r))}; + if (it == model::surface_map.end()) { + throw std::runtime_error { + "Invalid surface ID " + std::to_string(abs(r)) + + " specified in region for cell " + std::to_string(cell_id) + "."}; + } + r = (r > 0) ? it->second + 1 : -(it->second + 1); + } + } - } else if (type_ == Fill::UNIVERSE) { - write_dataset(group, "fill_type", "universe"); - write_dataset(group, "fill", model::universes[fill_]->id_); - if (translation_ != Position(0, 0, 0)) { - write_dataset(group, "translation", translation_); + // Check if this is a simple cell. + simple_ = true; + for (int32_t token : expression_) { + if (token == OP_UNION) { + simple_ = false; + // Ensure intersections have precedence over unions + add_precedence(); + break; + } } - if (!rotation_.empty()) { - if (rotation_.size() == 12) { - array rot {rotation_[9], rotation_[10], rotation_[11]}; - write_dataset(group, "rotation", rot); - } else { - write_dataset(group, "rotation", rotation_); + + // If this cell is simple, remove all the superfluous operator tokens. + if (simple_) { + for (auto it = expression_.begin(); it != expression_.end(); it++) { + if (*it == OP_INTERSECTION || *it > OP_COMPLEMENT) { + expression_.erase(it); + it--; + } } } + expression_.shrink_to_fit(); - } else if (type_ == Fill::LATTICE) { - write_dataset(group, "fill_type", "lattice"); - write_dataset(group, "lattice", model::lattices[fill_]->id_); + } else { + simple_ = true; } +} - close_group(group); +//============================================================================== + +void Region::apply_demorgan( + vector::iterator start, vector::iterator stop) +{ + do { + if (*start < OP_UNION) { + *start *= -1; + } else if (*start == OP_UNION) { + *start = OP_INTERSECTION; + } else if (*start == OP_INTERSECTION) { + *start = OP_UNION; + } + start++; + } while (start < stop); } -BoundingBox CSGCell::bounding_box_simple() const { - BoundingBox bbox; - for (int32_t token : rpn_) { - bbox &= model::surfaces[abs(token)-1]->bounding_box(token > 0); +//============================================================================== +//! Add precedence for infix regions so intersections have higher +//! precedence than unions using parentheses. +//============================================================================== + +std::vector::iterator Region::add_parentheses( + std::vector::iterator start) +{ + int32_t start_token = *start; + // Add left parenthesis + if (start_token == OP_INTERSECTION) { + start = expression_.insert(start - 1, OP_LEFT_PAREN); + } else { + start = expression_.insert(start + 1, OP_LEFT_PAREN); + } + start++; + + // Keep track of return iterator distance. If we don't encounter a left + // parenthesis, we return an iterator corresponding to wherever the right + // parenthesis is inserted. If a left parenthesis is encountered, an iterator + // corresponding to the left parenthesis is returned. Also note that we keep + // track of a *distance* instead of an iterator because the underlying memory + // allocation may change. + std::size_t return_it_dist = 0; + + // Add right parenthesis + // While the start iterator is within the bounds of infix + while (start < expression_.end()) { + start++; + + // If the current token is an operator and is different than the start token + if (*start >= OP_UNION && *start != start_token) { + // Skip wrapped regions but save iterator position to check precedence and + // add right parenthesis, right parenthesis position depends on the + // operator, when the operator is a union then do not include the operator + // in the region, when the operator is an intersection then include the + // operator and next surface + if (*start == OP_LEFT_PAREN) { + return_it_dist = std::distance(expression_.begin(), start); + int depth = 1; + do { + start++; + if (*start > OP_COMPLEMENT) { + if (*start == OP_RIGHT_PAREN) { + depth--; + } else { + depth++; + } + } + } while (depth > 0); + } else { + start = expression_.insert( + start_token == OP_UNION ? start - 1 : start, OP_RIGHT_PAREN); + if (return_it_dist > 0) { + return expression_.begin() + return_it_dist; + } else { + return start - 1; + } + } + } + } + // If we get here a right parenthesis hasn't been placed, + // return iterator + expression_.push_back(OP_RIGHT_PAREN); + if (return_it_dist > 0) { + return expression_.begin() + return_it_dist; + } else { + return start - 1; } - return bbox; } -void CSGCell::apply_demorgan( - vector::iterator start, vector::iterator stop) +//============================================================================== + +void Region::add_precedence() { - while (start < stop) { - if (*start < OP_UNION) { *start *= -1; } - else if (*start == OP_UNION) { *start = OP_INTERSECTION; } - else if (*start == OP_INTERSECTION) { *start = OP_UNION; } - start++; + int32_t current_op = 0; + std::size_t current_dist = 0; + + for (auto it = expression_.begin(); it != expression_.end(); it++) { + int32_t token = *it; + + if (token == OP_UNION || token == OP_INTERSECTION) { + if (current_op == 0) { + // Set the current operator if is hasn't been set + current_op = token; + current_dist = std::distance(expression_.begin(), it); + } else if (token != current_op) { + // If the current operator doesn't match the token, add parenthesis to + // assert precedence + if (current_op == OP_INTERSECTION) { + it = add_parentheses(expression_.begin() + current_dist); + } else { + it = add_parentheses(it); + } + current_op = 0; + current_dist = 0; + } + } else if (token > OP_COMPLEMENT) { + // If the token is a parenthesis reset the current operator + current_op = 0; + current_dist = 0; + } } } -vector::iterator CSGCell::find_left_parenthesis( - vector::iterator start, const vector& rpn) +//============================================================================== +//! Convert infix region specification to Reverse Polish Notation (RPN) +//! +//! This function uses the shunting-yard algorithm. +//============================================================================== + +vector Region::generate_postfix(int32_t cell_id) const { - // start search at zero - int parenthesis_level = 0; - auto it = start; - while (it != rpn.begin()) { - // look at two tokens at a time - int32_t one = *it; - int32_t two = *(it - 1); + vector rpn; + vector stack; - // decrement parenthesis level if there are two adjacent surfaces - if (one < OP_UNION && two < OP_UNION) { - parenthesis_level--; - // increment if there are two adjacent operators - } else if (one >= OP_UNION && two >= OP_UNION) { - parenthesis_level++; + for (int32_t token : expression_) { + if (token < OP_UNION) { + // If token is not an operator, add it to output + rpn.push_back(token); + } else if (token < OP_RIGHT_PAREN) { + // Regular operators union, intersection, complement + while (stack.size() > 0) { + int32_t op = stack.back(); + + if (op < OP_RIGHT_PAREN && ((token == OP_COMPLEMENT && token < op) || + (token != OP_COMPLEMENT && token <= op))) { + // While there is an operator, op, on top of the stack, if the token + // is left-associative and its precedence is less than or equal to + // that of op or if the token is right-associative and its precedence + // is less than that of op, move op to the output queue and push the + // token on to the stack. Note that only complement is + // right-associative. + rpn.push_back(op); + stack.pop_back(); + } else { + break; + } + } + + stack.push_back(token); + + } else if (token == OP_LEFT_PAREN) { + // If the token is a left parenthesis, push it onto the stack + stack.push_back(token); + + } else { + // If the token is a right parenthesis, move operators from the stack to + // the output queue until reaching the left parenthesis. + for (auto it = stack.rbegin(); *it != OP_LEFT_PAREN; it++) { + // If we run out of operators without finding a left parenthesis, it + // means there are mismatched parentheses. + if (it == stack.rend()) { + fatal_error(fmt::format( + "Mismatched parentheses in region specification for cell {}", + cell_id)); + } + rpn.push_back(stack.back()); + stack.pop_back(); + } + + // Pop the left parenthesis. + stack.pop_back(); } + } - // if the level gets to zero, return the position - if (parenthesis_level == 0) { - // move the iterator back one before leaving the loop - // so that all tokens in the parenthesis block are included - it--; - break; + while (stack.size() > 0) { + int32_t op = stack.back(); + + // If the operator is a parenthesis it is mismatched. + if (op >= OP_RIGHT_PAREN) { + fatal_error(fmt::format( + "Mismatched parentheses in region specification for cell {}", cell_id)); + } + + rpn.push_back(stack.back()); + stack.pop_back(); + } + + return rpn; +} + +//============================================================================== + +std::string Region::str() const +{ + std::stringstream region_spec {}; + if (!expression_.empty()) { + for (int32_t token : expression_) { + if (token == OP_LEFT_PAREN) { + region_spec << " ("; + } else if (token == OP_RIGHT_PAREN) { + region_spec << " )"; + } else if (token == OP_COMPLEMENT) { + region_spec << " ~"; + } else if (token == OP_INTERSECTION) { + } else if (token == OP_UNION) { + region_spec << " |"; + } else { + // Note the off-by-one indexing + auto surf_id = model::surfaces[abs(token) - 1]->id_; + region_spec << " " << ((token > 0) ? surf_id : -surf_id); + } } - - // continue loop, one token at a time - it--; } - return it; + return region_spec.str(); } -void CSGCell::remove_complement_ops(vector& rpn) -{ - auto it = std::find(rpn.begin(), rpn.end(), OP_COMPLEMENT); - while (it != rpn.end()) { - // find the opening parenthesis (if any) - auto left = find_left_parenthesis(it, rpn); - vector tmp(left, it + 1); - - // apply DeMorgan's law to any surfaces/operators between these - // positions in the RPN - apply_demorgan(left, it); - // remove complement operator - rpn.erase(it); - // update iterator position - it = std::find(rpn.begin(), rpn.end(), OP_COMPLEMENT); - } -} +//============================================================================== -BoundingBox CSGCell::bounding_box_complex(vector rpn) +std::pair Region::distance( + Position r, Direction u, int32_t on_surface) const { - // remove complements by adjusting surface signs and operators - remove_complement_ops(rpn); + double min_dist {INFTY}; + int32_t i_surf {std::numeric_limits::max()}; - vector stack(rpn.size()); - int i_stack = -1; + for (int32_t token : expression_) { + // Ignore this token if it corresponds to an operator rather than a region. + if (token >= OP_UNION) + continue; - for (auto& token : rpn) { - if (token == OP_UNION) { - stack[i_stack - 1] = stack[i_stack - 1] | stack[i_stack]; - i_stack--; - } else if (token == OP_INTERSECTION) { - stack[i_stack - 1] = stack[i_stack - 1] & stack[i_stack]; - i_stack--; - } else { - i_stack++; - stack[i_stack] = model::surfaces[abs(token) - 1]->bounding_box(token > 0); + // Calculate the distance to this surface. + // Note the off-by-one indexing + bool coincident {std::abs(token) == std::abs(on_surface)}; + double d {model::surfaces[abs(token) - 1]->distance(r, u, coincident)}; + + // Check if this distance is the new minimum. + if (d < min_dist) { + if (min_dist - d >= FP_PRECISION * min_dist) { + min_dist = d; + i_surf = -token; + } } } - Ensures(i_stack == 0); - return stack.front(); + return {min_dist, i_surf}; } -BoundingBox CSGCell::bounding_box() const { - return simple_ ? bounding_box_simple() : bounding_box_complex(rpn_); +//============================================================================== + +bool Region::contains(Position r, Direction u, int32_t on_surface) const +{ + if (simple_) { + return contains_simple(r, u, on_surface); + } else { + return contains_complex(r, u, on_surface); + } } //============================================================================== -bool -CSGCell::contains_simple(Position r, Direction u, int32_t on_surface) const +bool Region::contains_simple(Position r, Direction u, int32_t on_surface) const { - for (int32_t token : rpn_) { + for (int32_t token : expression_) { // Assume that no tokens are operators. Evaluate the sense of particle with // respect to the surface and see if the token matches the sense. If the // particle's surface attribute is set and matches the token, that @@ -718,8 +836,10 @@ CSGCell::contains_simple(Position r, Direction u, int32_t on_surface) const return false; } else { // Note the off-by-one indexing - bool sense = model::surfaces[abs(token)-1]->sense(r, u); - if (sense != (token > 0)) {return false;} + bool sense = model::surfaces[abs(token) - 1]->sense(r, u); + if (sense != (token > 0)) { + return false; + } } } return true; @@ -727,260 +847,131 @@ CSGCell::contains_simple(Position r, Direction u, int32_t on_surface) const //============================================================================== -bool -CSGCell::contains_complex(Position r, Direction u, int32_t on_surface) const +bool Region::contains_complex(Position r, Direction u, int32_t on_surface) const { - // Make a stack of booleans. We don't know how big it needs to be, but we do - // know that rpn.size() is an upper-bound. - vector stack(rpn_.size()); - int i_stack = -1; + bool in_cell = true; + int total_depth = 0; - for (int32_t token : rpn_) { - // If the token is a binary operator (intersection/union), apply it to - // the last two items on the stack. If the token is a unary operator - // (complement), apply it to the last item on the stack. - if (token == OP_UNION) { - stack[i_stack-1] = stack[i_stack-1] || stack[i_stack]; - i_stack --; - } else if (token == OP_INTERSECTION) { - stack[i_stack-1] = stack[i_stack-1] && stack[i_stack]; - i_stack --; - } else if (token == OP_COMPLEMENT) { - stack[i_stack] = !stack[i_stack]; - } else { - // If the token is not an operator, evaluate the sense of particle with - // respect to the surface and see if the token matches the sense. If the - // particle's surface attribute is set and matches the token, that - // overrides the determination based on sense(). - i_stack ++; + // For each token + for (auto it = expression_.begin(); it != expression_.end(); it++) { + int32_t token = *it; + + // If the token is a surface evaluate the sense + // If the token is a union or intersection check to + // short circuit + if (token < OP_UNION) { if (token == on_surface) { - stack[i_stack] = true; + in_cell = true; } else if (-token == on_surface) { - stack[i_stack] = false; + in_cell = false; } else { // Note the off-by-one indexing - bool sense = model::surfaces[abs(token)-1]->sense(r, u); - stack[i_stack] = (sense == (token > 0)); + bool sense = model::surfaces[abs(token) - 1]->sense(r, u); + in_cell = (sense == (token > 0)); + } + } else if ((token == OP_UNION && in_cell == true) || + (token == OP_INTERSECTION && in_cell == false)) { + // If the total depth is zero return + if (total_depth == 0) { + return in_cell; } - } - } - if (i_stack == 0) { - // The one remaining bool on the stack indicates whether the particle is - // in the cell. - return stack[i_stack]; - } else { - // This case occurs if there is no region specification since i_stack will - // still be -1. - return true; + total_depth--; + + // While the iterator is within the bounds of the vector + int depth = 1; + do { + // Get next token + it++; + int32_t next_token = *it; + + // If the token is an a parenthesis + if (next_token > OP_COMPLEMENT) { + // Adjust depth accordingly + if (next_token == OP_RIGHT_PAREN) { + depth--; + } else { + depth++; + } + } + } while (depth > 0); + } else if (token == OP_LEFT_PAREN) { + total_depth++; + } else if (token == OP_RIGHT_PAREN) { + total_depth--; + } } + return in_cell; } //============================================================================== -// DAGMC Cell implementation -//============================================================================== -#ifdef DAGMC -DAGCell::DAGCell() : Cell{} { simple_ = true; }; -std::pair -DAGCell::distance(Position r, Direction u, int32_t on_surface, Particle* p) const +BoundingBox Region::bounding_box(int32_t cell_id) const { - Expects(p); - // if we've changed direction or we're not on a surface, - // reset the history and update last direction - if (u != p->last_dir() || on_surface == 0) { - p->history().reset(); - p->last_dir() = u; - } - - moab::ErrorCode rval; - moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_); - moab::EntityHandle hit_surf; - double dist; - double pnt[3] = {r.x, r.y, r.z}; - double dir[3] = {u.x, u.y, u.z}; - rval = dagmc_ptr_->ray_fire(vol, pnt, dir, hit_surf, dist, &p->history()); - MB_CHK_ERR_CONT(rval); - int surf_idx; - if (hit_surf != 0) { - surf_idx = dagmc_ptr_->index_by_handle(hit_surf); + if (simple_) { + return bounding_box_simple(); } else { - // indicate that particle is lost - surf_idx = -1; - dist = INFINITY; + auto postfix = generate_postfix(cell_id); + return bounding_box_complex(postfix); } - - return {dist, surf_idx}; -} - -bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const -{ - moab::ErrorCode rval; - moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_); - - int result = 0; - double pnt[3] = {r.x, r.y, r.z}; - double dir[3] = {u.x, u.y, u.z}; - rval = dagmc_ptr_->point_in_volume(vol, pnt, result, dir); - MB_CHK_ERR_CONT(rval); - return result; } -void DAGCell::to_hdf5(hid_t group_id) const { return; } +//============================================================================== -BoundingBox DAGCell::bounding_box() const +BoundingBox Region::bounding_box_simple() const { - moab::ErrorCode rval; - moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_); - double min[3], max[3]; - rval = dagmc_ptr_->getobb(vol, min, max); - MB_CHK_ERR_CONT(rval); - return {min[0], max[0], min[1], max[1], min[2], max[2]}; + BoundingBox bbox; + for (int32_t token : expression_) { + bbox &= model::surfaces[abs(token) - 1]->bounding_box(token > 0); + } + return bbox; } -#endif - -//============================================================================== -// UniversePartitioner implementation //============================================================================== -UniversePartitioner::UniversePartitioner(const Universe& univ) +BoundingBox Region::bounding_box_complex(vector postfix) const { - // Define an ordered set of surface indices that point to z-planes. Use a - // functor to to order the set by the z0_ values of the corresponding planes. - struct compare_surfs { - bool operator()(const int32_t& i_surf, const int32_t& j_surf) const - { - const auto* surf = model::surfaces[i_surf].get(); - const auto* zplane = dynamic_cast(surf); - double zi = zplane->z0_; - surf = model::surfaces[j_surf].get(); - zplane = dynamic_cast(surf); - double zj = zplane->z0_; - return zi < zj; - } - }; - std::set surf_set; - - // Find all of the z-planes in this universe. A set is used here for the - // O(log(n)) insertions that will ensure entries are not repeated. - for (auto i_cell : univ.cells_) { - for (auto token : model::cells[i_cell]->rpn_) { - if (token < OP_UNION) { - auto i_surf = std::abs(token) - 1; - const auto* surf = model::surfaces[i_surf].get(); - if (const auto* zplane = dynamic_cast(surf)) - surf_set.insert(i_surf); - } + vector stack(postfix.size()); + int i_stack = -1; + + for (auto& token : postfix) { + if (token == OP_UNION) { + stack[i_stack - 1] = stack[i_stack - 1] | stack[i_stack]; + i_stack--; + } else if (token == OP_INTERSECTION) { + stack[i_stack - 1] = stack[i_stack - 1] & stack[i_stack]; + i_stack--; + } else { + i_stack++; + stack[i_stack] = model::surfaces[abs(token) - 1]->bounding_box(token > 0); } } - // Populate the surfs_ vector from the ordered set. - surfs_.insert(surfs_.begin(), surf_set.begin(), surf_set.end()); + Ensures(i_stack == 0); + return stack.front(); +} - // Populate the partition lists. - partitions_.resize(surfs_.size() + 1); - for (auto i_cell : univ.cells_) { - // It is difficult to determine the bounds of a complex cell, so add complex - // cells to all partitions. - if (!model::cells[i_cell]->simple_) { - for (auto& p : partitions_) p.push_back(i_cell); - continue; - } +//============================================================================== - // Find the tokens for bounding z-planes. - int32_t lower_token = 0, upper_token = 0; - double min_z, max_z; - for (auto token : model::cells[i_cell]->rpn_) { - if (token < OP_UNION) { - const auto* surf = model::surfaces[std::abs(token) - 1].get(); - if (const auto* zplane = dynamic_cast(surf)) { - if (lower_token == 0 || zplane->z0_ < min_z) { - lower_token = token; - min_z = zplane->z0_; - } - if (upper_token == 0 || zplane->z0_ > max_z) { - upper_token = token; - max_z = zplane->z0_; - } - } - } - } +vector Region::surfaces() const +{ + if (simple_) { + return expression_; + } - // If there are no bounding z-planes, add this cell to all partitions. - if (lower_token == 0) { - for (auto& p : partitions_) p.push_back(i_cell); - continue; - } + vector surfaces = expression_; - // Find the first partition this cell lies in. If the lower_token indicates - // a negative halfspace, then the cell is unbounded in the lower direction - // and it lies in the first partition onward. Otherwise, it is bounded by - // the positive halfspace given by the lower_token. - int first_partition = 0; - if (lower_token > 0) { - for (int i = 0; i < surfs_.size(); ++i) { - if (lower_token == surfs_[i] + 1) { - first_partition = i + 1; - break; - } - } - } + auto it = std::find_if(surfaces.begin(), surfaces.end(), + [&](const auto& value) { return value >= OP_UNION; }); - // Find the last partition this cell lies in. The logic is analogous to the - // logic for first_partition. - int last_partition = surfs_.size(); - if (upper_token < 0) { - for (int i = first_partition; i < surfs_.size(); ++i) { - if (upper_token == -(surfs_[i] + 1)) { - last_partition = i; - break; - } - } - } + while (it != surfaces.end()) { + surfaces.erase(it); - // Add the cell to all relevant partitions. - for (int i = first_partition; i <= last_partition; ++i) { - partitions_[i].push_back(i_cell); - } + it = std::find_if(surfaces.begin(), surfaces.end(), + [&](const auto& value) { return value >= OP_UNION; }); } -} - -const vector& UniversePartitioner::get_cells( - Position r, Direction u) const -{ - // Perform a binary search for the partition containing the given coordinates. - int left = 0; - int middle = (surfs_.size() - 1) / 2; - int right = surfs_.size() - 1; - while (true) { - // Check the sense of the coordinates for the current surface. - const auto& surf = *model::surfaces[surfs_[middle]]; - if (surf.sense(r, u)) { - // The coordinates lie in the positive halfspace. Recurse if there are - // more surfaces to check. Otherwise, return the cells on the positive - // side of this surface. - int right_leaf = right - (right - middle) / 2; - if (right_leaf != middle) { - left = middle + 1; - middle = right_leaf; - } else { - return partitions_[middle+1]; - } - } else { - // The coordinates lie in the negative halfspace. Recurse if there are - // more surfaces to check. Otherwise, return the cells on the negative - // side of this surface. - int left_leaf = left + (middle - left) / 2; - if (left_leaf != middle) { - right = middle-1; - middle = left_leaf; - } else { - return partitions_[middle]; - } - } - } + return surfaces; } //============================================================================== @@ -991,9 +982,8 @@ void read_cells(pugi::xml_node node) { // Count the number of cells. int n_cells = 0; - for (pugi::xml_node cell_node: node.children("cell")) {n_cells++;} - if (n_cells == 0) { - fatal_error("No cells found in geometry.xml!"); + for (pugi::xml_node cell_node : node.children("cell")) { + n_cells++; } // Loop over XML cell elements and populate the array. @@ -1009,37 +999,71 @@ void read_cells(pugi::xml_node node) if (search == model::cell_map.end()) { model::cell_map[id] = i; } else { - fatal_error(fmt::format("Two or more cells use the same unique ID: {}", id)); + fatal_error( + fmt::format("Two or more cells use the same unique ID: {}", id)); } } + read_dagmc_universes(node); + + populate_universes(); + + // Allocate the cell overlap count if necessary. + if (settings::check_overlaps) { + model::overlap_check_count.resize(model::cells.size(), 0); + } + + if (model::cells.size() == 0) { + fatal_error("No cells were found in the geometry.xml file"); + } +} + +void populate_universes() +{ + // Used to map universe index to the index of an implicit complement cell for + // DAGMC universes + std::unordered_map implicit_comp_cells; + // Populate the Universe vector and map. - for (int i = 0; i < model::cells.size(); i++) { - int32_t uid = model::cells[i]->universe_; + for (int index_cell = 0; index_cell < model::cells.size(); index_cell++) { + int32_t uid = model::cells[index_cell]->universe_; auto it = model::universe_map.find(uid); if (it == model::universe_map.end()) { model::universes.push_back(make_unique()); model::universes.back()->id_ = uid; - model::universes.back()->cells_.push_back(i); + model::universes.back()->cells_.push_back(index_cell); model::universe_map[uid] = model::universes.size() - 1; } else { - model::universes[it->second]->cells_.push_back(i); +#ifdef DAGMC + // Skip implicit complement cells for now + Universe* univ = model::universes[it->second].get(); + DAGUniverse* dag_univ = dynamic_cast(univ); + if (dag_univ && (dag_univ->implicit_complement_idx() == index_cell)) { + implicit_comp_cells[it->second] = index_cell; + continue; + } +#endif + + model::universes[it->second]->cells_.push_back(index_cell); } } - model::universes.shrink_to_fit(); - // Allocate the cell overlap count if necessary. - if (settings::check_overlaps) { - model::overlap_check_count.resize(model::cells.size(), 0); + // Add DAGUniverse implicit complement cells last + for (const auto& it : implicit_comp_cells) { + int index_univ = it.first; + int index_cell = it.second; + model::universes[index_univ]->cells_.push_back(index_cell); } + + model::universes.shrink_to_fit(); } //============================================================================== // C-API functions //============================================================================== -extern "C" int -openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n) +extern "C" int openmc_cell_get_fill( + int32_t index, int* type, int32_t** indices, int32_t* n) { if (index >= 0 && index < model::cells.size()) { Cell& c {*model::cells[index]}; @@ -1058,9 +1082,8 @@ openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n) return 0; } -extern "C" int -openmc_cell_set_fill(int32_t index, int type, int32_t n, - const int32_t* indices) +extern "C" int openmc_cell_set_fill( + int32_t index, int type, int32_t n, const int32_t* indices) { Fill filltype = static_cast(type); if (index >= 0 && index < model::cells.size()) { @@ -1092,8 +1115,8 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n, return 0; } -extern "C" int -openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance, bool set_contained) +extern "C" int openmc_cell_set_temperature( + int32_t index, double T, const int32_t* instance, bool set_contained) { if (index < 0 || index >= model::cells.size()) { strcpy(openmc_err_msg, "Index in cells array is out of bounds."); @@ -1110,8 +1133,8 @@ openmc_cell_set_temperature(int32_t index, double T, const int32_t* instance, bo return 0; } -extern "C" int -openmc_cell_get_temperature(int32_t index, const int32_t* instance, double* T) +extern "C" int openmc_cell_get_temperature( + int32_t index, const int32_t* instance, double* T) { if (index < 0 || index >= model::cells.size()) { strcpy(openmc_err_msg, "Index in cells array is out of bounds."); @@ -1129,8 +1152,9 @@ openmc_cell_get_temperature(int32_t index, const int32_t* instance, double* T) } //! Get the bounding box of a cell -extern "C" int -openmc_cell_bounding_box(const int32_t index, double* llc, double* urc) { +extern "C" int openmc_cell_bounding_box( + const int32_t index, double* llc, double* urc) +{ BoundingBox bbox; @@ -1151,8 +1175,8 @@ openmc_cell_bounding_box(const int32_t index, double* llc, double* urc) { } //! Get the name of a cell -extern "C" int -openmc_cell_get_name(int32_t index, const char** name) { +extern "C" int openmc_cell_get_name(int32_t index, const char** name) +{ if (index < 0 || index >= model::cells.size()) { set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; @@ -1164,8 +1188,8 @@ openmc_cell_get_name(int32_t index, const char** name) { } //! Set the name of a cell -extern "C" int -openmc_cell_set_name(int32_t index, const char* name) { +extern "C" int openmc_cell_set_name(int32_t index, const char* name) +{ if (index < 0 || index >= model::cells.size()) { set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; @@ -1176,11 +1200,263 @@ openmc_cell_set_name(int32_t index, const char* name) { return 0; } -std::unordered_map> Cell::get_contained_cells() const +//============================================================================== +//! Define a containing (parent) cell +//============================================================================== + +//! Used to locate a universe fill in the geometry +struct ParentCell { + bool operator==(const ParentCell& other) const + { + return cell_index == other.cell_index && + lattice_index == other.lattice_index; + } + + bool operator<(const ParentCell& other) const + { + return cell_index < other.cell_index || + (cell_index == other.cell_index && + lattice_index < other.lattice_index); + } + + gsl::index cell_index; + gsl::index lattice_index; +}; + +//! Structure used to insert ParentCell into hashed STL data structures +struct ParentCellHash { + std::size_t operator()(const ParentCell& p) const + { + return 4096 * p.cell_index + p.lattice_index; + } +}; + +//! Used to manage a traversal stack when locating parent cells of a cell +//! instance in the model +struct ParentCellStack { + + //! push method that adds to the parent_cells visited cells for this search + //! universe + void push(int32_t search_universe, const ParentCell& pc) + { + parent_cells_.push_back(pc); + // add parent cell to the set of cells we've visited for this search + // universe + visited_cells_[search_universe].insert(pc); + } + + //! removes the last parent_cell and clears the visited cells for the popped + //! cell's universe + void pop() + { + visited_cells_[this->current_univ()].clear(); + parent_cells_.pop_back(); + } + + //! checks whether or not the parent cell has been visited already for this + //! search universe + bool visited(int32_t search_universe, const ParentCell& parent_cell) + { + return visited_cells_[search_universe].count(parent_cell) != 0; + } + + //! return the next universe to search for a parent cell + int32_t current_univ() const + { + return model::cells[parent_cells_.back().cell_index]->universe_; + } + + //! indicates whether nor not parent cells are present on the stack + bool empty() const { return parent_cells_.empty(); } + + //! compute an instance for the provided distribcell index + int32_t compute_instance(int32_t distribcell_index) const + { + if (distribcell_index == C_NONE) + return 0; + + int32_t instance = 0; + for (const auto& parent_cell : this->parent_cells_) { + auto& cell = model::cells[parent_cell.cell_index]; + if (cell->type_ == Fill::UNIVERSE) { + instance += cell->offset_[distribcell_index]; + } else if (cell->type_ == Fill::LATTICE) { + auto& lattice = model::lattices[cell->fill_]; + instance += + lattice->offset(distribcell_index, parent_cell.lattice_index); + } + } + return instance; + } + + // Accessors + vector& parent_cells() { return parent_cells_; } + const vector& parent_cells() const { return parent_cells_; } + + // Data Members + vector parent_cells_; + std::unordered_map> + visited_cells_; +}; + +vector Cell::find_parent_cells( + int32_t instance, const Position& r) const +{ + + // create a temporary particle + GeometryState dummy_particle {}; + dummy_particle.r() = r; + dummy_particle.u() = {0., 0., 1.}; + + return find_parent_cells(instance, dummy_particle); +} + +vector Cell::find_parent_cells( + int32_t instance, GeometryState& p) const +{ + // look up the particle's location + exhaustive_find_cell(p); + const auto& coords = p.coord(); + + // build a parent cell stack from the particle coordinates + ParentCellStack stack; + bool cell_found = false; + for (auto it = coords.begin(); it != coords.end(); it++) { + const auto& coord = *it; + const auto& cell = model::cells[coord.cell]; + // if the cell at this level matches the current cell, stop adding to the + // stack + if (coord.cell == model::cell_map[this->id_]) { + cell_found = true; + break; + } + + // if filled with a lattice, get the lattice index from the next + // level in the coordinates to push to the stack + int lattice_idx = C_NONE; + if (cell->type_ == Fill::LATTICE) { + const auto& next_coord = *(it + 1); + lattice_idx = model::lattices[next_coord.lattice]->get_flat_index( + next_coord.lattice_i); + } + stack.push(coord.universe, {coord.cell, lattice_idx}); + } + + // if this loop finished because the cell was found and + // the instance matches the one requested in the call + // we have the correct path and can return the stack + if (cell_found && + stack.compute_instance(this->distribcell_index_) == instance) { + return stack.parent_cells(); + } + + // fall back on an exhaustive search for the cell's parents + return exhaustive_find_parent_cells(instance); +} + +vector Cell::exhaustive_find_parent_cells(int32_t instance) const +{ + ParentCellStack stack; + // start with this cell's universe + int32_t prev_univ_idx; + int32_t univ_idx = this->universe_; + + while (true) { + const auto& univ = model::universes[univ_idx]; + prev_univ_idx = univ_idx; + + // search for a cell that is filled w/ this universe + for (const auto& cell : model::cells) { + // if this is a material-filled cell, move on + if (cell->type_ == Fill::MATERIAL) + continue; + + if (cell->type_ == Fill::UNIVERSE) { + // if this is in the set of cells previously visited for this universe, + // move on + if (stack.visited(univ_idx, {model::cell_map[cell->id_], C_NONE})) + continue; + + // if this cell contains the universe we're searching for, add it to the + // stack + if (cell->fill_ == univ_idx) { + stack.push(univ_idx, {model::cell_map[cell->id_], C_NONE}); + univ_idx = cell->universe_; + } + } else if (cell->type_ == Fill::LATTICE) { + // retrieve the lattice and lattice universes + const auto& lattice = model::lattices[cell->fill_]; + const auto& lattice_univs = lattice->universes_; + + // start search for universe + auto lat_it = lattice_univs.begin(); + while (true) { + // find the next lattice cell with this universe + lat_it = std::find(lat_it, lattice_univs.end(), univ_idx); + if (lat_it == lattice_univs.end()) + break; + + int lattice_idx = lat_it - lattice_univs.begin(); + + // move iterator forward one to avoid finding the same entry + lat_it++; + if (stack.visited( + univ_idx, {model::cell_map[cell->id_], lattice_idx})) + continue; + + // add this cell and lattice index to the stack and exit loop + stack.push(univ_idx, {model::cell_map[cell->id_], lattice_idx}); + univ_idx = cell->universe_; + break; + } + } + // if we've updated the universe, break + if (prev_univ_idx != univ_idx) + break; + } // end cell loop search for universe + + // if we're at the top of the geometry and the instance matches, we're done + if (univ_idx == model::root_universe && + stack.compute_instance(this->distribcell_index_) == instance) + break; + + // if there is no match on the original cell's universe, report an error + if (univ_idx == this->universe_) { + fatal_error( + fmt::format("Could not find the parent cells for cell {}, instance {}.", + this->id_, instance)); + } + + // if we don't find a suitable update, adjust the stack and continue + if (univ_idx == model::root_universe || univ_idx == prev_univ_idx) { + stack.pop(); + univ_idx = stack.empty() ? this->universe_ : stack.current_univ(); + } + + } // end while + + // reverse the stack so the highest cell comes first + std::reverse(stack.parent_cells().begin(), stack.parent_cells().end()); + return stack.parent_cells(); +} + +std::unordered_map> Cell::get_contained_cells( + int32_t instance, Position* hint) const { std::unordered_map> contained_cells; + + // if this is a material-filled cell it has no contained cells + if (this->type_ == Fill::MATERIAL) + return contained_cells; + + // find the pathway through the geometry to this cell vector parent_cells; + // if a positional hint is provided, attempt to do a fast lookup + // of the parent cells + parent_cells = hint ? find_parent_cells(instance, *hint) + : exhaustive_find_parent_cells(instance); + // if this cell is filled w/ a material, it contains no other cells if (type_ != Fill::MATERIAL) { this->get_contained_cells_inner(contained_cells, parent_cells); @@ -1200,29 +1476,30 @@ void Cell::get_contained_cells_inner( int instance = 0; if (this->distribcell_index_ >= 0) { for (auto& parent_cell : parent_cells) { - auto& cell = openmc::model::cells[parent_cell.cell_index]; + auto& cell = model::cells[parent_cell.cell_index]; if (cell->type_ == Fill::UNIVERSE) { instance += cell->offset_[distribcell_index_]; } else if (cell->type_ == Fill::LATTICE) { auto& lattice = model::lattices[cell->fill_]; - instance += lattice->offset(this->distribcell_index_, parent_cell.lattice_index); + instance += lattice->offset( + this->distribcell_index_, parent_cell.lattice_index); } } } // add entry to contained cells contained_cells[model::cell_map[id_]].push_back(instance); - // filled with universe, add the containing cell to the parent cells - // and recurse + // filled with universe, add the containing cell to the parent cells + // and recurse } else if (type_ == Fill::UNIVERSE) { parent_cells.push_back({model::cell_map[id_], -1}); auto& univ = model::universes[fill_]; - for(auto cell_index : univ->cells_) { + for (auto cell_index : univ->cells_) { auto& cell = model::cells[cell_index]; cell->get_contained_cells_inner(contained_cells, parent_cells); } parent_cells.pop_back(); - // filled with a lattice, visit each universe in the lattice - // with a recursive call to collect the cell instances + // filled with a lattice, visit each universe in the lattice + // with a recursive call to collect the cell instances } else if (type_ == Fill::LATTICE) { auto& lattice = model::lattices[fill_]; for (auto i = lattice->begin(); i != lattice->end(); ++i) { @@ -1238,8 +1515,7 @@ void Cell::get_contained_cells_inner( } //! Return the index in the cells array of a cell with a given ID -extern "C" int -openmc_get_cell_index(int32_t id, int32_t* index) +extern "C" int openmc_get_cell_index(int32_t id, int32_t* index) { auto it = model::cell_map.find(id); if (it != model::cell_map.end()) { @@ -1252,8 +1528,7 @@ openmc_get_cell_index(int32_t id, int32_t* index) } //! Return the ID of a cell -extern "C" int -openmc_cell_get_id(int32_t index, int32_t* id) +extern "C" int openmc_cell_get_id(int32_t index, int32_t* id) { if (index >= 0 && index < model::cells.size()) { *id = model::cells[index]->id_; @@ -1265,8 +1540,7 @@ openmc_cell_get_id(int32_t index, int32_t* id) } //! Set the ID of a cell -extern "C" int -openmc_cell_set_id(int32_t index, int32_t id) +extern "C" int openmc_cell_set_id(int32_t index, int32_t id) { if (index >= 0 && index < model::cells.size()) { model::cells[index]->id_ = id; @@ -1278,33 +1552,102 @@ openmc_cell_set_id(int32_t index, int32_t id) } } +//! Return the translation vector of a cell +extern "C" int openmc_cell_get_translation(int32_t index, double xyz[]) +{ + if (index >= 0 && index < model::cells.size()) { + auto& cell = model::cells[index]; + xyz[0] = cell->translation_.x; + xyz[1] = cell->translation_.y; + xyz[2] = cell->translation_.z; + return 0; + } else { + set_errmsg("Index in cells array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } +} + +//! Set the translation vector of a cell +extern "C" int openmc_cell_set_translation(int32_t index, const double xyz[]) +{ + if (index >= 0 && index < model::cells.size()) { + if (model::cells[index]->fill_ == C_NONE) { + set_errmsg(fmt::format("Cannot apply a translation to cell {}" + " because it is not filled with another universe", + index)); + return OPENMC_E_GEOMETRY; + } + model::cells[index]->translation_ = Position(xyz); + return 0; + } else { + set_errmsg("Index in cells array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } +} + +//! Return the rotation matrix of a cell +extern "C" int openmc_cell_get_rotation(int32_t index, double rot[], size_t* n) +{ + if (index >= 0 && index < model::cells.size()) { + auto& cell = model::cells[index]; + *n = cell->rotation_.size(); + std::memcpy(rot, cell->rotation_.data(), *n * sizeof(cell->rotation_[0])); + return 0; + } else { + set_errmsg("Index in cells array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } +} + +//! Set the flattened rotation matrix of a cell +extern "C" int openmc_cell_set_rotation( + int32_t index, const double rot[], size_t rot_len) +{ + if (index >= 0 && index < model::cells.size()) { + if (model::cells[index]->fill_ == C_NONE) { + set_errmsg(fmt::format("Cannot apply a rotation to cell {}" + " because it is not filled with another universe", + index)); + return OPENMC_E_GEOMETRY; + } + std::vector vec_rot(rot, rot + rot_len); + model::cells[index]->set_rotation(vec_rot); + return 0; + } else { + set_errmsg("Index in cells array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } +} + +//! Get the number of instances of the requested cell +extern "C" int openmc_cell_get_num_instances( + int32_t index, int32_t* num_instances) +{ + if (index < 0 || index >= model::cells.size()) { + set_errmsg("Index in cells array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + *num_instances = model::cells[index]->n_instances_; + return 0; +} + //! Extend the cells array by n elements -extern "C" int -openmc_extend_cells(int32_t n, int32_t* index_start, int32_t* index_end) +extern "C" int openmc_extend_cells( + int32_t n, int32_t* index_start, int32_t* index_end) { - if (index_start) *index_start = model::cells.size(); - if (index_end) *index_end = model::cells.size() + n - 1; + if (index_start) + *index_start = model::cells.size(); + if (index_end) + *index_end = model::cells.size() + n - 1; for (int32_t i = 0; i < n; i++) { model::cells.push_back(make_unique()); } return 0; } -#ifdef DAGMC -int32_t next_cell(DAGCell* cur_cell, DAGSurface* surf_xed) +extern "C" int cells_size() { - moab::EntityHandle surf = - surf_xed->dagmc_ptr_->entity_by_index(2, surf_xed->dag_index_); - moab::EntityHandle vol = - cur_cell->dagmc_ptr_->entity_by_index(3, cur_cell->dag_index_); - - moab::EntityHandle new_vol; - cur_cell->dagmc_ptr_->next_vol(surf, vol, new_vol); - - return cur_cell->dagmc_ptr_->index_by_handle(new_vol); + return model::cells.size(); } -#endif - -extern "C" int cells_size() { return model::cells.size(); } } // namespace openmc diff --git a/src/cmfd_solver.cpp b/src/cmfd_solver.cpp index 4efc515ad51..943042f67e7 100644 --- a/src/cmfd_solver.cpp +++ b/src/cmfd_solver.cpp @@ -66,7 +66,7 @@ int get_cmfd_energy_bin(const double E) } else { // Iterate through energy grid to find matching bin for (int g = 0; g < cmfd::ng; g++) { - if (E >= cmfd::egrid[g] && E < cmfd::egrid[g+1]) { + if (E >= cmfd::egrid[g] && E < cmfd::egrid[g + 1]) { return g; } } @@ -79,7 +79,8 @@ int get_cmfd_energy_bin(const double E) // COUNT_BANK_SITES bins fission sites according to CMFD mesh and energy //============================================================================== -xt::xtensor count_bank_sites(xt::xtensor& bins, bool* outside) +xt::xtensor count_bank_sites( + xt::xtensor& bins, bool* outside) { // Determine shape of array for counts std::size_t cnt_size = cmfd::nx * cmfd::ny * cmfd::nz * cmfd::ng; @@ -106,22 +107,22 @@ xt::xtensor count_bank_sites(xt::xtensor& bins, bool* outside int energy_bin = get_cmfd_energy_bin(site.E); // add to appropriate bin - cnt(mesh_bin*cmfd::ng+energy_bin) += site.wgt; + cnt(mesh_bin * cmfd::ng + energy_bin) += site.wgt; // store bin index which is used again when updating weights - bins[i] = mesh_bin*cmfd::ng+energy_bin; + bins[i] = mesh_bin * cmfd::ng + energy_bin; } // Create copy of count data. Since ownership will be acquired by xtensor, // std::allocator must be used to avoid Valgrind mismatched free() / delete // warnings. int total = cnt.size(); - double* cnt_reduced = std::allocator{}.allocate(total); + double* cnt_reduced = std::allocator {}.allocate(total); #ifdef OPENMC_MPI // collect values from all processors - MPI_Reduce(cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, - mpi::intracomm); + MPI_Reduce( + cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); // Check if there were sites outside the mesh for any processor MPI_Reduce(&outside_, outside, 1, MPI_C_BOOL, MPI_LOR, 0, mpi::intracomm); @@ -142,8 +143,8 @@ xt::xtensor count_bank_sites(xt::xtensor& bins, bool* outside // OPENMC_CMFD_REWEIGHT performs reweighting of particles in source bank //============================================================================== -extern "C" -void openmc_cmfd_reweight(const bool feedback, const double* cmfd_src) +extern "C" void openmc_cmfd_reweight( + const bool feedback, const double* cmfd_src) { // Get size of source bank and cmfd_src auto bank_size = simulation::source_bank.size(); @@ -152,8 +153,8 @@ void openmc_cmfd_reweight(const bool feedback, const double* cmfd_src) // count bank sites for CMFD mesh, store bins in bank_bins for reweighting xt::xtensor bank_bins({bank_size}, 0); bool sites_outside; - xt::xtensor sourcecounts = count_bank_sites(bank_bins, - &sites_outside); + xt::xtensor sourcecounts = + count_bank_sites(bank_bins, &sites_outside); // Compute CMFD weightfactors xt::xtensor weightfactors = xt::xtensor({src_size}, 1.); @@ -162,7 +163,7 @@ void openmc_cmfd_reweight(const bool feedback, const double* cmfd_src) fatal_error("Source sites outside of the CMFD mesh"); } - double norm = xt::sum(sourcecounts)()/cmfd::norm; + double norm = xt::sum(sourcecounts)() / cmfd::norm; for (int i = 0; i < src_size; i++) { if (sourcecounts[i] > 0 && cmfd_src[i] > 0) { weightfactors[i] = cmfd_src[i] * norm / sourcecounts[i]; @@ -170,7 +171,8 @@ void openmc_cmfd_reweight(const bool feedback, const double* cmfd_src) } } - if (!feedback) return; + if (!feedback) + return; #ifdef OPENMC_MPI // Send weightfactors to all processors @@ -188,9 +190,8 @@ void openmc_cmfd_reweight(const bool feedback, const double* cmfd_src) // OPENMC_INITIALIZE_MESH_EGRID sets the mesh and energy grid for CMFD reweight //============================================================================== -extern "C" -void openmc_initialize_mesh_egrid(const int meshtally_id, const int* cmfd_indices, - const double norm) +extern "C" void openmc_initialize_mesh_egrid( + const int meshtally_id, const int* cmfd_indices, const double norm) { // Make sure all CMFD memory is freed free_memory_cmfd(); @@ -242,9 +243,9 @@ void openmc_initialize_mesh_egrid(const int meshtally_id, const int* cmfd_indice void matrix_to_indices(int irow, int& g, int& i, int& j, int& k) { g = irow % cmfd::ng; - i = cmfd::indexmap(irow/cmfd::ng, 0); - j = cmfd::indexmap(irow/cmfd::ng, 1); - k = cmfd::indexmap(irow/cmfd::ng, 2); + i = cmfd::indexmap(irow / cmfd::ng, 0); + j = cmfd::indexmap(irow / cmfd::ng, 1); + k = cmfd::indexmap(irow / cmfd::ng, 2); } //============================================================================== @@ -254,7 +255,7 @@ void matrix_to_indices(int irow, int& g, int& i, int& j, int& k) int get_diagonal_index(int row) { - for (int j = cmfd::indptr[row]; j < cmfd::indptr[row+1]; j++) { + for (int j = cmfd::indptr[row]; j < cmfd::indptr[row + 1]; j++) { if (cmfd::indices[j] == row) return j; } @@ -272,7 +273,7 @@ void set_indexmap(const int* coremap) for (int z = 0; z < cmfd::nz; z++) { for (int y = 0; y < cmfd::ny; y++) { for (int x = 0; x < cmfd::nx; x++) { - int idx = (z*cmfd::ny*cmfd::nx) + (y*cmfd::nx) + x; + int idx = (z * cmfd::ny * cmfd::nx) + (y * cmfd::nx) + x; if (coremap[idx] != CMFD_NOACCEL) { int counter = coremap[idx]; cmfd::indexmap(counter, 0) = x; @@ -288,8 +289,8 @@ void set_indexmap(const int* coremap) // CMFD_LINSOLVER_1G solves a one group CMFD linear system //============================================================================== -int cmfd_linsolver_1g(const double* A_data, const double* b, double* x, - double tol) +int cmfd_linsolver_1g( + const double* A_data, const double* b, double* x, double tol) { // Set overrelaxation parameter double w = 1.0; @@ -304,14 +305,15 @@ int cmfd_linsolver_1g(const double* A_data, const double* b, double* x, // Perform red/black Gauss-Seidel iterations for (int irb = 0; irb < 2; irb++) { - // Loop around matrix rows - #pragma omp parallel for reduction (+:err) if(cmfd::use_all_threads) +// Loop around matrix rows +#pragma omp parallel for reduction(+ : err) if (cmfd::use_all_threads) for (int irow = 0; irow < cmfd::dim; irow++) { int g, i, j, k; matrix_to_indices(irow, g, i, j, k); // Filter out black cells - if ((i+j+k) % 2 != irb) continue; + if ((i + j + k) % 2 != irb) + continue; // Get index of diagonal for current row int didx = get_diagonal_index(irow); @@ -341,7 +343,7 @@ int cmfd_linsolver_1g(const double* A_data, const double* b, double* x, return igs; // Calculate new overrelaxation parameter - w = 1.0/(1.0 - 0.25 * cmfd::spectral * w); + w = 1.0 / (1.0 - 0.25 * cmfd::spectral * w); } // Throw error, as max iterations met @@ -355,8 +357,8 @@ int cmfd_linsolver_1g(const double* A_data, const double* b, double* x, // CMFD_LINSOLVER_2G solves a two group CMFD linear system //============================================================================== -int cmfd_linsolver_2g(const double* A_data, const double* b, double* x, - double tol) +int cmfd_linsolver_2g( + const double* A_data, const double* b, double* x, double tol) { // Set overrelaxation parameter double w = 1.0; @@ -371,38 +373,41 @@ int cmfd_linsolver_2g(const double* A_data, const double* b, double* x, // Perform red/black Gauss-Seidel iterations for (int irb = 0; irb < 2; irb++) { - // Loop around matrix rows - #pragma omp parallel for reduction (+:err) if(cmfd::use_all_threads) - for (int irow = 0; irow < cmfd::dim; irow+=2) { +// Loop around matrix rows +#pragma omp parallel for reduction(+ : err) if (cmfd::use_all_threads) + for (int irow = 0; irow < cmfd::dim; irow += 2) { int g, i, j, k; matrix_to_indices(irow, g, i, j, k); // Filter out black cells - if ((i+j+k) % 2 != irb) continue; + if ((i + j + k) % 2 != irb) + continue; // Get index of diagonals for current row and next row int d1idx = get_diagonal_index(irow); - int d2idx = get_diagonal_index(irow+1); + int d2idx = get_diagonal_index(irow + 1); // Get block diagonal - double m11 = A_data[d1idx]; // group 1 diagonal - double m12 = A_data[d1idx + 1]; // group 1 right of diagonal (sorted by col) - double m21 = A_data[d2idx - 1]; // group 2 left of diagonal (sorted by col) - double m22 = A_data[d2idx]; // group 2 diagonal + double m11 = A_data[d1idx]; // group 1 diagonal + double m12 = + A_data[d1idx + 1]; // group 1 right of diagonal (sorted by col) + double m21 = + A_data[d2idx - 1]; // group 2 left of diagonal (sorted by col) + double m22 = A_data[d2idx]; // group 2 diagonal // Analytically invert the diagonal - double dm = m11*m22 - m12*m21; - double d11 = m22/dm; - double d12 = -m12/dm; - double d21 = -m21/dm; - double d22 = m11/dm; + double dm = m11 * m22 - m12 * m21; + double d11 = m22 / dm; + double d12 = -m12 / dm; + double d21 = -m21 / dm; + double d22 = m11 / dm; // Perform temporary sums, first do left of diag, then right of diag double tmp1 = 0.0; double tmp2 = 0.0; for (int icol = cmfd::indptr[irow]; icol < d1idx; icol++) tmp1 += A_data[icol] * x[cmfd::indices[icol]]; - for (int icol = cmfd::indptr[irow+1]; icol < d2idx-1; icol++) + for (int icol = cmfd::indptr[irow + 1]; icol < d2idx - 1; icol++) tmp2 += A_data[icol] * x[cmfd::indices[icol]]; for (int icol = d1idx + 2; icol < cmfd::indptr[irow + 1]; icol++) tmp1 += A_data[icol] * x[cmfd::indices[icol]]; @@ -414,8 +419,8 @@ int cmfd_linsolver_2g(const double* A_data, const double* b, double* x, tmp2 = b[irow + 1] - tmp2; // Solve for new x - double x1 = d11*tmp1 + d12*tmp2; - double x2 = d21*tmp1 + d22*tmp2; + double x1 = d11 * tmp1 + d12 * tmp2; + double x2 = d21 * tmp1 + d22 * tmp2; // Perform overrelaxation x[irow] = (1.0 - w) * x[irow] + w * x1; @@ -433,7 +438,7 @@ int cmfd_linsolver_2g(const double* A_data, const double* b, double* x, return igs; // Calculate new overrelaxation parameter - w = 1.0/(1.0 - 0.25 * cmfd::spectral * w); + w = 1.0 / (1.0 - 0.25 * cmfd::spectral * w); } // Throw error, as max iterations met @@ -447,8 +452,8 @@ int cmfd_linsolver_2g(const double* A_data, const double* b, double* x, // CMFD_LINSOLVER_NG solves a general CMFD linear system //============================================================================== -int cmfd_linsolver_ng(const double* A_data, const double* b, double* x, - double tol) +int cmfd_linsolver_ng( + const double* A_data, const double* b, double* x, double tol) { // Set overrelaxation parameter double w = 1.0; @@ -489,7 +494,7 @@ int cmfd_linsolver_ng(const double* A_data, const double* b, double* x, return igs; // Calculate new overrelaxation parameter - w = 1.0/(1.0 - 0.25 * cmfd::spectral * w); + w = 1.0 / (1.0 - 0.25 * cmfd::spectral * w); } // Throw error, as max iterations met @@ -504,11 +509,9 @@ int cmfd_linsolver_ng(const double* A_data, const double* b, double* x, // linear solver //============================================================================== -extern "C" -void openmc_initialize_linsolver(const int* indptr, int len_indptr, - const int* indices, int n_elements, int dim, - double spectral, const int* map, - bool use_all_threads) +extern "C" void openmc_initialize_linsolver(const int* indptr, int len_indptr, + const int* indices, int n_elements, int dim, double spectral, const int* map, + bool use_all_threads) { // Store elements of indptr for (int i = 0; i < len_indptr; i++) @@ -538,9 +541,8 @@ void openmc_initialize_linsolver(const int* indptr, int len_indptr, // equations //============================================================================== -extern "C" -int openmc_run_linsolver(const double* A_data, const double* b, double* x, - double tol) +extern "C" int openmc_run_linsolver( + const double* A_data, const double* b, double* x, double tol) { switch (cmfd::ng) { case 1: diff --git a/src/cross_sections.cpp b/src/cross_sections.cpp index ea8d0cfbbad..a7bd86095b3 100644 --- a/src/cross_sections.cpp +++ b/src/cross_sections.cpp @@ -3,12 +3,9 @@ #include "openmc/capi.h" #include "openmc/constants.h" #include "openmc/container_util.h" -#ifdef DAGMC -#include "openmc/dagmc.h" -#endif #include "openmc/error.h" -#include "openmc/geometry_aux.h" #include "openmc/file_utils.h" +#include "openmc/geometry_aux.h" #include "openmc/hdf5_interface.h" #include "openmc/material.h" #include "openmc/message_passing.h" @@ -18,10 +15,10 @@ #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/string_utils.h" -#include "openmc/timer.h" #include "openmc/thermal.h" -#include "openmc/xml_interface.h" +#include "openmc/timer.h" #include "openmc/wmp.h" +#include "openmc/xml_interface.h" #include "pugixml.hpp" @@ -38,7 +35,7 @@ namespace data { std::map library_map; vector libraries; -} +} // namespace data //============================================================================== // Library methods @@ -79,8 +76,10 @@ Library::Library(pugi::xml_node node, const std::string& directory) path_ = path; } else if (ends_with(directory, "/")) { path_ = directory + path; - } else { + } else if (!directory.empty()) { path_ = directory + "/" + path; + } else { + path_ = path; } if (!file_exists(path_)) { @@ -96,30 +95,20 @@ void read_cross_sections_xml() { pugi::xml_document doc; std::string filename = settings::path_input + "materials.xml"; -#ifdef DAGMC - std::string s; - bool found_uwuw_mats = false; - if (settings::dagmc) { - found_uwuw_mats = get_uwuw_materials_xml(s); - } - - if (found_uwuw_mats) { - // if we found uwuw materials, load those - doc.load_file(s.c_str()); - } else { -#endif // Check if materials.xml exists if (!file_exists(filename)) { fatal_error("Material XML file '" + filename + "' does not exist."); } // Parse materials.xml file doc.load_file(filename.c_str()); -#ifdef DAGMC - } -#endif auto root = doc.document_element(); + read_cross_sections_xml(root); +} + +void read_cross_sections_xml(pugi::xml_node root) +{ // Find cross_sections.xml file -- the first place to look is the // materials.xml file. If no file is found there, then we check the // OPENMC_CROSS_SECTIONS environment variable @@ -129,7 +118,8 @@ void read_cross_sections_xml() if (settings::run_CE) { char* envvar = std::getenv("OPENMC_CROSS_SECTIONS"); if (!envvar) { - fatal_error("No cross_sections.xml file was specified in " + fatal_error( + "No cross_sections.xml file was specified in " "materials.xml or in the OPENMC_CROSS_SECTIONS" " environment variable. OpenMC needs such a file to identify " "where to find data libraries. Please consult the" @@ -140,17 +130,25 @@ void read_cross_sections_xml() } else { char* envvar = std::getenv("OPENMC_MG_CROSS_SECTIONS"); if (!envvar) { - fatal_error("No mgxs.h5 file was specified in " - "materials.xml or in the OPENMC_MG_CROSS_SECTIONS environment " - "variable. OpenMC needs such a file to identify where to " - "find MG cross section libraries. Please consult the user's " - "guide at https://docs.openmc.org for information on " - "how to set up MG cross section libraries."); + fatal_error( + "No mgxs.h5 file was specified in " + "materials.xml or in the OPENMC_MG_CROSS_SECTIONS environment " + "variable. OpenMC needs such a file to identify where to " + "find MG cross section libraries. Please consult the user's " + "guide at https://docs.openmc.org for information on " + "how to set up MG cross section libraries."); } settings::path_cross_sections = envvar; } } else { settings::path_cross_sections = get_node_value(root, "cross_sections"); + + // If no '/' found, the file is probably in the input directory + auto pos = settings::path_cross_sections.rfind("/"); + if (pos == std::string::npos && !settings::path_input.empty()) { + settings::path_cross_sections = + settings::path_input + "/" + settings::path_cross_sections; + } } // Now that the cross_sections.xml or mgxs.h5 has been located, read it in @@ -175,8 +173,8 @@ void read_cross_sections_xml() for (const auto& name : settings::res_scat_nuclides) { LibraryKey key {Library::Type::neutron, name}; if (data::library_map.find(key) == data::library_map.end()) { - fatal_error("Could not find resonant scatterer " + - name + " in cross_sections.xml file!"); + fatal_error("Could not find resonant scatterer " + name + + " in cross_sections.xml file!"); } } } @@ -206,11 +204,13 @@ void read_ce_cross_sections(const vector>& nuc_temps, std::string& name = nuclide_names[i_nuc]; // If we've already read this nuclide, skip it - if (already_read.find(name) != already_read.end()) continue; + if (already_read.find(name) != already_read.end()) + continue; const auto& temps = nuc_temps[i_nuc]; int err = openmc_load_nuclide(name.c_str(), temps.data(), temps.size()); - if (err < 0) throw std::runtime_error{openmc_err_msg}; + if (err < 0) + throw std::runtime_error {openmc_err_msg}; already_read.insert(name); } @@ -250,14 +250,17 @@ void read_ce_cross_sections(const vector>& nuc_temps, mat->finalize(); } // materials - if (settings::photon_transport && settings::electron_treatment == ElectronTreatment::TTB) { + if (settings::photon_transport && + settings::electron_treatment == ElectronTreatment::TTB) { // Take logarithm of energies since they are log-log interpolated data::ttb_e_grid = xt::log(data::ttb_e_grid); } // Show minimum/maximum temperature - write_message(4, "Minimum neutron data temperature: {} K", data::temperature_min); - write_message(4, "Maximum neutron data temperature: {} K", data::temperature_max); + write_message( + 4, "Minimum neutron data temperature: {} K", data::temperature_min); + write_message( + 4, "Maximum neutron data temperature: {} K", data::temperature_max); // If the user wants multipole, make sure we found a multipole library. if (settings::temperature_multipole) { @@ -270,8 +273,8 @@ void read_ce_cross_sections(const vector>& nuc_temps, } if (mpi::master && !mp_found) { warning("Windowed multipole functionality is turned on, but no multipole " - "libraries were found. Make sure that windowed multipole data is " - "present in your cross_sections.xml file."); + "libraries were found. Make sure that windowed multipole data is " + "present in your cross_sections.xml file."); } } } @@ -282,8 +285,7 @@ void read_ce_cross_sections_xml() const auto& filename = settings::path_cross_sections; if (!file_exists(filename)) { // Could not find cross_sections.xml file - fatal_error("Cross sections XML file '" + filename + - "' does not exist."); + fatal_error("Cross sections XML file '" + filename + "' does not exist."); } write_message("Reading cross sections XML file...", 5); @@ -307,10 +309,12 @@ void read_ce_cross_sections_xml() // TODO: Use std::filesystem functionality when C++17 is adopted auto pos = filename.rfind("/"); if (pos == std::string::npos) { - // no '/' found, probably a Windows directory - pos = filename.rfind("\\"); + // No '\\' found, so the file must be in the same directory as + // materials.xml + directory = settings::path_input; + } else { + directory = filename.substr(0, pos); } - directory = filename.substr(0, pos); } for (const auto& node_library : root.children("library")) { @@ -319,11 +323,13 @@ void read_ce_cross_sections_xml() // Make sure file was not empty if (data::libraries.empty()) { - fatal_error("No cross section libraries present in cross_sections.xml file."); + fatal_error( + "No cross section libraries present in cross_sections.xml file."); } } -void finalize_cross_sections(){ +void finalize_cross_sections() +{ if (settings::run_mode != RunMode::PLOTTING) { simulation::time_read_xs.start(); if (settings::run_CE) { @@ -344,7 +350,8 @@ void finalize_cross_sections(){ } } -void library_clear() { +void library_clear() +{ data::libraries.clear(); data::library_map.clear(); } diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 0c2768834a5..2f2502f6ea1 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -1,27 +1,25 @@ #include "openmc/dagmc.h" -#include "openmc/cell.h" #include "openmc/constants.h" #include "openmc/container_util.h" #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/geometry.h" #include "openmc/geometry_aux.h" +#include "openmc/hdf5_interface.h" #include "openmc/material.h" -#include "openmc/string_utils.h" #include "openmc/settings.h" -#include "openmc/surface.h" +#include "openmc/string_utils.h" -#ifdef DAGMC +#ifdef UWUW #include "uwuw.hpp" -#include "dagmcmetadata.hpp" #endif #include -#include -#include #include #include +#include +#include namespace openmc { @@ -31,198 +29,173 @@ const bool DAGMC_ENABLED = true; const bool DAGMC_ENABLED = false; #endif -} +#ifdef UWUW +const bool UWUW_ENABLED = true; +#else +const bool UWUW_ENABLED = false; +#endif + +} // namespace openmc #ifdef DAGMC namespace openmc { -const std::string DAGMC_FILENAME = "dagmc.h5m"; - -namespace model { - -moab::DagMC* DAG; - -} // namespace model +//============================================================================== +// DAGMC Universe implementation +//============================================================================== +DAGUniverse::DAGUniverse(pugi::xml_node node) +{ + if (check_for_node(node, "id")) { + id_ = std::stoi(get_node_value(node, "id")); + } else { + fatal_error("Must specify the id of the DAGMC universe"); + } -std::string dagmc_file() { - std::string filename = settings::path_input + DAGMC_FILENAME; - if (!file_exists(filename)) { - fatal_error("Geometry DAGMC file '" + filename + "' does not exist!"); + if (check_for_node(node, "filename")) { + filename_ = get_node_value(node, "filename"); + if (!starts_with(filename_, "/")) { + filename_ = dir_name(settings::path_input) + filename_; + } + } else { + fatal_error("Must specify a file for the DAGMC universe"); } - return filename; -} -bool get_uwuw_materials_xml(std::string& s) { - std::string filename = dagmc_file(); - UWUW uwuw(filename.c_str()); + adjust_geometry_ids_ = false; + if (check_for_node(node, "auto_geom_ids")) { + adjust_geometry_ids_ = get_node_value_bool(node, "auto_geom_ids"); + } - std::stringstream ss; - bool uwuw_mats_present = false; - if (uwuw.material_library.size() != 0) { - uwuw_mats_present = true; - // write header - ss << "\n"; - ss << "\n"; - const auto& mat_lib = uwuw.material_library; - // write materials - for (auto mat : mat_lib) { ss << mat.second->openmc("atom"); } - // write footer - ss << ""; - s = ss.str(); + adjust_material_ids_ = false; + if (check_for_node(node, "auto_mat_ids")) { + adjust_material_ids_ = get_node_value_bool(node, "auto_mat_ids"); } - return uwuw_mats_present; + initialize(); } -bool read_uwuw_materials(pugi::xml_document& doc) { - std::string s; - bool found_uwuw_mats = get_uwuw_materials_xml(s); - if (found_uwuw_mats) { - pugi::xml_parse_result result = doc.load_string(s.c_str()); - if (!result) { - throw std::runtime_error{"Error reading UWUW materials"}; - } - } - return found_uwuw_mats; -} - -bool write_uwuw_materials_xml() { - std::string s; - bool found_uwuw_mats = get_uwuw_materials_xml(s); - // if there is a material library in the file - if (found_uwuw_mats) { - // write a material.xml file - std::ofstream mats_xml("materials.xml"); - mats_xml << s; - mats_xml.close(); - } - - return found_uwuw_mats; +DAGUniverse::DAGUniverse( + const std::string& filename, bool auto_geom_ids, bool auto_mat_ids) + : filename_(filename), adjust_geometry_ids_(auto_geom_ids), + adjust_material_ids_(auto_mat_ids) +{ + set_id(); + initialize(); } -void legacy_assign_material(std::string mat_string, DAGCell* c) +DAGUniverse::DAGUniverse(std::shared_ptr dagmc_ptr, + const std::string& filename, bool auto_geom_ids, bool auto_mat_ids) + : dagmc_instance_(dagmc_ptr), filename_(filename), + adjust_geometry_ids_(auto_geom_ids), adjust_material_ids_(auto_mat_ids) { - bool mat_found_by_name = false; - // attempt to find a material with a matching name - to_lower(mat_string); - for (const auto& m : model::materials) { - std::string m_name = m->name(); - to_lower(m_name); - if (mat_string == m_name) { - // assign the material with that name - if (!mat_found_by_name) { - mat_found_by_name = true; - c->material_.push_back(m->id_); - // report error if more than one material is found - } else { - fatal_error(fmt::format( - "More than one material found with name {}. Please ensure materials " - "have unique names if using this property to assign materials.", - mat_string)); - } - } - } + set_id(); + init_metadata(); + init_geometry(); +} - // if no material was set using a name, assign by id - if (!mat_found_by_name) { - try { - auto id = std::stoi(mat_string); - c->material_.emplace_back(id); - } catch (const std::invalid_argument&) { - fatal_error(fmt::format( - "No material {} found for volume (cell) {}", mat_string, c->id_)); - } +void DAGUniverse::set_id() +{ + // determine the next universe id + int32_t next_univ_id = 0; + for (const auto& u : model::universes) { + if (u->id_ > next_univ_id) + next_univ_id = u->id_; } + next_univ_id++; - if (settings::verbosity >= 10) { - const auto& m = model::materials[model::material_map.at(c->material_[0])]; - std::stringstream msg; - msg << "DAGMC material " << mat_string << " was assigned"; - if (mat_found_by_name) { - msg << " using material name: " << m->name_; - } else { - msg << " using material id: " << m->id_; - } - write_message(msg.str(), 10); - } + // set the universe id + id_ = next_univ_id; } -void load_dagmc_geometry() +void DAGUniverse::initialize() { - if (!model::DAG) { - model::DAG = new moab::DagMC(); - } + geom_type() = GeometryType::DAG; - // --- Materials --- + init_dagmc(); - // create uwuw instance - auto filename = dagmc_file(); - UWUW uwuw(filename.c_str()); + init_metadata(); - // check for uwuw material definitions - bool using_uwuw = !uwuw.material_library.empty(); + init_geometry(); +} - // notify user if UWUW materials are going to be used - if (using_uwuw) { - write_message("Found UWUW Materials in the DAGMC geometry file.", 6); - } +void DAGUniverse::init_dagmc() +{ - int32_t dagmc_univ_id = 0; // universe is always 0 for DAGMC runs + // create a new DAGMC instance + dagmc_instance_ = std::make_shared(); // load the DAGMC geometry - moab::ErrorCode rval = model::DAG->load_file(filename.c_str()); + if (!file_exists(filename_)) { + fatal_error("Geometry DAGMC file '" + filename_ + "' does not exist!"); + } + moab::ErrorCode rval = dagmc_instance_->load_file(filename_.c_str()); MB_CHK_ERR_CONT(rval); // initialize acceleration data structures - rval = model::DAG->init_OBBTree(); + rval = dagmc_instance_->init_OBBTree(); MB_CHK_ERR_CONT(rval); +} +void DAGUniverse::init_metadata() +{ // parse model metadata - dagmcMetaData DMD(model::DAG, false, false); - DMD.load_property_data(); + dmd_ptr = + std::make_unique(dagmc_instance_.get(), false, false); + dmd_ptr->load_property_data(); - vector keywords {"temp"}; + std::vector keywords {"temp"}; std::map dum; std::string delimiters = ":/"; - rval = model::DAG->parse_properties(keywords, dum, delimiters.c_str()); + moab::ErrorCode rval; + rval = dagmc_instance_->parse_properties(keywords, dum, delimiters.c_str()); MB_CHK_ERR_CONT(rval); +} - // --- Cells (Volumes) --- +void DAGUniverse::init_geometry() +{ + moab::ErrorCode rval; + + // determine the next cell id + int32_t next_cell_id = 0; + for (const auto& c : model::cells) { + if (c->id_ > next_cell_id) + next_cell_id = c->id_; + } + cell_idx_offset_ = model::cells.size(); + next_cell_id++; // initialize cell objects - int n_cells = model::DAG->num_entities(3); + int n_cells = dagmc_instance_->num_entities(3); moab::EntityHandle graveyard = 0; for (int i = 0; i < n_cells; i++) { - moab::EntityHandle vol_handle = model::DAG->entity_by_index(3, i+1); + moab::EntityHandle vol_handle = dagmc_instance_->entity_by_index(3, i + 1); // set cell ids using global IDs - DAGCell* c = new DAGCell(); - c->dag_index_ = i+1; - c->id_ = model::DAG->id_by_index(3, c->dag_index_); - c->dagmc_ptr_ = model::DAG; - c->universe_ = dagmc_univ_id; // set to zero for now + auto c = std::make_unique(dagmc_instance_, i + 1); + c->id_ = adjust_geometry_ids_ + ? next_cell_id++ + : dagmc_instance_->id_by_index(3, c->dag_index()); + c->universe_ = this->id_; c->fill_ = C_NONE; // no fill, single universe - model::cells.emplace_back(c); - model::cell_map[c->id_] = i; - - // Populate the Universe vector and dict - auto it = model::universe_map.find(dagmc_univ_id); - if (it == model::universe_map.end()) { - model::universes.push_back(make_unique()); - model::universes.back()->id_ = dagmc_univ_id; - model::universes.back()->cells_.push_back(i); - model::universe_map[dagmc_univ_id] = model::universes.size() - 1; + auto in_map = model::cell_map.find(c->id_); + if (in_map == model::cell_map.end()) { + model::cell_map[c->id_] = model::cells.size(); } else { - model::universes[it->second]->cells_.push_back(i); + warning(fmt::format("DAGMC Cell IDs: {}", dagmc_ids_for_dim(3))); + fatal_error(fmt::format( + "DAGMC Universe {} contains a cell with ID {}, which " + "already exists elsewhere in the geometry. Setting auto_geom_ids " + "to True when initiating the DAGMC Universe may " + "resolve this issue", + this->id_, c->id_)); } - // MATERIALS + // --- Materials --- // determine volume material assignment - std::string mat_str = DMD.get_volume_property("material", vol_handle); + std::string mat_str = dmd_ptr->get_volume_property("material", vol_handle); if (mat_str.empty()) { fatal_error(fmt::format("Volume {} has no material assignment.", c->id_)); @@ -238,17 +211,8 @@ void load_dagmc_geometry() if (mat_str == "void" || mat_str == "vacuum" || mat_str == "graveyard") { c->material_.push_back(MATERIAL_VOID); } else { - if (using_uwuw) { - // lookup material in uwuw if present - std::string uwuw_mat = DMD.volume_material_property_data_eh[vol_handle]; - if (uwuw.material_library.count(uwuw_mat) != 0) { - // Note: material numbers are set by UWUW - int mat_number = uwuw.material_library.get_material(uwuw_mat).metadata["mat_number"].asInt(); - c->material_.push_back(mat_number); - } else { - fatal_error(fmt::format("Material with value {} not found in the " - "UWUW material library", mat_str)); - } + if (uses_uwuw()) { + uwuw_assign_material(vol_handle, c); } else { legacy_assign_material(mat_str, c); } @@ -258,19 +222,26 @@ void load_dagmc_geometry() std::string temp_value; // no temperature if void - if (c->material_[0] == MATERIAL_VOID) continue; + if (c->material_[0] == MATERIAL_VOID) { + model::cells.emplace_back(std::move(c)); + continue; + } // assign cell temperature const auto& mat = model::materials[model::material_map.at(c->material_[0])]; - if (model::DAG->has_prop(vol_handle, "temp")) { - rval = model::DAG->prop_value(vol_handle, "temp", temp_value); + if (dagmc_instance_->has_prop(vol_handle, "temp")) { + rval = dagmc_instance_->prop_value(vol_handle, "temp", temp_value); MB_CHK_ERR_CONT(rval); double temp = std::stod(temp_value); c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * temp)); - } else { + } else if (mat->temperature() > 0.0) { c->sqrtkT_.push_back(std::sqrt(K_BOLTZMANN * mat->temperature())); + } else { + c->sqrtkT_.push_back( + std::sqrt(K_BOLTZMANN * settings::temperature_default)); } + model::cells.emplace_back(std::move(c)); } // allocate the cell overlap count if necessary @@ -278,79 +249,589 @@ void load_dagmc_geometry() model::overlap_check_count.resize(model::cells.size(), 0); } - if (!graveyard) { - warning("No graveyard volume found in the DagMC model." - "This may result in lost particles and rapid simulation failure."); - } + has_graveyard_ = graveyard; - // --- Surfaces --- + // determine the next surface id + int32_t next_surf_id = 0; + for (const auto& s : model::surfaces) { + if (s->id_ > next_surf_id) + next_surf_id = s->id_; + } + surf_idx_offset_ = model::surfaces.size(); + next_surf_id++; // initialize surface objects - int n_surfaces = model::DAG->num_entities(2); - + int n_surfaces = dagmc_instance_->num_entities(2); for (int i = 0; i < n_surfaces; i++) { - moab::EntityHandle surf_handle = model::DAG->entity_by_index(2, i+1); + moab::EntityHandle surf_handle = dagmc_instance_->entity_by_index(2, i + 1); // set cell ids using global IDs - DAGSurface* s = new DAGSurface(); - s->dag_index_ = i+1; - s->id_ = model::DAG->id_by_index(2, s->dag_index_); - s->dagmc_ptr_ = model::DAG; + auto s = std::make_unique(dagmc_instance_, i + 1); + s->id_ = adjust_geometry_ids_ ? next_surf_id++ + : dagmc_instance_->id_by_index(2, i + 1); - if (contains(settings::source_write_surf_id, s->id_)) { + // set surface source attribute if needed + if (contains(settings::source_write_surf_id, s->id_)) s->surf_source_ = true; - } // set BCs - std::string bc_value = DMD.get_surface_property("boundary", surf_handle); + std::string bc_value = + dmd_ptr->get_surface_property("boundary", surf_handle); to_lower(bc_value); - if (bc_value.empty() || bc_value == "transmit" || bc_value == "transmission") { - // Leave the bc_ a nullptr + if (bc_value.empty() || bc_value == "transmit" || + bc_value == "transmission") { + // set to transmission by default (nullptr) } else if (bc_value == "vacuum") { - s->bc_ = std::make_shared(); - } else if (bc_value == "reflective" || bc_value == "reflect" || bc_value == "reflecting") { - s->bc_ = std::make_shared(); - } else if (bc_value == "white") { - fatal_error("White boundary condition not supported in DAGMC."); + s->bc_ = make_unique(); + } else if (bc_value == "reflective" || bc_value == "reflect" || + bc_value == "reflecting") { + s->bc_ = make_unique(); } else if (bc_value == "periodic") { fatal_error("Periodic boundary condition not supported in DAGMC."); } else { fatal_error(fmt::format("Unknown boundary condition \"{}\" specified " - "on surface {}", bc_value, s->id_)); + "on surface {}", + bc_value, s->id_)); } // graveyard check moab::Range parent_vols; - rval = model::DAG->moab_instance()->get_parent_meshsets(surf_handle, parent_vols); + rval = dagmc_instance_->moab_instance()->get_parent_meshsets( + surf_handle, parent_vols); MB_CHK_ERR_CONT(rval); // if this surface belongs to the graveyard if (graveyard && parent_vols.find(graveyard) != parent_vols.end()) { // set graveyard surface BC's to vacuum - s->bc_ = std::make_shared(); + s->bc_ = make_unique(); } // add to global array and map - model::surfaces.emplace_back(s); - model::surface_map[s->id_] = i; + + auto in_map = model::surface_map.find(s->id_); + if (in_map == model::surface_map.end()) { + model::surface_map[s->id_] = model::surfaces.size(); + } else { + warning(fmt::format("DAGMC Surface IDs: {}", dagmc_ids_for_dim(2))); + fatal_error(fmt::format("Surface ID {} exists in both Universe {} " + "and the CSG geometry.", + s->id_, this->id_)); + } + + model::surfaces.emplace_back(std::move(s)); + } // end surface loop +} + +int32_t DAGUniverse::cell_index(moab::EntityHandle vol) const +{ + // return the index of the volume in the DAGMC instance and then + // adjust by the offset into the model cells for this DAGMC universe + return dagmc_ptr()->index_by_handle(vol) + cell_idx_offset_; +} + +int32_t DAGUniverse::surface_index(moab::EntityHandle surf) const +{ + // return the index of the surface in the DAGMC instance and then + // adjust by the offset into the model cells for this DAGMC universe + return dagmc_ptr()->index_by_handle(surf) + surf_idx_offset_; +} + +std::string DAGUniverse::dagmc_ids_for_dim(int dim) const +{ + // generate a vector of ids + std::vector id_vec; + int n_ents = dagmc_instance_->num_entities(dim); + for (int i = 1; i <= n_ents; i++) { + id_vec.push_back(dagmc_instance_->id_by_index(dim, i)); + } + + // sort the vector of ids + std::sort(id_vec.begin(), id_vec.end()); + + // generate a string representation of the ID range(s) + std::stringstream out; + + int i = 0; + int start_id = id_vec[0]; // initialize with first ID + int stop_id; + // loop over all cells in the universe + while (i < n_ents) { + + stop_id = id_vec[i]; + + // if the next ID is not in this contiguous set of IDS, + // figure out how to write the string representing this set + if (id_vec[i + 1] > stop_id + 1) { + + if (start_id != stop_id) { + // there are several IDs in a row, print condensed version (i.e. 1-10, + // 12-20) + out << start_id << "-" << stop_id; + } else { + // only one ID in this contiguous block (i.e. 3, 5, 7, 9) + out << start_id; + } + // insert a comma as long as we aren't in the last ID set + if (i < n_ents - 1) { + out << ", "; + } + + // if we are at the end of a set, set the start ID to the first value + // in the next set. + start_id = id_vec[++i]; + } + + i++; + } + + return out.str(); +} + +int32_t DAGUniverse::implicit_complement_idx() const +{ + moab::EntityHandle ic; + moab::ErrorCode rval = + dagmc_instance_->geom_tool()->get_implicit_complement(ic); + MB_CHK_SET_ERR_CONT(rval, "Failed to get implicit complement"); + // off-by-one: DAGMC indices start at one + return cell_idx_offset_ + dagmc_instance_->index_by_handle(ic) - 1; +} + +bool DAGUniverse::find_cell(GeometryState& p) const +{ + // if the particle isn't in any of the other DagMC + // cells, place it in the implicit complement + bool found = Universe::find_cell(p); + if (!found && model::universe_map[this->id_] != model::root_universe) { + p.lowest_coord().cell = implicit_complement_idx(); + found = true; + } + return found; +} + +void DAGUniverse::to_hdf5(hid_t universes_group) const +{ + // Create a group for this universe. + auto group = create_group(universes_group, fmt::format("universe {}", id_)); + + // Write the geometry representation type. + write_string(group, "geom_type", "dagmc", false); + + // Write other properties of the DAGMC Universe + write_string(group, "filename", filename_, false); + write_attribute( + group, "auto_geom_ids", static_cast(adjust_geometry_ids_)); + write_attribute( + group, "auto_mat_ids", static_cast(adjust_material_ids_)); + + close_group(group); +} + +bool DAGUniverse::uses_uwuw() const +{ +#ifdef UWUW + return uwuw_ && !uwuw_->material_library.empty(); +#else + return false; +#endif // UWUW +} + +std::string DAGUniverse::get_uwuw_materials_xml() const +{ +#ifdef UWUW + if (!uses_uwuw()) { + throw std::runtime_error("This DAGMC Universe does not use UWUW materials"); } - return; + std::stringstream ss; + // write header + ss << "\n"; + ss << "\n"; + const auto& mat_lib = uwuw_->material_library; + // write materials + for (auto mat : mat_lib) { + ss << mat.second->openmc("atom"); + } + // write footer + ss << ""; + + return ss.str(); +#else + fatal_error("DAGMC was not configured with UWUW."); +#endif // UWUW } -void read_geometry_dagmc() +void DAGUniverse::write_uwuw_materials_xml(const std::string& outfile) const { - write_message("Reading DAGMC geometry...", 5); - load_dagmc_geometry(); +#ifdef UWUW + if (!uses_uwuw()) { + throw std::runtime_error( + "This DAGMC universe does not use UWUW materials."); + } - model::root_universe = find_root_universe(); + std::string xml_str = get_uwuw_materials_xml(); + // if there is a material library in the file + std::ofstream mats_xml(outfile); + mats_xml << xml_str; + mats_xml.close(); +#else + fatal_error("DAGMC was not configured with UWUW."); +#endif } -void free_memory_dagmc() +void DAGUniverse::legacy_assign_material( + std::string mat_string, std::unique_ptr& c) const { - delete model::DAG; + bool mat_found_by_name = false; + // attempt to find a material with a matching name + to_lower(mat_string); + for (const auto& m : model::materials) { + std::string m_name = m->name(); + to_lower(m_name); + if (mat_string == m_name) { + // assign the material with that name + if (!mat_found_by_name) { + mat_found_by_name = true; + c->material_.push_back(m->id_); + // report error if more than one material is found + } else { + fatal_error(fmt::format( + "More than one material found with name '{}'. Please ensure " + "materials " + "have unique names if using this property to assign materials.", + mat_string)); + } + } + } + + // if no material was set using a name, assign by id + if (!mat_found_by_name) { + bool found_by_id = true; + try { + auto id = std::stoi(mat_string); + if (model::material_map.find(id) == model::material_map.end()) + found_by_id = false; + c->material_.emplace_back(id); + } catch (const std::invalid_argument&) { + found_by_id = false; + } + + // report failure for failed int conversion or missing material + if (!found_by_id) + fatal_error( + fmt::format("Material with name/ID '{}' not found for volume (cell) {}", + mat_string, c->id_)); + } + + if (settings::verbosity >= 10) { + const auto& m = model::materials[model::material_map.at(c->material_[0])]; + std::stringstream msg; + msg << "DAGMC material " << mat_string << " was assigned"; + if (mat_found_by_name) { + msg << " using material name: " << m->name_; + } else { + msg << " using material id: " << m->id_; + } + write_message(msg.str(), 10); + } } +void DAGUniverse::read_uwuw_materials() +{ +#ifdef UWUW + // If no filename was provided, don't read UWUW materials + if (filename_ == "") + return; + + uwuw_ = std::make_shared(filename_.c_str()); + + if (!uses_uwuw()) + return; + + // Notify user if UWUW materials are going to be used + write_message("Found UWUW Materials in the DAGMC geometry file.", 6); + + // if we're using automatic IDs, update the UWUW material metadata + if (adjust_material_ids_) { + int32_t next_material_id = 0; + for (const auto& m : model::materials) { + next_material_id = std::max(m->id_, next_material_id); + } + next_material_id++; + + for (auto& mat : uwuw_->material_library) { + mat.second->metadata["mat_number"] = next_material_id++; + } + } + + std::string mat_xml_string = get_uwuw_materials_xml(); + // create a pugi XML document from this string + pugi::xml_document doc; + auto result = doc.load_string(mat_xml_string.c_str()); + if (!result) { + fatal_error("Error processing XML created using DAGMC UWUW materials."); + } + pugi::xml_node root = doc.document_element(); + for (pugi::xml_node material_node : root.children("material")) { + model::materials.push_back(std::make_unique(material_node)); + } +#else + fatal_error("DAGMC was not configured with UWUW."); +#endif } + +void DAGUniverse::uwuw_assign_material( + moab::EntityHandle vol_handle, std::unique_ptr& c) const +{ +#ifdef UWUW + // read materials from uwuw material file + read_uwuw_materials(); + + // lookup material in uwuw if present + std::string uwuw_mat = dmd_ptr->volume_material_property_data_eh[vol_handle]; + if (uwuw_->material_library.count(uwuw_mat) != 0) { + // Note: material numbers are set by UWUW + int mat_number = uwuw_->material_library.get_material(uwuw_mat) + .metadata["mat_number"] + .asInt(); + c->material_.push_back(mat_number); + } else { + fatal_error(fmt::format("Material with value '{}' not found in the " + "UWUW material library", + mat_str)); + } +#else + fatal_error("DAGMC was not configured with UWUW."); #endif +} +//============================================================================== +// DAGMC Cell implementation +//============================================================================== + +DAGCell::DAGCell(std::shared_ptr dag_ptr, int32_t dag_idx) + : Cell {}, dagmc_ptr_(dag_ptr), dag_index_(dag_idx) +{ + geom_type_ = GeometryType::DAG; +}; + +std::pair DAGCell::distance( + Position r, Direction u, int32_t on_surface, GeometryState* p) const +{ + // if we've changed direction or we're not on a surface, + // reset the history and update last direction + if (u != p->last_dir()) { + p->last_dir() = u; + p->history().reset(); + } + if (on_surface == 0) { + p->history().reset(); + } + + const auto& univ = model::universes[p->lowest_coord().universe]; + + DAGUniverse* dag_univ = static_cast(univ.get()); + if (!dag_univ) + fatal_error("DAGMC call made for particle in a non-DAGMC universe"); + + // initialize to lost particle conditions + int surf_idx = -1; + double dist = INFINITY; + + moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_); + moab::EntityHandle hit_surf; + + // create the ray + double pnt[3] = {r.x, r.y, r.z}; + double dir[3] = {u.x, u.y, u.z}; + MB_CHK_ERR_CONT( + dagmc_ptr_->ray_fire(vol, pnt, dir, hit_surf, dist, &p->history())); + if (hit_surf != 0) { + surf_idx = + dag_univ->surf_idx_offset_ + dagmc_ptr_->index_by_handle(hit_surf); + } else if (!dagmc_ptr_->is_implicit_complement(vol) || + is_root_universe(dag_univ->id_)) { + // surface boundary conditions are ignored for projection plotting, meaning + // that the particle may move through the graveyard (bounding) volume and + // into the implicit complement on the other side where no intersection will + // be found. Treating this as a lost particle is problematic when plotting. + // Instead, the infinite distance and invalid surface index are returned. + if (settings::run_mode == RunMode::PLOTTING) + return {INFTY, -1}; + + // the particle should be marked as lost immediately if an intersection + // isn't found in a volume that is not the implicit complement. In the case + // that the DAGMC model is the root universe of the geometry, even a missing + // intersection in the implicit complement should trigger this condition. + std::string material_id = + p->material() == MATERIAL_VOID + ? "-1 (VOID)" + : std::to_string(model::materials[p->material()]->id()); + p->mark_as_lost(fmt::format( + "No intersection found with DAGMC cell {}, filled with material {}", id_, + material_id)); + } + + return {dist, surf_idx}; +} + +bool DAGCell::contains(Position r, Direction u, int32_t on_surface) const +{ + moab::ErrorCode rval; + moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_); + + int result = 0; + double pnt[3] = {r.x, r.y, r.z}; + double dir[3] = {u.x, u.y, u.z}; + rval = dagmc_ptr_->point_in_volume(vol, pnt, result, dir); + MB_CHK_ERR_CONT(rval); + return result; +} + +moab::EntityHandle DAGCell::mesh_handle() const +{ + return dagmc_ptr()->entity_by_index(3, dag_index()); +} + +void DAGCell::to_hdf5_inner(hid_t group_id) const +{ + write_string(group_id, "geom_type", "dagmc", false); +} + +BoundingBox DAGCell::bounding_box() const +{ + moab::ErrorCode rval; + moab::EntityHandle vol = dagmc_ptr_->entity_by_index(3, dag_index_); + double min[3], max[3]; + rval = dagmc_ptr_->getobb(vol, min, max); + MB_CHK_ERR_CONT(rval); + return {min[0], max[0], min[1], max[1], min[2], max[2]}; +} + +//============================================================================== +// DAGSurface implementation +//============================================================================== + +DAGSurface::DAGSurface(std::shared_ptr dag_ptr, int32_t dag_idx) + : Surface {}, dagmc_ptr_(dag_ptr), dag_index_(dag_idx) +{ + geom_type_ = GeometryType::DAG; +} // empty constructor + +moab::EntityHandle DAGSurface::mesh_handle() const +{ + return dagmc_ptr()->entity_by_index(2, dag_index()); +} + +double DAGSurface::evaluate(Position r) const +{ + return 0.0; +} + +double DAGSurface::distance(Position r, Direction u, bool coincident) const +{ + moab::ErrorCode rval; + moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); + moab::EntityHandle hit_surf; + double dist; + double pnt[3] = {r.x, r.y, r.z}; + double dir[3] = {u.x, u.y, u.z}; + rval = dagmc_ptr_->ray_fire(surf, pnt, dir, hit_surf, dist, NULL, 0, 0); + MB_CHK_ERR_CONT(rval); + if (dist < 0.0) + dist = INFTY; + return dist; +} + +Direction DAGSurface::normal(Position r) const +{ + moab::ErrorCode rval; + moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); + double pnt[3] = {r.x, r.y, r.z}; + double dir[3]; + rval = dagmc_ptr_->get_angle(surf, pnt, dir); + MB_CHK_ERR_CONT(rval); + return dir; +} + +Direction DAGSurface::reflect(Position r, Direction u, GeometryState* p) const +{ + Expects(p); + p->history().reset_to_last_intersection(); + moab::ErrorCode rval; + moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); + double pnt[3] = {r.x, r.y, r.z}; + double dir[3]; + rval = dagmc_ptr_->get_angle(surf, pnt, dir, &p->history()); + MB_CHK_ERR_CONT(rval); + p->last_dir() = u.reflect(dir); + return p->last_dir(); +} + +//============================================================================== +// Non-member functions +//============================================================================== + +void read_dagmc_universes(pugi::xml_node node) +{ + for (pugi::xml_node dag_node : node.children("dagmc_universe")) { + model::universes.push_back(std::make_unique(dag_node)); + model::universe_map[model::universes.back()->id_] = + model::universes.size() - 1; + } +} + +void check_dagmc_root_univ() +{ + const auto& ru = model::universes[model::root_universe]; + if (ru->geom_type() == GeometryType::DAG) { + // if the root universe contains DAGMC geometry, warn the user + // if it does not contain a graveyard volume + auto dag_univ = dynamic_cast(ru.get()); + if (dag_univ && !dag_univ->has_graveyard()) { + warning( + "No graveyard volume found in the DagMC model. " + "This may result in lost particles and rapid simulation failure."); + } + } +} + +int32_t next_cell(int32_t surf, int32_t curr_cell, int32_t univ) +{ + auto surfp = dynamic_cast(model::surfaces[surf - 1].get()); + auto cellp = dynamic_cast(model::cells[curr_cell].get()); + auto univp = static_cast(model::universes[univ].get()); + + moab::EntityHandle surf_handle = surfp->mesh_handle(); + moab::EntityHandle curr_vol = cellp->mesh_handle(); + + moab::EntityHandle new_vol; + moab::ErrorCode rval = + cellp->dagmc_ptr()->next_vol(surf_handle, curr_vol, new_vol); + if (rval != moab::MB_SUCCESS) + return -1; + + return univp->cell_index(new_vol); +} + +} // namespace openmc + +#else + +namespace openmc { + +void read_dagmc_universes(pugi::xml_node node) +{ + if (check_for_node(node, "dagmc_universe")) { + fatal_error("DAGMC Universes are present but OpenMC was not configured " + "with DAGMC"); + } +}; + +void check_dagmc_root_univ() {}; + +int32_t next_cell(int32_t surf, int32_t curr_cell, int32_t univ); + +} // namespace openmc + +#endif // DAGMC diff --git a/src/distribution.cpp b/src/distribution.cpp index 68318c992bb..3026630b335 100644 --- a/src/distribution.cpp +++ b/src/distribution.cpp @@ -1,12 +1,15 @@ #include "openmc/distribution.h" #include // for copy +#include #include // for sqrt, floor, max #include // for back_inserter #include // for accumulate #include // for runtime_error #include // for string, stod +#include + #include "openmc/error.h" #include "openmc/math_functions.h" #include "openmc/random_dist.h" @@ -16,51 +19,124 @@ namespace openmc { //============================================================================== -// Discrete implementation +// DiscreteIndex implementation //============================================================================== -Discrete::Discrete(pugi::xml_node node) +DiscreteIndex::DiscreteIndex(pugi::xml_node node) { auto params = get_node_array(node, "parameters"); + std::size_t n = params.size() / 2; - std::size_t n = params.size(); - std::copy(params.begin(), params.begin() + n/2, std::back_inserter(x_)); - std::copy(params.begin() + n/2, params.end(), std::back_inserter(p_)); + assign({params.data() + n, n}); +} - normalize(); +DiscreteIndex::DiscreteIndex(gsl::span p) +{ + assign(p); } -Discrete::Discrete(const double* x, const double* p, int n) - : x_{x, x+n}, p_{p, p+n} +void DiscreteIndex::assign(gsl::span p) +{ + prob_.assign(p.begin(), p.end()); + + this->init_alias(); +} + +void DiscreteIndex::init_alias() { normalize(); + + // The initialization and sampling method is based on Vose + // (DOI: 10.1109/32.92917) + // Vectors for large and small probabilities based on 1/n + vector large; + vector small; + + size_t n = prob_.size(); + + // Set and allocate memory + alias_.assign(n, 0); + + // Fill large and small vectors based on 1/n + for (size_t i = 0; i < n; i++) { + prob_[i] *= n; + if (prob_[i] > 1.0) { + large.push_back(i); + } else { + small.push_back(i); + } + } + + while (!large.empty() && !small.empty()) { + int j = small.back(); + int k = large.back(); + + // Remove last element of small + small.pop_back(); + + // Update probability and alias based on Vose's algorithm + prob_[k] += prob_[j] - 1.0; + alias_[j] = k; + + // Move large index to small vector, if it is no longer large + if (prob_[k] < 1.0) { + small.push_back(k); + large.pop_back(); + } + } } -double Discrete::sample(uint64_t* seed) const +size_t DiscreteIndex::sample(uint64_t* seed) const { - int n = x_.size(); + // Alias sampling of discrete distribution + size_t n = prob_.size(); if (n > 1) { - double xi = prn(seed); - double c = 0.0; - for (int i = 0; i < n; ++i) { - c += p_[i]; - if (xi < c) return x_[i]; + size_t u = prn(seed) * n; + if (prn(seed) < prob_[u]) { + return u; + } else { + return alias_[u]; } - throw std::runtime_error{"Error when sampling probability mass function."}; } else { - return x_[0]; + return 0; } } -void Discrete::normalize() +void DiscreteIndex::normalize() { - // Renormalize density function so that it sums to unity - double norm = std::accumulate(p_.begin(), p_.end(), 0.0); - for (auto& p_i : p_) { - p_i /= norm; + // Renormalize density function so that it sums to unity. Note that we save + // the integral of the distribution so that if it is used as part of another + // distribution (e.g., Mixture), we know its relative strength. + integral_ = std::accumulate(prob_.begin(), prob_.end(), 0.0); + for (auto& p_i : prob_) { + p_i /= integral_; } } +//============================================================================== +// Discrete implementation +//============================================================================== + +Discrete::Discrete(pugi::xml_node node) : di_(node) +{ + auto params = get_node_array(node, "parameters"); + + std::size_t n = params.size() / 2; + + x_.assign(params.begin(), params.begin() + n); +} + +Discrete::Discrete(const double* x, const double* p, size_t n) : di_({p, n}) +{ + + x_.assign(x, x + n); +} + +double Discrete::sample(uint64_t* seed) const +{ + return x_[di_.sample(seed)]; +} + //============================================================================== // Uniform implementation //============================================================================== @@ -69,8 +145,8 @@ Uniform::Uniform(pugi::xml_node node) { auto params = get_node_array(node, "parameters"); if (params.size() != 2) { - openmc::fatal_error("Uniform distribution must have two " - "parameters specified."); + fatal_error("Uniform distribution must have two " + "parameters specified."); } a_ = params.at(0); @@ -79,7 +155,33 @@ Uniform::Uniform(pugi::xml_node node) double Uniform::sample(uint64_t* seed) const { - return a_ + prn(seed)*(b_ - a_); + return a_ + prn(seed) * (b_ - a_); +} + +//============================================================================== +// PowerLaw implementation +//============================================================================== + +PowerLaw::PowerLaw(pugi::xml_node node) +{ + auto params = get_node_array(node, "parameters"); + if (params.size() != 3) { + fatal_error("PowerLaw distribution must have three " + "parameters specified."); + } + + const double a = params.at(0); + const double b = params.at(1); + const double n = params.at(2); + + offset_ = std::pow(a, n + 1); + span_ = std::pow(b, n + 1) - offset_; + ninv_ = 1 / (n + 1); +} + +double PowerLaw::sample(uint64_t* seed) const +{ + return std::pow(offset_ + prn(seed) * span_, ninv_); } //============================================================================== @@ -121,7 +223,7 @@ double Watt::sample(uint64_t* seed) const //============================================================================== Normal::Normal(pugi::xml_node node) { - auto params = get_node_array(node,"parameters"); + auto params = get_node_array(node, "parameters"); if (params.size() != 2) { openmc::fatal_error("Normal energy distribution must have two " "parameters specified."); @@ -136,27 +238,6 @@ double Normal::sample(uint64_t* seed) const return normal_variate(mean_value_, std_dev_, seed); } -//============================================================================== -// Muir implementation -//============================================================================== -Muir::Muir(pugi::xml_node node) -{ - auto params = get_node_array(node,"parameters"); - if (params.size() != 3) { - openmc::fatal_error("Muir energy distribution must have three " - "parameters specified."); - } - - e0_ = params.at(0); - m_rat_ = params.at(1); - kt_ = params.at(2); -} - -double Muir::sample(uint64_t* seed) const -{ - return muir_spectrum(e0_, m_rat_, kt_, seed); -} - //============================================================================== // Tabular implementation //============================================================================== @@ -170,7 +251,8 @@ Tabular::Tabular(pugi::xml_node node) } else if (temp == "linear-linear") { interp_ = Interpolation::lin_lin; } else { - openmc::fatal_error("Unknown interpolation type for distribution: " + temp); + openmc::fatal_error( + "Unsupported interpolation type for distribution: " + temp); } } else { interp_ = Interpolation::histogram; @@ -184,13 +266,15 @@ Tabular::Tabular(pugi::xml_node node) init(x, p, n); } -Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp, const double* c) - : interp_{interp} +Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp, + const double* c) + : interp_ {interp} { init(x, p, n, c); } -void Tabular::init(const double* x, const double* p, std::size_t n, const double* c) +void Tabular::init( + const double* x, const double* p, std::size_t n, const double* c) { // Copy x/p arrays into vectors std::copy(x, x + n, std::back_inserter(x_)); @@ -211,17 +295,20 @@ void Tabular::init(const double* x, const double* p, std::size_t n, const double c_[0] = 0.0; for (int i = 1; i < n; ++i) { if (interp_ == Interpolation::histogram) { - c_[i] = c_[i-1] + p_[i-1]*(x_[i] - x_[i-1]); + c_[i] = c_[i - 1] + p_[i - 1] * (x_[i] - x_[i - 1]); } else if (interp_ == Interpolation::lin_lin) { - c_[i] = c_[i-1] + 0.5*(p_[i-1] + p_[i]) * (x_[i] - x_[i-1]); + c_[i] = c_[i - 1] + 0.5 * (p_[i - 1] + p_[i]) * (x_[i] - x_[i - 1]); } } } - // Normalize density and distribution functions + // Normalize density and distribution functions. Note that we save the + // integral of the distribution so that if it is used as part of another + // distribution (e.g., Mixture), we know its relative strength. + integral_ = c_[n - 1]; for (int i = 0; i < n; ++i) { - p_[i] = p_[i]/c_[n-1]; - c_[i] = c_[i]/c_[n-1]; + p_[i] = p_[i] / integral_; + c_[i] = c_[i] / integral_; } } @@ -235,8 +322,9 @@ double Tabular::sample(uint64_t* seed) const int i; std::size_t n = c_.size(); for (i = 0; i < n - 1; ++i) { - if (c <= c_[i+1]) break; - c_i = c_[i+1]; + if (c <= c_[i + 1]) + break; + c_i = c_[i + 1]; } // Determine bounding PDF values @@ -246,7 +334,7 @@ double Tabular::sample(uint64_t* seed) const if (interp_ == Interpolation::histogram) { // Histogram interpolation if (p_i > 0.0) { - return x_i + (c - c_i)/p_i; + return x_i + (c - c_i) / p_i; } else { return x_i; } @@ -255,11 +343,13 @@ double Tabular::sample(uint64_t* seed) const double x_i1 = x_[i + 1]; double p_i1 = p_[i + 1]; - double m = (p_i1 - p_i)/(x_i1 - x_i); + double m = (p_i1 - p_i) / (x_i1 - x_i); if (m == 0.0) { - return x_i + (c - c_i)/p_i; + return x_i + (c - c_i) / p_i; } else { - return x_i + (std::sqrt(std::max(0.0, p_i*p_i + 2*m*(c - c_i))) - p_i)/m; + return x_i + + (std::sqrt(std::max(0.0, p_i * p_i + 2 * m * (c - c_i))) - p_i) / + m; } } } @@ -273,11 +363,57 @@ double Equiprobable::sample(uint64_t* seed) const std::size_t n = x_.size(); double r = prn(seed); - int i = std::floor((n - 1)*r); + int i = std::floor((n - 1) * r); double xl = x_[i]; - double xr = x_[i+i]; - return xl + ((n - 1)*r - i) * (xr - xl); + double xr = x_[i + i]; + return xl + ((n - 1) * r - i) * (xr - xl); +} + +//============================================================================== +// Mixture implementation +//============================================================================== + +Mixture::Mixture(pugi::xml_node node) +{ + double cumsum = 0.0; + for (pugi::xml_node pair : node.children("pair")) { + // Check that required data exists + if (!pair.attribute("probability")) + fatal_error("Mixture pair element does not have probability."); + if (!pair.child("dist")) + fatal_error("Mixture pair element does not have a distribution."); + + // cummulative sum of probabilities + double p = std::stod(pair.attribute("probability").value()); + + // Save cummulative probability and distribution + auto dist = distribution_from_xml(pair.child("dist")); + cumsum += p * dist->integral(); + + distribution_.push_back(std::make_pair(cumsum, std::move(dist))); + } + + // Normalize cummulative probabilities to 1 + for (auto& pair : distribution_) { + pair.first /= cumsum; + } +} + +double Mixture::sample(uint64_t* seed) const +{ + // Sample value of CDF + const double p = prn(seed); + + // find matching distribution + const auto it = std::lower_bound(distribution_.cbegin(), distribution_.cend(), + p, [](const DistPair& pair, double p) { return pair.first < p; }); + + // This should not happen. Catch it + Ensures(it != distribution_.cend()); + + // Sample the chosen distribution + return it->second->sample(seed); } //============================================================================== @@ -295,19 +431,25 @@ UPtrDist distribution_from_xml(pugi::xml_node node) // Allocate extension of Distribution UPtrDist dist; if (type == "uniform") { - dist = UPtrDist{new Uniform(node)}; + dist = UPtrDist {new Uniform(node)}; + } else if (type == "powerlaw") { + dist = UPtrDist {new PowerLaw(node)}; } else if (type == "maxwell") { - dist = UPtrDist{new Maxwell(node)}; + dist = UPtrDist {new Maxwell(node)}; } else if (type == "watt") { - dist = UPtrDist{new Watt(node)}; + dist = UPtrDist {new Watt(node)}; } else if (type == "normal") { - dist = UPtrDist{new Normal(node)}; - } else if (type == "muir") { - dist = UPtrDist{new Muir(node)}; + dist = UPtrDist {new Normal(node)}; } else if (type == "discrete") { - dist = UPtrDist{new Discrete(node)}; + dist = UPtrDist {new Discrete(node)}; } else if (type == "tabular") { - dist = UPtrDist{new Tabular(node)}; + dist = UPtrDist {new Tabular(node)}; + } else if (type == "mixture") { + dist = UPtrDist {new Mixture(node)}; + } else if (type == "muir") { + openmc::fatal_error( + "'muir' distributions are now specified using the openmc.stats.muir() " + "function in Python. Please regenerate your XML files."); } else { openmc::fatal_error("Invalid distribution type: " + type); } diff --git a/src/distribution_angle.cpp b/src/distribution_angle.cpp index 13e8c480fc9..5e92b794a72 100644 --- a/src/distribution_angle.cpp +++ b/src/distribution_angle.cpp @@ -1,6 +1,6 @@ #include "openmc/distribution_angle.h" -#include // for abs, copysign +#include // for abs, copysign #include "xtensor/xarray.hpp" #include "xtensor/xview.hpp" @@ -38,15 +38,15 @@ AngleDistribution::AngleDistribution(hid_t group) int j = offsets[i]; int n; if (i < n_energy - 1) { - n = offsets[i+1] - j; + n = offsets[i + 1] - j; } else { n = temp.shape()[1] - j; } // Create and initialize tabular distribution - auto xs = xt::view(temp, 0, xt::range(j, j+n)); - auto ps = xt::view(temp, 1, xt::range(j, j+n)); - auto cs = xt::view(temp, 2, xt::range(j, j+n)); + auto xs = xt::view(temp, 0, xt::range(j, j + n)); + auto ps = xt::view(temp, 1, xt::range(j, j + n)); + auto cs = xt::view(temp, 2, xt::range(j, j + n)); vector x {xs.begin(), xs.end()}; vector p {ps.begin(), ps.end()}; vector c {cs.begin(), cs.end()}; @@ -55,8 +55,8 @@ AngleDistribution::AngleDistribution(hid_t group) // CDF values that were passed through to the HDF5 library. At a later // time, we can remove the CDF values from the HDF5 library and // reconstruct them using the PDF - Tabular* mudist = new Tabular{x.data(), p.data(), n, int2interp(interp[i]), - c.data()}; + Tabular* mudist = + new Tabular {x.data(), p.data(), n, int2interp(interp[i]), c.data()}; distribution_.emplace_back(mudist); } @@ -79,17 +79,19 @@ double AngleDistribution::sample(double E, uint64_t* seed) const r = 1.0; } else { i = lower_bound_index(energy_.begin(), energy_.end(), E); - r = (E - energy_[i])/(energy_[i+1] - energy_[i]); + r = (E - energy_[i]) / (energy_[i + 1] - energy_[i]); } // Sample between the ith and (i+1)th bin - if (r > prn(seed)) ++i; + if (r > prn(seed)) + ++i; // Sample i-th distribution double mu = distribution_[i]->sample(seed); // Make sure mu is in range [-1,1] and return - if (std::abs(mu) > 1.0) mu = std::copysign(1.0, mu); + if (std::abs(mu) > 1.0) + mu = std::copysign(1.0, mu); return mu; } diff --git a/src/distribution_energy.cpp b/src/distribution_energy.cpp index 1fd95d4019c..a4a5ce9e1b6 100644 --- a/src/distribution_energy.cpp +++ b/src/distribution_energy.cpp @@ -29,7 +29,7 @@ DiscretePhoton::DiscretePhoton(hid_t group) double DiscretePhoton::sample(double E, uint64_t* seed) const { if (primary_flag_ == 2) { - return energy_ + A_/(A_+ 1)*E; + return energy_ + A_ / (A_ + 1) * E; } else { return energy_; } @@ -47,7 +47,7 @@ LevelInelastic::LevelInelastic(hid_t group) double LevelInelastic::sample(double E, uint64_t* seed) const { - return mass_ratio_*(E - threshold_); + return mass_ratio_ * (E - threshold_); } //============================================================================== @@ -94,7 +94,7 @@ ContinuousTabular::ContinuousTabular(hid_t group) int j = offsets[i]; int n; if (i < n_energy - 1) { - n = offsets[i+1] - j; + n = offsets[i + 1] - j; } else { n = eout.shape()[1] - j; } @@ -105,35 +105,35 @@ ContinuousTabular::ContinuousTabular(hid_t group) d.n_discrete = n_discrete[i]; // Copy data - d.e_out = xt::view(eout, 0, xt::range(j, j+n)); - d.p = xt::view(eout, 1, xt::range(j, j+n)); + d.e_out = xt::view(eout, 0, xt::range(j, j + n)); + d.p = xt::view(eout, 1, xt::range(j, j + n)); // To get answers that match ACE data, for now we still use the tabulated // CDF values that were passed through to the HDF5 library. At a later // time, we can remove the CDF values from the HDF5 library and // reconstruct them using the PDF if (true) { - d.c = xt::view(eout, 2, xt::range(j, j+n)); + d.c = xt::view(eout, 2, xt::range(j, j + n)); } else { // Calculate cumulative distribution function -- discrete portion for (int k = 0; k < d.n_discrete; ++k) { if (k == 0) { d.c[k] = d.p[k]; } else { - d.c[k] = d.c[k-1] + d.p[k]; + d.c[k] = d.c[k - 1] + d.p[k]; } } // Continuous portion for (int k = d.n_discrete; k < n; ++k) { if (k == d.n_discrete) { - d.c[k] = d.c[k-1] + d.p[k]; + d.c[k] = d.c[k - 1] + d.p[k]; } else { if (d.interpolation == Interpolation::histogram) { - d.c[k] = d.c[k-1] + d.p[k-1]*(d.e_out[k] - d.e_out[k-1]); + d.c[k] = d.c[k - 1] + d.p[k - 1] * (d.e_out[k] - d.e_out[k - 1]); } else if (d.interpolation == Interpolation::lin_lin) { - d.c[k] = d.c[k-1] + 0.5*(d.p[k-1] + d.p[k]) * - (d.e_out[k] - d.e_out[k-1]); + d.c[k] = d.c[k - 1] + 0.5 * (d.p[k - 1] + d.p[k]) * + (d.e_out[k] - d.e_out[k - 1]); } } } @@ -170,7 +170,7 @@ double ContinuousTabular::sample(double E, uint64_t* seed) const r = 1.0; } else { i = lower_bound_index(energy_.begin(), energy_.end(), E); - r = (E - energy_[i]) / (energy_[i+1] - energy_[i]); + r = (E - energy_[i]) / (energy_[i + 1] - energy_[i]); } // Sample between the ith and [i+1]th bin @@ -181,23 +181,9 @@ double ContinuousTabular::sample(double E, uint64_t* seed) const l = r > prn(seed) ? i + 1 : i; } - // Interpolation for energy E1 and EK - int n_energy_out = distribution_[i].e_out.size(); - int n_discrete = distribution_[i].n_discrete; - double E_i_1 = distribution_[i].e_out[n_discrete]; - double E_i_K = distribution_[i].e_out[n_energy_out - 1]; - - n_energy_out = distribution_[i+1].e_out.size(); - n_discrete = distribution_[i+1].n_discrete; - double E_i1_1 = distribution_[i+1].e_out[n_discrete]; - double E_i1_K = distribution_[i+1].e_out[n_energy_out - 1]; - - double E_1 = E_i_1 + r * (E_i1_1 - E_i_1); - double E_K = E_i_K + r * (E_i1_K - E_i_K); - // Determine outgoing energy bin - n_energy_out = distribution_[l].e_out.size(); - n_discrete = distribution_[l].n_discrete; + int n_energy_out = distribution_[l].e_out.size(); + int n_discrete = distribution_[l].n_discrete; double r1 = prn(seed); double c_k = distribution_[l].c[0]; int k = 0; @@ -217,8 +203,9 @@ double ContinuousTabular::sample(double E, uint64_t* seed) const double c_k1; for (int j = n_discrete; j < end; ++j) { k = j; - c_k1 = distribution_[l].c[k+1]; - if (r1 < c_k1) break; + c_k1 = distribution_[l].c[k + 1]; + if (r1 < c_k1) + break; k = j + 1; c_k = c_k1; } @@ -229,39 +216,55 @@ double ContinuousTabular::sample(double E, uint64_t* seed) const if (distribution_[l].interpolation == Interpolation::histogram) { // Histogram interpolation if (p_l_k > 0.0 && k >= n_discrete) { - E_out = E_l_k + (r1 - c_k)/p_l_k; + E_out = E_l_k + (r1 - c_k) / p_l_k; } } else if (distribution_[l].interpolation == Interpolation::lin_lin) { // Linear-linear interpolation - double E_l_k1 = distribution_[l].e_out[k+1]; - double p_l_k1 = distribution_[l].p[k+1]; + double E_l_k1 = distribution_[l].e_out[k + 1]; + double p_l_k1 = distribution_[l].p[k + 1]; if (E_l_k != E_l_k1) { - double frac = (p_l_k1 - p_l_k)/(E_l_k1 - E_l_k); + double frac = (p_l_k1 - p_l_k) / (E_l_k1 - E_l_k); if (frac == 0.0) { - E_out = E_l_k + (r1 - c_k)/p_l_k; + E_out = E_l_k + (r1 - c_k) / p_l_k; } else { - E_out = E_l_k + (std::sqrt(std::max(0.0, p_l_k*p_l_k + - 2.0*frac*(r1 - c_k))) - p_l_k)/frac; + E_out = + E_l_k + + (std::sqrt(std::max(0.0, p_l_k * p_l_k + 2.0 * frac * (r1 - c_k))) - + p_l_k) / + frac; } } } else { - throw std::runtime_error{"Unexpected interpolation for continuous energy " - "distribution."}; + throw std::runtime_error {"Unexpected interpolation for continuous energy " + "distribution."}; } // Now interpolate between incident energy bins i and i + 1 if (!histogram_interp && n_energy_out > 1 && k >= n_discrete) { + // Interpolation for energy E1 and EK + n_energy_out = distribution_[i].e_out.size(); + n_discrete = distribution_[i].n_discrete; + const double E_i_1 = distribution_[i].e_out[n_discrete]; + const double E_i_K = distribution_[i].e_out[n_energy_out - 1]; + + n_energy_out = distribution_[i + 1].e_out.size(); + n_discrete = distribution_[i + 1].n_discrete; + const double E_i1_1 = distribution_[i + 1].e_out[n_discrete]; + const double E_i1_K = distribution_[i + 1].e_out[n_energy_out - 1]; + + const double E_1 = E_i_1 + r * (E_i1_1 - E_i_1); + const double E_K = E_i_K + r * (E_i1_K - E_i_K); + if (l == i) { - return E_1 + (E_out - E_i_1)*(E_K - E_1)/(E_i_K - E_i_1); + return E_1 + (E_out - E_i_1) * (E_K - E_1) / (E_i_K - E_i_1); } else { - return E_1 + (E_out - E_i1_1)*(E_K - E_1)/(E_i1_K - E_i1_1); + return E_1 + (E_out - E_i1_1) * (E_K - E_1) / (E_i1_K - E_i1_1); } } else { return E_out; } - } //============================================================================== @@ -272,7 +275,7 @@ MaxwellEnergy::MaxwellEnergy(hid_t group) { read_attribute(group, "u", u_); hid_t dset = open_dataset(group, "theta"); - theta_ = Tabulated1D{dset}; + theta_ = Tabulated1D {dset}; close_dataset(dset); } @@ -286,7 +289,8 @@ double MaxwellEnergy::sample(double E, uint64_t* seed) const double E_out = maxwell_spectrum(theta, seed); // Accept energy based on restriction energy - if (E_out <= E - u_) return E_out; + if (E_out <= E - u_) + return E_out; } } @@ -298,7 +302,7 @@ Evaporation::Evaporation(hid_t group) { read_attribute(group, "u", u_); hid_t dset = open_dataset(group, "theta"); - theta_ = Tabulated1D{dset}; + theta_ = Tabulated1D {dset}; close_dataset(dset); } @@ -307,15 +311,16 @@ double Evaporation::sample(double E, uint64_t* seed) const // Get temperature corresponding to incoming energy double theta = theta_(E); - double y = (E - u_)/theta; + double y = (E - u_) / theta; double v = 1.0 - std::exp(-y); // Sample outgoing energy based on evaporation spectrum probability // density function double x; while (true) { - x = -std::log((1.0 - v*prn(seed))*(1.0 - v*prn(seed))); - if (x <= y) break; + x = -std::log((1.0 - v * prn(seed)) * (1.0 - v * prn(seed))); + if (x <= y) + break; } return x * theta; @@ -332,10 +337,10 @@ WattEnergy::WattEnergy(hid_t group) // Read tabulated functions hid_t dset = open_dataset(group, "a"); - a_ = Tabulated1D{dset}; + a_ = Tabulated1D {dset}; close_dataset(dset); dset = open_dataset(group, "b"); - b_ = Tabulated1D{dset}; + b_ = Tabulated1D {dset}; close_dataset(dset); } @@ -350,8 +355,9 @@ double WattEnergy::sample(double E, uint64_t* seed) const double E_out = watt_spectrum(a, b, seed); // Accept energy based on restriction energy - if (E_out <= E - u_) return E_out; + if (E_out <= E - u_) + return E_out; } } -} +} // namespace openmc diff --git a/src/distribution_multi.cpp b/src/distribution_multi.cpp index cdf73aee120..b7b3efe5268 100644 --- a/src/distribution_multi.cpp +++ b/src/distribution_multi.cpp @@ -12,6 +12,25 @@ namespace openmc { +unique_ptr UnitSphereDistribution::create( + pugi::xml_node node) +{ + // Check for type of angular distribution + std::string type; + if (check_for_node(node, "type")) + type = get_node_value(node, "type", true, true); + if (type == "isotropic") { + return UPtrAngle {new Isotropic()}; + } else if (type == "monodirectional") { + return UPtrAngle {new Monodirectional(node)}; + } else if (type == "mu-phi") { + return UPtrAngle {new PolarAzimuthal(node)}; + } else { + fatal_error(fmt::format( + "Invalid angular distribution for external source: {}", type)); + } +} + //============================================================================== // UnitSphereDistribution implementation //============================================================================== @@ -28,29 +47,29 @@ UnitSphereDistribution::UnitSphereDistribution(pugi::xml_node node) } } - //============================================================================== // PolarAzimuthal implementation //============================================================================== -PolarAzimuthal::PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi) : - UnitSphereDistribution{u}, mu_{std::move(mu)}, phi_{std::move(phi)} { } +PolarAzimuthal::PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi) + : UnitSphereDistribution {u}, mu_ {std::move(mu)}, phi_ {std::move(phi)} +{} PolarAzimuthal::PolarAzimuthal(pugi::xml_node node) - : UnitSphereDistribution{node} + : UnitSphereDistribution {node} { if (check_for_node(node, "mu")) { pugi::xml_node node_dist = node.child("mu"); mu_ = distribution_from_xml(node_dist); } else { - mu_ = UPtrDist{new Uniform(-1., 1.)}; + mu_ = UPtrDist {new Uniform(-1., 1.)}; } if (check_for_node(node, "phi")) { pugi::xml_node node_dist = node.child("phi"); phi_ = distribution_from_xml(node_dist); } else { - phi_ = UPtrDist{new Uniform(0.0, 2.0*PI)}; + phi_ = UPtrDist {new Uniform(0.0, 2.0 * PI)}; } } @@ -58,7 +77,8 @@ Direction PolarAzimuthal::sample(uint64_t* seed) const { // Sample cosine of polar angle double mu = mu_->sample(seed); - if (mu == 1.0) return u_ref_; + if (mu == 1.0) + return u_ref_; // Sample azimuthal angle double phi = phi_->sample(seed); @@ -72,10 +92,10 @@ Direction PolarAzimuthal::sample(uint64_t* seed) const Direction isotropic_direction(uint64_t* seed) { - double phi = uniform_distribution(0., 2.0*PI, seed); + double phi = uniform_distribution(0., 2.0 * PI, seed); double mu = uniform_distribution(-1., 1., seed); - return {mu, std::sqrt(1.0 - mu*mu) * std::cos(phi), - std::sqrt(1.0 - mu*mu) * std::sin(phi)}; + return {mu, std::sqrt(1.0 - mu * mu) * std::cos(phi), + std::sqrt(1.0 - mu * mu) * std::sin(phi)}; } Direction Isotropic::sample(uint64_t* seed) const diff --git a/src/distribution_spatial.cpp b/src/distribution_spatial.cpp index 356383eb7ae..8dbd7d88706 100644 --- a/src/distribution_spatial.cpp +++ b/src/distribution_spatial.cpp @@ -1,11 +1,43 @@ #include "openmc/distribution_spatial.h" #include "openmc/error.h" +#include "openmc/mesh.h" #include "openmc/random_lcg.h" +#include "openmc/search.h" #include "openmc/xml_interface.h" namespace openmc { +//============================================================================== +// SpatialDistribution implementation +//============================================================================== + +unique_ptr SpatialDistribution::create(pugi::xml_node node) +{ + // Check for type of spatial distribution and read + std::string type; + if (check_for_node(node, "type")) + type = get_node_value(node, "type", true, true); + if (type == "cartesian") { + return UPtrSpace {new CartesianIndependent(node)}; + } else if (type == "cylindrical") { + return UPtrSpace {new CylindricalIndependent(node)}; + } else if (type == "spherical") { + return UPtrSpace {new SphericalIndependent(node)}; + } else if (type == "mesh") { + return UPtrSpace {new MeshSpatial(node)}; + } else if (type == "box") { + return UPtrSpace {new SpatialBox(node)}; + } else if (type == "fission") { + return UPtrSpace {new SpatialBox(node, true)}; + } else if (type == "point") { + return UPtrSpace {new SpatialPoint(node)}; + } else { + fatal_error(fmt::format( + "Invalid spatial distribution for external source: {}", type)); + } +} + //============================================================================== // CartesianIndependent implementation //============================================================================== @@ -20,7 +52,7 @@ CartesianIndependent::CartesianIndependent(pugi::xml_node node) // If no distribution was specified, default to a single point at x=0 double x[] {0.0}; double p[] {1.0}; - x_ = UPtrDist{new Discrete{x, p, 1}}; + x_ = UPtrDist {new Discrete {x, p, 1}}; } // Read distribution for y coordinate @@ -31,7 +63,7 @@ CartesianIndependent::CartesianIndependent(pugi::xml_node node) // If no distribution was specified, default to a single point at y=0 double x[] {0.0}; double p[] {1.0}; - y_ = UPtrDist{new Discrete{x, p, 1}}; + y_ = UPtrDist {new Discrete {x, p, 1}}; } // Read distribution for z coordinate @@ -42,7 +74,7 @@ CartesianIndependent::CartesianIndependent(pugi::xml_node node) // If no distribution was specified, default to a single point at z=0 double x[] {0.0}; double p[] {1.0}; - z_ = UPtrDist{new Discrete{x, p, 1}}; + z_ = UPtrDist {new Discrete {x, p, 1}}; } } @@ -96,21 +128,21 @@ CylindricalIndependent::CylindricalIndependent(pugi::xml_node node) if (origin.size() == 3) { origin_ = origin; } else { - fatal_error("Origin for cylindrical source distribution must be length 3"); + fatal_error( + "Origin for cylindrical source distribution must be length 3"); } } else { // If no coordinates were specified, default to (0, 0, 0) origin_ = {0.0, 0.0, 0.0}; } - } Position CylindricalIndependent::sample(uint64_t* seed) const { double r = r_->sample(seed); double phi = phi_->sample(seed); - double x = r*cos(phi) + origin_.x; - double y = r*sin(phi) + origin_.y; + double x = r * cos(phi) + origin_.x; + double y = r * sin(phi) + origin_.y; double z = z_->sample(seed) + origin_.z; return {x, y, z}; } @@ -132,15 +164,16 @@ SphericalIndependent::SphericalIndependent(pugi::xml_node node) r_ = make_unique(x, p, 1); } - // Read distribution for theta-coordinate - if (check_for_node(node, "theta")) { - pugi::xml_node node_dist = node.child("theta"); - theta_ = distribution_from_xml(node_dist); + // Read distribution for cos_theta-coordinate + if (check_for_node(node, "cos_theta")) { + pugi::xml_node node_dist = node.child("cos_theta"); + cos_theta_ = distribution_from_xml(node_dist); } else { - // If no distribution was specified, default to a single point at theta=0 + // If no distribution was specified, default to a single point at + // cos_theta=0 double x[] {0.0}; double p[] {1.0}; - theta_ = make_unique(x, p, 1); + cos_theta_ = make_unique(x, p, 1); } // Read distribution for phi-coordinate @@ -166,26 +199,111 @@ SphericalIndependent::SphericalIndependent(pugi::xml_node node) // If no coordinates were specified, default to (0, 0, 0) origin_ = {0.0, 0.0, 0.0}; } - } Position SphericalIndependent::sample(uint64_t* seed) const { double r = r_->sample(seed); - double theta = theta_->sample(seed); + double cos_theta = cos_theta_->sample(seed); double phi = phi_->sample(seed); - double x = r*sin(theta)*cos(phi) + origin_.x; - double y = r*sin(theta)*sin(phi) + origin_.y; - double z = r*cos(theta) + origin_.z; + // sin(theta) by sin**2 + cos**2 = 1 + double x = r * std::sqrt(1 - cos_theta * cos_theta) * cos(phi) + origin_.x; + double y = r * std::sqrt(1 - cos_theta * cos_theta) * sin(phi) + origin_.y; + double z = r * cos_theta + origin_.z; return {x, y, z}; } +//============================================================================== +// MeshSpatial implementation +//============================================================================== + +MeshSpatial::MeshSpatial(pugi::xml_node node) +{ + + if (get_node_value(node, "type", true, true) != "mesh") { + fatal_error(fmt::format( + "Incorrect spatial type '{}' for a MeshSpatial distribution")); + } + + // No in-tet distributions implemented, could include distributions for the + // barycentric coords Read in unstructured mesh from mesh_id value + int32_t mesh_id = std::stoi(get_node_value(node, "mesh_id")); + // Get pointer to spatial distribution + mesh_idx_ = model::mesh_map.at(mesh_id); + + const auto mesh_ptr = model::meshes.at(mesh_idx_).get(); + + check_element_types(); + + size_t n_bins = this->n_sources(); + std::vector strengths(n_bins, 1.0); + + // Create cdfs for sampling for an element over a mesh + // Volume scheme is weighted by the volume of each tet + // File scheme is weighted by an array given in the xml file + if (check_for_node(node, "strengths")) { + strengths = get_node_array(node, "strengths"); + if (strengths.size() != n_bins) { + fatal_error( + fmt::format("Number of entries in the source strengths array {} does " + "not match the number of entities in mesh {} ({}).", + strengths.size(), mesh_id, n_bins)); + } + } + + if (get_node_value_bool(node, "volume_normalized")) { + for (int i = 0; i < n_bins; i++) { + strengths[i] *= this->mesh()->volume(i); + } + } + + elem_idx_dist_.assign(strengths); +} + +MeshSpatial::MeshSpatial(int32_t mesh_idx, gsl::span strengths) + : mesh_idx_(mesh_idx) +{ + check_element_types(); + elem_idx_dist_.assign(strengths); +} + +void MeshSpatial::check_element_types() const +{ + const auto umesh_ptr = dynamic_cast(this->mesh()); + if (umesh_ptr) { + // ensure that the unstructured mesh contains only linear tets + for (int bin = 0; bin < umesh_ptr->n_bins(); bin++) { + if (umesh_ptr->element_type(bin) != ElementType::LINEAR_TET) { + fatal_error( + "Mesh specified for source must contain only linear tetrahedra."); + } + } + } +} + +int32_t MeshSpatial::sample_element_index(uint64_t* seed) const +{ + return elem_idx_dist_.sample(seed); +} + +std::pair MeshSpatial::sample_mesh(uint64_t* seed) const +{ + // Sample the CDF defined in initialization above + int32_t elem_idx = this->sample_element_index(seed); + return {elem_idx, mesh()->sample_element(elem_idx, seed)}; +} + +Position MeshSpatial::sample(uint64_t* seed) const +{ + return this->sample_mesh(seed).second; +} + //============================================================================== // SpatialBox implementation //============================================================================== SpatialBox::SpatialBox(pugi::xml_node node, bool fission) - : only_fissionable_{fission} + : only_fissionable_ {fission} { // Read lower-right/upper-left coordinates auto params = get_node_array(node, "parameters"); @@ -193,14 +311,14 @@ SpatialBox::SpatialBox(pugi::xml_node node, bool fission) openmc::fatal_error("Box/fission spatial source must have six " "parameters specified."); - lower_left_ = Position{params[0], params[1], params[2]}; - upper_right_ = Position{params[3], params[4], params[5]}; + lower_left_ = Position {params[0], params[1], params[2]}; + upper_right_ = Position {params[3], params[4], params[5]}; } Position SpatialBox::sample(uint64_t* seed) const { Position xi {prn(seed), prn(seed), prn(seed)}; - return lower_left_ + xi*(upper_right_ - lower_left_); + return lower_left_ + xi * (upper_right_ - lower_left_); } //============================================================================== @@ -216,7 +334,7 @@ SpatialPoint::SpatialPoint(pugi::xml_node node) "parameters specified."); // Set position - r_ = Position{params.data()}; + r_ = Position {params.data()}; } Position SpatialPoint::sample(uint64_t* seed) const diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index 1e0d7d972ed..d5410094b18 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -22,10 +22,10 @@ #include "openmc/timer.h" #include // for min -#include // for sqrt, abs, pow -#include // for back_inserter +#include // for sqrt, abs, pow +#include // for back_inserter +#include //for infinity #include -#include //for infinity namespace openmc { @@ -51,20 +51,34 @@ void calculate_generation_keff() const auto& gt = simulation::global_tallies; // Get keff for this generation by subtracting off the starting value - simulation::keff_generation = gt(GlobalTally::K_TRACKLENGTH, TallyResult::VALUE) - simulation::keff_generation; + simulation::keff_generation = + gt(GlobalTally::K_TRACKLENGTH, TallyResult::VALUE) - + simulation::keff_generation; double keff_reduced; #ifdef OPENMC_MPI - // Combine values across all processors - MPI_Allreduce(&simulation::keff_generation, &keff_reduced, 1, MPI_DOUBLE, - MPI_SUM, mpi::intracomm); + if (settings::solver_type != SolverType::RANDOM_RAY) { + // Combine values across all processors + MPI_Allreduce(&simulation::keff_generation, &keff_reduced, 1, MPI_DOUBLE, + MPI_SUM, mpi::intracomm); + } else { + // If using random ray, MPI parallelism is provided by domain replication. + // As such, all fluxes will be reduced at the end of each transport sweep, + // such that all ranks have identical scalar flux vectors, and will all + // independently compute the same value of k. Thus, there is no need to + // perform any additional MPI reduction here. + keff_reduced = simulation::keff_generation; + } #else keff_reduced = simulation::keff_generation; #endif // Normalize single batch estimate of k // TODO: This should be normalized by total_weight, not by n_particles - keff_reduced /= settings::n_particles; + if (settings::solver_type != SolverType::RANDOM_RAY) { + keff_reduced /= settings::n_particles; + } + simulation::k_generation.push_back(keff_reduced); } @@ -89,16 +103,17 @@ void synchronize_bank() // While we would expect the value of start on rank 0 to be 0, the MPI // standard says that the receive buffer on rank 0 is undefined and not // significant - if (mpi::rank == 0) start = 0; + if (mpi::rank == 0) + start = 0; int64_t finish = start + simulation::fission_bank.size(); int64_t total = finish; MPI_Bcast(&total, 1, MPI_INT64_T, mpi::n_procs - 1, mpi::intracomm); #else - int64_t start = 0; + int64_t start = 0; int64_t finish = simulation::fission_bank.size(); - int64_t total = finish; + int64_t total = finish; #endif // If there are not that many particles per generation, it's possible that no @@ -107,7 +122,8 @@ void synchronize_bank() // runs enough particles to avoid this in the first place. if (simulation::fission_bank.size() == 0) { - fatal_error("No fission sites banked on MPI rank " + std::to_string(mpi::rank)); + fatal_error( + "No fission sites banked on MPI rank " + std::to_string(mpi::rank)); } // Make sure all processors start at the same point for random sampling. Then @@ -139,7 +155,7 @@ void synchronize_bank() int64_t index_temp = 0; vector temp_sites(3 * simulation::work_per_rank); - for (int64_t i = 0; i < simulation::fission_bank.size(); i++ ) { + for (int64_t i = 0; i < simulation::fission_bank.size(); i++) { const auto& site = simulation::fission_bank[i]; // If there are less than n_particles particles banked, automatically add @@ -174,8 +190,8 @@ void synchronize_bank() // Allocate space for bank_position if this hasn't been done yet int64_t bank_position[mpi::n_procs]; - MPI_Allgather(&start, 1, MPI_INT64_T, bank_position, 1, - MPI_INT64_T, mpi::intracomm); + MPI_Allgather( + &start, 1, MPI_INT64_T, bank_position, 1, MPI_INT64_T, mpi::intracomm); #else start = 0; finish = index_temp; @@ -219,19 +235,21 @@ void synchronize_bank() if (start < settings::n_particles) { // Determine the index of the processor which has the first part of the // source_bank for the local processor - int neighbor = upper_bound_index(simulation::work_index.begin(), - simulation::work_index.end(), start); + int neighbor = upper_bound_index( + simulation::work_index.begin(), simulation::work_index.end(), start); while (start < finish) { // Determine the number of sites to send - int64_t n = std::min(simulation::work_index[neighbor + 1], finish) - start; + int64_t n = + std::min(simulation::work_index[neighbor + 1], finish) - start; // Initiate an asynchronous send of source sites to the neighboring // process if (neighbor != mpi::rank) { requests.emplace_back(); - MPI_Isend(&temp_sites[index_local], static_cast(n), mpi::source_site, - neighbor, mpi::rank, mpi::intracomm, &requests.back()); + MPI_Isend(&temp_sites[index_local], static_cast(n), + mpi::source_site, neighbor, mpi::rank, mpi::intracomm, + &requests.back()); } // Increment all indices @@ -242,7 +260,8 @@ void synchronize_bank() // Check for sites out of bounds -- this only happens in the rare // circumstance that a processor close to the end has so many sites that // it would exceed the bank on the last processor - if (neighbor > mpi::n_procs - 1) break; + if (neighbor > mpi::n_procs - 1) + break; } } @@ -259,7 +278,8 @@ void synchronize_bank() if (start >= bank_position[mpi::n_procs - 1]) { neighbor = mpi::n_procs - 1; } else { - neighbor = upper_bound_index(bank_position, bank_position + mpi::n_procs, start); + neighbor = + upper_bound_index(bank_position, bank_position + mpi::n_procs, start); } while (start < simulation::work_index[mpi::rank + 1]) { @@ -268,7 +288,9 @@ void synchronize_bank() if (neighbor == mpi::n_procs - 1) { n = simulation::work_index[mpi::rank + 1] - start; } else { - n = std::min(bank_position[neighbor + 1], simulation::work_index[mpi::rank + 1]) - start; + n = std::min(bank_position[neighbor + 1], + simulation::work_index[mpi::rank + 1]) - + start; } if (neighbor != mpi::rank) { @@ -276,8 +298,8 @@ void synchronize_bank() // asynchronous receive for the source sites requests.emplace_back(); - MPI_Irecv(&simulation::source_bank[index_local], static_cast(n), mpi::source_site, - neighbor, neighbor, mpi::intracomm, &requests.back()); + MPI_Irecv(&simulation::source_bank[index_local], static_cast(n), + mpi::source_site, neighbor, neighbor, mpi::intracomm, &requests.back()); } else { // If the source sites are on this procesor, we can simply copy them @@ -316,7 +338,8 @@ void calculate_average_keff() int i = overall_generation() - 1; int n; if (simulation::current_batch > settings::n_inactive) { - n = settings::gen_per_batch*simulation::n_realizations + simulation::current_gen; + n = settings::gen_per_batch * simulation::n_realizations + + simulation::current_gen; } else { n = 0; } @@ -338,14 +361,16 @@ void calculate_average_keff() if (settings::confidence_intervals) { // Calculate t-value for confidence intervals double alpha = 1.0 - CONFIDENCE_LEVEL; - t_value = t_percentile(1.0 - alpha/2.0, n - 1); + t_value = t_percentile(1.0 - alpha / 2.0, n - 1); } else { t_value = 1.0; } // Standard deviation of the sample mean of k - simulation::keff_std = t_value * std::sqrt((simulation::k_sum[1]/n - - std::pow(simulation::keff, 2)) / (n - 1)); + simulation::keff_std = + t_value * + std::sqrt( + (simulation::k_sum[1] / n - std::pow(simulation::keff, 2)) / (n - 1)); } } } @@ -357,10 +382,11 @@ int openmc_get_keff(double* k_combined) // Special case for n <=3. Notice that at the end, // there is a N-3 term in a denominator. - if (simulation::n_realizations <= 3) { + if (simulation::n_realizations <= 3 || + settings::solver_type == SolverType::RANDOM_RAY) { k_combined[0] = simulation::keff; k_combined[1] = simulation::keff_std; - if (simulation::n_realizations <=1) { + if (simulation::n_realizations <= 1) { k_combined[1] = std::numeric_limits::infinity(); } return 0; @@ -377,9 +403,15 @@ int openmc_get_keff(double* k_combined) kv[0] = gt(GlobalTally::K_COLLISION, TallyResult::SUM) / n; kv[1] = gt(GlobalTally::K_ABSORPTION, TallyResult::SUM) / n; kv[2] = gt(GlobalTally::K_TRACKLENGTH, TallyResult::SUM) / n; - cov(0, 0) = (gt(GlobalTally::K_COLLISION, TallyResult::SUM_SQ) - n*kv[0]*kv[0]) / (n - 1); - cov(1, 1) = (gt(GlobalTally::K_ABSORPTION, TallyResult::SUM_SQ) - n*kv[1]*kv[1]) / (n - 1); - cov(2, 2) = (gt(GlobalTally::K_TRACKLENGTH, TallyResult::SUM_SQ) - n*kv[2]*kv[2]) / (n - 1); + cov(0, 0) = + (gt(GlobalTally::K_COLLISION, TallyResult::SUM_SQ) - n * kv[0] * kv[0]) / + (n - 1); + cov(1, 1) = + (gt(GlobalTally::K_ABSORPTION, TallyResult::SUM_SQ) - n * kv[1] * kv[1]) / + (n - 1); + cov(2, 2) = + (gt(GlobalTally::K_TRACKLENGTH, TallyResult::SUM_SQ) - n * kv[2] * kv[2]) / + (n - 1); // Calculate covariances based on sums with Bessel's correction cov(0, 1) = (simulation::k_col_abs - n * kv[0] * kv[1]) / (n - 1); @@ -455,7 +487,7 @@ int openmc_get_keff(double* k_combined) // Calculate weighting double f = cov(j, j) * (cov(k, k) - cov(i, k)) - cov(k, k) * cov(i, j) + - cov(j, k) * (cov(i, j) + cov(i, k) - cov(j, k)); + cov(j, k) * (cov(i, j) + cov(i, k) - cov(j, k)); // Add to S sums for variance of combined estimate S[0] += f * cov(0, l); @@ -471,15 +503,15 @@ int openmc_get_keff(double* k_combined) for (auto& S_i : S) { S_i *= (n - 1); } - S[0] *= (n - 1)*(n - 1); + S[0] *= (n - 1) * (n - 1); // Calculate combined estimate of k-effective k_combined[0] /= g; // Calculate standard deviation of combined estimate - g *= (n - 1)*(n - 1); - k_combined[1] = std::sqrt(S[0] / (g*n*(n - 3)) * - (1 + n*((S[1] - 2*S[2]) / g))); + g *= (n - 1) * (n - 1); + k_combined[1] = + std::sqrt(S[0] / (g * n * (n - 3)) * (1 + n * ((S[1] - 2 * S[2]) / g))); } else { // Use only two estimators @@ -489,16 +521,15 @@ int openmc_get_keff(double* k_combined) // Store the commonly used term double f = kv[i] - kv[j]; - double g = cov(i, i) + cov(j, j) - 2.0*cov(i, j); + double g = cov(i, i) + cov(j, j) - 2.0 * cov(i, j); // Calculate combined estimate of k-effective k_combined[0] = kv[i] - (cov(i, i) - cov(i, j)) / g * f; // Calculate standard deviation of combined estimate - k_combined[1] = (cov(i, i)*cov(j, j) - cov(i, j)*cov(i, j)) * - (g + n*f*f) / (n*(n - 2)*g*g); + k_combined[1] = (cov(i, i) * cov(j, j) - cov(i, j) * cov(i, j)) * + (g + n * f * f) / (n * (n - 2) * g * g); k_combined[1] = std::sqrt(k_combined[1]); - } return 0; } @@ -507,13 +538,14 @@ void shannon_entropy() { // Get source weight in each mesh bin bool sites_outside; - xt::xtensor p = simulation::entropy_mesh->count_sites( - simulation::fission_bank.data(), simulation::fission_bank.size(), - &sites_outside); + xt::xtensor p = + simulation::entropy_mesh->count_sites(simulation::fission_bank.data(), + simulation::fission_bank.size(), &sites_outside); // display warning message if there were sites outside entropy box if (sites_outside) { - if (mpi::master) warning("Fission source site(s) outside of entropy box."); + if (mpi::master) + warning("Fission source site(s) outside of entropy box."); } if (mpi::master) { @@ -524,7 +556,7 @@ void shannon_entropy() double H = 0.0; for (auto p_i : p) { if (p_i > 0.0) { - H -= p_i * std::log(p_i)/std::log(2.0); + H -= p_i * std::log(p_i) / std::log(2.0); } } @@ -547,8 +579,9 @@ void ufs_count_sites() } else { // count number of source sites in each ufs mesh cell bool sites_outside; - simulation::source_frac = simulation::ufs_mesh->count_sites( - simulation::source_bank.data(), simulation::source_bank.size(), &sites_outside); + simulation::source_frac = + simulation::ufs_mesh->count_sites(simulation::source_bank.data(), + simulation::source_bank.size(), &sites_outside); // Check for sites outside of the mesh if (mpi::master && sites_outside) { @@ -557,8 +590,9 @@ void ufs_count_sites() #ifdef OPENMC_MPI // Send source fraction to all processors - int n_bins = xt::prod(simulation::ufs_mesh->shape_)(); - MPI_Bcast(simulation::source_frac.data(), n_bins, MPI_DOUBLE, 0, mpi::intracomm); + int n_bins = simulation::ufs_mesh->n_bins(); + MPI_Bcast( + simulation::source_frac.data(), n_bins, MPI_DOUBLE, 0, mpi::intracomm); #endif // Normalize to total weight to get fraction of source in each cell @@ -583,8 +617,8 @@ double ufs_get_weight(const Particle& p) } if (simulation::source_frac(mesh_bin) != 0.0) { - return simulation::ufs_mesh->volume_frac_ - / simulation::source_frac(mesh_bin); + return simulation::ufs_mesh->volume_frac_ / + simulation::source_frac(mesh_bin); } else { return 1.0; } @@ -609,7 +643,7 @@ void write_eigenvalue_hdf5(hid_t group) void read_eigenvalue_hdf5(hid_t group) { read_dataset(group, "generations_per_batch", settings::gen_per_batch); - int n = simulation::restart_batch*settings::gen_per_batch; + int n = simulation::restart_batch * settings::gen_per_batch; simulation::k_generation.resize(n); read_dataset(group, "k_generation", simulation::k_generation); if (settings::entropy_on) { diff --git a/src/endf.cpp b/src/endf.cpp index eb7e00e2801..c0c1d2e7e8b 100644 --- a/src/endf.cpp +++ b/src/endf.cpp @@ -26,24 +26,35 @@ Interpolation int2interp(int i) // should be accounted for in the distribution classes somehow. switch (i) { - case 1: case 11: case 21: + case 1: + case 11: + case 21: return Interpolation::histogram; - case 2: case 12: case 22: + case 2: + case 12: + case 22: return Interpolation::lin_lin; - case 3: case 13: case 23: + case 3: + case 13: + case 23: return Interpolation::lin_log; - case 4: case 14: case 24: + case 4: + case 14: + case 24: return Interpolation::log_lin; - case 5: case 15: case 25: + case 5: + case 15: + case 25: return Interpolation::log_log; default: - throw std::runtime_error{"Invalid interpolation code."}; + throw std::runtime_error {"Invalid interpolation code."}; } } bool is_fission(int mt) { - return mt == N_FISSION || mt == N_F || mt == N_NF || mt == N_2NF || mt == N_3NF; + return mt == N_FISSION || mt == N_F || mt == N_NF || mt == N_2NF || + mt == N_3NF; } bool is_disappearance(int mt) @@ -52,8 +63,8 @@ bool is_disappearance(int mt) return true; } else if (mt >= N_P0 && mt <= N_AC) { return true; - } else if (mt == N_TA || mt == N_DT || mt == N_P3HE || mt == N_D3HE - || mt == N_3HEA || mt == N_3P) { + } else if (mt == N_TA || mt == N_DT || mt == N_P3HE || mt == N_D3HE || + mt == N_3HEA || mt == N_3P) { return true; } else { return false; @@ -79,23 +90,25 @@ bool is_inelastic_scatter(int mt) unique_ptr read_function(hid_t group, const char* name) { - hid_t dset = open_dataset(group, name); + hid_t obj_id = open_object(group, name); std::string func_type; - read_attribute(dset, "type", func_type); + read_attribute(obj_id, "type", func_type); unique_ptr func; if (func_type == "Tabulated1D") { - func = make_unique(dset); + func = make_unique(obj_id); } else if (func_type == "Polynomial") { - func = make_unique(dset); + func = make_unique(obj_id); } else if (func_type == "CoherentElastic") { - func = make_unique(dset); + func = make_unique(obj_id); } else if (func_type == "IncoherentElastic") { - func = make_unique(dset); + func = make_unique(obj_id); + } else if (func_type == "Sum") { + func = make_unique(obj_id); } else { - throw std::runtime_error{"Unknown function type " + func_type + - " for dataset " + object_name(dset)}; + throw std::runtime_error {"Unknown function type " + func_type + + " for dataset " + object_name(obj_id)}; } - close_dataset(dset); + close_object(obj_id); return func; } @@ -115,7 +128,7 @@ double Polynomial::operator()(double x) const // ordered in increasing powers of x. double y = 0.0; for (auto c = coef_.crbegin(); c != coef_.crend(); ++c) { - y = y*x + *c; + y = y * x + *c; } return y; } @@ -130,7 +143,8 @@ Tabulated1D::Tabulated1D(hid_t dset) n_regions_ = nbt_.size(); // Change 1-indexing to 0-indexing - for (auto& b : nbt_) --b; + for (auto& b : nbt_) + --b; vector int_temp; read_attribute(dset, "interpolation", int_temp); @@ -179,7 +193,8 @@ double Tabulated1D::operator()(double x) const } // handle special case of histogram interpolation - if (interp == Interpolation::histogram) return y_[i]; + if (interp == Interpolation::histogram) + return y_[i]; // determine bounding values double x0 = x_[i]; @@ -191,19 +206,19 @@ double Tabulated1D::operator()(double x) const double r; switch (interp) { case Interpolation::lin_lin: - r = (x - x0)/(x1 - x0); - return y0 + r*(y1 - y0); + r = (x - x0) / (x1 - x0); + return y0 + r * (y1 - y0); case Interpolation::lin_log: - r = log(x/x0)/log(x1/x0); - return y0 + r*(y1 - y0); + r = log(x / x0) / log(x1 / x0); + return y0 + r * (y1 - y0); case Interpolation::log_lin: - r = (x - x0)/(x1 - x0); - return y0*exp(r*log(y1/y0)); + r = (x - x0) / (x1 - x0); + return y0 * exp(r * log(y1 / y0)); case Interpolation::log_log: - r = log(x/x0)/log(x1/x0); - return y0*exp(r*log(y1/y0)); + r = log(x / x0) / log(x1 / x0); + return y0 * exp(r * log(y1 / y0)); default: - throw std::runtime_error{"Invalid interpolation scheme."}; + throw std::runtime_error {"Invalid interpolation scheme."}; } } @@ -233,7 +248,8 @@ double CoherentElasticXS::operator()(double E) const // section will be zero return 0.0; } else { - auto i_grid = lower_bound_index(bragg_edges_.begin(), bragg_edges_.end(), E); + auto i_grid = + lower_bound_index(bragg_edges_.begin(), bragg_edges_.end(), E); return factors_[i_grid] / E; } } @@ -254,7 +270,33 @@ double IncoherentElasticXS::operator()(double E) const { // Determine cross section using ENDF-102, Eq. (7.5) double W = debye_waller_; - return bound_xs_ / 2.0 * ((1 - std::exp(-4.0*E*W))/(2.0*E*W)); + return bound_xs_ / 2.0 * ((1 - std::exp(-4.0 * E * W)) / (2.0 * E * W)); +} + +//============================================================================== +// Sum1D implementation +//============================================================================== + +Sum1D::Sum1D(hid_t group) +{ + // Get number of functions + int n; + read_attribute(group, "n", n); + + // Get each function + for (int i = 0; i < n; ++i) { + auto dset_name = fmt::format("func_{}", i + 1); + functions_.push_back(read_function(group, dset_name.c_str())); + } +} + +double Sum1D::operator()(double x) const +{ + double result = 0.0; + for (auto& func : functions_) { + result += (*func)(x); + } + return result; } } // namespace openmc diff --git a/src/error.cpp b/src/error.cpp index d44e8766e63..566950a973c 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -3,7 +3,8 @@ #include "openmc/message_passing.h" #include "openmc/settings.h" -#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) || defined(__unix) || \ + (defined(__APPLE__) && defined(__MACH__)) #include // for isatty #endif @@ -98,7 +99,8 @@ void warning(const std::string& message) void write_message(const std::string& message, int level) { // Only allow master to print to screen - if (!mpi::master) return; + if (!mpi::master) + return; if (level <= settings::verbosity) { std::cout << " "; diff --git a/src/event.cpp b/src/event.cpp index 895b1d62e6a..ae914c8be34 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -51,7 +51,7 @@ void dispatch_xs_event(int64_t buffer_idx) { Particle& p = simulation::particles[buffer_idx]; if (p.material() == MATERIAL_VOID || - !model::materials[p.material()]->fissionable_) { + !model::materials[p.material()]->fissionable()) { simulation::calculate_nonfuel_xs_queue.thread_safe_append({p, buffer_idx}); } else { simulation::calculate_fuel_xs_queue.thread_safe_append({p, buffer_idx}); @@ -61,7 +61,7 @@ void dispatch_xs_event(int64_t buffer_idx) void process_init_events(int64_t n_particles, int64_t source_offset) { simulation::time_event_init.start(); - #pragma omp parallel for schedule(runtime) +#pragma omp parallel for schedule(runtime) for (int64_t i = 0; i < n_particles; i++) { initialize_history(simulation::particles[i], source_offset + i + 1); dispatch_xs_event(i); @@ -79,11 +79,13 @@ void process_calculate_xs_events(SharedArray& queue) // to C++17, std::sort is a serial only operation, which in this case // makes it too slow to be practical for most test problems. // - // std::sort(std::execution::par_unseq, queue.data(), queue.data() + queue.size()); + // std::sort(std::execution::par_unseq, queue.data(), queue.data() + + // queue.size()); - int64_t offset = simulation::advance_particle_queue.size();; + int64_t offset = simulation::advance_particle_queue.size(); + ; - #pragma omp parallel for schedule(runtime) +#pragma omp parallel for schedule(runtime) for (int64_t i = 0; i < queue.size(); i++) { Particle* p = &simulation::particles[queue[i].idx]; p->event_calculate_xs(); @@ -105,11 +107,13 @@ void process_advance_particle_events() { simulation::time_event_advance_particle.start(); - #pragma omp parallel for schedule(runtime) +#pragma omp parallel for schedule(runtime) for (int64_t i = 0; i < simulation::advance_particle_queue.size(); i++) { int64_t buffer_idx = simulation::advance_particle_queue[i].idx; Particle& p = simulation::particles[buffer_idx]; p.event_advance(); + if (!p.alive()) + continue; if (p.collision_distance() > p.boundary().distance) { simulation::surface_crossing_queue.thread_safe_append({p, buffer_idx}); } else { @@ -126,7 +130,7 @@ void process_surface_crossing_events() { simulation::time_event_surface_crossing.start(); - #pragma omp parallel for schedule(runtime) +#pragma omp parallel for schedule(runtime) for (int64_t i = 0; i < simulation::surface_crossing_queue.size(); i++) { int64_t buffer_idx = simulation::surface_crossing_queue[i].idx; Particle& p = simulation::particles[buffer_idx]; @@ -145,7 +149,7 @@ void process_collision_events() { simulation::time_event_collision.start(); - #pragma omp parallel for schedule(runtime) +#pragma omp parallel for schedule(runtime) for (int64_t i = 0; i < simulation::collision_queue.size(); i++) { int64_t buffer_idx = simulation::collision_queue[i].idx; Particle& p = simulation::particles[buffer_idx]; @@ -163,7 +167,7 @@ void process_collision_events() void process_death_events(int64_t n_particles) { simulation::time_event_death.start(); - #pragma omp parallel for schedule(runtime) +#pragma omp parallel for schedule(runtime) for (int64_t i = 0; i < n_particles; i++) { Particle& p = simulation::particles[i]; p.event_death(); diff --git a/vendor/faddeeva/Faddeeva.cc b/src/external/Faddeeva.cc similarity index 99% rename from vendor/faddeeva/Faddeeva.cc rename to src/external/Faddeeva.cc index 80e42228c11..6a7051e2498 100644 --- a/vendor/faddeeva/Faddeeva.cc +++ b/src/external/Faddeeva.cc @@ -157,7 +157,7 @@ #ifdef __cplusplus -# include "Faddeeva.hh" +# include "openmc/external/Faddeeva.hh" # include # include diff --git a/src/external/LICENSE b/src/external/LICENSE new file mode 100644 index 00000000000..ac09c7fcb77 --- /dev/null +++ b/src/external/LICENSE @@ -0,0 +1,32 @@ +The quartic solver was obtained from the paper: Alberto Giacomo Orellana and +Cristiano De Michele, "Algorithm 1010: Boosting Efficiency in Solving Quartic +Equations with No Compromise in Accuracy," ACM Transactions on Mathematical +Software, 46 (2), pp. 1-28. https://doi.org/10.1145/3386241 + +OpenMC developers contacted the authors, who have agreed to license their +software under the simplified BSD license, reproduced below: + +------------------------------------------------------------------------------- +Copyright (c) 2020 Alberto Giacomo Orellana and Cristiano De Michele +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE PYNE DEVELOPMENT TEAM ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/external/quartic_solver.cpp b/src/external/quartic_solver.cpp new file mode 100644 index 00000000000..0b280e83c29 --- /dev/null +++ b/src/external/quartic_solver.cpp @@ -0,0 +1,574 @@ +#include +#include +#include +#include +#include + +namespace oqs { + +// pow(DBL_MAX,1.0/3.0)/1.618034; +constexpr double CUBIC_RESCAL_FACT = 3.488062113727083e+102; +// pow(DBL_MAX,1.0/4.0)/1.618034; +constexpr double QUART_RESCAL_FACT = 7.156344627944542e+76; +constexpr double MACHEPS = std::numeric_limits::epsilon(); + +double solve_cubic_analytic_depressed_handle_inf(double b, double c) +{ + /* find analytically the dominant root of a depressed cubic x^3+b*x+c + * where coefficients b and c are large (see sec. 2.2 in the manuscript) */ + double Q = -b / 3.0; + double R = 0.5 * c; + if (R == 0) { + return (b <= 0) ? std::sqrt(-b) : 0; + } + + double KK; + if (std::abs(Q) < std::abs(R)) { + double QR = Q / R; + double QRSQ = QR * QR; + KK = 1.0 - Q * QRSQ; + } else { + double RQ = R / Q; + KK = std::copysign(1.0, Q) * (RQ * RQ / Q - 1.0); + } + + if (KK < 0.0) { + double sqrtQ = std::sqrt(Q); + double theta = std::acos((R / std::abs(Q)) / sqrtQ); + if (2.0 * theta < M_PI) + return -2.0 * sqrtQ * std::cos(theta / 3.0); + else + return -2.0 * sqrtQ * std::cos((theta + 2.0 * M_PI) / 3.0); + } else { + double A; + if (std::abs(Q) < std::abs(R)) + A = -std::copysign(1.0, R) * cbrt(std::abs(R) * (1.0 + std::sqrt(KK))); + else { + A = -std::copysign(1.0, R) * + cbrt( + std::abs(R) + std::sqrt(std::abs(Q)) * std::abs(Q) * std::sqrt(KK)); + } + double B = (A == 0.0) ? 0.0 : Q / A; + return A + B; + } +} + +double solve_cubic_analytic_depressed(double b, double c) +{ + /* find analytically the dominant root of a depressed cubic x^3+b*x+c + * (see sec. 2.2 in the manuscript) */ + double Q = -b / 3.0; + double R = 0.5 * c; + if (std::abs(Q) > 1e102 || std::abs(R) > 1e154) { + return oqs::solve_cubic_analytic_depressed_handle_inf(b, c); + } + double Q3 = Q * Q * Q; + double R2 = R * R; + if (R2 < Q3) { + double theta = std::acos(R / std::sqrt(Q3)); + double sqrtQ = -2.0 * std::sqrt(Q); + if (2.0 * theta < M_PI) + return sqrtQ * std::cos(theta / 3.0); + else + return sqrtQ * std::cos((theta + 2.0 * M_PI) / 3.0); + } else { + double A = -std::copysign(1.0, R) * + std::pow(std::abs(R) + std::sqrt(R2 - Q3), 1.0 / 3.0); + double B = (A == 0.0) ? 0.0 : Q / A; + return A + B; /* this is always largest root even if A=B */ + } +} + +double calc_phi0(double a, double b, double c, double d, int scaled) +{ + /* find phi0 as the dominant root of the depressed and shifted cubic + * in eq. (79) (see also the discussion in sec. 2.2 of the manuscript) */ + double diskr = 9 * a * a - 24 * b; + /* eq. (87) */ + double s; + if (diskr > 0.0) { + diskr = std::sqrt(diskr); + s = -2 * b / (3 * a + std::copysign(diskr, a)); + } else { + s = -a / 4; + } + /* eqs. (83) */ + double aq = a + 4 * s; + double bq = b + 3 * s * (a + 2 * s); + double cq = c + s * (2 * b + s * (3 * a + 4 * s)); + double dq = d + s * (c + s * (b + s * (a + s))); + double gg = bq * bq / 9; + double hh = aq * cq; + + double g = hh - 4 * dq - 3 * gg; /* eq. (85) */ + double h = + (8 * dq + hh - 2 * gg) * bq / 3 - cq * cq - dq * aq * aq; /* eq. (86) */ + double rmax = oqs::solve_cubic_analytic_depressed(g, h); + if (std::isnan(rmax) || std::isinf(rmax)) { + rmax = oqs::solve_cubic_analytic_depressed_handle_inf(g, h); + if ((std::isnan(rmax) || std::isinf(rmax)) && scaled) { + // try harder: rescale also the depressed cubic if quartic has been + // already rescaled + double rfact = CUBIC_RESCAL_FACT; + double rfactsq = rfact * rfact; + double ggss = gg / rfactsq; + double hhss = hh / rfactsq; + double dqss = dq / rfactsq; + double aqs = aq / rfact; + double bqs = bq / rfact; + double cqs = cq / rfact; + ggss = bqs * bqs / 9.0; + hhss = aqs * cqs; + g = hhss - 4.0 * dqss - 3.0 * ggss; + h = (8.0 * dqss + hhss - 2.0 * ggss) * bqs / 3 - cqs * (cqs / rfact) - + (dq / rfact) * aqs * aqs; + rmax = oqs::solve_cubic_analytic_depressed(g, h); + if (std::isnan(rmax) || std::isinf(rmax)) { + rmax = oqs::solve_cubic_analytic_depressed_handle_inf(g, h); + } + rmax *= rfact; + } + } + /* Newton-Raphson used to refine phi0 (see end of sec. 2.2 in the manuscript) + */ + double x = rmax; + double xsq = x * x; + double xxx = x * xsq; + double gx = g * x; + double f = x * (xsq + g) + h; + double maxtt = std::max(std::abs(xxx), std::abs(gx)); + if (std::abs(h) > maxtt) + maxtt = std::abs(h); + + if (std::abs(f) > MACHEPS * maxtt) { + for (int iter = 0; iter < 8; iter++) { + double df = 3.0 * xsq + g; + if (df == 0) { + break; + } + double xold = x; + x += -f / df; + double fold = f; + xsq = x * x; + f = x * (xsq + g) + h; + if (f == 0) { + break; + } + + if (std::abs(f) >= std::abs(fold)) { + x = xold; + break; + } + } + } + return x; +} + +double calc_err_ldlt( + double b, double c, double d, double d2, double l1, double l2, double l3) +{ + /* Eqs. (29) and (30) in the manuscript */ + double sum = (b == 0) ? std::abs(d2 + l1 * l1 + 2.0 * l3) + : std::abs(((d2 + l1 * l1 + 2.0 * l3) - b) / b); + sum += (c == 0) ? std::abs(2.0 * d2 * l2 + 2.0 * l1 * l3) + : std::abs(((2.0 * d2 * l2 + 2.0 * l1 * l3) - c) / c); + sum += (d == 0) ? std::abs(d2 * l2 * l2 + l3 * l3) + : std::abs(((d2 * l2 * l2 + l3 * l3) - d) / d); + return sum; +} + +double calc_err_abcd_cmplx(double a, double b, double c, double d, + std::complex aq, std::complex bq, std::complex cq, + std::complex dq) +{ + /* Eqs. (68) and (69) in the manuscript for complex alpha1 (aq), beta1 (bq), + * alpha2 (cq) and beta2 (dq) */ + double sum = (d == 0) ? std::abs(bq * dq) : std::abs((bq * dq - d) / d); + sum += (c == 0) ? std::abs(bq * cq + aq * dq) + : std::abs(((bq * cq + aq * dq) - c) / c); + sum += (b == 0) ? std::abs(bq + aq * cq + dq) + : std::abs(((bq + aq * cq + dq) - b) / b); + sum += (a == 0) ? std::abs(aq + cq) : std::abs(((aq + cq) - a) / a); + return sum; +} +double calc_err_abcd(double a, double b, double c, double d, double aq, + double bq, double cq, double dq) +{ + /* Eqs. (68) and (69) in the manuscript for real alpha1 (aq), beta1 (bq), + * alpha2 (cq) and beta2 (dq)*/ + double sum = (d == 0) ? std::abs(bq * dq) : std::abs((bq * dq - d) / d); + sum += (c == 0) ? std::abs(bq * cq + aq * dq) + : std::abs(((bq * cq + aq * dq) - c) / c); + sum += (b == 0) ? std::abs(bq + aq * cq + dq) + : std::abs(((bq + aq * cq + dq) - b) / b); + sum += (a == 0) ? std::abs(aq + cq) : std::abs(((aq + cq) - a) / a); + return sum; +} + +double calc_err_abc( + double a, double b, double c, double aq, double bq, double cq, double dq) +{ + /* Eqs. (48)-(51) in the manuscript */ + double sum = (c == 0) ? std::abs(bq * cq + aq * dq) + : std::abs(((bq * cq + aq * dq) - c) / c); + sum += (b == 0) ? std::abs(bq + aq * cq + dq) + : std::abs(((bq + aq * cq + dq) - b) / b); + sum += (a == 0) ? std::abs(aq + cq) : std::abs(((aq + cq) - a) / a); + return sum; +} +void NRabcd(double a, double b, double c, double d, double* AQ, double* BQ, + double* CQ, double* DQ) +{ + /* Newton-Raphson described in sec. 2.3 of the manuscript for complex + * coefficients a,b,c,d */ + double xold[4], x[4], dx[4], det, Jinv[4][4], fvec[4], vr[4]; + x[0] = *AQ; + x[1] = *BQ; + x[2] = *CQ; + x[3] = *DQ; + vr[0] = d; + vr[1] = c; + vr[2] = b; + vr[3] = a; + fvec[0] = x[1] * x[3] - d; + fvec[1] = x[1] * x[2] + x[0] * x[3] - c; + fvec[2] = x[1] + x[0] * x[2] + x[3] - b; + fvec[3] = x[0] + x[2] - a; + double errf = 0; + for (int k1 = 0; k1 < 4; k1++) { + errf += (vr[k1] == 0) ? std::abs(fvec[k1]) : std::abs(fvec[k1] / vr[k1]); + } + for (int iter = 0; iter < 8; iter++) { + double x02 = x[0] - x[2]; + det = x[1] * x[1] + x[1] * (-x[2] * x02 - 2.0 * x[3]) + + x[3] * (x[0] * x02 + x[3]); + if (det == 0.0) + break; + Jinv[0][0] = x02; + Jinv[0][1] = x[3] - x[1]; + Jinv[0][2] = x[1] * x[2] - x[0] * x[3]; + Jinv[0][3] = -x[1] * Jinv[0][1] - x[0] * Jinv[0][2]; + Jinv[1][0] = x[0] * Jinv[0][0] + Jinv[0][1]; + Jinv[1][1] = -x[1] * Jinv[0][0]; + Jinv[1][2] = -x[1] * Jinv[0][1]; + Jinv[1][3] = -x[1] * Jinv[0][2]; + Jinv[2][0] = -Jinv[0][0]; + Jinv[2][1] = -Jinv[0][1]; + Jinv[2][2] = -Jinv[0][2]; + Jinv[2][3] = Jinv[0][2] * x[2] + Jinv[0][1] * x[3]; + Jinv[3][0] = -x[2] * Jinv[0][0] - Jinv[0][1]; + Jinv[3][1] = Jinv[0][0] * x[3]; + Jinv[3][2] = x[3] * Jinv[0][1]; + Jinv[3][3] = x[3] * Jinv[0][2]; + for (int k1 = 0; k1 < 4; k1++) { + dx[k1] = 0; + for (int k2 = 0; k2 < 4; k2++) + dx[k1] += Jinv[k1][k2] * fvec[k2]; + } + for (int k1 = 0; k1 < 4; k1++) + xold[k1] = x[k1]; + + for (int k1 = 0; k1 < 4; k1++) { + x[k1] += -dx[k1] / det; + } + fvec[0] = x[1] * x[3] - d; + fvec[1] = x[1] * x[2] + x[0] * x[3] - c; + fvec[2] = x[1] + x[0] * x[2] + x[3] - b; + fvec[3] = x[0] + x[2] - a; + double errfold = errf; + errf = 0; + for (int k1 = 0; k1 < 4; k1++) { + errf += (vr[k1] == 0) ? std::abs(fvec[k1]) : std::abs(fvec[k1] / vr[k1]); + } + if (errf == 0) + break; + if (errf >= errfold) { + for (int k1 = 0; k1 < 4; k1++) + x[k1] = xold[k1]; + break; + } + } + *AQ = x[0]; + *BQ = x[1]; + *CQ = x[2]; + *DQ = x[3]; +} + +void solve_quadratic(double a, double b, std::complex roots[2]) +{ + double diskr = a * a - 4 * b; + if (diskr >= 0.0) { + double div = -a - std::copysign(std::sqrt(diskr), a); + double zmax = div / 2; + double zmin = (zmax == 0.0) ? 0.0 : b / zmax; + + roots[0] = std::complex(zmax, 0.0); + roots[1] = std::complex(zmin, 0.0); + } else { + double sqrtd = std::sqrt(-diskr); + roots[0] = std::complex(-a / 2, sqrtd / 2); + roots[1] = std::complex(-a / 2, -sqrtd / 2); + } +} + +void quartic_solver(double coeff[5], std::complex roots[4]) +{ + /* USAGE: + * + * This routine calculates the roots of the quartic equation + * + * coeff[4]*x^4 + coeff[3]*x^3 + coeff[2]*x^2 + coeff[1]*x + coeff[0] = 0 + * + * if coeff[4] != 0 + * + * the four roots will be stored in the complex array roots[] + * + * */ + std::complex acx, bcx, ccx, dcx; + double l2m[12], d2m[12], res[12]; + double errv[3], aqv[3], cqv[3]; + int realcase[2]; + + double a = coeff[3] / coeff[4]; + double b = coeff[2] / coeff[4]; + double c = coeff[1] / coeff[4]; + double d = coeff[0] / coeff[4]; + double phi0 = oqs::calc_phi0(a, b, c, d, 0); + + // simple polynomial rescaling + double rfact = 1.0; + if (std::isnan(phi0) || std::isinf(phi0)) { + rfact = QUART_RESCAL_FACT; + a /= rfact; + double rfactsq = rfact * rfact; + b /= rfactsq; + c /= rfactsq * rfact; + d /= rfactsq * rfactsq; + phi0 = oqs::calc_phi0(a, b, c, d, 1); + } + double l1 = a / 2; /* eq. (16) */ + double l3 = b / 6 + phi0 / 2; /* eq. (18) */ + double del2 = c - a * l3; /* defined just after eq. (27) */ + int nsol = 0; + double bl311 = + 2. * b / 3. - phi0 - l1 * l1; /* This is d2 as defined in eq. (20)*/ + double dml3l3 = + d - l3 * l3; /* dml3l3 is d3 as defined in eq. (15) with d2=0 */ + + /* Three possible solutions for d2 and l2 (see eqs. (28) and discussion which + * follows) */ + if (bl311 != 0.0) { + d2m[nsol] = bl311; + l2m[nsol] = del2 / (2.0 * d2m[nsol]); + res[nsol] = oqs::calc_err_ldlt(b, c, d, d2m[nsol], l1, l2m[nsol], l3); + nsol++; + } + if (del2 != 0) { + l2m[nsol] = 2 * dml3l3 / del2; + if (l2m[nsol] != 0) { + d2m[nsol] = del2 / (2 * l2m[nsol]); + res[nsol] = oqs::calc_err_ldlt(b, c, d, d2m[nsol], l1, l2m[nsol], l3); + nsol++; + } + + d2m[nsol] = bl311; + l2m[nsol] = 2.0 * dml3l3 / del2; + res[nsol] = oqs::calc_err_ldlt(b, c, d, d2m[nsol], l1, l2m[nsol], l3); + nsol++; + } + + double l2, d2; + if (nsol == 0) { + l2 = d2 = 0.0; + } else { + /* we select the (d2,l2) pair which minimizes errors */ + double resmin; + int kmin; + for (int k1 = 0; k1 < nsol; k1++) { + if (k1 == 0 || res[k1] < resmin) { + resmin = res[k1]; + kmin = k1; + } + } + d2 = d2m[kmin]; + l2 = l2m[kmin]; + } + int whichcase = 0; + double aq, bq, cq, dq; + if (d2 < 0.0) { + /* Case I eqs. (37)-(40) */ + double gamma = std::sqrt(-d2); + aq = l1 + gamma; + bq = l3 + gamma * l2; + + cq = l1 - gamma; + dq = l3 - gamma * l2; + if (std::abs(dq) < std::abs(bq)) + dq = d / bq; + else if (std::abs(dq) > std::abs(bq)) + bq = d / dq; + if (std::abs(aq) < std::abs(cq)) { + nsol = 0; + if (dq != 0) { + aqv[nsol] = (c - bq * cq) / dq; /* see eqs. (47) */ + errv[nsol] = oqs::calc_err_abc(a, b, c, aqv[nsol], bq, cq, dq); + nsol++; + } + if (cq != 0) { + aqv[nsol] = (b - dq - bq) / cq; /* see eqs. (47) */ + errv[nsol] = oqs::calc_err_abc(a, b, c, aqv[nsol], bq, cq, dq); + nsol++; + } + aqv[nsol] = a - cq; /* see eqs. (47) */ + errv[nsol] = oqs::calc_err_abc(a, b, c, aqv[nsol], bq, cq, dq); + nsol++; + /* we select the value of aq (i.e. alpha1 in the manuscript) which + * minimizes errors */ + double errmin; + int kmin; + for (int k = 0; k < nsol; k++) { + if (k == 0 || errv[k] < errmin) { + kmin = k; + errmin = errv[k]; + } + } + aq = aqv[kmin]; + } else { + nsol = 0; + if (bq != 0) { + cqv[nsol] = (c - aq * dq) / bq; /* see eqs. (53) */ + errv[nsol] = oqs::calc_err_abc(a, b, c, aq, bq, cqv[nsol], dq); + nsol++; + } + if (aq != 0) { + cqv[nsol] = (b - bq - dq) / aq; /* see eqs. (53) */ + errv[nsol] = oqs::calc_err_abc(a, b, c, aq, bq, cqv[nsol], dq); + nsol++; + } + cqv[nsol] = a - aq; /* see eqs. (53) */ + errv[nsol] = oqs::calc_err_abc(a, b, c, aq, bq, cqv[nsol], dq); + nsol++; + /* we select the value of cq (i.e. alpha2 in the manuscript) which + * minimizes errors */ + double errmin; + int kmin; + for (int k = 0; k < nsol; k++) { + if (k == 0 || errv[k] < errmin) { + kmin = k; + errmin = errv[k]; + } + } + cq = cqv[kmin]; + } + realcase[0] = 1; + } else if (d2 > 0) { + /* Case II eqs. (53)-(56) */ + double gamma = std::sqrt(d2); + acx = std::complex(l1, gamma); + bcx = std::complex(l3, gamma * l2); + ccx = std::conj(acx); + dcx = std::conj(bcx); + realcase[0] = 0; + } else + realcase[0] = -1; // d2=0 + /* Case III: d2 is 0 or approximately 0 (in this case check which solution is + * better) */ + if (realcase[0] == -1 || + (std::abs(d2) <= + MACHEPS * (std::abs(2. * b / 3.) + std::abs(phi0) + l1 * l1))) { + double d3 = d - l3 * l3; + double err0 = 0.0; + if (realcase[0] == 1) + err0 = oqs::calc_err_abcd(a, b, c, d, aq, bq, cq, dq); + else if (realcase[0] == 0) + err0 = oqs::calc_err_abcd_cmplx(a, b, c, d, acx, bcx, ccx, dcx); + double aq1, bq1, cq1, dq1; + std::complex acx1, bcx1, ccx1, dcx1; + double err1 = 0.0; + if (d3 <= 0) { + realcase[1] = 1; + aq1 = l1; + bq1 = l3 + std::sqrt(-d3); + cq1 = l1; + dq1 = l3 - std::sqrt(-d3); + if (std::abs(dq1) < std::abs(bq1)) + dq1 = d / bq1; + else if (std::abs(dq1) > std::abs(bq1)) + bq1 = d / dq1; + err1 = oqs::calc_err_abcd(a, b, c, d, aq1, bq1, cq1, dq1); /* eq. (68) */ + } else { + /* complex */ + realcase[1] = 0; + acx1 = l1; + bcx1 = l3 + std::complex(0., std::sqrt(d3)); + ccx1 = l1; + dcx1 = std::conj(bcx1); + err1 = oqs::calc_err_abcd_cmplx(a, b, c, d, acx1, bcx1, ccx1, dcx1); + } + if (realcase[0] == -1 || err1 < err0) { + whichcase = 1; // d2 = 0 + if (realcase[1] == 1) { + aq = aq1; + bq = bq1; + cq = cq1; + dq = dq1; + } else { + acx = acx1; + bcx = bcx1; + ccx = ccx1; + dcx = dcx1; + } + } + } + if (realcase[whichcase] == 1) { + /* if alpha1, beta1, alpha2 and beta2 are real first refine + * the coefficient through a Newton-Raphson */ + oqs::NRabcd(a, b, c, d, &aq, &bq, &cq, &dq); + /* finally calculate the roots as roots of p1(x) and p2(x) (see end of + * sec. 2.1) */ + std::complex qroots[2]; + oqs::solve_quadratic(aq, bq, qroots); + roots[0] = qroots[0]; + roots[1] = qroots[1]; + oqs::solve_quadratic(cq, dq, qroots); + roots[2] = qroots[0]; + roots[3] = qroots[1]; + } else { + /* complex coefficients of p1 and p2 */ + if (whichcase == 0) { // d2!=0 + auto cdiskr = 0.25 * acx * acx - bcx; + /* calculate the roots as roots of p1(x) and p2(x) (see end of sec. 2.1) + */ + auto zx1 = -0.5 * acx + std::sqrt(cdiskr); + auto zx2 = -0.5 * acx - std::sqrt(cdiskr); + auto zxmax = (std::abs(zx1) > std::abs(zx2)) ? zx1 : zx2; + auto zxmin = bcx / zxmax; + roots[0] = zxmin; + roots[1] = std::conj(zxmin); + roots[2] = zxmax; + roots[3] = std::conj(zxmax); + } else { // d2 ~ 0 + /* never gets here! */ + auto cdiskr = std::sqrt(acx * acx - 4.0 * bcx); + auto zx1 = -0.5 * (acx + cdiskr); + auto zx2 = -0.5 * (acx - cdiskr); + auto zxmax = (std::abs(zx1) > std::abs(zx2)) ? zx1 : zx2; + auto zxmin = bcx / zxmax; + roots[0] = zxmax; + roots[1] = zxmin; + cdiskr = std::sqrt(ccx * ccx - 4.0 * dcx); + zx1 = -0.5 * (ccx + cdiskr); + zx2 = -0.5 * (ccx - cdiskr); + zxmax = (std::abs(zx1) > std::abs(zx2)) ? zx1 : zx2; + zxmin = dcx / zxmax; + roots[2] = zxmax; + roots[3] = zxmin; + } + } + if (rfact != 1.0) { + for (int k = 0; k < 4; k++) + roots[k] *= rfact; + } +} + +} // namespace oqs diff --git a/src/file_utils.cpp b/src/file_utils.cpp new file mode 100644 index 00000000000..197c9767cb0 --- /dev/null +++ b/src/file_utils.cpp @@ -0,0 +1,65 @@ +#include "openmc/file_utils.h" + +#include // any_of +#include // for isalpha +#include // for ifstream +#include + +namespace openmc { + +bool dir_exists(const std::string& path) +{ + struct stat s; + if (stat(path.c_str(), &s) != 0) + return false; + + return s.st_mode & S_IFDIR; +} + +bool file_exists(const std::string& filename) +{ + // rule out file being a path to a directory + if (dir_exists(filename)) + return false; + + std::ifstream s {filename}; + return s.good(); +} + +std::string dir_name(const std::string& filename) +{ + size_t pos = filename.find_last_of("\\/"); + return (std::string::npos == pos) ? "" : filename.substr(0, pos + 1); +} + +std::string get_file_extension(const std::string& filename) +{ + // try our best to work on windows... +#if defined(_WIN32) || defined(_WIN64) + const char sep_char = '\\'; +#else + const char sep_char = '/'; +#endif + + // check that at least one letter is present + const auto last_period_pos = filename.find_last_of('.'); + const auto last_sep_pos = filename.find_last_of(sep_char); + + // no file extension. In the first case, we are only given + // a file name. In the second, we have been given a file path. + // If that's the case, periods are allowed in directory names, + // but have the interpretation as preceding a file extension + // after the last separator. + if (last_period_pos == std::string::npos || + (last_sep_pos < std::string::npos && last_period_pos < last_sep_pos)) + return ""; + + const std::string ending = filename.substr(last_period_pos + 1); + + // check that at least one character is present. + const bool has_alpha = std::any_of(ending.begin(), ending.end(), + [](char x) { return static_cast(std::isalpha(x)); }); + return has_alpha ? ending : ""; +} + +} // namespace openmc diff --git a/src/finalize.cpp b/src/finalize.cpp index 22dc6718360..26efc9723a5 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -15,15 +15,17 @@ #include "openmc/message_passing.h" #include "openmc/nuclide.h" #include "openmc/photon.h" +#include "openmc/plot.h" #include "openmc/random_lcg.h" #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/source.h" #include "openmc/surface.h" +#include "openmc/tallies/tally.h" #include "openmc/thermal.h" #include "openmc/timer.h" -#include "openmc/tallies/tally.h" #include "openmc/volume_calc.h" +#include "openmc/weight_windows.h" #include "xtensor/xview.hpp" @@ -45,23 +47,25 @@ void free_memory() free_memory_mesh(); free_memory_tally(); free_memory_bank(); + free_memory_plot(); + free_memory_weight_windows(); if (mpi::master) { free_memory_cmfd(); } if (settings::event_based) { free_event_queues(); } -#ifdef DAGMC - free_memory_dagmc(); -#endif } -} +} // namespace openmc using namespace openmc; int openmc_finalize() { + if (simulation::initialized) + openmc_simulation_finalize(); + // Clear results openmc_reset(); @@ -73,24 +77,39 @@ int openmc_finalize() settings::check_overlaps = false; settings::confidence_intervals = false; settings::create_fission_neutrons = true; + settings::create_delayed_neutrons = true; settings::electron_treatment = ElectronTreatment::LED; - settings::dagmc = false; settings::delayed_photon_scaling = true; settings::energy_cutoff = {0.0, 1000.0, 0.0, 0.0}; + settings::time_cutoff = {INFTY, INFTY, INFTY, INFTY}; settings::entropy_on = false; settings::event_based = false; settings::gen_per_batch = 1; settings::legendre_to_tabular = true; settings::legendre_to_tabular_points = -1; settings::material_cell_offsets = true; + settings::max_lost_particles = 10; + settings::max_order = 0; settings::max_particles_in_flight = 100000; + settings::max_particle_events = 1000000; + settings::max_splits = 1000; + settings::max_tracks = 1000; + settings::max_write_lost_particles = -1; + settings::n_log_bins = 8000; settings::n_inactive = 0; settings::n_particles = -1; settings::output_summary = true; settings::output_tallies = true; settings::particle_restart_run = false; + settings::path_cross_sections.clear(); + settings::path_input.clear(); + settings::path_output.clear(); + settings::path_particle_restart.clear(); + settings::path_sourcepoint.clear(); + settings::path_statepoint.clear(); settings::photon_transport = false; settings::reduce_tallies = true; + settings::rel_max_lost_particles = 1.0e-6; settings::res_scat_on = false; settings::res_scat_method = ResScatMethod::rvs; settings::res_scat_energy_min = 0.01; @@ -115,13 +134,13 @@ int openmc_finalize() settings::verbosity = 7; settings::weight_cutoff = 0.25; settings::weight_survive = 1.0; + settings::weight_windows_file.clear(); + settings::weight_windows_on = false; settings::write_all_tracks = false; settings::write_initial_source = false; simulation::keff = 1.0; - simulation::n_lost_particles = 0; simulation::need_depletion_rx = false; - simulation::satisfy_triggers = false; simulation::total_gen = 0; simulation::entropy_mesh = nullptr; @@ -132,6 +151,7 @@ int openmc_finalize() data::temperature_min = 0.0; data::temperature_max = INFTY; model::root_universe = -1; + model::plotter_seed = 1; openmc::openmc_set_seed(DEFAULT_SEED); // Deallocate arrays @@ -143,7 +163,8 @@ int openmc_finalize() // Free all MPI types #ifdef OPENMC_MPI - if (mpi::source_site != MPI_DATATYPE_NULL) MPI_Type_free(&mpi::source_site); + if (mpi::source_site != MPI_DATATYPE_NULL) + MPI_Type_free(&mpi::source_site); #endif return 0; @@ -167,9 +188,12 @@ int openmc_reset() simulation::k_col_tra = 0.0; simulation::k_abs_tra = 0.0; simulation::k_sum = {0.0, 0.0}; + simulation::satisfy_triggers = false; settings::cmfd_run = false; + simulation::n_lost_particles = 0; + return 0; } diff --git a/src/geometry.cpp b/src/geometry.cpp index 59607f637a5..445b19faac1 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -13,14 +13,12 @@ #include "openmc/string_utils.h" #include "openmc/surface.h" - namespace openmc { //============================================================================== // Global variables //============================================================================== - namespace model { int root_universe {-1}; @@ -34,7 +32,7 @@ vector overlap_check_count; // Non-member functions //============================================================================== -bool check_cell_overlap(Particle& p, bool error) +bool check_cell_overlap(GeometryState& p, bool error) { int n_coord = p.n_coord(); @@ -65,8 +63,44 @@ bool check_cell_overlap(Particle& p, bool error) //============================================================================== -bool -find_cell_inner(Particle& p, const NeighborList* neighbor_list) +int cell_instance_at_level(const GeometryState& p, int level) +{ + // throw error if the requested level is too deep for the geometry + if (level > model::n_coord_levels) { + fatal_error(fmt::format("Cell instance at level {} requested, but only {} " + "levels exist in the geometry.", + level, p.n_coord())); + } + + // determine the cell instance + Cell& c {*model::cells[p.coord(level).cell]}; + + // quick exit if this cell doesn't have distribcell instances + if (c.distribcell_index_ == C_NONE) + return C_NONE; + + // compute the cell's instance + int instance = 0; + for (int i = 0; i < level; i++) { + const auto& c_i {*model::cells[p.coord(i).cell]}; + if (c_i.type_ == Fill::UNIVERSE) { + instance += c_i.offset_[c.distribcell_index_]; + } else if (c_i.type_ == Fill::LATTICE) { + instance += c_i.offset_[c.distribcell_index_]; + auto& lat {*model::lattices[p.coord(i + 1).lattice]}; + const auto& i_xyz {p.coord(i + 1).lattice_i}; + if (lat.are_valid_indices(i_xyz)) { + instance += lat.offset(c.distribcell_index_, i_xyz); + } + } + } + return instance; +} + +//============================================================================== + +bool find_cell_inner( + GeometryState& p, const NeighborList* neighbor_list, bool verbose) { // Find which cell of this universe the particle is in. Use the neighbor list // to shorten the search if one was provided. @@ -77,15 +111,16 @@ find_cell_inner(Particle& p, const NeighborList* neighbor_list) i_cell = *it; // Make sure the search cell is in the same universe. - int i_universe = p.coord(p.n_coord() - 1).universe; - if (model::cells[i_cell]->universe_ != i_universe) continue; + int i_universe = p.lowest_coord().universe; + if (model::cells[i_cell]->universe_ != i_universe) + continue; // Check if this cell contains the particle. Position r {p.r_local()}; Direction u {p.u_local()}; auto surf = p.surface(); if (model::cells[i_cell]->contains(r, u, surf)) { - p.coord(p.n_coord() - 1).cell = i_cell; + p.lowest_coord().cell = i_cell; found = true; break; } @@ -101,7 +136,7 @@ find_cell_inner(Particle& p, const NeighborList* neighbor_list) } // Check successively lower coordinate levels until finding material fill - for (;;++p.n_coord()) { + for (;; ++p.n_coord()) { // If we did not attempt to use neighbor lists, i_cell is still C_NONE. In // that case, we should now do an exhaustive search to find the right value // of i_cell. @@ -111,38 +146,18 @@ find_cell_inner(Particle& p, const NeighborList* neighbor_list) // code below this conditional, we set i_cell back to C_NONE to indicate // that. if (i_cell == C_NONE) { - int i_universe = p.coord(p.n_coord() - 1).universe; - const auto& univ {*model::universes[i_universe]}; - const auto& cells { - !univ.partitioner_ - ? model::universes[i_universe]->cells_ - : univ.partitioner_->get_cells(p.r_local(), p.u_local()) - }; - - for (auto it = cells.cbegin(); it != cells.cend(); it++) { - i_cell = *it; - - // Make sure the search cell is in the same universe. - int i_universe = p.coord(p.n_coord() - 1).universe; - if (model::cells[i_cell]->universe_ != i_universe) continue; - - // Check if this cell contains the particle. - Position r {p.r_local()}; - Direction u {p.u_local()}; - auto surf = p.surface(); - if (model::cells[i_cell]->contains(r, u, surf)) { - p.coord(p.n_coord() - 1).cell = i_cell; - found = true; - break; - } - } + int i_universe = p.lowest_coord().universe; + const auto& univ {model::universes[i_universe]}; + found = univ->find_cell(p); } + if (!found) { return found; } + i_cell = p.lowest_coord().cell; // Announce the cell that the particle is entering. - if (found && (settings::verbosity >= 10 || p.trace())) { + if (found && verbose) { auto msg = fmt::format(" Entering cell {}", model::cells[i_cell]->id_); write_message(msg, 1); } @@ -151,37 +166,17 @@ find_cell_inner(Particle& p, const NeighborList* neighbor_list) if (c.type_ == Fill::MATERIAL) { // Found a material cell which means this is the lowest coord level. + p.cell_instance() = 0; // Find the distribcell instance number. - int offset = 0; if (c.distribcell_index_ >= 0) { - for (int i = 0; i < p.n_coord(); i++) { - const auto& c_i {*model::cells[p.coord(i).cell]}; - if (c_i.type_ == Fill::UNIVERSE) { - offset += c_i.offset_[c.distribcell_index_]; - } else if (c_i.type_ == Fill::LATTICE) { - auto& lat {*model::lattices[p.coord(i + 1).lattice]}; - const auto& i_xyz {p.coord(i + 1).lattice_i}; - if (lat.are_valid_indices(i_xyz)) { - offset += lat.offset(c.distribcell_index_, i_xyz); - } - } - } + p.cell_instance() = cell_instance_at_level(p, p.n_coord() - 1); } - p.cell_instance() = offset; // Set the material and temperature. p.material_last() = p.material(); - if (c.material_.size() > 1) { - p.material() = c.material_[p.cell_instance()]; - } else { - p.material() = c.material_[0]; - } + p.material() = c.material(p.cell_instance()); p.sqrtkT_last() = p.sqrtkT(); - if (c.sqrtkT_.size() > 1) { - p.sqrtkT() = c.sqrtkT_[p.cell_instance()]; - } else { - p.sqrtkT() = c.sqrtkT_[0]; - } + p.sqrtkT() = c.sqrtkT(p.cell_instance()); return true; @@ -241,10 +236,9 @@ find_cell_inner(Particle& p, const NeighborList* neighbor_list) if (lat.outer_ != NO_OUTER_UNIVERSE) { coord.universe = lat.outer_; } else { - warning(fmt::format("Particle {} is outside lattice {} but the " - "lattice has no defined outer universe.", + p.mark_as_lost(fmt::format( + "Particle {} left lattice {}, but it has no outer definition.", p.id(), lat.id_)); - return false; } } } @@ -257,7 +251,7 @@ find_cell_inner(Particle& p, const NeighborList* neighbor_list) //============================================================================== -bool neighbor_list_find_cell(Particle& p) +bool neighbor_list_find_cell(GeometryState& p, bool verbose) { // Reset all the deeper coordinate levels. @@ -272,22 +266,22 @@ bool neighbor_list_find_cell(Particle& p) // Search for the particle in that cell's neighbor list. Return if we // found the particle. - bool found = find_cell_inner(p, &c.neighbors_); + bool found = find_cell_inner(p, &c.neighbors_, verbose); if (found) return found; // The particle could not be found in the neighbor list. Try searching all // cells in this universe, and update the neighbor list if we find a new // neighboring cell. - found = find_cell_inner(p, nullptr); + found = find_cell_inner(p, nullptr, verbose); if (found) c.neighbors_.push_back(p.coord(coord_lvl).cell); return found; } -bool exhaustive_find_cell(Particle& p) +bool exhaustive_find_cell(GeometryState& p, bool verbose) { - int i_universe = p.coord(p.n_coord() - 1).universe; + int i_universe = p.lowest_coord().universe; if (i_universe == C_NONE) { p.coord(0).universe = model::root_universe; p.n_coord() = 1; @@ -297,21 +291,22 @@ bool exhaustive_find_cell(Particle& p) for (int i = p.n_coord(); i < model::n_coord_levels; i++) { p.coord(i).reset(); } - return find_cell_inner(p, nullptr); + return find_cell_inner(p, nullptr, verbose); } //============================================================================== -void -cross_lattice(Particle& p, const BoundaryInfo& boundary) +void cross_lattice(GeometryState& p, const BoundaryInfo& boundary, bool verbose) { - auto& coord {p.coord(p.n_coord() - 1)}; + auto& coord {p.lowest_coord()}; auto& lat {*model::lattices[coord.lattice]}; - if (settings::verbosity >= 10 || p.trace()) { - write_message(fmt::format( - " Crossing lattice {}. Current position ({},{},{}). r={}", - lat.id_, coord.lattice_i[0], coord.lattice_i[1], coord.lattice_i[2], p.r()), 1); + if (verbose) { + write_message( + fmt::format(" Crossing lattice {}. Current position ({},{},{}). r={}", + lat.id_, coord.lattice_i[0], coord.lattice_i[1], coord.lattice_i[2], + p.r()), + 1); } // Set the lattice indices. @@ -333,15 +328,16 @@ cross_lattice(Particle& p, const BoundaryInfo& boundary) // The particle is outside the lattice. Search for it from the base coords. p.n_coord() = 1; bool found = exhaustive_find_cell(p); - if (!found && p.alive()) { - p.mark_as_lost(fmt::format("Could not locate particle {} after " - "crossing a lattice boundary", - p.id())); + + if (!found) { + p.mark_as_lost(fmt::format("Particle {} could not be located after " + "crossing a boundary of lattice {}", + p.id(), lat.id_)); } } else { // Find cell in next lattice element. - p.coord(p.n_coord() - 1).universe = lat[coord.lattice_i]; + p.lowest_coord().universe = lat[coord.lattice_i]; bool found = exhaustive_find_cell(p); if (!found) { @@ -349,10 +345,10 @@ cross_lattice(Particle& p, const BoundaryInfo& boundary) // this case, search for it from the base coords. p.n_coord() = 1; bool found = exhaustive_find_cell(p); - if (!found && p.alive()) { - p.mark_as_lost(fmt::format("Could not locate particle {} after " - "crossing a lattice boundary", - p.id())); + if (!found) { + p.mark_as_lost(fmt::format("Particle {} could not be located after " + "crossing a boundary of lattice {}", + p.id(), lat.id_)); } } } @@ -360,7 +356,7 @@ cross_lattice(Particle& p, const BoundaryInfo& boundary) //============================================================================== -BoundaryInfo distance_to_boundary(Particle& p) +BoundaryInfo distance_to_boundary(GeometryState& p) { BoundaryInfo info; double d_lat = INFINITY; @@ -383,30 +379,31 @@ BoundaryInfo distance_to_boundary(Particle& p) // Find the distance to the next lattice tile crossing. if (coord.lattice != C_NONE) { auto& lat {*model::lattices[coord.lattice]}; - //TODO: refactor so both lattice use the same position argument (which - //also means the lat.type attribute can be removed) + // TODO: refactor so both lattice use the same position argument (which + // also means the lat.type attribute can be removed) std::pair> lattice_distance; switch (lat.type_) { - case LatticeType::rect: - lattice_distance = lat.distance(r, u, coord.lattice_i); - break; - case LatticeType::hex: - auto& cell_above {model::cells[p.coord(i - 1).cell]}; - Position r_hex {p.coord(i - 1).r}; - r_hex -= cell_above->translation_; - if (coord.rotated) { - r_hex = r_hex.rotate(cell_above->rotation_); - } - r_hex.z = coord.r.z; - lattice_distance = lat.distance(r_hex, u, coord.lattice_i); - break; + case LatticeType::rect: + lattice_distance = lat.distance(r, u, coord.lattice_i); + break; + case LatticeType::hex: + auto& cell_above {model::cells[p.coord(i - 1).cell]}; + Position r_hex {p.coord(i - 1).r}; + r_hex -= cell_above->translation_; + if (coord.rotated) { + r_hex = r_hex.rotate(cell_above->rotation_); + } + r_hex.z = coord.r.z; + lattice_distance = lat.distance(r_hex, u, coord.lattice_i); + break; } d_lat = lattice_distance.first; level_lat_trans = lattice_distance.second; if (d_lat < 0) { - p.mark_as_lost(fmt::format( - "Particle {} had a negative distance to a lattice boundary", p.id())); + p.mark_as_lost(fmt::format("Particle {} had a negative distance " + "to a lattice boundary.", + p.id())); } } @@ -415,18 +412,19 @@ BoundaryInfo distance_to_boundary(Particle& p) // is selected. This logic must consider floating point precision. double& d = info.distance; if (d_surf < d_lat - FP_COINCIDENT) { - if (d == INFINITY || (d - d_surf)/d >= FP_REL_PRECISION) { + if (d == INFINITY || (d - d_surf) / d >= FP_REL_PRECISION) { + // Update closest distance d = d_surf; // If the cell is not simple, it is possible that both the negative and // positive half-space were given in the region specification. Thus, we // have to explicitly check which half-space the particle would be // traveling into if the surface is crossed - if (c.simple_) { + if (c.is_simple() || d == INFTY) { info.surface_index = level_surf_cross; } else { Position r_hit = r + d_surf * u; - Surface& surf {*model::surfaces[std::abs(level_surf_cross)-1]}; + Surface& surf {*model::surfaces[std::abs(level_surf_cross) - 1]}; Direction norm = surf.normal(r_hit); if (u.dot(norm) > 0) { info.surface_index = std::abs(level_surf_cross); @@ -441,7 +439,7 @@ BoundaryInfo distance_to_boundary(Particle& p) info.coord_level = i + 1; } } else { - if (d == INFINITY || (d - d_lat)/d >= FP_REL_PRECISION) { + if (d == INFINITY || (d - d_lat) / d >= FP_REL_PRECISION) { d = d_lat; info.surface_index = 0; info.lattice_translation = level_lat_trans; @@ -456,25 +454,27 @@ BoundaryInfo distance_to_boundary(Particle& p) // C API //============================================================================== -extern "C" int -openmc_find_cell(const double* xyz, int32_t* index, int32_t* instance) +extern "C" int openmc_find_cell( + const double* xyz, int32_t* index, int32_t* instance) { - Particle p; + GeometryState geom_state; - p.r() = Position{xyz}; - p.u() = {0.0, 0.0, 1.0}; + geom_state.r() = Position {xyz}; + geom_state.u() = {0.0, 0.0, 1.0}; - if (!exhaustive_find_cell(p)) { - set_errmsg(fmt::format("Could not find cell at position {}.", p.r())); + if (!exhaustive_find_cell(geom_state)) { + set_errmsg( + fmt::format("Could not find cell at position {}.", geom_state.r())); return OPENMC_E_GEOMETRY; } - *index = p.coord(p.n_coord() - 1).cell; - *instance = p.cell_instance(); + *index = geom_state.lowest_coord().cell; + *instance = geom_state.cell_instance(); return 0; } -extern "C" int openmc_global_bounding_box(double* llc, double* urc) { +extern "C" int openmc_global_bounding_box(double* llc, double* urc) +{ auto bbox = model::universes.at(model::root_universe)->bounding_box(); // set lower left corner values diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 17000129d35..10b239be838 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -1,6 +1,6 @@ #include "openmc/geometry_aux.h" -#include // for std::max +#include // for std::max #include #include @@ -22,17 +22,17 @@ #include "openmc/tallies/filter_cell_instance.h" #include "openmc/tallies/filter_distribcell.h" - namespace openmc { namespace model { - std::unordered_map> universe_cell_counts; - std::unordered_map universe_level_counts; +std::unordered_map> + universe_cell_counts; +std::unordered_map universe_level_counts; } // namespace model - // adds the cell counts of universe b to universe a -void update_universe_cell_count(int32_t a, int32_t b) { +void update_universe_cell_count(int32_t a, int32_t b) +{ auto& universe_a_counts = model::universe_cell_counts[a]; const auto& universe_b_counts = model::universe_cell_counts[b]; for (const auto& it : universe_b_counts) { @@ -42,13 +42,6 @@ void update_universe_cell_count(int32_t a, int32_t b) { void read_geometry_xml() { -#ifdef DAGMC - if (settings::dagmc) { - read_geometry_dagmc(); - return; - } -#endif - // Display output message write_message("Reading geometry XML file...", 5); @@ -68,19 +61,41 @@ void read_geometry_xml() // Get root element pugi::xml_node root = doc.document_element(); + read_geometry_xml(root); +} + +void read_geometry_xml(pugi::xml_node root) +{ // Read surfaces, cells, lattice read_surfaces(root); read_cells(root); read_lattices(root); + // Check to make sure a boundary condition was applied to at least one + // surface + bool boundary_exists = false; + for (const auto& surf : model::surfaces) { + if (surf->bc_) { + boundary_exists = true; + break; + } + } + + if (settings::run_mode != RunMode::PLOTTING && + settings::run_mode != RunMode::VOLUME && !boundary_exists) { + fatal_error("No boundary conditions were applied to any surfaces!"); + } + // Allocate universes, universe cell arrays, and assign base universe model::root_universe = find_root_universe(); + + // if the root universe is DAGMC geometry, make sure the model is well-formed + check_dagmc_root_univ(); } //============================================================================== -void -adjust_indices() +void adjust_indices() { // Adjust material/fill idices. for (auto& c : model::cells) { @@ -96,7 +111,8 @@ adjust_indices() c->fill_ = search_lat->second; } else { fatal_error(fmt::format("Specified fill {} on cell {} is neither a " - "universe nor a lattice.", id, c->id_)); + "universe nor a lattice.", + id, c->id_)); } } else { c->type_ = Fill::MATERIAL; @@ -104,9 +120,9 @@ adjust_indices() if (mat_id != MATERIAL_VOID) { auto search = model::material_map.find(mat_id); if (search == model::material_map.end()) { - fatal_error(fmt::format( - "Could not find material {} specified on cell {}", - mat_id, c->id_)); + fatal_error( + fmt::format("Could not find material {} specified on cell {}", + mat_id, c->id_)); } // Change from ID to index mat_id = search->second; @@ -135,8 +151,7 @@ adjust_indices() //============================================================================== //! Partition some universes with many z-planes for faster find_cell searches. -void -partition_universes() +void partition_universes() { // Iterate over universes with more than 10 cells. (Fewer than 10 is likely // not worth partitioning.) @@ -145,8 +160,8 @@ partition_universes() // Collect the set of surfaces in this universe. std::unordered_set surf_inds; for (auto i_cell : univ->cells_) { - for (auto token : model::cells[i_cell]->rpn_) { - if (token < OP_UNION) surf_inds.insert(std::abs(token) - 1); + for (auto token : model::cells[i_cell]->surfaces()) { + surf_inds.insert(std::abs(token) - 1); } } @@ -168,13 +183,14 @@ partition_universes() //============================================================================== -void -assign_temperatures() +void assign_temperatures() { for (auto& c : model::cells) { // Ignore non-material cells and cells with defined temperature. - if (c->material_.size() == 0) continue; - if (c->sqrtkT_.size() > 0) continue; + if (c->material_.size() == 0) + continue; + if (c->sqrtkT_.size() > 0) + continue; c->sqrtkT_.reserve(c->material_.size()); for (auto i_mat : c->material_) { @@ -196,24 +212,26 @@ void get_temperatures( { for (const auto& cell : model::cells) { // Skip non-material cells. - if (cell->fill_ != C_NONE) continue; + if (cell->fill_ != C_NONE) + continue; for (int j = 0; j < cell->material_.size(); ++j) { // Skip void materials int i_material = cell->material_[j]; - if (i_material == MATERIAL_VOID) continue; + if (i_material == MATERIAL_VOID) + continue; // Get temperature(s) of cell (rounding to nearest integer) vector cell_temps; if (cell->sqrtkT_.size() == 1) { double sqrtkT = cell->sqrtkT_[0]; - cell_temps.push_back(sqrtkT*sqrtkT / K_BOLTZMANN); + cell_temps.push_back(sqrtkT * sqrtkT / K_BOLTZMANN); } else if (cell->sqrtkT_.size() == cell->material_.size()) { double sqrtkT = cell->sqrtkT_[j]; - cell_temps.push_back(sqrtkT*sqrtkT / K_BOLTZMANN); + cell_temps.push_back(sqrtkT * sqrtkT / K_BOLTZMANN); } else { for (double sqrtkT : cell->sqrtkT_) - cell_temps.push_back(sqrtkT*sqrtkT / K_BOLTZMANN); + cell_temps.push_back(sqrtkT * sqrtkT / K_BOLTZMANN); } const auto& mat {model::materials[i_material]}; @@ -257,8 +275,7 @@ void finalize_geometry() //============================================================================== -int32_t -find_root_universe() +int32_t find_root_universe() { // Find all the universes listed as a cell fill. std::unordered_set fill_univ_ids; @@ -292,32 +309,44 @@ find_root_universe() } } } - if (!root_found) fatal_error("Could not find a root universe. Make sure " - "there are no circular dependencies in the geometry."); + if (!root_found) + fatal_error("Could not find a root universe. Make sure " + "there are no circular dependencies in the geometry."); return root_univ; } //============================================================================== -void -prepare_distribcell() +void prepare_distribcell(const std::vector* user_distribcells) { write_message("Preparing distributed cell instances...", 5); - // Find all cells listed in a DistribcellFilter or CellInstanceFilter std::unordered_set distribcells; + + // start with any cells manually specified via the C++ API + if (user_distribcells) { + distribcells.insert(user_distribcells->begin(), user_distribcells->end()); + } + + // Find all cells listed in a DistribcellFilter or CellInstanceFilter for (auto& filt : model::tally_filters) { auto* distrib_filt = dynamic_cast(filt.get()); + auto* cell_inst_filt = dynamic_cast(filt.get()); if (distrib_filt) { distribcells.insert(distrib_filt->cell()); } + if (cell_inst_filt) { + const auto& filter_cells = cell_inst_filt->cells(); + distribcells.insert(filter_cells.begin(), filter_cells.end()); + } } // By default, add material cells to the list of distributed cells if (settings::material_cell_offsets) { for (gsl::index i = 0; i < model::cells.size(); ++i) { - if (model::cells[i]->type_ == Fill::MATERIAL) distribcells.insert(i); + if (model::cells[i]->type_ == Fill::MATERIAL) + distribcells.insert(i); } } @@ -331,8 +360,8 @@ prepare_distribcell() fatal_error(fmt::format( "Cell {} was specified with {} materials but has {} distributed " "instances. The number of materials must equal one or the number " - "of instances.", c.id_, c.material_.size(), c.n_instances_ - )); + "of instances.", + c.id_, c.material_.size(), c.n_instances_)); } } @@ -341,8 +370,8 @@ prepare_distribcell() fatal_error(fmt::format( "Cell {} was specified with {} temperatures but has {} distributed " "instances. The number of temperatures must equal one or the number " - "of instances.", c.id_, c.sqrtkT_.size(), c.n_instances_ - )); + "of instances.", + c.id_, c.sqrtkT_.size(), c.n_instances_)); } } } @@ -371,8 +400,8 @@ prepare_distribcell() lat->allocate_offset_table(n_maps); } - // Fill the cell and lattice offset tables. - #pragma omp parallel for +// Fill the cell and lattice offset tables. +#pragma omp parallel for for (int map = 0; map < target_univ_ids.size(); map++) { auto target_univ_id = target_univ_ids[map]; std::unordered_map univ_count_memo; @@ -384,13 +413,14 @@ prepare_distribcell() if (c.type_ == Fill::UNIVERSE) { c.offset_[map] = offset; int32_t search_univ = c.fill_; - offset += count_universe_instances(search_univ, target_univ_id, - univ_count_memo); + offset += count_universe_instances( + search_univ, target_univ_id, univ_count_memo); } else if (c.type_ == Fill::LATTICE) { + c.offset_[map] = offset; Lattice& lat = *model::lattices[c.fill_]; - offset = lat.fill_offset_table(offset, target_univ_id, map, - univ_count_memo); + offset += + lat.fill_offset_table(offset, target_univ_id, map, univ_count_memo); } } } @@ -399,8 +429,7 @@ prepare_distribcell() //============================================================================== -void -count_cell_instances(int32_t univ_indx) +void count_cell_instances(int32_t univ_indx) { const auto univ_counts = model::universe_cell_counts.find(univ_indx); if (univ_counts != model::universe_cell_counts.end()) { @@ -431,8 +460,7 @@ count_cell_instances(int32_t univ_indx) //============================================================================== -int -count_universe_instances(int32_t search_univ, int32_t target_univ_id, +int count_universe_instances(int32_t search_univ, int32_t target_univ_id, std::unordered_map& univ_count_memo) { // If this is the target, it can't contain itself. @@ -452,15 +480,15 @@ count_universe_instances(int32_t search_univ, int32_t target_univ_id, if (c.type_ == Fill::UNIVERSE) { int32_t next_univ = c.fill_; - count += count_universe_instances(next_univ, target_univ_id, - univ_count_memo); + count += + count_universe_instances(next_univ, target_univ_id, univ_count_memo); } else if (c.type_ == Fill::LATTICE) { Lattice& lat = *model::lattices[c.fill_]; for (auto it = lat.begin(); it != lat.end(); ++it) { int32_t next_univ = *it; - count += count_universe_instances(next_univ, target_univ_id, - univ_count_memo); + count += + count_universe_instances(next_univ, target_univ_id, univ_count_memo); } } } @@ -473,9 +501,8 @@ count_universe_instances(int32_t search_univ, int32_t target_univ_id, //============================================================================== -std::string -distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, - const Universe& search_univ, int32_t offset) +std::string distribcell_path_inner(int32_t target_cell, int32_t map, + int32_t target_offset, const Universe& search_univ, int32_t offset) { std::stringstream path; @@ -506,16 +533,26 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, temp_offset = offset + c.offset_[map]; } else { Lattice& lat = *model::lattices[c.fill_]; - int32_t indx = lat.universes_.size()*map + lat.begin().indx_; + int32_t indx = lat.universes_.size() * map + lat.begin().indx_; temp_offset = offset + lat.offsets_[indx]; } // The desired cell is the first cell that gives an offset smaller or // equal to the target offset. - if (temp_offset <= target_offset) break; + if (temp_offset <= target_offset - c.offset_[map]) + break; } } + // if we get through the loop without finding an appropriate entry, throw + // an error + if (cell_it == search_univ.cells_.crend()) { + fatal_error( + fmt::format("Failed to generate a text label for distribcell with ID {}." + "The current label is: '{}'", + model::cells[target_cell]->id_, path.str())); + } + // Add the cell to the path string. Cell& c = *model::cells[*cell_it]; path << "c" << c.id_ << "->"; @@ -523,30 +560,30 @@ distribcell_path_inner(int32_t target_cell, int32_t map, int32_t target_offset, if (c.type_ == Fill::UNIVERSE) { // Recurse into the fill cell. offset += c.offset_[map]; - path << distribcell_path_inner(target_cell, map, target_offset, - *model::universes[c.fill_], offset); + path << distribcell_path_inner( + target_cell, map, target_offset, *model::universes[c.fill_], offset); return path.str(); } else { // Recurse into the lattice cell. Lattice& lat = *model::lattices[c.fill_]; path << "l" << lat.id_; for (ReverseLatticeIter it = lat.rbegin(); it != lat.rend(); ++it) { - int32_t indx = lat.universes_.size()*map + it.indx_; + int32_t indx = lat.universes_.size() * map + it.indx_; int32_t temp_offset = offset + lat.offsets_[indx]; - if (temp_offset <= target_offset) { + if (temp_offset <= target_offset - c.offset_[map]) { offset = temp_offset; path << "(" << lat.index_to_string(it.indx_) << ")->"; path << distribcell_path_inner(target_cell, map, target_offset, - *model::universes[*it], offset); + *model::universes[*it], offset + c.offset_[map]); return path.str(); } } - throw std::runtime_error{"Error determining distribcell path."}; + throw std::runtime_error {"Error determining distribcell path."}; } } -std::string -distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset) +std::string distribcell_path( + int32_t target_cell, int32_t map, int32_t target_offset) { auto& root_univ = *model::universes[model::root_universe]; return distribcell_path_inner(target_cell, map, target_offset, root_univ, 0); @@ -554,8 +591,7 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset) //============================================================================== -int -maximum_levels(int32_t univ) +int maximum_levels(int32_t univ) { const auto level_count = model::universe_level_counts.find(univ); @@ -584,10 +620,14 @@ maximum_levels(int32_t univ) return levels_below; } +bool is_root_universe(int32_t univ_id) +{ + return model::universe_map[univ_id] == model::root_universe; +} + //============================================================================== -void -free_memory_geometry() +void free_memory_geometry() { model::cells.clear(); model::cell_map.clear(); diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 0f8db2dc5fe..27b750b931e 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -4,8 +4,8 @@ #include #include -#include "xtensor/xtensor.hpp" #include "xtensor/xarray.hpp" +#include "xtensor/xtensor.hpp" #include #include "hdf5.h" @@ -19,16 +19,13 @@ namespace openmc { -bool -attribute_exists(hid_t obj_id, const char* name) +bool attribute_exists(hid_t obj_id, const char* name) { htri_t out = H5Aexists_by_name(obj_id, ".", name, H5P_DEFAULT); return out > 0; } - -size_t -attribute_typesize(hid_t obj_id, const char* name) +size_t attribute_typesize(hid_t obj_id, const char* name) { hid_t attr = H5Aopen(obj_id, name, H5P_DEFAULT); hid_t filetype = H5Aget_type(attr); @@ -38,9 +35,7 @@ attribute_typesize(hid_t obj_id, const char* name) return n; } - -void -get_shape(hid_t obj_id, hsize_t* dims) +void get_shape(hid_t obj_id, hsize_t* dims) { auto type = H5Iget_type(obj_id); hid_t dspace; @@ -49,7 +44,7 @@ get_shape(hid_t obj_id, hsize_t* dims) } else if (type == H5I_ATTR) { dspace = H5Aget_space(obj_id); } else { - throw std::runtime_error{ + throw std::runtime_error { "Expected dataset or attribute in call to get_shape."}; } H5Sget_simple_extent_dims(dspace, dims, nullptr); @@ -74,7 +69,7 @@ vector object_shape(hid_t obj_id) } else if (type == H5I_ATTR) { dspace = H5Aget_space(obj_id); } else { - throw std::runtime_error{ + throw std::runtime_error { "Expected dataset or attribute in call to object_shape."}; } int n = H5Sget_simple_extent_ndims(dspace); @@ -88,8 +83,7 @@ vector object_shape(hid_t obj_id) return shape; } -void -get_shape_attr(hid_t obj_id, const char* name, hsize_t* dims) +void get_shape_attr(hid_t obj_id, const char* name, hsize_t* dims) { hid_t attr = H5Aopen(obj_id, name, H5P_DEFAULT); hid_t dspace = H5Aget_space(attr); @@ -98,9 +92,7 @@ get_shape_attr(hid_t obj_id, const char* name, hsize_t* dims) H5Aclose(attr); } - -hid_t -create_group(hid_t parent_id, char const *name) +hid_t create_group(hid_t parent_id, char const* name) { hid_t out = H5Gcreate(parent_id, name, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (out < 0) { @@ -109,30 +101,30 @@ create_group(hid_t parent_id, char const *name) return out; } - -hid_t -create_group(hid_t parent_id, const std::string &name) +hid_t create_group(hid_t parent_id, const std::string& name) { return create_group(parent_id, name.c_str()); } - -void -close_dataset(hid_t dataset_id) +void close_dataset(hid_t dataset_id) { - if (H5Dclose(dataset_id) < 0) fatal_error("Failed to close dataset"); + if (H5Dclose(dataset_id) < 0) + fatal_error("Failed to close dataset"); } - -void -close_group(hid_t group_id) +void close_group(hid_t group_id) { - if (H5Gclose(group_id) < 0) fatal_error("Failed to close group"); + if (H5Gclose(group_id) < 0) + fatal_error("Failed to close group"); } +void close_object(hid_t obj_id) +{ + if (H5Oclose(obj_id) < 0) + fatal_error("Failed to close object"); +} -int -dataset_ndims(hid_t dset) +int dataset_ndims(hid_t dset) { hid_t dspace = H5Dget_space(dset); int ndims = H5Sget_simple_extent_ndims(dspace); @@ -140,9 +132,7 @@ dataset_ndims(hid_t dset) return ndims; } - -size_t -dataset_typesize(hid_t obj_id, const char* name) +size_t dataset_typesize(hid_t obj_id, const char* name) { hid_t dset = open_dataset(obj_id, name); hid_t filetype = H5Dget_type(dset); @@ -152,9 +142,7 @@ dataset_typesize(hid_t obj_id, const char* name) return n; } - -void -ensure_exists(hid_t obj_id, const char* name, bool attribute) +void ensure_exists(hid_t obj_id, const char* name, bool attribute) { if (attribute) { if (!attribute_exists(obj_id, name)) { @@ -163,31 +151,29 @@ ensure_exists(hid_t obj_id, const char* name, bool attribute) } } else { if (!object_exists(obj_id, name)) { - fatal_error(fmt::format("Object \"{}\" does not exist in object {}", - name, object_name(obj_id))); + fatal_error(fmt::format("Object \"{}\" does not exist in object {}", name, + object_name(obj_id))); } } } - -hid_t -file_open(const char* filename, char mode, bool parallel) +hid_t file_open(const char* filename, char mode, bool parallel) { bool create; unsigned int flags; switch (mode) { - case 'r': - case 'a': - create = false; - flags = (mode == 'r' ? H5F_ACC_RDONLY : H5F_ACC_RDWR); - break; - case 'w': - case 'x': - create = true; - flags = (mode == 'x' ? H5F_ACC_EXCL : H5F_ACC_TRUNC); - break; - default: - fatal_error(fmt::format("Invalid file mode: ", mode)); + case 'r': + case 'a': + create = false; + flags = (mode == 'r' ? H5F_ACC_RDONLY : H5F_ACC_RDWR); + break; + case 'w': + case 'x': + create = true; + flags = (mode == 'x' ? H5F_ACC_EXCL : H5F_ACC_TRUNC); + break; + default: + fatal_error(fmt::format("Invalid file mode: ", mode)); } hid_t plist = H5P_DEFAULT; @@ -213,32 +199,36 @@ file_open(const char* filename, char mode, bool parallel) #ifdef PHDF5 // Close the property list - if (parallel) H5Pclose(plist); + if (parallel) + H5Pclose(plist); #endif return file_id; } -hid_t -file_open(const std::string& filename, char mode, bool parallel) +hid_t file_open(const std::string& filename, char mode, bool parallel) { return file_open(filename.c_str(), mode, parallel); } +hid_t open_group(hid_t group_id, const std::string& name) +{ + return open_group(group_id, name.c_str()); +} + void file_close(hid_t file_id) { H5Fclose(file_id); } - -void -get_name(hid_t obj_id, char* name) +void get_name(hid_t obj_id, std::string& name) { size_t size = 1 + H5Iget_name(obj_id, nullptr, 0); - H5Iget_name(obj_id, name, size); + name.resize(size); + // TODO: switch to name.data() when using C++17 + H5Iget_name(obj_id, &name[0], size); } - int get_num_datasets(hid_t group_id) { // Determine number of links in the group @@ -250,15 +240,15 @@ int get_num_datasets(hid_t group_id) int ndatasets = 0; for (hsize_t i = 0; i < info.nlinks; ++i) { // Determine type of object (and skip non-group) - H5Oget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, - H5P_DEFAULT); - if (oinfo.type == H5O_TYPE_DATASET) ndatasets += 1; + H5Oget_info_by_idx( + group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, H5P_DEFAULT); + if (oinfo.type == H5O_TYPE_DATASET) + ndatasets += 1; } return ndatasets; } - int get_num_groups(hid_t group_id) { // Determine number of links in the group @@ -270,17 +260,16 @@ int get_num_groups(hid_t group_id) int ngroups = 0; for (hsize_t i = 0; i < info.nlinks; ++i) { // Determine type of object (and skip non-group) - H5Oget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, - H5P_DEFAULT); - if (oinfo.type == H5O_TYPE_GROUP) ngroups += 1; + H5Oget_info_by_idx( + group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, H5P_DEFAULT); + if (oinfo.type == H5O_TYPE_GROUP) + ngroups += 1; } return ngroups; } - -void -get_datasets(hid_t group_id, char* name[]) +void get_datasets(hid_t group_id, char* name[]) { // Determine number of links in the group H5G_info_t info; @@ -292,24 +281,23 @@ get_datasets(hid_t group_id, char* name[]) size_t size; for (hsize_t i = 0; i < info.nlinks; ++i) { // Determine type of object (and skip non-group) - H5Oget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, - H5P_DEFAULT); - if (oinfo.type != H5O_TYPE_DATASET) continue; + H5Oget_info_by_idx( + group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, H5P_DEFAULT); + if (oinfo.type != H5O_TYPE_DATASET) + continue; // Get size of name - size = 1 + H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, - i, nullptr, 0, H5P_DEFAULT); + size = 1 + H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, + nullptr, 0, H5P_DEFAULT); // Read name H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, - name[count], size, H5P_DEFAULT); + name[count], size, H5P_DEFAULT); count += 1; } } - -void -get_groups(hid_t group_id, char* name[]) +void get_groups(hid_t group_id, char* name[]) { // Determine number of links in the group H5G_info_t info; @@ -321,17 +309,18 @@ get_groups(hid_t group_id, char* name[]) size_t size; for (hsize_t i = 0; i < info.nlinks; ++i) { // Determine type of object (and skip non-group) - H5Oget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, - H5P_DEFAULT); - if (oinfo.type != H5O_TYPE_GROUP) continue; + H5Oget_info_by_idx( + group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, H5P_DEFAULT); + if (oinfo.type != H5O_TYPE_GROUP) + continue; // Get size of name - size = 1 + H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, - i, nullptr, 0, H5P_DEFAULT); + size = 1 + H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, + nullptr, 0, H5P_DEFAULT); // Read name H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, - name[count], size, H5P_DEFAULT); + name[count], size, H5P_DEFAULT); count += 1; } } @@ -348,18 +337,19 @@ vector member_names(hid_t group_id, H5O_type_t type) vector names; for (hsize_t i = 0; i < info.nlinks; ++i) { // Determine type of object (and skip non-group) - H5Oget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, - H5P_DEFAULT); - if (oinfo.type != type) continue; + H5Oget_info_by_idx( + group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, H5P_DEFAULT); + if (oinfo.type != type) + continue; // Get size of name - size = 1 + H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, - i, nullptr, 0, H5P_DEFAULT); + size = 1 + H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, + nullptr, 0, H5P_DEFAULT); // Read name char* buffer = new char[size]; - H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, - buffer, size, H5P_DEFAULT); + H5Lget_name_by_idx( + group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, buffer, size, H5P_DEFAULT); names.emplace_back(&buffer[0]); delete[] buffer; } @@ -376,8 +366,7 @@ vector dataset_names(hid_t group_id) return member_names(group_id, H5O_TYPE_DATASET); } -bool -object_exists(hid_t object_id, const char* name) +bool object_exists(hid_t object_id, const char* name) { htri_t out = H5LTpath_valid(object_id, name, true); if (out < 0) { @@ -386,9 +375,7 @@ object_exists(hid_t object_id, const char* name) return (out > 0); } - -std::string -object_name(hid_t obj_id) +std::string object_name(hid_t obj_id) { // Determine size and create buffer size_t size = 1 + H5Iget_name(obj_id, nullptr, 0); @@ -401,47 +388,42 @@ object_name(hid_t obj_id) return str; } - -hid_t -open_dataset(hid_t group_id, const char* name) +hid_t open_dataset(hid_t group_id, const char* name) { ensure_exists(group_id, name); return H5Dopen(group_id, name, H5P_DEFAULT); } - -hid_t -open_group(hid_t group_id, const char* name) +hid_t open_group(hid_t group_id, const char* name) { ensure_exists(group_id, name); return H5Gopen(group_id, name, H5P_DEFAULT); } -void -read_attr(hid_t obj_id, const char* name, hid_t mem_type_id, void* buffer) +hid_t open_object(hid_t group_id, const std::string& name) +{ + ensure_exists(group_id, name.c_str()); + return H5Oopen(group_id, name.c_str(), H5P_DEFAULT); +} + +void read_attr(hid_t obj_id, const char* name, hid_t mem_type_id, void* buffer) { hid_t attr = H5Aopen(obj_id, name, H5P_DEFAULT); H5Aread(attr, mem_type_id, buffer); H5Aclose(attr); } - -void -read_attr_double(hid_t obj_id, const char* name, double* buffer) +void read_attr_double(hid_t obj_id, const char* name, double* buffer) { read_attr(obj_id, name, H5T_NATIVE_DOUBLE, buffer); } - -void -read_attr_int(hid_t obj_id, const char* name, int* buffer) +void read_attr_int(hid_t obj_id, const char* name, int* buffer) { read_attr(obj_id, name, H5T_NATIVE_INT, buffer); } - -void -read_attr_string(hid_t obj_id, const char* name, size_t slen, char* buffer) +void read_attr_string(hid_t obj_id, const char* name, size_t slen, char* buffer) { // Create datatype for a string hid_t datatype = H5Tcopy(H5T_C_S1); @@ -456,13 +438,12 @@ read_attr_string(hid_t obj_id, const char* name, size_t slen, char* buffer) H5Tclose(datatype); } - -void -read_dataset_lowlevel(hid_t obj_id, const char* name, hid_t mem_type_id, - hid_t mem_space_id, bool indep, void* buffer) +void read_dataset_lowlevel(hid_t obj_id, const char* name, hid_t mem_type_id, + hid_t mem_space_id, bool indep, void* buffer) { hid_t dset = obj_id; - if (name) dset = open_dataset(obj_id, name); + if (name) + dset = open_dataset(obj_id, name); if (using_mpio_device(dset)) { #ifdef PHDF5 @@ -481,7 +462,8 @@ read_dataset_lowlevel(hid_t obj_id, const char* name, hid_t mem_type_id, H5Dread(dset, mem_type_id, mem_space_id, H5S_ALL, H5P_DEFAULT, buffer); } - if (name) H5Dclose(dset); + if (name) + H5Dclose(dset); } template<> @@ -503,32 +485,24 @@ void read_dataset(hid_t dset, xt::xarray>& arr, bool indep) arr = xt::adapt(buffer, shape); } - -void -read_double(hid_t obj_id, const char* name, double* buffer, bool indep) +void read_double(hid_t obj_id, const char* name, double* buffer, bool indep) { - read_dataset_lowlevel(obj_id, name, H5T_NATIVE_DOUBLE, H5S_ALL, indep, - buffer); + read_dataset_lowlevel( + obj_id, name, H5T_NATIVE_DOUBLE, H5S_ALL, indep, buffer); } - -void -read_int(hid_t obj_id, const char* name, int* buffer, bool indep) +void read_int(hid_t obj_id, const char* name, int* buffer, bool indep) { read_dataset_lowlevel(obj_id, name, H5T_NATIVE_INT, H5S_ALL, indep, buffer); } - -void -read_llong(hid_t obj_id, const char* name, long long* buffer, bool indep) +void read_llong(hid_t obj_id, const char* name, long long* buffer, bool indep) { read_dataset_lowlevel(obj_id, name, H5T_NATIVE_LLONG, H5S_ALL, indep, buffer); } - -void -read_string(hid_t obj_id, const char* name, size_t slen, char* buffer, - bool indep) +void read_string( + hid_t obj_id, const char* name, size_t slen, char* buffer, bool indep) { // Create datatype for a string hid_t datatype = H5Tcopy(H5T_C_S1); @@ -543,10 +517,8 @@ read_string(hid_t obj_id, const char* name, size_t slen, char* buffer, H5Tclose(datatype); } - -void -read_complex(hid_t obj_id, const char* name, std::complex* buffer, - bool indep) +void read_complex( + hid_t obj_id, const char* name, std::complex* buffer, bool indep) { // Create compound datatype for complex numbers struct complex_t { @@ -565,10 +537,8 @@ read_complex(hid_t obj_id, const char* name, std::complex* buffer, H5Tclose(complex_id); } - -void -read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, - double* results) +void read_tally_results( + hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results) { // Create dataspace for hyperslab in memory constexpr int ndim = 3; @@ -579,17 +549,15 @@ read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, H5Sselect_hyperslab(memspace, H5S_SELECT_SET, start, nullptr, count, nullptr); // Read the dataset - read_dataset_lowlevel(group_id, "results", H5T_NATIVE_DOUBLE, memspace, - false, results); + read_dataset_lowlevel( + group_id, "results", H5T_NATIVE_DOUBLE, memspace, false, results); // Free resources H5Sclose(memspace); } - -void -write_attr(hid_t obj_id, int ndim, const hsize_t* dims, const char* name, - hid_t mem_type_id, const void* buffer) +void write_attr(hid_t obj_id, int ndim, const hsize_t* dims, const char* name, + hid_t mem_type_id, const void* buffer) { // If array is given, create a simple dataspace. Otherwise, create a scalar // datascape. @@ -601,8 +569,8 @@ write_attr(hid_t obj_id, int ndim, const hsize_t* dims, const char* name, } // Create attribute and Write data - hid_t attr = H5Acreate(obj_id, name, mem_type_id, dspace, - H5P_DEFAULT, H5P_DEFAULT); + hid_t attr = + H5Acreate(obj_id, name, mem_type_id, dspace, H5P_DEFAULT, H5P_DEFAULT); H5Awrite(attr, mem_type_id, buffer); // Free resources @@ -610,25 +578,19 @@ write_attr(hid_t obj_id, int ndim, const hsize_t* dims, const char* name, H5Sclose(dspace); } - -void -write_attr_double(hid_t obj_id, int ndim, const hsize_t* dims, const char* name, - const double* buffer) +void write_attr_double(hid_t obj_id, int ndim, const hsize_t* dims, + const char* name, const double* buffer) { write_attr(obj_id, ndim, dims, name, H5T_NATIVE_DOUBLE, buffer); } - -void -write_attr_int(hid_t obj_id, int ndim, const hsize_t* dims, const char* name, - const int* buffer) +void write_attr_int(hid_t obj_id, int ndim, const hsize_t* dims, + const char* name, const int* buffer) { write_attr(obj_id, ndim, dims, name, H5T_NATIVE_INT, buffer); } - -void -write_attr_string(hid_t obj_id, const char* name, const char* buffer) +void write_attr_string(hid_t obj_id, const char* name, const char* buffer) { size_t n = strlen(buffer); if (n > 0) { @@ -643,9 +605,7 @@ write_attr_string(hid_t obj_id, const char* name, const char* buffer) } } - -void -write_dataset_lowlevel(hid_t group_id, int ndim, const hsize_t* dims, +void write_dataset_lowlevel(hid_t group_id, int ndim, const hsize_t* dims, const char* name, hid_t mem_type_id, hid_t mem_space_id, bool indep, const void* buffer) { @@ -658,8 +618,8 @@ write_dataset_lowlevel(hid_t group_id, int ndim, const hsize_t* dims, dspace = H5Screate(H5S_SCALAR); } - hid_t dset = H5Dcreate(group_id, name, mem_type_id, dspace, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + hid_t dset = H5Dcreate( + group_id, name, mem_type_id, dspace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (using_mpio_device(group_id)) { #ifdef PHDF5 @@ -683,64 +643,52 @@ write_dataset_lowlevel(hid_t group_id, int ndim, const hsize_t* dims, H5Sclose(dspace); } - -void -write_double(hid_t group_id, int ndim, const hsize_t* dims, const char* name, - const double* buffer, bool indep) +void write_double(hid_t group_id, int ndim, const hsize_t* dims, + const char* name, const double* buffer, bool indep) { - write_dataset_lowlevel(group_id, ndim, dims, name, H5T_NATIVE_DOUBLE, H5S_ALL, - indep, buffer); + write_dataset_lowlevel( + group_id, ndim, dims, name, H5T_NATIVE_DOUBLE, H5S_ALL, indep, buffer); } - -void -write_int(hid_t group_id, int ndim, const hsize_t* dims, const char* name, - const int* buffer, bool indep) +void write_int(hid_t group_id, int ndim, const hsize_t* dims, const char* name, + const int* buffer, bool indep) { - write_dataset_lowlevel(group_id, ndim, dims, name, H5T_NATIVE_INT, H5S_ALL, - indep, buffer); + write_dataset_lowlevel( + group_id, ndim, dims, name, H5T_NATIVE_INT, H5S_ALL, indep, buffer); } - -void -write_llong(hid_t group_id, int ndim, const hsize_t* dims, const char* name, - const long long* buffer, bool indep) +void write_llong(hid_t group_id, int ndim, const hsize_t* dims, + const char* name, const long long* buffer, bool indep) { - write_dataset_lowlevel(group_id, ndim, dims, name, H5T_NATIVE_LLONG, H5S_ALL, - indep, buffer); + write_dataset_lowlevel( + group_id, ndim, dims, name, H5T_NATIVE_LLONG, H5S_ALL, indep, buffer); } - -void -write_string(hid_t group_id, int ndim, const hsize_t* dims, size_t slen, - const char* name, const char* buffer, bool indep) +void write_string(hid_t group_id, int ndim, const hsize_t* dims, size_t slen, + const char* name, const char* buffer, bool indep) { if (slen > 0) { // Set up appropriate datatype for a fixed-length string hid_t datatype = H5Tcopy(H5T_C_S1); H5Tset_size(datatype, slen); - write_dataset_lowlevel(group_id, ndim, dims, name, datatype, H5S_ALL, indep, - buffer); + write_dataset_lowlevel( + group_id, ndim, dims, name, datatype, H5S_ALL, indep, buffer); // Free resources H5Tclose(datatype); } } - -void -write_string(hid_t group_id, const char* name, const std::string& buffer, - bool indep) +void write_string( + hid_t group_id, const char* name, const std::string& buffer, bool indep) { - write_string(group_id, 0, nullptr, buffer.length(), name, buffer.c_str(), - indep); + write_string( + group_id, 0, nullptr, buffer.length(), name, buffer.c_str(), indep); } - -void -write_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, - const double* results) +void write_tally_results( + hid_t group_id, hsize_t n_filter, hsize_t n_score, const double* results) { // Set dimensions of sum/sum_sq hyperslab to store constexpr int ndim = 3; @@ -754,15 +702,13 @@ write_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, // Create and write dataset write_dataset_lowlevel(group_id, ndim, count, "results", H5T_NATIVE_DOUBLE, - memspace, false, results); + memspace, false, results); // Free resources H5Sclose(memspace); } - -bool -using_mpio_device(hid_t obj_id) +bool using_mpio_device(hid_t obj_id) { // Determine file that this object is part of hid_t file_id = H5Iget_file_id(obj_id); @@ -795,7 +741,7 @@ template<> const hid_t H5TypeMap::type_id = H5T_NATIVE_INT64; template<> const hid_t H5TypeMap::type_id = H5T_NATIVE_DOUBLE; -template <> +template<> const hid_t H5TypeMap::type_id = H5T_NATIVE_CHAR; } // namespace openmc diff --git a/src/initialize.cpp b/src/initialize.cpp index d67d6b3b31a..cc1eac9cf35 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -1,5 +1,6 @@ #include "openmc/initialize.h" +#include #include #include // for getenv #include @@ -14,6 +15,7 @@ #include "openmc/constants.h" #include "openmc/cross_sections.h" #include "openmc/error.h" +#include "openmc/file_utils.h" #include "openmc/geometry_aux.h" #include "openmc/hdf5_interface.h" #include "openmc/material.h" @@ -21,6 +23,7 @@ #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" +#include "openmc/openmp_interface.h" #include "openmc/output.h" #include "openmc/plot.h" #include "openmc/random_lcg.h" @@ -32,12 +35,12 @@ #include "openmc/thermal.h" #include "openmc/timer.h" #include "openmc/vector.h" +#include "openmc/weight_windows.h" #ifdef LIBMESH #include "libmesh/libmesh.h" #endif - int openmc_init(int argc, char* argv[], const void* intracomm) { using namespace openmc; @@ -46,7 +49,7 @@ int openmc_init(int argc, char* argv[], const void* intracomm) // Check if intracomm was passed MPI_Comm comm; if (intracomm) { - comm = *static_cast(intracomm); + comm = *static_cast(intracomm); } else { comm = MPI_COMM_WORLD; } @@ -57,33 +60,29 @@ int openmc_init(int argc, char* argv[], const void* intracomm) // Parse command-line arguments int err = parse_command_line(argc, argv); - if (err) return err; + if (err) + return err; #ifdef LIBMESH - -#ifdef _OPENMP - int n_threads = omp_get_max_threads(); -#else - int n_threads = 1; -#endif - -// initialize libMesh if it hasn't been initialized already -// (if initialized externally, the libmesh_init object needs to be provided also) -if (!settings::libmesh_init && !libMesh::initialized()) { + const int n_threads = num_threads(); + // initialize libMesh if it hasn't been initialized already + // (if initialized externally, the libmesh_init object needs to be provided + // also) + if (!settings::libmesh_init && !libMesh::initialized()) { #ifdef OPENMC_MPI - // pass command line args, empty MPI communicator, and number of threads. - // Because libMesh was not initialized, we assume that OpenMC is the primary - // application and that its main MPI comm should be used. - settings::libmesh_init = - make_unique(argc, argv, comm, n_threads); + // pass command line args, empty MPI communicator, and number of threads. + // Because libMesh was not initialized, we assume that OpenMC is the primary + // application and that its main MPI comm should be used. + settings::libmesh_init = + make_unique(argc, argv, comm, n_threads); #else - // pass command line args, empty MPI communicator, and number of threads - settings::libmesh_init = - make_unique(argc, argv, 0, n_threads); + // pass command line args, empty MPI communicator, and number of threads + settings::libmesh_init = + make_unique(argc, argv, 0, n_threads); #endif - settings::libmesh_comm = &(settings::libmesh_init->comm()); -} + settings::libmesh_comm = &(settings::libmesh_init->comm()); + } #endif @@ -103,11 +102,31 @@ if (!settings::libmesh_init && !libMesh::initialized()) { // will be re-initialized later openmc::openmc_set_seed(DEFAULT_SEED); + // Copy previous locale and set locale to C. This is a workaround for an issue + // whereby when openmc_init is called from the plotter, the Qt application + // framework first calls std::setlocale, which affects how pugixml reads + // floating point numbers due to a bug: + // https://github.com/zeux/pugixml/issues/469 + std::string prev_locale = std::setlocale(LC_ALL, nullptr); + if (std::setlocale(LC_ALL, "C") == NULL) { + fatal_error("Cannot set locale to C."); + } + // Read XML input files - read_input_xml(); + if (!read_model_xml()) + read_separate_xml_files(); + + // Reset locale to previous state + if (std::setlocale(LC_ALL, prev_locale.c_str()) == NULL) { + fatal_error("Cannot reset locale."); + } + + // Write some initial output under the header if needed + initial_output(); // Check for particle restart run - if (settings::particle_restart_run) settings::run_mode = RunMode::PARTICLE; + if (settings::particle_restart_run) + settings::run_mode = RunMode::PARTICLE; // Stop initialization timer simulation::time_initialize.stop(); @@ -126,7 +145,8 @@ void initialize_mpi(MPI_Comm intracomm) // Initialize MPI int flag; MPI_Initialized(&flag); - if (!flag) MPI_Init(nullptr, nullptr); + if (!flag) + MPI_Init(nullptr, nullptr); // Determine number of processes and rank for each MPI_Comm_size(intracomm, &mpi::n_procs); @@ -135,33 +155,33 @@ void initialize_mpi(MPI_Comm intracomm) // Create bank datatype SourceSite b; - MPI_Aint disp[9]; + MPI_Aint disp[10]; MPI_Get_address(&b.r, &disp[0]); MPI_Get_address(&b.u, &disp[1]); MPI_Get_address(&b.E, &disp[2]); - MPI_Get_address(&b.wgt, &disp[3]); - MPI_Get_address(&b.delayed_group, &disp[4]); - MPI_Get_address(&b.surf_id, &disp[5]); - MPI_Get_address(&b.particle, &disp[6]); - MPI_Get_address(&b.parent_id, &disp[7]); - MPI_Get_address(&b.progeny_id, &disp[8]); - for (int i = 8; i >= 0; --i) { + MPI_Get_address(&b.time, &disp[3]); + MPI_Get_address(&b.wgt, &disp[4]); + MPI_Get_address(&b.delayed_group, &disp[5]); + MPI_Get_address(&b.surf_id, &disp[6]); + MPI_Get_address(&b.particle, &disp[7]); + MPI_Get_address(&b.parent_id, &disp[8]); + MPI_Get_address(&b.progeny_id, &disp[9]); + for (int i = 9; i >= 0; --i) { disp[i] -= disp[0]; } - int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1}; - MPI_Datatype types[] {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG}; - MPI_Type_create_struct(9, blocks, disp, types, &mpi::source_site); + int blocks[] {3, 3, 1, 1, 1, 1, 1, 1, 1, 1}; + MPI_Datatype types[] {MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, MPI_DOUBLE, + MPI_DOUBLE, MPI_INT, MPI_INT, MPI_INT, MPI_LONG, MPI_LONG}; + MPI_Type_create_struct(10, blocks, disp, types, &mpi::source_site); MPI_Type_commit(&mpi::source_site); } #endif // OPENMC_MPI - -int -parse_command_line(int argc, char* argv[]) +int parse_command_line(int argc, char* argv[]) { int last_flag = 0; - for (int i=1; i < argc; ++i) { + for (int i = 1; i < argc; ++i) { std::string arg {argv[i]}; if (arg[0] == '-') { if (arg == "-p" || arg == "--plot") { @@ -174,10 +194,8 @@ parse_command_line(int argc, char* argv[]) } else if (arg == "-e" || arg == "--event") { settings::event_based = true; - } else if (arg == "-r" || arg == "--restart") { i += 1; - // Check what type of file this is hid_t file_id = file_open(argv[i], 'r', true); std::string filetype; @@ -187,12 +205,14 @@ parse_command_line(int argc, char* argv[]) // Set path and flag for type of run if (filetype == "statepoint") { settings::path_statepoint = argv[i]; + settings::path_statepoint_c = settings::path_statepoint.c_str(); settings::restart_run = true; } else if (filetype == "particle restart") { settings::path_particle_restart = argv[i]; settings::particle_restart_run = true; } else { - auto msg = fmt::format("Unrecognized file after restart flag: {}.", filetype); + auto msg = + fmt::format("Unrecognized file after restart flag: {}.", filetype); strcpy(openmc_err_msg, msg.c_str()); return OPENMC_E_INVALID_ARGUMENT; } @@ -200,20 +220,21 @@ parse_command_line(int argc, char* argv[]) // If its a restart run check for additional source file if (settings::restart_run && i + 1 < argc) { // Check if it has extension we can read - if (ends_with(argv[i+1], ".h5")) { + if (ends_with(argv[i + 1], ".h5")) { // Check file type is a source file - file_id = file_open(argv[i+1], 'r', true); + file_id = file_open(argv[i + 1], 'r', true); read_attribute(file_id, "filetype", filetype); file_close(file_id); if (filetype != "source") { - std::string msg {"Second file after restart flag must be a source file"}; + std::string msg { + "Second file after restart flag must be a source file"}; strcpy(openmc_err_msg, msg.c_str()); return OPENMC_E_INVALID_ARGUMENT; } // It is a source file - settings::path_sourcepoint = argv[i+1]; + settings::path_sourcepoint = argv[i + 1]; i += 1; } else { @@ -227,7 +248,7 @@ parse_command_line(int argc, char* argv[]) } } else if (arg == "-g" || arg == "--geometry-debug") { - settings::check_overlaps = true; + settings::check_overlaps = true; } else if (arg == "-c" || arg == "--volume") { settings::run_mode = RunMode::VOLUME; } else if (arg == "-s" || arg == "--threads") { @@ -255,6 +276,7 @@ parse_command_line(int argc, char* argv[]) } else if (arg == "-v" || arg == "--version") { print_version(); + print_build_info(); return OPENMC_E_UNASSIGNED; } else if (arg == "-t" || arg == "--track") { @@ -274,8 +296,17 @@ parse_command_line(int argc, char* argv[]) if (argc > 1 && last_flag < argc - 1) { settings::path_input = std::string(argv[last_flag + 1]); + // check that the path is either a valid directory or file + if (!dir_exists(settings::path_input) && + !file_exists(settings::path_input)) { + fatal_error(fmt::format( + "The path specified to the OpenMC executable '{}' does not exist.", + settings::path_input)); + } + // Add slash at end of directory if it isn't there - if (!ends_with(settings::path_input, "/")) { + if (!ends_with(settings::path_input, "/") && + dir_exists(settings::path_input)) { settings::path_input += "/"; } } @@ -283,10 +314,115 @@ parse_command_line(int argc, char* argv[]) return 0; } -void read_input_xml() +bool read_model_xml() +{ + std::string model_filename = settings::path_input; + + // if the current filename is a directory, append the default model filename + if (model_filename.empty() || dir_exists(model_filename)) + model_filename += "model.xml"; + + // if this file doesn't exist, stop here + if (!file_exists(model_filename)) + return false; + + // try to process the path input as an XML file + pugi::xml_document doc; + if (!doc.load_file(model_filename.c_str())) { + fatal_error(fmt::format( + "Error reading from single XML input file '{}'", model_filename)); + } + + pugi::xml_node root = doc.document_element(); + + // Read settings + if (!check_for_node(root, "settings")) { + fatal_error("No node present in the model.xml file."); + } + auto settings_root = root.child("settings"); + + // Verbosity + if (check_for_node(settings_root, "verbosity")) { + settings::verbosity = std::stoi(get_node_value(settings_root, "verbosity")); + } + + // To this point, we haven't displayed any output since we didn't know what + // the verbosity is. Now that we checked for it, show the title if necessary + if (mpi::master) { + if (settings::verbosity >= 2) + title(); + } + + write_message( + fmt::format("Reading model XML file '{}' ...", model_filename), 5); + + read_settings_xml(settings_root); + + // If other XML files are present, display warning + // that they will be ignored + auto other_inputs = {"materials.xml", "geometry.xml", "settings.xml", + "tallies.xml", "plots.xml"}; + for (const auto& input : other_inputs) { + if (file_exists(settings::path_input + input)) { + warning((fmt::format("Other XML file input(s) are present. These files " + "may be ignored in favor of the {} file.", + model_filename))); + break; + } + } + + // Read materials and cross sections + if (!check_for_node(root, "materials")) { + fatal_error(fmt::format( + "No node present in the {} file.", model_filename)); + } + + if (settings::run_mode != RunMode::PLOTTING) { + read_cross_sections_xml(root.child("materials")); + } + read_materials_xml(root.child("materials")); + + // Read geometry + if (!check_for_node(root, "geometry")) { + fatal_error(fmt::format( + "No node present in the {} file.", model_filename)); + } + read_geometry_xml(root.child("geometry")); + + // Final geometry setup and assign temperatures + finalize_geometry(); + + // Finalize cross sections having assigned temperatures + finalize_cross_sections(); + + if (check_for_node(root, "tallies")) + read_tallies_xml(root.child("tallies")); + + // Initialize distribcell_filters + prepare_distribcell(); + + if (check_for_node(root, "plots")) { + read_plots_xml(root.child("plots")); + } else { + // When no element is present in the model.xml file, check for a + // regular plots.xml file + std::string filename = settings::path_input + "plots.xml"; + if (file_exists(filename)) { + read_plots_xml(); + } + } + + finalize_variance_reduction(); + + return true; +} + +void read_separate_xml_files() { read_settings_xml(); - read_cross_sections_xml(); + if (settings::run_mode != RunMode::PLOTTING) { + read_cross_sections_xml(); + } read_materials_xml(); read_geometry_xml(); @@ -295,27 +431,36 @@ void read_input_xml() // Finalize cross sections having assigned temperatures finalize_cross_sections(); - read_tallies_xml(); // Initialize distribcell_filters prepare_distribcell(); + // Read the plots.xml regardless of plot mode in case plots are requested + // via the API + read_plots_xml(); + + finalize_variance_reduction(); +} + +void initial_output() +{ + // write initial output if (settings::run_mode == RunMode::PLOTTING) { // Read plots.xml if it exists - read_plots_xml(); - if (mpi::master && settings::verbosity >= 5) print_plot(); + if (mpi::master && settings::verbosity >= 5) + print_plot(); } else { // Write summary information - if (mpi::master && settings::output_summary) write_summary(); + if (mpi::master && settings::output_summary) + write_summary(); // Warn if overlap checking is on if (mpi::master && settings::check_overlaps) { warning("Cell overlap checking is ON."); } } - } } // namespace openmc diff --git a/src/lattice.cpp b/src/lattice.cpp index ee102eb3bb6..fa2e2828ecf 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -21,9 +21,9 @@ namespace openmc { //============================================================================== namespace model { - std::unordered_map lattice_map; - vector> lattices; -} +std::unordered_map lattice_map; +vector> lattices; +} // namespace model //============================================================================== // Lattice implementation @@ -49,21 +49,28 @@ Lattice::Lattice(pugi::xml_node lat_node) //============================================================================== LatticeIter Lattice::begin() -{return LatticeIter(*this, 0);} +{ + return LatticeIter(*this, 0); +} LatticeIter Lattice::end() -{return LatticeIter(*this, universes_.size());} +{ + return LatticeIter(*this, universes_.size()); +} ReverseLatticeIter Lattice::rbegin() -{return ReverseLatticeIter(*this, universes_.size()-1);} +{ + return ReverseLatticeIter(*this, universes_.size() - 1); +} ReverseLatticeIter Lattice::rend() -{return ReverseLatticeIter(*this, -1);} +{ + return ReverseLatticeIter(*this, -1); +} //============================================================================== -void -Lattice::adjust_indices() +void Lattice::adjust_indices() { // Adjust the indices for the universes array. for (LatticeIter it = begin(); it != end(); ++it) { @@ -91,10 +98,21 @@ Lattice::adjust_indices() //============================================================================== -int32_t -Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, int map, - std::unordered_map& univ_count_memo) +int32_t Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, + int map, std::unordered_map& univ_count_memo) { + // If the offsets have already been determined for this "map", don't bother + // recalculating all of them and just return the total offset. Note that the + // offsets_ array doesn't actually include the offset accounting for the last + // universe, so we get the before-last offset for the given map and then + // explicitly add the count for the last universe. + if (offsets_[map * universes_.size()] != C_NONE) { + int last_offset = offsets_[(map + 1) * universes_.size() - 1]; + int last_univ = universes_.back(); + return last_offset + + count_universe_instances(last_univ, target_univ_id, univ_count_memo); + } + for (LatticeIter it = begin(); it != end(); ++it) { offsets_[map * universes_.size() + it.indx_] = offset; offset += count_universe_instances(*it, target_univ_id, univ_count_memo); @@ -104,8 +122,7 @@ Lattice::fill_offset_table(int32_t offset, int32_t target_univ_id, int map, //============================================================================== -void -Lattice::to_hdf5(hid_t lattices_group) const +void Lattice::to_hdf5(hid_t lattices_group) const { // Make a group for the lattice. std::string group_name {"lattice "}; @@ -134,8 +151,7 @@ Lattice::to_hdf5(hid_t lattices_group) const // RectLattice implementation //============================================================================== -RectLattice::RectLattice(pugi::xml_node lat_node) - : Lattice {lat_node} +RectLattice::RectLattice(pugi::xml_node lat_node) : Lattice {lat_node} { type_ = LatticeType::rect; @@ -165,7 +181,9 @@ RectLattice::RectLattice(pugi::xml_node lat_node) } lower_left_[0] = stod(ll_words[0]); lower_left_[1] = stod(ll_words[1]); - if (is_3d_) {lower_left_[2] = stod(ll_words[2]);} + if (is_3d_) { + lower_left_[2] = stod(ll_words[2]); + } // Read the lattice pitches. std::string pitch_str {get_node_value(lat_node, "pitch")}; @@ -176,7 +194,9 @@ RectLattice::RectLattice(pugi::xml_node lat_node) } pitch_[0] = stod(pitch_words[0]); pitch_[1] = stod(pitch_words[1]); - if (is_3d_) {pitch_[2] = stod(pitch_words[2]);} + if (is_3d_) { + pitch_[2] = stod(pitch_words[2]); + } // Read the universes and make sure the correct number was specified. std::string univ_str {get_node_value(lat_node, "universes")}; @@ -207,18 +227,16 @@ RectLattice::RectLattice(pugi::xml_node lat_node) int32_t const& RectLattice::operator[](array const& i_xyz) { - int indx = - n_cells_[0] * n_cells_[1] * i_xyz[2] + n_cells_[0] * i_xyz[1] + i_xyz[0]; - return universes_[indx]; + return universes_[get_flat_index(i_xyz)]; } //============================================================================== bool RectLattice::are_valid_indices(array const& i_xyz) const { - return ( (i_xyz[0] >= 0) && (i_xyz[0] < n_cells_[0]) - && (i_xyz[1] >= 0) && (i_xyz[1] < n_cells_[1]) - && (i_xyz[2] >= 0) && (i_xyz[2] < n_cells_[2])); + return ((i_xyz[0] >= 0) && (i_xyz[0] < n_cells_[0]) && (i_xyz[1] >= 0) && + (i_xyz[1] < n_cells_[1]) && (i_xyz[2] >= 0) && + (i_xyz[2] < n_cells_[2])); } //============================================================================== @@ -315,15 +333,21 @@ void RectLattice::get_indices( } } +int RectLattice::get_flat_index(const array& i_xyz) const +{ + return n_cells_[0] * n_cells_[1] * i_xyz[2] + n_cells_[0] * i_xyz[1] + + i_xyz[0]; +} + //============================================================================== Position RectLattice::get_local_position( Position r, const array& i_xyz) const { - r.x -= (lower_left_.x + (i_xyz[0] + 0.5)*pitch_.x); - r.y -= (lower_left_.y + (i_xyz[1] + 0.5)*pitch_.y); + r.x -= (lower_left_.x + (i_xyz[0] + 0.5) * pitch_.x); + r.y -= (lower_left_.y + (i_xyz[1] + 0.5) * pitch_.y); if (is_3d_) { - r.z -= (lower_left_.z + (i_xyz[2] + 0.5)*pitch_.z); + r.z -= (lower_left_.z + (i_xyz[2] + 0.5) * pitch_.z); } return r; } @@ -339,16 +363,14 @@ int32_t& RectLattice::offset(int map, array const& i_xyz) //============================================================================== -int32_t -RectLattice::offset(int map, int indx) const +int32_t RectLattice::offset(int map, int indx) const { return offsets_[n_cells_[0] * n_cells_[1] * n_cells_[2] * map + indx]; } //============================================================================== -std::string -RectLattice::index_to_string(int indx) const +std::string RectLattice::index_to_string(int indx) const { int iz {indx / (n_cells_[0] * n_cells_[1])}; int iy {(indx - n_cells_[0] * n_cells_[1] * iz) / n_cells_[0]}; @@ -365,8 +387,7 @@ RectLattice::index_to_string(int indx) const //============================================================================== -void -RectLattice::to_hdf5_inner(hid_t lat_group) const +void RectLattice::to_hdf5_inner(hid_t lat_group) const { // Write basic lattice information. write_string(lat_group, "type", "rectangular", false); @@ -394,8 +415,8 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const for (int m = 0; m < nz; m++) { for (int k = 0; k < ny; k++) { for (int j = 0; j < nx; j++) { - int indx1 = nx*ny*m + nx*k + j; - int indx2 = nx*ny*m + nx*(ny-k-1) + j; + int indx1 = nx * ny * m + nx * k + j; + int indx2 = nx * ny * m + nx * (ny - k - 1) + j; out[indx2] = model::universes[universes_[indx1]]->id_; } } @@ -411,8 +432,8 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const for (int k = 0; k < ny; k++) { for (int j = 0; j < nx; j++) { - int indx1 = nx*k + j; - int indx2 = nx*(ny-k-1) + j; + int indx1 = nx * k + j; + int indx2 = nx * (ny - k - 1) + j; out[indx2] = model::universes[universes_[indx1]]->id_; } } @@ -426,8 +447,7 @@ RectLattice::to_hdf5_inner(hid_t lat_group) const // HexLattice implementation //============================================================================== -HexLattice::HexLattice(pugi::xml_node lat_node) - : Lattice {lat_node} +HexLattice::HexLattice(pugi::xml_node lat_node) : Lattice {lat_node} { type_ = LatticeType::hex; @@ -449,8 +469,8 @@ HexLattice::HexLattice(pugi::xml_node lat_node) } else if (orientation == "x") { orientation_ = Orientation::x; } else { - fatal_error("Unrecognized orientation '" + orientation - + "' for lattice " + std::to_string(id_)); + fatal_error("Unrecognized orientation '" + orientation + + "' for lattice " + std::to_string(id_)); } } else { orientation_ = Orientation::y; @@ -468,7 +488,9 @@ HexLattice::HexLattice(pugi::xml_node lat_node) } center_[0] = stod(center_words[0]); center_[1] = stod(center_words[1]); - if (is_3d_) {center_[2] = stod(center_words[2]);} + if (is_3d_) { + center_[2] = stod(center_words[2]); + } // Read the lattice pitches. std::string pitch_str {get_node_value(lat_node, "pitch")}; @@ -481,17 +503,19 @@ HexLattice::HexLattice(pugi::xml_node lat_node) "specified by 1 number."); } pitch_[0] = stod(pitch_words[0]); - if (is_3d_) {pitch_[1] = stod(pitch_words[1]);} + if (is_3d_) { + pitch_[1] = stod(pitch_words[1]); + } // Read the universes and make sure the correct number was specified. - int n_univ = (3*n_rings_*n_rings_ - 3*n_rings_ + 1) * n_axial_; + int n_univ = (3 * n_rings_ * n_rings_ - 3 * n_rings_ + 1) * n_axial_; std::string univ_str {get_node_value(lat_node, "universes")}; vector univ_words {split(univ_str)}; if (univ_words.size() != n_univ) { fatal_error(fmt::format( "Expected {} universes for a hexagonal lattice with {} rings and {} " - "axial levels but {} were specified.", n_univ, n_rings_, n_axial_, - univ_words.size())); + "axial levels but {} were specified.", + n_univ, n_rings_, n_axial_, univ_words.size())); } // Parse the universes. @@ -503,7 +527,7 @@ HexLattice::HexLattice(pugi::xml_node lat_node) // the following code walks a set of index values across the skewed array // in a manner that matches the input order. Note that i_x = 0, i_a = 0 // or i_a = 0, i_y = 0 corresponds to the center of the hexagonal lattice. - universes_.resize((2*n_rings_-1) * (2*n_rings_-1) * n_axial_, C_NONE); + universes_.resize((2 * n_rings_ - 1) * (2 * n_rings_ - 1) * n_axial_, C_NONE); if (orientation_ == Orientation::y) { fill_lattice_y(univ_words); } else { @@ -523,13 +547,13 @@ void HexLattice::fill_lattice_x(const vector& univ_words) // Map upper region of hexagonal lattice which is found in the // first n_rings-1 rows of the input. - for (int k = 0; k < n_rings_-1; k++) { + for (int k = 0; k < n_rings_ - 1; k++) { // Iterate over the input columns. - for (int j = 0; j < k+n_rings_; j++) { - int indx = (2*n_rings_-1)*(2*n_rings_-1) * m - + (2*n_rings_-1) * (i_y+n_rings_-1) - + (i_a+n_rings_-1); + for (int j = 0; j < k + n_rings_; j++) { + int indx = (2 * n_rings_ - 1) * (2 * n_rings_ - 1) * m + + (2 * n_rings_ - 1) * (i_y + n_rings_ - 1) + + (i_a + n_rings_ - 1); universes_[indx] = std::stoi(univ_words[input_index]); input_index++; // Move to the next right neighbour cell @@ -547,10 +571,10 @@ void HexLattice::fill_lattice_x(const vector& univ_words) i_a = -(n_rings_ - 1) + k; // Iterate over the input columns. - for (int j = 0; j < 2*n_rings_-k-1; j++) { - int indx = (2*n_rings_-1)*(2*n_rings_-1) * m - + (2*n_rings_-1) * (i_y+n_rings_-1) - + (i_a+n_rings_-1); + for (int j = 0; j < 2 * n_rings_ - k - 1; j++) { + int indx = (2 * n_rings_ - 1) * (2 * n_rings_ - 1) * m + + (2 * n_rings_ - 1) * (i_y + n_rings_ - 1) + + (i_a + n_rings_ - 1); universes_[indx] = std::stoi(univ_words[input_index]); input_index++; // Move to the next right neighbour cell @@ -575,15 +599,15 @@ void HexLattice::fill_lattice_y(const vector& univ_words) // Map upper triangular region of hexagonal lattice which is found in the // first n_rings-1 rows of the input. - for (int k = 0; k < n_rings_-1; k++) { + for (int k = 0; k < n_rings_ - 1; k++) { // Walk the index to lower-left neighbor of last row start. i_x -= 1; // Iterate over the input columns. - for (int j = 0; j < k+1; j++) { - int indx = (2*n_rings_-1)*(2*n_rings_-1) * m - + (2*n_rings_-1) * (i_a+n_rings_-1) - + (i_x+n_rings_-1); + for (int j = 0; j < k + 1; j++) { + int indx = (2 * n_rings_ - 1) * (2 * n_rings_ - 1) * m + + (2 * n_rings_ - 1) * (i_a + n_rings_ - 1) + + (i_x + n_rings_ - 1); universes_[indx] = std::stoi(univ_words[input_index]); input_index++; // Walk the index to the right neighbor (which is not adjacent). @@ -592,13 +616,13 @@ void HexLattice::fill_lattice_y(const vector& univ_words) } // Return the lattice index to the start of the current row. - i_x -= 2 * (k+1); - i_a += (k+1); + i_x -= 2 * (k + 1); + i_a += (k + 1); } // Map the middle square region of the hexagonal lattice which is found in // the next 2*n_rings-1 rows of the input. - for (int k = 0; k < 2*n_rings_-1; k++) { + for (int k = 0; k < 2 * n_rings_ - 1; k++) { if ((k % 2) == 0) { // Walk the index to the lower-left neighbor of the last row start. i_x -= 1; @@ -610,9 +634,9 @@ void HexLattice::fill_lattice_y(const vector& univ_words) // Iterate over the input columns. for (int j = 0; j < n_rings_ - (k % 2); j++) { - int indx = (2*n_rings_-1)*(2*n_rings_-1) * m - + (2*n_rings_-1) * (i_a+n_rings_-1) - + (i_x+n_rings_-1); + int indx = (2 * n_rings_ - 1) * (2 * n_rings_ - 1) * m + + (2 * n_rings_ - 1) * (i_a + n_rings_ - 1) + + (i_x + n_rings_ - 1); universes_[indx] = std::stoi(univ_words[input_index]); input_index++; // Walk the index to the right neighbor (which is not adjacent). @@ -621,21 +645,21 @@ void HexLattice::fill_lattice_y(const vector& univ_words) } // Return the lattice index to the start of the current row. - i_x -= 2*(n_rings_ - (k % 2)); + i_x -= 2 * (n_rings_ - (k % 2)); i_a += n_rings_ - (k % 2); } // Map the lower triangular region of the hexagonal lattice. - for (int k = 0; k < n_rings_-1; k++) { + for (int k = 0; k < n_rings_ - 1; k++) { // Walk the index to the lower-right neighbor of the last row start. i_x += 1; i_a -= 1; // Iterate over the input columns. - for (int j = 0; j < n_rings_-k-1; j++) { - int indx = (2*n_rings_-1)*(2*n_rings_-1) * m - + (2*n_rings_-1) * (i_a+n_rings_-1) - + (i_x+n_rings_-1); + for (int j = 0; j < n_rings_ - k - 1; j++) { + int indx = (2 * n_rings_ - 1) * (2 * n_rings_ - 1) * m + + (2 * n_rings_ - 1) * (i_a + n_rings_ - 1) + + (i_x + n_rings_ - 1); universes_[indx] = std::stoi(univ_words[input_index]); input_index++; // Walk the index to the right neighbor (which is not adjacent). @@ -644,7 +668,7 @@ void HexLattice::fill_lattice_y(const vector& univ_words) } // Return lattice index to start of current row. - i_x -= 2*(n_rings_ - k - 1); + i_x -= 2 * (n_rings_ - k - 1); i_a += n_rings_ - k - 1; } } @@ -654,30 +678,30 @@ void HexLattice::fill_lattice_y(const vector& univ_words) int32_t const& HexLattice::operator[](array const& i_xyz) { - int indx = (2*n_rings_-1)*(2*n_rings_-1) * i_xyz[2] - + (2*n_rings_-1) * i_xyz[1] - + i_xyz[0]; - return universes_[indx]; + return universes_[get_flat_index(i_xyz)]; } //============================================================================== LatticeIter HexLattice::begin() -{return LatticeIter(*this, n_rings_-1);} +{ + return LatticeIter(*this, n_rings_ - 1); +} ReverseLatticeIter HexLattice::rbegin() -{return ReverseLatticeIter(*this, universes_.size()-n_rings_);} +{ + return ReverseLatticeIter(*this, universes_.size() - n_rings_); +} //============================================================================== bool HexLattice::are_valid_indices(array const& i_xyz) const { // Check if (x, alpha, z) indices are valid, accounting for number of rings - return ((i_xyz[0] >= 0) && (i_xyz[1] >= 0) && (i_xyz[2] >= 0) - && (i_xyz[0] < 2*n_rings_-1) && (i_xyz[1] < 2*n_rings_-1) - && (i_xyz[0] + i_xyz[1] > n_rings_-2) - && (i_xyz[0] + i_xyz[1] < 3*n_rings_-2) - && (i_xyz[2] < n_axial_)); + return ((i_xyz[0] >= 0) && (i_xyz[1] >= 0) && (i_xyz[2] >= 0) && + (i_xyz[0] < 2 * n_rings_ - 1) && (i_xyz[1] < 2 * n_rings_ - 1) && + (i_xyz[0] + i_xyz[1] > n_rings_ - 2) && + (i_xyz[0] + i_xyz[1] < 3 * n_rings_ - 2) && (i_xyz[2] < n_axial_)); } //============================================================================== @@ -704,13 +728,13 @@ std::pair> HexLattice::distance( double gamma_dir; double delta_dir; if (orientation_ == Orientation::y) { - beta_dir = u.x * std::sqrt(3.0) / 2.0 + u.y / 2.0; - gamma_dir = u.x * std::sqrt(3.0) / 2.0 - u.y / 2.0; + beta_dir = u.x * std::sqrt(3.0) / 2.0 + u.y / 2.0; + gamma_dir = u.x * std::sqrt(3.0) / 2.0 - u.y / 2.0; delta_dir = u.y; } else { beta_dir = u.x; - gamma_dir = u.x / 2.0 - u.y * std::sqrt(3.0) / 2.0; - delta_dir = u.x / 2.0 + u.y * std::sqrt(3.0) / 2.0; + gamma_dir = u.x / 2.0 - u.y * std::sqrt(3.0) / 2.0; + delta_dir = u.x / 2.0 + u.y * std::sqrt(3.0) / 2.0; } // Note that hexagonal lattice distance calculations are performed @@ -722,7 +746,7 @@ std::pair> HexLattice::distance( // beta direction double d {INFTY}; array lattice_trans; - double edge = -copysign(0.5*pitch_[0], beta_dir); // Oncoming edge + double edge = -copysign(0.5 * pitch_[0], beta_dir); // Oncoming edge Position r_t; if (beta_dir > 0) { const array i_xyz_t {i_xyz[0] + 1, i_xyz[1], i_xyz[2]}; @@ -747,7 +771,7 @@ std::pair> HexLattice::distance( } // gamma direction - edge = -copysign(0.5*pitch_[0], gamma_dir); + edge = -copysign(0.5 * pitch_[0], gamma_dir); if (gamma_dir > 0) { const array i_xyz_t {i_xyz[0] + 1, i_xyz[1] - 1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); @@ -759,7 +783,7 @@ std::pair> HexLattice::distance( if (orientation_ == Orientation::y) { gamma = r_t.x * std::sqrt(3.0) / 2.0 - r_t.y / 2.0; } else { - gamma = r_t.x / 2.0 - r_t.y * std::sqrt(3.0) / 2.0; + gamma = r_t.x / 2.0 - r_t.y * std::sqrt(3.0) / 2.0; } if ((std::abs(gamma - edge) > FP_PRECISION) && gamma_dir != 0) { double this_d = (edge - gamma) / gamma_dir; @@ -774,7 +798,7 @@ std::pair> HexLattice::distance( } // delta direction - edge = -copysign(0.5*pitch_[0], delta_dir); + edge = -copysign(0.5 * pitch_[0], delta_dir); if (delta_dir > 0) { const array i_xyz_t {i_xyz[0], i_xyz[1] + 1, i_xyz[2]}; r_t = get_local_position(r, i_xyz_t); @@ -784,9 +808,9 @@ std::pair> HexLattice::distance( } double delta; if (orientation_ == Orientation::y) { - delta = r_t.y; + delta = r_t.y; } else { - delta = r_t.x / 2.0 + r_t.y * std::sqrt(3.0) / 2.0; + delta = r_t.x / 2.0 + r_t.y * std::sqrt(3.0) / 2.0; } if ((std::abs(delta - edge) > FP_PRECISION) && delta_dir != 0) { double this_d = (edge - delta) / delta_dir; @@ -828,7 +852,9 @@ void HexLattice::get_indices( { // Offset the xyz by the lattice center. Position r_o {r.x - center_.x, r.y - center_.y, r.z}; - if (is_3d_) {r_o.z -= center_.z;} + if (is_3d_) { + r_o.z -= center_.z; + } // Index the z direction, accounting for coincidence result[2] = 0; @@ -888,20 +914,21 @@ void HexLattice::get_indices( const array i_xyz {result[0] + j, result[1] + i, 0}; Position r_t = get_local_position(r, i_xyz); // calculate distance - double d = r_t.x*r_t.x + r_t.y*r_t.y; + double d = r_t.x * r_t.x + r_t.y * r_t.y; // check for coincidence. Because the numerical error incurred // in hex geometry is higher than other geometries, the relative // coincidence is checked here so that coincidence is successfully // detected on large hex lattice with particles far from the origin // which have rounding errors larger than the FP_COINCIDENT thresdhold. - bool on_boundary = coincident(1.0, d_min/d); + bool on_boundary = coincident(1.0, d_min / d); if (d < d_min || on_boundary) { // normalize r_t and find dot product r_t /= std::sqrt(d); double dp = u.x * r_t.x + u.y * r_t.y; // do not update values if particle is on a // boundary and not moving into this cell - if (on_boundary && dp > dp_min) continue; + if (on_boundary && dp > dp_min) + continue; // update values d_min = d; i1_chg = j; @@ -916,6 +943,12 @@ void HexLattice::get_indices( result[1] += i2_chg; } +int HexLattice::get_flat_index(const array& i_xyz) const +{ + return (2 * n_rings_ - 1) * (2 * n_rings_ - 1) * i_xyz[2] + + (2 * n_rings_ - 1) * i_xyz[1] + i_xyz[0]; +} + //============================================================================== Position HexLattice::get_local_position( @@ -923,37 +956,36 @@ Position HexLattice::get_local_position( { if (orientation_ == Orientation::y) { // x_l = x_g - (center + pitch_x*cos(30)*index_x) - r.x -= center_.x - + std::sqrt(3.0)/2.0 * (i_xyz[0] - n_rings_ + 1) * pitch_[0]; + r.x -= + center_.x + std::sqrt(3.0) / 2.0 * (i_xyz[0] - n_rings_ + 1) * pitch_[0]; // y_l = y_g - (center + pitch_x*index_x + pitch_y*sin(30)*index_y) - r.y -= (center_.y + (i_xyz[1] - n_rings_ + 1) * pitch_[0] - + (i_xyz[0] - n_rings_ + 1) * pitch_[0] / 2.0); + r.y -= (center_.y + (i_xyz[1] - n_rings_ + 1) * pitch_[0] + + (i_xyz[0] - n_rings_ + 1) * pitch_[0] / 2.0); } else { // x_l = x_g - (center + pitch_x*index_a + pitch_y*sin(30)*index_y) - r.x -= (center_.x + (i_xyz[0] - n_rings_ + 1) * pitch_[0] - + (i_xyz[1] - n_rings_ + 1) * pitch_[0] / 2.0); + r.x -= (center_.x + (i_xyz[0] - n_rings_ + 1) * pitch_[0] + + (i_xyz[1] - n_rings_ + 1) * pitch_[0] / 2.0); // y_l = y_g - (center + pitch_y*cos(30)*index_y) - r.y -= center_.y - + std::sqrt(3.0)/2.0 * (i_xyz[1] - n_rings_ + 1) * pitch_[0]; + r.y -= + center_.y + std::sqrt(3.0) / 2.0 * (i_xyz[1] - n_rings_ + 1) * pitch_[0]; } if (is_3d_) { - r.z -= center_.z - (0.5 * n_axial_ - i_xyz[2] - 0.5) * pitch_[1]; - } + r.z -= center_.z - (0.5 * n_axial_ - i_xyz[2] - 0.5) * pitch_[1]; + } return r; } //============================================================================== -bool -HexLattice::is_valid_index(int indx) const +bool HexLattice::is_valid_index(int indx) const { - int nx {2*n_rings_ - 1}; - int ny {2*n_rings_ - 1}; + int nx {2 * n_rings_ - 1}; + int ny {2 * n_rings_ - 1}; int iz = indx / (nx * ny); - int iy = (indx - nx*ny*iz) / nx; - int ix = indx - nx*ny*iz - nx*iy; + int iy = (indx - nx * ny * iz) / nx; + int ix = indx - nx * ny * iz - nx * iy; array i_xyz {ix, iy, iz}; return are_valid_indices(i_xyz); } @@ -962,28 +994,27 @@ HexLattice::is_valid_index(int indx) const int32_t& HexLattice::offset(int map, array const& i_xyz) { - int nx {2*n_rings_ - 1}; - int ny {2*n_rings_ - 1}; + int nx {2 * n_rings_ - 1}; + int ny {2 * n_rings_ - 1}; int nz {n_axial_}; - return offsets_[nx*ny*nz*map + nx*ny*i_xyz[2] + nx*i_xyz[1] + i_xyz[0]]; + return offsets_[nx * ny * nz * map + nx * ny * i_xyz[2] + nx * i_xyz[1] + + i_xyz[0]]; } -int32_t -HexLattice::offset(int map, int indx) const +int32_t HexLattice::offset(int map, int indx) const { - int nx {2*n_rings_ - 1}; - int ny {2*n_rings_ - 1}; + int nx {2 * n_rings_ - 1}; + int ny {2 * n_rings_ - 1}; int nz {n_axial_}; - return offsets_[nx*ny*nz*map + indx]; + return offsets_[nx * ny * nz * map + indx]; } //============================================================================== -std::string -HexLattice::index_to_string(int indx) const +std::string HexLattice::index_to_string(int indx) const { - int nx {2*n_rings_ - 1}; - int ny {2*n_rings_ - 1}; + int nx {2 * n_rings_ - 1}; + int ny {2 * n_rings_ - 1}; int iz {indx / (nx * ny)}; int iy {(indx - nx * ny * iz) / nx}; int ix {indx - nx * ny * iz - nx * iy}; @@ -999,8 +1030,7 @@ HexLattice::index_to_string(int indx) const //============================================================================== -void -HexLattice::to_hdf5_inner(hid_t lat_group) const +void HexLattice::to_hdf5_inner(hid_t lat_group) const { // Write basic lattice information. write_string(lat_group, "type", "hexagonal", false); @@ -1022,19 +1052,19 @@ HexLattice::to_hdf5_inner(hid_t lat_group) const } // Write the universe ids. - hsize_t nx {static_cast(2*n_rings_ - 1)}; - hsize_t ny {static_cast(2*n_rings_ - 1)}; + hsize_t nx {static_cast(2 * n_rings_ - 1)}; + hsize_t ny {static_cast(2 * n_rings_ - 1)}; hsize_t nz {static_cast(n_axial_)}; vector out(nx * ny * nz); for (int m = 0; m < nz; m++) { for (int k = 0; k < ny; k++) { for (int j = 0; j < nx; j++) { - int indx = nx*ny*m + nx*k + j; + int indx = nx * ny * m + nx * k + j; if (j + k < n_rings_ - 1) { // This array position is never used; put a -1 to indicate this. out[indx] = -1; - } else if (j + k > 3*n_rings_ - 3) { + } else if (j + k > 3 * n_rings_ - 3) { // This array position is never used; put a -1 to indicate this. out[indx] = -1; } else { @@ -1068,8 +1098,8 @@ void read_lattices(pugi::xml_node node) if (in_map == model::lattice_map.end()) { model::lattice_map[id] = i_lat; } else { - fatal_error(fmt::format( - "Two or more lattices use the same unique ID: {}", id)); + fatal_error( + fmt::format("Two or more lattices use the same unique ID: {}", id)); } } } diff --git a/src/main.cpp b/src/main.cpp index ccd2005bf5d..88251ac7232 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,10 +6,11 @@ #include "openmc/error.h" #include "openmc/message_passing.h" #include "openmc/particle_restart.h" +#include "openmc/random_ray/random_ray_simulation.h" #include "openmc/settings.h" - -int main(int argc, char* argv[]) { +int main(int argc, char* argv[]) +{ using namespace openmc; int err; @@ -29,30 +30,41 @@ int main(int argc, char* argv[]) { // start problem based on mode switch (settings::run_mode) { - case RunMode::FIXED_SOURCE: - case RunMode::EIGENVALUE: + case RunMode::FIXED_SOURCE: + case RunMode::EIGENVALUE: + switch (settings::solver_type) { + case SolverType::MONTE_CARLO: err = openmc_run(); break; - case RunMode::PLOTTING: - err = openmc_plot_geometry(); - break; - case RunMode::PARTICLE: - if (mpi::master) run_particle_restart(); + case SolverType::RANDOM_RAY: + openmc_run_random_ray(); err = 0; break; - case RunMode::VOLUME: - err = openmc_calculate_volumes(); - break; - default: - break; + } + break; + case RunMode::PLOTTING: + err = openmc_plot_geometry(); + break; + case RunMode::PARTICLE: + if (mpi::master) + run_particle_restart(); + err = 0; + break; + case RunMode::VOLUME: + err = openmc_calculate_volumes(); + break; + default: + break; } - if (err) fatal_error(openmc_err_msg); + if (err) + fatal_error(openmc_err_msg); // Finalize and free up memory err = openmc_finalize(); - if (err) fatal_error(openmc_err_msg); + if (err) + fatal_error(openmc_err_msg); - // If MPI is in use and enabled, terminate it + // If MPI is in use and enabled, terminate it #ifdef OPENMC_MPI MPI_Finalize(); #endif diff --git a/src/material.cpp b/src/material.cpp index 59d2f954e45..aad7008e703 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -3,8 +3,8 @@ #include // for min, max, sort, fill #include #include -#include #include +#include #include #include "xtensor/xbuilder.hpp" @@ -12,9 +12,8 @@ #include "xtensor/xview.hpp" #include "openmc/capi.h" -#include "openmc/cross_sections.h" #include "openmc/container_util.h" -#include "openmc/dagmc.h" +#include "openmc/cross_sections.h" #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/hdf5_interface.h" @@ -61,6 +60,13 @@ Material::Material(pugi::xml_node node) name_ = get_node_value(node, "name"); } + if (check_for_node(node, "cfg")) { + auto cfg = get_node_value(node, "cfg"); + write_message( + 5, "NCrystal config string for material #{}: '{}'", this->id(), cfg); + ncrystal_mat_ = NCrystalMat(cfg); + } + if (check_for_node(node, "depletable")) { depletable_ = get_node_value_bool(node, "depletable"); } @@ -81,8 +87,8 @@ Material::Material(pugi::xml_node node) } else { double val = std::stod(get_node_value(density_node, "value")); if (val <= 0.0) { - fatal_error("Need to specify a positive density on material " - + std::to_string(id_) + "."); + fatal_error("Need to specify a positive density on material " + + std::to_string(id_) + "."); } if (units == "g/cc" || units == "g/cm3") { @@ -94,17 +100,18 @@ Material::Material(pugi::xml_node node) } else if (units == "atom/cc" || units == "atom/cm3") { density_ = 1.0e-24 * val; } else { - fatal_error("Unknown units '" + units + "' specified on material " - + std::to_string(id_) + "."); + fatal_error("Unknown units '" + units + "' specified on material " + + std::to_string(id_) + "."); } } } else { - fatal_error("Must specify element in material " - + std::to_string(id_) + "."); + fatal_error("Must specify element in material " + + std::to_string(id_) + "."); } if (node.child("element")) { - fatal_error("Unable to add an element to material " + std::to_string(id_) + + fatal_error( + "Unable to add an element to material " + std::to_string(id_) + " since the element option has been removed from the xml input. " "Elements can only be added via the Python API, which will expand " "elements into their natural nuclides."); @@ -114,9 +121,10 @@ Material::Material(pugi::xml_node node) // READ AND PARSE TAGS // Check to ensure material has at least one nuclide - if (!check_for_node(node, "nuclide") && !check_for_node(node, "macroscopic")) { - fatal_error("No macroscopic data or nuclides specified on material " - + std::to_string(id_)); + if (!check_for_node(node, "nuclide") && + !check_for_node(node, "macroscopic")) { + fatal_error("No macroscopic data or nuclides specified on material " + + std::to_string(id_)); } // Create list of macroscopic x/s based on those specified, just treat @@ -132,15 +140,15 @@ Material::Material(pugi::xml_node node) if (settings::run_CE && num_macros > 0) { fatal_error("Macroscopic can not be used in continuous-energy mode."); } else if (num_macros > 1) { - fatal_error("Only one macroscopic object permitted per material, " - + std::to_string(id_)); + fatal_error("Only one macroscopic object permitted per material, " + + std::to_string(id_)); } else if (num_macros == 1) { pugi::xml_node node_nuc = *node_macros.begin(); // Check for empty name on nuclide if (!check_for_node(node_nuc, "name")) { - fatal_error("No name specified on macroscopic data in material " - + std::to_string(id_)); + fatal_error("No name specified on macroscopic data in material " + + std::to_string(id_)); } // store nuclide name @@ -158,8 +166,8 @@ Material::Material(pugi::xml_node node) for (auto node_nuc : node.children("nuclide")) { // Check for empty name on nuclide if (!check_for_node(node_nuc, "name")) { - fatal_error("No name specified on nuclide in material " - + std::to_string(id_)); + fatal_error( + "No name specified on nuclide in material " + std::to_string(id_)); } // store nuclide name @@ -175,10 +183,12 @@ Material::Material(pugi::xml_node node) bool has_wo = check_for_node(node_nuc, "wo"); if (!has_ao && !has_wo) { - fatal_error("No atom or weight percent specified for nuclide: " + name); + fatal_error( + "No atom or weight percent specified for nuclide: " + name); } else if (has_ao && has_wo) { fatal_error("Cannot specify both atom and weight percents for a " - "nuclide: " + name); + "nuclide: " + + name); } // Copy atom/weight percents @@ -206,17 +216,21 @@ Material::Material(pugi::xml_node node) auto n = names.size(); nuclide_.reserve(n); atom_density_ = xt::empty({n}); - if (settings::photon_transport) element_.reserve(n); + if (settings::photon_transport) + element_.reserve(n); for (int i = 0; i < n; ++i) { const auto& name {names[i]}; // Check that this nuclide is listed in the nuclear data library // (cross_sections.xml for CE and the MGXS HDF5 for MG) - LibraryKey key {Library::Type::neutron, name}; - if (data::library_map.find(key) == data::library_map.end()) { - fatal_error("Could not find nuclide " + name + " in the " - "nuclear data library."); + if (settings::run_mode != RunMode::PLOTTING) { + LibraryKey key {Library::Type::neutron, name}; + if (data::library_map.find(key) == data::library_map.end()) { + fatal_error("Could not find nuclide " + name + + " in the " + "nuclear data library."); + } } // If this nuclide hasn't been encountered yet, we need to add its name @@ -235,10 +249,12 @@ Material::Material(pugi::xml_node node) std::string element = to_element(name); // Make sure photon cross section data is available - LibraryKey key {Library::Type::photon, element}; - if (data::library_map.find(key) == data::library_map.end()) { - fatal_error("Could not find element " + element - + " in cross_sections.xml."); + if (settings::run_mode != RunMode::PLOTTING) { + LibraryKey key {Library::Type::photon, element}; + if (data::library_map.find(key) == data::library_map.end()) { + fatal_error( + "Could not find element " + element + " in cross_sections.xml."); + } } if (data::element_map.find(element) == data::element_map.end()) { @@ -274,13 +290,13 @@ Material::Material(pugi::xml_node node) // Check to make sure either all atom percents or all weight percents are // given if (!(xt::all(atom_density_ >= 0.0) || xt::all(atom_density_ <= 0.0))) { - fatal_error("Cannot mix atom and weight percents in material " - + std::to_string(id_)); + fatal_error( + "Cannot mix atom and weight percents in material " + std::to_string(id_)); } // Determine density if it is a sum value - if (sum_density) density_ = xt::sum(atom_density_)(); - + if (sum_density) + density_ = xt::sum(atom_density_)(); if (check_for_node(node, "temperature")) { temperature_ = std::stod(get_node_value(node, "temperature")); @@ -312,10 +328,12 @@ Material::Material(pugi::xml_node node) // Check that the thermal scattering table is listed in the // cross_sections.xml file - LibraryKey key {Library::Type::thermal, name}; - if (data::library_map.find(key) == data::library_map.end()) { - fatal_error("Could not find thermal scattering data " + name + - " in cross_sections.xml file."); + if (settings::run_mode != RunMode::PLOTTING) { + LibraryKey key {Library::Type::thermal, name}; + if (data::library_map.find(key) == data::library_map.end()) { + fatal_error("Could not find thermal scattering data " + name + + " in cross_sections.xml file."); + } } // Determine index of thermal scattering data in global @@ -341,23 +359,55 @@ Material::~Material() model::material_map.erase(id_); } +Material& Material::clone() +{ + std::unique_ptr mat = std::make_unique(); + + // set all other parameters to whatever the calling Material has + mat->name_ = name_; + mat->nuclide_ = nuclide_; + mat->element_ = element_; + mat->ncrystal_mat_ = ncrystal_mat_; + mat->atom_density_ = atom_density_; + mat->density_ = density_; + mat->density_gpcc_ = density_gpcc_; + mat->volume_ = volume_; + mat->fissionable() = fissionable_; + mat->depletable() = depletable_; + mat->p0_ = p0_; + mat->mat_nuclide_index_ = mat_nuclide_index_; + mat->thermal_tables_ = thermal_tables_; + mat->temperature_ = temperature_; + + if (ttb_) + mat->ttb_ = std::make_unique(*ttb_); + + mat->index_ = model::materials.size(); + mat->set_id(C_NONE); + model::materials.push_back(std::move(mat)); + return *model::materials.back(); +} + void Material::finalize() { // Set fissionable if any nuclide is fissionable - for (const auto& i_nuc : nuclide_) { - if (data::nuclides[i_nuc]->fissionable_) { - fissionable_ = true; - break; + if (settings::run_CE) { + for (const auto& i_nuc : nuclide_) { + if (data::nuclides[i_nuc]->fissionable_) { + fissionable_ = true; + break; + } } - } - // Generate material bremsstrahlung data for electrons and positrons - if (settings::photon_transport && settings::electron_treatment == ElectronTreatment::TTB) { - this->init_bremsstrahlung(); - } + // Generate material bremsstrahlung data for electrons and positrons + if (settings::photon_transport && + settings::electron_treatment == ElectronTreatment::TTB) { + this->init_bremsstrahlung(); + } - // Assign thermal scattering tables - this->init_thermal(); + // Assign thermal scattering tables + this->init_thermal(); + } // Normalize density this->normalize_density(); @@ -371,13 +421,14 @@ void Material::normalize_density() for (int i = 0; i < nuclide_.size(); ++i) { // determine atomic weight ratio int i_nuc = nuclide_[i]; - double awr = settings::run_CE ? - data::nuclides[i_nuc]->awr_ : data::mg.nuclides_[i_nuc].awr; + double awr = settings::run_CE ? data::nuclides[i_nuc]->awr_ + : data::mg.nuclides_[i_nuc].awr; // if given weight percent, convert all values so that they are divided // by awr. thus, when a sum is done over the values, it's actually // sum(w/awr) - if (!percent_in_atom) atom_density_(i) = -atom_density_(i) / awr; + if (!percent_in_atom) + atom_density_(i) = -atom_density_(i) / awr; } // determine normalized atom percents. if given atom percents, this is @@ -391,9 +442,9 @@ void Material::normalize_density() double sum_percent = 0.0; for (int i = 0; i < nuclide_.size(); ++i) { int i_nuc = nuclide_[i]; - double awr = settings::run_CE ? - data::nuclides[i_nuc]->awr_ : data::mg.nuclides_[i_nuc].awr; - sum_percent += atom_density_(i)*awr; + double awr = settings::run_CE ? data::nuclides[i_nuc]->awr_ + : data::mg.nuclides_[i_nuc].awr; + sum_percent += atom_density_(i) * awr; } sum_percent = 1.0 / sum_percent; density_ = -density_ * N_AVOGADRO / MASS_NEUTRON * sum_percent; @@ -437,19 +488,22 @@ void Material::init_thermal() // Check to make sure thermal scattering table matched a nuclide if (!found) { - fatal_error("Thermal scattering table " + data::thermal_scatt[ - table.index_table]->name_ + " did not match any nuclide on material " - + std::to_string(id_)); + fatal_error("Thermal scattering table " + + data::thermal_scatt[table.index_table]->name_ + + " did not match any nuclide on material " + + std::to_string(id_)); } } // Make sure each nuclide only appears in one table. for (int j = 0; j < tables.size(); ++j) { - for (int k = j+1; k < tables.size(); ++k) { + for (int k = j + 1; k < tables.size(); ++k) { if (tables[j].index_nuclide == tables[k].index_nuclide) { int index = nuclide_[tables[j].index_nuclide]; auto name = data::nuclides[index]->name_; - fatal_error(name + " in material " + std::to_string(id_) + " was found " + fatal_error( + name + " in material " + std::to_string(id_) + + " was found " "in multiple thermal scattering tables. Each nuclide can appear in " "only one table per material."); } @@ -489,8 +543,8 @@ void Material::collision_stopping_power(double* s_col, bool positron) double awr = data::nuclides[nuclide_[i]]->awr_; // Get atomic density of nuclide given atom/weight percent - double atom_density = (atom_density_[0] > 0.0) ? - atom_density_[i] : -atom_density_[i] / awr; + double atom_density = + (atom_density_[0] > 0.0) ? atom_density_[i] : -atom_density_[i] / awr; electron_density += atom_density * elm.Z_; mass_density += atom_density * awr * MASS_NEUTRON; @@ -507,58 +561,60 @@ void Material::collision_stopping_power(double* s_col, bool positron) } log_I /= electron_density; n_conduction /= electron_density; - for (auto& f_i : f) f_i /= electron_density; + for (auto& f_i : f) + f_i /= electron_density; // Get density in g/cm^3 if it is given in atom/b-cm double density = (density_ < 0.0) ? -density_ : mass_density / N_AVOGADRO; // Calculate the square of the plasma energy - double e_p_sq = PLANCK_C * PLANCK_C * PLANCK_C * N_AVOGADRO * - electron_density * density / (2.0 * PI * PI * FINE_STRUCTURE * - MASS_ELECTRON_EV * mass_density); + double e_p_sq = + PLANCK_C * PLANCK_C * PLANCK_C * N_AVOGADRO * electron_density * density / + (2.0 * PI * PI * FINE_STRUCTURE * MASS_ELECTRON_EV * mass_density); // Get the Sternheimer adjustment factor - double rho = sternheimer_adjustment(f, e_b_sq, e_p_sq, n_conduction, log_I, - 1.0e-6, 100); + double rho = + sternheimer_adjustment(f, e_b_sq, e_p_sq, n_conduction, log_I, 1.0e-6, 100); // Classical electron radius in cm constexpr double CM_PER_ANGSTROM {1.0e-8}; - constexpr double r_e = CM_PER_ANGSTROM * PLANCK_C / (2.0 * PI * - FINE_STRUCTURE * MASS_ELECTRON_EV); + constexpr double r_e = + CM_PER_ANGSTROM * PLANCK_C / (2.0 * PI * FINE_STRUCTURE * MASS_ELECTRON_EV); // Constant in expression for collision stopping power constexpr double BARN_PER_CM_SQ {1.0e24}; - double c = BARN_PER_CM_SQ * 2.0 * PI * r_e * r_e * MASS_ELECTRON_EV * - electron_density; + double c = + BARN_PER_CM_SQ * 2.0 * PI * r_e * r_e * MASS_ELECTRON_EV * electron_density; // Loop over incident charged particle energies for (int i = 0; i < data::ttb_e_grid.size(); ++i) { double E = data::ttb_e_grid(i); // Get the density effect correction - double delta = density_effect(f, e_b_sq, e_p_sq, n_conduction, rho, E, - 1.0e-6, 100); + double delta = + density_effect(f, e_b_sq, e_p_sq, n_conduction, rho, E, 1.0e-6, 100); // Square of the ratio of the speed of light to the velocity of the charged // particle - double beta_sq = E * (E + 2.0 * MASS_ELECTRON_EV) / ((E + MASS_ELECTRON_EV) - * (E + MASS_ELECTRON_EV)); + double beta_sq = E * (E + 2.0 * MASS_ELECTRON_EV) / + ((E + MASS_ELECTRON_EV) * (E + MASS_ELECTRON_EV)); double tau = E / MASS_ELECTRON_EV; double F; if (positron) { double t = tau + 2.0; - F = std::log(4.0) - (beta_sq / 12.0) * (23.0 + 14.0 / t + 10.0 / (t * t) - + 4.0 / (t * t * t)); + F = std::log(4.0) - (beta_sq / 12.0) * (23.0 + 14.0 / t + 10.0 / (t * t) + + 4.0 / (t * t * t)); } else { - F = (1.0 - beta_sq) * (1.0 + tau * tau / 8.0 - (2.0 * tau + 1.0) * - std::log(2.0)); + F = (1.0 - beta_sq) * + (1.0 + tau * tau / 8.0 - (2.0 * tau + 1.0) * std::log(2.0)); } // Calculate the collision stopping power for this energy - s_col[i] = c / beta_sq * (2.0 * (std::log(E) - log_I) + std::log(1.0 + tau - / 2.0) + F - delta); + s_col[i] = + c / beta_sq * + (2.0 * (std::log(E) - log_I) + std::log(1.0 + tau / 2.0) + F - delta); } } @@ -576,7 +632,8 @@ void Material::init_bremsstrahlung() for (int particle = 0; particle < 2; ++particle) { // Loop over logic twice, once for electron, once for positron - BremsstrahlungData* ttb = (particle == 0) ? &ttb_->electron : &ttb_->positron; + BremsstrahlungData* ttb = + (particle == 0) ? &ttb_->electron : &ttb_->positron; bool positron = (particle == 1); // Allocate arrays for TTB data @@ -595,16 +652,17 @@ void Material::init_bremsstrahlung() // Get the collision stopping power of the material this->collision_stopping_power(stopping_power_collision.data(), positron); - // Calculate the molecular DCS and the molecular radiative stopping power using - // Bragg's additivity rule. + // Calculate the molecular DCS and the molecular radiative stopping power + // using Bragg's additivity rule. for (int i = 0; i < n; ++i) { // Get pointer to current element const auto& elm = *data::elements[element_[i]]; double awr = data::nuclides[nuclide_[i]]->awr_; - // Get atomic density and mass density of nuclide given atom/weight percent - double atom_density = (atom_density_[0] > 0.0) ? - atom_density_[i] : -atom_density_[i] / awr; + // Get atomic density and mass density of nuclide given atom/weight + // percent + double atom_density = + (atom_density_[0] > 0.0) ? atom_density_[i] : -atom_density_[i] / awr; // Calculate the "equivalent" atomic number Zeq of the material Z_eq_sq += atom_density * elm.Z_ * elm.Z_; @@ -627,11 +685,14 @@ void Material::init_bremsstrahlung() // Issy-les-Moulineaux, France (2011). if (positron) { for (int i = 0; i < n_e; ++i) { - double t = std::log(1.0 + 1.0e6*data::ttb_e_grid(i)/(Z_eq_sq*MASS_ELECTRON_EV)); - double r = 1.0 - std::exp(-1.2359e-1*t + 6.1274e-2*std::pow(t, 2) - - 3.1516e-2*std::pow(t, 3) + 7.7446e-3*std::pow(t, 4) - - 1.0595e-3*std::pow(t, 5) + 7.0568e-5*std::pow(t, 6) - - 1.808e-6*std::pow(t, 7)); + double t = std::log( + 1.0 + 1.0e6 * data::ttb_e_grid(i) / (Z_eq_sq * MASS_ELECTRON_EV)); + double r = + 1.0 - + std::exp(-1.2359e-1 * t + 6.1274e-2 * std::pow(t, 2) - + 3.1516e-2 * std::pow(t, 3) + 7.7446e-3 * std::pow(t, 4) - + 1.0595e-3 * std::pow(t, 5) + 7.0568e-5 * std::pow(t, 6) - + 1.808e-6 * std::pow(t, 7)); stopping_power_radiative(i) *= r; auto dcs_i = xt::view(dcs, i, xt::all()); dcs_i *= r; @@ -639,8 +700,8 @@ void Material::init_bremsstrahlung() } // Total material stopping power - xt::xtensor stopping_power = stopping_power_collision + - stopping_power_radiative; + xt::xtensor stopping_power = + stopping_power_collision + stopping_power_radiative; // Loop over photon energies xt::xtensor f({n_e}, 0.0); @@ -656,8 +717,8 @@ void Material::init_bremsstrahlung() double k = w / e; // Find the lower bounding index of the reduced photon energy - int i_k = lower_bound_index(data::ttb_k_grid.cbegin(), - data::ttb_k_grid.cend(), k); + int i_k = lower_bound_index( + data::ttb_k_grid.cbegin(), data::ttb_k_grid.cend(), k); // Get the interpolation bounds double k_l = data::ttb_k_grid(i_k); @@ -667,12 +728,12 @@ void Material::init_bremsstrahlung() // Find the value of the DCS using linear interpolation in reduced // photon energy k - double x = x_l + (k - k_l)*(x_r - x_l)/(k_r - k_l); + double x = x_l + (k - k_l) * (x_r - x_l) / (k_r - k_l); // Square of the ratio of the speed of light to the velocity of the // charged particle - double beta_sq = e * (e + 2.0 * MASS_ELECTRON_EV) / ((e + - MASS_ELECTRON_EV) * (e + MASS_ELECTRON_EV)); + double beta_sq = e * (e + 2.0 * MASS_ELECTRON_EV) / + ((e + MASS_ELECTRON_EV) * (e + MASS_ELECTRON_EV)); // Compute the integrand of the PDF f(j) = x / (beta_sq * stopping_power(j) * w); @@ -689,19 +750,20 @@ void Material::init_bremsstrahlung() double c = 0.0; for (int j = i; j < n_e - 1; ++j) { c += spline_integrate(n, &data::ttb_e_grid(i), &f(i), &z(i), - data::ttb_e_grid(j), data::ttb_e_grid(j+1)); + data::ttb_e_grid(j), data::ttb_e_grid(j + 1)); - ttb->pdf(j+1,i) = c; + ttb->pdf(j + 1, i) = c; } - // Integrate the last two points using trapezoidal rule in log-log space + // Integrate the last two points using trapezoidal rule in log-log space } else { double e_l = std::log(data::ttb_e_grid(i)); - double e_r = std::log(data::ttb_e_grid(i+1)); + double e_r = std::log(data::ttb_e_grid(i + 1)); double x_l = std::log(f(i)); - double x_r = std::log(f(i+1)); + double x_r = std::log(f(i + 1)); - ttb->pdf(i+1,i) = 0.5*(e_r - e_l)*(std::exp(e_l + x_l) + std::exp(e_r + x_r)); + ttb->pdf(i + 1, i) = + 0.5 * (e_r - e_l) * (std::exp(e_l + x_l) + std::exp(e_r + x_r)); } } @@ -709,7 +771,7 @@ void Material::init_bremsstrahlung() for (int j = 1; j < n_e; ++j) { // Set last element of PDF to small non-zero value to enable log-log // interpolation - ttb->pdf(j,j) = std::exp(-500.0); + ttb->pdf(j, j) = std::exp(-500.0); // Loop over photon energies double c = 0.0; @@ -717,12 +779,12 @@ void Material::init_bremsstrahlung() // Integrate the CDF from the PDF using the trapezoidal rule in log-log // space double w_l = std::log(data::ttb_e_grid(i)); - double w_r = std::log(data::ttb_e_grid(i+1)); - double x_l = std::log(ttb->pdf(j,i)); - double x_r = std::log(ttb->pdf(j,i+1)); + double w_r = std::log(data::ttb_e_grid(i + 1)); + double x_l = std::log(ttb->pdf(j, i)); + double x_r = std::log(ttb->pdf(j, i + 1)); - c += 0.5*(w_r - w_l)*(std::exp(w_l + x_l) + std::exp(w_r + x_r)); - ttb->cdf(j,i+1) = c; + c += 0.5 * (w_r - w_l) * (std::exp(w_l + x_l) + std::exp(w_r + x_r)); + ttb->cdf(j, i + 1) = c; } // Set photon number yield @@ -736,8 +798,7 @@ void Material::init_bremsstrahlung() void Material::init_nuclide_index() { - int n = settings::run_CE ? - data::nuclides.size() : data::mg.nuclides_.size(); + int n = settings::run_CE ? data::nuclides.size() : data::mg.nuclides_.size(); mat_nuclide_index_.resize(n); std::fill(mat_nuclide_index_.begin(), mat_nuclide_index_.end(), C_NONE); for (int i = 0; i < nuclide_.size(); ++i) { @@ -773,6 +834,12 @@ void Material::calculate_neutron_xs(Particle& p) const // Initialize position in i_sab_nuclides int j = 0; + // Calculate NCrystal cross section + double ncrystal_xs = -1.0; + if (ncrystal_mat_ && p.E() < NCRYSTAL_MAX_ENERGY) { + ncrystal_xs = ncrystal_mat_.xs(p); + } + // Add contribution from each nuclide in material for (int i = 0; i < nuclide_.size(); ++i) { // ====================================================================== @@ -799,22 +866,20 @@ void Material::calculate_neutron_xs(Particle& p) const ++j; // Don't check for S(a,b) tables if there are no more left - if (j == thermal_tables_.size()) check_sab = false; + if (j == thermal_tables_.size()) + check_sab = false; } } // ====================================================================== // CALCULATE MICROSCOPIC CROSS SECTION - // Determine microscopic cross sections for this nuclide + // Get nuclide index int i_nuclide = nuclide_[i]; - // Calculate microscopic cross section for this nuclide - const auto& micro {p.neutron_xs(i_nuclide)}; - if (p.E() != micro.last_E || p.sqrtkT() != micro.last_sqrtkT || - i_sab != micro.index_sab || sab_frac != micro.sab_frac) { - data::nuclides[i_nuclide]->calculate_xs(i_sab, i_grid, sab_frac, p); - } + // Update microscopic cross section for this nuclide + p.update_neutron_xs(i_nuclide, i_grid, i_sab, sab_frac, ncrystal_xs); + auto& micro = p.neutron_xs(i_nuclide); // ====================================================================== // ADD TO MACROSCOPIC CROSS SECTION @@ -878,7 +943,8 @@ void Material::set_id(int32_t id) // Make sure no other material has same ID if (model::material_map.find(id) != model::material_map.end()) { - throw std::runtime_error{"Two materials have the same ID: " + std::to_string(id)}; + throw std::runtime_error { + "Two materials have the same ID: " + std::to_string(id)}; } // If no ID specified, auto-assign next ID in sequence @@ -900,7 +966,7 @@ void Material::set_density(double density, gsl::cstring_span units) Expects(density >= 0.0); if (nuclide_.empty()) { - throw std::runtime_error{"No nuclides exist in material yet."}; + throw std::runtime_error {"No nuclides exist in material yet."}; } if (units == "atom/b-cm") { @@ -931,8 +997,8 @@ void Material::set_density(double density, gsl::cstring_span units) density_ *= f; atom_density_ *= f; } else { - throw std::invalid_argument{"Invalid units '" + std::string(units.data()) - + "' specified."}; + throw std::invalid_argument { + "Invalid units '" + std::string(units.data()) + "' specified."}; } } @@ -946,7 +1012,8 @@ void Material::set_densities( if (n != nuclide_.size()) { nuclide_.resize(n); atom_density_ = xt::zeros({n}); - if (settings::photon_transport) element_.resize(n); + if (settings::photon_transport) + element_.resize(n); } double sum_density = 0.0; @@ -954,7 +1021,8 @@ void Material::set_densities( const auto& nuc {name[i]}; if (data::nuclide_map.find(nuc) == data::nuclide_map.end()) { int err = openmc_load_nuclide(nuc.c_str(), nullptr, 0); - if (err < 0) throw std::runtime_error{openmc_err_msg}; + if (err < 0) + throw std::runtime_error {openmc_err_msg}; } nuclide_[i] = data::nuclide_map.at(nuc); @@ -972,7 +1040,8 @@ void Material::set_densities( this->set_density(sum_density, "atom/b-cm"); // Generate material bremsstrahlung data for electrons and positrons - if (settings::photon_transport && settings::electron_treatment == ElectronTreatment::TTB) { + if (settings::photon_transport && + settings::electron_treatment == ElectronTreatment::TTB) { this->init_bremsstrahlung(); } @@ -983,8 +1052,8 @@ void Material::set_densities( double Material::volume() const { if (volume_ < 0.0) { - throw std::runtime_error{"Volume for material with ID=" - + std::to_string(id_) + " not set."}; + throw std::runtime_error { + "Volume for material with ID=" + std::to_string(id_) + " not set."}; } return volume_; } @@ -999,7 +1068,7 @@ void Material::to_hdf5(hid_t group) const { hid_t material_group = create_group(group, "material " + std::to_string(id_)); - write_attribute(material_group, "depletable", static_cast(depletable_)); + write_attribute(material_group, "depletable", static_cast(depletable())); if (volume_ > 0.0) { write_attribute(material_group, "volume", volume_); } @@ -1053,6 +1122,23 @@ void Material::to_hdf5(hid_t group) const close_group(material_group); } +void Material::export_properties_hdf5(hid_t group) const +{ + hid_t material_group = create_group(group, "material " + std::to_string(id_)); + write_attribute(material_group, "atom_density", density_); + write_attribute(material_group, "mass_density", density_gpcc_); + close_group(material_group); +} + +void Material::import_properties_hdf5(hid_t group) +{ + hid_t material_group = open_group(group, "material " + std::to_string(id_)); + double density; + read_attribute(material_group, "atom_density", density); + this->set_density(density, "atom/b-cm"); + close_group(material_group); +} + void Material::add_nuclide(const std::string& name, double density) { // Check if nuclide is already in material @@ -1061,8 +1147,8 @@ void Material::add_nuclide(const std::string& name, double density) if (data::nuclides[i_nuc]->name_ == name) { double awr = data::nuclides[i_nuc]->awr_; density_ += density - atom_density_(i); - density_gpcc_ += (density - atom_density_(i)) - * awr * MASS_NEUTRON / N_AVOGADRO; + density_gpcc_ += + (density - atom_density_(i)) * awr * MASS_NEUTRON / N_AVOGADRO; atom_density_(i) = density; return; } @@ -1070,7 +1156,8 @@ void Material::add_nuclide(const std::string& name, double density) // If nuclide wasn't found, extend nuclide/density arrays int err = openmc_load_nuclide(name.c_str(), nullptr, 0); - if (err < 0) throw std::runtime_error{openmc_err_msg}; + if (err < 0) + throw std::runtime_error {openmc_err_msg}; // Append new nuclide/density int i_nuc = data::nuclide_map[name]; @@ -1086,13 +1173,13 @@ void Material::add_nuclide(const std::string& name, double density) // Create copy of atom_density_ array with one extra entry xt::xtensor atom_density = xt::zeros({n}); - xt::view(atom_density, xt::range(0, n-1)) = atom_density_; - atom_density(n-1) = density; + xt::view(atom_density, xt::range(0, n - 1)) = atom_density_; + atom_density(n - 1) = density; atom_density_ = atom_density; density_ += density; - density_gpcc_ += density * data::nuclides[i_nuc]->awr_ - * MASS_NEUTRON / N_AVOGADRO; + density_gpcc_ += + density * data::nuclides[i_nuc]->awr_ * MASS_NEUTRON / N_AVOGADRO; } //============================================================================== @@ -1131,10 +1218,12 @@ double sternheimer_adjustment(const vector& f, rho -= (g - 2.0 * log_I) / (2.0 * gp); // If the initial guess is too large, rho can be negative - if (rho < 0.0) rho = rho_0 / 2.0; + if (rho < 0.0) + rho = rho_0 / 2.0; // Check for convergence - if (std::abs(rho - rho_0) / rho_0 < tol) break; + if (std::abs(rho - rho_0) / rho_0 < tol) + break; } // Did not converge if (iter >= max_iter) { @@ -1153,8 +1242,8 @@ double density_effect(const vector& f, const vector& e_b_sq, // Square of the ratio of the speed of light to the velocity of the charged // particle - double beta_sq = E * (E + 2.0 * MASS_ELECTRON_EV) / ((E + MASS_ELECTRON_EV) * - (E + MASS_ELECTRON_EV)); + double beta_sq = E * (E + 2.0 * MASS_ELECTRON_EV) / + ((E + MASS_ELECTRON_EV) * (E + MASS_ELECTRON_EV)); // For nonmetals, delta = 0 for beta < beta_0, where beta_0 is obtained by // setting the frequency w = 0. @@ -1166,7 +1255,8 @@ double density_effect(const vector& f, const vector& e_b_sq, beta_0_sq = 1.0 / (1.0 + beta_0_sq); } double delta = 0.0; - if (beta_sq < beta_0_sq) return delta; + if (beta_sq < beta_0_sq) + return delta; // Compute the square of the frequency w^2 using Newton's method, with the // initial guess of w^2 equal to beta^2 * gamma^2 @@ -1192,22 +1282,24 @@ double density_effect(const vector& f, const vector& e_b_sq, w_sq -= (g + 1.0 - 1.0 / beta_sq) / gp; // If the initial guess is too large, w can be negative - if (w_sq < 0.0) w_sq = w_sq_0 / 2.0; + if (w_sq < 0.0) + w_sq = w_sq_0 / 2.0; // Check for convergence - if (std::abs(w_sq - w_sq_0) / w_sq_0 < tol) break; + if (std::abs(w_sq - w_sq_0) / w_sq_0 < tol) + break; } // Did not converge if (iter >= max_iter) { warning("Maximum Newton-Raphson iterations exceeded: setting density " - "effect correction to zero."); + "effect correction to zero."); return delta; } // Solve for the density effect correction for (int i = 0; i < n; ++i) { double l_sq = e_b_sq[i] * rho * rho / e_p_sq + 2.0 / 3.0 * f[i]; - delta += f[i] * std::log((l_sq + w_sq)/l_sq); + delta += f[i] * std::log((l_sq + w_sq) / l_sq); } // Include conduction electrons if (n_conduction > 0.0) { @@ -1223,27 +1315,23 @@ void read_materials_xml() pugi::xml_document doc; - bool using_dagmc_mats = false; -#ifdef DAGMC - if (settings::dagmc) { - using_dagmc_mats = read_uwuw_materials(doc); + // Check if materials.xml exists + std::string filename = settings::path_input + "materials.xml"; + if (!file_exists(filename)) { + fatal_error("Material XML file '" + filename + "' does not exist!"); } -#endif - - if (!using_dagmc_mats) { - // Check if materials.xml exists - std::string filename = settings::path_input + "materials.xml"; - if (!file_exists(filename)) { - fatal_error("Material XML file '" + filename + "' does not exist!"); - } - - // Parse materials.xml file and get root element - doc.load_file(filename.c_str()); - } + // Parse materials.xml file and get root element + doc.load_file(filename.c_str()); // Loop over XML material elements and populate the array. pugi::xml_node root = doc.document_element(); + + read_materials_xml(root); +} + +void read_materials_xml(pugi::xml_node root) +{ for (pugi::xml_node material_node : root.children("material")) { model::materials.push_back(make_unique(material_node)); } @@ -1260,8 +1348,7 @@ void free_memory_material() // C API //============================================================================== -extern "C" int -openmc_get_material_index(int32_t id, int32_t* index) +extern "C" int openmc_get_material_index(int32_t id, int32_t* index) { auto it = model::material_map.find(id); if (it == model::material_map.end()) { @@ -1273,8 +1360,8 @@ openmc_get_material_index(int32_t id, int32_t* index) } } -extern "C" int -openmc_material_add_nuclide(int32_t index, const char* name, double density) +extern "C" int openmc_material_add_nuclide( + int32_t index, const char* name, double density) { int err = 0; if (index >= 0 && index < model::materials.size()) { @@ -1290,8 +1377,8 @@ openmc_material_add_nuclide(int32_t index, const char* name, double density) return err; } -extern "C" int -openmc_material_get_densities(int32_t index, const int** nuclides, const double** densities, int* n) +extern "C" int openmc_material_get_densities( + int32_t index, const int** nuclides, const double** densities, int* n) { if (index >= 0 && index < model::materials.size()) { auto& mat = model::materials[index]; @@ -1310,8 +1397,7 @@ openmc_material_get_densities(int32_t index, const int** nuclides, const double* } } -extern "C" int -openmc_material_get_density(int32_t index, double* density) +extern "C" int openmc_material_get_density(int32_t index, double* density) { if (index >= 0 && index < model::materials.size()) { auto& mat = model::materials[index]; @@ -1323,8 +1409,7 @@ openmc_material_get_density(int32_t index, double* density) } } -extern "C" int -openmc_material_get_fissionable(int32_t index, bool* fissionable) +extern "C" int openmc_material_get_fissionable(int32_t index, bool* fissionable) { if (index >= 0 && index < model::materials.size()) { *fissionable = model::materials[index]->fissionable(); @@ -1335,8 +1420,7 @@ openmc_material_get_fissionable(int32_t index, bool* fissionable) } } -extern "C" int -openmc_material_get_id(int32_t index, int32_t* id) +extern "C" int openmc_material_get_id(int32_t index, int32_t* id) { if (index >= 0 && index < model::materials.size()) { *id = model::materials[index]->id(); @@ -1347,8 +1431,8 @@ openmc_material_get_id(int32_t index, int32_t* id) } } -extern "C" int -openmc_material_get_temperature(int32_t index, double* temperature) +extern "C" int openmc_material_get_temperature( + int32_t index, double* temperature) { if (index < 0 || index >= model::materials.size()) { set_errmsg("Index in materials array is out of bounds."); @@ -1358,9 +1442,7 @@ openmc_material_get_temperature(int32_t index, double* temperature) return 0; } - -extern "C" int -openmc_material_get_volume(int32_t index, double* volume) +extern "C" int openmc_material_get_volume(int32_t index, double* volume) { if (index >= 0 && index < model::materials.size()) { try { @@ -1376,8 +1458,8 @@ openmc_material_get_volume(int32_t index, double* volume) } } -extern "C" int -openmc_material_set_density(int32_t index, double density, const char* units) +extern "C" int openmc_material_set_density( + int32_t index, double density, const char* units) { if (index >= 0 && index < model::materials.size()) { try { @@ -1393,12 +1475,13 @@ openmc_material_set_density(int32_t index, double density, const char* units) return 0; } -extern "C" int -openmc_material_set_densities(int32_t index, int n, const char** name, const double* density) +extern "C" int openmc_material_set_densities( + int32_t index, int n, const char** name, const double* density) { if (index >= 0 && index < model::materials.size()) { try { - model::materials[index]->set_densities({name, name + n}, {density, density + n}); + model::materials[index]->set_densities( + {name, name + n}, {density, density + n}); } catch (const std::exception& e) { set_errmsg(e.what()); return OPENMC_E_UNASSIGNED; @@ -1410,8 +1493,7 @@ openmc_material_set_densities(int32_t index, int n, const char** name, const dou return 0; } -extern "C" int -openmc_material_set_id(int32_t index, int32_t id) +extern "C" int openmc_material_set_id(int32_t index, int32_t id) { if (index >= 0 && index < model::materials.size()) { try { @@ -1427,8 +1509,8 @@ openmc_material_set_id(int32_t index, int32_t id) return 0; } -extern "C" int -openmc_material_get_name(int32_t index, const char** name) { +extern "C" int openmc_material_get_name(int32_t index, const char** name) +{ if (index < 0 || index >= model::materials.size()) { set_errmsg("Index in materials array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; @@ -1439,8 +1521,8 @@ openmc_material_get_name(int32_t index, const char** name) { return 0; } -extern "C" int -openmc_material_set_name(int32_t index, const char* name) { +extern "C" int openmc_material_set_name(int32_t index, const char* name) +{ if (index < 0 || index >= model::materials.size()) { set_errmsg("Index in materials array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; @@ -1451,8 +1533,7 @@ openmc_material_set_name(int32_t index, const char* name) { return 0; } -extern "C" int -openmc_material_set_volume(int32_t index, double volume) +extern "C" int openmc_material_set_volume(int32_t index, double volume) { if (index >= 0 && index < model::materials.size()) { auto& m {model::materials[index]}; @@ -1469,17 +1550,46 @@ openmc_material_set_volume(int32_t index, double volume) } } -extern "C" int -openmc_extend_materials(int32_t n, int32_t* index_start, int32_t* index_end) +extern "C" int openmc_material_get_depletable(int32_t index, bool* depletable) +{ + if (index < 0 || index >= model::materials.size()) { + set_errmsg("Index in materials array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + + *depletable = model::materials[index]->depletable(); + + return 0; +} + +extern "C" int openmc_material_set_depletable(int32_t index, bool depletable) { - if (index_start) *index_start = model::materials.size(); - if (index_end) *index_end = model::materials.size() + n - 1; + if (index < 0 || index >= model::materials.size()) { + set_errmsg("Index in materials array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + + model::materials[index]->depletable() = depletable; + + return 0; +} + +extern "C" int openmc_extend_materials( + int32_t n, int32_t* index_start, int32_t* index_end) +{ + if (index_start) + *index_start = model::materials.size(); + if (index_end) + *index_end = model::materials.size() + n - 1; for (int32_t i = 0; i < n; i++) { model::materials.push_back(make_unique()); } return 0; } -extern "C" size_t n_materials() { return model::materials.size(); } +extern "C" size_t n_materials() +{ + return model::materials.size(); +} } // namespace openmc diff --git a/src/math_functions.cpp b/src/math_functions.cpp index b9d058b7088..ba1c6c3db14 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -1,6 +1,6 @@ #include "openmc/math_functions.h" -#include "Faddeeva.hh" +#include "openmc/external/Faddeeva.hh" #include "openmc/constants.h" #include "openmc/random_lcg.h" @@ -15,16 +15,15 @@ double normal_percentile(double p) { constexpr double p_low = 0.02425; constexpr double a[6] = {-3.969683028665376e1, 2.209460984245205e2, - -2.759285104469687e2, 1.383577518672690e2, - -3.066479806614716e1, 2.506628277459239e0}; + -2.759285104469687e2, 1.383577518672690e2, -3.066479806614716e1, + 2.506628277459239e0}; constexpr double b[5] = {-5.447609879822406e1, 1.615858368580409e2, - -1.556989798598866e2, 6.680131188771972e1, - -1.328068155288572e1}; + -1.556989798598866e2, 6.680131188771972e1, -1.328068155288572e1}; constexpr double c[6] = {-7.784894002430293e-3, -3.223964580411365e-1, - -2.400758277161838, -2.549732539343734, - 4.374664141464968, 2.938163982698783}; + -2.400758277161838, -2.549732539343734, 4.374664141464968, + 2.938163982698783}; constexpr double d[4] = {7.784695709041462e-3, 3.224671290700398e-1, - 2.445134137142996, 3.754408661907416}; + 2.445134137142996, 3.754408661907416}; // The rational approximation used here is from an unpublished work at // http://home.online.no/~pjacklam/notes/invnorm/ @@ -36,34 +35,33 @@ double normal_percentile(double p) // Rational approximation for lower region. q = std::sqrt(-2.0 * std::log(p)); - z = (((((c[0]*q + c[1])*q + c[2])*q + c[3])*q + c[4])*q + c[5]) / - ((((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0); + z = (((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / + ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1.0); } else if (p <= 1.0 - p_low) { // Rational approximation for central region q = p - 0.5; double r = q * q; - z = (((((a[0]*r + a[1])*r + a[2])*r + a[3])*r + a[4])*r + a[5])*q / - (((((b[0]*r + b[1])*r + b[2])*r + b[3])*r + b[4])*r + 1.0); + z = (((((a[0] * r + a[1]) * r + a[2]) * r + a[3]) * r + a[4]) * r + a[5]) * + q / + (((((b[0] * r + b[1]) * r + b[2]) * r + b[3]) * r + b[4]) * r + 1.0); } else { // Rational approximation for upper region - q = std::sqrt(-2.0*std::log(1.0 - p)); - z = -(((((c[0]*q + c[1])*q + c[2])*q + c[3])*q + c[4])*q + c[5]) / - ((((d[0]*q + d[1])*q + d[2])*q + d[3])*q + 1.0); + q = std::sqrt(-2.0 * std::log(1.0 - p)); + z = -(((((c[0] * q + c[1]) * q + c[2]) * q + c[3]) * q + c[4]) * q + c[5]) / + ((((d[0] * q + d[1]) * q + d[2]) * q + d[3]) * q + 1.0); } // Refinement based on Newton's method z = z - (0.5 * std::erfc(-z / std::sqrt(2.0)) - p) * std::sqrt(2.0 * PI) * - std::exp(0.5 * z * z); + std::exp(0.5 * z * z); return z; - } - double t_percentile(double p, int df) { double t; @@ -72,13 +70,13 @@ double t_percentile(double p, int df) // For one degree of freedom, the t-distribution becomes a Cauchy // distribution whose cdf we can invert directly - t = std::tan(PI*(p - 0.5)); + t = std::tan(PI * (p - 0.5)); } else if (df == 2) { - // For two degrees of freedom, the cdf is given by 1/2 + x/(2*sqrt(x^2 + - // 2)). This can be directly inverted to yield the solution below + // For two degrees of freedom, the cdf is given by 1/2 + x/(2*sqrt(x^2 + + // 2)). This can be directly inverted to yield the solution below - t = 2.0 * std::sqrt(2.0)*(p - 0.5) / - std::sqrt(1. - 4. * std::pow(p - 0.5, 2.)); + t = 2.0 * std::sqrt(2.0) * (p - 0.5) / + std::sqrt(1. - 4. * std::pow(p - 0.5, 2.)); } else { // This approximation is from E. Olusegun George and Meenakshi Sivaram, "A // modification of the Fisher-Cornish approximation for the student t @@ -88,15 +86,15 @@ double t_percentile(double p, int df) double k = 1. / (n - 2.); double z = normal_percentile(p); double z2 = z * z; - t = std::sqrt(n * k) * (z + (z2 - 3.) * z * k / 4. + ((5. * z2 - 56.) * z2 + - 75.) * z * k * k / 96. + (((z2 - 27.) * 3. * z2 + 417.) * z2 - 315.) * - z * k * k * k / 384.); + t = std::sqrt(n * k) * + (z + (z2 - 3.) * z * k / 4. + + ((5. * z2 - 56.) * z2 + 75.) * z * k * k / 96. + + (((z2 - 27.) * 3. * z2 + 417.) * z2 - 315.) * z * k * k * k / 384.); } return t; } - void calc_pn_c(int n, double x, double pnx[]) { pnx[0] = 1.; @@ -110,7 +108,6 @@ void calc_pn_c(int n, double x, double pnx[]) } } - double evaluate_legendre(int n, const double data[], double x) { double* pnx = new double[n + 1]; @@ -123,14 +120,12 @@ double evaluate_legendre(int n, const double data[], double x) return val; } - void calc_rn_c(int n, const double uvw[3], double rn[]) { Direction u {uvw}; calc_rn(n, u, rn); } - void calc_rn(int n, Direction u, double rn[]) { // rn[] is assumed to have already been allocated to the correct size @@ -156,379 +151,502 @@ void calc_rn(int n, Direction u, double rn[]) // Now evaluate each switch (l) { - case 1: - // l = 1, m = -1 - rn[i] = -(std::sqrt(w2m1) * std::sin(phi)); - // l = 1, m = 0 - rn[i + 1] = w; - // l = 1, m = 1 - rn[i + 2] = -(std::sqrt(w2m1) * std::cos(phi)); - break; - case 2: - // l = 2, m = -2 - rn[i] = 0.288675134594813 * (-3. * w * w + 3.) * std::sin(2. * phi); - // l = 2, m = -1 - rn[i + 1] = -(1.73205080756888 * w*std::sqrt(w2m1) * std::sin(phi)); - // l = 2, m = 0 - rn[i + 2] = 1.5 * w * w - 0.5; - // l = 2, m = 1 - rn[i + 3] = -(1.73205080756888 * w*std::sqrt(w2m1) * std::cos(phi)); - // l = 2, m = 2 - rn[i + 4] = 0.288675134594813 * (-3. * w * w + 3.) * std::cos(2. * phi); - break; - case 3: - // l = 3, m = -3 - rn[i] = -(0.790569415042095 * std::pow(w2m1, 1.5) * std::sin(3. * phi)); - // l = 3, m = -2 - rn[i + 1] = 1.93649167310371 * w*(w2m1) * std::sin(2.*phi); - // l = 3, m = -1 - rn[i + 2] = -(0.408248290463863*std::sqrt(w2m1)*((7.5)*w * w - 3./2.) * - std::sin(phi)); - // l = 3, m = 0 - rn[i + 3] = 2.5 * std::pow(w, 3) - 1.5 * w; - // l = 3, m = 1 - rn[i + 4] = -(0.408248290463863*std::sqrt(w2m1)*((7.5)*w * w - 3./2.) * - std::cos(phi)); - // l = 3, m = 2 - rn[i + 5] = 1.93649167310371 * w*(w2m1) * std::cos(2.*phi); - // l = 3, m = 3 - rn[i + 6] = -(0.790569415042095 * std::pow(w2m1, 1.5) * std::cos(3.* phi)); - break; - case 4: - // l = 4, m = -4 - rn[i] = 0.739509972887452 * (w2m1 * w2m1) * std::sin(4.0*phi); - // l = 4, m = -3 - rn[i + 1] = -(2.09165006633519 * w * std::pow(w2m1, 1.5) * std::sin(3.* phi)); - // l = 4, m = -2 - rn[i + 2] = 0.074535599249993 * (w2m1)*(52.5 * w * w - 7.5) * std::sin(2. *phi); - // l = 4, m = -1 - rn[i + 3] = -(0.316227766016838*std::sqrt(w2m1)*(17.5 * std::pow(w, 3) - 7.5 * w) * - std::sin(phi)); - // l = 4, m = 0 - rn[i + 4] = 4.375 * std::pow(w, 4) - 3.75 * w * w + 0.375; - // l = 4, m = 1 - rn[i + 5] = -(0.316227766016838*std::sqrt(w2m1)*(17.5 * std::pow(w, 3) - 7.5*w) * - std::cos(phi)); - // l = 4, m = 2 - rn[i + 6] = 0.074535599249993 * (w2m1)*(52.5*w * w - 7.5) * std::cos(2.*phi); - // l = 4, m = 3 - rn[i + 7] = -(2.09165006633519 * w * std::pow(w2m1, 1.5) * std::cos(3.* phi)); - // l = 4, m = 4 - rn[i + 8] = 0.739509972887452 * w2m1 * w2m1 * std::cos(4.0*phi); - break; - case 5: - // l = 5, m = -5 - rn[i] = -(0.701560760020114 * std::pow(w2m1, 2.5) * std::sin(5.0 * phi)); - // l = 5, m = -4 - rn[i + 1] = 2.21852991866236 * w * w2m1 * w2m1 * std::sin(4.0 * phi); - // l = 5, m = -3 - rn[i + 2] = -(0.00996023841111995 * std::pow(w2m1, 1.5) * - ((945.0 /2.)* w * w - 52.5) * std::sin(3.*phi)); - // l = 5, m = -2 - rn[i + 3] = 0.0487950036474267 * (w2m1) - * ((315.0/2.)* std::pow(w, 3) - 52.5 * w) * std::sin(2.*phi); - // l = 5, m = -1 - rn[i + 4] = -(0.258198889747161*std::sqrt(w2m1) * - (39.375 * std::pow(w, 4) - 105.0/4.0 * w * w + 15.0/8.0) * std::sin(phi)); - // l = 5, m = 0 - rn[i + 5] = 7.875 * std::pow(w, 5) - 8.75 * std::pow(w, 3) + 1.875 * w; - // l = 5, m = 1 - rn[i + 6] = -(0.258198889747161 * std::sqrt(w2m1)* - (39.375 * std::pow(w, 4) - 105.0/4.0 * w * w + 15.0/8.0) * std::cos(phi)); - // l = 5, m = 2 - rn[i + 7] = 0.0487950036474267 * (w2m1) * - ((315.0 / 2.) * std::pow(w, 3) - 52.5*w) * std::cos(2.*phi); - // l = 5, m = 3 - rn[i + 8] = -(0.00996023841111995 * std::pow(w2m1, 1.5) * - ((945.0 / 2.) * w * w - 52.5) * std::cos(3.*phi)); - // l = 5, m = 4 - rn[i + 9] = 2.21852991866236 * w * w2m1 * w2m1 * std::cos(4.0*phi); - // l = 5, m = 5 - rn[i + 10] = -(0.701560760020114 * std::pow(w2m1, 2.5) * std::cos(5.0* phi)); - break; - case 6: - // l = 6, m = -6 - rn[i] = 0.671693289381396 * std::pow(w2m1, 3) * std::sin(6.0*phi); - // l = 6, m = -5 - rn[i + 1] = -(2.32681380862329 * w*std::pow(w2m1, 2.5) * std::sin(5.0*phi)); - // l = 6, m = -4 - rn[i + 2] = 0.00104990131391452 * w2m1 * w2m1 * - ((10395.0/2.) * w * w - 945.0/2.) * std::sin(4.0 * phi); - // l = 6, m = -3 - rn[i + 3] = -(0.00575054632785295 * std::pow(w2m1, 1.5) * - ((3465.0/2.) * std::pow(w, 3) - 945.0/2.*w) * std::sin(3.*phi)); - // l = 6, m = -2 - rn[i + 4] = 0.0345032779671177 * (w2m1) * - ((3465.0/8.0)* std::pow(w, 4) - 945.0/4.0 * w * w + 105.0/8.0) * - std::sin(2. * phi); - // l = 6, m = -1 - rn[i + 5] = -(0.218217890235992*std::sqrt(w2m1) * - ((693.0/8.0)* std::pow(w, 5)- 315.0/4.0 * std::pow(w, 3) + (105.0/8.0)*w) * - std::sin(phi)); - // l = 6, m = 0 - rn[i + 6] = 14.4375 * std::pow(w, 6) - 19.6875 * std::pow(w, 4) + 6.5625 * w * w - - 0.3125; - // l = 6, m = 1 - rn[i + 7] = -(0.218217890235992*std::sqrt(w2m1) * - ((693.0/8.0)* std::pow(w, 5)- 315.0/4.0 * std::pow(w, 3) + (105.0/8.0)*w) * - std::cos(phi)); - // l = 6, m = 2 - rn[i + 8] = 0.0345032779671177 * w2m1 * - ((3465.0/8.0)* std::pow(w, 4) -945.0/4.0 * w * w + 105.0/8.0) * - std::cos(2.*phi); - // l = 6, m = 3 - rn[i + 9] = -(0.00575054632785295 * std::pow(w2m1, 1.5) * - ((3465.0/2.) * std::pow(w, 3) - 945.0/2.*w) * std::cos(3.*phi)); - // l = 6, m = 4 - rn[i + 10] = 0.00104990131391452 * w2m1 * w2m1 * - ((10395.0/2.)*w * w - 945.0/2.) * std::cos(4.0*phi); - // l = 6, m = 5 - rn[i + 11] = -(2.32681380862329 * w * std::pow(w2m1, 2.5) * std::cos(5.0*phi)); - // l = 6, m = 6 - rn[i + 12] = 0.671693289381396 * std::pow(w2m1, 3) * std::cos(6.0*phi); - break; - case 7: - // l = 7, m = -7 - rn[i] = -(0.647259849287749 * std::pow(w2m1, 3.5) * std::sin(7.0*phi)); - // l = 7, m = -6 - rn[i + 1] = 2.42182459624969 * w*std::pow(w2m1, 3) * std::sin(6.0*phi); - // l = 7, m = -5 - rn[i + 2] = -(9.13821798555235e-5*std::pow(w2m1, 2.5) * - ((135135.0/2.)*w * w - 10395.0/2.) * std::sin(5.0*phi)); - // l = 7, m = -4 - rn[i + 3] = 0.000548293079133141 * w2m1 * w2m1 * - ((45045.0/2.)*std::pow(w, 3) - 10395.0/2.*w) * std::sin(4.0*phi); - // l = 7, m = -3 - rn[i + 4] = -(0.00363696483726654 * std::pow(w2m1, 1.5) * - ((45045.0/8.0)* std::pow(w, 4) - 10395.0/4.0 * w * w + 945.0/8.0) * - std::sin(3.*phi)); - // l = 7, m = -2 - rn[i + 5] = 0.025717224993682 * (w2m1) * - ((9009.0/8.0)* std::pow(w, 5) -3465.0/4.0 * std::pow(w, 3) + (945.0/8.0)*w) * - std::sin(2.*phi); - // l = 7, m = -1 - rn[i + 6] = -(0.188982236504614*std::sqrt(w2m1) * - ((3003.0/16.0)* std::pow(w, 6) - 3465.0/16.0 * std::pow(w, 4) + - (945.0/16.0)*w * w - 35.0/16.0) * std::sin(phi)); - // l = 7, m = 0 - rn[i + 7] = 26.8125 * std::pow(w, 7) - 43.3125 * std::pow(w, 5) + 19.6875 * std::pow(w, 3) - - 2.1875 * w; - // l = 7, m = 1 - rn[i + 8] = -(0.188982236504614*std::sqrt(w2m1) * ((3003.0/16.0) * std::pow(w, 6) - - 3465.0/16.0 * std::pow(w, 4) + (945.0/16.0)*w * w - 35.0/16.0) * std::cos(phi)); - // l = 7, m = 2 - rn[i + 9] = 0.025717224993682 * (w2m1) * ((9009.0/8.0)* std::pow(w, 5) - - 3465.0/4.0 * std::pow(w, 3) + (945.0/8.0)*w) * std::cos(2.*phi); - // l = 7, m = 3 - rn[i + 10] = -(0.00363696483726654 * std::pow(w2m1, 1.5) * - ((45045.0/8.0)* std::pow(w, 4) - 10395.0/4.0 * w * w + 945.0/8.0) * - std::cos(3.*phi)); - // l = 7, m = 4 - rn[i + 11] = 0.000548293079133141 * w2m1 * w2m1 * - ((45045.0/2.)*std::pow(w, 3) - 10395.0/2.*w) * std::cos(4.0*phi); - // l = 7, m = 5 - rn[i + 12] = -(9.13821798555235e-5*std::pow(w2m1, 2.5) * - ((135135.0/2.)*w * w - 10395.0/2.) * std::cos(5.0*phi)); - // l = 7, m = 6 - rn[i + 13] = 2.42182459624969 * w*std::pow(w2m1, 3) * std::cos(6.0*phi); - // l = 7, m = 7 - rn[i + 14] = -(0.647259849287749 * std::pow(w2m1, 3.5) * std::cos(7.0*phi)); - break; - case 8: - // l = 8, m = -8 - rn[i] = 0.626706654240044 * std::pow(w2m1, 4) * std::sin(8.0*phi); - // l = 8, m = -7 - rn[i + 1] = -(2.50682661696018 * w*std::pow(w2m1, 3.5) * std::sin(7.0*phi)); - // l = 8, m = -6 - rn[i + 2] = 6.77369783729086e-6*std::pow(w2m1, 3)* - ((2027025.0/2.)*w * w - 135135.0/2.) * std::sin(6.0*phi); - // l = 8, m = -5 - rn[i + 3] = -(4.38985792528482e-5*std::pow(w2m1, 2.5) * - ((675675.0/2.)*std::pow(w, 3) - 135135.0/2.*w) * std::sin(5.0*phi)); - // l = 8, m = -4 - rn[i + 4] = 0.000316557156832328 * w2m1 * w2m1 * - ((675675.0/8.0)* std::pow(w, 4) - 135135.0/4.0 * w * w + 10395.0/8.0) * - std::sin(4.0*phi); - // l = 8, m = -3 - rn[i + 5] = -(0.00245204119306875 * std::pow(w2m1, 1.5) * ((135135.0/8.0) * - std::pow(w, 5) - 45045.0/4.0 * std::pow(w, 3) + (10395.0/8.0)*w) * std::sin(3.*phi)); - // l = 8, m = -2 - rn[i + 6] = 0.0199204768222399 * (w2m1) * - ((45045.0/16.0)* std::pow(w, 6)- 45045.0/16.0 * std::pow(w, 4) + - (10395.0/16.0)*w * w - 315.0/16.0) * std::sin(2.*phi); - // l = 8, m = -1 - rn[i + 7] = -(0.166666666666667*std::sqrt(w2m1) * - ((6435.0/16.0)* std::pow(w, 7) - 9009.0/16.0 * std::pow(w, 5) + - (3465.0/16.0)*std::pow(w, 3) - 315.0/16.0 * w) * std::sin(phi)); - // l = 8, m = 0 - rn[i + 8] = 50.2734375 * std::pow(w, 8) - 93.84375 * std::pow(w, 6) + 54.140625 * - std::pow(w, 4) - 9.84375 * w * w + 0.2734375; - // l = 8, m = 1 - rn[i + 9] = -(0.166666666666667*std::sqrt(w2m1) * - ((6435.0/16.0)* std::pow(w, 7) - 9009.0/16.0 * std::pow(w, 5) + - (3465.0/16.0)*std::pow(w, 3) - 315.0/16.0 * w) * std::cos(phi)); - // l = 8, m = 2 - rn[i + 10] = 0.0199204768222399 * (w2m1)*((45045.0/16.0)* std::pow(w, 6)- - 45045.0/16.0 * std::pow(w, 4) + (10395.0/16.0)*w * w - - 315.0/16.0) * std::cos(2.*phi); - // l = 8, m = 3 - rn[i + 11] = -(0.00245204119306875 * std::pow(w2m1, 1.5)* - ((135135.0/8.0) * std::pow(w, 5) - 45045.0/4.0 * std::pow(w, 3) + - (10395.0/8.0)*w) * std::cos(3.*phi)); - // l = 8, m = 4 - rn[i + 12] = 0.000316557156832328 * w2m1 * w2m1*((675675.0/8.0)* std::pow(w, 4) - - 135135.0/4.0 * w * w + 10395.0/8.0) * std::cos(4.0*phi); - // l = 8, m = 5 - rn[i + 13] = -(4.38985792528482e-5*std::pow(w2m1, 2.5)*((675675.0/2.)*std::pow(w, 3) - - 135135.0/2.*w) * std::cos(5.0*phi)); - // l = 8, m = 6 - rn[i + 14] = 6.77369783729086e-6*std::pow(w2m1, 3)*((2027025.0/2.)*w * w - - 135135.0/2.) * std::cos(6.0*phi); - // l = 8, m = 7 - rn[i + 15] = -(2.50682661696018 * w*std::pow(w2m1, 3.5) * std::cos(7.0*phi)); - // l = 8, m = 8 - rn[i + 16] = 0.626706654240044 * std::pow(w2m1, 4) * std::cos(8.0*phi); - break; - case 9: - // l = 9, m = -9 - rn[i] = -(0.609049392175524 * std::pow(w2m1, 4.5) * std::sin(9.0 * phi)); - // l = 9, m = -8 - rn[i + 1] = 2.58397773170915 * w*std::pow(w2m1, 4) * std::sin(8.0 * phi); - // l = 9, m = -7 - rn[i + 2] = -(4.37240315267812e-7*std::pow(w2m1, 3.5) * - ((34459425.0/2.)*w * w - 2027025.0/2.) * std::sin(7.0 * phi)); - // l = 9, m = -6 - rn[i + 3] = 3.02928976464514e-6*std::pow(w2m1, 3)* - ((11486475.0/2.)*std::pow(w, 3) - 2027025.0/2.*w) * std::sin(6.0 * phi); - // l = 9, m = -5 - rn[i + 4] = -(2.34647776186144e-5*std::pow(w2m1, 2.5) * - ((11486475.0/8.0)* std::pow(w, 4) - 2027025.0 / 4.0 * w * w + - 135135.0/8.0) * std::sin(5.0 * phi)); - // l = 9, m = -4 - rn[i + 5] = 0.000196320414650061 * w2m1 * w2m1*((2297295.0/8.0)* std::pow(w, 5) - - 675675.0/4.0 * std::pow(w, 3) + (135135.0/8.0)*w) * std::sin(4.0*phi); - // l = 9, m = -3 - rn[i + 6] = -(0.00173385495536766 * std::pow(w2m1, 1.5) * - ((765765.0/16.0)* std::pow(w, 6) - 675675.0/16.0 * std::pow(w, 4) + - (135135.0/16.0)*w * w - 3465.0/16.0) * std::sin(3. * phi)); - // l = 9, m = -2 - rn[i + 7] = 0.0158910431540932 * (w2m1)*((109395.0/16.0)* std::pow(w, 7)- - 135135.0/16.0 * std::pow(w, 5) + (45045.0/16.0)*std::pow(w, 3) - - 3465.0/16.0 * w) * std::sin(2. * phi); - // l = 9, m = -1 - rn[i + 8] = -(0.149071198499986*std::sqrt(w2m1)*((109395.0/128.0)* std::pow(w, 8) - - 45045.0/32.0 * std::pow(w, 6) + (45045.0/64.0)* std::pow(w, 4) - - 3465.0/32.0 * w * w + 315.0/128.0) * std::sin(phi)); - // l = 9, m = 0 - rn[i + 9] = 94.9609375 * std::pow(w, 9) - 201.09375 * std::pow(w, 7) + - 140.765625 * std::pow(w, 5)- 36.09375 * std::pow(w, 3) + 2.4609375 * w; - // l = 9, m = 1 - rn[i + 10] = -(0.149071198499986*std::sqrt(w2m1)*((109395.0/128.0)* std::pow(w, 8) - - 45045.0/32.0 * std::pow(w, 6) + (45045.0/64.0)* std::pow(w, 4) - - 3465.0/32.0 * w * w + 315.0/128.0) * std::cos(phi)); - // l = 9, m = 2 - rn[i + 11] = 0.0158910431540932 * (w2m1)*((109395.0/16.0)* std::pow(w, 7) - - 135135.0/16.0 * std::pow(w, 5) + (45045.0/16.0)*std::pow(w, 3) - - 3465.0/ 16.0 * w) * std::cos(2. * phi); - // l = 9, m = 3 - rn[i + 12] = -(0.00173385495536766 * std::pow(w2m1, 1.5)*((765765.0/16.0) * - std::pow(w, 6) - 675675.0/16.0 * std::pow(w, 4) + - (135135.0/16.0)* w * w - 3465.0/16.0)* std::cos(3. * phi)); - // l = 9, m = 4 - rn[i + 13] = 0.000196320414650061 * w2m1 * w2m1*((2297295.0/8.0) * std::pow(w, 5) - - 675675.0/4.0 * std::pow(w, 3) + (135135.0/8.0)*w) * std::cos(4.0 * phi); - // l = 9, m = 5 - rn[i + 14] = -(2.34647776186144e-5*std::pow(w2m1, 2.5)*((11486475.0/8.0) * - std::pow(w, 4) - 2027025.0/4.0 * w * w + 135135.0/8.0) * - std::cos(5.0 * phi)); - // l = 9, m = 6 - rn[i + 15] = 3.02928976464514e-6*std::pow(w2m1, 3)*((11486475.0/2.)*std::pow(w, 3) - - 2027025.0/2. * w) * std::cos(6.0 * phi); - // l = 9, m = 7 - rn[i + 16] = -(4.37240315267812e-7*std::pow(w2m1, 3.5)* - ((34459425.0/2.) * w * w - 2027025.0/2.) * std::cos(7.0 * phi)); - // l = 9, m = 8 - rn[i + 17] = 2.58397773170915 * w*std::pow(w2m1, 4) * std::cos(8.0 * phi); - // l = 9, m = 9 - rn[i + 18] = -(0.609049392175524 * std::pow(w2m1, 4.5) * std::cos(9.0 * phi)); - break; - case 10: - // l = 10, m = -10 - rn[i] = 0.593627917136573 * std::pow(w2m1, 5) * std::sin(10.0 * phi); - // l = 10, m = -9 - rn[i + 1] = -(2.65478475211798 * w * std::pow(w2m1, 4.5) * std::sin(9.0 * phi)); - // l = 10, m = -8 - rn[i + 2] = 2.49953651452314e-8 * std::pow(w2m1, 4) * - ((654729075.0/2.) * w * w - 34459425.0/2.) * std::sin(8.0 * phi); - // l = 10, m = -7 - rn[i + 3] = -(1.83677671621093e-7*std::pow(w2m1, 3.5)* - ((218243025.0/2.)*std::pow(w, 3) - 34459425.0/2.*w) * - std::sin(7.0 * phi)); - // l = 10, m = -6 - rn[i + 4] = 1.51464488232257e-6*std::pow(w2m1, 3)*((218243025.0/8.0)* std::pow(w, 4) - - 34459425.0/4.0 * w * w + 2027025.0/8.0) * std::sin(6.0 * phi); - // l = 10, m = -5 - rn[i + 5] = -(1.35473956745817e-5*std::pow(w2m1, 2.5)* - ((43648605.0/8.0)* std::pow(w, 5) - 11486475.0/4.0 * std::pow(w, 3) + - (2027025.0/8.0)*w) * std::sin(5.0 * phi)); - // l = 10, m = -4 - rn[i + 6] = 0.000128521880085575 * w2m1 * w2m1*((14549535.0/16.0)* std::pow(w, 6) - - 11486475.0/16.0 * std::pow(w, 4) + (2027025.0/16.0)*w * w - - 45045.0/16.0) * std::sin(4.0 * phi); - // l = 10, m = -3 - rn[i + 7] = -(0.00127230170115096 * std::pow(w2m1, 1.5)* - ((2078505.0/16.0)* std::pow(w, 7) - 2297295.0/16.0 * std::pow(w, 5) + - (675675.0/16.0)*std::pow(w, 3) - 45045.0/16.0 * w) * std::sin(3. * phi)); - // l = 10, m = -2 - rn[i + 8] = 0.012974982402692 * (w2m1)*((2078505.0/128.0)* std::pow(w, 8) - - 765765.0/32.0 * std::pow(w, 6) + (675675.0/64.0)* std::pow(w, 4) - - 45045.0/32.0 * w * w + 3465.0/128.0) * std::sin(2. * phi); - // l = 10, m = -1 - rn[i + 9] = -(0.134839972492648*std::sqrt(w2m1)*((230945.0/128.0)* std::pow(w, 9) - - 109395.0/32.0 * std::pow(w, 7) + (135135.0/64.0)* std::pow(w, 5) - - 15015.0/32.0 * std::pow(w, 3) + (3465.0/128.0)*w) * std::sin(phi)); - // l = 10, m = 0 - rn[i + 10] = 180.42578125 * std::pow(w, 10) - 427.32421875 * std::pow(w, 8) +351.9140625 - * std::pow(w, 6) - 117.3046875 * std::pow(w, 4) + 13.53515625 * w * w -0.24609375; - // l = 10, m = 1 - rn[i + 11] = -(0.134839972492648*std::sqrt(w2m1)*((230945.0/128.0)* std::pow(w, 9) - - 109395.0/32.0 * std::pow(w, 7) + (135135.0/64.0)* std::pow(w, 5) -15015.0/ - 32.0 * std::pow(w, 3) + (3465.0/128.0)*w) * std::cos(phi)); - // l = 10, m = 2 - rn[i + 12] = 0.012974982402692 * (w2m1)*((2078505.0/128.0)* std::pow(w, 8) - - 765765.0/32.0 * std::pow(w, 6) + (675675.0/64.0)* std::pow(w, 4) - - 45045.0/32.0 * w * w + 3465.0/128.0) * std::cos(2. * phi); - // l = 10, m = 3 - rn[i + 13] = -(0.00127230170115096 * std::pow(w2m1, 1.5)* - ((2078505.0/16.0)* std::pow(w, 7) - 2297295.0/16.0 * std::pow(w, 5) + - (675675.0/16.0)*std::pow(w, 3) - 45045.0/16.0 * w) * std::cos(3. * phi)); - // l = 10, m = 4 - rn[i + 14] = 0.000128521880085575 * w2m1 * w2m1*((14549535.0/16.0)* std::pow(w, 6) - - 11486475.0/16.0 * std::pow(w, 4) + (2027025.0/16.0) * w * w - - 45045.0/16.0) * std::cos(4.0 * phi); - // l = 10, m = 5 - rn[i + 15] = -(1.35473956745817e-5*std::pow(w2m1, 2.5)* - ((43648605.0/8.0)* std::pow(w, 5) - 11486475.0/4.0 * std::pow(w, 3) + - (2027025.0/8.0)*w) * std::cos(5.0 * phi)); - // l = 10, m = 6 - rn[i + 16] = 1.51464488232257e-6*std::pow(w2m1, 3)*((218243025.0/8.0)* std::pow(w, 4) - - 34459425.0/4.0 * w * w + 2027025.0/8.0) * std::cos(6.0 * phi); - // l = 10, m = 7 - rn[i + 17] = -(1.83677671621093e-7*std::pow(w2m1, 3.5) * - ((218243025.0/2.)*std::pow(w, 3) - 34459425.0/2.*w) * std::cos(7.0 * phi)); - // l = 10, m = 8 - rn[i + 18] = 2.49953651452314e-8*std::pow(w2m1, 4)* - ((654729075.0/2.)*w * w - 34459425.0/2.) * std::cos(8.0 * phi); - // l = 10, m = 9 - rn[i + 19] = -(2.65478475211798 * w*std::pow(w2m1, 4.5) * std::cos(9.0 * phi)); - // l = 10, m = 10 - rn[i + 20] = 0.593627917136573 * std::pow(w2m1, 5) * std::cos(10.0 * phi); + case 1: + // l = 1, m = -1 + rn[i] = -(std::sqrt(w2m1) * std::sin(phi)); + // l = 1, m = 0 + rn[i + 1] = w; + // l = 1, m = 1 + rn[i + 2] = -(std::sqrt(w2m1) * std::cos(phi)); + break; + case 2: + // l = 2, m = -2 + rn[i] = 0.288675134594813 * (-3. * w * w + 3.) * std::sin(2. * phi); + // l = 2, m = -1 + rn[i + 1] = -(1.73205080756888 * w * std::sqrt(w2m1) * std::sin(phi)); + // l = 2, m = 0 + rn[i + 2] = 1.5 * w * w - 0.5; + // l = 2, m = 1 + rn[i + 3] = -(1.73205080756888 * w * std::sqrt(w2m1) * std::cos(phi)); + // l = 2, m = 2 + rn[i + 4] = 0.288675134594813 * (-3. * w * w + 3.) * std::cos(2. * phi); + break; + case 3: + // l = 3, m = -3 + rn[i] = -(0.790569415042095 * std::pow(w2m1, 1.5) * std::sin(3. * phi)); + // l = 3, m = -2 + rn[i + 1] = 1.93649167310371 * w * (w2m1)*std::sin(2. * phi); + // l = 3, m = -1 + rn[i + 2] = -(0.408248290463863 * std::sqrt(w2m1) * + ((7.5) * w * w - 3. / 2.) * std::sin(phi)); + // l = 3, m = 0 + rn[i + 3] = 2.5 * std::pow(w, 3) - 1.5 * w; + // l = 3, m = 1 + rn[i + 4] = -(0.408248290463863 * std::sqrt(w2m1) * + ((7.5) * w * w - 3. / 2.) * std::cos(phi)); + // l = 3, m = 2 + rn[i + 5] = 1.93649167310371 * w * (w2m1)*std::cos(2. * phi); + // l = 3, m = 3 + rn[i + 6] = + -(0.790569415042095 * std::pow(w2m1, 1.5) * std::cos(3. * phi)); + break; + case 4: + // l = 4, m = -4 + rn[i] = 0.739509972887452 * (w2m1 * w2m1) * std::sin(4.0 * phi); + // l = 4, m = -3 + rn[i + 1] = + -(2.09165006633519 * w * std::pow(w2m1, 1.5) * std::sin(3. * phi)); + // l = 4, m = -2 + rn[i + 2] = + 0.074535599249993 * (w2m1) * (52.5 * w * w - 7.5) * std::sin(2. * phi); + // l = 4, m = -1 + rn[i + 3] = -(0.316227766016838 * std::sqrt(w2m1) * + (17.5 * std::pow(w, 3) - 7.5 * w) * std::sin(phi)); + // l = 4, m = 0 + rn[i + 4] = 4.375 * std::pow(w, 4) - 3.75 * w * w + 0.375; + // l = 4, m = 1 + rn[i + 5] = -(0.316227766016838 * std::sqrt(w2m1) * + (17.5 * std::pow(w, 3) - 7.5 * w) * std::cos(phi)); + // l = 4, m = 2 + rn[i + 6] = + 0.074535599249993 * (w2m1) * (52.5 * w * w - 7.5) * std::cos(2. * phi); + // l = 4, m = 3 + rn[i + 7] = + -(2.09165006633519 * w * std::pow(w2m1, 1.5) * std::cos(3. * phi)); + // l = 4, m = 4 + rn[i + 8] = 0.739509972887452 * w2m1 * w2m1 * std::cos(4.0 * phi); + break; + case 5: + // l = 5, m = -5 + rn[i] = -(0.701560760020114 * std::pow(w2m1, 2.5) * std::sin(5.0 * phi)); + // l = 5, m = -4 + rn[i + 1] = 2.21852991866236 * w * w2m1 * w2m1 * std::sin(4.0 * phi); + // l = 5, m = -3 + rn[i + 2] = -(0.00996023841111995 * std::pow(w2m1, 1.5) * + ((945.0 / 2.) * w * w - 52.5) * std::sin(3. * phi)); + // l = 5, m = -2 + rn[i + 3] = 0.0487950036474267 * (w2m1) * + ((315.0 / 2.) * std::pow(w, 3) - 52.5 * w) * + std::sin(2. * phi); + // l = 5, m = -1 + rn[i + 4] = + -(0.258198889747161 * std::sqrt(w2m1) * + (39.375 * std::pow(w, 4) - 105.0 / 4.0 * w * w + 15.0 / 8.0) * + std::sin(phi)); + // l = 5, m = 0 + rn[i + 5] = 7.875 * std::pow(w, 5) - 8.75 * std::pow(w, 3) + 1.875 * w; + // l = 5, m = 1 + rn[i + 6] = + -(0.258198889747161 * std::sqrt(w2m1) * + (39.375 * std::pow(w, 4) - 105.0 / 4.0 * w * w + 15.0 / 8.0) * + std::cos(phi)); + // l = 5, m = 2 + rn[i + 7] = 0.0487950036474267 * (w2m1) * + ((315.0 / 2.) * std::pow(w, 3) - 52.5 * w) * + std::cos(2. * phi); + // l = 5, m = 3 + rn[i + 8] = -(0.00996023841111995 * std::pow(w2m1, 1.5) * + ((945.0 / 2.) * w * w - 52.5) * std::cos(3. * phi)); + // l = 5, m = 4 + rn[i + 9] = 2.21852991866236 * w * w2m1 * w2m1 * std::cos(4.0 * phi); + // l = 5, m = 5 + rn[i + 10] = + -(0.701560760020114 * std::pow(w2m1, 2.5) * std::cos(5.0 * phi)); + break; + case 6: + // l = 6, m = -6 + rn[i] = 0.671693289381396 * std::pow(w2m1, 3) * std::sin(6.0 * phi); + // l = 6, m = -5 + rn[i + 1] = + -(2.32681380862329 * w * std::pow(w2m1, 2.5) * std::sin(5.0 * phi)); + // l = 6, m = -4 + rn[i + 2] = 0.00104990131391452 * w2m1 * w2m1 * + ((10395.0 / 2.) * w * w - 945.0 / 2.) * std::sin(4.0 * phi); + // l = 6, m = -3 + rn[i + 3] = -(0.00575054632785295 * std::pow(w2m1, 1.5) * + ((3465.0 / 2.) * std::pow(w, 3) - 945.0 / 2. * w) * + std::sin(3. * phi)); + // l = 6, m = -2 + rn[i + 4] = + 0.0345032779671177 * (w2m1) * + ((3465.0 / 8.0) * std::pow(w, 4) - 945.0 / 4.0 * w * w + 105.0 / 8.0) * + std::sin(2. * phi); + // l = 6, m = -1 + rn[i + 5] = -(0.218217890235992 * std::sqrt(w2m1) * + ((693.0 / 8.0) * std::pow(w, 5) - + 315.0 / 4.0 * std::pow(w, 3) + (105.0 / 8.0) * w) * + std::sin(phi)); + // l = 6, m = 0 + rn[i + 6] = 14.4375 * std::pow(w, 6) - 19.6875 * std::pow(w, 4) + + 6.5625 * w * w - 0.3125; + // l = 6, m = 1 + rn[i + 7] = -(0.218217890235992 * std::sqrt(w2m1) * + ((693.0 / 8.0) * std::pow(w, 5) - + 315.0 / 4.0 * std::pow(w, 3) + (105.0 / 8.0) * w) * + std::cos(phi)); + // l = 6, m = 2 + rn[i + 8] = + 0.0345032779671177 * w2m1 * + ((3465.0 / 8.0) * std::pow(w, 4) - 945.0 / 4.0 * w * w + 105.0 / 8.0) * + std::cos(2. * phi); + // l = 6, m = 3 + rn[i + 9] = -(0.00575054632785295 * std::pow(w2m1, 1.5) * + ((3465.0 / 2.) * std::pow(w, 3) - 945.0 / 2. * w) * + std::cos(3. * phi)); + // l = 6, m = 4 + rn[i + 10] = 0.00104990131391452 * w2m1 * w2m1 * + ((10395.0 / 2.) * w * w - 945.0 / 2.) * std::cos(4.0 * phi); + // l = 6, m = 5 + rn[i + 11] = + -(2.32681380862329 * w * std::pow(w2m1, 2.5) * std::cos(5.0 * phi)); + // l = 6, m = 6 + rn[i + 12] = 0.671693289381396 * std::pow(w2m1, 3) * std::cos(6.0 * phi); + break; + case 7: + // l = 7, m = -7 + rn[i] = -(0.647259849287749 * std::pow(w2m1, 3.5) * std::sin(7.0 * phi)); + // l = 7, m = -6 + rn[i + 1] = + 2.42182459624969 * w * std::pow(w2m1, 3) * std::sin(6.0 * phi); + // l = 7, m = -5 + rn[i + 2] = + -(9.13821798555235e-5 * std::pow(w2m1, 2.5) * + ((135135.0 / 2.) * w * w - 10395.0 / 2.) * std::sin(5.0 * phi)); + // l = 7, m = -4 + rn[i + 3] = 0.000548293079133141 * w2m1 * w2m1 * + ((45045.0 / 2.) * std::pow(w, 3) - 10395.0 / 2. * w) * + std::sin(4.0 * phi); + // l = 7, m = -3 + rn[i + 4] = -(0.00363696483726654 * std::pow(w2m1, 1.5) * + ((45045.0 / 8.0) * std::pow(w, 4) - 10395.0 / 4.0 * w * w + + 945.0 / 8.0) * + std::sin(3. * phi)); + // l = 7, m = -2 + rn[i + 5] = 0.025717224993682 * (w2m1) * + ((9009.0 / 8.0) * std::pow(w, 5) - + 3465.0 / 4.0 * std::pow(w, 3) + (945.0 / 8.0) * w) * + std::sin(2. * phi); + // l = 7, m = -1 + rn[i + 6] = + -(0.188982236504614 * std::sqrt(w2m1) * + ((3003.0 / 16.0) * std::pow(w, 6) - 3465.0 / 16.0 * std::pow(w, 4) + + (945.0 / 16.0) * w * w - 35.0 / 16.0) * + std::sin(phi)); + // l = 7, m = 0 + rn[i + 7] = 26.8125 * std::pow(w, 7) - 43.3125 * std::pow(w, 5) + + 19.6875 * std::pow(w, 3) - 2.1875 * w; + // l = 7, m = 1 + rn[i + 8] = + -(0.188982236504614 * std::sqrt(w2m1) * + ((3003.0 / 16.0) * std::pow(w, 6) - 3465.0 / 16.0 * std::pow(w, 4) + + (945.0 / 16.0) * w * w - 35.0 / 16.0) * + std::cos(phi)); + // l = 7, m = 2 + rn[i + 9] = 0.025717224993682 * (w2m1) * + ((9009.0 / 8.0) * std::pow(w, 5) - + 3465.0 / 4.0 * std::pow(w, 3) + (945.0 / 8.0) * w) * + std::cos(2. * phi); + // l = 7, m = 3 + rn[i + 10] = -(0.00363696483726654 * std::pow(w2m1, 1.5) * + ((45045.0 / 8.0) * std::pow(w, 4) - 10395.0 / 4.0 * w * w + + 945.0 / 8.0) * + std::cos(3. * phi)); + // l = 7, m = 4 + rn[i + 11] = 0.000548293079133141 * w2m1 * w2m1 * + ((45045.0 / 2.) * std::pow(w, 3) - 10395.0 / 2. * w) * + std::cos(4.0 * phi); + // l = 7, m = 5 + rn[i + 12] = + -(9.13821798555235e-5 * std::pow(w2m1, 2.5) * + ((135135.0 / 2.) * w * w - 10395.0 / 2.) * std::cos(5.0 * phi)); + // l = 7, m = 6 + rn[i + 13] = + 2.42182459624969 * w * std::pow(w2m1, 3) * std::cos(6.0 * phi); + // l = 7, m = 7 + rn[i + 14] = + -(0.647259849287749 * std::pow(w2m1, 3.5) * std::cos(7.0 * phi)); + break; + case 8: + // l = 8, m = -8 + rn[i] = 0.626706654240044 * std::pow(w2m1, 4) * std::sin(8.0 * phi); + // l = 8, m = -7 + rn[i + 1] = + -(2.50682661696018 * w * std::pow(w2m1, 3.5) * std::sin(7.0 * phi)); + // l = 8, m = -6 + rn[i + 2] = 6.77369783729086e-6 * std::pow(w2m1, 3) * + ((2027025.0 / 2.) * w * w - 135135.0 / 2.) * + std::sin(6.0 * phi); + // l = 8, m = -5 + rn[i + 3] = -(4.38985792528482e-5 * std::pow(w2m1, 2.5) * + ((675675.0 / 2.) * std::pow(w, 3) - 135135.0 / 2. * w) * + std::sin(5.0 * phi)); + // l = 8, m = -4 + rn[i + 4] = 0.000316557156832328 * w2m1 * w2m1 * + ((675675.0 / 8.0) * std::pow(w, 4) - 135135.0 / 4.0 * w * w + + 10395.0 / 8.0) * + std::sin(4.0 * phi); + // l = 8, m = -3 + rn[i + 5] = -(0.00245204119306875 * std::pow(w2m1, 1.5) * + ((135135.0 / 8.0) * std::pow(w, 5) - + 45045.0 / 4.0 * std::pow(w, 3) + (10395.0 / 8.0) * w) * + std::sin(3. * phi)); + // l = 8, m = -2 + rn[i + 6] = + 0.0199204768222399 * (w2m1) * + ((45045.0 / 16.0) * std::pow(w, 6) - 45045.0 / 16.0 * std::pow(w, 4) + + (10395.0 / 16.0) * w * w - 315.0 / 16.0) * + std::sin(2. * phi); + // l = 8, m = -1 + rn[i + 7] = + -(0.166666666666667 * std::sqrt(w2m1) * + ((6435.0 / 16.0) * std::pow(w, 7) - 9009.0 / 16.0 * std::pow(w, 5) + + (3465.0 / 16.0) * std::pow(w, 3) - 315.0 / 16.0 * w) * + std::sin(phi)); + // l = 8, m = 0 + rn[i + 8] = 50.2734375 * std::pow(w, 8) - 93.84375 * std::pow(w, 6) + + 54.140625 * std::pow(w, 4) - 9.84375 * w * w + 0.2734375; + // l = 8, m = 1 + rn[i + 9] = + -(0.166666666666667 * std::sqrt(w2m1) * + ((6435.0 / 16.0) * std::pow(w, 7) - 9009.0 / 16.0 * std::pow(w, 5) + + (3465.0 / 16.0) * std::pow(w, 3) - 315.0 / 16.0 * w) * + std::cos(phi)); + // l = 8, m = 2 + rn[i + 10] = + 0.0199204768222399 * (w2m1) * + ((45045.0 / 16.0) * std::pow(w, 6) - 45045.0 / 16.0 * std::pow(w, 4) + + (10395.0 / 16.0) * w * w - 315.0 / 16.0) * + std::cos(2. * phi); + // l = 8, m = 3 + rn[i + 11] = -(0.00245204119306875 * std::pow(w2m1, 1.5) * + ((135135.0 / 8.0) * std::pow(w, 5) - + 45045.0 / 4.0 * std::pow(w, 3) + (10395.0 / 8.0) * w) * + std::cos(3. * phi)); + // l = 8, m = 4 + rn[i + 12] = 0.000316557156832328 * w2m1 * w2m1 * + ((675675.0 / 8.0) * std::pow(w, 4) - 135135.0 / 4.0 * w * w + + 10395.0 / 8.0) * + std::cos(4.0 * phi); + // l = 8, m = 5 + rn[i + 13] = -(4.38985792528482e-5 * std::pow(w2m1, 2.5) * + ((675675.0 / 2.) * std::pow(w, 3) - 135135.0 / 2. * w) * + std::cos(5.0 * phi)); + // l = 8, m = 6 + rn[i + 14] = 6.77369783729086e-6 * std::pow(w2m1, 3) * + ((2027025.0 / 2.) * w * w - 135135.0 / 2.) * + std::cos(6.0 * phi); + // l = 8, m = 7 + rn[i + 15] = + -(2.50682661696018 * w * std::pow(w2m1, 3.5) * std::cos(7.0 * phi)); + // l = 8, m = 8 + rn[i + 16] = 0.626706654240044 * std::pow(w2m1, 4) * std::cos(8.0 * phi); + break; + case 9: + // l = 9, m = -9 + rn[i] = -(0.609049392175524 * std::pow(w2m1, 4.5) * std::sin(9.0 * phi)); + // l = 9, m = -8 + rn[i + 1] = + 2.58397773170915 * w * std::pow(w2m1, 4) * std::sin(8.0 * phi); + // l = 9, m = -7 + rn[i + 2] = + -(4.37240315267812e-7 * std::pow(w2m1, 3.5) * + ((34459425.0 / 2.) * w * w - 2027025.0 / 2.) * std::sin(7.0 * phi)); + // l = 9, m = -6 + rn[i + 3] = 3.02928976464514e-6 * std::pow(w2m1, 3) * + ((11486475.0 / 2.) * std::pow(w, 3) - 2027025.0 / 2. * w) * + std::sin(6.0 * phi); + // l = 9, m = -5 + rn[i + 4] = -(2.34647776186144e-5 * std::pow(w2m1, 2.5) * + ((11486475.0 / 8.0) * std::pow(w, 4) - + 2027025.0 / 4.0 * w * w + 135135.0 / 8.0) * + std::sin(5.0 * phi)); + // l = 9, m = -4 + rn[i + 5] = 0.000196320414650061 * w2m1 * w2m1 * + ((2297295.0 / 8.0) * std::pow(w, 5) - + 675675.0 / 4.0 * std::pow(w, 3) + (135135.0 / 8.0) * w) * + std::sin(4.0 * phi); + // l = 9, m = -3 + rn[i + 6] = -( + 0.00173385495536766 * std::pow(w2m1, 1.5) * + ((765765.0 / 16.0) * std::pow(w, 6) - 675675.0 / 16.0 * std::pow(w, 4) + + (135135.0 / 16.0) * w * w - 3465.0 / 16.0) * + std::sin(3. * phi)); + // l = 9, m = -2 + rn[i + 7] = + 0.0158910431540932 * (w2m1) * + ((109395.0 / 16.0) * std::pow(w, 7) - 135135.0 / 16.0 * std::pow(w, 5) + + (45045.0 / 16.0) * std::pow(w, 3) - 3465.0 / 16.0 * w) * + std::sin(2. * phi); + // l = 9, m = -1 + rn[i + 8] = -( + 0.149071198499986 * std::sqrt(w2m1) * + ((109395.0 / 128.0) * std::pow(w, 8) - 45045.0 / 32.0 * std::pow(w, 6) + + (45045.0 / 64.0) * std::pow(w, 4) - 3465.0 / 32.0 * w * w + + 315.0 / 128.0) * + std::sin(phi)); + // l = 9, m = 0 + rn[i + 9] = 94.9609375 * std::pow(w, 9) - 201.09375 * std::pow(w, 7) + + 140.765625 * std::pow(w, 5) - 36.09375 * std::pow(w, 3) + + 2.4609375 * w; + // l = 9, m = 1 + rn[i + 10] = -( + 0.149071198499986 * std::sqrt(w2m1) * + ((109395.0 / 128.0) * std::pow(w, 8) - 45045.0 / 32.0 * std::pow(w, 6) + + (45045.0 / 64.0) * std::pow(w, 4) - 3465.0 / 32.0 * w * w + + 315.0 / 128.0) * + std::cos(phi)); + // l = 9, m = 2 + rn[i + 11] = + 0.0158910431540932 * (w2m1) * + ((109395.0 / 16.0) * std::pow(w, 7) - 135135.0 / 16.0 * std::pow(w, 5) + + (45045.0 / 16.0) * std::pow(w, 3) - 3465.0 / 16.0 * w) * + std::cos(2. * phi); + // l = 9, m = 3 + rn[i + 12] = -( + 0.00173385495536766 * std::pow(w2m1, 1.5) * + ((765765.0 / 16.0) * std::pow(w, 6) - 675675.0 / 16.0 * std::pow(w, 4) + + (135135.0 / 16.0) * w * w - 3465.0 / 16.0) * + std::cos(3. * phi)); + // l = 9, m = 4 + rn[i + 13] = 0.000196320414650061 * w2m1 * w2m1 * + ((2297295.0 / 8.0) * std::pow(w, 5) - + 675675.0 / 4.0 * std::pow(w, 3) + (135135.0 / 8.0) * w) * + std::cos(4.0 * phi); + // l = 9, m = 5 + rn[i + 14] = -(2.34647776186144e-5 * std::pow(w2m1, 2.5) * + ((11486475.0 / 8.0) * std::pow(w, 4) - + 2027025.0 / 4.0 * w * w + 135135.0 / 8.0) * + std::cos(5.0 * phi)); + // l = 9, m = 6 + rn[i + 15] = 3.02928976464514e-6 * std::pow(w2m1, 3) * + ((11486475.0 / 2.) * std::pow(w, 3) - 2027025.0 / 2. * w) * + std::cos(6.0 * phi); + // l = 9, m = 7 + rn[i + 16] = + -(4.37240315267812e-7 * std::pow(w2m1, 3.5) * + ((34459425.0 / 2.) * w * w - 2027025.0 / 2.) * std::cos(7.0 * phi)); + // l = 9, m = 8 + rn[i + 17] = + 2.58397773170915 * w * std::pow(w2m1, 4) * std::cos(8.0 * phi); + // l = 9, m = 9 + rn[i + 18] = + -(0.609049392175524 * std::pow(w2m1, 4.5) * std::cos(9.0 * phi)); + break; + case 10: + // l = 10, m = -10 + rn[i] = 0.593627917136573 * std::pow(w2m1, 5) * std::sin(10.0 * phi); + // l = 10, m = -9 + rn[i + 1] = + -(2.65478475211798 * w * std::pow(w2m1, 4.5) * std::sin(9.0 * phi)); + // l = 10, m = -8 + rn[i + 2] = 2.49953651452314e-8 * std::pow(w2m1, 4) * + ((654729075.0 / 2.) * w * w - 34459425.0 / 2.) * + std::sin(8.0 * phi); + // l = 10, m = -7 + rn[i + 3] = + -(1.83677671621093e-7 * std::pow(w2m1, 3.5) * + ((218243025.0 / 2.) * std::pow(w, 3) - 34459425.0 / 2. * w) * + std::sin(7.0 * phi)); + // l = 10, m = -6 + rn[i + 4] = 1.51464488232257e-6 * std::pow(w2m1, 3) * + ((218243025.0 / 8.0) * std::pow(w, 4) - + 34459425.0 / 4.0 * w * w + 2027025.0 / 8.0) * + std::sin(6.0 * phi); + // l = 10, m = -5 + rn[i + 5] = + -(1.35473956745817e-5 * std::pow(w2m1, 2.5) * + ((43648605.0 / 8.0) * std::pow(w, 5) - + 11486475.0 / 4.0 * std::pow(w, 3) + (2027025.0 / 8.0) * w) * + std::sin(5.0 * phi)); + // l = 10, m = -4 + rn[i + 6] = 0.000128521880085575 * w2m1 * w2m1 * + ((14549535.0 / 16.0) * std::pow(w, 6) - + 11486475.0 / 16.0 * std::pow(w, 4) + + (2027025.0 / 16.0) * w * w - 45045.0 / 16.0) * + std::sin(4.0 * phi); + // l = 10, m = -3 + rn[i + 7] = -(0.00127230170115096 * std::pow(w2m1, 1.5) * + ((2078505.0 / 16.0) * std::pow(w, 7) - + 2297295.0 / 16.0 * std::pow(w, 5) + + (675675.0 / 16.0) * std::pow(w, 3) - 45045.0 / 16.0 * w) * + std::sin(3. * phi)); + // l = 10, m = -2 + rn[i + 8] = 0.012974982402692 * (w2m1) * + ((2078505.0 / 128.0) * std::pow(w, 8) - + 765765.0 / 32.0 * std::pow(w, 6) + + (675675.0 / 64.0) * std::pow(w, 4) - + 45045.0 / 32.0 * w * w + 3465.0 / 128.0) * + std::sin(2. * phi); + // l = 10, m = -1 + rn[i + 9] = -(0.134839972492648 * std::sqrt(w2m1) * + ((230945.0 / 128.0) * std::pow(w, 9) - + 109395.0 / 32.0 * std::pow(w, 7) + + (135135.0 / 64.0) * std::pow(w, 5) - + 15015.0 / 32.0 * std::pow(w, 3) + (3465.0 / 128.0) * w) * + std::sin(phi)); + // l = 10, m = 0 + rn[i + 10] = 180.42578125 * std::pow(w, 10) - + 427.32421875 * std::pow(w, 8) + + 351.9140625 * std::pow(w, 6) - 117.3046875 * std::pow(w, 4) + + 13.53515625 * w * w - 0.24609375; + // l = 10, m = 1 + rn[i + 11] = -(0.134839972492648 * std::sqrt(w2m1) * + ((230945.0 / 128.0) * std::pow(w, 9) - + 109395.0 / 32.0 * std::pow(w, 7) + + (135135.0 / 64.0) * std::pow(w, 5) - + 15015.0 / 32.0 * std::pow(w, 3) + (3465.0 / 128.0) * w) * + std::cos(phi)); + // l = 10, m = 2 + rn[i + 12] = 0.012974982402692 * (w2m1) * + ((2078505.0 / 128.0) * std::pow(w, 8) - + 765765.0 / 32.0 * std::pow(w, 6) + + (675675.0 / 64.0) * std::pow(w, 4) - + 45045.0 / 32.0 * w * w + 3465.0 / 128.0) * + std::cos(2. * phi); + // l = 10, m = 3 + rn[i + 13] = + -(0.00127230170115096 * std::pow(w2m1, 1.5) * + ((2078505.0 / 16.0) * std::pow(w, 7) - + 2297295.0 / 16.0 * std::pow(w, 5) + + (675675.0 / 16.0) * std::pow(w, 3) - 45045.0 / 16.0 * w) * + std::cos(3. * phi)); + // l = 10, m = 4 + rn[i + 14] = 0.000128521880085575 * w2m1 * w2m1 * + ((14549535.0 / 16.0) * std::pow(w, 6) - + 11486475.0 / 16.0 * std::pow(w, 4) + + (2027025.0 / 16.0) * w * w - 45045.0 / 16.0) * + std::cos(4.0 * phi); + // l = 10, m = 5 + rn[i + 15] = + -(1.35473956745817e-5 * std::pow(w2m1, 2.5) * + ((43648605.0 / 8.0) * std::pow(w, 5) - + 11486475.0 / 4.0 * std::pow(w, 3) + (2027025.0 / 8.0) * w) * + std::cos(5.0 * phi)); + // l = 10, m = 6 + rn[i + 16] = 1.51464488232257e-6 * std::pow(w2m1, 3) * + ((218243025.0 / 8.0) * std::pow(w, 4) - + 34459425.0 / 4.0 * w * w + 2027025.0 / 8.0) * + std::cos(6.0 * phi); + // l = 10, m = 7 + rn[i + 17] = + -(1.83677671621093e-7 * std::pow(w2m1, 3.5) * + ((218243025.0 / 2.) * std::pow(w, 3) - 34459425.0 / 2. * w) * + std::cos(7.0 * phi)); + // l = 10, m = 8 + rn[i + 18] = 2.49953651452314e-8 * std::pow(w2m1, 4) * + ((654729075.0 / 2.) * w * w - 34459425.0 / 2.) * + std::cos(8.0 * phi); + // l = 10, m = 9 + rn[i + 19] = + -(2.65478475211798 * w * std::pow(w2m1, 4.5) * std::cos(9.0 * phi)); + // l = 10, m = 10 + rn[i + 20] = 0.593627917136573 * std::pow(w2m1, 5) * std::cos(10.0 * phi); } } } - -void calc_zn(int n, double rho, double phi, double zn[]) { +void calc_zn(int n, double rho, double phi, double zn[]) +{ // =========================================================================== // Determine vector of sin(n*phi) and cos(n*phi). This takes advantage of the // following recurrence relations so that only a single sin/cos have to be @@ -553,7 +671,7 @@ void calc_zn(int n, double rho, double phi, double zn[]) { } for (int i = 0; i <= n; i++) { - sin_phi_vec[i] *= sin_phi; + sin_phi_vec[i] *= sin_phi; } // =========================================================================== @@ -568,10 +686,11 @@ void calc_zn(int n, double rho, double phi, double zn[]) { // Fill the 2nd diagonal (Eq 3.10 in Chong) for (int q = 0; q <= n - 2; q++) { - zn_mat[q][q+2] = (q + 2) * zn_mat[q+2][q+2] - (q + 1) * zn_mat[q][q]; + zn_mat[q][q + 2] = (q + 2) * zn_mat[q + 2][q + 2] - (q + 1) * zn_mat[q][q]; } - // Fill in the rest of the values using the original results (Eq. 3.8 in Chong) + // Fill in the rest of the values using the original results (Eq. 3.8 in + // Chong) for (int p = 4; p <= n; p++) { double k2 = 2 * p * (p - 1) * (p - 2); for (int q = p - 4; q >= 0; q -= 2) { @@ -579,7 +698,7 @@ void calc_zn(int n, double rho, double phi, double zn[]) { double k3 = -q * q * (p - 1) - p * (p - 1) * (p - 2); double k4 = (-p * (p + q - 2) * (p - q - 2)) / 2.; zn_mat[q][p] = - ((k2 * rho * rho + k3) * zn_mat[q][p-2] + k4 * zn_mat[q][p-4]) / k1; + ((k2 * rho * rho + k3) * zn_mat[q][p - 2] + k4 * zn_mat[q][p - 4]) / k1; } } @@ -602,10 +721,10 @@ void calc_zn(int n, double rho, double phi, double zn[]) { i++; } } - } -void calc_zn_rad(int n, double rho, double zn_rad[]) { +void calc_zn_rad(int n, double rho, double zn_rad[]) +{ // Calculate R_p0(rho) as Zn_p0(rho) // Set up the array of the coefficients @@ -616,9 +735,9 @@ void calc_zn_rad(int n, double rho, double zn_rad[]) { // Fill in the rest of the array (Eq 3.8 and Eq 3.10 in Chong) for (int p = 2; p <= n; p += 2) { - int index = int(p/2); + int index = int(p / 2); if (p == 2) { - // Setting up R_22 to calculate R_20 (Eq 3.10 in Chong) + // Setting up R_22 to calculate R_20 (Eq 3.10 in Chong) double R_22 = rho * rho; zn_rad[index] = 2 * R_22 - zn_rad[0]; } else { @@ -627,51 +746,51 @@ void calc_zn_rad(int n, double rho, double zn_rad[]) { double k3 = -q * q * (p - 1) - p * (p - 1) * (p - 2); double k4 = (-p * (p + q - 2) * (p - q - 2)) / 2.; zn_rad[index] = - ((k2 * rho * rho + k3) * zn_rad[index-1] + k4 * zn_rad[index-2]) / k1; + ((k2 * rho * rho + k3) * zn_rad[index - 1] + k4 * zn_rad[index - 2]) / + k1; } } } - -void rotate_angle_c(double uvw[3], double mu, const double* phi, uint64_t* seed) { +void rotate_angle_c(double uvw[3], double mu, const double* phi, uint64_t* seed) +{ Direction u = rotate_angle({uvw}, mu, phi, seed); uvw[0] = u.x; uvw[1] = u.y; uvw[2] = u.z; } - -Direction rotate_angle(Direction u, double mu, const double* phi, uint64_t* seed) +Direction rotate_angle( + Direction u, double mu, const double* phi, uint64_t* seed) { // Sample azimuthal angle in [0,2pi) if none provided double phi_; if (phi != nullptr) { phi_ = (*phi); } else { - phi_ = 2.0*PI*prn(seed); + phi_ = 2.0 * PI * prn(seed); } // Precompute factors to save flops double sinphi = std::sin(phi_); double cosphi = std::cos(phi_); - double a = std::sqrt(std::fmax(0., 1. - mu*mu)); - double b = std::sqrt(std::fmax(0., 1. - u.z*u.z)); + double a = std::sqrt(std::fmax(0., 1. - mu * mu)); + double b = std::sqrt(std::fmax(0., 1. - u.z * u.z)); // Need to treat special case where sqrt(1 - w**2) is close to zero by // expanding about the v component rather than the w component if (b > 1e-10) { - return {mu*u.x + a*(u.x*u.z*cosphi - u.y*sinphi) / b, - mu*u.y + a*(u.y*u.z*cosphi + u.x*sinphi) / b, - mu*u.z - a*b*cosphi}; + return {mu * u.x + a * (u.x * u.z * cosphi - u.y * sinphi) / b, + mu * u.y + a * (u.y * u.z * cosphi + u.x * sinphi) / b, + mu * u.z - a * b * cosphi}; } else { - b = std::sqrt(1. - u.y*u.y); - return {mu*u.x + a*(-u.x*u.y*sinphi + u.z*cosphi) / b, - mu*u.y + a*b*sinphi, - mu*u.z - a*(u.y*u.z*sinphi + u.x*cosphi) / b}; + b = std::sqrt(1. - u.y * u.y); + return {mu * u.x + a * (-u.x * u.y * sinphi + u.z * cosphi) / b, + mu * u.y + a * b * sinphi, + mu * u.z - a * (u.y * u.z * sinphi + u.x * cosphi) / b}; } } - void spline(int n, const double x[], const double y[], double z[]) { vector c_new(n - 1); @@ -679,76 +798,78 @@ void spline(int n, const double x[], const double y[], double z[]) // Set natural boundary conditions c_new[0] = 0.0; z[0] = 0.0; - z[n-1] = 0.0; + z[n - 1] = 0.0; // Solve using tridiagonal matrix algorithm; first do forward sweep for (int i = 1; i < n - 1; i++) { - double a = x[i] - x[i-1]; - double c = x[i+1] - x[i]; - double b = 2.0*(a + c); - double d = 6.0*((y[i+1] - y[i])/c - (y[i] - y[i-1])/a); + double a = x[i] - x[i - 1]; + double c = x[i + 1] - x[i]; + double b = 2.0 * (a + c); + double d = 6.0 * ((y[i + 1] - y[i]) / c - (y[i] - y[i - 1]) / a); - c_new[i] = c/(b - a*c_new[i-1]); - z[i] = (d - a*z[i-1])/(b - a*c_new[i-1]); + c_new[i] = c / (b - a * c_new[i - 1]); + z[i] = (d - a * z[i - 1]) / (b - a * c_new[i - 1]); } // Back substitution for (int i = n - 2; i >= 0; i--) { - z[i] = z[i] - c_new[i]*z[i+1]; + z[i] = z[i] - c_new[i] * z[i + 1]; } } - -double spline_interpolate(int n, const double x[], const double y[], - const double z[], double xint) +double spline_interpolate( + int n, const double x[], const double y[], const double z[], double xint) { // Find the lower bounding index in x of xint int i = n - 1; while (--i) { - if (xint >= x[i]) break; + if (xint >= x[i]) + break; } - double h = x[i+1] - x[i]; + double h = x[i + 1] - x[i]; double r = xint - x[i]; // Compute the coefficients - double b = (y[i+1] - y[i])/h - (h/6.0)*(z[i+1] + 2.0*z[i]); - double c = z[i]/2.0; - double d = (z[i+1] - z[i])/(h*6.0); + double b = (y[i + 1] - y[i]) / h - (h / 6.0) * (z[i + 1] + 2.0 * z[i]); + double c = z[i] / 2.0; + double d = (z[i + 1] - z[i]) / (h * 6.0); - return y[i] + b*r + c*r*r + d*r*r*r; + return y[i] + b * r + c * r * r + d * r * r * r; } - double spline_integrate(int n, const double x[], const double y[], const double z[], double xa, double xb) { // Find the lower bounding index in x of the lower limit of integration. int ia = n - 1; while (--ia) { - if (xa >= x[ia]) break; + if (xa >= x[ia]) + break; } // Find the lower bounding index in x of the upper limit of integration. int ib = n - 1; while (--ib) { - if (xb >= x[ib]) break; + if (xb >= x[ib]) + break; } // Evaluate the integral double s = 0.0; for (int i = ia; i <= ib; i++) { - double h = x[i+1] - x[i]; + double h = x[i + 1] - x[i]; // Compute the coefficients - double b = (y[i+1] - y[i])/h - (h/6.0)*(z[i+1] + 2.0*z[i]); - double c = z[i]/2.0; - double d = (z[i+1] - z[i])/(h*6.0); + double b = (y[i + 1] - y[i]) / h - (h / 6.0) * (z[i + 1] + 2.0 * z[i]); + double c = z[i] / 2.0; + double d = (z[i + 1] - z[i]) / (h * 6.0); // Subtract the integral from x[ia] to xa if (i == ia) { double r = xa - x[ia]; - s = s - (y[i]*r + b/2.0*r*r + c/3.0*r*r*r + d/4.0*r*r*r*r); + s = s - (y[i] * r + b / 2.0 * r * r + c / 3.0 * r * r * r + + d / 4.0 * r * r * r * r); } // Integrate from x[ib] to xb in final interval @@ -757,7 +878,8 @@ double spline_integrate(int n, const double x[], const double y[], } // Accumulate the integral - s = s + y[i]*h + b/2.0*h*h + c/3.0*h*h*h + d/4.0*h*h*h*h; + s = s + y[i] * h + b / 2.0 * h * h + c / 3.0 * h * h * h + + d / 4.0 * h * h * h * h; } return s; @@ -779,8 +901,8 @@ std::complex faddeeva(std::complex z) // For imag(z) < 0, w_int(z) = -conjg(w_fun(conjg(z))) // Note that Faddeeva::w will interpret zero as machine epsilon - return z.imag() > 0.0 ? Faddeeva::w(z) : - -std::conj(Faddeeva::w(std::conj(z))); + return z.imag() > 0.0 ? Faddeeva::w(z) + : -std::conj(Faddeeva::w(std::conj(z))); } std::complex w_derivative(std::complex z, int order) @@ -790,10 +912,10 @@ std::complex w_derivative(std::complex z, int order) case 0: return faddeeva(z); case 1: - return -2.0*z*faddeeva(z) + 2.0i / SQRT_PI; + return -2.0 * z * faddeeva(z) + 2.0i / SQRT_PI; default: - return -2.0*z*w_derivative(z, order-1) - - 2.0*(order-1)*w_derivative(z, order-2); + return -2.0 * z * w_derivative(z, order - 1) - + 2.0 * (order - 1) * w_derivative(z, order - 2); } } diff --git a/src/mcpl_interface.cpp b/src/mcpl_interface.cpp new file mode 100644 index 00000000000..5c3df026ce5 --- /dev/null +++ b/src/mcpl_interface.cpp @@ -0,0 +1,227 @@ +#include "openmc/mcpl_interface.h" + +#include "openmc/bank.h" +#include "openmc/error.h" +#include "openmc/file_utils.h" +#include "openmc/message_passing.h" +#include "openmc/settings.h" +#include "openmc/simulation.h" +#include "openmc/state_point.h" +#include "openmc/vector.h" + +#include + +#ifdef OPENMC_MCPL +#include +#endif + +namespace openmc { + +//============================================================================== +// Constants +//============================================================================== + +#ifdef OPENMC_MCPL +const bool MCPL_ENABLED = true; +#else +const bool MCPL_ENABLED = false; +#endif + +//============================================================================== +// Functions +//============================================================================== + +#ifdef OPENMC_MCPL +SourceSite mcpl_particle_to_site(const mcpl_particle_t* particle) +{ + SourceSite site; + + switch (particle->pdgcode) { + case 2112: + site.particle = ParticleType::neutron; + break; + case 22: + site.particle = ParticleType::photon; + break; + case 11: + site.particle = ParticleType::electron; + break; + case -11: + site.particle = ParticleType::positron; + break; + } + + // Copy position and direction + site.r.x = particle->position[0]; + site.r.y = particle->position[1]; + site.r.z = particle->position[2]; + site.u.x = particle->direction[0]; + site.u.y = particle->direction[1]; + site.u.z = particle->direction[2]; + + // MCPL stores kinetic energy in [MeV], time in [ms] + site.E = particle->ekin * 1e6; + site.time = particle->time * 1e-3; + site.wgt = particle->weight; + + return site; +} +#endif + +//============================================================================== + +vector mcpl_source_sites(std::string path) +{ + vector sites; + +#ifdef OPENMC_MCPL + // Open MCPL file and determine number of particles + auto mcpl_file = mcpl_open_file(path.c_str()); + size_t n_sites = mcpl_hdr_nparticles(mcpl_file); + + for (int i = 0; i < n_sites; i++) { + // Extract particle from mcpl-file, checking if it is a neutron, photon, + // electron, or positron. Otherwise skip. + const mcpl_particle_t* particle; + int pdg = 0; + while (pdg != 2112 && pdg != 22 && pdg != 11 && pdg != -11) { + particle = mcpl_read(mcpl_file); + pdg = particle->pdgcode; + } + + // Convert to source site and add to vector + sites.push_back(mcpl_particle_to_site(particle)); + } + + // Check that some sites were read + if (sites.empty()) { + fatal_error("MCPL file contained no neutron, photon, electron, or positron " + "source particles."); + } + + mcpl_close_file(mcpl_file); +#else + fatal_error( + "Your build of OpenMC does not support reading MCPL source files."); +#endif + + return sites; +} + +//============================================================================== + +#ifdef OPENMC_MCPL +void write_mcpl_source_bank(mcpl_outfile_t file_id, + gsl::span source_bank, const vector& bank_index) +{ + int64_t dims_size = settings::n_particles; + int64_t count_size = simulation::work_per_rank; + + if (mpi::master) { + // Particles are writeen to disk from the master node only + + // Save source bank sites since the array is overwritten below +#ifdef OPENMC_MPI + vector temp_source {source_bank.begin(), source_bank.end()}; +#endif + + // loop over the other nodes and receive data - then write those. + for (int i = 0; i < mpi::n_procs; ++i) { + // number of particles for node node i + size_t count[] {static_cast(bank_index[i + 1] - bank_index[i])}; + +#ifdef OPENMC_MPI + if (i > 0) + MPI_Recv(source_bank.data(), count[0], mpi::source_site, i, i, + mpi::intracomm, MPI_STATUS_IGNORE); +#endif + // now write the source_bank data again. + for (const auto& site : source_bank) { + // particle is now at the iterator + // write it to the mcpl-file + mcpl_particle_t p; + p.position[0] = site.r.x; + p.position[1] = site.r.y; + p.position[2] = site.r.z; + + // mcpl requires that the direction vector is unit length + // which is also the case in openmc + p.direction[0] = site.u.x; + p.direction[1] = site.u.y; + p.direction[2] = site.u.z; + + // MCPL stores kinetic energy in [MeV], time in [ms] + p.ekin = site.E * 1e-6; + p.time = site.time * 1e3; + p.weight = site.wgt; + + switch (site.particle) { + case ParticleType::neutron: + p.pdgcode = 2112; + break; + case ParticleType::photon: + p.pdgcode = 22; + break; + case ParticleType::electron: + p.pdgcode = 11; + break; + case ParticleType::positron: + p.pdgcode = -11; + break; + } + + mcpl_add_particle(file_id, &p); + } + } +#ifdef OPENMC_MPI + // Restore state of source bank + std::copy(temp_source.begin(), temp_source.end(), source_bank.begin()); +#endif + } else { +#ifdef OPENMC_MPI + MPI_Send(source_bank.data(), count_size, mpi::source_site, 0, mpi::rank, + mpi::intracomm); +#endif + } +} +#endif + +//============================================================================== + +void write_mcpl_source_point(const char* filename, + gsl::span source_bank, const vector& bank_index) +{ + std::string filename_(filename); + const auto extension = get_file_extension(filename_); + if (extension == "") { + filename_.append(".mcpl"); + } else if (extension != "mcpl") { + warning("write_mcpl_source_point was passed a file extension differing " + "from .mcpl, but an mcpl file will be written."); + } + +#ifdef OPENMC_MCPL + mcpl_outfile_t file_id; + + std::string line; + if (mpi::master) { + file_id = mcpl_create_outfile(filename_.c_str()); + if (VERSION_DEV) { + line = fmt::format("OpenMC {0}.{1}.{2}-development", VERSION_MAJOR, + VERSION_MINOR, VERSION_RELEASE); + } else { + line = fmt::format( + "OpenMC {0}.{1}.{2}", VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE); + } + mcpl_hdr_set_srcname(file_id, line.c_str()); + } + + write_mcpl_source_bank(file_id, source_bank, bank_index); + + if (mpi::master) { + mcpl_close_outfile(file_id); + } +#endif +} + +} // namespace openmc diff --git a/src/mesh.cpp b/src/mesh.cpp index 09ae82c707b..c57dd5dcc31 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1,42 +1,53 @@ #include "openmc/mesh.h" #include // for copy, equal, min, min_element -#include // for size_t -#include // for ceil +#include // for ceil +#include // for size_t +#include #include -#include #ifdef OPENMC_MPI #include "mpi.h" #endif -#ifdef _OPENMP -#include -#endif -#include // for fmt + #include "xtensor/xbuilder.hpp" #include "xtensor/xeval.hpp" #include "xtensor/xmath.hpp" #include "xtensor/xsort.hpp" #include "xtensor/xtensor.hpp" #include "xtensor/xview.hpp" +#include // for fmt #include "openmc/capi.h" #include "openmc/constants.h" +#include "openmc/container_util.h" #include "openmc/error.h" #include "openmc/file_utils.h" +#include "openmc/geometry.h" #include "openmc/hdf5_interface.h" +#include "openmc/material.h" #include "openmc/memory.h" #include "openmc/message_passing.h" +#include "openmc/openmp_interface.h" +#include "openmc/particle_data.h" +#include "openmc/plot.h" +#include "openmc/random_dist.h" #include "openmc/search.h" #include "openmc/settings.h" #include "openmc/tallies/filter.h" #include "openmc/tallies/tally.h" +#include "openmc/volume_calc.h" #include "openmc/xml_interface.h" #ifdef LIBMESH +#include "libmesh/mesh_modification.h" #include "libmesh/mesh_tools.h" #include "libmesh/numeric_vector.h" #endif +#ifdef DAGMC +#include "moab/FileOptions.hpp" +#endif + namespace openmc { //============================================================================== @@ -49,7 +60,6 @@ const bool LIBMESH_ENABLED = true; const bool LIBMESH_ENABLED = false; #endif - namespace model { std::unordered_map mesh_map; @@ -61,7 +71,7 @@ vector> meshes; namespace settings { unique_ptr libmesh_init; const libMesh::Parallel::Communicator* libmesh_comm {nullptr}; -} +} // namespace settings #endif //============================================================================== @@ -76,10 +86,11 @@ const libMesh::Parallel::Communicator* libmesh_comm {nullptr}; //! will be updated to match the intersection point, and `min_distance` will //! also be updated. -inline bool check_intersection_point(double x1, double x0, double y1, - double y0, double z1, double z0, Position& r, double& min_distance) +inline bool check_intersection_point(double x1, double x0, double y1, double y0, + double z1, double z0, Position& r, double& min_distance) { - double dist = std::pow(x1-x0, 2) + std::pow(y1-y0, 2) + std::pow(z1-z0, 2); + double dist = + std::pow(x1 - x0, 2) + std::pow(y1 - y0, 2) + std::pow(z1 - z0, 2); if (dist < min_distance) { r.x = x1; r.y = y1; @@ -96,21 +107,13 @@ inline bool check_intersection_point(double x1, double x0, double y1, Mesh::Mesh(pugi::xml_node node) { - // Copy mesh id - if (check_for_node(node, "id")) { - id_ = std::stoi(get_node_value(node, "id")); - - // Check to make sure 'id' hasn't been used - if (model::mesh_map.find(id_) != model::mesh_map.end()) { - fatal_error("Two or more meshes use the same unique ID: " + - std::to_string(id_)); - } - } + // Read mesh id + id_ = std::stoi(get_node_value(node, "id")); } -void -Mesh::set_id(int32_t id) { - Expects(id >=0 || id == C_NONE); +void Mesh::set_id(int32_t id) +{ + Expects(id >= 0 || id == C_NONE); // Clear entry in mesh map in case one was already assigned if (id_ != C_NONE) { @@ -120,7 +123,8 @@ Mesh::set_id(int32_t id) { // Ensure no other mesh has the same ID if (model::mesh_map.find(id) != model::mesh_map.end()) { - throw std::runtime_error{fmt::format("Two meshes have the same ID: {}", id)}; + throw std::runtime_error { + fmt::format("Two meshes have the same ID: {}", id)}; } // If no ID is specified, auto-assign the next ID in the sequence @@ -137,48 +141,175 @@ Mesh::set_id(int32_t id) { model::mesh_map[id] = model::meshes.size() - 1; } +vector Mesh::volumes() const +{ + vector volumes(n_bins()); + for (int i = 0; i < n_bins(); i++) { + volumes[i] = this->volume(i); + } + return volumes; +} + +int Mesh::material_volumes( + int n_sample, int bin, gsl::span result, uint64_t* seed) const +{ + vector materials; + vector hits; + +#pragma omp parallel + { + vector local_materials; + vector local_hits; + GeometryState geom; + +#pragma omp for + for (int i = 0; i < n_sample; ++i) { + // Get seed for i-th sample + uint64_t seed_i = future_seed(3 * i, *seed); + + // Sample position and set geometry state + geom.r() = this->sample_element(bin, &seed_i); + geom.u() = {1., 0., 0.}; + geom.n_coord() = 1; + + // If this location is not in the geometry at all, move on to next block + if (!exhaustive_find_cell(geom)) + continue; + + int i_material = geom.material(); + + // Check if this material was previously hit and if so, increment count + auto it = + std::find(local_materials.begin(), local_materials.end(), i_material); + if (it == local_materials.end()) { + local_materials.push_back(i_material); + local_hits.push_back(1); + } else { + local_hits[it - local_materials.begin()]++; + } + } // omp for + + // Reduce index/hits lists from each thread into a single copy + reduce_indices_hits(local_materials, local_hits, materials, hits); + } // omp parallel + + // Advance RNG seed + advance_prn_seed(3 * n_sample, seed); + + // Make sure span passed in is large enough + if (hits.size() > result.size()) { + return -1; + } + + // Convert hits to fractions + for (int i_mat = 0; i_mat < hits.size(); ++i_mat) { + double fraction = double(hits[i_mat]) / n_sample; + result[i_mat].material = materials[i_mat]; + result[i_mat].volume = fraction * this->volume(bin); + } + return hits.size(); +} + +vector Mesh::material_volumes( + int n_sample, int bin, uint64_t* seed) const +{ + // Create result vector with space for 8 pairs + vector result; + result.reserve(8); + + int size = -1; + while (true) { + // Get material volumes + size = this->material_volumes( + n_sample, bin, {result.data(), result.data() + result.capacity()}, seed); + + // If capacity was sufficient, resize the vector and return + if (size >= 0) { + result.resize(size); + break; + } + + // Otherwise, increase capacity of the vector + result.reserve(2 * result.capacity()); + } + + return result; +} + //============================================================================== // Structured Mesh implementation //============================================================================== -std::string -StructuredMesh::bin_label(int bin) const { - vector ijk(n_dimension_); - get_indices_from_bin(bin, ijk.data()); +std::string StructuredMesh::bin_label(int bin) const +{ + MeshIndex ijk = get_indices_from_bin(bin); if (n_dimension_ > 2) { return fmt::format("Mesh Index ({}, {}, {})", ijk[0], ijk[1], ijk[2]); } else if (n_dimension_ > 1) { return fmt::format("Mesh Index ({}, {})", ijk[0], ijk[1]); } else { - return fmt::format("Mesh Index ({})", ijk[0]) ; + return fmt::format("Mesh Index ({})", ijk[0]); } } +xt::xtensor StructuredMesh::get_x_shape() const +{ + // because method is const, shape_ is const as well and can't be adapted + auto tmp_shape = shape_; + return xt::adapt(tmp_shape, {n_dimension_}); +} + +Position StructuredMesh::sample_element( + const MeshIndex& ijk, uint64_t* seed) const +{ + // lookup the lower/upper bounds for the mesh element + double x_min = negative_grid_boundary(ijk, 0); + double x_max = positive_grid_boundary(ijk, 0); + + double y_min = (n_dimension_ >= 2) ? negative_grid_boundary(ijk, 1) : 0.0; + double y_max = (n_dimension_ >= 2) ? positive_grid_boundary(ijk, 1) : 0.0; + + double z_min = (n_dimension_ == 3) ? negative_grid_boundary(ijk, 2) : 0.0; + double z_max = (n_dimension_ == 3) ? positive_grid_boundary(ijk, 2) : 0.0; + + return {x_min + (x_max - x_min) * prn(seed), + y_min + (y_max - y_min) * prn(seed), z_min + (z_max - z_min) * prn(seed)}; +} + //============================================================================== // Unstructured Mesh implementation //============================================================================== -UnstructuredMesh::UnstructuredMesh(pugi::xml_node node) : Mesh(node) { - n_dimension_ = 3; +UnstructuredMesh::UnstructuredMesh(pugi::xml_node node) : Mesh(node) +{ // check the mesh type if (check_for_node(node, "type")) { auto temp = get_node_value(node, "type", true, true); - if (temp != "unstructured") { + if (temp != mesh_type) { fatal_error(fmt::format("Invalid mesh type: {}", temp)); } } + // check if a length unit multiplier was specified + if (check_for_node(node, "length_multiplier")) { + length_multiplier_ = std::stod(get_node_value(node, "length_multiplier")); + } + // get the filename of the unstructured mesh to load if (check_for_node(node, "filename")) { filename_ = get_node_value(node, "filename"); if (!file_exists(filename_)) { fatal_error("Mesh file '" + filename_ + "' does not exist!"); } + } else { + fatal_error(fmt::format( + "No filename supplied for unstructured mesh with ID: {}", id_)); } - else { - fatal_error(fmt::format("No filename supplied for unstructured mesh with ID: {}", id_)); + + if (check_for_node(node, "options")) { + options_ = get_node_value(node, "options"); } // check if mesh tally data should be written with @@ -186,70 +317,172 @@ UnstructuredMesh::UnstructuredMesh(pugi::xml_node node) : Mesh(node) { if (check_for_node(node, "output")) { output_ = get_node_value_bool(node, "output"); } +} +Position UnstructuredMesh::sample_tet( + std::array coords, uint64_t* seed) const +{ + // Uniform distribution + double s = prn(seed); + double t = prn(seed); + double u = prn(seed); + + // From PyNE implementation of moab tet sampling C. Rocchini & P. Cignoni + // (2000) Generating Random Points in a Tetrahedron, Journal of Graphics + // Tools, 5:4, 9-12, DOI: 10.1080/10867651.2000.10487528 + if (s + t > 1) { + s = 1.0 - s; + t = 1.0 - t; + } + if (s + t + u > 1) { + if (t + u > 1) { + double old_t = t; + t = 1.0 - u; + u = 1.0 - s - old_t; + } else if (t + u <= 1) { + double old_s = s; + s = 1.0 - t - u; + u = old_s + t + u - 1; + } + } + return s * (coords[1] - coords[0]) + t * (coords[2] - coords[0]) + + u * (coords[3] - coords[0]) + coords[0]; +} + +const std::string UnstructuredMesh::mesh_type = "unstructured"; + +std::string UnstructuredMesh::get_mesh_type() const +{ + return mesh_type; } -void -UnstructuredMesh::surface_bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins) const { +void UnstructuredMesh::surface_bins_crossed( + Position r0, Position r1, const Direction& u, vector& bins) const +{ fatal_error("Unstructured mesh surface tallies are not implemented."); } -std::string -UnstructuredMesh::bin_label(int bin) const { +std::string UnstructuredMesh::bin_label(int bin) const +{ return fmt::format("Mesh Index ({})", bin); }; -void -UnstructuredMesh::to_hdf5(hid_t group) const -{ - hid_t mesh_group = create_group(group, fmt::format("mesh {}", id_)); - - write_dataset(mesh_group, "type", "unstructured"); - write_dataset(mesh_group, "filename", filename_); - write_dataset(mesh_group, "library", this->library()); - // write volume of each element - vector tet_vols; - xt::xtensor centroids({static_cast(this->n_bins()), 3}); - for (int i = 0; i < this->n_bins(); i++) { - tet_vols.emplace_back(this->volume(i)); - auto c = this->centroid(i); - xt::view(centroids, i, xt::all()) = xt::xarray({c.x, c.y, c.z}); +void UnstructuredMesh::to_hdf5(hid_t group) const +{ + hid_t mesh_group = create_group(group, fmt::format("mesh {}", id_)); + + write_dataset(mesh_group, "type", mesh_type); + write_dataset(mesh_group, "filename", filename_); + write_dataset(mesh_group, "library", this->library()); + if (!options_.empty()) { + write_attribute(mesh_group, "options", options_); + } + + if (length_multiplier_ > 0.0) + write_dataset(mesh_group, "length_multiplier", length_multiplier_); + + // write vertex coordinates + xt::xtensor vertices({static_cast(this->n_vertices()), 3}); + for (int i = 0; i < this->n_vertices(); i++) { + auto v = this->vertex(i); + xt::view(vertices, i, xt::all()) = xt::xarray({v.x, v.y, v.z}); + } + write_dataset(mesh_group, "vertices", vertices); + + int num_elem_skipped = 0; + + // write element types and connectivity + vector volumes; + xt::xtensor connectivity({static_cast(this->n_bins()), 8}); + xt::xtensor elem_types({static_cast(this->n_bins()), 1}); + for (int i = 0; i < this->n_bins(); i++) { + auto conn = this->connectivity(i); + + volumes.emplace_back(this->volume(i)); + + // write linear tet element + if (conn.size() == 4) { + xt::view(elem_types, i, xt::all()) = + static_cast(ElementType::LINEAR_TET); + xt::view(connectivity, i, xt::all()) = + xt::xarray({conn[0], conn[1], conn[2], conn[3], -1, -1, -1, -1}); + // write linear hex element + } else if (conn.size() == 8) { + xt::view(elem_types, i, xt::all()) = + static_cast(ElementType::LINEAR_HEX); + xt::view(connectivity, i, xt::all()) = xt::xarray({conn[0], conn[1], + conn[2], conn[3], conn[4], conn[5], conn[6], conn[7]}); + } else { + num_elem_skipped++; + xt::view(elem_types, i, xt::all()) = + static_cast(ElementType::UNSUPPORTED); + xt::view(connectivity, i, xt::all()) = -1; } + } + + // warn users that some elements were skipped + if (num_elem_skipped > 0) { + warning(fmt::format("The connectivity of {} elements " + "on mesh {} were not written " + "because they are not of type linear tet/hex.", + num_elem_skipped, this->id_)); + } + + write_dataset(mesh_group, "volumes", volumes); + write_dataset(mesh_group, "connectivity", connectivity); + write_dataset(mesh_group, "element_types", elem_types); + + close_group(mesh_group); +} + +void UnstructuredMesh::set_length_multiplier(double length_multiplier) +{ + length_multiplier_ = length_multiplier; +} - write_dataset(mesh_group, "volumes", tet_vols); - write_dataset(mesh_group, "centroids", centroids); - close_group(mesh_group); +ElementType UnstructuredMesh::element_type(int bin) const +{ + auto conn = connectivity(bin); + + if (conn.size() == 4) + return ElementType::LINEAR_TET; + else if (conn.size() == 8) + return ElementType::LINEAR_HEX; + else + return ElementType::UNSUPPORTED; } -void StructuredMesh::get_indices(Position r, int* ijk, bool* in_mesh) const +StructuredMesh::MeshIndex StructuredMesh::get_indices( + Position r, bool& in_mesh) const { - *in_mesh = true; + MeshIndex ijk; + in_mesh = true; for (int i = 0; i < n_dimension_; ++i) { ijk[i] = get_index_in_direction(r[i], i); - if (ijk[i] < 1 || ijk[i] > shape_[i]) *in_mesh = false; + if (ijk[i] < 1 || ijk[i] > shape_[i]) + in_mesh = false; } + return ijk; } -int StructuredMesh::get_bin_from_indices(const int* ijk) const +int StructuredMesh::get_bin_from_indices(const MeshIndex& ijk) const { switch (n_dimension_) { case 1: return ijk[0] - 1; case 2: - return (ijk[1] - 1)*shape_[0] + ijk[0] - 1; + return (ijk[1] - 1) * shape_[0] + ijk[0] - 1; case 3: - return ((ijk[2] - 1)*shape_[1] + (ijk[1] - 1))*shape_[0] + ijk[0] - 1; + return ((ijk[2] - 1) * shape_[1] + (ijk[1] - 1)) * shape_[0] + ijk[0] - 1; default: - throw std::runtime_error{"Invalid number of mesh dimensions"}; + throw std::runtime_error {"Invalid number of mesh dimensions"}; } } -void StructuredMesh::get_indices_from_bin(int bin, int* ijk) const +StructuredMesh::MeshIndex StructuredMesh::get_indices_from_bin(int bin) const { + MeshIndex ijk; if (n_dimension_ == 1) { ijk[0] = bin + 1; } else if (n_dimension_ == 2) { @@ -260,23 +493,25 @@ void StructuredMesh::get_indices_from_bin(int bin, int* ijk) const ijk[1] = (bin % (shape_[0] * shape_[1])) / shape_[0] + 1; ijk[2] = bin / (shape_[0] * shape_[1]) + 1; } + return ijk; } int StructuredMesh::get_bin(Position r) const { // Determine indices - vector ijk(n_dimension_); bool in_mesh; - get_indices(r, ijk.data(), &in_mesh); - if (!in_mesh) return -1; + MeshIndex ijk = get_indices(r, in_mesh); + if (!in_mesh) + return -1; // Convert indices to bin - return get_bin_from_indices(ijk.data()); + return get_bin_from_indices(ijk); } int StructuredMesh::n_bins() const { - return xt::prod(shape_)(); + return std::accumulate( + shape_.begin(), shape_.begin() + n_dimension_, 1, std::multiplies<>()); } int StructuredMesh::n_surface_bins() const @@ -315,12 +550,12 @@ xt::xtensor StructuredMesh::count_sites( // std::allocator must be used to avoid Valgrind mismatched free() / delete // warnings. int total = cnt.size(); - double* cnt_reduced = std::allocator{}.allocate(total); + double* cnt_reduced = std::allocator {}.allocate(total); #ifdef OPENMC_MPI // collect values from all processors - MPI_Reduce(cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, - mpi::intracomm); + MPI_Reduce( + cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); // Check if there were sites outside the mesh for any processor if (outside) { @@ -328,7 +563,8 @@ xt::xtensor StructuredMesh::count_sites( } #else std::copy(cnt.data(), cnt.data() + total, cnt_reduced); - if (outside) *outside = outside_; + if (outside) + *outside = outside_; #endif // Adapt reduced values in array back into an xarray @@ -338,383 +574,205 @@ xt::xtensor StructuredMesh::count_sites( return counts; } -bool StructuredMesh::intersects(Position& r0, Position r1, int* ijk) const -{ - switch(n_dimension_) { - case 1: - return intersects_1d(r0, r1, ijk); - case 2: - return intersects_2d(r0, r1, ijk); - case 3: - return intersects_3d(r0, r1, ijk); - default: - throw std::runtime_error{"Invalid number of mesh dimensions."}; - } -} - -bool StructuredMesh::intersects_1d(Position& r0, Position r1, int* ijk) const +// raytrace through the mesh. The template class T will do the tallying. +// A modern optimizing compiler can recognize the noop method of T and eleminate +// that call entirely. +template +void StructuredMesh::raytrace_mesh( + Position r0, Position r1, const Direction& u, T tally) const { - // Copy coordinates of starting point - double x0 = r0.x; - double y0 = r0.y; - double z0 = r0.z; - - // Copy coordinates of ending point - double x1 = r1.x; - double y1 = r1.y; - double z1 = r1.z; + // TODO: when c++-17 is available, use "if constexpr ()" to compile-time + // enable/disable tally calls for now, T template type needs to provide both + // surface and track methods, which might be empty. modern optimizing + // compilers will (hopefully) eliminate the complete code (including + // calculation of parameters) but for the future: be explicit - // Copy coordinates of mesh lower_left and upper_right - double xm0 = lower_left_[0]; - double xm1 = upper_right_[0]; - - double min_dist = INFTY; - - // Check if line intersects left surface -- calculate the intersection point - // (y,z) - if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) { - double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0); - double zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0); - if (check_intersection_point(xm0, x0, yi, yi, zi, zi, r0, min_dist)) { - ijk[0] = 1; - } - } - - // Check if line intersects right surface -- calculate the intersection point - // (y,z) - if ((x0 < xm1 && x1 > xm1) || (x0 > xm1 && x1 < xm1)) { - double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0); - double zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0); - if (check_intersection_point(xm1, x0, yi, yi, zi, zi, r0, min_dist)) { - ijk[0] = shape_[0]; - } - } - - return min_dist < INFTY; -} - -bool StructuredMesh::intersects_2d(Position& r0, Position r1, int* ijk) const -{ - // Copy coordinates of starting point - double x0 = r0.x; - double y0 = r0.y; - double z0 = r0.z; - - // Copy coordinates of ending point - double x1 = r1.x; - double y1 = r1.y; - double z1 = r1.z; - - // Copy coordinates of mesh lower_left - double xm0 = lower_left_[0]; - double ym0 = lower_left_[1]; - - // Copy coordinates of mesh upper_right - double xm1 = upper_right_[0]; - double ym1 = upper_right_[1]; + // Compute the length of the entire track. + double total_distance = (r1 - r0).norm(); + if (total_distance == 0.0 && settings::solver_type != SolverType::RANDOM_RAY) + return; - double min_dist = INFTY; + const int n = n_dimension_; - // Check if line intersects left surface -- calculate the intersection point - // (y,z) - if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) { - double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0); - double zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0); - if (yi >= ym0 && yi < ym1) { - if (check_intersection_point(xm0, x0, yi, y0, zi, zi, r0, min_dist)) { - ijk[0] = 1; - ijk[1] = get_index_in_direction(yi, 1); - } - } - } + // Flag if position is inside the mesh + bool in_mesh; - // Check if line intersects back surface -- calculate the intersection point - // (x,z) - if ((y0 < ym0 && y1 > ym0) || (y0 > ym0 && y1 < ym0)) { - double xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0); - double zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0); - if (xi >= xm0 && xi < xm1) { - if (check_intersection_point(xi, x0, ym0, y0, zi, zi, r0, min_dist)) { - ijk[0] = get_index_in_direction(xi, 0); - ijk[1] = 1; - } - } - } + // Position is r = r0 + u * traveled_distance, start at r0 + double traveled_distance {0.0}; - // Check if line intersects right surface -- calculate the intersection point - // (y,z) - if ((x0 < xm1 && x1 > xm1) || (x0 > xm1 && x1 < xm1)) { - double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0); - double zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0); - if (yi >= ym0 && yi < ym1) { - if (check_intersection_point(xm1, x0, yi, y0, zi, zi, r0, min_dist)) { - ijk[0] = shape_[0]; - ijk[1] = get_index_in_direction(yi, 1); - } - } - } + // Calculate index of current cell. Offset the position a tiny bit in + // direction of flight + MeshIndex ijk = get_indices(r0 + TINY_BIT * u, in_mesh); - // Check if line intersects front surface -- calculate the intersection point - // (x,z) - if ((y0 < ym1 && y1 > ym1) || (y0 > ym1 && y1 < ym1)) { - double xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0); - double zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0); - if (xi >= xm0 && xi < xm1) { - if (check_intersection_point(xi, x0, ym1, y0, zi, zi, r0, min_dist)) { - ijk[0] = get_index_in_direction(xi, 0); - ijk[1] = shape_[1]; - } + // if track is very short, assume that it is completely inside one cell. + // Only the current cell will score and no surfaces + if (total_distance < 2 * TINY_BIT) { + if (in_mesh) { + tally.track(ijk, 1.0); } + return; } - return min_dist < INFTY; -} - -bool StructuredMesh::intersects_3d(Position& r0, Position r1, int* ijk) const -{ - // Copy coordinates of starting point - double x0 = r0.x; - double y0 = r0.y; - double z0 = r0.z; - - // Copy coordinates of ending point - double x1 = r1.x; - double y1 = r1.y; - double z1 = r1.z; - - // Copy coordinates of mesh lower_left - double xm0 = lower_left_[0]; - double ym0 = lower_left_[1]; - double zm0 = lower_left_[2]; - - // Copy coordinates of mesh upper_right - double xm1 = upper_right_[0]; - double ym1 = upper_right_[1]; - double zm1 = upper_right_[2]; + // translate start and end positions, + // this needs to come after the get_indices call because it does its own + // translation + local_coords(r0); + local_coords(r1); - double min_dist = INFTY; - - // Check if line intersects left surface -- calculate the intersection point - // (y,z) - if ((x0 < xm0 && x1 > xm0) || (x0 > xm0 && x1 < xm0)) { - double yi = y0 + (xm0 - x0) * (y1 - y0) / (x1 - x0); - double zi = z0 + (xm0 - x0) * (z1 - z0) / (x1 - x0); - if (yi >= ym0 && yi < ym1 && zi >= zm0 && zi < zm1) { - if (check_intersection_point(xm0, x0, yi, y0, zi, z0, r0, min_dist)) { - ijk[0] = 1; - ijk[1] = get_index_in_direction(yi, 1); - ijk[2] = get_index_in_direction(zi, 2); - } - } + // Calculate initial distances to next surfaces in all three dimensions + std::array distances; + for (int k = 0; k < n; ++k) { + distances[k] = distance_to_grid_boundary(ijk, k, r0, u, 0.0); } - // Check if line intersects back surface -- calculate the intersection point - // (x,z) - if ((y0 < ym0 && y1 > ym0) || (y0 > ym0 && y1 < ym0)) { - double xi = x0 + (ym0 - y0) * (x1 - x0) / (y1 - y0); - double zi = z0 + (ym0 - y0) * (z1 - z0) / (y1 - y0); - if (xi >= xm0 && xi < xm1 && zi >= zm0 && zi < zm1) { - if (check_intersection_point(xi, x0, ym0, y0, zi, z0, r0, min_dist)) { - ijk[0] = get_index_in_direction(xi, 0); - ijk[1] = 1; - ijk[2] = get_index_in_direction(zi, 2); - } - } - } + // Loop until r = r1 is eventually reached + while (true) { - // Check if line intersects bottom surface -- calculate the intersection - // point (x,y) - if ((z0 < zm0 && z1 > zm0) || (z0 > zm0 && z1 < zm0)) { - double xi = x0 + (zm0 - z0) * (x1 - x0) / (z1 - z0); - double yi = y0 + (zm0 - z0) * (y1 - y0) / (z1 - z0); - if (xi >= xm0 && xi < xm1 && yi >= ym0 && yi < ym1) { - if (check_intersection_point(xi, x0, yi, y0, zm0, z0, r0, min_dist)) { - ijk[0] = get_index_in_direction(xi, 0); - ijk[1] = get_index_in_direction(yi, 1); - ijk[2] = 1; + if (in_mesh) { + + // find surface with minimal distance to current position + const auto k = std::min_element(distances.begin(), distances.end()) - + distances.begin(); + + // Tally track length delta since last step + tally.track(ijk, + (std::min(distances[k].distance, total_distance) - traveled_distance) / + total_distance); + + // update position and leave, if we have reached end position + traveled_distance = distances[k].distance; + if (traveled_distance >= total_distance) + return; + + // If we have not reached r1, we have hit a surface. Tally outward current + tally.surface(ijk, k, distances[k].max_surface, false); + + // Update cell and calculate distance to next surface in k-direction. + // The two other directions are still valid! + ijk[k] = distances[k].next_index; + distances[k] = + distance_to_grid_boundary(ijk, k, r0, u, traveled_distance); + + // Check if we have left the interior of the mesh + in_mesh = ((ijk[k] >= 1) && (ijk[k] <= shape_[k])); + + // If we are still inside the mesh, tally inward current for the next cell + if (in_mesh) + tally.surface(ijk, k, !distances[k].max_surface, true); + + } else { // not inside mesh + + // For all directions outside the mesh, find the distance that we need to + // travel to reach the next surface. Use the largest distance, as only + // this will cross all outer surfaces. + int k_max {0}; + for (int k = 0; k < n; ++k) { + if ((ijk[k] < 1 || ijk[k] > shape_[k]) && + (distances[k].distance > traveled_distance)) { + traveled_distance = distances[k].distance; + k_max = k; + } } - } - } - // Check if line intersects right surface -- calculate the intersection point - // (y,z) - if ((x0 < xm1 && x1 > xm1) || (x0 > xm1 && x1 < xm1)) { - double yi = y0 + (xm1 - x0) * (y1 - y0) / (x1 - x0); - double zi = z0 + (xm1 - x0) * (z1 - z0) / (x1 - x0); - if (yi >= ym0 && yi < ym1 && zi >= zm0 && zi < zm1) { - if (check_intersection_point(xm1, x0, yi, y0, zi, z0, r0, min_dist)) { - ijk[0] = shape_[0]; - ijk[1] = get_index_in_direction(yi, 1); - ijk[2] = get_index_in_direction(zi, 2); - } - } - } + // If r1 is not inside the mesh, exit here + if (traveled_distance >= total_distance) + return; - // Check if line intersects front surface -- calculate the intersection point - // (x,z) - if ((y0 < ym1 && y1 > ym1) || (y0 > ym1 && y1 < ym1)) { - double xi = x0 + (ym1 - y0) * (x1 - x0) / (y1 - y0); - double zi = z0 + (ym1 - y0) * (z1 - z0) / (y1 - y0); - if (xi >= xm0 && xi < xm1 && zi >= zm0 && zi < zm1) { - if (check_intersection_point(xi, x0, ym1, y0, zi, z0, r0, min_dist)) { - ijk[0] = get_index_in_direction(xi, 0); - ijk[1] = shape_[1]; - ijk[2] = get_index_in_direction(zi, 2); + // Calculate the new cell index and update all distances to next surfaces. + ijk = get_indices(r0 + (traveled_distance + TINY_BIT) * u, in_mesh); + for (int k = 0; k < n; ++k) { + distances[k] = + distance_to_grid_boundary(ijk, k, r0, u, traveled_distance); } - } - } - // Check if line intersects top surface -- calculate the intersection point - // (x,y) - if ((z0 < zm1 && z1 > zm1) || (z0 > zm1 && z1 < zm1)) { - double xi = x0 + (zm1 - z0) * (x1 - x0) / (z1 - z0); - double yi = y0 + (zm1 - z0) * (y1 - y0) / (z1 - z0); - if (xi >= xm0 && xi < xm1 && yi >= ym0 && yi < ym1) { - if (check_intersection_point(xi, x0, yi, y0, zm1, z0, r0, min_dist)) { - ijk[0] = get_index_in_direction(xi, 0); - ijk[1] = get_index_in_direction(yi, 1); - ijk[2] = shape_[2]; - } + // If inside the mesh, Tally inward current + if (in_mesh) + tally.surface(ijk, k_max, !distances[k_max].max_surface, true); } } - - return min_dist < INFTY; } -void StructuredMesh::bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins, - vector& lengths) const +void StructuredMesh::bins_crossed(Position r0, Position r1, const Direction& u, + vector& bins, vector& lengths) const { - // ======================================================================== - // Determine where the track intersects the mesh and if it intersects at all. - - // Compute the length of the entire track. - double total_distance = (r1 - r0).norm(); - if (total_distance == 0.0) return; - - // While determining if this track intersects the mesh, offset the starting - // and ending coords by a bit. This avoid finite-precision errors that can - // occur when the mesh surfaces coincide with lattice or geometric surfaces. - Position last_r = r0 + TINY_BIT*u; - Position r = r1 - TINY_BIT*u; - - // Determine the mesh indices for the starting and ending coords. Here, we - // use arrays for ijk0 and ijk1 instead of vector because we obtain a - // small performance improvement by forcing this data to live on the stack, - // rather than on the heap. We know the maximum length is 3, and by - // ensuring that all loops are only indexed up to n_dimension, we will not - // access any non-initialized values. The same concept is used throughout. - int n = n_dimension_; - int ijk0[3], ijk1[3]; - bool start_in_mesh; - get_indices(last_r, ijk0, &start_in_mesh); - bool end_in_mesh; - get_indices(r, ijk1, &end_in_mesh); - - // Reset coordinates and check for a mesh intersection if necessary. - if (start_in_mesh) { - // The initial coords lie in the mesh, use those coords for tallying. - last_r = r0; - } else { - // The initial coords do not lie in the mesh. Check to see if the particle - // eventually intersects the mesh and compute the relevant coords and - // indices. - if (!intersects(last_r, r, ijk0)) return; - } - r = r1; - - // The TINY_BIT offsets above mean that the preceding logic cannot always find - // the correct ijk0 and ijk1 indices. For tracks shorter than 2*TINY_BIT, just - // assume the track lies in only one mesh bin. These tracks are very short so - // any error caused by this assumption will be small. It is important that - // ijk0 values are used rather than ijk1 because the previous logic guarantees - // ijk0 is a valid mesh bin. - if (total_distance < 2*TINY_BIT) { - for (int i = 0; i < n; ++i) ijk1[i] = ijk0[i]; - } - // ======================================================================== - // Find which mesh cells are traversed and the length of each traversal. - - while (true) { - if (std::equal(ijk0, ijk0 + n, ijk1)) { - // The track ends in this cell. Use the particle end location rather - // than the mesh surface and stop iterating. - double distance = (last_r - r).norm(); - bins.push_back(get_bin_from_indices(ijk0)); - lengths.push_back(distance / total_distance); - break; + // Helper tally class. + // stores a pointer to the mesh class and references to bins and lengths + // parameters. Performs the actual tally through the track method. + struct TrackAggregator { + TrackAggregator( + const StructuredMesh* _mesh, vector& _bins, vector& _lengths) + : mesh(_mesh), bins(_bins), lengths(_lengths) + {} + void surface(const MeshIndex& ijk, int k, bool max, bool inward) const {} + void track(const MeshIndex& ijk, double l) const + { + bins.push_back(mesh->get_bin_from_indices(ijk)); + lengths.push_back(l); } - // The track exits this cell. Determine the distance to each mesh surface. - double d[3]; - for (int k = 0; k < n; ++k) { - if (std::fabs(u[k]) < FP_PRECISION) { - d[k] = INFTY; - } else if (u[k] > 0) { - double xyz_cross = positive_grid_boundary(ijk0, k); - d[k] = (xyz_cross - last_r[k]) / u[k]; - } else { - double xyz_cross = negative_grid_boundary(ijk0, k); - d[k] = (xyz_cross - last_r[k]) / u[k]; - } + const StructuredMesh* mesh; + vector& bins; + vector& lengths; + }; + + // Perform the mesh raytrace with the helper class. + raytrace_mesh(r0, r1, u, TrackAggregator(this, bins, lengths)); +} + +void StructuredMesh::surface_bins_crossed( + Position r0, Position r1, const Direction& u, vector& bins) const +{ + + // Helper tally class. + // stores a pointer to the mesh class and a reference to the bins parameter. + // Performs the actual tally through the surface method. + struct SurfaceAggregator { + SurfaceAggregator(const StructuredMesh* _mesh, vector& _bins) + : mesh(_mesh), bins(_bins) + {} + void surface(const MeshIndex& ijk, int k, bool max, bool inward) const + { + int i_bin = + 4 * mesh->n_dimension_ * mesh->get_bin_from_indices(ijk) + 4 * k; + if (max) + i_bin += 2; + if (inward) + i_bin += 1; + bins.push_back(i_bin); } + void track(const MeshIndex& idx, double l) const {} - // Pick the closest mesh surface and append this traversal to the output. - auto j = std::min_element(d, d + n) - d; - double distance = d[j]; - bins.push_back(get_bin_from_indices(ijk0)); - lengths.push_back(distance / total_distance); - - // Translate to the oncoming mesh surface. - last_r += distance * u; + const StructuredMesh* mesh; + vector& bins; + }; - // Increment the indices into the next mesh cell. - if (u[j] > 0.0) { - ++ijk0[j]; - } else { - --ijk0[j]; - } - - // If the next indices are invalid, then the track has left the mesh and - // we are done. - bool in_mesh = true; - for (int i = 0; i < n; ++i) { - if (ijk0[i] < 1 || ijk0[i] > shape_[i]) { - in_mesh = false; - break; - } - } - if (!in_mesh) break; - } + // Perform the mesh raytrace with the helper class. + raytrace_mesh(r0, r1, u, SurfaceAggregator(this, bins)); } - //============================================================================== // RegularMesh implementation //============================================================================== -RegularMesh::RegularMesh(pugi::xml_node node) - : StructuredMesh {node} +RegularMesh::RegularMesh(pugi::xml_node node) : StructuredMesh {node} { // Determine number of dimensions for mesh if (!check_for_node(node, "dimension")) { fatal_error("Must specify on a regular mesh."); } - - shape_ = get_node_xarray(node, "dimension"); - int n = n_dimension_ = shape_.size(); + xt::xtensor shape = get_node_xarray(node, "dimension"); + int n = n_dimension_ = shape.size(); if (n != 1 && n != 2 && n != 3) { fatal_error("Mesh must be one, two, or three dimensions."); } + std::copy(shape.begin(), shape.end(), shape_.begin()); // Check that dimensions are all greater than zero - if (xt::any(shape_ <= 0)) { + if (xt::any(shape <= 0)) { fatal_error("All entries on the element for a tally " - "mesh must be positive."); + "mesh must be positive."); } // Check for lower-left coordinates @@ -726,13 +784,13 @@ RegularMesh::RegularMesh(pugi::xml_node node) } // Make sure lower_left and dimension match - if (shape_.size() != lower_left_.size()) { + if (shape.size() != lower_left_.size()) { fatal_error("Number of entries on must be the same " - "as the number of entries on ."); + "as the number of entries on ."); } if (check_for_node(node, "width")) { - // Make sure both upper-right or width were specified + // Make sure one of upper-right or width were specified if (check_for_node(node, "upper_right")) { fatal_error("Cannot specify both and on a mesh."); } @@ -743,7 +801,7 @@ RegularMesh::RegularMesh(pugi::xml_node node) auto n = width_.size(); if (n != lower_left_.size()) { fatal_error("Number of entries on must be the same as " - "the number of entries on ."); + "the number of entries on ."); } // Check for negative widths @@ -752,7 +810,7 @@ RegularMesh::RegularMesh(pugi::xml_node node) } // Set width and upper right coordinate - upper_right_ = xt::eval(lower_left_ + shape_ * width_); + upper_right_ = xt::eval(lower_left_ + shape * width_); } else if (check_for_node(node, "upper_right")) { upper_right_ = get_node_xarray(node, "upper_right"); @@ -761,23 +819,28 @@ RegularMesh::RegularMesh(pugi::xml_node node) auto n = upper_right_.size(); if (n != lower_left_.size()) { fatal_error("Number of entries on must be the " - "same as the number of entries on ."); + "same as the number of entries on ."); } // Check that upper-right is above lower-left if (xt::any(upper_right_ < lower_left_)) { fatal_error("The coordinates must be greater than " - "the coordinates on a tally mesh."); + "the coordinates on a tally mesh."); } // Set width - width_ = xt::eval((upper_right_ - lower_left_) / shape_); + width_ = xt::eval((upper_right_ - lower_left_) / shape); } else { - fatal_error("Must specify either and on a mesh."); + fatal_error("Must specify either or on a mesh."); } - // Set volume fraction - volume_frac_ = 1.0/xt::prod(shape_)(); + // Set material volumes + volume_frac_ = 1.0 / xt::prod(shape)(); + + element_volume_ = 1.0; + for (int i = 0; i < n_dimension_; i++) { + element_volume_ *= width_[i]; + } } int RegularMesh::get_index_in_direction(double r, int i) const @@ -785,158 +848,41 @@ int RegularMesh::get_index_in_direction(double r, int i) const return std::ceil((r - lower_left_[i]) / width_[i]); } -double RegularMesh::positive_grid_boundary(int* ijk, int i) const +const std::string RegularMesh::mesh_type = "regular"; + +std::string RegularMesh::get_mesh_type() const +{ + return mesh_type; +} + +double RegularMesh::positive_grid_boundary(const MeshIndex& ijk, int i) const { return lower_left_[i] + ijk[i] * width_[i]; } -double RegularMesh::negative_grid_boundary(int* ijk, int i) const +double RegularMesh::negative_grid_boundary(const MeshIndex& ijk, int i) const { return lower_left_[i] + (ijk[i] - 1) * width_[i]; } -void -RegularMesh::surface_bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins) const +StructuredMesh::MeshDistance RegularMesh::distance_to_grid_boundary( + const MeshIndex& ijk, int i, const Position& r0, const Direction& u, + double l) const { - // Determine indices for starting and ending location. - int n = n_dimension_; - vector ijk0(n), ijk1(n); - bool start_in_mesh; - get_indices(r0, ijk0.data(), &start_in_mesh); - bool end_in_mesh; - get_indices(r1, ijk1.data(), &end_in_mesh); + MeshDistance d; + d.next_index = ijk[i]; + if (std::abs(u[i]) < FP_PRECISION) + return d; - // Check if the track intersects any part of the mesh. - if (!start_in_mesh) { - Position r0_copy = r0; - vector ijk0_copy(ijk0); - if (!intersects(r0_copy, r1, ijk0_copy.data())) return; - } - - // ======================================================================== - // Find which mesh surfaces are crossed. - - // Calculate number of surface crossings - int n_cross = 0; - for (int i = 0; i < n; ++i) n_cross += std::abs(ijk1[i] - ijk0[i]); - if (n_cross == 0) return; - - // Bounding coordinates - Position xyz_cross; - for (int i = 0; i < n; ++i) { - if (u[i] > 0.0) { - xyz_cross[i] = positive_grid_boundary(ijk0.data(), i); - } else { - xyz_cross[i] = negative_grid_boundary(ijk0.data(), i); - } - } - - for (int j = 0; j < n_cross; ++j) { - // Set the distances to infinity - Position d {INFTY, INFTY, INFTY}; - - // Determine closest bounding surface. We need to treat - // special case where the cosine of the angle is zero since this would - // result in a divide-by-zero. - double distance = INFTY; - for (int i = 0; i < n; ++i) { - if (u[i] == 0) { - d[i] = INFTY; - } else { - d[i] = (xyz_cross[i] - r0[i])/u[i]; - } - distance = std::min(distance, d[i]); - } - - // Loop over the dimensions - for (int i = 0; i < n; ++i) { - // Check whether distance is the shortest distance - if (distance == d[i]) { - - // Check whether the current indices are within the mesh bounds - bool in_mesh = true; - for (int j = 0; j < n; ++j) { - if (ijk0[j] < 1 || ijk0[j] > shape_[j]) { - in_mesh = false; - break; - } - } - - // Check whether particle is moving in positive i direction - if (u[i] > 0) { - - // Outward current on i max surface - if (in_mesh) { - int i_surf = 4*i + 3; - int i_mesh = get_bin_from_indices(ijk0.data()); - int i_bin = 4*n*i_mesh + i_surf - 1; - - bins.push_back(i_bin); - } - - // Advance position - ++ijk0[i]; - xyz_cross[i] += width_[i]; - in_mesh = true; - for (int j = 0; j < n; ++j) { - if (ijk0[j] < 1 || ijk0[j] > shape_[j]) { - in_mesh = false; - break; - } - } - - // If the particle crossed the surface, tally the inward current on - // i min surface - if (in_mesh) { - int i_surf = 4*i + 2; - int i_mesh = get_bin_from_indices(ijk0.data()); - int i_bin = 4*n*i_mesh + i_surf - 1; - - bins.push_back(i_bin); - } - - } else { - // The particle is moving in the negative i direction - - // Outward current on i min surface - if (in_mesh) { - int i_surf = 4*i + 1; - int i_mesh = get_bin_from_indices(ijk0.data()); - int i_bin = 4*n*i_mesh + i_surf - 1; - - bins.push_back(i_bin); - } - - // Advance position - --ijk0[i]; - xyz_cross[i] -= width_[i]; - in_mesh = true; - for (int j = 0; j < n; ++j) { - if (ijk0[j] < 1 || ijk0[j] > shape_[j]) { - in_mesh = false; - break; - } - } - - // If the particle crossed the surface, tally the inward current on - // i max surface - if (in_mesh) { - int i_surf = 4*i + 4; - int i_mesh = get_bin_from_indices(ijk0.data()); - int i_bin = 4*n*i_mesh + i_surf - 1; - - bins.push_back(i_bin); - } - } - } - } - - // Calculate new coordinates - r0 += distance * u; + d.max_surface = (u[i] > 0); + if (d.max_surface && (ijk[i] <= shape_[i])) { + d.next_index++; + d.distance = (positive_grid_boundary(ijk, i) - r0[i]) / u[i]; + } else if (!d.max_surface && (ijk[i] >= 1)) { + d.next_index--; + d.distance = (negative_grid_boundary(ijk, i) - r0[i]) / u[i]; } + return d; } std::pair, vector> RegularMesh::plot( @@ -946,13 +892,17 @@ std::pair, vector> RegularMesh::plot( array axes {-1, -1}; if (plot_ur.z == plot_ll.z) { axes[0] = 0; - if (n_dimension_ > 1) axes[1] = 1; + if (n_dimension_ > 1) + axes[1] = 1; } else if (plot_ur.y == plot_ll.y) { axes[0] = 0; - if (n_dimension_ > 2) axes[1] = 2; + if (n_dimension_ > 2) + axes[1] = 2; } else if (plot_ur.x == plot_ll.x) { - if (n_dimension_ > 1) axes[0] = 1; - if (n_dimension_ > 2) axes[1] = 2; + if (n_dimension_ > 1) + axes[0] = 1; + if (n_dimension_ > 2) + axes[1] = 2; } else { fatal_error("Can only plot mesh lines on an axis-aligned plot"); } @@ -961,7 +911,8 @@ std::pair, vector> RegularMesh::plot( array, 2> axis_lines; for (int i_ax = 0; i_ax < 2; ++i_ax) { int axis = axes[i_ax]; - if (axis == -1) continue; + if (axis == -1) + continue; auto& lines {axis_lines[i_ax]}; double coord = lower_left_[axis]; @@ -980,7 +931,7 @@ void RegularMesh::to_hdf5(hid_t group) const hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); write_dataset(mesh_group, "type", "regular"); - write_dataset(mesh_group, "dimension", shape_); + write_dataset(mesh_group, "dimension", get_x_shape()); write_dataset(mesh_group, "lower_left", lower_left_); write_dataset(mesh_group, "upper_right", upper_right_); write_dataset(mesh_group, "width", width_); @@ -1019,12 +970,12 @@ xt::xtensor RegularMesh::count_sites( // std::allocator must be used to avoid Valgrind mismatched free() / delete // warnings. int total = cnt.size(); - double* cnt_reduced = std::allocator{}.allocate(total); + double* cnt_reduced = std::allocator {}.allocate(total); #ifdef OPENMC_MPI // collect values from all processors - MPI_Reduce(cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, - mpi::intracomm); + MPI_Reduce( + cnt.data(), cnt_reduced, total, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); // Check if there were sites outside the mesh for any processor if (outside) { @@ -1032,7 +983,8 @@ xt::xtensor RegularMesh::count_sites( } #else std::copy(cnt.data(), cnt.data() + total, cnt_reduced); - if (outside) *outside = outside_; + if (outside) + *outside = outside_; #endif // Adapt reduced values in array back into an xarray @@ -1042,16 +994,19 @@ xt::xtensor RegularMesh::count_sites( return counts; } +double RegularMesh::volume(const MeshIndex& ijk) const +{ + return element_volume_; +} + //============================================================================== // RectilinearMesh implementation //============================================================================== -RectilinearMesh::RectilinearMesh(pugi::xml_node node) - : StructuredMesh {node} +RectilinearMesh::RectilinearMesh(pugi::xml_node node) : StructuredMesh {node} { n_dimension_ = 3; - grid_.resize(n_dimension_); grid_[0] = get_node_array(node, "x_grid"); grid_[1] = get_node_array(node, "y_grid"); grid_[2] = get_node_array(node, "z_grid"); @@ -1061,34 +1016,62 @@ RectilinearMesh::RectilinearMesh(pugi::xml_node node) } } -double RectilinearMesh::positive_grid_boundary(int* ijk, int i) const +const std::string RectilinearMesh::mesh_type = "rectilinear"; + +std::string RectilinearMesh::get_mesh_type() const +{ + return mesh_type; +} + +double RectilinearMesh::positive_grid_boundary( + const MeshIndex& ijk, int i) const { return grid_[i][ijk[i]]; } -double RectilinearMesh::negative_grid_boundary(int* ijk, int i) const +double RectilinearMesh::negative_grid_boundary( + const MeshIndex& ijk, int i) const { return grid_[i][ijk[i] - 1]; } +StructuredMesh::MeshDistance RectilinearMesh::distance_to_grid_boundary( + const MeshIndex& ijk, int i, const Position& r0, const Direction& u, + double l) const +{ + MeshDistance d; + d.next_index = ijk[i]; + if (std::abs(u[i]) < FP_PRECISION) + return d; + + d.max_surface = (u[i] > 0); + if (d.max_surface && (ijk[i] <= shape_[i])) { + d.next_index++; + d.distance = (positive_grid_boundary(ijk, i) - r0[i]) / u[i]; + } else if (!d.max_surface && (ijk[i] > 0)) { + d.next_index--; + d.distance = (negative_grid_boundary(ijk, i) - r0[i]) / u[i]; + } + return d; +} + int RectilinearMesh::set_grid() { shape_ = {static_cast(grid_[0].size()) - 1, - static_cast(grid_[1].size()) - 1, - static_cast(grid_[2].size()) - 1}; + static_cast(grid_[1].size()) - 1, + static_cast(grid_[2].size()) - 1}; for (const auto& g : grid_) { if (g.size() < 2) { set_errmsg("x-, y-, and z- grids for rectilinear meshes " - "must each have at least 2 points"); + "must each have at least 2 points"); return OPENMC_E_INVALID_ARGUMENT; } - for (int i = 1; i < g.size(); ++i) { - if (g[i] <= g[i-1]) { - set_errmsg("Values in for x-, y-, and z- grids for " - "rectilinear meshes must be sorted and unique."); - return OPENMC_E_INVALID_ARGUMENT; - } + if (std::adjacent_find(g.begin(), g.end(), std::greater_equal<>()) != + g.end()) { + set_errmsg("Values in for x-, y-, and z- grids for " + "rectilinear meshes must be sorted and unique."); + return OPENMC_E_INVALID_ARGUMENT; } } @@ -1098,221 +1081,666 @@ int RectilinearMesh::set_grid() return 0; } -void RectilinearMesh::surface_bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins) const -{ - // Determine indices for starting and ending location. - int ijk0[3], ijk1[3]; - bool start_in_mesh; - get_indices(r0, ijk0, &start_in_mesh); - bool end_in_mesh; - get_indices(r1, ijk1, &end_in_mesh); - - // If the starting coordinates do not lie in the mesh, compute the coords and - // mesh indices of the first intersection, and add the bin for this first - // intersection. Return if the particle does not intersect the mesh at all. - if (!start_in_mesh) { - // Compute the incoming intersection coordinates and indices. - if (!intersects(r0, r1, ijk0)) return; - - // Determine which surface the particle entered. - double min_dist = INFTY; - int i_surf; - for (int i = 0; i < 3; ++i) { - if (u[i] > 0.0 && ijk0[i] == 1) { - double d = std::abs(r0[i] - grid_[i][0]); - if (d < min_dist) { - min_dist = d; - i_surf = 4*i + 2; - } - } else if (u[i] < 0.0 && ijk0[i] == shape_[i]) { - double d = std::abs(r0[i] - grid_[i][shape_[i]]); - if (d < min_dist) { - min_dist = d; - i_surf = 4*i + 4; - } - } // u[i] == 0 intentionally skipped - } +int RectilinearMesh::get_index_in_direction(double r, int i) const +{ + return lower_bound_index(grid_[i].begin(), grid_[i].end(), r) + 1; +} - // Add the incoming current bin. - int i_mesh = get_bin_from_indices(ijk0); - int i_bin = 4*3*i_mesh + i_surf - 1; - bins.push_back(i_bin); - } - - // If the ending coordinates do not lie in the mesh, compute the coords and - // mesh indices of the last intersection, and add the bin for this last - // intersection. - if (!end_in_mesh) { - // Compute the outgoing intersection coordinates and indices. - intersects(r1, r0, ijk1); - - // Determine which surface the particle exited. - double min_dist = INFTY; - int i_surf; - for (int i = 0; i < 3; ++i) { - if (u[i] > 0.0 && ijk1[i] == shape_[i]) { - double d = std::abs(r1[i] - grid_[i][shape_[i]]); - if (d < min_dist) { - min_dist = d; - i_surf = 4*i + 3; - } - } else if (u[i] < 0.0 && ijk1[i] == 1) { - double d = std::abs(r1[i] - grid_[i][0]); - if (d < min_dist) { - min_dist = d; - i_surf = 4*i + 1; - } - } // u[i] == 0 intentionally skipped +std::pair, vector> RectilinearMesh::plot( + Position plot_ll, Position plot_ur) const +{ + // Figure out which axes lie in the plane of the plot. + array axes {-1, -1}; + if (plot_ur.z == plot_ll.z) { + axes = {0, 1}; + } else if (plot_ur.y == plot_ll.y) { + axes = {0, 2}; + } else if (plot_ur.x == plot_ll.x) { + axes = {1, 2}; + } else { + fatal_error("Can only plot mesh lines on an axis-aligned plot"); + } + + // Get the coordinates of the mesh lines along both of the axes. + array, 2> axis_lines; + for (int i_ax = 0; i_ax < 2; ++i_ax) { + int axis = axes[i_ax]; + vector& lines {axis_lines[i_ax]}; + + for (auto coord : grid_[axis]) { + if (coord >= plot_ll[axis] && coord <= plot_ur[axis]) + lines.push_back(coord); } + } + + return {axis_lines[0], axis_lines[1]}; +} + +void RectilinearMesh::to_hdf5(hid_t group) const +{ + hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); + + write_dataset(mesh_group, "type", "rectilinear"); + write_dataset(mesh_group, "x_grid", grid_[0]); + write_dataset(mesh_group, "y_grid", grid_[1]); + write_dataset(mesh_group, "z_grid", grid_[2]); - // Add the outgoing current bin. - int i_mesh = get_bin_from_indices(ijk1); - int i_bin = 4*3*i_mesh + i_surf - 1; - bins.push_back(i_bin); + close_group(mesh_group); +} + +double RectilinearMesh::volume(const MeshIndex& ijk) const +{ + double vol {1.0}; + + for (int i = 0; i < n_dimension_; i++) { + vol *= grid_[i][ijk[i]] - grid_[i][ijk[i] - 1]; } + return vol; +} - // ======================================================================== - // Find which mesh surfaces are crossed. +//============================================================================== +// CylindricalMesh implementation +//============================================================================== - // Calculate number of surface crossings - int n_cross = 0; - for (int i = 0; i < 3; ++i) n_cross += std::abs(ijk1[i] - ijk0[i]); - if (n_cross == 0) return; +CylindricalMesh::CylindricalMesh(pugi::xml_node node) + : PeriodicStructuredMesh {node} +{ + n_dimension_ = 3; + grid_[0] = get_node_array(node, "r_grid"); + grid_[1] = get_node_array(node, "phi_grid"); + grid_[2] = get_node_array(node, "z_grid"); + origin_ = get_node_position(node, "origin"); - // Bounding coordinates - Position xyz_cross; - for (int i = 0; i < 3; ++i) { - if (u[i] > 0.0) { - xyz_cross[i] = positive_grid_boundary(ijk0, i); - } else { - xyz_cross[i] = negative_grid_boundary(ijk0, i); - } + if (int err = set_grid()) { + fatal_error(openmc_err_msg); } +} - for (int j = 0; j < n_cross; ++j) { - // Set the distances to infinity - Position d {INFTY, INFTY, INFTY}; +const std::string CylindricalMesh::mesh_type = "cylindrical"; - // Determine closest bounding surface. We need to treat - // special case where the cosine of the angle is zero since this would - // result in a divide-by-zero. - double distance = INFTY; - for (int i = 0; i < 3; ++i) { - if (u[i] == 0) { - d[i] = INFTY; - } else { - d[i] = (xyz_cross[i] - r0[i])/u[i]; - } - distance = std::min(distance, d[i]); - } +std::string CylindricalMesh::get_mesh_type() const +{ + return mesh_type; +} - // Loop over the dimensions - for (int i = 0; i < 3; ++i) { - // Check whether distance is the shortest distance - if (distance == d[i]) { - - // Check whether particle is moving in positive i direction - if (u[i] > 0) { - - // Outward current on i max surface - int i_surf = 4*i + 3; - int i_mesh = get_bin_from_indices(ijk0); - int i_bin = 4*3*i_mesh + i_surf - 1; - bins.push_back(i_bin); - - // Advance position - ++ijk0[i]; - xyz_cross[i] = grid_[i][ijk0[i]]; - - // Inward current on i min surface - i_surf = 4*i + 2; - i_mesh = get_bin_from_indices(ijk0); - i_bin = 4*3*i_mesh + i_surf - 1; - bins.push_back(i_bin); - - } else { - // The particle is moving in the negative i direction - - // Outward current on i min surface - int i_surf = 4*i + 1; - int i_mesh = get_bin_from_indices(ijk0); - int i_bin = 4*3*i_mesh + i_surf - 1; - bins.push_back(i_bin); - - // Advance position - --ijk0[i]; - xyz_cross[i] = grid_[i][ijk0[i] - 1]; - - // Inward current on i min surface - i_surf = 4*i + 4; - i_mesh = get_bin_from_indices(ijk0); - i_bin = 4*3*i_mesh + i_surf - 1; - bins.push_back(i_bin); - } - } +StructuredMesh::MeshIndex CylindricalMesh::get_indices( + Position r, bool& in_mesh) const +{ + local_coords(r); + + Position mapped_r; + mapped_r[0] = std::hypot(r.x, r.y); + mapped_r[2] = r[2]; + + if (mapped_r[0] < FP_PRECISION) { + mapped_r[1] = 0.0; + } else { + mapped_r[1] = std::atan2(r.y, r.x); + if (mapped_r[1] < 0) + mapped_r[1] += 2 * M_PI; + } + + MeshIndex idx = StructuredMesh::get_indices(mapped_r, in_mesh); + + idx[1] = sanitize_phi(idx[1]); + + return idx; +} + +Position CylindricalMesh::sample_element( + const MeshIndex& ijk, uint64_t* seed) const +{ + double r_min = this->r(ijk[0] - 1); + double r_max = this->r(ijk[0]); + + double phi_min = this->phi(ijk[1] - 1); + double phi_max = this->phi(ijk[1]); + + double z_min = this->z(ijk[2] - 1); + double z_max = this->z(ijk[2]); + + double r_min_sq = r_min * r_min; + double r_max_sq = r_max * r_max; + double r = std::sqrt(uniform_distribution(r_min_sq, r_max_sq, seed)); + double phi = uniform_distribution(phi_min, phi_max, seed); + double z = uniform_distribution(z_min, z_max, seed); + + double x = r * std::cos(phi); + double y = r * std::sin(phi); + + return origin_ + Position(x, y, z); +} + +double CylindricalMesh::find_r_crossing( + const Position& r, const Direction& u, double l, int shell) const +{ + + if ((shell < 0) || (shell > shape_[0])) + return INFTY; + + // solve r.x^2 + r.y^2 == r0^2 + // x^2 + 2*s*u*x + s^2*u^2 + s^2*v^2+2*s*v*y + y^2 -r0^2 = 0 + // s^2 * (u^2 + v^2) + 2*s*(u*x+v*y) + x^2+y^2-r0^2 = 0 + + const double r0 = grid_[0][shell]; + if (r0 == 0.0) + return INFTY; + + const double denominator = u.x * u.x + u.y * u.y; + + // Direction of flight is in z-direction. Will never intersect r. + if (std::abs(denominator) < FP_PRECISION) + return INFTY; + + // inverse of dominator to help the compiler to speed things up + const double inv_denominator = 1.0 / denominator; + + const double p = (u.x * r.x + u.y * r.y) * inv_denominator; + double c = r.x * r.x + r.y * r.y - r0 * r0; + double D = p * p - c * inv_denominator; + + if (D < 0.0) + return INFTY; + + D = std::sqrt(D); + + // the solution -p - D is always smaller as -p + D : Check this one first + if (std::abs(c) <= RADIAL_MESH_TOL) + return INFTY; + + if (-p - D > l) + return -p - D; + if (-p + D > l) + return -p + D; + + return INFTY; +} + +double CylindricalMesh::find_phi_crossing( + const Position& r, const Direction& u, double l, int shell) const +{ + // Phi grid is [0, 2π], thus there is no real surface to cross + if (full_phi_ && (shape_[1] == 1)) + return INFTY; + + shell = sanitize_phi(shell); + + const double p0 = grid_[1][shell]; + + // solve y(s)/x(s) = tan(p0) = sin(p0)/cos(p0) + // => x(s) * cos(p0) = y(s) * sin(p0) + // => (y + s * v) * cos(p0) = (x + s * u) * sin(p0) + // = s * (v * cos(p0) - u * sin(p0)) = - (y * cos(p0) - x * sin(p0)) + + const double c0 = std::cos(p0); + const double s0 = std::sin(p0); + + const double denominator = (u.x * s0 - u.y * c0); + + // Check if direction of flight is not parallel to phi surface + if (std::abs(denominator) > FP_PRECISION) { + const double s = -(r.x * s0 - r.y * c0) / denominator; + // Check if solution is in positive direction of flight and crosses the + // correct phi surface (not -phi) + if ((s > l) && ((c0 * (r.x + s * u.x) + s0 * (r.y + s * u.y)) > 0.0)) + return s; + } + + return INFTY; +} + +StructuredMesh::MeshDistance CylindricalMesh::find_z_crossing( + const Position& r, const Direction& u, double l, int shell) const +{ + MeshDistance d; + d.next_index = shell; + + // Direction of flight is within xy-plane. Will never intersect z. + if (std::abs(u.z) < FP_PRECISION) + return d; + + d.max_surface = (u.z > 0.0); + if (d.max_surface && (shell <= shape_[2])) { + d.next_index += 1; + d.distance = (grid_[2][shell] - r.z) / u.z; + } else if (!d.max_surface && (shell > 0)) { + d.next_index -= 1; + d.distance = (grid_[2][shell - 1] - r.z) / u.z; + } + return d; +} + +StructuredMesh::MeshDistance CylindricalMesh::distance_to_grid_boundary( + const MeshIndex& ijk, int i, const Position& r0, const Direction& u, + double l) const +{ + Position r = r0 - origin_; + + if (i == 0) { + + return std::min( + MeshDistance(ijk[i] + 1, true, find_r_crossing(r, u, l, ijk[i])), + MeshDistance(ijk[i] - 1, false, find_r_crossing(r, u, l, ijk[i] - 1))); + + } else if (i == 1) { + + return std::min(MeshDistance(sanitize_phi(ijk[i] + 1), true, + find_phi_crossing(r, u, l, ijk[i])), + MeshDistance(sanitize_phi(ijk[i] - 1), false, + find_phi_crossing(r, u, l, ijk[i] - 1))); + + } else { + return find_z_crossing(r, u, l, ijk[i]); + } +} + +int CylindricalMesh::set_grid() +{ + shape_ = {static_cast(grid_[0].size()) - 1, + static_cast(grid_[1].size()) - 1, + static_cast(grid_[2].size()) - 1}; + + for (const auto& g : grid_) { + if (g.size() < 2) { + set_errmsg("r-, phi-, and z- grids for cylindrical meshes " + "must each have at least 2 points"); + return OPENMC_E_INVALID_ARGUMENT; + } + if (std::adjacent_find(g.begin(), g.end(), std::greater_equal<>()) != + g.end()) { + set_errmsg("Values in for r-, phi-, and z- grids for " + "cylindrical meshes must be sorted and unique."); + return OPENMC_E_INVALID_ARGUMENT; } + } + if (grid_[0].front() < 0.0) { + set_errmsg("r-grid for " + "cylindrical meshes must start at r >= 0."); + return OPENMC_E_INVALID_ARGUMENT; + } + if (grid_[1].front() < 0.0) { + set_errmsg("phi-grid for " + "cylindrical meshes must start at phi >= 0."); + return OPENMC_E_INVALID_ARGUMENT; + } + if (grid_[1].back() > 2.0 * PI) { + set_errmsg("phi-grids for " + "cylindrical meshes must end with theta <= 2*pi."); - // Calculate new coordinates - r0 += distance * u; + return OPENMC_E_INVALID_ARGUMENT; } + + full_phi_ = (grid_[1].front() == 0.0) && (grid_[1].back() == 2.0 * PI); + + lower_left_ = {grid_[0].front(), grid_[1].front(), grid_[2].front()}; + upper_right_ = {grid_[0].back(), grid_[1].back(), grid_[2].back()}; + + return 0; } -int RectilinearMesh::get_index_in_direction(double r, int i) const +int CylindricalMesh::get_index_in_direction(double r, int i) const { return lower_bound_index(grid_[i].begin(), grid_[i].end(), r) + 1; } -std::pair, vector> RectilinearMesh::plot( +std::pair, vector> CylindricalMesh::plot( Position plot_ll, Position plot_ur) const { + fatal_error("Plot of cylindrical Mesh not implemented"); + // Figure out which axes lie in the plane of the plot. - array axes {-1, -1}; - if (plot_ur.z == plot_ll.z) { - axes = {0, 1}; - } else if (plot_ur.y == plot_ll.y) { - axes = {0, 2}; - } else if (plot_ur.x == plot_ll.x) { - axes = {1, 2}; + array, 2> axis_lines; + return {axis_lines[0], axis_lines[1]}; +} + +void CylindricalMesh::to_hdf5(hid_t group) const +{ + hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); + + write_dataset(mesh_group, "type", "cylindrical"); + write_dataset(mesh_group, "r_grid", grid_[0]); + write_dataset(mesh_group, "phi_grid", grid_[1]); + write_dataset(mesh_group, "z_grid", grid_[2]); + write_dataset(mesh_group, "origin", origin_); + + close_group(mesh_group); +} + +double CylindricalMesh::volume(const MeshIndex& ijk) const +{ + double r_i = grid_[0][ijk[0] - 1]; + double r_o = grid_[0][ijk[0]]; + + double phi_i = grid_[1][ijk[1] - 1]; + double phi_o = grid_[1][ijk[1]]; + + double z_i = grid_[2][ijk[2] - 1]; + double z_o = grid_[2][ijk[2]]; + + return 0.5 * (r_o * r_o - r_i * r_i) * (phi_o - phi_i) * (z_o - z_i); +} + +//============================================================================== +// SphericalMesh implementation +//============================================================================== + +SphericalMesh::SphericalMesh(pugi::xml_node node) + : PeriodicStructuredMesh {node} +{ + n_dimension_ = 3; + + grid_[0] = get_node_array(node, "r_grid"); + grid_[1] = get_node_array(node, "theta_grid"); + grid_[2] = get_node_array(node, "phi_grid"); + origin_ = get_node_position(node, "origin"); + + if (int err = set_grid()) { + fatal_error(openmc_err_msg); + } +} + +const std::string SphericalMesh::mesh_type = "spherical"; + +std::string SphericalMesh::get_mesh_type() const +{ + return mesh_type; +} + +StructuredMesh::MeshIndex SphericalMesh::get_indices( + Position r, bool& in_mesh) const +{ + local_coords(r); + + Position mapped_r; + mapped_r[0] = r.norm(); + + if (mapped_r[0] < FP_PRECISION) { + mapped_r[1] = 0.0; + mapped_r[2] = 0.0; } else { - fatal_error("Can only plot mesh lines on an axis-aligned plot"); + mapped_r[1] = std::acos(r.z / mapped_r.x); + mapped_r[2] = std::atan2(r.y, r.x); + if (mapped_r[2] < 0) + mapped_r[2] += 2 * M_PI; } - // Get the coordinates of the mesh lines along both of the axes. - array, 2> axis_lines; - for (int i_ax = 0; i_ax < 2; ++i_ax) { - int axis = axes[i_ax]; - vector& lines {axis_lines[i_ax]}; + MeshIndex idx = StructuredMesh::get_indices(mapped_r, in_mesh); + + idx[1] = sanitize_theta(idx[1]); + idx[2] = sanitize_phi(idx[2]); + + return idx; +} + +Position SphericalMesh::sample_element( + const MeshIndex& ijk, uint64_t* seed) const +{ + double r_min = this->r(ijk[0] - 1); + double r_max = this->r(ijk[0]); + + double theta_min = this->theta(ijk[1] - 1); + double theta_max = this->theta(ijk[1]); + + double phi_min = this->phi(ijk[2] - 1); + double phi_max = this->phi(ijk[2]); + + double cos_theta = uniform_distribution(theta_min, theta_max, seed); + double sin_theta = std::sin(std::acos(cos_theta)); + double phi = uniform_distribution(phi_min, phi_max, seed); + double r_min_cub = std::pow(r_min, 3); + double r_max_cub = std::pow(r_max, 3); + // might be faster to do rejection here? + double r = std::cbrt(uniform_distribution(r_min_cub, r_max_cub, seed)); + + double x = r * std::cos(phi) * sin_theta; + double y = r * std::sin(phi) * sin_theta; + double z = r * cos_theta; + + return origin_ + Position(x, y, z); +} + +double SphericalMesh::find_r_crossing( + const Position& r, const Direction& u, double l, int shell) const +{ + if ((shell < 0) || (shell > shape_[0])) + return INFTY; + + // solve |r+s*u| = r0 + // |r+s*u| = |r| + 2*s*r*u + s^2 (|u|==1 !) + const double r0 = grid_[0][shell]; + if (r0 == 0.0) + return INFTY; + const double p = r.dot(u); + double c = r.dot(r) - r0 * r0; + double D = p * p - c; + + if (std::abs(c) <= RADIAL_MESH_TOL) + return INFTY; + + if (D >= 0.0) { + D = std::sqrt(D); + // the solution -p - D is always smaller as -p + D : Check this one first + if (-p - D > l) + return -p - D; + if (-p + D > l) + return -p + D; + } + + return INFTY; +} + +double SphericalMesh::find_theta_crossing( + const Position& r, const Direction& u, double l, int shell) const +{ + // Theta grid is [0, π], thus there is no real surface to cross + if (full_theta_ && (shape_[1] == 1)) + return INFTY; + + shell = sanitize_theta(shell); + + // solving z(s) = cos/theta) * r(s) with r(s) = r+s*u + // yields + // a*s^2 + 2*b*s + c == 0 with + // a = cos(theta)^2 - u.z * u.z + // b = r*u * cos(theta)^2 - u.z * r.z + // c = r*r * cos(theta)^2 - r.z^2 + + const double cos_t = std::cos(grid_[1][shell]); + const bool sgn = std::signbit(cos_t); + const double cos_t_2 = cos_t * cos_t; + + const double a = cos_t_2 - u.z * u.z; + const double b = r.dot(u) * cos_t_2 - r.z * u.z; + const double c = r.dot(r) * cos_t_2 - r.z * r.z; + + // if factor of s^2 is zero, direction of flight is parallel to theta surface + if (std::abs(a) < FP_PRECISION) { + // if b vanishes, direction of flight is within theta surface and crossing + // is not possible + if (std::abs(b) < FP_PRECISION) + return INFTY; + + const double s = -0.5 * c / b; + // Check if solution is in positive direction of flight and has correct sign + if ((s > l) && (std::signbit(r.z + s * u.z) == sgn)) + return s; + + // no crossing is possible + return INFTY; + } + + const double p = b / a; + double D = p * p - c / a; + + if (D < 0.0) + return INFTY; + + D = std::sqrt(D); + + // the solution -p-D is always smaller as -p+D : Check this one first + double s = -p - D; + // Check if solution is in positive direction of flight and has correct sign + if ((s > l) && (std::signbit(r.z + s * u.z) == sgn)) + return s; + + s = -p + D; + // Check if solution is in positive direction of flight and has correct sign + if ((s > l) && (std::signbit(r.z + s * u.z) == sgn)) + return s; + + return INFTY; +} + +double SphericalMesh::find_phi_crossing( + const Position& r, const Direction& u, double l, int shell) const +{ + // Phi grid is [0, 2π], thus there is no real surface to cross + if (full_phi_ && (shape_[2] == 1)) + return INFTY; + + shell = sanitize_phi(shell); + + const double p0 = grid_[2][shell]; + + // solve y(s)/x(s) = tan(p0) = sin(p0)/cos(p0) + // => x(s) * cos(p0) = y(s) * sin(p0) + // => (y + s * v) * cos(p0) = (x + s * u) * sin(p0) + // = s * (v * cos(p0) - u * sin(p0)) = - (y * cos(p0) - x * sin(p0)) + + const double c0 = std::cos(p0); + const double s0 = std::sin(p0); + + const double denominator = (u.x * s0 - u.y * c0); + + // Check if direction of flight is not parallel to phi surface + if (std::abs(denominator) > FP_PRECISION) { + const double s = -(r.x * s0 - r.y * c0) / denominator; + // Check if solution is in positive direction of flight and crosses the + // correct phi surface (not -phi) + if ((s > l) && ((c0 * (r.x + s * u.x) + s0 * (r.y + s * u.y)) > 0.0)) + return s; + } + + return INFTY; +} + +StructuredMesh::MeshDistance SphericalMesh::distance_to_grid_boundary( + const MeshIndex& ijk, int i, const Position& r0, const Direction& u, + double l) const +{ + + if (i == 0) { + return std::min( + MeshDistance(ijk[i] + 1, true, find_r_crossing(r0, u, l, ijk[i])), + MeshDistance(ijk[i] - 1, false, find_r_crossing(r0, u, l, ijk[i] - 1))); + + } else if (i == 1) { + return std::min(MeshDistance(sanitize_theta(ijk[i] + 1), true, + find_theta_crossing(r0, u, l, ijk[i])), + MeshDistance(sanitize_theta(ijk[i] - 1), false, + find_theta_crossing(r0, u, l, ijk[i] - 1))); + + } else { + return std::min(MeshDistance(sanitize_phi(ijk[i] + 1), true, + find_phi_crossing(r0, u, l, ijk[i])), + MeshDistance(sanitize_phi(ijk[i] - 1), false, + find_phi_crossing(r0, u, l, ijk[i] - 1))); + } +} + +int SphericalMesh::set_grid() +{ + shape_ = {static_cast(grid_[0].size()) - 1, + static_cast(grid_[1].size()) - 1, + static_cast(grid_[2].size()) - 1}; + + for (const auto& g : grid_) { + if (g.size() < 2) { + set_errmsg("x-, y-, and z- grids for spherical meshes " + "must each have at least 2 points"); + return OPENMC_E_INVALID_ARGUMENT; + } + if (std::adjacent_find(g.begin(), g.end(), std::greater_equal<>()) != + g.end()) { + set_errmsg("Values in for r-, theta-, and phi- grids for " + "spherical meshes must be sorted and unique."); + return OPENMC_E_INVALID_ARGUMENT; + } + if (g.front() < 0.0) { + set_errmsg("r-, theta-, and phi- grids for " + "spherical meshes must start at v >= 0."); + return OPENMC_E_INVALID_ARGUMENT; + } + } + if (grid_[1].back() > PI) { + set_errmsg("theta-grids for " + "spherical meshes must end with theta <= pi."); + + return OPENMC_E_INVALID_ARGUMENT; + } + if (grid_[2].back() > 2 * PI) { + set_errmsg("phi-grids for " + "spherical meshes must end with phi <= 2*pi."); + return OPENMC_E_INVALID_ARGUMENT; + } + + full_theta_ = (grid_[1].front() == 0.0) && (grid_[1].back() == PI); + full_phi_ = (grid_[2].front() == 0.0) && (grid_[2].back() == 2 * PI); + + lower_left_ = {grid_[0].front(), grid_[1].front(), grid_[2].front()}; + upper_right_ = {grid_[0].back(), grid_[1].back(), grid_[2].back()}; + + return 0; +} - for (auto coord : grid_[axis]) { - if (coord >= plot_ll[axis] && coord <= plot_ur[axis]) - lines.push_back(coord); - } - } +int SphericalMesh::get_index_in_direction(double r, int i) const +{ + return lower_bound_index(grid_[i].begin(), grid_[i].end(), r) + 1; +} + +std::pair, vector> SphericalMesh::plot( + Position plot_ll, Position plot_ur) const +{ + fatal_error("Plot of spherical Mesh not implemented"); + // Figure out which axes lie in the plane of the plot. + array, 2> axis_lines; return {axis_lines[0], axis_lines[1]}; } -void RectilinearMesh::to_hdf5(hid_t group) const +void SphericalMesh::to_hdf5(hid_t group) const { hid_t mesh_group = create_group(group, "mesh " + std::to_string(id_)); - write_dataset(mesh_group, "type", "rectilinear"); - write_dataset(mesh_group, "x_grid", grid_[0]); - write_dataset(mesh_group, "y_grid", grid_[1]); - write_dataset(mesh_group, "z_grid", grid_[2]); + write_dataset(mesh_group, "type", SphericalMesh::mesh_type); + write_dataset(mesh_group, "r_grid", grid_[0]); + write_dataset(mesh_group, "theta_grid", grid_[1]); + write_dataset(mesh_group, "phi_grid", grid_[2]); + write_dataset(mesh_group, "origin", origin_); close_group(mesh_group); } +double SphericalMesh::volume(const MeshIndex& ijk) const +{ + double r_i = grid_[0][ijk[0] - 1]; + double r_o = grid_[0][ijk[0]]; + + double theta_i = grid_[1][ijk[1] - 1]; + double theta_o = grid_[1][ijk[1]]; + + double phi_i = grid_[2][ijk[2] - 1]; + double phi_o = grid_[2][ijk[2]]; + + return (1.0 / 3.0) * (r_o * r_o * r_o - r_i * r_i * r_i) * + (std::cos(theta_i) - std::cos(theta_o)) * (phi_o - phi_i); +} + //============================================================================== // Helper functions for the C API //============================================================================== -int -check_mesh(int32_t index) +int check_mesh(int32_t index) { if (index < 0 || index >= model::meshes.size()) { set_errmsg("Index in meshes array is out of bounds."); @@ -1321,11 +1749,11 @@ check_mesh(int32_t index) return 0; } -template -int -check_mesh_type(int32_t index) +template +int check_mesh_type(int32_t index) { - if (int err = check_mesh(index)) return err; + if (int err = check_mesh(index)) + return err; T* mesh = dynamic_cast(model::meshes[index].get()); if (!mesh) { @@ -1335,68 +1763,72 @@ check_mesh_type(int32_t index) return 0; } +template +bool is_mesh_type(int32_t index) +{ + T* mesh = dynamic_cast(model::meshes[index].get()); + return mesh; +} + //============================================================================== // C API functions //============================================================================== // Return the type of mesh as a C string -extern "C" int -openmc_mesh_get_type(int32_t index, char* type) +extern "C" int openmc_mesh_get_type(int32_t index, char* type) { - if (int err = check_mesh(index)) return err; + if (int err = check_mesh(index)) + return err; + + std::strcpy(type, model::meshes[index].get()->get_mesh_type().c_str()); - RegularMesh* mesh = dynamic_cast(model::meshes[index].get()); - if (mesh) { - std::strcpy(type, "regular"); - } else { - RectilinearMesh* mesh = dynamic_cast(model::meshes[index].get()); - if (mesh) { - std::strcpy(type, "rectilinear"); - } - } return 0; } //! Extend the meshes array by n elements -extern "C" int -openmc_extend_meshes(int32_t n, const char* type, int32_t* index_start, - int32_t* index_end) +extern "C" int openmc_extend_meshes( + int32_t n, const char* type, int32_t* index_start, int32_t* index_end) { - if (index_start) *index_start = model::meshes.size(); + if (index_start) + *index_start = model::meshes.size(); std::string mesh_type; for (int i = 0; i < n; ++i) { - if (std::strcmp(type, "regular") == 0) { + if (RegularMesh::mesh_type == type) { model::meshes.push_back(make_unique()); - } else if (std::strcmp(type, "rectilinear") == 0) { + } else if (RectilinearMesh::mesh_type == type) { model::meshes.push_back(make_unique()); + } else if (CylindricalMesh::mesh_type == type) { + model::meshes.push_back(make_unique()); + } else if (SphericalMesh::mesh_type == type) { + model::meshes.push_back(make_unique()); } else { - throw std::runtime_error{"Unknown mesh type: " + std::string(type)}; + throw std::runtime_error {"Unknown mesh type: " + std::string(type)}; } } - if (index_end) *index_end = model::meshes.size() - 1; + if (index_end) + *index_end = model::meshes.size() - 1; return 0; } //! Adds a new unstructured mesh to OpenMC -extern "C" int openmc_add_unstructured_mesh(const char filename[], - const char library[], - int* id) +extern "C" int openmc_add_unstructured_mesh( + const char filename[], const char library[], int* id) { std::string lib_name(library); std::string mesh_file(filename); bool valid_lib = false; #ifdef DAGMC - if (lib_name == "moab") { + if (lib_name == MOABMesh::mesh_lib_type) { model::meshes.push_back(std::move(make_unique(mesh_file))); valid_lib = true; } #endif #ifdef LIBMESH - if (lib_name == "libmesh") { + if (lib_name == LibMesh::mesh_lib_type) { model::meshes.push_back(std::move(make_unique(mesh_file))); valid_lib = true; } @@ -1404,7 +1836,8 @@ extern "C" int openmc_add_unstructured_mesh(const char filename[], if (!valid_lib) { set_errmsg(fmt::format("Mesh library {} is not supported " - "by this build of OpenMC", lib_name)); + "by this build of OpenMC", + lib_name)); return OPENMC_E_INVALID_ARGUMENT; } @@ -1415,10 +1848,8 @@ extern "C" int openmc_add_unstructured_mesh(const char filename[], return 0; } - //! Return the index in the meshes array of a mesh with a given ID -extern "C" int -openmc_get_mesh_index(int32_t id, int32_t* index) +extern "C" int openmc_get_mesh_index(int32_t id, int32_t* index) { auto pair = model::mesh_map.find(id); if (pair == model::mesh_map.end()) { @@ -1430,29 +1861,125 @@ openmc_get_mesh_index(int32_t id, int32_t* index) } //! Return the ID of a mesh -extern "C" int -openmc_mesh_get_id(int32_t index, int32_t* id) +extern "C" int openmc_mesh_get_id(int32_t index, int32_t* id) { - if (int err = check_mesh(index)) return err; + if (int err = check_mesh(index)) + return err; *id = model::meshes[index]->id_; return 0; } //! Set the ID of a mesh -extern "C" int -openmc_mesh_set_id(int32_t index, int32_t id) +extern "C" int openmc_mesh_set_id(int32_t index, int32_t id) { - if (int err = check_mesh(index)) return err; + if (int err = check_mesh(index)) + return err; model::meshes[index]->id_ = id; model::mesh_map[id] = index; return 0; } +//! Get the number of elements in a mesh +extern "C" int openmc_mesh_get_n_elements(int32_t index, size_t* n) +{ + if (int err = check_mesh(index)) + return err; + *n = model::meshes[index]->n_bins(); + return 0; +} + +//! Get the volume of each element in the mesh +extern "C" int openmc_mesh_get_volumes(int32_t index, double* volumes) +{ + if (int err = check_mesh(index)) + return err; + for (int i = 0; i < model::meshes[index]->n_bins(); ++i) { + volumes[i] = model::meshes[index]->volume(i); + } + return 0; +} + +extern "C" int openmc_mesh_material_volumes(int32_t index, int n_sample, + int bin, int result_size, void* result, int* hits, uint64_t* seed) +{ + auto result_ = reinterpret_cast(result); + if (!result_) { + set_errmsg("Invalid result pointer passed to openmc_mesh_material_volumes"); + return OPENMC_E_INVALID_ARGUMENT; + } + + if (int err = check_mesh(index)) + return err; + + int n = model::meshes[index]->material_volumes( + n_sample, bin, {result_, result_ + result_size}, seed); + *hits = n; + return (n == -1) ? OPENMC_E_ALLOCATE : 0; +} + +extern "C" int openmc_mesh_get_plot_bins(int32_t index, Position origin, + Position width, int basis, int* pixels, int32_t* data) +{ + if (int err = check_mesh(index)) + return err; + const auto& mesh = model::meshes[index].get(); + + int pixel_width = pixels[0]; + int pixel_height = pixels[1]; + + // get pixel size + double in_pixel = (width[0]) / static_cast(pixel_width); + double out_pixel = (width[1]) / static_cast(pixel_height); + + // setup basis indices and initial position centered on pixel + int in_i, out_i; + Position xyz = origin; + enum class PlotBasis { xy = 1, xz = 2, yz = 3 }; + PlotBasis basis_enum = static_cast(basis); + switch (basis_enum) { + case PlotBasis::xy: + in_i = 0; + out_i = 1; + break; + case PlotBasis::xz: + in_i = 0; + out_i = 2; + break; + case PlotBasis::yz: + in_i = 1; + out_i = 2; + break; + default: + UNREACHABLE(); + } + + // set initial position + xyz[in_i] = origin[in_i] - width[0] / 2. + in_pixel / 2.; + xyz[out_i] = origin[out_i] + width[1] / 2. - out_pixel / 2.; + +#pragma omp parallel + { + Position r = xyz; + +#pragma omp for + for (int y = 0; y < pixel_height; y++) { + r[out_i] = xyz[out_i] - out_pixel * y; + for (int x = 0; x < pixel_width; x++) { + r[in_i] = xyz[in_i] + in_pixel * x; + data[pixel_width * y + x] = mesh->get_bin(r); + } + } + } + + return 0; +} + //! Get the dimension of a regular mesh -extern "C" int -openmc_regular_mesh_get_dimension(int32_t index, int** dims, int* n) +extern "C" int openmc_regular_mesh_get_dimension( + int32_t index, int** dims, int* n) { - if (int err = check_mesh_type(index)) return err; + if (int err = check_mesh_type(index)) + return err; RegularMesh* mesh = dynamic_cast(model::meshes[index].get()); *dims = mesh->shape_.data(); *n = mesh->n_dimension_; @@ -1460,25 +1987,25 @@ openmc_regular_mesh_get_dimension(int32_t index, int** dims, int* n) } //! Set the dimension of a regular mesh -extern "C" int -openmc_regular_mesh_set_dimension(int32_t index, int n, const int* dims) +extern "C" int openmc_regular_mesh_set_dimension( + int32_t index, int n, const int* dims) { - if (int err = check_mesh_type(index)) return err; + if (int err = check_mesh_type(index)) + return err; RegularMesh* mesh = dynamic_cast(model::meshes[index].get()); // Copy dimension - vector shape = {static_cast(n)}; - mesh->shape_ = xt::adapt(dims, n, xt::no_ownership(), shape); - mesh->n_dimension_ = mesh->shape_.size(); + mesh->n_dimension_ = n; + std::copy(dims, dims + n, mesh->shape_.begin()); return 0; } //! Get the regular mesh parameters -extern "C" int -openmc_regular_mesh_get_params(int32_t index, double** ll, double** ur, - double** width, int* n) +extern "C" int openmc_regular_mesh_get_params( + int32_t index, double** ll, double** ur, double** width, int* n) { - if (int err = check_mesh_type(index)) return err; + if (int err = check_mesh_type(index)) + return err; RegularMesh* m = dynamic_cast(model::meshes[index].get()); if (m->lower_left_.dimension() == 0) { @@ -1494,41 +2021,88 @@ openmc_regular_mesh_get_params(int32_t index, double** ll, double** ur, } //! Set the regular mesh parameters -extern "C" int -openmc_regular_mesh_set_params(int32_t index, int n, const double* ll, - const double* ur, const double* width) +extern "C" int openmc_regular_mesh_set_params( + int32_t index, int n, const double* ll, const double* ur, const double* width) { - if (int err = check_mesh_type(index)) return err; + if (int err = check_mesh_type(index)) + return err; RegularMesh* m = dynamic_cast(model::meshes[index].get()); + if (m->n_dimension_ == -1) { + set_errmsg("Need to set mesh dimension before setting parameters."); + return OPENMC_E_UNASSIGNED; + } + vector shape = {static_cast(n)}; if (ll && ur) { m->lower_left_ = xt::adapt(ll, n, xt::no_ownership(), shape); m->upper_right_ = xt::adapt(ur, n, xt::no_ownership(), shape); - m->width_ = (m->upper_right_ - m->lower_left_) / m->shape_; + m->width_ = (m->upper_right_ - m->lower_left_) / m->get_x_shape(); } else if (ll && width) { m->lower_left_ = xt::adapt(ll, n, xt::no_ownership(), shape); m->width_ = xt::adapt(width, n, xt::no_ownership(), shape); - m->upper_right_ = m->lower_left_ + m->shape_ * m->width_; + m->upper_right_ = m->lower_left_ + m->get_x_shape() * m->width_; } else if (ur && width) { m->upper_right_ = xt::adapt(ur, n, xt::no_ownership(), shape); m->width_ = xt::adapt(width, n, xt::no_ownership(), shape); - m->lower_left_ = m->upper_right_ - m->shape_ * m->width_; + m->lower_left_ = m->upper_right_ - m->get_x_shape() * m->width_; } else { set_errmsg("At least two parameters must be specified."); return OPENMC_E_INVALID_ARGUMENT; } + // Set material volumes + + // TODO: incorporate this into method in RegularMesh that can be called from + // here and from constructor + m->volume_frac_ = 1.0 / xt::prod(m->get_x_shape())(); + m->element_volume_ = 1.0; + for (int i = 0; i < m->n_dimension_; i++) { + m->element_volume_ *= m->width_[i]; + } + return 0; } -//! Get the rectilinear mesh grid -extern "C" int -openmc_rectilinear_mesh_get_grid(int32_t index, double** grid_x, int* nx, - double** grid_y, int* ny, double** grid_z, int* nz) +//! Set the mesh parameters for rectilinear, cylindrical and spharical meshes +template +int openmc_structured_mesh_set_grid_impl(int32_t index, const double* grid_x, + const int nx, const double* grid_y, const int ny, const double* grid_z, + const int nz) +{ + if (int err = check_mesh_type(index)) + return err; + + C* m = dynamic_cast(model::meshes[index].get()); + + m->n_dimension_ = 3; + + m->grid_[0].reserve(nx); + m->grid_[1].reserve(ny); + m->grid_[2].reserve(nz); + + for (int i = 0; i < nx; i++) { + m->grid_[0].push_back(grid_x[i]); + } + for (int i = 0; i < ny; i++) { + m->grid_[1].push_back(grid_y[i]); + } + for (int i = 0; i < nz; i++) { + m->grid_[2].push_back(grid_z[i]); + } + + int err = m->set_grid(); + return err; +} + +//! Get the mesh parameters for rectilinear, cylindrical and spherical meshes +template +int openmc_structured_mesh_get_grid_impl(int32_t index, double** grid_x, + int* nx, double** grid_y, int* ny, double** grid_z, int* nz) { - if (int err = check_mesh_type(index)) return err; - RectilinearMesh* m = dynamic_cast(model::meshes[index].get()); + if (int err = check_mesh_type(index)) + return err; + C* m = dynamic_cast(model::meshes[index].get()); if (m->lower_left_.dimension() == 0) { set_errmsg("Mesh parameters have not been set."); @@ -1545,51 +2119,93 @@ openmc_rectilinear_mesh_get_grid(int32_t index, double** grid_x, int* nx, return 0; } +//! Get the rectilinear mesh grid +extern "C" int openmc_rectilinear_mesh_get_grid(int32_t index, double** grid_x, + int* nx, double** grid_y, int* ny, double** grid_z, int* nz) +{ + return openmc_structured_mesh_get_grid_impl( + index, grid_x, nx, grid_y, ny, grid_z, nz); +} + //! Set the rectilienar mesh parameters -extern "C" int -openmc_rectilinear_mesh_set_grid(int32_t index, const double* grid_x, - const int nx, const double* grid_y, const int ny, - const double* grid_z, const int nz) +extern "C" int openmc_rectilinear_mesh_set_grid(int32_t index, + const double* grid_x, const int nx, const double* grid_y, const int ny, + const double* grid_z, const int nz) { - if (int err = check_mesh_type(index)) return err; - RectilinearMesh* m = dynamic_cast(model::meshes[index].get()); + return openmc_structured_mesh_set_grid_impl( + index, grid_x, nx, grid_y, ny, grid_z, nz); +} - m->n_dimension_ = 3; - m->grid_.resize(m->n_dimension_); +//! Get the cylindrical mesh grid +extern "C" int openmc_cylindrical_mesh_get_grid(int32_t index, double** grid_x, + int* nx, double** grid_y, int* ny, double** grid_z, int* nz) +{ + return openmc_structured_mesh_get_grid_impl( + index, grid_x, nx, grid_y, ny, grid_z, nz); +} - for (int i = 0; i < nx; i++) { - m->grid_[0].push_back(grid_x[i]); - } - for (int i = 0; i < ny; i++) { - m->grid_[1].push_back(grid_y[i]); - } - for (int i = 0; i < nz; i++) { - m->grid_[2].push_back(grid_z[i]); - } +//! Set the cylindrical mesh parameters +extern "C" int openmc_cylindrical_mesh_set_grid(int32_t index, + const double* grid_x, const int nx, const double* grid_y, const int ny, + const double* grid_z, const int nz) +{ + return openmc_structured_mesh_set_grid_impl( + index, grid_x, nx, grid_y, ny, grid_z, nz); +} - int err = m->set_grid(); - return err; +//! Get the spherical mesh grid +extern "C" int openmc_spherical_mesh_get_grid(int32_t index, double** grid_x, + int* nx, double** grid_y, int* ny, double** grid_z, int* nz) +{ + + return openmc_structured_mesh_get_grid_impl( + index, grid_x, nx, grid_y, ny, grid_z, nz); + ; +} + +//! Set the spherical mesh parameters +extern "C" int openmc_spherical_mesh_set_grid(int32_t index, + const double* grid_x, const int nx, const double* grid_y, const int ny, + const double* grid_z, const int nz) +{ + return openmc_structured_mesh_set_grid_impl( + index, grid_x, nx, grid_y, ny, grid_z, nz); } #ifdef DAGMC -MOABMesh::MOABMesh(pugi::xml_node node) : UnstructuredMesh(node) { +const std::string MOABMesh::mesh_lib_type = "moab"; + +MOABMesh::MOABMesh(pugi::xml_node node) : UnstructuredMesh(node) +{ initialize(); } -MOABMesh::MOABMesh(const std::string& filename) { +MOABMesh::MOABMesh(const std::string& filename, double length_multiplier) +{ filename_ = filename; + set_length_multiplier(length_multiplier); initialize(); } -void MOABMesh::initialize() { - // create MOAB instance - mbi_ = make_unique(); - // load unstructured mesh file - moab::ErrorCode rval = mbi_->load_file(filename_.c_str()); - if (rval != moab::MB_SUCCESS) { - fatal_error("Failed to load the unstructured mesh file: " + filename_); - } +MOABMesh::MOABMesh(std::shared_ptr external_mbi) +{ + mbi_ = external_mbi; + filename_ = "unknown (external file)"; + this->initialize(); +} + +void MOABMesh::initialize() +{ + + // Create the MOAB interface and load data from file + this->create_interface(); + + // Initialise MOAB error code + moab::ErrorCode rval = moab::MB_SUCCESS; + + // Set the dimension + n_dimension_ = 3; // set member range of tetrahedral entities rval = mbi_->get_entities_by_dimension(0, n_dimension_, ehs_); @@ -1599,7 +2215,15 @@ void MOABMesh::initialize() { if (!ehs_.all_of_type(moab::MBTET)) { warning("Non-tetrahedral elements found in unstructured " - "mesh file: " + filename_); + "mesh file: " + + filename_); + } + + // set member range of vertices + int vertex_dim = 0; + rval = mbi_->get_entities_by_dimension(0, vertex_dim, verts_); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to get all vertex handles"); } // make an entity set for all tetrahedra @@ -1614,28 +2238,77 @@ void MOABMesh::initialize() { fatal_error("Failed to add tetrahedra to an entity set."); } + if (length_multiplier_ > 0.0) { + // get the connectivity of all tets + moab::Range adj; + rval = mbi_->get_adjacencies(ehs_, 0, true, adj, moab::Interface::UNION); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to get adjacent vertices of tetrahedra."); + } + // scale all vertex coords by multiplier (done individually so not all + // coordinates are in memory twice at once) + for (auto vert : adj) { + // retrieve coords + std::array coord; + rval = mbi_->get_coords(&vert, 1, coord.data()); + if (rval != moab::MB_SUCCESS) { + fatal_error("Could not get coordinates of vertex."); + } + // scale coords + for (auto& c : coord) { + c *= length_multiplier_; + } + // set new coords + rval = mbi_->set_coords(&vert, 1, coord.data()); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to set new vertex coordinates"); + } + } + } +} + +void MOABMesh::prepare_for_tallies() +{ + // if the KDTree has already been constructed, do nothing + if (kdtree_) + return; + // build acceleration data structures compute_barycentric_data(ehs_); build_kdtree(ehs_); } -void -MOABMesh::build_kdtree(const moab::Range& all_tets) +void MOABMesh::create_interface() +{ + // Do not create a MOAB instance if one is already in memory + if (mbi_) + return; + + // create MOAB instance + mbi_ = std::make_shared(); + + // load unstructured mesh file + moab::ErrorCode rval = mbi_->load_file(filename_.c_str()); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to load the unstructured mesh file: " + filename_); + } +} + +void MOABMesh::build_kdtree(const moab::Range& all_tets) { moab::Range all_tris; int adj_dim = 2; - moab::ErrorCode rval = mbi_->get_adjacencies(all_tets, - adj_dim, - true, - all_tris, - moab::Interface::UNION); + write_message("Getting tet adjacencies...", 7); + moab::ErrorCode rval = mbi_->get_adjacencies( + all_tets, adj_dim, true, all_tris, moab::Interface::UNION); if (rval != moab::MB_SUCCESS) { fatal_error("Failed to get adjacent triangles for tets"); } if (!all_tris.all_of_type(moab::MBTRI)) { warning("Non-triangle elements found in tet adjacencies in " - "unstructured mesh file: " + filename_); + "unstructured mesh file: " + + filename_); } // combine into one range @@ -1644,13 +2317,24 @@ MOABMesh::build_kdtree(const moab::Range& all_tets) all_tets_and_tris.merge(all_tris); // create a kd-tree instance + write_message("Building adaptive k-d tree for tet mesh...", 7); kdtree_ = make_unique(mbi_.get()); - // build the tree - rval = kdtree_->build_tree(all_tets_and_tris, &kdtree_root_); + // Determine what options to use + std::ostringstream options_stream; + if (options_.empty()) { + options_stream << "MAX_DEPTH=20;PLANE_SET=2;"; + } else { + options_stream << options_; + } + moab::FileOptions file_opts(options_stream.str().c_str()); + + // Build the k-d tree + rval = kdtree_->build_tree(all_tets_and_tris, &kdtree_root_, &file_opts); if (rval != moab::MB_SUCCESS) { fatal_error("Failed to construct KDTree for the " - "unstructured mesh file: " + filename_); + "unstructured mesh file: " + + filename_); } } @@ -1663,16 +2347,11 @@ void MOABMesh::intersect_track(const moab::CartVect& start, vector tris; // get all intersections with triangles in the tet mesh // (distances are relative to the start point, not the previous intersection) - rval = kdtree_->ray_intersect_triangles(kdtree_root_, - FP_COINCIDENT, - dir.array(), - start.array(), - tris, - hits, - 0, - track_len); + rval = kdtree_->ray_intersect_triangles(kdtree_root_, FP_COINCIDENT, + dir.array(), start.array(), tris, hits, 0, track_len); if (rval != moab::MB_SUCCESS) { - fatal_error("Failed to compute intersections on unstructured mesh: " + filename_); + fatal_error( + "Failed to compute intersections on unstructured mesh: " + filename_); } // remove duplicate intersection distances @@ -1682,12 +2361,8 @@ void MOABMesh::intersect_track(const moab::CartVect& start, std::sort(hits.begin(), hits.end()); } -void -MOABMesh::bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins, - vector& lengths) const +void MOABMesh::bins_crossed(Position r0, Position r1, const Direction& u, + vector& bins, vector& lengths) const { moab::CartVect start(r0.x, r0.y, r0.z); moab::CartVect end(r1.x, r1.y, r1.z); @@ -1695,7 +2370,8 @@ MOABMesh::bins_crossed(Position r0, dir.normalize(); double track_len = (end - start).length(); - if (track_len == 0.0) return; + if (track_len == 0.0) + return; start -= TINY_BIT * dir; end += TINY_BIT * dir; @@ -1741,7 +2417,6 @@ MOABMesh::bins_crossed(Position r0, bins.push_back(bin); lengths.push_back(segment_length / track_len); - } // tally remaining portion of track after last hit if @@ -1759,14 +2434,15 @@ MOABMesh::bins_crossed(Position r0, } }; -moab::EntityHandle -MOABMesh::get_tet(const Position& r) const +moab::EntityHandle MOABMesh::get_tet(const Position& r) const { moab::CartVect pos(r.x, r.y, r.z); // find the leaf of the kd-tree for this position moab::AdaptiveKDTreeIter kdtree_iter; moab::ErrorCode rval = kdtree_->point_search(pos.array(), kdtree_iter); - if (rval != moab::MB_SUCCESS) { return 0; } + if (rval != moab::MB_SUCCESS) { + return 0; + } // retrieve the tet elements of this leaf moab::EntityHandle leaf = kdtree_iter.handle(); @@ -1794,7 +2470,36 @@ double MOABMesh::volume(int bin) const std::string MOABMesh::library() const { - return "moab"; + return mesh_lib_type; +} + +// Sample position within a tet for MOAB type tets +Position MOABMesh::sample_element(int32_t bin, uint64_t* seed) const +{ + + moab::EntityHandle tet_ent = get_ent_handle_from_bin(bin); + + // Get vertex coordinates for MOAB tet + const moab::EntityHandle* conn1; + int conn1_size; + moab::ErrorCode rval = mbi_->get_connectivity(tet_ent, conn1, conn1_size); + if (rval != moab::MB_SUCCESS || conn1_size != 4) { + fatal_error(fmt::format( + "Failed to get tet connectivity or connectivity size ({}) is invalid.", + conn1_size)); + } + moab::CartVect p[4]; + rval = mbi_->get_coords(conn1, conn1_size, p[0].array()); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to get tet coords"); + } + + std::array tet_verts; + for (int i = 0; i < 4; i++) { + tet_verts[i] = {p[i][0], p[i][1], p[i][2]}; + } + // Samples position within tet using Barycentric stuff + return this->sample_tet(tet_verts, seed); } double MOABMesh::tet_volume(moab::EntityHandle tet) const @@ -1808,7 +2513,7 @@ double MOABMesh::tet_volume(moab::EntityHandle tet) const moab::CartVect p[4]; rval = mbi_->get_coords(conn.data(), conn.size(), p[0].array()); if (rval != moab::MB_SUCCESS) { - fatal_error("Failed to get tet coords"); + fatal_error("Failed to get tet coords"); } return 1.0 / 6.0 * (((p[1] - p[0]) * (p[2] - p[0])) % (p[3] - p[0])); @@ -1824,8 +2529,8 @@ int MOABMesh::get_bin(Position r) const } } -void -MOABMesh::compute_barycentric_data(const moab::Range& tets) { +void MOABMesh::compute_barycentric_data(const moab::Range& tets) +{ moab::ErrorCode rval; baryc_data_.clear(); @@ -1854,9 +2559,8 @@ MOABMesh::compute_barycentric_data(const moab::Range& tets) { } } -bool -MOABMesh::point_in_tet(const moab::CartVect& r, - moab::EntityHandle tet) const +bool MOABMesh::point_in_tet( + const moab::CartVect& r, moab::EntityHandle tet) const { moab::ErrorCode rval; @@ -1875,7 +2579,8 @@ MOABMesh::point_in_tet(const moab::CartVect& r, rval = mbi_->get_coords(verts.data(), 1, p_zero.array()); if (rval != moab::MB_SUCCESS) { warning("Failed to get coordinates of a vertex in " - "unstructured mesh: " + filename_); + "unstructured mesh: " + + filename_); return false; } @@ -1885,14 +2590,12 @@ MOABMesh::point_in_tet(const moab::CartVect& r, moab::CartVect bary_coords = a_inv * (r - p_zero); - return (bary_coords[0] >= 0.0 && - bary_coords[1] >= 0.0 && + return (bary_coords[0] >= 0.0 && bary_coords[1] >= 0.0 && bary_coords[2] >= 0.0 && bary_coords[0] + bary_coords[1] + bary_coords[2] <= 1.0); } -int -MOABMesh::get_bin_from_index(int idx) const +int MOABMesh::get_bin_from_index(int idx) const { if (idx >= n_bins()) { fatal_error(fmt::format("Invalid bin index: {}", idx)); @@ -1900,9 +2603,7 @@ MOABMesh::get_bin_from_index(int idx) const return ehs_[idx] - ehs_[0]; } -int -MOABMesh::get_index(const Position& r, - bool* in_mesh) const +int MOABMesh::get_index(const Position& r, bool* in_mesh) const { int bin = get_bin(r); *in_mesh = bin != -1; @@ -1921,8 +2622,17 @@ std::pair, vector> MOABMesh::plot( return {}; } -int -MOABMesh::get_bin_from_ent_handle(moab::EntityHandle eh) const +int MOABMesh::get_vert_idx_from_handle(moab::EntityHandle vert) const +{ + int idx = vert - verts_[0]; + if (idx >= n_vertices()) { + fatal_error( + fmt::format("Invalid vertex idx {} (# vertices {})", idx, n_vertices())); + } + return idx; +} + +int MOABMesh::get_bin_from_ent_handle(moab::EntityHandle eh) const { int bin = eh - ehs_[0]; if (bin >= n_bins()) { @@ -1931,8 +2641,7 @@ MOABMesh::get_bin_from_ent_handle(moab::EntityHandle eh) const return bin; } -moab::EntityHandle -MOABMesh::get_ent_handle_from_bin(int bin) const +moab::EntityHandle MOABMesh::get_ent_handle_from_bin(int bin) const { if (bin >= n_bins()) { fatal_error(fmt::format("Invalid bin index: ", bin)); @@ -1958,8 +2667,7 @@ int MOABMesh::n_surface_bins() const return 2 * tris.size(); } -Position -MOABMesh::centroid(int bin) const +Position MOABMesh::centroid(int bin) const { moab::ErrorCode rval; @@ -1983,7 +2691,7 @@ MOABMesh::centroid(int bin) const // compute the centroid of the element vertices moab::CartVect centroid(0.0, 0.0, 0.0); - for(const auto& coord : coords) { + for (const auto& coord : coords) { centroid += coord; } centroid /= double(coords.size()); @@ -1991,8 +2699,51 @@ MOABMesh::centroid(int bin) const return {centroid[0], centroid[1], centroid[2]}; } -std::pair -MOABMesh::get_score_tags(std::string score) const +int MOABMesh::n_vertices() const +{ + return verts_.size(); +} + +Position MOABMesh::vertex(int id) const +{ + + moab::ErrorCode rval; + + moab::EntityHandle vert = verts_[id]; + + moab::CartVect coords; + rval = mbi_->get_coords(&vert, 1, coords.array()); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to get the coordinates of a vertex."); + } + + return {coords[0], coords[1], coords[2]}; +} + +std::vector MOABMesh::connectivity(int bin) const +{ + moab::ErrorCode rval; + + auto tet = get_ent_handle_from_bin(bin); + + // look up the tet connectivity + vector conn; + rval = mbi_->get_connectivity(&tet, 1, conn); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to get connectivity of a mesh element."); + return {}; + } + + std::vector verts(4); + for (int i = 0; i < verts.size(); i++) { + verts[i] = get_vert_idx_from_handle(conn[i]); + } + + return verts; +} + +std::pair MOABMesh::get_score_tags( + std::string score) const { moab::ErrorCode rval; // add a tag to the mesh @@ -2003,30 +2754,26 @@ MOABMesh::get_score_tags(std::string score) const // create the value tag if not present and get handle double default_val = 0.0; auto val_string = score + "_mean"; - rval = mbi_->tag_get_handle(val_string.c_str(), - 1, - moab::MB_TYPE_DOUBLE, - value_tag, - moab::MB_TAG_DENSE|moab::MB_TAG_CREAT, - &default_val); + rval = mbi_->tag_get_handle(val_string.c_str(), 1, moab::MB_TYPE_DOUBLE, + value_tag, moab::MB_TAG_DENSE | moab::MB_TAG_CREAT, &default_val); if (rval != moab::MB_SUCCESS) { - auto msg = fmt::format("Could not create or retrieve the value tag for the score {}" - " on unstructured mesh {}", score, id_); + auto msg = + fmt::format("Could not create or retrieve the value tag for the score {}" + " on unstructured mesh {}", + score, id_); fatal_error(msg); } // create the std dev tag if not present and get handle moab::Tag error_tag; std::string err_string = score + "_std_dev"; - rval = mbi_->tag_get_handle(err_string.c_str(), - 1, - moab::MB_TYPE_DOUBLE, - error_tag, - moab::MB_TAG_DENSE|moab::MB_TAG_CREAT, - &default_val); + rval = mbi_->tag_get_handle(err_string.c_str(), 1, moab::MB_TYPE_DOUBLE, + error_tag, moab::MB_TAG_DENSE | moab::MB_TAG_CREAT, &default_val); if (rval != moab::MB_SUCCESS) { - auto msg = fmt::format("Could not create or retrieve the error tag for the score {}" - " on unstructured mesh {}", score, id_); + auto msg = + fmt::format("Could not create or retrieve the error tag for the score {}" + " on unstructured mesh {}", + score, id_); fatal_error(msg); } @@ -2034,8 +2781,7 @@ MOABMesh::get_score_tags(std::string score) const return {value_tag, error_tag}; } -void -MOABMesh::add_score(const std::string& score) +void MOABMesh::add_score(const std::string& score) { auto score_tags = get_score_tags(score); tag_names_.push_back(score); @@ -2047,26 +2793,31 @@ void MOABMesh::remove_scores() auto value_name = name + "_mean"; moab::Tag tag; moab::ErrorCode rval = mbi_->tag_get_handle(value_name.c_str(), tag); - if (rval != moab::MB_SUCCESS) return; + if (rval != moab::MB_SUCCESS) + return; rval = mbi_->tag_delete(tag); if (rval != moab::MB_SUCCESS) { auto msg = fmt::format("Failed to delete mesh tag for the score {}" - " on unstructured mesh {}", name, id_); + " on unstructured mesh {}", + name, id_); fatal_error(msg); } auto std_dev_name = name + "_std_dev"; rval = mbi_->tag_get_handle(std_dev_name.c_str(), tag); if (rval != moab::MB_SUCCESS) { - auto msg = fmt::format("Std. Dev. mesh tag does not exist for the score {}" - " on unstructured mesh {}", name, id_); + auto msg = + fmt::format("Std. Dev. mesh tag does not exist for the score {}" + " on unstructured mesh {}", + name, id_); } rval = mbi_->tag_delete(tag); if (rval != moab::MB_SUCCESS) { auto msg = fmt::format("Failed to delete mesh tag for the score {}" - " on unstructured mesh {}", name, id_); + " on unstructured mesh {}", + name, id_); fatal_error(msg); } } @@ -2074,8 +2825,7 @@ void MOABMesh::remove_scores() } void MOABMesh::set_score_data(const std::string& score, - const vector& values, - const vector& std_dev) + const vector& values, const vector& std_dev) { auto score_tags = this->get_score_tags(score); @@ -2084,7 +2834,8 @@ void MOABMesh::set_score_data(const std::string& score, rval = mbi_->tag_set_data(score_tags.first, ehs_, values.data()); if (rval != moab::MB_SUCCESS) { auto msg = fmt::format("Failed to set the tally value for score '{}' " - "on unstructured mesh {}", score, id_); + "on unstructured mesh {}", + score, id_); warning(msg); } @@ -2092,13 +2843,13 @@ void MOABMesh::set_score_data(const std::string& score, rval = mbi_->tag_set_data(score_tags.second, ehs_, std_dev.data()); if (rval != moab::MB_SUCCESS) { auto msg = fmt::format("Failed to set the tally error for score '{}' " - "on unstructured mesh {}", score, id_); + "on unstructured mesh {}", + score, id_); warning(msg); } } -void -MOABMesh::write(const std::string& base_filename) const +void MOABMesh::write(const std::string& base_filename) const { // add extension to the base name auto filename = base_filename + ".vtk"; @@ -2120,33 +2871,66 @@ MOABMesh::write(const std::string& base_filename) const #ifdef LIBMESH +const std::string LibMesh::mesh_lib_type = "libmesh"; + LibMesh::LibMesh(pugi::xml_node node) : UnstructuredMesh(node) { + // filename_ and length_multiplier_ will already be set by the + // UnstructuredMesh constructor + set_mesh_pointer_from_filename(filename_); + set_length_multiplier(length_multiplier_); initialize(); } -LibMesh::LibMesh(const std::string& filename) +// create the mesh from a pointer to a libMesh Mesh +LibMesh::LibMesh(libMesh::MeshBase& input_mesh, double length_multiplier) { - filename_ = filename; + m_ = &input_mesh; + set_length_multiplier(length_multiplier); + initialize(); +} + +// create the mesh from an input file +LibMesh::LibMesh(const std::string& filename, double length_multiplier) +{ + set_mesh_pointer_from_filename(filename); + set_length_multiplier(length_multiplier); initialize(); } +void LibMesh::set_mesh_pointer_from_filename(const std::string& filename) +{ + filename_ = filename; + unique_m_ = make_unique(*settings::libmesh_comm, n_dimension_); + m_ = unique_m_.get(); + m_->read(filename_); +} + +// intialize from mesh file void LibMesh::initialize() { if (!settings::libmesh_comm) { - fatal_error("Attempting to use an unstructured mesh without a libMesh communicator."); + fatal_error( + "Attempting to use an unstructured mesh without a libMesh communicator."); } // assuming that unstructured meshes used in OpenMC are 3D n_dimension_ = 3; - m_ = make_unique(*settings::libmesh_comm, n_dimension_); - m_->read(filename_); - m_->prepare_for_use(); + if (length_multiplier_ > 0.0) { + libMesh::MeshTools::Modification::scale(*m_, length_multiplier_); + } + // if OpenMC is managing the libMesh::MeshBase instance, prepare the mesh. + // Otherwise assume that it is prepared by its owning application + if (unique_m_) { + m_->prepare_for_use(); + } // ensure that the loaded mesh is 3 dimensional - if(m_->mesh_dimension() != n_dimension_) { - fatal_error(fmt::format("Mesh file {} specified for use in an unstructured mesh is not a 3D mesh.", filename_)); + if (m_->mesh_dimension() != n_dimension_) { + fatal_error(fmt::format("Mesh file {} specified for use in an unstructured " + "mesh is not a 3D mesh.", + filename_)); } // create an equation system for storing values @@ -2156,14 +2940,7 @@ void LibMesh::initialize() libMesh::ExplicitSystem& eq_sys = equation_systems_->add_system(eq_system_name_); - - #ifdef _OPENMP - int n_threads = omp_get_max_threads(); - #else - int n_threads = 1; - #endif - - for (int i = 0; i < n_threads; i++) { + for (int i = 0; i < num_threads(); i++) { pl_.emplace_back(m_->sub_point_locator()); pl_.back()->set_contains_point_tol(FP_COINCIDENT); pl_.back()->enable_out_of_mesh_mode(); @@ -2177,23 +2954,60 @@ void LibMesh::initialize() bbox_ = libMesh::MeshTools::create_bounding_box(*m_); } -Position -LibMesh::centroid(int bin) const +// Sample position within a tet for LibMesh type tets +Position LibMesh::sample_element(int32_t bin, uint64_t* seed) const +{ + const auto& elem = get_element_from_bin(bin); + // Get tet vertex coordinates from LibMesh + std::array tet_verts; + for (int i = 0; i < elem.n_nodes(); i++) { + auto node_ref = elem.node_ref(i); + tet_verts[i] = {node_ref(0), node_ref(1), node_ref(2)}; + } + // Samples position within tet using Barycentric coordinates + return this->sample_tet(tet_verts, seed); +} + +Position LibMesh::centroid(int bin) const { const auto& elem = this->get_element_from_bin(bin); - auto centroid = elem.centroid(); + auto centroid = elem.vertex_average(); return {centroid(0), centroid(1), centroid(2)}; } -std::string LibMesh::library() const { return "libmesh"; } +int LibMesh::n_vertices() const +{ + return m_->n_nodes(); +} + +Position LibMesh::vertex(int vertex_id) const +{ + const auto node_ref = m_->node_ref(vertex_id); + return {node_ref(0), node_ref(1), node_ref(2)}; +} + +std::vector LibMesh::connectivity(int elem_id) const +{ + std::vector conn; + const auto* elem_ptr = m_->elem_ptr(elem_id); + for (int i = 0; i < elem_ptr->n_nodes(); i++) { + conn.push_back(elem_ptr->node_id(i)); + } + return conn; +} + +std::string LibMesh::library() const +{ + return mesh_lib_type; +} int LibMesh::n_bins() const { return m_->n_elem(); } -int -LibMesh::n_surface_bins() const { +int LibMesh::n_surface_bins() const +{ int n_bins = 0; for (int i = 0; i < this->n_bins(); i++) { const libMesh::Elem& e = get_element_from_bin(i); @@ -2202,20 +3016,22 @@ LibMesh::n_surface_bins() const { // the number of surface bins is incremented to for (auto neighbor_ptr : e.neighbor_ptr_range()) { // null neighbor pointer indicates a boundary face - if (!neighbor_ptr) { n_bins++; } + if (!neighbor_ptr) { + n_bins++; + } } } return n_bins; } -void -LibMesh::add_score(const std::string& var_name) +void LibMesh::add_score(const std::string& var_name) { // check if this is a new variable std::string value_name = var_name + "_mean"; if (!variable_map_.count(value_name)) { auto& eqn_sys = equation_systems_->get_system(eq_system_name_); - auto var_num = eqn_sys.add_variable(value_name, libMesh::CONSTANT, libMesh::MONOMIAL); + auto var_num = + eqn_sys.add_variable(value_name, libMesh::CONSTANT, libMesh::MONOMIAL); variable_map_[value_name] = var_num; } @@ -2223,13 +3039,13 @@ LibMesh::add_score(const std::string& var_name) // check if this is a new variable if (!variable_map_.count(std_dev_name)) { auto& eqn_sys = equation_systems_->get_system(eq_system_name_); - auto var_num = eqn_sys.add_variable(std_dev_name, libMesh::CONSTANT, libMesh::MONOMIAL); + auto var_num = + eqn_sys.add_variable(std_dev_name, libMesh::CONSTANT, libMesh::MONOMIAL); variable_map_[std_dev_name] = var_num; } } -void -LibMesh::remove_scores() +void LibMesh::remove_scores() { auto& eqn_sys = equation_systems_->get_system(eq_system_name_); eqn_sys.clear(); @@ -2241,7 +3057,9 @@ void LibMesh::set_score_data(const std::string& var_name, { auto& eqn_sys = equation_systems_->get_system(eq_system_name_); - if (!eqn_sys.is_initialized()) { equation_systems_->init(); } + if (!eqn_sys.is_initialized()) { + equation_systems_->init(); + } const libMesh::DofMap& dof_map = eqn_sys.get_dof_map(); @@ -2252,7 +3070,8 @@ void LibMesh::set_score_data(const std::string& var_name, std::string std_dev_name = var_name + "_std_dev"; unsigned int std_dev_num = variable_map_.at(std_dev_name); - for (auto it = m_->local_elements_begin(); it != m_->local_elements_end(); it++) { + for (auto it = m_->local_elements_begin(); it != m_->local_elements_end(); + it++) { auto bin = get_bin_from_element(*it); // set value @@ -2271,46 +3090,38 @@ void LibMesh::set_score_data(const std::string& var_name, void LibMesh::write(const std::string& filename) const { - write_message(fmt::format("Writing file: {}.e for unstructured mesh {}", filename, this->id_)); + write_message(fmt::format( + "Writing file: {}.e for unstructured mesh {}", filename, this->id_)); libMesh::ExodusII_IO exo(*m_); std::set systems_out = {eq_system_name_}; - exo.write_discontinuous_exodusII(filename + ".e", *equation_systems_, &systems_out); + exo.write_discontinuous_exodusII( + filename + ".e", *equation_systems_, &systems_out); } -void -LibMesh::bins_crossed(Position r0, - Position r1, - const Direction& u, - vector& bins, - vector& lengths) const +void LibMesh::bins_crossed(Position r0, Position r1, const Direction& u, + vector& bins, vector& lengths) const { // TODO: Implement triangle crossings here fatal_error("Tracklength tallies on libMesh instances are not implemented."); } -int -LibMesh::get_bin(Position r) const +int LibMesh::get_bin(Position r) const { // look-up a tet using the point locator libMesh::Point p(r.x, r.y, r.z); // quick rejection check - if (!bbox_.contains_point(p)) { return -1; } - - #ifdef _OPENMP - int thread_num = omp_get_thread_num(); - #else - int thread_num = 0; - #endif + if (!bbox_.contains_point(p)) { + return -1; + } - const auto& point_locator = pl_.at(thread_num); + const auto& point_locator = pl_.at(thread_num()); const auto elem_ptr = (*point_locator)(p); return elem_ptr ? get_bin_from_element(elem_ptr) : -1; } -int -LibMesh::get_bin_from_element(const libMesh::Elem* elem) const +int LibMesh::get_bin_from_element(const libMesh::Elem* elem) const { int bin = elem->id() - first_element_id_; if (bin >= n_bins() || bin < 0) { @@ -2325,15 +3136,14 @@ std::pair, vector> LibMesh::plot( return {}; } -const libMesh::Elem& -LibMesh::get_element_from_bin(int bin) const +const libMesh::Elem& LibMesh::get_element_from_bin(int bin) const { return m_->elem_ref(bin); } double LibMesh::volume(int bin) const { - return m_->elem_ref(bin).volume(); + return this->get_element_from_bin(bin).volume(); } #endif // LIBMESH @@ -2344,7 +3154,25 @@ double LibMesh::volume(int bin) const void read_meshes(pugi::xml_node root) { + std::unordered_set mesh_ids; + for (auto node : root.children("mesh")) { + // Check to make sure multiple meshes in the same file don't share IDs + int id = std::stoi(get_node_value(node, "id")); + if (contains(mesh_ids, id)) { + fatal_error(fmt::format( + "Two or more meshes use the same unique ID '{}' in the same input file", + id)); + } + mesh_ids.insert(id); + + // If we've already read a mesh with the same ID in a *different* file, + // assume it is the same here + if (model::mesh_map.find(id) != model::mesh_map.end()) { + warning(fmt::format("Mesh with ID={} appears in multiple files.", id)); + continue; + } + std::string mesh_type; if (check_for_node(node, "type")) { mesh_type = get_node_value(node, "type", true, true); @@ -2359,20 +3187,27 @@ void read_meshes(pugi::xml_node root) } // Read mesh and add to vector - if (mesh_type == "regular") { + if (mesh_type == RegularMesh::mesh_type) { model::meshes.push_back(make_unique(node)); - } else if (mesh_type == "rectilinear") { + } else if (mesh_type == RectilinearMesh::mesh_type) { model::meshes.push_back(make_unique(node)); + } else if (mesh_type == CylindricalMesh::mesh_type) { + model::meshes.push_back(make_unique(node)); + } else if (mesh_type == SphericalMesh::mesh_type) { + model::meshes.push_back(make_unique(node)); #ifdef DAGMC - } else if (mesh_type == "unstructured" && mesh_lib == "moab") { + } else if (mesh_type == UnstructuredMesh::mesh_type && + mesh_lib == MOABMesh::mesh_lib_type) { model::meshes.push_back(make_unique(node)); #endif #ifdef LIBMESH - } else if (mesh_type == "unstructured" && mesh_lib == "libmesh") { + } else if (mesh_type == UnstructuredMesh::mesh_type && + mesh_lib == LibMesh::mesh_lib_type) { model::meshes.push_back(make_unique(node)); #endif - } else if (mesh_type == "unstructured") { - fatal_error("Unstructured mesh support is not enabled or the mesh library is invalid."); + } else if (mesh_type == UnstructuredMesh::mesh_type) { + fatal_error("Unstructured mesh support is not enabled or the mesh " + "library is invalid."); } else { fatal_error("Invalid mesh type: " + mesh_type); } @@ -2408,6 +3243,9 @@ void free_memory_mesh() model::mesh_map.clear(); } -extern "C" int n_meshes() { return model::meshes.size(); } +extern "C" int n_meshes() +{ + return model::meshes.size(); +} } // namespace openmc diff --git a/src/message_passing.cpp b/src/message_passing.cpp index f479d3db741..374c1aa7257 100644 --- a/src/message_passing.cpp +++ b/src/message_passing.cpp @@ -12,7 +12,31 @@ MPI_Comm intracomm {MPI_COMM_NULL}; MPI_Datatype source_site {MPI_DATATYPE_NULL}; #endif -extern "C" bool openmc_master() { return mpi::master; } +extern "C" bool openmc_master() +{ + return mpi::master; +} + +vector calculate_parallel_index_vector(int64_t size) +{ + vector result; + result.resize(n_procs + 1); + result[0] = 0; + +#ifdef OPENMC_MPI + + // Populate the result with cumulative sum of the number of + // surface source banks per process + int64_t scan_total; + MPI_Scan(&size, &scan_total, 1, MPI_INT64_T, MPI_SUM, intracomm); + MPI_Allgather( + &scan_total, 1, MPI_INT64_T, result.data() + 1, 1, MPI_INT64_T, intracomm); +#else + result[1] = size; +#endif + + return result; +} } // namespace mpi diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 00263b5410b..9eae5a7da7f 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -1,19 +1,15 @@ #include "openmc/mgxs.h" +#include #include #include -#include #include -#ifdef _OPENMP -#include -#endif - -#include +#include "xtensor/xadapt.hpp" #include "xtensor/xmath.hpp" #include "xtensor/xsort.hpp" -#include "xtensor/xadapt.hpp" #include "xtensor/xview.hpp" +#include #include "openmc/error.h" #include "openmc/math_functions.h" @@ -22,7 +18,6 @@ #include "openmc/settings.h" #include "openmc/string_utils.h" - namespace openmc { //============================================================================== @@ -37,7 +32,7 @@ void Mgxs::init(const std::string& in_name, double in_awr, // Set the metadata name = in_name; awr = in_awr; - //TODO: Remove adapt when in_KTs is an xtensor + // TODO: Remove adapt when in_KTs is an xtensor kTs = xt::adapt(in_kTs); fissionable = in_fissionable; scatter_format = in_scatter_format; @@ -47,15 +42,6 @@ void Mgxs::init(const std::string& in_name, double in_awr, n_azi = in_azimuthal.size(); polar = in_polar; azimuthal = in_azimuthal; - - // Set the cross section index cache -#ifdef _OPENMP - int n_threads = omp_get_max_threads(); -#else - int n_threads = 1; -#endif - cache.resize(n_threads); - // vector.resize() will value-initialize the members of cache[:] } //============================================================================== @@ -64,9 +50,8 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, vector& temps_to_read, int& order_dim) { // get name - char char_name[MAX_WORD_LEN]; - get_name(xs_id, char_name); - std::string in_name {char_name}; + std::string in_name; + get_name(xs_id, in_name); // remove the leading '/' in_name = in_name.substr(1); @@ -102,57 +87,56 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, // If only one temperature is available, lets just use nearest temperature // interpolation - if ((num_temps == 1) && (settings::temperature_method == TemperatureMethod::INTERPOLATION)) { + if ((num_temps == 1) && + (settings::temperature_method == TemperatureMethod::INTERPOLATION)) { warning("Cross sections for " + strtrim(name) + " are only available " + "at one temperature. Reverting to the nearest temperature " + "method."); settings::temperature_method = TemperatureMethod::NEAREST; } - switch(settings::temperature_method) { - case TemperatureMethod::NEAREST: - // Determine actual temperatures to read - for (const auto& T : temperature) { - auto i_closest = xt::argmin(xt::abs(available_temps - T))[0]; - double temp_actual = available_temps[i_closest]; - if (std::fabs(temp_actual - T) < settings::temperature_tolerance) { - if (std::find(temps_to_read.begin(), temps_to_read.end(), std::round(temp_actual)) - == temps_to_read.end()) { - temps_to_read.push_back(std::round(temp_actual)); - } - } else { - fatal_error(fmt::format( - "MGXS library does not contain cross sections for {} at or near {} K.", - in_name, std::round(T))); + switch (settings::temperature_method) { + case TemperatureMethod::NEAREST: + // Determine actual temperatures to read + for (const auto& T : temperature) { + auto i_closest = xt::argmin(xt::abs(available_temps - T))[0]; + double temp_actual = available_temps[i_closest]; + if (std::fabs(temp_actual - T) < settings::temperature_tolerance) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), + std::round(temp_actual)) == temps_to_read.end()) { + temps_to_read.push_back(std::round(temp_actual)); } + } else { + fatal_error(fmt::format("MGXS library does not contain cross sections " + "for {} at or near {} K.", + in_name, std::round(T))); } - break; - - case TemperatureMethod::INTERPOLATION: - for (int i = 0; i < temperature.size(); i++) { - for (int j = 0; j < num_temps; j++) { - if (j == (num_temps - 1)) { - fatal_error("MGXS Library does not contain cross sections for " + - in_name + " at temperatures that bound " + - std::to_string(std::round(temperature[i]))); + } + break; + + case TemperatureMethod::INTERPOLATION: + for (int i = 0; i < temperature.size(); i++) { + for (int j = 0; j < num_temps; j++) { + if (j == (num_temps - 1)) { + fatal_error("MGXS Library does not contain cross sections for " + + in_name + " at temperatures that bound " + + std::to_string(std::round(temperature[i]))); + } + if ((available_temps[j] <= temperature[i]) && + (temperature[i] < available_temps[j + 1])) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), + std::round(available_temps[j])) == temps_to_read.end()) { + temps_to_read.push_back(std::round((int)available_temps[j])); } - if ((available_temps[j] <= temperature[i]) && - (temperature[i] < available_temps[j + 1])) { - if (std::find(temps_to_read.begin(), - temps_to_read.end(), - std::round(available_temps[j])) == temps_to_read.end()) { - temps_to_read.push_back(std::round((int)available_temps[j])); - } - if (std::find(temps_to_read.begin(), temps_to_read.end(), - std::round(available_temps[j + 1])) == temps_to_read.end()) { - temps_to_read.push_back(std::round((int) available_temps[j + 1])); - } - break; + if (std::find(temps_to_read.begin(), temps_to_read.end(), + std::round(available_temps[j + 1])) == temps_to_read.end()) { + temps_to_read.push_back(std::round((int)available_temps[j + 1])); } + break; } - } + } } std::sort(temps_to_read.begin(), temps_to_read.end()); @@ -162,7 +146,7 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, for (int i = 0; i < n_temperature; i++) { std::string temp_str(std::to_string(temps_to_read[i]) + "K"); - //read exact temperature value + // read exact temperature value read_double(kT_group, temp_str.c_str(), &in_kTs[i], true); } close_group(kT_group); @@ -170,8 +154,8 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, // Load the remaining metadata AngleDistributionType in_scatter_format; if (attribute_exists(xs_id, "scatter_format")) { - std::string temp_str(MAX_WORD_LEN, ' '); - read_attr_string(xs_id, "scatter_format", MAX_WORD_LEN, &temp_str[0]); + std::string temp_str; + read_attribute(xs_id, "scatter_format", temp_str); to_lower(strtrim(temp_str)); if (temp_str.compare(0, 8, "legendre") == 0) { in_scatter_format = AngleDistributionType::LEGENDRE; @@ -187,8 +171,8 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, } if (attribute_exists(xs_id, "scatter_shape")) { - std::string temp_str(MAX_WORD_LEN, ' '); - read_attr_string(xs_id, "scatter_shape", MAX_WORD_LEN, &temp_str[0]); + std::string temp_str; + read_attribute(xs_id, "scatter_shape", temp_str); to_lower(strtrim(temp_str)); if (temp_str.compare(0, 14, "[g][g\'][order]") != 0) { fatal_error("Invalid scatter_shape option!"); @@ -225,8 +209,8 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, int in_n_azi; bool in_is_isotropic = true; if (attribute_exists(xs_id, "representation")) { - std::string temp_str(MAX_WORD_LEN, ' '); - read_attr_string(xs_id, "representation", MAX_WORD_LEN, &temp_str[0]); + std::string temp_str; + read_attribute(xs_id, "representation", temp_str); to_lower(strtrim(temp_str)); if (temp_str.compare(0, 5, "angle") == 0) { in_is_isotropic = false; @@ -255,7 +239,7 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, vector in_polar(in_n_pol); double dangle = PI / in_n_pol; for (int p = 0; p < in_n_pol; p++) { - in_polar[p] = (p + 0.5) * dangle; + in_polar[p] = (p + 0.5) * dangle; } vector in_azimuthal(in_n_azi); dangle = 2. * PI / in_n_azi; @@ -265,8 +249,7 @@ void Mgxs::metadata_from_hdf5(hid_t xs_id, const vector& temperature, // Finally use this data to initialize the MGXS Object init(in_name, in_awr, in_kTs, in_fissionable, in_scatter_format, - in_is_isotropic, in_polar, - in_azimuthal); + in_is_isotropic, in_polar, in_azimuthal); } //============================================================================== @@ -283,19 +266,20 @@ Mgxs::Mgxs( // Set number of energy and delayed groups AngleDistributionType final_scatter_format = scatter_format; if (settings::legendre_to_tabular) { - if (scatter_format == AngleDistributionType::LEGENDRE) final_scatter_format = AngleDistributionType::TABULAR; + if (scatter_format == AngleDistributionType::LEGENDRE) + final_scatter_format = AngleDistributionType::TABULAR; } // Load the more specific XsData information for (int t = 0; t < temps_to_read.size(); t++) { - xs[t] = XsData(fissionable, final_scatter_format, n_pol, n_azi, - num_groups, num_delayed_groups); + xs[t] = XsData(fissionable, final_scatter_format, n_pol, n_azi, num_groups, + num_delayed_groups); // Get the temperature as a string and then open the HDF5 group std::string temp_str = std::to_string(temps_to_read[t]) + "K"; hid_t xsdata_grp = open_group(xs_id, temp_str.c_str()); xs[t].from_hdf5(xsdata_grp, fissionable, scatter_format, - final_scatter_format, order_data, is_isotropic, n_pol, n_azi); + final_scatter_format, order_data, is_isotropic, n_pol, n_azi); close_group(xsdata_grp); } // end temperature loop @@ -318,7 +302,8 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, // the fissionable status if we learn differently bool in_fissionable = false; for (int m = 0; m < micros.size(); m++) { - if (micros[m]->fissionable) in_fissionable = true; + if (micros[m]->fissionable) + in_fissionable = true; } // Force all of the following data to be the same; these will be verified // to be true later @@ -328,7 +313,7 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, vector in_azimuthal = micros[0]->azimuthal; init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format, - in_is_isotropic, in_polar, in_azimuthal); + in_is_isotropic, in_polar, in_azimuthal); // Create the xs data for each temperature for (int t = 0; t < mat_kTs.size(); t++) { @@ -343,19 +328,18 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, vector micro_t(micros.size(), 0); vector micro_t_interp(micros.size(), 0.); for (int m = 0; m < micros.size(); m++) { - switch(settings::temperature_method) { - case TemperatureMethod::NEAREST: - { - micro_t[m] = xt::argmin(xt::abs(micros[m]->kTs - temp_desired))[0]; - auto temp_actual = micros[m]->kTs[micro_t[m]]; - - if (std::abs(temp_actual - temp_desired) >= K_BOLTZMANN * settings::temperature_tolerance) { - fatal_error(fmt::format( - "MGXS Library does not contain cross section for {} at or near {} K.", - name, std::round(temp_desired / K_BOLTZMANN))); - } + switch (settings::temperature_method) { + case TemperatureMethod::NEAREST: { + micro_t[m] = xt::argmin(xt::abs(micros[m]->kTs - temp_desired))[0]; + auto temp_actual = micros[m]->kTs[micro_t[m]]; + + if (std::abs(temp_actual - temp_desired) >= + K_BOLTZMANN * settings::temperature_tolerance) { + fatal_error(fmt::format("MGXS Library does not contain cross section " + "for {} at or near {} K.", + name, std::round(temp_desired / K_BOLTZMANN))); } - break; + } break; case TemperatureMethod::INTERPOLATION: // Get a list of bounding temperatures for each actual temperature // present in the model @@ -365,14 +349,14 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, micro_t[m] = k; if (k == 0) { micro_t_interp[m] = (temp_desired - micros[m]->kTs[k]) / - (micros[m]->kTs[k + 1] - micros[m]->kTs[k]); + (micros[m]->kTs[k + 1] - micros[m]->kTs[k]); } else { micro_t_interp[m] = 1.; } } } } // end switch - } // end microscopic temperature loop + } // end microscopic temperature loop // Now combine the microscopic data at each relevant temperature // We will do this by treating the multiple temperatures of a nuclide as @@ -410,7 +394,6 @@ Mgxs::Mgxs(const std::string& in_name, const vector& mat_kTs, // And finally, combine the data combine(mgxs_to_combine, interpolant, temp_indices, t); } // end temperature (t) loop - } //============================================================================== @@ -429,21 +412,12 @@ void Mgxs::combine(const vector& micros, const vector& scalars, //============================================================================== -double -Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, - const int* dg) +double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, + const int* dg, int t, int a) { - // This method assumes that the temperature and angle indices are set -#ifdef _OPENMP - int tid = omp_get_thread_num(); - XsData* xs_t = &xs[cache[tid].t]; - int a = cache[tid].a; -#else - XsData* xs_t = &xs[cache[0].t]; - int a = cache[0].a; -#endif + XsData* xs_t = &xs[t]; double val; - switch(xstype) { + switch (xstype) { case MgxsType::TOTAL: val = xs_t->total(a, gin); break; @@ -451,7 +425,8 @@ Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, val = fissionable ? xs_t->nu_fission(a, gin) : 0.; break; case MgxsType::ABSORPTION: - val = xs_t->absorption(a, gin);; + val = xs_t->absorption(a, gin); + ; break; case MgxsType::FISSION: val = fissionable ? xs_t->fission(a, gin) : 0.; @@ -490,7 +465,7 @@ Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, // provide an outgoing group-wise sum val = 0.; for (int g = 0; g < xs_t->chi_prompt.shape()[2]; g++) { - val += xs_t->chi_prompt(a, gin, g); + val += xs_t->chi_prompt(a, gin, g); } } } else { @@ -515,7 +490,7 @@ Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, val = 0.; for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { for (int d = 0; d < xs_t->delayed_nu_fission.shape()[3]; d++) { - val += xs_t->delayed_nu_fission(a, d, gin, g); + val += xs_t->delayed_nu_fission(a, d, gin, g); } } } @@ -542,20 +517,14 @@ Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, //============================================================================== -void -Mgxs::sample_fission_energy(int gin, int& dg, int& gout, uint64_t* seed) +void Mgxs::sample_fission_energy( + int gin, int& dg, int& gout, uint64_t* seed, int t, int a) { - // This method assumes that the temperature and angle indices are set -#ifdef _OPENMP - int tid = omp_get_thread_num(); -#else - int tid = 0; -#endif - XsData* xs_t = &xs[cache[tid].t]; - double nu_fission = xs_t->nu_fission(cache[tid].a, gin); + XsData* xs_t = &xs[t]; + double nu_fission = xs_t->nu_fission(a, gin); // Find the probability of having a prompt neutron - double prob_prompt = xs_t->prompt_nu_fission(cache[tid].a, gin); + double prob_prompt = xs_t->prompt_nu_fission(a, gin); // sample random numbers double xi_pd = prn(seed) * nu_fission; @@ -571,8 +540,9 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout, uint64_t* seed) // sample the outgoing energy group double prob_gout = 0.; for (gout = 0; gout < num_groups; ++gout) { - prob_gout += xs_t->chi_prompt(cache[tid].a, gin, gout); - if (xi_gout < prob_gout) break; + prob_gout += xs_t->chi_prompt(a, gin, gout); + if (xi_gout < prob_gout) + break; } } else { @@ -580,8 +550,9 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout, uint64_t* seed) // get the delayed group for (dg = 0; dg < num_delayed_groups; ++dg) { - prob_prompt += xs_t->delayed_nu_fission(cache[tid].a, dg, gin); - if (xi_pd < prob_prompt) break; + prob_prompt += xs_t->delayed_nu_fission(a, dg, gin); + if (xi_pd < prob_prompt) + break; } // adjust dg in case of round-off error @@ -590,92 +561,86 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout, uint64_t* seed) // sample the outgoing energy group double prob_gout = 0.; for (gout = 0; gout < num_groups; ++gout) { - prob_gout += xs_t->chi_delayed(cache[tid].a, dg, gin, gout); - if (xi_gout < prob_gout) break; + prob_gout += xs_t->chi_delayed(a, dg, gin, gout); + if (xi_gout < prob_gout) + break; } } } //============================================================================== -void -Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt, uint64_t* seed) +void Mgxs::sample_scatter( + int gin, int& gout, double& mu, double& wgt, uint64_t* seed, int t, int a) { - // This method assumes that the temperature and angle indices are set // Sample the data -#ifdef _OPENMP - int tid = omp_get_thread_num(); -#else - int tid = 0; -#endif - xs[cache[tid].t].scatter[cache[tid].a]->sample(gin, gout, mu, wgt, seed); + xs[t].scatter[a]->sample(gin, gout, mu, wgt, seed); } //============================================================================== -void -Mgxs::calculate_xs(Particle& p) +void Mgxs::calculate_xs(Particle& p) { - // Set our indices -#ifdef _OPENMP - int tid = omp_get_thread_num(); -#else - int tid = 0; -#endif - set_temperature_index(p.sqrtkT()); - set_angle_index(p.u_local()); - XsData* xs_t = &xs[cache[tid].t]; - p.macro_xs().total = xs_t->total(cache[tid].a, p.g()); - p.macro_xs().absorption = xs_t->absorption(cache[tid].a, p.g()); + // If the material is different, then we need to do a full lookup + if (p.material() != p.mg_xs_cache().material) { + set_temperature_index(p); + set_angle_index(p); + p.mg_xs_cache().material = p.material(); + } else { + // If material is the same, but temperature is different, need to + // find the new temperature index + if (p.sqrtkT() != p.mg_xs_cache().sqrtkT) { + set_temperature_index(p); + } + // If the material is the same, but angle is different, need to + // find the new angle index + if (p.u_local() != p.mg_xs_cache().u) { + set_angle_index(p); + } + } + int temperature = p.mg_xs_cache().t; + int angle = p.mg_xs_cache().a; + p.macro_xs().total = xs[temperature].total(angle, p.g()); + p.macro_xs().absorption = xs[temperature].absorption(angle, p.g()); p.macro_xs().nu_fission = - fissionable ? xs_t->nu_fission(cache[tid].a, p.g()) : 0.; + fissionable ? xs[temperature].nu_fission(angle, p.g()) : 0.; } //============================================================================== -bool -Mgxs::equiv(const Mgxs& that) +bool Mgxs::equiv(const Mgxs& that) { - return ((num_delayed_groups == that.num_delayed_groups) && - (num_groups == that.num_groups) && - (n_pol == that.n_pol) && - (n_azi == that.n_azi) && - (std::equal(polar.begin(), polar.end(), that.polar.begin())) && - (std::equal(azimuthal.begin(), azimuthal.end(), that.azimuthal.begin())) && - (scatter_format == that.scatter_format)); + return ( + (num_delayed_groups == that.num_delayed_groups) && + (num_groups == that.num_groups) && (n_pol == that.n_pol) && + (n_azi == that.n_azi) && + (std::equal(polar.begin(), polar.end(), that.polar.begin())) && + (std::equal(azimuthal.begin(), azimuthal.end(), that.azimuthal.begin())) && + (scatter_format == that.scatter_format)); } //============================================================================== -void -Mgxs::set_temperature_index(double sqrtkT) +int Mgxs::get_temperature_index(double sqrtkT) const { - // See if we need to find the new index -#ifdef _OPENMP - int tid = omp_get_thread_num(); -#else - int tid = 0; -#endif - if (sqrtkT != cache[tid].sqrtkT) { - cache[tid].t = xt::argmin(xt::abs(kTs - sqrtkT * sqrtkT))[0]; - cache[tid].sqrtkT = sqrtkT; - } + return xt::argmin(xt::abs(kTs - sqrtkT * sqrtkT))[0]; } //============================================================================== -void -Mgxs::set_angle_index(Direction u) +void Mgxs::set_temperature_index(Particle& p) { - // See if we need to find the new index -#ifdef _OPENMP - int tid = omp_get_thread_num(); -#else - int tid = 0; -#endif - if (!is_isotropic && - ((u.x != cache[tid].u) || (u.y != cache[tid].v) || - (u.z != cache[tid].w))) { + p.mg_xs_cache().t = get_temperature_index(p.sqrtkT()); + p.mg_xs_cache().sqrtkT = p.sqrtkT(); +} + +//============================================================================== + +int Mgxs::get_angle_index(const Direction& u) const +{ + if (is_isotropic) { + return 0; + } else { // convert direction to polar and azimuthal angles double my_pol = std::acos(u.z); double my_azi = std::atan2(u.y, u.x); @@ -686,12 +651,18 @@ Mgxs::set_angle_index(Direction u) delta_angle = 2. * PI / n_azi; int a = std::floor((my_azi + PI) / delta_angle); - cache[tid].a = n_azi * p + a; + return n_azi * p + a; + } +} + +//============================================================================== - // store this direction as the last one used - cache[tid].u = u.x; - cache[tid].v = u.y; - cache[tid].w = u.z; +void Mgxs::set_angle_index(Particle& p) +{ + // See if we need to find the new index + if (!is_isotropic) { + p.mg_xs_cache().a = get_angle_index(p.u_local()); + p.mg_xs_cache().u = p.u_local(); } } diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 227896d800c..d54211ecaf1 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -6,8 +6,8 @@ #include #include "openmc/cell.h" -#include "openmc/cross_sections.h" #include "openmc/container_util.h" +#include "openmc/cross_sections.h" #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/geometry_aux.h" @@ -17,7 +17,6 @@ #include "openmc/nuclide.h" #include "openmc/settings.h" - namespace openmc { //============================================================================== @@ -25,7 +24,7 @@ namespace openmc { //============================================================================== namespace data { - MgxsInterface mg; +MgxsInterface mg; } MgxsInterface::MgxsInterface(const std::string& path_cross_sections, @@ -57,7 +56,8 @@ void MgxsInterface::init() // Check if MGXS Library exists if (!file_exists(cross_sections_path_)) { // Could not find MGXS Library file - fatal_error(fmt::format("Cross sections HDF5 file '{}' does not exist!", cross_sections_path_)); + fatal_error(fmt::format( + "Cross sections HDF5 file '{}' does not exist!", cross_sections_path_)); } write_message("Loading cross section data...", 5); @@ -78,12 +78,12 @@ void MgxsInterface::init() read_attribute(file_id, "version", array); if (array != VERSION_MGXS_LIBRARY) { fatal_error("MGXS Library file version does not match current version " - "supported by OpenMC."); + "supported by OpenMC."); } // ========================================================================== // READ ALL MGXS CROSS SECTION TABLES - for (unsigned i_nuc=0; i_nucnuclide_[0]]) dictates type(macroxs). // At the same time, we will find the scattering type, as that will dictate // how we allocate the scatter object within macroxs. + for (int i = 0; i < model::materials.size(); ++i) { + // First we have to normalize the densities as it has not been called yet + // for MG mode + auto& mat {model::materials[i]}; + mat->finalize(); if (kTs[i].size() > 0) { // Convert atom_densities to a vector - auto& mat {model::materials[i]}; vector atom_densities( mat->atom_density_.begin(), mat->atom_density_.end()); @@ -137,7 +142,7 @@ void MgxsInterface::create_macro_xs() } macro_xs_.emplace_back(mat->name_, kTs[i], mgxs_ptr, atom_densities, - num_energy_groups_, num_delayed_groups_); + num_energy_groups_, num_delayed_groups_); } else { // Preserve the ordering of materials by including a blank entry macro_xs_.emplace_back(); @@ -153,16 +158,18 @@ vector> MgxsInterface::get_mat_kTs() for (const auto& cell : model::cells) { // Skip non-material cells - if (cell->fill_ != C_NONE) continue; + if (cell->fill_ != C_NONE) + continue; for (int j = 0; j < cell->material_.size(); ++j) { // Skip void materials int i_material = cell->material_[j]; - if (i_material == MATERIAL_VOID) continue; + if (i_material == MATERIAL_VOID) + continue; // Get temperature of cell (rounding to nearest integer) - double sqrtkT = cell->sqrtkT_.size() == 1 ? - cell->sqrtkT_[j] : cell->sqrtkT_[0]; + double sqrtkT = + cell->sqrtkT_.size() == 1 ? cell->sqrtkT_[j] : cell->sqrtkT_[0]; double kT = sqrtkT * sqrtkT; // Add temperature if it hasn't already been added @@ -184,7 +191,8 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) // Check if MGXS Library exists if (!file_exists(cross_sections_path_)) { // Could not find MGXS Library file - fatal_error(fmt::format("Cross section HDF5 file '{}' does not exist", cross_sections_path_)); + fatal_error(fmt::format( + "Cross section HDF5 file '{}' does not exist", cross_sections_path_)); } write_message("Reading cross sections HDF5 file...", 5); @@ -209,15 +217,14 @@ void MgxsInterface::read_header(const std::string& path_cross_sections) // Create average energies for (int i = 0; i < energy_bins_.size() - 1; ++i) { - energy_bin_avg_.push_back(0.5* - (energy_bins_[i] + energy_bins_[i+1])); + energy_bin_avg_.push_back(0.5 * (energy_bins_[i] + energy_bins_[i + 1])); } // Add entries into libraries for MG data xs_names_ = group_names(file_id); if (xs_names_.empty()) { fatal_error("At least one MGXS data set must be present in mgxs " - "library file!"); + "library file!"); } // Close MGXS HDF5 file @@ -277,7 +284,7 @@ void mark_fissionable_mgxs_materials() for (const auto& mat : model::materials) { for (int i_nuc : mat->nuclide_) { if (data::mg.nuclides_[i_nuc].fissionable) { - mat->fissionable_ = true; + mat->fissionable() = true; } } } diff --git a/src/ncrystal_interface.cpp b/src/ncrystal_interface.cpp new file mode 100644 index 00000000000..b39f62d9020 --- /dev/null +++ b/src/ncrystal_interface.cpp @@ -0,0 +1,108 @@ +#include "openmc/ncrystal_interface.h" + +#include "openmc/error.h" +#include "openmc/material.h" +#include "openmc/random_lcg.h" + +namespace openmc { + +//============================================================================== +// Constants +//============================================================================== + +#ifdef NCRYSTAL +const bool NCRYSTAL_ENABLED = true; +#else +const bool NCRYSTAL_ENABLED = false; +#endif + +//============================================================================== +// NCrystal wrapper class for the OpenMC random number generator +//============================================================================== + +#ifdef NCRYSTAL +class NCrystalRNGWrapper : public NCrystal::RNGStream { +public: + constexpr NCrystalRNGWrapper(uint64_t* seed) noexcept : openmc_seed_(seed) {} + +protected: + double actualGenerate() override + { + return std::max( + std::numeric_limits::min(), prn(openmc_seed_)); + } + +private: + uint64_t* openmc_seed_; +}; +#endif + +//============================================================================== +// NCrystal implementation +//============================================================================== + +NCrystalMat::NCrystalMat(const std::string& cfg) +{ +#ifdef NCRYSTAL + cfg_ = cfg; + ptr_ = NCrystal::FactImpl::createScatter(cfg); +#else + fatal_error("Your build of OpenMC does not support NCrystal materials."); +#endif +} + +#ifdef NCRYSTAL +std::string NCrystalMat::cfg() const +{ + return cfg_; +} + +double NCrystalMat::xs(const Particle& p) const +{ + // Calculate scattering XS per atom with NCrystal, only once per material + NCrystal::CachePtr dummy_cache; + auto nc_energy = NCrystal::NeutronEnergy {p.E()}; + return ptr_->crossSection(dummy_cache, nc_energy, {p.u().x, p.u().y, p.u().z}) + .get(); +} + +void NCrystalMat::scatter(Particle& p) const +{ + NCrystalRNGWrapper rng(p.current_seed()); // Initialize RNG + // create a cache pointer for multi thread physics + NCrystal::CachePtr dummy_cache; + auto nc_energy = NCrystal::NeutronEnergy {p.E()}; + auto outcome = ptr_->sampleScatter( + dummy_cache, rng, nc_energy, {p.u().x, p.u().y, p.u().z}); + + // Modify attributes of particle + p.E() = outcome.ekin.get(); + Direction u_old {p.u()}; + p.u() = + Direction(outcome.direction[0], outcome.direction[1], outcome.direction[2]); + p.mu() = u_old.dot(p.u()); + p.event_mt() = ELASTIC; +} + +NCrystalMat::operator bool() const +{ + return ptr_.get(); +} +#endif + +//============================================================================== +// Functions +//============================================================================== + +void ncrystal_update_micro(double xs, NuclideMicroXS& micro) +{ + if (micro.thermal > 0 || micro.thermal_elastic > 0) { + fatal_error("S(a,b) treatment and NCrystal are not compatible."); + } + // remove free atom cross section + // and replace it by scattering cross section per atom from NCrystal + micro.total = micro.total - micro.elastic + xs; + micro.elastic = xs; +} + +} // namespace openmc diff --git a/src/nuclide.cpp b/src/nuclide.cpp index a7eff14f95e..91adc077799 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -21,7 +21,7 @@ #include "xtensor/xview.hpp" #include // for sort, min_element -#include // for to_string, stoi +#include // for to_string, stoi namespace openmc { @@ -62,6 +62,10 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) read_attribute(group, "metastable", metastable_); read_attribute(group, "atomic_weight_ratio", awr_); + if (settings::run_mode == RunMode::VOLUME) { + return; + } + // Determine temperatures available hid_t kT_group = open_group(group, "kTs"); auto dset_names = dataset_names(kT_group); @@ -74,10 +78,12 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) std::sort(temps_available.begin(), temps_available.end()); // If only one temperature is available, revert to nearest temperature - if (temps_available.size() == 1 && settings::temperature_method == TemperatureMethod::INTERPOLATION) { + if (temps_available.size() == 1 && + settings::temperature_method == TemperatureMethod::INTERPOLATION) { if (mpi::master) { - warning("Cross sections for " + name_ + " are only available at one " - "temperature. Reverting to nearest temperature method."); + warning("Cross sections for " + name_ + + " are only available at one " + "temperature. Reverting to nearest temperature method."); } settings::temperature_method = TemperatureMethod::NEAREST; } @@ -92,12 +98,16 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) double T_max = n > 0 ? settings::temperature_range[1] : INFTY; if (T_max > 0.0) { // Determine first available temperature below or equal to T_min - auto T_min_it = std::upper_bound(temps_available.begin(), temps_available.end(), T_min); - if (T_min_it != temps_available.begin()) --T_min_it; + auto T_min_it = + std::upper_bound(temps_available.begin(), temps_available.end(), T_min); + if (T_min_it != temps_available.begin()) + --T_min_it; // Determine first available temperature above or equal to T_max - auto T_max_it = std::lower_bound(temps_available.begin(), temps_available.end(), T_max); - if (T_max_it != temps_available.end()) ++T_max_it; + auto T_max_it = + std::lower_bound(temps_available.begin(), temps_available.end(), T_max); + if (T_max_it != temps_available.end()) + ++T_max_it; // Add corresponding temperatures to vector for (auto it = T_min_it; it != T_max_it; ++it) { @@ -126,15 +136,18 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) temps_to_read.push_back(std::round(T_actual)); // Write warning for resonance scattering data if 0K is not available - if (std::abs(T_actual - T_desired) > 0 && T_desired == 0 && mpi::master) { - warning(name_ + " does not contain 0K data needed for resonance " - "scattering options selected. Using data at " + std::to_string(T_actual) - + " K instead."); + if (std::abs(T_actual - T_desired) > 0 && T_desired == 0 && + mpi::master) { + warning(name_ + + " does not contain 0K data needed for resonance " + "scattering options selected. Using data at " + + std::to_string(T_actual) + " K instead."); } } } else { - fatal_error("Nuclear data library does not contain cross sections for " + - name_ + " at or near " + std::to_string(T_desired) + " K."); + fatal_error( + "Nuclear data library does not contain cross sections for " + name_ + + " at or near " + std::to_string(T_desired) + " K."); } } break; @@ -145,9 +158,10 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) for (double T_desired : temperature) { bool found_pair = false; for (int j = 0; j < temps_available.size() - 1; ++j) { - if (temps_available[j] <= T_desired && T_desired < temps_available[j + 1]) { + if (temps_available[j] <= T_desired && + T_desired < temps_available[j + 1]) { int T_j = std::round(temps_available[j]); - int T_j1 = std::round(temps_available[j+1]); + int T_j1 = std::round(temps_available[j + 1]); if (!contains(temps_to_read, T_j)) { temps_to_read.push_back(T_j); } @@ -159,8 +173,25 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) } if (!found_pair) { - fatal_error("Nuclear data library does not contain cross sections for " + - name_ +" at temperatures that bound " + std::to_string(T_desired) + " K."); + // If no pairs found, check if the desired temperature falls just + // outside of data + if (std::abs(T_desired - temps_available.front()) <= + settings::temperature_tolerance) { + if (!contains(temps_to_read, temps_available.front())) { + temps_to_read.push_back(std::round(temps_available.front())); + } + continue; + } + if (std::abs(T_desired - temps_available.back()) <= + settings::temperature_tolerance) { + if (!contains(temps_to_read, temps_available.back())) { + temps_to_read.push_back(std::round(temps_available.back())); + } + continue; + } + fatal_error( + "Nuclear data library does not contain cross sections for " + name_ + + " at temperatures that bound " + std::to_string(T_desired) + " K."); } } break; @@ -236,7 +267,7 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) close_group(urr_group); // Check for negative values - if (xt::any(urr_data_[i].prob_ < 0.) && mpi::master) { + if (urr_data_[i].has_negative() && mpi::master) { warning("Negative value(s) found on probability table for nuclide " + name_ + " at " + temp_str); } @@ -248,14 +279,15 @@ Nuclide::Nuclide(hid_t group, const vector& temperature) if (temps_to_read.size() > 0) { // Make sure inelastic flags are consistent for different temperatures for (int i = 0; i < urr_data_.size() - 1; ++i) { - if (urr_data_[i].inelastic_flag_ != urr_data_[i+1].inelastic_flag_) { - fatal_error(fmt::format("URR inelastic flag is not consistent for " + if (urr_data_[i].inelastic_flag_ != urr_data_[i + 1].inelastic_flag_) { + fatal_error(fmt::format( + "URR inelastic flag is not consistent for " "multiple temperatures in nuclide {}. This most likely indicates " - "a problem in how the data was processed.", name_)); + "a problem in how the data was processed.", + name_)); } } - if (urr_data_[0].inelastic_flag_ > 0) { for (int i = 0; i < reactions_.size(); i++) { if (reactions_[i]->mt_ == urr_data_[0].inelastic_flag_) { @@ -306,7 +338,8 @@ Nuclide::~Nuclide() data::nuclide_map.erase(name_); } -void Nuclide::create_derived(const Function1D* prompt_photons, const Function1D* delayed_photons) +void Nuclide::create_derived( + const Function1D* prompt_photons, const Function1D* delayed_photons) { for (const auto& grid : grid_) { // Allocate and initialize cross section @@ -328,9 +361,9 @@ void Nuclide::create_derived(const Function1D* prompt_photons, const Function1D* for (const auto& p : rx->products_) { if (p.particle_ == ParticleType::photon) { - auto pprod = xt::view(xs_[t], xt::range(j, j+n), XS_PHOTON_PROD); + auto pprod = xt::view(xs_[t], xt::range(j, j + n), XS_PHOTON_PROD); for (int k = 0; k < n; ++k) { - double E = grid_[t].energy[k+j]; + double E = grid_[t].energy[k + j]; // For fission, artificially increase the photon yield to account // for delayed photons @@ -340,7 +373,7 @@ void Nuclide::create_derived(const Function1D* prompt_photons, const Function1D* if (prompt_photons && delayed_photons) { double energy_prompt = (*prompt_photons)(E); double energy_delayed = (*delayed_photons)(E); - f = (energy_prompt + energy_delayed)/(energy_prompt); + f = (energy_prompt + energy_delayed) / (energy_prompt); } } } @@ -351,28 +384,30 @@ void Nuclide::create_derived(const Function1D* prompt_photons, const Function1D* } // Skip redundant reactions - if (rx->redundant_) continue; + if (rx->redundant_) + continue; // Add contribution to total cross section - auto total = xt::view(xs_[t], xt::range(j,j+n), XS_TOTAL); + auto total = xt::view(xs_[t], xt::range(j, j + n), XS_TOTAL); total += xs; // Add contribution to absorption cross section - auto absorption = xt::view(xs_[t], xt::range(j,j+n), XS_ABSORPTION); + auto absorption = xt::view(xs_[t], xt::range(j, j + n), XS_ABSORPTION); if (is_disappearance(rx->mt_)) { absorption += xs; } if (is_fission(rx->mt_)) { fissionable_ = true; - auto fission = xt::view(xs_[t], xt::range(j,j+n), XS_FISSION); + auto fission = xt::view(xs_[t], xt::range(j, j + n), XS_FISSION); fission += xs; absorption += xs; // Keep track of fission reactions if (t == 0) { fission_rx_.push_back(rx.get()); - if (rx->mt_ == N_F) has_partial_fission_ = true; + if (rx->mt_ == N_F) + has_partial_fission_ = true; } } } @@ -393,8 +428,8 @@ void Nuclide::create_derived(const Function1D* prompt_photons, const Function1D* int n = grid_[t].energy.size(); for (int i = 0; i < n; ++i) { double E = grid_[t].energy[i]; - xs_[t](i, XS_NU_FISSION) = nu(E, EmissionMode::total) - * xs_[t](i, XS_FISSION); + xs_[t](i, XS_NU_FISSION) = + nu(E, EmissionMode::total) * xs_[t](i, XS_FISSION); } } } @@ -409,8 +444,9 @@ void Nuclide::create_derived(const Function1D* prompt_photons, const Function1D* // Make sure nuclide has 0K data if (energy_0K_.empty()) { - fatal_error("Cannot treat " + name_ + " as a resonant scatterer " - "because 0 K elastic scattering data is not present."); + fatal_error("Cannot treat " + name_ + + " as a resonant scatterer " + "because 0 K elastic scattering data is not present."); } break; } @@ -432,12 +468,14 @@ void Nuclide::create_derived(const Function1D* prompt_photons, const Function1D* for (int i = 0; i < E.size() - 1; ++i) { // Negative cross sections result in a CDF that is not monotonically // increasing. Set all negative xs values to zero. - if (xs[i] < 0.0) xs[i] = 0.0; + if (xs[i] < 0.0) + xs[i] = 0.0; // build xs cdf - xs_cdf_sum += (std::sqrt(E[i])*xs[i] + std::sqrt(E[i+1])*xs[i+1]) - / 2.0 * (E[i+1] - E[i]); - xs_cdf_[i] = xs_cdf_sum; + xs_cdf_sum += + (std::sqrt(E[i]) * xs[i] + std::sqrt(E[i + 1]) * xs[i + 1]) / 2.0 * + (E[i + 1] - E[i]); + xs_cdf_[i + 1] = xs_cdf_sum; } } } @@ -451,10 +489,10 @@ void Nuclide::init_grid() int M = settings::n_log_bins; // Determine equal-logarithmic energy spacing - double spacing = std::log(E_max/E_min)/M; + double spacing = std::log(E_max / E_min) / M; // Create equally log-spaced energy grid - auto umesh = xt::linspace(0.0, M*spacing, M+1); + auto umesh = xt::linspace(0.0, M * spacing, M + 1); for (auto& grid : grid_) { // Resize array for storing grid indices @@ -464,10 +502,11 @@ void Nuclide::init_grid() // equal-logarithmic grid int j = 0; for (int k = 0; k <= M; ++k) { - while (std::log(grid.energy[j + 1]/E_min) <= umesh(k)) { + while (std::log(grid.energy[j + 1] / E_min) <= umesh(k)) { // Ensure that for isotopes where maxval(grid.energy) << E_max that // there are no out-of-bounds issues. - if (j + 2 == grid.energy.size()) break; + if (j + 2 == grid.energy.size()) + break; ++j; } grid.grid_index[k] = j; @@ -477,13 +516,14 @@ void Nuclide::init_grid() double Nuclide::nu(double E, EmissionMode mode, int group) const { - if (!fissionable_) return 0.0; + if (!fissionable_) + return 0.0; switch (mode) { case EmissionMode::prompt: return (*fission_rx_[0]->products_[0].yield_)(E); case EmissionMode::delayed: - if (n_precursor_ > 0) { + if (n_precursor_ > 0 && settings::create_delayed_neutrons) { auto rx = fission_rx_[0]; if (group >= 1 && group < rx->products_.size()) { // If delayed group specified, determine yield immediately @@ -508,7 +548,7 @@ double Nuclide::nu(double E, EmissionMode mode, int group) const return 0.0; } case EmissionMode::total: - if (total_nu_) { + if (total_nu_ && settings::create_delayed_neutrons) { return (*total_nu_)(E); } else { return (*fission_rx_[0]->products_[0].yield_)(E); @@ -527,7 +567,7 @@ void Nuclide::calculate_elastic_xs(Particle& p) const if (i_temp >= 0) { const auto& xs = reactions_[0]->xs_[i_temp].value; - micro.elastic = (1.0 - f)*xs[i_grid] + f*xs[i_grid + 1]; + micro.elastic = (1.0 - f) * xs[i_grid] + f * xs[i_grid + 1]; } } @@ -544,17 +584,19 @@ double Nuclide::elastic_xs_0K(double E) const } // check for rare case where two energy points are the same - if (energy_0K_[i_grid] == energy_0K_[i_grid+1]) ++i_grid; + if (energy_0K_[i_grid] == energy_0K_[i_grid + 1]) + ++i_grid; // calculate interpolation factor - double f = (E - energy_0K_[i_grid]) / - (energy_0K_[i_grid + 1] - energy_0K_[i_grid]); + double f = + (E - energy_0K_[i_grid]) / (energy_0K_[i_grid + 1] - energy_0K_[i_grid]); // Calculate microscopic nuclide elastic cross section - return (1.0 - f)*elastic_0K_[i_grid] + f*elastic_0K_[i_grid + 1]; + return (1.0 - f) * elastic_0K_[i_grid] + f * elastic_0K_[i_grid + 1]; } -void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle& p) +void Nuclide::calculate_xs( + int i_sab, int i_log_union, double sab_frac, Particle& p) { auto& micro {p.neutron_xs(index_)}; @@ -592,16 +634,23 @@ void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle } } - // Ensure these values are set - // Note, the only time either is used is in one of 4 places: - // 1. physics.cpp - scatter - For inelastic scatter. - // 2. physics.cpp - sample_fission - For partial fissions. - // 3. tally.F90 - score_general - For tallying on MTxxx reactions. - // 4. nuclide.cpp - calculate_urr_xs - For unresolved purposes. - // It is worth noting that none of these occur in the resolved - // resonance range, so the value here does not matter. index_temp is - // set to -1 to force a segfault in case a developer messes up and tries - // to use it with multipole. + /* + * index_temp, index_grid, and interp_factor are used only in the + * following places: + * 1. physics.cpp - scatter - For inelastic scatter. + * 2. physics.cpp - sample_fission - For partial fissions. + * 3. tallies/tally_scoring.cpp - score_general - + * For tallying on MTxxx reactions. + * 4. nuclide.cpp - calculate_urr_xs - For unresolved purposes. + * It is worth noting that none of these occur in the resolved resonance + * range, so the value here does not matter. index_temp is set to -1 to + * force a segfault in case a developer messes up and tries to use it with + * multipole. + * + * However, a segfault is not necessarily guaranteed with an out-of-bounds + * access, so this technique should be replaced by something more robust + * in the future. + */ micro.index_temp = -1; micro.index_grid = -1; micro.interp_factor = 0.0; @@ -612,28 +661,38 @@ void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle double f; int i_temp = -1; switch (settings::temperature_method) { - case TemperatureMethod::NEAREST: - { - double max_diff = INFTY; - for (int t = 0; t < kTs_.size(); ++t) { - double diff = std::abs(kTs_[t] - kT); - if (diff < max_diff) { - i_temp = t; - max_diff = diff; - } + case TemperatureMethod::NEAREST: { + double max_diff = INFTY; + for (int t = 0; t < kTs_.size(); ++t) { + double diff = std::abs(kTs_[t] - kT); + if (diff < max_diff) { + i_temp = t; + max_diff = diff; } } - break; + } break; case TemperatureMethod::INTERPOLATION: + // If current kT outside of the bounds of available, snap to the bound + if (kT < kTs_.front()) { + i_temp = 0; + break; + } + if (kT > kTs_.back()) { + i_temp = kTs_.size() - 1; + break; + } + // Find temperatures that bound the actual temperature for (i_temp = 0; i_temp < kTs_.size() - 1; ++i_temp) { - if (kTs_[i_temp] <= kT && kT < kTs_[i_temp + 1]) break; + if (kTs_[i_temp] <= kT && kT < kTs_[i_temp + 1]) + break; } // Randomly sample between temperature i and i+1 f = (kT - kTs_[i_temp]) / (kTs_[i_temp + 1] - kTs_[i_temp]); - if (f > prn(p.current_seed())) ++i_temp; + if (f > prn(p.current_seed())) + ++i_temp; break; } @@ -652,7 +711,7 @@ void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle } else { // Determine bounding indices based on which equal log-spaced // interval the energy is in - int i_low = grid.grid_index[i_log_union]; + int i_low = grid.grid_index[i_log_union]; int i_high = grid.grid_index[i_log_union + 1] + 1; // Perform binary search over reduced range @@ -661,7 +720,8 @@ void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle } // check for rare case where two energy points are the same - if (grid.energy[i_grid] == grid.energy[i_grid + 1]) ++i_grid; + if (grid.energy[i_grid] == grid.energy[i_grid + 1]) + ++i_grid; // calculate interpolation factor f = (p.E() - grid.energy[i_grid]) / @@ -672,29 +732,29 @@ void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle micro.interp_factor = f; // Calculate microscopic nuclide total cross section - micro.total = (1.0 - f)*xs(i_grid, XS_TOTAL) - + f*xs(i_grid + 1, XS_TOTAL); + micro.total = + (1.0 - f) * xs(i_grid, XS_TOTAL) + f * xs(i_grid + 1, XS_TOTAL); // Calculate microscopic nuclide absorption cross section - micro.absorption = (1.0 - f)*xs(i_grid, XS_ABSORPTION) - + f*xs(i_grid + 1, XS_ABSORPTION); + micro.absorption = + (1.0 - f) * xs(i_grid, XS_ABSORPTION) + f * xs(i_grid + 1, XS_ABSORPTION); if (fissionable_) { // Calculate microscopic nuclide total cross section - micro.fission = (1.0 - f)*xs(i_grid, XS_FISSION) - + f*xs(i_grid + 1, XS_FISSION); + micro.fission = + (1.0 - f) * xs(i_grid, XS_FISSION) + f * xs(i_grid + 1, XS_FISSION); // Calculate microscopic nuclide nu-fission cross section - micro.nu_fission = (1.0 - f)*xs(i_grid, XS_NU_FISSION) - + f*xs(i_grid + 1, XS_NU_FISSION); + micro.nu_fission = (1.0 - f) * xs(i_grid, XS_NU_FISSION) + + f * xs(i_grid + 1, XS_NU_FISSION); } else { micro.fission = 0.0; micro.nu_fission = 0.0; } // Calculate microscopic nuclide photon production cross section - micro.photon_prod = (1.0 - f)*xs(i_grid, XS_PHOTON_PROD) - + f*xs(i_grid + 1, XS_PHOTON_PROD); + micro.photon_prod = (1.0 - f) * xs(i_grid, XS_PHOTON_PROD) + + f * xs(i_grid + 1, XS_PHOTON_PROD); // Depletion-related reactions if (simulation::need_depletion_rx) { @@ -711,18 +771,18 @@ void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle const auto& rx = reactions_[i_rx]; const auto& rx_xs = rx->xs_[i_temp].value; - // Physics says that (n,gamma) is not a threshold reaction, so we don't - // need to specifically check its threshold index + // Physics says that (n,gamma) is not a threshold reaction, so we + // don't need to specifically check its threshold index if (j == 0) { - micro.reaction[0] = (1.0 - f)*rx_xs[i_grid] - + f*rx_xs[i_grid + 1]; + micro.reaction[0] = + (1.0 - f) * rx_xs[i_grid] + f * rx_xs[i_grid + 1]; continue; } int threshold = rx->xs_[i_temp].threshold; if (i_grid >= threshold) { - micro.reaction[j] = (1.0 - f)*rx_xs[i_grid - threshold] + - f*rx_xs[i_grid - threshold + 1]; + micro.reaction[j] = (1.0 - f) * rx_xs[i_grid - threshold] + + f * rx_xs[i_grid - threshold + 1]; } else if (j >= 3) { // One can show that the the threshold for (n,(x+1)n) is always // higher than the threshold for (n,xn). Thus, if we are below @@ -746,16 +806,14 @@ void Nuclide::calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle // and sab_elastic cross sections and correct the total and elastic cross // sections. - if (i_sab >= 0) this->calculate_sab_xs(i_sab, sab_frac, p); + if (i_sab >= 0) + this->calculate_sab_xs(i_sab, sab_frac, p); // If the particle is in the unresolved resonance range and there are // probability tables, we need to determine cross sections from the table if (settings::urr_ptables_on && urr_present_ && !use_mp) { - int n = urr_data_[micro.index_temp].n_energy_; - if ((p.E() > urr_data_[micro.index_temp].energy_(0)) && - (p.E() < urr_data_[micro.index_temp].energy_(n - 1))) { + if (urr_data_[micro.index_temp].energy_in_bounds(p.E())) this->calculate_urr_xs(micro.index_temp, p); - } } micro.last_E = p.E(); @@ -784,8 +842,8 @@ void Nuclide::calculate_sab_xs(int i_sab, double sab_frac, Particle& p) this->calculate_elastic_xs(p); // Correct total and elastic cross sections - micro.total = micro.total + micro.thermal - sab_frac*micro.elastic; - micro.elastic = micro.thermal + (1.0 - sab_frac)*micro.elastic; + micro.total = micro.total + micro.thermal - sab_frac * micro.elastic; + micro.elastic = micro.thermal + (1.0 - sab_frac) * micro.elastic; // Save temperature index and thermal fraction micro.index_temp_sab = i_temp; @@ -801,10 +859,8 @@ void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const const auto& urr = urr_data_[i_temp]; // Determine the energy table - int i_energy = 0; - while (p.E() >= urr.energy_(i_energy + 1)) { - ++i_energy; - }; + int i_energy = + lower_bound_index(urr.energy_.begin(), urr.energy_.end(), p.E()); // Sample the probability table using the cumulative distribution @@ -812,15 +868,16 @@ void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const // This guarantees the randomness and, at the same time, makes sure we // reuse random numbers for the same nuclide at different temperatures, // therefore preserving correlation of temperature in probability tables. - p.stream() = STREAM_URR_PTABLE; - double r = future_prn(static_cast(index_), *p.current_seed()); - p.stream() = STREAM_TRACKING; - - int i_low = 0; - while (urr.prob_(i_energy, URRTableParam::CUM_PROB, i_low) <= r) {++i_low;}; + double r = + future_prn(static_cast(index_), p.seeds(STREAM_URR_PTABLE)); - int i_up = 0; - while (urr.prob_(i_energy + 1, URRTableParam::CUM_PROB, i_up) <= r) {++i_up;}; + // Warning: this assumes row-major order of cdf_values_ + int i_low = upper_bound_index(&urr.cdf_values_(i_energy, 0), + &urr.cdf_values_(i_energy, 0) + urr.n_cdf(), r) + + 1; + int i_up = upper_bound_index(&urr.cdf_values_(i_energy + 1, 0), + &urr.cdf_values_(i_energy + 1, 0) + urr.n_cdf(), r) + + 1; // Determine elastic, fission, and capture cross sections from the // probability table @@ -830,49 +887,46 @@ void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const double f; if (urr.interp_ == Interpolation::lin_lin) { // Determine the interpolation factor on the table - f = (p.E() - urr.energy_(i_energy)) / - (urr.energy_(i_energy + 1) - urr.energy_(i_energy)); - - elastic = (1. - f) * urr.prob_(i_energy, URRTableParam::ELASTIC, i_low) + - f * urr.prob_(i_energy + 1, URRTableParam::ELASTIC, i_up); - fission = (1. - f) * urr.prob_(i_energy, URRTableParam::FISSION, i_low) + - f * urr.prob_(i_energy + 1, URRTableParam::FISSION, i_up); - capture = (1. - f) * urr.prob_(i_energy, URRTableParam::N_GAMMA, i_low) + - f * urr.prob_(i_energy + 1, URRTableParam::N_GAMMA, i_up); + f = (p.E() - urr.energy_[i_energy]) / + (urr.energy_[i_energy + 1] - urr.energy_[i_energy]); + + elastic = (1. - f) * urr.xs_values_(i_energy, i_low).elastic + + f * urr.xs_values_(i_energy + 1, i_up).elastic; + fission = (1. - f) * urr.xs_values_(i_energy, i_low).fission + + f * urr.xs_values_(i_energy + 1, i_up).fission; + capture = (1. - f) * urr.xs_values_(i_energy, i_low).n_gamma + + f * urr.xs_values_(i_energy + 1, i_up).n_gamma; } else if (urr.interp_ == Interpolation::log_log) { // Determine interpolation factor on the table - f = std::log(p.E() / urr.energy_(i_energy)) / - std::log(urr.energy_(i_energy + 1) / urr.energy_(i_energy)); + f = std::log(p.E() / urr.energy_[i_energy]) / + std::log(urr.energy_[i_energy + 1] / urr.energy_[i_energy]); // Calculate the elastic cross section/factor - if ((urr.prob_(i_energy, URRTableParam::ELASTIC, i_low) > 0.) && - (urr.prob_(i_energy + 1, URRTableParam::ELASTIC, i_up) > 0.)) { + if ((urr.xs_values_(i_energy, i_low).elastic > 0.) && + (urr.xs_values_(i_energy + 1, i_up).elastic > 0.)) { elastic = - std::exp((1. - f) * - std::log(urr.prob_(i_energy, URRTableParam::ELASTIC, i_low)) + - f * std::log(urr.prob_(i_energy + 1, URRTableParam::ELASTIC, i_up))); + std::exp((1. - f) * std::log(urr.xs_values_(i_energy, i_low).elastic) + + f * std::log(urr.xs_values_(i_energy + 1, i_up).elastic)); } else { elastic = 0.; } // Calculate the fission cross section/factor - if ((urr.prob_(i_energy, URRTableParam::FISSION, i_low) > 0.) && - (urr.prob_(i_energy + 1, URRTableParam::FISSION, i_up) > 0.)) { + if ((urr.xs_values_(i_energy, i_low).fission > 0.) && + (urr.xs_values_(i_energy + 1, i_up).fission > 0.)) { fission = - std::exp((1. - f) * - std::log(urr.prob_(i_energy, URRTableParam::FISSION, i_low)) + - f * std::log(urr.prob_(i_energy + 1, URRTableParam::FISSION, i_up))); + std::exp((1. - f) * std::log(urr.xs_values_(i_energy, i_low).fission) + + f * std::log(urr.xs_values_(i_energy + 1, i_up).fission)); } else { fission = 0.; } // Calculate the capture cross section/factor - if ((urr.prob_(i_energy, URRTableParam::N_GAMMA, i_low) > 0.) && - (urr.prob_(i_energy + 1, URRTableParam::N_GAMMA, i_up) > 0.)) { + if ((urr.xs_values_(i_energy, i_low).n_gamma > 0.) && + (urr.xs_values_(i_energy + 1, i_up).n_gamma > 0.)) { capture = - std::exp((1. - f) * - std::log(urr.prob_(i_energy, URRTableParam::N_GAMMA, i_low)) + - f * std::log(urr.prob_(i_energy + 1, URRTableParam::N_GAMMA, i_up))); + std::exp((1. - f) * std::log(urr.xs_values_(i_energy, i_low).n_gamma) + + f * std::log(urr.xs_values_(i_energy + 1, i_up).n_gamma)); } else { capture = 0.; } @@ -889,7 +943,7 @@ void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const int xs_index = micro.index_grid - rx->xs_[i_temp].threshold; if (xs_index >= 0) { inelastic = (1. - f) * rx->xs_[i_temp].value[xs_index] + - f * rx->xs_[i_temp].value[xs_index + 1]; + f * rx->xs_[i_temp].value[xs_index + 1]; } } @@ -902,9 +956,15 @@ void Nuclide::calculate_urr_xs(int i_temp, Particle& p) const } // Check for negative values - if (elastic < 0.) {elastic = 0.;} - if (fission < 0.) {fission = 0.;} - if (capture < 0.) {capture = 0.;} + if (elastic < 0.) { + elastic = 0.; + } + if (fission < 0.) { + fission = 0.; + } + if (capture < 0.) { + capture = 0.; + } // Set elastic, absorption, fission, total, and capture x/s. Note that the // total x/s is calculated as a sum of partials instead of the table-provided @@ -933,22 +993,30 @@ std::pair Nuclide::find_temperature(double T) const double kT = K_BOLTZMANN * T; gsl::index n = kTs_.size(); switch (settings::temperature_method) { - case TemperatureMethod::NEAREST: - { - double max_diff = INFTY; - for (gsl::index t = 0; t < n; ++t) { - double diff = std::abs(kTs_[t] - kT); - if (diff < max_diff) { - i_temp = t; - max_diff = diff; - } + case TemperatureMethod::NEAREST: { + double max_diff = INFTY; + for (gsl::index t = 0; t < n; ++t) { + double diff = std::abs(kTs_[t] - kT); + if (diff < max_diff) { + i_temp = t; + max_diff = diff; } } - break; + } break; case TemperatureMethod::INTERPOLATION: + // If current kT outside of the bounds of available, snap to the bound + if (kT < kTs_.front()) { + i_temp = 0; + break; + } + if (kT > kTs_.back()) { + i_temp = kTs_.size() - 1; + break; + } // Find temperatures that bound the actual temperature - while (kTs_[i_temp + 1] < kT && i_temp + 1 < n - 1) ++i_temp; + while (kTs_[i_temp + 1] < kT && i_temp + 1 < n - 1) + ++i_temp; // Determine interpolation factor f = (kT - kTs_[i_temp]) / (kTs_[i_temp + 1] - kTs_[i_temp]); @@ -959,15 +1027,16 @@ std::pair Nuclide::find_temperature(double T) const return {i_temp, f}; } -double Nuclide::collapse_rate(int MT, double temperature, gsl::span energy, - gsl::span flux) const +double Nuclide::collapse_rate(int MT, double temperature, + gsl::span energy, gsl::span flux) const { Expects(MT > 0); Expects(energy.size() > 0); Expects(energy.size() == flux.size() + 1); int i_rx = reaction_index_[MT]; - if (i_rx < 0) return 0.0; + if (i_rx < 0) + return 0.0; const auto& rx = reactions_[i_rx]; // Determine temperature index @@ -983,9 +1052,10 @@ double Nuclide::collapse_rate(int MT, double temperature, gsl::spancollapse_rate(i_temp + 1, energy, flux, grid_high); - return rr_low + f*(rr_high - rr_low); + return rr_low + f * (rr_high - rr_low); } else { - // If interpolation factor is zero, return reaction rate at lower temperature + // If interpolation factor is zero, return reaction rate at lower + // temperature return rr_low; } } @@ -1000,20 +1070,21 @@ void check_data_version(hid_t file_id) vector version; read_attribute(file_id, "version", version); if (version[0] != HDF5_VERSION[0]) { - fatal_error("HDF5 data format uses version " + std::to_string(version[0]) - + "." + std::to_string(version[1]) + " whereas your installation of " - "OpenMC expects version " + std::to_string(HDF5_VERSION[0]) - + ".x data."); + fatal_error("HDF5 data format uses version " + + std::to_string(version[0]) + "." + + std::to_string(version[1]) + + " whereas your installation of " + "OpenMC expects version " + + std::to_string(HDF5_VERSION[0]) + ".x data."); } } else { fatal_error("HDF5 data does not indicate a version. Your installation of " - "OpenMC expects version " + std::to_string(HDF5_VERSION[0]) + - ".x data."); + "OpenMC expects version " + + std::to_string(HDF5_VERSION[0]) + ".x data."); } } -extern "C" size_t -nuclides_size() +extern "C" size_t nuclides_size() { return data::nuclides.size(); } @@ -1029,7 +1100,8 @@ extern "C" int openmc_load_nuclide(const char* name, const double* temps, int n) LibraryKey key {Library::Type::neutron, name}; const auto& it = data::library_map.find(key); if (it == data::library_map.end()) { - set_errmsg("Nuclide '" + std::string{name} + "' is not present in library."); + set_errmsg( + "Nuclide '" + std::string {name} + "' is not present in library."); return OPENMC_E_DATA; } @@ -1052,7 +1124,8 @@ extern "C" int openmc_load_nuclide(const char* name, const double* temps, int n) // Read multipole file into the appropriate entry on the nuclides array int i_nuclide = data::nuclide_map.at(name); - if (settings::temperature_multipole) read_multipole_data(i_nuclide); + if (settings::temperature_multipole) + read_multipole_data(i_nuclide); // Read elemental data, if necessary if (settings::photon_transport) { @@ -1063,7 +1136,8 @@ extern "C" int openmc_load_nuclide(const char* name, const double* temps, int n) LibraryKey key {Library::Type::photon, element}; const auto& it = data::library_map.find(key); if (it == data::library_map.end()) { - set_errmsg("Element '" + std::string{element} + "' is not present in library."); + set_errmsg("Element '" + std::string {element} + + "' is not present in library."); return OPENMC_E_DATA; } @@ -1087,20 +1161,19 @@ extern "C" int openmc_load_nuclide(const char* name, const double* temps, int n) return 0; } -extern "C" int -openmc_get_nuclide_index(const char* name, int* index) +extern "C" int openmc_get_nuclide_index(const char* name, int* index) { auto it = data::nuclide_map.find(name); if (it == data::nuclide_map.end()) { - set_errmsg("No nuclide named '" + std::string{name} + "' has been loaded."); + set_errmsg( + "No nuclide named '" + std::string {name} + "' has been loaded."); return OPENMC_E_DATA; } *index = it->second; return 0; } -extern "C" int -openmc_nuclide_name(int index, const char** name) +extern "C" int openmc_nuclide_name(int index, const char** name) { if (index >= 0 && index < data::nuclides.size()) { *name = data::nuclides[index]->name_.data(); @@ -1111,9 +1184,9 @@ openmc_nuclide_name(int index, const char** name) } } -extern "C" int -openmc_nuclide_collapse_rate(int index, int MT, double temperature, - const double* energy, const double* flux, int n, double* xs) +extern "C" int openmc_nuclide_collapse_rate(int index, int MT, + double temperature, const double* energy, const double* flux, int n, + double* xs) { if (index < 0 || index >= data::nuclides.size()) { set_errmsg("Index in nuclides vector is out of bounds."); @@ -1121,8 +1194,8 @@ openmc_nuclide_collapse_rate(int index, int MT, double temperature, } try { - *xs = data::nuclides[index]->collapse_rate(MT, temperature, - {energy, energy + n + 1}, {flux, flux + n}); + *xs = data::nuclides[index]->collapse_rate( + MT, temperature, {energy, energy + n + 1}, {flux, flux + n}); } catch (const std::out_of_range& e) { fmt::print("Caught error\n"); set_errmsg(e.what()); diff --git a/src/output.cpp b/src/output.cpp index beac21ddd05..5fdbea1304e 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -1,12 +1,13 @@ #include "openmc/output.h" -#include // for transform, max -#include // for strlen -#include // for time, localtime -#include // for setw, setprecision, put_time -#include // for fixed, scientific, left -#include +#include // for transform, max +#include // for stdout +#include // for strlen +#include // for time, localtime #include +#include // for setw, setprecision, put_time +#include // for fixed, scientific, left +#include #include #include #include // for pair @@ -30,6 +31,7 @@ #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" #include "openmc/plot.h" +#include "openmc/random_ray/flat_source_domain.h" #include "openmc/reaction.h" #include "openmc/settings.h" #include "openmc/simulation.h" @@ -46,65 +48,66 @@ namespace openmc { void title() { - fmt::print( - " %%%%%%%%%%%%%%%\n" - " %%%%%%%%%%%%%%%%%%%%%%%%\n" - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" - " %%%%%%%%%%%%%%%%%%%%%%%%\n" - " %%%%%%%%%%%%%%%%%%%%%%%%\n" - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n" - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n" - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n" - " #################### %%%%%%%%%%%%%%%%%%%%%%\n" - " ##################### %%%%%%%%%%%%%%%%%%%%%\n" - " ###################### %%%%%%%%%%%%%%%%%%%%\n" - " ####################### %%%%%%%%%%%%%%%%%%\n" - " ####################### %%%%%%%%%%%%%%%%%\n" - " ###################### %%%%%%%%%%%%%%%%%\n" - " #################### %%%%%%%%%%%%%%%%%\n" - " ################# %%%%%%%%%%%%%%%%%\n" - " ############### %%%%%%%%%%%%%%%%\n" - " ############ %%%%%%%%%%%%%%%\n" - " ######## %%%%%%%%%%%%%%\n" - " %%%%%%%%%%%\n\n"); + fmt::print(" %%%%%%%%%%%%%%%\n" + " %%%%%%%%%%%%%%%%%%%%%%%%\n" + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + " %%%%%%%%%%%%%%%%%%%%%%%%\n" + " %%%%%%%%%%%%%%%%%%%%%%%%\n" + " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n" + " ################## %%%%%%%%%%%%%%%%%%%%%%%\n" + " ################### %%%%%%%%%%%%%%%%%%%%%%%\n" + " #################### %%%%%%%%%%%%%%%%%%%%%%\n" + " ##################### %%%%%%%%%%%%%%%%%%%%%\n" + " ###################### %%%%%%%%%%%%%%%%%%%%\n" + " ####################### %%%%%%%%%%%%%%%%%%\n" + " ####################### %%%%%%%%%%%%%%%%%\n" + " ###################### %%%%%%%%%%%%%%%%%\n" + " #################### %%%%%%%%%%%%%%%%%\n" + " ################# %%%%%%%%%%%%%%%%%\n" + " ############### %%%%%%%%%%%%%%%%\n" + " ############ %%%%%%%%%%%%%%%\n" + " ######## %%%%%%%%%%%%%%\n" + " %%%%%%%%%%%\n\n"); // Write version information fmt::print( - " | The OpenMC Monte Carlo Code\n" - " Copyright | 2011-2021 MIT and OpenMC contributors\n" - " License | https://docs.openmc.org/en/latest/license.html\n" - " Version | {}.{}.{}{}\n", VERSION_MAJOR, VERSION_MINOR, - VERSION_RELEASE, VERSION_DEV ? "-dev" : ""); + " | The OpenMC Monte Carlo Code\n" + " Copyright | 2011-2024 MIT, UChicago Argonne LLC, and contributors\n" + " License | https://docs.openmc.org/en/latest/license.html\n" + " Version | {}.{}.{}{}\n", + VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE, VERSION_DEV ? "-dev" : ""); #ifdef GIT_SHA1 - fmt::print(" Git SHA1 | {}\n", GIT_SHA1); + fmt::print(" Git SHA1 | {}\n", GIT_SHA1); #endif // Write the date and time - fmt::print(" Date/Time | {}\n", time_stamp()); + fmt::print(" Date/Time | {}\n", time_stamp()); #ifdef OPENMC_MPI // Write number of processors - fmt::print(" MPI Processes | {}\n", mpi::n_procs); + fmt::print(" MPI Processes | {}\n", mpi::n_procs); #endif #ifdef _OPENMP // Write number of OpenMP threads - fmt::print(" OpenMP Threads | {}\n", omp_get_max_threads()); + fmt::print(" OpenMP Threads | {}\n", omp_get_max_threads()); #endif - std::cout << std::endl; + fmt::print("\n"); + std::fflush(stdout); } //============================================================================== -std::string -header(const char* msg) { +std::string header(const char* msg) +{ // Determine how many times to repeat the '=' character. int n_prefix = (63 - strlen(msg)) / 2; int n_suffix = n_prefix; - if ((strlen(msg) % 2) == 0) ++n_suffix; + if ((strlen(msg) % 2) == 0) + ++n_suffix; // Convert to uppercase. std::string upper(msg); @@ -113,22 +116,29 @@ header(const char* msg) { // Add ===> <=== markers. std::stringstream out; out << ' '; - for (int i = 0; i < n_prefix; i++) out << '='; + for (int i = 0; i < n_prefix; i++) + out << '='; out << "> " << upper << " <"; - for (int i = 0; i < n_suffix; i++) out << '='; + for (int i = 0; i < n_suffix; i++) + out << '='; return out.str(); } -std::string header(const std::string& msg) {return header(msg.c_str());} +std::string header(const std::string& msg) +{ + return header(msg.c_str()); +} -void -header(const char* msg, int level) { +void header(const char* msg, int level) +{ auto out = header(msg); // Print header based on verbosity level. - if (settings::verbosity >= level) - std::cout << '\n' << out << "\n" << std::endl; + if (settings::verbosity >= level) { + fmt::print("\n{}\n\n", out); + std::fflush(stdout); + } } //============================================================================== @@ -136,7 +146,7 @@ header(const char* msg, int level) { std::string time_stamp() { std::stringstream ts; - std::time_t t = std::time(nullptr); // get time now + std::time_t t = std::time(nullptr); // get time now ts << std::put_time(std::localtime(&t), "%Y-%m-%d %H:%M:%S"); return ts.str(); } @@ -209,66 +219,23 @@ void print_particle(Particle& p) void print_plot() { header("PLOTTING SUMMARY", 5); - if (settings::verbosity < 5) return; - - for (auto pl : model::plots) { - // Plot id - fmt::print("Plot ID: {}\n", pl.id_); - // Plot filename - fmt::print("Plot file: {}\n", pl.path_plot_); - // Plot level - fmt::print("Universe depth: {}\n", pl.level_); - - // Plot type - if (PlotType::slice == pl.type_) { - fmt::print("Plot Type: Slice\n"); - } else if (PlotType::voxel == pl.type_) { - fmt::print("Plot Type: Voxel\n"); - } - - // Plot parameters - fmt::print("Origin: {} {} {}\n", pl.origin_[0], pl.origin_[1], pl.origin_[2]); - - if (PlotType::slice == pl.type_) { - fmt::print("Width: {:4} {:4}\n", pl.width_[0], pl.width_[1]); - } else if (PlotType::voxel == pl.type_) { - fmt::print("Width: {:4} {:4} {:4}\n", pl.width_[0], pl.width_[1], - pl.width_[2]); - } - - if (PlotColorBy::cells == pl.color_by_) { - fmt::print("Coloring: Cells\n"); - } else if (PlotColorBy::mats == pl.color_by_) { - fmt::print("Coloring: Materials\n"); - } - - if (PlotType::slice == pl.type_) { - switch(pl.basis_) { - case PlotBasis::xy: - fmt::print("Basis: XY\n"); - break; - case PlotBasis::xz: - fmt::print("Basis: XZ\n"); - break; - case PlotBasis::yz: - fmt::print("Basis: YZ\n"); - break; - } - fmt::print("Pixels: {} {}\n", pl.pixels_[0], pl.pixels_[1]); - } else if (PlotType::voxel == pl.type_) { - fmt::print("Voxels: {} {} {}\n", pl.pixels_[0], pl.pixels_[1], pl.pixels_[2]); - } - + if (settings::verbosity < 5) + return; + + for (const auto& pl : model::plots) { + fmt::print("Plot ID: {}\n", pl->id()); + fmt::print("Plot file: {}\n", pl->path_plot()); + fmt::print("Universe depth: {}\n", pl->level()); + pl->print_info(); // prints type-specific plot info fmt::print("\n"); } } //============================================================================== -void -print_overlap_check() +void print_overlap_check() { - #ifdef OPENMC_MPI +#ifdef OPENMC_MPI vector temp(model::overlap_check_count); MPI_Reduce(temp.data(), model::overlap_check_count.data(), model::overlap_check_count.size(), MPI_INT64_T, MPI_SUM, 0, mpi::intracomm); @@ -280,7 +247,8 @@ print_overlap_check() vector sparse_cell_ids; for (int i = 0; i < model::cells.size(); i++) { - fmt::print(" {:8} {:17}\n", model::cells[i]->id_, model::overlap_check_count[i]); + fmt::print( + " {:8} {:17}\n", model::cells[i]->id_, model::overlap_check_count[i]); if (model::overlap_check_count[i] < 10) { sparse_cell_ids.push_back(model::cells[i]->id_); } @@ -301,7 +269,7 @@ void print_usage() { if (mpi::master) { fmt::print( - "Usage: openmc [options] [directory]\n\n" + "Usage: openmc [options] [path]\n\n" "Options:\n" " -c, --volume Run in stochastic volume calculation mode\n" " -g, --geometry-debug Run with geometry debugging on\n" @@ -310,7 +278,8 @@ void print_usage() " -r, --restart Restart a previous run from a state point\n" " or a particle restart file\n" " -s, --threads Number of OpenMP threads\n" - " -t, --track Write tracks for all particles\n" + " -t, --track Write tracks for all particles (up to " + "max_tracks)\n" " -e, --event Run using event-based parallelism\n" " -v, --version Show version information\n" " -h, --help Show this message\n"); @@ -327,9 +296,79 @@ void print_version() #ifdef GIT_SHA1 fmt::print("Git SHA1: {}\n", GIT_SHA1); #endif - fmt::print("Copyright (c) 2011-2021 Massachusetts Institute of " - "Technology and OpenMC contributors\nMIT/X license at " - "\n"); + fmt::print("Copyright (c) 2011-2024 MIT, UChicago Argonne LLC, and " + "contributors\nMIT/X license at " + "\n"); + } +} + +//============================================================================== + +void print_build_info() +{ + const std::string n("no"); + const std::string y("yes"); + + std::string mpi(n); + std::string phdf5(n); + std::string dagmc(n); + std::string libmesh(n); + std::string png(n); + std::string profiling(n); + std::string coverage(n); + std::string mcpl(n); + std::string ncrystal(n); + std::string uwuw(n); + +#ifdef PHDF5 + phdf5 = y; +#endif +#ifdef OPENMC_MPI + mpi = y; +#endif +#ifdef DAGMC + dagmc = y; +#endif +#ifdef LIBMESH + libmesh = y; +#endif +#ifdef OPENMC_MCPL + mcpl = y; +#endif +#ifdef NCRYSTAL + ncrystal = y; +#endif +#ifdef USE_LIBPNG + png = y; +#endif +#ifdef PROFILINGBUILD + profiling = y; +#endif +#ifdef COVERAGEBUILD + coverage = y; +#endif +#ifdef UWUW + uwuw = y; +#endif + + // Wraps macro variables in quotes +#define STRINGIFY(x) STRINGIFY2(x) +#define STRINGIFY2(x) #x + + if (mpi::master) { + fmt::print("Build type: {}\n", STRINGIFY(BUILD_TYPE)); + fmt::print("Compiler ID: {} {}\n", STRINGIFY(COMPILER_ID), + STRINGIFY(COMPILER_VERSION)); + fmt::print("MPI enabled: {}\n", mpi); + fmt::print("Parallel HDF5 enabled: {}\n", phdf5); + fmt::print("PNG support: {}\n", png); + fmt::print("DAGMC support: {}\n", dagmc); + fmt::print("libMesh support: {}\n", libmesh); + fmt::print("MCPL support: {}\n", mcpl); + fmt::print("NCrystal support: {}\n", ncrystal); + fmt::print("Coverage testing: {}\n", coverage); + fmt::print("Profiling flags: {}\n", profiling); + fmt::print("UWUW support: {}\n", uwuw); } } @@ -338,13 +377,11 @@ void print_version() void print_columns() { if (settings::entropy_on) { - fmt::print( - " Bat./Gen. k Entropy Average k \n" - " ========= ======== ======== ====================\n"); + fmt::print(" Bat./Gen. k Entropy Average k \n" + " ========= ======== ======== ====================\n"); } else { - fmt::print( - " Bat./Gen. k Average k\n" - " ========= ======== ====================\n"); + fmt::print(" Bat./Gen. k Average k\n" + " ========= ======== ====================\n"); } } @@ -354,12 +391,14 @@ void print_generation() { // Determine overall generation index and number of active generations int idx = overall_generation() - 1; - int n = simulation::current_batch > settings::n_inactive ? - settings::gen_per_batch*simulation::n_realizations + simulation::current_gen : 0; + int n = simulation::current_batch > settings::n_inactive + ? settings::gen_per_batch * simulation::n_realizations + + simulation::current_gen + : 0; // write out batch/generation and generation k-effective auto batch_and_gen = std::to_string(simulation::current_batch) + "/" + - std::to_string(simulation::current_gen); + std::to_string(simulation::current_gen); fmt::print(" {:>9} {:8.5f}", batch_and_gen, simulation::k_generation[idx]); // write out entropy info @@ -370,16 +409,17 @@ void print_generation() if (n > 1) { fmt::print(" {:8.5f} +/-{:8.5f}", simulation::keff, simulation::keff_std); } - std::cout << std::endl; + fmt::print("\n"); + std::fflush(stdout); } //============================================================================== -void show_time(const char* label, double secs, int indent_level=0) +void show_time(const char* label, double secs, int indent_level) { - int width = 33 - indent_level*2; - fmt::print("{0:{1}} {2:<{3}} = {4:>10.4e} seconds\n", - "", 2*indent_level, label, width, secs); + int width = 33 - indent_level * 2; + fmt::print("{0:{1}} {2:<{3}} = {4:>10.4e} seconds\n", "", 2 * indent_level, + label, width, secs); } void show_rate(const char* label, double particles_per_sec) @@ -393,13 +433,14 @@ void print_runtime() // display header block header("Timing Statistics", 6); - if (settings::verbosity < 6) return; + if (settings::verbosity < 6) + return; // display time elapsed for various sections show_time("Total time for initialization", time_initialize.elapsed()); show_time("Reading cross sections", time_read_xs.elapsed(), 1); - show_time("Total time in simulation", time_inactive.elapsed() + - time_active.elapsed()); + show_time("Total time in simulation", + time_inactive.elapsed() + time_active.elapsed()); show_time("Time in transport only", time_transport.elapsed(), 1); if (settings::event_based) { show_time("Particle initialization", time_event_init.elapsed(), 2); @@ -429,28 +470,34 @@ void print_runtime() double speed_active; if (settings::restart_run) { if (simulation::restart_batch < settings::n_inactive) { - speed_inactive = (settings::n_particles * (settings::n_inactive - - simulation::restart_batch) * settings::gen_per_batch) - / time_inactive.elapsed(); - speed_active = (settings::n_particles * n_active - * settings::gen_per_batch) / time_active.elapsed(); + speed_inactive = (settings::n_particles * + (settings::n_inactive - simulation::restart_batch) * + settings::gen_per_batch) / + time_inactive.elapsed(); + speed_active = + (settings::n_particles * n_active * settings::gen_per_batch) / + time_active.elapsed(); } else { - speed_active = (settings::n_particles * (settings::n_batches - - simulation::restart_batch) * settings::gen_per_batch) - / time_active.elapsed(); + speed_active = (settings::n_particles * + (settings::n_batches - simulation::restart_batch) * + settings::gen_per_batch) / + time_active.elapsed(); } } else { if (settings::n_inactive > 0) { - speed_inactive = (settings::n_particles * settings::n_inactive - * settings::gen_per_batch) / time_inactive.elapsed(); + speed_inactive = (settings::n_particles * settings::n_inactive * + settings::gen_per_batch) / + time_inactive.elapsed(); } - speed_active = (settings::n_particles * n_active * settings::gen_per_batch) - / time_active.elapsed(); + speed_active = + (settings::n_particles * n_active * settings::gen_per_batch) / + time_active.elapsed(); } // display calculation rate - if (!(settings::restart_run && (simulation::restart_batch >= settings::n_inactive)) - && settings::n_inactive > 0) { + if (!(settings::restart_run && + (simulation::restart_batch >= settings::n_inactive)) && + settings::n_inactive > 0) { show_rate("Calculation Rate (inactive)", speed_inactive); } show_rate("Calculation Rate (active)", speed_active); @@ -458,12 +505,14 @@ void print_runtime() //============================================================================== -std::pair -mean_stdev(const double* x, int n) +std::pair mean_stdev(const double* x, int n) { double mean = x[static_cast(TallyResult::SUM)] / n; - double stdev = n > 1 ? std::sqrt(std::max(0.0, ( - x[static_cast(TallyResult::SUM_SQ)]/n - mean*mean)/(n - 1))) : 0.0; + double stdev = + n > 1 ? std::sqrt(std::max(0.0, + (x[static_cast(TallyResult::SUM_SQ)] / n - mean * mean) / + (n - 1))) + : 0.0; return {mean, stdev}; } @@ -473,15 +522,16 @@ void print_results() { // display header block for results header("Results", 4); - if (settings::verbosity < 4) return; + if (settings::verbosity < 4) + return; // Calculate t-value for confidence intervals int n = simulation::n_realizations; double alpha, t_n1, t_n3; if (settings::confidence_intervals) { alpha = 1.0 - CONFIDENCE_LEVEL; - t_n1 = t_percentile(1.0 - alpha/2.0, n - 1); - t_n3 = t_percentile(1.0 - alpha/2.0, n - 3); + t_n1 = t_percentile(1.0 - alpha / 2.0, n - 1); + t_n3 = t_percentile(1.0 - alpha / 2.0, n - 3); } else { t_n1 = 1.0; t_n3 = 1.0; @@ -493,14 +543,14 @@ void print_results() if (n > 1) { if (settings::run_mode == RunMode::EIGENVALUE) { std::tie(mean, stdev) = mean_stdev(>(GlobalTally::K_COLLISION, 0), n); - fmt::print(" k-effective (Collision) = {:.5f} +/- {:.5f}\n", - mean, t_n1 * stdev); + fmt::print(" k-effective (Collision) = {:.5f} +/- {:.5f}\n", mean, + t_n1 * stdev); std::tie(mean, stdev) = mean_stdev(>(GlobalTally::K_TRACKLENGTH, 0), n); - fmt::print(" k-effective (Track-length) = {:.5f} +/- {:.5f}\n", - mean, t_n1 * stdev); + fmt::print(" k-effective (Track-length) = {:.5f} +/- {:.5f}\n", mean, + t_n1 * stdev); std::tie(mean, stdev) = mean_stdev(>(GlobalTally::K_ABSORPTION, 0), n); - fmt::print(" k-effective (Absorption) = {:.5f} +/- {:.5f}\n", - mean, t_n1 * stdev); + fmt::print(" k-effective (Absorption) = {:.5f} +/- {:.5f}\n", mean, + t_n1 * stdev); if (n > 3) { double k_combined[2]; openmc_get_keff(k_combined); @@ -509,11 +559,12 @@ void print_results() } } std::tie(mean, stdev) = mean_stdev(>(GlobalTally::LEAKAGE, 0), n); - fmt::print(" Leakage Fraction = {:.5f} +/- {:.5f}\n", - mean, t_n1 * stdev); + fmt::print( + " Leakage Fraction = {:.5f} +/- {:.5f}\n", mean, t_n1 * stdev); } else { - if (mpi::master) warning("Could not compute uncertainties -- only one " - "active batch simulated!"); + if (mpi::master) + warning("Could not compute uncertainties -- only one " + "active batch simulated!"); if (settings::run_mode == RunMode::EIGENVALUE) { fmt::print(" k-effective (Collision) = {:.5f}\n", @@ -527,39 +578,44 @@ void print_results() gt(GlobalTally::LEAKAGE, TallyResult::SUM) / n); } fmt::print("\n"); + std::fflush(stdout); } //============================================================================== const std::unordered_map score_names = { - {SCORE_FLUX, "Flux"}, - {SCORE_TOTAL, "Total Reaction Rate"}, - {SCORE_SCATTER, "Scattering Rate"}, - {SCORE_NU_SCATTER, "Scattering Production Rate"}, - {SCORE_ABSORPTION, "Absorption Rate"}, - {SCORE_FISSION, "Fission Rate"}, - {SCORE_NU_FISSION, "Nu-Fission Rate"}, - {SCORE_KAPPA_FISSION, "Kappa-Fission Rate"}, - {SCORE_EVENTS, "Events"}, - {SCORE_DECAY_RATE, "Decay Rate"}, + {SCORE_FLUX, "Flux"}, + {SCORE_TOTAL, "Total Reaction Rate"}, + {SCORE_SCATTER, "Scattering Rate"}, + {SCORE_NU_SCATTER, "Scattering Production Rate"}, + {SCORE_ABSORPTION, "Absorption Rate"}, + {SCORE_FISSION, "Fission Rate"}, + {SCORE_NU_FISSION, "Nu-Fission Rate"}, + {SCORE_KAPPA_FISSION, "Kappa-Fission Rate"}, + {SCORE_EVENTS, "Events"}, + {SCORE_DECAY_RATE, "Decay Rate"}, {SCORE_DELAYED_NU_FISSION, "Delayed-Nu-Fission Rate"}, - {SCORE_PROMPT_NU_FISSION, "Prompt-Nu-Fission Rate"}, - {SCORE_INVERSE_VELOCITY, "Flux-Weighted Inverse Velocity"}, - {SCORE_FISS_Q_PROMPT, "Prompt fission power"}, - {SCORE_FISS_Q_RECOV, "Recoverable fission power"}, - {SCORE_CURRENT, "Current"}, + {SCORE_PROMPT_NU_FISSION, "Prompt-Nu-Fission Rate"}, + {SCORE_INVERSE_VELOCITY, "Flux-Weighted Inverse Velocity"}, + {SCORE_FISS_Q_PROMPT, "Prompt fission power"}, + {SCORE_FISS_Q_RECOV, "Recoverable fission power"}, + {SCORE_CURRENT, "Current"}, + {SCORE_PULSE_HEIGHT, "pulse-height"}, }; //! Create an ASCII output file showing all tally results. -void -write_tallies() +void write_tallies() { - if (model::tallies.empty()) return; + if (model::tallies.empty()) + return; + + // Set filename for tallies_out + std::string filename = fmt::format("{}tallies.out", settings::path_output); // Open the tallies.out file. std::ofstream tallies_out; - tallies_out.open("tallies.out", std::ios::out | std::ios::trunc); + tallies_out.open(filename, std::ios::out | std::ios::trunc); // Loop over each tally. for (auto i_tally = 0; i_tally < model::tallies.size(); ++i_tally) { @@ -567,7 +623,8 @@ write_tallies() // Write header block. std::string tally_header("TALLY " + std::to_string(tally.id_)); - if (!tally.name_.empty()) tally_header += ": " + tally.name_; + if (!tally.name_.empty()) + tally_header += ": " + tally.name_; fmt::print(tallies_out, "{}\n\n", header(tally_header)); if (!tally.writable_) { @@ -579,7 +636,7 @@ write_tallies() double t_value = 1; if (settings::confidence_intervals) { auto alpha = 1 - CONFIDENCE_LEVEL; - t_value = t_percentile(1 - alpha*0.5, tally.n_realizations_ - 1); + t_value = t_percentile(1 - alpha * 0.5, tally.n_realizations_ - 1); } // Write derivative information. @@ -591,7 +648,8 @@ write_tallies() deriv.diff_material); break; case DerivativeVariable::NUCLIDE_DENSITY: - fmt::print(tallies_out, " Nuclide density derivative Material {} Nuclide {}\n", + fmt::print(tallies_out, + " Nuclide density derivative Material {} Nuclide {}\n", deriv.diff_material, data::nuclides[deriv.diff_nuclide]->name_); break; case DerivativeVariable::TEMPERATURE: @@ -600,7 +658,8 @@ write_tallies() break; default: fatal_error(fmt::format("Differential tally dependent variable for " - "tally {} not defined in output.cpp", tally.id_)); + "tally {} not defined in output.cpp", + tally.id_)); } } @@ -648,13 +707,14 @@ write_tallies() // Write the score, mean, and uncertainty. indent += 2; for (auto score : tally.scores_) { - std::string score_name = score > 0 ? reaction_name(score) - : score_names.at(score); + std::string score_name = + score > 0 ? reaction_name(score) : score_names.at(score); double mean, stdev; - std::tie(mean, stdev) = mean_stdev( - &tally.results_(filter_index, score_index, 0), tally.n_realizations_); - fmt::print(tallies_out, "{0:{1}}{2:<36} {3:.6} +/- {4:.6}\n", - "", indent + 1, score_name, mean, t_value * stdev); + std::tie(mean, stdev) = + mean_stdev(&tally.results_(filter_index, score_index, 0), + tally.n_realizations_); + fmt::print(tallies_out, "{0:{1}}{2:<36} {3:.6} +/- {4:.6}\n", "", + indent + 1, score_name, mean, t_value * stdev); score_index += 1; } indent -= 2; diff --git a/src/particle.cpp b/src/particle.cpp index fe2579593e5..a91113c61ad 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -9,6 +9,7 @@ #include "openmc/capi.h" #include "openmc/cell.h" #include "openmc/constants.h" +#include "openmc/dagmc.h" #include "openmc/error.h" #include "openmc/geometry.h" #include "openmc/hdf5_interface.h" @@ -16,18 +17,20 @@ #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" +#include "openmc/particle_data.h" #include "openmc/photon.h" #include "openmc/physics.h" #include "openmc/physics_mg.h" #include "openmc/random_lcg.h" #include "openmc/settings.h" +#include "openmc/simulation.h" #include "openmc/source.h" #include "openmc/surface.h" -#include "openmc/simulation.h" #include "openmc/tallies/derivative.h" #include "openmc/tallies/tally.h" #include "openmc/tallies/tally_scoring.h" #include "openmc/track_output.h" +#include "openmc/weight_windows.h" #ifdef DAGMC #include "DagMC.hpp" @@ -35,9 +38,59 @@ namespace openmc { +//============================================================================== +// Particle implementation +//============================================================================== + +double Particle::speed() const +{ + // Determine mass in eV/c^2 + double mass; + switch (this->type()) { + case ParticleType::neutron: + mass = MASS_NEUTRON_EV; + break; + case ParticleType::photon: + mass = 0.0; + break; + case ParticleType::electron: + case ParticleType::positron: + mass = MASS_ELECTRON_EV; + break; + } + + if (this->E() < 1.0e-9 * mass) { + // If the energy is much smaller than the mass, revert to non-relativistic + // formula. The 1e-9 criterion is specifically chosen as the point below + // which the error from using the non-relativistic formula is less than the + // round-off eror when using the relativistic formula (see analysis at + // https://gist.github.com/paulromano/da3b473fe3df33de94b265bdff0c7817) + return C_LIGHT * std::sqrt(2 * this->E() / mass); + } else { + // Calculate inverse of Lorentz factor + const double inv_gamma = mass / (this->E() + mass); + + // Calculate speed via v = c * sqrt(1 - γ^-2) + return C_LIGHT * std::sqrt(1 - inv_gamma * inv_gamma); + } +} + +void Particle::move_distance(double length) +{ + for (int j = 0; j < n_coord(); ++j) { + coord(j).r += length * coord(j).u; + } +} + void Particle::create_secondary( double wgt, Direction u, double E, ParticleType type) { + // If energy is below cutoff for this particle, don't create secondary + // particle + if (E < settings::energy_cutoff[static_cast(type)]) { + return; + } + secondary_bank().emplace_back(); auto& bank {secondary_bank().back()}; @@ -46,6 +99,7 @@ void Particle::create_secondary( bank.r = r(); bank.u = u; bank.E = settings::run_CE ? E : g(); + bank.time = time(); n_bank_second() += 1; } @@ -54,7 +108,6 @@ void Particle::from_source(const SourceSite* src) { // Reset some attributes clear(); - alive() = true; surface() = 0; cell_born() = C_NONE; material() = C_NONE; @@ -68,6 +121,7 @@ void Particle::from_source(const SourceSite* src) wgt_last() = src->wgt; r() = src->r; u() = src->u; + r_born() = src->r; r_last_current() = src->r; r_last() = src->r; u_last() = src->u; @@ -80,10 +134,11 @@ void Particle::from_source(const SourceSite* src) E() = data::mg.energy_bin_avg_[g()]; } E_last() = E(); + time() = src->time; + time_last() = src->time; } -void -Particle::event_calculate_xs() +void Particle::event_calculate_xs() { // Set the random number stream stream() = STREAM_TRACKING; @@ -93,6 +148,7 @@ Particle::event_calculate_xs() E_last() = E(); u_last() = u(); r_last() = r(); + time_last() = time(); // Reset event variables event() = TallyEvent::KILL; @@ -102,7 +158,7 @@ Particle::event_calculate_xs() // If the cell hasn't been determined based on the particle's location, // initiate a search for the current cell. This generally happens at the // beginning of the history and again for any secondary particles - if (coord(n_coord() - 1).cell == C_NONE) { + if (lowest_coord().cell == C_NONE) { if (!exhaustive_find_cell(*this)) { mark_as_lost( "Could not find the cell containing particle " + std::to_string(id())); @@ -111,14 +167,15 @@ Particle::event_calculate_xs() // Set birth cell attribute if (cell_born() == C_NONE) - cell_born() = coord(n_coord() - 1).cell; + cell_born() = lowest_coord().cell; } // Write particle track. if (write_track()) write_particle_track(*this); - if (settings::check_overlaps) check_cell_overlap(*this); + if (settings::check_overlaps) + check_cell_overlap(*this); // Calculate microscopic and macroscopic cross sections if (material() != MATERIAL_VOID) { @@ -146,8 +203,7 @@ Particle::event_calculate_xs() } } -void -Particle::event_advance() +void Particle::event_advance() { // Find the distance to the nearest boundary boundary() = distance_to_boundary(*this); @@ -164,10 +220,25 @@ Particle::event_advance() // Select smaller of the two distances double distance = std::min(boundary().distance, collision_distance()); - // Advance particle + // Advance particle in space and time + // Short-term solution until the surface source is revised and we can use + // this->move_distance(distance) for (int j = 0; j < n_coord(); ++j) { coord(j).r += distance * coord(j).u; } + this->time() += distance / this->speed(); + + // Kill particle if its time exceeds the cutoff + bool hit_time_boundary = false; + double time_cutoff = settings::time_cutoff[static_cast(type())]; + if (time() > time_cutoff) { + double dt = time() - time_cutoff; + time() = time_cutoff; + + double push_back_distance = speed() * dt; + this->move_distance(-push_back_distance); + hit_time_boundary = true; + } // Score track-length tallies if (!model::active_tracklength_tallies.empty()) { @@ -184,10 +255,14 @@ Particle::event_advance() if (!model::active_tallies.empty()) { score_track_derivative(*this, distance); } + + // Set particle weight to zero if it hit the time boundary + if (hit_time_boundary) { + wgt() = 0.0; + } } -void -Particle::event_cross_surface() +void Particle::event_cross_surface() { // Set surface that particle is on and adjust coordinate levels surface() = boundary().surface_index; @@ -203,11 +278,16 @@ Particle::event_cross_surface() boundary().lattice_translation[1] != 0 || boundary().lattice_translation[2] != 0) { // Particle crosses lattice boundary - cross_lattice(*this, boundary()); + + bool verbose = settings::verbosity >= 10 || trace(); + cross_lattice(*this, boundary(), verbose); event() = TallyEvent::LATTICE; } else { // Particle crosses surface cross_surface(); + if (settings::weight_window_checkpoint_surface) { + apply_weight_windows(*this); + } event() = TallyEvent::SURFACE; } // Score cell to cell partial currents @@ -216,8 +296,7 @@ Particle::event_cross_surface() } } -void -Particle::event_collide() +void Particle::event_collide() { // Score collision estimate of keff if (settings::run_mode == RunMode::EIGENVALUE && @@ -244,7 +323,8 @@ Particle::event_collide() // Score collision estimator tallies -- this is done after a collision // has occurred rather than before because we need information on the // outgoing energy for any tallies with an outgoing energy filter - if (!model::active_collision_tallies.empty()) score_collision_tally(*this); + if (!model::active_collision_tallies.empty()) + score_collision_tally(*this); if (!model::active_analog_tallies.empty()) { if (settings::run_CE) { score_analog_tally_ce(*this); @@ -253,6 +333,11 @@ Particle::event_collide() } } + if (!model::active_pulse_height_tallies.empty() && + type() == ParticleType::photon) { + pht_collision_energy(); + } + // Reset banked weight during collision n_bank() = 0; n_bank_second() = 0; @@ -284,22 +369,31 @@ Particle::event_collide() } // Score flux derivative accumulators for differential tallies. - if (!model::active_tallies.empty()) score_collision_derivative(*this); + if (!model::active_tallies.empty()) + score_collision_derivative(*this); + +#ifdef DAGMC + history().reset(); +#endif } -void -Particle::event_revive_from_secondary() +void Particle::event_revive_from_secondary() { // If particle has too many events, display warning and kill it ++n_event(); - if (n_event() == MAX_EVENTS) { + if (n_event() == settings::max_particle_events) { warning("Particle " + std::to_string(id()) + " underwent maximum number of events."); - alive() = false; + wgt() = 0.0; } // Check for secondary particles if this particle is dead if (!alive()) { + // Write final position for this particle + if (write_track()) { + write_particle_track(*this); + } + // If no secondary particles, break out of event loop if (secondary_bank().empty()) return; @@ -308,28 +402,45 @@ Particle::event_revive_from_secondary() secondary_bank().pop_back(); n_event() = 0; + // Subtract secondary particle energy from interim pulse-height results + if (!model::active_pulse_height_tallies.empty() && + this->type() == ParticleType::photon) { + // Since the birth cell of the particle has not been set we + // have to determine it before the energy of the secondary particle can be + // removed from the pulse-height of this cell. + if (lowest_coord().cell == C_NONE) { + bool verbose = settings::verbosity >= 10 || trace(); + if (!exhaustive_find_cell(*this, verbose)) { + mark_as_lost("Could not find the cell containing particle " + + std::to_string(id())); + return; + } + // Set birth cell attribute + if (cell_born() == C_NONE) + cell_born() = lowest_coord().cell; + } + pht_secondary_particles(); + } + // Enter new particle in particle track file if (write_track()) add_particle_track(*this); } } -void -Particle::event_death() +void Particle::event_death() { - #ifdef DAGMC - if (settings::dagmc) - history().reset(); +#ifdef DAGMC + history().reset(); #endif // Finish particle track output. if (write_track()) { - write_particle_track(*this); finalize_particle_track(*this); } - // Contribute tally reduction variables to global accumulator - #pragma omp atomic +// Contribute tally reduction variables to global accumulator +#pragma omp atomic global_tally_absorption += keff_tally_absorption(); #pragma omp atomic global_tally_collision += keff_tally_collision(); @@ -344,6 +455,10 @@ Particle::event_death() keff_tally_tracklength() = 0.0; keff_tally_leakage() = 0.0; + if (!model::active_pulse_height_tallies.empty()) { + score_pulse_height_tally(*this, model::active_pulse_height_tallies); + } + // Record the number of progeny created by this particle. // This data will be used to efficiently sort the fission bank. if (settings::run_mode == RunMode::EIGENVALUE) { @@ -352,9 +467,42 @@ Particle::event_death() } } +void Particle::pht_collision_energy() +{ + // Adds the energy particles lose in a collision to the pulse-height + + // determine index of cell in pulse_height_cells + auto it = std::find(model::pulse_height_cells.begin(), + model::pulse_height_cells.end(), lowest_coord().cell); + + if (it != model::pulse_height_cells.end()) { + int index = std::distance(model::pulse_height_cells.begin(), it); + pht_storage()[index] += E_last() - E(); + + // If the energy of the particle is below the cutoff, it will not be sampled + // so its energy is added to the pulse-height in the cell + int photon = static_cast(ParticleType::photon); + if (E() < settings::energy_cutoff[photon]) { + pht_storage()[index] += E(); + } + } +} -void -Particle::cross_surface() +void Particle::pht_secondary_particles() +{ + // Removes the energy of secondary produced particles from the pulse-height + + // determine index of cell in pulse_height_cells + auto it = std::find(model::pulse_height_cells.begin(), + model::pulse_height_cells.end(), cell_born()); + + if (it != model::pulse_height_cells.end()) { + int index = std::distance(model::pulse_height_cells.begin(), it); + pht_storage()[index] -= E(); + } +} + +void Particle::cross_surface() { int i_surface = std::abs(surface()); // TODO: off-by-one @@ -363,11 +511,13 @@ Particle::cross_surface() write_message(1, " Crossing surface {}", surf->id_); } - if (surf->surf_source_ && simulation::current_batch == settings::n_batches) { + if (surf->surf_source_ && simulation::current_batch > settings::n_inactive && + !simulation::surf_source_bank.full()) { SourceSite site; site.r = r(); site.u = u(); site.E = E(); + site.time = time(); site.wgt = wgt(); site.delayed_group = delayed_group(); site.surf_id = surf->id_; @@ -377,6 +527,12 @@ Particle::cross_surface() int64_t idx = simulation::surf_source_bank.thread_safe_append(site); } +// if we're crossing a CSG surface, make sure the DAG history is reset +#ifdef DAGMC + if (surf->geom_type_ == GeometryType::CSG) + history().reset(); +#endif + // Handle any applicable boundary conditions. if (surf->bc_ && settings::run_mode != RunMode::PLOTTING) { surf->bc_->handle_particle(*this, *surf); @@ -387,17 +543,16 @@ Particle::cross_surface() // SEARCH NEIGHBOR LISTS FOR NEXT CELL #ifdef DAGMC - if (settings::dagmc) { - auto cellp = dynamic_cast(model::cells[cell_last(0)].get()); - // TODO: off-by-one - auto surfp = - dynamic_cast(model::surfaces[std::abs(surface()) - 1].get()); - int32_t i_cell = next_cell(cellp, surfp) - 1; + // in DAGMC, we know what the next cell should be + if (surf->geom_type_ == GeometryType::DAG) { + int32_t i_cell = + next_cell(i_surface, cell_last(n_coord() - 1), lowest_coord().universe) - + 1; // save material and temp material_last() = material(); sqrtkT_last() = sqrtkT(); // set new cell value - coord(0).cell = i_cell; + lowest_coord().cell = i_cell; cell_instance() = 0; material() = model::cells[i_cell]->material_[0]; sqrtkT() = model::cells[i_cell]->sqrtkT_[0]; @@ -405,16 +560,16 @@ Particle::cross_surface() } #endif - if (neighbor_list_find_cell(*this)) + bool verbose = settings::verbosity >= 10 || trace(); + if (neighbor_list_find_cell(*this, verbose)) return; // ========================================================================== // COULDN'T FIND PARTICLE IN NEIGHBORING CELLS, SEARCH ALL CELLS - // Remove lower coordinate levels and assignment of surface - surface() = 0; + // Remove lower coordinate levels n_coord() = 1; - bool found = exhaustive_find_cell(*this); + bool found = exhaustive_find_cell(*this, verbose); if (settings::run_mode != RunMode::PLOTTING && (!found)) { // If a cell is still not found, there are two possible causes: 1) there is @@ -422,13 +577,14 @@ Particle::cross_surface() // the particle is really traveling tangent to a surface, if we move it // forward a tiny bit it should fix the problem. + surface() = 0; n_coord() = 1; r() += TINY_BIT * u(); // Couldn't find next cell anywhere! This probably means there is an actual // undefined region in the geometry. - if (!exhaustive_find_cell(*this)) { + if (!exhaustive_find_cell(*this, verbose)) { mark_as_lost("After particle " + std::to_string(id()) + " crossed surface " + std::to_string(surf->id_) + " it could not be located in any cell and it did not leak."); @@ -437,12 +593,8 @@ Particle::cross_surface() } } -void -Particle::cross_vacuum_bc(const Surface& surf) +void Particle::cross_vacuum_bc(const Surface& surf) { - // Kill the particle - alive() = false; - // Score any surface current tallies -- note that the particle is moved // forward slightly so that if the mesh boundary is on the surface, it is // still processed @@ -458,14 +610,16 @@ Particle::cross_vacuum_bc(const Surface& surf) // Score to global leakage tally keff_tally_leakage() += wgt(); + // Kill the particle + wgt() = 0.0; + // Display message if (settings::verbosity >= 10 || trace()) { write_message(1, " Leaked out of surface {}", surf.id_); } } -void -Particle::cross_reflective_bc(const Surface& surf, Direction new_u) +void Particle::cross_reflective_bc(const Surface& surf, Direction new_u) { // Do not handle reflective boundary conditions on lower universes if (n_coord() != 1) { @@ -503,13 +657,11 @@ Particle::cross_reflective_bc(const Surface& surf, Direction new_u) // boundary, it is necessary to redetermine the particle's coordinates in // the lower universes. // (unless we're using a dagmc model, which has exactly one universe) - if (!settings::dagmc) { - n_coord() = 1; - if (!neighbor_list_find_cell(*this)) { - mark_as_lost("Couldn't find particle after reflecting from surface " + - std::to_string(surf.id_) + "."); - return; - } + n_coord() = 1; + if (surf.geom_type_ != GeometryType::DAG && !neighbor_list_find_cell(*this)) { + mark_as_lost("Couldn't find particle after reflecting from surface " + + std::to_string(surf.id_) + "."); + return; } // Set previous coordinate going slightly past surface crossing @@ -521,9 +673,8 @@ Particle::cross_reflective_bc(const Surface& surf, Direction new_u) } } -void -Particle::cross_periodic_bc(const Surface& surf, Position new_r, - Direction new_u, int new_surface) +void Particle::cross_periodic_bc( + const Surface& surf, Position new_r, Direction new_u, int new_surface) { // Do not handle periodic boundary conditions on lower universes if (n_coord() != 1) { @@ -572,41 +723,42 @@ Particle::cross_periodic_bc(const Surface& surf, Position new_r, } } -void -Particle::mark_as_lost(const char* message) +void Particle::mark_as_lost(const char* message) { // Print warning and write lost particle file warning(message); - write_restart(); - + if (settings::max_write_lost_particles < 0 || + simulation::n_lost_particles < settings::max_write_lost_particles) { + write_restart(); + } // Increment number of lost particles - alive() = false; + wgt() = 0.0; #pragma omp atomic simulation::n_lost_particles += 1; // Count the total number of simulated particles (on this processor) auto n = simulation::current_batch * settings::gen_per_batch * - simulation::work_per_rank; + simulation::work_per_rank; // Abort the simulation if the maximum number of lost particles has been // reached if (simulation::n_lost_particles >= settings::max_lost_particles && - simulation::n_lost_particles >= settings::rel_max_lost_particles*n) { + simulation::n_lost_particles >= settings::rel_max_lost_particles * n) { fatal_error("Maximum number of lost particles has been reached."); } } -void -Particle::write_restart() const +void Particle::write_restart() const { // Dont write another restart file if in particle restart mode - if (settings::run_mode == RunMode::PARTICLE) return; + if (settings::run_mode == RunMode::PARTICLE) + return; // Set up file name auto filename = fmt::format("{}particle_{}_{}.h5", settings::path_output, simulation::current_batch, id()); -#pragma omp critical (WriteParticleRestart) +#pragma omp critical(WriteParticleRestart) { // Create file hid_t file_id = file_open(filename, 'w'); @@ -625,32 +777,34 @@ Particle::write_restart() const write_dataset(file_id, "current_generation", simulation::current_gen); write_dataset(file_id, "n_particles", settings::n_particles); switch (settings::run_mode) { - case RunMode::FIXED_SOURCE: - write_dataset(file_id, "run_mode", "fixed source"); - break; - case RunMode::EIGENVALUE: - write_dataset(file_id, "run_mode", "eigenvalue"); - break; - case RunMode::PARTICLE: - write_dataset(file_id, "run_mode", "particle restart"); - break; - default: - break; + case RunMode::FIXED_SOURCE: + write_dataset(file_id, "run_mode", "fixed source"); + break; + case RunMode::EIGENVALUE: + write_dataset(file_id, "run_mode", "eigenvalue"); + break; + case RunMode::PARTICLE: + write_dataset(file_id, "run_mode", "particle restart"); + break; + default: + break; } write_dataset(file_id, "id", id()); write_dataset(file_id, "type", static_cast(type())); int64_t i = current_work(); if (settings::run_mode == RunMode::EIGENVALUE) { - //take source data from primary bank for eigenvalue simulation - write_dataset(file_id, "weight", simulation::source_bank[i-1].wgt); - write_dataset(file_id, "energy", simulation::source_bank[i-1].E); - write_dataset(file_id, "xyz", simulation::source_bank[i-1].r); - write_dataset(file_id, "uvw", simulation::source_bank[i-1].u); + // take source data from primary bank for eigenvalue simulation + write_dataset(file_id, "weight", simulation::source_bank[i - 1].wgt); + write_dataset(file_id, "energy", simulation::source_bank[i - 1].E); + write_dataset(file_id, "xyz", simulation::source_bank[i - 1].r); + write_dataset(file_id, "uvw", simulation::source_bank[i - 1].u); + write_dataset(file_id, "time", simulation::source_bank[i - 1].time); } else if (settings::run_mode == RunMode::FIXED_SOURCE) { // re-sample using rng random number seed used to generate source particle - int64_t id = (simulation::total_gen + overall_generation() - 1)*settings::n_particles + - simulation::work_index[mpi::rank] + i; + int64_t id = (simulation::total_gen + overall_generation() - 1) * + settings::n_particles + + simulation::work_index[mpi::rank] + i; uint64_t seed = init_seed(id, STREAM_SOURCE); // re-sample source site auto site = sample_external_source(&seed); @@ -658,6 +812,7 @@ Particle::write_restart() const write_dataset(file_id, "energy", site.E); write_dataset(file_id, "xyz", site.r); write_dataset(file_id, "uvw", site.u); + write_dataset(file_id, "time", site.time); } // Close file @@ -665,6 +820,29 @@ Particle::write_restart() const } // #pragma omp critical } +void Particle::update_neutron_xs( + int i_nuclide, int i_grid, int i_sab, double sab_frac, double ncrystal_xs) +{ + // Get microscopic cross section cache + auto& micro = this->neutron_xs(i_nuclide); + + // If the cache doesn't match, recalculate micro xs + if (this->E() != micro.last_E || this->sqrtkT() != micro.last_sqrtkT || + i_sab != micro.index_sab || sab_frac != micro.sab_frac) { + data::nuclides[i_nuclide]->calculate_xs(i_sab, i_grid, sab_frac, *this); + + // If NCrystal is being used, update micro cross section cache + if (ncrystal_xs >= 0.0) { + data::nuclides[i_nuclide]->calculate_elastic_xs(*this); + ncrystal_update_micro(ncrystal_xs, micro); + } + } +} + +//============================================================================== +// Non-method functions +//============================================================================== + std::string particle_type_to_str(ParticleType type) { switch (type) { @@ -691,7 +869,7 @@ ParticleType str_to_particle_type(std::string str) } else if (str == "positron") { return ParticleType::positron; } else { - throw std::invalid_argument{fmt::format("Invalid particle name: {}", str)}; + throw std::invalid_argument {fmt::format("Invalid particle name: {}", str)}; } } diff --git a/src/particle_data.cpp b/src/particle_data.cpp index 701e6cbc0ef..d8a5bb9d99c 100644 --- a/src/particle_data.cpp +++ b/src/particle_data.cpp @@ -1,6 +1,11 @@ #include "openmc/particle_data.h" +#include + +#include "openmc/cell.h" +#include "openmc/error.h" #include "openmc/geometry.h" +#include "openmc/material.h" #include "openmc/nuclide.h" #include "openmc/photon.h" #include "openmc/settings.h" @@ -10,6 +15,21 @@ namespace openmc { +void GeometryState::mark_as_lost(const std::string& message) +{ + mark_as_lost(message.c_str()); +} + +void GeometryState::mark_as_lost(const std::stringstream& message) +{ + mark_as_lost(message.str()); +} + +void GeometryState::mark_as_lost(const char* message) +{ + fatal_error(message); +} + void LocalCoord::rotate(const vector& rotation) { r = r.rotate(rotation); @@ -28,13 +48,16 @@ void LocalCoord::reset() rotated = false; } -ParticleData::ParticleData() +GeometryState::GeometryState() { // Create and clear coordinate levels coord_.resize(model::n_coord_levels); cell_last_.resize(model::n_coord_levels); clear(); +} +ParticleData::ParticleData() +{ zero_delayed_bank(); // Every particle starts with no accumulated flux derivative. Note that in @@ -51,6 +74,27 @@ ParticleData::ParticleData() // Create microscopic cross section caches neutron_xs_.resize(data::nuclides.size()); photon_xs_.resize(data::elements.size()); + + // Creates the pulse-height storage for the particle + if (!model::pulse_height_cells.empty()) { + pht_storage_.resize(model::pulse_height_cells.size(), 0.0); + } +} + +TrackState ParticleData::get_track_state() const +{ + TrackState state; + state.r = this->r(); + state.u = this->u(); + state.E = this->E(); + state.time = this->time(); + state.wgt = this->wgt(); + state.cell_id = model::cells[this->lowest_coord().cell]->id_; + state.cell_instance = this->cell_instance(); + if (this->material() != MATERIAL_VOID) { + state.material_id = model::materials[material()]->id_; + } + return state; } } // namespace openmc diff --git a/src/particle_restart.cpp b/src/particle_restart.cpp index 7150bc6da18..6b7778211af 100644 --- a/src/particle_restart.cpp +++ b/src/particle_restart.cpp @@ -24,7 +24,8 @@ namespace openmc { void read_particle_restart(Particle& p, RunMode& previous_run_mode) { // Write meessage - write_message(5, "Loading particle restart file {}", settings::path_particle_restart); + write_message( + 5, "Loading particle restart file {}", settings::path_particle_restart); // Open file hid_t file_id = file_open(settings::path_particle_restart, 'r'); @@ -49,6 +50,7 @@ void read_particle_restart(Particle& p, RunMode& previous_run_mode) read_dataset(file_id, "energy", p.E()); read_dataset(file_id, "xyz", p.r()); read_dataset(file_id, "uvw", p.u()); + read_dataset(file_id, "time", p.time()); // Set energy group and average energy in multi-group mode if (!settings::run_CE) { @@ -63,6 +65,7 @@ void read_particle_restart(Particle& p, RunMode& previous_run_mode) p.u_last() = p.u(); p.E_last() = p.E(); p.g_last() = p.g(); + p.time_last() = p.time(); // Close hdf5 file file_close(file_id); @@ -84,8 +87,10 @@ void run_particle_restart() read_particle_restart(p, previous_run_mode); // write track if that was requested on command line - if (settings::write_all_tracks) + if (settings::write_all_tracks) { + open_track_file(); p.write_track() = true; + } // Set all tallies to 0 for now (just tracking errors) model::tallies.clear(); @@ -94,15 +99,14 @@ void run_particle_restart() int64_t particle_seed; switch (previous_run_mode) { case RunMode::EIGENVALUE: + case RunMode::FIXED_SOURCE: particle_seed = (simulation::total_gen + overall_generation() - 1) * settings::n_particles + p.id(); break; - case RunMode::FIXED_SOURCE: - particle_seed = p.id(); - break; default: - throw std::runtime_error{"Unexpected run mode: " + + throw std::runtime_error { + "Unexpected run mode: " + std::to_string(static_cast(previous_run_mode))}; } init_particle_seeds(particle_seed, p.seeds()); @@ -121,6 +125,10 @@ void run_particle_restart() // Write output if particle made it print_particle(p); + + if (settings::write_all_tracks) { + close_track_file(); + } } } // namespace openmc diff --git a/src/photon.cpp b/src/photon.cpp index 1e9a2557a73..08062a2e9f5 100644 --- a/src/photon.cpp +++ b/src/photon.cpp @@ -5,6 +5,7 @@ #include "openmc/constants.h" #include "openmc/distribution_multi.h" #include "openmc/hdf5_interface.h" +#include "openmc/message_passing.h" #include "openmc/nuclide.h" #include "openmc/particle.h" #include "openmc/random_dist.h" @@ -13,14 +14,19 @@ #include "openmc/settings.h" #include "xtensor/xbuilder.hpp" +#include "xtensor/xmath.hpp" #include "xtensor/xoperation.hpp" +#include "xtensor/xslice.hpp" #include "xtensor/xview.hpp" #include +#include #include // for tie namespace openmc { +constexpr int PhotonInteraction::MAX_STACK_SIZE; + //============================================================================== // Global variables //============================================================================== @@ -40,6 +46,8 @@ vector> elements; PhotonInteraction::PhotonInteraction(hid_t group) { + using namespace xt::placeholders; + // Set index of element in global vector index_ = data::elements.size(); @@ -58,18 +66,18 @@ PhotonInteraction::PhotonInteraction(hid_t group) read_dataset(rgroup, "xs", coherent_); hid_t dset = open_dataset(rgroup, "integrated_scattering_factor"); - coherent_int_form_factor_ = Tabulated1D{dset}; + coherent_int_form_factor_ = Tabulated1D {dset}; close_dataset(dset); if (object_exists(group, "anomalous_real")) { dset = open_dataset(rgroup, "anomalous_real"); - coherent_anomalous_real_ = Tabulated1D{dset}; + coherent_anomalous_real_ = Tabulated1D {dset}; close_dataset(dset); } if (object_exists(group, "anomalous_imag")) { dset = open_dataset(rgroup, "anomalous_imag"); - coherent_anomalous_imag_ = Tabulated1D{dset}; + coherent_anomalous_imag_ = Tabulated1D {dset}; close_dataset(dset); } close_group(rgroup); @@ -78,14 +86,18 @@ PhotonInteraction::PhotonInteraction(hid_t group) rgroup = open_group(group, "incoherent"); read_dataset(rgroup, "xs", incoherent_); dset = open_dataset(rgroup, "scattering_factor"); - incoherent_form_factor_ = Tabulated1D{dset}; + incoherent_form_factor_ = Tabulated1D {dset}; close_dataset(dset); close_group(rgroup); // Read pair production - rgroup = open_group(group, "pair_production_electron"); - read_dataset(rgroup, "xs", pair_production_electron_); - close_group(rgroup); + if (object_exists(group, "pair_production_electron")) { + rgroup = open_group(group, "pair_production_electron"); + read_dataset(rgroup, "xs", pair_production_electron_); + close_group(rgroup); + } else { + pair_production_electron_ = xt::zeros_like(energy_); + } // Read pair production if (object_exists(group, "pair_production_nuclear")) { @@ -116,44 +128,56 @@ PhotonInteraction::PhotonInteraction(hid_t group) read_attribute(rgroup, "designators", designators); auto n_shell = designators.size(); if (n_shell == 0) { - throw std::runtime_error{"Photoatomic data for " + name_ + - " does not have subshell data."}; + throw std::runtime_error { + "Photoatomic data for " + name_ + " does not have subshell data."}; } + shells_.resize(n_shell); + cross_sections_ = xt::zeros({energy_.size(), n_shell}); + + // Create mapping from designator to index + std::unordered_map shell_map; for (int i = 0; i < n_shell; ++i) { const auto& designator {designators[i]}; - // TODO: Move to ElectronSubshell constructor - - // Add empty shell - shells_.emplace_back(); - - // Create mapping from designator to index int j = 1; for (const auto& subshell : SUBSHELLS) { if (designator == subshell) { - shell_map_[j] = i; + shell_map[j] = i; shells_[i].index_subshell = j; break; } ++j; } + } + shell_map[0] = -1; + + for (int i = 0; i < n_shell; ++i) { + const auto& designator {designators[i]}; + auto& shell {shells_[i]}; + + // TODO: Move to ElectronSubshell constructor - // Read binding energy and number of electrons - auto& shell {shells_.back()}; hid_t tgroup = open_group(rgroup, designator.c_str()); - read_attribute(tgroup, "binding_energy", shell.binding_energy); - read_attribute(tgroup, "num_electrons", shell.n_electrons); + + // Read binding energy energy and number of electrons if atomic relaxation + // data is present + if (attribute_exists(tgroup, "binding_energy")) { + has_atomic_relaxation_ = true; + read_attribute(tgroup, "binding_energy", shell.binding_energy); + read_attribute(tgroup, "num_electrons", shell.n_electrons); + } // Read subshell cross section + xt::xtensor xs; dset = open_dataset(tgroup, "xs"); - read_attribute(dset, "threshold_idx", j); - shell.threshold = j; + read_attribute(dset, "threshold_idx", shell.threshold); close_dataset(dset); - read_dataset(tgroup, "xs", shell.cross_section); + read_dataset(tgroup, "xs", xs); - auto& xs = shell.cross_section; - xs = xt::where(xs > 0.0, xt::log(xs), -500.0); + auto cross_section = + xt::view(cross_sections_, xt::range(shell.threshold, _), i); + cross_section = xt::where(xs > 0, xt::log(xs), 0); if (object_exists(tgroup, "transitions")) { // Determine dimensions of transitions @@ -162,23 +186,36 @@ PhotonInteraction::PhotonInteraction(hid_t group) close_dataset(dset); int n_transition = dims[0]; - shell.n_transitions = n_transition; if (n_transition > 0) { xt::xtensor matrix; read_dataset(tgroup, "transitions", matrix); - shell.transition_subshells = xt::view(matrix, xt::all(), xt::range(0, 2)); - shell.transition_energy = xt::view(matrix, xt::all(), 2); - shell.transition_probability = xt::view(matrix, xt::all(), 3); - shell.transition_probability /= xt::sum(shell.transition_probability)(); + // Transition probability normalization + double norm = xt::sum(xt::col(matrix, 3))(); + + shell.transitions.resize(n_transition); + for (int j = 0; j < n_transition; ++j) { + auto& transition = shell.transitions[j]; + transition.primary_subshell = shell_map.at(matrix(j, 0)); + transition.secondary_subshell = shell_map.at(matrix(j, 1)); + transition.energy = matrix(j, 2); + transition.probability = matrix(j, 3) / norm; + } } - } else { - shell.n_transitions = 0; } close_group(tgroup); } close_group(rgroup); + // Check the maximum size of the atomic relaxation stack + auto max_size = this->calc_max_stack_size(); + if (max_size > MAX_STACK_SIZE && mpi::master) { + warning(fmt::format( + "The subshell vacancy stack in atomic relaxation can grow up to {}, but " + "the stack size limit is set to {}.", + max_size, MAX_STACK_SIZE)); + } + // Determine number of electron shells rgroup = open_group(group, "compton_profiles"); @@ -198,14 +235,16 @@ PhotonInteraction::PhotonInteraction(hid_t group) // Create Compton profile CDF auto n_profile = data::compton_profile_pz.size(); - profile_cdf_ = xt::empty({n_shell, n_profile}); - for (int i = 0; i < n_shell; ++i) { + auto n_shell_compton = profile_pdf_.shape(0); + profile_cdf_ = xt::empty({n_shell_compton, n_profile}); + for (int i = 0; i < n_shell_compton; ++i) { double c = 0.0; - profile_cdf_(i,0) = 0.0; + profile_cdf_(i, 0) = 0.0; for (int j = 0; j < n_profile - 1; ++j) { - c += 0.5*(data::compton_profile_pz(j+1) - data::compton_profile_pz(j)) * - (profile_pdf_(i,j) + profile_pdf_(i,j+1)); - profile_cdf_(i,j+1) = c; + c += 0.5 * + (data::compton_profile_pz(j + 1) - data::compton_profile_pz(j)) * + (profile_pdf_(i, j) + profile_pdf_(i, j + 1)); + profile_cdf_(i, j + 1) = c; } } @@ -237,18 +276,19 @@ PhotonInteraction::PhotonInteraction(hid_t group) const auto& E {electron_energy}; double cutoff = settings::energy_cutoff[photon]; if (cutoff > E(0)) { - size_t i_grid = lower_bound_index(E.cbegin(), E.cend(), - settings::energy_cutoff[photon]); + size_t i_grid = lower_bound_index( + E.cbegin(), E.cend(), settings::energy_cutoff[photon]); // calculate interpolation factor double f = (std::log(cutoff) - std::log(E(i_grid))) / - (std::log(E(i_grid+1)) - std::log(E(i_grid))); + (std::log(E(i_grid + 1)) - std::log(E(i_grid))); // Interpolate bremsstrahlung DCS at the cutoff energy and truncate xt::xtensor dcs({n_e - i_grid, n_k}); for (int i = 0; i < n_k; ++i) { - double y = std::exp(std::log(dcs_(i_grid,i)) + - f*(std::log(dcs_(i_grid+1,i)) - std::log(dcs_(i_grid,i)))); + double y = std::exp( + std::log(dcs_(i_grid, i)) + + f * (std::log(dcs_(i_grid + 1, i)) - std::log(dcs_(i_grid, i)))); auto col_i = xt::view(dcs, xt::all(), i); col_i(0) = y; for (int j = i_grid + 1; j < n_e; ++j) { @@ -259,7 +299,7 @@ PhotonInteraction::PhotonInteraction(hid_t group) xt::xtensor frst {cutoff}; electron_energy = xt::concatenate(xt::xtuple( - frst, xt::view(electron_energy, xt::range(i_grid+1, n_e)))); + frst, xt::view(electron_energy, xt::range(i_grid + 1, n_e)))); } // Set incident particle energy grid @@ -273,15 +313,15 @@ PhotonInteraction::PhotonInteraction(hid_t group) // Integrate over reduced photon energy double c = 0.0; for (int j = 0; j < data::ttb_k_grid.size() - 1; ++j) { - c += 0.5 * (dcs_(i, j+1) + dcs_(i, j)) * (data::ttb_k_grid(j+1) - - data::ttb_k_grid(j)); + c += 0.5 * (dcs_(i, j + 1) + dcs_(i, j)) * + (data::ttb_k_grid(j + 1) - data::ttb_k_grid(j)); } double e = data::ttb_e_grid(i); // Square of the ratio of the speed of light to the velocity of the // charged particle - double beta_sq = e * (e + 2.0 * MASS_ELECTRON_EV) / ((e + - MASS_ELECTRON_EV) * (e + MASS_ELECTRON_EV)); + double beta_sq = e * (e + 2.0 * MASS_ELECTRON_EV) / + ((e + MASS_ELECTRON_EV) * (e + MASS_ELECTRON_EV)); stopping_power_radiative_(i) = Z_ * Z_ / beta_sq * e * c; } @@ -292,10 +332,10 @@ PhotonInteraction::PhotonInteraction(hid_t group) energy_ = xt::log(energy_); coherent_ = xt::where(coherent_ > 0.0, xt::log(coherent_), -500.0); incoherent_ = xt::where(incoherent_ > 0.0, xt::log(incoherent_), -500.0); - photoelectric_total_ = xt::where(photoelectric_total_ > 0.0, - xt::log(photoelectric_total_), -500.0); - pair_production_total_ = xt::where(pair_production_total_ > 0.0, - xt::log(pair_production_total_), -500.0); + photoelectric_total_ = xt::where( + photoelectric_total_ > 0.0, xt::log(photoelectric_total_), -500.0); + pair_production_total_ = xt::where( + pair_production_total_ > 0.0, xt::log(pair_production_total_), -500.0); heating_ = xt::where(heating_ > 0.0, xt::log(heating_), -500.0); } @@ -304,6 +344,54 @@ PhotonInteraction::~PhotonInteraction() data::element_map.erase(name_); } +int PhotonInteraction::calc_max_stack_size() const +{ + // Table to store solutions to sub-problems + std::unordered_map visited; + + // Find the maximum possible size of the stack used to store holes created + // during atomic relaxation, checking over every subshell the initial hole + // could be in + int max_size = 0; + for (int i_shell = 0; i_shell < shells_.size(); ++i_shell) { + max_size = std::max(max_size, this->calc_helper(visited, i_shell)); + } + return max_size; +} + +int PhotonInteraction::calc_helper( + std::unordered_map& visited, int i_shell) const +{ + // No transitions for this subshell, so this is the only shell in the stack + const auto& shell {shells_[i_shell]}; + if (shell.transitions.empty()) { + return 1; + } + + // Check the table to see if the maximum stack size has already been + // calculated for this shell + auto it = visited.find(i_shell); + if (it != visited.end()) { + return it->second; + } + + int max_size = 0; + for (const auto& transition : shell.transitions) { + // If this is a non-radiative transition two vacancies are created and + // the stack grows by one; if this is a radiative transition only one + // vacancy is created and the stack size stays the same + int size = 0; + if (transition.secondary_subshell != -1) { + size = this->calc_helper(visited, transition.secondary_subshell) + 1; + } + size = + std::max(size, this->calc_helper(visited, transition.primary_subshell)); + max_size = std::max(max_size, size); + } + visited[i_shell] = max_size; + return max_size; +} + void PhotonInteraction::compton_scatter(double alpha, bool doppler, double* alpha_out, double* mu, int* i_shell, uint64_t* seed) const { @@ -315,12 +403,14 @@ void PhotonInteraction::compton_scatter(double alpha, bool doppler, // Note that the parameter used here does not correspond exactly to the // momentum transfer q in ENDF-102 Eq. (27.2). Rather, this is the // parameter as defined by Hubbell, where the actual data comes from - double x = MASS_ELECTRON_EV/PLANCK_C*alpha*std::sqrt(0.5*(1.0 - *mu)); + double x = + MASS_ELECTRON_EV / PLANCK_C * alpha * std::sqrt(0.5 * (1.0 - *mu)); // Calculate S(x, Z) and S(x_max, Z) double form_factor_x = incoherent_form_factor_(x); if (form_factor_xmax == 0.0) { - form_factor_xmax = incoherent_form_factor_(MASS_ELECTRON_EV/PLANCK_C*alpha); + form_factor_xmax = + incoherent_form_factor_(MASS_ELECTRON_EV / PLANCK_C * alpha); } // Perform rejection on form factor @@ -328,7 +418,14 @@ void PhotonInteraction::compton_scatter(double alpha, bool doppler, if (doppler) { double E_out; this->compton_doppler(alpha, *mu, &E_out, i_shell, seed); - *alpha_out = E_out/MASS_ELECTRON_EV; + *alpha_out = E_out / MASS_ELECTRON_EV; + + // It's possible for the Compton profile data to have more shells than + // there are in the ENDF data. Make sure the shell index doesn't end up + // out of bounds. + if (*i_shell >= shells_.size()) { + *i_shell = -1; + } } else { *i_shell = -1; } @@ -337,8 +434,8 @@ void PhotonInteraction::compton_scatter(double alpha, bool doppler, } } -void PhotonInteraction::compton_doppler(double alpha, double mu, - double* E_out, int* i_shell, uint64_t* seed) const +void PhotonInteraction::compton_doppler( + double alpha, double mu, double* E_out, int* i_shell, uint64_t* seed) const { auto n = data::compton_profile_pz.size(); @@ -349,23 +446,24 @@ void PhotonInteraction::compton_doppler(double alpha, double mu, double c = 0.0; for (shell = 0; shell < electron_pdf_.size(); ++shell) { c += electron_pdf_(shell); - if (rn < c) break; + if (rn < c) + break; } // Determine binding energy of shell double E_b = binding_energy_(shell); // Determine p_z,max - double E = alpha*MASS_ELECTRON_EV; + double E = alpha * MASS_ELECTRON_EV; if (E < E_b) { - *E_out = alpha/(1 + alpha*(1 - mu))*MASS_ELECTRON_EV; + *E_out = alpha / (1 + alpha * (1 - mu)) * MASS_ELECTRON_EV; break; } - double pz_max = -FINE_STRUCTURE*(E_b - (E - E_b)*alpha*(1.0 - mu)) / - std::sqrt(2.0*E*(E - E_b)*(1.0 - mu) + E_b*E_b); + double pz_max = -FINE_STRUCTURE * (E_b - (E - E_b) * alpha * (1.0 - mu)) / + std::sqrt(2.0 * E * (E - E_b) * (1.0 - mu) + E_b * E_b); if (pz_max < 0.0) { - *E_out = alpha/(1 + alpha*(1 - mu))*MASS_ELECTRON_EV; + *E_out = alpha / (1 + alpha * (1 - mu)) * MASS_ELECTRON_EV; break; } @@ -384,15 +482,16 @@ void PhotonInteraction::compton_doppler(double alpha, double mu, if (pz_l == pz_r) { c_max = c_l; } else if (p_l == p_r) { - c_max = c_l + (pz_max - pz_l)*p_l; + c_max = c_l + (pz_max - pz_l) * p_l; } else { - double m = (p_l - p_r)/(pz_l - pz_r); - c_max = c_l + (std::pow((m*(pz_max - pz_l) + p_l), 2) - p_l*p_l)/(2.0*m); + double m = (p_l - p_r) / (pz_l - pz_r); + c_max = c_l + (std::pow((m * (pz_max - pz_l) + p_l), 2) - p_l * p_l) / + (2.0 * m); } } // Sample value on bounded cdf - c = prn(seed)*c_max; + c = prn(seed) * c_max; // Determine pz corresponding to sampled cdf value auto cdf_shell = xt::view(profile_cdf_, shell, xt::all()); @@ -406,28 +505,28 @@ void PhotonInteraction::compton_doppler(double alpha, double mu, if (pz_l == pz_r) { pz = pz_l; } else if (p_l == p_r) { - pz = pz_l + (c - c_l)/p_l; + pz = pz_l + (c - c_l) / p_l; } else { - double m = (p_l - p_r)/(pz_l - pz_r); - pz = pz_l + (std::sqrt(p_l*p_l + 2.0*m*(c - c_l)) - p_l)/m; + double m = (p_l - p_r) / (pz_l - pz_r); + pz = pz_l + (std::sqrt(p_l * p_l + 2.0 * m * (c - c_l)) - p_l) / m; } // Determine outgoing photon energy corresponding to electron momentum // (solve Eq. 39 in LA-UR-04-0487 for E') - double momentum_sq = std::pow((pz/FINE_STRUCTURE), 2); - double f = 1.0 + alpha*(1.0 - mu); - double a = momentum_sq - f*f; - double b = 2.0*E*(f - momentum_sq*mu); - c = E*E*(momentum_sq - 1.0); + double momentum_sq = std::pow((pz / FINE_STRUCTURE), 2); + double f = 1.0 + alpha * (1.0 - mu); + double a = momentum_sq - f * f; + double b = 2.0 * E * (f - momentum_sq * mu); + c = E * E * (momentum_sq - 1.0); - double quad = b*b - 4.0*a*c; + double quad = b * b - 4.0 * a * c; if (quad < 0) { - *E_out = alpha/(1 + alpha*(1 - mu))*MASS_ELECTRON_EV; + *E_out = alpha / (1 + alpha * (1 - mu)) * MASS_ELECTRON_EV; break; } quad = std::sqrt(quad); - double E_out1 = -(b + quad)/(2.0*a); - double E_out2 = -(b - quad)/(2.0*a); + double E_out1 = -(b + quad) / (2.0 * a); + double E_out2 = -(b - quad) / (2.0 * a); // Determine solution to quadratic equation that is positive if (E_out1 > 0.0) { @@ -445,7 +544,8 @@ void PhotonInteraction::compton_doppler(double alpha, double mu, continue; } } - if (*E_out < E - E_b) break; + if (*E_out < E - E_b) + break; } *i_shell = shell; @@ -469,45 +569,43 @@ void PhotonInteraction::calculate_xs(Particle& p) const } // check for case where two energy points are the same - if (energy_(i_grid) == energy_(i_grid+1)) ++i_grid; + if (energy_(i_grid) == energy_(i_grid + 1)) + ++i_grid; // calculate interpolation factor - double f = (log_E - energy_(i_grid)) / (energy_(i_grid+1) - energy_(i_grid)); + double f = + (log_E - energy_(i_grid)) / (energy_(i_grid + 1) - energy_(i_grid)); auto& xs {p.photon_xs(index_)}; xs.index_grid = i_grid; xs.interp_factor = f; // Calculate microscopic coherent cross section - xs.coherent = std::exp(coherent_(i_grid) + - f*(coherent_(i_grid+1) - coherent_(i_grid))); + xs.coherent = std::exp( + coherent_(i_grid) + f * (coherent_(i_grid + 1) - coherent_(i_grid))); // Calculate microscopic incoherent cross section - xs.incoherent = std::exp(incoherent_(i_grid) + - f*(incoherent_(i_grid+1) - incoherent_(i_grid))); + xs.incoherent = std::exp( + incoherent_(i_grid) + f * (incoherent_(i_grid + 1) - incoherent_(i_grid))); // Calculate microscopic photoelectric cross section xs.photoelectric = 0.0; - for (const auto& shell : shells_) { - // Check threshold of reaction - int i_start = shell.threshold; - if (i_grid < i_start) continue; - - // Evaluation subshell photoionization cross section - xs.photoelectric += - std::exp(shell.cross_section(i_grid-i_start) + - f*(shell.cross_section(i_grid+1-i_start) - - shell.cross_section(i_grid-i_start))); - } + const auto& xs_lower = xt::row(cross_sections_, i_grid); + const auto& xs_upper = xt::row(cross_sections_, i_grid + 1); + + for (int i = 0; i < xs_upper.size(); ++i) + if (xs_lower(i) != 0) + xs.photoelectric += + std::exp(xs_lower(i) + f * (xs_upper(i) - xs_lower(i))); // Calculate microscopic pair production cross section xs.pair_production = std::exp( - pair_production_total_(i_grid) + f*( - pair_production_total_(i_grid+1) - - pair_production_total_(i_grid))); + pair_production_total_(i_grid) + + f * (pair_production_total_(i_grid + 1) - pair_production_total_(i_grid))); // Calculate microscopic total cross section - xs.total = xs.coherent + xs.incoherent + xs.photoelectric + xs.pair_production; + xs.total = + xs.coherent + xs.incoherent + xs.photoelectric + xs.pair_production; xs.last_E = p.E(); } @@ -516,25 +614,26 @@ double PhotonInteraction::rayleigh_scatter(double alpha, uint64_t* seed) const double mu; while (true) { // Determine maximum value of x^2 - double x2_max = std::pow(MASS_ELECTRON_EV/PLANCK_C*alpha, 2); + double x2_max = std::pow(MASS_ELECTRON_EV / PLANCK_C * alpha, 2); // Determine F(x^2_max, Z) double F_max = coherent_int_form_factor_(x2_max); // Sample cumulative distribution - double F = prn(seed)*F_max; + double F = prn(seed) * F_max; // Determine x^2 corresponding to F const auto& x {coherent_int_form_factor_.x()}; const auto& y {coherent_int_form_factor_.y()}; int i = lower_bound_index(y.cbegin(), y.cend(), F); - double r = (F - y[i]) / (y[i+1] - y[i]); - double x2 = x[i] + r*(x[i+1] - x[i]); + double r = (F - y[i]) / (y[i + 1] - y[i]); + double x2 = x[i] + r * (x[i + 1] - x[i]); // Calculate mu - mu = 1.0 - 2.0*x2/x2_max; + mu = 1.0 - 2.0 * x2 / x2_max; - if (prn(seed) < 0.5*(1.0 + mu*mu)) break; + if (prn(seed) < 0.5 * (1.0 + mu * mu)) + break; } return mu; } @@ -543,24 +642,18 @@ void PhotonInteraction::pair_production(double alpha, double* E_electron, double* E_positron, double* mu_electron, double* mu_positron, uint64_t* seed) const { - constexpr double r[] { - 122.81, 73.167, 69.228, 67.301, 64.696, 61.228, - 57.524, 54.033, 50.787, 47.851, 46.373, 45.401, - 44.503, 43.815, 43.074, 42.321, 41.586, 40.953, - 40.524, 40.256, 39.756, 39.144, 38.462, 37.778, - 37.174, 36.663, 35.986, 35.317, 34.688, 34.197, - 33.786, 33.422, 33.068, 32.740, 32.438, 32.143, - 31.884, 31.622, 31.438, 31.142, 30.950, 30.758, - 30.561, 30.285, 30.097, 29.832, 29.581, 29.411, - 29.247, 29.085, 28.930, 28.721, 28.580, 28.442, - 28.312, 28.139, 27.973, 27.819, 27.675, 27.496, - 27.285, 27.093, 26.911, 26.705, 26.516, 26.304, - 26.108, 25.929, 25.730, 25.577, 25.403, 25.245, - 25.100, 24.941, 24.790, 24.655, 24.506, 24.391, - 24.262, 24.145, 24.039, 23.922, 23.813, 23.712, - 23.621, 23.523, 23.430, 23.331, 23.238, 23.139, - 23.048, 22.967, 22.833, 22.694, 22.624, 22.545, - 22.446, 22.358, 22.264}; + constexpr double r[] {122.81, 73.167, 69.228, 67.301, 64.696, 61.228, 57.524, + 54.033, 50.787, 47.851, 46.373, 45.401, 44.503, 43.815, 43.074, 42.321, + 41.586, 40.953, 40.524, 40.256, 39.756, 39.144, 38.462, 37.778, 37.174, + 36.663, 35.986, 35.317, 34.688, 34.197, 33.786, 33.422, 33.068, 32.740, + 32.438, 32.143, 31.884, 31.622, 31.438, 31.142, 30.950, 30.758, 30.561, + 30.285, 30.097, 29.832, 29.581, 29.411, 29.247, 29.085, 28.930, 28.721, + 28.580, 28.442, 28.312, 28.139, 27.973, 27.819, 27.675, 27.496, 27.285, + 27.093, 26.911, 26.705, 26.516, 26.304, 26.108, 25.929, 25.730, 25.577, + 25.403, 25.245, 25.100, 24.941, 24.790, 24.655, 24.506, 24.391, 24.262, + 24.145, 24.039, 23.922, 23.813, 23.712, 23.621, 23.523, 23.430, 23.331, + 23.238, 23.139, 23.048, 22.967, 22.833, 22.694, 22.624, 22.545, 22.446, + 22.358, 22.264}; // The reduced screening radius r is the ratio of the screening radius to // the Compton wavelength of the electron, where the screening radius is @@ -575,27 +668,35 @@ void PhotonInteraction::pair_production(double alpha, double* E_electron, // Compute the high-energy Coulomb correction double a = Z_ / FINE_STRUCTURE; - double c = a*a*(1.0/(1.0 + a*a) + 0.202059 + a*a*(-0.03693 + a*a*(0.00835 + - a*a*(-0.00201 + a*a*(0.00049 + a*a*(-0.00012 + a*a*0.00003)))))); + double c = + a * a * + (1.0 / (1.0 + a * a) + 0.202059 + + a * a * + (-0.03693 + + a * a * + (0.00835 + + a * a * + (-0.00201 + + a * a * (0.00049 + a * a * (-0.00012 + a * a * 0.00003)))))); // The analytical approximation of the DCS underestimates the cross section // at low energies. The correction factor f compensates for this. - double q = std::sqrt(2.0/alpha); - double f = q*(-0.1774 - 12.10*a + 11.18*a*a) - + q*q*(8.523 + 73.26*a - 44.41*a*a) - + q*q*q*(-13.52 - 121.1*a + 96.41*a*a) - + q*q*q*q*(8.946 + 62.05*a - 63.41*a*a); + double q = std::sqrt(2.0 / alpha); + double f = q * (-0.1774 - 12.10 * a + 11.18 * a * a) + + q * q * (8.523 + 73.26 * a - 44.41 * a * a) + + q * q * q * (-13.52 - 121.1 * a + 96.41 * a * a) + + q * q * q * q * (8.946 + 62.05 * a - 63.41 * a * a); // Calculate phi_1(1/2) and phi_2(1/2). The unnormalized PDF for the reduced // energy is given by p = 2*(1/2 - e)^2*phi_1(e) + phi_2(e), where phi_1 and // phi_2 are non-negative and maximum at e = 1/2. - double b = 2.0*r[Z_]/alpha; - double t1 = 2.0*std::log(1.0 + b*b); - double t2 = b*std::atan(1.0/b); - double t3 = b*b*(4.0 - 4.0*t2 - 3.0*std::log(1.0 + 1.0/(b*b))); - double t4 = 4.0*std::log(r[Z_]) - 4.0*c + f; - double phi1_max = 7.0/3.0 - t1 - 6.0*t2 - t3 + t4; - double phi2_max = 11.0/6.0 - t1 - 3.0*t2 + 0.5*t3 + t4; + double b = 2.0 * r[Z_] / alpha; + double t1 = 2.0 * std::log(1.0 + b * b); + double t2 = b * std::atan(1.0 / b); + double t3 = b * b * (4.0 - 4.0 * t2 - 3.0 * std::log(1.0 + 1.0 / (b * b))); + double t4 = 4.0 * std::log(r[Z_]) - 4.0 * c + f; + double phi1_max = 7.0 / 3.0 - t1 - 6.0 * t2 - t3 + t4; + double phi2_max = 11.0 / 6.0 - t1 - 3.0 * t2 + 0.5 * t3 + t4; // To aid sampling, the unnormalized PDF can be expressed as // p = u_1*U_1(e)*pi_1(e) + u_2*U_2(e)*pi_2(e), where pi_1 and pi_2 are @@ -604,7 +705,7 @@ void PhotonInteraction::pair_production(double alpha, double* E_electron, // U_1 = phi_1(e)/phi_1(1/2) and U_2 = phi_2(e)/phi_2(1/2) are valid // rejection functions. The reduced energy can now be sampled using a // combination of the composition and rejection methods. - double u1 = 2.0/3.0*std::pow(0.5 - 1.0/alpha, 2)*phi1_max; + double u1 = 2.0 / 3.0 * std::pow(0.5 - 1.0 / alpha, 2) * phi1_max; double u2 = phi2_max; double e; while (true) { @@ -613,103 +714,114 @@ void PhotonInteraction::pair_production(double alpha, double* E_electron, // Sample the index i in (1, 2) using the point probabilities // p(1) = u_1/(u_1 + u_2) and p(2) = u_2/(u_1 + u_2) int i; - if (prn(seed) < u1/(u1 + u2)) { + if (prn(seed) < u1 / (u1 + u2)) { i = 1; // Sample e from pi_1 using the inverse transform method - e = rn >= 0.5 ? - 0.5 + (0.5 - 1.0/alpha)*std::pow(2.0*rn - 1.0, 1.0/3.0) : - 0.5 - (0.5 - 1.0/alpha)*std::pow(1.0 - 2.0*rn, 1.0/3.0); + e = rn >= 0.5 + ? 0.5 + (0.5 - 1.0 / alpha) * std::pow(2.0 * rn - 1.0, 1.0 / 3.0) + : 0.5 - (0.5 - 1.0 / alpha) * std::pow(1.0 - 2.0 * rn, 1.0 / 3.0); } else { i = 2; // Sample e from pi_2 using the inverse transform method - e = 1.0/alpha + (0.5 - 1.0/alpha)*2.0*rn; + e = 1.0 / alpha + (0.5 - 1.0 / alpha) * 2.0 * rn; } // Calculate phi_i(e) and deliver e if rn <= U_i(e) - b = r[Z_]/(2.0*alpha*e*(1.0 - e)); - t1 = 2.0*std::log(1.0 + b*b); - t2 = b*std::atan(1.0/b); - t3 = b*b*(4.0 - 4.0*t2 - 3.0*std::log(1.0 + 1.0/(b*b))); + b = r[Z_] / (2.0 * alpha * e * (1.0 - e)); + t1 = 2.0 * std::log(1.0 + b * b); + t2 = b * std::atan(1.0 / b); + t3 = b * b * (4.0 - 4.0 * t2 - 3.0 * std::log(1.0 + 1.0 / (b * b))); if (i == 1) { - double phi1 = 7.0/3.0 - t1 - 6.0*t2 - t3 + t4; - if (prn(seed) <= phi1/phi1_max) break; + double phi1 = 7.0 / 3.0 - t1 - 6.0 * t2 - t3 + t4; + if (prn(seed) <= phi1 / phi1_max) + break; } else { - double phi2 = 11.0/6.0 - t1 - 3.0*t2 + 0.5*t3 + t4; - if (prn(seed) <= phi2/phi2_max) break; + double phi2 = 11.0 / 6.0 - t1 - 3.0 * t2 + 0.5 * t3 + t4; + if (prn(seed) <= phi2 / phi2_max) + break; } } // Compute the kinetic energy of the electron and the positron - *E_electron = (alpha*e - 1.0)*MASS_ELECTRON_EV; - *E_positron = (alpha*(1.0 - e) - 1.0)*MASS_ELECTRON_EV; + *E_electron = (alpha * e - 1.0) * MASS_ELECTRON_EV; + *E_positron = (alpha * (1.0 - e) - 1.0) * MASS_ELECTRON_EV; // Sample the scattering angle of the electron. The cosine of the polar // angle of the direction relative to the incident photon is sampled from // p(mu) = C/(1 - beta*mu)^2 using the inverse transform method. - double beta = std::sqrt(*E_electron*(*E_electron + 2.0*MASS_ELECTRON_EV)) - / (*E_electron + MASS_ELECTRON_EV) ; + double beta = + std::sqrt(*E_electron * (*E_electron + 2.0 * MASS_ELECTRON_EV)) / + (*E_electron + MASS_ELECTRON_EV); double rn = uniform_distribution(-1., 1., seed); - *mu_electron = (rn + beta)/(rn*beta + 1.0); + *mu_electron = (rn + beta) / (rn * beta + 1.0); // Sample the scattering angle of the positron - beta = std::sqrt(*E_positron*(*E_positron + 2.0*MASS_ELECTRON_EV)) - / (*E_positron + MASS_ELECTRON_EV); + beta = std::sqrt(*E_positron * (*E_positron + 2.0 * MASS_ELECTRON_EV)) / + (*E_positron + MASS_ELECTRON_EV); rn = uniform_distribution(-1., 1., seed); - *mu_positron = (rn + beta)/(rn*beta + 1.0); + *mu_positron = (rn + beta) / (rn * beta + 1.0); } -void PhotonInteraction::atomic_relaxation(const ElectronSubshell& shell, Particle& p) const +void PhotonInteraction::atomic_relaxation(int i_shell, Particle& p) const { - // If no transitions, assume fluorescent photon from captured free electron - if (shell.n_transitions == 0) { - Direction u = isotropic_direction(p.current_seed()); - double E = shell.binding_energy; - p.create_secondary(p.wgt(), u, E, ParticleType::photon); + // Return if no atomic relaxation data is present + if (!has_atomic_relaxation_) return; - } - // Sample transition - double rn = prn(p.current_seed()); - double c = 0.0; - int i_transition; - for (i_transition = 0; i_transition < shell.n_transitions; ++i_transition) { - c += shell.transition_probability(i_transition); - if (rn < c) break; - } + // Stack for unprocessed holes left by transitioning electrons + int n_holes = 0; + array holes; - // Get primary and secondary subshell designators - int primary = shell.transition_subshells(i_transition, 0); - int secondary = shell.transition_subshells(i_transition, 1); + // Push the initial hole onto the stack + holes[n_holes++] = i_shell; - // Sample angle isotropically - Direction u = isotropic_direction(p.current_seed()); + while (n_holes > 0) { + // Pop the next hole off the stack + int i_hole = holes[--n_holes]; + const auto& shell {shells_[i_hole]}; - // Get the transition energy - double E = shell.transition_energy(i_transition); + // If no transitions, assume fluorescent photon from captured free electron + if (shell.transitions.empty()) { + Direction u = isotropic_direction(p.current_seed()); + double E = shell.binding_energy; + p.create_secondary(p.wgt(), u, E, ParticleType::photon); + continue; + } - if (secondary != 0) { - // Non-radiative transition -- Auger/Coster-Kronig effect + // Sample transition + double c = -prn(p.current_seed()); + int i_trans; + for (i_trans = 0; i_trans < shell.transitions.size(); ++i_trans) { + c += shell.transitions[i_trans].probability; + if (c > 0) + break; + } + const auto& transition = shell.transitions[i_trans]; - // Create auger electron - p.create_secondary(p.wgt(), u, E, ParticleType::electron); + // Sample angle isotropically + Direction u = isotropic_direction(p.current_seed()); - // Fill hole left by emitted auger electron - int i_hole = shell_map_.at(secondary); - const auto& hole = shells_[i_hole]; - this->atomic_relaxation(hole, p); - } else { - // Radiative transition -- get X-ray energy + // Push the hole created by the electron transitioning to the photoelectron + // hole onto the stack + holes[n_holes++] = transition.primary_subshell; - // Create fluorescent photon - p.create_secondary(p.wgt(), u, E, ParticleType::photon); - } + if (transition.secondary_subshell != -1) { + // Non-radiative transition -- Auger/Coster-Kronig effect + + // Push the hole left by emitted auger electron onto the stack + holes[n_holes++] = transition.secondary_subshell; + + // Create auger electron + p.create_secondary(p.wgt(), u, transition.energy, ParticleType::electron); + } else { + // Radiative transition -- get X-ray energy - // Fill hole created by electron transitioning to the photoelectron hole - int i_hole = shell_map_.at(primary); - const auto& hole = shells_[i_hole]; - this->atomic_relaxation(hole, p); + // Create fluorescent photon + p.create_secondary(p.wgt(), u, transition.energy, ParticleType::photon); + } + } } //============================================================================== @@ -719,54 +831,56 @@ void PhotonInteraction::atomic_relaxation(const ElectronSubshell& shell, Particl std::pair klein_nishina(double alpha, uint64_t* seed) { double alpha_out, mu; - double beta = 1.0 + 2.0*alpha; + double beta = 1.0 + 2.0 * alpha; if (alpha < 3.0) { // Kahn's rejection method - double t = beta/(beta + 8.0); + double t = beta / (beta + 8.0); double x; while (true) { if (prn(seed) < t) { // Left branch of flow chart double r = uniform_distribution(0.0, 2.0, seed); - x = 1.0 + alpha*r; - if (prn(seed) < 4.0/x*(1.0 - 1.0/x)) { + x = 1.0 + alpha * r; + if (prn(seed) < 4.0 / x * (1.0 - 1.0 / x)) { mu = 1 - r; break; } } else { // Right branch of flow chart - x = beta/(1.0 + 2.0*alpha*prn(seed)); - mu = 1.0 + (1.0 - x)/alpha; - if (prn(seed) < 0.5*(mu*mu + 1.0/x)) break; + x = beta / (1.0 + 2.0 * alpha * prn(seed)); + mu = 1.0 + (1.0 - x) / alpha; + if (prn(seed) < 0.5 * (mu * mu + 1.0 / x)) + break; } } - alpha_out = alpha/x; + alpha_out = alpha / x; } else { // Koblinger's direct method double gamma = 1.0 - std::pow(beta, -2); - double s = prn(seed)*(4.0/alpha + 0.5*gamma + - (1.0 - (1.0 + beta)/(alpha*alpha))*std::log(beta)); - if (s <= 2.0/alpha) { + double s = + prn(seed) * (4.0 / alpha + 0.5 * gamma + + (1.0 - (1.0 + beta) / (alpha * alpha)) * std::log(beta)); + if (s <= 2.0 / alpha) { // For first term, x = 1 + 2ar // Therefore, a' = a/(1 + 2ar) - alpha_out = alpha/(1.0 + 2.0*alpha*prn(seed)); - } else if (s <= 4.0/alpha) { + alpha_out = alpha / (1.0 + 2.0 * alpha * prn(seed)); + } else if (s <= 4.0 / alpha) { // For third term, x = beta/(1 + 2ar) // Therefore, a' = a(1 + 2ar)/beta - alpha_out = alpha*(1.0 + 2.0*alpha*prn(seed))/beta; - } else if (s <= 4.0/alpha + 0.5*gamma) { + alpha_out = alpha * (1.0 + 2.0 * alpha * prn(seed)) / beta; + } else if (s <= 4.0 / alpha + 0.5 * gamma) { // For fourth term, x = 1/sqrt(1 - gamma*r) // Therefore, a' = a*sqrt(1 - gamma*r) - alpha_out = alpha*std::sqrt(1.0 - gamma*prn(seed)); + alpha_out = alpha * std::sqrt(1.0 - gamma * prn(seed)); } else { // For third term, x = beta^r // Therefore, a' = a/beta^r - alpha_out = alpha/std::pow(beta, prn(seed)); + alpha_out = alpha / std::pow(beta, prn(seed)); } // Calculate cosine of scattering angle based on basic relation - mu = 1.0 + 1.0/alpha - 1.0/alpha_out; + mu = 1.0 + 1.0 / alpha - 1.0 / alpha_out; } return {alpha_out, mu}; } diff --git a/src/physics.cpp b/src/physics.cpp index 21214969464..69e74f2eafd 100644 --- a/src/physics.cpp +++ b/src/physics.cpp @@ -10,24 +10,27 @@ #include "openmc/material.h" #include "openmc/math_functions.h" #include "openmc/message_passing.h" +#include "openmc/ncrystal_interface.h" #include "openmc/nuclide.h" #include "openmc/photon.h" #include "openmc/physics_common.h" #include "openmc/random_dist.h" #include "openmc/random_lcg.h" #include "openmc/reaction.h" -#include "openmc/secondary_uncorrelated.h" #include "openmc/search.h" +#include "openmc/secondary_uncorrelated.h" #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/string_utils.h" -#include "openmc/thermal.h" #include "openmc/tallies/tally.h" +#include "openmc/thermal.h" +#include "openmc/weight_windows.h" #include #include // for max, min, max_element -#include // for sqrt, exp, log, abs, copysign +#include // for sqrt, exp, log, abs, copysign +#include namespace openmc { @@ -56,10 +59,12 @@ void collision(Particle& p) break; } + if (settings::weight_window_checkpoint_collision) + apply_weight_windows(p); + // Kill particle if energy falls below cutoff int type = static_cast(p.type()); if (p.E() < settings::energy_cutoff[type]) { - p.alive() = false; p.wgt() = 0.0; } @@ -98,20 +103,21 @@ void sample_neutron_reaction(Particle& p) const auto& nuc {data::nuclides[i_nuclide]}; - if (nuc->fissionable_) { + if (nuc->fissionable_ && p.neutron_xs(i_nuclide).fission > 0.0) { auto& rx = sample_fission(i_nuclide, p); if (settings::run_mode == RunMode::EIGENVALUE) { create_fission_sites(p, i_nuclide, rx); } else if (settings::run_mode == RunMode::FIXED_SOURCE && - settings::create_fission_neutrons) { + settings::create_fission_neutrons) { create_fission_sites(p, i_nuclide, rx); // Make sure particle population doesn't grow out of control for // subcritical multiplication problems. if (p.secondary_bank().size() >= 10000) { - fatal_error("The secondary particle bank appears to be growing without " - "bound. You are likely running a subcritical multiplication problem " - "with k-effective close to or greater than one."); + fatal_error( + "The secondary particle bank appears to be growing without " + "bound. You are likely running a subcritical multiplication problem " + "with k-effective close to or greater than one."); } } } @@ -126,33 +132,33 @@ void sample_neutron_reaction(Particle& p) if (p.neutron_xs(i_nuclide).absorption > 0.0) { absorption(p, i_nuclide); - } else { - p.wgt_absorb() = 0.0; } if (!p.alive()) return; // Sample a scattering reaction and determine the secondary energy of the // exiting neutron - scatter(p, i_nuclide); + const auto& ncrystal_mat = model::materials[p.material()]->ncrystal_mat(); + if (ncrystal_mat && p.E() < NCRYSTAL_MAX_ENERGY) { + ncrystal_mat.scatter(p); + } else { + scatter(p, i_nuclide); + } // Advance URR seed stream 'N' times after energy changes if (p.E() != p.E_last()) { - p.stream() = STREAM_URR_PTABLE; - advance_prn_seed(data::nuclides.size(), p.current_seed()); - p.stream() = STREAM_TRACKING; + advance_prn_seed(data::nuclides.size(), &p.seeds(STREAM_URR_PTABLE)); } // Play russian roulette if survival biasing is turned on if (settings::survival_biasing) { - russian_roulette(p); - if (!p.alive()) - return; + if (p.wgt() < settings::weight_cutoff) { + russian_roulette(p, settings::weight_survive); + } } } -void -create_fission_sites(Particle& p, int i_nuclide, const Reaction& rx) +void create_fission_sites(Particle& p, int i_nuclide, const Reaction& rx) { // If uniform fission source weighting is turned on, we increase or decrease // the expected number of fission sites produced @@ -165,11 +171,12 @@ create_fission_sites(Particle& p, int i_nuclide, const Reaction& rx) // Sample the number of neutrons produced int nu = static_cast(nu_t); - if (prn(p.current_seed()) <= (nu_t - nu)) ++nu; + if (prn(p.current_seed()) <= (nu_t - nu)) + ++nu; - // Begin banking the source neutrons - // First, if our bank is full then don't continue - if (nu == 0) return; + // If no neutrons were produced then don't continue + if (nu == 0) + return; // Initialize the counter of delayed neutrons encountered for each delayed // group. @@ -179,32 +186,44 @@ create_fission_sites(Particle& p, int i_nuclide, const Reaction& rx) p.nu_bank().clear(); p.fission() = true; - int skipped = 0; // Determine whether to place fission sites into the shared fission bank // or the secondary particle bank. bool use_fission_bank = (settings::run_mode == RunMode::EIGENVALUE); - for (int i = 0; i < nu; ++i) { + // Counter for the number of fission sites successfully stored to the shared + // fission bank or the secondary particle bank + int n_sites_stored; + + for (n_sites_stored = 0; n_sites_stored < nu; n_sites_stored++) { // Initialize fission site object with particle data SourceSite site; site.r = p.r(); site.particle = ParticleType::neutron; + site.time = p.time(); site.wgt = 1. / weight; site.parent_id = p.id(); site.progeny_id = p.n_progeny()++; site.surf_id = 0; // Sample delayed group and angle/energy for fission reaction - sample_fission_neutron(i_nuclide, rx, p.E(), &site, p.current_seed()); + sample_fission_neutron(i_nuclide, rx, &site, p); // Store fission site in bank if (use_fission_bank) { int64_t idx = simulation::fission_bank.thread_safe_append(site); if (idx == -1) { - warning("The shared fission bank is full. Additional fission sites created " - "in this generation will not be banked."); - skipped++; + warning( + "The shared fission bank is full. Additional fission sites created " + "in this generation will not be banked. Results may be " + "non-deterministic."); + + // Decrement number of particle progeny as storage was unsuccessful. + // This step is needed so that the sum of all progeny is equal to the + // size of the shared fission bank. + p.n_progeny()--; + + // Break out of loop as no more sites can be added to fission bank break; } } else { @@ -222,21 +241,21 @@ create_fission_sites(Particle& p, int i_nuclide, const Reaction& rx) // Write fission particles to nuBank p.nu_bank().emplace_back(); NuBank* nu_bank_entry = &p.nu_bank().back(); - nu_bank_entry->wgt = site.wgt; - nu_bank_entry->E = site.E; - nu_bank_entry->delayed_group = site.delayed_group; + nu_bank_entry->wgt = site.wgt; + nu_bank_entry->E = site.E; + nu_bank_entry->delayed_group = site.delayed_group; } // If shared fission bank was full, and no fissions could be added, // set the particle fission flag to false. - if (nu == skipped) { + if (n_sites_stored == 0) { p.fission() = false; return; } - // If shared fission bank was full, but some fissions could be added, - // reduce nu accordingly - nu -= skipped; + // Set nu to the number of fission sites successfully stored. If the fission + // bank was not found to be full then these values are already equivalent. + nu = n_sites_stored; // Store the total weight banked for analog fission tallies p.n_bank() = nu; @@ -254,7 +273,7 @@ void sample_photon_reaction(Particle& p) int photon = static_cast(ParticleType::photon); if (p.E() < settings::energy_cutoff[photon]) { p.E() = 0.0; - p.alive() = false; + p.wgt() = 0.0; return; } @@ -286,7 +305,8 @@ void sample_photon_reaction(Particle& p) if (prob > cutoff) { double alpha_out, mu; int i_shell; - element.compton_scatter(alpha, true, &alpha_out, &mu, &i_shell, p.current_seed()); + element.compton_scatter( + alpha, true, &alpha_out, &mu, &i_shell, p.current_seed()); // Determine binding energy of shell. The binding energy is 0.0 if // doppler broadening is not used. @@ -298,12 +318,13 @@ void sample_photon_reaction(Particle& p) } // Create Compton electron - double phi = uniform_distribution(0., 2.0*PI, p.current_seed()); - double E_electron = (alpha - alpha_out)*MASS_ELECTRON_EV - e_b; + double phi = uniform_distribution(0., 2.0 * PI, p.current_seed()); + double E_electron = (alpha - alpha_out) * MASS_ELECTRON_EV - e_b; int electron = static_cast(ParticleType::electron); if (E_electron >= settings::energy_cutoff[electron]) { - double mu_electron = (alpha - alpha_out*mu) - / std::sqrt(alpha*alpha + alpha_out*alpha_out - 2.0*alpha*alpha_out*mu); + double mu_electron = (alpha - alpha_out * mu) / + std::sqrt(alpha * alpha + alpha_out * alpha_out - + 2.0 * alpha * alpha_out * mu); Direction u = rotate_angle(p.u(), mu_electron, &phi, p.current_seed()); p.create_secondary(p.wgt(), u, E_electron, ParticleType::electron); } @@ -312,8 +333,7 @@ void sample_photon_reaction(Particle& p) // Allow electrons to fill orbital and produce auger electrons // and fluorescent photons if (i_shell >= 0) { - const auto& shell = element.shells_[i_shell]; - element.atomic_relaxation(shell, p); + element.atomic_relaxation(i_shell, p); } phi += PI; @@ -326,24 +346,35 @@ void sample_photon_reaction(Particle& p) // Photoelectric effect double prob_after = prob + micro.photoelectric; + if (prob_after > cutoff) { - for (const auto& shell : element.shells_) { - // Get grid index and interpolation factor - int i_grid = micro.index_grid; - double f = micro.interp_factor; + // Get grid index, interpolation factor, and bounding subshell + // cross sections + int i_grid = micro.index_grid; + double f = micro.interp_factor; + const auto& xs_lower = xt::row(element.cross_sections_, i_grid); + const auto& xs_upper = xt::row(element.cross_sections_, i_grid + 1); + + for (int i_shell = 0; i_shell < element.shells_.size(); ++i_shell) { + const auto& shell {element.shells_[i_shell]}; // Check threshold of reaction - int i_start = shell.threshold; - if (i_grid < i_start) continue; + if (xs_lower(i_shell) == 0) + continue; - // Evaluation subshell photoionization cross section - double xs = std::exp(shell.cross_section(i_grid - i_start) + - f*(shell.cross_section(i_grid + 1 - i_start) - - shell.cross_section(i_grid - i_start))); + // Evaluation subshell photoionization cross section + prob += std::exp( + xs_lower(i_shell) + f * (xs_upper(i_shell) - xs_lower(i_shell))); - prob += xs; if (prob > cutoff) { - double E_electron = p.E() - shell.binding_energy; + // Determine binding energy based on whether atomic relaxation data is + // present (if not, use value from Compton profile data) + double binding_energy = element.has_atomic_relaxation_ + ? shell.binding_energy + : element.binding_energy_[i_shell]; + + // Determine energy of secondary electron + double E_electron = p.E() - binding_energy; // Sample mu using non-relativistic Sauter distribution. // See Eqns 3.19 and 3.20 in "Implementing a photon physics @@ -351,29 +382,31 @@ void sample_photon_reaction(Particle& p) double mu; while (true) { double r = prn(p.current_seed()); - if (4.0*(1.0 - r)*r >= prn(p.current_seed())) { - double rel_vel = std::sqrt(E_electron * (E_electron + - 2.0*MASS_ELECTRON_EV)) / (E_electron + MASS_ELECTRON_EV); - mu = (2.0*r + rel_vel - 1.0) / (2.0*rel_vel*r - rel_vel + 1.0); + if (4.0 * (1.0 - r) * r >= prn(p.current_seed())) { + double rel_vel = + std::sqrt(E_electron * (E_electron + 2.0 * MASS_ELECTRON_EV)) / + (E_electron + MASS_ELECTRON_EV); + mu = + (2.0 * r + rel_vel - 1.0) / (2.0 * rel_vel * r - rel_vel + 1.0); break; } } - double phi = uniform_distribution(0., 2.0*PI, p.current_seed()); + double phi = uniform_distribution(0., 2.0 * PI, p.current_seed()); Direction u; u.x = mu; - u.y = std::sqrt(1.0 - mu*mu)*std::cos(phi); - u.z = std::sqrt(1.0 - mu*mu)*std::sin(phi); + u.y = std::sqrt(1.0 - mu * mu) * std::cos(phi); + u.z = std::sqrt(1.0 - mu * mu) * std::sin(phi); // Create secondary electron p.create_secondary(p.wgt(), u, E_electron, ParticleType::electron); // Allow electrons to fill orbital and produce auger electrons // and fluorescent photons - element.atomic_relaxation(shell, p); + element.atomic_relaxation(i_shell, p); p.event() = TallyEvent::ABSORB; p.event_mt() = 533 + shell.index_subshell; - p.alive() = false; + p.wgt() = 0.0; p.E() = 0.0; return; } @@ -386,8 +419,8 @@ void sample_photon_reaction(Particle& p) if (prob > cutoff) { double E_electron, E_positron; double mu_electron, mu_positron; - element.pair_production(alpha, &E_electron, &E_positron, - &mu_electron, &mu_positron, p.current_seed()); + element.pair_production(alpha, &E_electron, &E_positron, &mu_electron, + &mu_positron, p.current_seed()); // Create secondary electron Direction u = rotate_angle(p.u(), mu_electron, nullptr, p.current_seed()); @@ -399,7 +432,7 @@ void sample_photon_reaction(Particle& p) p.event() = TallyEvent::ABSORB; p.event_mt() = PAIR_PROD; - p.alive() = false; + p.wgt() = 0.0; p.E() = 0.0; } } @@ -414,7 +447,7 @@ void sample_electron_reaction(Particle& p) } p.E() = 0.0; - p.alive() = false; + p.wgt() = 0.0; p.event() = TallyEvent::ABSORB; } @@ -435,7 +468,7 @@ void sample_positron_reaction(Particle& p) p.create_secondary(p.wgt(), -u, MASS_ELECTRON_EV, ParticleType::photon); p.E() = 0.0; - p.alive() = false; + p.wgt() = 0.0; p.event() = TallyEvent::ABSORB; } @@ -456,12 +489,13 @@ int sample_nuclide(Particle& p) // Increment probability to compare to cutoff prob += atom_density * p.neutron_xs(i_nuclide).total; - if (prob >= cutoff) return i_nuclide; + if (prob >= cutoff) + return i_nuclide; } // If we reach here, no nuclide was sampled p.write_restart(); - throw std::runtime_error{"Did not sample any nuclide during collision."}; + throw std::runtime_error {"Did not sample any nuclide during collision."}; } int sample_element(Particle& p) @@ -516,52 +550,44 @@ Reaction& sample_fission(int i_nuclide, Particle& p) } } - // Get grid index and interpolatoin factor and sample fission cdf - int i_temp = p.neutron_xs(i_nuclide).index_temp; - int i_grid = p.neutron_xs(i_nuclide).index_grid; - double f = p.neutron_xs(i_nuclide).interp_factor; + // Get grid index and interpolation factor and sample fission cdf + const auto& micro = p.neutron_xs(i_nuclide); double cutoff = prn(p.current_seed()) * p.neutron_xs(i_nuclide).fission; double prob = 0.0; // Loop through each partial fission reaction type for (auto& rx : nuc->fission_rx_) { - // if energy is below threshold for this reaction, skip it - int threshold = rx->xs_[i_temp].threshold; - if (i_grid < threshold) continue; - // add to cumulative probability - prob += (1.0 - f) * rx->xs_[i_temp].value[i_grid - threshold] - + f*rx->xs_[i_temp].value[i_grid - threshold + 1]; + prob += rx->xs(micro); // Create fission bank sites if fission occurs - if (prob > cutoff) return *rx; + if (prob > cutoff) + return *rx; } // If we reached here, no reaction was sampled - throw std::runtime_error{"No fission reaction was sampled for " + nuc->name_}; + throw std::runtime_error { + "No fission reaction was sampled for " + nuc->name_}; } -void sample_photon_product(int i_nuclide, Particle& p, int* i_rx, int* i_product) +void sample_photon_product( + int i_nuclide, Particle& p, int* i_rx, int* i_product) { // Get grid index and interpolation factor and sample photon production cdf - int i_temp = p.neutron_xs(i_nuclide).index_temp; - int i_grid = p.neutron_xs(i_nuclide).index_grid; - double f = p.neutron_xs(i_nuclide).interp_factor; - double cutoff = prn(p.current_seed()) * p.neutron_xs(i_nuclide).photon_prod; + const auto& micro = p.neutron_xs(i_nuclide); + double cutoff = prn(p.current_seed()) * micro.photon_prod; double prob = 0.0; // Loop through each reaction type const auto& nuc {data::nuclides[i_nuclide]}; for (int i = 0; i < nuc->reactions_.size(); ++i) { + // Evaluate neutron cross section const auto& rx = nuc->reactions_[i]; - int threshold = rx->xs_[i_temp].threshold; - - // if energy is below threshold for this reaction, skip it - if (i_grid < threshold) continue; + double xs = rx->xs(micro); - // Evaluate neutron cross section - double xs = ((1.0 - f) * rx->xs_[i_temp].value[i_grid - threshold] - + f*(rx->xs_[i_temp].value[i_grid - threshold + 1])); + // if cross section is zero for this reaction, skip it + if (xs == 0.0) + continue; for (int j = 0; j < rx->products_.size(); ++j) { if (rx->products_[j].particle_ == ParticleType::photon) { @@ -573,7 +599,7 @@ void sample_photon_product(int i_nuclide, Particle& p, int* i_rx, int* i_product if (nuc->prompt_photons_ && nuc->delayed_photons_) { double energy_prompt = (*nuc->prompt_photons_)(p.E()); double energy_delayed = (*nuc->delayed_photons_)(p.E()); - f = (energy_prompt + energy_delayed)/(energy_prompt); + f = (energy_prompt + energy_delayed) / (energy_prompt); } } } @@ -583,7 +609,8 @@ void sample_photon_product(int i_nuclide, Particle& p, int* i_rx, int* i_product *i_rx = i; *i_product = j; - if (prob > cutoff) return; + if (prob > cutoff) + return; } } } @@ -593,16 +620,15 @@ void absorption(Particle& p, int i_nuclide) { if (settings::survival_biasing) { // Determine weight absorbed in survival biasing - p.wgt_absorb() = p.wgt() * p.neutron_xs(i_nuclide).absorption / - p.neutron_xs(i_nuclide).total; + const double wgt_absorb = p.wgt() * p.neutron_xs(i_nuclide).absorption / + p.neutron_xs(i_nuclide).total; // Adjust weight of particle by probability of absorption - p.wgt() -= p.wgt_absorb(); - p.wgt_last() = p.wgt(); + p.wgt() -= wgt_absorb; // Score implicit absorption estimate of keff if (settings::run_mode == RunMode::EIGENVALUE) { - p.keff_tally_absorption() += p.wgt_absorb() * + p.keff_tally_absorption() += wgt_absorb * p.neutron_xs(i_nuclide).nu_fission / p.neutron_xs(i_nuclide).absorption; } @@ -617,7 +643,7 @@ void absorption(Particle& p, int i_nuclide) p.neutron_xs(i_nuclide).absorption; } - p.alive() = false; + p.wgt() = 0.0; p.event() = TallyEvent::ABSORB; p.event_mt() = N_DISAPPEAR; } @@ -632,9 +658,7 @@ void scatter(Particle& p, int i_nuclide) // Get pointer to nuclide and grid index/interpolation factor const auto& nuc {data::nuclides[i_nuclide]}; const auto& micro {p.neutron_xs(i_nuclide)}; - int i_temp = micro.index_temp; - int i_grid = micro.index_grid; - double f = micro.interp_factor; + int i_temp = micro.index_temp; // For tallying purposes, this routine might be called directly. In that // case, we need to sample a reaction via the cutoff variable @@ -676,25 +700,13 @@ void scatter(Particle& p, int i_nuclide) // ======================================================================= // INELASTIC SCATTERING - int j = 0; + int n = nuc->index_inelastic_scatter_.size(); int i = 0; - while (prob < cutoff) { + for (int j = 0; j < n && prob < cutoff; ++j) { i = nuc->index_inelastic_scatter_[j]; - ++j; - - // Check to make sure inelastic scattering reaction sampled - if (i >= nuc->reactions_.size()) { - p.write_restart(); - fatal_error("Did not sample any reaction for nuclide " + nuc->name_); - } - - // if energy is below threshold for this reaction, skip it - const auto& xs {nuc->reactions_[i]->xs_[i_temp]}; - if (i_grid < xs.threshold) continue; // add to cumulative probability - prob += (1.0 - f)*xs.value[i_grid - xs.threshold] + - f*xs.value[i_grid - xs.threshold + 1]; + prob += nuc->reactions_[i]->xs(micro); } // Perform collision physics for inelastic scattering @@ -718,8 +730,7 @@ void scatter(Particle& p, int i_nuclide) } } -void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, - Particle& p) +void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, Particle& p) { // get pointer to nuclide const auto& nuc {data::nuclides[i_nuclide]}; @@ -728,7 +739,7 @@ void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, double awr = nuc->awr_; // Neutron velocity in LAB - Direction v_n = vel*p.u(); + Direction v_n = vel * p.u(); // Sample velocity of target nucleus Direction v_t {}; @@ -738,7 +749,7 @@ void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, } // Velocity of center-of-mass - Direction v_cm = (v_n + awr*v_t)/(awr + 1.0); + Direction v_cm = (v_n + awr * v_t) / (awr + 1.0); // Transform to CM frame v_n -= v_cm; @@ -758,7 +769,7 @@ void elastic_scatter(int i_nuclide, const Reaction& rx, double kT, } // Determine direction cosines in CM - Direction u_cm = v_n/vel; + Direction u_cm = v_n / vel; // Rotate neutron velocity vector to new angle -- note that the speed of the // neutron in CM does not change in elastic scattering. However, the speed @@ -815,12 +826,12 @@ Direction sample_target_velocity(const Nuclide& nuc, double E, Direction u, if (E > settings::res_scat_energy_max) { return {}; - // lower resonance scattering energy bound (should be no resonances below) + // lower resonance scattering energy bound (should be no resonances below) } else if (E < settings::res_scat_energy_min) { sampling_method = ResScatMethod::cxs; } - // otherwise, use free gas model + // otherwise, use free gas model } else { if (E >= FREE_GAS_THRESHOLD * kT && nuc.awr_ > 1.0) { return {}; @@ -840,7 +851,7 @@ Direction sample_target_velocity(const Nuclide& nuc, double E, Direction u, case ResScatMethod::rvs: { double E_red = std::sqrt(nuc.awr_ * E / kT); double E_low = std::pow(std::max(0.0, E_red - 4.0), 2) * kT / nuc.awr_; - double E_up = (E_red + 4.0)*(E_red + 4.0) * kT / nuc.awr_; + double E_up = (E_red + 4.0) * (E_red + 4.0) * kT / nuc.awr_; // find lower and upper energy bound indices // lower index @@ -850,8 +861,8 @@ Direction sample_target_velocity(const Nuclide& nuc, double E, Direction u, } else if (E_low > nuc.energy_0K_.back()) { i_E_low = nuc.energy_0K_.size() - 2; } else { - i_E_low = lower_bound_index(nuc.energy_0K_.begin(), - nuc.energy_0K_.end(), E_low); + i_E_low = + lower_bound_index(nuc.energy_0K_.begin(), nuc.energy_0K_.end(), E_low); } // upper index @@ -861,8 +872,8 @@ Direction sample_target_velocity(const Nuclide& nuc, double E, Direction u, } else if (E_up > nuc.energy_0K_.back()) { i_E_up = nuc.energy_0K_.size() - 2; } else { - i_E_up = lower_bound_index(nuc.energy_0K_.begin(), - nuc.energy_0K_.end(), E_up); + i_E_up = + lower_bound_index(nuc.energy_0K_.begin(), nuc.energy_0K_.end(), E_up); } if (i_E_up == i_E_low) { @@ -874,70 +885,73 @@ Direction sample_target_velocity(const Nuclide& nuc, double E, Direction u, if (sampling_method == ResScatMethod::dbrc) { // interpolate xs since we're not exactly at the energy indices double xs_low = nuc.elastic_0K_[i_E_low]; - double m = (nuc.elastic_0K_[i_E_low + 1] - xs_low) - / (nuc.energy_0K_[i_E_low + 1] - nuc.energy_0K_[i_E_low]); + double m = (nuc.elastic_0K_[i_E_low + 1] - xs_low) / + (nuc.energy_0K_[i_E_low + 1] - nuc.energy_0K_[i_E_low]); xs_low += m * (E_low - nuc.energy_0K_[i_E_low]); double xs_up = nuc.elastic_0K_[i_E_up]; - m = (nuc.elastic_0K_[i_E_up + 1] - xs_up) - / (nuc.energy_0K_[i_E_up + 1] - nuc.energy_0K_[i_E_up]); + m = (nuc.elastic_0K_[i_E_up + 1] - xs_up) / + (nuc.energy_0K_[i_E_up + 1] - nuc.energy_0K_[i_E_up]); xs_up += m * (E_up - nuc.energy_0K_[i_E_up]); // get max 0K xs value over range of practical relative energies - double xs_max = *std::max_element(&nuc.elastic_0K_[i_E_low + 1], - &nuc.elastic_0K_[i_E_up + 1]); + double xs_max = *std::max_element( + &nuc.elastic_0K_[i_E_low + 1], &nuc.elastic_0K_[i_E_up + 1]); xs_max = std::max({xs_low, xs_max, xs_up}); while (true) { double E_rel; Direction v_target; while (true) { - // sample target velocity with the constant cross section (cxs) approx. + // sample target velocity with the constant cross section (cxs) + // approx. v_target = sample_cxs_target_velocity(nuc.awr_, E, u, kT, seed); Direction v_rel = v_neut - v_target; E_rel = v_rel.dot(v_rel); - if (E_rel < E_up) break; + if (E_rel < E_up) + break; } // perform Doppler broadening rejection correction (dbrc) double xs_0K = nuc.elastic_xs_0K(E_rel); double R = xs_0K / xs_max; - if (prn(seed) < R) return v_target; + if (prn(seed) < R) + return v_target; } } else if (sampling_method == ResScatMethod::rvs) { // interpolate xs CDF since we're not exactly at the energy indices // cdf value at lower bound attainable energy - double m = (nuc.xs_cdf_[i_E_low] - nuc.xs_cdf_[i_E_low - 1]) - / (nuc.energy_0K_[i_E_low + 1] - nuc.energy_0K_[i_E_low]); - double cdf_low = nuc.xs_cdf_[i_E_low - 1] - + m * (E_low - nuc.energy_0K_[i_E_low]); - if (E_low <= nuc.energy_0K_.front()) cdf_low = 0.0; + double cdf_low = 0.0; + if (E_low > nuc.energy_0K_.front()) { + double m = (nuc.xs_cdf_[i_E_low + 1] - nuc.xs_cdf_[i_E_low]) / + (nuc.energy_0K_[i_E_low + 1] - nuc.energy_0K_[i_E_low]); + cdf_low = nuc.xs_cdf_[i_E_low] + m * (E_low - nuc.energy_0K_[i_E_low]); + } // cdf value at upper bound attainable energy - m = (nuc.xs_cdf_[i_E_up] - nuc.xs_cdf_[i_E_up - 1]) - / (nuc.energy_0K_[i_E_up + 1] - nuc.energy_0K_[i_E_up]); - double cdf_up = nuc.xs_cdf_[i_E_up - 1] - + m*(E_up - nuc.energy_0K_[i_E_up]); + double m = (nuc.xs_cdf_[i_E_up + 1] - nuc.xs_cdf_[i_E_up]) / + (nuc.energy_0K_[i_E_up + 1] - nuc.energy_0K_[i_E_up]); + double cdf_up = nuc.xs_cdf_[i_E_up] + m * (E_up - nuc.energy_0K_[i_E_up]); while (true) { // directly sample Maxwellian double E_t = -kT * std::log(prn(seed)); // sample a relative energy using the xs cdf - double cdf_rel = cdf_low + prn(seed)*(cdf_up - cdf_low); - int i_E_rel = lower_bound_index(&nuc.xs_cdf_[i_E_low-1], - &nuc.xs_cdf_[i_E_up+1], cdf_rel); + double cdf_rel = cdf_low + prn(seed) * (cdf_up - cdf_low); + int i_E_rel = lower_bound_index(nuc.xs_cdf_.begin() + i_E_low, + nuc.xs_cdf_.begin() + i_E_up + 2, cdf_rel); double E_rel = nuc.energy_0K_[i_E_low + i_E_rel]; - double m = (nuc.xs_cdf_[i_E_low + i_E_rel] - - nuc.xs_cdf_[i_E_low + i_E_rel - 1]) - / (nuc.energy_0K_[i_E_low + i_E_rel + 1] - - nuc.energy_0K_[i_E_low + i_E_rel]); - E_rel += (cdf_rel - nuc.xs_cdf_[i_E_low + i_E_rel - 1]) / m; + double m = (nuc.xs_cdf_[i_E_low + i_E_rel + 1] - + nuc.xs_cdf_[i_E_low + i_E_rel]) / + (nuc.energy_0K_[i_E_low + i_E_rel + 1] - + nuc.energy_0K_[i_E_low + i_E_rel]); + E_rel += (cdf_rel - nuc.xs_cdf_[i_E_low + i_E_rel]) / m; // perform rejection sampling on cosine between // neutron and target velocities double mu = (E_t + nuc.awr_ * (E - E_rel)) / - (2.0 * std::sqrt(nuc.awr_ * E * E_t)); + (2.0 * std::sqrt(nuc.awr_ * E * E_t)); if (std::abs(mu) < 1.0) { // set and accept target velocity @@ -946,17 +960,17 @@ Direction sample_target_velocity(const Nuclide& nuc, double E, Direction u, } } } - } // case RVS, DBRC + } // case RVS, DBRC } // switch (sampling_method) UNREACHABLE(); } -Direction -sample_cxs_target_velocity(double awr, double E, Direction u, double kT, uint64_t* seed) +Direction sample_cxs_target_velocity( + double awr, double E, Direction u, double kT, uint64_t* seed) { double beta_vn = std::sqrt(awr * E / kT); - double alpha = 1.0/(1.0 + std::sqrt(PI)*beta_vn/2.0); + double alpha = 1.0 / (1.0 + std::sqrt(PI) * beta_vn / 2.0); double beta_vt_sq; double mu; @@ -970,15 +984,15 @@ sample_cxs_target_velocity(double awr, double E, Direction u, double kT, uint64_ // y*e^(-y). This can be done with sampling scheme C45 from the Monte // Carlo sampler - beta_vt_sq = -std::log(r1*r2); + beta_vt_sq = -std::log(r1 * r2); } else { // With probability 1-alpha, we sample the distribution p(y) = y^2 * // e^(-y^2). This can be done with sampling scheme C61 from the Monte // Carlo sampler - double c = std::cos(PI/2.0 * prn(seed)); - beta_vt_sq = -std::log(r1) - std::log(r2)*c*c; + double c = std::cos(PI / 2.0 * prn(seed)); + beta_vt_sq = -std::log(r1) - std::log(r2) * c * c; } // Determine beta * vt @@ -988,24 +1002,30 @@ sample_cxs_target_velocity(double awr, double E, Direction u, double kT, uint64_ mu = uniform_distribution(-1., 1., seed); // Determine rejection probability - double accept_prob = std::sqrt(beta_vn*beta_vn + beta_vt_sq - - 2*beta_vn*beta_vt*mu) / (beta_vn + beta_vt); + double accept_prob = + std::sqrt(beta_vn * beta_vn + beta_vt_sq - 2 * beta_vn * beta_vt * mu) / + (beta_vn + beta_vt); // Perform rejection sampling on vt and mu - if (prn(seed) < accept_prob) break; + if (prn(seed) < accept_prob) + break; } // Determine speed of target nucleus - double vt = std::sqrt(beta_vt_sq*kT/awr); + double vt = std::sqrt(beta_vt_sq * kT / awr); // Determine velocity vector of target nucleus based on neutron's velocity // and the sampled angle between them return vt * rotate_angle(u, mu, nullptr, seed); } -void sample_fission_neutron(int i_nuclide, const Reaction& rx, double E_in, - SourceSite* site, uint64_t* seed) +void sample_fission_neutron( + int i_nuclide, const Reaction& rx, SourceSite* site, Particle& p) { + // Get attributes of particle + double E_in = p.E(); + uint64_t* seed = p.current_seed(); + // Determine total nu, delayed nu, and delayed neutron fraction const auto& nuc {data::nuclides[i_nuclide]}; double nu_t = nuc->nu(E_in, Nuclide::EmissionMode::total); @@ -1017,7 +1037,7 @@ void sample_fission_neutron(int i_nuclide, const Reaction& rx, double E_in, // DELAYED NEUTRON SAMPLED // sampled delayed precursor group - double xi = prn(seed)*nu_d; + double xi = prn(seed) * nu_d; double prob = 0.0; int group; for (group = 1; group < nuc->n_precursor_; ++group) { @@ -1026,7 +1046,8 @@ void sample_fission_neutron(int i_nuclide, const Reaction& rx, double E_in, // Check if this group is sampled prob += yield; - if (xi < prob) break; + if (xi < prob) + break; } // if the sum of the probabilities is slightly less than one and the @@ -1053,21 +1074,21 @@ void sample_fission_neutron(int i_nuclide, const Reaction& rx, double E_in, // resample if energy is greater than maximum neutron energy constexpr int neutron = static_cast(ParticleType::neutron); - if (site->E < data::energy_max[neutron]) break; + if (site->E < data::energy_max[neutron]) + break; // check for large number of resamples ++n_sample; if (n_sample == MAX_SAMPLE) { // particle_write_restart(p) fatal_error("Resampled energy distribution maximum number of times " - "for nuclide " + nuc->name_); + "for nuclide " + + nuc->name_); } } // Sample azimuthal angle uniformly in [0, 2*pi) and assign angle - // TODO: account for dependence on incident neutron? - Direction ref(1., 0., 0.); - site->u = rotate_angle(ref, mu, nullptr, seed); + site->u = rotate_angle(p.u(), mu, nullptr, seed); } void inelastic_scatter(const Nuclide& nuc, const Reaction& rx, Particle& p) @@ -1087,17 +1108,18 @@ void inelastic_scatter(const Nuclide& nuc, const Reaction& rx, Particle& p) // determine outgoing energy in lab double A = nuc.awr_; - E = E_cm + (E_in + 2.0*mu*(A + 1.0) * std::sqrt(E_in*E_cm)) - / ((A + 1.0)*(A + 1.0)); + E = E_cm + (E_in + 2.0 * mu * (A + 1.0) * std::sqrt(E_in * E_cm)) / + ((A + 1.0) * (A + 1.0)); // determine outgoing angle in lab - mu = mu*std::sqrt(E_cm/E) + 1.0/(A+1.0) * std::sqrt(E_in/E); + mu = mu * std::sqrt(E_cm / E) + 1.0 / (A + 1.0) * std::sqrt(E_in / E); } // Because of floating-point roundoff, it may be possible for mu to be // outside of the range [-1,1). In these cases, we just set mu to exactly -1 // or 1 - if (std::abs(mu) > 1.0) mu = std::copysign(1.0, mu); + if (std::abs(mu) > 1.0) + mu = std::copysign(1.0, mu); // Set outgoing energy and scattering angle p.E() = E; @@ -1108,7 +1130,7 @@ void inelastic_scatter(const Nuclide& nuc, const Reaction& rx, Particle& p) // evaluate yield double yield = (*rx.products_[0].yield_)(E_in); - if (std::floor(yield) == yield) { + if (std::floor(yield) == yield && yield > 0) { // If yield is integral, create exactly that many secondary particles for (int i = 0; i < static_cast(std::round(yield)) - 1; ++i) { p.create_secondary(p.wgt(), p.u(), p.E(), ParticleType::neutron); @@ -1125,7 +1147,8 @@ void sample_secondary_photons(Particle& p, int i_nuclide) double y_t = p.neutron_xs(i_nuclide).photon_prod / p.neutron_xs(i_nuclide).total; int y = static_cast(y_t); - if (prn(p.current_seed()) <= y_t - y) ++y; + if (prn(p.current_seed()) <= y_t - y) + ++y; // Sample each secondary photon for (int i = 0; i < y; ++i) { diff --git a/src/physics_common.cpp b/src/physics_common.cpp index 2a63b188dce..e25ae6b97ab 100644 --- a/src/physics_common.cpp +++ b/src/physics_common.cpp @@ -1,7 +1,7 @@ #include "openmc/physics_common.h" -#include "openmc/settings.h" #include "openmc/random_lcg.h" +#include "openmc/settings.h" namespace openmc { @@ -9,18 +9,13 @@ namespace openmc { // RUSSIAN_ROULETTE //============================================================================== -void russian_roulette(Particle& p) +void russian_roulette(Particle& p, double weight_survive) { - if (p.wgt() < settings::weight_cutoff) { - if (prn(p.current_seed()) < p.wgt() / settings::weight_survive) { - p.wgt() = settings::weight_survive; - p.wgt_last() = p.wgt(); - } else { - p.wgt() = 0.; - p.wgt_last() = 0.; - p.alive() = false; - } + if (weight_survive * prn(p.current_seed()) < p.wgt()) { + p.wgt() = weight_survive; + } else { + p.wgt() = 0.; } } -} //namespace openmc +} // namespace openmc diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index 06ed845deaf..361cf5affcf 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -2,8 +2,8 @@ #include -#include #include "xtensor/xarray.hpp" +#include #include "openmc/bank.h" #include "openmc/constants.h" @@ -22,8 +22,7 @@ namespace openmc { -void -collision_mg(Particle& p) +void collision_mg(Particle& p) { // Add to the collision counter for the particle p.n_collision()++; @@ -37,18 +36,17 @@ collision_mg(Particle& p) } } -void -sample_reaction(Particle& p) +void sample_reaction(Particle& p) { // Create fission bank sites. Note that while a fission reaction is sampled, // it never actually "happens", i.e. the weight of the particle does not // change when sampling fission sites. The following block handles all // absorption (including fission) - if (model::materials[p.material()]->fissionable_) { - if (settings::run_mode == RunMode::EIGENVALUE || - (settings::run_mode == RunMode::FIXED_SOURCE && - settings::create_fission_neutrons)) { + if (model::materials[p.material()]->fissionable()) { + if (settings::run_mode == RunMode::EIGENVALUE || + (settings::run_mode == RunMode::FIXED_SOURCE && + settings::create_fission_neutrons)) { create_fission_sites(p); } } @@ -57,8 +55,6 @@ sample_reaction(Particle& p) // weight of the particle. Otherwise, it checks to see if absorption occurs. if (p.macro_xs().absorption > 0.) { absorption(p); - } else { - p.wgt_absorb() = 0.; } if (!p.alive()) return; @@ -68,17 +64,16 @@ sample_reaction(Particle& p) // Play Russian roulette if survival biasing is turned on if (settings::survival_biasing) { - russian_roulette(p); - if (!p.alive()) - return; + if (p.wgt() < settings::weight_cutoff) { + russian_roulette(p, settings::weight_survive); + } } } -void -scatter(Particle& p) +void scatter(Particle& p) { - data::mg.macro_xs_[p.material()].sample_scatter( - p.g_last(), p.g(), p.mu(), p.wgt(), p.current_seed()); + data::mg.macro_xs_[p.material()].sample_scatter(p.g_last(), p.g(), p.mu(), + p.wgt(), p.current_seed(), p.mg_xs_cache().t, p.mg_xs_cache().a); // Rotate the angle p.u() = rotate_angle(p.u(), p.mu(), nullptr, p.current_seed()); @@ -90,8 +85,7 @@ scatter(Particle& p) p.event() = TallyEvent::SCATTER; } -void -create_fission_sites(Particle& p) +void create_fission_sites(Particle& p) { // If uniform fission source weighting is turned on, we increase or decrease // the expected number of fission sites produced @@ -107,9 +101,9 @@ create_fission_sites(Particle& p) nu++; } - // Begin banking the source neutrons - // First, if our bank is full then don't continue - if (nu == 0) return; + // If no neutrons were produced then don't continue + if (nu == 0) + return; // Initialize the counter of delayed neutrons encountered for each delayed // group. @@ -119,13 +113,16 @@ create_fission_sites(Particle& p) p.nu_bank().clear(); p.fission() = true; - int skipped = 0; // Determine whether to place fission sites into the shared fission bank // or the secondary particle bank. bool use_fission_bank = (settings::run_mode == RunMode::EIGENVALUE); - for (int i = 0; i < nu; ++i) { + // Counter for the number of fission sites successfully stored to the shared + // fission bank or the secondary particle bank + int n_sites_stored; + + for (n_sites_stored = 0; n_sites_stored < nu; n_sites_stored++) { // Initialize fission site object with particle data SourceSite site; site.r = p.r(); @@ -136,10 +133,10 @@ create_fission_sites(Particle& p) // Sample the cosine of the angle, assuming fission neutrons are emitted // isotropically - double mu = 2.*prn(p.current_seed()) - 1.; + double mu = 2. * prn(p.current_seed()) - 1.; // Sample the azimuthal angle uniformly in [0, 2.pi) - double phi = 2. * PI * prn(p.current_seed() ); + double phi = 2. * PI * prn(p.current_seed()); site.u.x = mu; site.u.y = std::sqrt(1. - mu * mu) * std::cos(phi); site.u.z = std::sqrt(1. - mu * mu) * std::sin(phi); @@ -148,7 +145,7 @@ create_fission_sites(Particle& p) int dg; int gout; data::mg.macro_xs_[p.material()].sample_fission_energy( - p.g(), dg, gout, p.current_seed()); + p.g(), dg, gout, p.current_seed(), p.mg_xs_cache().t, p.mg_xs_cache().a); // Store the energy and delayed groups on the fission bank site.E = gout; @@ -161,9 +158,17 @@ create_fission_sites(Particle& p) if (use_fission_bank) { int64_t idx = simulation::fission_bank.thread_safe_append(site); if (idx == -1) { - warning("The shared fission bank is full. Additional fission sites created " - "in this generation will not be banked."); - skipped++; + warning( + "The shared fission bank is full. Additional fission sites created " + "in this generation will not be banked. Results may be " + "non-deterministic."); + + // Decrement number of particle progeny as storage was unsuccessful. + // This step is needed so that the sum of all progeny is equal to the + // size of the shared fission bank. + p.n_progeny()--; + + // Break out of loop as no more sites can be added to fission bank break; } } else { @@ -181,21 +186,21 @@ create_fission_sites(Particle& p) // Write fission particles to nuBank p.nu_bank().emplace_back(); NuBank* nu_bank_entry = &p.nu_bank().back(); - nu_bank_entry->wgt = site.wgt; - nu_bank_entry->E = site.E; - nu_bank_entry->delayed_group = site.delayed_group; + nu_bank_entry->wgt = site.wgt; + nu_bank_entry->E = site.E; + nu_bank_entry->delayed_group = site.delayed_group; } // If shared fission bank was full, and no fissions could be added, // set the particle fission flag to false. - if (nu == skipped) { + if (n_sites_stored == 0) { p.fission() = false; return; } - // If shared fission bank was full, but some fissions could be added, - // reduce nu accordingly - nu -= skipped; + // Set nu to the number of fission sites successfully stored. If the fission + // bank was not found to be full then these values are already equivalent. + nu = n_sites_stored; // Store the total weight banked for analog fission tallies p.n_bank() = nu; @@ -205,28 +210,26 @@ create_fission_sites(Particle& p) } } -void -absorption(Particle& p) +void absorption(Particle& p) { if (settings::survival_biasing) { // Determine weight absorbed in survival biasing - p.wgt_absorb() = p.wgt() * p.macro_xs().absorption / p.macro_xs().total; + double wgt_absorb = p.wgt() * p.macro_xs().absorption / p.macro_xs().total; // Adjust weight of particle by the probability of absorption - p.wgt() -= p.wgt_absorb(); - p.wgt_last() = p.wgt(); + p.wgt() -= wgt_absorb; // Score implicit absorpion estimate of keff p.keff_tally_absorption() += - p.wgt_absorb() * p.macro_xs().nu_fission / p.macro_xs().absorption; + wgt_absorb * p.macro_xs().nu_fission / p.macro_xs().absorption; } else { if (p.macro_xs().absorption > prn(p.current_seed()) * p.macro_xs().total) { p.keff_tally_absorption() += p.wgt() * p.macro_xs().nu_fission / p.macro_xs().absorption; - p.alive() = false; + p.wgt() = 0.0; p.event() = TallyEvent::ABSORB; } } } -} //namespace openmc +} // namespace openmc diff --git a/src/plot.cpp b/src/plot.cpp index 615701341e8..bf733cff48f 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -1,21 +1,29 @@ #include "openmc/plot.h" #include +#include #include #include +#include "xtensor/xmanipulation.hpp" +#include "xtensor/xview.hpp" #include #include -#include "xtensor/xview.hpp" +#ifdef USE_LIBPNG +#include +#endif #include "openmc/constants.h" +#include "openmc/container_util.h" +#include "openmc/dagmc.h" +#include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/geometry.h" -#include "openmc/error.h" #include "openmc/hdf5_interface.h" #include "openmc/material.h" #include "openmc/mesh.h" #include "openmc/message_passing.h" +#include "openmc/openmp_interface.h" #include "openmc/output.h" #include "openmc/particle.h" #include "openmc/progress_bar.h" @@ -30,54 +38,59 @@ namespace openmc { // Constants //============================================================================== - constexpr int PLOT_LEVEL_LOWEST {-1}; //!< lower bound on plot universe level constexpr int32_t NOT_FOUND {-2}; constexpr int32_t OVERLAP {-3}; -IdData::IdData(size_t h_res, size_t v_res) - : data_({v_res, h_res, 2}, NOT_FOUND) -{ } +IdData::IdData(size_t h_res, size_t v_res) : data_({v_res, h_res, 3}, NOT_FOUND) +{} -void -IdData::set_value(size_t y, size_t x, const Particle& p, int level) { +void IdData::set_value(size_t y, size_t x, const GeometryState& p, int level) +{ // set cell data if (p.n_coord() <= level) { data_(y, x, 0) = NOT_FOUND; + data_(y, x, 1) = NOT_FOUND; } else { data_(y, x, 0) = model::cells.at(p.coord(level).cell)->id_; + data_(y, x, 1) = level == p.n_coord() - 1 + ? p.cell_instance() + : cell_instance_at_level(p, level); } // set material data - Cell* c = model::cells.at(p.coord(p.n_coord() - 1).cell).get(); + Cell* c = model::cells.at(p.lowest_coord().cell).get(); if (p.material() == MATERIAL_VOID) { - data_(y, x, 1) = MATERIAL_VOID; + data_(y, x, 2) = MATERIAL_VOID; return; } else if (c->type_ == Fill::MATERIAL) { Material* m = model::materials.at(p.material()).get(); - data_(y, x, 1) = m->id_; + data_(y, x, 2) = m->id_; } } -void IdData::set_overlap(size_t y, size_t x) { +void IdData::set_overlap(size_t y, size_t x) +{ xt::view(data_, y, x, xt::all()) = OVERLAP; } PropertyData::PropertyData(size_t h_res, size_t v_res) : data_({v_res, h_res, 2}, NOT_FOUND) -{ } +{} -void -PropertyData::set_value(size_t y, size_t x, const Particle& p, int level) { - Cell* c = model::cells.at(p.coord(p.n_coord() - 1).cell).get(); +void PropertyData::set_value( + size_t y, size_t x, const GeometryState& p, int level) +{ + Cell* c = model::cells.at(p.lowest_coord().cell).get(); data_(y, x, 0) = (p.sqrtkT() * p.sqrtkT()) / K_BOLTZMANN; if (c->type_ != Fill::UNIVERSE && p.material() != MATERIAL_VOID) { Material* m = model::materials.at(p.material()).get(); - data_(y,x,1) = m->density_gpcc_; + data_(y, x, 1) = m->density_gpcc_; } } -void PropertyData::set_overlap(size_t y, size_t x) { +void PropertyData::set_overlap(size_t y, size_t x) +{ data_(y, x) = OVERLAP; } @@ -88,7 +101,7 @@ void PropertyData::set_overlap(size_t y, size_t x) { namespace model { std::unordered_map plot_map; -vector plots; +vector> plots; uint64_t plotter_seed = 1; } // namespace model @@ -97,29 +110,77 @@ uint64_t plotter_seed = 1; // RUN_PLOT controls the logic for making one or many plots //============================================================================== -extern "C" -int openmc_plot_geometry() +extern "C" int openmc_plot_geometry() { + for (auto& pl : model::plots) { - write_message(5, "Processing plot {}: {}...", pl.id_, pl.path_plot_); - - if (PlotType::slice == pl.type_) { - // create 2D image - create_ppm(pl); - } else if (PlotType::voxel == pl.type_) { - // create voxel file for 3D viewing - create_voxel(pl); - } + write_message(5, "Processing plot {}: {}...", pl->id(), pl->path_plot()); + pl->create_output(); } + return 0; } +void Plot::create_output() const +{ + if (PlotType::slice == type_) { + // create 2D image + create_image(); + } else if (PlotType::voxel == type_) { + // create voxel file for 3D viewing + create_voxel(); + } +} + +void Plot::print_info() const +{ + // Plot type + if (PlotType::slice == type_) { + fmt::print("Plot Type: Slice\n"); + } else if (PlotType::voxel == type_) { + fmt::print("Plot Type: Voxel\n"); + } + + // Plot parameters + fmt::print("Origin: {} {} {}\n", origin_[0], origin_[1], origin_[2]); + + if (PlotType::slice == type_) { + fmt::print("Width: {:4} {:4}\n", width_[0], width_[1]); + } else if (PlotType::voxel == type_) { + fmt::print("Width: {:4} {:4} {:4}\n", width_[0], width_[1], width_[2]); + } + + if (PlotColorBy::cells == color_by_) { + fmt::print("Coloring: Cells\n"); + } else if (PlotColorBy::mats == color_by_) { + fmt::print("Coloring: Materials\n"); + } + + if (PlotType::slice == type_) { + switch (basis_) { + case PlotBasis::xy: + fmt::print("Basis: XY\n"); + break; + case PlotBasis::xz: + fmt::print("Basis: XZ\n"); + break; + case PlotBasis::yz: + fmt::print("Basis: YZ\n"); + break; + } + fmt::print("Pixels: {} {}\n", pixels_[0], pixels_[1]); + } else if (PlotType::voxel == type_) { + fmt::print("Voxels: {} {} {}\n", pixels_[0], pixels_[1], pixels_[2]); + } +} void read_plots_xml() { - // Check if plots.xml exists + // Check if plots.xml exists; this is only necessary when the plot runmode is + // initiated. Otherwise, we want to read plots.xml because it may be called + // later via the API. In that case, its ok for a plots.xml to not exist std::string filename = settings::path_input + "plots.xml"; - if (!file_exists(filename)) { + if (!file_exists(filename) && settings::run_mode == RunMode::PLOTTING) { fatal_error(fmt::format("Plots XML file '{}' does not exist!", filename)); } @@ -130,59 +191,94 @@ void read_plots_xml() doc.load_file(filename.c_str()); pugi::xml_node root = doc.document_element(); + + read_plots_xml(root); +} + +void read_plots_xml(pugi::xml_node root) +{ for (auto node : root.children("plot")) { - model::plots.emplace_back(node); - model::plot_map[model::plots.back().id_] = model::plots.size() - 1; + std::string id_string = get_node_value(node, "id", true); + int id = std::stoi(id_string); + if (check_for_node(node, "type")) { + std::string type_str = get_node_value(node, "type", true); + if (type_str == "slice") + model::plots.emplace_back( + std::make_unique(node, Plot::PlotType::slice)); + else if (type_str == "voxel") + model::plots.emplace_back( + std::make_unique(node, Plot::PlotType::voxel)); + else if (type_str == "projection") + model::plots.emplace_back(std::make_unique(node)); + else + fatal_error( + fmt::format("Unsupported plot type '{}' in plot {}", type_str, id)); + + model::plot_map[model::plots.back()->id()] = model::plots.size() - 1; + } else { + fatal_error(fmt::format("Must specify plot type in plot {}", id)); + } } } -//============================================================================== -// CREATE_PPM creates an image based on user input from a plots.xml -// specification in the portable pixmap format (PPM) -//============================================================================== +void free_memory_plot() +{ + model::plots.clear(); + model::plot_map.clear(); +} -void create_ppm(Plot const& pl) +// creates an image based on user input from a plots.xml +// specification in the PNG/PPM format +void Plot::create_image() const { - size_t width = pl.pixels_[0]; - size_t height = pl.pixels_[1]; + size_t width = pixels_[0]; + size_t height = pixels_[1]; - ImageData data({width, height}, pl.not_found_); + ImageData data({width, height}, not_found_); // generate ids for the plot - auto ids = pl.get_map(); + auto ids = get_map(); // assign colors for (size_t y = 0; y < height; y++) { for (size_t x = 0; x < width; x++) { - auto id = ids.data_(y, x, pl.color_by_); + int idx = color_by_ == PlotColorBy::cells ? 0 : 2; + auto id = ids.data_(y, x, idx); // no setting needed if not found - if (id == NOT_FOUND) { continue; } + if (id == NOT_FOUND) { + continue; + } if (id == OVERLAP) { - data(x,y) = pl.overlap_color_; + data(x, y) = overlap_color_; continue; } - if (PlotColorBy::cells == pl.color_by_) { - data(x,y) = pl.colors_[model::cell_map[id]]; - } else if (PlotColorBy::mats == pl.color_by_) { + if (PlotColorBy::cells == color_by_) { + data(x, y) = colors_[model::cell_map[id]]; + } else if (PlotColorBy::mats == color_by_) { if (id == MATERIAL_VOID) { - data(x,y) = WHITE; + data(x, y) = WHITE; continue; } - data(x,y) = pl.colors_[model::material_map[id]]; + data(x, y) = colors_[model::material_map[id]]; } // color_by if-else - } // x for loop - } // y for loop + } // x for loop + } // y for loop // draw mesh lines if present - if (pl.index_meshlines_mesh_ >= 0) {draw_mesh_lines(pl, data);} + if (index_meshlines_mesh_ >= 0) { + draw_mesh_lines(data); + } - // write ppm data to file - output_ppm(pl, data); +// create image file +#ifdef USE_LIBPNG + output_png(path_plot(), data); +#else + output_ppm(path_plot(), data); +#endif } -void -Plot::set_id(pugi::xml_node plot_node) +void PlottableInterface::set_id(pugi::xml_node plot_node) { // Copy data into plots if (check_for_node(plot_node, "id")) { @@ -193,35 +289,23 @@ Plot::set_id(pugi::xml_node plot_node) // Check to make sure 'id' hasn't been used if (model::plot_map.find(id_) != model::plot_map.end()) { - fatal_error(fmt::format("Two or more plots use the same unique ID: {}", id_)); + fatal_error( + fmt::format("Two or more plots use the same unique ID: {}", id_)); } } -void -Plot::set_type(pugi::xml_node plot_node) +// Checks if png or ppm is already present +bool file_extension_present( + const std::string& filename, const std::string& extension) { - // Copy plot type - // Default is slice - type_ = PlotType::slice; - // check type specified on plot node - if (check_for_node(plot_node, "type")) { - std::string type_str = get_node_value(plot_node, "type", true); - // set type using node value - if (type_str == "slice") { - type_ = PlotType::slice; - } - else if (type_str == "voxel") { - type_ = PlotType::voxel; - } else { - // if we're here, something is wrong - fatal_error(fmt::format("Unsupported plot type '{}' in plot {}", - type_str, id_)); - } - } + std::string file_extension_if_present = + filename.substr(filename.find_last_of(".") + 1); + if (file_extension_if_present == extension) + return true; + return false; } -void -Plot::set_output_path(pugi::xml_node plot_node) +void Plot::set_output_path(pugi::xml_node plot_node) { // Set output file path std::string filename; @@ -229,15 +313,22 @@ Plot::set_output_path(pugi::xml_node plot_node) if (check_for_node(plot_node, "filename")) { filename = get_node_value(plot_node, "filename"); } else { - filename = fmt::format("plot_{}", id_); + filename = fmt::format("plot_{}", id()); } // add appropriate file extension to name - switch(type_) { + switch (type_) { case PlotType::slice: - filename.append(".ppm"); +#ifdef USE_LIBPNG + if (!file_extension_present(filename, "png")) + filename.append(".png"); +#else + if (!file_extension_present(filename, "ppm")) + filename.append(".ppm"); +#endif break; case PlotType::voxel: - filename.append(".h5"); + if (!file_extension_present(filename, "h5")) + filename.append(".h5"); break; } @@ -250,7 +341,8 @@ Plot::set_output_path(pugi::xml_node plot_node) pixels_[0] = pxls[0]; pixels_[1] = pxls[1]; } else { - fatal_error(fmt::format(" must be length 2 in slice plot {}", id_)); + fatal_error( + fmt::format(" must be length 2 in slice plot {}", id())); } } else if (PlotType::voxel == type_) { if (pxls.size() == 3) { @@ -258,32 +350,26 @@ Plot::set_output_path(pugi::xml_node plot_node) pixels_[1] = pxls[1]; pixels_[2] = pxls[2]; } else { - fatal_error(fmt::format(" must be length 3 in voxel plot {}", id_)); + fatal_error( + fmt::format(" must be length 3 in voxel plot {}", id())); } } } -void -Plot::set_bg_color(pugi::xml_node plot_node) +void PlottableInterface::set_bg_color(pugi::xml_node plot_node) { // Copy plot background color if (check_for_node(plot_node, "background")) { vector bg_rgb = get_node_array(plot_node, "background"); - if (PlotType::voxel == type_) { - if (mpi::master) { - warning(fmt::format("Background color ignored in voxel plot {}", id_)); - } - } if (bg_rgb.size() == 3) { not_found_ = bg_rgb; } else { - fatal_error(fmt::format("Bad background RGB in plot {}", id_)); + fatal_error(fmt::format("Bad background RGB in plot {}", id())); } } } -void -Plot::set_basis(pugi::xml_node plot_node) +void Plot::set_basis(pugi::xml_node plot_node) { // Copy plot basis if (PlotType::slice == type_) { @@ -298,26 +384,24 @@ Plot::set_basis(pugi::xml_node plot_node) } else if ("yz" == pl_basis) { basis_ = PlotBasis::yz; } else { - fatal_error(fmt::format("Unsupported plot basis '{}' in plot {}", - pl_basis, id_)); + fatal_error( + fmt::format("Unsupported plot basis '{}' in plot {}", pl_basis, id())); } } } -void -Plot::set_origin(pugi::xml_node plot_node) +void Plot::set_origin(pugi::xml_node plot_node) { // Copy plotting origin auto pl_origin = get_node_array(plot_node, "origin"); if (pl_origin.size() == 3) { origin_ = pl_origin; } else { - fatal_error(fmt::format("Origin must be length 3 in plot {}", id_)); + fatal_error(fmt::format("Origin must be length 3 in plot {}", id())); } } -void -Plot::set_width(pugi::xml_node plot_node) +void Plot::set_width(pugi::xml_node plot_node) { // Copy plotting width vector pl_width = get_node_array(plot_node, "width"); @@ -326,34 +410,34 @@ Plot::set_width(pugi::xml_node plot_node) width_.x = pl_width[0]; width_.y = pl_width[1]; } else { - fatal_error(fmt::format(" must be length 2 in slice plot {}", id_)); + fatal_error( + fmt::format(" must be length 2 in slice plot {}", id())); } } else if (PlotType::voxel == type_) { if (pl_width.size() == 3) { pl_width = get_node_array(plot_node, "width"); width_ = pl_width; } else { - fatal_error(fmt::format(" must be length 3 in voxel plot {}", id_)); + fatal_error( + fmt::format(" must be length 3 in voxel plot {}", id())); } } } -void -Plot::set_universe(pugi::xml_node plot_node) +void PlottableInterface::set_universe(pugi::xml_node plot_node) { // Copy plot universe level if (check_for_node(plot_node, "level")) { level_ = std::stoi(get_node_value(plot_node, "level")); if (level_ < 0) { - fatal_error(fmt::format("Bad universe level in plot {}", id_)); + fatal_error(fmt::format("Bad universe level in plot {}", id())); } } else { level_ = PLOT_LEVEL_LOWEST; } } -void -Plot::set_default_colors(pugi::xml_node plot_node) +void PlottableInterface::set_default_colors(pugi::xml_node plot_node) { // Copy plot color type and initialize all colors randomly std::string pl_color_by = "cell"; @@ -363,12 +447,12 @@ Plot::set_default_colors(pugi::xml_node plot_node) if ("cell" == pl_color_by) { color_by_ = PlotColorBy::cells; colors_.resize(model::cells.size()); - } else if("material" == pl_color_by) { + } else if ("material" == pl_color_by) { color_by_ = PlotColorBy::mats; colors_.resize(model::materials.size()); } else { - fatal_error(fmt::format("Unsupported plot color type '{}' in plot {}", - pl_color_by, id_)); + fatal_error(fmt::format( + "Unsupported plot color type '{}' in plot {}", pl_color_by, id())); } for (auto& c : colors_) { @@ -380,20 +464,13 @@ Plot::set_default_colors(pugi::xml_node plot_node) } } -void -Plot::set_user_colors(pugi::xml_node plot_node) +void PlottableInterface::set_user_colors(pugi::xml_node plot_node) { - if (!plot_node.select_nodes("color").empty() && PlotType::voxel == type_) { - if (mpi::master) { - warning(fmt::format("Color specifications ignored in voxel plot {}", id_)); - } - } - for (auto cn : plot_node.children("color")) { // Make sure 3 values are specified for RGB vector user_rgb = get_node_array(cn, "rgb"); if (user_rgb.size() != 3) { - fatal_error(fmt::format("Bad RGB in plot {}", id_)); + fatal_error(fmt::format("Bad RGB in plot {}", id())); } // Ensure that there is an id for this color specification int col_id; @@ -401,7 +478,7 @@ Plot::set_user_colors(pugi::xml_node plot_node) col_id = std::stoi(get_node_value(cn, "id")); } else { fatal_error(fmt::format( - "Must specify id for color specification in plot {}", id_)); + "Must specify id for color specification in plot {}", id())); } // Add RGB if (PlotColorBy::cells == color_by_) { @@ -409,30 +486,29 @@ Plot::set_user_colors(pugi::xml_node plot_node) col_id = model::cell_map[col_id]; colors_[col_id] = user_rgb; } else { - fatal_error(fmt::format("Could not find cell {} specified in plot {}", - col_id, id_)); + warning(fmt::format( + "Could not find cell {} specified in plot {}", col_id, id())); } } else if (PlotColorBy::mats == color_by_) { if (model::material_map.find(col_id) != model::material_map.end()) { col_id = model::material_map[col_id]; colors_[col_id] = user_rgb; } else { - fatal_error(fmt::format( - "Could not find material {} specified in plot {}", col_id, id_)); + warning(fmt::format( + "Could not find material {} specified in plot {}", col_id, id())); } } } // color node loop } -void -Plot::set_meshlines(pugi::xml_node plot_node) +void Plot::set_meshlines(pugi::xml_node plot_node) { // Deal with meshlines pugi::xpath_node_set mesh_line_nodes = plot_node.select_nodes("meshlines"); if (!mesh_line_nodes.empty()) { if (PlotType::voxel == type_) { - warning(fmt::format("Meshlines ignored in voxel plot {}", id_)); + warning(fmt::format("Meshlines ignored in voxel plot {}", id())); } if (mesh_line_nodes.size() == 1) { @@ -445,7 +521,8 @@ Plot::set_meshlines(pugi::xml_node plot_node) meshtype = get_node_value(meshlines_node, "meshtype"); } else { fatal_error(fmt::format( - "Must specify a meshtype for meshlines specification in plot {}", id_)); + "Must specify a meshtype for meshlines specification in plot {}", + id())); } // Ensure that there is a linewidth for this meshlines specification @@ -455,7 +532,8 @@ Plot::set_meshlines(pugi::xml_node plot_node) meshlines_width_ = std::stoi(meshline_width); } else { fatal_error(fmt::format( - "Must specify a linewidth for meshlines specification in plot {}", id_)); + "Must specify a linewidth for meshlines specification in plot {}", + id())); } // Check for color @@ -463,7 +541,8 @@ Plot::set_meshlines(pugi::xml_node plot_node) // Check and make sure 3 values are specified for RGB vector ml_rgb = get_node_array(meshlines_node, "color"); if (ml_rgb.size() != 3) { - fatal_error(fmt::format("Bad RGB for meshlines color in plot {}", id_)); + fatal_error( + fmt::format("Bad RGB for meshlines color in plot {}", id())); } meshlines_color_ = ml_rgb; } @@ -471,11 +550,12 @@ Plot::set_meshlines(pugi::xml_node plot_node) // Set mesh based on type if ("ufs" == meshtype) { if (!simulation::ufs_mesh) { - fatal_error(fmt::format("No UFS mesh for meshlines on plot {}", id_)); + fatal_error( + fmt::format("No UFS mesh for meshlines on plot {}", id())); } else { for (int i = 0; i < model::meshes.size(); ++i) { - if (const auto* m - = dynamic_cast(model::meshes[i].get())) { + if (const auto* m = + dynamic_cast(model::meshes[i].get())) { if (m == simulation::ufs_mesh) { index_meshlines_mesh_ = i; } @@ -486,11 +566,12 @@ Plot::set_meshlines(pugi::xml_node plot_node) } } else if ("entropy" == meshtype) { if (!simulation::entropy_mesh) { - fatal_error(fmt::format("No entropy mesh for meshlines on plot {}", id_)); + fatal_error( + fmt::format("No entropy mesh for meshlines on plot {}", id())); } else { for (int i = 0; i < model::meshes.size(); ++i) { - if (const auto* m - = dynamic_cast(model::meshes[i].get())) { + if (const auto* m = + dynamic_cast(model::meshes[i].get())) { if (m == simulation::entropy_mesh) { index_meshlines_mesh_ = i; } @@ -507,38 +588,33 @@ Plot::set_meshlines(pugi::xml_node plot_node) } else { std::stringstream err_msg; fatal_error(fmt::format("Must specify a mesh id for meshlines tally " - "mesh specification in plot {}", id_)); + "mesh specification in plot {}", + id())); } // find the tally index int idx; int err = openmc_get_mesh_index(tally_mesh_id, &idx); if (err != 0) { fatal_error(fmt::format("Could not find mesh {} specified in " - "meshlines for plot {}", tally_mesh_id, id_)); + "meshlines for plot {}", + tally_mesh_id, id())); } index_meshlines_mesh_ = idx; } else { - fatal_error(fmt::format("Invalid type for meshlines on plot {}", id_ )); + fatal_error(fmt::format("Invalid type for meshlines on plot {}", id())); } } else { - fatal_error(fmt::format("Mutliple meshlines specified in plot {}", id_)); + fatal_error(fmt::format("Mutliple meshlines specified in plot {}", id())); } } } -void -Plot::set_mask(pugi::xml_node plot_node) +void PlottableInterface::set_mask(pugi::xml_node plot_node) { // Deal with masks pugi::xpath_node_set mask_nodes = plot_node.select_nodes("mask"); if (!mask_nodes.empty()) { - if (PlotType::voxel == type_) { - if (mpi::master) { - warning(fmt::format("Mask ignored in voxel plot {}", id_)); - } - } - if (mask_nodes.size() == 1) { // Get pointer to mask pugi::xml_node mask_node = mask_nodes[0].node(); @@ -546,7 +622,8 @@ Plot::set_mask(pugi::xml_node plot_node) // Determine how many components there are and allocate vector iarray = get_node_array(mask_node, "components"); if (iarray.size() == 0) { - fatal_error(fmt::format("Missing in mask of plot {}", id_)); + fatal_error( + fmt::format("Missing in mask of plot {}", id())); } // First we need to change the user-specified identifiers to indices @@ -554,26 +631,26 @@ Plot::set_mask(pugi::xml_node plot_node) for (auto& col_id : iarray) { if (PlotColorBy::cells == color_by_) { if (model::cell_map.find(col_id) != model::cell_map.end()) { - col_id = model::cell_map[col_id]; - } - else { + col_id = model::cell_map[col_id]; + } else { fatal_error(fmt::format("Could not find cell {} specified in the " - "mask in plot {}", col_id, id_)); + "mask in plot {}", + col_id, id())); } } else if (PlotColorBy::mats == color_by_) { if (model::material_map.find(col_id) != model::material_map.end()) { col_id = model::material_map[col_id]; - } - else { + } else { fatal_error(fmt::format("Could not find material {} specified in " - "the mask in plot {}", col_id, id_)); + "the mask in plot {}", + col_id, id())); } } } // Alter colors based on mask information for (int j = 0; j < colors_.size(); j++) { - if (std::find(iarray.begin(), iarray.end(), j) == iarray.end()) { + if (contains(iarray, j)) { if (check_for_node(mask_node, "background")) { vector bg_rgb = get_node_array(mask_node, "background"); colors_[j] = bg_rgb; @@ -584,12 +661,13 @@ Plot::set_mask(pugi::xml_node plot_node) } } else { - fatal_error(fmt::format("Mutliple masks specified in plot {}", id_)); + fatal_error(fmt::format("Mutliple masks specified in plot {}", id())); } } } -void Plot::set_overlap_color(pugi::xml_node plot_node) { +void PlottableInterface::set_overlap_color(pugi::xml_node plot_node) +{ color_overlaps_ = false; if (check_for_node(plot_node, "show_overlaps")) { color_overlaps_ = get_node_value_bool(plot_node, "show_overlaps"); @@ -597,13 +675,14 @@ void Plot::set_overlap_color(pugi::xml_node plot_node) { if (check_for_node(plot_node, "overlap_color")) { if (!color_overlaps_) { warning(fmt::format( - "Overlap color specified in plot {} but overlaps won't be shown.", id_)); + "Overlap color specified in plot {} but overlaps won't be shown.", + id())); } vector olap_clr = get_node_array(plot_node, "overlap_color"); if (olap_clr.size() == 3) { overlap_color_ = olap_clr; } else { - fatal_error(fmt::format("Bad overlap RGB in plot {}", id_)); + fatal_error(fmt::format("Bad overlap RGB in plot {}", id())); } } } @@ -616,32 +695,37 @@ void Plot::set_overlap_color(pugi::xml_node plot_node) { } } -Plot::Plot(pugi::xml_node plot_node) - : index_meshlines_mesh_{-1}, overlap_color_{RED} +PlottableInterface::PlottableInterface(pugi::xml_node plot_node) { set_id(plot_node); - set_type(plot_node); - set_output_path(plot_node); set_bg_color(plot_node); - set_basis(plot_node); - set_origin(plot_node); - set_width(plot_node); set_universe(plot_node); set_default_colors(plot_node); set_user_colors(plot_node); - set_meshlines(plot_node); set_mask(plot_node); set_overlap_color(plot_node); -} // End Plot constructor +} + +Plot::Plot(pugi::xml_node plot_node, PlotType type) + : PlottableInterface(plot_node), type_(type), index_meshlines_mesh_ {-1} +{ + set_output_path(plot_node); + set_basis(plot_node); + set_origin(plot_node); + set_width(plot_node); + set_meshlines(plot_node); + slice_level_ = level_; // Copy level employed in SlicePlotBase::get_map + slice_color_overlaps_ = color_overlaps_; +} //============================================================================== // OUTPUT_PPM writes out a previously generated image to a PPM file //============================================================================== -void output_ppm(Plot const& pl, const ImageData& data) +void output_ppm(const std::string& filename, const ImageData& data) { // Open PPM file for writing - std::string fname = pl.path_plot_; + std::string fname = filename; fname = strtrim(fname); std::ofstream of; @@ -649,41 +733,95 @@ void output_ppm(Plot const& pl, const ImageData& data) // Write header of << "P6\n"; - of << pl.pixels_[0] << " " << pl.pixels_[1] << "\n"; + of << data.shape()[0] << " " << data.shape()[1] << "\n"; of << "255\n"; of.close(); of.open(fname, std::ios::binary | std::ios::app); // Write color for each pixel - for (int y = 0; y < pl.pixels_[1]; y++) { - for (int x = 0; x < pl.pixels_[0]; x++) { - RGBColor rgb = data(x,y); + for (int y = 0; y < data.shape()[1]; y++) { + for (int x = 0; x < data.shape()[0]; x++) { + RGBColor rgb = data(x, y); of << rgb.red << rgb.green << rgb.blue; } } of << "\n"; } +//============================================================================== +// OUTPUT_PNG writes out a previously generated image to a PNG file +//============================================================================== + +#ifdef USE_LIBPNG +void output_png(const std::string& filename, const ImageData& data) +{ + // Open PNG file for writing + std::string fname = filename; + fname = strtrim(fname); + auto fp = std::fopen(fname.c_str(), "wb"); + + // Initialize write and info structures + auto png_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); + auto info_ptr = png_create_info_struct(png_ptr); + + // Setup exception handling + if (setjmp(png_jmpbuf(png_ptr))) + fatal_error("Error during png creation"); + + png_init_io(png_ptr, fp); + + // Write header (8 bit colour depth) + int width = data.shape()[0]; + int height = data.shape()[1]; + png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + png_write_info(png_ptr, info_ptr); + + // Allocate memory for one row (3 bytes per pixel - RGB) + std::vector row(3 * width); + + // Write color for each pixel + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + RGBColor rgb = data(x, y); + row[3 * x] = rgb.red; + row[3 * x + 1] = rgb.green; + row[3 * x + 2] = rgb.blue; + } + png_write_row(png_ptr, row.data()); + } + + // End write + png_write_end(png_ptr, nullptr); + + // Clean up data structures + std::fclose(fp); + png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); + png_destroy_write_struct(&png_ptr, &info_ptr); +} +#endif + //============================================================================== // DRAW_MESH_LINES draws mesh line boundaries on an image //============================================================================== -void draw_mesh_lines(Plot const& pl, ImageData& data) +void Plot::draw_mesh_lines(ImageData& data) const { RGBColor rgb; - rgb = pl.meshlines_color_; + rgb = meshlines_color_; int ax1, ax2; - switch(pl.basis_) { - case PlotBasis::xy : + switch (basis_) { + case PlotBasis::xy: ax1 = 0; ax2 = 1; break; - case PlotBasis::xz : + case PlotBasis::xz: ax1 = 0; ax2 = 2; break; - case PlotBasis::yz : + case PlotBasis::yz: ax1 = 1; ax2 = 2; break; @@ -691,44 +829,46 @@ void draw_mesh_lines(Plot const& pl, ImageData& data) UNREACHABLE(); } - Position ll_plot {pl.origin_}; - Position ur_plot {pl.origin_}; + Position ll_plot {origin_}; + Position ur_plot {origin_}; - ll_plot[ax1] -= pl.width_[0] / 2.; - ll_plot[ax2] -= pl.width_[1] / 2.; - ur_plot[ax1] += pl.width_[0] / 2.; - ur_plot[ax2] += pl.width_[1] / 2.; + ll_plot[ax1] -= width_[0] / 2.; + ll_plot[ax2] -= width_[1] / 2.; + ur_plot[ax1] += width_[0] / 2.; + ur_plot[ax2] += width_[1] / 2.; Position width = ur_plot - ll_plot; // Find the (axis-aligned) lines of the mesh that intersect this plot. - auto axis_lines = model::meshes[pl.index_meshlines_mesh_] - ->plot(ll_plot, ur_plot); + auto axis_lines = + model::meshes[index_meshlines_mesh_]->plot(ll_plot, ur_plot); // Find the bounds along the second axis (accounting for low-D meshes). int ax2_min, ax2_max; if (axis_lines.second.size() > 0) { double frac = (axis_lines.second.back() - ll_plot[ax2]) / width[ax2]; - ax2_min = (1.0 - frac) * pl.pixels_[1]; - if (ax2_min < 0) ax2_min = 0; + ax2_min = (1.0 - frac) * pixels_[1]; + if (ax2_min < 0) + ax2_min = 0; frac = (axis_lines.second.front() - ll_plot[ax2]) / width[ax2]; - ax2_max = (1.0 - frac) * pl.pixels_[1]; - if (ax2_max > pl.pixels_[1]) ax2_max = pl.pixels_[1]; + ax2_max = (1.0 - frac) * pixels_[1]; + if (ax2_max > pixels_[1]) + ax2_max = pixels_[1]; } else { ax2_min = 0; - ax2_max = pl.pixels_[1]; + ax2_max = pixels_[1]; } // Iterate across the first axis and draw lines. for (auto ax1_val : axis_lines.first) { double frac = (ax1_val - ll_plot[ax1]) / width[ax1]; - int ax1_ind = frac * pl.pixels_[0]; + int ax1_ind = frac * pixels_[0]; for (int ax2_ind = ax2_min; ax2_ind < ax2_max; ++ax2_ind) { - for (int plus = 0; plus <= pl.meshlines_width_; plus++) { - if (ax1_ind+plus >= 0 && ax1_ind+plus < pl.pixels_[0]) - data(ax1_ind+plus, ax2_ind) = rgb; - if (ax1_ind-plus >= 0 && ax1_ind-plus < pl.pixels_[0]) - data(ax1_ind-plus, ax2_ind) = rgb; + for (int plus = 0; plus <= meshlines_width_; plus++) { + if (ax1_ind + plus >= 0 && ax1_ind + plus < pixels_[0]) + data(ax1_ind + plus, ax2_ind) = rgb; + if (ax1_ind - plus >= 0 && ax1_ind - plus < pixels_[0]) + data(ax1_ind - plus, ax2_ind) = rgb; } } } @@ -737,58 +877,57 @@ void draw_mesh_lines(Plot const& pl, ImageData& data) int ax1_min, ax1_max; if (axis_lines.first.size() > 0) { double frac = (axis_lines.first.front() - ll_plot[ax1]) / width[ax1]; - ax1_min = frac * pl.pixels_[0]; - if (ax1_min < 0) ax1_min = 0; + ax1_min = frac * pixels_[0]; + if (ax1_min < 0) + ax1_min = 0; frac = (axis_lines.first.back() - ll_plot[ax1]) / width[ax1]; - ax1_max = frac * pl.pixels_[0]; - if (ax1_max > pl.pixels_[0]) ax1_max = pl.pixels_[0]; + ax1_max = frac * pixels_[0]; + if (ax1_max > pixels_[0]) + ax1_max = pixels_[0]; } else { ax1_min = 0; - ax1_max = pl.pixels_[0]; + ax1_max = pixels_[0]; } // Iterate across the second axis and draw lines. for (auto ax2_val : axis_lines.second) { double frac = (ax2_val - ll_plot[ax2]) / width[ax2]; - int ax2_ind = (1.0 - frac) * pl.pixels_[1]; + int ax2_ind = (1.0 - frac) * pixels_[1]; for (int ax1_ind = ax1_min; ax1_ind < ax1_max; ++ax1_ind) { - for (int plus = 0; plus <= pl.meshlines_width_; plus++) { - if (ax2_ind+plus >= 0 && ax2_ind+plus < pl.pixels_[1]) - data(ax1_ind, ax2_ind+plus) = rgb; - if (ax2_ind-plus >= 0 && ax2_ind-plus < pl.pixels_[1]) - data(ax1_ind, ax2_ind-plus) = rgb; + for (int plus = 0; plus <= meshlines_width_; plus++) { + if (ax2_ind + plus >= 0 && ax2_ind + plus < pixels_[1]) + data(ax1_ind, ax2_ind + plus) = rgb; + if (ax2_ind - plus >= 0 && ax2_ind - plus < pixels_[1]) + data(ax1_ind, ax2_ind - plus) = rgb; } } } } -//============================================================================== -// CREATE_VOXEL outputs a binary file that can be input into silomesh for 3D -// geometry visualization. It works the same way as create_ppm by dragging a -// particle across the geometry for the specified number of voxels. The first 3 -// int's in the binary are the number of x, y, and z voxels. The next 3 -// double's are the widths of the voxels in the x, y, and z directions. The -// next 3 double's are the x, y, and z coordinates of the lower left -// point. Finally the binary is filled with entries of four int's each. Each -// 'row' in the binary contains four int's: 3 for x,y,z position and 1 for -// cell or material id. For 1 million voxels this produces a file of -// approximately 15MB. -// ============================================================================= - -void create_voxel(Plot const& pl) +/* outputs a binary file that can be input into silomesh for 3D geometry + * visualization. It works the same way as create_image by dragging a particle + * across the geometry for the specified number of voxels. The first 3 int's in + * the binary are the number of x, y, and z voxels. The next 3 double's are + * the widths of the voxels in the x, y, and z directions. The next 3 double's + * are the x, y, and z coordinates of the lower left point. Finally the binary + * is filled with entries of four int's each. Each 'row' in the binary contains + * four int's: 3 for x,y,z position and 1 for cell or material id. For 1 + * million voxels this produces a file of approximately 15MB. + */ +void Plot::create_voxel() const { // compute voxel widths in each direction array vox; - vox[0] = pl.width_[0]/(double)pl.pixels_[0]; - vox[1] = pl.width_[1]/(double)pl.pixels_[1]; - vox[2] = pl.width_[2]/(double)pl.pixels_[2]; + vox[0] = width_[0] / static_cast(pixels_[0]); + vox[1] = width_[1] / static_cast(pixels_[1]); + vox[2] = width_[2] / static_cast(pixels_[2]); // initial particle position - Position ll = pl.origin_ - pl.width_ / 2.; + Position ll = origin_ - width_ / 2.; // Open binary plot file for writing std::ofstream of; - std::string fname = std::string(pl.path_plot_); + std::string fname = std::string(path_plot_); fname = strtrim(fname); hid_t file_id = file_open(fname, 'w'); @@ -804,7 +943,7 @@ void create_voxel(Plot const& pl) // Write current date and time write_attribute(file_id, "date_and_time", time_stamp().c_str()); array pixels; - std::copy(pl.pixels_.begin(), pl.pixels_.end(), pixels.begin()); + std::copy(pixels_.begin(), pixels_.end(), pixels.begin()); write_attribute(file_id, "num_voxels", pixels); write_attribute(file_id, "voxel_width", vox); write_attribute(file_id, "lower_left", ll); @@ -812,24 +951,24 @@ void create_voxel(Plot const& pl) // Create dataset for voxel data -- note that the dimensions are reversed // since we want the order in the file to be z, y, x hsize_t dims[3]; - dims[0] = pl.pixels_[2]; - dims[1] = pl.pixels_[1]; - dims[2] = pl.pixels_[0]; + dims[0] = pixels_[2]; + dims[1] = pixels_[1]; + dims[2] = pixels_[0]; hid_t dspace, dset, memspace; voxel_init(file_id, &(dims[0]), &dspace, &dset, &memspace); - PlotBase pltbase; - pltbase.width_ = pl.width_; - pltbase.origin_ = pl.origin_; + SlicePlotBase pltbase; + pltbase.width_ = width_; + pltbase.origin_ = origin_; pltbase.basis_ = PlotBasis::xy; - pltbase.pixels_ = pl.pixels_; - pltbase.level_ = -1; // all universes for voxel files - pltbase.color_overlaps_ = pl.color_overlaps_; + pltbase.pixels_ = pixels_; + pltbase.slice_color_overlaps_ = color_overlaps_; ProgressBar pb; - for (int z = 0; z < pl.pixels_[2]; z++) { + for (int z = 0; z < pixels_[2]; z++) { // update progress bar - pb.set_value(100.*(double)z/(double)(pl.pixels_[2]-1)); + pb.set_value( + 100. * static_cast(z) / static_cast((pixels_[2] - 1))); // update z coordinate pltbase.origin_.z = ll.z + z * vox[2]; @@ -838,8 +977,9 @@ void create_voxel(Plot const& pl) IdData ids = pltbase.get_map(); // select only cell/material ID data and flip the y-axis - int idx = pl.color_by_ == PlotColorBy::cells ? 0 : 1; - xt::xtensor data_slice = xt::view(ids.data_, xt::all(), xt::all(), idx); + int idx = color_by_ == PlotColorBy::cells ? 0 : 2; + xt::xtensor data_slice = + xt::view(ids.data_, xt::all(), xt::all(), idx); xt::xtensor data_flipped = xt::flip(data_slice, 0); // Write to HDF5 dataset @@ -850,14 +990,13 @@ void create_voxel(Plot const& pl) file_close(file_id); } -void -voxel_init(hid_t file_id, const hsize_t* dims, - hid_t* dspace, hid_t* dset, hid_t* memspace) +void voxel_init(hid_t file_id, const hsize_t* dims, hid_t* dspace, hid_t* dset, + hid_t* memspace) { // Create dataspace/dataset for voxel data *dspace = H5Screate_simple(3, dims, nullptr); *dset = H5Dcreate(file_id, "data", H5T_NATIVE_INT, *dspace, H5P_DEFAULT, - H5P_DEFAULT, H5P_DEFAULT); + H5P_DEFAULT, H5P_DEFAULT); // Create dataspace for a slice of the voxel hsize_t dims_slice[2] {dims[1], dims[2]}; @@ -869,40 +1008,577 @@ voxel_init(hid_t file_id, const hsize_t* dims, H5Sselect_hyperslab(*dspace, H5S_SELECT_SET, start, nullptr, count, nullptr); } - -void -voxel_write_slice(int x, hid_t dspace, hid_t dset, hid_t memspace, void* buf) +void voxel_write_slice( + int x, hid_t dspace, hid_t dset, hid_t memspace, void* buf) { hssize_t offset[3] {x, 0, 0}; H5Soffset_simple(dspace, offset); H5Dwrite(dset, H5T_NATIVE_INT, memspace, dspace, H5P_DEFAULT, buf); } - -void -voxel_finalize(hid_t dspace, hid_t dset, hid_t memspace) +void voxel_finalize(hid_t dspace, hid_t dset, hid_t memspace) { H5Dclose(dset); H5Sclose(dspace); H5Sclose(memspace); } -RGBColor random_color(void) { - return {int(prn(&model::plotter_seed)*255), - int(prn(&model::plotter_seed)*255), - int(prn(&model::plotter_seed)*255)}; +RGBColor random_color(void) +{ + return {int(prn(&model::plotter_seed) * 255), + int(prn(&model::plotter_seed) * 255), int(prn(&model::plotter_seed) * 255)}; +} + +ProjectionPlot::ProjectionPlot(pugi::xml_node node) : PlottableInterface(node) +{ + set_output_path(node); + set_look_at(node); + set_camera_position(node); + set_field_of_view(node); + set_pixels(node); + set_opacities(node); + set_orthographic_width(node); + set_wireframe_thickness(node); + set_wireframe_ids(node); + set_wireframe_color(node); + + if (check_for_node(node, "orthographic_width") && + check_for_node(node, "field_of_view")) + fatal_error("orthographic_width and field_of_view are mutually exclusive " + "parameters."); +} + +void ProjectionPlot::set_wireframe_color(pugi::xml_node plot_node) +{ + // Copy plot background color + if (check_for_node(plot_node, "wireframe_color")) { + vector w_rgb = get_node_array(plot_node, "wireframe_color"); + if (w_rgb.size() == 3) { + wireframe_color_ = w_rgb; + } else { + fatal_error(fmt::format("Bad wireframe RGB in plot {}", id())); + } + } +} + +void ProjectionPlot::set_output_path(pugi::xml_node node) +{ + // Set output file path + std::string filename; + + if (check_for_node(node, "filename")) { + filename = get_node_value(node, "filename"); + } else { + filename = fmt::format("plot_{}", id()); + } + +#ifdef USE_LIBPNG + if (!file_extension_present(filename, "png")) + filename.append(".png"); +#else + if (!file_extension_present(filename, "ppm")) + filename.append(".ppm"); +#endif + path_plot_ = filename; +} + +// Advances to the next boundary from outside the geometry +// Returns -1 if no intersection found, and the surface index +// if an intersection was found. +int ProjectionPlot::advance_to_boundary_from_void(GeometryState& p) +{ + constexpr double scoot = 1e-5; + double min_dist = {INFINITY}; + auto coord = p.coord(0); + Universe* uni = model::universes[model::root_universe].get(); + int intersected_surface = -1; + for (auto c_i : uni->cells_) { + auto dist = model::cells.at(c_i)->distance(coord.r, coord.u, 0, &p); + if (dist.first < min_dist) { + min_dist = dist.first; + intersected_surface = dist.second; + } + } + if (min_dist > 1e300) + return -1; + else { // advance the particle + for (int j = 0; j < p.n_coord(); ++j) + p.coord(j).r += (min_dist + scoot) * p.coord(j).u; + return std::abs(intersected_surface); + } +} + +bool ProjectionPlot::trackstack_equivalent( + const std::vector& track1, + const std::vector& track2) const +{ + if (wireframe_ids_.empty()) { + // Draw wireframe for all surfaces/cells/materials + if (track1.size() != track2.size()) + return false; + for (int i = 0; i < track1.size(); ++i) { + if (track1[i].id != track2[i].id || + track1[i].surface != track2[i].surface) { + return false; + } + } + return true; + } else { + // This runs in O(nm) where n is the intersection stack size + // and m is the number of IDs we are wireframing. A simpler + // algorithm can likely be found. + for (const int id : wireframe_ids_) { + int t1_i = 0; + int t2_i = 0; + + // Advance to first instance of the ID + while (t1_i < track1.size() && t2_i < track2.size()) { + while (t1_i < track1.size() && track1[t1_i].id != id) + t1_i++; + while (t2_i < track2.size() && track2[t2_i].id != id) + t2_i++; + + // This one is really important! + if ((t1_i == track1.size() && t2_i != track2.size()) || + (t1_i != track1.size() && t2_i == track2.size())) + return false; + if (t1_i == track1.size() && t2_i == track2.size()) + break; + // Check if surface different + if (track1[t1_i].surface != track2[t2_i].surface) + return false; + + // Pretty sure this should not be used: + // if (t2_i != track2.size() - 1 && + // t1_i != track1.size() - 1 && + // track1[t1_i+1].id != track2[t2_i+1].id) return false; + if (t2_i != 0 && t1_i != 0 && + track1[t1_i - 1].surface != track2[t2_i - 1].surface) + return false; + + // Check if neighboring cells are different + // if (track1[t1_i ? t1_i - 1 : 0].id != track2[t2_i ? t2_i - 1 : 0].id) + // return false; if (track1[t1_i < track1.size() - 1 ? t1_i + 1 : t1_i + // ].id != + // track2[t2_i < track2.size() - 1 ? t2_i + 1 : t2_i].id) return + // false; + t1_i++, t2_i++; + } + } + return true; + } +} + +void ProjectionPlot::create_output() const +{ + // Get centerline vector for camera-to-model. We create vectors around this + // that form a pixel array, and then trace rays along that. + auto up = up_ / up_.norm(); + Direction looking_direction = look_at_ - camera_position_; + looking_direction /= looking_direction.norm(); + if (std::abs(std::abs(looking_direction.dot(up)) - 1.0) < 1e-9) + fatal_error("Up vector cannot align with vector between camera position " + "and look_at!"); + Direction cam_yaxis = looking_direction.cross(up); + cam_yaxis /= cam_yaxis.norm(); + Direction cam_zaxis = cam_yaxis.cross(looking_direction); + cam_zaxis /= cam_zaxis.norm(); + + // Transformation matrix for directions + std::vector camera_to_model = {looking_direction.x, cam_yaxis.x, + cam_zaxis.x, looking_direction.y, cam_yaxis.y, cam_zaxis.y, + looking_direction.z, cam_yaxis.z, cam_zaxis.z}; + + // Now we convert to the polar coordinate system with the polar angle + // measuring the angle from the vector up_. Phi is the rotation about up_. For + // now, up_ is hard-coded to be +z. + constexpr double DEGREE_TO_RADIAN = M_PI / 180.0; + double horiz_fov_radians = horizontal_field_of_view_ * DEGREE_TO_RADIAN; + double p0 = static_cast(pixels_[0]); + double p1 = static_cast(pixels_[1]); + double vert_fov_radians = horiz_fov_radians * p1 / p0; + double dphi = horiz_fov_radians / p0; + double dmu = vert_fov_radians / p1; + + size_t width = pixels_[0]; + size_t height = pixels_[1]; + ImageData data({width, height}, not_found_); + + // This array marks where the initial wireframe was drawn. + // We convolve it with a filter that gets adjusted with the + // wireframe thickness in order to thicken the lines. + xt::xtensor wireframe_initial({width, height}, 0); + + /* Holds all of the track segments for the current rendered line of pixels. + * old_segments holds a copy of this_line_segments from the previous line. + * By holding both we can check if the cell/material intersection stack + * differs from the left or upper neighbor. This allows a robustly drawn + * wireframe. If only checking the left pixel (which requires substantially + * less memory), the wireframe tends to be spotty and be disconnected for + * surface edges oriented horizontally in the rendering. + * + * Note that a vector of vectors is required rather than a 2-tensor, + * since the stack size varies within each column. + */ + const int n_threads = num_threads(); + std::vector>> this_line_segments( + n_threads); + for (int t = 0; t < n_threads; ++t) { + this_line_segments[t].resize(pixels_[0]); + } + + // The last thread writes to this, and the first thread reads from it. + std::vector> old_segments(pixels_[0]); + +#pragma omp parallel + { + const int n_threads = num_threads(); + const int tid = thread_num(); + + GeometryState p; + p.u() = {1.0, 0.0, 0.0}; + + int vert = tid; + for (int iter = 0; iter <= pixels_[1] / n_threads; iter++) { + + // Save bottom line of current work chunk to compare against later + // I used to have this inside the below if block, but it causes a + // spurious line to be drawn at the bottom of the image. Not sure + // why, but moving it here fixes things. + if (tid == n_threads - 1) + old_segments = this_line_segments[n_threads - 1]; + + if (vert < pixels_[1]) { + + for (int horiz = 0; horiz < pixels_[0]; ++horiz) { + + // Projection mode below decides ray starting conditions + Position init_r; + Direction init_u; + + // Generate the starting position/direction of the ray + if (orthographic_width_ == 0.0) { // perspective projection + double this_phi = + -horiz_fov_radians / 2.0 + dphi * horiz + 0.5 * dphi; + double this_mu = + -vert_fov_radians / 2.0 + dmu * vert + M_PI / 2.0 + 0.5 * dmu; + Direction camera_local_vec; + camera_local_vec.x = std::cos(this_phi) * std::sin(this_mu); + camera_local_vec.y = std::sin(this_phi) * std::sin(this_mu); + camera_local_vec.z = std::cos(this_mu); + init_u = camera_local_vec.rotate(camera_to_model); + init_r = camera_position_; + } else { // orthographic projection + init_u = looking_direction; + + double x_pix_coord = (static_cast(horiz) - p0 / 2.0) / p0; + double y_pix_coord = (static_cast(vert) - p1 / 2.0) / p0; + + init_r = camera_position_; + init_r += cam_yaxis * x_pix_coord * orthographic_width_; + init_r += cam_zaxis * y_pix_coord * orthographic_width_; + } + + // Resets internal geometry state of particle + p.init_from_r_u(init_r, init_u); + + bool hitsomething = false; + bool intersection_found = true; + int loop_counter = 0; + + this_line_segments[tid][horiz].clear(); + + int first_surface = + -1; // surface first passed when entering the model + bool first_inside_model = true; // false after entering the model + while (intersection_found) { + bool inside_cell = false; + + int32_t i_surface = std::abs(p.surface()) - 1; + if (i_surface > 0 && + model::surfaces[i_surface]->geom_type_ == GeometryType::DAG) { +#ifdef DAGMC + int32_t i_cell = next_cell(i_surface, + p.cell_last(p.n_coord() - 1), p.lowest_coord().universe); + inside_cell = i_cell >= 0; +#else + fatal_error( + "Not compiled for DAGMC, but somehow you have a DAGCell!"); +#endif + } else { + inside_cell = exhaustive_find_cell(p); + } + + if (inside_cell) { + + // This allows drawing wireframes with surface intersection + // edges on the model boundary for the same cell. + if (first_inside_model) { + this_line_segments[tid][horiz].emplace_back( + color_by_ == PlotColorBy::mats ? p.material() + : p.lowest_coord().cell, + 0.0, first_surface); + first_inside_model = false; + } + + hitsomething = true; + intersection_found = true; + auto dist = distance_to_boundary(p); + this_line_segments[tid][horiz].emplace_back( + color_by_ == PlotColorBy::mats ? p.material() + : p.lowest_coord().cell, + dist.distance, std::abs(dist.surface_index)); + + // Advance particle + for (int lev = 0; lev < p.n_coord(); ++lev) { + p.coord(lev).r += dist.distance * p.coord(lev).u; + } + p.surface() = dist.surface_index; + p.n_coord_last() = p.n_coord(); + p.n_coord() = dist.coord_level; + if (dist.lattice_translation[0] != 0 || + dist.lattice_translation[1] != 0 || + dist.lattice_translation[2] != 0) { + cross_lattice(p, dist); + } + + } else { + first_surface = advance_to_boundary_from_void(p); + intersection_found = + first_surface != -1; // -1 if no surface found + } + loop_counter++; + if (loop_counter > MAX_INTERSECTIONS) + fatal_error("Infinite loop in projection plot"); + } + + // Now color the pixel based on what we have intersected... + // Loops backwards over intersections. + Position current_color( + not_found_.red, not_found_.green, not_found_.blue); + const auto& segments = this_line_segments[tid][horiz]; + for (unsigned i = segments.size(); i-- > 0;) { + int colormap_idx = segments[i].id; + RGBColor seg_color = colors_[colormap_idx]; + Position seg_color_vec( + seg_color.red, seg_color.green, seg_color.blue); + double mixing = std::exp(-xs_[colormap_idx] * segments[i].length); + current_color = + current_color * mixing + (1.0 - mixing) * seg_color_vec; + RGBColor result; + result.red = static_cast(current_color.x); + result.green = static_cast(current_color.y); + result.blue = static_cast(current_color.z); + data(horiz, vert) = result; + } + + // Check to draw wireframe in horizontal direction. No inter-thread + // comm. + if (horiz > 0) { + if (!trackstack_equivalent(this_line_segments[tid][horiz], + this_line_segments[tid][horiz - 1])) { + wireframe_initial(horiz, vert) = 1; + } + } + } + } // end "if" vert in correct range + + // We require a barrier before comparing vertical neighbors' intersection + // stacks. i.e. all threads must be done with their line. +#pragma omp barrier + + // Now that the horizontal line has finished rendering, we can fill in + // wireframe entries that require comparison among all the threads. Hence + // the omp barrier being used. It has to be OUTSIDE any if blocks! + if (vert < pixels_[1]) { + // Loop over horizontal pixels, checking intersection stack of upper + // neighbor + + const std::vector>* top_cmp = nullptr; + if (tid == 0) + top_cmp = &old_segments; + else + top_cmp = &this_line_segments[tid - 1]; + + for (int horiz = 0; horiz < pixels_[0]; ++horiz) { + if (!trackstack_equivalent( + this_line_segments[tid][horiz], (*top_cmp)[horiz])) { + wireframe_initial(horiz, vert) = 1; + } + } + } + + // We need another barrier to ensure threads don't proceed to modify their + // intersection stacks on that horizontal line while others are + // potentially still working on the above. +#pragma omp barrier + vert += n_threads; + } + } // end omp parallel + + // Now thicken the wireframe lines and apply them to our image + for (int vert = 0; vert < pixels_[1]; ++vert) { + for (int horiz = 0; horiz < pixels_[0]; ++horiz) { + if (wireframe_initial(horiz, vert)) { + if (wireframe_thickness_ == 1) + data(horiz, vert) = wireframe_color_; + for (int i = -wireframe_thickness_ / 2; i < wireframe_thickness_ / 2; + ++i) + for (int j = -wireframe_thickness_ / 2; j < wireframe_thickness_ / 2; + ++j) + if (i * i + j * j < wireframe_thickness_ * wireframe_thickness_) { + + // Check if wireframe pixel is out of bounds + int w_i = std::max(std::min(horiz + i, pixels_[0] - 1), 0); + int w_j = std::max(std::min(vert + j, pixels_[1] - 1), 0); + data(w_i, w_j) = wireframe_color_; + } + } + } + } + +#ifdef USE_LIBPNG + output_png(path_plot(), data); +#else + output_ppm(path_plot(), data); +#endif +} + +void ProjectionPlot::print_info() const +{ + fmt::print("Plot Type: Projection\n"); + fmt::print("Camera position: {} {} {}\n", camera_position_.x, + camera_position_.y, camera_position_.z); + fmt::print("Look at: {} {} {}\n", look_at_.x, look_at_.y, look_at_.z); + fmt::print( + "Horizontal field of view: {} degrees\n", horizontal_field_of_view_); + fmt::print("Pixels: {} {}\n", pixels_[0], pixels_[1]); +} + +void ProjectionPlot::set_opacities(pugi::xml_node node) +{ + xs_.resize(colors_.size(), 1e6); // set to large value for opaque by default + + for (auto cn : node.children("color")) { + // Make sure 3 values are specified for RGB + double user_xs = std::stod(get_node_value(cn, "xs")); + int col_id = std::stoi(get_node_value(cn, "id")); + + // Add RGB + if (PlotColorBy::cells == color_by_) { + if (model::cell_map.find(col_id) != model::cell_map.end()) { + col_id = model::cell_map[col_id]; + xs_[col_id] = user_xs; + } else { + warning(fmt::format( + "Could not find cell {} specified in plot {}", col_id, id())); + } + } else if (PlotColorBy::mats == color_by_) { + if (model::material_map.find(col_id) != model::material_map.end()) { + col_id = model::material_map[col_id]; + xs_[col_id] = user_xs; + } else { + warning(fmt::format( + "Could not find material {} specified in plot {}", col_id, id())); + } + } + } +} + +void ProjectionPlot::set_orthographic_width(pugi::xml_node node) +{ + if (check_for_node(node, "orthographic_width")) { + double orthographic_width = + std::stod(get_node_value(node, "orthographic_width", true)); + if (orthographic_width < 0.0) + fatal_error("Requires positive orthographic_width"); + orthographic_width_ = orthographic_width; + } +} + +void ProjectionPlot::set_wireframe_thickness(pugi::xml_node node) +{ + if (check_for_node(node, "wireframe_thickness")) { + int wireframe_thickness = + std::stoi(get_node_value(node, "wireframe_thickness", true)); + if (wireframe_thickness < 0) + fatal_error("Requires non-negative wireframe thickness"); + wireframe_thickness_ = wireframe_thickness; + } +} + +void ProjectionPlot::set_wireframe_ids(pugi::xml_node node) +{ + if (check_for_node(node, "wireframe_ids")) { + wireframe_ids_ = get_node_array(node, "wireframe_ids"); + // It is read in as actual ID values, but we have to convert to indices in + // mat/cell array + for (auto& x : wireframe_ids_) + x = color_by_ == PlotColorBy::mats ? model::material_map[x] + : model::cell_map[x]; + } + // We make sure the list is sorted in order to later use + // std::binary_search. + std::sort(wireframe_ids_.begin(), wireframe_ids_.end()); +} + +void ProjectionPlot::set_pixels(pugi::xml_node node) +{ + vector pxls = get_node_array(node, "pixels"); + if (pxls.size() != 2) + fatal_error( + fmt::format(" must be length 2 in projection plot {}", id())); + pixels_[0] = pxls[0]; + pixels_[1] = pxls[1]; +} + +void ProjectionPlot::set_camera_position(pugi::xml_node node) +{ + vector camera_pos = get_node_array(node, "camera_position"); + if (camera_pos.size() != 3) { + fatal_error( + fmt::format("look_at element must have three floating point values")); + } + camera_position_.x = camera_pos[0]; + camera_position_.y = camera_pos[1]; + camera_position_.z = camera_pos[2]; +} + +void ProjectionPlot::set_look_at(pugi::xml_node node) +{ + vector look_at = get_node_array(node, "look_at"); + if (look_at.size() != 3) { + fatal_error("look_at element must have three floating point values"); + } + look_at_.x = look_at[0]; + look_at_.y = look_at[1]; + look_at_.z = look_at[2]; +} + +void ProjectionPlot::set_field_of_view(pugi::xml_node node) +{ + // Defaults to 70 degree horizontal field of view (see .h file) + if (check_for_node(node, "field_of_view")) { + double fov = std::stod(get_node_value(node, "field_of_view", true)); + if (fov < 180.0 && fov > 0.0) { + horizontal_field_of_view_ = fov; + } else { + fatal_error(fmt::format( + "Field of view for plot {} out-of-range. Must be in (0, 180).", id())); + } + } } extern "C" int openmc_id_map(const void* plot, int32_t* data_out) { - auto plt = reinterpret_cast(plot); + auto plt = reinterpret_cast(plot); if (!plt) { set_errmsg("Invalid slice pointer passed to openmc_id_map"); return OPENMC_E_INVALID_ARGUMENT; } - if (plt->color_overlaps_ && model::overlap_check_count.size() == 0) { + if (plt->slice_color_overlaps_ && model::overlap_check_count.size() == 0) { model::overlap_check_count.resize(model::cells.size()); } @@ -914,15 +1590,16 @@ extern "C" int openmc_id_map(const void* plot, int32_t* data_out) return 0; } -extern "C" int openmc_property_map(const void* plot, double* data_out) { +extern "C" int openmc_property_map(const void* plot, double* data_out) +{ - auto plt = reinterpret_cast(plot); + auto plt = reinterpret_cast(plot); if (!plt) { set_errmsg("Invalid slice pointer passed to openmc_id_map"); return OPENMC_E_INVALID_ARGUMENT; } - if (plt->color_overlaps_ && model::overlap_check_count.size() == 0) { + if (plt->slice_color_overlaps_ && model::overlap_check_count.size() == 0) { model::overlap_check_count.resize(model::cells.size()); } @@ -934,5 +1611,4 @@ extern "C" int openmc_property_map(const void* plot, double* data_out) { return 0; } - } // namespace openmc diff --git a/src/position.cpp b/src/position.cpp index 46611df9986..5b3613b2897 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -6,8 +6,7 @@ namespace openmc { // Position implementation //============================================================================== -Position& -Position::operator+=(Position other) +Position& Position::operator+=(Position other) { x += other.x; y += other.y; @@ -15,8 +14,7 @@ Position::operator+=(Position other) return *this; } -Position& -Position::operator+=(double v) +Position& Position::operator+=(double v) { x += v; y += v; @@ -24,8 +22,7 @@ Position::operator+=(double v) return *this; } -Position& -Position::operator-=(Position other) +Position& Position::operator-=(Position other) { x -= other.x; y -= other.y; @@ -33,8 +30,7 @@ Position::operator-=(Position other) return *this; } -Position& -Position::operator-=(double v) +Position& Position::operator-=(double v) { x -= v; y -= v; @@ -42,8 +38,7 @@ Position::operator-=(double v) return *this; } -Position& -Position::operator*=(Position other) +Position& Position::operator*=(Position other) { x *= other.x; y *= other.y; @@ -51,8 +46,7 @@ Position::operator*=(Position other) return *this; } -Position& -Position::operator*=(double v) +Position& Position::operator*=(double v) { x *= v; y *= v; @@ -60,8 +54,7 @@ Position::operator*=(double v) return *this; } -Position& -Position::operator/=(Position other) +Position& Position::operator/=(Position other) { x /= other.x; y /= other.y; @@ -69,8 +62,7 @@ Position::operator/=(Position other) return *this; } -Position& -Position::operator/=(double v) +Position& Position::operator/=(double v) { x /= v; y /= v; @@ -78,23 +70,19 @@ Position::operator/=(double v) return *this; } -Position -Position::operator-() const +Position Position::operator-() const { return {-x, -y, -z}; } Position Position::rotate(const vector& rotation) const { - return { - x*rotation[0] + y*rotation[1] + z*rotation[2], - x*rotation[3] + y*rotation[4] + z*rotation[5], - x*rotation[6] + y*rotation[7] + z*rotation[8] - }; + return {x * rotation[0] + y * rotation[1] + z * rotation[2], + x * rotation[3] + y * rotation[4] + z * rotation[5], + x * rotation[6] + y * rotation[7] + z * rotation[8]}; } -std::ostream& -operator<<(std::ostream& os, Position r) +std::ostream& operator<<(std::ostream& os, Position r) { os << "(" << r.x << ", " << r.y << ", " << r.z << ")"; return os; diff --git a/src/progress_bar.cpp b/src/progress_bar.cpp index ab77c72f97e..538b50b872e 100644 --- a/src/progress_bar.cpp +++ b/src/progress_bar.cpp @@ -1,17 +1,19 @@ #include "openmc/progress_bar.h" -#include -#include #include +#include +#include -#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)) +#if defined(__unix__) || defined(__unix) || \ + (defined(__APPLE__) && defined(__MACH__)) #include #endif #define BAR_WIDTH 72 -bool is_terminal() { +bool is_terminal() +{ #ifdef _POSIX_VERSION return isatty(STDOUT_FILENO) != 0; #else @@ -19,15 +21,17 @@ bool is_terminal() { #endif } -ProgressBar::ProgressBar() { +ProgressBar::ProgressBar() +{ // initialize bar set_value(0.0); } -void -ProgressBar::set_value(double val) { +void ProgressBar::set_value(double val) +{ - if (!is_terminal()) return; + if (!is_terminal()) + return; // set the bar percentage if (val >= 100.0) { @@ -50,17 +54,19 @@ ProgressBar::set_value(double val) { } else if (val < 0.0) { bar.append(remaining_width, ' '); } else { - int width = (int)((double)remaining_width*val/100); + int width = (int)((double)remaining_width * val / 100); bar.append(width, '='); bar.append(1, '>'); - bar.append(remaining_width-width-1, ' '); + bar.append(remaining_width - width - 1, ' '); } bar.append("|+"); // write the bar std::cout << '\r' << bar << std::flush; - if (val >= 100.0) { std::cout << "\n"; } + if (val >= 100.0) { + std::cout << "\n"; + } // reset the bar value bar = ""; diff --git a/src/random_dist.cpp b/src/random_dist.cpp index c8d2380c364..1aa35a689cf 100644 --- a/src/random_dist.cpp +++ b/src/random_dist.cpp @@ -46,11 +46,4 @@ double normal_variate(double mean, double standard_deviation, uint64_t* seed) return mean + standard_deviation * z * x; } -double muir_spectrum(double e0, double m_rat, double kt, uint64_t* seed) -{ - // https://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-05411-MS - double sigma = std::sqrt(4. * e0 * kt / m_rat); - return normal_variate(e0, sigma, seed); -} - } // namespace openmc diff --git a/src/random_lcg.cpp b/src/random_lcg.cpp index 38174be6573..581d696176f 100644 --- a/src/random_lcg.cpp +++ b/src/random_lcg.cpp @@ -2,26 +2,25 @@ #include - namespace openmc { // Starting seed int64_t master_seed {1}; // LCG parameters -constexpr uint64_t prn_mult {6364136223846793005ULL}; // multiplication -constexpr uint64_t prn_add {1442695040888963407ULL}; // additive factor, c -constexpr uint64_t prn_stride {152917LL}; // stride between particles +constexpr uint64_t prn_mult {6364136223846793005ULL}; // multiplication +constexpr uint64_t prn_add {1442695040888963407ULL}; // additive factor, c +constexpr uint64_t prn_stride {152917LL}; // stride between particles //============================================================================== // PRN //============================================================================== -// 64 bit implementation of the PCG-RXS-M-XS 64-bit state / 64-bit output geneator -// Adapted from: https://github.com/imneme/pcg-c +// 64 bit implementation of the PCG-RXS-M-XS 64-bit state / 64-bit output +// geneator Adapted from: https://github.com/imneme/pcg-c // @techreport{oneill:pcg2014, -// title = "PCG: A Family of Simple Fast Space-Efficient Statistically Good Algorithms for Random Number Generation", -// author = "Melissa E. O'Neill", +// title = "PCG: A Family of Simple Fast Space-Efficient Statistically Good +// Algorithms for Random Number Generation", author = "Melissa E. O'Neill", // institution = "Harvey Mudd College", // address = "Claremont, CA", // number = "HMC-CS-2014-0905", @@ -35,7 +34,8 @@ double prn(uint64_t* seed) *seed = (prn_mult * (*seed) + prn_add); // Permute the output - uint64_t word = ((*seed >> ((*seed >> 59u) + 5u)) ^ *seed) * 12605985483714917081ull; + uint64_t word = + ((*seed >> ((*seed >> 59u) + 5u)) ^ *seed) * 12605985483714917081ull; uint64_t result = (word >> 43u) ^ word; // Convert output from unsigned integer to double @@ -58,7 +58,8 @@ double future_prn(int64_t n, uint64_t seed) uint64_t init_seed(int64_t id, int offset) { - return future_seed(static_cast(id) * prn_stride, master_seed + offset); + return future_seed( + static_cast(id) * prn_stride, master_seed + offset); } //============================================================================== @@ -68,7 +69,8 @@ uint64_t init_seed(int64_t id, int offset) void init_particle_seeds(int64_t id, uint64_t* seeds) { for (int i = 0; i < N_STREAMS; i++) { - seeds[i] = future_seed(static_cast(id) * prn_stride, master_seed + i); + seeds[i] = + future_seed(static_cast(id) * prn_stride, master_seed + i); } } @@ -94,8 +96,8 @@ uint64_t future_seed(uint64_t n, uint64_t seed) // and C which can then be used to find x_N = G*x_0 + C mod 2^M. // Initialize constants - uint64_t g {prn_mult}; - uint64_t c {prn_add}; + uint64_t g {prn_mult}; + uint64_t c {prn_add}; uint64_t g_new {1}; uint64_t c_new {0}; @@ -120,7 +122,10 @@ uint64_t future_seed(uint64_t n, uint64_t seed) // API FUNCTIONS //============================================================================== -extern "C" int64_t openmc_get_seed() {return master_seed;} +extern "C" int64_t openmc_get_seed() +{ + return master_seed; +} extern "C" void openmc_set_seed(int64_t new_seed) { diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp new file mode 100644 index 00000000000..5e1194aa92a --- /dev/null +++ b/src/random_ray/flat_source_domain.cpp @@ -0,0 +1,686 @@ +#include "openmc/random_ray/flat_source_domain.h" + +#include "openmc/cell.h" +#include "openmc/geometry.h" +#include "openmc/message_passing.h" +#include "openmc/mgxs_interface.h" +#include "openmc/output.h" +#include "openmc/plot.h" +#include "openmc/random_ray/random_ray.h" +#include "openmc/simulation.h" +#include "openmc/tallies/filter.h" +#include "openmc/tallies/tally.h" +#include "openmc/tallies/tally_scoring.h" +#include "openmc/timer.h" + +#include + +namespace openmc { + +//============================================================================== +// FlatSourceDomain implementation +//============================================================================== + +FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_) +{ + // Count the number of source regions, compute the cell offset + // indices, and store the material type The reason for the offsets is that + // some cell types may not have material fills, and therefore do not + // produce FSRs. Thus, we cannot index into the global arrays directly + for (const auto& c : model::cells) { + if (c->type_ != Fill::MATERIAL) { + source_region_offsets_.push_back(-1); + } else { + source_region_offsets_.push_back(n_source_regions_); + n_source_regions_ += c->n_instances_; + n_source_elements_ += c->n_instances_ * negroups_; + } + } + + // Initialize cell-wise arrays + lock_.resize(n_source_regions_); + material_.resize(n_source_regions_); + position_recorded_.assign(n_source_regions_, 0); + position_.resize(n_source_regions_); + volume_.assign(n_source_regions_, 0.0); + volume_t_.assign(n_source_regions_, 0.0); + was_hit_.assign(n_source_regions_, 0); + + // Initialize element-wise arrays + scalar_flux_new_.assign(n_source_elements_, 0.0); + scalar_flux_old_.assign(n_source_elements_, 1.0); + scalar_flux_final_.assign(n_source_elements_, 0.0); + source_.resize(n_source_elements_); + tally_task_.resize(n_source_elements_); + + // Initialize material array + int64_t source_region_id = 0; + for (int i = 0; i < model::cells.size(); i++) { + Cell& cell = *model::cells[i]; + if (cell.type_ == Fill::MATERIAL) { + for (int j = 0; j < cell.n_instances_; j++) { + material_[source_region_id++] = cell.material(j); + } + } + } + + // Sanity check + if (source_region_id != n_source_regions_) { + fatal_error("Unexpected number of source regions"); + } +} + +void FlatSourceDomain::batch_reset() +{ + // Reset scalar fluxes, iteration volume tallies, and region hit flags to + // zero + parallel_fill(scalar_flux_new_, 0.0f); + parallel_fill(volume_, 0.0); + parallel_fill(was_hit_, 0); +} + +void FlatSourceDomain::accumulate_iteration_flux() +{ +#pragma omp parallel for + for (int64_t se = 0; se < n_source_elements_; se++) { + scalar_flux_final_[se] += scalar_flux_new_[se]; + } +} + +// Compute new estimate of scattering + fission sources in each source region +// based on the flux estimate from the previous iteration. +void FlatSourceDomain::update_neutron_source(double k_eff) +{ + simulation::time_update_src.start(); + + double inverse_k_eff = 1.0 / k_eff; + + // Temperature and angle indices, if using multiple temperature + // data sets and/or anisotropic data sets. + // TODO: Currently assumes we are only using single temp/single + // angle data. + const int t = 0; + const int a = 0; + +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + int material = material_[sr]; + + for (int e_out = 0; e_out < negroups_; e_out++) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, e_out, nullptr, nullptr, nullptr, t, a); + float scatter_source = 0.0f; + float fission_source = 0.0f; + + for (int e_in = 0; e_in < negroups_; e_in++) { + float scalar_flux = scalar_flux_old_[sr * negroups_ + e_in]; + float sigma_s = data::mg.macro_xs_[material].get_xs( + MgxsType::NU_SCATTER, e_in, &e_out, nullptr, nullptr, t, a); + float nu_sigma_f = data::mg.macro_xs_[material].get_xs( + MgxsType::NU_FISSION, e_in, nullptr, nullptr, nullptr, t, a); + float chi = data::mg.macro_xs_[material].get_xs( + MgxsType::CHI_PROMPT, e_in, &e_out, nullptr, nullptr, t, a); + scatter_source += sigma_s * scalar_flux; + fission_source += nu_sigma_f * scalar_flux * chi; + } + + fission_source *= inverse_k_eff; + float new_isotropic_source = (scatter_source + fission_source) / sigma_t; + source_[sr * negroups_ + e_out] = new_isotropic_source; + } + } + + simulation::time_update_src.stop(); +} + +// Normalizes flux and updates simulation-averaged volume estimate +void FlatSourceDomain::normalize_scalar_flux_and_volumes( + double total_active_distance_per_iteration) +{ + float normalization_factor = 1.0 / total_active_distance_per_iteration; + double volume_normalization_factor = + 1.0 / (total_active_distance_per_iteration * simulation::current_batch); + +// Normalize scalar flux to total distance travelled by all rays this iteration +#pragma omp parallel for + for (int64_t e = 0; e < scalar_flux_new_.size(); e++) { + scalar_flux_new_[e] *= normalization_factor; + } + +// Accumulate cell-wise ray length tallies collected this iteration, then +// update the simulation-averaged cell-wise volume estimates +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions_; sr++) { + volume_t_[sr] += volume_[sr]; + volume_[sr] = volume_t_[sr] * volume_normalization_factor; + } +} + +// Combine transport flux contributions and flat source contributions from the +// previous iteration to generate this iteration's estimate of scalar flux. +int64_t FlatSourceDomain::add_source_to_scalar_flux() +{ + int64_t n_hits = 0; + + // Temperature and angle indices, if using multiple temperature + // data sets and/or anisotropic data sets. + // TODO: Currently assumes we are only using single temp/single + // angle data. + const int t = 0; + const int a = 0; + +#pragma omp parallel for reduction(+ : n_hits) + for (int sr = 0; sr < n_source_regions_; sr++) { + + // Check if this cell was hit this iteration + int was_cell_hit = was_hit_[sr]; + if (was_cell_hit) { + n_hits++; + } + + double volume = volume_[sr]; + int material = material_[sr]; + for (int g = 0; g < negroups_; g++) { + int64_t idx = (sr * negroups_) + g; + + // There are three scenarios we need to consider: + if (was_cell_hit) { + // 1. If the FSR was hit this iteration, then the new flux is equal to + // the flat source from the previous iteration plus the contributions + // from rays passing through the source region (computed during the + // transport sweep) + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, nullptr, nullptr, nullptr, t, a); + scalar_flux_new_[idx] /= (sigma_t * volume); + scalar_flux_new_[idx] += source_[idx]; + } else if (volume > 0.0) { + // 2. If the FSR was not hit this iteration, but has been hit some + // previous iteration, then we simply set the new scalar flux to be + // equal to the contribution from the flat source alone. + scalar_flux_new_[idx] = source_[idx]; + } else { + // If the FSR was not hit this iteration, and it has never been hit in + // any iteration (i.e., volume is zero), then we want to set this to 0 + // to avoid dividing anything by a zero volume. + scalar_flux_new_[idx] = 0.0f; + } + } + } + + // Return the number of source regions that were hit this iteration + return n_hits; +} + +// Generates new estimate of k_eff based on the differences between this +// iteration's estimate of the scalar flux and the last iteration's estimate. +double FlatSourceDomain::compute_k_eff(double k_eff_old) const +{ + double fission_rate_old = 0; + double fission_rate_new = 0; + + // Temperature and angle indices, if using multiple temperature + // data sets and/or anisotropic data sets. + // TODO: Currently assumes we are only using single temp/single + // angle data. + const int t = 0; + const int a = 0; + +#pragma omp parallel for reduction(+ : fission_rate_old, fission_rate_new) + for (int sr = 0; sr < n_source_regions_; sr++) { + + // If simulation averaged volume is zero, don't include this cell + double volume = volume_[sr]; + if (volume == 0.0) { + continue; + } + + int material = material_[sr]; + + double sr_fission_source_old = 0; + double sr_fission_source_new = 0; + + for (int g = 0; g < negroups_; g++) { + int64_t idx = (sr * negroups_) + g; + double nu_sigma_f = data::mg.macro_xs_[material].get_xs( + MgxsType::NU_FISSION, g, nullptr, nullptr, nullptr, t, a); + sr_fission_source_old += nu_sigma_f * scalar_flux_old_[idx]; + sr_fission_source_new += nu_sigma_f * scalar_flux_new_[idx]; + } + + fission_rate_old += sr_fission_source_old * volume; + fission_rate_new += sr_fission_source_new * volume; + } + + double k_eff_new = k_eff_old * (fission_rate_new / fission_rate_old); + + return k_eff_new; +} + +// This function is responsible for generating a mapping between random +// ray flat source regions (cell instances) and tally bins. The mapping +// takes the form of a "TallyTask" object, which accounts for one single +// score being applied to a single tally. Thus, a single source region +// may have anywhere from zero to many tally tasks associated with it --- +// meaning that the global "tally_task" data structure is in 2D. The outer +// dimension corresponds to the source element (i.e., each entry corresponds +// to a specific energy group within a specific source region), and the +// inner dimension corresponds to the tallying task itself. Mechanically, +// the mapping between FSRs and spatial filters is done by considering +// the location of a single known ray midpoint that passed through the +// FSR. I.e., during transport, the first ray to pass through a given FSR +// will write down its midpoint for use with this function. This is a cheap +// and easy way of mapping FSRs to spatial tally filters, but comes with +// the downside of adding the restriction that spatial tally filters must +// share boundaries with the physical geometry of the simulation (so as +// not to subdivide any FSR). It is acceptable for a spatial tally region +// to contain multiple FSRs, but not the other way around. + +// TODO: In future work, it would be preferable to offer a more general +// (but perhaps slightly more expensive) option for handling arbitrary +// spatial tallies that would be allowed to subdivide FSRs. + +// Besides generating the mapping structure, this function also keeps track +// of whether or not all flat source regions have been hit yet. This is +// required, as there is no guarantee that all flat source regions will +// be hit every iteration, such that in the first few iterations some FSRs +// may not have a known position within them yet to facilitate mapping to +// spatial tally filters. However, after several iterations, if all FSRs +// have been hit and have had a tally map generated, then this status will +// be passed back to the caller to alert them that this function doesn't +// need to be called for the remainder of the simulation. + +void FlatSourceDomain::convert_source_regions_to_tallies() +{ + openmc::simulation::time_tallies.start(); + + // Tracks if we've generated a mapping yet for all source regions. + bool all_source_regions_mapped = true; + +// Attempt to generate mapping for all source regions +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + + // If this source region has not been hit by a ray yet, then + // we aren't going to be able to map it, so skip it. + if (!position_recorded_[sr]) { + all_source_regions_mapped = false; + continue; + } + + // A particle located at the recorded midpoint of a ray + // crossing through this source region is used to estabilish + // the spatial location of the source region + Particle p; + p.r() = position_[sr]; + p.r_last() = position_[sr]; + bool found = exhaustive_find_cell(p); + + // Loop over energy groups (so as to support energy filters) + for (int g = 0; g < negroups_; g++) { + + // Set particle to the current energy + p.g() = g; + p.g_last() = g; + p.E() = data::mg.energy_bin_avg_[p.g()]; + p.E_last() = p.E(); + + int64_t source_element = sr * negroups_ + g; + + // If this task has already been populated, we don't need to do + // it again. + if (tally_task_[source_element].size() > 0) { + continue; + } + + // Loop over all active tallies. This logic is essentially identical + // to what happens when scanning for applicable tallies during + // MC transport. + for (auto i_tally : model::active_tallies) { + Tally& tally {*model::tallies[i_tally]}; + + // Initialize an iterator over valid filter bin combinations. + // If there are no valid combinations, use a continue statement + // to ensure we skip the assume_separate break below. + auto filter_iter = FilterBinIter(tally, p); + auto end = FilterBinIter(tally, true, &p.filter_matches()); + if (filter_iter == end) + continue; + + // Loop over filter bins. + for (; filter_iter != end; ++filter_iter) { + auto filter_index = filter_iter.index_; + auto filter_weight = filter_iter.weight_; + + // Loop over scores + for (auto score_index = 0; score_index < tally.scores_.size(); + score_index++) { + auto score_bin = tally.scores_[score_index]; + // If a valid tally, filter, and score cobination has been found, + // then add it to the list of tally tasks for this source element. + tally_task_[source_element].emplace_back( + i_tally, filter_index, score_index, score_bin); + } + } + } + // Reset all the filter matches for the next tally event. + for (auto& match : p.filter_matches()) + match.bins_present_ = false; + } + } + openmc::simulation::time_tallies.stop(); + + mapped_all_tallies_ = all_source_regions_mapped; +} + +// Tallying in random ray is not done directly during transport, rather, +// it is done only once after each power iteration. This is made possible +// by way of a mapping data structure that relates spatial source regions +// (FSRs) to tally/filter/score combinations. The mechanism by which the +// mapping is done (and the limitations incurred) is documented in the +// "convert_source_regions_to_tallies()" function comments above. The present +// tally function simply traverses the mapping data structure and executes +// the scoring operations to OpenMC's native tally result arrays. + +void FlatSourceDomain::random_ray_tally() const +{ + openmc::simulation::time_tallies.start(); + + // Temperature and angle indices, if using multiple temperature + // data sets and/or anisotropic data sets. + // TODO: Currently assumes we are only using single temp/single + // angle data. + const int t = 0; + const int a = 0; + +// We loop over all source regions and energy groups. For each +// element, we check if there are any scores needed and apply +// them. +#pragma omp parallel for + for (int sr = 0; sr < n_source_regions_; sr++) { + double volume = volume_[sr]; + double material = material_[sr]; + for (int g = 0; g < negroups_; g++) { + int idx = sr * negroups_ + g; + double flux = scalar_flux_new_[idx] * volume; + for (auto& task : tally_task_[idx]) { + double score; + switch (task.score_type) { + + case SCORE_FLUX: + score = flux; + break; + + case SCORE_TOTAL: + score = flux * data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); + break; + + case SCORE_FISSION: + score = flux * data::mg.macro_xs_[material].get_xs( + MgxsType::FISSION, g, NULL, NULL, NULL, t, a); + break; + + case SCORE_NU_FISSION: + score = flux * data::mg.macro_xs_[material].get_xs( + MgxsType::NU_FISSION, g, NULL, NULL, NULL, t, a); + break; + + case SCORE_EVENTS: + score = 1.0; + break; + + default: + fatal_error("Invalid score specified in tallies.xml. Only flux, " + "total, fission, nu-fission, and events are supported in " + "random ray mode."); + break; + } + Tally& tally {*model::tallies[task.tally_idx]}; +#pragma omp atomic + tally.results_(task.filter_idx, task.score_idx, TallyResult::VALUE) += + score; + } + } + } +} + +void FlatSourceDomain::all_reduce_replicated_source_regions() +{ +#ifdef OPENMC_MPI + + // If we only have 1 MPI rank, no need + // to reduce anything. + if (mpi::n_procs <= 1) + return; + + simulation::time_bank_sendrecv.start(); + + // The "position_recorded" variable needs to be allreduced (and maxed), + // as whether or not a cell was hit will affect some decisions in how the + // source is calculated in the next iteration so as to avoid dividing + // by zero. We take the max rather than the sum as the hit values are + // expected to be zero or 1. + MPI_Allreduce(MPI_IN_PLACE, position_recorded_.data(), n_source_regions_, + MPI_INT, MPI_MAX, mpi::intracomm); + + // The position variable is more complicated to reduce than the others, + // as we do not want the sum of all positions in each cell, rather, we + // want to just pick any single valid position. Thus, we perform a gather + // and then pick the first valid position we find for all source regions + // that have had a position recorded. This operation does not need to + // be broadcast back to other ranks, as this value is only used for the + // tally conversion operation, which is only performed on the master rank. + // While this is expensive, it only needs to be done for active batches, + // and only if we have not mapped all the tallies yet. Once tallies are + // fully mapped, then the position vector is fully populated, so this + // operation can be skipped. + + // First, we broadcast the fully mapped tally status variable so that + // all ranks are on the same page + int mapped_all_tallies_i = static_cast(mapped_all_tallies_); + MPI_Bcast(&mapped_all_tallies_i, 1, MPI_INT, 0, mpi::intracomm); + + // Then, we perform the gather of position data, if needed + if (simulation::current_batch > settings::n_inactive && + !mapped_all_tallies_i) { + + // Master rank will gather results and pick valid positions + if (mpi::master) { + // Initialize temporary vector for receiving positions + vector> all_position; + all_position.resize(mpi::n_procs); + for (int i = 0; i < mpi::n_procs; i++) { + all_position[i].resize(n_source_regions_); + } + + // Copy master rank data into gathered vector for convenience + all_position[0] = position_; + + // Receive all data into gather vector + for (int i = 1; i < mpi::n_procs; i++) { + MPI_Recv(all_position[i].data(), n_source_regions_ * 3, MPI_DOUBLE, i, + 0, mpi::intracomm, MPI_STATUS_IGNORE); + } + + // Scan through gathered data and pick first valid cell posiiton + for (int sr = 0; sr < n_source_regions_; sr++) { + if (position_recorded_[sr] == 1) { + for (int i = 0; i < mpi::n_procs; i++) { + if (all_position[i][sr].x != 0.0 || all_position[i][sr].y != 0.0 || + all_position[i][sr].z != 0.0) { + position_[sr] = all_position[i][sr]; + break; + } + } + } + } + } else { + // Other ranks just send in their data + MPI_Send(position_.data(), n_source_regions_ * 3, MPI_DOUBLE, 0, 0, + mpi::intracomm); + } + } + + // For the rest of the source region data, we simply perform an all reduce, + // as these values will be needed on all ranks for transport during the + // next iteration. + MPI_Allreduce(MPI_IN_PLACE, volume_.data(), n_source_regions_, MPI_DOUBLE, + MPI_SUM, mpi::intracomm); + + MPI_Allreduce(MPI_IN_PLACE, was_hit_.data(), n_source_regions_, MPI_INT, + MPI_SUM, mpi::intracomm); + + MPI_Allreduce(MPI_IN_PLACE, scalar_flux_new_.data(), n_source_elements_, + MPI_FLOAT, MPI_SUM, mpi::intracomm); + + simulation::time_bank_sendrecv.stop(); +#endif +} + +// Outputs all basic material, FSR ID, multigroup flux, and +// fission source data to .vtk file that can be directly +// loaded and displayed by Paraview. Note that .vtk binary +// files require big endian byte ordering, so endianness +// is checked and flipped if necessary. +void FlatSourceDomain::output_to_vtk() const +{ + // Rename .h5 plot filename(s) to .vtk filenames + for (int p = 0; p < model::plots.size(); p++) { + PlottableInterface* plot = model::plots[p].get(); + plot->path_plot() = + plot->path_plot().substr(0, plot->path_plot().find_last_of('.')) + ".vtk"; + } + + // Print header information + print_plot(); + + // Outer loop over plots + for (int p = 0; p < model::plots.size(); p++) { + + // Get handle to OpenMC plot object and extract params + Plot* openmc_plot = dynamic_cast(model::plots[p].get()); + + // Random ray plots only support voxel plots + if (!openmc_plot) { + warning(fmt::format("Plot {} is invalid plot type -- only voxel plotting " + "is allowed in random ray mode.", + p)); + continue; + } else if (openmc_plot->type_ != Plot::PlotType::voxel) { + warning(fmt::format("Plot {} is invalid plot type -- only voxel plotting " + "is allowed in random ray mode.", + p)); + continue; + } + + int Nx = openmc_plot->pixels_[0]; + int Ny = openmc_plot->pixels_[1]; + int Nz = openmc_plot->pixels_[2]; + Position origin = openmc_plot->origin_; + Position width = openmc_plot->width_; + Position ll = origin - width / 2.0; + double x_delta = width.x / Nx; + double y_delta = width.y / Ny; + double z_delta = width.z / Nz; + std::string filename = openmc_plot->path_plot(); + + // Perform sanity checks on file size + uint64_t bytes = Nx * Ny * Nz * (negroups_ + 1 + 1 + 1) * sizeof(float); + write_message(5, "Processing plot {}: {}... (Estimated size is {} MB)", + openmc_plot->id(), filename, bytes / 1.0e6); + if (bytes / 1.0e9 > 1.0) { + warning("Voxel plot specification is very large (>1 GB). Plotting may be " + "slow."); + } else if (bytes / 1.0e9 > 100.0) { + fatal_error("Voxel plot specification is too large (>100 GB). Exiting."); + } + + // Relate voxel spatial locations to random ray source regions + vector voxel_indices(Nx * Ny * Nz); + +#pragma omp parallel for collapse(3) + for (int z = 0; z < Nz; z++) { + for (int y = 0; y < Ny; y++) { + for (int x = 0; x < Nx; x++) { + Position sample; + sample.z = ll.z + z_delta / 2.0 + z * z_delta; + sample.y = ll.y + y_delta / 2.0 + y * y_delta; + sample.x = ll.x + x_delta / 2.0 + x * x_delta; + Particle p; + p.r() = sample; + bool found = exhaustive_find_cell(p); + int i_cell = p.lowest_coord().cell; + int64_t source_region_idx = + source_region_offsets_[i_cell] + p.cell_instance(); + voxel_indices[z * Ny * Nx + y * Nx + x] = source_region_idx; + } + } + } + + // Open file for writing + std::FILE* plot = std::fopen(filename.c_str(), "wb"); + + // Write vtk metadata + std::fprintf(plot, "# vtk DataFile Version 2.0\n"); + std::fprintf(plot, "Dataset File\n"); + std::fprintf(plot, "BINARY\n"); + std::fprintf(plot, "DATASET STRUCTURED_POINTS\n"); + std::fprintf(plot, "DIMENSIONS %d %d %d\n", Nx, Ny, Nz); + std::fprintf(plot, "ORIGIN 0 0 0\n"); + std::fprintf(plot, "SPACING %lf %lf %lf\n", x_delta, y_delta, z_delta); + std::fprintf(plot, "POINT_DATA %d\n", Nx * Ny * Nz); + + // Plot multigroup flux data + for (int g = 0; g < negroups_; g++) { + std::fprintf(plot, "SCALARS flux_group_%d float\n", g); + std::fprintf(plot, "LOOKUP_TABLE default\n"); + for (int fsr : voxel_indices) { + int64_t source_element = fsr * negroups_ + g; + float flux = scalar_flux_final_[source_element]; + flux /= (settings::n_batches - settings::n_inactive); + flux = convert_to_big_endian(flux); + std::fwrite(&flux, sizeof(float), 1, plot); + } + } + + // Plot FSRs + std::fprintf(plot, "SCALARS FSRs float\n"); + std::fprintf(plot, "LOOKUP_TABLE default\n"); + for (int fsr : voxel_indices) { + float value = future_prn(10, fsr); + value = convert_to_big_endian(value); + std::fwrite(&value, sizeof(float), 1, plot); + } + + // Plot Materials + std::fprintf(plot, "SCALARS Materials int\n"); + std::fprintf(plot, "LOOKUP_TABLE default\n"); + for (int fsr : voxel_indices) { + int mat = material_[fsr]; + mat = convert_to_big_endian(mat); + std::fwrite(&mat, sizeof(int), 1, plot); + } + + // Plot fission source + std::fprintf(plot, "SCALARS total_fission_source float\n"); + std::fprintf(plot, "LOOKUP_TABLE default\n"); + for (int fsr : voxel_indices) { + float total_fission = 0.0; + int mat = material_[fsr]; + for (int g = 0; g < negroups_; g++) { + int64_t source_element = fsr * negroups_ + g; + float flux = scalar_flux_final_[source_element]; + flux /= (settings::n_batches - settings::n_inactive); + float Sigma_f = data::mg.macro_xs_[mat].get_xs( + MgxsType::FISSION, g, nullptr, nullptr, nullptr, 0, 0); + total_fission += Sigma_f * flux; + } + total_fission = convert_to_big_endian(total_fission); + std::fwrite(&total_fission, sizeof(float), 1, plot); + } + + std::fclose(plot); + } +} + +} // namespace openmc diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp new file mode 100644 index 00000000000..63d728cce8b --- /dev/null +++ b/src/random_ray/random_ray.cpp @@ -0,0 +1,289 @@ +#include "openmc/random_ray/random_ray.h" + +#include "openmc/geometry.h" +#include "openmc/message_passing.h" +#include "openmc/mgxs_interface.h" +#include "openmc/random_ray/flat_source_domain.h" +#include "openmc/search.h" +#include "openmc/settings.h" +#include "openmc/simulation.h" +#include "openmc/source.h" + +namespace openmc { + +//============================================================================== +// Non-method functions +//============================================================================== + +// returns 1 - exp(-tau) +// Equivalent to -(_expm1f(-tau)), but faster +// Written by Colin Josey. +float cjosey_exponential(float tau) +{ + constexpr float c1n = -1.0000013559236386308f; + constexpr float c2n = 0.23151368626911062025f; + constexpr float c3n = -0.061481916409314966140f; + constexpr float c4n = 0.0098619906458127653020f; + constexpr float c5n = -0.0012629460503540849940f; + constexpr float c6n = 0.00010360973791574984608f; + constexpr float c7n = -0.000013276571933735820960f; + + constexpr float c0d = 1.0f; + constexpr float c1d = -0.73151337729389001396f; + constexpr float c2d = 0.26058381273536471371f; + constexpr float c3d = -0.059892419041316836940f; + constexpr float c4d = 0.0099070188241094279067f; + constexpr float c5d = -0.0012623388962473160860f; + constexpr float c6d = 0.00010361277635498731388f; + constexpr float c7d = -0.000013276569500666698498f; + + float x = -tau; + + float den = c7d; + den = den * x + c6d; + den = den * x + c5d; + den = den * x + c4d; + den = den * x + c3d; + den = den * x + c2d; + den = den * x + c1d; + den = den * x + c0d; + + float num = c7n; + num = num * x + c6n; + num = num * x + c5n; + num = num * x + c4n; + num = num * x + c3n; + num = num * x + c2n; + num = num * x + c1n; + num = num * x; + + return num / den; +} + +//============================================================================== +// RandomRay implementation +//============================================================================== + +// Static Variable Declarations +double RandomRay::distance_inactive_; +double RandomRay::distance_active_; +unique_ptr RandomRay::ray_source_; + +RandomRay::RandomRay() + : angular_flux_(data::mg.num_energy_groups_), + delta_psi_(data::mg.num_energy_groups_), + negroups_(data::mg.num_energy_groups_) +{} + +RandomRay::RandomRay(uint64_t ray_id, FlatSourceDomain* domain) : RandomRay() +{ + initialize_ray(ray_id, domain); +} + +// Transports ray until termination criteria are met +uint64_t RandomRay::transport_history_based_single_ray() +{ + using namespace openmc; + while (alive()) { + event_advance_ray(); + if (!alive()) + break; + event_cross_surface(); + } + + return n_event(); +} + +// Transports ray across a single source region +void RandomRay::event_advance_ray() +{ + // Find the distance to the nearest boundary + boundary() = distance_to_boundary(*this); + double distance = boundary().distance; + + if (distance <= 0.0) { + mark_as_lost("Negative transport distance detected for particle " + + std::to_string(id())); + return; + } + + if (is_active_) { + // If the ray is in the active length, need to check if it has + // reached its maximum termination distance. If so, reduce + // the ray traced length so that the ray does not overrun the + // maximum numerical length (so as to avoid numerical bias). + if (distance_travelled_ + distance >= distance_active_) { + distance = distance_active_ - distance_travelled_; + wgt() = 0.0; + } + + distance_travelled_ += distance; + attenuate_flux(distance, true); + } else { + // If the ray is still in the dead zone, need to check if it + // has entered the active phase. If so, split into two segments (one + // representing the final part of the dead zone, the other representing the + // first part of the active length) and attenuate each. Otherwise, if the + // full length of the segment is within the dead zone, attenuate as normal. + if (distance_travelled_ + distance >= distance_inactive_) { + is_active_ = true; + double distance_dead = distance_inactive_ - distance_travelled_; + attenuate_flux(distance_dead, false); + + double distance_alive = distance - distance_dead; + + // Ensure we haven't travelled past the active phase as well + if (distance_alive > distance_active_) { + distance_alive = distance_active_; + wgt() = 0.0; + } + + attenuate_flux(distance_alive, true); + distance_travelled_ = distance_alive; + } else { + distance_travelled_ += distance; + attenuate_flux(distance, false); + } + } + + // Advance particle + for (int j = 0; j < n_coord(); ++j) { + coord(j).r += distance * coord(j).u; + } +} + +// This function forms the inner loop of the random ray transport process. +// It is responsible for several tasks. Based on the incoming angular flux +// of the ray and the source term in the region, the outgoing angular flux +// is computed. The delta psi between the incoming and outgoing fluxes is +// contributed to the estimate of the total scalar flux in the source region. +// Additionally, the contribution of the ray path to the stochastically +// estimated volume is also kept track of. All tasks involving writing +// to the data for the source region are done with a lock over the entire +// source region. Locks are used instead of atomics as all energy groups +// must be written, such that locking once is typically much more efficient +// than use of many atomic operations corresponding to each energy group +// individually (at least on CPU). Several other bookkeeping tasks are also +// performed when inside the lock. +void RandomRay::attenuate_flux(double distance, bool is_active) +{ + // The number of geometric intersections is counted for reporting purposes + n_event()++; + + // Determine source region index etc. + int i_cell = lowest_coord().cell; + + // The source region is the spatial region index + int64_t source_region = + domain_->source_region_offsets_[i_cell] + cell_instance(); + + // The source element is the energy-specific region index + int64_t source_element = source_region * negroups_; + int material = this->material(); + + // Temperature and angle indices, if using multiple temperature + // data sets and/or anisotropic data sets. + // TODO: Currently assumes we are only using single temp/single + // angle data. + const int t = 0; + const int a = 0; + + // MOC incoming flux attenuation + source contribution/attenuation equation + for (int g = 0; g < negroups_; g++) { + float sigma_t = data::mg.macro_xs_[material].get_xs( + MgxsType::TOTAL, g, NULL, NULL, NULL, t, a); + float tau = sigma_t * distance; + float exponential = cjosey_exponential(tau); // exponential = 1 - exp(-tau) + float new_delta_psi = + (angular_flux_[g] - domain_->source_[source_element + g]) * exponential; + delta_psi_[g] = new_delta_psi; + angular_flux_[g] -= new_delta_psi; + } + + // If ray is in the active phase (not in dead zone), make contributions to + // source region bookkeeping + if (is_active) { + + // Aquire lock for source region + domain_->lock_[source_region].lock(); + + // Accumulate delta psi into new estimate of source region flux for + // this iteration + for (int g = 0; g < negroups_; g++) { + domain_->scalar_flux_new_[source_element + g] += delta_psi_[g]; + } + + // If the source region hasn't been hit yet this iteration, + // indicate that it now has + if (domain_->was_hit_[source_region] == 0) { + domain_->was_hit_[source_region] = 1; + } + + // Accomulate volume (ray distance) into this iteration's estimate + // of the source region's volume + domain_->volume_[source_region] += distance; + + // Tally valid position inside the source region (e.g., midpoint of + // the ray) if not done already + if (!domain_->position_recorded_[source_region]) { + Position midpoint = r() + u() * (distance / 2.0); + domain_->position_[source_region] = midpoint; + domain_->position_recorded_[source_region] = 1; + } + + // Release lock + domain_->lock_[source_region].unlock(); + } +} + +void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) +{ + domain_ = domain; + + // Reset particle event counter + n_event() = 0; + + is_active_ = (distance_inactive_ <= 0.0); + + wgt() = 1.0; + + // set identifier for particle + id() = simulation::work_index[mpi::rank] + ray_id; + + // set random number seed + int64_t particle_seed = + (simulation::current_batch - 1) * settings::n_particles + id(); + init_particle_seeds(particle_seed, seeds()); + stream() = STREAM_TRACKING; + + // Sample from ray source distribution + SourceSite site {ray_source_->sample(current_seed())}; + site.E = lower_bound_index( + data::mg.rev_energy_bins_.begin(), data::mg.rev_energy_bins_.end(), site.E); + site.E = negroups_ - site.E - 1.; + this->from_source(&site); + + // Locate ray + if (lowest_coord().cell == C_NONE) { + if (!exhaustive_find_cell(*this)) { + this->mark_as_lost( + "Could not find the cell containing particle " + std::to_string(id())); + } + + // Set birth cell attribute + if (cell_born() == C_NONE) + cell_born() = lowest_coord().cell; + } + + // Initialize ray's starting angular flux to starting location's isotropic + // source + int i_cell = lowest_coord().cell; + int64_t source_region_idx = + domain_->source_region_offsets_[i_cell] + cell_instance(); + + for (int g = 0; g < negroups_; g++) { + angular_flux_[g] = domain_->source_[source_region_idx * negroups_ + g]; + } +} + +} // namespace openmc diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp new file mode 100644 index 00000000000..b9fd93a48f6 --- /dev/null +++ b/src/random_ray/random_ray_simulation.cpp @@ -0,0 +1,397 @@ +#include "openmc/random_ray/random_ray_simulation.h" + +#include "openmc/eigenvalue.h" +#include "openmc/geometry.h" +#include "openmc/message_passing.h" +#include "openmc/mgxs_interface.h" +#include "openmc/output.h" +#include "openmc/plot.h" +#include "openmc/random_ray/random_ray.h" +#include "openmc/simulation.h" +#include "openmc/source.h" +#include "openmc/tallies/filter.h" +#include "openmc/tallies/tally.h" +#include "openmc/tallies/tally_scoring.h" +#include "openmc/timer.h" + +namespace openmc { + +//============================================================================== +// Non-member functions +//============================================================================== + +void openmc_run_random_ray() +{ + // Initialize OpenMC general data structures + openmc_simulation_init(); + + // Validate that inputs meet requirements for random ray mode + if (mpi::master) + validate_random_ray_inputs(); + + // Initialize Random Ray Simulation Object + RandomRaySimulation sim; + + // Begin main simulation timer + simulation::time_total.start(); + + // Execute random ray simulation + sim.simulate(); + + // End main simulation timer + openmc::simulation::time_total.stop(); + + // Finalize OpenMC + openmc_simulation_finalize(); + + // Reduce variables across MPI ranks + sim.reduce_simulation_statistics(); + + // Output all simulation results + sim.output_simulation_results(); +} + +// Enforces restrictions on inputs in random ray mode. While there are +// many features that don't make sense in random ray mode, and are therefore +// unsupported, we limit our testing/enforcement operations only to inputs +// that may cause erroneous/misleading output or crashes from the solver. +void validate_random_ray_inputs() +{ + // Validate tallies + /////////////////////////////////////////////////////////////////// + for (auto& tally : model::tallies) { + + // Validate score types + for (auto score_bin : tally->scores_) { + switch (score_bin) { + case SCORE_FLUX: + case SCORE_TOTAL: + case SCORE_FISSION: + case SCORE_NU_FISSION: + case SCORE_EVENTS: + break; + default: + fatal_error( + "Invalid score specified. Only flux, total, fission, nu-fission, and " + "event scores are supported in random ray mode."); + } + } + + // Validate filter types + for (auto f : tally->filters()) { + auto& filter = *model::tally_filters[f]; + + switch (filter.type()) { + case FilterType::CELL: + case FilterType::CELL_INSTANCE: + case FilterType::DISTRIBCELL: + case FilterType::ENERGY: + case FilterType::MATERIAL: + case FilterType::MESH: + case FilterType::UNIVERSE: + break; + default: + fatal_error("Invalid filter specified. Only cell, cell_instance, " + "distribcell, energy, material, mesh, and universe filters " + "are supported in random ray mode."); + } + } + } + + // Validate MGXS data + /////////////////////////////////////////////////////////////////// + for (auto& material : data::mg.macro_xs_) { + if (!material.is_isotropic) { + fatal_error("Anisotropic MGXS detected. Only isotropic XS data sets " + "supported in random ray mode."); + } + if (material.get_xsdata().size() > 1) { + fatal_error("Non-isothermal MGXS detected. Only isothermal XS data sets " + "supported in random ray mode."); + } + } + + // Validate solver mode + /////////////////////////////////////////////////////////////////// + if (settings::run_mode == RunMode::FIXED_SOURCE) { + fatal_error( + "Invalid run mode. Fixed source not yet supported in random ray mode."); + } + + // Validate ray source + /////////////////////////////////////////////////////////////////// + + // Check for independent source + IndependentSource* is = + dynamic_cast(RandomRay::ray_source_.get()); + if (!is) { + fatal_error( + "Invalid ray source definition. Ray source must be IndependentSource."); + } + + // Check for box source + SpatialDistribution* space_dist = is->space(); + SpatialBox* sb = dynamic_cast(space_dist); + if (!sb) { + fatal_error( + "Invalid source definition -- only box sources are allowed in random " + "ray " + "mode. If no source is specified, OpenMC default is an isotropic point " + "source at the origin, which is invalid in random ray mode."); + } + + // Check that box source is not restricted to fissionable areas + if (sb->only_fissionable()) { + fatal_error("Invalid source definition -- fissionable spatial distribution " + "not allowed for random ray source."); + } + + // Check for isotropic source + UnitSphereDistribution* angle_dist = is->angle(); + Isotropic* id = dynamic_cast(angle_dist); + if (!id) { + fatal_error("Invalid source definition -- only isotropic sources are " + "allowed for random ray source."); + } + + // Validate plotting files + /////////////////////////////////////////////////////////////////// + for (int p = 0; p < model::plots.size(); p++) { + + // Get handle to OpenMC plot object + Plot* openmc_plot = dynamic_cast(model::plots[p].get()); + + // Random ray plots only support voxel plots + if (!openmc_plot) { + warning(fmt::format( + "Plot {} will not be used for end of simulation data plotting -- only " + "voxel plotting is allowed in random ray mode.", + p)); + continue; + } else if (openmc_plot->type_ != Plot::PlotType::voxel) { + warning(fmt::format( + "Plot {} will not be used for end of simulation data plotting -- only " + "voxel plotting is allowed in random ray mode.", + p)); + continue; + } + } + + // Warn about slow MPI domain replication, if detected + /////////////////////////////////////////////////////////////////// +#ifdef OPENMC_MPI + if (mpi::n_procs > 1) { + warning( + "Domain replication in random ray is supported, but suffers from poor " + "scaling of source all-reduce operations. Performance may severely " + "degrade beyond just a few MPI ranks. Domain decomposition may be " + "implemented in the future to provide efficient scaling."); + } +#endif +} + +//============================================================================== +// RandomRaySimulation implementation +//============================================================================== + +RandomRaySimulation::RandomRaySimulation() + : negroups_(data::mg.num_energy_groups_) +{ + // There are no source sites in random ray mode, so be sure to disable to + // ensure we don't attempt to write source sites to statepoint + settings::source_write = false; + + // Random ray mode does not have an inner loop over generations within a + // batch, so set the current gen to 1 + simulation::current_gen = 1; +} + +void RandomRaySimulation::simulate() +{ + // Random ray power iteration loop + while (simulation::current_batch < settings::n_batches) { + + // Initialize the current batch + initialize_batch(); + initialize_generation(); + + // Reset total starting particle weight used for normalizing tallies + simulation::total_weight = 1.0; + + // Update source term (scattering + fission) + domain_.update_neutron_source(k_eff_); + + // Reset scalar fluxes, iteration volume tallies, and region hit flags to + // zero + domain_.batch_reset(); + + // Start timer for transport + simulation::time_transport.start(); + +// Transport sweep over all random rays for the iteration +#pragma omp parallel for schedule(dynamic) \ + reduction(+ : total_geometric_intersections_) + for (int i = 0; i < simulation::work_per_rank; i++) { + RandomRay ray(i, &domain_); + total_geometric_intersections_ += + ray.transport_history_based_single_ray(); + } + + simulation::time_transport.stop(); + + // If using multiple MPI ranks, perform all reduce on all transport results + domain_.all_reduce_replicated_source_regions(); + + // Normalize scalar flux and update volumes + domain_.normalize_scalar_flux_and_volumes( + settings::n_particles * RandomRay::distance_active_); + + // Add source to scalar flux, compute number of FSR hits + int64_t n_hits = domain_.add_source_to_scalar_flux(); + + // Compute random ray k-eff + k_eff_ = domain_.compute_k_eff(k_eff_); + + // Store random ray k-eff into OpenMC's native k-eff variable + global_tally_tracklength = k_eff_; + + // Execute all tallying tasks, if this is an active batch + if (simulation::current_batch > settings::n_inactive && mpi::master) { + + // Generate mapping between source regions and tallies + if (!domain_.mapped_all_tallies_) { + domain_.convert_source_regions_to_tallies(); + } + + // Use above mapping to contribute FSR flux data to appropriate tallies + domain_.random_ray_tally(); + + // Add this iteration's scalar flux estimate to final accumulated estimate + domain_.accumulate_iteration_flux(); + } + + // Set phi_old = phi_new + domain_.scalar_flux_old_.swap(domain_.scalar_flux_new_); + + // Check for any obvious insabilities/nans/infs + instability_check(n_hits, k_eff_, avg_miss_rate_); + + // Finalize the current batch + finalize_generation(); + finalize_batch(); + } // End random ray power iteration loop +} + +void RandomRaySimulation::reduce_simulation_statistics() +{ + // Reduce number of intersections +#ifdef OPENMC_MPI + if (mpi::n_procs > 1) { + uint64_t total_geometric_intersections_reduced = 0; + MPI_Reduce(&total_geometric_intersections_, + &total_geometric_intersections_reduced, 1, MPI_UNSIGNED_LONG, MPI_SUM, 0, + mpi::intracomm); + total_geometric_intersections_ = total_geometric_intersections_reduced; + } +#endif +} + +void RandomRaySimulation::output_simulation_results() const +{ + // Print random ray results + if (mpi::master) { + print_results_random_ray(total_geometric_intersections_, + avg_miss_rate_ / settings::n_batches, negroups_, + domain_.n_source_regions_); + if (model::plots.size() > 0) { + domain_.output_to_vtk(); + } + } +} + +// Apply a few sanity checks to catch obvious cases of numerical instability. +// Instability typically only occurs if ray density is extremely low. +void RandomRaySimulation::instability_check( + int64_t n_hits, double k_eff, double& avg_miss_rate) const +{ + double percent_missed = ((domain_.n_source_regions_ - n_hits) / + static_cast(domain_.n_source_regions_)) * + 100.0; + avg_miss_rate += percent_missed; + + if (percent_missed > 10.0) { + warning(fmt::format( + "Very high FSR miss rate detected ({:.3f}%). Instability may occur. " + "Increase ray density by adding more rays and/or active distance.", + percent_missed)); + } else if (percent_missed > 0.01) { + warning(fmt::format("Elevated FSR miss rate detected ({:.3f}%). Increasing " + "ray density by adding more rays and/or active " + "distance may improve simulation efficiency.", + percent_missed)); + } + + if (k_eff > 10.0 || k_eff < 0.01 || !(std::isfinite(k_eff))) { + fatal_error("Instability detected"); + } +} + +// Print random ray simulation results +void RandomRaySimulation::print_results_random_ray( + uint64_t total_geometric_intersections, double avg_miss_rate, int negroups, + int64_t n_source_regions) const +{ + using namespace simulation; + + if (settings::verbosity >= 6) { + double total_integrations = total_geometric_intersections * negroups; + double time_per_integration = + simulation::time_transport.elapsed() / total_integrations; + double misc_time = time_total.elapsed() - time_update_src.elapsed() - + time_transport.elapsed() - time_tallies.elapsed() - + time_bank_sendrecv.elapsed(); + + header("Simulation Statistics", 4); + fmt::print( + " Total Iterations = {}\n", settings::n_batches); + fmt::print(" Flat Source Regions (FSRs) = {}\n", n_source_regions); + fmt::print(" Total Geometric Intersections = {:.4e}\n", + static_cast(total_geometric_intersections)); + fmt::print(" Avg per Iteration = {:.4e}\n", + static_cast(total_geometric_intersections) / settings::n_batches); + fmt::print(" Avg per Iteration per FSR = {:.2f}\n", + static_cast(total_geometric_intersections) / + static_cast(settings::n_batches) / n_source_regions); + fmt::print(" Avg FSR Miss Rate per Iteration = {:.4f}%\n", avg_miss_rate); + fmt::print(" Energy Groups = {}\n", negroups); + fmt::print( + " Total Integrations = {:.4e}\n", total_integrations); + fmt::print(" Avg per Iteration = {:.4e}\n", + total_integrations / settings::n_batches); + + header("Timing Statistics", 4); + show_time("Total time for initialization", time_initialize.elapsed()); + show_time("Reading cross sections", time_read_xs.elapsed(), 1); + show_time("Total simulation time", time_total.elapsed()); + show_time("Transport sweep only", time_transport.elapsed(), 1); + show_time("Source update only", time_update_src.elapsed(), 1); + show_time("Tally conversion only", time_tallies.elapsed(), 1); + show_time("MPI source reductions only", time_bank_sendrecv.elapsed(), 1); + show_time("Other iteration routines", misc_time, 1); + if (settings::run_mode == RunMode::EIGENVALUE) { + show_time("Time in inactive batches", time_inactive.elapsed()); + } + show_time("Time in active batches", time_active.elapsed()); + show_time("Time writing statepoints", time_statepoint.elapsed()); + show_time("Total time for finalization", time_finalize.elapsed()); + show_time("Time per integration", time_per_integration); + } + + if (settings::verbosity >= 4) { + header("Results", 4); + fmt::print(" k-effective = {:.5f} +/- {:.5f}\n", + simulation::keff, simulation::keff_std); + } +} + +} // namespace openmc diff --git a/src/reaction.cpp b/src/reaction.cpp index ddb82a22493..0643cb08bdd 100644 --- a/src/reaction.cpp +++ b/src/reaction.cpp @@ -7,8 +7,8 @@ #include #include "openmc/constants.h" -#include "openmc/hdf5_interface.h" #include "openmc/endf.h" +#include "openmc/hdf5_interface.h" #include "openmc/random_lcg.h" #include "openmc/search.h" #include "openmc/secondary_uncorrelated.h" @@ -65,6 +65,23 @@ Reaction::Reaction(hid_t group, const vector& temperatures) } } +double Reaction::xs( + gsl::index i_temp, gsl::index i_grid, double interp_factor) const +{ + // If energy is below threshold, return 0. Otherwise interpolate between + // nearest grid points + const auto& x = xs_[i_temp]; + return (i_grid < x.threshold) + ? 0.0 + : (1.0 - interp_factor) * x.value[i_grid - x.threshold] + + interp_factor * x.value[i_grid - x.threshold + 1]; +} + +double Reaction::xs(const NuclideMicroXS& micro) const +{ + return this->xs(micro.index_temp, micro.index_grid, micro.interp_factor); +} + double Reaction::collapse_rate(gsl::index i_temp, gsl::span energy, gsl::span flux, const vector& grid) const @@ -80,7 +97,8 @@ double Reaction::collapse_rate(gsl::index i_temp, i_low = i_threshold; while (energy[j_start + 1] < grid[i_low]) { ++j_start; - if (j_start + 1 == energy.size()) return 0.0; + if (j_start + 1 == energy.size()) + return 0.0; } } @@ -93,14 +111,16 @@ double Reaction::collapse_rate(gsl::index i_temp, // Determine energy grid index corresponding to group high int i_high = i_low; - while (grid[i_high + 1] < E_group_high && i_high + 1 < grid.size() - 1) ++i_high; + while (grid[i_high + 1] < E_group_high && i_high + 1 < grid.size() - 1) + ++i_high; // Loop over energy grid points within [E_group_low, E_group_high] for (; i_low <= i_high; ++i_low) { // Determine bounding grid energies and cross sections double E_l = grid[i_low]; double E_r = grid[i_low + 1]; - if (E_l == E_r) continue; + if (E_l == E_r) + continue; double xs_l = xs[i_low - i_threshold]; double xs_r = xs[i_low + 1 - i_threshold]; @@ -111,9 +131,9 @@ double Reaction::collapse_rate(gsl::index i_temp, // Determine average cross section across segment double m = (xs_r - xs_l) / (E_r - E_l); - double xs_low = xs_l + m*(E_low - E_l); - double xs_high = xs_l + m*(E_high - E_l); - double xs_avg = 0.5*(xs_low + xs_high); + double xs_low = xs_l + m * (E_low - E_l); + double xs_high = xs_l + m * (E_high - E_l); + double xs_avg = 0.5 * (xs_low + xs_high); // Add contribution from segment double dE = (E_high - E_low); @@ -123,7 +143,8 @@ double Reaction::collapse_rate(gsl::index i_temp, i_low = i_high; // Check for end of energy grid - if (i_low + 1 == grid.size()) break; + if (i_low + 1 == grid.size()) + break; } return xs_flux_sum; @@ -150,6 +171,7 @@ std::unordered_map REACTION_NAME_MAP { {SCORE_INVERSE_VELOCITY, "inverse-velocity"}, {SCORE_FISS_Q_PROMPT, "fission-q-prompt"}, {SCORE_FISS_Q_RECOV, "fission-q-recoverable"}, + {SCORE_PULSE_HEIGHT, "pulse-height"}, // Normal ENDF-based reactions {TOTAL_XS, "(n,total)"}, {ELASTIC, "(n,elastic)"}, @@ -290,8 +312,8 @@ void initialize_maps() // Create photoelectric subshells for (int mt = 534; mt <= 572; ++mt) { - REACTION_NAME_MAP[mt] = fmt::format("photoelectric, {} subshell", - SUBSHELLS[mt - 534]); + REACTION_NAME_MAP[mt] = + fmt::format("photoelectric, {} subshell", SUBSHELLS[mt - 534]); } // Invert name map to create type map @@ -303,7 +325,8 @@ void initialize_maps() std::string reaction_name(int mt) { // Initialize remainder of name map and all of type map - if (REACTION_TYPE_MAP.empty()) initialize_maps(); + if (REACTION_TYPE_MAP.empty()) + initialize_maps(); // Get reaction name from map auto it = REACTION_NAME_MAP.find(mt); @@ -317,11 +340,13 @@ std::string reaction_name(int mt) int reaction_type(std::string name) { // Initialize remainder of name map and all of type map - if (REACTION_TYPE_MAP.empty()) initialize_maps(); + if (REACTION_TYPE_MAP.empty()) + initialize_maps(); // (n,total) exists in REACTION_TYPE_MAP for MT=1, but we need this to return // the special SCORE_TOTAL score - if (name == "(n,total)") return SCORE_TOTAL; + if (name == "(n,total)") + return SCORE_TOTAL; // Check if type map has an entry for this reaction name auto it = REACTION_TYPE_MAP.find(name); @@ -356,12 +381,18 @@ int reaction_type(std::string name) try { MT = std::stoi(name); } catch (const std::invalid_argument& ex) { - throw std::invalid_argument("Invalid tally score \"" + name + "\". See the docs " - "for details: https://docs.openmc.org/en/stable/usersguide/tallies.html#scores"); + throw std::invalid_argument( + "Invalid tally score \"" + name + + "\". See the docs " + "for details: " + "https://docs.openmc.org/en/stable/usersguide/tallies.html#scores"); } if (MT < 1) - throw std::invalid_argument("Invalid tally score \"" + name + "\". See the docs " - "for details: https://docs.openmc.org/en/stable/usersguide/tallies.html#scores"); + throw std::invalid_argument( + "Invalid tally score \"" + name + + "\". See the docs " + "for details: " + "https://docs.openmc.org/en/stable/usersguide/tallies.html#scores"); return MT; } diff --git a/src/reaction_product.cpp b/src/reaction_product.cpp index f73f63335b3..4cef8d3a958 100644 --- a/src/reaction_product.cpp +++ b/src/reaction_product.cpp @@ -44,7 +44,8 @@ ReactionProduct::ReactionProduct(hid_t group) read_attribute(group, "decay_rate", decay_rate_); } else if (particle_ == ParticleType::neutron) { warning(fmt::format("Decay rate doesn't exist for delayed neutron " - "emission ({}).", object_name(group))); + "emission ({}).", + object_name(group))); } } @@ -82,8 +83,8 @@ ReactionProduct::ReactionProduct(hid_t group) } } -void ReactionProduct::sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const +void ReactionProduct::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { auto n = applicability_.size(); if (n > 1) { @@ -105,4 +106,4 @@ void ReactionProduct::sample(double E_in, double& E_out, double& mu, } } -} +} // namespace openmc diff --git a/src/relaxng/cross_sections.rnc b/src/relaxng/cross_sections.rnc deleted file mode 100644 index 7fbc610a280..00000000000 --- a/src/relaxng/cross_sections.rnc +++ /dev/null @@ -1,12 +0,0 @@ -element cross_sections { - element library { - (element materials { xsd:string } | - attribute materials { xsd:string }) & - (element type { xsd:string } | - attribute type { xsd:string }) & - (element path { xsd:string } | - attribute path { xsd:string }) - }* & - - element directory { xsd:string { maxLength = "255" } }? -} \ No newline at end of file diff --git a/src/relaxng/cross_sections.rng b/src/relaxng/cross_sections.rng deleted file mode 100644 index 435f7fa8439..00000000000 --- a/src/relaxng/cross_sections.rng +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 255 - - - - - diff --git a/src/relaxng/geometry.rnc b/src/relaxng/geometry.rnc deleted file mode 100644 index e3c88c445c5..00000000000 --- a/src/relaxng/geometry.rnc +++ /dev/null @@ -1,55 +0,0 @@ -element geometry { - element cell { - (element id { xsd:int } | attribute id { xsd:int }) & - (element name { xsd:string { maxLength="52" } } | - attribute name { xsd:string { maxLength="52" } })? & - (element universe { xsd:int } | attribute universe { xsd:int })? & - ( - (element fill { xsd:int } | attribute fill { xsd:int }) | - (element material { list { ( xsd:int | "void" )+ } } | - attribute material { list { ( xsd:int | "void" )+ } }) - ) & - (element temperature { list { xsd:double+ } } | - attribute temperature { list { xsd:double+ } } )? & - (element region { xsd:string } | attribute region { xsd:string })? & - (element rotation { list { xsd:double+ } } | attribute rotation { list { xsd:double+ } })? & - (element translation { list { xsd:double+ } } | attribute translation { list { xsd:double+ } })? - }* - - & element surface { - (element id { xsd:int } | attribute id { xsd:int }) & - (element name { xsd:string { maxLength="52" } } | - attribute name { xsd:string { maxLength="52" } })? & - (element type { xsd:string { maxLength = "15" } } | - attribute type { xsd:string { maxLength = "15" } }) & - (element coeffs { list { xsd:double+ } } | attribute coeffs { list { xsd:double+ } }) & - (element boundary { ( "transmit" | "reflective" | "vacuum" | "periodic" ) } | - attribute boundary { ( "transmit" | "reflective" | "vacuum" | "periodic" ) })? & - (element periodic_surface_id { xsd:int } | attribute periodic_surface_id { xsd:int })? - }* - - & element lattice { - (element id { xsd:int } | attribute id { xsd:int }) & - (element name { xsd:string { maxLength="52" } } | - attribute name { xsd:string { maxLength="52" } })? & - (element dimension { list { xsd:positiveInteger+ } } | - attribute dimension { list { xsd:positiveInteger+ } }) & - (element lower_left { list { xsd:double+ } } | attribute lower_left { list { xsd:double+ } }) & - (element pitch { list { xsd:double+ } } | attribute pitch { list { xsd:double+ } }) & - (element universes { list { xsd:int+ } } | attribute universes { list { xsd:int+ } }) & - (element outer { xsd:int } | attribute outer { xsd:int })? - }* - - & element hex_lattice { - (element id { xsd:int } | attribute id { xsd:int }) & - (element name { xsd:string { maxLength="52" } } | - attribute name { xsd:string { maxLength="52" } })? & - (element n_rings { xsd:int } | attribute n_rings { xsd:int }) & - (element n_axial { xsd:int } | attribute n_axial { xsd:int })? & - (element center { list { xsd:double+ } } | attribute center { list { xsd:double+ } }) & - (element pitch { list { xsd:double+ } } | attribute pitch { list { xsd:double+ } }) & - (element orientation { ( "x" | "y" ) } | attribute orientation { ( "x" | "y" ) })? & - (element universes { list { xsd:int+ } } | attribute universes { list { xsd:int+ } }) & - (element outer { xsd:int } | attribute outer { xsd:int })? - }* -} diff --git a/src/relaxng/geometry.rng b/src/relaxng/geometry.rng deleted file mode 100644 index 56bf3858077..00000000000 --- a/src/relaxng/geometry.rng +++ /dev/null @@ -1,447 +0,0 @@ - - - - - - - - - - - - - - - - - - - 52 - - - - - 52 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void - - - - - - - - - - void - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 52 - - - - - 52 - - - - - - - - 15 - - - - - 15 - - - - - - - - - - - - - - - - - - - - - - - - transmit - reflective - vacuum - periodic - - - - - transmit - reflective - vacuum - periodic - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 52 - - - - - 52 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 52 - - - - - 52 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - x - y - - - - - x - y - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/relaxng/materials.rnc b/src/relaxng/materials.rnc deleted file mode 100644 index c82ecfeaac5..00000000000 --- a/src/relaxng/materials.rnc +++ /dev/null @@ -1,41 +0,0 @@ -element materials { - element material { - (element id { xsd:int } | attribute id { xsd:int }) & - - (element name { xsd:string } | attribute name { xsd:string })? & - - (element depletable { xsd:boolean } | attribute depletable { xsd:boolean })? & - - (element volume { xsd:double } | attribute volume { xsd:double })? & - - (element temperature { xsd:double } | attribute temperature { xsd:double })? & - - element density { - (element value { xsd:double } | attribute value { xsd:double })? & - (element units { xsd:string { maxLength = "10" } } | - attribute units { xsd:string { maxLength = "10" } }) - } & - - element nuclide { - (element name { xsd:string } | attribute name { xsd:string }) & - ( - (element ao { xsd:double } | attribute ao { xsd:double }) | - (element wo { xsd:double } | attribute wo { xsd:double }) - ) - }* & - - element isotropic { xsd:string }? & - - element macroscopic { - (element name { xsd:string } | - attribute name { xsd:string }) - }* & - - element sab { - (element name { xsd:string } | attribute name { xsd:string }) & - (element fraction { xsd:double } | attribute fraction { xsd:double })? - }* - }+ & - - element cross_sections { xsd:string { maxLength = "255" } }? -} diff --git a/src/relaxng/materials.rng b/src/relaxng/materials.rng deleted file mode 100644 index e99fb7adfea..00000000000 --- a/src/relaxng/materials.rng +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10 - - - - - 10 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 255 - - - - - diff --git a/src/relaxng/mg_cross_sections.rnc b/src/relaxng/mg_cross_sections.rnc deleted file mode 100644 index b2aaec4d407..00000000000 --- a/src/relaxng/mg_cross_sections.rnc +++ /dev/null @@ -1,61 +0,0 @@ -element cross_sections { - - element groups { xsd:int } & - - element group_structure { list { xsd:double+ } } & - - element inverse_velocities { list { xsd:double+ } }? & - - element xsdata { - (element name { xsd:string { maxLength = "15" } } | - attribute name { xsd:string { maxLength = "15" } }) & - (element alias { xsd:string { maxLength = "15" } } | - attribute alias { xsd:string { maxLength = "15" } })? & - (element kT { xsd:double } | attribute kT { xsd:double })? & - (element fissionable { ( "true" | "false" ) } | - attribute fissionable { ( "true" | "false" ) }) & - (element representation { ( "isotropic" | "angle" ) } | - attribute representation { ( "isotropic" | "angle" ) })? & - (element num_azimuthal { xsd:positiveInteger } | - attribute num_azimuthal { xsd:positiveInteger })? & - (element num_polar { xsd:positiveInteger } | - attribute num_polar { xsd:positiveInteger })? & - (element scatt_type { ( "legendre" | "histogram" | "tabular" ) } | - attribute scatt_type { ( "legendre" | "histogram" | "tabular" ) })? & - (element order { xsd:positiveInteger } | - attribute order { xsd:positiveInteger }) & - element tabular_legendre { - (element enable { ( "true" | "false" ) } | - attribute enable { ( "true" | "false" ) })? & - (element num_points { xsd:positiveInteger } | - attribute num_points { xsd:positiveInteger })? - }? & - - (element total { list { xsd:double+ } } | - attribute total { list { xsd:double+ } })? & - - (element absorption { list { xsd:double+ } } | - attribute absorption { list { xsd:double+ } }) & - - (element scatter { list { xsd:double+ } } | - attribute scatter { list { xsd:double+ } }) & - - (element fission { list { xsd:double+ } } | - attribute fission { list { xsd:double+ } })? & - - (element fission { list { xsd:double+ } } | - attribute fission { list { xsd:double+ } })? & - - (element k_fission { list { xsd:double+ } } | - attribute k_fission { list { xsd:double+ } })? & - - (element chi { list { xsd:double+ } } | - attribute chi { list { xsd:double+ } })? & - - (element nu_fission { list { xsd:double+ } } | - attribute nu_fission { list { xsd:double+ } })? - - }* - - -} \ No newline at end of file diff --git a/src/relaxng/mg_cross_sections.rng b/src/relaxng/mg_cross_sections.rng deleted file mode 100644 index b293cddbe4b..00000000000 --- a/src/relaxng/mg_cross_sections.rng +++ /dev/null @@ -1,314 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 15 - - - - - 15 - - - - - - - - 15 - - - - - 15 - - - - - - - - - - - - - - - - - - true - false - - - - - true - false - - - - - - - - isotropic - angle - - - - - isotropic - angle - - - - - - - - - - - - - - - - - - - - - - - - - - - - - legendre - histogram - tabular - - - - - legendre - histogram - tabular - - - - - - - - - - - - - - - - - - - - true - false - - - - - true - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/relaxng/plots.rnc b/src/relaxng/plots.rnc deleted file mode 100644 index e53cc15f72c..00000000000 --- a/src/relaxng/plots.rnc +++ /dev/null @@ -1,41 +0,0 @@ -element plots { - element plot { - (element id { xsd:int } | attribute id { xsd:int })? & - (element filename { xsd:string { maxLength = "50" } } | - attribute filename { xsd:string { maxLength = "50" } })? & - (element type { "slice" | "voxel" } | - attribute type { "slice" | "voxel" })? & - (element color_by { ( "cell" | "material" ) } | - attribute color_by { ( "cell" | "material" ) })? & - (element level { xsd:int } | attribute level { xsd:int })? & - (element origin { list { xsd:double+ } } | - attribute origin { list { xsd:double+ } })? & - (element width { list { xsd:double+ } } | - attribute width { list { xsd:double+ } })? & - (element basis { ( "xy" | "yz" | "xz" ) } | - attribute basis { ( "xy" | "yz" | "xz" ) })? & - (element pixels { list { xsd:int+ } } | - attribute pixels { list { xsd:int+ } })? & - (element background { list { xsd:int+ } } | - attribute background { list { xsd:int+ } })? & - element color { - (element id { xsd:int } | attribute id { xsd:int }) & - (element rgb { list { xsd:int+ } } | - attribute rgb { list { xsd:int+ } }) - }* & - element mask { - (element components { list { xsd:int+ } } | - attribute components { list { xsd:int+ } }) & - (element background { list { xsd:int+ } } | - attribute background { list { xsd:int+ } }) - }* & - element meshlines { - (element meshtype { ( "tally" | "entropy" | "ufs" | "cmfd" ) } | - attribute meshtype { ( "tally" | "entropy" | "ufs" | "cmfd" ) }) & - (element id { xsd:int } | attribute id { xsd:int })? & - (element linewidth { xsd:int } | attribute linewidth { xsd:int }) & - (element color { list { xsd:int+ } } | - attribute color { list { xsd:int+ } })? - }* - }* -} diff --git a/src/relaxng/plots.rng b/src/relaxng/plots.rng deleted file mode 100644 index 55d69008ee6..00000000000 --- a/src/relaxng/plots.rng +++ /dev/null @@ -1,293 +0,0 @@ - - - - - - - - - - - - - - - - - - - - 50 - - - - - 50 - - - - - - - - - slice - voxel - - - - - slice - voxel - - - - - - - - - cell - material - - - - - cell - material - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - xy - yz - xz - - - - - xy - yz - xz - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - tally - entropy - ufs - cmfd - - - - - tally - entropy - ufs - cmfd - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/relaxng/readme.rst b/src/relaxng/readme.rst deleted file mode 100644 index 9660e3f8ce8..00000000000 --- a/src/relaxng/readme.rst +++ /dev/null @@ -1,19 +0,0 @@ -===================== -Editing RelaxNG files -===================== - -All direct edits to RelaxNG files should be in the .rnc files. The program -TRANG_ should be used to generate a correcsponding .rng file. For Ubuntu, you -can install with: - -.. code-block:: bash - - sudo apt-get install trang - -To convert the .rnc file to .rng, use the following syntax: - -.. code-block:: bash - - trang {filename}.rnc {filename}.rng - -.. _TRANG: http://www.thaiopensource.com/relaxng/trang.html diff --git a/src/relaxng/settings.rnc b/src/relaxng/settings.rnc deleted file mode 100644 index f9877a3f98a..00000000000 --- a/src/relaxng/settings.rnc +++ /dev/null @@ -1,204 +0,0 @@ -element settings { - element batches { xsd:positiveInteger }? & - - element confidence_intervals { xsd:boolean }? & - - element create_fission_neutrons { xsd:boolean }? & - - element cutoff { - (element weight { xsd:double } | attribute weight { xsd:double })? & - (element weight_avg { xsd:double } | attribute weight_avg { xsd:double })? & - (element energy_neutron { xsd:double } | attribute energy_neutron { xsd:double })? & - (element energy_photon { xsd:double } | attribute energy_photon { xsd:double })? & - (element energy_electron { xsd:double } | attribute energy_electron { xsd:double })? & - (element energy_positron { xsd:double } | attribute energy_positron { xsd:double })? - }? & - - element delayed_photon_scaling { xsd:boolean }? & - - element electron_treatment { ( "led" | "ttb" ) }? & - - element energy_grid { ( "nuclide" | "log" | "logarithm" | "logarithmic" | "material-union" | "union" ) }? & - - element energy_mode { ( "continuous-energy" | "ce" | "CE" | "multi-group" | "mg" | "MG" ) }? & - - element entropy_mesh { xsd:positiveInteger }? & - - element event_based { xsd:boolean }? & - - element generations_per_batch { xsd:positiveInteger }? & - - element inactive { xsd:nonNegativeInteger }? & - - element keff_trigger { - (element type { xsd:string } | attribute type { xsd:string }) & - (element threshold { xsd:double} | attribute threshold { xsd:double }) - }? & - - element log_grid_bins { xsd:positiveInteger }? & - - element material_cell_offsets { xsd:boolean }? & - - element max_particles_in_flight { xsd:positiveInteger }? & - - element max_order { xsd:nonNegativeInteger }? & - - element mesh { - (element id { xsd:int } | attribute id { xsd:int }) & - (element type { ( "regular" ) } | - attribute type { ( "regular" ) })? & - (element dimension { list { xsd:positiveInteger+ } } | - attribute dimension { list { xsd:positiveInteger+ } }) & - (element lower_left { list { xsd:double+ } } | - attribute lower_left { list { xsd:double+ } }) & - ( - (element upper_right { list { xsd:double+ } } | - attribute upper_right { list { xsd:double+ } }) | - (element width { list { xsd:double+ } } | - attribute width { list { xsd:double+ } }) - ) - }* & - - element no_reduce { xsd:boolean }? & - - element output { - (element summary { xsd:boolean } | attribute summary { xsd:boolean })? & - (element tallies { xsd:boolean } | attribute tallies { xsd:boolean })? & - (element path { xsd:string } | attribute path { xsd:string })? - }? & - - element particles { xsd:positiveInteger }? & - - element photon_transport { xsd:boolean }? & - - element ptables { xsd:boolean }? & - - element dagmc { xsd:boolean }? & - - element run_mode { xsd:string }? & - - element seed { xsd:positiveInteger }? & - - element source { - grammar { - start = - (element particle { xsd:string } | attribute particle { xsd:string })? & - (element strength { xsd:double } | attribute strength { xsd:double })? & - (element file { xsd:string } | attribute file { xsd:string })? & - element space { - (element type { xsd:string } | attribute type { xsd:string }) & - (element parameters { list { xsd:double+ } } | - attribute parameters { list { xsd:double+ } })? & - element x { distribution }? & - element y { distribution }? & - element z { distribution }? & - element r { distribution }? & - element theta { distribution }? & - element phi { distribution }? & - element origin { list { xsd:double, xsd:double, xsd:double } }? - }? & - element angle { - (element type { xsd:string } | attribute type { xsd:string }) & - (element reference_uvw { list { xsd:double, xsd:double, xsd:double } } | - attribute reference_uvw { list { xsd:double, xsd:double, xsd:double } })? & - element mu { distribution }? & - element phi { distribution }? - }? & - element energy { distribution }? - distribution = - (element type { xsd:string { maxLength = "16" } } | - attribute type { xsd:string { maxLength = "16" } }) & - (element interpolation { xsd:string } | - attribute interpolation { xsd:string })? & - (element parameters { list { xsd:double+ } } | - attribute parameters { list { xsd:double+ } })? - } - }* & - - element state_point { - ( - (element batches { list { xsd:positiveInteger+ } } | - attribute batches { list { xsd:positiveInteger+ } }) | - (element interval { xsd:positiveInteger } | - attribute interval { xsd:positiveInteger }) - ) - }? & - - element source_point { - ( - (element batches { list { xsd:positiveInteger+ } } | - attribute batches { list { xsd:positiveInteger+ } }) | - (element interval { xsd:positiveInteger } | - attribute interval { xsd:positiveInteger }) - )? & - (element separate { xsd:boolean } | - attribute separate { xsd:boolean })? & - (element write { xsd:boolean } | - attribute write { xsd:boolean })? & - (element overwrite_latest { xsd:boolean} | - attribute overwrite_latest {xsd:boolean})? - }? & - - element surf_source_read { - (element path { xsd:string } | attribute path { xsd:string }) - }? & - - element surf_source_write { - (element surface_ids { list { xsd:positiveInteger+ } } | - attribute surface_ids { list { xsd:positiveInteger+ } }) & - (element max_particles { xsd:positiveInteger } | - attribute max_particles { xsd:positiveInteger }) - }? & - - element survival_biasing { xsd:boolean }? & - - element temperature_default { xsd:double }? & - - element temperature_method { xsd:string }? & - - element temperature_multipole { xsd:boolean }? & - - element temperature_range { list { xsd:double, xsd:double } }? & - - element temperature_tolerance { xsd:double }? & - - element threads { xsd:positiveInteger }? & - - element trace { list { xsd:positiveInteger+ } }? & - - element track { list { xsd:positiveInteger+ } }? & - - element trigger { - (element active { xsd:boolean } | attribute active { xsd:boolean }) & - (element max_batches { xsd:positiveInteger } | attribute max_batches { xsd:positiveInteger }) & - (element batch_interval { xsd:positiveInteger } | attribute batch_interval { xsd:positiveInteger })? - }? & - - element ufs_mesh { xsd:positiveInteger }? & - - element verbosity { xsd:positiveInteger }? & - - element volume_calc { - (element domain_type { xsd:string } | - attribute domain_type { xsd:string }) & - (element domain_ids { list { xsd:integer+ } } | - attribute domain_ids { list { xsd:integer+ } }) & - (element samples { xsd:positiveInteger } | - attribute samples { xsd:positiveInteger }) & - (element lower_left { list { xsd:double+ } } | - attribute lower_left { list { xsd:double+ } }) & - (element upper_right { list { xsd:double+ } } | - attribute upper_right { list { xsd:double+ } }) - }* & - - element write_initial_source { xsd:boolean }? & - - element resonance_scattering { - (element enable { xsd:boolean } | attribute enable { xsd:boolean })? & - (element method { xsd:string } | attribute method { xsd:string })? & - (element energy_min { xsd:double } | attribute energy_min { xsd:double })? & - (element energy_max { xsd:double } | attribute energy_max { xsd:double })? & - (element nuclides { list { xsd:string+ } } | - attribute nuclides { list { xsd:string+ } })? - }? -} diff --git a/src/relaxng/settings.rng b/src/relaxng/settings.rng deleted file mode 100644 index 07b8a6d1d7b..00000000000 --- a/src/relaxng/settings.rng +++ /dev/null @@ -1,921 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - led - ttb - - - - - - - nuclide - log - logarithm - logarithmic - material-union - union - - - - - - - continuous-energy - ce - CE - multi-group - mg - MG - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - regular - - - regular - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 16 - - - - - 16 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/relaxng/tallies.rnc b/src/relaxng/tallies.rnc deleted file mode 100644 index 3d504a66c8d..00000000000 --- a/src/relaxng/tallies.rnc +++ /dev/null @@ -1,96 +0,0 @@ -element tallies { - element mesh { - (element id { xsd:int } | attribute id { xsd:int }) & - ( - ( - (element type { ( "regular" ) } | - attribute type { ( "regular" ) }) & - (element dimension { list { xsd:positiveInteger+ } } | - attribute dimension { list { xsd:positiveInteger+ } }) & - (element lower_left { list { xsd:double+ } } | - attribute lower_left { list { xsd:double+ } }) & - ( - (element upper_right { list { xsd:double+ } } | - attribute upper_right { list { xsd:double+ } }) | - (element width { list { xsd:double+ } } | - attribute width { list { xsd:double+ } }) - ) - ) | ( - (element type { ( "rectilinear" ) } | - attribute type { ( "rectilinear" ) }) & - (element x_grid { list { xsd:double+ } } | - attribute x_grid { list { xsd:double+ } }) & - (element y_grid { list { xsd:double+ } } | - attribute y_grid { list { xsd:double+ } }) & - (element z_grid { list { xsd:double+ } } | - attribute z_grid { list { xsd:double+ } }) - ) - ) - }* & - - element derivative { - (element id { xsd:int } | attribute id { xsd:int }) & - (element material { xsd:int } | attribute material { xsd:int }) & - ( (element variable { ( "density") } - | attribute variable { ( "density" ) } ) | - ( - (element variable { ( "nuclide_density" ) } - | attribute variable { ( "nuclide_density" ) } ) - & - (element nuclide { xsd:string { maxLength = "12" } } - | attribute nuclide { xsd:string { maxLength = "12" } } ) - ) | - (element variable { ( "temperature") } - | attribute variable { ( "temperature" ) } ) - ) - }* & - - element filter { - (element id { xsd:int } | attribute id { xsd:int }) & - ( - ( (element type { ( "cell" | "cellfrom" | "cellborn" | "material" | - "universe" | "surface" | "distribcell" | "mesh" | "energy" | - "energyout" | "mu" | "polar" | "azimuthal" | "delayedgroup" | - "energyfunction" | "meshsurface" | "cellinstance") } | - attribute type { ( "cell" | "cellfrom" | "cellborn" | "material" | - "universe" | "surface" | "distribcell" | "mesh" | "energy" | - "energyout" | "mu" | "polar" | "azimuthal" | "delayedgroup" | - "energyfunction" | "meshsurface" | "cellinstance") }) & - (element bins { list { xsd:double+ } } | - attribute bins { list { xsd:double+ } }) - ) | - ( - (element type { ("energyfunction") } | - attribute type { ("energyfunction") }) & - (element energy { list { xsd:double+ } } | - attribute energy { list { xsd:double+ } }) & - (element y { list { xsd:double+ } } | - attribute y { list { xsd:double+ } }) - ) - ) - }* & - - element tally { - (element id { xsd:int } | attribute id { xsd:int }) & - (element name { xsd:string { maxLength="52" } } | - attribute name { xsd:string { maxLength="52" } })? & - (element estimator { ( "analog" | "tracklength" | "collision" ) } | - attribute estimator { ( "analog" | "tracklength" | "collision" ) })? & - (element filters { list { xsd:int+ } } | - attribute filters { list { xsd:int+ } })? & - element nuclides { - list { xsd:string { maxLength = "12" }+ } - }? & - element scores { - list { xsd:string { maxLength = "20" }+ } - } & - element trigger { - (element type { xsd:string } | attribute type { xsd:string }) & - (element threshold { xsd:double} | attribute threshold { xsd:double }) & - (element scores { list { xsd:string { maxLength = "20" }+ } } | attribute scores { list { xsd:string { maxLength = "20"}+ } } )? - }* & - (element derivative { xsd:int } | attribute derivative { xsd:int } )? - }* & - - element assume_separate { xsd:boolean }? -} diff --git a/src/relaxng/tallies.rng b/src/relaxng/tallies.rng deleted file mode 100644 index 350c3cb4aa8..00000000000 --- a/src/relaxng/tallies.rng +++ /dev/null @@ -1,480 +0,0 @@ - - - - - - - - - - - - - - - - - - - regular - - - regular - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - rectilinear - - - rectilinear - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - density - - - density - - - - - - nuclide_density - - - nuclide_density - - - - - - 12 - - - - - 12 - - - - - - - temperature - - - temperature - - - - - - - - - - - - - - - - - - - - - - - cell - cellfrom - cellborn - material - universe - surface - distribcell - mesh - energy - energyout - mu - polar - azimuthal - delayedgroup - energyfunction - meshsurface - cellinstance - - - - - cell - cellfrom - cellborn - material - universe - surface - distribcell - mesh - energy - energyout - mu - polar - azimuthal - delayedgroup - energyfunction - meshsurface - cellinstance - - - - - - - - - - - - - - - - - - - - - - - - energyfunction - - - energyfunction - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 52 - - - - - 52 - - - - - - - - - analog - tracklength - collision - - - - - analog - tracklength - collision - - - - - - - - - - - - - - - - - - - - - - - - - - - - 12 - - - - - - - - - - 20 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 20 - - - - - - - - - 20 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/scattdata.cpp b/src/scattdata.cpp index a0341b153e3..813f9e19b5b 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -1,8 +1,8 @@ #include "openmc/scattdata.h" #include -#include #include +#include #include "xtensor/xbuilder.hpp" #include "xtensor/xview.hpp" @@ -19,10 +19,9 @@ namespace openmc { // ScattData base-class methods //============================================================================== -void -ScattData::base_init(int order, const xt::xtensor& in_gmin, - const xt::xtensor& in_gmax, const double_2dvec& in_energy, - const double_2dvec& in_mult) +void ScattData::base_init(int order, const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_energy, + const double_2dvec& in_mult) { size_t groups = in_energy.size(); @@ -48,8 +47,9 @@ ScattData::base_init(int order, const xt::xtensor& in_gmin, if (num_converted > 0) { // Raise a warning to the user if we did have to do the conversion - std::string msg = std::to_string(num_converted) + - "entries in the Multiplicity Matrix were changed from 0 to 1"; + std::string msg = + std::to_string(num_converted) + + " entries in the Multiplicity Matrix were changed from 0 to 1"; warning(msg); } @@ -57,7 +57,8 @@ ScattData::base_init(int order, const xt::xtensor& in_gmin, double norm = std::accumulate(energy[gin].begin(), energy[gin].end(), 0.); if (norm != 0.) { - for (auto& n : energy[gin]) n /= norm; + for (auto& n : energy[gin]) + n /= norm; } // Initialize the distribution data @@ -75,7 +76,7 @@ void ScattData::base_combine(size_t max_order, size_t order_dim, xt::xtensor& in_gmin, xt::xtensor& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter) { - size_t groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0]->energy.size(); // Now allocate and zero our storage spaces xt::xtensor this_nuscatt_matrix({groups, groups, order_dim}, 0.); @@ -97,10 +98,9 @@ void ScattData::base_combine(size_t max_order, size_t order_dim, for (int gin = 0; gin < groups; gin++) { for (int go = 0; go < groups; go++) { this_nuscatt_P0(gin, go) += - scalars[i] * that->get_xs(MgxsType::NU_SCATTER, gin, &go, nullptr); + scalars[i] * that->get_xs(MgxsType::NU_SCATTER, gin, &go, nullptr); this_scatt_P0(gin, go) += - scalars[i] * - that->get_xs(MgxsType::SCATTER, gin, &go, nullptr); + scalars[i] * that->get_xs(MgxsType::SCATTER, gin, &go, nullptr); } } } @@ -122,7 +122,8 @@ void ScattData::base_combine(size_t max_order, size_t order_dim, break; } } - if (non_zero) break; + if (non_zero) + break; } int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { @@ -133,7 +134,8 @@ void ScattData::base_combine(size_t max_order, size_t order_dim, break; } } - if (non_zero) break; + if (non_zero) + break; } // treat the case of all values being 0 @@ -161,11 +163,9 @@ void ScattData::base_combine(size_t max_order, size_t order_dim, } } - //============================================================================== -void -ScattData::sample_energy(int gin, int& gout, int& i_gout, uint64_t* seed) +void ScattData::sample_energy(int gin, int& gout, int& i_gout, uint64_t* seed) { // Sample the outgoing group double xi = prn(seed); @@ -173,15 +173,16 @@ ScattData::sample_energy(int gin, int& gout, int& i_gout, uint64_t* seed) i_gout = 0; for (gout = gmin[gin]; gout < gmax[gin]; ++gout) { prob += energy[gin][i_gout]; - if (xi < prob) break; + if (xi < prob) + break; ++i_gout; } } //============================================================================== -double -ScattData::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu) +double ScattData::get_xs( + MgxsType xstype, int gin, const int* gout, const double* mu) { // Set the outgoing group offset index as needed int i_gout = 0; @@ -195,16 +196,17 @@ ScattData::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu) } double val = scattxs[gin]; - switch(xstype) { + switch (xstype) { case MgxsType::NU_SCATTER: - if (gout != nullptr) val *= energy[gin][i_gout]; + if (gout != nullptr) + val *= energy[gin][i_gout]; break; case MgxsType::SCATTER: if (gout != nullptr) { val *= energy[gin][i_gout] / mult[gin][i_gout]; } else { - val /= std::inner_product(mult[gin].begin(), mult[gin].end(), - energy[gin].begin(), 0.0); + val /= std::inner_product( + mult[gin].begin(), mult[gin].end(), energy[gin].begin(), 0.0); } break; case MgxsType::NU_SCATTER_FMU: @@ -235,10 +237,9 @@ ScattData::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu) // ScattDataLegendre methods //============================================================================== -void -ScattDataLegendre::init(const xt::xtensor& in_gmin, - const xt::xtensor& in_gmax, const double_2dvec& in_mult, - const double_3dvec& coeffs) +void ScattDataLegendre::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) { size_t groups = coeffs.size(); size_t order = coeffs[0][0].size(); @@ -268,7 +269,8 @@ ScattDataLegendre::init(const xt::xtensor& in_gmin, double norm = matrix[gin][i_gout][0]; in_energy[gin][i_gout] = norm; if (norm != 0.) { - for (auto& n : matrix[gin][i_gout]) n /= norm; + for (auto& n : matrix[gin][i_gout]) + n /= norm; } } } @@ -284,7 +286,8 @@ ScattDataLegendre::init(const xt::xtensor& in_gmin, dist[gin][i_gout] = matrix[gin][i_gout]; } max_val[gin].resize(num_groups); - for (auto& n : max_val[gin]) n = 0.; + for (auto& n : max_val[gin]) + n = 0.; } // Now update the maximum value @@ -293,8 +296,7 @@ ScattDataLegendre::init(const xt::xtensor& in_gmin, //============================================================================== -void -ScattDataLegendre::update_max_val() +void ScattDataLegendre::update_max_val() { size_t groups = max_val.size(); // Step through the polynomial with fixed number of points to identify the @@ -315,11 +317,12 @@ ScattDataLegendre::update_max_val() } // Calculate probability - double f = evaluate_legendre(dist[gin][i_gout].size() - 1, - dist[gin][i_gout].data(), mu); + double f = evaluate_legendre( + dist[gin][i_gout].size() - 1, dist[gin][i_gout].data(), mu); // if this is a new maximum, store it - if (f > max_val[gin][i_gout]) max_val[gin][i_gout] = f; + if (f > max_val[gin][i_gout]) + max_val[gin][i_gout] = f; } // end imu loop // Since we may not have caught the true max, add 10% margin @@ -330,25 +333,23 @@ ScattDataLegendre::update_max_val() //============================================================================== -double -ScattDataLegendre::calc_f(int gin, int gout, double mu) +double ScattDataLegendre::calc_f(int gin, int gout, double mu) { double f; if ((gout < gmin[gin]) || (gout > gmax[gin])) { f = 0.; } else { int i_gout = gout - gmin[gin]; - f = evaluate_legendre(dist[gin][i_gout].size() - 1, - dist[gin][i_gout].data(), mu); + f = evaluate_legendre( + dist[gin][i_gout].size() - 1, dist[gin][i_gout].data(), mu); } return f; } //============================================================================== -void -ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt, - uint64_t* seed) +void ScattDataLegendre::sample( + int gin, int& gout, double& mu, double& wgt, uint64_t* seed) { // Sample the outgoing energy using the base-class method int i_gout; @@ -363,7 +364,8 @@ ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt, double f = calc_f(gin, gout, mu); if (f > 0.) { double u = prn(seed) * M; - if (u <= f) break; + if (u <= f) + break; } } if (samples == MAX_SAMPLE) { @@ -388,10 +390,11 @@ void ScattDataLegendre::combine( fatal_error("Cannot combine the ScattData objects!"); } size_t that_order = that->get_order(); - if (that_order > max_order) max_order = that_order; + if (that_order > max_order) + max_order = that_order; } - size_t groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0]->energy.size(); xt::xtensor in_gmin({groups}, 0); xt::xtensor in_gmax({groups}, 0); @@ -403,7 +406,7 @@ void ScattDataLegendre::combine( // matrices size_t order_dim = max_order + 1; ScattData::base_combine(max_order, order_dim, those_scatts, scalars, in_gmin, - in_gmax, sparse_mult, sparse_scatter); + in_gmax, sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -411,8 +414,7 @@ void ScattDataLegendre::combine( //============================================================================== -xt::xtensor -ScattDataLegendre::get_matrix(size_t max_order) +xt::xtensor ScattDataLegendre::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 size_t groups = energy.size(); @@ -423,8 +425,8 @@ ScattDataLegendre::get_matrix(size_t max_order) for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { - matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] * - dist[gin][i_gout][l]; + matrix(gin, gout, l) = + scattxs[gin] * energy[gin][i_gout] * dist[gin][i_gout][l]; } } } @@ -435,10 +437,9 @@ ScattDataLegendre::get_matrix(size_t max_order) // ScattDataHistogram methods //============================================================================== -void -ScattDataHistogram::init(const xt::xtensor& in_gmin, - const xt::xtensor& in_gmax, const double_2dvec& in_mult, - const double_3dvec& coeffs) +void ScattDataHistogram::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) { size_t groups = coeffs.size(); size_t order = coeffs[0][0].size(); @@ -451,8 +452,8 @@ ScattDataHistogram::init(const xt::xtensor& in_gmin, scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { - scattxs[gin] += std::accumulate(matrix[gin][i_gout].begin(), - matrix[gin][i_gout].end(), 0.); + scattxs[gin] += std::accumulate( + matrix[gin][i_gout].begin(), matrix[gin][i_gout].end(), 0.); } } @@ -463,11 +464,12 @@ ScattDataHistogram::init(const xt::xtensor& in_gmin, int num_groups = in_gmax[gin] - in_gmin[gin] + 1; in_energy[gin].resize(num_groups); for (int i_gout = 0; i_gout < num_groups; i_gout++) { - double norm = std::accumulate(matrix[gin][i_gout].begin(), - matrix[gin][i_gout].end(), 0.); + double norm = std::accumulate( + matrix[gin][i_gout].begin(), matrix[gin][i_gout].end(), 0.); in_energy[gin][i_gout] = norm; if (norm != 0.) { - for (auto& n : matrix[gin][i_gout]) n /= norm; + for (auto& n : matrix[gin][i_gout]) + n /= norm; } } } @@ -492,8 +494,8 @@ ScattDataHistogram::init(const xt::xtensor& in_gmin, // Integrate the histogram dist[gin][i_gout][0] = dmu * matrix[gin][i_gout][0]; for (int imu = 1; imu < order; imu++) { - dist[gin][i_gout][imu] = dmu * matrix[gin][i_gout][imu] + - dist[gin][i_gout][imu - 1]; + dist[gin][i_gout][imu] = + dmu * matrix[gin][i_gout][imu] + dist[gin][i_gout][imu - 1]; } // Now re-normalize for integral to unity @@ -510,8 +512,7 @@ ScattDataHistogram::init(const xt::xtensor& in_gmin, //============================================================================== -double -ScattDataHistogram::calc_f(int gin, int gout, double mu) +double ScattDataHistogram::calc_f(int gin, int gout, double mu) { double f; if ((gout < gmin[gin]) || (gout > gmax[gin])) { @@ -534,9 +535,8 @@ ScattDataHistogram::calc_f(int gin, int gout, double mu) //============================================================================== -void -ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt, - uint64_t* seed) +void ScattDataHistogram::sample( + int gin, int& gout, double& mu, double& wgt, uint64_t* seed) { // Sample the outgoing energy using the base-class method int i_gout; @@ -549,9 +549,9 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt, if (xi < dist[gin][i_gout][0]) { imu = 0; } else { - imu = std::upper_bound(dist[gin][i_gout].begin(), - dist[gin][i_gout].end(), xi) - - dist[gin][i_gout].begin(); + imu = + std::upper_bound(dist[gin][i_gout].begin(), dist[gin][i_gout].end(), xi) - + dist[gin][i_gout].begin(); } // Randomly select mu within the imu bin @@ -569,8 +569,7 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt, //============================================================================== -xt::xtensor -ScattDataHistogram::get_matrix(size_t max_order) +xt::xtensor ScattDataHistogram::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 size_t groups = energy.size(); @@ -582,8 +581,8 @@ ScattDataHistogram::get_matrix(size_t max_order) for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { - matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] * - fmu[gin][i_gout][l]; + matrix(gin, gout, l) = + scattxs[gin] * energy[gin][i_gout] * fmu[gin][i_gout][l]; } } } @@ -599,7 +598,8 @@ void ScattDataHistogram::combine( size_t max_order = those_scatts[0]->get_order(); for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable - ScattDataHistogram* that = dynamic_cast(those_scatts[i]); + ScattDataHistogram* that = + dynamic_cast(those_scatts[i]); if (!that) { fatal_error("Cannot combine the ScattData objects!"); } @@ -608,7 +608,7 @@ void ScattDataHistogram::combine( } } - size_t groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0]->energy.size(); xt::xtensor in_gmin({groups}, 0); xt::xtensor in_gmax({groups}, 0); @@ -620,7 +620,7 @@ void ScattDataHistogram::combine( // matrices size_t order_dim = max_order; ScattData::base_combine(max_order, order_dim, those_scatts, scalars, in_gmin, - in_gmax, sparse_mult, sparse_scatter); + in_gmax, sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -630,10 +630,9 @@ void ScattDataHistogram::combine( // ScattDataTabular methods //============================================================================== -void -ScattDataTabular::init(const xt::xtensor& in_gmin, - const xt::xtensor& in_gmax, const double_2dvec& in_mult, - const double_3dvec& coeffs) +void ScattDataTabular::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) { size_t groups = coeffs.size(); size_t order = coeffs[0][0].size(); @@ -651,8 +650,8 @@ ScattDataTabular::init(const xt::xtensor& in_gmin, for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { for (int imu = 1; imu < order; imu++) { - scattxs[gin] += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] + - matrix[gin][i_gout][imu]); + scattxs[gin] += + 0.5 * dmu * (matrix[gin][i_gout][imu - 1] + matrix[gin][i_gout][imu]); } } } @@ -665,8 +664,8 @@ ScattDataTabular::init(const xt::xtensor& in_gmin, for (int i_gout = 0; i_gout < num_groups; i_gout++) { double norm = 0.; for (int imu = 1; imu < order; imu++) { - norm += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] + - matrix[gin][i_gout][imu]); + norm += + 0.5 * dmu * (matrix[gin][i_gout][imu - 1] + matrix[gin][i_gout][imu]); } in_energy[gin][i_gout] = norm; } @@ -687,15 +686,15 @@ ScattDataTabular::init(const xt::xtensor& in_gmin, // Ensure positivity for (auto& val : fmu[gin][i_gout]) { - if (val < 0.) val = 0.; + if (val < 0.) + val = 0.; } // Now re-normalize for numerical integration issues and to take care of // the above negative fix-up. Also accrue the CDF double norm = 0.; for (int imu = 1; imu < order; imu++) { - norm += 0.5 * dmu * (fmu[gin][i_gout][imu - 1] + - fmu[gin][i_gout][imu]); + norm += 0.5 * dmu * (fmu[gin][i_gout][imu - 1] + fmu[gin][i_gout][imu]); // incorporate to the CDF dist[gin][i_gout][imu] = norm; } @@ -713,8 +712,7 @@ ScattDataTabular::init(const xt::xtensor& in_gmin, //============================================================================== -double -ScattDataTabular::calc_f(int gin, int gout, double mu) +double ScattDataTabular::calc_f(int gin, int gout, double mu) { double f; if ((gout < gmin[gin]) || (gout > gmax[gin])) { @@ -738,9 +736,8 @@ ScattDataTabular::calc_f(int gin, int gout, double mu) //============================================================================== -void -ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt, - uint64_t* seed) +void ScattDataTabular::sample( + int gin, int& gout, double& mu, double& wgt, uint64_t* seed) { // Sample the outgoing energy using the base-class method int i_gout; @@ -754,7 +751,8 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt, int k; for (k = 0; k < NP - 1; k++) { double c_k1 = dist[gin][i_gout][k + 1]; - if (xi < c_k1) break; + if (xi < c_k1) + break; c_k = c_k1; } @@ -763,16 +761,17 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt, // Find the pdf values we want double p0 = fmu[gin][i_gout][k]; - double mu0 = this -> mu[k]; + double mu0 = this->mu[k]; double p1 = fmu[gin][i_gout][k + 1]; - double mu1 = this -> mu[k + 1]; + double mu1 = this->mu[k + 1]; if (p0 == p1) { mu = mu0 + (xi - c_k) / p0; } else { double frac = (p1 - p0) / (mu1 - mu0); - mu = mu0 + (std::sqrt(std::max(0., p0 * p0 + 2. * frac * (xi - c_k))) - - p0) / frac; + mu = + mu0 + + (std::sqrt(std::max(0., p0 * p0 + 2. * frac * (xi - c_k))) - p0) / frac; } if (mu < -1.) { @@ -787,8 +786,7 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt, //============================================================================== -xt::xtensor -ScattDataTabular::get_matrix(size_t max_order) +xt::xtensor ScattDataTabular::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 size_t groups = energy.size(); @@ -800,8 +798,8 @@ ScattDataTabular::get_matrix(size_t max_order) for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { - matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] * - fmu[gin][i_gout][l]; + matrix(gin, gout, l) = + scattxs[gin] * energy[gin][i_gout] * fmu[gin][i_gout][l]; } } } @@ -826,7 +824,7 @@ void ScattDataTabular::combine( } } - size_t groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0]->energy.size(); xt::xtensor in_gmin({groups}, 0); xt::xtensor in_gmax({groups}, 0); @@ -838,7 +836,7 @@ void ScattDataTabular::combine( // matrices size_t order_dim = max_order; ScattData::base_combine(max_order, order_dim, those_scatts, scalars, in_gmin, - in_gmax, sparse_mult, sparse_scatter); + in_gmax, sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -848,8 +846,7 @@ void ScattDataTabular::combine( // module-level methods //============================================================================== -void -convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab) +void convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab) { // See if the user wants us to figure out how many points to use int n_mu = settings::legendre_to_tabular_points; @@ -880,13 +877,14 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab) tab.fmu[gin][i_gout].resize(n_mu); for (int imu = 0; imu < n_mu; imu++) { tab.fmu[gin][i_gout][imu] = - evaluate_legendre(leg.dist[gin][i_gout].size() - 1, - leg.dist[gin][i_gout].data(), tab.mu[imu]); + evaluate_legendre(leg.dist[gin][i_gout].size() - 1, + leg.dist[gin][i_gout].data(), tab.mu[imu]); } // Ensure positivity for (auto& val : tab.fmu[gin][i_gout]) { - if (val < 0.) val = 0.; + if (val < 0.) + val = 0.; } // Now re-normalize for numerical integration issues and to take care of @@ -894,8 +892,8 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab) double norm = 0.; tab.dist[gin][i_gout][0] = 0.; for (int imu = 1; imu < n_mu; imu++) { - norm += 0.5 * tab.dmu * (tab.fmu[gin][i_gout][imu - 1] + - tab.fmu[gin][i_gout][imu]); + norm += 0.5 * tab.dmu * + (tab.fmu[gin][i_gout][imu - 1] + tab.fmu[gin][i_gout][imu]); // incorporate to the CDF tab.dist[gin][i_gout][imu] = norm; } diff --git a/src/secondary_kalbach.cpp b/src/secondary_kalbach.cpp index 637650b431b..4a7878343c6 100644 --- a/src/secondary_kalbach.cpp +++ b/src/secondary_kalbach.cpp @@ -60,7 +60,7 @@ KalbachMann::KalbachMann(hid_t group) int j = offsets[i]; int n; if (i < n_energy - 1) { - n = offsets[i+1] - j; + n = offsets[i + 1] - j; } else { n = eout.shape()[1] - j; } @@ -71,11 +71,11 @@ KalbachMann::KalbachMann(hid_t group) d.n_discrete = n_discrete[i]; // Copy data - d.e_out = xt::view(eout, 0, xt::range(j, j+n)); - d.p = xt::view(eout, 1, xt::range(j, j+n)); - d.c = xt::view(eout, 2, xt::range(j, j+n)); - d.r = xt::view(eout, 3, xt::range(j, j+n)); - d.a = xt::view(eout, 4, xt::range(j, j+n)); + d.e_out = xt::view(eout, 0, xt::range(j, j + n)); + d.p = xt::view(eout, 1, xt::range(j, j + n)); + d.c = xt::view(eout, 2, xt::range(j, j + n)); + d.r = xt::view(eout, 3, xt::range(j, j + n)); + d.a = xt::view(eout, 4, xt::range(j, j + n)); // To get answers that match ACE data, for now we still use the tabulated // CDF values that were passed through to the HDF5 library. At a later @@ -87,20 +87,20 @@ KalbachMann::KalbachMann(hid_t group) if (k == 0) { d.c[k] = d.p[k]; } else { - d.c[k] = d.c[k-1] + d.p[k]; + d.c[k] = d.c[k - 1] + d.p[k]; } } // Continuous portion for (int k = d.n_discrete; k < n; ++k) { if (k == d.n_discrete) { - d.c[k] = d.c[k-1] + d.p[k]; + d.c[k] = d.c[k - 1] + d.p[k]; } else { if (d.interpolation == Interpolation::histogram) { - d.c[k] = d.c[k-1] + d.p[k-1]*(d.e_out[k] - d.e_out[k-1]); + d.c[k] = d.c[k - 1] + d.p[k - 1] * (d.e_out[k] - d.e_out[k - 1]); } else if (d.interpolation == Interpolation::lin_lin) { - d.c[k] = d.c[k-1] + 0.5*(d.p[k-1] + d.p[k]) * - (d.e_out[k] - d.e_out[k-1]); + d.c[k] = d.c[k - 1] + 0.5 * (d.p[k - 1] + d.p[k]) * + (d.e_out[k] - d.e_out[k - 1]); } } } @@ -114,7 +114,8 @@ KalbachMann::KalbachMann(hid_t group) } // incoming energies } -void KalbachMann::sample(double E_in, double& E_out, double& mu, uint64_t* seed) const +void KalbachMann::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // Find energy bin and calculate interpolation factor -- if the energy is // outside the range of the tabulated energies, choose the first or last bins @@ -129,7 +130,7 @@ void KalbachMann::sample(double E_in, double& E_out, double& mu, uint64_t* seed) r = 1.0; } else { i = lower_bound_index(energy_.begin(), energy_.end(), E_in); - r = (E_in - energy_[i]) / (energy_[i+1] - energy_[i]); + r = (E_in - energy_[i]) / (energy_[i + 1] - energy_[i]); } // Sample between the ith and [i+1]th bin @@ -141,13 +142,13 @@ void KalbachMann::sample(double E_in, double& E_out, double& mu, uint64_t* seed) double E_i_1 = distribution_[i].e_out[n_discrete]; double E_i_K = distribution_[i].e_out[n_energy_out - 1]; - n_energy_out = distribution_[i+1].e_out.size(); - n_discrete = distribution_[i+1].n_discrete; - double E_i1_1 = distribution_[i+1].e_out[n_discrete]; - double E_i1_K = distribution_[i+1].e_out[n_energy_out - 1]; + n_energy_out = distribution_[i + 1].e_out.size(); + n_discrete = distribution_[i + 1].n_discrete; + double E_i1_1 = distribution_[i + 1].e_out[n_discrete]; + double E_i1_K = distribution_[i + 1].e_out[n_energy_out - 1]; - double E_1 = E_i_1 + r*(E_i1_1 - E_i_1); - double E_K = E_i_K + r*(E_i1_K - E_i_K); + double E_1 = E_i_1 + r * (E_i1_1 - E_i_1); + double E_K = E_i_K + r * (E_i1_K - E_i_K); // Determine outgoing energy bin n_energy_out = distribution_[l].e_out.size(); @@ -171,8 +172,9 @@ void KalbachMann::sample(double E_in, double& E_out, double& mu, uint64_t* seed) double c_k1; for (int j = n_discrete; j < end; ++j) { k = j; - c_k1 = distribution_[l].c[k+1]; - if (r1 < c_k1) break; + c_k1 = distribution_[l].c[k + 1]; + if (r1 < c_k1) + break; k = j + 1; c_k = c_k1; } @@ -183,7 +185,7 @@ void KalbachMann::sample(double E_in, double& E_out, double& mu, uint64_t* seed) if (distribution_[l].interpolation == Interpolation::histogram) { // Histogram interpolation if (p_l_k > 0.0 && k >= n_discrete) { - E_out = E_l_k + (r1 - c_k)/p_l_k; + E_out = E_l_k + (r1 - c_k) / p_l_k; } else { E_out = E_l_k; } @@ -194,41 +196,46 @@ void KalbachMann::sample(double E_in, double& E_out, double& mu, uint64_t* seed) } else { // Linear-linear interpolation - double E_l_k1 = distribution_[l].e_out[k+1]; - double p_l_k1 = distribution_[l].p[k+1]; + double E_l_k1 = distribution_[l].e_out[k + 1]; + double p_l_k1 = distribution_[l].p[k + 1]; - double frac = (p_l_k1 - p_l_k)/(E_l_k1 - E_l_k); + double frac = (p_l_k1 - p_l_k) / (E_l_k1 - E_l_k); if (frac == 0.0) { - E_out = E_l_k + (r1 - c_k)/p_l_k; + E_out = E_l_k + (r1 - c_k) / p_l_k; } else { - E_out = E_l_k + (std::sqrt(std::max(0.0, p_l_k*p_l_k + - 2.0*frac*(r1 - c_k))) - p_l_k)/frac; + E_out = + E_l_k + + (std::sqrt(std::max(0.0, p_l_k * p_l_k + 2.0 * frac * (r1 - c_k))) - + p_l_k) / + frac; } // Determine Kalbach-Mann parameters - km_r = distribution_[l].r[k] + (E_out - E_l_k)/(E_l_k1 - E_l_k) * - (distribution_[l].r[k+1] - distribution_[l].r[k]); - km_a = distribution_[l].a[k] + (E_out - E_l_k)/(E_l_k1 - E_l_k) * - (distribution_[l].a[k+1] - distribution_[l].a[k]); + km_r = distribution_[l].r[k] + + (E_out - E_l_k) / (E_l_k1 - E_l_k) * + (distribution_[l].r[k + 1] - distribution_[l].r[k]); + km_a = distribution_[l].a[k] + + (E_out - E_l_k) / (E_l_k1 - E_l_k) * + (distribution_[l].a[k + 1] - distribution_[l].a[k]); } // Now interpolate between incident energy bins i and i + 1 if (k >= n_discrete) { if (l == i) { - E_out = E_1 + (E_out - E_i_1)*(E_K - E_1)/(E_i_K - E_i_1); + E_out = E_1 + (E_out - E_i_1) * (E_K - E_1) / (E_i_K - E_i_1); } else { - E_out = E_1 + (E_out - E_i1_1)*(E_K - E_1)/(E_i1_K - E_i1_1); + E_out = E_1 + (E_out - E_i1_1) * (E_K - E_1) / (E_i1_K - E_i1_1); } } // Sampled correlated angle from Kalbach-Mann parameters if (prn(seed) > km_r) { double T = uniform_distribution(-1., 1., seed) * std::sinh(km_a); - mu = std::log(T + std::sqrt(T*T + 1.0))/km_a; + mu = std::log(T + std::sqrt(T * T + 1.0)) / km_a; } else { double r1 = prn(seed); - mu = std::log(r1*std::exp(km_a) + (1.0 - r1)*std::exp(-km_a))/km_a; + mu = std::log(r1 * std::exp(km_a) + (1.0 - r1) * std::exp(-km_a)) / km_a; } } -} +} // namespace openmc diff --git a/src/secondary_nbody.cpp b/src/secondary_nbody.cpp index 0b27f3d08cd..da0bb81c471 100644 --- a/src/secondary_nbody.cpp +++ b/src/secondary_nbody.cpp @@ -22,8 +22,8 @@ NBodyPhaseSpace::NBodyPhaseSpace(hid_t group) read_attribute(group, "q_value", Q_); } -void NBodyPhaseSpace::sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const +void NBodyPhaseSpace::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // By definition, the distribution of the angle is isotropic for an N-body // phase space distribution @@ -31,7 +31,7 @@ void NBodyPhaseSpace::sample(double E_in, double& E_out, double& mu, // Determine E_max parameter double Ap = mass_ratio_; - double E_max = (Ap - 1.0)/Ap * (A_/(A_ + 1.0)*E_in + Q_); + double E_max = (Ap - 1.0) / Ap * (A_ / (A_ + 1.0) * E_in + Q_); // x is essentially a Maxwellian distribution double x = maxwell_spectrum(1.0, seed); @@ -46,7 +46,7 @@ void NBodyPhaseSpace::sample(double E_in, double& E_out, double& mu, r1 = prn(seed); r2 = prn(seed); r3 = prn(seed); - y = -std::log(r1*r2*r3); + y = -std::log(r1 * r2 * r3); break; case 5: r1 = prn(seed); @@ -55,14 +55,15 @@ void NBodyPhaseSpace::sample(double E_in, double& E_out, double& mu, r4 = prn(seed); r5 = prn(seed); r6 = prn(seed); - y = -std::log(r1*r2*r3*r4) - std::log(r5) * std::pow(std::cos(PI/2.0*r6), 2); + y = -std::log(r1 * r2 * r3 * r4) - + std::log(r5) * std::pow(std::cos(PI / 2.0 * r6), 2); break; default: - throw std::runtime_error{"N-body phase space with >5 bodies."}; + throw std::runtime_error {"N-body phase space with >5 bodies."}; } // Now determine v and E_out - double v = x/(x + y); + double v = x / (x + y); E_out = E_max * v; } diff --git a/src/secondary_thermal.cpp b/src/secondary_thermal.cpp index dd86c0d0716..0b8e1ab42db 100644 --- a/src/secondary_thermal.cpp +++ b/src/secondary_thermal.cpp @@ -4,6 +4,8 @@ #include "openmc/random_lcg.h" #include "openmc/search.h" +#include + #include "xtensor/xview.hpp" #include // for log, exp @@ -19,7 +21,8 @@ void get_energy_index( f = 0.0; if (E >= energies.front()) { i = lower_bound_index(energies.begin(), energies.end(), E); - f = (E - energies[i]) / (energies[i+1] - energies[i]); + if (i + 1 < energies.size()) + f = (E - energies[i]) / (energies[i + 1] - energies[i]); } } @@ -27,33 +30,30 @@ void get_energy_index( // CoherentElasticAE implementation //============================================================================== -CoherentElasticAE::CoherentElasticAE(const CoherentElasticXS& xs) - : xs_{xs} -{ } +CoherentElasticAE::CoherentElasticAE(const CoherentElasticXS& xs) : xs_ {xs} {} -void -CoherentElasticAE::sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const +void CoherentElasticAE::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { - // Get index and interpolation factor for elastic grid - int i; - double f; + // Energy doesn't change in elastic scattering (ENDF-102, Eq. 7-1) + E_out = E_in; + const auto& energies {xs_.bragg_edges()}; - get_energy_index(energies, E_in, i, f); + + Expects(E_in >= energies.front()); + + const int i = lower_bound_index(energies.begin(), energies.end(), E_in); // Sample a Bragg edge between 1 and i + // E[0] < E_in < E[i+1] -> can scatter in bragg edges 0..i const auto& factors = xs_.factors(); - double prob = prn(seed) * factors[i+1]; - int k = 0; - if (prob >= factors.front()) { - k = lower_bound_index(factors.begin(), factors.begin() + (i+1), prob); - } + const double prob = prn(seed) * factors[i]; - // Characteristic scattering cosine for this Bragg edge (ENDF-102, Eq. 7-2) - mu = 1.0 - 2.0*energies[k] / E_in; + const int k = std::lower_bound(factors.begin(), factors.begin() + i, prob) - + factors.begin(); - // Energy doesn't change in elastic scattering (ENDF-102, Eq. 7-1) - E_out = E_in; + // Characteristic scattering cosine for this Bragg edge (ENDF-102, Eq. 7-2) + mu = 1.0 - 2.0 * energies[k] / E_in; } //============================================================================== @@ -65,13 +65,12 @@ IncoherentElasticAE::IncoherentElasticAE(hid_t group) read_dataset(group, "debye_waller", debye_waller_); } -void -IncoherentElasticAE::sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const +void IncoherentElasticAE::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // Sample angle by inverting the distribution in ENDF-102, Eq. 7.4 double c = 2 * E_in * debye_waller_; - mu = std::log(1.0 + prn(seed)*(std::exp(2.0*c) - 1))/c - 1.0; + mu = std::log(1.0 + prn(seed) * (std::exp(2.0 * c) - 1)) / c - 1.0; // Energy doesn't change in elastic scattering (ENDF-102, Eq. 7.4) E_out = E_in; @@ -88,9 +87,8 @@ IncoherentElasticAEDiscrete::IncoherentElasticAEDiscrete( read_dataset(group, "mu_out", mu_out_); } -void -IncoherentElasticAEDiscrete::sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const +void IncoherentElasticAEDiscrete::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // Get index and interpolation factor for elastic grid int i; @@ -109,23 +107,24 @@ IncoherentElasticAEDiscrete::sample(double E_in, double& E_out, double& mu, // discrete mu value itself. // Interpolate kth mu value between distributions at energies i and i+1 - mu = mu_out_(i, k) + f*(mu_out_(i+1, k) - mu_out_(i, k)); + mu = mu_out_(i, k) + f * (mu_out_(i + 1, k) - mu_out_(i, k)); // Inteprolate (k-1)th mu value between distributions at energies i and i+1. // When k==0, pick a value that will smear the cosine out to a minimum of -1. - double mu_left = (k == 0) ? - -1.0 - (mu + 1.0) : - mu_out_(i, k-1) + f*(mu_out_(i+1, k-1) - mu_out_(i, k-1)); + double mu_left = (k == 0) ? -1.0 - (mu + 1.0) + : mu_out_(i, k - 1) + + f * (mu_out_(i + 1, k - 1) - mu_out_(i, k - 1)); // Inteprolate (k+1)th mu value between distributions at energies i and i+1. // When k is the last discrete value, pick a value that will smear the cosine // out to a maximum of 1. - double mu_right = (k == n_mu - 1) ? - 1.0 + (1.0 - mu) : - mu_out_(i, k+1) + f*(mu_out_(i+1, k+1) - mu_out_(i, k+1)); + double mu_right = + (k == n_mu - 1) + ? 1.0 + (1.0 - mu) + : mu_out_(i, k + 1) + f * (mu_out_(i + 1, k + 1) - mu_out_(i, k + 1)); // Smear cosine - mu += std::min(mu - mu_left, mu_right - mu)*(prn(seed) - 0.5); + mu += std::min(mu - mu_left, mu_right - mu) * (prn(seed) - 0.5); // Energy doesn't change in elastic scattering E_out = E_in; @@ -144,9 +143,8 @@ IncoherentInelasticAEDiscrete::IncoherentInelasticAEDiscrete( read_dataset(group, "skewed", skewed_); } -void -IncoherentInelasticAEDiscrete::sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const +void IncoherentInelasticAEDiscrete::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // Get index and interpolation factor for inelastic grid int i; @@ -187,22 +185,22 @@ IncoherentInelasticAEDiscrete::sample(double E_in, double& E_out, double& mu, } // Determine outgoing energy corresponding to E_in[i] and E_in[i+1] - double E_ij = energy_out_(i, j); - double E_i1j = energy_out_(i+1, j); + double E_ij = energy_out_(i, j); + double E_i1j = energy_out_(i + 1, j); // Outgoing energy - E_out = (1 - f)*E_ij + f*E_i1j; + E_out = (1 - f) * E_ij + f * E_i1j; // Sample outgoing cosine bin int m = mu_out_.shape()[2]; int k = prn(seed) * m; // Determine outgoing cosine corresponding to E_in[i] and E_in[i+1] - double mu_ijk = mu_out_(i, j, k); - double mu_i1jk = mu_out_(i+1, j, k); + double mu_ijk = mu_out_(i, j, k); + double mu_i1jk = mu_out_(i + 1, j, k); // Cosine of angle between incoming and outgoing neutron - mu = (1 - f)*mu_ijk + f*mu_i1jk; + mu = (1 - f) * mu_ijk + f * mu_i1jk; } //============================================================================== @@ -245,12 +243,10 @@ IncoherentInelasticAE::IncoherentInelasticAE(hid_t group) distribution_.emplace_back(std::move(d)); } - } -void -IncoherentInelasticAE::sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const +void IncoherentInelasticAE::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // Get index and interpolation factor for inelastic grid int i; @@ -269,7 +265,8 @@ IncoherentInelasticAE::sample(double E_in, double& E_out, double& mu, std::size_t j; for (j = 0; j < n - 1; ++j) { c_j1 = distribution_[l].e_out_cdf[j + 1]; - if (r1 < c_j1) break; + if (r1 < c_j1) + break; c_j = c_j1; } @@ -289,14 +286,16 @@ IncoherentInelasticAE::sample(double E_in, double& E_out, double& mu, if (frac == 0.0) { E_out = E_l_j + (r1 - c_j) / p_l_j; } else { - E_out = E_l_j + (std::sqrt(std::max(0.0, p_l_j*p_l_j + - 2.0*frac*(r1 - c_j))) - p_l_j) / frac; + E_out = E_l_j + + (std::sqrt(std::max(0.0, p_l_j * p_l_j + 2.0 * frac * (r1 - c_j))) - + p_l_j) / + frac; } // Adjustment of outgoing energy double E_l = energy_[l]; - if (E_out < 0.5*E_l) { - E_out *= 2.0*E_in/E_l - 1.0; + if (E_out < 0.5 * E_l) { + E_out *= 2.0 * E_in / E_l - 1.0; } else { E_out += E_in - E_l; } @@ -309,26 +308,64 @@ IncoherentInelasticAE::sample(double E_in, double& E_out, double& mu, // a bin of width 0.5*min(mu[k] - mu[k-1], mu[k+1] - mu[k]) centered on the // discrete mu value itself. const auto& mu_l = distribution_[l].mu; - f = (r1 - c_j)/(c_j1 - c_j); + f = (r1 - c_j) / (c_j1 - c_j); // Interpolate kth mu value between distributions at energies j and j+1 - mu = mu_l(j, k) + f*(mu_l(j+1, k) - mu_l(j, k)); + mu = mu_l(j, k) + f * (mu_l(j + 1, k) - mu_l(j, k)); // Inteprolate (k-1)th mu value between distributions at energies j and j+1. // When k==0, pick a value that will smear the cosine out to a minimum of -1. - double mu_left = (k == 0) ? - mu_left = -1.0 - (mu + 1.0) : - mu_left = mu_l(j, k-1) + f*(mu_l(j+1, k-1) - mu_l(j, k-1)); + double mu_left = + (k == 0) + ? mu_left = -1.0 - (mu + 1.0) + : mu_left = mu_l(j, k - 1) + f * (mu_l(j + 1, k - 1) - mu_l(j, k - 1)); // Inteprolate (k+1)th mu value between distributions at energies j and j+1. // When k is the last discrete value, pick a value that will smear the cosine // out to a maximum of 1. - double mu_right = (k == n_mu - 1) ? - mu_right = 1.0 + (1.0 - mu) : - mu_right = mu_l(j, k+1) + f*(mu_l(j+1, k+1) - mu_l(j, k+1)); + double mu_right = + (k == n_mu - 1) + ? mu_right = 1.0 + (1.0 - mu) + : mu_right = mu_l(j, k + 1) + f * (mu_l(j + 1, k + 1) - mu_l(j, k + 1)); // Smear cosine - mu += std::min(mu - mu_left, mu_right - mu)*(prn(seed) - 0.5); + mu += std::min(mu - mu_left, mu_right - mu) * (prn(seed) - 0.5); +} + +//============================================================================== +// MixedElasticAE implementation +//============================================================================== + +MixedElasticAE::MixedElasticAE( + hid_t group, const CoherentElasticXS& coh_xs, const Function1D& incoh_xs) + : coherent_dist_(coh_xs), coherent_xs_(coh_xs), incoherent_xs_(incoh_xs) +{ + // Read incoherent elastic distribution + hid_t incoherent_group = open_group(group, "incoherent"); + std::string temp; + read_attribute(incoherent_group, "type", temp); + if (temp == "incoherent_elastic") { + incoherent_dist_ = make_unique(incoherent_group); + } else if (temp == "incoherent_elastic_discrete") { + auto xs = dynamic_cast(&incoh_xs); + incoherent_dist_ = + make_unique(incoherent_group, xs->x()); + } + close_group(incoherent_group); +} + +void MixedElasticAE::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const +{ + // Evaluate coherent and incoherent elastic cross sections + double xs_coh = coherent_xs_(E_in); + double xs_incoh = incoherent_xs_(E_in); + + if (prn(seed) * (xs_coh + xs_incoh) < xs_coh) { + coherent_dist_.sample(E_in, E_out, mu, seed); + } else { + incoherent_dist_->sample(E_in, E_out, mu, seed); + } } } // namespace openmc diff --git a/src/secondary_uncorrelated.cpp b/src/secondary_uncorrelated.cpp index 39b3eb4ed54..5cbb76fb9b9 100644 --- a/src/secondary_uncorrelated.cpp +++ b/src/secondary_uncorrelated.cpp @@ -1,6 +1,6 @@ #include "openmc/secondary_uncorrelated.h" -#include // for string +#include // for string #include @@ -19,7 +19,7 @@ UncorrelatedAngleEnergy::UncorrelatedAngleEnergy(hid_t group) // Check if angle group is present & read if (object_exists(group, "angle")) { hid_t angle_group = open_group(group, "angle"); - angle_ = AngleDistribution{angle_group}; + angle_ = AngleDistribution {angle_group}; close_group(angle_group); } @@ -31,28 +31,27 @@ UncorrelatedAngleEnergy::UncorrelatedAngleEnergy(hid_t group) read_attribute(energy_group, "type", type); using UPtrEDist = unique_ptr; if (type == "discrete_photon") { - energy_ = UPtrEDist{new DiscretePhoton{energy_group}}; + energy_ = UPtrEDist {new DiscretePhoton {energy_group}}; } else if (type == "level") { - energy_ = UPtrEDist{new LevelInelastic{energy_group}}; + energy_ = UPtrEDist {new LevelInelastic {energy_group}}; } else if (type == "continuous") { - energy_ = UPtrEDist{new ContinuousTabular{energy_group}}; + energy_ = UPtrEDist {new ContinuousTabular {energy_group}}; } else if (type == "maxwell") { - energy_ = UPtrEDist{new MaxwellEnergy{energy_group}}; + energy_ = UPtrEDist {new MaxwellEnergy {energy_group}}; } else if (type == "evaporation") { - energy_ = UPtrEDist{new Evaporation{energy_group}}; + energy_ = UPtrEDist {new Evaporation {energy_group}}; } else if (type == "watt") { - energy_ = UPtrEDist{new WattEnergy{energy_group}}; + energy_ = UPtrEDist {new WattEnergy {energy_group}}; } else { - warning(fmt::format("Energy distribution type '{}' not implemented.", type)); + warning( + fmt::format("Energy distribution type '{}' not implemented.", type)); } close_group(energy_group); } - } -void -UncorrelatedAngleEnergy::sample(double E_in, double& E_out, double& mu, - uint64_t* seed) const +void UncorrelatedAngleEnergy::sample( + double E_in, double& E_out, double& mu, uint64_t* seed) const { // Sample cosine of scattering angle if (!angle_.empty()) { diff --git a/src/settings.cpp b/src/settings.cpp index 2617da9788a..6790f2cc0f7 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,6 +1,6 @@ #include "openmc/settings.h" -#include // for ceil, pow +#include // for ceil, pow #include // for numeric_limits #include @@ -18,15 +18,19 @@ #include "openmc/eigenvalue.h" #include "openmc/error.h" #include "openmc/file_utils.h" +#include "openmc/mcpl_interface.h" #include "openmc/mesh.h" #include "openmc/message_passing.h" #include "openmc/output.h" +#include "openmc/plot.h" #include "openmc/random_lcg.h" +#include "openmc/random_ray/random_ray.h" #include "openmc/simulation.h" #include "openmc/source.h" #include "openmc/string_utils.h" #include "openmc/tallies/trigger.h" #include "openmc/volume_calc.h" +#include "openmc/weight_windows.h" #include "openmc/xml_interface.h" namespace openmc { @@ -38,38 +42,43 @@ namespace openmc { namespace settings { // Default values for boolean flags -bool assume_separate {false}; -bool check_overlaps {false}; -bool cmfd_run {false}; -bool confidence_intervals {false}; +bool assume_separate {false}; +bool check_overlaps {false}; +bool cmfd_run {false}; +bool confidence_intervals {false}; +bool create_delayed_neutrons {true}; bool create_fission_neutrons {true}; -bool dagmc {false}; -bool delayed_photon_scaling {true}; -bool entropy_on {false}; -bool event_based {false}; -bool legendre_to_tabular {true}; -bool material_cell_offsets {true}; -bool output_summary {true}; -bool output_tallies {true}; -bool particle_restart_run {false}; -bool photon_transport {false}; -bool reduce_tallies {true}; -bool res_scat_on {false}; -bool restart_run {false}; -bool run_CE {true}; -bool source_latest {false}; -bool source_separate {false}; -bool source_write {true}; -bool surf_source_write {false}; -bool surf_source_read {false}; -bool survival_biasing {false}; -bool temperature_multipole {false}; -bool trigger_on {false}; -bool trigger_predict {false}; -bool ufs_on {false}; -bool urr_ptables_on {true}; -bool write_all_tracks {false}; -bool write_initial_source {false}; +bool delayed_photon_scaling {true}; +bool entropy_on {false}; +bool event_based {false}; +bool legendre_to_tabular {true}; +bool material_cell_offsets {true}; +bool output_summary {true}; +bool output_tallies {true}; +bool particle_restart_run {false}; +bool photon_transport {false}; +bool reduce_tallies {true}; +bool res_scat_on {false}; +bool restart_run {false}; +bool run_CE {true}; +bool source_latest {false}; +bool source_separate {false}; +bool source_write {true}; +bool source_mcpl_write {false}; +bool surf_source_write {false}; +bool surf_mcpl_write {false}; +bool surf_source_read {false}; +bool survival_biasing {false}; +bool temperature_multipole {false}; +bool trigger_on {false}; +bool trigger_predict {false}; +bool ufs_on {false}; +bool urr_ptables_on {true}; +bool weight_windows_on {false}; +bool weight_window_checkpoint_surface {false}; +bool weight_window_checkpoint_collision {true}; +bool write_all_tracks {false}; +bool write_initial_source {false}; std::string path_cross_sections; std::string path_input; @@ -77,27 +86,35 @@ std::string path_output; std::string path_particle_restart; std::string path_sourcepoint; std::string path_statepoint; +const char* path_statepoint_c {path_statepoint.c_str()}; +std::string weight_windows_file; int32_t n_inactive {0}; int32_t max_lost_particles {10}; double rel_max_lost_particles {1.0e-6}; +int32_t max_write_lost_particles {-1}; int32_t gen_per_batch {1}; int64_t n_particles {-1}; int64_t max_particles_in_flight {100000}; +int max_particle_events {1000000}; ElectronTreatment electron_treatment {ElectronTreatment::TTB}; array energy_cutoff {0.0, 1000.0, 0.0, 0.0}; +array time_cutoff {INFTY, INFTY, INFTY, INFTY}; int legendre_to_tabular_points {C_NONE}; int max_order {0}; int n_log_bins {8000}; int n_batches; int n_max_batches; +int max_splits {1000}; +int max_tracks {1000}; ResScatMethod res_scat_method {ResScatMethod::rvs}; double res_scat_energy_min {0.01}; double res_scat_energy_max {1000.0}; vector res_scat_nuclides; RunMode run_mode {RunMode::UNSET}; +SolverType solver_type {SolverType::MONTE_CARLO}; std::unordered_set sourcepoint_batch; std::unordered_set statepoint_batch; std::unordered_set source_write_surf_id; @@ -138,24 +155,39 @@ void get_run_parameters(pugi::xml_node node_base) // Get maximum number of in flight particles for event-based mode if (check_for_node(node_base, "max_particles_in_flight")) { - max_particles_in_flight = std::stoll(get_node_value(node_base, - "max_particles_in_flight")); + max_particles_in_flight = + std::stoll(get_node_value(node_base, "max_particles_in_flight")); + } + + // Get maximum number of events allowed per particle + if (check_for_node(node_base, "max_particle_events")) { + max_particle_events = + std::stoll(get_node_value(node_base, "max_particle_events")); } // Get number of basic batches if (check_for_node(node_base, "batches")) { n_batches = std::stoi(get_node_value(node_base, "batches")); } - if (!trigger_on) n_max_batches = n_batches; + if (!trigger_on) + n_max_batches = n_batches; // Get max number of lost particles if (check_for_node(node_base, "max_lost_particles")) { - max_lost_particles = std::stoi(get_node_value(node_base, "max_lost_particles")); + max_lost_particles = + std::stoi(get_node_value(node_base, "max_lost_particles")); } // Get relative number of lost particles if (check_for_node(node_base, "rel_max_lost_particles")) { - rel_max_lost_particles = std::stod(get_node_value(node_base, "rel_max_lost_particles")); + rel_max_lost_particles = + std::stod(get_node_value(node_base, "rel_max_lost_particles")); + } + + // Get relative number of lost particles + if (check_for_node(node_base, "max_write_lost_particles")) { + max_write_lost_particles = + std::stoi(get_node_value(node_base, "max_write_lost_particles")); } // Get number of inactive batches @@ -164,7 +196,8 @@ void get_run_parameters(pugi::xml_node node_base) n_inactive = std::stoi(get_node_value(node_base, "inactive")); } if (check_for_node(node_base, "generations_per_batch")) { - gen_per_batch = std::stoi(get_node_value(node_base, "generations_per_batch")); + gen_per_batch = + std::stoi(get_node_value(node_base, "generations_per_batch")); } // Preallocate space for keff and entropy by generation @@ -192,8 +225,8 @@ void get_run_parameters(pugi::xml_node node_base) } if (check_for_node(node_keff_trigger, "threshold")) { - keff_trigger.threshold = std::stod(get_node_value( - node_keff_trigger, "threshold")); + keff_trigger.threshold = + std::stod(get_node_value(node_keff_trigger, "threshold")); if (keff_trigger.threshold <= 0) { fatal_error("keff trigger threshold must be positive"); } @@ -202,24 +235,53 @@ void get_run_parameters(pugi::xml_node node_base) } } } + + // Random ray variables + if (solver_type == SolverType::RANDOM_RAY) { + xml_node random_ray_node = node_base.child("random_ray"); + if (check_for_node(random_ray_node, "distance_active")) { + RandomRay::distance_active_ = + std::stod(get_node_value(random_ray_node, "distance_active")); + if (RandomRay::distance_active_ <= 0.0) { + fatal_error("Random ray active distance must be greater than 0"); + } + } else { + fatal_error("Specify random ray active distance in settings XML"); + } + if (check_for_node(random_ray_node, "distance_inactive")) { + RandomRay::distance_inactive_ = + std::stod(get_node_value(random_ray_node, "distance_inactive")); + if (RandomRay::distance_inactive_ < 0) { + fatal_error( + "Random ray inactive distance must be greater than or equal to 0"); + } + } else { + fatal_error("Specify random ray inactive distance in settings XML"); + } + if (check_for_node(random_ray_node, "source")) { + xml_node source_node = random_ray_node.child("source"); + // Get point to list of elements and make sure there is at least + // one + RandomRay::ray_source_ = Source::create(source_node); + } else { + fatal_error("Specify random ray source in settings XML"); + } + } } void read_settings_xml() { using namespace settings; using namespace pugi; - // Check if settings.xml exists - std::string filename = path_input + "settings.xml"; + std::string filename = settings::path_input + "settings.xml"; if (!file_exists(filename)) { if (run_mode != RunMode::PLOTTING) { - fatal_error(fmt::format( - "Settings XML file '{}' does not exist! In order " - "to run OpenMC, you first need a set of input files; at a minimum, this " - "includes settings.xml, geometry.xml, and materials.xml. Please consult " - "the user's guide at https://docs.openmc.org for further " - "information.", filename - )); + fatal_error("Could not find any XML input files! In order to run OpenMC, " + "you first need a set of input files; at a minimum, this " + "includes settings.xml, geometry.xml, and materials.xml or a " + "single model XML file. Please consult the user's guide at " + "https://docs.openmc.org for further information."); } else { // The settings.xml file is optional if we just want to make a plot. return; @@ -241,24 +303,23 @@ void read_settings_xml() verbosity = std::stoi(get_node_value(root, "verbosity")); } - // DAGMC geometry check - if (check_for_node(root, "dagmc")) { - dagmc = get_node_value_bool(root, "dagmc"); - } - -#ifndef DAGMC - if (dagmc) { - fatal_error("DAGMC mode unsupported for this build of OpenMC"); - } -#endif - // To this point, we haven't displayed any output since we didn't know what // the verbosity is. Now that we checked for it, show the title if necessary if (mpi::master) { - if (verbosity >= 2) title(); + if (verbosity >= 2) + title(); } + write_message("Reading settings XML file...", 5); + read_settings_xml(root); +} + +void read_settings_xml(pugi::xml_node root) +{ + using namespace settings; + using namespace pugi; + // Find if a multi-group or continuous-energy simulation is desired if (check_for_node(root, "energy_mode")) { std::string temp_str = get_node_value(root, "energy_mode", true, true); @@ -269,13 +330,17 @@ void read_settings_xml() } } + // Check for user meshes and allocate + read_meshes(root); + // Look for deprecated cross_sections.xml file in settings.xml if (check_for_node(root, "cross_sections")) { - warning("Setting cross_sections in settings.xml has been deprecated." - " The cross_sections are now set in materials.xml and the " - "cross_sections input to materials.xml and the OPENMC_CROSS_SECTIONS" - " environment variable will take precendent over setting " - "cross_sections in settings.xml."); + warning( + "Setting cross_sections in settings.xml has been deprecated." + " The cross_sections are now set in materials.xml and the " + "cross_sections input to materials.xml and the OPENMC_CROSS_SECTIONS" + " environment variable will take precendent over setting " + "cross_sections in settings.xml."); path_cross_sections = get_node_value(root, "cross_sections"); } @@ -300,17 +365,18 @@ void read_settings_xml() trigger_on = get_node_value_bool(node_trigger, "active"); if (trigger_on) { - if (check_for_node(node_trigger, "max_batches") ){ + if (check_for_node(node_trigger, "max_batches")) { n_max_batches = std::stoi(get_node_value(node_trigger, "max_batches")); } else { fatal_error(" must be specified with triggers"); } // Get the batch interval to check triggers - if (!check_for_node(node_trigger, "batch_interval")){ + if (!check_for_node(node_trigger, "batch_interval")) { trigger_predict = true; } else { - trigger_batch_interval = std::stoi(get_node_value(node_trigger, "batch_interval")); + trigger_batch_interval = + std::stoi(get_node_value(node_trigger, "batch_interval")); if (trigger_batch_interval <= 0) { fatal_error("Trigger batch interval must be greater than zero"); } @@ -357,11 +423,20 @@ void read_settings_xml() } } + // Check solver type + if (check_for_node(root, "random_ray")) { + solver_type = SolverType::RANDOM_RAY; + if (run_CE) + fatal_error("multi-group energy mode must be specified in settings XML " + "when using the random ray solver."); + } + if (run_mode == RunMode::EIGENVALUE || run_mode == RunMode::FIXED_SOURCE) { // Read run parameters get_run_parameters(node_mode); - // Check number of active batches, inactive batches, max lost particles and particles + // Check number of active batches, inactive batches, max lost particles and + // particles if (n_batches <= n_inactive) { fatal_error("Number of active batches must be greater than zero."); } else if (n_inactive < 0) { @@ -375,6 +450,12 @@ void read_settings_xml() } } + // Copy plotting random number seed if specified + if (check_for_node(root, "plot_seed")) { + auto seed = std::stoll(get_node_value(root, "plot_seed")); + model::plotter_seed = seed; + } + // Copy random number seed if specified if (check_for_node(root, "seed")) { auto seed = std::stoll(get_node_value(root, "seed")); @@ -399,7 +480,7 @@ void read_settings_xml() if (!run_CE && photon_transport) { fatal_error("Photon transport is not currently supported in " - "multigroup mode"); + "multigroup mode"); } } @@ -408,14 +489,16 @@ void read_settings_xml() n_log_bins = std::stoi(get_node_value(root, "log_grid_bins")); if (n_log_bins < 1) { fatal_error("Number of bins for logarithmic grid must be greater " - "than zero."); + "than zero."); } } // Number of OpenMP threads if (check_for_node(root, "threads")) { - if (mpi::master) warning("The element has been deprecated. Use " - "the OMP_NUM_THREADS environment variable to set the number of threads."); + if (mpi::master) + warning("The element has been deprecated. Use " + "the OMP_NUM_THREADS environment variable to set the number of " + "threads."); } // ========================================================================== @@ -423,23 +506,7 @@ void read_settings_xml() // Get point to list of elements and make sure there is at least one for (pugi::xml_node node : root.children("source")) { - if (check_for_node(node, "file")) { - auto path = get_node_value(node, "file", false, true); - model::external_sources.push_back(make_unique(path)); - } else if (check_for_node(node, "library")) { - // Get shared library path and parameters - auto path = get_node_value(node, "library", false, true); - std::string parameters; - if (check_for_node(node, "parameters")) { - parameters = get_node_value(node, "parameters", false, true); - } - - // Create custom source - model::external_sources.push_back( - make_unique(path, parameters)); - } else { - model::external_sources.push_back(make_unique(node)); - } + model::external_sources.push_back(Source::create(node)); } // Check if the user has specified to read surface source @@ -456,11 +523,15 @@ void read_settings_xml() model::external_sources.push_back(make_unique(path)); } - // If no source specified, default to isotropic point source at origin with Watt spectrum + // If no source specified, default to isotropic point source at origin with + // Watt spectrum if (model::external_sources.empty()) { + double T[] {0.0}; + double p[] {1.0}; model::external_sources.push_back(make_unique( UPtrSpace {new SpatialPoint({0.0, 0.0, 0.0})}, - UPtrAngle {new Isotropic()}, UPtrDist {new Watt(0.988e6, 2.249e-6)})); + UPtrAngle {new Isotropic()}, UPtrDist {new Watt(0.988e6, 2.249e-6)}, + UPtrDist {new Discrete(T, p, 1)})); } // Check if we want to write out source @@ -488,20 +559,36 @@ void read_settings_xml() weight_survive = std::stod(get_node_value(node_cutoff, "weight_avg")); } if (check_for_node(node_cutoff, "energy_neutron")) { - energy_cutoff[0] = std::stod(get_node_value(node_cutoff, "energy_neutron")); + energy_cutoff[0] = + std::stod(get_node_value(node_cutoff, "energy_neutron")); } else if (check_for_node(node_cutoff, "energy")) { warning("The use of an cutoff is deprecated and should " - "be replaced by ."); + "be replaced by ."); energy_cutoff[0] = std::stod(get_node_value(node_cutoff, "energy")); } if (check_for_node(node_cutoff, "energy_photon")) { - energy_cutoff[1] = std::stod(get_node_value(node_cutoff, "energy_photon")); + energy_cutoff[1] = + std::stod(get_node_value(node_cutoff, "energy_photon")); } if (check_for_node(node_cutoff, "energy_electron")) { - energy_cutoff[2] = std::stof(get_node_value(node_cutoff, "energy_electron")); + energy_cutoff[2] = + std::stof(get_node_value(node_cutoff, "energy_electron")); } if (check_for_node(node_cutoff, "energy_positron")) { - energy_cutoff[3] = std::stod(get_node_value(node_cutoff, "energy_positron")); + energy_cutoff[3] = + std::stod(get_node_value(node_cutoff, "energy_positron")); + } + if (check_for_node(node_cutoff, "time_neutron")) { + time_cutoff[0] = std::stod(get_node_value(node_cutoff, "time_neutron")); + } + if (check_for_node(node_cutoff, "time_photon")) { + time_cutoff[1] = std::stod(get_node_value(node_cutoff, "time_photon")); + } + if (check_for_node(node_cutoff, "time_electron")) { + time_cutoff[2] = std::stod(get_node_value(node_cutoff, "time_electron")); + } + if (check_for_node(node_cutoff, "time_positron")) { + time_cutoff[3] = std::stod(get_node_value(node_cutoff, "time_positron")); } } @@ -510,10 +597,10 @@ void read_settings_xml() auto temp = get_node_array(root, "trace"); if (temp.size() != 3) { fatal_error("Must provide 3 integers for that specify the " - "batch, generation, and particle number."); + "batch, generation, and particle number."); } - trace_batch = temp.at(0); - trace_gen = temp.at(1); + trace_batch = temp.at(0); + trace_gen = temp.at(1); trace_particle = temp.at(2); } @@ -522,7 +609,8 @@ void read_settings_xml() // Get values and make sure there are three per particle auto temp = get_node_array(root, "track"); if (temp.size() % 3 != 0) { - fatal_error("Number of integers specified in 'track' is not " + fatal_error( + "Number of integers specified in 'track' is not " "divisible by 3. Please provide 3 integers per particle to be " "tracked."); } @@ -530,14 +618,11 @@ void read_settings_xml() // Reshape into track_identifiers int n_tracks = temp.size() / 3; for (int i = 0; i < n_tracks; ++i) { - track_identifiers.push_back({temp[3*i], temp[3*i + 1], - temp[3*i + 2]}); + track_identifiers.push_back( + {temp[3 * i], temp[3 * i + 1], temp[3 * i + 2]}); } } - // Read meshes - read_meshes(root); - // Shannon Entropy mesh if (check_for_node(root, "entropy_mesh")) { int temp = std::stoi(get_node_value(root, "entropy_mesh")); @@ -546,16 +631,18 @@ void read_settings_xml() "Mesh {} specified for Shannon entropy does not exist.", temp)); } - auto* m = dynamic_cast( - model::meshes[model::mesh_map.at(temp)].get()); - if (!m) fatal_error("Only regular meshes can be used as an entropy mesh"); + auto* m = + dynamic_cast(model::meshes[model::mesh_map.at(temp)].get()); + if (!m) + fatal_error("Only regular meshes can be used as an entropy mesh"); simulation::entropy_mesh = m; // Turn on Shannon entropy calculation entropy_on = true; } else if (check_for_node(root, "entropy")) { - fatal_error("Specifying a Shannon entropy mesh via the element " + fatal_error( + "Specifying a Shannon entropy mesh via the element " "is deprecated. Please create a mesh using and then reference " "it by specifying its ID in an element."); } @@ -565,18 +652,22 @@ void read_settings_xml() auto temp = std::stoi(get_node_value(root, "ufs_mesh")); if (model::mesh_map.find(temp) == model::mesh_map.end()) { fatal_error(fmt::format("Mesh {} specified for uniform fission site " - "method does not exist.", temp)); + "method does not exist.", + temp)); } - auto* m = dynamic_cast(model::meshes[model::mesh_map.at(temp)].get()); - if (!m) fatal_error("Only regular meshes can be used as a UFS mesh"); + auto* m = + dynamic_cast(model::meshes[model::mesh_map.at(temp)].get()); + if (!m) + fatal_error("Only regular meshes can be used as a UFS mesh"); simulation::ufs_mesh = m; // Turn on uniform fission source weighting ufs_on = true; } else if (check_for_node(root, "uniform_fs")) { - fatal_error("Specifying a UFS mesh via the element " + fatal_error( + "Specifying a UFS mesh via the element " "is deprecated. Please create a mesh using and then reference " "it by specifying its ID in a element."); } @@ -628,6 +719,15 @@ void read_settings_xml() if (check_for_node(node_sp, "write")) { source_write = get_node_value_bool(node_sp, "write"); } + if (check_for_node(node_sp, "mcpl")) { + source_mcpl_write = get_node_value_bool(node_sp, "mcpl"); + + // Make sure MCPL support is enabled + if (source_mcpl_write && !MCPL_ENABLED) { + fatal_error( + "Your build of OpenMC does not support writing MCPL source files."); + } + } if (check_for_node(node_sp, "overwrite_latest")) { source_latest = get_node_value_bool(node_sp, "overwrite_latest"); source_separate = source_latest; @@ -655,17 +755,28 @@ void read_settings_xml() // Get maximum number of particles to be banked per surface if (check_for_node(node_ssw, "max_particles")) { - max_surface_particles = std::stoll(get_node_value(node_ssw, "max_particles")); + max_surface_particles = + std::stoll(get_node_value(node_ssw, "max_particles")); + } + if (check_for_node(node_ssw, "mcpl")) { + surf_mcpl_write = get_node_value_bool(node_ssw, "mcpl"); + + // Make sure MCPL support is enabled + if (surf_mcpl_write && !MCPL_ENABLED) { + fatal_error("Your build of OpenMC does not support writing MCPL " + "surface source files."); + } } } - // If source is not seperate and is to be written out in the statepoint file, + // If source is not separate and is to be written out in the statepoint file, // make sure that the sourcepoint batch numbers are contained in the // statepoint list if (!source_separate) { for (const auto& b : sourcepoint_batch) { if (!contains(statepoint_batch, b)) { - fatal_error("Sourcepoint batches are not a subset of statepoint batches."); + fatal_error( + "Sourcepoint batches are not a subset of statepoint batches."); } } } @@ -725,14 +836,15 @@ void read_settings_xml() } else if (temp == "dbrc") { res_scat_method = ResScatMethod::dbrc; } else { - fatal_error("Unrecognized resonance elastic scattering method: " - + temp + "."); + fatal_error( + "Unrecognized resonance elastic scattering method: " + temp + "."); } } // Minimum energy for resonance scattering if (check_for_node(node_res_scat, "energy_min")) { - res_scat_energy_min = std::stod(get_node_value(node_res_scat, "energy_min")); + res_scat_energy_min = + std::stod(get_node_value(node_res_scat, "energy_min")); } if (res_scat_energy_min < 0.0) { fatal_error("Lower resonance scattering energy bound is negative"); @@ -740,16 +852,18 @@ void read_settings_xml() // Maximum energy for resonance scattering if (check_for_node(node_res_scat, "energy_max")) { - res_scat_energy_max = std::stod(get_node_value(node_res_scat, "energy_max")); + res_scat_energy_max = + std::stod(get_node_value(node_res_scat, "energy_max")); } if (res_scat_energy_max < res_scat_energy_min) { fatal_error("Upper resonance scattering energy bound is below the " - "lower resonance scattering energy bound."); + "lower resonance scattering energy bound."); } // Get resonance scattering nuclides if (check_for_node(node_res_scat, "nuclides")) { - res_scat_nuclides = get_node_array(node_res_scat, "nuclides"); + res_scat_nuclides = + get_node_array(node_res_scat, "nuclides"); } } @@ -760,7 +874,8 @@ void read_settings_xml() // Get temperature settings if (check_for_node(root, "temperature_default")) { - temperature_default = std::stod(get_node_value(root, "temperature_default")); + temperature_default = + std::stod(get_node_value(root, "temperature_default")); } if (check_for_node(root, "temperature_method")) { auto temp = get_node_value(root, "temperature_method", true, true); @@ -773,10 +888,17 @@ void read_settings_xml() } } if (check_for_node(root, "temperature_tolerance")) { - temperature_tolerance = std::stod(get_node_value(root, "temperature_tolerance")); + temperature_tolerance = + std::stod(get_node_value(root, "temperature_tolerance")); } if (check_for_node(root, "temperature_multipole")) { temperature_multipole = get_node_value_bool(root, "temperature_multipole"); + + // Multipole currently doesn't work with photon transport + if (temperature_multipole && photon_transport) { + fatal_error("Multipole data cannot currently be used in conjunction with " + "photon transport."); + } } if (check_for_node(root, "temperature_range")) { auto range = get_node_array(root, "temperature_range"); @@ -796,25 +918,34 @@ void read_settings_xml() // Check for the number of points if (check_for_node(node_tab_leg, "num_points")) { - legendre_to_tabular_points = std::stoi(get_node_value( - node_tab_leg, "num_points")); + legendre_to_tabular_points = + std::stoi(get_node_value(node_tab_leg, "num_points")); if (legendre_to_tabular_points <= 1 && !run_CE) { - fatal_error("The 'num_points' subelement/attribute of the " + fatal_error( + "The 'num_points' subelement/attribute of the " " element must contain a value greater than 1"); } } } + // Check whether create delayed neutrons in fission + if (check_for_node(root, "create_delayed_neutrons")) { + create_delayed_neutrons = + get_node_value_bool(root, "create_delayed_neutrons"); + } + // Check whether create fission sites if (run_mode == RunMode::FIXED_SOURCE) { if (check_for_node(root, "create_fission_neutrons")) { - create_fission_neutrons = get_node_value_bool(root, "create_fission_neutrons"); + create_fission_neutrons = + get_node_value_bool(root, "create_fission_neutrons"); } } // Check whether to scale fission photon yields if (check_for_node(root, "delayed_photon_scaling")) { - delayed_photon_scaling = get_node_value_bool(root, "delayed_photon_scaling"); + delayed_photon_scaling = + get_node_value_bool(root, "delayed_photon_scaling"); } // Check whether to use event-based parallelism @@ -826,9 +957,70 @@ void read_settings_xml() if (check_for_node(root, "material_cell_offsets")) { material_cell_offsets = get_node_value_bool(root, "material_cell_offsets"); } + + // Weight window information + for (pugi::xml_node node_ww : root.children("weight_windows")) { + variance_reduction::weight_windows.emplace_back( + std::make_unique(node_ww)); + } + + // Enable weight windows by default if one or more are present + if (variance_reduction::weight_windows.size() > 0) + settings::weight_windows_on = true; + + // read weight windows from file + if (check_for_node(root, "weight_windows_file")) { + weight_windows_file = get_node_value(root, "weight_windows_file"); + } + + // read settings for weight windows value, this will override + // the automatic setting even if weight windows are present + if (check_for_node(root, "weight_windows_on")) { + weight_windows_on = get_node_value_bool(root, "weight_windows_on"); + } + + if (check_for_node(root, "max_splits")) { + settings::max_splits = std::stoi(get_node_value(root, "max_splits")); + } + + if (check_for_node(root, "max_tracks")) { + settings::max_tracks = std::stoi(get_node_value(root, "max_tracks")); + } + + // Create weight window generator objects + if (check_for_node(root, "weight_window_generators")) { + auto wwgs_node = root.child("weight_window_generators"); + for (pugi::xml_node node_wwg : + wwgs_node.children("weight_windows_generator")) { + variance_reduction::weight_windows_generators.emplace_back( + std::make_unique(node_wwg)); + } + // if any of the weight windows are intended to be generated otf, make sure + // they're applied + for (const auto& wwg : variance_reduction::weight_windows_generators) { + if (wwg->on_the_fly_) { + settings::weight_windows_on = true; + break; + } + } + } + + // Set up weight window checkpoints + if (check_for_node(root, "weight_window_checkpoints")) { + xml_node ww_checkpoints = root.child("weight_window_checkpoints"); + if (check_for_node(ww_checkpoints, "collision")) { + weight_window_checkpoint_collision = + get_node_value_bool(ww_checkpoints, "collision"); + } + if (check_for_node(ww_checkpoints, "surface")) { + weight_window_checkpoint_surface = + get_node_value_bool(ww_checkpoints, "surface"); + } + } } -void free_memory_settings() { +void free_memory_settings() +{ settings::statepoint_batch.clear(); settings::sourcepoint_batch.clear(); settings::source_write_surf_id.clear(); @@ -839,9 +1031,8 @@ void free_memory_settings() { // C API functions //============================================================================== -extern "C" int -openmc_set_n_batches(int32_t n_batches, bool set_max_batches, - bool add_statepoint_batch) +extern "C" int openmc_set_n_batches( + int32_t n_batches, bool set_max_batches, bool add_statepoint_batch) { if (settings::n_inactive >= n_batches) { set_errmsg("Number of active batches must be greater than zero."); @@ -879,8 +1070,7 @@ openmc_set_n_batches(int32_t n_batches, bool set_max_batches, return 0; } -extern "C" int -openmc_get_n_batches(int* n_batches, bool get_max_batches) +extern "C" int openmc_get_n_batches(int* n_batches, bool get_max_batches) { *n_batches = get_max_batches ? settings::n_max_batches : settings::n_batches; diff --git a/src/simulation.cpp b/src/simulation.cpp index e6de68b7e44..527d98db4f1 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -8,6 +8,7 @@ #include "openmc/event.h" #include "openmc/geometry_aux.h" #include "openmc/material.h" +#include "openmc/mcpl_interface.h" #include "openmc/message_passing.h" #include "openmc/nuclide.h" #include "openmc/output.h" @@ -17,12 +18,13 @@ #include "openmc/settings.h" #include "openmc/source.h" #include "openmc/state_point.h" -#include "openmc/timer.h" #include "openmc/tallies/derivative.h" #include "openmc/tallies/filter.h" #include "openmc/tallies/tally.h" #include "openmc/tallies/trigger.h" +#include "openmc/timer.h" #include "openmc/track_output.h" +#include "openmc/weight_windows.h" #ifdef _OPENMP #include @@ -39,22 +41,27 @@ #include #include - //============================================================================== // C API functions //============================================================================== // OPENMC_RUN encompasses all the main logic where iterations are performed -// over the batches, generations, and histories in a fixed source or k-eigenvalue -// calculation. +// over the batches, generations, and histories in a fixed source or +// k-eigenvalue calculation. int openmc_run() { openmc::simulation::time_total.start(); openmc_simulation_init(); - int err = 0; + // Ensure that a batch isn't executed in the case that the maximum number of + // batches has already been run in a restart statepoint file int status = 0; + if (openmc::simulation::current_batch >= openmc::settings::n_max_batches) { + status = openmc::STATUS_EXIT_MAX_BATCH; + } + + int err = 0; while (status == 0 && err == 0) { err = openmc_next_batch(&status); } @@ -69,7 +76,8 @@ int openmc_simulation_init() using namespace openmc; // Skip if simulation has already been initialized - if (simulation::initialized) return 0; + if (simulation::initialized) + return 0; // Initialize nuclear data (energy limits, log grid) if (settings::run_CE) { @@ -82,16 +90,22 @@ int openmc_simulation_init() // Allocate source, fission and surface source banks. allocate_banks(); + // Create track file if needed + if (!settings::track_identifiers.empty() || settings::write_all_tracks) { + open_track_file(); + } + // If doing an event-based simulation, intialize the particle buffer // and event queues if (settings::event_based) { - int64_t event_buffer_length = std::min(simulation::work_per_rank, - settings::max_particles_in_flight); + int64_t event_buffer_length = + std::min(simulation::work_per_rank, settings::max_particles_in_flight); init_event_queues(event_buffer_length); } // Allocate tally results arrays if they're not allocated yet for (auto& t : model::tallies) { + t->set_strides(); t->init_results(); } @@ -114,7 +128,8 @@ int openmc_simulation_init() write_message("Resuming simulation...", 6); } else { // Only initialize primary source bank for eigenvalue simulations - if (settings::run_mode == RunMode::EIGENVALUE) { + if (settings::run_mode == RunMode::EIGENVALUE && + settings::solver_type == SolverType::MONTE_CARLO) { initialize_source(); } } @@ -124,11 +139,21 @@ int openmc_simulation_init() if (settings::run_mode == RunMode::FIXED_SOURCE) { header("FIXED SOURCE TRANSPORT SIMULATION", 3); } else if (settings::run_mode == RunMode::EIGENVALUE) { - header("K EIGENVALUE SIMULATION", 3); - if (settings::verbosity >= 7) print_columns(); + if (settings::solver_type == SolverType::MONTE_CARLO) { + header("K EIGENVALUE SIMULATION", 3); + } else if (settings::solver_type == SolverType::RANDOM_RAY) { + header("K EIGENVALUE SIMULATION (RANDOM RAY SOLVER)", 3); + } + if (settings::verbosity >= 7) + print_columns(); } } + // load weight windows from file + if (!settings::weight_windows_file.empty()) { + openmc_weight_windows_import(settings::weight_windows_file.c_str()); + } + // Set flag indicating initialization is done simulation::initialized = true; return 0; @@ -139,7 +164,8 @@ int openmc_simulation_finalize() using namespace openmc; // Skip if simulation was never run - if (!simulation::initialized) return 0; + if (!simulation::initialized) + return 0; // Stop active batch timer and start finalization timer simulation::time_active.stop(); @@ -150,15 +176,27 @@ int openmc_simulation_finalize() mat->mat_nuclide_index_.clear(); } + // Close track file if open + if (!settings::track_identifiers.empty() || settings::write_all_tracks) { + close_track_file(); + } + // Increment total number of generations - simulation::total_gen += simulation::current_batch*settings::gen_per_batch; + simulation::total_gen += simulation::current_batch * settings::gen_per_batch; #ifdef OPENMC_MPI broadcast_results(); #endif // Write tally results to tallies.out - if (settings::output_tallies && mpi::master) write_tallies(); + if (settings::output_tallies && mpi::master) + write_tallies(); + + // If weight window generators are present in this simulation, + // write a weight windows file + if (variance_reduction::weight_windows_generators.size() > 0) { + openmc_weight_windows_export(); + } // Deactivate all tallies for (auto& t : model::tallies) { @@ -169,10 +207,15 @@ int openmc_simulation_finalize() simulation::time_finalize.stop(); simulation::time_total.stop(); if (mpi::master) { - if (settings::verbosity >= 6) print_runtime(); - if (settings::verbosity >= 4) print_results(); + if (settings::solver_type != SolverType::RANDOM_RAY) { + if (settings::verbosity >= 6) + print_runtime(); + if (settings::verbosity >= 4) + print_results(); + } } - if (settings::check_overlaps) print_overlap_check(); + if (settings::check_overlaps) + print_overlap_check(); // Reset flags simulation::initialized = false; @@ -218,7 +261,7 @@ int openmc_next_batch(int* status) // Check simulation ending criteria if (status) { - if (simulation::current_batch == settings::n_max_batches) { + if (simulation::current_batch >= settings::n_max_batches) { *status = STATUS_EXIT_MAX_BATCH; } else if (simulation::satisfy_triggers) { *status = STATUS_EXIT_ON_TRIGGER; @@ -229,7 +272,8 @@ int openmc_next_batch(int* status) return 0; } -bool openmc_is_statepoint_batch() { +bool openmc_is_statepoint_batch() +{ using namespace openmc; using openmc::simulation::current_gen; @@ -278,19 +322,19 @@ vector work_index; void allocate_banks() { - if (settings::run_mode == RunMode::EIGENVALUE) { + if (settings::run_mode == RunMode::EIGENVALUE && + settings::solver_type == SolverType::MONTE_CARLO) { // Allocate source bank simulation::source_bank.resize(simulation::work_per_rank); // Allocate fission bank - init_fission_bank(3*simulation::work_per_rank); + init_fission_bank(3 * simulation::work_per_rank); } if (settings::surf_source_write) { // Allocate surface source bank simulation::surf_source_bank.reserve(settings::max_surface_particles); } - } void initialize_batch() @@ -311,7 +355,7 @@ void initialize_batch() if (!settings::restart_run) { first_inactive = settings::n_inactive > 0 && simulation::current_batch == 1; first_active = simulation::current_batch == settings::n_inactive + 1; - } else if (simulation::current_batch == simulation::restart_batch + 1){ + } else if (simulation::current_batch == simulation::restart_batch + 1) { first_inactive = simulation::restart_batch < settings::n_inactive; first_active = !first_inactive; } @@ -338,6 +382,11 @@ void finalize_batch() accumulate_tallies(); simulation::time_tallies.stop(); + // update weight windows if needed + for (const auto& wwg : variance_reduction::weight_windows_generators) { + wwg->update(); + } + // Reset global tally results if (simulation::current_batch <= settings::n_inactive) { xt::view(simulation::global_tallies, xt::all()) = 0.0; @@ -345,21 +394,23 @@ void finalize_batch() } // Check_triggers - if (mpi::master) check_triggers(); + if (mpi::master) + check_triggers(); #ifdef OPENMC_MPI MPI_Bcast(&simulation::satisfy_triggers, 1, MPI_C_BOOL, 0, mpi::intracomm); #endif - if (simulation::satisfy_triggers || (settings::trigger_on && - simulation::current_batch == settings::n_max_batches)) { + if (simulation::satisfy_triggers || + (settings::trigger_on && + simulation::current_batch == settings::n_max_batches)) { settings::statepoint_batch.insert(simulation::current_batch); } // Write out state point if it's been specified for this batch and is not // a CMFD run instance - if (contains(settings::statepoint_batch, simulation::current_batch) - && !settings::cmfd_run) { - if (contains(settings::sourcepoint_batch, simulation::current_batch) - && settings::source_write && !settings::source_separate) { + if (contains(settings::statepoint_batch, simulation::current_batch) && + !settings::cmfd_run) { + if (contains(settings::sourcepoint_batch, simulation::current_batch) && + settings::source_write && !settings::source_separate) { bool b = (settings::run_mode == RunMode::EIGENVALUE); openmc_statepoint_write(nullptr, &b); } else { @@ -370,22 +421,51 @@ void finalize_batch() if (settings::run_mode == RunMode::EIGENVALUE) { // Write out a separate source point if it's been specified for this batch - if (contains(settings::sourcepoint_batch, simulation::current_batch) - && settings::source_write && settings::source_separate) { - write_source_point(nullptr); + if (contains(settings::sourcepoint_batch, simulation::current_batch) && + settings::source_write && settings::source_separate) { + + // Determine width for zero padding + int w = std::to_string(settings::n_max_batches).size(); + std::string source_point_filename = fmt::format("{0}source.{1:0{2}}", + settings::path_output, simulation::current_batch, w); + gsl::span bankspan(simulation::source_bank); + if (settings::source_mcpl_write) { + write_mcpl_source_point( + source_point_filename.c_str(), bankspan, simulation::work_index); + } else { + write_source_point( + source_point_filename.c_str(), bankspan, simulation::work_index); + } } // Write a continously-overwritten source point if requested. if (settings::source_latest) { - auto filename = settings::path_output + "source.h5"; - write_source_point(filename.c_str()); + + // note: correct file extension appended automatically + auto filename = settings::path_output + "source"; + gsl::span bankspan(simulation::source_bank); + if (settings::source_mcpl_write) { + write_mcpl_source_point( + filename.c_str(), bankspan, simulation::work_index); + } else { + write_source_point(filename.c_str(), bankspan, simulation::work_index); + } } } // Write out surface source if requested. - if (settings::surf_source_write && simulation::current_batch == settings::n_batches) { - auto filename = settings::path_output + "surface_source.h5"; - write_source_point(filename.c_str(), true); + if (settings::surf_source_write && + simulation::current_batch == settings::n_batches) { + auto filename = settings::path_output + "surface_source"; + auto surf_work_index = + mpi::calculate_parallel_index_vector(simulation::surf_source_bank.size()); + gsl::span surfbankspan(simulation::surf_source_bank.begin(), + simulation::surf_source_bank.size()); + if (settings::surf_mcpl_write) { + write_mcpl_source_point(filename.c_str(), surfbankspan, surf_work_index); + } else { + write_source_point(filename.c_str(), surfbankspan, surf_work_index); + } } } @@ -396,7 +476,8 @@ void initialize_generation() simulation::fission_bank.resize(0); // Count source sites if using uniform fission source weighting - if (settings::ufs_on) ufs_count_sites(); + if (settings::ufs_on) + ufs_count_sites(); // Store current value of tracklength k simulation::keff_generation = simulation::global_tallies( @@ -411,8 +492,10 @@ void finalize_generation() // Update global tallies with the accumulation variables if (settings::run_mode == RunMode::EIGENVALUE) { gt(GlobalTally::K_COLLISION, TallyResult::VALUE) += global_tally_collision; - gt(GlobalTally::K_ABSORPTION, TallyResult::VALUE) += global_tally_absorption; - gt(GlobalTally::K_TRACKLENGTH, TallyResult::VALUE) += global_tally_tracklength; + gt(GlobalTally::K_ABSORPTION, TallyResult::VALUE) += + global_tally_absorption; + gt(GlobalTally::K_TRACKLENGTH, TallyResult::VALUE) += + global_tally_tracklength; } gt(GlobalTally::LEAKAGE, TallyResult::VALUE) += global_tally_leakage; @@ -424,7 +507,8 @@ void finalize_generation() } global_tally_leakage = 0.0; - if (settings::run_mode == RunMode::EIGENVALUE) { + if (settings::run_mode == RunMode::EIGENVALUE && + settings::solver_type == SolverType::MONTE_CARLO) { // If using shared memory, stable sort the fission bank (by parent IDs) // so as to allow for reproducibility regardless of which order particles // are run in. @@ -432,9 +516,13 @@ void finalize_generation() // Distribute fission bank across processors evenly synchronize_bank(); + } + + if (settings::run_mode == RunMode::EIGENVALUE) { // Calculate shannon entropy - if (settings::entropy_on) shannon_entropy(); + if (settings::entropy_on) + shannon_entropy(); // Collect results and statistics calculate_generation_keff(); @@ -444,7 +532,6 @@ void finalize_generation() if (mpi::master && settings::verbosity >= 7) { print_generation(); } - } } @@ -456,8 +543,9 @@ void initialize_history(Particle& p, int64_t index_source) p.from_source(&simulation::source_bank[index_source - 1]); } else if (settings::run_mode == RunMode::FIXED_SOURCE) { // initialize random number seed - int64_t id = (simulation::total_gen + overall_generation() - 1)*settings::n_particles + - simulation::work_index[mpi::rank] + index_source; + int64_t id = (simulation::total_gen + overall_generation() - 1) * + settings::n_particles + + simulation::work_index[mpi::rank] + index_source; uint64_t seed = init_seed(id, STREAM_SOURCE); // sample from external source distribution or custom library then set auto site = sample_external_source(&seed); @@ -474,6 +562,15 @@ void initialize_history(Particle& p, int64_t index_source) // Reset particle event counter p.n_event() = 0; + // Reset split counter + p.n_split() = 0; + + // Reset weight window ratio + p.ww_factor() = 0.0; + + // Reset pulse_height_storage + std::fill(p.pht_storage().begin(), p.pht_storage().end(), 0); + // set random number seed int64_t particle_seed = (simulation::total_gen + overall_generation() - 1) * settings::n_particles + @@ -488,26 +585,15 @@ void initialize_history(Particle& p, int64_t index_source) p.trace() = true; // Set particle track. - p.write_track() = false; - if (settings::write_all_tracks) { - p.write_track() = true; - } else if (settings::track_identifiers.size() > 0) { - for (const auto& t : settings::track_identifiers) { - if (simulation::current_batch == t[0] && - simulation::current_gen == t[1] && p.id() == t[2]) { - p.write_track() = true; - break; - } - } - } + p.write_track() = check_track_criteria(p); // Display message if high verbosity or trace is on if (settings::verbosity >= 9 || p.trace()) { write_message("Simulating Particle {}", p.id()); } - // Add paricle's starting weight to count for normalizing tallies later - #pragma omp atomic +// Add paricle's starting weight to count for normalizing tallies later +#pragma omp atomic simulation::total_weight += p.wgt(); // Force calculation of cross-sections by setting last energy to zero @@ -523,7 +609,7 @@ void initialize_history(Particle& p, int64_t index_source) int overall_generation() { using namespace simulation; - return settings::gen_per_batch*(current_batch - 1) + current_gen; + return settings::gen_per_batch * (current_batch - 1) + current_gen; } void calculate_work() @@ -542,7 +628,8 @@ void calculate_work() int64_t work_i = i < remainder ? min_work + 1 : min_work; // Set number of particles - if (mpi::rank == i) simulation::work_per_rank = work_i; + if (mpi::rank == i) + simulation::work_per_rank = work_i; // Set index into source bank for rank i i_bank += work_i; @@ -558,10 +645,10 @@ void initialize_data() for (const auto& nuc : data::nuclides) { if (nuc->grid_.size() >= 1) { int neutron = static_cast(ParticleType::neutron); - data::energy_min[neutron] = std::max(data::energy_min[neutron], - nuc->grid_[0].energy.front()); - data::energy_max[neutron] = std::min(data::energy_max[neutron], - nuc->grid_[0].energy.back()); + data::energy_min[neutron] = + std::max(data::energy_min[neutron], nuc->grid_[0].energy.front()); + data::energy_max[neutron] = + std::min(data::energy_max[neutron], nuc->grid_[0].energy.back()); } } @@ -570,10 +657,10 @@ void initialize_data() if (elem->energy_.size() >= 1) { int photon = static_cast(ParticleType::photon); int n = elem->energy_.size(); - data::energy_min[photon] = std::max(data::energy_min[photon], - std::exp(elem->energy_(1))); - data::energy_max[photon] = std::min(data::energy_max[photon], - std::exp(elem->energy_(n - 1))); + data::energy_min[photon] = + std::max(data::energy_min[photon], std::exp(elem->energy_(1))); + data::energy_max[photon] = + std::min(data::energy_max[photon], std::exp(elem->energy_(n - 1))); } } @@ -583,10 +670,10 @@ void initialize_data() if (data::ttb_e_grid.size() >= 1) { int photon = static_cast(ParticleType::photon); int n_e = data::ttb_e_grid.size(); - data::energy_min[photon] = std::max(data::energy_min[photon], - std::exp(data::ttb_e_grid(1))); - data::energy_max[photon] = std::min(data::energy_max[photon], - std::exp(data::ttb_e_grid(n_e - 1))); + data::energy_min[photon] = + std::max(data::energy_min[photon], std::exp(data::ttb_e_grid(1))); + data::energy_max[photon] = std::min( + data::energy_max[photon], std::exp(data::ttb_e_grid(n_e - 1))); } } } @@ -603,7 +690,7 @@ void initialize_data() data::energy_max[neutron], nuc->name_); if (mpi::master && data::energy_max[neutron] < 20.0e6) { warning("Maximum neutron energy is below 20 MeV. This may bias " - "the results."); + "the results."); } break; } @@ -615,12 +702,14 @@ void initialize_data() nuc->init_grid(); } int neutron = static_cast(ParticleType::neutron); - simulation::log_spacing = std::log(data::energy_max[neutron] / - data::energy_min[neutron]) / settings::n_log_bins; + simulation::log_spacing = + std::log(data::energy_max[neutron] / data::energy_min[neutron]) / + settings::n_log_bins; } #ifdef OPENMC_MPI -void broadcast_results() { +void broadcast_results() +{ // Broadcast tally results so that each process has access to results for (auto& t : model::tallies) { // Create a new datatype that consists of all values for a given filter @@ -643,8 +732,8 @@ void broadcast_results() { // These guys are needed so that non-master processes can calculate the // combined estimate of k-effective - double temp[] {simulation::k_col_abs, simulation::k_col_tra, - simulation::k_abs_tra}; + double temp[] { + simulation::k_col_abs, simulation::k_col_tra, simulation::k_abs_tra}; MPI_Bcast(temp, 3, MPI_DOUBLE, 0, mpi::intracomm); simulation::k_col_abs = temp[0]; simulation::k_col_tra = temp[1]; @@ -661,8 +750,10 @@ void free_memory_simulation() void transport_history_based_single_particle(Particle& p) { - while (true) { + while (p.alive()) { p.event_calculate_xs(); + if (!p.alive()) + break; p.event_advance(); if (p.collision_distance() > p.boundary().distance) { p.event_cross_surface(); @@ -670,15 +761,13 @@ void transport_history_based_single_particle(Particle& p) p.event_collide(); } p.event_revive_from_secondary(); - if (!p.alive()) - break; } p.event_death(); } void transport_history_based() { - #pragma omp parallel for schedule(runtime) +#pragma omp parallel for schedule(runtime) for (int64_t i_work = 1; i_work <= simulation::work_per_rank; ++i_work) { Particle p; initialize_history(p, i_work); @@ -698,7 +787,8 @@ void transport_event_based() // loop is executed multiple times until all particles have been completed. while (remaining_work > 0) { // Figure out # of particles to run for this subiteration - int64_t n_particles = std::min(remaining_work, settings::max_particles_in_flight); + int64_t n_particles = + std::min(remaining_work, settings::max_particles_in_flight); // Initialize all particle histories for this subiteration process_init_events(n_particles, source_offset); @@ -706,8 +796,7 @@ void transport_event_based() // Event-based transport loop while (true) { // Determine which event kernel has the longest queue - int64_t max = std::max({ - simulation::calculate_fuel_xs_queue.size(), + int64_t max = std::max({simulation::calculate_fuel_xs_queue.size(), simulation::calculate_nonfuel_xs_queue.size(), simulation::advance_particle_queue.size(), simulation::surface_crossing_queue.size(), diff --git a/src/source.cpp b/src/source.cpp index 909e871255e..405de998c89 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -1,6 +1,6 @@ #include "openmc/source.h" -#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__)) +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #define HAS_DYNAMIC_LINKING #endif @@ -10,16 +10,19 @@ #include // for dlopen, dlsym, dlclose, dlerror #endif -#include #include "xtensor/xadapt.hpp" +#include #include "openmc/bank.h" #include "openmc/capi.h" #include "openmc/cell.h" +#include "openmc/container_util.h" #include "openmc/error.h" #include "openmc/file_utils.h" +#include "openmc/geometry.h" #include "openmc/hdf5_interface.h" #include "openmc/material.h" +#include "openmc/mcpl_interface.h" #include "openmc/memory.h" #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" @@ -29,6 +32,7 @@ #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/state_point.h" +#include "openmc/string_utils.h" #include "openmc/xml_interface.h" namespace openmc { @@ -42,14 +46,221 @@ namespace model { vector> external_sources; } +//============================================================================== +// Source implementation +//============================================================================== + +Source::Source(pugi::xml_node node) +{ + // Check for source strength + if (check_for_node(node, "strength")) { + strength_ = std::stod(get_node_value(node, "strength")); + if (strength_ < 0.0) { + fatal_error("Source strength is negative."); + } + } + + // Check for additional defined constraints + read_constraints(node); +} + +unique_ptr Source::create(pugi::xml_node node) +{ + // if the source type is present, use it to determine the type + // of object to create + if (check_for_node(node, "type")) { + std::string source_type = get_node_value(node, "type"); + if (source_type == "independent") { + return make_unique(node); + } else if (source_type == "file") { + return make_unique(node); + } else if (source_type == "compiled") { + return make_unique(node); + } else if (source_type == "mesh") { + return make_unique(node); + } else { + fatal_error(fmt::format("Invalid source type '{}' found.", source_type)); + } + } else { + // support legacy source format + if (check_for_node(node, "file")) { + return make_unique(node); + } else if (check_for_node(node, "library")) { + return make_unique(node); + } else { + return make_unique(node); + } + } +} + +void Source::read_constraints(pugi::xml_node node) +{ + // Check for constraints node. For backwards compatibility, if no constraints + // node is given, still try searching for domain constraints from top-level + // node. + pugi::xml_node constraints_node = node.child("constraints"); + if (constraints_node) { + node = constraints_node; + } + + // Check for domains to reject from + if (check_for_node(node, "domain_type")) { + std::string domain_type = get_node_value(node, "domain_type"); + if (domain_type == "cell") { + domain_type_ = DomainType::CELL; + } else if (domain_type == "material") { + domain_type_ = DomainType::MATERIAL; + } else if (domain_type == "universe") { + domain_type_ = DomainType::UNIVERSE; + } else { + fatal_error( + std::string("Unrecognized domain type for constraint: " + domain_type)); + } + + auto ids = get_node_array(node, "domain_ids"); + domain_ids_.insert(ids.begin(), ids.end()); + } + + if (check_for_node(node, "time_bounds")) { + auto ids = get_node_array(node, "time_bounds"); + if (ids.size() != 2) { + fatal_error("Time bounds must be represented by two numbers."); + } + time_bounds_ = std::make_pair(ids[0], ids[1]); + } + if (check_for_node(node, "energy_bounds")) { + auto ids = get_node_array(node, "energy_bounds"); + if (ids.size() != 2) { + fatal_error("Energy bounds must be represented by two numbers."); + } + energy_bounds_ = std::make_pair(ids[0], ids[1]); + } + + if (check_for_node(node, "fissionable")) { + only_fissionable_ = get_node_value_bool(node, "fissionable"); + } + + // Check for how to handle rejected particles + if (check_for_node(node, "rejection_strategy")) { + std::string rejection_strategy = get_node_value(node, "rejection_strategy"); + if (rejection_strategy == "kill") { + rejection_strategy_ = RejectionStrategy::KILL; + } else if (rejection_strategy == "resample") { + rejection_strategy_ = RejectionStrategy::RESAMPLE; + } else { + fatal_error(std::string( + "Unrecognized strategy source rejection: " + rejection_strategy)); + } + } +} + +SourceSite Source::sample_with_constraints(uint64_t* seed) const +{ + bool accepted = false; + static int n_reject = 0; + static int n_accept = 0; + SourceSite site; + + while (!accepted) { + // Sample a source site without considering constraints yet + site = this->sample(seed); + + if (constraints_applied()) { + accepted = true; + } else { + // Check whether sampled site satisfies constraints + accepted = satisfies_spatial_constraints(site.r) && + satisfies_energy_constraints(site.E) && + satisfies_time_constraints(site.time); + if (!accepted) { + ++n_reject; + if (n_reject >= EXTSRC_REJECT_THRESHOLD && + static_cast(n_accept) / n_reject <= + EXTSRC_REJECT_FRACTION) { + fatal_error("More than 95% of external source sites sampled were " + "rejected. Please check your source definition."); + } + + // For the "kill" strategy, accept particle but set weight to 0 so that + // it is terminated immediately + if (rejection_strategy_ == RejectionStrategy::KILL) { + accepted = true; + site.wgt = 0.0; + } + } + } + } + + // Increment number of accepted samples + ++n_accept; + + return site; +} + +bool Source::satisfies_energy_constraints(double E) const +{ + return E > energy_bounds_.first && E < energy_bounds_.second; +} + +bool Source::satisfies_time_constraints(double time) const +{ + return time > time_bounds_.first && time < time_bounds_.second; +} + +bool Source::satisfies_spatial_constraints(Position r) const +{ + GeometryState geom_state; + geom_state.r() = r; + + // Reject particle if it's not in the geometry at all + bool found = exhaustive_find_cell(geom_state); + if (!found) + return false; + + // Check the geometry state against specified domains + bool accepted = true; + if (!domain_ids_.empty()) { + if (domain_type_ == DomainType::MATERIAL) { + auto mat_index = geom_state.material(); + if (mat_index != MATERIAL_VOID) { + accepted = contains(domain_ids_, model::materials[mat_index]->id()); + } + } else { + for (int i = 0; i < geom_state.n_coord(); i++) { + auto id = (domain_type_ == DomainType::CELL) + ? model::cells[geom_state.coord(i).cell]->id_ + : model::universes[geom_state.coord(i).universe]->id_; + if ((accepted = contains(domain_ids_, id))) + break; + } + } + } + + // Check if spatial site is in fissionable material + if (accepted && only_fissionable_) { + // Determine material + auto mat_index = geom_state.material(); + if (mat_index == MATERIAL_VOID) { + accepted = false; + } else { + accepted = model::materials[mat_index]->fissionable(); + } + } + + return accepted; +} + //============================================================================== // IndependentSource implementation //============================================================================== -IndependentSource::IndependentSource(UPtrSpace space, UPtrAngle angle, UPtrDist energy) - : space_{std::move(space)}, angle_{std::move(angle)}, energy_{std::move(energy)} { } +IndependentSource::IndependentSource( + UPtrSpace space, UPtrAngle angle, UPtrDist energy, UPtrDist time) + : space_ {std::move(space)}, angle_ {std::move(angle)}, + energy_ {std::move(energy)}, time_ {std::move(time)} +{} -IndependentSource::IndependentSource(pugi::xml_node node) +IndependentSource::IndependentSource(pugi::xml_node node) : Source(node) { // Check for particle type if (check_for_node(node, "particle")) { @@ -64,11 +275,6 @@ IndependentSource::IndependentSource(pugi::xml_node node) } } - // Check for source strength - if (check_for_node(node, "strength")) { - strength_ = std::stod(get_node_value(node, "strength")); - } - // Check for external source file if (check_for_node(node, "file")) { @@ -76,57 +282,26 @@ IndependentSource::IndependentSource(pugi::xml_node node) // Spatial distribution for external source if (check_for_node(node, "space")) { - // Get pointer to spatial distribution - pugi::xml_node node_space = node.child("space"); - - // Check for type of spatial distribution and read - std::string type; - if (check_for_node(node_space, "type")) - type = get_node_value(node_space, "type", true, true); - if (type == "cartesian") { - space_ = UPtrSpace{new CartesianIndependent(node_space)}; - } else if (type == "cylindrical") { - space_ = UPtrSpace{new CylindricalIndependent(node_space)}; - } else if (type == "spherical") { - space_ = UPtrSpace{new SphericalIndependent(node_space)}; - } else if (type == "box") { - space_ = UPtrSpace{new SpatialBox(node_space)}; - } else if (type == "fission") { - space_ = UPtrSpace{new SpatialBox(node_space, true)}; - } else if (type == "point") { - space_ = UPtrSpace{new SpatialPoint(node_space)}; - } else { - fatal_error(fmt::format( - "Invalid spatial distribution for external source: {}", type)); - } - + space_ = SpatialDistribution::create(node.child("space")); } else { // If no spatial distribution specified, make it a point source - space_ = UPtrSpace{new SpatialPoint()}; + space_ = UPtrSpace {new SpatialPoint()}; } - // Determine external source angular distribution - if (check_for_node(node, "angle")) { - // Get pointer to angular distribution - pugi::xml_node node_angle = node.child("angle"); - - // Check for type of angular distribution - std::string type; - if (check_for_node(node_angle, "type")) - type = get_node_value(node_angle, "type", true, true); - if (type == "isotropic") { - angle_ = UPtrAngle{new Isotropic()}; - } else if (type == "monodirectional") { - angle_ = UPtrAngle{new Monodirectional(node_angle)}; - } else if (type == "mu-phi") { - angle_ = UPtrAngle{new PolarAzimuthal(node_angle)}; - } else { - fatal_error(fmt::format( - "Invalid angular distribution for external source: {}", type)); + // For backwards compatibility, check for only fissionable setting on box + // source + auto space_box = dynamic_cast(space_.get()); + if (space_box) { + if (!only_fissionable_) { + only_fissionable_ = space_box->only_fissionable(); } + } + // Determine external source angular distribution + if (check_for_node(node, "angle")) { + angle_ = UnitSphereDistribution::create(node.child("angle")); } else { - angle_ = UPtrAngle{new Isotropic()}; + angle_ = UPtrAngle {new Isotropic()}; } // Determine external source energy distribution @@ -135,7 +310,18 @@ IndependentSource::IndependentSource(pugi::xml_node node) energy_ = distribution_from_xml(node_dist); } else { // Default to a Watt spectrum with parameters 0.988 MeV and 2.249 MeV^-1 - energy_ = UPtrDist{new Watt(0.988e6, 2.249e-6)}; + energy_ = UPtrDist {new Watt(0.988e6, 2.249e-6)}; + } + + // Determine external source time distribution + if (check_for_node(node, "time")) { + pugi::xml_node node_dist = node.child("time"); + time_ = distribution_from_xml(node_dist); + } else { + // Default to a Constant time T=0 + double T[] {0.0}; + double p[] {1.0}; + time_ = UPtrDist {new Discrete {T, p, 1}}; } } } @@ -143,89 +329,74 @@ IndependentSource::IndependentSource(pugi::xml_node node) SourceSite IndependentSource::sample(uint64_t* seed) const { SourceSite site; + site.particle = particle_; - // Set weight to one by default - site.wgt = 1.0; - - // Repeat sampling source location until a good site has been found - bool found = false; - int n_reject = 0; + // Repeat sampling source location until a good site has been accepted + bool accepted = false; + static int n_reject = 0; static int n_accept = 0; - while (!found) { - // Set particle type - site.particle = particle_; + + while (!accepted) { // Sample spatial distribution site.r = space_->sample(seed); - // Now search to see if location exists in geometry - int32_t cell_index, instance; - double xyz[] {site.r.x, site.r.y, site.r.z}; - int err = openmc_find_cell(xyz, &cell_index, &instance); - found = (err != OPENMC_E_GEOMETRY); - - // Check if spatial site is in fissionable material - if (found) { - auto space_box = dynamic_cast(space_.get()); - if (space_box) { - if (space_box->only_fissionable()) { - // Determine material - const auto& c = model::cells[cell_index]; - auto mat_index = c->material_.size() == 1 - ? c->material_[0] : c->material_[instance]; - - if (mat_index == MATERIAL_VOID) { - found = false; - } else { - if (!model::materials[mat_index]->fissionable_) found = false; - } - } - } - } + // Check if sampled position satisfies spatial constraints + accepted = satisfies_spatial_constraints(site.r); // Check for rejection - if (!found) { + if (!accepted) { ++n_reject; if (n_reject >= EXTSRC_REJECT_THRESHOLD && - static_cast(n_accept)/n_reject <= EXTSRC_REJECT_FRACTION) { + static_cast(n_accept) / n_reject <= EXTSRC_REJECT_FRACTION) { fatal_error("More than 95% of external source sites sampled were " - "rejected. Please check your external source definition."); + "rejected. Please check your external source's spatial " + "definition."); } } } - // Increment number of accepted samples - ++n_accept; - // Sample angle site.u = angle_->sample(seed); - // Check for monoenergetic source above maximum particle energy - auto p = static_cast(particle_); - auto energy_ptr = dynamic_cast(energy_.get()); - if (energy_ptr) { - auto energies = xt::adapt(energy_ptr->x()); - if (xt::any(energies > data::energy_max[p])) { - fatal_error("Source energy above range of energies of at least " - "one cross section table"); - } else if (xt::any(energies < data::energy_min[p])) { - fatal_error("Source energy below range of energies of at least " - "one cross section table"); + // Sample energy and time for neutron and photon sources + if (settings::solver_type != SolverType::RANDOM_RAY) { + // Check for monoenergetic source above maximum particle energy + auto p = static_cast(particle_); + auto energy_ptr = dynamic_cast(energy_.get()); + if (energy_ptr) { + auto energies = xt::adapt(energy_ptr->x()); + if (xt::any(energies > data::energy_max[p])) { + fatal_error("Source energy above range of energies of at least " + "one cross section table"); + } } - } - while (true) { - // Sample energy spectrum - site.E = energy_->sample(seed); + while (true) { + // Sample energy spectrum + site.E = energy_->sample(seed); + + // Resample if energy falls above maximum particle energy + if (site.E < data::energy_max[p] and + (satisfies_energy_constraints(site.E))) + break; + + n_reject++; + if (n_reject >= EXTSRC_REJECT_THRESHOLD && + static_cast(n_accept) / n_reject <= EXTSRC_REJECT_FRACTION) { + fatal_error( + "More than 95% of external source sites sampled were " + "rejected. Please check your external source energy spectrum " + "definition."); + } + } - // Resample if energy falls outside minimum or maximum particle energy - if (site.E < data::energy_max[p] && site.E > data::energy_min[p]) break; + // Sample particle creation time + site.time = time_->sample(seed); } - // Set delayed group - site.delayed_group = 0; - // Set surface ID - site.surf_id = 0; + // Increment number of accepted samples + ++n_accept; return site; } @@ -234,7 +405,22 @@ SourceSite IndependentSource::sample(uint64_t* seed) const // FileSource implementation //============================================================================== -FileSource::FileSource(std::string path) +FileSource::FileSource(pugi::xml_node node) : Source(node) +{ + auto path = get_node_value(node, "file", false, true); + if (ends_with(path, ".mcpl") || ends_with(path, ".mcpl.gz")) { + sites_ = mcpl_source_sites(path); + } else { + this->load_sites_from_file(path); + } +} + +FileSource::FileSource(const std::string& path) +{ + load_sites_from_file(path); +} + +void FileSource::load_sites_from_file(const std::string& path) { // Check if source file exists if (!file_exists(path)) { @@ -264,15 +450,28 @@ FileSource::FileSource(std::string path) SourceSite FileSource::sample(uint64_t* seed) const { - size_t i_site = sites_.size()*prn(seed); + // Sample a particle randomly from list + size_t i_site = sites_.size() * prn(seed); return sites_[i_site]; } //============================================================================== -// CustomSourceWrapper implementation +// CompiledSourceWrapper implementation //============================================================================== -CustomSourceWrapper::CustomSourceWrapper(std::string path, std::string parameters) +CompiledSourceWrapper::CompiledSourceWrapper(pugi::xml_node node) : Source(node) +{ + // Get shared library path and parameters + auto path = get_node_value(node, "library", false, true); + std::string parameters; + if (check_for_node(node, "parameters")) { + parameters = get_node_value(node, "parameters", false, true); + } + setup(path, parameters); +} + +void CompiledSourceWrapper::setup( + const std::string& path, const std::string& parameters) { #ifdef HAS_DYNAMIC_LINKING // Open the library @@ -285,30 +484,32 @@ CustomSourceWrapper::CustomSourceWrapper(std::string path, std::string parameter dlerror(); // get the function to create the custom source from the library - auto create_custom_source = reinterpret_cast( + auto create_compiled_source = reinterpret_cast( dlsym(shared_library_, "openmc_create_source")); // check for any dlsym errors auto dlsym_error = dlerror(); if (dlsym_error) { - std::string error_msg = fmt::format("Couldn't open the openmc_create_source symbol: {}", dlsym_error); + std::string error_msg = fmt::format( + "Couldn't open the openmc_create_source symbol: {}", dlsym_error); dlclose(shared_library_); fatal_error(error_msg); } // create a pointer to an instance of the custom source - custom_source_ = create_custom_source(parameters); + compiled_source_ = create_compiled_source(parameters); #else fatal_error("Custom source libraries have not yet been implemented for " - "non-POSIX systems"); + "non-POSIX systems"); #endif } -CustomSourceWrapper::~CustomSourceWrapper() +CompiledSourceWrapper::~CompiledSourceWrapper() { // Make sure custom source is cleared before closing shared library - if (custom_source_.get()) custom_source_.reset(); + if (compiled_source_.get()) + compiled_source_.reset(); #ifdef HAS_DYNAMIC_LINKING dlclose(shared_library_); @@ -318,6 +519,62 @@ CustomSourceWrapper::~CustomSourceWrapper() #endif } +//============================================================================== +// MeshSource implementation +//============================================================================== + +MeshSource::MeshSource(pugi::xml_node node) : Source(node) +{ + int32_t mesh_id = stoi(get_node_value(node, "mesh")); + int32_t mesh_idx = model::mesh_map.at(mesh_id); + const auto& mesh = model::meshes[mesh_idx]; + + std::vector strengths; + // read all source distributions and populate strengths vector for MeshSpatial + // object + for (auto source_node : node.children("source")) { + sources_.emplace_back(Source::create(source_node)); + strengths.push_back(sources_.back()->strength()); + } + + // the number of source distributions should either be one or equal to the + // number of mesh elements + if (sources_.size() > 1 && sources_.size() != mesh->n_bins()) { + fatal_error(fmt::format("Incorrect number of source distributions ({}) for " + "mesh source with {} elements.", + sources_.size(), mesh->n_bins())); + } + + space_ = std::make_unique(mesh_idx, strengths); +} + +SourceSite MeshSource::sample(uint64_t* seed) const +{ + // Sample the CDF defined in initialization above + int32_t element = space_->sample_element_index(seed); + + // Sample position and apply rejection on spatial domains + Position r; + do { + r = space_->mesh()->sample_element(element, seed); + } while (!this->satisfies_spatial_constraints(r)); + + SourceSite site; + while (true) { + // Sample source for the chosen element and replace the position + site = source(element)->sample_with_constraints(seed); + site.r = r; + + // Apply other rejections + if (satisfies_energy_constraints(site.E) && + satisfies_time_constraints(site.time)) { + break; + } + } + + return site; +} + //============================================================================== // Non-member functions //============================================================================== @@ -326,12 +583,12 @@ void initialize_source() { write_message("Initializing source particles...", 5); - // Generation source sites from specified distribution in user input - #pragma omp parallel for +// Generation source sites from specified distribution in user input +#pragma omp parallel for for (int64_t i = 0; i < simulation::work_per_rank; ++i) { // initialize random number seed - int64_t id = simulation::total_gen*settings::n_particles + - simulation::work_index[mpi::rank] + i + 1; + int64_t id = simulation::total_gen * settings::n_particles + + simulation::work_index[mpi::rank] + i + 1; uint64_t seed = init_seed(id, STREAM_SOURCE); // sample external source distribution @@ -343,7 +600,7 @@ void initialize_source() write_message("Writing out initial source...", 5); std::string filename = settings::path_output + "initial_source.h5"; hid_t file_id = file_open(filename, 'w', true); - write_source_bank(file_id, false); + write_source_bank(file_id, simulation::source_bank, simulation::work_index); file_close(file_id); } } @@ -358,16 +615,17 @@ SourceSite sample_external_source(uint64_t* seed) // Sample from among multiple source distributions int i = 0; if (model::external_sources.size() > 1) { - double xi = prn(seed)*total_strength; + double xi = prn(seed) * total_strength; double c = 0.0; for (; i < model::external_sources.size(); ++i) { c += model::external_sources[i]->strength(); - if (xi < c) break; + if (xi < c) + break; } } // Sample source site from i-th source distribution - SourceSite site {model::external_sources[i]->sample(seed)}; + SourceSite site {model::external_sources[i]->sample_with_constraints(seed)}; // If running in MG, convert site.E to group if (!settings::run_CE) { @@ -384,4 +642,28 @@ void free_memory_source() model::external_sources.clear(); } +//============================================================================== +// C API +//============================================================================== + +extern "C" int openmc_sample_external_source( + size_t n, uint64_t* seed, void* sites) +{ + if (!sites || !seed) { + set_errmsg("Received null pointer."); + return OPENMC_E_INVALID_ARGUMENT; + } + + if (model::external_sources.empty()) { + set_errmsg("No external sources have been defined."); + return OPENMC_E_OUT_OF_BOUNDS; + } + + auto sites_array = static_cast(sites); + for (size_t i = 0; i < n; ++i) { + sites_array[i] = sample_external_source(seed); + } + return 0; +} + } // namespace openmc diff --git a/src/state_point.cpp b/src/state_point.cpp index f98727a08dd..c7b7d6ad85c 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -4,15 +4,16 @@ #include // for int64_t #include -#include #include "xtensor/xbuilder.hpp" // for empty_like #include "xtensor/xview.hpp" +#include #include "openmc/bank.h" #include "openmc/capi.h" #include "openmc/constants.h" #include "openmc/eigenvalue.h" #include "openmc/error.h" +#include "openmc/file_utils.h" #include "openmc/hdf5_interface.h" #include "openmc/mesh.h" #include "openmc/message_passing.h" @@ -30,12 +31,12 @@ namespace openmc { -extern "C" int -openmc_statepoint_write(const char* filename, bool* write_source) +extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) { simulation::time_statepoint.start(); - // Set the filename + // If a nullptr is passed in, we assume that the user + // wants a default name for this, of the form like output/statepoint.20.h5 std::string filename_; if (filename) { filename_ = filename; @@ -44,8 +45,17 @@ openmc_statepoint_write(const char* filename, bool* write_source) int w = std::to_string(settings::n_max_batches).size(); // Set filename for state point - filename_ = fmt::format("{0}statepoint.{1:0{2}}.h5", - settings::path_output, simulation::current_batch, w); + filename_ = fmt::format("{0}statepoint.{1:0{2}}.h5", settings::path_output, + simulation::current_batch, w); + } + + // If a file name was specified, ensure it has .h5 file extension + const auto extension = get_file_extension(filename_); + if (extension == "") { + filename_.append(".h5"); + } else if (extension != "h5") { + warning("openmc_statepoint_write was passed a file extension differing " + "from .h5, but an hdf5 file will be written."); } // Determine whether or not to write the source bank @@ -81,8 +91,8 @@ openmc_statepoint_write(const char* filename, bool* write_source) write_dataset(file_id, "seed", openmc_get_seed()); // Write run information - write_dataset(file_id, "energy_mode", settings::run_CE ? - "continuous-energy" : "multi-group"); + write_dataset(file_id, "energy_mode", + settings::run_CE ? "continuous-energy" : "multi-group"); switch (settings::run_mode) { case RunMode::FIXED_SOURCE: write_dataset(file_id, "run_mode", "fixed source"); @@ -116,20 +126,21 @@ openmc_statepoint_write(const char* filename, bool* write_source) if (!model::tally_derivs.empty()) { hid_t derivs_group = create_group(tallies_group, "derivatives"); for (const auto& deriv : model::tally_derivs) { - hid_t deriv_group = create_group(derivs_group, - "derivative " + std::to_string(deriv.id)); + hid_t deriv_group = + create_group(derivs_group, "derivative " + std::to_string(deriv.id)); write_dataset(deriv_group, "material", deriv.diff_material); if (deriv.variable == DerivativeVariable::DENSITY) { write_dataset(deriv_group, "independent variable", "density"); } else if (deriv.variable == DerivativeVariable::NUCLIDE_DENSITY) { write_dataset(deriv_group, "independent variable", "nuclide_density"); - write_dataset(deriv_group, "nuclide", - data::nuclides[deriv.diff_nuclide]->name_); + write_dataset( + deriv_group, "nuclide", data::nuclides[deriv.diff_nuclide]->name_); } else if (deriv.variable == DerivativeVariable::TEMPERATURE) { write_dataset(deriv_group, "independent variable", "temperature"); } else { - fatal_error("Independent variable for derivative " - + std::to_string(deriv.id) + " not defined in state_point.cpp"); + fatal_error("Independent variable for derivative " + + std::to_string(deriv.id) + + " not defined in state_point.cpp"); } close_group(deriv_group); } @@ -149,8 +160,8 @@ openmc_statepoint_write(const char* filename, bool* write_source) // Write info for each filter for (const auto& filt : model::tally_filters) { - hid_t filter_group = create_group(filters_group, - "filter " + std::to_string(filt->id())); + hid_t filter_group = + create_group(filters_group, "filter " + std::to_string(filt->id())); filt->to_statepoint(filter_group); close_group(filter_group); } @@ -169,10 +180,10 @@ openmc_statepoint_write(const char* filename, bool* write_source) // Write all tally information except results for (const auto& tally : model::tallies) { - hid_t tally_group = create_group(tallies_group, - "tally " + std::to_string(tally->id_)); + hid_t tally_group = + create_group(tallies_group, "tally " + std::to_string(tally->id_)); - write_dataset(tally_group, "name", tally->name_); + write_dataset(tally_group, "name", tally->name_); if (tally->writable_) { write_attribute(tally_group, "internal", 0); @@ -182,6 +193,12 @@ openmc_statepoint_write(const char* filename, bool* write_source) continue; } + if (tally->multiply_density()) { + write_attribute(tally_group, "multiply_density", 1); + } else { + write_attribute(tally_group, "multiply_density", 0); + } + if (tally->estimator_ == TallyEstimator::ANALOG) { write_dataset(tally_group, "estimator", "analog"); } else if (tally->estimator_ == TallyEstimator::TRACKLENGTH) { @@ -217,18 +234,19 @@ openmc_statepoint_write(const char* filename, bool* write_source) } write_dataset(tally_group, "nuclides", nuclides); - if (tally->deriv_ != C_NONE) write_dataset(tally_group, "derivative", - model::tally_derivs[tally->deriv_].id); + if (tally->deriv_ != C_NONE) + write_dataset( + tally_group, "derivative", model::tally_derivs[tally->deriv_].id); // Write the tally score bins vector scores; - for (auto sc : tally->scores_) scores.push_back(reaction_name(sc)); + for (auto sc : tally->scores_) + scores.push_back(reaction_name(sc)); write_dataset(tally_group, "n_score_bins", scores.size()); write_dataset(tally_group, "score_bins", scores); close_group(tally_group); } - } if (settings::reduce_tallies) { @@ -242,7 +260,8 @@ openmc_statepoint_write(const char* filename, bool* write_source) // Write all tally results for (const auto& tally : model::tallies) { - if (!tally->writable_) continue; + if (!tally->writable_) + continue; // Write sum and sum_sq for each bin std::string name = "tally " + std::to_string(tally->id_); hid_t tally_group = open_group(tallies_group, name.c_str()); @@ -275,23 +294,30 @@ openmc_statepoint_write(const char* filename, bool* write_source) // Write out the runtime metrics. using namespace simulation; hid_t runtime_group = create_group(file_id, "runtime"); - write_dataset(runtime_group, "total initialization", time_initialize.elapsed()); - write_dataset(runtime_group, "reading cross sections", time_read_xs.elapsed()); - write_dataset(runtime_group, "simulation", time_inactive.elapsed() - + time_active.elapsed()); + write_dataset( + runtime_group, "total initialization", time_initialize.elapsed()); + write_dataset( + runtime_group, "reading cross sections", time_read_xs.elapsed()); + write_dataset(runtime_group, "simulation", + time_inactive.elapsed() + time_active.elapsed()); write_dataset(runtime_group, "transport", time_transport.elapsed()); if (settings::run_mode == RunMode::EIGENVALUE) { write_dataset(runtime_group, "inactive batches", time_inactive.elapsed()); } write_dataset(runtime_group, "active batches", time_active.elapsed()); if (settings::run_mode == RunMode::EIGENVALUE) { - write_dataset(runtime_group, "synchronizing fission bank", time_bank.elapsed()); - write_dataset(runtime_group, "sampling source sites", time_bank_sample.elapsed()); - write_dataset(runtime_group, "SEND-RECV source sites", time_bank_sendrecv.elapsed()); + write_dataset( + runtime_group, "synchronizing fission bank", time_bank.elapsed()); + write_dataset( + runtime_group, "sampling source sites", time_bank_sample.elapsed()); + write_dataset( + runtime_group, "SEND-RECV source sites", time_bank_sendrecv.elapsed()); } - write_dataset(runtime_group, "accumulating tallies", time_tallies.elapsed()); + write_dataset( + runtime_group, "accumulating tallies", time_tallies.elapsed()); write_dataset(runtime_group, "total", time_total.elapsed()); - write_dataset(runtime_group, "writing statepoints", time_statepoint.elapsed()); + write_dataset( + runtime_group, "writing statepoints", time_statepoint.elapsed()); close_group(runtime_group); file_close(file_id); @@ -305,9 +331,11 @@ openmc_statepoint_write(const char* filename, bool* write_source) // Write the source bank if desired if (write_source_) { - if (mpi::master || parallel) file_id = file_open(filename_, 'a', true); - write_source_bank(file_id, false); - if (mpi::master || parallel) file_close(file_id); + if (mpi::master || parallel) + file_id = file_open(filename_, 'a', true); + write_source_bank(file_id, simulation::source_bank, simulation::work_index); + if (mpi::master || parallel) + file_close(file_id); } #if defined(LIBMESH) || defined(DAGMC) @@ -327,7 +355,7 @@ void restart_set_keff() simulation::k_sum[0] += simulation::k_generation[i]; simulation::k_sum[1] += std::pow(simulation::k_generation[i], 2); } - int n = settings::gen_per_batch*simulation::n_realizations; + int n = settings::gen_per_batch * simulation::n_realizations; simulation::keff = simulation::k_sum[0] / n; } else { simulation::keff = simulation::k_generation.back(); @@ -336,11 +364,27 @@ void restart_set_keff() void load_state_point() { - // Write message - write_message("Loading state point " + settings::path_statepoint + "...", 5); + write_message( + fmt::format("Loading state point {}...", settings::path_statepoint_c), 5); + openmc_statepoint_load(settings::path_statepoint.c_str()); +} +void statepoint_version_check(hid_t file_id) +{ + // Read revision number for state point file and make sure it matches with + // current version + array version_array; + read_attribute(file_id, "version", version_array); + if (version_array != VERSION_STATEPOINT) { + fatal_error( + "State point version does not match current version in OpenMC."); + } +} + +extern "C" int openmc_statepoint_load(const char* filename) +{ // Open file for reading - hid_t file_id = file_open(settings::path_statepoint.c_str(), 'r', true); + hid_t file_id = file_open(filename, 'r', true); // Read filetype std::string word; @@ -349,13 +393,7 @@ void load_state_point() fatal_error("OpenMC tried to restart from a non-statepoint file."); } - // Read revision number for state point file and make sure it matches with - // current version - array array; - read_attribute(file_id, "version", array); - if (array != VERSION_STATEPOINT) { - fatal_error("State point version does not match current version in OpenMC."); - } + statepoint_version_check(file_id); // Read and overwrite random number seed int64_t seed; @@ -367,10 +405,10 @@ void load_state_point() read_dataset(file_id, "energy_mode", word); if (word == "multi-group" && settings::run_CE) { fatal_error("State point file is from multigroup run but current run is " - "continous energy."); + "continous energy."); } else if (word == "continuous-energy" && !settings::run_CE) { fatal_error("State point file is from continuous-energy run but current " - "run is multigroup!"); + "run is multigroup!"); } // Read and overwrite run information except number of batches @@ -391,9 +429,12 @@ void load_state_point() // Read batch number to restart at read_dataset(file_id, "current_batch", simulation::restart_batch); - if (simulation::restart_batch > settings::n_batches) { - fatal_error("The number batches specified in settings.xml is fewer " - " than the number of batches in the given statepoint file."); + if (simulation::restart_batch >= settings::n_max_batches) { + warning(fmt::format( + "The number of batches specified for simulation ({}) is smaller " + "than or equal to the number of batches in the restart statepoint file " + "({})", + settings::n_max_batches, simulation::restart_batch)); } // Logical flag for source present in statepoint file @@ -435,8 +476,8 @@ void load_state_point() if (mpi::master) { #endif // Read global tally data - read_dataset_lowlevel(file_id, "global_tallies", H5T_NATIVE_DOUBLE, - H5S_ALL, false, simulation::global_tallies.data()); + read_dataset_lowlevel(file_id, "global_tallies", H5T_NATIVE_DOUBLE, H5S_ALL, + false, simulation::global_tallies.data()); // Check if tally results are present bool present; @@ -451,14 +492,13 @@ void load_state_point() std::string name = "tally " + std::to_string(tally->id_); hid_t tally_group = open_group(tallies_group, name.c_str()); - int internal=0; + int internal = 0; if (attribute_exists(tally_group, "internal")) { read_attribute(tally_group, "internal", internal); } if (internal) { tally->writable_ = false; } else { - auto& results = tally->results_; read_tally_results(tally_group, results.shape()[0], results.shape()[1], results.data()); @@ -466,7 +506,6 @@ void load_state_point() close_group(tally_group); } } - close_group(tallies_group); } } @@ -481,8 +520,8 @@ void load_state_point() file_close(file_id); // Write message - write_message("Loading source file " + settings::path_sourcepoint - + "...", 5); + write_message( + "Loading source file " + settings::path_sourcepoint + "...", 5); // Open source file file_id = file_open(settings::path_sourcepoint.c_str(), 'r', true); @@ -490,15 +529,16 @@ void load_state_point() // Read source read_source_bank(file_id, simulation::source_bank, true); - } // Close file file_close(file_id); -} + return 0; +} -hid_t h5banktype() { +hid_t h5banktype() +{ // Create compound type for position hid_t postype = H5Tcreate(H5T_COMPOUND, sizeof(struct Position)); H5Tinsert(postype, "x", HOFFSET(Position, x), H5T_NATIVE_DOUBLE); @@ -516,6 +556,7 @@ hid_t h5banktype() { H5Tinsert(banktype, "r", HOFFSET(SourceSite, r), postype); H5Tinsert(banktype, "u", HOFFSET(SourceSite, u), postype); H5Tinsert(banktype, "E", HOFFSET(SourceSite, E), H5T_NATIVE_DOUBLE); + H5Tinsert(banktype, "time", HOFFSET(SourceSite, time), H5T_NATIVE_DOUBLE); H5Tinsert(banktype, "wgt", HOFFSET(SourceSite, wgt), H5T_NATIVE_DOUBLE); H5Tinsert(banktype, "delayed_group", HOFFSET(SourceSite, delayed_group), H5T_NATIVE_INT); @@ -527,31 +568,8 @@ hid_t h5banktype() { return banktype; } -vector calculate_surf_source_size() -{ - vector surf_source_index; - surf_source_index.reserve(mpi::n_procs + 1); - -#ifdef OPENMC_MPI - surf_source_index.resize(mpi::n_procs); - vector bank_size(mpi::n_procs); - - // Populate the surf_source_index with cumulative sum of the number of - // surface source banks per process - int64_t size = simulation::surf_source_bank.size(); - MPI_Scan(&size, bank_size.data(), 1, MPI_INT64_T, MPI_SUM, mpi::intracomm); - MPI_Allgather(bank_size.data(), 1, MPI_INT64_T, surf_source_index.data(), 1, MPI_INT64_T, mpi::intracomm); - surf_source_index.insert(surf_source_index.begin(), 0); -#else - surf_source_index.push_back(0); - surf_source_index.push_back(simulation::surf_source_bank.size()); -#endif - - return surf_source_index; -} - -void -write_source_point(const char* filename, bool surf_source_bank) +void write_source_point(const char* filename, gsl::span source_bank, + const vector& bank_index) { // When using parallel HDF5, the file is written to collectively by all // processes. With MPI-only, the file is opened and written by the master @@ -563,72 +581,53 @@ write_source_point(const char* filename, bool surf_source_bank) bool parallel = false; #endif - std::string filename_; - if (filename) { - filename_ = filename; - } else { - // Determine width for zero padding - int w = std::to_string(settings::n_max_batches).size(); + if (!filename) + fatal_error("write_source_point filename needs a nonempty name."); - filename_ = fmt::format("{0}source.{1:0{2}}.h5", - settings::path_output, simulation::current_batch, w); + std::string filename_(filename); + const auto extension = get_file_extension(filename_); + if (extension == "") { + filename_.append(".h5"); + } else if (extension != "h5") { + warning("write_source_point was passed a file extension differing " + "from .h5, but an hdf5 file will be written."); } hid_t file_id; if (mpi::master || parallel) { - file_id = file_open(filename_, 'w', true); + file_id = file_open(filename_.c_str(), 'w', true); write_attribute(file_id, "filetype", "source"); } // Get pointer to source bank and write to file - write_source_bank(file_id, surf_source_bank); + write_source_bank(file_id, source_bank, bank_index); - if (mpi::master || parallel) file_close(file_id); + if (mpi::master || parallel) + file_close(file_id); } -void -write_source_bank(hid_t group_id, bool surf_source_bank) +void write_source_bank(hid_t group_id, gsl::span source_bank, + const vector& bank_index) { hid_t banktype = h5banktype(); // Set total and individual process dataspace sizes for source bank - int64_t dims_size = settings::n_particles; - int64_t count_size = simulation::work_per_rank; - - // Set vectors for source bank and starting bank index of each process - vector* bank_index = &simulation::work_index; - vector* source_bank = &simulation::source_bank; - vector surf_source_index_vector; - vector surf_source_bank_vector; - - // Reset dataspace sizes and vectors for surface source bank - if (surf_source_bank) { - surf_source_index_vector = calculate_surf_source_size(); - dims_size = surf_source_index_vector[mpi::n_procs]; - count_size = simulation::surf_source_bank.size(); - - bank_index = &surf_source_index_vector; - - // Copy data in a SharedArray into a vector. - surf_source_bank_vector.resize(count_size); - surf_source_bank_vector.assign(simulation::surf_source_bank.data(), - simulation::surf_source_bank.data() + count_size); - source_bank = &surf_source_bank_vector; - } + int64_t dims_size = bank_index.back(); + int64_t count_size = bank_index[mpi::rank + 1] - bank_index[mpi::rank]; #ifdef PHDF5 // Set size of total dataspace for all procs and rank hsize_t dims[] {static_cast(dims_size)}; hid_t dspace = H5Screate_simple(1, dims, nullptr); - hid_t dset = H5Dcreate(group_id, "source_bank", banktype, dspace, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + hid_t dset = H5Dcreate(group_id, "source_bank", banktype, dspace, H5P_DEFAULT, + H5P_DEFAULT, H5P_DEFAULT); // Create another data space but for each proc individually hsize_t count[] {static_cast(count_size)}; hid_t memspace = H5Screate_simple(1, count, nullptr); // Select hyperslab for this dataspace - hsize_t start[] {static_cast((*bank_index)[mpi::rank])}; + hsize_t start[] {static_cast(bank_index[mpi::rank])}; H5Sselect_hyperslab(dspace, H5S_SELECT_SET, start, nullptr, count, nullptr); // Set up the property list for parallel writing @@ -636,7 +635,7 @@ write_source_bank(hid_t group_id, bool surf_source_bank) H5Pset_dxpl_mpio(plist, H5FD_MPIO_COLLECTIVE); // Write data to file in parallel - H5Dwrite(dset, banktype, memspace, dspace, plist, source_bank->data()); + H5Dwrite(dset, banktype, memspace, dspace, plist, source_bank.data()); // Free resources H5Sclose(dspace); @@ -651,32 +650,34 @@ write_source_bank(hid_t group_id, bool surf_source_bank) hsize_t dims[] {static_cast(dims_size)}; hid_t dspace = H5Screate_simple(1, dims, nullptr); hid_t dset = H5Dcreate(group_id, "source_bank", banktype, dspace, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); // Save source bank sites since the array is overwritten below #ifdef OPENMC_MPI - vector temp_source {source_bank->begin(), source_bank->end()}; + vector temp_source {source_bank.begin(), source_bank.end()}; #endif for (int i = 0; i < mpi::n_procs; ++i) { // Create memory space - hsize_t count[] {static_cast((*bank_index)[i+1] - (*bank_index)[i])}; + hsize_t count[] {static_cast(bank_index[i + 1] - bank_index[i])}; hid_t memspace = H5Screate_simple(1, count, nullptr); #ifdef OPENMC_MPI // Receive source sites from other processes if (i > 0) - MPI_Recv(source_bank->data(), count[0], mpi::source_site, i, i, - mpi::intracomm, MPI_STATUS_IGNORE); + MPI_Recv(source_bank.data(), count[0], mpi::source_site, i, i, + mpi::intracomm, MPI_STATUS_IGNORE); #endif // Select hyperslab for this dataspace dspace = H5Dget_space(dset); - hsize_t start[] {static_cast((*bank_index)[i])}; - H5Sselect_hyperslab(dspace, H5S_SELECT_SET, start, nullptr, count, nullptr); + hsize_t start[] {static_cast(bank_index[i])}; + H5Sselect_hyperslab( + dspace, H5S_SELECT_SET, start, nullptr, count, nullptr); // Write data to hyperslab - H5Dwrite(dset, banktype, memspace, dspace, H5P_DEFAULT, (*source_bank).data()); + H5Dwrite( + dset, banktype, memspace, dspace, H5P_DEFAULT, source_bank.data()); H5Sclose(memspace); H5Sclose(dspace); @@ -687,12 +688,12 @@ write_source_bank(hid_t group_id, bool surf_source_bank) #ifdef OPENMC_MPI // Restore state of source bank - std::copy(temp_source.begin(), temp_source.end(), source_bank->begin()); + std::copy(temp_source.begin(), temp_source.end(), source_bank.begin()); #endif } else { #ifdef OPENMC_MPI - MPI_Send(source_bank->data(), count_size, mpi::source_site, - 0, mpi::rank, mpi::intracomm); + MPI_Send(source_bank.data(), count_size, mpi::source_site, 0, mpi::rank, + mpi::intracomm); #endif } #endif @@ -706,8 +707,11 @@ std::string dtype_member_names(hid_t dtype_id) int nmembers = H5Tget_nmembers(dtype_id); std::string names; for (int i = 0; i < nmembers; i++) { - names = names.append(H5Tget_member_name(dtype_id, i)); - if (i < nmembers - 1) names += ", "; + char* name = H5Tget_member_name(dtype_id, i); + names = names.append(name); + H5free_memory(name); + if (i < nmembers - 1) + names += ", "; } return names; } @@ -725,9 +729,11 @@ void read_source_bank( auto file_member_names = dtype_member_names(dtype); auto bank_member_names = dtype_member_names(banktype); if (file_member_names != bank_member_names) { - fatal_error(fmt::format("Source site attributes in file do not match what is " + fatal_error(fmt::format( + "Source site attributes in file do not match what is " "expected for this version of OpenMC. File attributes = ({}). Expected " - "attributes = ({})", file_member_names, bank_member_names)); + "attributes = ({})", + file_member_names, bank_member_names)); } hid_t dspace = H5Dget_space(dset); @@ -736,7 +742,8 @@ void read_source_bank( // Make sure vector is big enough in case where we're reading entire source on // each process - if (!distribute) sites.resize(n_sites); + if (!distribute) + sites.resize(n_sites); hid_t memspace; if (distribute) { @@ -751,13 +758,14 @@ void read_source_bank( // Select hyperslab for each process hsize_t offset = simulation::work_index[mpi::rank]; - H5Sselect_hyperslab(dspace, H5S_SELECT_SET, &offset, nullptr, &n_sites_local, nullptr); + H5Sselect_hyperslab( + dspace, H5S_SELECT_SET, &offset, nullptr, &n_sites_local, nullptr); } else { memspace = H5S_ALL; } #ifdef PHDF5 - // Read data in parallel + // Read data in parallel hid_t plist = H5Pcreate(H5P_DATASET_XFER); H5Pset_dxpl_mpio(plist, H5FD_MPIO_COLLECTIVE); H5Dread(dset, banktype, memspace, dspace, plist, sites.data()); @@ -768,35 +776,51 @@ void read_source_bank( // Close all ids H5Sclose(dspace); - if (distribute) H5Sclose(memspace); + if (distribute) + H5Sclose(memspace); H5Dclose(dset); H5Tclose(banktype); } -void write_unstructured_mesh_results() { +void write_unstructured_mesh_results() +{ for (auto& tally : model::tallies) { vector tally_scores; for (auto filter_idx : tally->filters()) { auto& filter = model::tally_filters[filter_idx]; - if (filter->type() != "mesh") continue; + if (filter->type() != FilterType::MESH) + continue; // check if the filter uses an unstructured mesh auto mesh_filter = dynamic_cast(filter.get()); auto mesh_idx = mesh_filter->mesh(); - auto umesh = dynamic_cast(model::meshes[mesh_idx].get()); - - if (!umesh) continue; - - if (!umesh->output_) continue; + auto umesh = + dynamic_cast(model::meshes[mesh_idx].get()); + + if (!umesh) + continue; + + if (!umesh->output_) + continue; + + if (umesh->library() == "moab") { + if (mpi::master) + warning(fmt::format( + "Output for a MOAB mesh (mesh {}) was " + "requested but will not be written. Please use the Python " + "API to generated the desired VTK tetrahedral mesh.", + umesh->id_)); + continue; + } // if this tally has more than one filter, print // warning and skip writing the mesh if (tally->filters().size() > 1) { warning(fmt::format("Skipping unstructured mesh writing for tally " "{}. More than one filter is present on the tally.", - tally->id_)); + tally->id_)); break; } @@ -805,9 +829,8 @@ void write_unstructured_mesh_results() { for (int score_idx = 0; score_idx < tally->scores_.size(); score_idx++) { for (int nuc_idx = 0; nuc_idx < tally->nuclides_.size(); nuc_idx++) { // combine the score and nuclide into a name for the value - auto score_str = fmt::format("{}_{}", - tally->score_name(score_idx), - tally->nuclide_name(nuc_idx)); + auto score_str = fmt::format("{}_{}", tally->score_name(score_idx), + tally->nuclide_name(nuc_idx)); // add this score to the mesh // (this is in a separate loop because all variables need to be added // to libMesh's equation system before any are initialized, which @@ -819,12 +842,11 @@ void write_unstructured_mesh_results() { for (int score_idx = 0; score_idx < tally->scores_.size(); score_idx++) { for (int nuc_idx = 0; nuc_idx < tally->nuclides_.size(); nuc_idx++) { // combine the score and nuclide into a name for the value - auto score_str = fmt::format("{}_{}", - tally->score_name(score_idx), - tally->nuclide_name(nuc_idx)); + auto score_str = fmt::format("{}_{}", tally->score_name(score_idx), + tally->nuclide_name(nuc_idx)); // index for this nuclide and score - int nuc_score_idx = score_idx + nuc_idx*tally->scores_.size(); + int nuc_score_idx = score_idx + nuc_idx * tally->scores_.size(); // construct result vectors vector mean_vec(umesh->n_bins()), @@ -833,21 +855,25 @@ void write_unstructured_mesh_results() { // get the volume for this bin double volume = umesh->volume(j); // compute the mean - double mean = tally->results_(j, nuc_score_idx, TallyResult::SUM) / n_realizations; + double mean = tally->results_(j, nuc_score_idx, TallyResult::SUM) / + n_realizations; mean_vec.at(j) = mean / volume; // compute the standard deviation - double sum_sq = tally->results_(j , nuc_score_idx, TallyResult::SUM_SQ); + double sum_sq = + tally->results_(j, nuc_score_idx, TallyResult::SUM_SQ); double std_dev {0.0}; if (n_realizations > 1) { - std_dev = sum_sq/n_realizations - mean*mean; + std_dev = sum_sq / n_realizations - mean * mean; std_dev = std::sqrt(std_dev / (n_realizations - 1)); } std_dev_vec[j] = std_dev / volume; } #ifdef OPENMC_MPI - MPI_Bcast(mean_vec.data(), mean_vec.size(), MPI_DOUBLE, 0, mpi::intracomm); - MPI_Bcast(std_dev_vec.data(), std_dev_vec.size(), MPI_DOUBLE, 0, mpi::intracomm); + MPI_Bcast( + mean_vec.data(), mean_vec.size(), MPI_DOUBLE, 0, mpi::intracomm); + MPI_Bcast(std_dev_vec.data(), std_dev_vec.size(), MPI_DOUBLE, 0, + mpi::intracomm); #endif // set the data for this score umesh->set_score_data(score_str, mean_vec, std_dev_vec); @@ -857,16 +883,13 @@ void write_unstructured_mesh_results() { // Generate a file name based on the tally id // and the current batch number size_t batch_width {std::to_string(settings::n_max_batches).size()}; - std::string filename = fmt::format("tally_{0}.{1:0{2}}", - tally->id_, - simulation::current_batch, - batch_width); - - if (umesh->library() == "moab" && !mpi::master) continue; + std::string filename = fmt::format("tally_{0}.{1:0{2}}", tally->id_, + simulation::current_batch, batch_width); // Write the unstructured mesh and data to file umesh->write(filename); + // remove score data added for this mesh write umesh->remove_scores(); } } @@ -891,8 +914,8 @@ void write_tally_results_nr(hid_t file_id) #ifdef OPENMC_MPI // Reduce global tallies xt::xtensor gt_reduced = xt::empty_like(gt); - MPI_Reduce(gt.data(), gt_reduced.data(), gt.size(), MPI_DOUBLE, - MPI_SUM, 0, mpi::intracomm); + MPI_Reduce(gt.data(), gt_reduced.data(), gt.size(), MPI_DOUBLE, MPI_SUM, 0, + mpi::intracomm); // Transfer values to value on master if (mpi::master) { @@ -910,8 +933,10 @@ void write_tally_results_nr(hid_t file_id) for (const auto& t : model::tallies) { // Skip any tallies that are not active - if (!t->active_) continue; - if (!t->writable_) continue; + if (!t->active_) + continue; + if (!t->writable_) + continue; if (mpi::master && !attribute_exists(file_id, "tallies_present")) { write_attribute(file_id, "tallies_present", 1); @@ -919,7 +944,8 @@ void write_tally_results_nr(hid_t file_id) // Get view of accumulated tally values auto values_view = xt::view(t->results_, xt::all(), xt::all(), - xt::range(static_cast(TallyResult::SUM), static_cast(TallyResult::SUM_SQ) + 1)); + xt::range(static_cast(TallyResult::SUM), + static_cast(TallyResult::SUM_SQ) + 1)); // Make copy of tally values in contiguous array xt::xtensor values = values_view; @@ -946,7 +972,8 @@ void write_tally_results_nr(hid_t file_id) // Put in temporary tally result xt::xtensor results_copy = xt::zeros_like(t->results_); auto copy_view = xt::view(results_copy, xt::all(), xt::all(), - xt::range(static_cast(TallyResult::SUM), static_cast(TallyResult::SUM_SQ) + 1)); + xt::range(static_cast(TallyResult::SUM), + static_cast(TallyResult::SUM_SQ) + 1)); copy_view = values; // Write reduced tally results to file @@ -957,8 +984,8 @@ void write_tally_results_nr(hid_t file_id) } else { // Receive buffer not significant at other processors #ifdef OPENMC_MPI - MPI_Reduce(values.data(), nullptr, values.size(), MPI_DOUBLE, MPI_SUM, - 0, mpi::intracomm); + MPI_Reduce(values.data(), nullptr, values.size(), MPI_DOUBLE, MPI_SUM, 0, + mpi::intracomm); #endif } } diff --git a/src/string_utils.cpp b/src/string_utils.cpp index 5ad977aabf4..3b1c1b4a678 100644 --- a/src/string_utils.cpp +++ b/src/string_utils.cpp @@ -14,7 +14,6 @@ std::string& strtrim(std::string& s) return s; } - char* strtrim(char* c_str) { std::string std_str; @@ -25,16 +24,16 @@ char* strtrim(char* c_str) return c_str; } - -std::string to_element(const std::string& name) { +std::string to_element(const std::string& name) +{ int pos = name.find_first_of("0123456789"); return name.substr(0, pos); } - void to_lower(std::string& str) { - for (int i = 0; i < str.size(); i++) str[i] = std::tolower(str[i]); + for (int i = 0; i < str.size(); i++) + str[i] = std::tolower(str[i]); } int word_count(std::string const& str) @@ -42,7 +41,9 @@ int word_count(std::string const& str) std::stringstream stream(str); std::string dum; int count = 0; - while (stream >> dum) {count++;} + while (stream >> dum) { + count++; + } return count; } @@ -50,7 +51,7 @@ vector split(const std::string& in) { vector out; - for (int i = 0; i < in.size(); ) { + for (int i = 0; i < in.size();) { // Increment i until we find a non-whitespace character. if (std::isspace(in[i])) { i++; @@ -58,10 +59,12 @@ vector split(const std::string& in) } else { // Find the next whitespace character at j. int j = i + 1; - while (j < in.size() && std::isspace(in[j]) == 0) {j++;} + while (j < in.size() && std::isspace(in[j]) == 0) { + j++; + } // Push-back everything between i and j. - out.push_back(in.substr(i, j-i)); + out.push_back(in.substr(i, j - i)); i = j + 1; // j is whitespace so leapfrog to j+1 } } @@ -71,13 +74,15 @@ vector split(const std::string& in) bool ends_with(const std::string& value, const std::string& ending) { - if (ending.size() > value.size()) return false; + if (ending.size() > value.size()) + return false; return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); } bool starts_with(const std::string& value, const std::string& beginning) { - if (beginning.size() > value.size()) return false; + if (beginning.size() > value.size()) + return false; return std::equal(beginning.begin(), beginning.end(), value.begin()); } diff --git a/src/summary.cpp b/src/summary.cpp index 3d2c6816b42..b3ea0254e6e 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -1,14 +1,19 @@ #include "openmc/summary.h" +#include + +#include "openmc/capi.h" #include "openmc/cell.h" +#include "openmc/file_utils.h" #include "openmc/hdf5_interface.h" #include "openmc/lattice.h" #include "openmc/material.h" +#include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" #include "openmc/output.h" -#include "openmc/surface.h" #include "openmc/settings.h" +#include "openmc/surface.h" namespace openmc { @@ -17,8 +22,11 @@ void write_summary() // Display output message write_message("Writing summary.h5 file...", 5); + // Set filename for summary file + std::string filename = fmt::format("{}summary.h5", settings::path_output); + // Create a new file using default properties. - hid_t file = file_open("summary.h5", 'w'); + hid_t file = file_open(filename, 'w'); write_header(file); write_nuclides(file); @@ -89,33 +97,29 @@ void write_geometry(hid_t file) { auto geom_group = create_group(file, "geometry"); -#ifdef DAGMC - if (settings::dagmc) { - write_attribute(geom_group, "dagmc", 1); - close_group(geom_group); - return; - } -#endif - write_attribute(geom_group, "n_cells", model::cells.size()); write_attribute(geom_group, "n_surfaces", model::surfaces.size()); write_attribute(geom_group, "n_universes", model::universes.size()); write_attribute(geom_group, "n_lattices", model::lattices.size()); auto cells_group = create_group(geom_group, "cells"); - for (const auto& c : model::cells) c->to_hdf5(cells_group); + for (const auto& c : model::cells) + c->to_hdf5(cells_group); close_group(cells_group); auto surfaces_group = create_group(geom_group, "surfaces"); - for (const auto& surf : model::surfaces) surf->to_hdf5(surfaces_group); + for (const auto& surf : model::surfaces) + surf->to_hdf5(surfaces_group); close_group(surfaces_group); auto universes_group = create_group(geom_group, "universes"); - for (const auto& u : model::universes) u->to_hdf5(universes_group); + for (const auto& u : model::universes) + u->to_hdf5(universes_group); close_group(universes_group); auto lattices_group = create_group(geom_group, "lattices"); - for (const auto& lat : model::lattices) lat->to_hdf5(lattices_group); + for (const auto& lat : model::lattices) + lat->to_hdf5(lattices_group); close_group(lattices_group); close_group(geom_group); @@ -133,4 +137,126 @@ void write_materials(hid_t file) close_group(materials_group); } +//============================================================================== +// C API +//============================================================================== + +extern "C" int openmc_properties_export(const char* filename) +{ + // Only write from master process + if (!mpi::master) + return 0; + + // Set a default filename if none was passed + std::string name = filename ? filename : "properties.h5"; + + // Display output message + auto msg = fmt::format("Exporting properties to {}...", name); + write_message(msg, 5); + + // Create a new file using default properties. + hid_t file = file_open(name, 'w'); + + // Write metadata + write_attribute(file, "filetype", "properties"); + write_attribute(file, "version", VERSION_STATEPOINT); + write_attribute(file, "openmc_version", VERSION); +#ifdef GIT_SHA1 + write_attribute(file, "git_sha1", GIT_SHA1); +#endif + write_attribute(file, "date_and_time", time_stamp()); + write_attribute(file, "path", settings::path_input); + + // Write cell properties + auto geom_group = create_group(file, "geometry"); + write_attribute(geom_group, "n_cells", model::cells.size()); + auto cells_group = create_group(geom_group, "cells"); + for (const auto& c : model::cells) { + c->export_properties_hdf5(cells_group); + } + close_group(cells_group); + close_group(geom_group); + + // Write material properties + hid_t materials_group = create_group(file, "materials"); + write_attribute(materials_group, "n_materials", model::materials.size()); + for (const auto& mat : model::materials) { + mat->export_properties_hdf5(materials_group); + } + close_group(materials_group); + + // Terminate access to the file. + file_close(file); + return 0; +} + +extern "C" int openmc_properties_import(const char* filename) +{ + // Display output message + auto msg = fmt::format("Importing properties from {}...", filename); + write_message(msg, 5); + + // Create a new file using default properties. + if (!file_exists(filename)) { + set_errmsg(fmt::format("File '{}' does not exist.", filename)); + return OPENMC_E_INVALID_ARGUMENT; + } + hid_t file = file_open(filename, 'r'); + + // Ensure the filetype is correct + std::string filetype; + read_attribute(file, "filetype", filetype); + if (filetype != "properties") { + file_close(file); + set_errmsg(fmt::format("File '{}' is not a properties file.", filename)); + return OPENMC_E_INVALID_ARGUMENT; + } + + // Make sure number of cells matches + auto geom_group = open_group(file, "geometry"); + int32_t n; + read_attribute(geom_group, "n_cells", n); + if (n != openmc::model::cells.size()) { + close_group(geom_group); + file_close(file); + set_errmsg(fmt::format( + "Number of cells in {} doesn't match current model.", filename)); + return OPENMC_E_GEOMETRY; + } + + // Read cell properties + auto cells_group = open_group(geom_group, "cells"); + try { + for (const auto& c : model::cells) { + c->import_properties_hdf5(cells_group); + } + } catch (const std::exception& e) { + set_errmsg(e.what()); + return OPENMC_E_UNASSIGNED; + } + close_group(cells_group); + close_group(geom_group); + + // Make sure number of cells matches + auto materials_group = open_group(file, "materials"); + read_attribute(materials_group, "n_materials", n); + if (n != openmc::model::materials.size()) { + close_group(materials_group); + file_close(file); + set_errmsg(fmt::format( + "Number of materials in {} doesn't match current model.", filename)); + return OPENMC_E_GEOMETRY; + } + + // Read material properties + for (const auto& mat : model::materials) { + mat->import_properties_hdf5(materials_group); + } + close_group(materials_group); + + // Terminate access to the file. + file_close(file); + return 0; +} + } // namespace openmc diff --git a/src/surface.cpp b/src/surface.cpp index 76542fcd86e..12fef070e18 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -1,16 +1,18 @@ #include "openmc/surface.h" #include -#include +#include +#include #include +#include #include -#include +#include #include "openmc/array.h" #include "openmc/container_util.h" -#include "openmc/dagmc.h" #include "openmc/error.h" +#include "openmc/external/quartic_solver.h" #include "openmc/hdf5_interface.h" #include "openmc/math_functions.h" #include "openmc/random_lcg.h" @@ -25,84 +27,29 @@ namespace openmc { //============================================================================== namespace model { - std::unordered_map surface_map; - vector> surfaces; +std::unordered_map surface_map; +vector> surfaces; } // namespace model //============================================================================== // Helper functions for reading the "coeffs" node of an XML surface element //============================================================================== -void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1) -{ - // Check the given number of coefficients. - std::string coeffs = get_node_value(surf_node, "coeffs"); - int n_words = word_count(coeffs); - if (n_words != 1) { - fatal_error(fmt::format("Surface {} expects 1 coeff but was given {}", - surf_id, n_words)); - } - - // Parse the coefficients. - int stat = sscanf(coeffs.c_str(), "%lf", &c1); - if (stat != 1) { - fatal_error("Something went wrong reading surface coeffs"); - } -} - -void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, - double &c3) +void read_coeffs( + pugi::xml_node surf_node, int surf_id, std::initializer_list coeffs) { // Check the given number of coefficients. - std::string coeffs = get_node_value(surf_node, "coeffs"); - int n_words = word_count(coeffs); - if (n_words != 3) { - fatal_error(fmt::format("Surface {} expects 3 coeffs but was given {}", - surf_id, n_words)); + auto coeffs_file = get_node_array(surf_node, "coeffs"); + if (coeffs_file.size() != coeffs.size()) { + fatal_error( + fmt::format("Surface {} expects {} coefficient but was given {}", surf_id, + coeffs.size(), coeffs_file.size())); } - // Parse the coefficients. - int stat = sscanf(coeffs.c_str(), "%lf %lf %lf", &c1, &c2, &c3); - if (stat != 3) { - fatal_error("Something went wrong reading surface coeffs"); - } -} - -void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, - double &c3, double &c4) -{ - // Check the given number of coefficients. - std::string coeffs = get_node_value(surf_node, "coeffs"); - int n_words = word_count(coeffs); - if (n_words != 4) { - fatal_error(fmt::format("Surface {} expects 4 coeffs but was given ", - surf_id, n_words)); - } - - // Parse the coefficients. - int stat = sscanf(coeffs.c_str(), "%lf %lf %lf %lf", &c1, &c2, &c3, &c4); - if (stat != 4) { - fatal_error("Something went wrong reading surface coeffs"); - } -} - -void read_coeffs(pugi::xml_node surf_node, int surf_id, double &c1, double &c2, - double &c3, double &c4, double &c5, double &c6, double &c7, - double &c8, double &c9, double &c10) -{ - // Check the given number of coefficients. - std::string coeffs = get_node_value(surf_node, "coeffs"); - int n_words = word_count(coeffs); - if (n_words != 10) { - fatal_error(fmt::format("Surface {} expects 10 coeffs but was given {}", - surf_id, n_words)); - } - - // Parse the coefficients. - int stat = sscanf(coeffs.c_str(), "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &c1, &c2, &c3, &c4, &c5, &c6, &c7, &c8, &c9, &c10); - if (stat != 10) { - fatal_error("Something went wrong reading surface coeffs"); + // Copy the coefficients + int i = 0; + for (auto c : coeffs) { + *c = coeffs_file[i++]; } } @@ -130,27 +77,43 @@ Surface::Surface(pugi::xml_node surf_node) if (check_for_node(surf_node, "boundary")) { std::string surf_bc = get_node_value(surf_node, "boundary", true, true); - if (surf_bc == "transmission" || surf_bc == "transmit" ||surf_bc.empty()) { + if (surf_bc == "transmission" || surf_bc == "transmit" || surf_bc.empty()) { // Leave the bc_ a nullptr } else if (surf_bc == "vacuum") { - bc_ = std::make_shared(); - } else if (surf_bc == "reflective" || surf_bc == "reflect" - || surf_bc == "reflecting") { - bc_ = std::make_shared(); + bc_ = make_unique(); + } else if (surf_bc == "reflective" || surf_bc == "reflect" || + surf_bc == "reflecting") { + bc_ = make_unique(); } else if (surf_bc == "white") { - bc_ = std::make_shared(); + bc_ = make_unique(); } else if (surf_bc == "periodic") { - // periodic BC's are handled separately + // Periodic BCs are handled separately } else { fatal_error(fmt::format("Unknown boundary condition \"{}\" specified " - "on surface {}", surf_bc, id_)); + "on surface {}", + surf_bc, id_)); } - } + if (check_for_node(surf_node, "albedo") && bc_) { + double surf_alb = std::stod(get_node_value(surf_node, "albedo")); + + if (surf_alb < 0.0) + fatal_error(fmt::format("Surface {} has an albedo of {}. " + "Albedo values must be positive.", + id_, surf_alb)); + + if (surf_alb > 1.0) + warning(fmt::format("Surface {} has an albedo of {}. " + "Albedos greater than 1 may cause " + "unphysical behaviour.", + id_, surf_alb)); + + bc_->set_albedo(surf_alb); + } + } } -bool -Surface::sense(Position r, Direction u) const +bool Surface::sense(Position r, Direction u) const { // Evaluate the surface equation at the particle's coordinates to determine // which side the particle is on. @@ -166,8 +129,7 @@ Surface::sense(Position r, Direction u) const return f > 0.0; } -Direction -Surface::reflect(Position r, Direction u, Particle* p) const +Direction Surface::reflect(Position r, Direction u, GeometryState* p) const { // Determine projection of direction onto normal and squared magnitude of // normal. @@ -177,8 +139,8 @@ Surface::reflect(Position r, Direction u, Particle* p) const return u.reflect(n); } -Direction -Surface::diffuse_reflect(Position r, Direction u, uint64_t* seed) const +Direction Surface::diffuse_reflect( + Position r, Direction u, uint64_t* seed, GeometryState* p) const { // Diffuse reflect direction according to the normal. // cosine distribution @@ -188,31 +150,31 @@ Surface::diffuse_reflect(Position r, Direction u, uint64_t* seed) const const double projection = n.dot(u); // sample from inverse function, u=sqrt(rand) since p(u)=2u, so F(u)=u^2 - const double mu = (projection>=0.0) ? - -std::sqrt(prn(seed)) : std::sqrt(prn(seed)); + const double mu = + (projection >= 0.0) ? -std::sqrt(prn(seed)) : std::sqrt(prn(seed)); // sample azimuthal distribution uniformly u = rotate_angle(n, mu, nullptr, seed); // normalize the direction - return u/u.norm(); + return u / u.norm(); } -CSGSurface::CSGSurface() : Surface{} {}; -CSGSurface::CSGSurface(pugi::xml_node surf_node) : Surface{surf_node} {}; - -void -CSGSurface::to_hdf5(hid_t group_id) const +void Surface::to_hdf5(hid_t group_id) const { - std::string group_name {"surface "}; - group_name += std::to_string(id_); + hid_t surf_group = create_group(group_id, fmt::format("surface {}", id_)); - hid_t surf_group = create_group(group_id, group_name); + if (geom_type_ == GeometryType::DAG) { + write_string(surf_group, "geom_type", "dagmc", false); + } else if (geom_type_ == GeometryType::CSG) { + write_string(surf_group, "geom_type", "csg", false); - if (bc_) { - write_string(surf_group, "boundary_type", bc_->type(), false); - } else { - write_string(surf_group, "boundary_type", "transmission", false); + if (bc_) { + write_string(surf_group, "boundary_type", bc_->type(), false); + bc_->to_hdf5(surf_group); + } else { + write_string(surf_group, "boundary_type", "transmission", false); + } } if (!name_.empty()) { @@ -224,73 +186,30 @@ CSGSurface::to_hdf5(hid_t group_id) const close_group(surf_group); } -//============================================================================== -// DAGSurface implementation -//============================================================================== -#ifdef DAGMC -DAGSurface::DAGSurface() : Surface{} {} // empty constructor - -double DAGSurface::evaluate(Position r) const +CSGSurface::CSGSurface() : Surface {} { - return 0.0; -} - -double -DAGSurface::distance(Position r, Direction u, bool coincident) const + geom_type_ = GeometryType::CSG; +}; +CSGSurface::CSGSurface(pugi::xml_node surf_node) : Surface {surf_node} { - moab::ErrorCode rval; - moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); - moab::EntityHandle hit_surf; - double dist; - double pnt[3] = {r.x, r.y, r.z}; - double dir[3] = {u.x, u.y, u.z}; - rval = dagmc_ptr_->ray_fire(surf, pnt, dir, hit_surf, dist, NULL, 0, 0); - MB_CHK_ERR_CONT(rval); - if (dist < 0.0) dist = INFTY; - return dist; -} - -Direction DAGSurface::normal(Position r) const -{ - moab::ErrorCode rval; - moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); - double pnt[3] = {r.x, r.y, r.z}; - double dir[3]; - rval = dagmc_ptr_->get_angle(surf, pnt, dir); - MB_CHK_ERR_CONT(rval); - return dir; -} - -Direction DAGSurface::reflect(Position r, Direction u, Particle* p) const -{ - Expects(p); - p->history().reset_to_last_intersection(); - moab::ErrorCode rval; - moab::EntityHandle surf = dagmc_ptr_->entity_by_index(2, dag_index_); - double pnt[3] = {r.x, r.y, r.z}; - double dir[3]; - rval = dagmc_ptr_->get_angle(surf, pnt, dir, &p->history()); - MB_CHK_ERR_CONT(rval); - p->last_dir() = u.reflect(dir); - return p->last_dir(); -} - -void DAGSurface::to_hdf5(hid_t group_id) const {} - -#endif + geom_type_ = GeometryType::CSG; +}; //============================================================================== // Generic functions for x-, y-, and z-, planes. //============================================================================== // The template parameter indicates the axis normal to the plane. -template double -axis_aligned_plane_distance(Position r, Direction u, bool coincident, double offset) +template +double axis_aligned_plane_distance( + Position r, Direction u, bool coincident, double offset) { const double f = offset - r[i]; - if (coincident || std::abs(f) < FP_COINCIDENT || u[i] == 0.0) return INFTY; + if (coincident || std::abs(f) < FP_COINCIDENT || u[i] == 0.0) + return INFTY; const double d = f / u[i]; - if (d < 0.0) return INFTY; + if (d < 0.0) + return INFTY; return d; } @@ -298,10 +217,9 @@ axis_aligned_plane_distance(Position r, Direction u, bool coincident, double off // SurfaceXPlane implementation //============================================================================== -SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) - : CSGSurface(surf_node) +SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_); + read_coeffs(surf_node, id_, {&x0_}); } double SurfaceXPlane::evaluate(Position r) const @@ -326,8 +244,7 @@ void SurfaceXPlane::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -BoundingBox -SurfaceXPlane::bounding_box(bool pos_side) const +BoundingBox SurfaceXPlane::bounding_box(bool pos_side) const { if (pos_side) { return {x0_, INFTY, -INFTY, INFTY, -INFTY, INFTY}; @@ -340,10 +257,9 @@ SurfaceXPlane::bounding_box(bool pos_side) const // SurfaceYPlane implementation //============================================================================== -SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) - : CSGSurface(surf_node) +SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, y0_); + read_coeffs(surf_node, id_, {&y0_}); } double SurfaceYPlane::evaluate(Position r) const @@ -368,8 +284,7 @@ void SurfaceYPlane::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -BoundingBox -SurfaceYPlane::bounding_box(bool pos_side) const +BoundingBox SurfaceYPlane::bounding_box(bool pos_side) const { if (pos_side) { return {-INFTY, INFTY, y0_, INFTY, -INFTY, INFTY}; @@ -382,10 +297,9 @@ SurfaceYPlane::bounding_box(bool pos_side) const // SurfaceZPlane implementation //============================================================================== -SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) - : CSGSurface(surf_node) +SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, z0_); + read_coeffs(surf_node, id_, {&z0_}); } double SurfaceZPlane::evaluate(Position r) const @@ -410,8 +324,7 @@ void SurfaceZPlane::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -BoundingBox -SurfaceZPlane::bounding_box(bool pos_side) const +BoundingBox SurfaceZPlane::bounding_box(bool pos_side) const { if (pos_side) { return {-INFTY, INFTY, -INFTY, INFTY, z0_, INFTY}; @@ -424,34 +337,31 @@ SurfaceZPlane::bounding_box(bool pos_side) const // SurfacePlane implementation //============================================================================== -SurfacePlane::SurfacePlane(pugi::xml_node surf_node) - : CSGSurface(surf_node) +SurfacePlane::SurfacePlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, A_, B_, C_, D_); + read_coeffs(surf_node, id_, {&A_, &B_, &C_, &D_}); } -double -SurfacePlane::evaluate(Position r) const +double SurfacePlane::evaluate(Position r) const { - return A_*r.x + B_*r.y + C_*r.z - D_; + return A_ * r.x + B_ * r.y + C_ * r.z - D_; } -double -SurfacePlane::distance(Position r, Direction u, bool coincident) const +double SurfacePlane::distance(Position r, Direction u, bool coincident) const { - const double f = A_*r.x + B_*r.y + C_*r.z - D_; - const double projection = A_*u.x + B_*u.y + C_*u.z; + const double f = A_ * r.x + B_ * r.y + C_ * r.z - D_; + const double projection = A_ * u.x + B_ * u.y + C_ * u.z; if (coincident || std::abs(f) < FP_COINCIDENT || projection == 0.0) { return INFTY; } else { const double d = -f / projection; - if (d < 0.0) return INFTY; + if (d < 0.0) + return INFTY; return d; } } -Direction -SurfacePlane::normal(Position r) const +Direction SurfacePlane::normal(Position r) const { return {A_, B_, C_}; } @@ -470,30 +380,31 @@ void SurfacePlane::to_hdf5_inner(hid_t group_id) const // The template parameters indicate the axes perpendicular to the axis of the // cylinder. offset1 and offset2 should correspond with i1 and i2, // respectively. -template double -axis_aligned_cylinder_evaluate(Position r, double offset1, - double offset2, double radius) +template +double axis_aligned_cylinder_evaluate( + Position r, double offset1, double offset2, double radius) { const double r1 = r.get() - offset1; const double r2 = r.get() - offset2; - return r1*r1 + r2*r2 - radius*radius; + return r1 * r1 + r2 * r2 - radius * radius; } // The first template parameter indicates which axis the cylinder is aligned to. // The other two parameters indicate the other two axes. offset1 and offset2 // should correspond with i2 and i3, respectively. -template double -axis_aligned_cylinder_distance(Position r, Direction u, - bool coincident, double offset1, double offset2, double radius) +template +double axis_aligned_cylinder_distance(Position r, Direction u, bool coincident, + double offset1, double offset2, double radius) { const double a = 1.0 - u.get() * u.get(); // u^2 + v^2 - if (a == 0.0) return INFTY; + if (a == 0.0) + return INFTY; const double r2 = r.get() - offset1; const double r3 = r.get() - offset2; const double k = r2 * u.get() + r3 * u.get(); - const double c = r2*r2 + r3*r3 - radius*radius; - const double quad = k*k - a*c; + const double c = r2 * r2 + r3 * r3 - radius * radius; + const double quad = k * k - a * c; if (quad < 0.0) { // No intersection with cylinder. @@ -520,7 +431,8 @@ axis_aligned_cylinder_distance(Position r, Direction u, // positive or negative. If positive, the smaller distance is the one // with positive sign on sqrt(quad). const double d = (-k - sqrt(quad)) / a; - if (d < 0.0) return INFTY; + if (d < 0.0) + return INFTY; return d; } } @@ -528,8 +440,9 @@ axis_aligned_cylinder_distance(Position r, Direction u, // The first template parameter indicates which axis the cylinder is aligned to. // The other two parameters indicate the other two axes. offset1 and offset2 // should correspond with i2 and i3, respectively. -template Direction -axis_aligned_cylinder_normal(Position r, double offset1, double offset2) +template +Direction axis_aligned_cylinder_normal( + Position r, double offset1, double offset2) { Direction u; u.get() = 2.0 * (r.get() - offset1); @@ -545,7 +458,7 @@ axis_aligned_cylinder_normal(Position r, double offset1, double offset2) SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, y0_, z0_, radius_); + read_coeffs(surf_node, id_, {&y0_, &z0_, &radius_}); } double SurfaceXCylinder::evaluate(Position r) const @@ -553,10 +466,11 @@ double SurfaceXCylinder::evaluate(Position r) const return axis_aligned_cylinder_evaluate<1, 2>(r, y0_, z0_, radius_); } -double SurfaceXCylinder::distance(Position r, Direction u, bool coincident) const +double SurfaceXCylinder::distance( + Position r, Direction u, bool coincident) const { - return axis_aligned_cylinder_distance<0, 1, 2>(r, u, coincident, y0_, z0_, - radius_); + return axis_aligned_cylinder_distance<0, 1, 2>( + r, u, coincident, y0_, z0_, radius_); } Direction SurfaceXCylinder::normal(Position r) const @@ -571,9 +485,11 @@ void SurfaceXCylinder::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -BoundingBox SurfaceXCylinder::bounding_box(bool pos_side) const { +BoundingBox SurfaceXCylinder::bounding_box(bool pos_side) const +{ if (!pos_side) { - return {-INFTY, INFTY, y0_ - radius_, y0_ + radius_, z0_ - radius_, z0_ + radius_}; + return {-INFTY, INFTY, y0_ - radius_, y0_ + radius_, z0_ - radius_, + z0_ + radius_}; } else { return {}; } @@ -585,7 +501,7 @@ BoundingBox SurfaceXCylinder::bounding_box(bool pos_side) const { SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, z0_, radius_); + read_coeffs(surf_node, id_, {&x0_, &z0_, &radius_}); } double SurfaceYCylinder::evaluate(Position r) const @@ -593,10 +509,11 @@ double SurfaceYCylinder::evaluate(Position r) const return axis_aligned_cylinder_evaluate<0, 2>(r, x0_, z0_, radius_); } -double SurfaceYCylinder::distance(Position r, Direction u, bool coincident) const +double SurfaceYCylinder::distance( + Position r, Direction u, bool coincident) const { - return axis_aligned_cylinder_distance<1, 0, 2>(r, u, coincident, x0_, z0_, - radius_); + return axis_aligned_cylinder_distance<1, 0, 2>( + r, u, coincident, x0_, z0_, radius_); } Direction SurfaceYCylinder::normal(Position r) const @@ -611,9 +528,11 @@ void SurfaceYCylinder::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -BoundingBox SurfaceYCylinder::bounding_box(bool pos_side) const { +BoundingBox SurfaceYCylinder::bounding_box(bool pos_side) const +{ if (!pos_side) { - return {x0_ - radius_, x0_ + radius_, -INFTY, INFTY, z0_ - radius_, z0_ + radius_}; + return {x0_ - radius_, x0_ + radius_, -INFTY, INFTY, z0_ - radius_, + z0_ + radius_}; } else { return {}; } @@ -626,7 +545,7 @@ BoundingBox SurfaceYCylinder::bounding_box(bool pos_side) const { SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, radius_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &radius_}); } double SurfaceZCylinder::evaluate(Position r) const @@ -634,10 +553,11 @@ double SurfaceZCylinder::evaluate(Position r) const return axis_aligned_cylinder_evaluate<0, 1>(r, x0_, y0_, radius_); } -double SurfaceZCylinder::distance(Position r, Direction u, bool coincident) const +double SurfaceZCylinder::distance( + Position r, Direction u, bool coincident) const { - return axis_aligned_cylinder_distance<2, 0, 1>(r, u, coincident, x0_, y0_, - radius_); + return axis_aligned_cylinder_distance<2, 0, 1>( + r, u, coincident, x0_, y0_, radius_); } Direction SurfaceZCylinder::normal(Position r) const @@ -652,23 +572,23 @@ void SurfaceZCylinder::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -BoundingBox SurfaceZCylinder::bounding_box(bool pos_side) const { +BoundingBox SurfaceZCylinder::bounding_box(bool pos_side) const +{ if (!pos_side) { - return {x0_ - radius_, x0_ + radius_, y0_ - radius_, y0_ + radius_, -INFTY, INFTY}; + return {x0_ - radius_, x0_ + radius_, y0_ - radius_, y0_ + radius_, -INFTY, + INFTY}; } else { return {}; } } - //============================================================================== // SurfaceSphere implementation //============================================================================== -SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) - : CSGSurface(surf_node) +SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_}); } double SurfaceSphere::evaluate(Position r) const @@ -676,7 +596,7 @@ double SurfaceSphere::evaluate(Position r) const const double x = r.x - x0_; const double y = r.y - y0_; const double z = r.z - z0_; - return x*x + y*y + z*z - radius_*radius_; + return x * x + y * y + z * z - radius_ * radius_; } double SurfaceSphere::distance(Position r, Direction u, bool coincident) const @@ -684,9 +604,9 @@ double SurfaceSphere::distance(Position r, Direction u, bool coincident) const const double x = r.x - x0_; const double y = r.y - y0_; const double z = r.z - z0_; - const double k = x*u.x + y*u.y + z*u.z; - const double c = x*x + y*y + z*z - radius_*radius_; - const double quad = k*k - c; + const double k = x * u.x + y * u.y + z * u.z; + const double c = x * x + y * y + z * z - radius_ * radius_; + const double quad = k * k - c; if (quad < 0.0) { // No intersection with sphere. @@ -712,14 +632,15 @@ double SurfaceSphere::distance(Position r, Direction u, bool coincident) const // or negative. If positive, the smaller distance is the one with positive // sign on sqrt(quad). const double d = -k - sqrt(quad); - if (d < 0.0) return INFTY; + if (d < 0.0) + return INFTY; return d; } } Direction SurfaceSphere::normal(Position r) const { - return {2.0*(r.x - x0_), 2.0*(r.y - y0_), 2.0*(r.z - z0_)}; + return {2.0 * (r.x - x0_), 2.0 * (r.y - y0_), 2.0 * (r.z - z0_)}; } void SurfaceSphere::to_hdf5_inner(hid_t group_id) const @@ -729,11 +650,11 @@ void SurfaceSphere::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } -BoundingBox SurfaceSphere::bounding_box(bool pos_side) const { +BoundingBox SurfaceSphere::bounding_box(bool pos_side) const +{ if (!pos_side) { - return {x0_ - radius_, x0_ + radius_, - y0_ - radius_, y0_ + radius_, - z0_ - radius_, z0_ + radius_}; + return {x0_ - radius_, x0_ + radius_, y0_ - radius_, y0_ + radius_, + z0_ - radius_, z0_ + radius_}; } else { return {}; } @@ -746,23 +667,22 @@ BoundingBox SurfaceSphere::bounding_box(bool pos_side) const { // The first template parameter indicates which axis the cone is aligned to. // The other two parameters indicate the other two axes. offset1, offset2, // and offset3 should correspond with i1, i2, and i3, respectively. -template double -axis_aligned_cone_evaluate(Position r, double offset1, - double offset2, double offset3, double radius_sq) +template +double axis_aligned_cone_evaluate( + Position r, double offset1, double offset2, double offset3, double radius_sq) { const double r1 = r.get() - offset1; const double r2 = r.get() - offset2; const double r3 = r.get() - offset3; - return r2*r2 + r3*r3 - radius_sq*r1*r1; + return r2 * r2 + r3 * r3 - radius_sq * r1 * r1; } // The first template parameter indicates which axis the cone is aligned to. // The other two parameters indicate the other two axes. offset1, offset2, // and offset3 should correspond with i1, i2, and i3, respectively. -template double -axis_aligned_cone_distance(Position r, Direction u, - bool coincident, double offset1, double offset2, double offset3, - double radius_sq) +template +double axis_aligned_cone_distance(Position r, Direction u, bool coincident, + double offset1, double offset2, double offset3, double radius_sq) { const double r1 = r.get() - offset1; const double r2 = r.get() - offset2; @@ -771,8 +691,8 @@ axis_aligned_cone_distance(Position r, Direction u, radius_sq * u.get() * u.get(); const double k = r2 * u.get() + r3 * u.get() - radius_sq * r1 * u.get(); - const double c = r2*r2 + r3*r3 - radius_sq*r1*r1; - double quad = k*k - a*c; + const double c = r2 * r2 + r3 * r3 - radius_sq * r1 * r1; + double quad = k * k - a * c; double d; @@ -798,25 +718,28 @@ axis_aligned_cone_distance(Position r, Direction u, // Determine the smallest positive solution. if (d < 0.0) { - if (b > 0.0) d = b; + if (b > 0.0) + d = b; } else { if (b > 0.0) { - if (b < d) d = b; + if (b < d) + d = b; } } } // If the distance was negative, set boundary distance to infinity. - if (d <= 0.0) return INFTY; + if (d <= 0.0) + return INFTY; return d; } // The first template parameter indicates which axis the cone is aligned to. // The other two parameters indicate the other two axes. offset1, offset2, // and offset3 should correspond with i1, i2, and i3, respectively. -template Direction -axis_aligned_cone_normal(Position r, double offset1, double offset2, - double offset3, double radius_sq) +template +Direction axis_aligned_cone_normal( + Position r, double offset1, double offset2, double offset3, double radius_sq) { Direction u; u.get() = -2.0 * radius_sq * (r.get() - offset1); @@ -829,10 +752,9 @@ axis_aligned_cone_normal(Position r, double offset1, double offset2, // SurfaceXCone implementation //============================================================================== -SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) - : CSGSurface(surf_node) +SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_sq_}); } double SurfaceXCone::evaluate(Position r) const @@ -842,8 +764,8 @@ double SurfaceXCone::evaluate(Position r) const double SurfaceXCone::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cone_distance<0, 1, 2>(r, u, coincident, x0_, y0_, z0_, - radius_sq_); + return axis_aligned_cone_distance<0, 1, 2>( + r, u, coincident, x0_, y0_, z0_, radius_sq_); } Direction SurfaceXCone::normal(Position r) const @@ -862,10 +784,9 @@ void SurfaceXCone::to_hdf5_inner(hid_t group_id) const // SurfaceYCone implementation //============================================================================== -SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) - : CSGSurface(surf_node) +SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_sq_}); } double SurfaceYCone::evaluate(Position r) const @@ -875,8 +796,8 @@ double SurfaceYCone::evaluate(Position r) const double SurfaceYCone::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cone_distance<1, 0, 2>(r, u, coincident, y0_, x0_, z0_, - radius_sq_); + return axis_aligned_cone_distance<1, 0, 2>( + r, u, coincident, y0_, x0_, z0_, radius_sq_); } Direction SurfaceYCone::normal(Position r) const @@ -895,10 +816,9 @@ void SurfaceYCone::to_hdf5_inner(hid_t group_id) const // SurfaceZCone implementation //============================================================================== -SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) - : CSGSurface(surf_node) +SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_sq_}); } double SurfaceZCone::evaluate(Position r) const @@ -908,8 +828,8 @@ double SurfaceZCone::evaluate(Position r) const double SurfaceZCone::distance(Position r, Direction u, bool coincident) const { - return axis_aligned_cone_distance<2, 0, 1>(r, u, coincident, z0_, x0_, y0_, - radius_sq_); + return axis_aligned_cone_distance<2, 0, 1>( + r, u, coincident, z0_, x0_, y0_, radius_sq_); } Direction SurfaceZCone::normal(Position r) const @@ -928,39 +848,39 @@ void SurfaceZCone::to_hdf5_inner(hid_t group_id) const // SurfaceQuadric implementation //============================================================================== -SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) - : CSGSurface(surf_node) +SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, A_, B_, C_, D_, E_, F_, G_, H_, J_, K_); + read_coeffs( + surf_node, id_, {&A_, &B_, &C_, &D_, &E_, &F_, &G_, &H_, &J_, &K_}); } -double -SurfaceQuadric::evaluate(Position r) const +double SurfaceQuadric::evaluate(Position r) const { const double x = r.x; const double y = r.y; const double z = r.z; - return x*(A_*x + D_*y + G_) + - y*(B_*y + E_*z + H_) + - z*(C_*z + F_*x + J_) + K_; + return x * (A_ * x + D_ * y + G_) + y * (B_ * y + E_ * z + H_) + + z * (C_ * z + F_ * x + J_) + K_; } -double -SurfaceQuadric::distance(Position r, Direction ang, bool coincident) const +double SurfaceQuadric::distance( + Position r, Direction ang, bool coincident) const { - const double &x = r.x; - const double &y = r.y; - const double &z = r.z; - const double &u = ang.x; - const double &v = ang.y; - const double &w = ang.z; + const double& x = r.x; + const double& y = r.y; + const double& z = r.z; + const double& u = ang.x; + const double& v = ang.y; + const double& w = ang.z; - const double a = A_*u*u + B_*v*v + C_*w*w + D_*u*v + E_*v*w + F_*u*w; - const double k = A_*u*x + B_*v*y + C_*w*z + 0.5*(D_*(u*y + v*x) - + E_*(v*z + w*y) + F_*(w*x + u*z) + G_*u + H_*v + J_*w); - const double c = A_*x*x + B_*y*y + C_*z*z + D_*x*y + E_*y*z + F_*x*z + G_*x - + H_*y + J_*z + K_; - double quad = k*k - a*c; + const double a = + A_ * u * u + B_ * v * v + C_ * w * w + D_ * u * v + E_ * v * w + F_ * u * w; + const double k = A_ * u * x + B_ * v * y + C_ * w * z + + 0.5 * (D_ * (u * y + v * x) + E_ * (v * z + w * y) + + F_ * (w * x + u * z) + G_ * u + H_ * v + J_ * w); + const double c = A_ * x * x + B_ * y * y + C_ * z * z + D_ * x * y + + E_ * y * z + F_ * x * z + G_ * x + H_ * y + J_ * z + K_; + double quad = k * k - a * c; double d; @@ -998,28 +918,29 @@ SurfaceQuadric::distance(Position r, Direction ang, bool coincident) const // Determine the smallest positive solution. if (d < 0.0) { - if (b > 0.0) d = b; + if (b > 0.0) + d = b; } else { if (b > 0.0) { - if (b < d) d = b; + if (b < d) + d = b; } } } // If the distance was negative, set boundary distance to infinity. - if (d <= 0.0) return INFTY; + if (d <= 0.0) + return INFTY; return d; } -Direction -SurfaceQuadric::normal(Position r) const +Direction SurfaceQuadric::normal(Position r) const { - const double &x = r.x; - const double &y = r.y; - const double &z = r.z; - return {2.0*A_*x + D_*y + F_*z + G_, - 2.0*B_*y + D_*x + E_*z + H_, - 2.0*C_*z + E_*y + F_*x + J_}; + const double& x = r.x; + const double& y = r.y; + const double& z = r.z; + return {2.0 * A_ * x + D_ * y + F_ * z + G_, + 2.0 * B_ * y + D_ * x + E_ * z + H_, 2.0 * C_ * z + E_ * y + F_ * x + J_}; } void SurfaceQuadric::to_hdf5_inner(hid_t group_id) const @@ -1029,21 +950,234 @@ void SurfaceQuadric::to_hdf5_inner(hid_t group_id) const write_dataset(group_id, "coefficients", coeffs); } +//============================================================================== +// Torus helper functions +//============================================================================== + +double torus_distance(double x1, double x2, double x3, double u1, double u2, + double u3, double A, double B, double C, bool coincident) +{ + // Coefficients for equation: (c2 t^2 + c1 t + c0)^2 = c2' t^2 + c1' t + c0' + double D = (C * C) / (B * B); + double c2 = u1 * u1 + u2 * u2 + D * u3 * u3; + double c1 = 2 * (u1 * x1 + u2 * x2 + D * u3 * x3); + double c0 = x1 * x1 + x2 * x2 + D * x3 * x3 + A * A - C * C; + double four_A2 = 4 * A * A; + double c2p = four_A2 * (u1 * u1 + u2 * u2); + double c1p = 2 * four_A2 * (u1 * x1 + u2 * x2); + double c0p = four_A2 * (x1 * x1 + x2 * x2); + + // Coefficient for equation: a t^4 + b t^3 + c t^2 + d t + e = 0. If the point + // is coincident, the 'e' coefficient should be zero. Explicitly setting it to + // zero helps avoid numerical issues below with root finding. + double coeff[5]; + coeff[0] = coincident ? 0.0 : c0 * c0 - c0p; + coeff[1] = 2 * c0 * c1 - c1p; + coeff[2] = c1 * c1 + 2 * c0 * c2 - c2p; + coeff[3] = 2 * c1 * c2; + coeff[4] = c2 * c2; + + std::complex roots[4]; + oqs::quartic_solver(coeff, roots); + + // Find smallest positive, real root. In the case where the particle is + // coincident with the surface, we are sure to have one root very close to + // zero but possibly small and positive. A tolerance is set to discard that + // zero. + double distance = INFTY; + double cutoff = coincident ? TORUS_TOL : 0.0; + for (int i = 0; i < 4; ++i) { + if (roots[i].imag() == 0) { + double root = roots[i].real(); + if (root > cutoff && root < distance) { + // Avoid roots corresponding to internal surfaces + double s1 = x1 + u1 * root; + double s2 = x2 + u2 * root; + double s3 = x3 + u3 * root; + double check = D * s3 * s3 + s1 * s1 + s2 * s2 + A * A - C * C; + if (check >= 0) { + distance = root; + } + } + } + } + return distance; +} + +//============================================================================== +// SurfaceXTorus implementation +//============================================================================== + +SurfaceXTorus::SurfaceXTorus(pugi::xml_node surf_node) : CSGSurface(surf_node) +{ + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &A_, &B_, &C_}); +} + +void SurfaceXTorus::to_hdf5_inner(hid_t group_id) const +{ + write_string(group_id, "type", "x-torus", false); + std::array coeffs {{x0_, y0_, z0_, A_, B_, C_}}; + write_dataset(group_id, "coefficients", coeffs); +} + +double SurfaceXTorus::evaluate(Position r) const +{ + double x = r.x - x0_; + double y = r.y - y0_; + double z = r.z - z0_; + return (x * x) / (B_ * B_) + + std::pow(std::sqrt(y * y + z * z) - A_, 2) / (C_ * C_) - 1.; +} + +double SurfaceXTorus::distance(Position r, Direction u, bool coincident) const +{ + double x = r.x - x0_; + double y = r.y - y0_; + double z = r.z - z0_; + return torus_distance(y, z, x, u.y, u.z, u.x, A_, B_, C_, coincident); +} + +Direction SurfaceXTorus::normal(Position r) const +{ + // reduce the expansion of the full form for torus + double x = r.x - x0_; + double y = r.y - y0_; + double z = r.z - z0_; + + // f(x,y,z) = x^2/B^2 + (sqrt(y^2 + z^2) - A)^2/C^2 - 1 + // ∂f/∂x = 2x/B^2 + // ∂f/∂y = 2y(g - A)/(g*C^2) where g = sqrt(y^2 + z^2) + // ∂f/∂z = 2z(g - A)/(g*C^2) + // Multiplying by g*C^2*B^2 / 2 gives: + double g = std::sqrt(y * y + z * z); + double nx = C_ * C_ * g * x; + double ny = y * (g - A_) * B_ * B_; + double nz = z * (g - A_) * B_ * B_; + Direction n(nx, ny, nz); + return n / n.norm(); +} + +//============================================================================== +// SurfaceYTorus implementation +//============================================================================== + +SurfaceYTorus::SurfaceYTorus(pugi::xml_node surf_node) : CSGSurface(surf_node) +{ + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &A_, &B_, &C_}); +} + +void SurfaceYTorus::to_hdf5_inner(hid_t group_id) const +{ + write_string(group_id, "type", "y-torus", false); + std::array coeffs {{x0_, y0_, z0_, A_, B_, C_}}; + write_dataset(group_id, "coefficients", coeffs); +} + +double SurfaceYTorus::evaluate(Position r) const +{ + double x = r.x - x0_; + double y = r.y - y0_; + double z = r.z - z0_; + return (y * y) / (B_ * B_) + + std::pow(std::sqrt(x * x + z * z) - A_, 2) / (C_ * C_) - 1.; +} + +double SurfaceYTorus::distance(Position r, Direction u, bool coincident) const +{ + double x = r.x - x0_; + double y = r.y - y0_; + double z = r.z - z0_; + return torus_distance(x, z, y, u.x, u.z, u.y, A_, B_, C_, coincident); +} + +Direction SurfaceYTorus::normal(Position r) const +{ + // reduce the expansion of the full form for torus + double x = r.x - x0_; + double y = r.y - y0_; + double z = r.z - z0_; + + // f(x,y,z) = y^2/B^2 + (sqrt(x^2 + z^2) - A)^2/C^2 - 1 + // ∂f/∂x = 2x(g - A)/(g*C^2) where g = sqrt(x^2 + z^2) + // ∂f/∂y = 2y/B^2 + // ∂f/∂z = 2z(g - A)/(g*C^2) + // Multiplying by g*C^2*B^2 / 2 gives: + double g = std::sqrt(x * x + z * z); + double nx = x * (g - A_) * B_ * B_; + double ny = C_ * C_ * g * y; + double nz = z * (g - A_) * B_ * B_; + Direction n(nx, ny, nz); + return n / n.norm(); +} + +//============================================================================== +// SurfaceZTorus implementation +//============================================================================== + +SurfaceZTorus::SurfaceZTorus(pugi::xml_node surf_node) : CSGSurface(surf_node) +{ + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &A_, &B_, &C_}); +} + +void SurfaceZTorus::to_hdf5_inner(hid_t group_id) const +{ + write_string(group_id, "type", "z-torus", false); + std::array coeffs {{x0_, y0_, z0_, A_, B_, C_}}; + write_dataset(group_id, "coefficients", coeffs); +} + +double SurfaceZTorus::evaluate(Position r) const +{ + double x = r.x - x0_; + double y = r.y - y0_; + double z = r.z - z0_; + return (z * z) / (B_ * B_) + + std::pow(std::sqrt(x * x + y * y) - A_, 2) / (C_ * C_) - 1.; +} + +double SurfaceZTorus::distance(Position r, Direction u, bool coincident) const +{ + double x = r.x - x0_; + double y = r.y - y0_; + double z = r.z - z0_; + return torus_distance(x, y, z, u.x, u.y, u.z, A_, B_, C_, coincident); +} + +Direction SurfaceZTorus::normal(Position r) const +{ + // reduce the expansion of the full form for torus + double x = r.x - x0_; + double y = r.y - y0_; + double z = r.z - z0_; + + // f(x,y,z) = z^2/B^2 + (sqrt(x^2 + y^2) - A)^2/C^2 - 1 + // ∂f/∂x = 2x(g - A)/(g*C^2) where g = sqrt(x^2 + y^2) + // ∂f/∂y = 2y(g - A)/(g*C^2) + // ∂f/∂z = 2z/B^2 + // Multiplying by g*C^2*B^2 / 2 gives: + double g = std::sqrt(x * x + y * y); + double nx = x * (g - A_) * B_ * B_; + double ny = y * (g - A_) * B_ * B_; + double nz = C_ * C_ * g * z; + Position n(nx, ny, nz); + return n / n.norm(); +} + //============================================================================== void read_surfaces(pugi::xml_node node) { // Count the number of surfaces int n_surfaces = 0; - for (pugi::xml_node surf_node : node.children("surface")) {n_surfaces++;} - if (n_surfaces == 0) { - fatal_error("No surfaces found in geometry.xml!"); + for (pugi::xml_node surf_node : node.children("surface")) { + n_surfaces++; } // Loop over XML surface elements and populate the array. Keep track of - // periodic surfaces. + // periodic surfaces and their albedos. model::surfaces.reserve(n_surfaces); std::set> periodic_pairs; + std::unordered_map albedo_map; { pugi::xml_node surf_node; int i_surf; @@ -1089,6 +1223,15 @@ void read_surfaces(pugi::xml_node node) } else if (surf_type == "quadric") { model::surfaces.push_back(make_unique(surf_node)); + } else if (surf_type == "x-torus") { + model::surfaces.push_back(std::make_unique(surf_node)); + + } else if (surf_type == "y-torus") { + model::surfaces.push_back(std::make_unique(surf_node)); + + } else if (surf_type == "z-torus") { + model::surfaces.push_back(std::make_unique(surf_node)); + } else { fatal_error(fmt::format("Invalid surface type, \"{}\"", surf_type)); } @@ -1097,9 +1240,15 @@ void read_surfaces(pugi::xml_node node) if (check_for_node(surf_node, "boundary")) { std::string surf_bc = get_node_value(surf_node, "boundary", true, true); if (surf_bc == "periodic") { + // Check for surface albedo. Skip sanity check as it is already done + // in the Surface class's constructor. + if (check_for_node(surf_node, "albedo")) { + albedo_map[model::surfaces.back()->id_] = + std::stod(get_node_value(surf_node, "albedo")); + } if (check_for_node(surf_node, "periodic_surface_id")) { - int i_periodic = std::stoi(get_node_value(surf_node, - "periodic_surface_id")); + int i_periodic = + std::stoi(get_node_value(surf_node, "periodic_surface_id")); int lo_id = std::min(model::surfaces.back()->id_, i_periodic); int hi_id = std::max(model::surfaces.back()->id_, i_periodic); periodic_pairs.insert({lo_id, hi_id}); @@ -1118,35 +1267,37 @@ void read_surfaces(pugi::xml_node node) if (in_map == model::surface_map.end()) { model::surface_map[id] = i_surf; } else { - fatal_error(fmt::format( - "Two or more surfaces use the same unique ID: {}", id)); + fatal_error( + fmt::format("Two or more surfaces use the same unique ID: {}", id)); } } // Resolve unpaired periodic surfaces. A lambda function is used with // std::find_if to identify the unpaired surfaces. - auto is_unresolved_pair = - [](const std::pair p){return p.second == -1;}; - auto first_unresolved = std::find_if(periodic_pairs.begin(), - periodic_pairs.end(), is_unresolved_pair); + auto is_unresolved_pair = [](const std::pair p) { + return p.second == -1; + }; + auto first_unresolved = std::find_if( + periodic_pairs.begin(), periodic_pairs.end(), is_unresolved_pair); if (first_unresolved != periodic_pairs.end()) { // Found one unpaired surface; search for a second one auto next_elem = first_unresolved; next_elem++; - auto second_unresolved = std::find_if(next_elem, periodic_pairs.end(), - is_unresolved_pair); + auto second_unresolved = + std::find_if(next_elem, periodic_pairs.end(), is_unresolved_pair); if (second_unresolved == periodic_pairs.end()) { fatal_error("Found only one periodic surface without a specified partner." - " Please specify the partner for each periodic surface."); + " Please specify the partner for each periodic surface."); } // Make sure there isn't a third unpaired surface next_elem = second_unresolved; next_elem++; - auto third_unresolved = std::find_if(next_elem, - periodic_pairs.end(), is_unresolved_pair); + auto third_unresolved = + std::find_if(next_elem, periodic_pairs.end(), is_unresolved_pair); if (third_unresolved != periodic_pairs.end()) { - fatal_error("Found at least three periodic surfaces without a specified " + fatal_error( + "Found at least three periodic surfaces without a specified " "partner. Please specify the partner for each periodic surface."); } @@ -1158,7 +1309,7 @@ void read_surfaces(pugi::xml_node node) periodic_pairs.erase(second_unresolved); } - // Assign the periodic boundary conditions + // Assign the periodic boundary conditions with albedos for (auto periodic_pair : periodic_pairs) { int i_surf = model::surface_map[periodic_pair.first]; int j_surf = model::surface_map[periodic_pair.second]; @@ -1176,25 +1327,20 @@ void read_surfaces(pugi::xml_node node) // planes are parallel which indicates a translational periodic boundary // condition. Otherwise, it is a rotational periodic BC. if (std::abs(1.0 - dot_prod) < FP_PRECISION) { - surf1.bc_ = std::make_shared(i_surf, j_surf); - surf2.bc_ = surf1.bc_; + surf1.bc_ = make_unique(i_surf, j_surf); + surf2.bc_ = make_unique(i_surf, j_surf); } else { - surf1.bc_ = std::make_shared(i_surf, j_surf); - surf2.bc_ = surf1.bc_; + surf1.bc_ = make_unique(i_surf, j_surf); + surf2.bc_ = make_unique(i_surf, j_surf); } - } - // Check to make sure a boundary condition was applied to at least one - // surface - bool boundary_exists = false; - for (const auto& surf : model::surfaces) { - if (surf->bc_) { - boundary_exists = true; - break; + // If albedo data is present in albedo map, set the boundary albedo. + if (albedo_map.count(surf1.id_)) { + surf1.bc_->set_albedo(albedo_map[surf1.id_]); + } + if (albedo_map.count(surf2.id_)) { + surf2.bc_->set_albedo(albedo_map[surf2.id_]); } - } - if (settings::run_mode != RunMode::PLOTTING && !boundary_exists) { - fatal_error("No boundary conditions were applied to any surfaces!"); } } diff --git a/src/tallies/derivative.cpp b/src/tallies/derivative.cpp index 41ea57370b5..57d66db0db1 100644 --- a/src/tallies/derivative.cpp +++ b/src/tallies/derivative.cpp @@ -18,9 +18,9 @@ namespace openmc { //============================================================================== namespace model { - std::unordered_map tally_deriv_map; - vector tally_derivs; -} +std::unordered_map tally_deriv_map; +vector tally_derivs; +} // namespace model //============================================================================== // TallyDerivative implementation @@ -55,13 +55,14 @@ TallyDerivative::TallyDerivative(pugi::xml_node node) } if (!found) { fatal_error(fmt::format("Could not find the nuclide \"{}\" specified in " - "derivative {} in any material.", nuclide_name, id)); + "derivative {} in any material.", + nuclide_name, id)); } } else if (variable_str == "temperature") { variable = DerivativeVariable::TEMPERATURE; } else { - fatal_error(fmt::format("Unrecognized variable \"{}\" on derivative {}", - variable_str, id)); + fatal_error(fmt::format( + "Unrecognized variable \"{}\" on derivative {}", variable_str, id)); } diff_material = std::stoi(get_node_value(node, "material")); @@ -71,8 +72,7 @@ TallyDerivative::TallyDerivative(pugi::xml_node node) // Non-method functions //============================================================================== -void -read_tally_derivatives(pugi::xml_node node) +void read_tally_derivatives(pugi::xml_node node) { // Populate the derivatives array. for (auto deriv_node : node.children("derivative")) @@ -85,8 +85,8 @@ read_tally_derivatives(pugi::xml_node node) if (search == model::tally_deriv_map.end()) { model::tally_deriv_map[id] = i; } else { - fatal_error("Two or more derivatives use the same unique ID: " - + std::to_string(id)); + fatal_error("Two or more derivatives use the same unique ID: " + + std::to_string(id)); } } @@ -95,13 +95,13 @@ read_tally_derivatives(pugi::xml_node node) fatal_error("Differential tallies not supported in multi-group mode"); } -void -apply_derivative_to_score(const Particle& p, int i_tally, int i_nuclide, +void apply_derivative_to_score(const Particle& p, int i_tally, int i_nuclide, double atom_density, int score_bin, double& score) { const Tally& tally {*model::tallies[i_tally]}; - if (score == 0.0) return; + if (score == 0.0) + return; // If our score was previously c then the new score is // c * (1/f * d_f/d_p + 1/c * d_c/d_p) @@ -127,13 +127,13 @@ apply_derivative_to_score(const Particle& p, int i_tally, int i_nuclide, switch (deriv.variable) { - //============================================================================ - // Density derivative: - // c = Sigma_MT - // c = sigma_MT * N - // c = sigma_MT * rho * const - // d_c / d_rho = sigma_MT * const - // (1 / c) * (d_c / d_rho) = 1 / rho + //============================================================================ + // Density derivative: + // c = Sigma_MT + // c = sigma_MT * N + // c = sigma_MT * rho * const + // d_c / d_rho = sigma_MT * const + // (1 / c) * (d_c / d_rho) = 1 / rho case DerivativeVariable::DENSITY: switch (tally.estimator_) { @@ -151,29 +151,29 @@ apply_derivative_to_score(const Particle& p, int i_tally, int i_nuclide, break; default: - fatal_error("Tally derivative not defined for a score on tally " - + std::to_string(tally.id_)); + fatal_error("Tally derivative not defined for a score on tally " + + std::to_string(tally.id_)); } break; default: fatal_error("Differential tallies are only implemented for analog and " - "collision estimators."); + "collision estimators."); } break; - //============================================================================ - // Nuclide density derivative: - // If we are scoring a reaction rate for a single nuclide then - // c = Sigma_MT_i - // c = sigma_MT_i * N_i - // d_c / d_N_i = sigma_MT_i - // (1 / c) * (d_c / d_N_i) = 1 / N_i - // If the score is for the total material (i_nuclide = -1) - // c = Sum_i(Sigma_MT_i) - // d_c / d_N_i = sigma_MT_i - // (1 / c) * (d_c / d_N) = sigma_MT_i / Sigma_MT - // where i is the perturbed nuclide. + //============================================================================ + // Nuclide density derivative: + // If we are scoring a reaction rate for a single nuclide then + // c = Sigma_MT_i + // c = sigma_MT_i * N_i + // d_c / d_N_i = sigma_MT_i + // (1 / c) * (d_c / d_N_i) = 1 / N_i + // If the score is for the total material (i_nuclide = -1) + // c = Sum_i(Sigma_MT_i) + // d_c / d_N_i = sigma_MT_i + // (1 / c) * (d_c / d_N) = sigma_MT_i / Sigma_MT + // where i is the perturbed nuclide. case DerivativeVariable::NUCLIDE_DENSITY: switch (tally.estimator_) { @@ -190,19 +190,18 @@ apply_derivative_to_score(const Particle& p, int i_tally, int i_nuclide, case SCORE_SCATTER: case SCORE_ABSORPTION: case SCORE_FISSION: - case SCORE_NU_FISSION: - { - // Find the index of the perturbed nuclide. - int i; - for (i = 0; i < material.nuclide_.size(); ++i) - if (material.nuclide_[i] == deriv.diff_nuclide) break; - score *= flux_deriv + 1. / material.atom_density_(i); - } - break; + case SCORE_NU_FISSION: { + // Find the index of the perturbed nuclide. + int i; + for (i = 0; i < material.nuclide_.size(); ++i) + if (material.nuclide_[i] == deriv.diff_nuclide) + break; + score *= flux_deriv + 1. / material.atom_density_(i); + } break; default: - fatal_error("Tally derivative not defined for a score on tally " - + std::to_string(tally.id_)); + fatal_error("Tally derivative not defined for a score on tally " + + std::to_string(tally.id_)); } break; @@ -272,120 +271,117 @@ apply_derivative_to_score(const Particle& p, int i_tally, int i_nuclide, break; default: - fatal_error("Tally derivative not defined for a score on tally " - + std::to_string(tally.id_)); + fatal_error("Tally derivative not defined for a score on tally " + + std::to_string(tally.id_)); } break; default: fatal_error("Differential tallies are only implemented for analog and " - "collision estimators."); + "collision estimators."); } break; - //============================================================================ - // Temperature derivative: - // If we are scoring a reaction rate for a single nuclide then - // c = Sigma_MT_i - // c = sigma_MT_i * N_i - // d_c / d_T = (d_sigma_Mt_i / d_T) * N_i - // (1 / c) * (d_c / d_T) = (d_sigma_MT_i / d_T) / sigma_MT_i - // If the score is for the total material (i_nuclide = -1) - // (1 / c) * (d_c / d_T) = Sum_i((d_sigma_MT_i / d_T) * N_i) / Sigma_MT_i - // where i is the perturbed nuclide. The d_sigma_MT_i / d_T term is - // computed by multipole_deriv_eval. It only works for the resolved - // resonance range and requires multipole data. + //============================================================================ + // Temperature derivative: + // If we are scoring a reaction rate for a single nuclide then + // c = Sigma_MT_i + // c = sigma_MT_i * N_i + // d_c / d_T = (d_sigma_Mt_i / d_T) * N_i + // (1 / c) * (d_c / d_T) = (d_sigma_MT_i / d_T) / sigma_MT_i + // If the score is for the total material (i_nuclide = -1) + // (1 / c) * (d_c / d_T) = Sum_i((d_sigma_MT_i / d_T) * N_i) / Sigma_MT_i + // where i is the perturbed nuclide. The d_sigma_MT_i / d_T term is + // computed by multipole_deriv_eval. It only works for the resolved + // resonance range and requires multipole data. case DerivativeVariable::TEMPERATURE: switch (tally.estimator_) { - case TallyEstimator::ANALOG: - { - // Find the index of the event nuclide. - int i; - for (i = 0; i < material.nuclide_.size(); ++i) - if (material.nuclide_[i] == p.event_nuclide()) - break; - - const auto& nuc {*data::nuclides[p.event_nuclide()]}; - if (!multipole_in_range(nuc, p.E_last())) { - score *= flux_deriv; + case TallyEstimator::ANALOG: { + // Find the index of the event nuclide. + int i; + for (i = 0; i < material.nuclide_.size(); ++i) + if (material.nuclide_[i] == p.event_nuclide()) break; - } - switch (score_bin) { - - case SCORE_TOTAL: - if (p.neutron_xs(p.event_nuclide()).total) { - double dsig_s, dsig_a, dsig_f; - std::tie(dsig_s, dsig_a, dsig_f) = - nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); - score *= flux_deriv + (dsig_s + dsig_a) * - material.atom_density_(i) / - p.macro_xs().total; - } else { - score *= flux_deriv; - } - break; + const auto& nuc {*data::nuclides[p.event_nuclide()]}; + if (!multipole_in_range(nuc, p.E_last())) { + score *= flux_deriv; + break; + } - case SCORE_SCATTER: - if (p.neutron_xs(p.event_nuclide()).total - - p.neutron_xs(p.event_nuclide()).absorption) { - double dsig_s, dsig_a, dsig_f; - std::tie(dsig_s, dsig_a, dsig_f) = - nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); - score *= - flux_deriv + dsig_s * material.atom_density_(i) / - (p.macro_xs().total - p.macro_xs().absorption); - } else { - score *= flux_deriv; - } - break; + switch (score_bin) { - case SCORE_ABSORPTION: - if (p.neutron_xs(p.event_nuclide()).absorption) { - double dsig_s, dsig_a, dsig_f; - std::tie(dsig_s, dsig_a, dsig_f) = - nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); - score *= flux_deriv + dsig_a * material.atom_density_(i) / - p.macro_xs().absorption; - } else { - score *= flux_deriv; - } - break; + case SCORE_TOTAL: + if (p.neutron_xs(p.event_nuclide()).total) { + double dsig_s, dsig_a, dsig_f; + std::tie(dsig_s, dsig_a, dsig_f) = + nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); + score *= flux_deriv + (dsig_s + dsig_a) * material.atom_density_(i) / + p.macro_xs().total; + } else { + score *= flux_deriv; + } + break; - case SCORE_FISSION: - if (p.neutron_xs(p.event_nuclide()).fission) { - double dsig_s, dsig_a, dsig_f; - std::tie(dsig_s, dsig_a, dsig_f) = - nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); - score *= flux_deriv + - dsig_f * material.atom_density_(i) / p.macro_xs().fission; - } else { - score *= flux_deriv; - } - break; + case SCORE_SCATTER: + if (p.neutron_xs(p.event_nuclide()).total - + p.neutron_xs(p.event_nuclide()).absorption) { + double dsig_s, dsig_a, dsig_f; + std::tie(dsig_s, dsig_a, dsig_f) = + nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); + score *= + flux_deriv + dsig_s * material.atom_density_(i) / + (p.macro_xs().total - p.macro_xs().absorption); + } else { + score *= flux_deriv; + } + break; - case SCORE_NU_FISSION: - if (p.neutron_xs(p.event_nuclide()).fission) { - double nu = p.neutron_xs(p.event_nuclide()).nu_fission / - p.neutron_xs(p.event_nuclide()).fission; - double dsig_s, dsig_a, dsig_f; - std::tie(dsig_s, dsig_a, dsig_f) = - nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); - score *= flux_deriv + nu * dsig_f * material.atom_density_(i) / - p.macro_xs().nu_fission; - } else { - score *= flux_deriv; - } - break; + case SCORE_ABSORPTION: + if (p.neutron_xs(p.event_nuclide()).absorption) { + double dsig_s, dsig_a, dsig_f; + std::tie(dsig_s, dsig_a, dsig_f) = + nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); + score *= flux_deriv + + dsig_a * material.atom_density_(i) / p.macro_xs().absorption; + } else { + score *= flux_deriv; + } + break; + + case SCORE_FISSION: + if (p.neutron_xs(p.event_nuclide()).fission) { + double dsig_s, dsig_a, dsig_f; + std::tie(dsig_s, dsig_a, dsig_f) = + nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); + score *= flux_deriv + + dsig_f * material.atom_density_(i) / p.macro_xs().fission; + } else { + score *= flux_deriv; + } + break; - default: - fatal_error("Tally derivative not defined for a score on tally " - + std::to_string(tally.id_)); + case SCORE_NU_FISSION: + if (p.neutron_xs(p.event_nuclide()).fission) { + double nu = p.neutron_xs(p.event_nuclide()).nu_fission / + p.neutron_xs(p.event_nuclide()).fission; + double dsig_s, dsig_a, dsig_f; + std::tie(dsig_s, dsig_a, dsig_f) = + nuc.multipole_->evaluate_deriv(p.E_last(), p.sqrtkT()); + score *= flux_deriv + nu * dsig_f * material.atom_density_(i) / + p.macro_xs().nu_fission; + } else { + score *= flux_deriv; } + break; + + default: + fatal_error("Tally derivative not defined for a score on tally " + + std::to_string(tally.id_)); } - break; + } break; case TallyEstimator::COLLISION: if (i_nuclide != -1) { @@ -541,14 +537,13 @@ apply_derivative_to_score(const Particle& p, int i_tally, int i_nuclide, default: fatal_error("Differential tallies are only implemented for analog and " - "collision estimators."); + "collision estimators."); } break; } } -void -score_track_derivative(Particle& p, double distance) +void score_track_derivative(Particle& p, double distance) { // A void material cannot be perturbed so it will not affect flux derivatives. if (p.material() == MATERIAL_VOID) @@ -559,7 +554,8 @@ score_track_derivative(Particle& p, double distance) for (auto idx = 0; idx < model::tally_derivs.size(); idx++) { const auto& deriv = model::tally_derivs[idx]; auto& flux_deriv = p.flux_derivs(idx); - if (deriv.diff_material != material.id_) continue; + if (deriv.diff_material != material.id_) + continue; switch (deriv.variable) { @@ -587,8 +583,8 @@ score_track_derivative(Particle& p, double distance) double dsig_s, dsig_a, dsig_f; std::tie(dsig_s, dsig_a, dsig_f) = nuc.multipole_->evaluate_deriv(p.E(), p.sqrtkT()); - flux_deriv -= distance * (dsig_s + dsig_a) - * material.atom_density_(i); + flux_deriv -= + distance * (dsig_s + dsig_a) * material.atom_density_(i); } } break; @@ -608,7 +604,8 @@ void score_collision_derivative(Particle& p) const auto& deriv = model::tally_derivs[idx]; auto& flux_deriv = p.flux_derivs(idx); - if (deriv.diff_material != material.id_) continue; + if (deriv.diff_material != material.id_) + continue; switch (deriv.variable) { @@ -625,7 +622,8 @@ void score_collision_derivative(Particle& p) // Find the index in this material for the diff_nuclide. int i; for (i = 0; i < material.nuclide_.size(); ++i) - if (material.nuclide_[i] == deriv.diff_nuclide) break; + if (material.nuclide_[i] == deriv.diff_nuclide) + break; // Make sure we found the nuclide. if (material.nuclide_[i] != deriv.diff_nuclide) { fatal_error(fmt::format( @@ -666,4 +664,4 @@ void score_collision_derivative(Particle& p) } } -}// namespace openmc +} // namespace openmc diff --git a/src/tallies/filter.cpp b/src/tallies/filter.cpp index 55916401f42..ff7a3416b90 100644 --- a/src/tallies/filter.cpp +++ b/src/tallies/filter.cpp @@ -1,28 +1,29 @@ #include "openmc/tallies/filter.h" #include // for max -#include // for strcpy +#include // for strcpy #include #include #include "openmc/capi.h" -#include "openmc/constants.h" // for MAX_LINE_LEN; +#include "openmc/constants.h" // for MAX_LINE_LEN; #include "openmc/error.h" -#include "openmc/xml_interface.h" #include "openmc/tallies/filter_azimuthal.h" #include "openmc/tallies/filter_cell.h" +#include "openmc/tallies/filter_cell_instance.h" #include "openmc/tallies/filter_cellborn.h" #include "openmc/tallies/filter_cellfrom.h" -#include "openmc/tallies/filter_cell_instance.h" #include "openmc/tallies/filter_collision.h" #include "openmc/tallies/filter_delayedgroup.h" #include "openmc/tallies/filter_distribcell.h" -#include "openmc/tallies/filter_energyfunc.h" #include "openmc/tallies/filter_energy.h" +#include "openmc/tallies/filter_energyfunc.h" #include "openmc/tallies/filter_legendre.h" #include "openmc/tallies/filter_material.h" +#include "openmc/tallies/filter_materialfrom.h" #include "openmc/tallies/filter_mesh.h" +#include "openmc/tallies/filter_meshborn.h" #include "openmc/tallies/filter_meshsurface.h" #include "openmc/tallies/filter_mu.h" #include "openmc/tallies/filter_particle.h" @@ -30,8 +31,10 @@ #include "openmc/tallies/filter_sph_harm.h" #include "openmc/tallies/filter_sptl_legendre.h" #include "openmc/tallies/filter_surface.h" +#include "openmc/tallies/filter_time.h" #include "openmc/tallies/filter_universe.h" #include "openmc/tallies/filter_zernike.h" +#include "openmc/xml_interface.h" // explicit template instantiation definition template class openmc::vector; @@ -43,9 +46,9 @@ namespace openmc { //============================================================================== namespace model { - std::unordered_map filter_map; - vector> tally_filters; -} +std::unordered_map filter_map; +vector> tally_filters; +} // namespace model //============================================================================== // Non-member functions @@ -70,20 +73,6 @@ Filter::~Filter() model::filter_map.erase(id_); } -template -T* Filter::create(int32_t id) { - static_assert(std::is_base_of::value, - "Type specified is not derived from openmc::Filter"); - // Create filter and add to filters vector - auto filter = make_unique(); - auto ptr_out = filter.get(); - model::tally_filters.emplace_back(std::move(filter)); - // Assign ID - model::tally_filters.back()->set_id(id); - - return ptr_out; -} - Filter* Filter::create(pugi::xml_node node) { // Copy filter id @@ -113,7 +102,7 @@ Filter* Filter::create(const std::string& type, int32_t id) } else if (type == "cell") { return Filter::create(id); } else if (type == "cellborn") { - return Filter::create(id); + return Filter::create(id); } else if (type == "cellfrom") { return Filter::create(id); } else if (type == "cellinstance") { @@ -134,8 +123,12 @@ Filter* Filter::create(const std::string& type, int32_t id) return Filter::create(id); } else if (type == "material") { return Filter::create(id); + } else if (type == "materialfrom") { + return Filter::create(id); } else if (type == "mesh") { return Filter::create(id); + } else if (type == "meshborn") { + return Filter::create(id); } else if (type == "meshsurface") { return Filter::create(id); } else if (type == "mu") { @@ -150,6 +143,8 @@ Filter* Filter::create(const std::string& type, int32_t id) return Filter::create(id); } else if (type == "sphericalharmonics") { return Filter::create(id); + } else if (type == "time") { + return Filter::create(id); } else if (type == "universe") { return Filter::create(id); } else if (type == "zernike") { @@ -157,7 +152,7 @@ Filter* Filter::create(const std::string& type, int32_t id) } else if (type == "zernikeradial") { return Filter::create(id); } else { - throw std::runtime_error{fmt::format("Unknown filter type: {}", type)}; + throw std::runtime_error {fmt::format("Unknown filter type: {}", type)}; } return nullptr; } @@ -174,7 +169,8 @@ void Filter::set_id(int32_t id) // Make sure no other filter has same ID if (model::filter_map.find(id) != model::filter_map.end()) { - throw std::runtime_error{"Two filters have the same ID: " + std::to_string(id)}; + throw std::runtime_error { + "Two filters have the same ID: " + std::to_string(id)}; } // If no ID specified, auto-assign next ID in sequence @@ -204,35 +200,43 @@ int verify_filter(int32_t index) return 0; } -extern "C" int -openmc_filter_get_id(int32_t index, int32_t* id) +extern "C" int openmc_filter_get_id(int32_t index, int32_t* id) { - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; *id = model::tally_filters[index]->id(); return 0; } -extern "C" int -openmc_filter_set_id(int32_t index, int32_t id) +extern "C" int openmc_filter_set_id(int32_t index, int32_t id) { - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; model::tally_filters[index]->set_id(id); return 0; } -extern "C" int -openmc_filter_get_type(int32_t index, char* type) +extern "C" int openmc_filter_get_type(int32_t index, char* type) +{ + if (int err = verify_filter(index)) + return err; + + std::strcpy(type, model::tally_filters[index]->type_str().c_str()); + return 0; +} + +extern "C" int openmc_filter_get_num_bins(int32_t index, int* n_bins) { - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; - std::strcpy(type, model::tally_filters[index]->type().c_str()); + *n_bins = model::tally_filters[index]->n_bins(); return 0; } -extern "C" int -openmc_get_filter_index(int32_t id, int32_t* index) +extern "C" int openmc_get_filter_index(int32_t id, int32_t* index) { auto it = model::filter_map.find(id); if (it == model::filter_map.end()) { @@ -244,8 +248,7 @@ openmc_get_filter_index(int32_t id, int32_t* index) return 0; } -extern "C" void -openmc_get_filter_next_id(int32_t* id) +extern "C" void openmc_get_filter_next_id(int32_t* id) { int32_t largest_filter_id = 0; for (const auto& t : model::tally_filters) { @@ -254,8 +257,7 @@ openmc_get_filter_next_id(int32_t* id) *id = largest_filter_id + 1; } -extern "C" int -openmc_new_filter(const char* type, int32_t* index) +extern "C" int openmc_new_filter(const char* type, int32_t* index) { *index = model::tally_filters.size(); Filter::create(type); diff --git a/src/tallies/filter_azimuthal.cpp b/src/tallies/filter_azimuthal.cpp index 7bf5343b79e..e77aa8bdc1e 100644 --- a/src/tallies/filter_azimuthal.cpp +++ b/src/tallies/filter_azimuthal.cpp @@ -11,8 +11,7 @@ namespace openmc { -void -AzimuthalFilter::from_xml(pugi::xml_node node) +void AzimuthalFilter::from_xml(pugi::xml_node node) { auto bins = get_node_array(node, "bins"); @@ -21,12 +20,14 @@ AzimuthalFilter::from_xml(pugi::xml_node node) // [-pi,pi) evenly with the input being the number of bins int n_angle = bins[0]; - if (n_angle <= 1) throw std::runtime_error{ - "Number of bins for azimuthal filter must be greater than 1."}; + if (n_angle <= 1) + throw std::runtime_error { + "Number of bins for azimuthal filter must be greater than 1."}; double d_angle = 2.0 * PI / n_angle; bins.resize(n_angle + 1); - for (int i = 0; i < n_angle; i++) bins[i] = -PI + i * d_angle; + for (int i = 0; i < n_angle; i++) + bins[i] = -PI + i * d_angle; bins[n_angle] = PI; } @@ -41,8 +42,9 @@ void AzimuthalFilter::set_bins(gsl::span bins) // Copy bins, ensuring they are valid for (gsl::index i = 0; i < bins.size(); ++i) { - if (i > 0 && bins[i] <= bins[i-1]) { - throw std::runtime_error{"Azimuthal bins must be monotonically increasing."}; + if (i > 0 && bins[i] <= bins[i - 1]) { + throw std::runtime_error { + "Azimuthal bins must be monotonically increasing."}; } bins_.push_back(bins[i]); } @@ -50,9 +52,8 @@ void AzimuthalFilter::set_bins(gsl::span bins) n_bins_ = bins_.size() - 1; } -void -AzimuthalFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void AzimuthalFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { Direction u = (estimator == TallyEstimator::TRACKLENGTH) ? p.u() : p.u_last(); double phi = std::atan2(u.y, u.x); @@ -64,17 +65,16 @@ AzimuthalFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -AzimuthalFilter::to_statepoint(hid_t filter_group) const +void AzimuthalFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "bins", bins_); } -std::string -AzimuthalFilter::text_label(int bin) const +std::string AzimuthalFilter::text_label(int bin) const { - return fmt::format("Azimuthal Angle [{}, {})", bins_.at(bin), bins_.at(bin+1)); + return fmt::format( + "Azimuthal Angle [{}, {})", bins_.at(bin), bins_.at(bin + 1)); } } // namespace openmc diff --git a/src/tallies/filter_cell.cpp b/src/tallies/filter_cell.cpp index 10fa0040eaa..794d2ae08b0 100644 --- a/src/tallies/filter_cell.cpp +++ b/src/tallies/filter_cell.cpp @@ -9,16 +9,15 @@ namespace openmc { -void -CellFilter::from_xml(pugi::xml_node node) +void CellFilter::from_xml(pugi::xml_node node) { // Get cell IDs and convert to indices into the global cells vector auto cells = get_node_array(node, "bins"); for (auto& c : cells) { auto search = model::cell_map.find(c); if (search == model::cell_map.end()) { - throw std::runtime_error{fmt::format( - "Could not find cell {} specified on tally filter.", c)}; + throw std::runtime_error { + fmt::format("Could not find cell {} specified on tally filter.", c)}; } c = search->second; } @@ -26,8 +25,7 @@ CellFilter::from_xml(pugi::xml_node node) this->set_cells(cells); } -void -CellFilter::set_cells(gsl::span cells) +void CellFilter::set_cells(gsl::span cells) { // Clear existing cells cells_.clear(); @@ -45,9 +43,8 @@ CellFilter::set_cells(gsl::span cells) n_bins_ = cells_.size(); } -void -CellFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void CellFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { for (int i = 0; i < p.n_coord(); i++) { auto search = map_.find(p.coord(i).cell); @@ -58,17 +55,16 @@ CellFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -CellFilter::to_statepoint(hid_t filter_group) const +void CellFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); vector cell_ids; - for (auto c : cells_) cell_ids.push_back(model::cells[c]->id_); + for (auto c : cells_) + cell_ids.push_back(model::cells[c]->id_); write_dataset(filter_group, "bins", cell_ids); } -std::string -CellFilter::text_label(int bin) const +std::string CellFilter::text_label(int bin) const { return fmt::format("Cell {}", model::cells[cells_[bin]]->id_); } @@ -77,13 +73,14 @@ CellFilter::text_label(int bin) const // C-API functions //============================================================================== -extern "C" int -openmc_cell_filter_get_bins(int32_t index, const int32_t** cells, int32_t* n) +extern "C" int openmc_cell_filter_get_bins( + int32_t index, const int32_t** cells, int32_t* n) { - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; const auto& filt = model::tally_filters[index].get(); - if (filt->type() != "cell") { + if (filt->type() != FilterType::CELL) { set_errmsg("Tried to get cells from a non-cell filter."); return OPENMC_E_INVALID_TYPE; } diff --git a/src/tallies/filter_cell_instance.cpp b/src/tallies/filter_cell_instance.cpp index c410776315b..3e78a5bbed9 100644 --- a/src/tallies/filter_cell_instance.cpp +++ b/src/tallies/filter_cell_instance.cpp @@ -7,6 +7,7 @@ #include "openmc/capi.h" #include "openmc/cell.h" #include "openmc/error.h" +#include "openmc/geometry.h" #include "openmc/xml_interface.h" namespace openmc { @@ -16,8 +17,7 @@ CellInstanceFilter::CellInstanceFilter(gsl::span instances) this->set_cell_instances(instances); } -void -CellInstanceFilter::from_xml(pugi::xml_node node) +void CellInstanceFilter::from_xml(pugi::xml_node node) { // Get cell IDs/instances auto cells = get_node_array(node, "bins"); @@ -26,11 +26,11 @@ CellInstanceFilter::from_xml(pugi::xml_node node) // Convert into vector of CellInstance vector instances; for (gsl::index i = 0; i < cells.size() / 2; ++i) { - int32_t cell_id = cells[2*i]; - gsl::index instance = cells[2*i + 1]; + int32_t cell_id = cells[2 * i]; + gsl::index instance = cells[2 * i + 1]; auto search = model::cell_map.find(cell_id); if (search == model::cell_map.end()) { - throw std::runtime_error{fmt::format( + throw std::runtime_error {fmt::format( "Could not find cell {} specified on tally filter.", cell_id)}; } gsl::index index = search->second; @@ -40,47 +40,70 @@ CellInstanceFilter::from_xml(pugi::xml_node node) this->set_cell_instances(instances); } -void -CellInstanceFilter::set_cell_instances(gsl::span instances) +void CellInstanceFilter::set_cell_instances(gsl::span instances) { // Clear existing cells cell_instances_.clear(); cell_instances_.reserve(instances.size()); + cells_.clear(); map_.clear(); // Update cells and mapping for (auto& x : instances) { Expects(x.index_cell >= 0); Expects(x.index_cell < model::cells.size()); - const auto& c {model::cells[x.index_cell]}; - if (c->type_ != Fill::MATERIAL) { - throw std::invalid_argument{fmt::format( - "Cell {} is not filled with a material. Only material cells can be " - "used in a cell instance filter.", c->id_)}; - } cell_instances_.push_back(x); + cells_.insert(x.index_cell); map_[x] = cell_instances_.size() - 1; } n_bins_ = cell_instances_.size(); + + material_cells_only_ = true; + for (const auto& cell_inst : cell_instances_) { + const auto& c = *model::cells[cell_inst.index_cell]; + if (c.type_ == Fill::MATERIAL) + continue; + material_cells_only_ = false; + break; + } } -void -CellInstanceFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void CellInstanceFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { - gsl::index index_cell = p.coord(p.n_coord() - 1).cell; + gsl::index index_cell = p.lowest_coord().cell; gsl::index instance = p.cell_instance(); - auto search = map_.find({index_cell, instance}); - if (search != map_.end()) { - int index_bin = search->second; - match.bins_.push_back(index_bin); - match.weights_.push_back(1.0); + + if (cells_.count(index_cell) > 0) { + auto search = map_.find({index_cell, instance}); + if (search != map_.end()) { + int index_bin = search->second; + match.bins_.push_back(index_bin); + match.weights_.push_back(1.0); + } + } + + if (material_cells_only_) + return; + + for (int i = 0; i < p.n_coord() - 1; i++) { + gsl::index index_cell = p.coord(i).cell; + // if this cell isn't used on the filter, move on + if (cells_.count(index_cell) == 0) + continue; + + // if this cell is used in the filter, check the instance as well + gsl::index instance = cell_instance_at_level(p, i); + auto search = map_.find({index_cell, instance}); + if (search != map_.end()) { + match.bins_.push_back(search->second); + match.weights_.push_back(1.0); + } } } -void -CellInstanceFilter::to_statepoint(hid_t filter_group) const +void CellInstanceFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); size_t n = cell_instances_.size(); @@ -93,13 +116,12 @@ CellInstanceFilter::to_statepoint(hid_t filter_group) const write_dataset(filter_group, "bins", data); } -std::string -CellInstanceFilter::text_label(int bin) const +std::string CellInstanceFilter::text_label(int bin) const { const auto& x = cell_instances_[bin]; auto cell_id = model::cells[x.index_cell]->id_; - return "Cell " + std::to_string(cell_id) + ", Instance " - + std::to_string(x.instance); + return "Cell " + std::to_string(cell_id) + ", Instance " + + std::to_string(x.instance); } } // namespace openmc diff --git a/src/tallies/filter_cellborn.cpp b/src/tallies/filter_cellborn.cpp index ac5b8be9d2f..ad8363e7b4d 100644 --- a/src/tallies/filter_cellborn.cpp +++ b/src/tallies/filter_cellborn.cpp @@ -4,9 +4,8 @@ namespace openmc { -void -CellbornFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void CellBornFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { auto search = map_.find(p.cell_born()); if (search != map_.end()) { @@ -15,8 +14,7 @@ CellbornFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -std::string -CellbornFilter::text_label(int bin) const +std::string CellBornFilter::text_label(int bin) const { return "Birth Cell " + std::to_string(model::cells[cells_[bin]]->id_); } diff --git a/src/tallies/filter_cellfrom.cpp b/src/tallies/filter_cellfrom.cpp index 9d6af07dd1e..3c2003263d1 100644 --- a/src/tallies/filter_cellfrom.cpp +++ b/src/tallies/filter_cellfrom.cpp @@ -4,9 +4,8 @@ namespace openmc { -void -CellFromFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void CellFromFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { for (int i = 0; i < p.n_coord_last(); i++) { auto search = map_.find(p.cell_last(i)); @@ -17,8 +16,7 @@ CellFromFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -std::string -CellFromFilter::text_label(int bin) const +std::string CellFromFilter::text_label(int bin) const { return "Cell from " + std::to_string(model::cells[cells_[bin]]->id_); } diff --git a/src/tallies/filter_collision.cpp b/src/tallies/filter_collision.cpp index cf7d98c85a0..fbb186a2381 100644 --- a/src/tallies/filter_collision.cpp +++ b/src/tallies/filter_collision.cpp @@ -43,7 +43,7 @@ void CollisionFilter::get_all_bins( // Bin the collision number. Must fit exactly the desired collision number. auto search = map_.find(n); - if (search != map_.end()){ + if (search != map_.end()) { match.bins_.push_back(search->second); match.weights_.push_back(1.0); } diff --git a/src/tallies/filter_delayedgroup.cpp b/src/tallies/filter_delayedgroup.cpp index 824b2e81502..c6ec217666a 100644 --- a/src/tallies/filter_delayedgroup.cpp +++ b/src/tallies/filter_delayedgroup.cpp @@ -5,15 +5,13 @@ namespace openmc { -void -DelayedGroupFilter::from_xml(pugi::xml_node node) +void DelayedGroupFilter::from_xml(pugi::xml_node node) { auto groups = get_node_array(node, "bins"); this->set_groups(groups); } -void -DelayedGroupFilter::set_groups(gsl::span groups) +void DelayedGroupFilter::set_groups(gsl::span groups) { // Clear existing groups groups_.clear(); @@ -23,12 +21,14 @@ DelayedGroupFilter::set_groups(gsl::span groups) // TODO: do these need to be decremented for zero-based indexing? for (auto group : groups) { if (group < 1) { - throw std::invalid_argument{"Encountered delayedgroup bin with index " - + std::to_string(group) + " which is less than 1"}; + throw std::invalid_argument {"Encountered delayedgroup bin with index " + + std::to_string(group) + + " which is less than 1"}; } else if (group > MAX_DELAYED_GROUPS) { - throw std::invalid_argument{"Encountered delayedgroup bin with index " - + std::to_string(group) + " which is greater than MAX_DELATED_GROUPS (" - + std::to_string(MAX_DELAYED_GROUPS) + ")"}; + throw std::invalid_argument { + "Encountered delayedgroup bin with index " + std::to_string(group) + + " which is greater than MAX_DELATED_GROUPS (" + + std::to_string(MAX_DELAYED_GROUPS) + ")"}; } groups_.push_back(group); } @@ -36,23 +36,20 @@ DelayedGroupFilter::set_groups(gsl::span groups) n_bins_ = groups_.size(); } -void -DelayedGroupFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void DelayedGroupFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { match.bins_.push_back(0); match.weights_.push_back(1.0); } -void -DelayedGroupFilter::to_statepoint(hid_t filter_group) const +void DelayedGroupFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "bins", groups_); } -std::string -DelayedGroupFilter::text_label(int bin) const +std::string DelayedGroupFilter::text_label(int bin) const { return "Delayed Group " + std::to_string(groups_[bin]); } diff --git a/src/tallies/filter_distribcell.cpp b/src/tallies/filter_distribcell.cpp index c33c88cbc43..c754dbd44ab 100644 --- a/src/tallies/filter_distribcell.cpp +++ b/src/tallies/filter_distribcell.cpp @@ -10,8 +10,7 @@ namespace openmc { -void -DistribcellFilter::from_xml(pugi::xml_node node) +void DistribcellFilter::from_xml(pugi::xml_node node) { auto cells = get_node_array(node, "bins"); if (cells.size() != 1) { @@ -21,15 +20,14 @@ DistribcellFilter::from_xml(pugi::xml_node node) // Find index in global cells vector corresponding to cell ID auto search = model::cell_map.find(cells[0]); if (search == model::cell_map.end()) { - throw std::runtime_error{fmt::format( - "Could not find cell {} specified on tally filter.", cell_)}; + throw std::runtime_error { + fmt::format("Could not find cell {} specified on tally filter.", cell_)}; } this->set_cell(search->second); } -void -DistribcellFilter::set_cell(int32_t cell) +void DistribcellFilter::set_cell(int32_t cell) { Expects(cell >= 0); Expects(cell < model::cells.size()); @@ -37,9 +35,8 @@ DistribcellFilter::set_cell(int32_t cell) n_bins_ = model::cells[cell]->n_instances_; } -void -DistribcellFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void DistribcellFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { int offset = 0; auto distribcell_index = model::cells[cell_]->distribcell_index_; @@ -51,7 +48,8 @@ DistribcellFilter::get_all_bins(const Particle& p, TallyEstimator estimator, auto& lat {*model::lattices[p.coord(i + 1).lattice]}; const auto& i_xyz {p.coord(i + 1).lattice_i}; if (lat.are_valid_indices(i_xyz)) { - offset += lat.offset(distribcell_index, i_xyz); + offset += + lat.offset(distribcell_index, i_xyz) + c.offset_[distribcell_index]; } } if (cell_ == p.coord(i).cell) { @@ -62,15 +60,13 @@ DistribcellFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -DistribcellFilter::to_statepoint(hid_t filter_group) const +void DistribcellFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "bins", model::cells[cell_]->id_); } -std::string -DistribcellFilter::text_label(int bin) const +std::string DistribcellFilter::text_label(int bin) const { auto map = model::cells[cell_]->distribcell_index_; auto path = distribcell_path(cell_, map, bin); diff --git a/src/tallies/filter_energy.cpp b/src/tallies/filter_energy.cpp index 9169c4d8547..4767dd175f0 100644 --- a/src/tallies/filter_energy.cpp +++ b/src/tallies/filter_energy.cpp @@ -3,7 +3,7 @@ #include #include "openmc/capi.h" -#include "openmc/constants.h" // For F90_NONE +#include "openmc/constants.h" // For C_NONE #include "openmc/mgxs_interface.h" #include "openmc/search.h" #include "openmc/settings.h" @@ -15,15 +15,13 @@ namespace openmc { // EnergyFilter implementation //============================================================================== -void -EnergyFilter::from_xml(pugi::xml_node node) +void EnergyFilter::from_xml(pugi::xml_node node) { auto bins = get_node_array(node, "bins"); this->set_bins(bins); } -void -EnergyFilter::set_bins(gsl::span bins) +void EnergyFilter::set_bins(gsl::span bins) { // Clear existing bins bins_.clear(); @@ -31,8 +29,9 @@ EnergyFilter::set_bins(gsl::span bins) // Copy bins, ensuring they are valid for (gsl::index i = 0; i < bins.size(); ++i) { - if (i > 0 && bins[i] <= bins[i-1]) { - throw std::runtime_error{"Energy bins must be monotonically increasing."}; + if (i > 0 && bins[i] <= bins[i - 1]) { + throw std::runtime_error { + "Energy bins must be monotonically increasing."}; } bins_.push_back(bins[i]); } @@ -57,11 +56,10 @@ EnergyFilter::set_bins(gsl::span bins) } } -void -EnergyFilter::get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) -const +void EnergyFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { - if (p.g() != F90_NONE && matches_transport_groups_) { + if (p.g() != C_NONE && matches_transport_groups_) { if (estimator == TallyEstimator::TRACKLENGTH) { match.bins_.push_back(data::mg.num_energy_groups_ - p.g() - 1); } else { @@ -82,28 +80,25 @@ const } } -void -EnergyFilter::to_statepoint(hid_t filter_group) const +void EnergyFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "bins", bins_); } -std::string -EnergyFilter::text_label(int bin) const +std::string EnergyFilter::text_label(int bin) const { - return fmt::format("Incoming Energy [{}, {})", bins_[bin], bins_[bin+1]); + return fmt::format("Incoming Energy [{}, {})", bins_[bin], bins_[bin + 1]); } //============================================================================== // EnergyoutFilter implementation //============================================================================== -void -EnergyoutFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void EnergyoutFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { - if (p.g() != F90_NONE && matches_transport_groups_) { + if (p.g() != C_NONE && matches_transport_groups_) { match.bins_.push_back(data::mg.num_energy_groups_ - p.g() - 1); match.weights_.push_back(1.0); @@ -116,21 +111,22 @@ EnergyoutFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -std::string -EnergyoutFilter::text_label(int bin) const +std::string EnergyoutFilter::text_label(int bin) const { - return fmt::format("Outgoing Energy [{}, {})", bins_.at(bin), bins_.at(bin+1)); + return fmt::format( + "Outgoing Energy [{}, {})", bins_.at(bin), bins_.at(bin + 1)); } //============================================================================== // C-API functions //============================================================================== -extern"C" int -openmc_energy_filter_get_bins(int32_t index, const double** energies, size_t* n) +extern "C" int openmc_energy_filter_get_bins( + int32_t index, const double** energies, size_t* n) { // Make sure this is a valid index to an allocated filter. - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Get a pointer to the filter and downcast. const auto& filt_base = model::tally_filters[index].get(); @@ -148,11 +144,12 @@ openmc_energy_filter_get_bins(int32_t index, const double** energies, size_t* n) return 0; } -extern "C" int -openmc_energy_filter_set_bins(int32_t index, size_t n, const double* energies) +extern "C" int openmc_energy_filter_set_bins( + int32_t index, size_t n, const double* energies) { // Make sure this is a valid index to an allocated filter. - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Get a pointer to the filter and downcast. const auto& filt_base = model::tally_filters[index].get(); @@ -169,4 +166,4 @@ openmc_energy_filter_set_bins(int32_t index, size_t n, const double* energies) return 0; } -}// namespace openmc +} // namespace openmc diff --git a/src/tallies/filter_energyfunc.cpp b/src/tallies/filter_energyfunc.cpp index bea35c8e077..93ae24b2ada 100644 --- a/src/tallies/filter_energyfunc.cpp +++ b/src/tallies/filter_energyfunc.cpp @@ -3,14 +3,14 @@ #include #include "openmc/error.h" +#include "openmc/interpolate.h" #include "openmc/search.h" #include "openmc/settings.h" #include "openmc/xml_interface.h" namespace openmc { -void -EnergyFunctionFilter::from_xml(pugi::xml_node node) +void EnergyFunctionFilter::from_xml(pugi::xml_node node) { if (!settings::run_CE) fatal_error("EnergyFunction filters are only supported for " @@ -25,13 +25,18 @@ EnergyFunctionFilter::from_xml(pugi::xml_node node) fatal_error("y values not specified for EnergyFunction filter."); auto y = get_node_array(node, "y"); - this->set_data(energy, y); + + // default to linear-linear interpolation + interpolation_ = Interpolation::lin_lin; + if (check_for_node(node, "interpolation")) { + std::string interpolation = get_node_value(node, "interpolation"); + this->set_interpolation(interpolation); + } } -void -EnergyFunctionFilter::set_data(gsl::span energy, - gsl::span y) +void EnergyFunctionFilter::set_data( + gsl::span energy, gsl::span y) { // Check for consistent sizes with new data if (energy.size() != y.size()) { @@ -45,40 +50,71 @@ EnergyFunctionFilter::set_data(gsl::span energy, // Copy over energy values, ensuring they are valid for (gsl::index i = 0; i < energy.size(); ++i) { if (i > 0 && energy[i] <= energy[i - 1]) { - throw std::runtime_error{"Energy bins must be monotonically increasing."}; + throw std::runtime_error { + "Energy bins must be monotonically increasing."}; } energy_.push_back(energy[i]); y_.push_back(y[i]); } } -void -EnergyFunctionFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void EnergyFunctionFilter::set_interpolation(const std::string& interpolation) +{ + if (interpolation == "histogram") { + interpolation_ = Interpolation::histogram; + } else if (interpolation == "linear-linear") { + interpolation_ = Interpolation::lin_lin; + } else if (interpolation == "linear-log") { + interpolation_ = Interpolation::lin_log; + } else if (interpolation == "log-linear") { + interpolation_ = Interpolation::log_lin; + } else if (interpolation == "log-log") { + interpolation_ = Interpolation::log_log; + } else if (interpolation == "quadratic") { + if (energy_.size() < 3) + fatal_error( + fmt::format("Quadratic interpolation on EnergyFunctionFilter {} " + "requires at least 3 data points.", + this->id())); + interpolation_ = Interpolation::quadratic; + } else if (interpolation == "cubic") { + if (energy_.size() < 4) + fatal_error(fmt::format("Cubic interpolation on EnergyFunctionFilter " + "{} requires at least 4 data points.", + this->id())); + interpolation_ = Interpolation::cubic; + } else { + fatal_error(fmt::format( + "Found invalid interpolation type '{}' on EnergyFunctionFilter {}.", + interpolation, this->id())); + } +} + +void EnergyFunctionFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { if (p.E_last() >= energy_.front() && p.E_last() <= energy_.back()) { - // Search for the incoming energy bin. - auto i = lower_bound_index(energy_.begin(), energy_.end(), p.E_last()); - // Compute the interpolation factor between the nearest bins. - double f = (p.E_last() - energy_[i]) / (energy_[i + 1] - energy_[i]); + double w = interpolate(energy_, y_, p.E_last(), interpolation_); // Interpolate on the lin-lin grid. match.bins_.push_back(0); - match.weights_.push_back((1-f) * y_[i] + f * y_[i+1]); + match.weights_.push_back(w); } } -void -EnergyFunctionFilter::to_statepoint(hid_t filter_group) const +void EnergyFunctionFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "energy", energy_); write_dataset(filter_group, "y", y_); + hid_t y_dataset = open_dataset(filter_group, "y"); + write_attribute( + y_dataset, "interpolation", static_cast(interpolation_)); + close_dataset(y_dataset); } -std::string -EnergyFunctionFilter::text_label(int bin) const +std::string EnergyFunctionFilter::text_label(int bin) const { return fmt::format( "Energy Function f([{:.1e}, ..., {:.1e}]) = [{:.1e}, ..., {:.1e}]", @@ -89,12 +125,12 @@ EnergyFunctionFilter::text_label(int bin) const // C-API functions //============================================================================== -extern "C" int -openmc_energyfunc_filter_set_data(int32_t index, size_t n, const double* energy, - const double* y) +extern "C" int openmc_energyfunc_filter_set_data( + int32_t index, size_t n, const double* energy, const double* y) { // Ensure this is a valid index to allocated filter - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Get a pointer to the filter const auto& filt_base = model::tally_filters[index].get(); @@ -103,7 +139,8 @@ openmc_energyfunc_filter_set_data(int32_t index, size_t n, const double* energy, // Check if a valid filter was produced if (!filt) { - set_errmsg("Tried to set interpolation data for non-energy function filter."); + set_errmsg( + "Tried to set interpolation data for non-energy function filter."); return OPENMC_E_INVALID_TYPE; } @@ -111,11 +148,12 @@ openmc_energyfunc_filter_set_data(int32_t index, size_t n, const double* energy, return 0; } -extern "C" int -openmc_energyfunc_filter_get_energy(int32_t index, size_t *n, const double** energy) +extern "C" int openmc_energyfunc_filter_get_energy( + int32_t index, size_t* n, const double** energy) { // ensure this is a valid index to allocated filter - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // get a pointer to the filter const auto& filt_base = model::tally_filters[index].get(); @@ -124,7 +162,8 @@ openmc_energyfunc_filter_get_energy(int32_t index, size_t *n, const double** ene // check if a valid filter was produced if (!filt) { - set_errmsg("Tried to set interpolation data for non-energy function filter."); + set_errmsg( + "Tried to set interpolation data for non-energy function filter."); return OPENMC_E_INVALID_TYPE; } *energy = filt->energy().data(); @@ -132,11 +171,12 @@ openmc_energyfunc_filter_get_energy(int32_t index, size_t *n, const double** ene return 0; } -extern "C" int -openmc_energyfunc_filter_get_y(int32_t index, size_t *n, const double** y) +extern "C" int openmc_energyfunc_filter_get_y( + int32_t index, size_t* n, const double** y) { // ensure this is a valid index to allocated filter - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // get a pointer to the filter const auto& filt_base = model::tally_filters[index].get(); @@ -145,7 +185,8 @@ openmc_energyfunc_filter_get_y(int32_t index, size_t *n, const double** y) // check if a valid filter was produced if (!filt) { - set_errmsg("Tried to set interpolation data for non-energy function filter."); + set_errmsg( + "Tried to set interpolation data for non-energy function filter."); return OPENMC_E_INVALID_TYPE; } *y = filt->y().data(); @@ -153,4 +194,51 @@ openmc_energyfunc_filter_get_y(int32_t index, size_t *n, const double** y) return 0; } +extern "C" int openmc_energyfunc_filter_set_interpolation( + int32_t index, const char* interp) +{ + // ensure this is a valid index to allocated filter + if (int err = verify_filter(index)) + return err; + + // get a pointer to the filter + const auto& filt_base = model::tally_filters[index].get(); + // downcast to EnergyFunctionFilter + auto* filt = dynamic_cast(filt_base); + + // check if a valid filter was produced + if (!filt) { + set_errmsg( + "Tried to set interpolation data for non-energy function filter."); + return OPENMC_E_INVALID_TYPE; + } + + // Set interpolation + filt->set_interpolation(interp); + return 0; +} + +extern "C" int openmc_energyfunc_filter_get_interpolation( + int32_t index, int* interp) +{ + // ensure this is a valid index to allocated filter + if (int err = verify_filter(index)) + return err; + + // get a pointer to the filter + const auto& filt_base = model::tally_filters[index].get(); + // downcast to EnergyFunctionFilter + auto* filt = dynamic_cast(filt_base); + + // check if a valid filter was produced + if (!filt) { + set_errmsg( + "Tried to set interpolation data for non-energy function filter."); + return OPENMC_E_INVALID_TYPE; + } + + *interp = static_cast(filt->interpolation()); + return 0; +} + } // namespace openmc diff --git a/src/tallies/filter_legendre.cpp b/src/tallies/filter_legendre.cpp index 6626f5ea183..36ae0e41a05 100644 --- a/src/tallies/filter_legendre.cpp +++ b/src/tallies/filter_legendre.cpp @@ -7,25 +7,22 @@ namespace openmc { -void -LegendreFilter::from_xml(pugi::xml_node node) +void LegendreFilter::from_xml(pugi::xml_node node) { this->set_order(std::stoi(get_node_value(node, "order"))); } -void -LegendreFilter::set_order(int order) +void LegendreFilter::set_order(int order) { if (order < 0) { - throw std::invalid_argument{"Legendre order must be non-negative."}; + throw std::invalid_argument {"Legendre order must be non-negative."}; } order_ = order; n_bins_ = order_ + 1; } -void -LegendreFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void LegendreFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { vector wgt(n_bins_); calc_pn_c(order_, p.mu(), wgt.data()); @@ -35,15 +32,13 @@ LegendreFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -LegendreFilter::to_statepoint(hid_t filter_group) const +void LegendreFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "order", order_); } -std::string -LegendreFilter::text_label(int bin) const +std::string LegendreFilter::text_label(int bin) const { return "Legendre expansion, P" + std::to_string(bin); } @@ -52,11 +47,11 @@ LegendreFilter::text_label(int bin) const // C-API functions //============================================================================== -extern "C" int -openmc_legendre_filter_get_order(int32_t index, int* order) +extern "C" int openmc_legendre_filter_get_order(int32_t index, int* order) { // Make sure this is a valid index to an allocated filter. - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Get a pointer to the filter and downcast. const auto& filt_base = model::tally_filters[index].get(); @@ -73,11 +68,11 @@ openmc_legendre_filter_get_order(int32_t index, int* order) return 0; } -extern "C" int -openmc_legendre_filter_set_order(int32_t index, int order) +extern "C" int openmc_legendre_filter_set_order(int32_t index, int order) { // Make sure this is a valid index to an allocated filter. - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Get a pointer to the filter and downcast. const auto& filt_base = model::tally_filters[index].get(); diff --git a/src/tallies/filter_material.cpp b/src/tallies/filter_material.cpp index e9247457f3a..6669ab2fa39 100644 --- a/src/tallies/filter_material.cpp +++ b/src/tallies/filter_material.cpp @@ -8,15 +8,14 @@ namespace openmc { -void -MaterialFilter::from_xml(pugi::xml_node node) +void MaterialFilter::from_xml(pugi::xml_node node) { // Get material IDs and convert to indices in the global materials vector auto mats = get_node_array(node, "bins"); for (auto& m : mats) { auto search = model::material_map.find(m); if (search == model::material_map.end()) { - throw std::runtime_error{fmt::format( + throw std::runtime_error {fmt::format( "Could not find material {} specified on tally filter.", m)}; } m = search->second; @@ -25,8 +24,7 @@ MaterialFilter::from_xml(pugi::xml_node node) this->set_materials(mats); } -void -MaterialFilter::set_materials(gsl::span materials) +void MaterialFilter::set_materials(gsl::span materials) { // Clear existing materials materials_.clear(); @@ -44,9 +42,8 @@ MaterialFilter::set_materials(gsl::span materials) n_bins_ = materials_.size(); } -void -MaterialFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void MaterialFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { auto search = map_.find(p.material()); if (search != map_.end()) { @@ -55,17 +52,16 @@ MaterialFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -MaterialFilter::to_statepoint(hid_t filter_group) const +void MaterialFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); vector material_ids; - for (auto c : materials_) material_ids.push_back(model::materials[c]->id_); + for (auto c : materials_) + material_ids.push_back(model::materials[c]->id_); write_dataset(filter_group, "bins", material_ids); } -std::string -MaterialFilter::text_label(int bin) const +std::string MaterialFilter::text_label(int bin) const { return fmt::format("Material {}", model::materials[materials_[bin]]->id_); } @@ -74,11 +70,12 @@ MaterialFilter::text_label(int bin) const // C-API functions //============================================================================== -extern "C" int -openmc_material_filter_get_bins(int32_t index, const int32_t** bins, size_t* n) +extern "C" int openmc_material_filter_get_bins( + int32_t index, const int32_t** bins, size_t* n) { // Make sure this is a valid index to an allocated filter. - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Get a pointer to the filter and downcast. const auto& filt_base = model::tally_filters[index].get(); @@ -96,11 +93,12 @@ openmc_material_filter_get_bins(int32_t index, const int32_t** bins, size_t* n) return 0; } -extern "C" int -openmc_material_filter_set_bins(int32_t index, size_t n, const int32_t* bins) +extern "C" int openmc_material_filter_set_bins( + int32_t index, size_t n, const int32_t* bins) { // Make sure this is a valid index to an allocated filter. - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Get a pointer to the filter and downcast. const auto& filt_base = model::tally_filters[index].get(); diff --git a/src/tallies/filter_materialfrom.cpp b/src/tallies/filter_materialfrom.cpp new file mode 100644 index 00000000000..91f03aef85e --- /dev/null +++ b/src/tallies/filter_materialfrom.cpp @@ -0,0 +1,24 @@ +#include "openmc/tallies/filter_materialfrom.h" + +#include "openmc/cell.h" +#include "openmc/material.h" + +namespace openmc { + +void MaterialFromFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const +{ + auto search = map_.find(p.material_last()); + if (search != map_.end()) { + match.bins_.push_back(search->second); + match.weights_.push_back(1.0); + } +} + +std::string MaterialFromFilter::text_label(int bin) const +{ + return "Material from " + + std::to_string(model::materials[materials_[bin]]->id_); +} + +} // namespace openmc diff --git a/src/tallies/filter_mesh.cpp b/src/tallies/filter_mesh.cpp index d36fdb6f7a8..5b01da1f65a 100644 --- a/src/tallies/filter_mesh.cpp +++ b/src/tallies/filter_mesh.cpp @@ -1,7 +1,7 @@ #include "openmc/tallies/filter_mesh.h" #include -#include +#include #include "openmc/capi.h" #include "openmc/constants.h" @@ -11,33 +11,30 @@ namespace openmc { -void -MeshFilter::from_xml(pugi::xml_node node) +void MeshFilter::from_xml(pugi::xml_node node) { auto bins_ = get_node_array(node, "bins"); if (bins_.size() != 1) { - fatal_error("Only one mesh can be specified per " + type() - + " mesh filter."); + fatal_error( + "Only one mesh can be specified per " + type_str() + " mesh filter."); } auto id = bins_[0]; auto search = model::mesh_map.find(id); if (search != model::mesh_map.end()) { set_mesh(search->second); - } else{ - fatal_error(fmt::format( - "Could not find mesh {} specified on tally filter.", id)); + } else { + fatal_error( + fmt::format("Could not find mesh {} specified on tally filter.", id)); } if (check_for_node(node, "translation")) { set_translation(get_node_array(node, "translation")); } - } -void -MeshFilter::get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) -const +void MeshFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { Position last_r = p.r_last(); @@ -57,12 +54,12 @@ const match.weights_.push_back(1.0); } } else { - model::meshes[mesh_]->bins_crossed(last_r, r, u, match.bins_, match.weights_); + model::meshes[mesh_]->bins_crossed( + last_r, r, u, match.bins_, match.weights_); } } -void -MeshFilter::to_statepoint(hid_t filter_group) const +void MeshFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "bins", model::meshes[mesh_]->id_); @@ -71,19 +68,19 @@ MeshFilter::to_statepoint(hid_t filter_group) const } } -std::string -MeshFilter::text_label(int bin) const +std::string MeshFilter::text_label(int bin) const { auto& mesh = *model::meshes.at(mesh_); std::string label = mesh.bin_label(bin); return label; } -void -MeshFilter::set_mesh(int32_t mesh) +void MeshFilter::set_mesh(int32_t mesh) { + // perform any additional perparation for mesh tallies here mesh_ = mesh; n_bins_ = model::meshes[mesh_]->n_bins(); + model::meshes[mesh_]->prepare_for_tallies(); } void MeshFilter::set_translation(const Position& translation) @@ -101,8 +98,7 @@ void MeshFilter::set_translation(const double translation[3]) // C-API functions //============================================================================== -extern "C" int -openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh) +extern "C" int openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh) { if (!index_mesh) { set_errmsg("Mesh index argument is a null pointer."); @@ -110,7 +106,8 @@ openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh) } // Make sure this is a valid index to an allocated filter. - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Get a pointer to the filter and downcast. const auto& filt_base = model::tally_filters[index].get(); @@ -127,11 +124,11 @@ openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh) return 0; } -extern "C" int -openmc_mesh_filter_set_mesh(int32_t index, int32_t index_mesh) +extern "C" int openmc_mesh_filter_set_mesh(int32_t index, int32_t index_mesh) { // Make sure this is a valid index to an allocated filter. - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Get a pointer to the filter and downcast. const auto& filt_base = model::tally_filters[index].get(); @@ -154,15 +151,18 @@ openmc_mesh_filter_set_mesh(int32_t index, int32_t index_mesh) return 0; } -extern "C" int -openmc_mesh_filter_get_translation(int32_t index, double translation[3]) +extern "C" int openmc_mesh_filter_get_translation( + int32_t index, double translation[3]) { // Make sure this is a valid index to an allocated filter - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; // Check the filter type const auto& filter = model::tally_filters[index]; - if (filter->type() != "mesh" && filter->type() != "meshsurface") { + if (filter->type() != FilterType::MESH && + filter->type() != FilterType::MESHBORN && + filter->type() != FilterType::MESH_SURFACE) { set_errmsg("Tried to get a translation from a non-mesh-based filter."); return OPENMC_E_INVALID_TYPE; } @@ -170,20 +170,25 @@ openmc_mesh_filter_get_translation(int32_t index, double translation[3]) // Get translation from the mesh filter and set value auto mesh_filter = dynamic_cast(filter.get()); const auto& t = mesh_filter->translation(); - for (int i = 0; i < 3; i++) { translation[i] = t[i]; } + for (int i = 0; i < 3; i++) { + translation[i] = t[i]; + } return 0; } -extern "C" int -openmc_mesh_filter_set_translation(int32_t index, double translation[3]) +extern "C" int openmc_mesh_filter_set_translation( + int32_t index, double translation[3]) { // Make sure this is a valid index to an allocated filter - if (int err = verify_filter(index)) return err; + if (int err = verify_filter(index)) + return err; const auto& filter = model::tally_filters[index]; // Check the filter type - if (filter->type() != "mesh" && filter->type() != "meshsurface") { + if (filter->type() != FilterType::MESH && + filter->type() != FilterType::MESHBORN && + filter->type() != FilterType::MESH_SURFACE) { set_errmsg("Tried to set mesh on a non-mesh-based filter."); return OPENMC_E_INVALID_TYPE; } diff --git a/src/tallies/filter_meshborn.cpp b/src/tallies/filter_meshborn.cpp new file mode 100644 index 00000000000..c95dc3dc78a --- /dev/null +++ b/src/tallies/filter_meshborn.cpp @@ -0,0 +1,61 @@ +#include "openmc/tallies/filter_meshborn.h" + +#include "openmc/capi.h" +#include "openmc/constants.h" +#include "openmc/error.h" +#include "openmc/mesh.h" + +namespace openmc { + +void MeshBornFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const +{ + Position r_born = p.r_born(); + + // apply translation if present + if (translated_) { + r_born -= translation(); + } + + auto bin = model::meshes[mesh_]->get_bin(r_born); + if (bin >= 0) { + match.bins_.push_back(bin); + match.weights_.push_back(1.0); + } +} + +std::string MeshBornFilter::text_label(int bin) const +{ + auto& mesh = *model::meshes.at(mesh_); + return mesh.bin_label(bin) + " (born)"; +} + +//============================================================================== +// C-API functions +//============================================================================== + +extern "C" int openmc_meshborn_filter_get_mesh( + int32_t index, int32_t* index_mesh) +{ + return openmc_mesh_filter_get_mesh(index, index_mesh); +} + +extern "C" int openmc_meshborn_filter_set_mesh( + int32_t index, int32_t index_mesh) +{ + return openmc_mesh_filter_set_mesh(index, index_mesh); +} + +extern "C" int openmc_meshborn_filter_get_translation( + int32_t index, double translation[3]) +{ + return openmc_mesh_filter_get_translation(index, translation); +} + +extern "C" int openmc_meshborn_filter_set_translation( + int32_t index, double translation[3]) +{ + return openmc_mesh_filter_set_translation(index, translation); +} + +} // namespace openmc diff --git a/src/tallies/filter_meshsurface.cpp b/src/tallies/filter_meshsurface.cpp index 8f94e5ecbcf..b26cd198b32 100644 --- a/src/tallies/filter_meshsurface.cpp +++ b/src/tallies/filter_meshsurface.cpp @@ -7,9 +7,8 @@ namespace openmc { -void -MeshSurfaceFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void MeshSurfaceFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { Position r0 = p.r_last_current(); Position r1 = p.r(); @@ -20,11 +19,11 @@ MeshSurfaceFilter::get_all_bins(const Particle& p, TallyEstimator estimator, Direction u = p.u(); model::meshes[mesh_]->surface_bins_crossed(r0, r1, u, match.bins_); - for (auto b : match.bins_) match.weights_.push_back(1.0); + for (auto b : match.bins_) + match.weights_.push_back(1.0); } -std::string -MeshSurfaceFilter::text_label(int bin) const +std::string MeshSurfaceFilter::text_label(int bin) const { auto& mesh = *model::meshes[mesh_]; int n_dim = mesh.n_dimension_; @@ -38,49 +37,48 @@ MeshSurfaceFilter::text_label(int bin) const // Get surface part of label. switch (surf_dir) { - case MeshDir::OUT_LEFT: - out += " Outgoing, x-min"; - break; - case MeshDir::IN_LEFT: - out += " Incoming, x-min"; - break; - case MeshDir::OUT_RIGHT: - out += " Outgoing, x-max"; - break; - case MeshDir::IN_RIGHT: - out += " Incoming, x-max"; - break; - case MeshDir::OUT_BACK: - out += " Outgoing, y-min"; - break; - case MeshDir::IN_BACK: - out += " Incoming, y-min"; - break; - case MeshDir::OUT_FRONT: - out += " Outgoing, y-max"; - break; - case MeshDir::IN_FRONT: - out += " Incoming, y-max"; - break; - case MeshDir::OUT_BOTTOM: - out += " Outgoing, z-min"; - break; - case MeshDir::IN_BOTTOM: - out += " Incoming, z-min"; - break; - case MeshDir::OUT_TOP: - out += " Outgoing, z-max"; - break; - case MeshDir::IN_TOP: - out += " Incoming, z-max"; - break; + case MeshDir::OUT_LEFT: + out += " Outgoing, x-min"; + break; + case MeshDir::IN_LEFT: + out += " Incoming, x-min"; + break; + case MeshDir::OUT_RIGHT: + out += " Outgoing, x-max"; + break; + case MeshDir::IN_RIGHT: + out += " Incoming, x-max"; + break; + case MeshDir::OUT_BACK: + out += " Outgoing, y-min"; + break; + case MeshDir::IN_BACK: + out += " Incoming, y-min"; + break; + case MeshDir::OUT_FRONT: + out += " Outgoing, y-max"; + break; + case MeshDir::IN_FRONT: + out += " Incoming, y-max"; + break; + case MeshDir::OUT_BOTTOM: + out += " Outgoing, z-min"; + break; + case MeshDir::IN_BOTTOM: + out += " Incoming, z-min"; + break; + case MeshDir::OUT_TOP: + out += " Outgoing, z-max"; + break; + case MeshDir::IN_TOP: + out += " Incoming, z-max"; + break; } return out; } -void -MeshSurfaceFilter::set_mesh(int32_t mesh) +void MeshSurfaceFilter::set_mesh(int32_t mesh) { mesh_ = mesh; n_bins_ = model::meshes[mesh_]->n_surface_bins(); @@ -90,12 +88,28 @@ MeshSurfaceFilter::set_mesh(int32_t mesh) // C-API functions //============================================================================== -extern"C" int -openmc_meshsurface_filter_get_mesh(int32_t index, int32_t* index_mesh) -{return openmc_mesh_filter_get_mesh(index, index_mesh);} +extern "C" int openmc_meshsurface_filter_get_mesh( + int32_t index, int32_t* index_mesh) +{ + return openmc_mesh_filter_get_mesh(index, index_mesh); +} + +extern "C" int openmc_meshsurface_filter_set_mesh( + int32_t index, int32_t index_mesh) +{ + return openmc_mesh_filter_set_mesh(index, index_mesh); +} -extern"C" int -openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh) -{return openmc_mesh_filter_set_mesh(index, index_mesh);} +extern "C" int openmc_meshsurface_filter_get_translation( + int32_t index, double translation[3]) +{ + return openmc_mesh_filter_get_translation(index, translation); +} + +extern "C" int openmc_meshsurface_filter_set_translation( + int32_t index, double translation[3]) +{ + return openmc_mesh_filter_set_translation(index, translation); +} } // namespace openmc diff --git a/src/tallies/filter_mu.cpp b/src/tallies/filter_mu.cpp index b157ff2dbae..95bb3b21082 100644 --- a/src/tallies/filter_mu.cpp +++ b/src/tallies/filter_mu.cpp @@ -8,8 +8,7 @@ namespace openmc { -void -MuFilter::from_xml(pugi::xml_node node) +void MuFilter::from_xml(pugi::xml_node node) { auto bins = get_node_array(node, "bins"); @@ -18,20 +17,21 @@ MuFilter::from_xml(pugi::xml_node node) // [-1,1) evenly with the input being the number of bins int n_angle = bins[0]; - if (n_angle <= 1) throw std::runtime_error{ + if (n_angle <= 1) + throw std::runtime_error { "Number of bins for mu filter must be greater than 1."}; double d_angle = 2.0 / n_angle; bins.resize(n_angle + 1); - for (int i = 0; i < n_angle; i++) bins[i] = -1 + i * d_angle; + for (int i = 0; i < n_angle; i++) + bins[i] = -1 + i * d_angle; bins[n_angle] = 1; } this->set_bins(bins); } -void -MuFilter::set_bins(gsl::span bins) +void MuFilter::set_bins(gsl::span bins) { // Clear existing bins bins_.clear(); @@ -39,8 +39,8 @@ MuFilter::set_bins(gsl::span bins) // Copy bins, ensuring they are valid for (gsl::index i = 0; i < bins.size(); ++i) { - if (i > 0 && bins[i] <= bins[i-1]) { - throw std::runtime_error{"Mu bins must be monotonically increasing."}; + if (i > 0 && bins[i] <= bins[i - 1]) { + throw std::runtime_error {"Mu bins must be monotonically increasing."}; } bins_.push_back(bins[i]); } @@ -48,9 +48,8 @@ MuFilter::set_bins(gsl::span bins) n_bins_ = bins_.size() - 1; } -void -MuFilter::get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) -const +void MuFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { if (p.mu() >= bins_.front() && p.mu() <= bins_.back()) { auto bin = lower_bound_index(bins_.begin(), bins_.end(), p.mu()); @@ -59,17 +58,15 @@ const } } -void -MuFilter::to_statepoint(hid_t filter_group) const +void MuFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "bins", bins_); } -std::string -MuFilter::text_label(int bin) const +std::string MuFilter::text_label(int bin) const { - return fmt::format("Change-in-Angle [{}, {})", bins_[bin], bins_[bin+1]); + return fmt::format("Change-in-Angle [{}, {})", bins_[bin], bins_[bin + 1]); } } // namespace openmc diff --git a/src/tallies/filter_particle.cpp b/src/tallies/filter_particle.cpp index a9669661e98..56d93a47f40 100644 --- a/src/tallies/filter_particle.cpp +++ b/src/tallies/filter_particle.cpp @@ -6,8 +6,7 @@ namespace openmc { -void -ParticleFilter::from_xml(pugi::xml_node node) +void ParticleFilter::from_xml(pugi::xml_node node) { auto particles = get_node_array(node, "bins"); @@ -32,9 +31,8 @@ void ParticleFilter::set_particles(gsl::span particles) n_bins_ = particles_.size(); } -void -ParticleFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void ParticleFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { for (auto i = 0; i < particles_.size(); i++) { if (particles_[i] == p.type()) { @@ -44,8 +42,7 @@ ParticleFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -ParticleFilter::to_statepoint(hid_t filter_group) const +void ParticleFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); vector particles; @@ -55,11 +52,29 @@ ParticleFilter::to_statepoint(hid_t filter_group) const write_dataset(filter_group, "bins", particles); } -std::string -ParticleFilter::text_label(int bin) const +std::string ParticleFilter::text_label(int bin) const { const auto& p = particles_.at(bin); return fmt::format("Particle: {}", particle_type_to_str(p)); } +extern "C" int openmc_particle_filter_get_bins(int32_t idx, int bins[]) +{ + if (int err = verify_filter(idx)) + return err; + + const auto& f = model::tally_filters[idx]; + auto pf = dynamic_cast(f.get()); + if (pf) { + const auto& particles = pf->particles(); + for (int i = 0; i < particles.size(); i++) { + bins[i] = static_cast(particles[i]); + } + } else { + set_errmsg("The filter at the specified index is not a ParticleFilter"); + return OPENMC_E_INVALID_ARGUMENT; + } + return 0; +} + } // namespace openmc diff --git a/src/tallies/filter_polar.cpp b/src/tallies/filter_polar.cpp index 51ff496cd7e..d132ccf4236 100644 --- a/src/tallies/filter_polar.cpp +++ b/src/tallies/filter_polar.cpp @@ -9,8 +9,7 @@ namespace openmc { -void -PolarFilter::from_xml(pugi::xml_node node) +void PolarFilter::from_xml(pugi::xml_node node) { auto bins = get_node_array(node, "bins"); @@ -19,20 +18,21 @@ PolarFilter::from_xml(pugi::xml_node node) // [0,pi] evenly with the input being the number of bins int n_angle = bins[0]; - if (n_angle <= 1) throw std::runtime_error{ - "Number of bins for polar filter must be greater than 1."}; + if (n_angle <= 1) + throw std::runtime_error { + "Number of bins for polar filter must be greater than 1."}; double d_angle = PI / n_angle; bins.resize(n_angle + 1); - for (int i = 0; i < n_angle; i++) bins[i] = i * d_angle; + for (int i = 0; i < n_angle; i++) + bins[i] = i * d_angle; bins[n_angle] = PI; } this->set_bins(bins); } -void -PolarFilter::set_bins(gsl::span bins) +void PolarFilter::set_bins(gsl::span bins) { // Clear existing bins bins_.clear(); @@ -40,8 +40,8 @@ PolarFilter::set_bins(gsl::span bins) // Copy bins, ensuring they are valid for (gsl::index i = 0; i < bins.size(); ++i) { - if (i > 0 && bins[i] <= bins[i-1]) { - throw std::runtime_error{"Polar bins must be monotonically increasing."}; + if (i > 0 && bins[i] <= bins[i - 1]) { + throw std::runtime_error {"Polar bins must be monotonically increasing."}; } bins_.push_back(bins[i]); } @@ -49,9 +49,8 @@ PolarFilter::set_bins(gsl::span bins) n_bins_ = bins_.size() - 1; } -void -PolarFilter::get_all_bins(const Particle& p, TallyEstimator estimator, FilterMatch& match) -const +void PolarFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { double z = (estimator == TallyEstimator::TRACKLENGTH) ? p.u().z : p.u_last().z; @@ -64,17 +63,15 @@ const } } -void -PolarFilter::to_statepoint(hid_t filter_group) const +void PolarFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "bins", bins_); } -std::string -PolarFilter::text_label(int bin) const +std::string PolarFilter::text_label(int bin) const { - return fmt::format("Polar Angle [{}, {})", bins_[bin], bins_[bin+1]); + return fmt::format("Polar Angle [{}, {})", bins_[bin], bins_[bin + 1]); } } // namespace openmc diff --git a/src/tallies/filter_sph_harm.cpp b/src/tallies/filter_sph_harm.cpp index e8f8eed21fd..359df379b2f 100644 --- a/src/tallies/filter_sph_harm.cpp +++ b/src/tallies/filter_sph_harm.cpp @@ -1,9 +1,9 @@ #include "openmc/tallies/filter_sph_harm.h" -#include // For pair +#include // For pair #include -#include +#include #include "openmc/capi.h" #include "openmc/error.h" @@ -12,8 +12,7 @@ namespace openmc { -void -SphericalHarmonicsFilter::from_xml(pugi::xml_node node) +void SphericalHarmonicsFilter::from_xml(pugi::xml_node node) { this->set_order(std::stoi(get_node_value(node, "order"))); if (check_for_node(node, "cosine")) { @@ -21,32 +20,31 @@ SphericalHarmonicsFilter::from_xml(pugi::xml_node node) } } -void -SphericalHarmonicsFilter::set_order(int order) +void SphericalHarmonicsFilter::set_order(int order) { if (order < 0) { - throw std::invalid_argument{"Spherical harmonics order must be non-negative."}; + throw std::invalid_argument { + "Spherical harmonics order must be non-negative."}; } order_ = order; n_bins_ = (order_ + 1) * (order_ + 1); } -void -SphericalHarmonicsFilter::set_cosine(gsl::cstring_span cosine) +void SphericalHarmonicsFilter::set_cosine(gsl::cstring_span cosine) { if (cosine == "scatter") { cosine_ = SphericalHarmonicsCosine::scatter; } else if (cosine == "particle") { cosine_ = SphericalHarmonicsCosine::particle; } else { - throw std::invalid_argument{fmt::format("Unrecognized cosine type, \"{}\" " - "in spherical harmonics filter", gsl::to_string(cosine))}; + throw std::invalid_argument {fmt::format("Unrecognized cosine type, \"{}\" " + "in spherical harmonics filter", + gsl::to_string(cosine))}; } } -void -SphericalHarmonicsFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void SphericalHarmonicsFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { // Determine cosine term for scatter expansion if necessary vector wgt(order_ + 1); @@ -65,7 +63,7 @@ SphericalHarmonicsFilter::get_all_bins(const Particle& p, TallyEstimator estimat int j = 0; for (int n = 0; n < order_ + 1; n++) { // Calculate n-th order spherical harmonics for (u,v,w) - int num_nm = 2*n + 1; + int num_nm = 2 * n + 1; // Append the matching (bin,weight) for each moment for (int i = 0; i < num_nm; i++) { @@ -76,8 +74,7 @@ SphericalHarmonicsFilter::get_all_bins(const Particle& p, TallyEstimator estimat } } -void -SphericalHarmonicsFilter::to_statepoint(hid_t filter_group) const +void SphericalHarmonicsFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "order", order_); @@ -88,13 +85,12 @@ SphericalHarmonicsFilter::to_statepoint(hid_t filter_group) const } } -std::string -SphericalHarmonicsFilter::text_label(int bin) const +std::string SphericalHarmonicsFilter::text_label(int bin) const { Expects(bin >= 0 && bin < n_bins_); for (int n = 0; n < order_ + 1; n++) { if (bin < (n + 1) * (n + 1)) { - int m = (bin - n*n) - n; + int m = (bin - n * n) - n; return fmt::format("Spherical harmonic expansion, Y{},{}", n, m); } } @@ -105,8 +101,7 @@ SphericalHarmonicsFilter::text_label(int bin) const // C-API functions //============================================================================== -std::pair -check_sphharm_filter(int32_t index) +std::pair check_sphharm_filter(int32_t index) { // Make sure this is a valid index to an allocated filter. int err = verify_filter(index); @@ -126,28 +121,28 @@ check_sphharm_filter(int32_t index) return {err, filt}; } -extern "C" int -openmc_sphharm_filter_get_order(int32_t index, int* order) +extern "C" int openmc_sphharm_filter_get_order(int32_t index, int* order) { // Check the filter. auto check_result = check_sphharm_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Output the order. *order = filt->order(); return 0; } -extern "C" int -openmc_sphharm_filter_get_cosine(int32_t index, char cosine[]) +extern "C" int openmc_sphharm_filter_get_cosine(int32_t index, char cosine[]) { // Check the filter. auto check_result = check_sphharm_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Output the cosine. if (filt->cosine() == SphericalHarmonicsCosine::scatter) { @@ -158,28 +153,29 @@ openmc_sphharm_filter_get_cosine(int32_t index, char cosine[]) return 0; } -extern "C" int -openmc_sphharm_filter_set_order(int32_t index, int order) +extern "C" int openmc_sphharm_filter_set_order(int32_t index, int order) { // Check the filter. auto check_result = check_sphharm_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Update the filter. filt->set_order(order); return 0; } -extern "C" int -openmc_sphharm_filter_set_cosine(int32_t index, const char cosine[]) +extern "C" int openmc_sphharm_filter_set_cosine( + int32_t index, const char cosine[]) { // Check the filter. auto check_result = check_sphharm_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Update the filter. try { diff --git a/src/tallies/filter_sptl_legendre.cpp b/src/tallies/filter_sptl_legendre.cpp index c835f1dd927..cf5ef2aed2d 100644 --- a/src/tallies/filter_sptl_legendre.cpp +++ b/src/tallies/filter_sptl_legendre.cpp @@ -1,6 +1,6 @@ #include "openmc/tallies/filter_sptl_legendre.h" -#include // For pair +#include // For pair #include @@ -11,8 +11,7 @@ namespace openmc { -void -SpatialLegendreFilter::from_xml(pugi::xml_node node) +void SpatialLegendreFilter::from_xml(pugi::xml_node node) { this->set_order(std::stoi(get_node_value(node, "order"))); @@ -28,7 +27,8 @@ SpatialLegendreFilter::from_xml(pugi::xml_node node) this->set_axis(LegendreAxis::z); break; default: - throw std::runtime_error{"Axis for SpatialLegendreFilter must be 'x', 'y', or 'z'"}; + throw std::runtime_error { + "Axis for SpatialLegendreFilter must be 'x', 'y', or 'z'"}; } double min = std::stod(get_node_value(node, "min")); @@ -36,35 +36,32 @@ SpatialLegendreFilter::from_xml(pugi::xml_node node) this->set_minmax(min, max); } -void -SpatialLegendreFilter::set_order(int order) +void SpatialLegendreFilter::set_order(int order) { if (order < 0) { - throw std::invalid_argument{"Legendre order must be non-negative."}; + throw std::invalid_argument {"Legendre order must be non-negative."}; } order_ = order; n_bins_ = order_ + 1; } -void -SpatialLegendreFilter::set_axis(LegendreAxis axis) +void SpatialLegendreFilter::set_axis(LegendreAxis axis) { axis_ = axis; } -void -SpatialLegendreFilter::set_minmax(double min, double max) +void SpatialLegendreFilter::set_minmax(double min, double max) { if (max <= min) { - throw std::invalid_argument{"Maximum value must be greater than minimum value"}; + throw std::invalid_argument { + "Maximum value must be greater than minimum value"}; } min_ = min; max_ = max; } -void -SpatialLegendreFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void SpatialLegendreFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { // Get the coordinate along the axis of interest. double x; @@ -78,7 +75,7 @@ SpatialLegendreFilter::get_all_bins(const Particle& p, TallyEstimator estimator, if (x >= min_ && x <= max_) { // Compute the normalized coordinate value. - double x_norm = 2.0*(x - min_) / (max_ - min_) - 1.0; + double x_norm = 2.0 * (x - min_) / (max_ - min_) - 1.0; // Compute and return the Legendre weights. vector wgt(order_ + 1); @@ -90,8 +87,7 @@ SpatialLegendreFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -SpatialLegendreFilter::to_statepoint(hid_t filter_group) const +void SpatialLegendreFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "order", order_); @@ -106,8 +102,7 @@ SpatialLegendreFilter::to_statepoint(hid_t filter_group) const write_dataset(filter_group, "max", max_); } -std::string -SpatialLegendreFilter::text_label(int bin) const +std::string SpatialLegendreFilter::text_label(int bin) const { if (axis_ == LegendreAxis::x) { return fmt::format("Legendre expansion, x axis, P{}", bin); @@ -122,8 +117,7 @@ SpatialLegendreFilter::text_label(int bin) const // C-API functions //============================================================================== -std::pair -check_sptl_legendre_filter(int32_t index) +std::pair check_sptl_legendre_filter(int32_t index) { // Make sure this is a valid index to an allocated filter. int err = verify_filter(index); @@ -143,29 +137,30 @@ check_sptl_legendre_filter(int32_t index) return {err, filt}; } -extern "C" int -openmc_spatial_legendre_filter_get_order(int32_t index, int* order) +extern "C" int openmc_spatial_legendre_filter_get_order( + int32_t index, int* order) { // Check the filter. auto check_result = check_sptl_legendre_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Output the order. *order = filt->order(); return 0; } -extern "C" int -openmc_spatial_legendre_filter_get_params(int32_t index, int* axis, - double* min, double* max) +extern "C" int openmc_spatial_legendre_filter_get_params( + int32_t index, int* axis, double* min, double* max) { // Check the filter. auto check_result = check_sptl_legendre_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Output the params. *axis = static_cast(filt->axis()); @@ -174,33 +169,36 @@ openmc_spatial_legendre_filter_get_params(int32_t index, int* axis, return 0; } -extern "C" int -openmc_spatial_legendre_filter_set_order(int32_t index, int order) +extern "C" int openmc_spatial_legendre_filter_set_order( + int32_t index, int order) { // Check the filter. auto check_result = check_sptl_legendre_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Update the filter. filt->set_order(order); return 0; } -extern "C" int -openmc_spatial_legendre_filter_set_params(int32_t index, const int* axis, - const double* min, const double* max) +extern "C" int openmc_spatial_legendre_filter_set_params( + int32_t index, const int* axis, const double* min, const double* max) { // Check the filter. auto check_result = check_sptl_legendre_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Update the filter. - if (axis) filt->set_axis(static_cast(*axis)); - if (min && max) filt->set_minmax(*min, *max); + if (axis) + filt->set_axis(static_cast(*axis)); + if (min && max) + filt->set_minmax(*min, *max); return 0; } diff --git a/src/tallies/filter_surface.cpp b/src/tallies/filter_surface.cpp index 53bbf40459a..a84d1772822 100644 --- a/src/tallies/filter_surface.cpp +++ b/src/tallies/filter_surface.cpp @@ -8,8 +8,7 @@ namespace openmc { -void -SurfaceFilter::from_xml(pugi::xml_node node) +void SurfaceFilter::from_xml(pugi::xml_node node) { auto surfaces = get_node_array(node, "bins"); @@ -17,8 +16,8 @@ SurfaceFilter::from_xml(pugi::xml_node node) for (auto& s : surfaces) { auto search = model::surface_map.find(s); if (search == model::surface_map.end()) { - throw std::runtime_error{fmt::format( - "Could not find surface {} specified on tally filter.", s)}; + throw std::runtime_error { + fmt::format("Could not find surface {} specified on tally filter.", s)}; } s = search->second; @@ -27,8 +26,7 @@ SurfaceFilter::from_xml(pugi::xml_node node) this->set_surfaces(surfaces); } -void -SurfaceFilter::set_surfaces(gsl::span surfaces) +void SurfaceFilter::set_surfaces(gsl::span surfaces) { // Clear existing surfaces surfaces_.clear(); @@ -46,9 +44,8 @@ SurfaceFilter::set_surfaces(gsl::span surfaces) n_bins_ = surfaces_.size(); } -void -SurfaceFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void SurfaceFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { auto search = map_.find(std::abs(p.surface()) - 1); if (search != map_.end()) { @@ -61,17 +58,16 @@ SurfaceFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -SurfaceFilter::to_statepoint(hid_t filter_group) const +void SurfaceFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); vector surface_ids; - for (auto c : surfaces_) surface_ids.push_back(model::surfaces[c]->id_); + for (auto c : surfaces_) + surface_ids.push_back(model::surfaces[c]->id_); write_dataset(filter_group, "bins", surface_ids); } -std::string -SurfaceFilter::text_label(int bin) const +std::string SurfaceFilter::text_label(int bin) const { return fmt::format("Surface {}", model::surfaces[surfaces_[bin]]->id_); } diff --git a/src/tallies/filter_time.cpp b/src/tallies/filter_time.cpp new file mode 100644 index 00000000000..0378aa28de3 --- /dev/null +++ b/src/tallies/filter_time.cpp @@ -0,0 +1,105 @@ +#include "openmc/tallies/filter_time.h" + +#include // for min, max, copy, adjacent_find +#include // for greater_equal +#include // for back_inserter + +#include + +#include "openmc/search.h" +#include "openmc/xml_interface.h" + +namespace openmc { + +//============================================================================== +// TimeFilter implementation +//============================================================================== + +void TimeFilter::from_xml(pugi::xml_node node) +{ + auto bins = get_node_array(node, "bins"); + this->set_bins(bins); +} + +void TimeFilter::set_bins(gsl::span bins) +{ + // Clear existing bins + bins_.clear(); + bins_.reserve(bins.size()); + + // Ensure time bins are sorted and don't have duplicates + if (std::adjacent_find(bins.cbegin(), bins.cend(), std::greater_equal<>()) != + bins.end()) { + throw std::runtime_error {"Time bins must be monotonically increasing."}; + } + + // Copy bins + std::copy(bins.cbegin(), bins.cend(), std::back_inserter(bins_)); + n_bins_ = bins_.size() - 1; +} + +void TimeFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const +{ + // Get the start/end time of the particle for this track + const auto t_start = p.time_last(); + const auto t_end = p.time(); + + // If time interval is entirely out of time bin range, exit + if (t_end < bins_.front() || t_start >= bins_.back()) + return; + + if (estimator == TallyEstimator::TRACKLENGTH) { + // ------------------------------------------------------------------------- + // For tracklength estimator, we have to check the start/end time of + // the current track and find where it overlaps with time bins and score + // accordingly + + // Determine first bin containing a portion of time interval + auto i_bin = lower_bound_index(bins_.begin(), bins_.end(), t_start); + + // If time interval is zero, add a match corresponding to the starting time + if (t_end == t_start) { + match.bins_.push_back(i_bin); + match.weights_.push_back(1.0); + return; + } + + // Find matching bins + double dt_total = t_end - t_start; + for (; i_bin < bins_.size() - 1; ++i_bin) { + double t_left = std::max(t_start, bins_[i_bin]); + double t_right = std::min(t_end, bins_[i_bin + 1]); + + // Add match with weight equal to the fraction of the time interval within + // the current time bin + const double fraction = (t_right - t_left) / dt_total; + match.bins_.push_back(i_bin); + match.weights_.push_back(fraction); + + if (t_end < bins_[i_bin + 1]) + break; + } + } else if (t_end < bins_.back()) { + // ------------------------------------------------------------------------- + // For collision estimator or surface tallies, find a match based on the + // exact time of the particle + + const auto i_bin = lower_bound_index(bins_.begin(), bins_.end(), t_end); + match.bins_.push_back(i_bin); + match.weights_.push_back(1.0); + } +} + +void TimeFilter::to_statepoint(hid_t filter_group) const +{ + Filter::to_statepoint(filter_group); + write_dataset(filter_group, "bins", bins_); +} + +std::string TimeFilter::text_label(int bin) const +{ + return fmt::format("Time [{}, {})", bins_[bin], bins_[bin + 1]); +} + +} // namespace openmc diff --git a/src/tallies/filter_universe.cpp b/src/tallies/filter_universe.cpp index 8dbfa646277..96ad0212d50 100644 --- a/src/tallies/filter_universe.cpp +++ b/src/tallies/filter_universe.cpp @@ -8,15 +8,14 @@ namespace openmc { -void -UniverseFilter::from_xml(pugi::xml_node node) +void UniverseFilter::from_xml(pugi::xml_node node) { // Get material IDs and convert to indices in the global materials vector auto universes = get_node_array(node, "bins"); for (auto& u : universes) { auto search = model::universe_map.find(u); if (search == model::universe_map.end()) { - throw std::runtime_error{fmt::format( + throw std::runtime_error {fmt::format( "Could not find universe {} specified on tally filter.", u)}; } u = search->second; @@ -25,8 +24,7 @@ UniverseFilter::from_xml(pugi::xml_node node) this->set_universes(universes); } -void -UniverseFilter::set_universes(gsl::span universes) +void UniverseFilter::set_universes(gsl::span universes) { // Clear existing universes universes_.clear(); @@ -44,9 +42,8 @@ UniverseFilter::set_universes(gsl::span universes) n_bins_ = universes_.size(); } -void -UniverseFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void UniverseFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { for (int i = 0; i < p.n_coord(); i++) { auto search = map_.find(p.coord(i).universe); @@ -57,17 +54,16 @@ UniverseFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -UniverseFilter::to_statepoint(hid_t filter_group) const +void UniverseFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); vector universe_ids; - for (auto u : universes_) universe_ids.push_back(model::universes[u]->id_); + for (auto u : universes_) + universe_ids.push_back(model::universes[u]->id_); write_dataset(filter_group, "bins", universe_ids); } -std::string -UniverseFilter::text_label(int bin) const +std::string UniverseFilter::text_label(int bin) const { return fmt::format("Universe {}", model::universes[universes_[bin]]->id_); } diff --git a/src/tallies/filter_zernike.cpp b/src/tallies/filter_zernike.cpp index d86298c4564..eb4c8bdfd00 100644 --- a/src/tallies/filter_zernike.cpp +++ b/src/tallies/filter_zernike.cpp @@ -2,10 +2,10 @@ #include #include -#include // For pair +#include // For pair #include -#include +#include #include "openmc/capi.h" #include "openmc/error.h" @@ -18,8 +18,7 @@ namespace openmc { // ZernikeFilter implementation //============================================================================== -void -ZernikeFilter::from_xml(pugi::xml_node node) +void ZernikeFilter::from_xml(pugi::xml_node node) { set_order(std::stoi(get_node_value(node, "order"))); x_ = std::stod(get_node_value(node, "x")); @@ -27,14 +26,13 @@ ZernikeFilter::from_xml(pugi::xml_node node) r_ = std::stod(get_node_value(node, "r")); } -void -ZernikeFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void ZernikeFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { // Determine the normalized (r,theta) coordinates. double x = p.r().x - x_; double y = p.r().y - y_; - double r = std::sqrt(x*x + y*y) / r_; + double r = std::sqrt(x * x + y * y) / r_; double theta = std::atan2(y, x); if (r <= 1.0) { @@ -48,8 +46,7 @@ ZernikeFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -void -ZernikeFilter::to_statepoint(hid_t filter_group) const +void ZernikeFilter::to_statepoint(hid_t filter_group) const { Filter::to_statepoint(filter_group); write_dataset(filter_group, "order", order_); @@ -58,11 +55,10 @@ ZernikeFilter::to_statepoint(hid_t filter_group) const write_dataset(filter_group, "r", r_); } -std::string -ZernikeFilter::text_label(int bin) const +std::string ZernikeFilter::text_label(int bin) const { Expects(bin >= 0 && bin < n_bins_); - for (int n = 0; n < order_+1; n++) { + for (int n = 0; n < order_ + 1; n++) { int last = (n + 1) * (n + 2) / 2; if (bin < last) { int first = last - (n + 1); @@ -73,28 +69,26 @@ ZernikeFilter::text_label(int bin) const UNREACHABLE(); } -void -ZernikeFilter::set_order(int order) +void ZernikeFilter::set_order(int order) { if (order < 0) { - throw std::invalid_argument{"Zernike order must be non-negative."}; + throw std::invalid_argument {"Zernike order must be non-negative."}; } order_ = order; - n_bins_ = ((order+1) * (order+2)) / 2; + n_bins_ = ((order + 1) * (order + 2)) / 2; } //============================================================================== // ZernikeRadialFilter implementation //============================================================================== -void -ZernikeRadialFilter::get_all_bins(const Particle& p, TallyEstimator estimator, - FilterMatch& match) const +void ZernikeRadialFilter::get_all_bins( + const Particle& p, TallyEstimator estimator, FilterMatch& match) const { // Determine the normalized radius coordinate. double x = p.r().x - x_; double y = p.r().y - y_; - double r = std::sqrt(x*x + y*y) / r_; + double r = std::sqrt(x * x + y * y) / r_; if (r <= 1.0) { // Compute and return the Zernike weights. @@ -107,14 +101,12 @@ ZernikeRadialFilter::get_all_bins(const Particle& p, TallyEstimator estimator, } } -std::string -ZernikeRadialFilter::text_label(int bin) const +std::string ZernikeRadialFilter::text_label(int bin) const { - return "Zernike expansion, Z" + std::to_string(2*bin) + ",0"; + return "Zernike expansion, Z" + std::to_string(2 * bin) + ",0"; } -void -ZernikeRadialFilter::set_order(int order) +void ZernikeRadialFilter::set_order(int order) { ZernikeFilter::set_order(order); n_bins_ = order / 2 + 1; @@ -124,8 +116,7 @@ ZernikeRadialFilter::set_order(int order) // C-API functions //============================================================================== -std::pair -check_zernike_filter(int32_t index) +std::pair check_zernike_filter(int32_t index) { // Make sure this is a valid index to an allocated filter. int err = verify_filter(index); @@ -145,29 +136,29 @@ check_zernike_filter(int32_t index) return {err, filt}; } -extern "C" int -openmc_zernike_filter_get_order(int32_t index, int* order) +extern "C" int openmc_zernike_filter_get_order(int32_t index, int* order) { // Check the filter. auto check_result = check_zernike_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Output the order. *order = filt->order(); return 0; } -extern "C" int -openmc_zernike_filter_get_params(int32_t index, double* x, double* y, - double* r) +extern "C" int openmc_zernike_filter_get_params( + int32_t index, double* x, double* y, double* r) { // Check the filter. auto check_result = check_zernike_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Output the params. *x = filt->x(); @@ -176,34 +167,37 @@ openmc_zernike_filter_get_params(int32_t index, double* x, double* y, return 0; } -extern "C" int -openmc_zernike_filter_set_order(int32_t index, int order) +extern "C" int openmc_zernike_filter_set_order(int32_t index, int order) { // Check the filter. auto check_result = check_zernike_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Update the filter. filt->set_order(order); return 0; } -extern "C" int -openmc_zernike_filter_set_params(int32_t index, const double* x, - const double* y, const double* r) +extern "C" int openmc_zernike_filter_set_params( + int32_t index, const double* x, const double* y, const double* r) { // Check the filter. auto check_result = check_zernike_filter(index); auto err = check_result.first; auto filt = check_result.second; - if (err) return err; + if (err) + return err; // Update the filter. - if (x) filt->set_x(*x); - if (y) filt->set_y(*y); - if (r) filt->set_r(*r); + if (x) + filt->set_x(*x); + if (y) + filt->set_y(*y); + if (r) + filt->set_r(*r); return 0; } diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index b159f43b03b..674987b8f13 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -3,6 +3,7 @@ #include "openmc/array.h" #include "openmc/capi.h" #include "openmc/constants.h" +#include "openmc/container_util.h" #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/mesh.h" @@ -18,25 +19,27 @@ #include "openmc/tallies/derivative.h" #include "openmc/tallies/filter.h" #include "openmc/tallies/filter_cell.h" +#include "openmc/tallies/filter_cellborn.h" #include "openmc/tallies/filter_cellfrom.h" #include "openmc/tallies/filter_collision.h" #include "openmc/tallies/filter_delayedgroup.h" #include "openmc/tallies/filter_energy.h" #include "openmc/tallies/filter_legendre.h" #include "openmc/tallies/filter_mesh.h" +#include "openmc/tallies/filter_meshborn.h" #include "openmc/tallies/filter_meshsurface.h" #include "openmc/tallies/filter_particle.h" #include "openmc/tallies/filter_sph_harm.h" #include "openmc/tallies/filter_surface.h" #include "openmc/xml_interface.h" -#include #include "xtensor/xadapt.hpp" #include "xtensor/xbuilder.hpp" // for empty_like #include "xtensor/xview.hpp" +#include #include // for max -#include // for size_t +#include // for size_t #include namespace openmc { @@ -46,20 +49,23 @@ namespace openmc { //============================================================================== namespace model { - std::unordered_map tally_map; - vector> tallies; - vector active_tallies; - vector active_analog_tallies; - vector active_tracklength_tallies; - vector active_collision_tallies; - vector active_meshsurf_tallies; - vector active_surface_tallies; -} +//! a mapping of tally ID to index in the tallies vector +std::unordered_map tally_map; +vector> tallies; +vector active_tallies; +vector active_analog_tallies; +vector active_tracklength_tallies; +vector active_collision_tallies; +vector active_meshsurf_tallies; +vector active_surface_tallies; +vector active_pulse_height_tallies; +vector pulse_height_cells; +} // namespace model namespace simulation { - xt::xtensor_fixed> global_tallies; - int32_t n_realizations {0}; -} +xt::xtensor_fixed> global_tallies; +int32_t n_realizations {0}; +} // namespace simulation double global_tally_absorption; double global_tally_collision; @@ -83,19 +89,25 @@ Tally::Tally(pugi::xml_node node) // Copy and set tally id if (!check_for_node(node, "id")) { - throw std::runtime_error{"Must specify id for tally in tally XML file."}; + throw std::runtime_error {"Must specify id for tally in tally XML file."}; } int32_t id = std::stoi(get_node_value(node, "id")); this->set_id(id); - if (check_for_node(node, "name")) name_ = get_node_value(node, "name"); + if (check_for_node(node, "name")) + name_ = get_node_value(node, "name"); + + if (check_for_node(node, "multiply_density")) { + multiply_density_ = get_node_value_bool(node, "multiply_density"); + } // ======================================================================= // READ DATA FOR FILTERS // Check if user is using old XML format and throw an error if so if (check_for_node(node, "filter")) { - throw std::runtime_error{"Tally filters must be specified independently of " + throw std::runtime_error { + "Tally filters must be specified independently of " "tallies in a element. The element itself should " "have a list of filters that apply, e.g., 1 2 " "where 1 and 2 are the IDs of filters specified outside of " @@ -114,7 +126,7 @@ Tally::Tally(pugi::xml_node node) // Determine if filter ID is valid auto it = model::filter_map.find(filter_id); if (it == model::filter_map.end()) { - throw std::runtime_error{fmt::format( + throw std::runtime_error {fmt::format( "Could not find filter {} specified on tally {}", filter_id, id_)}; } @@ -133,19 +145,22 @@ Tally::Tally(pugi::xml_node node) const auto& f = model::tally_filters[i_filter].get(); auto pf = dynamic_cast(f); - if (pf) particle_filter_index = i_filter; + if (pf) + particle_filter_index = i_filter; // Change the tally estimator if a filter demands it - std::string filt_type = f->type(); - if (filt_type == "energyout" || filt_type == "legendre") { + FilterType filt_type = f->type(); + if (filt_type == FilterType::ENERGY_OUT || + filt_type == FilterType::LEGENDRE) { estimator_ = TallyEstimator::ANALOG; - } else if (filt_type == "sphericalharmonics") { + } else if (filt_type == FilterType::SPHERICAL_HARMONICS) { auto sf = dynamic_cast(f); if (sf->cosine() == SphericalHarmonicsCosine::scatter) { estimator_ = TallyEstimator::ANALOG; } - } else if (filt_type == "spatiallegendre" || filt_type == "zernike" - || filt_type == "zernikeradial") { + } else if (filt_type == FilterType::SPATIAL_LEGENDRE || + filt_type == FilterType::ZERNIKE || + filt_type == FilterType::ZERNIKE_RADIAL) { estimator_ = TallyEstimator::COLLISION; } } @@ -165,13 +180,23 @@ Tally::Tally(pugi::xml_node node) } // Check if tally is compatible with particle type + if (!settings::photon_transport) { + for (int score : scores_) { + switch (score) { + case SCORE_PULSE_HEIGHT: + fatal_error( + "For pulse-height tallies, photon transport needs to be activated."); + break; + } + } + } if (settings::photon_transport) { if (particle_filter_index == C_NONE) { for (int score : scores_) { switch (score) { case SCORE_INVERSE_VELOCITY: fatal_error("Particle filter must be used with photon " - "transport on and inverse velocity score"); + "transport on and inverse velocity score"); break; case SCORE_FLUX: case SCORE_TOTAL: @@ -185,8 +210,9 @@ Tally::Tally(pugi::xml_node node) case SCORE_DELAYED_NU_FISSION: case SCORE_PROMPT_NU_FISSION: case SCORE_DECAY_RATE: - warning("Particle filter is not used with photon transport" - " on and " + reaction_name(score) + " score."); + warning("You are tallying the '" + reaction_name(score) + + "' score and haven't used a particle filter. This score will " + "include contributions from all particles."); break; } } @@ -197,9 +223,11 @@ Tally::Tally(pugi::xml_node node) auto pf = dynamic_cast(f); for (auto p : pf->particles()) { if (p != ParticleType::neutron) { - warning(fmt::format("Particle filter other than NEUTRON used with " + warning(fmt::format( + "Particle filter other than NEUTRON used with " "photon transport turned off. All tallies for particle type {}" - " will have no scores", static_cast(p))); + " will have no scores", + static_cast(p))); } } } @@ -225,14 +253,16 @@ Tally::Tally(pugi::xml_node node) } const auto& deriv = model::tally_derivs[deriv_]; - if (deriv.variable == DerivativeVariable::NUCLIDE_DENSITY - || deriv.variable == DerivativeVariable::TEMPERATURE) { + if (deriv.variable == DerivativeVariable::NUCLIDE_DENSITY || + deriv.variable == DerivativeVariable::TEMPERATURE) { for (int i_nuc : nuclides_) { if (has_energyout && i_nuc == -1) { - fatal_error(fmt::format("Error on tally {}: Cannot use a " + fatal_error(fmt::format( + "Error on tally {}: Cannot use a " "'nuclide_density' or 'temperature' derivative on a tally with an " "outgoing energy filter and 'total' nuclide rate. Instead, tally " - "each nuclide in the material individually.", id_)); + "each nuclide in the material individually.", + id_)); // Note that diff tallies with these characteristics would work // correctly if no tally events occur in the perturbed material // (e.g. pertrubing moderator but only tallying fuel), but this @@ -255,13 +285,15 @@ Tally::Tally(pugi::xml_node node) std::string est = get_node_value(node, "estimator"); if (est == "analog") { estimator_ = TallyEstimator::ANALOG; - } else if (est == "tracklength" || est == "track-length" - || est == "pathlength" || est == "path-length") { + } else if (est == "tracklength" || est == "track-length" || + est == "pathlength" || est == "path-length") { // If the estimator was set to an analog estimator, this means the // tally needs post-collision information - if (estimator_ == TallyEstimator::ANALOG || estimator_ == TallyEstimator::COLLISION) { - throw std::runtime_error{fmt::format("Cannot use track-length " - "estimator for tally {}", id_)}; + if (estimator_ == TallyEstimator::ANALOG || + estimator_ == TallyEstimator::COLLISION) { + throw std::runtime_error {fmt::format("Cannot use track-length " + "estimator for tally {}", + id_)}; } // Set estimator to track-length estimator @@ -271,16 +303,17 @@ Tally::Tally(pugi::xml_node node) // If the estimator was set to an analog estimator, this means the // tally needs post-collision information if (estimator_ == TallyEstimator::ANALOG) { - throw std::runtime_error{fmt::format("Cannot use collision estimator " - "for tally ", id_)}; + throw std::runtime_error {fmt::format("Cannot use collision estimator " + "for tally ", + id_)}; } // Set estimator to collision estimator estimator_ = TallyEstimator::COLLISION; } else { - throw std::runtime_error{fmt::format( - "Invalid estimator '{}' on tally {}", est, id_)}; + throw std::runtime_error { + fmt::format("Invalid estimator '{}' on tally {}", est, id_)}; } } @@ -297,7 +330,6 @@ Tally::Tally(pugi::xml_node node) } } #endif - } Tally::~Tally() @@ -305,15 +337,13 @@ Tally::~Tally() model::tally_map.erase(id_); } -Tally* -Tally::create(int32_t id) +Tally* Tally::create(int32_t id) { model::tallies.push_back(make_unique(id)); return model::tallies.back().get(); } -void -Tally::set_id(int32_t id) +void Tally::set_id(int32_t id) { Expects(id >= 0 || id == C_NONE); @@ -325,7 +355,8 @@ Tally::set_id(int32_t id) // Make sure no other tally has the same ID if (model::tally_map.find(id) != model::tally_map.end()) { - throw std::runtime_error{fmt::format("Two tallies have the same ID: {}", id)}; + throw std::runtime_error { + fmt::format("Two tallies have the same ID: {}", id)}; } // If no ID specified, auto-assign next ID in sequence @@ -342,8 +373,35 @@ Tally::set_id(int32_t id) model::tally_map[id] = index_; } -void -Tally::set_filters(gsl::span filters) +std::vector Tally::filter_types() const +{ + std::vector filter_types; + for (auto idx : this->filters()) + filter_types.push_back(model::tally_filters[idx]->type()); + return filter_types; +} + +std::unordered_map Tally::filter_indices() const +{ + std::unordered_map filter_indices; + for (int i = 0; i < this->filters().size(); i++) { + const auto& f = model::tally_filters[this->filters(i)]; + + filter_indices[f->type()] = i; + } + return filter_indices; +} + +bool Tally::has_filter(FilterType filter_type) const +{ + for (auto idx : this->filters()) { + if (model::tally_filters[idx]->type() == filter_type) + return true; + } + return false; +} + +void Tally::set_filters(gsl::span filters) { // Clear old data. filters_.clear(); @@ -353,33 +411,47 @@ Tally::set_filters(gsl::span filters) auto n = filters.size(); filters_.reserve(n); - for (int i = 0; i < n; ++i) { - // Add index to vector of filters - auto& f {filters[i]}; - filters_.push_back(model::filter_map.at(f->id())); - - // Keep track of indices for special filters. - if (dynamic_cast(f)) { - energyout_filter_ = i; - } else if (dynamic_cast(f)) { - delayedgroup_filter_ = i; - } + for (auto* filter : filters) { + add_filter(filter); } +} + +void Tally::add_filter(Filter* filter) +{ + int32_t filter_idx = model::filter_map.at(filter->id()); + // if this filter is already present, do nothing and return + if (std::find(filters_.begin(), filters_.end(), filter_idx) != filters_.end()) + return; + // Keep track of indices for special filters + if (filter->type() == FilterType::ENERGY_OUT) { + energyout_filter_ = filters_.size(); + } else if (filter->type() == FilterType::DELAYED_GROUP) { + delayedgroup_filter_ = filters_.size(); + } else if (filter->type() == FilterType::CELL) { + cell_filter_ = filters_.size(); + } else if (filter->type() == FilterType::ENERGY) { + energy_filter_ = filters_.size(); + } + filters_.push_back(filter_idx); +} + +void Tally::set_strides() +{ // Set the strides. Filters are traversed in reverse so that the last filter // has the shortest stride in memory and the first filter has the longest // stride. + auto n = filters_.size(); strides_.resize(n, 0); int stride = 1; - for (int i = n-1; i >= 0; --i) { + for (int i = n - 1; i >= 0; --i) { strides_[i] = stride; stride *= model::tally_filters[filters_[i]]->n_bins(); } n_filter_bins_ = stride; } -void -Tally::set_scores(pugi::xml_node node) +void Tally::set_scores(pugi::xml_node node) { if (!check_for_node(node, "scores")) fatal_error(fmt::format("No scores specified on tally {}", id_)); @@ -401,17 +473,23 @@ void Tally::set_scores(const vector& scores) bool cellfrom_present = false; bool surface_present = false; bool meshsurface_present = false; + bool non_cell_energy_present = false; for (auto i_filt : filters_) { const auto* filt {model::tally_filters[i_filt].get()}; - if (dynamic_cast(filt)) { + // Checking for only cell and energy filters for pulse-height tally + if (!(filt->type() == FilterType::CELL || + filt->type() == FilterType::ENERGY)) { + non_cell_energy_present = true; + } + if (filt->type() == FilterType::LEGENDRE) { legendre_present = true; - } else if (dynamic_cast(filt)) { + } else if (filt->type() == FilterType::CELLFROM) { cellfrom_present = true; - } else if (dynamic_cast(filt)) { + } else if (filt->type() == FilterType::CELL) { cell_present = true; - } else if (dynamic_cast(filt)) { + } else if (filt->type() == FilterType::SURFACE) { surface_present = true; - } else if (dynamic_cast(filt)) { + } else if (filt->type() == FilterType::MESH_SURFACE) { meshsurface_present = true; } } @@ -440,8 +518,9 @@ void Tally::set_scores(const vector& scores) case SCORE_ABSORPTION: case SCORE_FISSION: if (energyout_present) - fatal_error("Cannot tally " + score_str + " reaction rate with an " - "outgoing energy filter"); + fatal_error("Cannot tally " + score_str + + " reaction rate with an " + "outgoing energy filter"); break; case SCORE_SCATTER: @@ -468,8 +547,9 @@ void Tally::set_scores(const vector& scores) if (surface_present || cell_present || cellfrom_present) { if (meshsurface_present) fatal_error("Cannot tally mesh surface currents in the same tally as " - "normal surface currents"); + "normal surface currents"); type_ = TallyType::SURFACE; + estimator_ = TallyEstimator::ANALOG; } else if (meshsurface_present) { type_ = TallyType::MESH_SURFACE; } else { @@ -478,7 +558,33 @@ void Tally::set_scores(const vector& scores) break; case HEATING: - if (settings::photon_transport) estimator_ = TallyEstimator::COLLISION; + if (settings::photon_transport) + estimator_ = TallyEstimator::COLLISION; + break; + + case SCORE_PULSE_HEIGHT: + if (non_cell_energy_present) { + fatal_error("Pulse-height tallies are not compatible with filters " + "other than CellFilter and EnergyFilter"); + } + type_ = TallyType::PULSE_HEIGHT; + + // Collecting indices of all cells covered by the filters in the pulse + // height tally in global variable pulse_height_cells + for (const auto& i_filt : filters_) { + auto cell_filter = + dynamic_cast(model::tally_filters[i_filt].get()); + if (cell_filter) { + const auto& cells = cell_filter->cells(); + for (int i = 0; i < cell_filter->n_bins(); i++) { + int cell_index = cells[i]; + if (!contains(model::pulse_height_cells, cell_index)) { + model::pulse_height_cells.push_back(cell_index); + } + } + } + } + break; } @@ -489,9 +595,9 @@ void Tally::set_scores(const vector& scores) for (auto it1 = scores_.begin(); it1 != scores_.end(); ++it1) { for (auto it2 = it1 + 1; it2 != scores_.end(); ++it2) { if (*it1 == *it2) - fatal_error(fmt::format( - "Duplicate score of type \"{}\" found in tally {}", - reaction_name(*it1), id_)); + fatal_error( + fmt::format("Duplicate score of type \"{}\" found in tally {}", + reaction_name(*it1), id_)); } } @@ -499,23 +605,23 @@ void Tally::set_scores(const vector& scores) if (!settings::run_CE) { for (auto sc : scores_) if (sc > 0) - fatal_error("Cannot tally " + reaction_name(sc) + " reaction rate " - "in multi-group mode"); + fatal_error("Cannot tally " + reaction_name(sc) + + " reaction rate " + "in multi-group mode"); } // Make sure current scores are not mixed in with volumetric scores. if (type_ == TallyType::SURFACE || type_ == TallyType::MESH_SURFACE) { if (scores_.size() != 1) fatal_error("Cannot tally other scores in the same tally as surface " - "currents."); + "currents."); } if ((surface_present || meshsurface_present) && scores_[0] != SCORE_CURRENT) fatal_error("Cannot tally score other than 'current' when using a surface " - "or mesh-surface filter."); + "or mesh-surface filter."); } -void -Tally::set_nuclides(pugi::xml_node node) +void Tally::set_nuclides(pugi::xml_node node) { nuclides_.clear(); @@ -525,22 +631,10 @@ Tally::set_nuclides(pugi::xml_node node) return; } - if (get_node_value(node, "nuclides") == "all") { - // This tally should bin every nuclide in the problem. It should also bin - // the total material rates. To achieve this, set the nuclides_ vector to - // 0, 1, 2, ..., -1. - nuclides_.reserve(data::nuclides.size() + 1); - for (auto i = 0; i < data::nuclides.size(); ++i) - nuclides_.push_back(i); - nuclides_.push_back(-1); - all_nuclides_ = true; - - } else { - // The user provided specifics nuclides. Parse it as an array with either - // "total" or a nuclide name like "U-235" in each position. - auto words = get_node_array(node, "nuclides"); - this->set_nuclides(words); - } + // The user provided specifics nuclides. Parse it as an array with either + // "total" or a nuclide name like "U235" in each position. + auto words = get_node_array(node, "nuclides"); + this->set_nuclides(words); } void Tally::set_nuclides(const vector& nuclides) @@ -552,18 +646,19 @@ void Tally::set_nuclides(const vector& nuclides) nuclides_.push_back(-1); } else { auto search = data::nuclide_map.find(nuc); - if (search == data::nuclide_map.end()) - fatal_error(fmt::format("Could not find the nuclide {} specified in " - "tally {} in any material", nuc, id_)); - nuclides_.push_back(search->second); + if (search == data::nuclide_map.end()) { + int err = openmc_load_nuclide(nuc.c_str(), nullptr, 0); + if (err < 0) + throw std::runtime_error {openmc_err_msg}; + } + nuclides_.push_back(data::nuclide_map.at(nuc)); } } } -void -Tally::init_triggers(pugi::xml_node node) +void Tally::init_triggers(pugi::xml_node node) { - for (auto trigger_node: node.children("trigger")) { + for (auto trigger_node : node.children("trigger")) { // Read the trigger type. TriggerMetric metric; if (check_for_node(trigger_node, "type")) { @@ -575,8 +670,8 @@ Tally::init_triggers(pugi::xml_node node) } else if (type_str == "rel_err") { metric = TriggerMetric::relative_error; } else { - fatal_error(fmt::format("Unknown trigger type \"{}\" in tally {}", - type_str, id_)); + fatal_error(fmt::format( + "Unknown trigger type \"{}\" in tally {}", type_str, id_)); } } else { fatal_error(fmt::format( @@ -595,6 +690,12 @@ Tally::init_triggers(pugi::xml_node node) "Must specify trigger threshold for tally {} in tally XML file", id_)); } + // Read whether to allow zero-tally bins to be ignored. + bool ignore_zeros = false; + if (check_for_node(trigger_node, "ignore_zeros")) { + ignore_zeros = get_node_value_bool(trigger_node, "ignore_zeros"); + } + // Read the trigger scores. vector trigger_scores; if (check_for_node(trigger_node, "scores")) { @@ -608,18 +709,21 @@ Tally::init_triggers(pugi::xml_node node) if (score_str == "all") { triggers_.reserve(triggers_.size() + this->scores_.size()); for (auto i_score = 0; i_score < this->scores_.size(); ++i_score) { - triggers_.push_back({metric, threshold, i_score}); + triggers_.push_back({metric, threshold, ignore_zeros, i_score}); } } else { int i_score = 0; for (; i_score < this->scores_.size(); ++i_score) { - if (reaction_name(this->scores_[i_score]) == score_str) break; + if (reaction_name(this->scores_[i_score]) == score_str) + break; } if (i_score == this->scores_.size()) { - fatal_error(fmt::format("Could not find the score \"{}\" in tally " - "{} but it was listed in a trigger on that tally", score_str, id_)); + fatal_error( + fmt::format("Could not find the score \"{}\" in tally " + "{} but it was listed in a trigger on that tally", + score_str, id_)); } - triggers_.push_back({metric, threshold, i_score}); + triggers_.push_back({metric, threshold, ignore_zeros, i_score}); } } } @@ -656,37 +760,77 @@ void Tally::accumulate() } // Account for number of source particles in normalization - double norm = total_source / (settings::n_particles * settings::gen_per_batch); + double norm = + total_source / (settings::n_particles * settings::gen_per_batch); + + if (settings::solver_type == SolverType::RANDOM_RAY) { + norm = 1.0; + } - // Accumulate each result - #pragma omp parallel for +// Accumulate each result +#pragma omp parallel for for (int i = 0; i < results_.shape()[0]; ++i) { for (int j = 0; j < results_.shape()[1]; ++j) { double val = results_(i, j, TallyResult::VALUE) * norm; results_(i, j, TallyResult::VALUE) = 0.0; results_(i, j, TallyResult::SUM) += val; - results_(i, j, TallyResult::SUM_SQ) += val*val; + results_(i, j, TallyResult::SUM_SQ) += val * val; } } } } -std::string -Tally::score_name(int score_idx) const { +int Tally::score_index(const std::string& score) const +{ + for (int i = 0; i < scores_.size(); i++) { + if (this->score_name(i) == score) + return i; + } + return -1; +} + +xt::xarray Tally::get_reshaped_data() const +{ + std::vector shape; + for (auto f : filters()) { + shape.push_back(model::tally_filters[f]->n_bins()); + } + + // add number of scores and nuclides to tally + shape.push_back(results_.shape()[1]); + shape.push_back(results_.shape()[2]); + + xt::xarray reshaped_results = results_; + reshaped_results.reshape(shape); + return reshaped_results; +} + +std::string Tally::score_name(int score_idx) const +{ if (score_idx < 0 || score_idx >= scores_.size()) { fatal_error("Index in scores array is out of bounds."); } return reaction_name(scores_[score_idx]); } -std::string -Tally::nuclide_name(int nuclide_idx) const { +std::vector Tally::scores() const +{ + std::vector score_names; + for (int score : scores_) + score_names.push_back(reaction_name(score)); + return score_names; +} + +std::string Tally::nuclide_name(int nuclide_idx) const +{ if (nuclide_idx < 0 || nuclide_idx >= nuclides_.size()) { fatal_error("Index in nuclides array is out of bounds"); } int nuclide = nuclides_.at(nuclide_idx); - if (nuclide == -1) { return "total"; } + if (nuclide == -1) { + return "total"; + } return data::nuclides.at(nuclide)->name_; } @@ -698,7 +842,8 @@ void read_tallies_xml() { // Check if tallies.xml exists. If not, just return since it is optional std::string filename = settings::path_input + "tallies.xml"; - if (!file_exists(filename)) return; + if (!file_exists(filename)) + return; write_message("Reading tallies XML file...", 5); @@ -707,6 +852,11 @@ void read_tallies_xml() doc.load_file(filename.c_str()); pugi::xml_node root = doc.document_element(); + read_tallies_xml(root); +} + +void read_tallies_xml(pugi::xml_node root) +{ // Check for setting if (check_for_node(root, "assume_separate")) { settings::assume_separate = get_node_value_bool(root, "assume_separate"); @@ -716,7 +866,8 @@ void read_tallies_xml() read_meshes(root); // We only need the mesh info for plotting - if (settings::run_mode == RunMode::PLOTTING) return; + if (settings::run_mode == RunMode::PLOTTING) + return; // Read data for tally derivatives read_tally_derivatives(root); @@ -734,7 +885,8 @@ void read_tallies_xml() // Check for user tallies int n = 0; - for (auto node : root.children("tally")) ++n; + for (auto node : root.children("tally")) + ++n; if (n == 0 && mpi::master) { warning("No tallies present in tallies.xml file."); } @@ -754,7 +906,8 @@ void reduce_tally_results() auto& tally {model::tallies[i_tally]}; // Get view of accumulated tally values - auto values_view = xt::view(tally->results_, xt::all(), xt::all(), static_cast(TallyResult::VALUE)); + auto values_view = xt::view(tally->results_, xt::all(), xt::all(), + static_cast(TallyResult::VALUE)); // Make copy of tally values in contiguous array xt::xtensor values = values_view; @@ -778,7 +931,8 @@ void reduce_tally_results() // Get view of global tally values auto& gt = simulation::global_tallies; - auto gt_values_view = xt::view(gt, xt::all(), static_cast(TallyResult::VALUE)); + auto gt_values_view = + xt::view(gt, xt::all(), static_cast(TallyResult::VALUE)); // Make copy of values in contiguous array xt::xtensor gt_values = gt_values_view; @@ -800,16 +954,18 @@ void reduce_tally_results() double weight_reduced; MPI_Reduce(&simulation::total_weight, &weight_reduced, 1, MPI_DOUBLE, MPI_SUM, 0, mpi::intracomm); - if (mpi::master) simulation::total_weight = weight_reduced; + if (mpi::master) + simulation::total_weight = weight_reduced; } #endif -void -accumulate_tallies() +void accumulate_tallies() { #ifdef OPENMC_MPI // Combine tally results onto master process - if (mpi::n_procs > 1) reduce_tally_results(); + if (mpi::n_procs > 1 && settings::solver_type == SolverType::MONTE_CARLO) { + reduce_tally_results(); + } #endif // Increase number of realizations (only used for global tallies) @@ -822,9 +978,12 @@ accumulate_tallies() if (settings::run_mode == RunMode::EIGENVALUE) { if (simulation::current_batch > settings::n_inactive) { // Accumulate products of different estimators of k - double k_col = gt(GlobalTally::K_COLLISION, TallyResult::VALUE) / simulation::total_weight; - double k_abs = gt(GlobalTally::K_ABSORPTION, TallyResult::VALUE) / simulation::total_weight; - double k_tra = gt(GlobalTally::K_TRACKLENGTH, TallyResult::VALUE) / simulation::total_weight; + double k_col = gt(GlobalTally::K_COLLISION, TallyResult::VALUE) / + simulation::total_weight; + double k_abs = gt(GlobalTally::K_ABSORPTION, TallyResult::VALUE) / + simulation::total_weight; + double k_tra = gt(GlobalTally::K_TRACKLENGTH, TallyResult::VALUE) / + simulation::total_weight; simulation::k_col_abs += k_col * k_abs; simulation::k_col_tra += k_col * k_tra; simulation::k_abs_tra += k_abs * k_tra; @@ -833,10 +992,10 @@ accumulate_tallies() // Accumulate results for global tallies for (int i = 0; i < N_GLOBAL_TALLIES; ++i) { - double val = gt(i, TallyResult::VALUE)/simulation::total_weight; + double val = gt(i, TallyResult::VALUE) / simulation::total_weight; gt(i, TallyResult::VALUE) = 0.0; gt(i, TallyResult::SUM) += val; - gt(i, TallyResult::SUM_SQ) += val*val; + gt(i, TallyResult::SUM_SQ) += val * val; } } @@ -847,8 +1006,7 @@ accumulate_tallies() } } -void -setup_active_tallies() +void setup_active_tallies() { model::active_tallies.clear(); model::active_analog_tallies.clear(); @@ -856,6 +1014,7 @@ setup_active_tallies() model::active_collision_tallies.clear(); model::active_meshsurf_tallies.clear(); model::active_surface_tallies.clear(); + model::active_pulse_height_tallies.clear(); for (auto i = 0; i < model::tallies.size(); ++i) { const auto& tally {*model::tallies[i]}; @@ -866,14 +1025,14 @@ setup_active_tallies() case TallyType::VOLUME: switch (tally.estimator_) { - case TallyEstimator::ANALOG: - model::active_analog_tallies.push_back(i); - break; - case TallyEstimator::TRACKLENGTH: - model::active_tracklength_tallies.push_back(i); - break; - case TallyEstimator::COLLISION: - model::active_collision_tallies.push_back(i); + case TallyEstimator::ANALOG: + model::active_analog_tallies.push_back(i); + break; + case TallyEstimator::TRACKLENGTH: + model::active_tracklength_tallies.push_back(i); + break; + case TallyEstimator::COLLISION: + model::active_collision_tallies.push_back(i); } break; @@ -883,13 +1042,17 @@ setup_active_tallies() case TallyType::SURFACE: model::active_surface_tallies.push_back(i); + break; + + case TallyType::PULSE_HEIGHT: + model::active_pulse_height_tallies.push_back(i); + break; } } } } -void -free_memory_tally() +void free_memory_tally() { model::tally_derivs.clear(); model::tally_deriv_map.clear(); @@ -905,6 +1068,7 @@ free_memory_tally() model::active_collision_tallies.clear(); model::active_meshsurf_tallies.clear(); model::active_surface_tallies.clear(); + model::active_pulse_height_tallies.clear(); model::tally_map.clear(); } @@ -913,19 +1077,20 @@ free_memory_tally() // C-API functions //============================================================================== -extern "C" int -openmc_extend_tallies(int32_t n, int32_t* index_start, int32_t* index_end) +extern "C" int openmc_extend_tallies( + int32_t n, int32_t* index_start, int32_t* index_end) { - if (index_start) *index_start = model::tallies.size(); - if (index_end) *index_end = model::tallies.size() + n - 1; + if (index_start) + *index_start = model::tallies.size(); + if (index_end) + *index_end = model::tallies.size() + n - 1; for (int i = 0; i < n; ++i) { model::tallies.push_back(make_unique(-1)); } return 0; } -extern "C" int -openmc_get_tally_index(int32_t id, int32_t* index) +extern "C" int openmc_get_tally_index(int32_t id, int32_t* index) { auto it = model::tally_map.find(id); if (it == model::tally_map.end()) { @@ -937,8 +1102,7 @@ openmc_get_tally_index(int32_t id, int32_t* index) return 0; } -extern "C" void -openmc_get_tally_next_id(int32_t* id) +extern "C" void openmc_get_tally_next_id(int32_t* id) { int32_t largest_tally_id = 0; for (const auto& t : model::tallies) { @@ -947,8 +1111,7 @@ openmc_get_tally_next_id(int32_t* id) *id = largest_tally_id + 1; } -extern "C" int -openmc_tally_get_estimator(int32_t index, int* estimator) +extern "C" int openmc_tally_get_estimator(int32_t index, int* estimator) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -959,8 +1122,7 @@ openmc_tally_get_estimator(int32_t index, int* estimator) return 0; } -extern "C" int -openmc_tally_set_estimator(int32_t index, const char* estimator) +extern "C" int openmc_tally_set_estimator(int32_t index, const char* estimator) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -983,8 +1145,7 @@ openmc_tally_set_estimator(int32_t index, const char* estimator) return 0; } -extern "C" int -openmc_tally_get_id(int32_t index, int32_t* id) +extern "C" int openmc_tally_get_id(int32_t index, int32_t* id) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -995,8 +1156,7 @@ openmc_tally_get_id(int32_t index, int32_t* id) return 0; } -extern "C" int -openmc_tally_set_id(int32_t index, int32_t id) +extern "C" int openmc_tally_set_id(int32_t index, int32_t id) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1007,8 +1167,7 @@ openmc_tally_set_id(int32_t index, int32_t id) return 0; } -extern "C" int -openmc_tally_get_type(int32_t index, int32_t* type) +extern "C" int openmc_tally_get_type(int32_t index, int32_t* type) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1019,8 +1178,7 @@ openmc_tally_get_type(int32_t index, int32_t* type) return 0; } -extern "C" int -openmc_tally_set_type(int32_t index, const char* type) +extern "C" int openmc_tally_set_type(int32_t index, const char* type) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1032,6 +1190,8 @@ openmc_tally_set_type(int32_t index, const char* type) model::tallies[index]->type_ = TallyType::MESH_SURFACE; } else if (strcmp(type, "surface") == 0) { model::tallies[index]->type_ = TallyType::SURFACE; + } else if (strcmp(type, "pulse-height") == 0) { + model::tallies[index]->type_ = TallyType::PULSE_HEIGHT; } else { set_errmsg(fmt::format("Unknown tally type: {}", type)); return OPENMC_E_INVALID_ARGUMENT; @@ -1040,8 +1200,7 @@ openmc_tally_set_type(int32_t index, const char* type) return 0; } -extern "C" int -openmc_tally_get_active(int32_t index, bool* active) +extern "C" int openmc_tally_get_active(int32_t index, bool* active) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1052,8 +1211,7 @@ openmc_tally_get_active(int32_t index, bool* active) return 0; } -extern "C" int -openmc_tally_set_active(int32_t index, bool active) +extern "C" int openmc_tally_set_active(int32_t index, bool active) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1064,8 +1222,7 @@ openmc_tally_set_active(int32_t index, bool active) return 0; } -extern "C" int -openmc_tally_get_writable(int32_t index, bool* writable) +extern "C" int openmc_tally_get_writable(int32_t index, bool* writable) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1076,8 +1233,7 @@ openmc_tally_get_writable(int32_t index, bool* writable) return 0; } -extern "C" int -openmc_tally_set_writable(int32_t index, bool writable) +extern "C" int openmc_tally_set_writable(int32_t index, bool writable) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1088,8 +1244,29 @@ openmc_tally_set_writable(int32_t index, bool writable) return 0; } -extern "C" int -openmc_tally_get_scores(int32_t index, int** scores, int* n) +extern "C" int openmc_tally_get_multiply_density(int32_t index, bool* value) +{ + if (index < 0 || index >= model::tallies.size()) { + set_errmsg("Index in tallies array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + *value = model::tallies[index]->multiply_density(); + + return 0; +} + +extern "C" int openmc_tally_set_multiply_density(int32_t index, bool value) +{ + if (index < 0 || index >= model::tallies.size()) { + set_errmsg("Index in tallies array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + model::tallies[index]->set_multiply_density(value); + + return 0; +} + +extern "C" int openmc_tally_get_scores(int32_t index, int** scores, int* n) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1101,8 +1278,8 @@ openmc_tally_get_scores(int32_t index, int** scores, int* n) return 0; } -extern "C" int -openmc_tally_set_scores(int32_t index, int n, const char** scores) +extern "C" int openmc_tally_set_scores( + int32_t index, int n, const char** scores) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1120,8 +1297,7 @@ openmc_tally_set_scores(int32_t index, int n, const char** scores) return 0; } -extern "C" int -openmc_tally_get_nuclides(int32_t index, int** nuclides, int* n) +extern "C" int openmc_tally_get_nuclides(int32_t index, int** nuclides, int* n) { // Make sure the index fits in the array bounds. if (index < 0 || index >= model::tallies.size()) { @@ -1135,8 +1311,8 @@ openmc_tally_get_nuclides(int32_t index, int** nuclides, int* n) return 0; } -extern "C" int -openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides) +extern "C" int openmc_tally_set_nuclides( + int32_t index, int n, const char** nuclides) { // Make sure the index fits in the array bounds. if (index < 0 || index >= model::tallies.size()) { @@ -1146,16 +1322,19 @@ openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides) vector words(nuclides, nuclides + n); vector nucs; - for (auto word : words){ + for (auto word : words) { if (word == "total") { nucs.push_back(-1); } else { auto search = data::nuclide_map.find(word); if (search == data::nuclide_map.end()) { - set_errmsg("Nuclide \"" + word + "\" has not been loaded yet"); - return OPENMC_E_DATA; + int err = openmc_load_nuclide(word.c_str(), nullptr, 0); + if (err < 0) { + set_errmsg(openmc_err_msg); + return OPENMC_E_DATA; + } } - nucs.push_back(search->second); + nucs.push_back(data::nuclide_map.at(word)); } } @@ -1164,8 +1343,8 @@ openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides) return 0; } -extern "C" int -openmc_tally_get_filters(int32_t index, const int32_t** indices, size_t* n) +extern "C" int openmc_tally_get_filters( + int32_t index, const int32_t** indices, size_t* n) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); @@ -1177,8 +1356,8 @@ openmc_tally_get_filters(int32_t index, const int32_t** indices, size_t* n) return 0; } -extern "C" int -openmc_tally_set_filters(int32_t index, size_t n, const int32_t* indices) +extern "C" int openmc_tally_set_filters( + int32_t index, size_t n, const int32_t* indices) { // Make sure the index fits in the array bounds. if (index < 0 || index >= model::tallies.size()) { @@ -1204,8 +1383,7 @@ openmc_tally_set_filters(int32_t index, size_t n, const int32_t* indices) } //! Reset tally results and number of realizations -extern "C" int -openmc_tally_reset(int32_t index) +extern "C" int openmc_tally_reset(int32_t index) { // Make sure the index fits in the array bounds. if (index < 0 || index >= model::tallies.size()) { @@ -1217,8 +1395,7 @@ openmc_tally_reset(int32_t index) return 0; } -extern "C" int -openmc_tally_get_n_realizations(int32_t index, int32_t* n) +extern "C" int openmc_tally_get_n_realizations(int32_t index, int32_t* n) { // Make sure the index fits in the array bounds. if (index < 0 || index >= model::tallies.size()) { @@ -1232,8 +1409,8 @@ openmc_tally_get_n_realizations(int32_t index, int32_t* n) //! \brief Returns a pointer to a tally results array along with its shape. This //! allows a user to obtain in-memory tally results from Python directly. -extern "C" int -openmc_tally_results(int32_t index, double** results, size_t* shape) +extern "C" int openmc_tally_results( + int32_t index, double** results, size_t* shape) { // Make sure the index fits in the array bounds. if (index < 0 || index >= model::tallies.size()) { @@ -1256,13 +1433,31 @@ openmc_tally_results(int32_t index, double** results, size_t* shape) return 0; } -extern "C" int -openmc_global_tallies(double** ptr) +extern "C" int openmc_global_tallies(double** ptr) { *ptr = simulation::global_tallies.data(); return 0; } -extern "C" size_t tallies_size() { return model::tallies.size(); } +extern "C" size_t tallies_size() +{ + return model::tallies.size(); +} + +// given a tally ID, remove it from the tallies vector +extern "C" int openmc_remove_tally(int32_t index) +{ + // check that id is in the map + if (index < 0 || index >= model::tallies.size()) { + set_errmsg("Index in tallies array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + + // delete the tally via iterator pointing to correct position + // this calls the Tally destructor, removing the tally from the map as well + model::tallies.erase(model::tallies.begin() + index); + + return 0; +} } // namespace openmc diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index 5242db2e3f4..e798161ec2f 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -15,6 +15,7 @@ #include "openmc/string_utils.h" #include "openmc/tallies/derivative.h" #include "openmc/tallies/filter.h" +#include "openmc/tallies/filter_cell.h" #include "openmc/tallies/filter_delayedgroup.h" #include "openmc/tallies/filter_energy.h" @@ -89,17 +90,16 @@ FilterBinIter::FilterBinIter( this->compute_index_weight(); } -FilterBinIter& -FilterBinIter::operator++() +FilterBinIter& FilterBinIter::operator++() { // Find the next valid combination of filter bins. To do this, we search // backwards through the filters until we find the first filter whose bins // can be incremented. bool visited_all_combinations = true; - for (int i = tally_.filters().size()-1; i >= 0; --i) { + for (int i = tally_.filters().size() - 1; i >= 0; --i) { auto i_filt = tally_.filters(i); auto& match {filter_matches_[i_filt]}; - if (match.i_bin_ < match.bins_.size()-1) { + if (match.i_bin_ < match.bins_.size() - 1) { // The bin for this filter can be incremented. Increment it and do not // touch any of the remaining filters. ++match.i_bin_; @@ -124,8 +124,7 @@ FilterBinIter::operator++() return *this; } -void -FilterBinIter::compute_index_weight() +void FilterBinIter::compute_index_weight() { index_ = 0; weight_ = 1.; @@ -166,9 +165,10 @@ void score_fission_delayed_dg(int i_tally, int d_bin, double score, filter_weight *= match.weights_[i_bin]; } - // Update the tally result - #pragma omp atomic - tally.results_(filter_index, score_index, TallyResult::VALUE) += score*filter_weight; +// Update the tally result +#pragma omp atomic + tally.results_(filter_index, score_index, TallyResult::VALUE) += + score * filter_weight; // Reset the original delayed group bin dg_match.bins_[i_bin] = original_bin; @@ -204,10 +204,10 @@ double score_fission_q(const Particle& p, int score_bin, const Tally& tally, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // fission scaled by the Q-value - if (p.neutron_xs(p.event_nuclide()).absorption > 0) { - return p.wgt_absorb() * get_nuc_fission_q(nuc, p, score_bin) * + if (p.neutron_xs(p.event_nuclide()).total > 0) { + return p.wgt_last() * get_nuc_fission_q(nuc, p, score_bin) * p.neutron_xs(p.event_nuclide()).fission * flux / - p.neutron_xs(p.event_nuclide()).absorption; + p.neutron_xs(p.event_nuclide()).total; } } else { // Skip any non-absorption events @@ -245,24 +245,23 @@ double score_fission_q(const Particle& p, int score_bin, const Tally& tally, //! Helper function to obtain the kerma coefficient for a given nuclide -double get_nuclide_neutron_heating(const Particle& p, const Nuclide& nuc, - int rxn_index, int i_nuclide) +double get_nuclide_neutron_heating( + const Particle& p, const Nuclide& nuc, int rxn_index, int i_nuclide) { size_t mt = nuc.reaction_index_[rxn_index]; - if (mt == C_NONE) return 0.0; - - auto i_temp = p.neutron_xs(i_nuclide).index_temp; - if (i_temp < 0) return 0.0; // Can be true due to multipole + if (mt == C_NONE) + return 0.0; - const auto& rxn {*nuc.reactions_[mt]}; - const auto& xs {rxn.xs_[i_temp]}; - auto i_grid = p.neutron_xs(i_nuclide).index_grid; - if (i_grid < xs.threshold) return 0.0; + const auto& micro = p.neutron_xs(i_nuclide); + auto i_temp = micro.index_temp; + if (i_temp < 0) + return 0.0; // Can be true due to multipole // Determine total kerma - auto f = p.neutron_xs(i_nuclide).interp_factor; - double kerma = (1.0 - f) * xs.value[i_grid-xs.threshold] - + f * xs.value[i_grid-xs.threshold+1]; + const auto& rx {*nuc.reactions_[mt]}; + double kerma = rx.xs(micro); + if (kerma == 0.0) + return 0.0; if (settings::run_mode == RunMode::EIGENVALUE) { // Determine kerma for fission as (EFR + EB)*sigma_f @@ -287,9 +286,8 @@ double get_nuclide_neutron_heating(const Particle& p, const Nuclide& nuc, //! Helper function to obtain neutron heating [eV] double score_neutron_heating(const Particle& p, const Tally& tally, double flux, - int rxn_bin, int i_nuclide, double atom_density) + int rxn_bin, int i_nuclide, double atom_density) { - double score; // Get heating macroscopic "cross section" double heating_xs; if (i_nuclide >= 0) { @@ -304,28 +302,24 @@ double score_neutron_heating(const Particle& p, const Tally& tally, double flux, if (p.material() != MATERIAL_VOID) { heating_xs = 0.0; const Material& material {*model::materials[p.material()]}; - for (auto i = 0; i< material.nuclide_.size(); ++i) { + for (auto i = 0; i < material.nuclide_.size(); ++i) { int j_nuclide = material.nuclide_[i]; double atom_density {material.atom_density_(i)}; const Nuclide& nuc {*data::nuclides[j_nuclide]}; - heating_xs += atom_density * get_nuclide_neutron_heating(p, nuc, rxn_bin, j_nuclide); + heating_xs += atom_density * + get_nuclide_neutron_heating(p, nuc, rxn_bin, j_nuclide); } if (tally.estimator_ == TallyEstimator::ANALOG) { heating_xs /= p.macro_xs().total; } } } - score = heating_xs * flux; + double score = heating_xs * flux; if (tally.estimator_ == TallyEstimator::ANALOG) { // All events score to a heating tally bin. We actually use a // collision estimator in place of an analog one since there is no // reaction-wise heating cross section - if (settings::survival_biasing) { - // Account for the fact that some weight has been absorbed - score *= p.wgt_last() + p.wgt_absorb(); - } else { - score *= p.wgt_last(); - } + score *= p.wgt_last(); } return score; } @@ -335,16 +329,15 @@ double score_neutron_heating(const Particle& p, const Tally& tally, double flux, //! In this case, we may need to score to multiple bins if there were multiple //! neutrons produced with different energies. -void -score_fission_eout(Particle& p, int i_tally, int i_score, int score_bin) +void score_fission_eout(Particle& p, int i_tally, int i_score, int score_bin) { auto& tally {*model::tallies[i_tally]}; auto i_eout_filt = tally.filters()[tally.energyout_filter_]; auto i_bin = p.filter_matches(i_eout_filt).i_bin_; auto bin_energyout = p.filter_matches(i_eout_filt).bins_[i_bin]; - const EnergyoutFilter& eo_filt - {*dynamic_cast(model::tally_filters[i_eout_filt].get())}; + const EnergyoutFilter& eo_filt { + *dynamic_cast(model::tally_filters[i_eout_filt].get())}; // Note that the score below is weighted by keff. Since the creation of // fission sites is weighted such that it is expected to create n_particles @@ -392,16 +385,15 @@ score_fission_eout(Particle& p, int i_tally, int i_score, int score_bin) if (E_out < eo_filt.bins().front() || E_out > eo_filt.bins().back()) { continue; } else { - auto i_match = lower_bound_index(eo_filt.bins().begin(), - eo_filt.bins().end(), E_out); + auto i_match = lower_bound_index( + eo_filt.bins().begin(), eo_filt.bins().end(), E_out); p.filter_matches(i_eout_filt).bins_[i_bin] = i_match; } - } // Case for tallying prompt neutrons - if (score_bin == SCORE_NU_FISSION - || (score_bin == SCORE_PROMPT_NU_FISSION && g == 0)) { + if (score_bin == SCORE_NU_FISSION || + (score_bin == SCORE_PROMPT_NU_FISSION && g == 0)) { // Find the filter scoring index for this filter combination int filter_index = 0; @@ -414,9 +406,10 @@ score_fission_eout(Particle& p, int i_tally, int i_score, int score_bin) filter_weight *= match.weights_[i_bin]; } - // Update tally results - #pragma omp atomic - tally.results_(filter_index, i_score, TallyResult::VALUE) += score*filter_weight; +// Update tally results +#pragma omp atomic + tally.results_(filter_index, i_score, TallyResult::VALUE) += + score * filter_weight; } else if (score_bin == SCORE_DELAYED_NU_FISSION && g != 0) { @@ -447,7 +440,7 @@ score_fission_eout(Particle& p, int i_tally, int i_score, int score_bin) } } - // If the delayed group filter is not present, add score to tally + // If the delayed group filter is not present, add score to tally } else { // Find the filter index and weight for this filter combination @@ -461,9 +454,10 @@ score_fission_eout(Particle& p, int i_tally, int i_score, int score_bin) filter_weight *= match.weights_[i_bin]; } - // Update tally results - #pragma omp atomic - tally.results_(filter_index, i_score, TallyResult::VALUE) += score*filter_weight; +// Update tally results +#pragma omp atomic + tally.results_(filter_index, i_score, TallyResult::VALUE) += + score * filter_weight; } } } @@ -472,13 +466,15 @@ score_fission_eout(Particle& p, int i_tally, int i_score, int score_bin) p.filter_matches(i_eout_filt).bins_[i_bin] = bin_energyout; } -double get_nuclide_xs(const Particle& p, int i_nuclide, int score_bin) { +double get_nuclide_xs(const Particle& p, int i_nuclide, int score_bin) +{ const auto& nuc {*data::nuclides[i_nuclide]}; // Get reaction object, or return 0 if reaction is not present auto m = nuc.reaction_index_[score_bin]; - if (m == C_NONE) return 0.0; - const auto& rxn {*nuc.reactions_[m]}; + if (m == C_NONE) + return 0.0; + const auto& rx {*nuc.reactions_[m]}; const auto& micro {p.neutron_xs(i_nuclide)}; // In the URR, the (n,gamma) cross section is sampled randomly from @@ -495,16 +491,10 @@ double get_nuclide_xs(const Particle& p, int i_nuclide, int score_bin) { auto f = micro.interp_factor; // Calculate interpolated cross section - const auto& xs {rxn.xs_[i_temp]}; - double value; - if (i_grid >= xs.threshold) { - value = ((1.0 - f) * xs.value[i_grid-xs.threshold] - + f * xs.value[i_grid-xs.threshold+1]); - } else { - value = 0.0; - } + double xs = rx.xs(micro); - if (settings::run_mode == RunMode::EIGENVALUE && score_bin == HEATING_LOCAL) { + if (settings::run_mode == RunMode::EIGENVALUE && + score_bin == HEATING_LOCAL) { // Determine kerma for fission as (EFR + EGP + EGD + EB)*sigma_f double kerma_fission = nuc.fragments_ @@ -515,31 +505,28 @@ double get_nuclide_xs(const Particle& p, int i_nuclide, int score_bin) { : 0.0; // Determine non-fission kerma as difference - double kerma_non_fission = value - kerma_fission; + double kerma_non_fission = xs - kerma_fission; // Re-weight non-fission kerma by keff to properly balance energy release - // and deposition. See D. P. Griesheimer, S. J. Douglass, and M. H. Stedry, - // "Self-consistent energy normalization for quasistatic reactor + // and deposition. See D. P. Griesheimer, S. J. Douglass, and M. H. + // Stedry, "Self-consistent energy normalization for quasistatic reactor // calculations", Proc. PHYSOR, Cambridge, UK, Mar 29-Apr 2, 2020. - value = simulation::keff * kerma_non_fission + kerma_fission; + xs = simulation::keff * kerma_non_fission + kerma_fission; } - return value; + return xs; } else { // For multipole, calculate (n,gamma) from other reactions - return rxn.mt_ == N_GAMMA ? micro.absorption - micro.fission : 0.0; + return rx.mt_ == N_GAMMA ? micro.absorption - micro.fission : 0.0; } return 0.0; } -//! Update tally results for continuous-energy tallies with any estimator. -// -//! For analog tallies, the flux estimate depends on the score type so the flux -//! argument is really just used for filter weights. The atom_density argument -//! is not used for analog tallies. +//! Update tally results for continuous-energy tallies with a tracklength or +//! collision estimator. -void -score_general_ce(Particle& p, int i_tally, int start_index, int filter_index, - double filter_weight, int i_nuclide, double atom_density, double flux) +void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, + int filter_index, double filter_weight, int i_nuclide, double atom_density, + double flux) { Tally& tally {*model::tallies[i_tally]}; @@ -555,299 +542,172 @@ score_general_ce(Particle& p, int i_tally, int start_index, int filter_index, switch (score_bin) { case SCORE_FLUX: - if (tally.estimator_ == TallyEstimator::ANALOG) { - // All events score to a flux bin. We actually use a collision estimator - // in place of an analog one since there is no way to count 'events' - // exactly for the flux - if (settings::survival_biasing) { - // We need to account for the fact that some weight was already - // absorbed - score = p.wgt_last() + p.wgt_absorb(); - } else { - score = p.wgt_last(); - } - - if (p.type() == Type::neutron || p.type() == Type::photon) { - score *= flux / p.macro_xs().total; - } else { - score = 0.; - } - } else { - score = flux; - } + score = flux; break; - case SCORE_TOTAL: - if (tally.estimator_ == TallyEstimator::ANALOG) { - // All events will score to the total reaction rate. We can just use - // use the weight of the particle entering the collision as the score - if (settings::survival_biasing) { - // We need to account for the fact that some weight was already - // absorbed - score = (p.wgt_last() + p.wgt_absorb()) * flux; - } else { - score = p.wgt_last() * flux; + if (i_nuclide >= 0) { + if (p.type() == Type::neutron) { + score = p.neutron_xs(i_nuclide).total * atom_density * flux; + } else if (p.type() == Type::photon) { + score = p.photon_xs(i_nuclide).total * atom_density * flux; } - } else { - if (i_nuclide >= 0) { - if (p.type() == Type::neutron) { - score = p.neutron_xs(i_nuclide).total * atom_density * flux; - } else if (p.type() == Type::photon) { - score = p.photon_xs(i_nuclide).total * atom_density * flux; - } - } else { - score = p.macro_xs().total * flux; - } + score = p.macro_xs().total * flux; } break; - case SCORE_INVERSE_VELOCITY: if (p.type() != Type::neutron) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - // All events score to an inverse velocity bin. We actually use a - // collision estimator in place of an analog one since there is no way - // to count 'events' exactly for the inverse velocity - if (settings::survival_biasing) { - // We need to account for the fact that some weight was already - // absorbed - score = p.wgt_last() + p.wgt_absorb(); - } else { - score = p.wgt_last(); - } - score *= flux / p.macro_xs().total; - } else { - score = flux; - } // Score inverse velocity in units of s/cm. - score /= std::sqrt(2. * E / MASS_NEUTRON_EV) * C_LIGHT * 100.; + score = flux / p.speed(); break; - case SCORE_SCATTER: if (p.type() != Type::neutron && p.type() != Type::photon) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - // Skip any event where the particle didn't scatter - if (p.event() != TallyEvent::SCATTER) - continue; - // Since only scattering events make it here, again we can use the - // weight entering the collision as the estimator for the reaction rate - score = p.wgt_last() * flux; - } else { - if (i_nuclide >= 0) { - if (p.type() == Type::neutron) { - const auto& micro = p.neutron_xs(i_nuclide); - score = (micro.total - micro.absorption) * atom_density * flux; - } else { - const auto& micro = p.photon_xs(i_nuclide); - score = (micro.coherent + micro.incoherent) * atom_density * flux; - } + if (i_nuclide >= 0) { + if (p.type() == Type::neutron) { + const auto& micro = p.neutron_xs(i_nuclide); + score = (micro.total - micro.absorption) * atom_density * flux; } else { - if (p.type() == Type::neutron) { - score = (p.macro_xs().total - p.macro_xs().absorption) * flux; - } else { - score = (p.macro_xs().coherent + p.macro_xs().incoherent) * flux; - } + const auto& micro = p.photon_xs(i_nuclide); + score = (micro.coherent + micro.incoherent) * atom_density * flux; } - } - break; - - - case SCORE_NU_SCATTER: - if (p.type() != Type::neutron) - continue; - - // Only analog estimators are available. - // Skip any event where the particle didn't scatter - if (p.event() != TallyEvent::SCATTER) - continue; - // For scattering production, we need to use the pre-collision weight - // times the yield as the estimate for the number of neutrons exiting a - // reaction with neutrons in the exit channel - if (p.event_mt() == ELASTIC || p.event_mt() == N_LEVEL || - (p.event_mt() >= N_N1 && p.event_mt() <= N_NC)) { - // Don't waste time on very common reactions we know have - // multiplicities of one. - score = p.wgt_last() * flux; } else { - // Get yield and apply to score - auto m = - data::nuclides[p.event_nuclide()]->reaction_index_[p.event_mt()]; - const auto& rxn {*data::nuclides[p.event_nuclide()]->reactions_[m]}; - score = p.wgt_last() * flux * (*rxn.products_[0].yield_)(E); + if (p.type() == Type::neutron) { + score = (p.macro_xs().total - p.macro_xs().absorption) * flux; + } else { + score = (p.macro_xs().coherent + p.macro_xs().incoherent) * flux; + } } break; - case SCORE_ABSORPTION: if (p.type() != Type::neutron && p.type() != Type::photon) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - if (settings::survival_biasing) { - // No absorption events actually occur if survival biasing is on -- - // just use weight absorbed in survival biasing - score = p.wgt_absorb() * flux; + if (i_nuclide >= 0) { + if (p.type() == Type::neutron) { + score = p.neutron_xs(i_nuclide).absorption * atom_density * flux; } else { - // Skip any event where the particle wasn't absorbed - if (p.event() == TallyEvent::SCATTER) - continue; - // All fission and absorption events will contribute here, so we - // can just use the particle's weight entering the collision - score = p.wgt_last() * flux; + const auto& xs = p.photon_xs(i_nuclide); + score = + (xs.total - xs.coherent - xs.incoherent) * atom_density * flux; } } else { - if (i_nuclide >= 0) { - if (p.type() == Type::neutron) { - score = p.neutron_xs(i_nuclide).absorption * atom_density * flux; - } else { - const auto& xs = p.photon_xs(i_nuclide); - score = (xs.total - xs.coherent - xs.incoherent) * atom_density * flux; - } + if (p.type() == Type::neutron) { + score = p.macro_xs().absorption * flux; } else { - if (p.type() == Type::neutron) { - score = p.macro_xs().absorption * flux; - } else { - score = - (p.macro_xs().photoelectric + p.macro_xs().pair_production) * - flux; - } + score = + (p.macro_xs().photoelectric + p.macro_xs().pair_production) * flux; } } break; - case SCORE_FISSION: - if (p.macro_xs().absorption == 0) + if (p.macro_xs().fission == 0) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - if (settings::survival_biasing) { - // No fission events occur if survival biasing is on -- need to - // calculate fraction of absorptions that would have resulted in - // fission - if (p.neutron_xs(p.event_nuclide()).absorption > 0) { - score = p.wgt_absorb() * p.neutron_xs(p.event_nuclide()).fission / - p.neutron_xs(p.event_nuclide()).absorption * flux; - } else { - score = 0.; - } - } else { - // Skip any non-absorption events - if (p.event() == TallyEvent::SCATTER) - continue; - // All fission events will contribute, so again we can use particle's - // weight entering the collision as the estimate for the fission - // reaction rate - score = p.wgt_last() * p.neutron_xs(p.event_nuclide()).fission / - p.neutron_xs(p.event_nuclide()).absorption * flux; - } + + if (i_nuclide >= 0) { + score = p.neutron_xs(i_nuclide).fission * atom_density * flux; } else { - if (i_nuclide >= 0) { - score = p.neutron_xs(i_nuclide).fission * atom_density * flux; - } else { - score = p.macro_xs().fission * flux; - } + score = p.macro_xs().fission * flux; } break; - case SCORE_NU_FISSION: - if (p.macro_xs().absorption == 0) + if (p.macro_xs().fission == 0) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - if (settings::survival_biasing || p.fission()) { - if (tally.energyout_filter_ != C_NONE) { - // Fission has multiple outgoing neutrons so this helper function - // is used to handle scoring the multiple filter bins. - score_fission_eout(p, i_tally, score_index, score_bin); - continue; - } - } - if (settings::survival_biasing) { - // No fission events occur if survival biasing is on -- need to - // calculate fraction of absorptions that would have resulted in - // nu-fission - if (p.neutron_xs(p.event_nuclide()).absorption > 0) { - score = p.wgt_absorb() * - p.neutron_xs(p.event_nuclide()).nu_fission / - p.neutron_xs(p.event_nuclide()).absorption * flux; - } else { - score = 0.; - } - } else { - // Skip any non-fission events - if (!p.fission()) - continue; - // If there is no outgoing energy filter, than we only need to score - // to one bin. For the score to be 'analog', we need to score the - // number of particles that were banked in the fission bank. Since - // this was weighted by 1/keff, we multiply by keff to get the proper - // score. - score = simulation::keff * p.wgt_bank() * flux; - } + + if (i_nuclide >= 0) { + score = p.neutron_xs(i_nuclide).nu_fission * atom_density * flux; } else { - if (i_nuclide >= 0) { - score = p.neutron_xs(i_nuclide).nu_fission * atom_density * flux; - } else { - score = p.macro_xs().nu_fission * flux; - } + score = p.macro_xs().nu_fission * flux; } break; - case SCORE_PROMPT_NU_FISSION: - if (p.macro_xs().absorption == 0) + if (p.macro_xs().fission == 0) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - if (settings::survival_biasing || p.fission()) { - if (tally.energyout_filter_ != C_NONE) { - // Fission has multiple outgoing neutrons so this helper function - // is used to handle scoring the multiple filter bins. - score_fission_eout(p, i_tally, score_index, score_bin); - continue; + if (i_nuclide >= 0) { + score = p.neutron_xs(i_nuclide).fission * + data::nuclides[i_nuclide]->nu( + E, ReactionProduct::EmissionMode::prompt) * + atom_density * flux; + } else { + score = 0.; + // Add up contributions from each nuclide in the material. + if (p.material() != MATERIAL_VOID) { + const Material& material {*model::materials[p.material()]}; + for (auto i = 0; i < material.nuclide_.size(); ++i) { + auto j_nuclide = material.nuclide_[i]; + auto atom_density = material.atom_density_(i); + score += p.neutron_xs(j_nuclide).fission * + data::nuclides[j_nuclide]->nu( + E, ReactionProduct::EmissionMode::prompt) * + atom_density * flux; } } - if (settings::survival_biasing) { - // No fission events occur if survival biasing is on -- need to - // calculate fraction of absorptions that would have resulted in - // prompt-nu-fission - if (p.neutron_xs(p.event_nuclide()).absorption > 0) { - score = p.wgt_absorb() * p.neutron_xs(p.event_nuclide()).fission * - data::nuclides[p.event_nuclide()]->nu( - E, ReactionProduct::EmissionMode::prompt) / - p.neutron_xs(p.event_nuclide()).absorption * flux; - } else { - score = 0.; + } + break; + + case SCORE_DELAYED_NU_FISSION: + if (p.macro_xs().fission == 0) + continue; + if (i_nuclide >= 0) { + if (tally.delayedgroup_filter_ != C_NONE) { + auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; + const DelayedGroupFilter& filt {*dynamic_cast( + model::tally_filters[i_dg_filt].get())}; + // Tally each delayed group bin individually + for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { + auto d = filt.groups()[d_bin]; + auto yield = data::nuclides[i_nuclide]->nu( + E, ReactionProduct::EmissionMode::delayed, d); + score = + p.neutron_xs(i_nuclide).fission * yield * atom_density * flux; + score_fission_delayed_dg( + i_tally, d_bin, score, score_index, p.filter_matches()); } + continue; } else { - // Skip any non-fission events - if (!p.fission()) - continue; - // If there is no outgoing energy filter, than we only need to score - // to one bin. For the score to be 'analog', we need to score the - // number of particles that were banked in the fission bank. Since - // this was weighted by 1/keff, we multiply by keff to get the proper - // score. - auto n_delayed = std::accumulate( - p.n_delayed_bank(), p.n_delayed_bank() + MAX_DELAYED_GROUPS, 0); - auto prompt_frac = 1. - n_delayed / static_cast(p.n_bank()); - score = simulation::keff * p.wgt_bank() * prompt_frac * flux; - } - } else { - if (i_nuclide >= 0) { + // If the delayed group filter is not present, compute the score + // by multiplying the delayed-nu-fission macro xs by the flux score = p.neutron_xs(i_nuclide).fission * data::nuclides[i_nuclide]->nu( - E, ReactionProduct::EmissionMode::prompt) * + E, ReactionProduct::EmissionMode::delayed) * atom_density * flux; + } + } else { + // Need to add up contributions for each nuclide + if (tally.delayedgroup_filter_ != C_NONE) { + auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; + const DelayedGroupFilter& filt {*dynamic_cast( + model::tally_filters[i_dg_filt].get())}; + if (p.material() != MATERIAL_VOID) { + const Material& material {*model::materials[p.material()]}; + for (auto i = 0; i < material.nuclide_.size(); ++i) { + auto j_nuclide = material.nuclide_[i]; + auto atom_density = material.atom_density_(i); + // Tally each delayed group bin individually + for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { + auto d = filt.groups()[d_bin]; + auto yield = data::nuclides[j_nuclide]->nu( + E, ReactionProduct::EmissionMode::delayed, d); + score = + p.neutron_xs(j_nuclide).fission * yield * atom_density * flux; + score_fission_delayed_dg( + i_tally, d_bin, score, score_index, p.filter_matches()); + } + } + } + continue; } else { score = 0.; - // Add up contributions from each nuclide in the material. if (p.material() != MATERIAL_VOID) { const Material& material {*model::materials[p.material()]}; for (auto i = 0; i < material.nuclide_.size(); ++i) { @@ -855,7 +715,7 @@ score_general_ce(Particle& p, int i_tally, int start_index, int filter_index, auto atom_density = material.atom_density_(i); score += p.neutron_xs(j_nuclide).fission * data::nuclides[j_nuclide]->nu( - E, ReactionProduct::EmissionMode::prompt) * + E, ReactionProduct::EmissionMode::delayed) * atom_density * flux; } } @@ -863,147 +723,101 @@ score_general_ce(Particle& p, int i_tally, int start_index, int filter_index, } break; - - case SCORE_DELAYED_NU_FISSION: - if (p.macro_xs().absorption == 0) + case SCORE_DECAY_RATE: + if (p.macro_xs().fission == 0) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - if (settings::survival_biasing || p.fission()) { - if (tally.energyout_filter_ != C_NONE) { - // Fission has multiple outgoing neutrons so this helper function - // is used to handle scoring the multiple filter bins. - score_fission_eout(p, i_tally, score_index, score_bin); - continue; - } - } - if (settings::survival_biasing) { - // No fission events occur if survival biasing is on -- need to - // calculate fraction of absorptions that would have resulted in - // delayed-nu-fission - if (p.neutron_xs(p.event_nuclide()).absorption > 0 && - data::nuclides[p.event_nuclide()]->fissionable_) { - if (tally.delayedgroup_filter_ != C_NONE) { - auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( - model::tally_filters[i_dg_filt].get())}; - // Tally each delayed group bin individually - for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto dg = filt.groups()[d_bin]; - auto yield = data::nuclides[p.event_nuclide()]->nu( - E, ReactionProduct::EmissionMode::delayed, dg); - score = p.wgt_absorb() * yield * - p.neutron_xs(p.event_nuclide()).fission / - p.neutron_xs(p.event_nuclide()).absorption * flux; - score_fission_delayed_dg( - i_tally, d_bin, score, score_index, p.filter_matches()); - } - continue; - } else { - // If the delayed group filter is not present, compute the score - // by multiplying the absorbed weight by the fraction of the - // delayed-nu-fission xs to the absorption xs - score = p.wgt_absorb() * p.neutron_xs(p.event_nuclide()).fission * - data::nuclides[p.event_nuclide()]->nu( - E, ReactionProduct::EmissionMode::delayed) / - p.neutron_xs(p.event_nuclide()).absorption * flux; - } + if (i_nuclide >= 0) { + const auto& nuc {*data::nuclides[i_nuclide]}; + if (!nuc.fissionable_) + continue; + const auto& rxn {*nuc.fission_rx_[0]}; + if (tally.delayedgroup_filter_ != C_NONE) { + auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; + const DelayedGroupFilter& filt {*dynamic_cast( + model::tally_filters[i_dg_filt].get())}; + // Tally each delayed group bin individually + for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { + auto d = filt.groups()[d_bin]; + auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); + auto rate = rxn.products_[d].decay_rate_; + score = p.neutron_xs(i_nuclide).fission * yield * flux * + atom_density * rate; + score_fission_delayed_dg( + i_tally, d_bin, score, score_index, p.filter_matches()); } + continue; } else { - // Skip any non-fission events - if (!p.fission()) - continue; - // If there is no outgoing energy filter, than we only need to score - // to one bin. For the score to be 'analog', we need to score the - // number of particles that were banked in the fission bank. Since - // this was weighted by 1/keff, we multiply by keff to get the proper - // score. Loop over the neutrons produced from fission and check which - // ones are delayed. If a delayed neutron is encountered, add its - // contribution to the fission bank to the score. - if (tally.delayedgroup_filter_ != C_NONE) { - auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( - model::tally_filters[i_dg_filt].get())}; - // Tally each delayed group bin individually - for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; - score = simulation::keff * p.wgt_bank() / p.n_bank() * - p.n_delayed_bank(d - 1) * flux; - score_fission_delayed_dg( - i_tally, d_bin, score, score_index, p.filter_matches()); - } - continue; - } else { - // Add the contribution from all delayed groups - auto n_delayed = std::accumulate( - p.n_delayed_bank(), p.n_delayed_bank() + MAX_DELAYED_GROUPS, 0); - score = - simulation::keff * p.wgt_bank() / p.n_bank() * n_delayed * flux; + score = 0.; + // We need to be careful not to overshoot the number of + // delayed groups since this could cause the range of the + // rxn.products_ array to be exceeded. Hence, we use the size + // of this array and not the MAX_DELAYED_GROUPS constant for + // this loop. + for (auto d = 1; d < rxn.products_.size(); ++d) { + const auto& product = rxn.products_[d]; + if (product.particle_ != Type::neutron) + continue; + + auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); + auto rate = product.decay_rate_; + score += p.neutron_xs(i_nuclide).fission * flux * yield * + atom_density * rate; } } } else { - if (i_nuclide >= 0) { - if (tally.delayedgroup_filter_ != C_NONE) { - auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( - model::tally_filters[i_dg_filt].get())}; - // Tally each delayed group bin individually - for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; - auto yield = data::nuclides[i_nuclide] - ->nu(E, ReactionProduct::EmissionMode::delayed, d); - score = - p.neutron_xs(i_nuclide).fission * yield * atom_density * flux; - score_fission_delayed_dg( - i_tally, d_bin, score, score_index, p.filter_matches()); - } - continue; - } else { - // If the delayed group filter is not present, compute the score - // by multiplying the delayed-nu-fission macro xs by the flux - score = p.neutron_xs(i_nuclide).fission * - data::nuclides[i_nuclide]->nu( - E, ReactionProduct::EmissionMode::delayed) * - atom_density * flux; - } - } else { - // Need to add up contributions for each nuclide - if (tally.delayedgroup_filter_ != C_NONE) { - auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( - model::tally_filters[i_dg_filt].get())}; - if (p.material() != MATERIAL_VOID) { - const Material& material {*model::materials[p.material()]}; - for (auto i = 0; i < material.nuclide_.size(); ++i) { - auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density_(i); + if (tally.delayedgroup_filter_ != C_NONE) { + auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; + const DelayedGroupFilter& filt {*dynamic_cast( + model::tally_filters[i_dg_filt].get())}; + if (p.material() != MATERIAL_VOID) { + const Material& material {*model::materials[p.material()]}; + for (auto i = 0; i < material.nuclide_.size(); ++i) { + auto j_nuclide = material.nuclide_[i]; + auto atom_density = material.atom_density_(i); + const auto& nuc {*data::nuclides[j_nuclide]}; + if (nuc.fissionable_) { + const auto& rxn {*nuc.fission_rx_[0]}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { auto d = filt.groups()[d_bin]; - auto yield = data::nuclides[j_nuclide] - ->nu(E, ReactionProduct::EmissionMode::delayed, d); - score = p.neutron_xs(j_nuclide).fission * yield * - atom_density * flux; + auto yield = + nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); + auto rate = rxn.products_[d].decay_rate_; + score = p.neutron_xs(j_nuclide).fission * yield * flux * + atom_density * rate; score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); } } } - continue; - } else { - score = 0.; - if (p.material() != MATERIAL_VOID) { - const Material& material {*model::materials[p.material()]}; - for (auto i = 0; i < material.nuclide_.size(); ++i) { - auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density_(i); - score += p.neutron_xs(j_nuclide).fission * - data::nuclides[j_nuclide]->nu( - E, ReactionProduct::EmissionMode::delayed) * - atom_density * flux; + } + continue; + } else { + score = 0.; + if (p.material() != MATERIAL_VOID) { + const Material& material {*model::materials[p.material()]}; + for (auto i = 0; i < material.nuclide_.size(); ++i) { + auto j_nuclide = material.nuclide_[i]; + auto atom_density = material.atom_density_(i); + const auto& nuc {*data::nuclides[j_nuclide]}; + if (nuc.fissionable_) { + const auto& rxn {*nuc.fission_rx_[0]}; + // We need to be careful not to overshoot the number of + // delayed groups since this could cause the range of the + // rxn.products_ array to be exceeded. Hence, we use the size + // of this array and not the MAX_DELAYED_GROUPS constant for + // this loop. + for (auto d = 1; d < rxn.products_.size(); ++d) { + const auto& product = rxn.products_[d]; + if (product.particle_ != Type::neutron) + continue; + + auto yield = + nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); + auto rate = product.decay_rate_; + score += p.neutron_xs(j_nuclide).fission * yield * + atom_density * flux * rate; + } } } } @@ -1011,298 +825,631 @@ score_general_ce(Particle& p, int i_tally, int start_index, int filter_index, } break; - - case SCORE_DECAY_RATE: - if (p.macro_xs().absorption == 0) + case SCORE_KAPPA_FISSION: + if (p.macro_xs().fission == 0.) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - if (settings::survival_biasing) { - // No fission events occur if survival biasing is on -- need to - // calculate fraction of absorptions that would have resulted in - // delayed-nu-fission - const auto& nuc {*data::nuclides[p.event_nuclide()]}; - if (p.neutron_xs(p.event_nuclide()).absorption > 0 && - nuc.fissionable_) { + score = 0.; + // Kappa-fission values are determined from the Q-value listed for the + // fission cross section. + if (i_nuclide >= 0) { + const auto& nuc {*data::nuclides[i_nuclide]}; + if (nuc.fissionable_) { + const auto& rxn {*nuc.fission_rx_[0]}; + score = rxn.q_value_ * p.neutron_xs(i_nuclide).fission * + atom_density * flux; + } + } else if (p.material() != MATERIAL_VOID) { + const Material& material {*model::materials[p.material()]}; + for (auto i = 0; i < material.nuclide_.size(); ++i) { + auto j_nuclide = material.nuclide_[i]; + auto atom_density = material.atom_density_(i); + const auto& nuc {*data::nuclides[j_nuclide]}; + if (nuc.fissionable_) { const auto& rxn {*nuc.fission_rx_[0]}; - if (tally.delayedgroup_filter_ != C_NONE) { - auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( - model::tally_filters[i_dg_filt].get())}; - // Tally each delayed group bin individually - for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; - auto yield - = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); - auto rate = rxn.products_[d].decay_rate_; - score = p.wgt_absorb() * yield * - p.neutron_xs(p.event_nuclide()).fission / - p.neutron_xs(p.event_nuclide()).absorption * rate * - flux; - score_fission_delayed_dg( - i_tally, d_bin, score, score_index, p.filter_matches()); - } - continue; - } else { - // If the delayed group filter is not present, compute the score - // by multiplying the absorbed weight by the fraction of the - // delayed-nu-fission xs to the absorption xs for all delayed - // groups - score = 0.; - // We need to be careful not to overshoot the number of - // delayed groups since this could cause the range of the - // rxn.products_ array to be exceeded. Hence, we use the size - // of this array and not the MAX_DELAYED_GROUPS constant for - // this loop. - for (auto d = 0; d < rxn.products_.size() - 2; ++d) { - auto yield - = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d+1); - auto rate = rxn.products_[d+1].decay_rate_; - score += rate * p.wgt_absorb() * - p.neutron_xs(p.event_nuclide()).fission * yield / - p.neutron_xs(p.event_nuclide()).absorption * flux; - } - } + score += rxn.q_value_ * p.neutron_xs(j_nuclide).fission * + atom_density * flux; + } + } + } + break; + + case SCORE_EVENTS: +// Simply count the number of scoring events +#pragma omp atomic + tally.results_(filter_index, score_index, TallyResult::VALUE) += 1.0; + continue; + + case ELASTIC: + if (p.type() != Type::neutron) + continue; + + if (i_nuclide >= 0) { + if (p.neutron_xs(i_nuclide).elastic == CACHE_INVALID) + data::nuclides[i_nuclide]->calculate_elastic_xs(p); + score = p.neutron_xs(i_nuclide).elastic * atom_density * flux; + } else { + score = 0.; + if (p.material() != MATERIAL_VOID) { + const Material& material {*model::materials[p.material()]}; + for (auto i = 0; i < material.nuclide_.size(); ++i) { + auto j_nuclide = material.nuclide_[i]; + auto atom_density = material.atom_density_(i); + if (p.neutron_xs(j_nuclide).elastic == CACHE_INVALID) + data::nuclides[j_nuclide]->calculate_elastic_xs(p); + score += p.neutron_xs(j_nuclide).elastic * atom_density * flux; + } + } + } + break; + + case SCORE_FISS_Q_PROMPT: + case SCORE_FISS_Q_RECOV: + if (p.macro_xs().fission == 0.) + continue; + score = + score_fission_q(p, score_bin, tally, flux, i_nuclide, atom_density); + break; + + case N_2N: + case N_3N: + case N_4N: + case N_GAMMA: + case N_P: + case N_A: + // This case block only works if cross sections for these reactions have + // been precalculated. When they are not, we revert to the default case, + // which looks up cross sections + if (!simulation::need_depletion_rx) + goto default_case; + + if (p.type() != Type::neutron) + continue; + + int m; + switch (score_bin) { + // clang-format off + case N_GAMMA: m = 0; break; + case N_P: m = 1; break; + case N_A: m = 2; break; + case N_2N: m = 3; break; + case N_3N: m = 4; break; + case N_4N: m = 5; break; + // clang-format on + } + if (i_nuclide >= 0) { + score = p.neutron_xs(i_nuclide).reaction[m] * atom_density * flux; + } else { + score = 0.; + if (p.material() != MATERIAL_VOID) { + const Material& material {*model::materials[p.material()]}; + for (auto i = 0; i < material.nuclide_.size(); ++i) { + auto j_nuclide = material.nuclide_[i]; + auto atom_density = material.atom_density_(i); + score += p.neutron_xs(j_nuclide).reaction[m] * atom_density * flux; } + } + } + break; + + case COHERENT: + case INCOHERENT: + case PHOTOELECTRIC: + case PAIR_PROD: + if (p.type() != Type::photon) + continue; + + if (i_nuclide >= 0) { + const auto& micro = p.photon_xs(i_nuclide); + double xs = (score_bin == COHERENT) ? micro.coherent + : (score_bin == INCOHERENT) ? micro.incoherent + : (score_bin == PHOTOELECTRIC) ? micro.photoelectric + : micro.pair_production; + score = xs * atom_density * flux; + } else { + double xs = (score_bin == COHERENT) ? p.macro_xs().coherent + : (score_bin == INCOHERENT) ? p.macro_xs().incoherent + : (score_bin == PHOTOELECTRIC) + ? p.macro_xs().photoelectric + : p.macro_xs().pair_production; + score = xs * flux; + } + break; + + case HEATING: + if (p.type() == Type::neutron) { + score = score_neutron_heating( + p, tally, flux, HEATING, i_nuclide, atom_density); + } else { + if (i_nuclide == -1 || i_nuclide == p.event_nuclide()) { + // The energy deposited is the difference between the pre-collision + // and post-collision energy... + score = E - p.E(); + + // ...less the energy of any secondary particles since they will be + // transported individually later + const auto& bank = p.secondary_bank(); + for (auto it = bank.end() - p.n_bank_second(); it < bank.end(); + ++it) { + score -= it->E; + } + + score *= p.wgt_last(); + } else { + score = 0.0; + } + } + break; + + default: + default_case: + + // The default block is really only meant for redundant neutron reactions + // (e.g. 444, 901) + if (p.type() != Type::neutron) + continue; + + // Any other cross section has to be calculated on-the-fly + if (score_bin < 2) + fatal_error("Invalid score type on tally " + std::to_string(tally.id_)); + score = 0.; + if (i_nuclide >= 0) { + score = get_nuclide_xs(p, i_nuclide, score_bin) * atom_density * flux; + } else if (p.material() != MATERIAL_VOID) { + const Material& material {*model::materials[p.material()]}; + for (auto i = 0; i < material.nuclide_.size(); ++i) { + auto j_nuclide = material.nuclide_[i]; + auto atom_density = material.atom_density_(i); + score += + get_nuclide_xs(p, j_nuclide, score_bin) * atom_density * flux; + } + } + } + + // Add derivative information on score for differential tallies. + if (tally.deriv_ != C_NONE) + apply_derivative_to_score( + p, i_tally, i_nuclide, atom_density, score_bin, score); + +// Update tally results +#pragma omp atomic + tally.results_(filter_index, score_index, TallyResult::VALUE) += + score * filter_weight; + } +} + +//! Update tally results for continuous-energy tallies with an analog estimator. +// +//! For analog tallies, the flux estimate depends on the score type so the flux +//! argument is really just used for filter weights. The atom_density argument +//! is not used for analog tallies. + +void score_general_ce_analog(Particle& p, int i_tally, int start_index, + int filter_index, double filter_weight, int i_nuclide, double atom_density, + double flux) +{ + Tally& tally {*model::tallies[i_tally]}; + + // Get the pre-collision energy of the particle. + auto E = p.E_last(); + + // Determine how much weight was absorbed due to survival biasing + double wgt_absorb = settings::survival_biasing + ? p.wgt_last() * + p.neutron_xs(p.event_nuclide()).absorption / + p.neutron_xs(p.event_nuclide()).total + : 0.0; + + using Type = ParticleType; + + for (auto i = 0; i < tally.scores_.size(); ++i) { + auto score_bin = tally.scores_[i]; + auto score_index = start_index + i; + double score = 0.0; + + switch (score_bin) { + case SCORE_FLUX: + // All events score to a flux bin. We actually use a collision estimator + // in place of an analog one since there is no way to count 'events' + // exactly for the flux + if (p.type() == Type::neutron || p.type() == Type::photon) { + score = flux * p.wgt_last() / p.macro_xs().total; + } else { + score = 0.; + } + break; + + case SCORE_TOTAL: + // All events will score to the total reaction rate. We can just use + // use the weight of the particle entering the collision as the score + score = p.wgt_last() * flux; + break; + + case SCORE_INVERSE_VELOCITY: + if (p.type() != Type::neutron) + continue; + + // All events score to an inverse velocity bin. We actually use a + // collision estimator in place of an analog one since there is no way + // to count 'events' exactly for the inverse velocity + score = flux * p.wgt_last() / (p.macro_xs().total * p.speed()); + break; + + case SCORE_SCATTER: + if (p.type() != Type::neutron && p.type() != Type::photon) + continue; + + // Skip any event where the particle didn't scatter + if (p.event() != TallyEvent::SCATTER) + continue; + // Since only scattering events make it here, again we can use the + // weight entering the collision as the estimator for the reaction rate + score = (p.wgt_last() - wgt_absorb) * flux; + break; + + case SCORE_NU_SCATTER: + if (p.type() != Type::neutron) + continue; + + // Only analog estimators are available. + // Skip any event where the particle didn't scatter + if (p.event() != TallyEvent::SCATTER) + continue; + // For scattering production, we need to use the pre-collision weight + // times the yield as the estimate for the number of neutrons exiting a + // reaction with neutrons in the exit channel + score = (p.wgt_last() - wgt_absorb) * flux; + + // Don't waste time on very common reactions we know have multiplicities + // of one. + if (p.event_mt() != ELASTIC && p.event_mt() != N_LEVEL && + !(p.event_mt() >= N_N1 && p.event_mt() <= N_NC)) { + // Get yield and apply to score + auto m = + data::nuclides[p.event_nuclide()]->reaction_index_[p.event_mt()]; + const auto& rxn {*data::nuclides[p.event_nuclide()]->reactions_[m]}; + score *= (*rxn.products_[0].yield_)(E); + } + break; + + case SCORE_ABSORPTION: + if (p.type() != Type::neutron && p.type() != Type::photon) + continue; + + if (settings::survival_biasing) { + // No absorption events actually occur if survival biasing is on -- + // just use weight absorbed in survival biasing + score = wgt_absorb * flux; + } else { + // Skip any event where the particle wasn't absorbed + if (p.event() == TallyEvent::SCATTER) + continue; + // All fission and absorption events will contribute here, so we + // can just use the particle's weight entering the collision + score = p.wgt_last() * flux; + } + break; + + case SCORE_FISSION: + if (p.macro_xs().fission == 0) + continue; + if (settings::survival_biasing) { + // No fission events occur if survival biasing is on -- use collision + // estimator instead + if (p.neutron_xs(p.event_nuclide()).total > 0) { + score = p.wgt_last() * p.neutron_xs(p.event_nuclide()).fission / + p.neutron_xs(p.event_nuclide()).total * flux; } else { - // Skip any non-fission events - if (!p.fission()) - continue; - // If there is no outgoing energy filter, than we only need to score - // to one bin. For the score to be 'analog', we need to score the - // number of particles that were banked in the fission bank. Since - // this was weighted by 1/keff, we multiply by keff to get the proper - // score. Loop over the neutrons produced from fission and check which - // ones are delayed. If a delayed neutron is encountered, add its - // contribution to the fission bank to the score. score = 0.; - for (auto i = 0; i < p.n_bank(); ++i) { - const auto& bank = p.nu_bank(i); - auto g = bank.delayed_group; - if (g != 0) { - const auto& nuc {*data::nuclides[p.event_nuclide()]}; - const auto& rxn {*nuc.fission_rx_[0]}; - auto rate = rxn.products_[g].decay_rate_; - score += simulation::keff * bank.wgt * rate * flux; - if (tally.delayedgroup_filter_ != C_NONE) { - auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( - model::tally_filters[i_dg_filt].get())}; - // Find the corresponding filter bin and then score - for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; - if (d == g) - score_fission_delayed_dg( - i_tally, d_bin, score, score_index, p.filter_matches()); - } - score = 0.; - } - } - } } } else { - if (i_nuclide >= 0) { - const auto& nuc {*data::nuclides[i_nuclide]}; - if (!nuc.fissionable_) continue; - const auto& rxn {*nuc.fission_rx_[0]}; + // Skip any non-absorption events + if (p.event() == TallyEvent::SCATTER) + continue; + // All fission events will contribute, so again we can use particle's + // weight entering the collision as the estimate for the fission + // reaction rate + score = p.wgt_last() * p.neutron_xs(p.event_nuclide()).fission / + p.neutron_xs(p.event_nuclide()).absorption * flux; + } + break; + + case SCORE_NU_FISSION: + if (p.macro_xs().fission == 0) + continue; + if (settings::survival_biasing || p.fission()) { + if (tally.energyout_filter_ != C_NONE) { + // Fission has multiple outgoing neutrons so this helper function + // is used to handle scoring the multiple filter bins. + score_fission_eout(p, i_tally, score_index, score_bin); + continue; + } + } + if (settings::survival_biasing) { + // No fission events occur if survival biasing is on -- use collision + // estimator instead + if (p.neutron_xs(p.event_nuclide()).total > 0) { + score = p.wgt_last() * p.neutron_xs(p.event_nuclide()).nu_fission / + p.neutron_xs(p.event_nuclide()).total * flux; + } else { + score = 0.; + } + } else { + // Skip any non-fission events + if (!p.fission()) + continue; + // If there is no outgoing energy filter, than we only need to score + // to one bin. For the score to be 'analog', we need to score the + // number of particles that were banked in the fission bank. Since + // this was weighted by 1/keff, we multiply by keff to get the proper + // score. + score = simulation::keff * p.wgt_bank() * flux; + } + break; + + case SCORE_PROMPT_NU_FISSION: + if (p.macro_xs().fission == 0) + continue; + if (settings::survival_biasing || p.fission()) { + if (tally.energyout_filter_ != C_NONE) { + // Fission has multiple outgoing neutrons so this helper function + // is used to handle scoring the multiple filter bins. + score_fission_eout(p, i_tally, score_index, score_bin); + continue; + } + } + if (settings::survival_biasing) { + // No fission events occur if survival biasing is on -- need to + // calculate fraction of absorptions that would have resulted in + // prompt-nu-fission + if (p.neutron_xs(p.event_nuclide()).total > 0) { + score = p.wgt_last() * p.neutron_xs(p.event_nuclide()).fission * + data::nuclides[p.event_nuclide()]->nu( + E, ReactionProduct::EmissionMode::prompt) / + p.neutron_xs(p.event_nuclide()).total * flux; + } else { + score = 0.; + } + } else { + // Skip any non-fission events + if (!p.fission()) + continue; + // If there is no outgoing energy filter, than we only need to score + // to one bin. For the score to be 'analog', we need to score the + // number of particles that were banked in the fission bank. Since + // this was weighted by 1/keff, we multiply by keff to get the proper + // score. + auto n_delayed = std::accumulate( + p.n_delayed_bank(), p.n_delayed_bank() + MAX_DELAYED_GROUPS, 0); + auto prompt_frac = 1. - n_delayed / static_cast(p.n_bank()); + score = simulation::keff * p.wgt_bank() * prompt_frac * flux; + } + break; + + case SCORE_DELAYED_NU_FISSION: + if (p.macro_xs().fission == 0) + continue; + if (settings::survival_biasing || p.fission()) { + if (tally.energyout_filter_ != C_NONE) { + // Fission has multiple outgoing neutrons so this helper function + // is used to handle scoring the multiple filter bins. + score_fission_eout(p, i_tally, score_index, score_bin); + continue; + } + } + if (settings::survival_biasing) { + // No fission events occur if survival biasing is on -- need to + // calculate fraction of absorptions that would have resulted in + // delayed-nu-fission + if (p.neutron_xs(p.event_nuclide()).total > 0 && + data::nuclides[p.event_nuclide()]->fissionable_) { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( + const DelayedGroupFilter& filt {*dynamic_cast( model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; - auto yield - = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); - auto rate = rxn.products_[d].decay_rate_; - score = p.neutron_xs(i_nuclide).fission * yield * flux * - atom_density * rate; + auto dg = filt.groups()[d_bin]; + auto yield = data::nuclides[p.event_nuclide()]->nu( + E, ReactionProduct::EmissionMode::delayed, dg); + score = p.wgt_last() * yield * + p.neutron_xs(p.event_nuclide()).fission / + p.neutron_xs(p.event_nuclide()).total * flux; score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); } continue; } else { - score = 0.; - // We need to be careful not to overshoot the number of - // delayed groups since this could cause the range of the - // rxn.products_ array to be exceeded. Hence, we use the size - // of this array and not the MAX_DELAYED_GROUPS constant for - // this loop. - for (auto d = 0; d < rxn.products_.size() - 2; ++d) { - auto yield - = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d+1); - auto rate = rxn.products_[d+1].decay_rate_; - score += p.neutron_xs(i_nuclide).fission * flux * yield * - atom_density * rate; - } + // If the delayed group filter is not present, compute the score + // by multiplying the absorbed weight by the fraction of the + // delayed-nu-fission xs to the absorption xs + score = p.wgt_last() * p.neutron_xs(p.event_nuclide()).fission * + data::nuclides[p.event_nuclide()]->nu( + E, ReactionProduct::EmissionMode::delayed) / + p.neutron_xs(p.event_nuclide()).total * flux; } + } + } else { + // Skip any non-fission events + if (!p.fission()) + continue; + // If there is no outgoing energy filter, than we only need to score + // to one bin. For the score to be 'analog', we need to score the + // number of particles that were banked in the fission bank. Since + // this was weighted by 1/keff, we multiply by keff to get the proper + // score. Loop over the neutrons produced from fission and check which + // ones are delayed. If a delayed neutron is encountered, add its + // contribution to the fission bank to the score. + if (tally.delayedgroup_filter_ != C_NONE) { + auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; + const DelayedGroupFilter& filt {*dynamic_cast( + model::tally_filters[i_dg_filt].get())}; + // Tally each delayed group bin individually + for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { + auto d = filt.groups()[d_bin]; + score = simulation::keff * p.wgt_bank() / p.n_bank() * + p.n_delayed_bank(d - 1) * flux; + score_fission_delayed_dg( + i_tally, d_bin, score, score_index, p.filter_matches()); + } + continue; } else { + // Add the contribution from all delayed groups + auto n_delayed = std::accumulate( + p.n_delayed_bank(), p.n_delayed_bank() + MAX_DELAYED_GROUPS, 0); + score = + simulation::keff * p.wgt_bank() / p.n_bank() * n_delayed * flux; + } + } + break; + + case SCORE_DECAY_RATE: + if (p.macro_xs().fission == 0) + continue; + if (settings::survival_biasing) { + // No fission events occur if survival biasing is on -- need to + // calculate fraction of absorptions that would have resulted in + // delayed-nu-fission + const auto& nuc {*data::nuclides[p.event_nuclide()]}; + if (p.neutron_xs(p.event_nuclide()).total > 0 && nuc.fissionable_) { + const auto& rxn {*nuc.fission_rx_[0]}; if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( + const DelayedGroupFilter& filt {*dynamic_cast( model::tally_filters[i_dg_filt].get())}; - if (p.material() != MATERIAL_VOID) { - const Material& material {*model::materials[p.material()]}; - for (auto i = 0; i < material.nuclide_.size(); ++i) { - auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density_(i); - const auto& nuc {*data::nuclides[j_nuclide]}; - if (nuc.fissionable_) { - const auto& rxn {*nuc.fission_rx_[0]}; - // Tally each delayed group bin individually - for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; - auto yield - = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); - auto rate = rxn.products_[d].decay_rate_; - score = p.neutron_xs(j_nuclide).fission * yield * flux * - atom_density * rate; - score_fission_delayed_dg( - i_tally, d_bin, score, score_index, p.filter_matches()); - } - } - } + // Tally each delayed group bin individually + for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { + auto d = filt.groups()[d_bin]; + auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); + auto rate = rxn.products_[d].decay_rate_; + score = p.wgt_last() * yield * + p.neutron_xs(p.event_nuclide()).fission / + p.neutron_xs(p.event_nuclide()).total * rate * flux; + score_fission_delayed_dg( + i_tally, d_bin, score, score_index, p.filter_matches()); } continue; } else { + // If the delayed group filter is not present, compute the score + // by multiplying the absorbed weight by the fraction of the + // delayed-nu-fission xs to the absorption xs for all delayed + // groups score = 0.; - if (p.material() != MATERIAL_VOID) { - const Material& material {*model::materials[p.material()]}; - for (auto i = 0; i < material.nuclide_.size(); ++i) { - auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density_(i); - const auto& nuc {*data::nuclides[j_nuclide]}; - if (nuc.fissionable_) { - const auto& rxn {*nuc.fission_rx_[0]}; - // We need to be careful not to overshoot the number of - // delayed groups since this could cause the range of the - // rxn.products_ array to be exceeded. Hence, we use the size - // of this array and not the MAX_DELAYED_GROUPS constant for - // this loop. - for (auto d = 0; d < rxn.products_.size() - 2; ++d) { - auto yield - = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d+1); - auto rate = rxn.products_[d+1].decay_rate_; - score += p.neutron_xs(j_nuclide).fission * yield * - atom_density * flux * rate; - } - } + // We need to be careful not to overshoot the number of + // delayed groups since this could cause the range of the + // rxn.products_ array to be exceeded. Hence, we use the size + // of this array and not the MAX_DELAYED_GROUPS constant for + // this loop. + for (auto d = 1; d < rxn.products_.size(); ++d) { + const auto& product = rxn.products_[d]; + if (product.particle_ != Type::neutron) + continue; + + auto yield = nuc.nu(E, ReactionProduct::EmissionMode::delayed, d); + auto rate = product.decay_rate_; + score += rate * p.wgt_last() * + p.neutron_xs(p.event_nuclide()).fission * yield / + p.neutron_xs(p.event_nuclide()).total * flux; + } + } + } + } else { + // Skip any non-fission events + if (!p.fission()) + continue; + // If there is no outgoing energy filter, than we only need to score + // to one bin. For the score to be 'analog', we need to score the + // number of particles that were banked in the fission bank. Since + // this was weighted by 1/keff, we multiply by keff to get the proper + // score. Loop over the neutrons produced from fission and check which + // ones are delayed. If a delayed neutron is encountered, add its + // contribution to the fission bank to the score. + score = 0.; + for (auto i = 0; i < p.n_bank(); ++i) { + const auto& bank = p.nu_bank(i); + auto g = bank.delayed_group; + if (g != 0) { + const auto& nuc {*data::nuclides[p.event_nuclide()]}; + const auto& rxn {*nuc.fission_rx_[0]}; + auto rate = rxn.products_[g].decay_rate_; + score += simulation::keff * bank.wgt * rate * flux; + if (tally.delayedgroup_filter_ != C_NONE) { + auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; + const DelayedGroupFilter& filt { + *dynamic_cast( + model::tally_filters[i_dg_filt].get())}; + // Find the corresponding filter bin and then score + for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { + auto d = filt.groups()[d_bin]; + if (d == g) + score_fission_delayed_dg( + i_tally, d_bin, score, score_index, p.filter_matches()); } + score = 0.; } } } } break; - case SCORE_KAPPA_FISSION: - if (p.macro_xs().absorption == 0.) + if (p.macro_xs().fission == 0.) continue; score = 0.; // Kappa-fission values are determined from the Q-value listed for the // fission cross section. - if (tally.estimator_ == TallyEstimator::ANALOG) { - if (settings::survival_biasing) { - // No fission events occur if survival biasing is on -- need to - // calculate fraction of absorptions that would have resulted in - // fission scaled by the Q-value - const auto& nuc {*data::nuclides[p.event_nuclide()]}; - if (p.neutron_xs(p.event_nuclide()).absorption > 0 && - nuc.fissionable_) { - const auto& rxn {*nuc.fission_rx_[0]}; - score = p.wgt_absorb() * rxn.q_value_ * - p.neutron_xs(p.event_nuclide()).fission / - p.neutron_xs(p.event_nuclide()).absorption * flux; - } - } else { - // Skip any non-absorption events - if (p.event() == TallyEvent::SCATTER) - continue; - // All fission events will contribute, so again we can use particle's - // weight entering the collision as the estimate for the fission - // reaction rate - const auto& nuc {*data::nuclides[p.event_nuclide()]}; - if (p.neutron_xs(p.event_nuclide()).absorption > 0 && - nuc.fissionable_) { - const auto& rxn {*nuc.fission_rx_[0]}; - score = p.wgt_last() * rxn.q_value_ * - p.neutron_xs(p.event_nuclide()).fission / - p.neutron_xs(p.event_nuclide()).absorption * flux; - } + if (settings::survival_biasing) { + // No fission events occur if survival biasing is on -- need to + // calculate fraction of absorptions that would have resulted in + // fission scaled by the Q-value + const auto& nuc {*data::nuclides[p.event_nuclide()]}; + if (p.neutron_xs(p.event_nuclide()).total > 0 && nuc.fissionable_) { + const auto& rxn {*nuc.fission_rx_[0]}; + score = p.wgt_last() * rxn.q_value_ * + p.neutron_xs(p.event_nuclide()).fission / + p.neutron_xs(p.event_nuclide()).total * flux; } } else { - if (i_nuclide >= 0) { - const auto& nuc {*data::nuclides[i_nuclide]}; - if (nuc.fissionable_) { - const auto& rxn {*nuc.fission_rx_[0]}; - score = rxn.q_value_ * p.neutron_xs(i_nuclide).fission * - atom_density * flux; - } - } else if (p.material() != MATERIAL_VOID) { - const Material& material {*model::materials[p.material()]}; - for (auto i = 0; i < material.nuclide_.size(); ++i) { - auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density_(i); - const auto& nuc {*data::nuclides[j_nuclide]}; - if (nuc.fissionable_) { - const auto& rxn {*nuc.fission_rx_[0]}; - score += rxn.q_value_ * p.neutron_xs(j_nuclide).fission * - atom_density * flux; - } - } + // Skip any non-absorption events + if (p.event() == TallyEvent::SCATTER) + continue; + // All fission events will contribute, so again we can use particle's + // weight entering the collision as the estimate for the fission + // reaction rate + const auto& nuc {*data::nuclides[p.event_nuclide()]}; + if (p.neutron_xs(p.event_nuclide()).absorption > 0 && + nuc.fissionable_) { + const auto& rxn {*nuc.fission_rx_[0]}; + score = p.wgt_last() * rxn.q_value_ * + p.neutron_xs(p.event_nuclide()).fission / + p.neutron_xs(p.event_nuclide()).absorption * flux; } } break; - case SCORE_EVENTS: - // Simply count the number of scoring events - #pragma omp atomic +// Simply count the number of scoring events +#pragma omp atomic tally.results_(filter_index, score_index, TallyResult::VALUE) += 1.0; continue; - case ELASTIC: if (p.type() != Type::neutron) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - // Check if event MT matches - if (p.event_mt() != ELASTIC) - continue; - score = p.wgt_last() * flux; - } else { - if (i_nuclide >= 0) { - if (p.neutron_xs(i_nuclide).elastic == CACHE_INVALID) - data::nuclides[i_nuclide]->calculate_elastic_xs(p); - score = p.neutron_xs(i_nuclide).elastic * atom_density * flux; - } else { - score = 0.; - if (p.material() != MATERIAL_VOID) { - const Material& material {*model::materials[p.material()]}; - for (auto i = 0; i < material.nuclide_.size(); ++i) { - auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density_(i); - if (p.neutron_xs(j_nuclide).elastic == CACHE_INVALID) - data::nuclides[j_nuclide]->calculate_elastic_xs(p); - score += p.neutron_xs(j_nuclide).elastic * atom_density * flux; - } - } - } - } + // Check if event MT matches + if (p.event_mt() != ELASTIC) + continue; + score = (p.wgt_last() - wgt_absorb) * flux; break; case SCORE_FISS_Q_PROMPT: case SCORE_FISS_Q_RECOV: - if (p.macro_xs().absorption == 0.) + if (p.macro_xs().fission == 0.) continue; - score = score_fission_q(p, score_bin, tally, flux, i_nuclide, atom_density); + score = + score_fission_q(p, score_bin, tally, flux, i_nuclide, atom_density); break; - case N_2N: case N_3N: case N_4N: @@ -1312,44 +1459,18 @@ score_general_ce(Particle& p, int i_tally, int start_index, int filter_index, // This case block only works if cross sections for these reactions have // been precalculated. When they are not, we revert to the default case, // which looks up cross sections - if (!simulation::need_depletion_rx) goto default_case; + if (!simulation::need_depletion_rx) + goto default_case; if (p.type() != Type::neutron) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - // Check if the event MT matches - if (p.event_mt() != score_bin) - continue; - score = p.wgt_last() * flux; - } else { - int m; - switch (score_bin) { - case N_GAMMA: m = 0; break; - case N_P: m = 1; break; - case N_A: m = 2; break; - case N_2N: m = 3; break; - case N_3N: m = 4; break; - case N_4N: m = 5; break; - } - if (i_nuclide >= 0) { - score = p.neutron_xs(i_nuclide).reaction[m] * atom_density * flux; - } else { - score = 0.; - if (p.material() != MATERIAL_VOID) { - const Material& material {*model::materials[p.material()]}; - for (auto i = 0; i < material.nuclide_.size(); ++i) { - auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density_(i); - score += - p.neutron_xs(j_nuclide).reaction[m] * atom_density * flux; - } - } - } - } + // Check if the event MT matches + if (p.event_mt() != score_bin) + continue; + score = (p.wgt_last() - wgt_absorb) * flux; break; - case COHERENT: case INCOHERENT: case PHOTOELECTRIC: @@ -1357,44 +1478,24 @@ score_general_ce(Particle& p, int i_tally, int start_index, int filter_index, if (p.type() != Type::photon) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - if (score_bin == PHOTOELECTRIC) { - // Photoelectric events are assigned an MT value corresponding to the - // shell cross section. Also, photons below the energy cutoff are - // assumed to have been absorbed via photoelectric absorption - if ((p.event_mt() < 534 || p.event_mt() > 572) && - p.event_mt() != REACTION_NONE) - continue; - } else { - if (p.event_mt() != score_bin) - continue; - } - score = p.wgt_last() * flux; + if (score_bin == PHOTOELECTRIC) { + // Photoelectric events are assigned an MT value corresponding to the + // shell cross section. Also, photons below the energy cutoff are + // assumed to have been absorbed via photoelectric absorption + if ((p.event_mt() < 534 || p.event_mt() > 572) && + p.event_mt() != REACTION_NONE) + continue; } else { - if (i_nuclide >= 0) { - const auto& micro = p.photon_xs(i_nuclide); - double xs = - (score_bin == COHERENT) ? micro.coherent : - (score_bin == INCOHERENT) ? micro.incoherent : - (score_bin == PHOTOELECTRIC) ? micro.photoelectric : - micro.pair_production; - score = xs * atom_density * flux; - } else { - double xs = (score_bin == COHERENT) ? p.macro_xs().coherent - : (score_bin == INCOHERENT) ? p.macro_xs().incoherent - : (score_bin == PHOTOELECTRIC) - ? p.macro_xs().photoelectric - : p.macro_xs().pair_production; - score = xs * flux; - } + if (p.event_mt() != score_bin) + continue; } + score = p.wgt_last() * flux; break; - case HEATING: if (p.type() == Type::neutron) { - score = score_neutron_heating(p, tally, flux, HEATING, - i_nuclide, atom_density); + score = score_neutron_heating( + p, tally, flux, HEATING, i_nuclide, atom_density); } else { // The energy deposited is the difference between the pre-collision and // post-collision energy... @@ -1419,39 +1520,22 @@ score_general_ce(Particle& p, int i_tally, int start_index, int filter_index, if (p.type() != Type::neutron) continue; - if (tally.estimator_ == TallyEstimator::ANALOG) { - - // Any other score is assumed to be a MT number. Thus, we just need - // to check if it matches the MT number of the event - if (p.event_mt() != score_bin) - continue; - score = p.wgt_last() * flux; - } else { - // Any other cross section has to be calculated on-the-fly - if (score_bin < 2) fatal_error("Invalid score type on tally " - + std::to_string(tally.id_)); - score = 0.; - if (i_nuclide >= 0) { - score = get_nuclide_xs(p, i_nuclide, score_bin) * atom_density * flux; - } else if (p.material() != MATERIAL_VOID) { - const Material& material {*model::materials[p.material()]}; - for (auto i = 0; i < material.nuclide_.size(); ++i) { - auto j_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density_(i); - score += get_nuclide_xs(p, j_nuclide, score_bin) * atom_density * flux; - } - } - } + // Any other score is assumed to be a MT number. Thus, we just need + // to check if it matches the MT number of the event + if (p.event_mt() != score_bin) + continue; + score = (p.wgt_last() - wgt_absorb) * flux; } // Add derivative information on score for differential tallies. if (tally.deriv_ != C_NONE) - apply_derivative_to_score(p, i_tally, i_nuclide, atom_density, score_bin, - score); + apply_derivative_to_score( + p, i_tally, i_nuclide, atom_density, score_bin, score); - // Update tally results - #pragma omp atomic - tally.results_(filter_index, score_index, TallyResult::VALUE) += score*filter_weight; +// Update tally results +#pragma omp atomic + tally.results_(filter_index, score_index, TallyResult::VALUE) += + score * filter_weight; } } @@ -1460,19 +1544,22 @@ score_general_ce(Particle& p, int i_tally, int start_index, int filter_index, //! For analog tallies, the flux estimate depends on the score type so the flux //! argument is really just used for filter weights. -void -score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, - double filter_weight, int i_nuclide, double atom_density, double flux) +void score_general_mg(Particle& p, int i_tally, int start_index, + int filter_index, double filter_weight, int i_nuclide, double atom_density, + double flux) { auto& tally {*model::tallies[i_tally]}; // Set the direction and group to use with get_xs Direction p_u; int p_g; - if (tally.estimator_ == TallyEstimator::ANALOG - || tally.estimator_ == TallyEstimator::COLLISION) { - + double wgt_absorb = 0.0; + if (tally.estimator_ == TallyEstimator::ANALOG || + tally.estimator_ == TallyEstimator::COLLISION) { if (settings::survival_biasing) { + // Determine weight that was absorbed + wgt_absorb = p.wgt_last() * p.neutron_xs(p.event_nuclide()).absorption / + p.neutron_xs(p.event_nuclide()).total; // Then we either are alive and had a scatter (and so g changed), // or are dead and g did not change @@ -1503,14 +1590,18 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, } // For shorthand, assign pointers to the material and nuclide xs set - auto& nuc_xs = data::mg.nuclides_[i_nuclide]; + auto& nuc_xs = (i_nuclide >= 0) ? data::mg.nuclides_[i_nuclide] + : data::mg.macro_xs_[p.material()]; auto& macro_xs = data::mg.macro_xs_[p.material()]; // Find the temperature and angle indices of interest - macro_xs.set_angle_index(p_u); + int macro_t = p.mg_xs_cache().t; + int macro_a = macro_xs.get_angle_index(p_u); + int nuc_t = 0; + int nuc_a = 0; if (i_nuclide >= 0) { - nuc_xs.set_temperature_index(p.sqrtkT()); - nuc_xs.set_angle_index(p_u); + nuc_t = nuc_xs.get_temperature_index(p.sqrtkT()); + nuc_a = nuc_xs.get_angle_index(p_u); } for (auto i = 0; i < tally.scores_.size(); ++i) { @@ -1521,82 +1612,64 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, switch (score_bin) { - case SCORE_FLUX: if (tally.estimator_ == TallyEstimator::ANALOG) { // All events score to a flux bin. We actually use a collision estimator // in place of an analog one since there is no way to count 'events' // exactly for the flux - if (settings::survival_biasing) { - // We need to account for the fact that some weight was already - // absorbed - score = p.wgt_last() + p.wgt_absorb(); - } else { - score = p.wgt_last(); - } - score *= flux / p.macro_xs().total; + score = flux * p.wgt_last() / p.macro_xs().total; } else { score = flux; } break; - case SCORE_TOTAL: if (tally.estimator_ == TallyEstimator::ANALOG) { // All events will score to the total reaction rate. We can just use // use the weight of the particle entering the collision as the score - if (settings::survival_biasing) { - // We need to account for the fact that some weight was already - // absorbed - score = p.wgt_last() + p.wgt_absorb(); - } else { - score = p.wgt_last(); - } - //TODO: should flux be multiplied in above instead of below? + score = flux * p.wgt_last(); if (i_nuclide >= 0) { - score *= flux * atom_density * nuc_xs.get_xs(MgxsType::TOTAL, p_g) - / macro_xs.get_xs(MgxsType::TOTAL, p_g); + score *= atom_density * + nuc_xs.get_xs(MgxsType::TOTAL, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::TOTAL, p_g, macro_t, macro_a); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * nuc_xs.get_xs(MgxsType::TOTAL, p_g); + score = atom_density * flux * + nuc_xs.get_xs(MgxsType::TOTAL, p_g, nuc_t, nuc_a); } else { score = p.macro_xs().total * flux; } } break; - case SCORE_INVERSE_VELOCITY: - if (tally.estimator_ == TallyEstimator::ANALOG - || tally.estimator_ == TallyEstimator::COLLISION) { + if (tally.estimator_ == TallyEstimator::ANALOG || + tally.estimator_ == TallyEstimator::COLLISION) { // All events score to an inverse velocity bin. We actually use a // collision estimator in place of an analog one since there is no way // to count 'events' exactly for the inverse velocity - if (settings::survival_biasing) { - // We need to account for the fact that some weight was already - // absorbed - score = p.wgt_last() + p.wgt_absorb(); - } else { - score = p.wgt_last(); - } + score = flux * p.wgt_last(); if (i_nuclide >= 0) { - score *= flux * nuc_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g) - / macro_xs.get_xs(MgxsType::TOTAL, p_g); + score *= + nuc_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::TOTAL, p_g, macro_t, macro_a); } else { - score *= flux * macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g) - / macro_xs.get_xs(MgxsType::TOTAL, p_g); + score *= + macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g, macro_t, macro_a) / + macro_xs.get_xs(MgxsType::TOTAL, p_g, macro_t, macro_a); } } else { if (i_nuclide >= 0) { - score = flux * nuc_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g); + score = + flux * nuc_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g, nuc_t, nuc_a); } else { - score = flux * macro_xs.get_xs(MgxsType::INVERSE_VELOCITY, p_g); + score = flux * macro_xs.get_xs( + MgxsType::INVERSE_VELOCITY, p_g, macro_t, macro_a); } } break; - case SCORE_SCATTER: if (tally.estimator_ == TallyEstimator::ANALOG) { // Skip any event where the particle didn't scatter @@ -1604,27 +1677,26 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, continue; // Since only scattering events make it here, again we can use the // weight entering the collision as the estimator for the reaction rate - score = p.wgt_last() * flux; + score = (p.wgt_last() - wgt_absorb) * flux; if (i_nuclide >= 0) { score *= atom_density * nuc_xs.get_xs(MgxsType::SCATTER_FMU, p.g_last(), &p.g(), - &p.mu(), nullptr) / + &p.mu(), nullptr, nuc_t, nuc_a) / macro_xs.get_xs(MgxsType::SCATTER_FMU, p.g_last(), &p.g(), - &p.mu(), nullptr); + &p.mu(), nullptr, macro_t, macro_a); } } else { if (i_nuclide >= 0) { - score = - atom_density * flux * - nuc_xs.get_xs(MgxsType::SCATTER, p_g, nullptr, &p.mu(), nullptr); + score = atom_density * flux * + nuc_xs.get_xs(MgxsType::SCATTER, p_g, nullptr, &p.mu(), + nullptr, nuc_t, nuc_a); } else { - score = flux * macro_xs.get_xs( - MgxsType::SCATTER, p_g, nullptr, &p.mu(), nullptr); + score = flux * macro_xs.get_xs(MgxsType::SCATTER, p_g, nullptr, + &p.mu(), nullptr, macro_t, macro_a); } } break; - case SCORE_NU_SCATTER: if (tally.estimator_ == TallyEstimator::ANALOG) { // Skip any event where the particle didn't scatter @@ -1633,33 +1705,34 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, // For scattering production, we need to use the pre-collision weight // times the multiplicity as the estimate for the number of neutrons // exiting a reaction with neutrons in the exit channel - score = p.wgt() * flux; + score = (p.wgt_last() - wgt_absorb) * flux; // Since we transport based on material data, the angle selected // was not selected from the f(mu) for the nuclide. Therefore // adjust the score by the actual probability for that nuclide. if (i_nuclide >= 0) { score *= atom_density * nuc_xs.get_xs(MgxsType::NU_SCATTER_FMU, p.g_last(), &p.g(), - &p.mu(), nullptr) / + &p.mu(), nullptr, nuc_t, nuc_a) / macro_xs.get_xs(MgxsType::NU_SCATTER_FMU, p.g_last(), &p.g(), - &p.mu(), nullptr); + &p.mu(), nullptr, macro_t, macro_a); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * nuc_xs.get_xs(MgxsType::NU_SCATTER, p_g); + score = atom_density * flux * + nuc_xs.get_xs(MgxsType::NU_SCATTER, p_g, nuc_t, nuc_a); } else { - score = flux * macro_xs.get_xs(MgxsType::NU_SCATTER, p_g); + score = + flux * macro_xs.get_xs(MgxsType::NU_SCATTER, p_g, macro_t, macro_a); } } break; - case SCORE_ABSORPTION: if (tally.estimator_ == TallyEstimator::ANALOG) { if (settings::survival_biasing) { // No absorption events actually occur if survival biasing is on -- // just use weight absorbed in survival biasing - score = p.wgt_absorb() * flux; + score = wgt_absorb * flux; } else { // Skip any event where the particle wasn't absorbed if (p.event() == TallyEvent::SCATTER) @@ -1669,27 +1742,27 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, score = p.wgt_last() * flux; } if (i_nuclide >= 0) { - score *= atom_density * nuc_xs.get_xs(MgxsType::ABSORPTION, p_g) - / macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + score *= atom_density * + nuc_xs.get_xs(MgxsType::ABSORPTION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); } } else { if (i_nuclide >= 0) { - score = atom_density * flux - * nuc_xs.get_xs(MgxsType::ABSORPTION, p_g); + score = atom_density * flux * + nuc_xs.get_xs(MgxsType::ABSORPTION, p_g, nuc_t, nuc_a); } else { score = p.macro_xs().absorption * flux; } } break; - case SCORE_FISSION: if (tally.estimator_ == TallyEstimator::ANALOG) { if (settings::survival_biasing) { // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // fission - score = p.wgt_absorb() * flux; + score = wgt_absorb * flux; } else { // Skip any non-absorption events if (p.event() == TallyEvent::SCATTER) @@ -1700,22 +1773,24 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, score = p.wgt_last() * flux; } if (i_nuclide >= 0) { - score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) - / macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + score *= atom_density * + nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); } else { - score *= macro_xs.get_xs(MgxsType::FISSION, p_g) - / macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + score *= macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * nuc_xs.get_xs(MgxsType::FISSION, p_g); + score = atom_density * flux * + nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a); } else { - score = flux * macro_xs.get_xs(MgxsType::FISSION, p_g); + score = + flux * macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); } } break; - case SCORE_NU_FISSION: if (tally.estimator_ == TallyEstimator::ANALOG) { if (settings::survival_biasing || p.fission()) { @@ -1730,13 +1805,16 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // nu-fission - score = p.wgt_absorb() * flux; + score = wgt_absorb * flux; if (i_nuclide >= 0) { - score *= atom_density * nuc_xs.get_xs(MgxsType::NU_FISSION, p_g) - / macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + score *= + atom_density * + nuc_xs.get_xs(MgxsType::NU_FISSION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); } else { - score *= macro_xs.get_xs(MgxsType::NU_FISSION, p_g) - / macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + score *= + macro_xs.get_xs(MgxsType::NU_FISSION, p_g, macro_t, macro_a) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); } } else { // Skip any non-fission events @@ -1749,21 +1827,22 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, // score. score = simulation::keff * p.wgt_bank() * flux; if (i_nuclide >= 0) { - score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) - / macro_xs.get_xs(MgxsType::FISSION, p_g); + score *= atom_density * + nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); } } } else { if (i_nuclide >= 0) { - score = atom_density * flux - * nuc_xs.get_xs(MgxsType::NU_FISSION, p_g); + score = atom_density * flux * + nuc_xs.get_xs(MgxsType::NU_FISSION, p_g, nuc_t, nuc_a); } else { - score = flux * macro_xs.get_xs(MgxsType::NU_FISSION, p_g); + score = + flux * macro_xs.get_xs(MgxsType::NU_FISSION, p_g, macro_t, macro_a); } } break; - case SCORE_PROMPT_NU_FISSION: if (tally.estimator_ == TallyEstimator::ANALOG) { if (settings::survival_biasing || p.fission()) { @@ -1778,14 +1857,17 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // prompt-nu-fission - score = p.wgt_absorb() * flux; + score = wgt_absorb * flux; if (i_nuclide >= 0) { - score *= atom_density * - nuc_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g) - / macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + score *= + atom_density * + nuc_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); } else { - score *= macro_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g) - / macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + score *= + macro_xs.get_xs( + MgxsType::PROMPT_NU_FISSION, p_g, macro_t, macro_a) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); } } else { // Skip any non-fission events @@ -1801,21 +1883,22 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, auto prompt_frac = 1. - n_delayed / static_cast(p.n_bank()); score = simulation::keff * p.wgt_bank() * prompt_frac * flux; if (i_nuclide >= 0) { - score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) - / macro_xs.get_xs(MgxsType::FISSION, p_g); + score *= atom_density * + nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); } } } else { if (i_nuclide >= 0) { score = atom_density * flux * - nuc_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g); + nuc_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g, nuc_t, nuc_a); } else { - score = flux * macro_xs.get_xs(MgxsType::PROMPT_NU_FISSION, p_g); + score = flux * macro_xs.get_xs( + MgxsType::PROMPT_NU_FISSION, p_g, macro_t, macro_a); } } break; - case SCORE_DELAYED_NU_FISSION: if (tally.estimator_ == TallyEstimator::ANALOG) { if (settings::survival_biasing || p.fission()) { @@ -1830,25 +1913,26 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission - double abs_xs = macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + double abs_xs = + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); if (abs_xs > 0.) { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( - model::tally_filters[i_dg_filt].get())}; + const DelayedGroupFilter& filt { + *dynamic_cast( + model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { auto d = filt.groups()[d_bin] - 1; - score = p.wgt_absorb() * flux; + score = wgt_absorb * flux; if (i_nuclide >= 0) { score *= nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d) - / abs_xs; + nullptr, nullptr, &d, nuc_t, nuc_a) / + abs_xs; } else { score *= macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d) - / abs_xs; + nullptr, nullptr, &d, macro_t, macro_a) / + abs_xs; } score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); @@ -1858,13 +1942,15 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, // If the delayed group filter is not present, compute the score // by multiplying the absorbed weight by the fraction of the // delayed-nu-fission xs to the absorption xs - score = p.wgt_absorb() * flux; + score = wgt_absorb * flux; if (i_nuclide >= 0) { - score *= nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g) - / abs_xs; + score *= nuc_xs.get_xs( + MgxsType::DELAYED_NU_FISSION, p_g, nuc_t, nuc_a) / + abs_xs; } else { - score *= macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g) - / abs_xs; + score *= macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, + macro_t, macro_a) / + abs_xs; } } } @@ -1881,8 +1967,7 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, // contribution to the fission bank to the score. if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( + const DelayedGroupFilter& filt {*dynamic_cast( model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { @@ -1890,8 +1975,10 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, score = simulation::keff * p.wgt_bank() / p.n_bank() * p.n_delayed_bank(d - 1) * flux; if (i_nuclide >= 0) { - score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) - / macro_xs.get_xs(MgxsType::FISSION, p_g); + score *= + atom_density * + nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); } score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); @@ -1904,26 +1991,28 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, score = simulation::keff * p.wgt_bank() / p.n_bank() * n_delayed * flux; if (i_nuclide >= 0) { - score *= atom_density * nuc_xs.get_xs(MgxsType::FISSION, p_g) - / macro_xs.get_xs(MgxsType::FISSION, p_g); + score *= + atom_density * + nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); } } } } else { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( + const DelayedGroupFilter& filt {*dynamic_cast( model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { auto d = filt.groups()[d_bin] - 1; if (i_nuclide >= 0) { - score = flux * atom_density * nuc_xs.get_xs( - MgxsType::DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); + score = flux * atom_density * + nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, + nullptr, &d, nuc_t, nuc_a); } else { - score = flux * macro_xs.get_xs( - MgxsType::DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); + score = flux * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d, macro_t, macro_a); } score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); @@ -1931,43 +2020,47 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, continue; } else { if (i_nuclide >= 0) { - score = flux * atom_density * - nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g); + score = + flux * atom_density * + nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nuc_t, nuc_a); } else { - score = flux * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g); + score = flux * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, + macro_t, macro_a); } } } break; - case SCORE_DECAY_RATE: if (tally.estimator_ == TallyEstimator::ANALOG) { if (settings::survival_biasing) { // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission - double abs_xs = macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + double abs_xs = + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); if (abs_xs > 0) { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( - model::tally_filters[i_dg_filt].get())}; + const DelayedGroupFilter& filt { + *dynamic_cast( + model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { auto d = filt.groups()[d_bin] - 1; - score = p.wgt_absorb() * flux; + score = wgt_absorb * flux; if (i_nuclide >= 0) { - score *= nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, - nullptr, nullptr, &d) - * nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d) / abs_xs; + score *= nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, + nullptr, &d, nuc_t, nuc_a) * + nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d, nuc_t, nuc_a) / + abs_xs; } else { score *= macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d) - * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d) / abs_xs; + nullptr, &d, macro_t, macro_a) * + macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d, macro_t, macro_a) / + abs_xs; } score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); @@ -1981,18 +2074,18 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, score = 0.; for (auto d = 0; d < data::mg.num_delayed_groups_; ++d) { if (i_nuclide >= 0) { - score += p.wgt_absorb() * flux * - nuc_xs.get_xs( - MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * + score += wgt_absorb * flux * + nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, + nullptr, &d, nuc_t, nuc_a) * nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d) / + nullptr, nullptr, &d, nuc_t, nuc_a) / abs_xs; } else { - score += p.wgt_absorb() * flux * - macro_xs.get_xs( - MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) * + score += wgt_absorb * flux * + macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, + nullptr, &d, macro_t, macro_a) * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, - nullptr, nullptr, &d) / + nullptr, nullptr, &d, macro_t, macro_a) / abs_xs; } } @@ -2015,19 +2108,22 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, auto d = bank.delayed_group - 1; if (d != -1) { if (i_nuclide >= 0) { - score += simulation::keff * atom_density * bank.wgt * flux - * nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) - * nuc_xs.get_xs(MgxsType::FISSION, p_g) - / macro_xs.get_xs(MgxsType::FISSION, p_g); + score += + simulation::keff * atom_density * bank.wgt * flux * + nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d, + nuc_t, nuc_a) * + nuc_xs.get_xs(MgxsType::FISSION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::FISSION, p_g, macro_t, macro_a); } else { - score += simulation::keff * bank.wgt * flux - * macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d); + score += simulation::keff * bank.wgt * flux * + macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, + nullptr, &d, macro_t, macro_a); } if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( - model::tally_filters[i_dg_filt].get())}; + const DelayedGroupFilter& filt { + *dynamic_cast( + model::tally_filters[i_dg_filt].get())}; // Find the corresponding filter bin and then score for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { auto dg = filt.groups()[d_bin]; @@ -2039,29 +2135,29 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, } } } - if (tally.delayedgroup_filter_ != C_NONE) continue; + if (tally.delayedgroup_filter_ != C_NONE) + continue; } } else { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; - const DelayedGroupFilter& filt - {*dynamic_cast( + const DelayedGroupFilter& filt {*dynamic_cast( model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { auto d = filt.groups()[d_bin] - 1; if (i_nuclide >= 0) { - score = atom_density * flux - * nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d) - * nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, - nullptr, &d); + score = atom_density * flux * + nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, + &d, nuc_t, nuc_a) * + nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, + nullptr, &d, nuc_t, nuc_a); } else { - score = flux - * macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, - nullptr, &d) - * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, - nullptr, &d); + score = flux * + macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, + nullptr, &d, macro_t, macro_a) * + macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d, macro_t, macro_a); } score_fission_delayed_dg( i_tally, d_bin, score, score_index, p.filter_matches()); @@ -2071,27 +2167,30 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, score = 0.; for (auto d = 0; d < data::mg.num_delayed_groups_; ++d) { if (i_nuclide >= 0) { - score += atom_density * flux - * nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) - * nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); + score += atom_density * flux * + nuc_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, + nullptr, &d, nuc_t, nuc_a) * + nuc_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, + nullptr, &d, nuc_t, nuc_a); } else { - score += flux - * macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, nullptr, &d) - * macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); + score += flux * + macro_xs.get_xs(MgxsType::DECAY_RATE, p_g, nullptr, + nullptr, &d, macro_t, macro_a) * + macro_xs.get_xs(MgxsType::DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d, macro_t, macro_a); } } } } break; - case SCORE_KAPPA_FISSION: if (tally.estimator_ == TallyEstimator::ANALOG) { if (settings::survival_biasing) { // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // fission scaled by the Q-value - score = p.wgt_absorb() * flux; + score = wgt_absorb * flux; } else { // Skip any non-absorption events if (p.event() == TallyEvent::SCATTER) @@ -2102,75 +2201,39 @@ score_general_mg(Particle& p, int i_tally, int start_index, int filter_index, score = p.wgt_last() * flux; } if (i_nuclide >= 0) { - score *= atom_density - * nuc_xs.get_xs(MgxsType::KAPPA_FISSION, p_g) - / macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + score *= atom_density * + nuc_xs.get_xs(MgxsType::KAPPA_FISSION, p_g, nuc_t, nuc_a) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); } else { score *= - macro_xs.get_xs(MgxsType::KAPPA_FISSION, p_g) - / macro_xs.get_xs(MgxsType::ABSORPTION, p_g); + macro_xs.get_xs(MgxsType::KAPPA_FISSION, p_g, macro_t, macro_a) / + macro_xs.get_xs(MgxsType::ABSORPTION, p_g, macro_t, macro_a); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * nuc_xs.get_xs(MgxsType::KAPPA_FISSION, p_g); + score = atom_density * flux * + nuc_xs.get_xs(MgxsType::KAPPA_FISSION, p_g, nuc_t, nuc_a); } else { - score = flux * macro_xs.get_xs(MgxsType::KAPPA_FISSION, p_g); + score = flux * macro_xs.get_xs( + MgxsType::KAPPA_FISSION, p_g, macro_t, macro_a); } } break; case SCORE_EVENTS: - // Simply count the number of scoring events - #pragma omp atomic +// Simply count the number of scoring events +#pragma omp atomic tally.results_(filter_index, score_index, TallyResult::VALUE) += 1.0; continue; - default: continue; } - // Update tally results - #pragma omp atomic - tally.results_(filter_index, score_index, TallyResult::VALUE) += score*filter_weight; - } -} - -//! Tally rates for when the user requests a tally on all nuclides. - -void -score_all_nuclides(Particle& p, int i_tally, double flux, - int filter_index, double filter_weight) -{ - const Tally& tally {*model::tallies[i_tally]}; - const Material& material {*model::materials[p.material()]}; - - // Score all individual nuclide reaction rates. - for (auto i = 0; i < material.nuclide_.size(); ++i) { - auto i_nuclide = material.nuclide_[i]; - auto atom_density = material.atom_density_(i); - - //TODO: consider replacing this "if" with pointers or templates - if (settings::run_CE) { - score_general_ce(p, i_tally, i_nuclide*tally.scores_.size(), filter_index, - filter_weight, i_nuclide, atom_density, flux); - } else { - score_general_mg(p, i_tally, i_nuclide*tally.scores_.size(), filter_index, - filter_weight, i_nuclide, atom_density, flux); - } - } - - // Score total material reaction rates. - int i_nuclide = -1; - double atom_density = 0.; - auto n_nuclides = data::nuclides.size(); - //TODO: consider replacing this "if" with pointers or templates - if (settings::run_CE) { - score_general_ce(p, i_tally, n_nuclides*tally.scores_.size(), filter_index, - filter_weight, i_nuclide, atom_density, flux); - } else { - score_general_mg(p, i_tally, n_nuclides*tally.scores_.size(), filter_index, - filter_weight, i_nuclide, atom_density, flux); +// Update tally results +#pragma omp atomic + tally.results_(filter_index, score_index, TallyResult::VALUE) += + score * filter_weight; } } @@ -2192,7 +2255,8 @@ void score_analog_tally_ce(Particle& p) // assume_separate break below. auto filter_iter = FilterBinIter(tally, p); auto end = FilterBinIter(tally, true, &p.filter_matches()); - if (filter_iter == end) continue; + if (filter_iter == end) + continue; // Loop over filter bins. for (; filter_iter != end; ++filter_iter) { @@ -2200,30 +2264,15 @@ void score_analog_tally_ce(Particle& p) auto filter_weight = filter_iter.weight_; // Loop over nuclide bins. - if (!tally.all_nuclides_) { - for (auto i = 0; i < tally.nuclides_.size(); ++i) { - auto i_nuclide = tally.nuclides_[i]; - - // Tally this event in the present nuclide bin if that bin represents - // the event nuclide or the total material. Note that the atomic - // density argument for score_general is not used for analog tallies. - if (i_nuclide == p.event_nuclide() || i_nuclide == -1) - score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index, - filter_weight, i_nuclide, -1.0, flux); - } + for (auto i = 0; i < tally.nuclides_.size(); ++i) { + auto i_nuclide = tally.nuclides_[i]; - } else { - // In the case that the user has requested to tally all nuclides, we - // can take advantage of the fact that we know exactly how nuclide - // bins correspond to nuclide indices. First, tally the nuclide. - auto i = p.event_nuclide(); - score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index, - filter_weight, -1, -1.0, flux); - - // Now tally the total material. - i = tally.nuclides_.size(); - score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index, - filter_weight, -1, -1.0, flux); + // Tally this event in the present nuclide bin if that bin represents + // the event nuclide or the total material. Note that the atomic + // density argument for score_general is not used for analog tallies. + if (i_nuclide == p.event_nuclide() || i_nuclide == -1) + score_general_ce_analog(p, i_tally, i * tally.scores_.size(), + filter_index, filter_weight, i_nuclide, -1.0, flux); } } @@ -2231,7 +2280,8 @@ void score_analog_tally_ce(Particle& p) // separate, this implies that once a tally has been scored to, we needn't // check the others. This cuts down on overhead when there are many // tallies specified - if (settings::assume_separate) break; + if (settings::assume_separate) + break; } // Reset all the filter matches for the next tally event. @@ -2249,7 +2299,8 @@ void score_analog_tally_mg(Particle& p) // assume_separate break below. auto filter_iter = FilterBinIter(tally, p); auto end = FilterBinIter(tally, true, &p.filter_matches()); - if (filter_iter == end) continue; + if (filter_iter == end) + continue; // Loop over filter bins. for (; filter_iter != end; ++filter_iter) { @@ -2264,11 +2315,12 @@ void score_analog_tally_mg(Particle& p) if (i_nuclide >= 0) { auto j = model::materials[p.material()]->mat_nuclide_index_[i_nuclide]; - if (j == C_NONE) continue; + if (j == C_NONE) + continue; atom_density = model::materials[p.material()]->atom_density_(j); } - score_general_mg(p, i_tally, i*tally.scores_.size(), filter_index, + score_general_mg(p, i_tally, i * tally.scores_.size(), filter_index, filter_weight, i_nuclide, atom_density, 1.0); } } @@ -2277,7 +2329,8 @@ void score_analog_tally_mg(Particle& p) // separate, this implies that once a tally has been scored to, we needn't // check the others. This cuts down on overhead when there are many // tallies specified - if (settings::assume_separate) break; + if (settings::assume_separate) + break; } // Reset all the filter matches for the next tally event. @@ -2285,12 +2338,14 @@ void score_analog_tally_mg(Particle& p) match.bins_present_ = false; } -void -score_tracklength_tally(Particle& p, double distance) +void score_tracklength_tally(Particle& p, double distance) { // Determine the tracklength estimate of the flux double flux = p.wgt() * distance; + // Set 'none' value for log union grid index + int i_log_union = C_NONE; + for (auto i_tally : model::active_tracklength_tallies) { const Tally& tally {*model::tallies[i_tally]}; @@ -2299,7 +2354,8 @@ score_tracklength_tally(Particle& p, double distance) // assume_separate break below. auto filter_iter = FilterBinIter(tally, p); auto end = FilterBinIter(tally, true, &p.filter_matches()); - if (filter_iter == end) continue; + if (filter_iter == end) + continue; // Loop over filter bins. for (; filter_iter != end; ++filter_iter) { @@ -2307,43 +2363,51 @@ score_tracklength_tally(Particle& p, double distance) auto filter_weight = filter_iter.weight_; // Loop over nuclide bins. - if (tally.all_nuclides_) { - if (p.material() != MATERIAL_VOID) - score_all_nuclides(p, i_tally, flux*filter_weight, filter_index, - filter_weight); + for (auto i = 0; i < tally.nuclides_.size(); ++i) { + auto i_nuclide = tally.nuclides_[i]; - } else { - for (auto i = 0; i < tally.nuclides_.size(); ++i) { - auto i_nuclide = tally.nuclides_[i]; + double atom_density = 0.; + if (i_nuclide >= 0) { + if (p.material() != MATERIAL_VOID) { + const auto& mat = model::materials[p.material()]; + auto j = mat->mat_nuclide_index_[i_nuclide]; + if (j == C_NONE) { + // Determine log union grid index + if (i_log_union == C_NONE) { + int neutron = static_cast(ParticleType::neutron); + i_log_union = std::log(p.E() / data::energy_min[neutron]) / + simulation::log_spacing; + } - double atom_density = 0.; - if (i_nuclide >= 0) { - if (p.material() != MATERIAL_VOID) { - auto j = - model::materials[p.material()]->mat_nuclide_index_[i_nuclide]; - if (j == C_NONE) continue; - atom_density = model::materials[p.material()]->atom_density_(j); + // Update micro xs cache + if (!tally.multiply_density()) { + p.update_neutron_xs(i_nuclide, i_log_union); + atom_density = 1.0; + } + } else { + atom_density = + tally.multiply_density() ? mat->atom_density_(j) : 1.0; } } + } - //TODO: consider replacing this "if" with pointers or templates - if (settings::run_CE) { - score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index, - filter_weight, i_nuclide, atom_density, flux); - } else { - score_general_mg(p, i_tally, i*tally.scores_.size(), filter_index, - filter_weight, i_nuclide, atom_density, flux); - } + // TODO: consider replacing this "if" with pointers or templates + if (settings::run_CE) { + score_general_ce_nonanalog(p, i_tally, i * tally.scores_.size(), + filter_index, filter_weight, i_nuclide, atom_density, flux); + } else { + score_general_mg(p, i_tally, i * tally.scores_.size(), filter_index, + filter_weight, i_nuclide, atom_density, flux); } } - } // If the user has specified that we can assume all tallies are spatially // separate, this implies that once a tally has been scored to, we needn't // check the others. This cuts down on overhead when there are many // tallies specified - if (settings::assume_separate) break; + if (settings::assume_separate) + break; } // Reset all the filter matches for the next tally event. @@ -2356,13 +2420,12 @@ void score_collision_tally(Particle& p) // Determine the collision estimate of the flux double flux = 0.0; if (p.type() == ParticleType::neutron || p.type() == ParticleType::photon) { - if (!settings::survival_biasing) { - flux = p.wgt_last() / p.macro_xs().total; - } else { - flux = (p.wgt_last() + p.wgt_absorb()) / p.macro_xs().total; - } + flux = p.wgt_last() / p.macro_xs().total; } + // Set 'none value for log union grid index + int i_log_union = C_NONE; + for (auto i_tally : model::active_collision_tallies) { const Tally& tally {*model::tallies[i_tally]}; @@ -2371,7 +2434,8 @@ void score_collision_tally(Particle& p) // assume_separate break below. auto filter_iter = FilterBinIter(tally, p); auto end = FilterBinIter(tally, true, &p.filter_matches()); - if (filter_iter == end) continue; + if (filter_iter == end) + continue; // Loop over filter bins. for (; filter_iter != end; ++filter_iter) { @@ -2379,31 +2443,40 @@ void score_collision_tally(Particle& p) auto filter_weight = filter_iter.weight_; // Loop over nuclide bins. - if (tally.all_nuclides_) { - score_all_nuclides(p, i_tally, flux*filter_weight, filter_index, - filter_weight); - - } else { - for (auto i = 0; i < tally.nuclides_.size(); ++i) { - auto i_nuclide = tally.nuclides_[i]; + for (auto i = 0; i < tally.nuclides_.size(); ++i) { + auto i_nuclide = tally.nuclides_[i]; - double atom_density = 0.; - if (i_nuclide >= 0) { - auto j = - model::materials[p.material()]->mat_nuclide_index_[i_nuclide]; - if (j == C_NONE) continue; - atom_density = model::materials[p.material()]->atom_density_(j); - } + double atom_density = 0.; + if (i_nuclide >= 0) { + const auto& mat = model::materials[p.material()]; + auto j = mat->mat_nuclide_index_[i_nuclide]; + if (j == C_NONE) { + // Determine log union grid index + if (i_log_union == C_NONE) { + int neutron = static_cast(ParticleType::neutron); + i_log_union = std::log(p.E() / data::energy_min[neutron]) / + simulation::log_spacing; + } - //TODO: consider replacing this "if" with pointers or templates - if (settings::run_CE) { - score_general_ce(p, i_tally, i*tally.scores_.size(), filter_index, - filter_weight, i_nuclide, atom_density, flux); + // Update micro xs cache + if (!tally.multiply_density()) { + p.update_neutron_xs(i_nuclide, i_log_union); + atom_density = 1.0; + } } else { - score_general_mg(p, i_tally, i*tally.scores_.size(), filter_index, - filter_weight, i_nuclide, atom_density, flux); + atom_density = + tally.multiply_density() ? mat->atom_density_(j) : 1.0; } } + + // TODO: consider replacing this "if" with pointers or templates + if (settings::run_CE) { + score_general_ce_nonanalog(p, i_tally, i * tally.scores_.size(), + filter_index, filter_weight, i_nuclide, atom_density, flux); + } else { + score_general_mg(p, i_tally, i * tally.scores_.size(), filter_index, + filter_weight, i_nuclide, atom_density, flux); + } } } @@ -2411,7 +2484,8 @@ void score_collision_tally(Particle& p) // separate, this implies that once a tally has been scored to, we needn't // check the others. This cuts down on overhead when there are many // tallies specified - if (settings::assume_separate) break; + if (settings::assume_separate) + break; } // Reset all the filter matches for the next tally event. @@ -2421,8 +2495,7 @@ void score_collision_tally(Particle& p) void score_surface_tally(Particle& p, const vector& tallies) { - // No collision, so no weight change when survival biasing - double flux = p.wgt(); + double current = p.wgt_last(); for (auto i_tally : tallies) { auto& tally {*model::tallies[i_tally]}; @@ -2432,7 +2505,8 @@ void score_surface_tally(Particle& p, const vector& tallies) // assume_separate break below. auto filter_iter = FilterBinIter(tally, p); auto end = FilterBinIter(tally, true, &p.filter_matches()); - if (filter_iter == end) continue; + if (filter_iter == end) + continue; // Loop over filter bins. for (; filter_iter != end; ++filter_iter) { @@ -2442,10 +2516,10 @@ void score_surface_tally(Particle& p, const vector& tallies) // Loop over scores. // There is only one score type for current tallies so there is no need // for a further scoring function. - double score = flux * filter_weight; + double score = current * filter_weight; for (auto score_index = 0; score_index < tally.scores_.size(); ++score_index) { - #pragma omp atomic +#pragma omp atomic tally.results_(filter_index, score_index, TallyResult::VALUE) += score; } } @@ -2454,7 +2528,8 @@ void score_surface_tally(Particle& p, const vector& tallies) // separate, this implies that once a tally has been scored to, we needn't // check the others. This cuts down on overhead when there are many // tallies specified - if (settings::assume_separate) break; + if (settings::assume_separate) + break; } // Reset all the filter matches for the next tally event. @@ -2462,4 +2537,79 @@ void score_surface_tally(Particle& p, const vector& tallies) match.bins_present_ = false; } +void score_pulse_height_tally(Particle& p, const vector& tallies) +{ + // The pulse height tally in OpenMC hijacks the logic of CellFilter and + // EnergyFilter to score specific quantities related to particle pulse height. + // This is achieved by setting the pulse-height cell of the tally to the cell + // of the particle being scored, and the energy to the particle's last + // recorded energy (E_last()). After the tally is scored, the values are reset + // to ensure proper accounting and avoid interference with subsequent + // calculations or tallies. + + // Save original cell/energy information + int orig_n_coord = p.n_coord(); + int orig_cell = p.coord(0).cell; + double orig_E_last = p.E_last(); + + for (auto i_tally : tallies) { + auto& tally {*model::tallies[i_tally]}; + + // Determine all CellFilter in the tally + for (const auto& filter : tally.filters()) { + auto cell_filter = + dynamic_cast(model::tally_filters[filter].get()); + if (cell_filter != nullptr) { + + const auto& cells = cell_filter->cells(); + // Loop over all cells in the CellFilter + for (auto cell_index = 0; cell_index < cells.size(); ++cell_index) { + int cell_id = cells[cell_index]; + + // Temporarily change cell of particle + p.n_coord() = 1; + p.coord(0).cell = cell_id; + + // Determine index of cell in model::pulse_height_cells + auto it = std::find(model::pulse_height_cells.begin(), + model::pulse_height_cells.end(), cell_id); + int index = std::distance(model::pulse_height_cells.begin(), it); + + // Temporarily change energy of particle to pulse-height value + p.E_last() = p.pht_storage()[index]; + + // Initialize an iterator over valid filter bin combinations. If + // there are no valid combinations, use a continue statement to ensure + // we skip the assume_separate break below. + auto filter_iter = FilterBinIter(tally, p); + auto end = FilterBinIter(tally, true, &p.filter_matches()); + if (filter_iter == end) + continue; + + // Loop over filter bins. + for (; filter_iter != end; ++filter_iter) { + auto filter_index = filter_iter.index_; + auto filter_weight = filter_iter.weight_; + + // Loop over scores. + for (auto score_index = 0; score_index < tally.scores_.size(); + ++score_index) { +#pragma omp atomic + tally.results_(filter_index, score_index, TallyResult::VALUE) += + filter_weight; + } + } + + // Reset all the filter matches for the next tally event. + for (auto& match : p.filter_matches()) + match.bins_present_ = false; + } + } + } + // Restore cell/energy + p.n_coord() = orig_n_coord; + p.coord(0).cell = orig_cell; + p.E_last() = orig_E_last; + } +} } // namespace openmc diff --git a/src/tallies/trigger.cpp b/src/tallies/trigger.cpp index 40eb3290fe4..f1f83e2982c 100644 --- a/src/tallies/trigger.cpp +++ b/src/tallies/trigger.cpp @@ -20,15 +20,15 @@ namespace openmc { //============================================================================== namespace settings { - KTrigger keff_trigger; +KTrigger keff_trigger; } //============================================================================== // Non-member functions //============================================================================== -std::pair -get_tally_uncertainty(int i_tally, int score_index, int filter_index) +std::pair get_tally_uncertainty( + int i_tally, int score_index, int filter_index) { const auto& tally {model::tallies[i_tally]}; @@ -37,7 +37,12 @@ get_tally_uncertainty(int i_tally, int score_index, int filter_index) int n = tally->n_realizations_; auto mean = sum / n; - double std_dev = std::sqrt((sum_sq/n - mean*mean) / (n-1)); + + // if the result has no contributions, return an invalid pair + if (mean == 0) + return {-1, -1}; + + double std_dev = std::sqrt((sum_sq / n - mean * mean) / (n - 1)); double rel_err = (mean != 0.) ? std_dev / std::abs(mean) : 0.; return {std_dev, rel_err}; @@ -50,59 +55,67 @@ get_tally_uncertainty(int i_tally, int score_index, int filter_index) //! param[out] tally_id The ID number of the most limiting tally //! param[out] score The most limiting tally score bin -void -check_tally_triggers(double& ratio, int& tally_id, int& score) +void check_tally_triggers(double& ratio, int& tally_id, int& score) { ratio = 0.; for (auto i_tally = 0; i_tally < model::tallies.size(); ++i_tally) { const Tally& t {*model::tallies[i_tally]}; // Ignore tallies with less than two realizations. - if (t.n_realizations_ < 2) continue; + if (t.n_realizations_ < 2) + continue; for (const auto& trigger : t.triggers_) { // Skip trigger if it is not active - if (trigger.metric == TriggerMetric::not_active) continue; + if (trigger.metric == TriggerMetric::not_active) + continue; const auto& results = t.results_; for (auto filter_index = 0; filter_index < results.shape()[0]; ++filter_index) { - for (auto score_index = 0; score_index < results.shape()[1]; - ++score_index) { - // Compute the tally uncertainty metrics. - auto uncert_pair = get_tally_uncertainty(i_tally, score_index, - filter_index); - double std_dev = uncert_pair.first; - double rel_err = uncert_pair.second; - - // Pick out the relevant uncertainty metric for this trigger. - double uncertainty; - switch (trigger.metric) { - case TriggerMetric::variance: - uncertainty = std_dev * std_dev; - break; - case TriggerMetric::standard_deviation: - uncertainty = std_dev; - break; - case TriggerMetric::relative_error: - uncertainty = rel_err; - break; - case TriggerMetric::not_active: - UNREACHABLE(); - } - - // Compute the uncertainty / threshold ratio. - double this_ratio = uncertainty / trigger.threshold; - if (trigger.metric == TriggerMetric::variance) { - this_ratio = std::sqrt(ratio); - } - - // If this is the most uncertain value, set the output variables. - if (this_ratio > ratio) { - ratio = this_ratio; - score = t.scores_[trigger.score_index]; - tally_id = t.id_; - } + // Compute the tally uncertainty metrics. + auto uncert_pair = + get_tally_uncertainty(i_tally, trigger.score_index, filter_index); + + // If there is a score without contributions, set ratio to inf and + // exit early, unless zero scores are ignored for this trigger. + if (uncert_pair.first == -1 && !trigger.ignore_zeros) { + ratio = INFINITY; + score = t.scores_[trigger.score_index]; + tally_id = t.id_; + return; + } + + double std_dev = uncert_pair.first; + double rel_err = uncert_pair.second; + + // Pick out the relevant uncertainty metric for this trigger. + double uncertainty; + switch (trigger.metric) { + case TriggerMetric::variance: + uncertainty = std_dev * std_dev; + break; + case TriggerMetric::standard_deviation: + uncertainty = std_dev; + break; + case TriggerMetric::relative_error: + uncertainty = rel_err; + break; + case TriggerMetric::not_active: + UNREACHABLE(); + } + + // Compute the uncertainty / threshold ratio. + double this_ratio = uncertainty / trigger.threshold; + if (trigger.metric == TriggerMetric::variance) { + this_ratio = std::sqrt(ratio); + } + + // If this is the most uncertain value, set the output variables. + if (this_ratio > ratio) { + ratio = this_ratio; + score = t.scores_[trigger.score_index]; + tally_id = t.id_; } } } @@ -111,10 +124,10 @@ check_tally_triggers(double& ratio, int& tally_id, int& score) //! Compute the uncertainty/threshold ratio for the eigenvalue trigger. -double -check_keff_trigger() +double check_keff_trigger() { - if (settings::run_mode != RunMode::EIGENVALUE) return 0.0; + if (settings::run_mode != RunMode::EIGENVALUE) + return 0.0; double k_combined[2]; openmc_get_keff(k_combined); @@ -144,8 +157,7 @@ check_keff_trigger() //! See if tally and eigenvalue uncertainties are under trigger thresholds. -void -check_triggers() +void check_triggers() { // Make some aliases. const auto current_batch {simulation::current_batch}; @@ -153,9 +165,12 @@ check_triggers() const auto interval {settings::trigger_batch_interval}; // See if the current batch is one for which the triggers must be checked. - if (!settings::trigger_on) return; - if (current_batch < n_batches) return; - if (((current_batch - n_batches) % interval) != 0) return; + if (!settings::trigger_on) + return; + if (current_batch < n_batches) + return; + if (((current_batch - n_batches) % interval) != 0) + return; // Check the eigenvalue and tally triggers. double keff_ratio = check_keff_trigger(); @@ -175,11 +190,18 @@ check_triggers() std::string msg; if (keff_ratio >= tally_ratio) { msg = fmt::format("Triggers unsatisfied, max unc./thresh. is {} for " - "eigenvalue", keff_ratio); + "eigenvalue", + keff_ratio); } else { - msg = fmt::format( - "Triggers unsatisfied, max unc./thresh. is {} for {} in tally {}", - tally_ratio, reaction_name(score), tally_id); + if (tally_ratio == INFINITY) { + msg = fmt::format( + "Triggers unsatisfied, no result tallied for score {} in tally {}", + reaction_name(score), tally_id); + } else { + msg = fmt::format( + "Triggers unsatisfied, max unc./thresh. is {} for {} in tally {}", + tally_ratio, reaction_name(score), tally_id); + } } write_message(msg, 7); @@ -189,16 +211,23 @@ check_triggers() // the number of batches. auto max_ratio = std::max(keff_ratio, tally_ratio); auto n_active = current_batch - settings::n_inactive; - auto n_pred_batches = static_cast(n_active * max_ratio * max_ratio) - + settings::n_inactive + 1; - - std::string msg = fmt::format("The estimated number of batches is {}", - n_pred_batches); - if (n_pred_batches > settings::n_max_batches) { - msg.append(" --- greater than max batches"); - warning(msg); - } else { + auto n_pred_batches = static_cast(n_active * max_ratio * max_ratio) + + settings::n_inactive + 1; + + if (max_ratio == INFINITY) { + std::string msg = + fmt::format("One or more tallies with triggers have no scores. Unable " + "to estimate the number of remaining batches."); write_message(msg, 7); + } else { + std::string msg = + fmt::format("The estimated number of batches is {}", n_pred_batches); + if (n_pred_batches > settings::n_max_batches) { + msg.append(" --- greater than max batches"); + warning(msg); + } else { + write_message(msg, 7); + } } } } diff --git a/src/thermal.cpp b/src/thermal.cpp index 5e3c6d6bb11..741f89ed104 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -3,13 +3,13 @@ #include // for sort, move, min, max, find #include // for round, sqrt, abs -#include #include "xtensor/xarray.hpp" #include "xtensor/xbuilder.hpp" #include "xtensor/xmath.hpp" #include "xtensor/xsort.hpp" #include "xtensor/xtensor.hpp" #include "xtensor/xview.hpp" +#include #include "openmc/constants.h" #include "openmc/endf.h" @@ -29,7 +29,7 @@ namespace openmc { namespace data { std::unordered_map thermal_scatt_map; vector> thermal_scatt; -} +} // namespace data //============================================================================== // ThermalScattering implementation @@ -84,13 +84,14 @@ ThermalScattering::ThermalScattering( auto i_closest = xt::argmin(xt::abs(temps_available - T))[0]; auto temp_actual = temps_available[i_closest]; if (std::abs(temp_actual - T) < settings::temperature_tolerance) { - if (std::find(temps_to_read.begin(), temps_to_read.end(), std::round(temp_actual)) - == temps_to_read.end()) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), + std::round(temp_actual)) == temps_to_read.end()) { temps_to_read.push_back(std::round(temp_actual)); } } else { fatal_error(fmt::format("Nuclear data library does not contain cross " - "sections for {} at or near {} K.", name_, std::round(T))); + "sections for {} at or near {} K.", + name_, std::round(T))); } } break; @@ -104,18 +105,38 @@ ThermalScattering::ThermalScattering( if (temps_available[j] <= T && T < temps_available[j + 1]) { int T_j = std::round(temps_available[j]); int T_j1 = std::round(temps_available[j + 1]); - if (std::find(temps_to_read.begin(), temps_to_read.end(), T_j) == temps_to_read.end()) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), T_j) == + temps_to_read.end()) { temps_to_read.push_back(T_j); } - if (std::find(temps_to_read.begin(), temps_to_read.end(), T_j1) == temps_to_read.end()) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), T_j1) == + temps_to_read.end()) { temps_to_read.push_back(T_j1); } found = true; } } if (!found) { - fatal_error(fmt::format("Nuclear data library does not contain cross " - "sections for {} at temperatures that bound {} K.", name_, std::round(T))); + // If no pairs found, check if the desired temperature falls within + // bounds' tolerance + if (std::abs(T - temps_available[0]) <= + settings::temperature_tolerance) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), + std::round(temps_available[0])) == temps_to_read.end()) { + temps_to_read.push_back(std::round(temps_available[0])); + } + } else if (std::abs(T - temps_available[n - 1]) <= + settings::temperature_tolerance) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), + std::round(temps_available[n - 1])) == temps_to_read.end()) { + temps_to_read.push_back(std::round(temps_available[n - 1])); + } + } else { + fatal_error( + fmt::format("Nuclear data library does not contain cross " + "sections for {} at temperatures that bound {} K.", + name_, std::round(T))); + } } } } @@ -145,28 +166,36 @@ ThermalScattering::ThermalScattering( close_group(kT_group); } -void -ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, - double* elastic, double* inelastic, - uint64_t* seed) const +void ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, + double* elastic, double* inelastic, uint64_t* seed) const { // Determine temperature for S(a,b) table - double kT = sqrtkT*sqrtkT; + double kT = sqrtkT * sqrtkT; int i = 0; auto n = kTs_.size(); if (n > 1) { - // Find temperatures that bound the actual temperature - while (kTs_[i+1] < kT && i + 1 < n - 1) ++i; - if (settings::temperature_method == TemperatureMethod::NEAREST) { + while (kTs_[i + 1] < kT && i + 1 < n - 1) + ++i; // Pick closer of two bounding temperatures - if (kT - kTs_[i] > kTs_[i+1] - kT) ++i; - + if (kT - kTs_[i] > kTs_[i + 1] - kT) + ++i; } else { - // Randomly sample between temperature i and i+1 - double f = (kT - kTs_[i]) / (kTs_[i+1] - kTs_[i]); - if (f > prn(seed)) ++i; + // If current kT outside of the bounds of available, snap to the bound + if (kT < kTs_.front()) { + i = 0; + } else if (kT > kTs_.back()) { + i = kTs_.size() - 1; + } else { + // Find temperatures that bound the actual temperature + while (kTs_[i + 1] < kT && i + 1 < n - 1) + ++i; + // Randomly sample between temperature i and i+1 + double f = (kT - kTs_[i]) / (kTs_[i + 1] - kTs_[i]); + if (f > prn(seed)) + ++i; + } } } @@ -177,8 +206,7 @@ ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, data_[i].calculate_xs(E, elastic, inelastic); } -bool -ThermalScattering::has_nuclide(const char* name) const +bool ThermalScattering::has_nuclide(const char* name) const { std::string nuc {name}; return std::find(nuclides_.begin(), nuclides_.end(), nuc) != nuclides_.end(); @@ -205,14 +233,22 @@ ThermalData::ThermalData(hid_t group) if (temp == "coherent_elastic") { auto xs = dynamic_cast(elastic_.xs.get()); elastic_.distribution = make_unique(*xs); - } else { - if (temp == "incoherent_elastic") { - elastic_.distribution = make_unique(dgroup); - } else if (temp == "incoherent_elastic_discrete") { - auto xs = dynamic_cast(elastic_.xs.get()); - elastic_.distribution = - make_unique(dgroup, xs->x()); - } + } else if (temp == "incoherent_elastic") { + elastic_.distribution = make_unique(dgroup); + } else if (temp == "incoherent_elastic_discrete") { + auto xs = dynamic_cast(elastic_.xs.get()); + elastic_.distribution = + make_unique(dgroup, xs->x()); + } else if (temp == "mixed_elastic") { + // Get coherent/incoherent cross sections + auto mixed_xs = dynamic_cast(elastic_.xs.get()); + const auto& coh_xs = + dynamic_cast(mixed_xs->functions(0).get()); + const auto& incoh_xs = mixed_xs->functions(1).get(); + + // Create mixed elastic distribution + elastic_.distribution = + make_unique(dgroup, *coh_xs, *incoh_xs); } close_group(elastic_group); @@ -242,8 +278,8 @@ ThermalData::ThermalData(hid_t group) } } -void -ThermalData::calculate_xs(double E, double* elastic, double* inelastic) const +void ThermalData::calculate_xs( + double E, double* elastic, double* inelastic) const { // Calculate thermal elastic scattering cross section if (elastic_.xs) { @@ -256,9 +292,8 @@ ThermalData::calculate_xs(double E, double* elastic, double* inelastic) const *inelastic = (*inelastic_.xs)(E); } -void -ThermalData::sample(const NuclideMicroXS& micro_xs, double E, - double* E_out, double* mu, uint64_t* seed) +void ThermalData::sample(const NuclideMicroXS& micro_xs, double E, + double* E_out, double* mu, uint64_t* seed) { // Determine whether inelastic or elastic scattering will occur if (prn(seed) < micro_xs.thermal_elastic / micro_xs.thermal) { @@ -270,7 +305,8 @@ ThermalData::sample(const NuclideMicroXS& micro_xs, double E, // Because of floating-point roundoff, it may be possible for mu to be // outside of the range [-1,1). In these cases, we just set mu to exactly // -1 or 1 - if (std::abs(*mu) > 1.0) *mu = std::copysign(1.0, *mu); + if (std::abs(*mu) > 1.0) + *mu = std::copysign(1.0, *mu); } void free_memory_thermal() diff --git a/src/timer.cpp b/src/timer.cpp index 395fa0988f4..6d692d4fbf6 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -26,6 +26,7 @@ Timer time_event_advance_particle; Timer time_event_surface_crossing; Timer time_event_collision; Timer time_event_death; +Timer time_update_src; } // namespace simulation @@ -33,7 +34,7 @@ Timer time_event_death; // Timer implementation //============================================================================== -void Timer::start () +void Timer::start() { running_ = true; start_ = clock::now(); @@ -85,6 +86,7 @@ void reset_timers() simulation::time_event_surface_crossing.reset(); simulation::time_event_collision.reset(); simulation::time_event_death.reset(); + simulation::time_update_src.reset(); } } // namespace openmc diff --git a/src/track_output.cpp b/src/track_output.cpp index ed20b057b3d..5c1436de716 100644 --- a/src/track_output.cpp +++ b/src/track_output.cpp @@ -2,13 +2,15 @@ #include "openmc/constants.h" #include "openmc/hdf5_interface.h" +#include "openmc/message_passing.h" #include "openmc/position.h" #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/vector.h" -#include #include "xtensor/xtensor.hpp" +#include +#include #include // for size_t #include @@ -19,6 +21,10 @@ namespace openmc { // Global variables //============================================================================== +hid_t track_file; //! HDF5 identifier for track file +hid_t track_dtype; //! HDF5 identifier for track datatype +int n_tracks_written; //! Number of tracks written + //============================================================================== // Non-member functions //============================================================================== @@ -26,45 +32,123 @@ namespace openmc { void add_particle_track(Particle& p) { p.tracks().emplace_back(); + p.tracks().back().particle = p.type(); } void write_particle_track(Particle& p) { - p.tracks().back().push_back(p.r()); + p.tracks().back().states.push_back(p.get_track_state()); } -void finalize_particle_track(Particle& p) +void open_track_file() { - std::string filename = - fmt::format("{}track_{}_{}_{}.h5", settings::path_output, - simulation::current_batch, simulation::current_gen, p.id()); + // Open file and write filetype/version -- when MPI is enabled and there is + // more than one rank, each rank writes its own file +#ifdef OPENMC_MPI + std::string filename; + if (mpi::n_procs > 1) { + filename = fmt::format("{}tracks_p{}.h5", settings::path_output, mpi::rank); + } else { + filename = fmt::format("{}tracks.h5", settings::path_output); + } +#else + std::string filename = fmt::format("{}tracks.h5", settings::path_output); +#endif + track_file = file_open(filename, 'w'); + write_attribute(track_file, "filetype", "track"); + write_attribute(track_file, "version", VERSION_TRACK); - // Determine number of coordinates for each particle - vector n_coords; - for (auto& coords : p.tracks()) { - n_coords.push_back(coords.size()); + // Create compound type for Position + hid_t postype = H5Tcreate(H5T_COMPOUND, sizeof(struct Position)); + H5Tinsert(postype, "x", HOFFSET(Position, x), H5T_NATIVE_DOUBLE); + H5Tinsert(postype, "y", HOFFSET(Position, y), H5T_NATIVE_DOUBLE); + H5Tinsert(postype, "z", HOFFSET(Position, z), H5T_NATIVE_DOUBLE); + + // Create compound type for TrackState + track_dtype = H5Tcreate(H5T_COMPOUND, sizeof(struct TrackState)); + H5Tinsert(track_dtype, "r", HOFFSET(TrackState, r), postype); + H5Tinsert(track_dtype, "u", HOFFSET(TrackState, u), postype); + H5Tinsert(track_dtype, "E", HOFFSET(TrackState, E), H5T_NATIVE_DOUBLE); + H5Tinsert(track_dtype, "time", HOFFSET(TrackState, time), H5T_NATIVE_DOUBLE); + H5Tinsert(track_dtype, "wgt", HOFFSET(TrackState, wgt), H5T_NATIVE_DOUBLE); + H5Tinsert( + track_dtype, "cell_id", HOFFSET(TrackState, cell_id), H5T_NATIVE_INT); + H5Tinsert(track_dtype, "cell_instance", HOFFSET(TrackState, cell_instance), + H5T_NATIVE_INT); + H5Tinsert(track_dtype, "material_id", HOFFSET(TrackState, material_id), + H5T_NATIVE_INT); + H5Tclose(postype); +} + +void close_track_file() +{ + H5Tclose(track_dtype); + file_close(track_file); + + // Reset number of tracks written + n_tracks_written = 0; +} + +bool check_track_criteria(const Particle& p) +{ + if (settings::write_all_tracks) { + // Increment number of tracks written and get previous value + int n; +#pragma omp atomic capture + n = n_tracks_written++; + + // Indicate that track should be written for this particle + return n < settings::max_tracks; } -#pragma omp critical (FinalizeParticleTrack) - { - hid_t file_id = file_open(filename, 'w'); - write_attribute(file_id, "filetype", "track"); - write_attribute(file_id, "version", VERSION_TRACK); - write_attribute(file_id, "n_particles", p.tracks().size()); - write_attribute(file_id, "n_coords", n_coords); - for (auto i = 1; i <= p.tracks().size(); ++i) { - const auto& t {p.tracks()[i - 1]}; - size_t n = t.size(); - xt::xtensor data({n,3}); - for (int j = 0; j < n; ++j) { - data(j, 0) = t[j].x; - data(j, 1) = t[j].y; - data(j, 2) = t[j].z; + // Check for match from explicit track identifiers + if (settings::track_identifiers.size() > 0) { + for (const auto& t : settings::track_identifiers) { + if (simulation::current_batch == t[0] && + simulation::current_gen == t[1] && p.id() == t[2]) { + return true; } - std::string name = fmt::format("coordinates_{}", i); - write_dataset(file_id, name.c_str(), data); } - file_close(file_id); + } + return false; +} + +void finalize_particle_track(Particle& p) +{ + // Determine number of coordinates for each particle + vector offsets; + vector particles; + vector tracks; + int offset = 0; + for (auto& track_i : p.tracks()) { + offsets.push_back(offset); + particles.push_back(static_cast(track_i.particle)); + offset += track_i.states.size(); + tracks.insert(tracks.end(), track_i.states.begin(), track_i.states.end()); + } + offsets.push_back(offset); + +#pragma omp critical(FinalizeParticleTrack) + { + // Create name for dataset + std::string dset_name = fmt::format("track_{}_{}_{}", + simulation::current_batch, simulation::current_gen, p.id()); + + // Write array of TrackState to file + hsize_t dims[] {static_cast(tracks.size())}; + hid_t dspace = H5Screate_simple(1, dims, nullptr); + hid_t dset = H5Dcreate(track_file, dset_name.c_str(), track_dtype, dspace, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + H5Dwrite(dset, track_dtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, tracks.data()); + + // Write attributes + write_attribute(dset, "n_particles", p.tracks().size()); + write_attribute(dset, "offsets", offsets); + write_attribute(dset, "particles", particles); + + // Free resources + H5Dclose(dset); + H5Sclose(dspace); } // Clear particle tracks diff --git a/src/universe.cpp b/src/universe.cpp new file mode 100644 index 00000000000..b4ef6b4b265 --- /dev/null +++ b/src/universe.cpp @@ -0,0 +1,217 @@ +#include "openmc/universe.h" + +#include + +#include "openmc/hdf5_interface.h" +#include "openmc/particle.h" + +namespace openmc { + +namespace model { + +std::unordered_map universe_map; +vector> universes; + +} // namespace model + +//============================================================================== +// Universe implementation +//============================================================================== + +void Universe::to_hdf5(hid_t universes_group) const +{ + // Create a group for this universe. + auto group = create_group(universes_group, fmt::format("universe {}", id_)); + + // Write the geometry representation type. + write_string(group, "geom_type", "csg", false); + + // Write the contained cells. + if (cells_.size() > 0) { + vector cell_ids; + for (auto i_cell : cells_) + cell_ids.push_back(model::cells[i_cell]->id_); + write_dataset(group, "cells", cell_ids); + } + + close_group(group); +} + +bool Universe::find_cell(GeometryState& p) const +{ + const auto& cells { + !partitioner_ ? cells_ : partitioner_->get_cells(p.r_local(), p.u_local())}; + + Position r {p.r_local()}; + Position u {p.u_local()}; + auto surf = p.surface(); + int32_t i_univ = p.lowest_coord().universe; + + for (auto i_cell : cells) { + if (model::cells[i_cell]->universe_ != i_univ) + continue; + // Check if this cell contains the particle + if (model::cells[i_cell]->contains(r, u, surf)) { + p.lowest_coord().cell = i_cell; + return true; + } + } + return false; +} + +BoundingBox Universe::bounding_box() const +{ + BoundingBox bbox = {INFTY, -INFTY, INFTY, -INFTY, INFTY, -INFTY}; + if (cells_.size() == 0) { + return {}; + } else { + for (const auto& cell : cells_) { + auto& c = model::cells[cell]; + bbox |= c->bounding_box(); + } + } + return bbox; +} + +//============================================================================== +// UniversePartitioner implementation +//============================================================================== + +UniversePartitioner::UniversePartitioner(const Universe& univ) +{ + // Define an ordered set of surface indices that point to z-planes. Use a + // functor to to order the set by the z0_ values of the corresponding planes. + struct compare_surfs { + bool operator()(const int32_t& i_surf, const int32_t& j_surf) const + { + const auto* surf = model::surfaces[i_surf].get(); + const auto* zplane = dynamic_cast(surf); + double zi = zplane->z0_; + surf = model::surfaces[j_surf].get(); + zplane = dynamic_cast(surf); + double zj = zplane->z0_; + return zi < zj; + } + }; + std::set surf_set; + + // Find all of the z-planes in this universe. A set is used here for the + // O(log(n)) insertions that will ensure entries are not repeated. + for (auto i_cell : univ.cells_) { + for (auto token : model::cells[i_cell]->surfaces()) { + auto i_surf = std::abs(token) - 1; + const auto* surf = model::surfaces[i_surf].get(); + if (const auto* zplane = dynamic_cast(surf)) + surf_set.insert(i_surf); + } + } + + // Populate the surfs_ vector from the ordered set. + surfs_.insert(surfs_.begin(), surf_set.begin(), surf_set.end()); + + // Populate the partition lists. + partitions_.resize(surfs_.size() + 1); + for (auto i_cell : univ.cells_) { + // It is difficult to determine the bounds of a complex cell, so add complex + // cells to all partitions. + if (!model::cells[i_cell]->is_simple()) { + for (auto& p : partitions_) + p.push_back(i_cell); + continue; + } + + // Find the tokens for bounding z-planes. + int32_t lower_token = 0, upper_token = 0; + double min_z, max_z; + for (auto token : model::cells[i_cell]->surfaces()) { + const auto* surf = model::surfaces[std::abs(token) - 1].get(); + if (const auto* zplane = dynamic_cast(surf)) { + if (lower_token == 0 || zplane->z0_ < min_z) { + lower_token = token; + min_z = zplane->z0_; + } + if (upper_token == 0 || zplane->z0_ > max_z) { + upper_token = token; + max_z = zplane->z0_; + } + } + } + + // If there are no bounding z-planes, add this cell to all partitions. + if (lower_token == 0) { + for (auto& p : partitions_) + p.push_back(i_cell); + continue; + } + + // Find the first partition this cell lies in. If the lower_token indicates + // a negative halfspace, then the cell is unbounded in the lower direction + // and it lies in the first partition onward. Otherwise, it is bounded by + // the positive halfspace given by the lower_token. + int first_partition = 0; + if (lower_token > 0) { + for (int i = 0; i < surfs_.size(); ++i) { + if (lower_token == surfs_[i] + 1) { + first_partition = i + 1; + break; + } + } + } + + // Find the last partition this cell lies in. The logic is analogous to the + // logic for first_partition. + int last_partition = surfs_.size(); + if (upper_token < 0) { + for (int i = first_partition; i < surfs_.size(); ++i) { + if (upper_token == -(surfs_[i] + 1)) { + last_partition = i; + break; + } + } + } + + // Add the cell to all relevant partitions. + for (int i = first_partition; i <= last_partition; ++i) { + partitions_[i].push_back(i_cell); + } + } +} + +const vector& UniversePartitioner::get_cells( + Position r, Direction u) const +{ + // Perform a binary search for the partition containing the given coordinates. + int left = 0; + int middle = (surfs_.size() - 1) / 2; + int right = surfs_.size() - 1; + while (true) { + // Check the sense of the coordinates for the current surface. + const auto& surf = *model::surfaces[surfs_[middle]]; + if (surf.sense(r, u)) { + // The coordinates lie in the positive halfspace. Recurse if there are + // more surfaces to check. Otherwise, return the cells on the positive + // side of this surface. + int right_leaf = right - (right - middle) / 2; + if (right_leaf != middle) { + left = middle + 1; + middle = right_leaf; + } else { + return partitions_[middle + 1]; + } + + } else { + // The coordinates lie in the negative halfspace. Recurse if there are + // more surfaces to check. Otherwise, return the cells on the negative + // side of this surface. + int left_leaf = left + (middle - left) / 2; + if (left_leaf != middle) { + right = middle - 1; + middle = left_leaf; + } else { + return partitions_[middle]; + } + } + } +} + +} // namespace openmc diff --git a/src/urr.cpp b/src/urr.cpp index 28ad2505f02..02cef228099 100644 --- a/src/urr.cpp +++ b/src/urr.cpp @@ -1,5 +1,6 @@ #include "openmc/urr.h" +#include // any_of #include namespace openmc { @@ -21,11 +22,62 @@ UrrData::UrrData(hid_t group_id) // read the energies at which tables exist read_dataset(group_id, "energy", energy_); - // Set n_energy_ - n_energy_ = energy_.shape()[0]; + // Read URR tables. The HDF5 format is a little + // different from how we want it laid out in memory. + // This array used to be called "prob_". + xt::xtensor tmp_prob; + read_dataset(group_id, "table", tmp_prob); + auto shape = tmp_prob.shape(); - // Read URR tables - read_dataset(group_id, "table", prob_); + // We separate out into two matrices (one with CDF values, + // the other with cross section sets) in order to improve + // contiguity of memory accesses. + const auto n_energy = shape[0]; + const auto n_cdf_values = shape[2]; + cdf_values_.resize({n_energy, n_cdf_values}); + xs_values_.resize({n_energy, n_cdf_values}); + + // Now fill in the values. Using manual loops here since we might + // not have fancy xtensor slicing code written for GPU tensors. + // The below enum gives how URR tables are laid out in our HDF5 tables. + enum class URRTableParam { + CUM_PROB, + TOTAL, + ELASTIC, + FISSION, + N_GAMMA, + HEATING + }; + for (int i_energy = 0; i_energy < n_energy; ++i_energy) { + for (int i_cdf = 0; i_cdf < n_cdf_values; ++i_cdf) { + cdf_values_(i_energy, i_cdf) = + tmp_prob(i_energy, URRTableParam::CUM_PROB, i_cdf); + xs_values_(i_energy, i_cdf).total = + tmp_prob(i_energy, URRTableParam::TOTAL, i_cdf); + xs_values_(i_energy, i_cdf).elastic = + tmp_prob(i_energy, URRTableParam::ELASTIC, i_cdf); + xs_values_(i_energy, i_cdf).fission = + tmp_prob(i_energy, URRTableParam::FISSION, i_cdf); + xs_values_(i_energy, i_cdf).n_gamma = + tmp_prob(i_energy, URRTableParam::N_GAMMA, i_cdf); + xs_values_(i_energy, i_cdf).heating = + tmp_prob(i_energy, URRTableParam::HEATING, i_cdf); + } + } +} + +bool UrrData::has_negative() const +{ + + // Lambda checks if any value in XSSset is negative + auto xs_set_negative = [](const XSSet& xs) { + return xs.total < 0.0 || xs.elastic < 0.0 || xs.fission < 0.0 || + xs.n_gamma < 0.0 || xs.heating < 0.0; + }; + + return std::any_of(cdf_values_.begin(), cdf_values_.end(), [](double x) { + return x < 0.0; + }) || std::any_of(xs_values_.begin(), xs_values_.end(), xs_set_negative); } -} \ No newline at end of file +} // namespace openmc diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 33c7883585e..8b5c27f14eb 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -8,22 +8,21 @@ #include "openmc/hdf5_interface.h" #include "openmc/material.h" #include "openmc/message_passing.h" +#include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" +#include "openmc/openmp_interface.h" #include "openmc/output.h" #include "openmc/random_lcg.h" #include "openmc/settings.h" #include "openmc/timer.h" #include "openmc/xml_interface.h" -#include -#ifdef _OPENMP -#include -#endif #include "xtensor/xadapt.hpp" #include "xtensor/xview.hpp" +#include #include // for copy -#include // for pow, sqrt +#include // for pow, sqrt #include namespace openmc { @@ -52,7 +51,8 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) domain_type_ = TallyDomain::UNIVERSE; } else { fatal_error(std::string("Unrecognized domain type for stochastic " - "volume calculation: " + domain_type)); + "volume calculation: " + + domain_type)); } // Read domain IDs, bounding corodinates and number of samples @@ -67,7 +67,8 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) threshold_ = std::stod(get_node_value(threshold_node, "threshold")); if (threshold_ <= 0.0) { fatal_error(fmt::format("Invalid error threshold {} provided for a " - "volume calculation.", threshold_)); + "volume calculation.", + threshold_)); } std::string tmp = get_node_value(threshold_node, "type"); @@ -75,66 +76,90 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) trigger_type_ = TriggerMetric::variance; } else if (tmp == "std_dev") { trigger_type_ = TriggerMetric::standard_deviation; - } else if ( tmp == "rel_err") { + } else if (tmp == "rel_err") { trigger_type_ = TriggerMetric::relative_error; } else { fatal_error(fmt::format( "Invalid volume calculation trigger type '{}' provided.", tmp)); } - } // Ensure there are no duplicates by copying elements to a set and then // comparing the length with the original vector std::unordered_set unique_ids(domain_ids_.cbegin(), domain_ids_.cend()); if (unique_ids.size() != domain_ids_.size()) { - throw std::runtime_error{"Domain IDs for a volume calculation " - "must be unique."}; + throw std::runtime_error {"Domain IDs for a volume calculation " + "must be unique."}; } - } vector VolumeCalculation::execute() const { + // Check to make sure domain IDs are valid + for (auto uid : domain_ids_) { + switch (domain_type_) { + case TallyDomain::CELL: + if (model::cell_map.find(uid) == model::cell_map.end()) { + throw std::runtime_error {fmt::format( + "Cell {} in volume calculation does not exist in geometry.", uid)}; + } + break; + case TallyDomain::MATERIAL: + if (model::material_map.find(uid) == model::material_map.end()) { + throw std::runtime_error {fmt::format( + "Material {} in volume calculation does not exist in geometry.", + uid)}; + } + break; + case TallyDomain::UNIVERSE: + if (model::universe_map.find(uid) == model::universe_map.end()) { + throw std::runtime_error {fmt::format( + "Universe {} in volume calculation does not exist in geometry.", + uid)}; + } + } + } + // Shared data that is collected from all threads int n = domain_ids_.size(); - vector> master_indices( + vector> master_indices( n); // List of material indices for each domain - vector> master_hits( + vector> master_hits( n); // Number of hits for each material in each domain int iterations = 0; // Divide work over MPI processes - size_t min_samples = n_samples_ / mpi::n_procs; - size_t remainder = n_samples_ % mpi::n_procs; - size_t i_start, i_end; + uint64_t min_samples = n_samples_ / mpi::n_procs; + uint64_t remainder = n_samples_ % mpi::n_procs; + uint64_t i_start, i_end; if (mpi::rank < remainder) { - i_start = (min_samples + 1)*mpi::rank; + i_start = (min_samples + 1) * mpi::rank; i_end = i_start + min_samples + 1; } else { - i_start = (min_samples + 1)*remainder + (mpi::rank - remainder)*min_samples; + i_start = + (min_samples + 1) * remainder + (mpi::rank - remainder) * min_samples; i_end = i_start + min_samples; } while (true) { - #pragma omp parallel +#pragma omp parallel { // Variables that are private to each thread - vector> indices(n); - vector> hits(n); + vector> indices(n); + vector> hits(n); Particle p; - // Sample locations and count hits - #pragma omp for +// Sample locations and count hits +#pragma omp for for (size_t i = i_start; i < i_end; i++) { - int64_t id = iterations * n_samples_ + i; + uint64_t id = iterations * n_samples_ + i; uint64_t seed = init_seed(id, STREAM_VOLUME); p.n_coord() = 1; Position xi {prn(&seed), prn(&seed), prn(&seed)}; - p.r() = lower_left_ + xi*(upper_right_ - lower_left_); - p.u() = {0.5, 0.5, 0.5}; + p.r() = lower_left_ + xi * (upper_right_ - lower_left_); + p.u() = {1. / std::sqrt(3.), 1. / std::sqrt(3.), 1. / std::sqrt(3.)}; // If this location is not in the geometry at all, move on to next block if (!exhaustive_find_cell(p)) @@ -153,7 +178,7 @@ vector VolumeCalculation::execute() const } } else if (domain_type_ == TallyDomain::CELL) { for (int level = 0; level < p.n_coord(); ++level) { - for (int i_domain=0; i_domain < n; i_domain++) { + for (int i_domain = 0; i_domain < n; i_domain++) { if (model::cells[p.coord(level).cell]->id_ == domain_ids_[i_domain]) { this->check_hit( @@ -175,39 +200,12 @@ vector VolumeCalculation::execute() const } } - // At this point, each thread has its own pair of index/hits lists and we now - // need to reduce them. OpenMP is not nearly smart enough to do this on its own, - // so we have to manually reduce them - - #ifdef _OPENMP - int n_threads = omp_get_num_threads(); - #else - int n_threads = 1; - #endif - - #pragma omp for ordered schedule(static) - for (int i = 0; i < n_threads; ++i) { - #pragma omp ordered - for (int i_domain = 0; i_domain < n; ++i_domain) { - for (int j = 0; j < indices[i_domain].size(); ++j) { - // Check if this material has been added to the master list and if so, - // accumulate the number of hits - bool already_added = false; - for (int k = 0; k < master_indices[i_domain].size(); k++) { - if (indices[i_domain][j] == master_indices[i_domain][k]) { - master_hits[i_domain][k] += hits[i_domain][j]; - already_added = true; - break; - } - } - if (!already_added) { - // If we made it here, the material hasn't yet been added to the master - // list, so add entries to the master indices and master hits lists - master_indices[i_domain].push_back(indices[i_domain][j]); - master_hits[i_domain].push_back(hits[i_domain][j]); - } - } - } + // At this point, each thread has its own pair of index/hits lists and we + // now need to reduce them. OpenMP is not nearly smart enough to do this + // on its own, so we have to manually reduce them + for (int i_domain = 0; i_domain < n; ++i_domain) { + reduce_indices_hits(indices[i_domain], hits[i_domain], + master_indices[i_domain], master_hits[i_domain]); } } // omp parallel @@ -215,12 +213,19 @@ vector VolumeCalculation::execute() const // Determine volume of bounding box Position d {upper_right_ - lower_left_}; - double volume_sample = d.x*d.y*d.z; + double volume_sample = d.x * d.y * d.z; // bump iteration counter and get total number // of samples at this point iterations++; - size_t total_samples = iterations * n_samples_; + uint64_t total_samples = iterations * n_samples_; + + // warn user if total sample size is greater than what the uin64_t type can + // represent + if (total_samples == std::numeric_limits::max()) { + warning("The number of samples has exceeded the type used to track hits. " + "Volume results may be inaccurate."); + } // reset double trigger_val = -INFTY; @@ -233,54 +238,62 @@ vector VolumeCalculation::execute() const auto& result {results[i_domain]}; // Create 2D array to store atoms/uncertainty for each nuclide. Later this - // is compressed into vectors storing only those nuclides that are non-zero - auto n_nuc = data::nuclides.size(); + // is compressed into vectors storing only those nuclides that are + // non-zero + auto n_nuc = + settings::run_CE ? data::nuclides.size() : data::mg.nuclides_.size(); xt::xtensor atoms({n_nuc, 2}, 0.0); #ifdef OPENMC_MPI if (mpi::master) { for (int j = 1; j < mpi::n_procs; j++) { int q; - MPI_Recv(&q, 1, MPI_INTEGER, j, 2*j, mpi::intracomm, MPI_STATUS_IGNORE); - vector buffer(2 * q); - MPI_Recv(buffer.data(), 2*q, MPI_INTEGER, j, 2*j + 1, mpi::intracomm, MPI_STATUS_IGNORE); + // retrieve results + MPI_Recv( + &q, 1, MPI_UINT64_T, j, 2 * j, mpi::intracomm, MPI_STATUS_IGNORE); + vector buffer(2 * q); + MPI_Recv(buffer.data(), 2 * q, MPI_UINT64_T, j, 2 * j + 1, + mpi::intracomm, MPI_STATUS_IGNORE); for (int k = 0; k < q; ++k) { bool already_added = false; for (int m = 0; m < master_indices[i_domain].size(); ++m) { - if (buffer[2*k] == master_indices[i_domain][m]) { - master_hits[i_domain][m] += buffer[2*k + 1]; + if (buffer[2 * k] == master_indices[i_domain][m]) { + master_hits[i_domain][m] += buffer[2 * k + 1]; already_added = true; break; } } if (!already_added) { - master_indices[i_domain].push_back(buffer[2*k]); - master_hits[i_domain].push_back(buffer[2*k + 1]); + master_indices[i_domain].push_back(buffer[2 * k]); + master_hits[i_domain].push_back(buffer[2 * k + 1]); } } } } else { int q = master_indices[i_domain].size(); - vector buffer(2 * q); + vector buffer(2 * q); for (int k = 0; k < q; ++k) { - buffer[2*k] = master_indices[i_domain][k]; - buffer[2*k + 1] = master_hits[i_domain][k]; + buffer[2 * k] = master_indices[i_domain][k]; + buffer[2 * k + 1] = master_hits[i_domain][k]; } - MPI_Send(&q, 1, MPI_INTEGER, 0, 2*mpi::rank, mpi::intracomm); - MPI_Send(buffer.data(), 2*q, MPI_INTEGER, 0, 2*mpi::rank + 1, mpi::intracomm); + MPI_Send(&q, 1, MPI_UINT64_T, 0, 2 * mpi::rank, mpi::intracomm); + MPI_Send(buffer.data(), 2 * q, MPI_UINT64_T, 0, 2 * mpi::rank + 1, + mpi::intracomm); } #endif if (mpi::master) { - int total_hits = 0; + size_t total_hits = 0; for (int j = 0; j < master_indices[i_domain].size(); ++j) { total_hits += master_hits[i_domain][j]; - double f = static_cast(master_hits[i_domain][j]) / total_samples; - double var_f = f*(1.0 - f) / total_samples; + double f = + static_cast(master_hits[i_domain][j]) / total_samples; + double var_f = f * (1.0 - f) / total_samples; int i_material = master_indices[i_domain][j]; - if (i_material == MATERIAL_VOID) continue; + if (i_material == MATERIAL_VOID) + continue; const auto& mat = model::materials[i_material]; for (int k = 0; k < mat->nuclide_.size(); ++k) { @@ -292,29 +305,34 @@ vector VolumeCalculation::execute() const } // Determine volume - result.volume[0] = static_cast(total_hits) / total_samples * volume_sample; - result.volume[1] = std::sqrt(result.volume[0] - * (volume_sample - result.volume[0]) / total_samples); + result.volume[0] = + static_cast(total_hits) / total_samples * volume_sample; + result.volume[1] = + std::sqrt(result.volume[0] * (volume_sample - result.volume[0]) / + total_samples); result.iterations = iterations; // update threshold value if needed if (trigger_type_ != TriggerMetric::not_active) { double val = 0.0; switch (trigger_type_) { - case TriggerMetric::standard_deviation: - val = result.volume[1]; - break; - case TriggerMetric::relative_error: - val = result.volume[0] == 0.0 ? INFTY : result.volume[1] / result.volume[0]; - break; - case TriggerMetric::variance: - val = result.volume[1] * result.volume[1]; - break; - default: - break; + case TriggerMetric::standard_deviation: + val = result.volume[1]; + break; + case TriggerMetric::relative_error: + val = result.volume[0] == 0.0 ? INFTY + : result.volume[1] / result.volume[0]; + break; + case TriggerMetric::variance: + val = result.volume[1] * result.volume[1]; + break; + default: + break; } // update max if entry is valid - if (val > 0.0) { trigger_val = std::max(trigger_val, val); } + if (val > 0.0) { + trigger_val = std::max(trigger_val, val); + } } for (int j = 0; j < n_nuc; ++j) { @@ -334,7 +352,9 @@ vector VolumeCalculation::execute() const } // end domain loop // if no trigger is applied, we're done - if (trigger_type_ == TriggerMetric::not_active) { return results; } + if (trigger_type_ == TriggerMetric::not_active) { + return results; + } #ifdef OPENMC_MPI // update maximum error value on all processes @@ -342,13 +362,20 @@ vector VolumeCalculation::execute() const #endif // return results of the calculation - if (trigger_val < threshold_) { return results; } + if (trigger_val < threshold_) { + return results; + } #ifdef OPENMC_MPI - // if iterating in an MPI run, need to zero indices and hits so they aren't counted twice + // if iterating in an MPI run, need to zero indices and hits so they aren't + // counted twice if (!mpi::master) { - for (auto& v : master_indices) { std::fill(v.begin(), v.end(), 0); } - for (auto& v : master_hits) { std::fill(v.begin(), v.end(), 0); } + for (auto& v : master_indices) { + std::fill(v.begin(), v.end(), 0); + } + for (auto& v : master_hits) { + std::fill(v.begin(), v.end(), 0); + } } #endif @@ -381,18 +408,18 @@ void VolumeCalculation::to_hdf5( write_attribute(file_id, "iterations", results[0].iterations); write_attribute(file_id, "threshold", threshold_); std::string trigger_str; - switch(trigger_type_) { - case TriggerMetric::variance: - trigger_str = "variance"; - break; - case TriggerMetric::standard_deviation: - trigger_str = "std_dev"; - break; - case TriggerMetric::relative_error: - trigger_str = "rel_err"; - break; - default: - break; + switch (trigger_type_) { + case TriggerMetric::variance: + trigger_str = "variance"; + break; + case TriggerMetric::standard_deviation: + trigger_str = "std_dev"; + break; + case TriggerMetric::relative_error: + trigger_str = "rel_err"; + break; + default: + break; } write_attribute(file_id, "trigger_type", trigger_str); } else { @@ -401,17 +428,15 @@ void VolumeCalculation::to_hdf5( if (domain_type_ == TallyDomain::CELL) { write_attribute(file_id, "domain_type", "cell"); - } - else if (domain_type_ == TallyDomain::MATERIAL) { + } else if (domain_type_ == TallyDomain::MATERIAL) { write_attribute(file_id, "domain_type", "material"); - } - else if (domain_type_ == TallyDomain::UNIVERSE) { + } else if (domain_type_ == TallyDomain::UNIVERSE) { write_attribute(file_id, "domain_type", "universe"); } - for (int i = 0; i < domain_ids_.size(); ++i) - { - hid_t group_id = create_group(file_id, fmt::format("domain_{}", domain_ids_[i])); + for (int i = 0; i < domain_ids_.size(); ++i) { + hid_t group_id = + create_group(file_id, fmt::format("domain_{}", domain_ids_[i])); // Write volume for domain const auto& result {results[i]}; @@ -422,7 +447,8 @@ void VolumeCalculation::to_hdf5( vector nucnames; for (int i_nuc : result.nuclides) { - nucnames.push_back(data::nuclides[i_nuc]->name_); + nucnames.push_back(settings::run_CE ? data::nuclides[i_nuc]->name_ + : data::mg.nuclides_[i_nuc].name); } // Create array of total # of atoms with uncertainty for each nuclide @@ -441,7 +467,7 @@ void VolumeCalculation::to_hdf5( } void VolumeCalculation::check_hit( - int i_material, vector& indices, vector& hits) const + int i_material, vector& indices, vector& hits) const { // Check if this material was previously hit and if so, increment count @@ -473,7 +499,8 @@ void free_memory_volume() // that the user has specified and writes results to HDF5 files //============================================================================== -int openmc_calculate_volumes() { +int openmc_calculate_volumes() +{ using namespace openmc; if (mpi::master) { @@ -483,17 +510,24 @@ int openmc_calculate_volumes() { time_volume.start(); for (int i = 0; i < model::volume_calcs.size(); ++i) { - write_message(4, "Running volume calculation {}", i+1); + write_message(4, "Running volume calculation {}", i + 1); // Run volume calculation const auto& vol_calc {model::volume_calcs[i]}; - auto results = vol_calc.execute(); + std::vector results; + try { + results = vol_calc.execute(); + } catch (const std::exception& e) { + set_errmsg(e.what()); + return OPENMC_E_UNASSIGNED; + } if (mpi::master) { std::string domain_type; if (vol_calc.domain_type_ == VolumeCalculation::TallyDomain::CELL) { domain_type = " Cell "; - } else if (vol_calc.domain_type_ == VolumeCalculation::TallyDomain::MATERIAL) { + } else if (vol_calc.domain_type_ == + VolumeCalculation::TallyDomain::MATERIAL) { domain_type = " Material "; } else { domain_type = " Universe "; @@ -501,16 +535,28 @@ int openmc_calculate_volumes() { // Display domain volumes for (int j = 0; j < vol_calc.domain_ids_.size(); j++) { - write_message(4, "{}{}: {} +/- {} cm^3", domain_type, - vol_calc.domain_ids_[j], results[j].volume[0], results[j].volume[1]); + std::string region_name {""}; + if (vol_calc.domain_type_ == VolumeCalculation::TallyDomain::CELL) { + int cell_idx = model::cell_map[vol_calc.domain_ids_[j]]; + region_name = model::cells[cell_idx]->name(); + } else if (vol_calc.domain_type_ == + VolumeCalculation::TallyDomain::MATERIAL) { + int mat_idx = model::material_map[vol_calc.domain_ids_[j]]; + region_name = model::materials[mat_idx]->name(); + } + if (region_name.size()) + region_name.insert(0, " "); // prepend space for formatting + + write_message(4, "{}{}{}: {} +/- {} cm^3", domain_type, + vol_calc.domain_ids_[j], region_name, results[j].volume[0], + results[j].volume[1]); } // Write volumes to HDF5 file - std::string filename = fmt::format("{}volume_{}.h5", - settings::path_output, i + 1); + std::string filename = + fmt::format("{}volume_{}.h5", settings::path_output, i + 1); vol_calc.to_hdf5(filename, results); } - } // Show elapsed time diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp new file mode 100644 index 00000000000..1ca83a2bd79 --- /dev/null +++ b/src/weight_windows.cpp @@ -0,0 +1,1231 @@ +#include "openmc/weight_windows.h" + +#include +#include +#include +#include + +#include "xtensor/xindex_view.hpp" +#include "xtensor/xio.hpp" +#include "xtensor/xmasked_view.hpp" +#include "xtensor/xnoalias.hpp" +#include "xtensor/xstrided_view.hpp" +#include "xtensor/xview.hpp" + +#include "openmc/error.h" +#include "openmc/file_utils.h" +#include "openmc/hdf5_interface.h" +#include "openmc/mesh.h" +#include "openmc/message_passing.h" +#include "openmc/nuclide.h" +#include "openmc/output.h" +#include "openmc/particle.h" +#include "openmc/particle_data.h" +#include "openmc/physics_common.h" +#include "openmc/search.h" +#include "openmc/settings.h" +#include "openmc/tallies/filter_energy.h" +#include "openmc/tallies/filter_mesh.h" +#include "openmc/tallies/filter_particle.h" +#include "openmc/tallies/tally.h" +#include "openmc/xml_interface.h" + +#include +#include + +namespace openmc { + +//============================================================================== +// Global variables +//============================================================================== + +namespace variance_reduction { + +std::unordered_map ww_map; +openmc::vector> weight_windows; +openmc::vector> weight_windows_generators; + +} // namespace variance_reduction + +//============================================================================== +// Non-member functions +//============================================================================== + +void apply_weight_windows(Particle& p) +{ + if (!settings::weight_windows_on) + return; + + // WW on photon and neutron only + if (p.type() != ParticleType::neutron && p.type() != ParticleType::photon) + return; + + // skip dead or no energy + if (p.E() <= 0 || !p.alive()) + return; + + bool in_domain = false; + // TODO: this is a linear search - should do something more clever + WeightWindow weight_window; + for (const auto& ww : variance_reduction::weight_windows) { + weight_window = ww->get_weight_window(p); + if (weight_window.is_valid()) + break; + } + // particle is not in any of the ww domains, do nothing + if (!weight_window.is_valid()) + return; + + // get the paramters + double weight = p.wgt(); + + // first check to see if particle should be killed for weight cutoff + if (p.wgt() < weight_window.weight_cutoff) { + p.wgt() = 0.0; + return; + } + + // check if particle is far above current weight window + // only do this if the factor is not already set on the particle and a + // maximum lower bound ratio is specified + if (p.ww_factor() == 0.0 && weight_window.max_lb_ratio > 1.0 && + p.wgt() > weight_window.lower_weight * weight_window.max_lb_ratio) { + p.ww_factor() = + p.wgt() / (weight_window.lower_weight * weight_window.max_lb_ratio); + } + + // move weight window closer to the particle weight if needed + if (p.ww_factor() > 1.0) + weight_window.scale(p.ww_factor()); + + // if particle's weight is above the weight window split until they are within + // the window + if (weight > weight_window.upper_weight) { + // do not further split the particle if above the limit + if (p.n_split() >= settings::max_splits) + return; + + double n_split = std::ceil(weight / weight_window.upper_weight); + double max_split = weight_window.max_split; + n_split = std::min(n_split, max_split); + + p.n_split() += n_split; + + // Create secondaries and divide weight among all particles + int i_split = std::round(n_split); + for (int l = 0; l < i_split - 1; l++) { + p.create_secondary(weight / n_split, p.u(), p.E(), p.type()); + } + // remaining weight is applied to current particle + p.wgt() = weight / n_split; + + } else if (weight <= weight_window.lower_weight) { + // if the particle weight is below the window, play Russian roulette + double weight_survive = + std::min(weight * weight_window.max_split, weight_window.survival_weight); + russian_roulette(p, weight_survive); + } // else particle is in the window, continue as normal +} + +void free_memory_weight_windows() +{ + variance_reduction::ww_map.clear(); + variance_reduction::weight_windows.clear(); +} + +//============================================================================== +// WeightWindowSettings implementation +//============================================================================== + +WeightWindows::WeightWindows(int32_t id) +{ + index_ = variance_reduction::weight_windows.size(); + set_id(id); + set_defaults(); +} + +WeightWindows::WeightWindows(pugi::xml_node node) +{ + // Make sure required elements are present + const vector required_elems {"id", "particle_type", + "energy_bounds", "lower_ww_bounds", "upper_ww_bounds"}; + for (const auto& elem : required_elems) { + if (!check_for_node(node, elem.c_str())) { + fatal_error(fmt::format("Must specify <{}> for weight windows.", elem)); + } + } + + // Get weight windows ID + int32_t id = std::stoi(get_node_value(node, "id")); + this->set_id(id); + + // get the particle type + auto particle_type_str = std::string(get_node_value(node, "particle_type")); + particle_type_ = openmc::str_to_particle_type(particle_type_str); + + // Determine associated mesh + int32_t mesh_id = std::stoi(get_node_value(node, "mesh")); + mesh_idx_ = model::mesh_map.at(mesh_id); + + // energy bounds + if (check_for_node(node, "energy_bounds")) + energy_bounds_ = get_node_array(node, "energy_bounds"); + + // get the survival value - optional + if (check_for_node(node, "survival_ratio")) { + survival_ratio_ = std::stod(get_node_value(node, "survival_ratio")); + if (survival_ratio_ <= 1) + fatal_error("Survival to lower weight window ratio must bigger than 1 " + "and less than the upper to lower weight window ratio."); + } + + // get the max lower bound ratio - optional + if (check_for_node(node, "max_lower_bound_ratio")) { + max_lb_ratio_ = std::stod(get_node_value(node, "max_lower_bound_ratio")); + if (max_lb_ratio_ < 1.0) { + fatal_error("Maximum lower bound ratio must be larger than 1"); + } + } + + // get the max split - optional + if (check_for_node(node, "max_split")) { + max_split_ = std::stod(get_node_value(node, "max_split")); + if (max_split_ <= 1) + fatal_error("max split must be larger than 1"); + } + + // weight cutoff - optional + if (check_for_node(node, "weight_cutoff")) { + weight_cutoff_ = std::stod(get_node_value(node, "weight_cutoff")); + if (weight_cutoff_ <= 0) + fatal_error("weight_cutoff must be larger than 0"); + if (weight_cutoff_ > 1) + fatal_error("weight_cutoff must be less than 1"); + } + + // read the lower/upper weight bounds + this->set_bounds(get_node_array(node, "lower_ww_bounds"), + get_node_array(node, "upper_ww_bounds")); + + set_defaults(); +} + +WeightWindows::~WeightWindows() +{ + variance_reduction::ww_map.erase(id()); +} + +WeightWindows* WeightWindows::create(int32_t id) +{ + variance_reduction::weight_windows.push_back(make_unique()); + auto wws = variance_reduction::weight_windows.back().get(); + variance_reduction::ww_map[wws->id()] = + variance_reduction::weight_windows.size() - 1; + return wws; +} + +WeightWindows* WeightWindows::from_hdf5( + hid_t wws_group, const std::string& group_name) +{ + // collect ID from the name of this group + hid_t ww_group = open_group(wws_group, group_name); + + auto wws = WeightWindows::create(); + + std::string particle_type; + read_dataset(ww_group, "particle_type", particle_type); + wws->particle_type_ = openmc::str_to_particle_type(particle_type); + + read_dataset(ww_group, "energy_bounds", wws->energy_bounds_); + + int32_t mesh_id; + read_dataset(ww_group, "mesh", mesh_id); + + if (model::mesh_map.count(mesh_id) == 0) { + fatal_error( + fmt::format("Mesh {} used in weight windows does not exist.", mesh_id)); + } + wws->set_mesh(model::mesh_map[mesh_id]); + + wws->lower_ww_ = xt::empty(wws->bounds_size()); + wws->upper_ww_ = xt::empty(wws->bounds_size()); + + read_dataset(ww_group, "lower_ww_bounds", wws->lower_ww_); + read_dataset(ww_group, "upper_ww_bounds", wws->upper_ww_); + read_dataset(ww_group, "survival_ratio", wws->survival_ratio_); + read_dataset(ww_group, "max_lower_bound_ratio", wws->max_lb_ratio_); + read_dataset(ww_group, "max_split", wws->max_split_); + read_dataset(ww_group, "weight_cutoff", wws->weight_cutoff_); + + close_group(ww_group); + + return wws; +} + +void WeightWindows::set_defaults() +{ + // set energy bounds to the min/max energy supported by the data + if (energy_bounds_.size() == 0) { + int p_type = static_cast(particle_type_); + energy_bounds_.push_back(data::energy_min[p_type]); + energy_bounds_.push_back(data::energy_max[p_type]); + } +} + +void WeightWindows::allocate_ww_bounds() +{ + auto shape = bounds_size(); + if (shape[0] * shape[1] == 0) { + auto msg = fmt::format( + "Size of weight window bounds is zero for WeightWindows {}", id()); + warning(msg); + } + lower_ww_ = xt::empty(shape); + lower_ww_.fill(-1); + upper_ww_ = xt::empty(shape); + upper_ww_.fill(-1); +} + +void WeightWindows::set_id(int32_t id) +{ + Expects(id >= 0 || id == C_NONE); + + // Clear entry in mesh map in case one was already assigned + if (id_ != C_NONE) { + variance_reduction::ww_map.erase(id_); + id_ = C_NONE; + } + + // Ensure no other mesh has the same ID + if (variance_reduction::ww_map.find(id) != variance_reduction::ww_map.end()) { + throw std::runtime_error { + fmt::format("Two weight windows have the same ID: {}", id)}; + } + + // If no ID is specified, auto-assign the next ID in the sequence + if (id == C_NONE) { + id = 0; + for (const auto& m : variance_reduction::weight_windows) { + id = std::max(id, m->id_); + } + ++id; + } + + // Update ID and entry in the mesh map + id_ = id; + variance_reduction::ww_map[id] = index_; +} + +void WeightWindows::set_energy_bounds(gsl::span bounds) +{ + energy_bounds_.clear(); + energy_bounds_.insert(energy_bounds_.begin(), bounds.begin(), bounds.end()); + // if the mesh is set, allocate space for weight window bounds + if (mesh_idx_ != C_NONE) + allocate_ww_bounds(); +} + +void WeightWindows::set_particle_type(ParticleType p_type) +{ + if (p_type != ParticleType::neutron && p_type != ParticleType::photon) + fatal_error( + fmt::format("Particle type '{}' cannot be applied to weight windows.", + particle_type_to_str(p_type))); + particle_type_ = p_type; +} + +void WeightWindows::set_mesh(int32_t mesh_idx) +{ + if (mesh_idx < 0 || mesh_idx >= model::meshes.size()) + fatal_error(fmt::format("Could not find a mesh for index {}", mesh_idx)); + + mesh_idx_ = mesh_idx; + allocate_ww_bounds(); +} + +void WeightWindows::set_mesh(const std::unique_ptr& mesh) +{ + set_mesh(mesh.get()); +} + +void WeightWindows::set_mesh(const Mesh* mesh) +{ + set_mesh(model::mesh_map[mesh->id_]); +} + +WeightWindow WeightWindows::get_weight_window(const Particle& p) const +{ + // check for particle type + if (particle_type_ != p.type()) { + return {}; + } + + // Get mesh index for particle's position + const auto& mesh = this->mesh(); + int mesh_bin = mesh->get_bin(p.r()); + + // particle is outside the weight window mesh + if (mesh_bin < 0) + return {}; + + // particle energy + double E = p.E(); + + // check to make sure energy is in range, expects sorted energy values + if (E < energy_bounds_.front() || E > energy_bounds_.back()) + return {}; + + // get the mesh bin in energy group + int energy_bin = + lower_bound_index(energy_bounds_.begin(), energy_bounds_.end(), E); + + // mesh_bin += energy_bin * mesh->n_bins(); + // Create individual weight window + WeightWindow ww; + ww.lower_weight = lower_ww_(energy_bin, mesh_bin); + ww.upper_weight = upper_ww_(energy_bin, mesh_bin); + ww.survival_weight = ww.lower_weight * survival_ratio_; + ww.max_lb_ratio = max_lb_ratio_; + ww.max_split = max_split_; + ww.weight_cutoff = weight_cutoff_; + return ww; +} + +std::array WeightWindows::bounds_size() const +{ + int num_spatial_bins = this->mesh()->n_bins(); + int num_energy_bins = + energy_bounds_.size() > 0 ? energy_bounds_.size() - 1 : 1; + return {num_energy_bins, num_spatial_bins}; +} + +template +void WeightWindows::check_bounds(const T& lower, const T& upper) const +{ + // make sure that the upper and lower bounds have the same size + if (lower.size() != upper.size()) { + auto msg = fmt::format("The upper and lower weight window lengths do not " + "match.\n Lower size: {}\n Upper size: {}", + lower.size(), upper.size()); + fatal_error(msg); + } + this->check_bounds(lower); +} + +template +void WeightWindows::check_bounds(const T& bounds) const +{ + // check that the number of weight window entries is correct + auto dims = this->bounds_size(); + if (bounds.size() != dims[0] * dims[1]) { + auto err_msg = + fmt::format("In weight window domain {} the number of spatial " + "energy/spatial bins ({}) does not match the number " + "of weight bins ({})", + id_, dims, bounds.size()); + fatal_error(err_msg); + } +} + +void WeightWindows::set_bounds(const xt::xtensor& lower_bounds, + const xt::xtensor& upper_bounds) +{ + + this->check_bounds(lower_bounds, upper_bounds); + + // set new weight window values + lower_ww_ = lower_bounds; + upper_ww_ = upper_bounds; +} + +void WeightWindows::set_bounds( + const xt::xtensor& lower_bounds, double ratio) +{ + this->check_bounds(lower_bounds); + + // set new weight window values + lower_ww_ = lower_bounds; + upper_ww_ = lower_bounds; + upper_ww_ *= ratio; +} + +void WeightWindows::set_bounds( + gsl::span lower_bounds, gsl::span upper_bounds) +{ + check_bounds(lower_bounds, upper_bounds); + auto shape = this->bounds_size(); + lower_ww_ = xt::empty(shape); + upper_ww_ = xt::empty(shape); + + // set new weight window values + xt::view(lower_ww_, xt::all()) = + xt::adapt(lower_bounds.data(), lower_ww_.shape()); + xt::view(upper_ww_, xt::all()) = + xt::adapt(upper_bounds.data(), upper_ww_.shape()); +} + +void WeightWindows::set_bounds( + gsl::span lower_bounds, double ratio) +{ + this->check_bounds(lower_bounds); + + auto shape = this->bounds_size(); + lower_ww_ = xt::empty(shape); + upper_ww_ = xt::empty(shape); + + // set new weight window values + xt::view(lower_ww_, xt::all()) = + xt::adapt(lower_bounds.data(), lower_ww_.shape()); + xt::view(upper_ww_, xt::all()) = + xt::adapt(lower_bounds.data(), upper_ww_.shape()); + upper_ww_ *= ratio; +} + +void WeightWindows::update_magic( + const Tally* tally, const std::string& value, double threshold, double ratio) +{ + /////////////////////////// + // Setup and checks + /////////////////////////// + this->check_tally_update_compatibility(tally); + + lower_ww_.fill(-1); + upper_ww_.fill(-1); + + // determine which value to use + const std::set allowed_values = {"mean", "rel_err"}; + if (allowed_values.count(value) == 0) { + fatal_error(fmt::format("Invalid value '{}' specified for weight window " + "generation. Must be one of: 'mean' or 'rel_err'", + value)); + } + + // determine the index of the specified score + int score_index = tally->score_index("flux"); + if (score_index == C_NONE) { + fatal_error( + fmt::format("A 'flux' score required for weight window generation " + "is not present on tally {}.", + tally->id())); + } + + /////////////////////////// + // Extract tally data + // + // At the end of this section, the mean and rel_err array + // is a 2D view of tally data (n_e_groups, n_mesh_bins) + // + /////////////////////////// + + // build a shape for a view of the tally results, this will always be + // dimension 5 (3 filter dimensions, 1 score dimension, 1 results dimension) + std::array shape = { + 1, 1, 1, tally->n_scores(), static_cast(TallyResult::SIZE)}; + + // set the shape for the filters applied on the tally + for (int i = 0; i < tally->filters().size(); i++) { + const auto& filter = model::tally_filters[tally->filters(i)]; + shape[i] = filter->n_bins(); + } + + // build the transpose information to re-order data according to filter type + std::array transpose = {0, 1, 2, 3, 4}; + + // track our filter types and where we've added new ones + std::vector filter_types = tally->filter_types(); + + // assign other filter types to dummy positions if needed + if (!tally->has_filter(FilterType::PARTICLE)) + filter_types.push_back(FilterType::PARTICLE); + + if (!tally->has_filter(FilterType::ENERGY)) + filter_types.push_back(FilterType::ENERGY); + + // particle axis mapping + transpose[0] = + std::find(filter_types.begin(), filter_types.end(), FilterType::PARTICLE) - + filter_types.begin(); + + // energy axis mapping + transpose[1] = + std::find(filter_types.begin(), filter_types.end(), FilterType::ENERGY) - + filter_types.begin(); + + // mesh axis mapping + transpose[2] = + std::find(filter_types.begin(), filter_types.end(), FilterType::MESH) - + filter_types.begin(); + + // get a fully reshaped view of the tally according to tally ordering of + // filters + auto tally_values = xt::reshape_view(tally->results(), shape); + + // get a that is (particle, energy, mesh, scores, values) + auto transposed_view = xt::transpose(tally_values, transpose); + + // determine the dimension and index of the particle data + int particle_idx = 0; + if (tally->has_filter(FilterType::PARTICLE)) { + // get the particle filter + auto pf = tally->get_filter(); + const auto& particles = pf->particles(); + + // find the index of the particle that matches these weight windows + auto p_it = + std::find(particles.begin(), particles.end(), this->particle_type_); + // if the particle filter doesn't have particle data for the particle + // used on this weight windows instance, report an error + if (p_it == particles.end()) { + auto msg = fmt::format("Particle type '{}' not present on Filter {} for " + "Tally {} used to update WeightWindows {}", + particle_type_to_str(this->particle_type_), pf->id(), tally->id(), + this->id()); + fatal_error(msg); + } + + // use the index of the particle in the filter to down-select data later + particle_idx = p_it - particles.begin(); + } + + // down-select data based on particle and score + auto sum = xt::view(transposed_view, particle_idx, xt::all(), xt::all(), + score_index, static_cast(TallyResult::SUM)); + auto sum_sq = xt::view(transposed_view, particle_idx, xt::all(), xt::all(), + score_index, static_cast(TallyResult::SUM_SQ)); + int n = tally->n_realizations_; + + ////////////////////////////////////////////// + // + // Assign new weight windows + // + // Use references to the existing weight window data + // to store and update the values + // + ////////////////////////////////////////////// + + // up to this point the data arrays are views into the tally results (no + // computation has been performed) now we'll switch references to the tally's + // bounds to avoid allocating additional memory + auto& new_bounds = this->lower_ww_; + auto& rel_err = this->upper_ww_; + + // noalias avoids memory allocation here + xt::noalias(new_bounds) = sum / n; + + xt::noalias(rel_err) = + xt::sqrt(((sum_sq / n) - xt::square(new_bounds)) / (n - 1)) / new_bounds; + xt::filter(rel_err, sum <= 0.0).fill(INFTY); + + if (value == "rel_err") + xt::noalias(new_bounds) = 1 / rel_err; + + // get mesh volumes + auto mesh_vols = this->mesh()->volumes(); + + int e_bins = new_bounds.shape()[0]; + for (int e = 0; e < e_bins; e++) { + // select all + auto group_view = xt::view(new_bounds, e); + + // divide by volume of mesh elements + for (int i = 0; i < group_view.size(); i++) { + group_view[i] /= mesh_vols[i]; + } + + double group_max = *std::max_element(group_view.begin(), group_view.end()); + // normalize values in this energy group by the maximum value for this + // group + if (group_max > 0.0) + group_view /= 2.0 * group_max; + } + + // make sure that values where the mean is zero are set s.t. the weight window + // value will be ignored + xt::filter(new_bounds, sum <= 0.0).fill(-1.0); + + // make sure the weight windows are ignored for any locations where the + // relative error is higher than the specified relative error threshold + xt::filter(new_bounds, rel_err > threshold).fill(-1.0); + + // update the bounds of this weight window class + // noalias avoids additional memory allocation + xt::noalias(upper_ww_) = ratio * lower_ww_; +} + +void WeightWindows::check_tally_update_compatibility(const Tally* tally) +{ + // define the set of allowed filters for the tally + const std::set allowed_filters = { + FilterType::MESH, FilterType::ENERGY, FilterType::PARTICLE}; + + // retrieve a mapping of filter type to filter index for the tally + auto filter_indices = tally->filter_indices(); + + // a mesh filter is required for a tally used to update weight windows + if (!filter_indices.count(FilterType::MESH)) { + fatal_error( + "A mesh filter is required for a tally to update weight window bounds"); + } + + // ensure the mesh filter is using the same mesh as this weight window object + auto mesh_filter = tally->get_filter(); + + // make sure that all of the filters present on the tally are allowed + for (auto filter_pair : filter_indices) { + if (allowed_filters.find(filter_pair.first) == allowed_filters.end()) { + fatal_error(fmt::format("Invalid filter type '{}' found on tally " + "used for weight window generation.", + model::tally_filters[tally->filters(filter_pair.second)]->type_str())); + } + } + + if (mesh_filter->mesh() != mesh_idx_) { + int32_t mesh_filter_id = model::meshes[mesh_filter->mesh()]->id(); + int32_t ww_mesh_id = model::meshes[this->mesh_idx_]->id(); + fatal_error(fmt::format("Mesh filter {} uses a different mesh ({}) than " + "weight window {} mesh ({})", + mesh_filter->id(), mesh_filter_id, id_, ww_mesh_id)); + } + + // if an energy filter exists, make sure the energy grid matches that of this + // weight window object + if (auto energy_filter = tally->get_filter()) { + std::vector filter_bins = energy_filter->bins(); + std::set filter_e_bounds( + energy_filter->bins().begin(), energy_filter->bins().end()); + if (filter_e_bounds.size() != energy_bounds().size()) { + fatal_error( + fmt::format("Energy filter {} does not have the same number of energy " + "bounds ({}) as weight window object {} ({})", + energy_filter->id(), filter_e_bounds.size(), id_, + energy_bounds().size())); + } + + for (auto e : energy_bounds()) { + if (filter_e_bounds.count(e) == 0) { + fatal_error(fmt::format( + "Energy bounds of filter {} and weight windows {} do not match", + energy_filter->id(), id_)); + } + } + } +} + +void WeightWindows::to_hdf5(hid_t group) const +{ + hid_t ww_group = create_group(group, fmt::format("weight_windows_{}", id())); + + write_dataset(ww_group, "mesh", this->mesh()->id()); + write_dataset( + ww_group, "particle_type", openmc::particle_type_to_str(particle_type_)); + write_dataset(ww_group, "energy_bounds", energy_bounds_); + write_dataset(ww_group, "lower_ww_bounds", lower_ww_); + write_dataset(ww_group, "upper_ww_bounds", upper_ww_); + write_dataset(ww_group, "survival_ratio", survival_ratio_); + write_dataset(ww_group, "max_lower_bound_ratio", max_lb_ratio_); + write_dataset(ww_group, "max_split", max_split_); + write_dataset(ww_group, "weight_cutoff", weight_cutoff_); + + close_group(ww_group); +} + +WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) +{ + // read information from the XML node + int32_t mesh_id = std::stoi(get_node_value(node, "mesh")); + int32_t mesh_idx = model::mesh_map[mesh_id]; + max_realizations_ = std::stoi(get_node_value(node, "max_realizations")); + + int active_batches = settings::n_batches - settings::n_inactive; + if (max_realizations_ > active_batches) { + auto msg = + fmt::format("The maximum number of specified tally realizations ({}) is " + "greater than the number of active batches ({}).", + max_realizations_, active_batches); + warning(msg); + } + auto tmp_str = get_node_value(node, "particle_type", true, true); + auto particle_type = str_to_particle_type(tmp_str); + + update_interval_ = std::stoi(get_node_value(node, "update_interval")); + on_the_fly_ = get_node_value_bool(node, "on_the_fly"); + + std::vector e_bounds; + if (check_for_node(node, "energy_bounds")) { + e_bounds = get_node_array(node, "energy_bounds"); + } else { + int p_type = static_cast(particle_type); + e_bounds.push_back(data::energy_min[p_type]); + e_bounds.push_back(data::energy_max[p_type]); + } + + // set method and parameters for updates + method_ = get_node_value(node, "method"); + if (method_ == "magic") { + // parse non-default update parameters if specified + if (check_for_node(node, "update_parameters")) { + pugi::xml_node params_node = node.child("update_parameters"); + if (check_for_node(params_node, "value")) + tally_value_ = get_node_value(params_node, "value"); + if (check_for_node(params_node, "threshold")) + threshold_ = std::stod(get_node_value(params_node, "threshold")); + if (check_for_node(params_node, "ratio")) { + ratio_ = std::stod(get_node_value(params_node, "ratio")); + } + } + // check update parameter values + if (tally_value_ != "mean" && tally_value_ != "rel_err") { + fatal_error(fmt::format("Unsupported tally value '{}' specified for " + "weight window generation.", + tally_value_)); + } + if (threshold_ <= 0.0) + fatal_error(fmt::format("Invalid relative error threshold '{}' (<= 0.0) " + "specified for weight window generation", + ratio_)); + if (ratio_ <= 1.0) + fatal_error(fmt::format("Invalid weight window ratio '{}' (<= 1.0) " + "specified for weight window generation")); + } else { + fatal_error(fmt::format( + "Unknown weight window update method '{}' specified", method_)); + } + + // create a matching weight windows object + auto wws = WeightWindows::create(); + ww_idx_ = wws->index(); + wws->set_mesh(mesh_idx); + if (e_bounds.size() > 0) + wws->set_energy_bounds(e_bounds); + wws->set_particle_type(particle_type); + wws->set_defaults(); +} + +void WeightWindowsGenerator::create_tally() +{ + const auto& wws = variance_reduction::weight_windows[ww_idx_]; + + // create a tally based on the WWG information + Tally* ww_tally = Tally::create(); + tally_idx_ = model::tally_map[ww_tally->id()]; + ww_tally->set_scores({"flux"}); + + int32_t mesh_id = wws->mesh()->id(); + int32_t mesh_idx = model::mesh_map.at(mesh_id); + // see if there's already a mesh filter using this mesh + bool found_mesh_filter = false; + for (const auto& f : model::tally_filters) { + if (f->type() == FilterType::MESH) { + const auto* mesh_filter = dynamic_cast(f.get()); + if (mesh_filter->mesh() == mesh_idx && !mesh_filter->translated()) { + ww_tally->add_filter(f.get()); + found_mesh_filter = true; + break; + } + } + } + + if (!found_mesh_filter) { + auto mesh_filter = Filter::create("mesh"); + openmc_mesh_filter_set_mesh(mesh_filter->index(), model::mesh_map[mesh_id]); + ww_tally->add_filter(mesh_filter); + } + + const auto& e_bounds = wws->energy_bounds(); + if (e_bounds.size() > 0) { + auto energy_filter = Filter::create("energy"); + openmc_energy_filter_set_bins( + energy_filter->index(), e_bounds.size(), e_bounds.data()); + ww_tally->add_filter(energy_filter); + } + + // add a particle filter + auto particle_type = wws->particle_type(); + auto particle_filter = Filter::create("particle"); + auto pf = dynamic_cast(particle_filter); + pf->set_particles({&particle_type, 1}); + ww_tally->add_filter(particle_filter); +} + +void WeightWindowsGenerator::update() const +{ + const auto& wws = variance_reduction::weight_windows[ww_idx_]; + + Tally* tally = model::tallies[tally_idx_].get(); + + // if we're beyond the number of max realizations or not at the corrrect + // update interval, skip the update + if (max_realizations_ < tally->n_realizations_ || + tally->n_realizations_ % update_interval_ != 0) + return; + + wws->update_magic(tally, tally_value_, threshold_, ratio_); + + // if we're not doing on the fly generation, reset the tally results once + // we're done with the update + if (!on_the_fly_) + tally->reset(); + + // TODO: deactivate or remove tally once weight window generation is + // complete +} + +//============================================================================== +// Non-member functions +//============================================================================== + +void finalize_variance_reduction() +{ + for (const auto& wwg : variance_reduction::weight_windows_generators) { + wwg->create_tally(); + } +} + +//============================================================================== +// C API +//============================================================================== + +int verify_ww_index(int32_t index) +{ + if (index < 0 || index >= variance_reduction::weight_windows.size()) { + set_errmsg(fmt::format("Index '{}' for weight windows is invalid", index)); + return OPENMC_E_OUT_OF_BOUNDS; + } + return 0; +} + +extern "C" int openmc_get_weight_windows_index(int32_t id, int32_t* idx) +{ + auto it = variance_reduction::ww_map.find(id); + if (it == variance_reduction::ww_map.end()) { + set_errmsg(fmt::format("No weight windows exist with ID={}", id)); + return OPENMC_E_INVALID_ID; + } + + *idx = it->second; + return 0; +} + +extern "C" int openmc_weight_windows_get_id(int32_t index, int32_t* id) +{ + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows.at(index); + *id = wws->id(); + return 0; +} + +extern "C" int openmc_weight_windows_set_id(int32_t index, int32_t id) +{ + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows.at(index); + wws->set_id(id); + return 0; +} + +extern "C" int openmc_weight_windows_update_magic(int32_t ww_idx, + int32_t tally_idx, const char* value, double threshold, double ratio) +{ + if (int err = verify_ww_index(ww_idx)) + return err; + + if (tally_idx < 0 || tally_idx >= model::tallies.size()) { + set_errmsg(fmt::format("Index '{}' for tally is invalid", tally_idx)); + return OPENMC_E_OUT_OF_BOUNDS; + } + + // get the requested tally + const Tally* tally = model::tallies.at(tally_idx).get(); + + // get the WeightWindows object + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + + wws->update_magic(tally, value, threshold, ratio); + + return 0; +} + +extern "C" int openmc_weight_windows_set_mesh(int32_t ww_idx, int32_t mesh_idx) +{ + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + wws->set_mesh(mesh_idx); + return 0; +} + +extern "C" int openmc_weight_windows_get_mesh(int32_t ww_idx, int32_t* mesh_idx) +{ + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + *mesh_idx = model::mesh_map.at(wws->mesh()->id()); + return 0; +} + +extern "C" int openmc_weight_windows_set_energy_bounds( + int32_t ww_idx, double* e_bounds, size_t e_bounds_size) +{ + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + wws->set_energy_bounds({e_bounds, e_bounds_size}); + return 0; +} + +extern "C" int openmc_weight_windows_get_energy_bounds( + int32_t ww_idx, const double** e_bounds, size_t* e_bounds_size) +{ + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows[ww_idx].get(); + *e_bounds = wws->energy_bounds().data(); + *e_bounds_size = wws->energy_bounds().size(); + return 0; +} + +extern "C" int openmc_weight_windows_set_particle(int32_t index, int particle) +{ + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows.at(index); + wws->set_particle_type(static_cast(particle)); + return 0; +} + +extern "C" int openmc_weight_windows_get_particle(int32_t index, int* particle) +{ + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows.at(index); + *particle = static_cast(wws->particle_type()); + return 0; +} + +extern "C" int openmc_weight_windows_get_bounds(int32_t index, + const double** lower_bounds, const double** upper_bounds, size_t* size) +{ + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows[index]; + *size = wws->lower_ww_bounds().size(); + *lower_bounds = wws->lower_ww_bounds().data(); + *upper_bounds = wws->upper_ww_bounds().data(); + return 0; +} + +extern "C" int openmc_weight_windows_set_bounds(int32_t index, + const double* lower_bounds, const double* upper_bounds, size_t size) +{ + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows[index]; + wws->set_bounds({lower_bounds, size}, {upper_bounds, size}); + return 0; +} + +extern "C" int openmc_weight_windows_get_survival_ratio( + int32_t index, double* ratio) +{ + if (int err = verify_ww_index(index)) + return err; + const auto& wws = variance_reduction::weight_windows[index]; + *ratio = wws->survival_ratio(); + return 0; +} + +extern "C" int openmc_weight_windows_set_survival_ratio( + int32_t index, double ratio) +{ + if (int err = verify_ww_index(index)) + return err; + const auto& wws = variance_reduction::weight_windows[index]; + wws->survival_ratio() = ratio; + std::cout << "Survival ratio: " << wws->survival_ratio() << std::endl; + return 0; +} + +extern "C" int openmc_weight_windows_get_max_lower_bound_ratio( + int32_t index, double* lb_ratio) +{ + if (int err = verify_ww_index(index)) + return err; + const auto& wws = variance_reduction::weight_windows[index]; + *lb_ratio = wws->max_lower_bound_ratio(); + return 0; +} + +extern "C" int openmc_weight_windows_set_max_lower_bound_ratio( + int32_t index, double lb_ratio) +{ + if (int err = verify_ww_index(index)) + return err; + const auto& wws = variance_reduction::weight_windows[index]; + wws->max_lower_bound_ratio() = lb_ratio; + return 0; +} + +extern "C" int openmc_weight_windows_get_weight_cutoff( + int32_t index, double* cutoff) +{ + if (int err = verify_ww_index(index)) + return err; + const auto& wws = variance_reduction::weight_windows[index]; + *cutoff = wws->weight_cutoff(); + return 0; +} + +extern "C" int openmc_weight_windows_set_weight_cutoff( + int32_t index, double cutoff) +{ + if (int err = verify_ww_index(index)) + return err; + const auto& wws = variance_reduction::weight_windows[index]; + wws->weight_cutoff() = cutoff; + return 0; +} + +extern "C" int openmc_weight_windows_get_max_split( + int32_t index, int* max_split) +{ + if (int err = verify_ww_index(index)) + return err; + const auto& wws = variance_reduction::weight_windows[index]; + *max_split = wws->max_split(); + return 0; +} + +extern "C" int openmc_weight_windows_set_max_split(int32_t index, int max_split) +{ + if (int err = verify_ww_index(index)) + return err; + const auto& wws = variance_reduction::weight_windows[index]; + wws->max_split() = max_split; + return 0; +} + +extern "C" int openmc_extend_weight_windows( + int32_t n, int32_t* index_start, int32_t* index_end) +{ + if (index_start) + *index_start = variance_reduction::weight_windows.size(); + if (index_end) + *index_end = variance_reduction::weight_windows.size() + n - 1; + for (int i = 0; i < n; ++i) + variance_reduction::weight_windows.push_back(make_unique()); + return 0; +} + +extern "C" size_t openmc_weight_windows_size() +{ + return variance_reduction::weight_windows.size(); +} + +extern "C" int openmc_weight_windows_export(const char* filename) +{ + + if (!mpi::master) + return 0; + + std::string name = filename ? filename : "weight_windows.h5"; + + write_message(fmt::format("Exporting weight windows to {}...", name), 5); + + hid_t ww_file = file_open(name, 'w'); + + // Write file type + write_attribute(ww_file, "filetype", "weight_windows"); + + // Write revisiion number for state point file + write_attribute(ww_file, "version", VERSION_WEIGHT_WINDOWS); + + hid_t weight_windows_group = create_group(ww_file, "weight_windows"); + + hid_t mesh_group = create_group(ww_file, "meshes"); + + std::vector mesh_ids; + std::vector ww_ids; + for (const auto& ww : variance_reduction::weight_windows) { + + ww->to_hdf5(weight_windows_group); + ww_ids.push_back(ww->id()); + + // if the mesh has already been written, move on + int32_t mesh_id = ww->mesh()->id(); + if (std::find(mesh_ids.begin(), mesh_ids.end(), mesh_id) != mesh_ids.end()) + continue; + + mesh_ids.push_back(mesh_id); + ww->mesh()->to_hdf5(mesh_group); + } + + write_attribute(mesh_group, "n_meshes", mesh_ids.size()); + write_attribute(mesh_group, "ids", mesh_ids); + close_group(mesh_group); + + write_attribute(weight_windows_group, "n_weight_windows", ww_ids.size()); + write_attribute(weight_windows_group, "ids", ww_ids); + close_group(weight_windows_group); + + file_close(ww_file); + + return 0; +} + +extern "C" int openmc_weight_windows_import(const char* filename) +{ + std::string name = filename ? filename : "weight_windows.h5"; + + if (mpi::master) + write_message(fmt::format("Importing weight windows from {}...", name), 5); + + if (!file_exists(name)) { + set_errmsg(fmt::format("File '{}' does not exist", name)); + } + + hid_t ww_file = file_open(name, 'r'); + + // Check that filetype is correct + std::string filetype; + read_attribute(ww_file, "filetype", filetype); + if (filetype != "weight_windows") { + file_close(ww_file); + set_errmsg(fmt::format("File '{}' is not a weight windows file.", name)); + return OPENMC_E_INVALID_ARGUMENT; + } + + // Check that the file version is compatible + std::array file_version; + read_attribute(ww_file, "version", file_version); + if (file_version[0] != VERSION_WEIGHT_WINDOWS[0]) { + std::string err_msg = + fmt::format("File '{}' has version {} which is incompatible with the " + "expected version ({}).", + name, file_version, VERSION_WEIGHT_WINDOWS); + set_errmsg(err_msg); + return OPENMC_E_INVALID_ARGUMENT; + } + + hid_t weight_windows_group = open_group(ww_file, "weight_windows"); + + std::vector names = group_names(weight_windows_group); + + for (const auto& name : names) { + WeightWindows::from_hdf5(weight_windows_group, name); + } + + close_group(weight_windows_group); + + file_close(ww_file); + + return 0; +} + +} // namespace openmc diff --git a/src/wmp.cpp b/src/wmp.cpp index 4299b940027..e9c4fb5e3e6 100644 --- a/src/wmp.cpp +++ b/src/wmp.cpp @@ -2,15 +2,15 @@ #include "openmc/constants.h" #include "openmc/cross_sections.h" +#include "openmc/error.h" // for writing messages #include "openmc/hdf5_interface.h" #include "openmc/math_functions.h" #include "openmc/nuclide.h" -#include "openmc/error.h" // for writing messages #include -#include #include // for min +#include namespace openmc { @@ -50,14 +50,16 @@ WindowedMultipole::WindowedMultipole(hid_t group) read_dataset(group, "broaden_poly", broaden_poly); if (n_windows != broaden_poly.shape()[0]) { fatal_error("broaden_poly array shape is not consistent with the windows " - "array shape in WMP library for " + name_ + "."); + "array shape in WMP library for " + + name_ + "."); } // Read the "curvefit" array. read_dataset(group, "curvefit", curvefit_); if (n_windows != curvefit_.shape()[0]) { fatal_error("curvefit array shape is not consistent with the windows " - "array shape in WMP library for " + name_ + "."); + "array shape in WMP library for " + + name_ + "."); } fit_order_ = curvefit_.shape()[1] - 1; @@ -77,8 +79,8 @@ WindowedMultipole::WindowedMultipole(hid_t group) } } -std::tuple -WindowedMultipole::evaluate(double E, double sqrtkT) const +std::tuple WindowedMultipole::evaluate( + double E, double sqrtkT) const { using namespace std::complex_literals; @@ -106,12 +108,16 @@ WindowedMultipole::evaluate(double E, double sqrtkT) const // Broaden the curvefit. double dopp = sqrt_awr_ / sqrtkT; array broadened_polynomials; - broaden_wmp_polynomials(E, dopp, fit_order_ + 1, broadened_polynomials.data()); + broaden_wmp_polynomials( + E, dopp, fit_order_ + 1, broadened_polynomials.data()); for (int i_poly = 0; i_poly < fit_order_ + 1; ++i_poly) { - sig_s += curvefit_(i_window, i_poly, FIT_S) * broadened_polynomials[i_poly]; - sig_a += curvefit_(i_window, i_poly, FIT_A) * broadened_polynomials[i_poly]; + sig_s += + curvefit_(i_window, i_poly, FIT_S) * broadened_polynomials[i_poly]; + sig_a += + curvefit_(i_window, i_poly, FIT_A) * broadened_polynomials[i_poly]; if (fissionable_) { - sig_f += curvefit_(i_window, i_poly, FIT_F) * broadened_polynomials[i_poly]; + sig_f += + curvefit_(i_window, i_poly, FIT_F) * broadened_polynomials[i_poly]; } } } else { @@ -132,7 +138,8 @@ WindowedMultipole::evaluate(double E, double sqrtkT) const if (sqrtkT == 0.0) { // If at 0K, use asymptotic form. - for (int i_pole = window.index_start; i_pole <= window.index_end; ++i_pole) { + for (int i_pole = window.index_start; i_pole <= window.index_end; + ++i_pole) { std::complex psi_chi = -1.0i / (data_(i_pole, MP_EA) - sqrtE); std::complex c_temp = psi_chi * invE; sig_s += (data_(i_pole, MP_RS) * c_temp).real(); @@ -144,7 +151,8 @@ WindowedMultipole::evaluate(double E, double sqrtkT) const } else { // At temperature, use Faddeeva function-based form. double dopp = sqrt_awr_ / sqrtkT; - for (int i_pole = window.index_start; i_pole <= window.index_end; ++i_pole) { + for (int i_pole = window.index_start; i_pole <= window.index_end; + ++i_pole) { std::complex z = (sqrtE - data_(i_pole, MP_EA)) * dopp; std::complex w_val = faddeeva(z) * dopp * invE * SQRT_PI; sig_s += (data_(i_pole, MP_RS) * w_val).real(); @@ -158,8 +166,8 @@ WindowedMultipole::evaluate(double E, double sqrtkT) const return std::make_tuple(sig_s, sig_a, sig_f); } -std::tuple -WindowedMultipole::evaluate_deriv(double E, double sqrtkT) const +std::tuple WindowedMultipole::evaluate_deriv( + double E, double sqrtkT) const { // ========================================================================== // Bookkeeping @@ -167,11 +175,11 @@ WindowedMultipole::evaluate_deriv(double E, double sqrtkT) const // Define some frequently used variables. double sqrtE = std::sqrt(E); double invE = 1.0 / E; - double T = sqrtkT*sqrtkT / K_BOLTZMANN; + double T = sqrtkT * sqrtkT / K_BOLTZMANN; if (sqrtkT == 0.0) { fatal_error("Windowed multipole temperature derivatives are not implemented" - " for 0 Kelvin cross sections."); + " for 0 Kelvin cross sections."); } // Locate us @@ -201,7 +209,7 @@ WindowedMultipole::evaluate_deriv(double E, double sqrtkT) const sig_f += (data_(i_pole, MP_RF) * w_val).real(); } } - double norm = -0.5*sqrt_awr_ / std::sqrt(K_BOLTZMANN) * std::pow(T, -1.5); + double norm = -0.5 * sqrt_awr_ / std::sqrt(K_BOLTZMANN) * std::pow(T, -1.5); sig_s *= norm; sig_a *= norm; sig_f *= norm; @@ -226,7 +234,8 @@ void check_wmp_version(hid_t file) } } else { fatal_error(fmt::format("WMP data does not indicate a version. Your " - "installation of OpenMC expects version {}x data.", WMP_VERSION[0])); + "installation of OpenMC expects version {}x data.", + WMP_VERSION[0])); } } @@ -237,7 +246,8 @@ void read_multipole_data(int i_nuclide) auto it = data::library_map.find({Library::Type::wmp, nuc->name_}); // If no WMP library for this nuclide, just return - if (it == data::library_map.end()) return; + if (it == data::library_map.end()) + return; // Check if WMP library exists int idx = it->second; @@ -286,16 +296,17 @@ void broaden_wmp_polynomials(double E, double dopp, int n, double factors[]) // fit, and no less. factors[0] = erf_beta / E; factors[1] = 1. / sqrtE; - factors[2] = factors[0] * (half_inv_dopp2 + E) + exp_m_beta2 / - (beta * SQRT_PI); - if (n > 3) factors[3] = factors[1] * (E + 3.0 * half_inv_dopp2); + factors[2] = + factors[0] * (half_inv_dopp2 + E) + exp_m_beta2 / (beta * SQRT_PI); + if (n > 3) + factors[3] = factors[1] * (E + 3.0 * half_inv_dopp2); // Perform recursive broadening of high order components (Eq. 16) for (int i = 1; i < n - 3; i++) { double ip1_dbl = i + 1; - factors[i + 3] = -factors[i - 1] * (ip1_dbl - 1.) * ip1_dbl * - quarter_inv_dopp4 + factors[i + 1] * - (E + (1. + 2. * ip1_dbl) * half_inv_dopp2); + factors[i + 3] = + -factors[i - 1] * (ip1_dbl - 1.) * ip1_dbl * quarter_inv_dopp4 + + factors[i + 1] * (E + (1. + 2. * ip1_dbl) * half_inv_dopp2); } } diff --git a/src/xml_interface.cpp b/src/xml_interface.cpp index a715dfae285..6ce465bafb9 100644 --- a/src/xml_interface.cpp +++ b/src/xml_interface.cpp @@ -7,9 +7,8 @@ namespace openmc { -std::string -get_node_value(pugi::xml_node node, const char* name, bool lowercase, - bool strip) +std::string get_node_value( + pugi::xml_node node, const char* name, bool lowercase, bool strip) { // Search for either an attribute or child tag and get the data as a char*. const pugi::char_t* value_char; @@ -24,7 +23,8 @@ get_node_value(pugi::xml_node node, const char* name, bool lowercase, std::string value {value_char}; // Convert to lower-case if needed - if (lowercase) to_lower(value); + if (lowercase) + to_lower(value); // Strip leading/trailing whitespace if needed if (strip) { @@ -35,8 +35,7 @@ get_node_value(pugi::xml_node node, const char* name, bool lowercase, return value; } -bool -get_node_value_bool(pugi::xml_node node, const char* name) +bool get_node_value_bool(pugi::xml_node node, const char* name) { if (node.attribute(name)) { return node.attribute(name).as_bool(); @@ -49,4 +48,11 @@ get_node_value_bool(pugi::xml_node node, const char* name) return false; } +Position get_node_position( + pugi::xml_node node, const char* name, bool lowercase) +{ + vector arr = get_node_array(node, name, lowercase); + return Position(arr); +} + } // namespace openmc diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 4cfc0b85aa7..1929f51e6fa 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -1,14 +1,14 @@ #include "openmc/xsdata.h" +#include #include #include -#include #include -#include "xtensor/xview.hpp" +#include "xtensor/xbuilder.hpp" #include "xtensor/xindex_view.hpp" #include "xtensor/xmath.hpp" -#include "xtensor/xbuilder.hpp" +#include "xtensor/xview.hpp" #include "openmc/constants.h" #include "openmc/error.h" @@ -17,22 +17,21 @@ #include "openmc/random_lcg.h" #include "openmc/settings.h" - namespace openmc { //============================================================================== // XsData class methods //============================================================================== -XsData::XsData(bool fissionable, AngleDistributionType scatter_format, int n_pol, int n_azi, - size_t n_groups, size_t n_d_groups) : - n_g_(n_groups), - n_dg_(n_d_groups) +XsData::XsData(bool fissionable, AngleDistributionType scatter_format, + int n_pol, int n_azi, size_t n_groups, size_t n_d_groups) + : n_g_(n_groups), n_dg_(n_d_groups) { size_t n_ang = n_pol * n_azi; // check to make sure scatter format is OK before we allocate - if (scatter_format != AngleDistributionType::HISTOGRAM && scatter_format != AngleDistributionType::TABULAR && + if (scatter_format != AngleDistributionType::HISTOGRAM && + scatter_format != AngleDistributionType::TABULAR && scatter_format != AngleDistributionType::LEGENDRE) { fatal_error("Invalid scatter_format!"); } @@ -66,7 +65,6 @@ XsData::XsData(bool fissionable, AngleDistributionType scatter_format, int n_pol chi_delayed = xt::zeros(shape); } - for (int a = 0; a < n_ang; a++) { if (scatter_format == AngleDistributionType::HISTOGRAM) { scatter.emplace_back(new ScattDataHistogram); @@ -80,9 +78,10 @@ XsData::XsData(bool fissionable, AngleDistributionType scatter_format, int n_pol //============================================================================== -void -XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, AngleDistributionType scatter_format, - AngleDistributionType final_scatter_format, int order_data, bool is_isotropic, int n_pol, int n_azi) +void XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, + AngleDistributionType scatter_format, + AngleDistributionType final_scatter_format, int order_data, bool is_isotropic, + int n_pol, int n_azi) { // Reconstruct the dimension information so it doesn't need to be passed size_t n_ang = n_pol * n_azi; @@ -98,8 +97,8 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, AngleDistributionType scat read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); // Get scattering data - scatter_from_hdf5(xsdata_grp, n_ang, scatter_format, - final_scatter_format, order_data); + scatter_from_hdf5( + xsdata_grp, n_ang, scatter_format, final_scatter_format, order_data); // Check absorption to ensure it is not 0 since it is often the // denominator in tally methods @@ -122,9 +121,8 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, AngleDistributionType scat //============================================================================== -void -XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, - bool is_isotropic) +void XsData::fission_vector_beta_from_hdf5( + hid_t xsdata_grp, size_t n_ang, bool is_isotropic) { // Data is provided as nu-fission and chi with a beta for delayed info @@ -138,8 +136,8 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Now every incoming group in prompt_chi and delayed_chi is the normalized // chi we just made chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); - chi_delayed = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::newaxis(), - xt::all()); + chi_delayed = + xt::view(temp_chi, xt::all(), xt::newaxis(), xt::newaxis(), xt::all()); // Get nu-fission xt::xtensor temp_nufiss({n_ang, n_g_}, 0.); @@ -150,7 +148,8 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, int beta_ndims = dataset_ndims(beta_dset); close_dataset(beta_dset); int ndim_target = 1; - if (!is_isotropic) ndim_target += 2; + if (!is_isotropic) + ndim_target += 2; if (beta_ndims == ndim_target) { xt::xtensor temp_beta({n_ang, n_dg_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); @@ -160,8 +159,8 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Set delayed_nu_fission as beta * nu_fission delayed_nu_fission = - xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * - xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); } else if (beta_ndims == ndim_target + 1) { xt::xtensor temp_beta({n_ang, n_dg_, n_g_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); @@ -170,13 +169,12 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); // Set delayed_nu_fission as beta * nu_fission - delayed_nu_fission = temp_beta * - xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); + delayed_nu_fission = + temp_beta * xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); } } -void -XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) +void XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // Data is provided separately as prompt + delayed nu-fission and chi @@ -192,23 +190,21 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi_d /= xt::view(xt::sum(temp_chi_d, {2}), - xt::all(), xt::all(), xt::newaxis()); + temp_chi_d /= + xt::view(xt::sum(temp_chi_d, {2}), xt::all(), xt::all(), xt::newaxis()); - // Now assign the prompt and delayed chis by replicating for each incoming group + // Now assign the prompt and delayed chis by replicating for each incoming + // group chi_prompt = xt::view(temp_chi_p, xt::all(), xt::newaxis(), xt::all()); - chi_delayed = xt::view(temp_chi_d, xt::all(), xt::all(), xt::newaxis(), - xt::all()); + chi_delayed = + xt::view(temp_chi_d, xt::all(), xt::all(), xt::newaxis(), xt::all()); // Get prompt and delayed nu-fission directly - read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, - true); - read_nd_vector(xsdata_grp, "delayed-nu-fission", - delayed_nu_fission, true); + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); + read_nd_vector(xsdata_grp, "delayed-nu-fission", delayed_nu_fission, true); } -void -XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) +void XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // No beta is provided and there is no prompt/delay distinction. // Therefore, the code only considers the data as prompt. @@ -229,8 +225,8 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) //============================================================================== -void -XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) +void XsData::fission_matrix_beta_from_hdf5( + hid_t xsdata_grp, size_t n_ang, bool is_isotropic) { // Data is provided as nu-fission and chi with a beta for delayed info @@ -243,7 +239,8 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is int beta_ndims = dataset_ndims(beta_dset); close_dataset(beta_dset); int ndim_target = 1; - if (!is_isotropic) ndim_target += 2; + if (!is_isotropic) + ndim_target += 2; if (beta_ndims == ndim_target) { xt::xtensor temp_beta({n_ang, n_dg_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); @@ -256,19 +253,20 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); // Store chi-prompt - chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::newaxis(), - xt::newaxis()) * temp_matrix; + chi_prompt = + xt::view(1.0 - temp_beta_sum, xt::all(), xt::newaxis(), xt::newaxis()) * + temp_matrix; // delayed_nu_fission is the sum of this matrix over outgoing groups and // multiplied by beta delayed_nu_fission = - xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * - xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); // Store chi-delayed chi_delayed = - xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * - xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); } else if (beta_ndims == ndim_target + 1) { xt::xtensor temp_beta({n_ang, n_dg_, n_g_}, 0.); @@ -282,30 +280,30 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); // Store chi-prompt - chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::all(), - xt::newaxis()) * temp_matrix; + chi_prompt = + xt::view(1.0 - temp_beta_sum, xt::all(), xt::all(), xt::newaxis()) * + temp_matrix; // delayed_nu_fission is the sum of this matrix over outgoing groups and // multiplied by beta - delayed_nu_fission = temp_beta * - xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); + delayed_nu_fission = temp_beta * xt::view(xt::sum(temp_matrix, {2}), + xt::all(), xt::newaxis(), xt::all()); // Store chi-delayed chi_delayed = - xt::view(temp_beta, xt::all(), xt::all(), xt::all(), xt::newaxis()) * - xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); + xt::view(temp_beta, xt::all(), xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); } - //Normalize both chis - chi_prompt /= xt::view(xt::sum(chi_prompt, {2}), - xt::all(), xt::all(), xt::newaxis()); + // Normalize both chis + chi_prompt /= + xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::all(), xt::newaxis()); - chi_delayed /= xt::view(xt::sum(chi_delayed, {3}), - xt::all(), xt::all(), xt::all(), xt::newaxis()); + chi_delayed /= xt::view( + xt::sum(chi_delayed, {3}), xt::all(), xt::all(), xt::all(), xt::newaxis()); } -void -XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) +void XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // Data is provided separately as prompt + delayed nu-fission and chi @@ -319,7 +317,7 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) // chi_prompt is this matrix but normalized over outgoing groups, which we // have already stored in prompt_nu_fission chi_prompt = temp_matrix_p / - xt::view(prompt_nu_fission, xt::all(), xt::all(), xt::newaxis()); + xt::view(prompt_nu_fission, xt::all(), xt::all(), xt::newaxis()); // Get the delayed nu-fission matrix xt::xtensor temp_matrix_d({n_ang, n_dg_, n_g_, n_g_}, 0.); @@ -330,12 +328,11 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) // chi_prompt is this matrix but normalized over outgoing groups, which we // have already stored in prompt_nu_fission - chi_delayed = temp_matrix_d / - xt::view(delayed_nu_fission, xt::all(), xt::all(), xt::all(), xt::newaxis()); + chi_delayed = temp_matrix_d / xt::view(delayed_nu_fission, xt::all(), + xt::all(), xt::all(), xt::newaxis()); } -void -XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) +void XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // No beta is provided and there is no prompt/delay distinction. // Therefore, the code only considers the data as prompt. @@ -349,14 +346,14 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // chi_prompt is this matrix but normalized over outgoing groups, which we // have already stored in prompt_nu_fission - chi_prompt = temp_matrix / xt::view(prompt_nu_fission, xt::all(), xt::all(), - xt::newaxis()); + chi_prompt = temp_matrix / + xt::view(prompt_nu_fission, xt::all(), xt::all(), xt::newaxis()); } //============================================================================== -void -XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) +void XsData::fission_from_hdf5( + hid_t xsdata_grp, size_t n_ang, bool is_isotropic) { // Get the fission and kappa_fission data xs; these are optional read_nd_vector(xsdata_grp, "fission", fission); @@ -397,9 +394,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) //============================================================================== -void -XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, AngleDistributionType scatter_format, - AngleDistributionType final_scatter_format, int order_data) +void XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, + AngleDistributionType scatter_format, + AngleDistributionType final_scatter_format, int order_data) { if (!object_exists(xsdata_grp, "scatter_data")) { fatal_error("Must provide scatter_data group!"); @@ -487,12 +484,11 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, AngleDistributionType xt::xtensor in_gmin = xt::view(gmin, a, xt::all()); xt::xtensor in_gmax = xt::view(gmax, a, xt::all()); - legendre_scatt.init(in_gmin, in_gmax, - temp_mult[a], input_scatt[a]); + legendre_scatt.init(in_gmin, in_gmax, temp_mult[a], input_scatt[a]); // Now create a tabular version of legendre_scatt - convert_legendre_to_tabular(legendre_scatt, - *static_cast(scatter[a].get())); + convert_legendre_to_tabular( + legendre_scatt, *static_cast(scatter[a].get())); scatter_format = final_scatter_format; } @@ -515,7 +511,8 @@ void XsData::combine( // Combine the non-scattering data for (size_t i = 0; i < those_xs.size(); i++) { XsData* that = those_xs[i]; - if (!equiv(*that)) fatal_error("Cannot combine the XsData objects!"); + if (!equiv(*that)) + fatal_error("Cannot combine the XsData objects!"); double scalar = scalars[i]; total += scalar * that->total; absorption += scalar * that->absorption; @@ -529,13 +526,13 @@ void XsData::combine( fission += scalar * that->fission; delayed_nu_fission += scalar * that->delayed_nu_fission; chi_prompt += scalar * - xt::view(xt::sum(that->prompt_nu_fission, {1}), - xt::all(), xt::newaxis(), xt::newaxis()) * - that->chi_prompt; + xt::view(xt::sum(that->prompt_nu_fission, {1}), xt::all(), + xt::newaxis(), xt::newaxis()) * + that->chi_prompt; chi_delayed += scalar * - xt::view(xt::sum(that->delayed_nu_fission, {2}), - xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * - that->chi_delayed; + xt::view(xt::sum(that->delayed_nu_fission, {2}), xt::all(), + xt::all(), xt::newaxis(), xt::newaxis()) * + that->chi_delayed; } decay_rate += scalar * that->decay_rate; } @@ -544,8 +541,8 @@ void XsData::combine( // azimuthal angle and delayed group (for chi_delayed) chi_prompt /= xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::all(), xt::newaxis()); - chi_delayed /= xt::view(xt::sum(chi_delayed, {3}), xt::all(), xt::all(), - xt::all(), xt::newaxis()); + chi_delayed /= xt::view( + xt::sum(chi_delayed, {3}), xt::all(), xt::all(), xt::all(), xt::newaxis()); // Allow the ScattData object to combine itself for (size_t a = 0; a < total.shape()[0]; a++) { @@ -562,10 +559,9 @@ void XsData::combine( //============================================================================== -bool -XsData::equiv(const XsData& that) +bool XsData::equiv(const XsData& that) { return (absorption.shape() == that.absorption.shape()); } -} //namespace openmc +} // namespace openmc diff --git a/tests/__init__.py b/tests/__init__.py index 5c21cd93806..0228348a23a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,13 +1,23 @@ from contextlib import contextmanager import os +from shutil import copy import tempfile @contextmanager -def cdtemp(): - """Context manager to change to/return from a tmpdir.""" +def cdtemp(files=None): + """Context manager to change to/return from a tmpdir. + + Parameters + ---------- + files : Iterable of str or Path-like + Set of files to copy into the temporary directory + """ with tempfile.TemporaryDirectory() as tmpdir: cwd = os.getcwd() + if files: + for file in files: + copy(file, tmpdir, follow_symlinks=True) try: os.chdir(tmpdir) yield diff --git a/tests/chain_simple.xml b/tests/chain_simple.xml index c2e50a370f3..4e08995a8dc 100644 --- a/tests/chain_simple.xml +++ b/tests/chain_simple.xml @@ -1,12 +1,18 @@ - + + + 3696.125 4095.822 4477.27 5097.122 29452.1 29781.3 33566.5 33629.4 33865.1 33878.5 34395.3 34408.0 34486.2 34488.2 112780.0 113150.0 162650.0 165740.0 184490.0 197190.0 220502.0 229720.0 247500.0 254740.0 264260.0 288451.0 290270.0 304910.0 305830.0 326000.0 333600.0 342520.0 361850.0 403030.0 414830.0 417633.0 429930.0 433741.0 451630.0 530800.0 546557.0 575970.0 588280.0 616900.0 649850.0 656090.0 679220.0 684600.0 690130.0 707920.0 785480.0 795500.0 797710.0 807200.0 836804.0 960290.0 961430.0 971960.0 972620.0 995090.0 1038760.0 1096860.0 1101580.0 1124000.0 1131511.0 1151510.0 1159900.0 1169040.0 1225600.0 1240470.0 1254800.0 1260409.0 1315770.0 1334800.0 1343660.0 1367890.0 1441800.0 1448350.0 1457560.0 1502790.0 1521990.0 1543700.0 1566410.0 1678027.0 1706459.0 1791196.0 1830690.0 1845300.0 1927300.0 1948490.0 2045880.0 2112400.0 2151500.0 2189400.0 2255457.0 2408650.0 2466070.0 2477100.0 9.714352819815078e-10 7.460941651551526e-09 6.047882056201745e-09 8.510389107205747e-10 3.7979729633684727e-08 7.033747061198817e-08 6.602815946851458e-09 1.2800909198245071e-08 6.513060244589454e-11 8.894667887850525e-11 1.3843783302275766e-09 2.700005498135763e-09 1.2141115256573815e-11 1.654893875618862e-11 3.7007705885806645e-09 2.0186021392258173e-09 2.859686363903241e-09 9.16781804898392e-09 6.896890642354875e-09 9.588360161322631e-09 5.130613770532286e-07 7.06510748729036e-08 8.410842246774237e-09 6.7286737974193905e-09 5.3829390379355124e-08 9.083709626516178e-07 8.915492781580693e-08 9.251926471451662e-09 2.783988783682273e-08 6.728673797419391e-10 1.093409492080651e-08 2.5232526740322717e-10 5.467047460403255e-08 6.812782219887132e-08 8.83138435911295e-08 1.0345335963532313e-06 8.915492781580693e-08 1.623292553627428e-07 9.251926471451663e-08 9.251926471451662e-09 2.0942997194467853e-06 3.784879011048407e-08 1.513951604419363e-08 1.093409492080651e-08 1.337323917237104e-07 2.186818984161302e-08 1.5980600268871052e-08 6.7286737974193905e-09 3.784879011048407e-08 1.9344937167580748e-07 4.457746390790346e-08 6.7286737974193905e-09 5.0465053480645434e-08 1.3457347594838781e-08 1.9597262434983976e-06 1.0093010696129087e-08 4.289529545854862e-08 2.607361096500014e-07 3.53255374364518e-07 4.541854813258089e-08 2.329803302356464e-06 2.607361096500014e-08 4.7100716581935733e-07 1.059766123093554e-06 6.6193328482113254e-06 4.205421123387119e-10 3.027903208838726e-08 2.565306885266143e-07 1.2616263370161358e-08 2.649415307733885e-07 3.3643368987096953e-09 8.410842246774237e-06 1.934493716758075e-08 9.251926471451662e-09 2.2709274066290446e-08 1.7830985563161385e-07 5.046505348064544e-09 9.251926471451663e-08 2.5400743585258203e-06 3.154065842540339e-07 1.093409492080651e-08 7.569758022096815e-09 3.784879011048407e-07 2.8008104681758214e-06 1.2027504412887161e-06 2.26251656438227e-06 1.6989901338483962e-07 1.6821684493548476e-09 8.663167514177466e-08 1.8503852942903323e-08 2.5568960430193683e-07 2.0186021392258175e-08 6.560456952483906e-09 3.784879011048407e-09 1.7999202408096872e-07 2.800810468175822e-07 2.1027105616935597e-08 4.205421123387119e-10 + - + + + 0.0 10000.0 20000.0 50000.0 100000.0 200000.0 300000.0 400000.0 600000.0 800000.0 1000000.0 1220000.0 1.1612176249914943e-11 0.0 3.1976524142990123e-11 0.0 6.418466676129901e-13 1.894551923065874e-10 5.099949011192198e-13 3.170644340540729e-13 2.756798470867507e-12 6.67627508515641e-14 3.711746246444946e-15 0.0 + @@ -28,6 +34,9 @@ + + 3065.349 12960.11 13197.49 16125.43 19185.05 19590.0 31600.0 34700.0 41400.0 41960.0 51220.0 54100.0 54250.0 64350.0 72700.0 75020.0 76198.0 90330.0 93795.0 96090.0 105278.0 106074.0 106608.0 106771.0 108948.0 109154.0 109160.0 109395.0 109433.0 115450.0 120350.0 136550.0 140760.0 142400.0 143760.0 150930.0 163330.0 173300.0 182610.0 185715.0 194940.0 198900.0 202110.0 205311.0 215280.0 221380.0 228780.0 233500.0 240870.0 246840.0 266450.0 275129.0 275430.0 281420.0 282920.0 289560.0 291650.0 301700.0 317100.0 343500.0 345900.0 356030.0 387820.0 410290.0 428710.0 448400.0 1.4211820389290126e-18 3.695705148646686e-18 4.752472005970374e-19 4.0825252294602915e-18 8.998127221991115e-19 1.9035285506819052e-21 5.305446177665699e-21 1.1547147563154756e-20 9.362552078233586e-21 1.86835843588509e-20 1.0610892355331398e-20 2.736290732002608e-22 4.776811520523089e-21 3.977552295559136e-21 3.432935762018982e-20 1.872510415646717e-20 2.4966805541956234e-21 1.0265454754703584e-18 1.7575878976520235e-18 2.839974130397521e-20 2.1057468800839102e-19 4.1342252420362975e-19 7.098565272539688e-21 8.20050332279016e-21 5.276915360632628e-20 1.0602918581811435e-19 4.806110066826575e-19 2.0521431485853304e-21 2.375669880669523e-21 9.362552078233586e-21 8.267152210184412e-21 3.745020831293435e-21 6.865871524037964e-20 1.5604253463722645e-21 3.420452359248004e-18 2.4966805541956232e-20 1.5853921519142206e-18 1.8725104156467174e-21 1.0610892355331397e-19 1.7851265962498703e-17 1.966135936429053e-19 1.3107572909527022e-20 3.370518748164091e-19 1.5635461970650089e-18 9.050467008959134e-21 3.745020831293434e-20 2.18459548492117e-21 9.050467008959134e-21 2.3406380195583967e-20 1.6540508671546e-20 1.8725104156467174e-21 1.622842360227155e-20 2.18459548492117e-21 1.8725104156467174e-21 1.8725104156467174e-21 2.18459548492117e-21 1.2483402770978116e-20 1.5604253463722645e-21 3.120850692744529e-22 9.362552078233587e-22 1.2483402770978116e-20 1.5604253463722645e-21 1.2483402770978116e-20 9.362552078233587e-22 3.120850692744529e-22 3.120850692744529e-22 + 2.53000e-02 @@ -38,6 +47,9 @@ + + 3061.32 12959.8 13440.07 16150.05 19148.83 49550.0 90330.0 93795.0 105278.0 106074.0 106608.0 106771.0 108948.0 109154.0 109395.0 109433.0 113500.0 5.3130501476983077e-20 1.4936931167066328e-19 1.943509007980312e-20 1.8224649880365157e-19 4.0452400597373603e-20 3.146222282132249e-21 3.300026341588747e-23 5.444173877278485e-23 6.3486292118621375e-24 1.2400176384733938e-23 2.124537722121886e-25 2.4542156071495764e-25 1.5792541400719878e-24 3.1731991718126067e-24 6.141568457919309e-26 7.109808533300877e-26 5.014291762148272e-22 + 2.53000e-02 diff --git a/tests/chain_simple_decay.xml b/tests/chain_simple_decay.xml new file mode 100644 index 00000000000..1c8c5e4eecc --- /dev/null +++ b/tests/chain_simple_decay.xml @@ -0,0 +1,66 @@ + + + + + + + 3696.125 4095.822 4477.27 5097.122 29452.1 29781.3 33566.5 33629.4 33865.1 33878.5 34395.3 34408.0 34486.2 34488.2 112780.0 113150.0 162650.0 165740.0 184490.0 197190.0 220502.0 229720.0 247500.0 254740.0 264260.0 288451.0 290270.0 304910.0 305830.0 326000.0 333600.0 342520.0 361850.0 403030.0 414830.0 417633.0 429930.0 433741.0 451630.0 530800.0 546557.0 575970.0 588280.0 616900.0 649850.0 656090.0 679220.0 684600.0 690130.0 707920.0 785480.0 795500.0 797710.0 807200.0 836804.0 960290.0 961430.0 971960.0 972620.0 995090.0 1038760.0 1096860.0 1101580.0 1124000.0 1131511.0 1151510.0 1159900.0 1169040.0 1225600.0 1240470.0 1254800.0 1260409.0 1315770.0 1334800.0 1343660.0 1367890.0 1441800.0 1448350.0 1457560.0 1502790.0 1521990.0 1543700.0 1566410.0 1678027.0 1706459.0 1791196.0 1830690.0 1845300.0 1927300.0 1948490.0 2045880.0 2112400.0 2151500.0 2189400.0 2255457.0 2408650.0 2466070.0 2477100.0 9.714352819815078e-10 7.460941651551526e-09 6.047882056201745e-09 8.510389107205747e-10 3.7979729633684727e-08 7.033747061198817e-08 6.602815946851458e-09 1.2800909198245071e-08 6.513060244589454e-11 8.894667887850525e-11 1.3843783302275766e-09 2.700005498135763e-09 1.2141115256573815e-11 1.654893875618862e-11 3.7007705885806645e-09 2.0186021392258173e-09 2.859686363903241e-09 9.16781804898392e-09 6.896890642354875e-09 9.588360161322631e-09 5.130613770532286e-07 7.06510748729036e-08 8.410842246774237e-09 6.7286737974193905e-09 5.3829390379355124e-08 9.083709626516178e-07 8.915492781580693e-08 9.251926471451662e-09 2.783988783682273e-08 6.728673797419391e-10 1.093409492080651e-08 2.5232526740322717e-10 5.467047460403255e-08 6.812782219887132e-08 8.83138435911295e-08 1.0345335963532313e-06 8.915492781580693e-08 1.623292553627428e-07 9.251926471451663e-08 9.251926471451662e-09 2.0942997194467853e-06 3.784879011048407e-08 1.513951604419363e-08 1.093409492080651e-08 1.337323917237104e-07 2.186818984161302e-08 1.5980600268871052e-08 6.7286737974193905e-09 3.784879011048407e-08 1.9344937167580748e-07 4.457746390790346e-08 6.7286737974193905e-09 5.0465053480645434e-08 1.3457347594838781e-08 1.9597262434983976e-06 1.0093010696129087e-08 4.289529545854862e-08 2.607361096500014e-07 3.53255374364518e-07 4.541854813258089e-08 2.329803302356464e-06 2.607361096500014e-08 4.7100716581935733e-07 1.059766123093554e-06 6.6193328482113254e-06 4.205421123387119e-10 3.027903208838726e-08 2.565306885266143e-07 1.2616263370161358e-08 2.649415307733885e-07 3.3643368987096953e-09 8.410842246774237e-06 1.934493716758075e-08 9.251926471451662e-09 2.2709274066290446e-08 1.7830985563161385e-07 5.046505348064544e-09 9.251926471451663e-08 2.5400743585258203e-06 3.154065842540339e-07 1.093409492080651e-08 7.569758022096815e-09 3.784879011048407e-07 2.8008104681758214e-06 1.2027504412887161e-06 2.26251656438227e-06 1.6989901338483962e-07 1.6821684493548476e-09 8.663167514177466e-08 1.8503852942903323e-08 2.5568960430193683e-07 2.0186021392258175e-08 6.560456952483906e-09 3.784879011048407e-09 1.7999202408096872e-07 2.800810468175822e-07 2.1027105616935597e-08 4.205421123387119e-10 + + + + + + 0.0 10000.0 20000.0 50000.0 100000.0 200000.0 300000.0 400000.0 600000.0 800000.0 1000000.0 1220000.0 1.1612176249914943e-11 0.0 3.1976524142990123e-11 0.0 6.418466676129901e-13 1.894551923065874e-10 5.099949011192198e-13 3.170644340540729e-13 2.756798470867507e-12 6.67627508515641e-14 3.711746246444946e-15 0.0 + + + + + + + + + + + + + + + + + + + + 2.53000e-02 + + Gd157 Gd156 I135 Xe135 Xe136 Cs135 + 1.093250e-04 2.087260e-04 2.780820e-02 6.759540e-03 2.392300e-02 4.356330e-05 + + + + + + + 3065.349 12960.11 13197.49 16125.43 19185.05 19590.0 31600.0 34700.0 41400.0 41960.0 51220.0 54100.0 54250.0 64350.0 72700.0 75020.0 76198.0 90330.0 93795.0 96090.0 105278.0 106074.0 106608.0 106771.0 108948.0 109154.0 109160.0 109395.0 109433.0 115450.0 120350.0 136550.0 140760.0 142400.0 143760.0 150930.0 163330.0 173300.0 182610.0 185715.0 194940.0 198900.0 202110.0 205311.0 215280.0 221380.0 228780.0 233500.0 240870.0 246840.0 266450.0 275129.0 275430.0 281420.0 282920.0 289560.0 291650.0 301700.0 317100.0 343500.0 345900.0 356030.0 387820.0 410290.0 428710.0 448400.0 1.4211820389290126e-18 3.695705148646686e-18 4.752472005970374e-19 4.0825252294602915e-18 8.998127221991115e-19 1.9035285506819052e-21 5.305446177665699e-21 1.1547147563154756e-20 9.362552078233586e-21 1.86835843588509e-20 1.0610892355331398e-20 2.736290732002608e-22 4.776811520523089e-21 3.977552295559136e-21 3.432935762018982e-20 1.872510415646717e-20 2.4966805541956234e-21 1.0265454754703584e-18 1.7575878976520235e-18 2.839974130397521e-20 2.1057468800839102e-19 4.1342252420362975e-19 7.098565272539688e-21 8.20050332279016e-21 5.276915360632628e-20 1.0602918581811435e-19 4.806110066826575e-19 2.0521431485853304e-21 2.375669880669523e-21 9.362552078233586e-21 8.267152210184412e-21 3.745020831293435e-21 6.865871524037964e-20 1.5604253463722645e-21 3.420452359248004e-18 2.4966805541956232e-20 1.5853921519142206e-18 1.8725104156467174e-21 1.0610892355331397e-19 1.7851265962498703e-17 1.966135936429053e-19 1.3107572909527022e-20 3.370518748164091e-19 1.5635461970650089e-18 9.050467008959134e-21 3.745020831293434e-20 2.18459548492117e-21 9.050467008959134e-21 2.3406380195583967e-20 1.6540508671546e-20 1.8725104156467174e-21 1.622842360227155e-20 2.18459548492117e-21 1.8725104156467174e-21 1.8725104156467174e-21 2.18459548492117e-21 1.2483402770978116e-20 1.5604253463722645e-21 3.120850692744529e-22 9.362552078233587e-22 1.2483402770978116e-20 1.5604253463722645e-21 1.2483402770978116e-20 9.362552078233587e-22 3.120850692744529e-22 3.120850692744529e-22 + + + 2.53000e-02 + + Gd157 Gd156 I135 Xe135 Xe136 Cs135 + 6.142710e-5 1.483250e-04 0.0292737 0.002566345 0.0219242 4.9097e-6 + + + + + + + 3061.32 12959.8 13440.07 16150.05 19148.83 49550.0 90330.0 93795.0 105278.0 106074.0 106608.0 106771.0 108948.0 109154.0 109395.0 109433.0 113500.0 5.3130501476983077e-20 1.4936931167066328e-19 1.943509007980312e-20 1.8224649880365157e-19 4.0452400597373603e-20 3.146222282132249e-21 3.300026341588747e-23 5.444173877278485e-23 6.3486292118621375e-24 1.2400176384733938e-23 2.124537722121886e-25 2.4542156071495764e-25 1.5792541400719878e-24 3.1731991718126067e-24 6.141568457919309e-26 7.109808533300877e-26 5.014291762148272e-22 + + + 2.53000e-02 + + Gd157 Gd156 I135 Xe135 Xe136 Cs135 + 4.141120e-04 7.605360e-04 0.0135457 0.00026864 0.0024432 3.7100E-07 + + + + diff --git a/tests/cpp_unit_tests/CMakeLists.txt b/tests/cpp_unit_tests/CMakeLists.txt new file mode 100644 index 00000000000..24ec1b7a90e --- /dev/null +++ b/tests/cpp_unit_tests/CMakeLists.txt @@ -0,0 +1,13 @@ +set(TEST_NAMES + test_distribution + test_file_utils + test_tally + test_interpolate + # Add additional unit test files here +) + +foreach(test ${TEST_NAMES}) + add_executable(${test} ${test}.cpp) + target_link_libraries(${test} Catch2::Catch2WithMain libopenmc) + add_test(NAME ${test} COMMAND ${test} WORKING_DIRECTORY ${UNIT_TEST_BIN_OUTPUT_DIR}) +endforeach() diff --git a/tests/cpp_unit_tests/test_distribution.cpp b/tests/cpp_unit_tests/test_distribution.cpp new file mode 100644 index 00000000000..e1a212db556 --- /dev/null +++ b/tests/cpp_unit_tests/test_distribution.cpp @@ -0,0 +1,81 @@ +#include "openmc/distribution.h" +#include "openmc/random_lcg.h" +#include +#include +#include +#include + +TEST_CASE("Test alias method sampling of a discrete distribution") +{ + constexpr int n_samples = 1000000; + double x[5] = {-1.6, 1.1, 20.3, 4.7, 0.9}; + double p[5] = {0.2, 0.1, 0.65, 0.02, 0.03}; + + // Initialize distribution + openmc::Discrete dist(x, p, 5); + uint64_t seed = openmc::init_seed(0, 0); + + // Calculate expected distribution mean + double mean = 0.0; + for (size_t i = 0; i < 5; i++) { + mean += x[i] * p[i]; + } + + // Sample distribution and calculate mean, standard deviation, and number of + // x[0] sampled + double dist_mean = 0.0; + double std = 0.0; + int counter = 0; + + for (size_t i = 0; i < n_samples; i++) { + auto sample = dist.sample(&seed); + std += sample * sample / n_samples; + dist_mean += sample; + + if (sample == x[0]) + counter++; + } + + dist_mean /= n_samples; + std -= dist_mean * dist_mean; + + // Require sampled distribution mean is within 4 standard deviations of the + // expected mean + REQUIRE(std::abs(dist_mean - mean) < 4 * std); + + // Require counter of number of x[0] is within the 95% confidence interval + // assuming a Poisson distribution of 200,000 + REQUIRE(std::abs((double)counter / n_samples - p[0]) < + 1.96 * std::sqrt(p[0] / n_samples)); +} + +TEST_CASE("Test alias sampling method for pugixml constructor") +{ + // XML doc node for Discrete contructor + pugi::xml_document doc; + pugi::xml_node energy = doc.append_child("energy"); + pugi::xml_node parameters = energy.append_child("parameters"); + parameters.append_child(pugi::node_pcdata) + .set_value("800 500000 30000 0.1 0.6 0.3"); + + // Initialize discrete distribution and seed + openmc::Discrete dist(energy); + uint64_t seed = openmc::init_seed(0, 0); + auto sample = dist.sample(&seed); + + // Assertions + REQUIRE(dist.x().size() == 3); + REQUIRE(dist.prob().size() == 3); + REQUIRE(dist.alias().size() == 3); + + openmc::vector correct_x = {800, 500000, 30000}; + openmc::vector correct_prob = {0.3, 1.0, 0.9}; + openmc::vector correct_alias = {1, 0, 1}; + + for (size_t i = 0; i < 3; i++) { + REQUIRE(dist.x()[i] == correct_x[i]); + REQUIRE_THAT( + dist.prob()[i], Catch::Matchers::WithinAbs(correct_prob[i], 1e-12)); + REQUIRE(dist.alias()[i] == correct_alias[i]); + } +} diff --git a/tests/cpp_unit_tests/test_file_utils.cpp b/tests/cpp_unit_tests/test_file_utils.cpp new file mode 100644 index 00000000000..3b7a74346bd --- /dev/null +++ b/tests/cpp_unit_tests/test_file_utils.cpp @@ -0,0 +1,32 @@ +#include "openmc/file_utils.h" +#include + +using namespace openmc; + +TEST_CASE("Test get_file_extension") +{ + REQUIRE(get_file_extension("rememberthealamo.png") == "png"); + REQUIRE(get_file_extension("statepoint.20.h5") == "h5"); + REQUIRE(get_file_extension("wEiRDNaa_ame.h4") == "h4"); + REQUIRE(get_file_extension("has_directory/asdf.20.h5") == "h5"); + REQUIRE(get_file_extension("wasssssup_lol") == ""); + REQUIRE(get_file_extension("has_directory/secret_file") == ""); + REQUIRE(get_file_extension("lovely.dir/extensionless_file") == ""); + REQUIRE(get_file_extension("lovely.dir/statepoint.20.h5") == "h5"); + REQUIRE(get_file_extension("lovely.dir/asdf123.cpp") == "cpp"); +} + +TEST_CASE("Test dir_exists") +{ + // not sure how to test this when running on windows? + REQUIRE(dir_exists("/")); + + // if this exists on your system... you deserve for this test to fail + REQUIRE(!dir_exists("/asdfa/asdfasdf/asdgasodgosuihasjkgh/")); +} + +TEST_CASE("Test file_exists") +{ + // Note: not clear how to portably test where a file should exist. + REQUIRE(!file_exists("./should_not_exist/really_do_not_make_this_please")); +} diff --git a/tests/cpp_unit_tests/test_interpolate.cpp b/tests/cpp_unit_tests/test_interpolate.cpp new file mode 100644 index 00000000000..4f19f2b63f3 --- /dev/null +++ b/tests/cpp_unit_tests/test_interpolate.cpp @@ -0,0 +1,51 @@ +#include +#include + +#include +#include + +#include "openmc/interpolate.h" +#include "openmc/search.h" + +using namespace openmc; + +TEST_CASE("Test Lagranian Interpolation") +{ + std::vector xs {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; + std::vector ys {0.0, 1.0, 1.0, 2.0, 3.0, 3.0, 5.0}; + + // ensure we get data points back at the x values + for (int n = 1; n <= 6; n++) { + for (int i = 0; i < xs.size(); i++) { + double x = xs[i]; + double y = ys[i]; + + size_t idx = lower_bound_index(xs.begin(), xs.end(), x); + idx = std::min(idx, xs.size() - n - 1); + double out = interpolate_lagrangian(xs, ys, idx, x, n); + REQUIRE(out == y); + } + } + + // spot checks based on an independent implementation of Lagrangian + // interpolation + std::map>> checks; + checks[1] = {{0.5, 0.5}, {4.5, 3.0}, {2.5, 1.5}, {5.5, 4.0}}; + checks[2] = {{2.5, 1.5}, {4.5, 2.75}, {4.9999, 3.0}, {4.00001, 3.0}}; + checks[3] = {{2.5592, 1.5}, {4.5, 2.9375}, {4.9999, 3.0}, {4.00001, 3.0}}; + + for (auto check_set : checks) { + int order = check_set.first; + auto checks = check_set.second; + + for (auto check : checks) { + double input = check.first; + double exp_output = check.second; + + size_t idx = lower_bound_index(xs.begin(), xs.end(), input); + idx = std::min(idx, xs.size() - order - 1); + double out = interpolate_lagrangian(xs, ys, idx, input, order); + REQUIRE_THAT(out, Catch::Matchers::WithinAbs(exp_output, 1e-04)); + } + } +} \ No newline at end of file diff --git a/tests/cpp_unit_tests/test_tally.cpp b/tests/cpp_unit_tests/test_tally.cpp new file mode 100644 index 00000000000..964d30cc42a --- /dev/null +++ b/tests/cpp_unit_tests/test_tally.cpp @@ -0,0 +1,55 @@ +#include "openmc/tallies/tally.h" +#include + +using namespace openmc; + +TEST_CASE("Test add/set_filter") +{ + // create a new tally object + Tally* tally = Tally::create(); + + // create a new particle filter + Filter* particle_filter = Filter::create("particle"); + + // add the particle filter to the tally + tally->add_filter(particle_filter); + + // the filter should be added to the tally + REQUIRE(tally->filters().size() == 1); + REQUIRE(model::filter_map[particle_filter->id()] == tally->filters(0)); + + // add the particle filter to the tally again + tally->add_filter(particle_filter); + // the tally should have the same number of filters + REQUIRE(tally->filters().size() == 1); + + // create a cell filter + Filter* cell_filter = Filter::create("cell"); + tally->add_filter(cell_filter); + + // now the size of the filters should have increased + REQUIRE(tally->filters().size() == 2); + REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(1)); + + // if we set the filters explicitly there shouldn't be extra filters hanging + // around + tally->set_filters({&cell_filter, 1}); + + REQUIRE(tally->filters().size() == 1); + REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(0)); + + // set filters again using both filters + std::vector filters = {cell_filter, particle_filter}; + tally->set_filters(filters); + + REQUIRE(tally->filters().size() == 2); + REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(0)); + REQUIRE(model::filter_map[particle_filter->id()] == tally->filters(1)); + + // set filters with a duplicate filter, should only add the filter to the tally once + filters = {cell_filter, cell_filter}; + tally->set_filters(filters); + REQUIRE(tally->filters().size() == 1); + REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(0)); + +} \ No newline at end of file diff --git a/tests/micro_xs_simple.csv b/tests/micro_xs_simple.csv new file mode 100644 index 00000000000..146896aa290 --- /dev/null +++ b/tests/micro_xs_simple.csv @@ -0,0 +1,25 @@ +nuclides,reactions,groups,xs +U234,"(n,gamma)",1,22.23198982200245 +U234,fission,1,0.4962074466374984 +U235,"(n,gamma)",1,10.47900897119712 +U235,fission,1,48.41787337164606 +U238,"(n,gamma)",1,0.8673334105437321 +U238,fission,1,0.1046788058876236 +U236,"(n,gamma)",1,8.651710446071224 +U236,fission,1,0.3194839240001929 +O16,"(n,gamma)",1,7.497851000107522e-05 +O16,fission,1,0.0 +O17,"(n,gamma)",1,0.0004079227797153 +O17,fission,1,0.0 +I135,"(n,gamma)",1,6.842395323713929 +I135,fission,1,0.0 +Xe135,"(n,gamma)",1,227463.8642699061 +Xe135,fission,1,0.0 +Xe136,"(n,gamma)",1,0.0231789603475358 +Xe136,fission,1,0.0 +Cs135,"(n,gamma)",1,2.1721665580713623 +Cs135,fission,1,0.0 +Gd157,"(n,gamma)",1,12786.099392370175 +Gd157,fission,1,0.0 +Gd156,"(n,gamma)",1,3.4006085445846983 +Gd156,fission,1,0.0 diff --git a/tests/regression_tests/__init__.py b/tests/regression_tests/__init__.py index a887448c111..ba48fc01e9e 100644 --- a/tests/regression_tests/__init__.py +++ b/tests/regression_tests/__init__.py @@ -1,3 +1,5 @@ +import pytest + # Test configuration options for regression tests config = { 'event' : False, @@ -8,3 +10,25 @@ 'update': False, 'build_inputs': False } + + +def assert_atoms_equal(res_ref, res_test, tol=1e-5): + for mat in res_test[0].index_mat: + for nuc in res_test[0].index_nuc: + _, y_test = res_test.get_atoms(mat, nuc) + _, y_ref = res_ref.get_atoms(mat, nuc) + assert y_test == pytest.approx(y_ref, rel=tol), \ + f'Atoms not equal for material {mat}, nuclide {nuc}\n' \ + f'y_ref={y_ref}\ny_test={y_test}' + + +def assert_reaction_rates_equal(res_ref, res_test, tol=1e-5): + for reactions in res_test[0].rates: + for mat in reactions.index_mat: + for nuc in reactions.index_nuc: + for rx in reactions.index_rx: + y_test = res_test.get_reaction_rate(mat, nuc, rx)[1] + y_ref = res_ref.get_reaction_rate(mat, nuc, rx)[1] + assert y_test == pytest.approx(y_ref, rel=tol), \ + f'Reaction rate not equal for material {mat}, nuclide '\ + f'{nuc}, {rx}\ny_ref={y_ref}\ny_test={y_test}' diff --git a/tests/regression_tests/adj_cell_rotation/inputs_true.dat b/tests/regression_tests/adj_cell_rotation/inputs_true.dat index 24b00199beb..7e2a0cf628f 100644 --- a/tests/regression_tests/adj_cell_rotation/inputs_true.dat +++ b/tests/regression_tests/adj_cell_rotation/inputs_true.dat @@ -1,38 +1,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 10000 - 10 - 5 - - - -4.0 -4.0 -4.0 4.0 4.0 4.0 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 10000 + 10 + 5 + + + -4.0 -4.0 -4.0 4.0 4.0 4.0 + + + + diff --git a/tests/regression_tests/adj_cell_rotation/results_true.dat b/tests/regression_tests/adj_cell_rotation/results_true.dat index 2bdfe433054..b3df12e71fe 100644 --- a/tests/regression_tests/adj_cell_rotation/results_true.dat +++ b/tests/regression_tests/adj_cell_rotation/results_true.dat @@ -1,2 +1,2 @@ k-combined: -4.381997E-01 1.286263E-03 +4.403987E-01 1.514158E-03 diff --git a/tests/regression_tests/adj_cell_rotation/test.py b/tests/regression_tests/adj_cell_rotation/test.py index 25aada5aada..3fe24053665 100644 --- a/tests/regression_tests/adj_cell_rotation/test.py +++ b/tests/regression_tests/adj_cell_rotation/test.py @@ -24,14 +24,14 @@ def model(): # Create one cell on top of the other. Only one # has a rotation - box = openmc.rectangular_prism(15., 15., 'z', boundary_type='vacuum') + box = openmc.model.RectangularPrism(15., 15., 'z', boundary_type='vacuum') lower_z = openmc.ZPlane(-7.5, boundary_type='vacuum') upper_z = openmc.ZPlane(22.5, boundary_type='vacuum') middle_z = openmc.ZPlane(7.5) - lower_cell = openmc.Cell(fill=univ, region=box & +lower_z & -middle_z) + lower_cell = openmc.Cell(fill=univ, region=-box & +lower_z & -middle_z) lower_cell.rotation = (10, 20, 30) - upper_cell = openmc.Cell(fill=univ, region=box & +middle_z & -upper_z) + upper_cell = openmc.Cell(fill=univ, region=-box & +middle_z & -upper_z) upper_cell.translation = (0, 0, 15) model.geometry = openmc.Geometry(root=[lower_cell, upper_cell]) @@ -40,7 +40,7 @@ def model(): model.settings.inactive = 5 model.settings.batches = 10 source_box = openmc.stats.Box((-4., -4., -4.), (4., 4., 4.)) - model.settings.source = openmc.Source(space=source_box) + model.settings.source = openmc.IndependentSource(space=source_box) return model diff --git a/tests/regression_tests/albedo_box/__init__.py b/tests/regression_tests/albedo_box/__init__.py new file mode 100755 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/albedo_box/geometry.xml b/tests/regression_tests/albedo_box/geometry.xml new file mode 100644 index 00000000000..7d0e9b5f5dd --- /dev/null +++ b/tests/regression_tests/albedo_box/geometry.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/tests/regression_tests/infinite_cell/materials.xml b/tests/regression_tests/albedo_box/materials.xml similarity index 58% rename from tests/regression_tests/infinite_cell/materials.xml rename to tests/regression_tests/albedo_box/materials.xml index 6acd8df74b4..2472a747174 100644 --- a/tests/regression_tests/infinite_cell/materials.xml +++ b/tests/regression_tests/albedo_box/materials.xml @@ -6,9 +6,4 @@ - - - - - diff --git a/tests/regression_tests/albedo_box/results_true.dat b/tests/regression_tests/albedo_box/results_true.dat new file mode 100644 index 00000000000..0f571f2459d --- /dev/null +++ b/tests/regression_tests/albedo_box/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +1.590800E+00 4.251788E-03 diff --git a/tests/regression_tests/infinite_cell/settings.xml b/tests/regression_tests/albedo_box/settings.xml similarity index 59% rename from tests/regression_tests/infinite_cell/settings.xml rename to tests/regression_tests/albedo_box/settings.xml index 70b4e802f83..cc66683057c 100644 --- a/tests/regression_tests/infinite_cell/settings.xml +++ b/tests/regression_tests/albedo_box/settings.xml @@ -6,10 +6,4 @@ 5 1000 - - - -4 -4 -4 4 4 4 - - - diff --git a/tests/regression_tests/albedo_box/test.py b/tests/regression_tests/albedo_box/test.py new file mode 100755 index 00000000000..179f58e5b36 --- /dev/null +++ b/tests/regression_tests/albedo_box/test.py @@ -0,0 +1,6 @@ +from tests.testing_harness import TestHarness + + +def test_albedo_box(): + harness = TestHarness('statepoint.10.h5') + harness.main() diff --git a/tests/regression_tests/asymmetric_lattice/inputs_true.dat b/tests/regression_tests/asymmetric_lattice/inputs_true.dat index bbdc79715b0..302ef24c200 100644 --- a/tests/regression_tests/asymmetric_lattice/inputs_true.dat +++ b/tests/regression_tests/asymmetric_lattice/inputs_true.dat @@ -1,19 +1,168 @@ - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -31,197 +180,50 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 3 3 - -32.13 -32.13 - + + + 21.42 21.42 + 3 3 + -32.13 -32.13 + 8 7 7 8 8 8 7 7 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -32 -32 0 32 32 32 - - - - - - - 27 - - - 1 - nu-fission - - + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -32 -32 0 32 32 32 + + + true + + + + + + 27 + + + 1 + nu-fission + + + diff --git a/tests/regression_tests/asymmetric_lattice/results_true.dat b/tests/regression_tests/asymmetric_lattice/results_true.dat index 66ee9cdd282..741327d80b3 100644 --- a/tests/regression_tests/asymmetric_lattice/results_true.dat +++ b/tests/regression_tests/asymmetric_lattice/results_true.dat @@ -1 +1 @@ -73bae264aaca0988fd2ae207722461d161ddbcf9aef083b99a2efc536b09665bbe839d6cae89b32ebab3089a820a2c35ae63a88d5869f0c91b0d6c2f2e090e55 \ No newline at end of file +b0ca1fb0436732188b1a199b3250ca9a33782f8fc379b0f7ff9c582e0c794b0a0470df063cafd0b05e802b26f61eaaf9ff5c0a8a672a933246acf49eed3ebf9f \ No newline at end of file diff --git a/tests/regression_tests/asymmetric_lattice/test.py b/tests/regression_tests/asymmetric_lattice/test.py index 2197a1e7e2c..fadf272ffd3 100644 --- a/tests/regression_tests/asymmetric_lattice/test.py +++ b/tests/regression_tests/asymmetric_lattice/test.py @@ -54,8 +54,10 @@ def __init__(self, *args, **kwargs): self._model.tallies.append(tally) # Specify summary output and correct source sampling box - self._model.settings.source = openmc.Source(space=openmc.stats.Box( - [-32, -32, 0], [32, 32, 32], only_fissionable = True)) + self._model.settings.source = openmc.IndependentSource( + space=openmc.stats.Box([-32, -32, 0], [32, 32, 32]), + constraints={'fissionable': True} + ) def _get_results(self, hash_output=True): """Digest info in statepoint and summary and return as a string.""" diff --git a/tests/regression_tests/cmfd_feed/geometry.xml b/tests/regression_tests/cmfd_feed/geometry.xml deleted file mode 100644 index 73ea679c4c2..00000000000 --- a/tests/regression_tests/cmfd_feed/geometry.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - 0 - -1 2 -3 4 -5 6 - 1 - - - - - x-plane - 10 - vacuum - - - x-plane - -10 - vacuum - - - y-plane - 1 - reflective - - - y-plane - -1 - reflective - - - z-plane - 1 - reflective - - - z-plane - -1 - reflective - - - diff --git a/tests/regression_tests/cmfd_feed/materials.xml b/tests/regression_tests/cmfd_feed/materials.xml deleted file mode 100644 index 70580e3a8db..00000000000 --- a/tests/regression_tests/cmfd_feed/materials.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/tests/regression_tests/cmfd_feed/model.xml b/tests/regression_tests/cmfd_feed/model.xml new file mode 100644 index 00000000000..b3fe853b269 --- /dev/null +++ b/tests/regression_tests/cmfd_feed/model.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 20 + 10 + + + -10.0 -1.0 -1.0 10.0 1.0 1.0 + + + 10 + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + 1 + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_feed/results_true.dat b/tests/regression_tests/cmfd_feed/results_true.dat index 90d8820d0c0..f5f22d9acd1 100644 --- a/tests/regression_tests/cmfd_feed/results_true.dat +++ b/tests/regression_tests/cmfd_feed/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.159021E+00 8.924006E-03 +1.164262E+00 9.207592E-03 tally 1: -1.140162E+01 -1.306940E+01 -2.093739E+01 -4.404780E+01 -2.914408E+01 -8.521010E+01 -3.483677E+01 -1.216824E+02 -3.778463E+01 -1.429632E+02 -3.810371E+01 -1.455108E+02 -3.465248E+01 -1.207868E+02 -2.862033E+01 -8.218833E+01 -2.086025E+01 -4.365941E+01 -1.130798E+01 -1.286509E+01 +1.156972E+01 +1.339924E+01 +2.136306E+01 +4.567185E+01 +2.859527E+01 +8.195821E+01 +3.470754E+01 +1.207851E+02 +3.766403E+01 +1.422263E+02 +3.778821E+01 +1.432660E+02 +3.573197E+01 +1.278854E+02 +2.849979E+01 +8.135515E+01 +2.073803E+01 +4.303374E+01 +1.112117E+01 +1.242944E+01 tally 2: -2.234393E+01 -2.516414E+01 -1.555024E+01 -1.218205E+01 -4.087743E+01 -8.401702E+01 -2.883717E+01 -4.185393E+01 -5.635166E+01 -1.595225E+02 -3.998857E+01 -8.040398E+01 -6.887126E+01 -2.379185E+02 -4.903103E+01 -1.206174E+02 -7.452051E+01 -2.785675E+02 -5.295380E+01 -1.406900E+02 -7.495422E+01 -2.819070E+02 -5.333191E+01 -1.427474E+02 -6.921815E+01 -2.408568E+02 -4.928246E+01 -1.221076E+02 -5.668548E+01 -1.612556E+02 -4.035856E+01 -8.181159E+01 -4.259952E+01 -9.112630E+01 -3.026717E+01 -4.600625E+01 -2.310563E+01 -2.688378E+01 -1.615934E+01 -1.315528E+01 +2.388054E+01 +2.875255E+01 +1.667791E+01 +1.403426E+01 +4.224771E+01 +8.942109E+01 +2.993088E+01 +4.490335E+01 +5.689839E+01 +1.625557E+02 +4.043633E+01 +8.212299E+01 +6.764024E+01 +2.297126E+02 +4.807902E+01 +1.161468E+02 +7.314835E+01 +2.684645E+02 +5.203584E+01 +1.359261E+02 +7.375727E+01 +2.733105E+02 +5.252944E+01 +1.386205E+02 +6.909571E+01 +2.397721E+02 +4.922548E+01 +1.217465E+02 +5.685978E+01 +1.621746E+02 +4.051938E+01 +8.237277E+01 +4.185562E+01 +8.784067E+01 +2.983570E+01 +4.467414E+01 +2.238373E+01 +2.520356E+01 +1.566758E+01 +1.234103E+01 tally 3: -1.496375E+01 -1.128154E+01 -9.905641E-01 -5.125710E-02 -2.774937E+01 -3.877241E+01 -1.786861E+00 -1.627655E-01 -3.849739E+01 -7.453828E+01 -2.494135E+00 -3.158098E-01 -4.724085E+01 -1.119901E+02 -3.031174E+00 -4.653741E-01 -5.096719E+01 -1.303552E+02 -3.254375E+00 -5.351020E-01 -5.133808E+01 -1.322892E+02 -3.383595E+00 -5.798798E-01 -4.756072E+01 -1.137527E+02 -3.001917E+00 -4.558247E-01 -3.887437E+01 -7.593416E+01 -2.517908E+00 -3.221926E-01 -2.910687E+01 -4.255173E+01 -1.817765E+00 -1.678763E-01 -1.557241E+01 -1.222026E+01 -9.852737E-01 -5.002659E-02 +1.609520E+01 +1.307542E+01 +1.033429E+00 +5.510889E-02 +2.877073E+01 +4.149542E+01 +1.964219E+00 +1.954692E-01 +3.896816E+01 +7.629752E+01 +2.484053E+00 +3.103733E-01 +4.634285E+01 +1.079367E+02 +2.974750E+00 +4.468223E-01 +5.007964E+01 +1.259202E+02 +3.181802E+00 +5.103621E-01 +5.058915E+01 +1.286193E+02 +3.249442E+00 +5.337712E-01 +4.744464E+01 +1.131026E+02 +3.067644E+00 +4.736335E-01 +3.900632E+01 +7.634433E+01 +2.443552E+00 +3.028060E-01 +2.874166E+01 +4.146375E+01 +1.810421E+00 +1.671667E-01 +1.509222E+01 +1.145579E+01 +1.014919E+00 +5.391053E-02 tally 4: -3.047490E+00 -4.661458E-01 +3.148231E+00 +4.974555E-01 0.000000E+00 0.000000E+00 -2.635775E+00 -3.524426E-01 -5.357229E+00 -1.440049E+00 +2.805439E+00 +3.982239E-01 +5.574031E+00 +1.561105E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.357229E+00 -1.440049E+00 -2.635775E+00 -3.524426E-01 -4.982072E+00 -1.251449E+00 -7.228146E+00 -2.620353E+00 +5.574031E+00 +1.561105E+00 +2.805439E+00 +3.982239E-01 +5.171038E+00 +1.344877E+00 +7.372031E+00 +2.725420E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.228146E+00 -2.620353E+00 -4.982072E+00 -1.251449E+00 -7.082265E+00 -2.520047E+00 -8.736529E+00 -3.831244E+00 +7.372031E+00 +2.725420E+00 +5.171038E+00 +1.344877E+00 +6.946847E+00 +2.424850E+00 +8.496610E+00 +3.627542E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.736529E+00 -3.831244E+00 -7.082265E+00 -2.520047E+00 -8.474631E+00 -3.607043E+00 -9.346623E+00 -4.390819E+00 +8.496610E+00 +3.627542E+00 +6.946847E+00 +2.424850E+00 +8.479501E+00 +3.607280E+00 +9.261869E+00 +4.305912E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.346623E+00 -4.390819E+00 -8.474631E+00 -3.607043E+00 -9.496684E+00 -4.522478E+00 -9.532822E+00 -4.559003E+00 +9.261869E+00 +4.305912E+00 +8.479501E+00 +3.607280E+00 +9.232858E+00 +4.278432E+00 +9.306384E+00 +4.348594E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.532822E+00 -4.559003E+00 -9.496684E+00 -4.522478E+00 -9.404949E+00 -4.446260E+00 -8.550930E+00 -3.668401E+00 +9.306384E+00 +4.348594E+00 +9.232858E+00 +4.278432E+00 +9.299764E+00 +4.347828E+00 +8.511976E+00 +3.639893E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.550930E+00 -3.668401E+00 -9.404949E+00 -4.446260E+00 -8.785273E+00 -3.874792E+00 -7.128863E+00 -2.554326E+00 +8.511976E+00 +3.639893E+00 +9.299764E+00 +4.347828E+00 +8.726086E+00 +3.819567E+00 +7.147277E+00 +2.562747E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.128863E+00 -2.554326E+00 -8.785273E+00 -3.874792E+00 -7.408549E+00 -2.755885E+00 -5.094992E+00 -1.305737E+00 +7.147277E+00 +2.562747E+00 +8.726086E+00 +3.819567E+00 +7.218790E+00 +2.612243E+00 +5.018287E+00 +1.263077E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.094992E+00 -1.305737E+00 -7.408549E+00 -2.755885E+00 -5.532149E+00 -1.537289E+00 -2.812344E+00 -3.997146E-01 +5.018287E+00 +1.263077E+00 +7.218790E+00 +2.612243E+00 +5.443494E+00 +1.487018E+00 +2.732334E+00 +3.773047E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.812344E+00 -3.997146E-01 -5.532149E+00 -1.537289E+00 -3.063251E+00 -4.728672E-01 +2.732334E+00 +3.773047E-01 +5.443494E+00 +1.487018E+00 +3.044773E+00 +4.655756E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,144 +345,144 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -1.496000E+01 -1.127586E+01 -2.280081E+00 -2.675609E-01 -2.774503E+01 -3.876011E+01 -3.908836E+00 -7.703029E-01 -3.848706E+01 -7.449836E+01 -5.299924E+00 -1.422782E+00 -4.723172E+01 -1.119459E+02 -6.450156E+00 -2.105590E+00 -5.095931E+01 -1.303132E+02 -7.050681E+00 -2.515092E+00 -5.133412E+01 -1.322694E+02 -6.853429E+00 -2.384127E+00 -4.754621E+01 -1.136848E+02 -6.370026E+00 -2.058896E+00 -3.886829E+01 -7.591042E+01 -5.266816E+00 -1.400495E+00 -2.910277E+01 -4.253981E+01 -4.090844E+00 -8.442500E-01 -1.556949E+01 -1.221526E+01 -2.266123E+00 -2.641551E-01 +1.609029E+01 +1.306718E+01 +2.230601E+00 +2.559496E-01 +2.876780E+01 +4.148686E+01 +3.835952E+00 +7.456562E-01 +3.895738E+01 +7.625344E+01 +4.841024E+00 +1.197335E+00 +4.633595E+01 +1.079043E+02 +6.236821E+00 +1.963311E+00 +5.007472E+01 +1.258967E+02 +6.749745E+00 +2.297130E+00 +5.058336E+01 +1.285894E+02 +6.727612E+00 +2.315656E+00 +4.743869E+01 +1.130735E+02 +6.338193E+00 +2.042159E+00 +3.899838E+01 +7.631289E+01 +5.187573E+00 +1.359733E+00 +2.873434E+01 +4.144233E+01 +3.815610E+00 +7.367619E-01 +1.509020E+01 +1.145268E+01 +2.125767E+00 +2.341894E-01 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.161531E+00 -1.182724E+00 -1.169653E+00 -1.164722E+00 -1.164583E+00 -1.162952E+00 -1.167024E+00 -1.164509E+00 -1.165693E+00 -1.170623E+00 -1.166618E+00 -1.170805E+00 -1.170962E+00 -1.170964E+00 -1.168224E+00 -1.169864E+00 +1.129918E+00 +1.143848E+00 +1.147976E+00 +1.151534E+00 +1.152378E+00 +1.148219E+00 +1.150402E+00 +1.154647E+00 +1.156159E+00 +1.160048E+00 +1.167441E+00 +1.168163E+00 +1.168629E+00 +1.164120E+00 +1.165051E+00 +1.169177E+00 cmfd entropy -3.206619E+00 -3.205815E+00 -3.208678E+00 -3.210820E+00 -3.217023E+00 -3.215014E+00 -3.214592E+00 -3.215913E+00 -3.214998E+00 -3.213644E+00 -3.210755E+00 -3.210496E+00 -3.212488E+00 -3.211553E+00 -3.212999E+00 -3.214052E+00 +3.224769E+00 +3.225945E+00 +3.227421E+00 +3.226174E+00 +3.224429E+00 +3.227049E+00 +3.230710E+00 +3.230315E+00 +3.226825E+00 +3.226655E+00 +3.226588E+00 +3.224155E+00 +3.223246E+00 +3.222640E+00 +3.223920E+00 +3.222838E+00 cmfd balance -4.99833E-03 -5.64677E-03 -3.62795E-03 -3.91962E-03 -3.87172E-03 -2.48450E-03 -3.15554E-03 -2.49335E-03 -2.31973E-03 -2.19156E-03 -2.31352E-03 -2.03401E-03 -1.80242E-03 -1.65868E-03 -1.47543E-03 -1.49706E-03 +3.90454E-03 +4.08089E-03 +3.46511E-03 +4.09535E-03 +2.62009E-03 +2.23559E-03 +2.54033E-03 +2.12799E-03 +2.25864E-03 +1.85766E-03 +1.49916E-03 +1.63471E-03 +1.48377E-03 +1.59800E-03 +1.37354E-03 +1.32853E-03 cmfd dominance ratio -5.283E-01 -5.289E-01 -5.305E-01 -5.327E-01 -5.377E-01 -5.360E-01 -5.353E-01 -4.983E-01 -5.379E-01 -5.370E-01 -5.359E-01 -5.349E-01 -5.364E-01 -5.347E-01 -5.360E-01 -5.378E-01 +5.539E-01 +5.537E-01 +5.536E-01 +5.515E-01 +5.512E-01 +5.514E-01 +5.518E-01 +5.507E-01 +5.500E-01 +5.497E-01 +5.477E-01 +5.461E-01 +5.444E-01 +5.445E-01 +5.454E-01 +5.441E-01 cmfd openmc source comparison -1.291827E-02 -1.027137E-02 -8.738370E-03 -6.854409E-03 -4.188357E-03 -4.941359E-03 -5.139239E-03 -4.244784E-03 -4.240559E-03 -3.375424E-03 -3.716858E-03 -3.595700E-03 -3.626952E-03 -3.999302E-03 -2.431760E-03 -1.673200E-03 +9.875240E-03 +1.106163E-02 +9.847628E-03 +6.065921E-03 +5.772039E-03 +4.615656E-03 +4.244331E-03 +3.694299E-03 +3.545814E-03 +3.213063E-03 +3.467537E-03 +3.383489E-03 +3.697591E-03 +3.937358E-03 +3.369124E-03 +3.190359E-03 cmfd source -4.185460E-02 -7.636314E-02 -1.075536E-01 -1.307167E-01 -1.400879E-01 -1.459944E-01 -1.297413E-01 -1.084649E-01 -7.772031E-02 -4.150306E-02 +4.360494E-02 +8.397599E-02 +1.074181E-01 +1.294531E-01 +1.385611E-01 +1.407934E-01 +1.325191E-01 +1.044311E-01 +7.660359E-02 +4.263941E-02 diff --git a/tests/regression_tests/cmfd_feed/settings.xml b/tests/regression_tests/cmfd_feed/settings.xml deleted file mode 100644 index 24b0b6ab508..00000000000 --- a/tests/regression_tests/cmfd_feed/settings.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - eigenvalue - 20 - 10 - 1000 - - - - - box - -10 -1 -1 10 1 1 - - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - 10 - - diff --git a/tests/regression_tests/cmfd_feed/tallies.xml b/tests/regression_tests/cmfd_feed/tallies.xml deleted file mode 100644 index c869711147f..00000000000 --- a/tests/regression_tests/cmfd_feed/tallies.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - regular - -10 -1 -1 - 10 1 1 - 10 1 1 - - - - mesh - 1 - - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_feed/test.py b/tests/regression_tests/cmfd_feed/test.py index fa22b0fe36d..d513dee2aa5 100644 --- a/tests/regression_tests/cmfd_feed/test.py +++ b/tests/regression_tests/cmfd_feed/test.py @@ -111,7 +111,7 @@ def test_cmfd_write_matrices(): # Load flux vector from numpy output file flux_np = np.load('fluxvec.npy') # Load flux from data file - flux_dat = np.loadtxt("fluxvec.dat", delimiter='\n') + flux_dat = np.loadtxt("fluxvec.dat") # Compare flux from numpy file, .dat file, and from simulation assert(np.all(np.isclose(flux_np, cmfd_run._phi))) diff --git a/tests/regression_tests/cmfd_feed_2g/results_true.dat b/tests/regression_tests/cmfd_feed_2g/results_true.dat index d27e291e7f4..2b61d9f4e81 100644 --- a/tests/regression_tests/cmfd_feed_2g/results_true.dat +++ b/tests/regression_tests/cmfd_feed_2g/results_true.dat @@ -1,112 +1,112 @@ k-combined: -1.021592E+00 7.184545E-03 +1.035567E+00 9.463160E-03 tally 1: -1.158654E+02 -1.342707E+03 -1.151877E+02 -1.327269E+03 -1.153781E+02 -1.331661E+03 -1.151151E+02 -1.325578E+03 +1.146535E+02 +1.315267E+03 +1.157458E+02 +1.340166E+03 +1.140491E+02 +1.301364E+03 +1.146589E+02 +1.315433E+03 tally 2: -4.299142E+01 -9.258204E+01 -6.324043E+01 -2.003732E+02 -1.860419E+02 -1.731270E+03 -1.037502E+02 -5.383979E+02 -4.229132E+01 -8.952923E+01 -6.264581E+01 -1.965074E+02 -1.838340E+02 -1.690620E+03 -1.029415E+02 -5.299801E+02 -4.314759E+01 -9.337463E+01 -6.404361E+01 -2.056541E+02 -1.836548E+02 -1.687065E+03 -1.028141E+02 -5.287334E+02 -4.256836E+01 -9.079806E+01 -6.336524E+01 -2.012627E+02 -1.837730E+02 -1.689124E+03 -1.021852E+02 -5.222598E+02 +4.319968E+01 +9.360083E+01 +6.373035E+01 +2.038056E+02 +1.889646E+02 +1.812892E+03 +1.024866E+02 +5.254528E+02 +4.323262E+01 +9.360200E+01 +6.363111E+01 +2.028178E+02 +1.849746E+02 +1.711533E+03 +1.034532E+02 +5.352768E+02 +4.296541E+01 +9.249656E+01 +6.346919E+01 +2.018659E+02 +1.888697E+02 +1.812037E+03 +1.025707E+02 +5.262261E+02 +4.691085E+01 +1.269707E+02 +6.299377E+01 +1.990497E+02 +1.853864E+02 +1.719984E+03 +1.023015E+02 +5.235858E+02 tally 3: -5.973628E+01 -1.787876E+02 +6.034963E+01 +1.827718E+02 0.000000E+00 0.000000E+00 -1.724004E-02 -2.766372E-05 -4.379655E+00 -9.682433E-01 -3.484795E+00 -6.104792E-01 +1.865665E-02 +4.244195E-05 +4.170941E+00 +8.769372E-01 +3.453368E+00 +5.989168E-01 0.000000E+00 0.000000E+00 -9.874445E+01 -4.877157E+02 -8.886034E-01 -4.009294E-02 -5.923584E+01 -1.757014E+02 +9.743205E+01 +4.749420E+02 +8.570316E-01 +3.807993E-02 +6.005903E+01 +1.807233E+02 0.000000E+00 0.000000E+00 -1.733168E-02 -3.950365E-05 -4.212697E+00 -8.996477E-01 -3.503046E+00 -6.150657E-01 +1.885450E-02 +3.653402E-05 +4.323863E+00 +9.447512E-01 +3.465465E+00 +6.022861E-01 0.000000E+00 0.000000E+00 -9.780995E+01 -4.784706E+02 -8.648283E-01 -3.899383E-02 -6.057017E+01 -1.839745E+02 +9.843481E+01 +4.846158E+02 +9.048150E-01 +4.205551E-02 +5.996660E+01 +1.802150E+02 0.000000E+00 0.000000E+00 -2.056597E-02 -3.726744E-05 -4.280120E+00 -9.288225E-01 -3.378205E+00 -5.730279E-01 +1.221444E-02 +2.263445E-05 +4.301287E+00 +9.309882E-01 +3.456076E+00 +5.992144E-01 0.000000E+00 0.000000E+00 -9.790474E+01 -4.794523E+02 -9.073765E-01 -4.204720E-02 -5.990874E+01 -1.799224E+02 +9.761231E+01 +4.765834E+02 +8.434644E-01 +3.728180E-02 +5.961891E+01 +1.783106E+02 0.000000E+00 0.000000E+00 -1.881508E-02 -4.239902E-05 -4.206916E+00 -8.926965E-01 -3.478009E+00 -6.067461E-01 +1.500709E-02 +3.541280E-05 +4.155669E+00 +8.713442E-01 +3.455342E+00 +6.006426E-01 0.000000E+00 0.000000E+00 -9.715787E+01 -4.721453E+02 -8.602457E-01 -3.786346E-02 +9.726798E+01 +4.733393E+02 +9.202611E-01 +4.390503E-02 tally 4: 0.000000E+00 0.000000E+00 @@ -116,14 +116,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.735001E+00 -3.821211E+00 -3.708124E+01 -6.880811E+01 -8.713175E+00 -3.807176E+00 -3.703536E+01 -6.862245E+01 +8.943264E+00 +4.008855E+00 +3.661063E+01 +6.704808E+01 +8.945553E+00 +4.011707E+00 +3.696832E+01 +6.835286E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -132,14 +132,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.851322E+00 -3.930766E+00 -3.716154E+01 -6.908449E+01 -8.892499E+00 -3.970458E+00 -3.718644E+01 -6.918810E+01 +8.844569E+00 +3.924591E+00 +3.666726E+01 +6.726522E+01 +8.769637E+00 +3.855006E+00 +3.654115E+01 +6.680777E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -156,14 +156,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.713175E+00 -3.807176E+00 -3.703536E+01 -6.862245E+01 -8.735001E+00 -3.821211E+00 -3.708124E+01 -6.880811E+01 +8.945553E+00 +4.011707E+00 +3.696832E+01 +6.835286E+01 +8.943264E+00 +4.008855E+00 +3.661063E+01 +6.704808E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -180,14 +180,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.915310E+00 -3.982710E+00 -3.682783E+01 -6.786998E+01 -8.800405E+00 -3.881868E+00 -3.692302E+01 -6.819716E+01 +8.648474E+00 +3.752219E+00 +3.689442E+01 +6.808997E+01 +8.757378E+00 +3.850408E+00 +3.716920E+01 +6.909715E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -212,22 +212,22 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.659918E+00 -3.761908E+00 -3.709957E+01 -6.884298E+01 -8.796329E+00 -3.881588E+00 -3.693599E+01 -6.825932E+01 -8.892499E+00 -3.970458E+00 -3.718644E+01 -6.918810E+01 -8.851322E+00 -3.930766E+00 -3.716154E+01 -6.908449E+01 +8.783669E+00 +3.870748E+00 +3.687358E+01 +6.802581E+01 +8.755250E+00 +3.846298E+00 +3.660278E+01 +6.704349E+01 +8.769637E+00 +3.855006E+00 +3.654115E+01 +6.680777E+01 +8.844569E+00 +3.924591E+00 +3.666726E+01 +6.726522E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -252,14 +252,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.796329E+00 -3.881588E+00 -3.693599E+01 -6.825932E+01 -8.659918E+00 -3.761908E+00 -3.709957E+01 -6.884298E+01 +8.755250E+00 +3.846298E+00 +3.660278E+01 +6.704349E+01 +8.783669E+00 +3.870748E+00 +3.687358E+01 +6.802581E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -268,14 +268,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.800405E+00 -3.881868E+00 -3.692302E+01 -6.819716E+01 -8.915310E+00 -3.982710E+00 -3.682783E+01 -6.786998E+01 +8.757378E+00 +3.850408E+00 +3.716920E+01 +6.909715E+01 +8.648474E+00 +3.752219E+00 +3.689442E+01 +6.808997E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -301,133 +301,133 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -5.975352E+01 -1.788900E+02 -1.022213E+02 -5.226556E+02 -1.378440E+01 -9.544964E+00 -4.668065E+01 -1.090372E+02 -5.925317E+01 -1.758044E+02 -1.013043E+02 -5.132587E+02 -1.356187E+01 -9.210736E+00 -4.606346E+01 -1.061497E+02 -6.059074E+01 -1.840993E+02 -1.012721E+02 -5.130091E+02 -1.356441E+01 -9.262377E+00 -4.634250E+01 -1.074283E+02 -5.992755E+01 -1.800342E+02 -1.006299E+02 -5.065012E+02 -1.370402E+01 -9.450980E+00 -4.575433E+01 -1.047310E+02 +6.036829E+01 +1.828885E+02 +1.008777E+02 +5.091033E+02 +1.353211E+01 +9.188155E+00 +4.618716E+01 +1.067410E+02 +6.007789E+01 +1.808371E+02 +1.018892E+02 +5.192269E+02 +1.357961E+01 +9.247052E+00 +4.618560E+01 +1.067058E+02 +5.997882E+01 +1.802895E+02 +1.010597E+02 +5.108478E+02 +1.374955E+01 +9.502494E+00 +4.619500E+01 +1.067547E+02 +5.963392E+01 +1.783999E+02 +1.007134E+02 +5.074700E+02 +1.319398E+01 +8.734106E+00 +4.586295E+01 +1.052870E+02 cmfd indices 2.000000E+00 2.000000E+00 1.000000E+00 2.000000E+00 k cmfd -1.037231E+00 -1.035671E+00 -1.042384E+00 -1.033525E+00 -1.031304E+00 -1.029654E+00 -1.031704E+00 -1.032213E+00 -1.030500E+00 -1.036227E+00 -1.034924E+00 -1.035753E+00 -1.034679E+00 -1.035096E+00 -1.033818E+00 -1.030023E+00 +1.018115E+00 +1.022665E+00 +1.020323E+00 +1.020653E+00 +1.021036E+00 +1.020623E+00 +1.021482E+00 +1.025450E+00 +1.027292E+00 +1.028065E+00 +1.027065E+00 +1.024275E+00 +1.025309E+00 +1.026039E+00 +1.026700E+00 +1.023865E+00 cmfd entropy -1.999702E+00 -1.999790E+00 -1.999713E+00 -1.999852E+00 -1.999820E+00 -1.999667E+00 -1.999553E+00 -1.999649E+00 -1.999398E+00 -1.999527E+00 -1.999648E+00 -1.999607E+00 +1.998965E+00 +1.999214E+00 +1.999348E+00 +1.999366E+00 +1.999564E+00 +1.999453E+00 1.999533E+00 -1.999684E+00 -1.999714E+00 -1.999812E+00 +1.999630E+00 +1.999739E+00 +1.999588E+00 +1.999581E+00 +1.999719E+00 +1.999773E+00 +1.999764E+00 +1.999821E+00 +1.999843E+00 cmfd balance -7.33587E-04 -1.00987E-03 -8.26985E-04 -5.20809E-04 -6.47932E-04 -9.69990E-04 -8.62860E-04 -4.92175E-04 -5.80764E-04 -4.49167E-04 -4.05541E-04 -4.13811E-04 -4.27271E-04 -3.64944E-04 -3.43522E-04 -2.82842E-04 +5.73174E-04 +7.55398E-04 +1.46671E-03 +6.39625E-04 +8.19008E-04 +1.93449E-03 +1.15900E-03 +1.01690E-03 +5.62788E-04 +6.90450E-04 +6.01060E-04 +5.73418E-04 +4.37190E-04 +4.82966E-04 +4.09700E-04 +3.45096E-04 cmfd dominance ratio -6.259E-03 -6.252E-03 -6.292E-03 -6.347E-03 -6.360E-03 -6.403E-03 -6.375E-03 -6.400E-03 -6.374E-03 -6.343E-03 -6.331E-03 -6.312E-03 -6.305E-03 -6.271E-03 -6.267E-03 -6.265E-03 +6.264E-03 +6.142E-03 +5.987E-03 +6.082E-03 +5.895E-03 +5.939E-03 +5.910E-03 +5.948E-03 +6.013E-03 +6.017E-03 +6.024E-03 +6.008E-03 +5.976E-03 +5.987E-03 +5.967E-03 +5.929E-03 cmfd openmc source comparison -7.908947E-05 -7.452591E-05 -9.249409E-05 -8.223037E-05 -7.355125E-05 -8.926808E-05 -9.363510E-05 -7.628519E-05 -9.019193E-05 -7.130550E-05 -5.947633E-05 -5.744157E-05 -6.093797E-05 -4.505304E-05 -4.430670E-05 -3.019083E-05 +4.832872E-05 +6.552342E-05 +7.516800E-05 +7.916087E-05 +9.022260E-05 +8.574478E-05 +7.891622E-05 +7.281636E-05 +7.750571E-05 +6.565408E-05 +6.078665E-05 +5.834343E-05 +4.758176E-05 +5.723990E-05 +4.994116E-05 +4.116808E-05 cmfd source -2.557606E-01 -2.464707E-01 -2.518098E-01 -2.459589E-01 +2.455663E-01 +2.553511E-01 +2.512257E-01 +2.478570E-01 0.000000E+00 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/cmfd_feed_expanding_window/geometry.xml b/tests/regression_tests/cmfd_feed_expanding_window/geometry.xml deleted file mode 100644 index 73ea679c4c2..00000000000 --- a/tests/regression_tests/cmfd_feed_expanding_window/geometry.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - 0 - -1 2 -3 4 -5 6 - 1 - - - - - x-plane - 10 - vacuum - - - x-plane - -10 - vacuum - - - y-plane - 1 - reflective - - - y-plane - -1 - reflective - - - z-plane - 1 - reflective - - - z-plane - -1 - reflective - - - diff --git a/tests/regression_tests/cmfd_feed_expanding_window/materials.xml b/tests/regression_tests/cmfd_feed_expanding_window/materials.xml deleted file mode 100644 index 70580e3a8db..00000000000 --- a/tests/regression_tests/cmfd_feed_expanding_window/materials.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/tests/regression_tests/cmfd_feed_expanding_window/model.xml b/tests/regression_tests/cmfd_feed_expanding_window/model.xml new file mode 100644 index 00000000000..b3fe853b269 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_expanding_window/model.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 20 + 10 + + + -10.0 -1.0 -1.0 10.0 1.0 1.0 + + + 10 + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + 1 + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_feed_expanding_window/results_true.dat b/tests/regression_tests/cmfd_feed_expanding_window/results_true.dat index a235a9f6f00..8fd8cdbb845 100644 --- a/tests/regression_tests/cmfd_feed_expanding_window/results_true.dat +++ b/tests/regression_tests/cmfd_feed_expanding_window/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.184725E+00 9.808181E-03 +1.167865E+00 7.492213E-03 tally 1: -1.121111E+01 -1.261033E+01 -2.101271E+01 -4.433294E+01 -2.782926E+01 -7.776546E+01 -3.351044E+01 -1.125084E+02 -3.625691E+01 -1.319666E+02 -3.741881E+01 -1.403776E+02 -3.538049E+01 -1.255798E+02 -3.030311E+01 -9.228152E+01 -2.188389E+01 -4.811272E+01 -1.172417E+01 -1.379179E+01 +1.146860E+01 +1.318884E+01 +2.161527E+01 +4.685283E+01 +2.951158E+01 +8.733566E+01 +3.521610E+01 +1.242821E+02 +3.774236E+01 +1.426501E+02 +3.727918E+01 +1.391158E+02 +3.377176E+01 +1.143839E+02 +2.904497E+01 +8.452907E+01 +2.090871E+01 +4.384549E+01 +1.078642E+01 +1.168086E+01 tally 2: -1.146940E+00 -1.315471E+00 -8.068187E-01 -6.509564E-01 -2.070090E+00 -4.285274E+00 -1.469029E+00 -2.158045E+00 -2.703224E+00 -7.307421E+00 -1.895589E+00 -3.593259E+00 -3.567634E+00 -1.272801E+01 -2.541493E+00 -6.459185E+00 -3.937463E+00 -1.550361E+01 -2.770463E+00 -7.675465E+00 -3.960472E+00 -1.568534E+01 -2.792668E+00 -7.798997E+00 -3.243459E+00 -1.052002E+01 -2.296673E+00 -5.274706E+00 -2.794726E+00 -7.810492E+00 -1.953143E+00 -3.814769E+00 -2.187302E+00 -4.784292E+00 -1.544500E+00 -2.385481E+00 -1.199609E+00 -1.439061E+00 -8.356062E-01 -6.982377E-01 +1.136810E+00 +1.292338E+00 +7.987303E-01 +6.379700E-01 +2.266938E+00 +5.139009E+00 +1.613483E+00 +2.603328E+00 +3.046349E+00 +9.280239E+00 +2.182459E+00 +4.763126E+00 +3.568068E+00 +1.273111E+01 +2.532456E+00 +6.413333E+00 +3.989504E+00 +1.591614E+01 +2.848301E+00 +8.112818E+00 +3.853133E+00 +1.484663E+01 +2.718493E+00 +7.390202E+00 +3.478138E+00 +1.209745E+01 +2.467281E+00 +6.087476E+00 +2.952220E+00 +8.715605E+00 +2.103261E+00 +4.423706E+00 +1.917459E+00 +3.676649E+00 +1.378369E+00 +1.899902E+00 +1.048240E+00 +1.098807E+00 +7.511947E-01 +5.642934E-01 tally 3: -7.817522E-01 -6.111366E-01 -5.930056E-02 -3.516556E-03 -1.426374E+00 -2.034542E+00 -8.539281E-02 -7.291931E-03 -1.815687E+00 -3.296718E+00 -1.221592E-01 -1.492286E-02 -2.447191E+00 -5.988744E+00 -1.624835E-01 -2.640090E-02 -2.670084E+00 -7.129351E+00 -1.838317E-01 -3.379411E-02 -2.683007E+00 -7.198528E+00 -1.719716E-01 -2.957424E-02 -2.215446E+00 -4.908202E+00 -1.707856E-01 -2.916773E-02 -1.872330E+00 -3.505620E+00 -1.209731E-01 -1.463450E-02 -1.484167E+00 -2.202752E+00 -1.114851E-01 -1.242892E-02 -8.018653E-01 -6.429879E-01 -5.692854E-02 -3.240858E-03 +7.701233E-01 +5.930898E-01 +4.481585E-02 +2.008461E-03 +1.547307E+00 +2.394158E+00 +1.226539E-01 +1.504398E-02 +2.106373E+00 +4.436806E+00 +1.450618E-01 +2.104294E-02 +2.437654E+00 +5.942157E+00 +1.521380E-01 +2.314598E-02 +2.754639E+00 +7.588038E+00 +1.745460E-01 +3.046629E-02 +2.623852E+00 +6.884601E+00 +1.851602E-01 +3.428432E-02 +2.376886E+00 +5.649588E+00 +1.615729E-01 +2.610582E-02 +2.021856E+00 +4.087900E+00 +1.533174E-01 +2.350622E-02 +1.333190E+00 +1.777397E+00 +7.076188E-02 +5.007243E-03 +7.258527E-01 +5.268622E-01 +3.656030E-02 +1.336656E-03 tally 4: -1.404203E-01 -1.971786E-02 +1.667432E-01 +2.780328E-02 0.000000E+00 0.000000E+00 -1.383954E-01 -1.915329E-02 -2.626162E-01 -6.896729E-02 +1.292567E-01 +1.670730E-02 +2.813370E-01 +7.915052E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.626162E-01 -6.896729E-02 -1.383954E-01 -1.915329E-02 -2.300607E-01 -5.292793E-02 -3.213893E-01 -1.032911E-01 +2.813370E-01 +7.915052E-02 +1.292567E-01 +1.670730E-02 +2.670549E-01 +7.131835E-02 +4.055324E-01 +1.644566E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.213893E-01 -1.032911E-01 -2.300607E-01 -5.292793E-02 -3.621797E-01 -1.311741E-01 -4.326081E-01 -1.871498E-01 +4.055324E-01 +1.644566E-01 +2.670549E-01 +7.131835E-02 +3.848125E-01 +1.480807E-01 +4.809430E-01 +2.313062E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.326081E-01 -1.871498E-01 -3.621797E-01 -1.311741E-01 -4.274873E-01 -1.827454E-01 -4.701391E-01 -2.210307E-01 +4.809430E-01 +2.313062E-01 +3.848125E-01 +1.480807E-01 +4.543918E-01 +2.064719E-01 +5.106133E-01 +2.607260E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.701391E-01 -2.210307E-01 -4.274873E-01 -1.827454E-01 -4.867763E-01 -2.369512E-01 -5.027339E-01 -2.527413E-01 +5.106133E-01 +2.607260E-01 +4.543918E-01 +2.064719E-01 +4.543120E-01 +2.063994E-01 +4.626328E-01 +2.140291E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.027339E-01 -2.527413E-01 -4.867763E-01 -2.369512E-01 -4.679231E-01 -2.189520E-01 -4.504626E-01 -2.029166E-01 +4.626328E-01 +2.140291E-01 +4.543120E-01 +2.063994E-01 +4.827759E-01 +2.330726E-01 +4.442622E-01 +1.973689E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.504626E-01 -2.029166E-01 -4.679231E-01 -2.189520E-01 -4.340994E-01 -1.884423E-01 -3.622741E-01 -1.312425E-01 +4.442622E-01 +1.973689E-01 +4.827759E-01 +2.330726E-01 +4.630420E-01 +2.144079E-01 +3.886524E-01 +1.510507E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.622741E-01 -1.312425E-01 -4.340994E-01 -1.884423E-01 -3.743415E-01 -1.401316E-01 -2.666952E-01 -7.112632E-02 +3.886524E-01 +1.510507E-01 +4.630420E-01 +2.144079E-01 +3.535870E-01 +1.250237E-01 +2.530312E-01 +6.402478E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.666952E-01 -7.112632E-02 -3.743415E-01 -1.401316E-01 -2.832774E-01 -8.024609E-02 -1.469617E-01 -2.159775E-02 +2.530312E-01 +6.402478E-02 +3.535870E-01 +1.250237E-01 +2.465524E-01 +6.078808E-02 +1.197152E-01 +1.433173E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.469617E-01 -2.159775E-02 -2.832774E-01 -8.024609E-02 -1.514998E-01 -2.295220E-02 +1.197152E-01 +1.433173E-02 +2.465524E-01 +6.078808E-02 +1.369631E-01 +1.875888E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,119 +345,119 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -7.817522E-01 -6.111366E-01 -1.254009E-01 -1.572539E-02 -1.426374E+00 -2.034542E+00 -2.208879E-01 -4.879148E-02 -1.815687E+00 -3.296718E+00 -2.598747E-01 -6.753484E-02 -2.446236E+00 -5.984069E+00 -3.067269E-01 -9.408137E-02 -2.670084E+00 -7.129351E+00 -3.358701E-01 -1.128087E-01 -2.682078E+00 -7.193544E+00 -3.021763E-01 -9.131050E-02 -2.215446E+00 -4.908202E+00 -3.092066E-01 -9.560869E-02 -1.871260E+00 -3.501614E+00 -2.400592E-01 -5.762841E-02 -1.483097E+00 -2.199577E+00 -2.197780E-01 -4.830237E-02 -8.009060E-01 -6.414504E-01 -1.023121E-01 -1.046776E-02 +7.701233E-01 +5.930898E-01 +1.386250E-01 +1.921688E-02 +1.547307E+00 +2.394158E+00 +2.630277E-01 +6.918357E-02 +2.106373E+00 +4.436806E+00 +2.807880E-01 +7.884187E-02 +2.435849E+00 +5.933361E+00 +3.322060E-01 +1.103608E-01 +2.753634E+00 +7.582501E+00 +3.825922E-01 +1.463768E-01 +2.623852E+00 +6.884601E+00 +3.888710E-01 +1.512206E-01 +2.376886E+00 +5.649588E+00 +3.196217E-01 +1.021581E-01 +2.021856E+00 +4.087900E+00 +2.897881E-01 +8.397715E-02 +1.333190E+00 +1.777397E+00 +1.627110E-01 +2.647486E-02 +7.258527E-01 +5.268622E-01 +9.348666E-02 +8.739755E-03 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.165553E+00 -1.179705E+00 -1.191818E+00 -1.207372E+00 -1.203745E+00 -1.208055E+00 -1.208191E+00 -1.201797E+00 -1.201945E+00 -1.203753E+00 -1.209025E+00 +1.149077E+00 +1.156751E+00 +1.158648E+00 +1.159506E+00 +1.156567E+00 +1.160259E+00 +1.150345E+00 +1.149846E+00 +1.151606E+00 +1.164544E+00 +1.174648E+00 cmfd entropy -3.217557E+00 -3.209881E+00 -3.204672E+00 -3.212484E+00 -3.217253E+00 -3.216845E+00 -3.219057E+00 -3.217057E+00 -3.223643E+00 -3.230985E+00 -3.230377E+00 +3.216173E+00 +3.228717E+00 +3.220402E+00 +3.214352E+00 +3.215636E+00 +3.213599E+00 +3.212854E+00 +3.213131E+00 +3.213196E+00 +3.205474E+00 +3.202869E+00 cmfd balance -1.65304E-03 -2.29940E-03 -1.63416E-03 -1.39975E-03 -1.91312E-03 -1.62824E-03 -1.95516E-03 -2.02934E-03 -1.92846E-03 -2.33117E-03 -2.29845E-03 +3.08825E-03 +1.42345E-03 +1.21253E-03 +1.17694E-03 +1.05901E-03 +9.29611E-04 +1.35587E-03 +1.13579E-03 +1.14964E-03 +1.29313E-03 +1.46566E-03 cmfd dominance ratio -5.465E-01 -5.481E-01 -5.432E-01 -5.459E-01 -5.463E-01 -5.486E-01 -5.515E-01 -5.493E-01 -5.511E-01 -5.518E-01 -5.499E-01 +5.524E-01 +5.614E-01 +5.522E-01 +5.487E-01 +5.482E-01 +5.446E-01 +5.437E-01 +5.429E-01 +5.407E-01 +5.380E-01 +5.377E-01 cmfd openmc source comparison -6.499546E-03 -3.419761E-03 -4.342514E-03 -7.229618E-03 -9.943057E-03 -1.050086E-02 -1.055060E-02 -6.562146E-03 -7.232860E-03 -4.424331E-03 -2.531323E-03 +1.586045E-02 +6.953134E-03 +6.860419E-03 +6.198467E-03 +5.142854E-03 +4.373354E-03 +5.564831E-03 +4.184765E-03 +1.867780E-03 +2.734784E-03 +2.523985E-03 cmfd source -4.224785E-02 -7.504165E-02 -1.009909E-01 -1.238160E-01 -1.301409E-01 -1.425954E-01 -1.353275E-01 -1.134617E-01 -8.830470E-02 -4.807346E-02 +4.241440E-02 +8.226026E-02 +1.180811E-01 +1.328433E-01 +1.412410E-01 +1.424902E-01 +1.269340E-01 +1.096490E-01 +6.953251E-02 +3.455422E-02 diff --git a/tests/regression_tests/cmfd_feed_expanding_window/settings.xml b/tests/regression_tests/cmfd_feed_expanding_window/settings.xml deleted file mode 100644 index 24b0b6ab508..00000000000 --- a/tests/regression_tests/cmfd_feed_expanding_window/settings.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - eigenvalue - 20 - 10 - 1000 - - - - - box - -10 -1 -1 10 1 1 - - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - 10 - - diff --git a/tests/regression_tests/cmfd_feed_expanding_window/tallies.xml b/tests/regression_tests/cmfd_feed_expanding_window/tallies.xml deleted file mode 100644 index c869711147f..00000000000 --- a/tests/regression_tests/cmfd_feed_expanding_window/tallies.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - regular - -10 -1 -1 - 10 1 1 - 10 1 1 - - - - mesh - 1 - - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_feed_ng/results_true.dat b/tests/regression_tests/cmfd_feed_ng/results_true.dat index 722cb16c8c2..153238bfeb5 100644 --- a/tests/regression_tests/cmfd_feed_ng/results_true.dat +++ b/tests/regression_tests/cmfd_feed_ng/results_true.dat @@ -1,208 +1,208 @@ k-combined: -1.027584E+00 1.502267E-02 +1.005987E+00 1.354263E-02 tally 1: -1.148263E+02 -1.318910E+03 -1.144863E+02 -1.311468E+03 -1.163124E+02 -1.353643E+03 -1.149445E+02 -1.321759E+03 +1.140273E+02 +1.301245E+03 +1.147962E+02 +1.319049E+03 +1.151426E+02 +1.326442E+03 +1.149265E+02 +1.321518E+03 tally 2: -3.397796E+01 -7.265736E+01 -5.019405E+01 -1.585764E+02 -1.053191E+01 -6.978659E+00 -8.739144E+00 -4.800811E+00 -1.368395E+02 -1.172003E+03 -7.370695E+01 -3.398875E+02 -3.374845E+01 -7.161454E+01 -5.011266E+01 -1.580982E+02 -1.014814E+01 -6.486800E+00 -8.590537E+00 -4.639730E+00 -1.379236E+02 -1.198395E+03 -7.277377E+01 -3.313373E+02 -3.554441E+01 -7.913690E+01 -5.224651E+01 -1.709692E+02 -1.050466E+01 -6.961148E+00 -8.866162E+00 -4.951519E+00 -1.388541E+02 -1.206000E+03 -7.399637E+01 -3.423642E+02 -3.479281E+01 -7.602778E+01 -5.139230E+01 -1.659298E+02 -1.026632E+01 -6.621042E+00 -8.649433E+00 -4.697954E+00 -1.402563E+02 -1.235504E+03 -7.374718E+01 -3.400080E+02 +3.462748E+01 +7.542476E+01 +5.129219E+01 +1.658142E+02 +1.034704E+01 +6.730603E+00 +8.672967E+00 +4.715295E+00 +1.344669E+02 +1.132019E+03 +7.262519E+01 +3.300787E+02 +3.447358E+01 +7.459545E+01 +5.075836E+01 +1.619570E+02 +1.080516E+01 +7.366369E+00 +8.908065E+00 +4.991975E+00 +1.354224E+02 +1.146824E+03 +7.300078E+01 +3.332531E+02 +3.432298E+01 +7.388666E+01 +5.096378E+01 +1.627979E+02 +1.053664E+01 +7.029789E+00 +8.826624E+00 +4.904429E+00 +1.388389E+02 +1.207280E+03 +7.376623E+01 +3.403211E+02 +4.383841E+01 +1.943331E+02 +5.165881E+01 +1.675923E+02 +1.059646E+01 +7.048052E+00 +8.763673E+00 +4.823505E+00 +1.378179E+02 +1.188104E+03 +7.431708E+01 +3.453746E+02 tally 3: -4.748159E+01 -1.419494E+02 +4.858880E+01 +1.488705E+02 0.000000E+00 0.000000E+00 -8.132630E-03 -1.326503E-05 +8.148667E-03 +1.337050E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.299481E+00 -6.900644E-01 -2.429296E+00 -3.713869E-01 +3.347376E+00 +7.045574E-01 +2.433484E+00 +3.727266E-01 0.000000E+00 0.000000E+00 -6.175576E+00 -2.403118E+00 +6.095478E+00 +2.332622E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -7.020357E-02 -6.481773E-04 -3.097931E-01 -6.853044E-03 +1.235421E-01 +1.205155E-03 +3.647699E-01 +8.953589E-03 0.000000E+00 0.000000E+00 -2.592969E+00 -4.215508E-01 +2.673965E+00 +4.517972E-01 0.000000E+00 0.000000E+00 -6.972257E+01 -3.041404E+02 -5.792796E-01 -2.191871E-02 -4.745221E+01 -1.418371E+02 +6.841105E+01 +2.929195E+02 +5.902473E-01 +2.307683E-02 +4.792291E+01 +1.444397E+02 0.000000E+00 0.000000E+00 -1.507569E-02 -3.140047E-05 +2.183275E-02 +8.061011E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.307769E+00 -6.924370E-01 -2.473164E+00 -3.840166E-01 +3.435826E+00 +7.480244E-01 +2.450829E+00 +3.800327E-01 0.000000E+00 0.000000E+00 -5.967063E+00 -2.251947E+00 +6.331358E+00 +2.530492E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -9.143833E-02 -8.020544E-04 -3.234880E-01 -7.219562E-03 +1.012941E-01 +8.217580E-04 +2.981274E-01 +5.863186E-03 0.000000E+00 0.000000E+00 -2.477436E+00 -3.882619E-01 +2.535628E+00 +4.048310E-01 0.000000E+00 0.000000E+00 -6.888326E+01 -2.968630E+02 -5.925099E-01 -2.344632E-02 -4.946736E+01 -1.533087E+02 +6.912003E+01 +2.987684E+02 +5.984862E-01 +2.386115E-02 +4.822881E+01 +1.458309E+02 0.000000E+00 0.000000E+00 -1.369119E-02 -3.099298E-05 +1.525590E-02 +3.794082E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.513467E+00 -7.852189E-01 -2.483110E+00 -3.901527E-01 +3.314494E+00 +6.944527E-01 +2.424209E+00 +3.691360E-01 0.000000E+00 0.000000E+00 -6.238898E+00 -2.455700E+00 +6.254897E+00 +2.474317E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -9.032973E-02 -6.677512E-04 -2.816159E-01 -5.349737E-03 +1.112542E-01 +1.051688E-03 +3.234880E-01 +7.156753E-03 0.000000E+00 0.000000E+00 -2.620828E+00 -4.350795E-01 +2.474142E+00 +3.837496E-01 0.000000E+00 0.000000E+00 -6.992910E+01 -3.057653E+02 -5.890670E-01 -2.307978E-02 -4.853121E+01 -1.480132E+02 +6.987095E+01 +3.053358E+02 +5.928782E-01 +2.368116E-02 +4.885415E+01 +1.499856E+02 0.000000E+00 0.000000E+00 -1.719291E-02 -4.141727E-05 +1.262416E-02 +2.486286E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.490129E+00 -7.743548E-01 -2.381968E+00 -3.564896E-01 +3.426826E+00 +7.480396E-01 +2.487209E+00 +3.903882E-01 0.000000E+00 0.000000E+00 -6.151693E+00 -2.382656E+00 +6.127303E+00 +2.364605E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.653178E-02 -5.524601E-04 -3.307211E-01 -7.362512E-03 +9.439007E-02 +1.082564E-03 +2.963491E-01 +5.652952E-03 0.000000E+00 0.000000E+00 -2.566722E+00 -4.136929E-01 +2.620696E+00 +4.311792E-01 0.000000E+00 0.000000E+00 -6.968935E+01 -3.036323E+02 -6.295592E-01 -2.609911E-02 +7.030725E+01 +3.091241E+02 +5.986966E-01 +2.352487E-02 tally 4: 0.000000E+00 0.000000E+00 @@ -216,18 +216,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.910417E+00 -3.013908E+00 -2.099086E+00 -2.794191E-01 -2.725309E+01 -4.645663E+01 -7.076086E+00 -3.154776E+00 -2.051075E+00 -2.671542E-01 -2.737348E+01 -4.686718E+01 +7.028624E+00 +3.105990E+00 +2.154648E+00 +2.948865E-01 +2.714077E+01 +4.607926E+01 +7.035506E+00 +3.118549E+00 +2.085916E+00 +2.730884E-01 +2.750091E+01 +4.731304E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -240,18 +240,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.215131E+00 -3.265328E+00 -2.066108E+00 -2.704238E-01 -2.755564E+01 -4.753705E+01 -7.022836E+00 -3.102535E+00 -2.076586E+00 -2.741254E-01 -2.756981E+01 -4.756632E+01 +7.170567E+00 +3.240715E+00 +2.131758E+00 +2.862355E-01 +2.747702E+01 +4.722977E+01 +7.068817E+00 +3.139275E+00 +2.095865E+00 +2.762179E-01 +2.737835E+01 +4.688689E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -276,18 +276,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.076086E+00 -3.154776E+00 -2.051075E+00 -2.671542E-01 -2.737348E+01 -4.686718E+01 -6.910417E+00 -3.013908E+00 -2.099086E+00 -2.794191E-01 -2.725309E+01 -4.645663E+01 +7.035506E+00 +3.118549E+00 +2.085916E+00 +2.730884E-01 +2.750091E+01 +4.731304E+01 +7.028624E+00 +3.105990E+00 +2.154648E+00 +2.948865E-01 +2.714077E+01 +4.607926E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -312,18 +312,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.008937E+00 -3.087084E+00 -2.040640E+00 -2.622272E-01 -2.705295E+01 -4.578207E+01 -7.038404E+00 -3.111878E+00 -2.123591E+00 -2.840551E-01 -2.708214E+01 -4.588834E+01 +7.103896E+00 +3.171147E+00 +2.095666E+00 +2.756673E-01 +2.711842E+01 +4.600196E+01 +7.197270E+00 +3.255501E+00 +2.046179E+00 +2.630301E-01 +2.729901E+01 +4.662030E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -360,30 +360,30 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.286308E+00 -3.346248E+00 -2.108252E+00 -2.794781E-01 -2.738387E+01 -4.689407E+01 -7.108444E+00 -3.172810E+00 -2.111474E+00 -2.804633E-01 -2.737249E+01 -4.687424E+01 -7.022836E+00 -3.102535E+00 -2.076586E+00 -2.741254E-01 -2.756981E+01 -4.756632E+01 -7.215131E+00 -3.265328E+00 -2.066108E+00 -2.704238E-01 -2.755564E+01 -4.753705E+01 +7.240906E+00 +3.296285E+00 +2.130816E+00 +2.850713E-01 +2.761433E+01 +4.771548E+01 +7.126427E+00 +3.199209E+00 +2.177254E+00 +2.998765E-01 +2.754936E+01 +4.748447E+01 +7.068817E+00 +3.139275E+00 +2.095865E+00 +2.762179E-01 +2.737835E+01 +4.688689E+01 +7.170567E+00 +3.240715E+00 +2.131758E+00 +2.862355E-01 +2.747702E+01 +4.722977E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -420,18 +420,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.108444E+00 -3.172810E+00 -2.111474E+00 -2.804633E-01 -2.737249E+01 -4.687424E+01 -7.286308E+00 -3.346248E+00 -2.108252E+00 -2.794781E-01 -2.738387E+01 -4.689407E+01 +7.126427E+00 +3.199209E+00 +2.177254E+00 +2.998765E-01 +2.754936E+01 +4.748447E+01 +7.240906E+00 +3.296285E+00 +2.130816E+00 +2.850713E-01 +2.761433E+01 +4.771548E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -444,18 +444,18 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.038404E+00 -3.111878E+00 -2.123591E+00 -2.840551E-01 -2.708214E+01 -4.588834E+01 -7.008937E+00 -3.087084E+00 -2.040640E+00 -2.622272E-01 -2.705295E+01 -4.578207E+01 +7.197270E+00 +3.255501E+00 +2.046179E+00 +2.630301E-01 +2.729901E+01 +4.662030E+01 +7.103896E+00 +3.171147E+00 +2.095666E+00 +2.756673E-01 +2.711842E+01 +4.600196E+01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -493,124 +493,124 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -4.748972E+01 -1.419968E+02 -8.604872E+00 -4.655596E+00 -7.261430E+01 -3.298767E+02 -1.092092E+01 -7.540081E+00 -3.984923E+00 -1.000404E+00 -3.294804E+01 -6.794642E+01 -4.746728E+01 -1.419250E+02 -8.440227E+00 -4.478243E+00 -7.167598E+01 -3.214310E+02 -1.073385E+01 -7.257545E+00 -3.904158E+00 -9.587510E-01 -3.253492E+01 -6.626202E+01 -4.948105E+01 -1.533940E+02 -8.722008E+00 -4.791509E+00 -7.283154E+01 -3.316829E+02 -1.138387E+01 -8.162117E+00 -4.131397E+00 -1.078045E+00 -3.254336E+01 -6.624925E+01 -4.854840E+01 -1.481182E+02 -8.533661E+00 -4.573316E+00 -7.258180E+01 -3.293419E+02 -1.053673E+01 -7.002045E+00 -3.988151E+00 -1.001884E+00 -3.284213E+01 -6.749116E+01 +4.859695E+01 +1.489217E+02 +8.528963E+00 +4.561881E+00 +7.144500E+01 +3.194467E+02 +1.120265E+01 +7.944038E+00 +4.009821E+00 +1.012575E+00 +3.235456E+01 +6.558658E+01 +4.794474E+01 +1.445671E+02 +8.782187E+00 +4.852477E+00 +7.195036E+01 +3.237389E+02 +1.075572E+01 +7.333822E+00 +4.084680E+00 +1.054714E+00 +3.267154E+01 +6.675266E+01 +4.824407E+01 +1.459220E+02 +8.679106E+00 +4.742342E+00 +7.266858E+01 +3.302641E+02 +1.094872E+01 +7.536318E+00 +3.935828E+00 +9.749543E-01 +3.319517E+01 +6.894791E+01 +4.886677E+01 +1.500624E+02 +8.614512E+00 +4.662618E+00 +7.321408E+01 +3.352172E+02 +1.095123E+01 +7.574359E+00 +3.885927E+00 +9.539315E-01 +3.334065E+01 +6.953215E+01 cmfd indices 2.000000E+00 2.000000E+00 1.000000E+00 3.000000E+00 k cmfd -1.026167E+00 -1.026753E+00 -1.034560E+00 -1.028298E+00 -1.029032E+00 -1.033531E+00 -1.034902E+00 -1.029837E+00 -1.025313E+00 -1.019855E+00 -1.021235E+00 +1.026473E+00 +1.024183E+00 +1.023151E+00 +1.025047E+00 +1.019801E+00 +1.020492E+00 +1.015249E+00 +1.016714E+00 +1.016047E+00 +1.019687E+00 +1.020955E+00 cmfd entropy -1.998818E+00 -1.998853E+00 -1.999048E+00 -1.998864E+00 -1.998999E+00 -1.998789E+00 -1.998670E+00 -1.998822E+00 -1.998782E+00 -1.999027E+00 -1.999420E+00 +1.999640E+00 +1.999556E+00 +1.999484E+00 +1.999718E+00 +1.999697E+00 +1.999657E+00 +1.999883E+00 +1.999902E+00 +1.999977E+00 +1.999977E+00 +1.999906E+00 cmfd balance -1.00064E-03 -6.95941E-04 -5.74967E-04 -4.34776E-04 -4.03288E-04 -4.32457E-04 -4.49075E-04 -3.57342E-04 -3.62891E-04 -2.86133E-04 -2.08678E-04 +8.10090E-04 +1.28103E-03 +7.97200E-04 +5.82188E-04 +7.20670E-04 +7.31475E-04 +5.71904E-04 +6.14057E-04 +6.00142E-04 +5.47870E-04 +3.53604E-04 cmfd dominance ratio -3.759E-03 -3.706E-03 -3.719E-03 -3.796E-03 -3.724E-03 -3.809E-03 -3.792E-03 -3.782E-03 -3.841E-03 +3.977E-03 +4.018E-03 +3.950E-03 3.866E-03 -3.868E-03 +3.840E-03 +3.888E-03 +3.867E-03 +3.896E-03 +3.924E-03 +3.885E-03 +3.913E-03 cmfd openmc source comparison -8.283222E-05 -6.636005E-05 -5.320110E-05 -4.474530E-05 -4.409263E-05 -4.914331E-05 -4.834447E-05 -4.040592E-05 -4.173469E-05 -3.118350E-05 -1.667967E-05 +4.787501E-05 +4.450525E-05 +2.532345E-05 +3.844307E-05 +4.821504E-05 +4.840760E-05 +3.739246E-05 +3.957960E-05 +4.521480E-05 +4.072007E-05 +2.532636E-05 cmfd source -2.416781E-01 -2.442811E-01 -2.566121E-01 -2.574288E-01 +2.486236E-01 +2.531628E-01 +2.460219E-01 +2.521918E-01 0.000000E+00 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/cmfd_feed_rectlin/geometry.xml b/tests/regression_tests/cmfd_feed_rectlin/geometry.xml deleted file mode 100644 index 73ea679c4c2..00000000000 --- a/tests/regression_tests/cmfd_feed_rectlin/geometry.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - 0 - -1 2 -3 4 -5 6 - 1 - - - - - x-plane - 10 - vacuum - - - x-plane - -10 - vacuum - - - y-plane - 1 - reflective - - - y-plane - -1 - reflective - - - z-plane - 1 - reflective - - - z-plane - -1 - reflective - - - diff --git a/tests/regression_tests/cmfd_feed_rectlin/materials.xml b/tests/regression_tests/cmfd_feed_rectlin/materials.xml deleted file mode 100644 index 70580e3a8db..00000000000 --- a/tests/regression_tests/cmfd_feed_rectlin/materials.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/tests/regression_tests/cmfd_feed_rectlin/model.xml b/tests/regression_tests/cmfd_feed_rectlin/model.xml new file mode 100644 index 00000000000..b3fe853b269 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rectlin/model.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 20 + 10 + + + -10.0 -1.0 -1.0 10.0 1.0 1.0 + + + 10 + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + 1 + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_feed_rectlin/results_true.dat b/tests/regression_tests/cmfd_feed_rectlin/results_true.dat index 1a9c3f4e470..600b5d1528d 100644 --- a/tests/regression_tests/cmfd_feed_rectlin/results_true.dat +++ b/tests/regression_tests/cmfd_feed_rectlin/results_true.dat @@ -1,149 +1,149 @@ k-combined: -1.167761E+00 4.293426E-03 +1.160561E+00 1.029736E-02 tally 1: -1.202277E+01 -1.452746E+01 -2.195725E+01 -4.835710E+01 -2.862021E+01 -8.215585E+01 -3.453333E+01 -1.196497E+02 -3.756803E+01 -1.414919E+02 -3.739045E+01 -1.403446E+02 -3.361501E+01 -1.134271E+02 -2.819861E+01 -7.968185E+01 -2.111919E+01 -4.472336E+01 -1.129975E+01 -1.280982E+01 +1.089904E+01 +1.193573E+01 +2.026534E+01 +4.113383E+01 +2.723584E+01 +7.440537E+01 +3.309956E+01 +1.101184E+02 +3.659327E+01 +1.341221E+02 +3.780158E+01 +1.430045E+02 +3.520883E+01 +1.241772E+02 +2.961801E+01 +8.784675E+01 +2.182029E+01 +4.781083E+01 +1.180347E+01 +1.399970E+01 tally 2: -8.743037E+00 -3.861220E+00 -6.027264E+00 -1.836570E+00 -3.366159E+01 -5.708871E+01 -2.367086E+01 -2.824484E+01 -2.348709E+01 -2.777633E+01 -1.668756E+01 -1.403629E+01 -5.609969E+01 -1.580739E+02 -3.985682E+01 -7.985715E+01 -3.319543E+01 -5.528370E+01 -2.358360E+01 -2.791829E+01 -7.132407E+01 -2.550603E+02 -5.083603E+01 -1.296049E+02 -3.801086E+01 -7.257141E+01 -2.709688E+01 -3.686995E+01 -3.751307E+01 -7.073318E+01 -2.660859E+01 -3.559134E+01 -7.258292E+01 -2.644619E+02 -5.168044E+01 -1.340982E+02 -3.304423E+01 -5.486256E+01 -2.335526E+01 -2.742989E+01 -5.655005E+01 -1.603926E+02 -4.014572E+01 -8.087797E+01 -2.351019E+01 -2.776367E+01 -1.670083E+01 -1.401374E+01 -3.451886E+01 -5.983149E+01 -2.443300E+01 -2.997375E+01 -8.551177E+00 -3.691263E+00 -5.916124E+00 -1.768556E+00 +8.794706E+00 +3.939413E+00 +6.131113E+00 +1.913116E+00 +3.265522E+01 +5.364042E+01 +2.304238E+01 +2.672742E+01 +2.250225E+01 +2.541491E+01 +1.601668E+01 +1.288405E+01 +5.525355E+01 +1.531915E+02 +3.929637E+01 +7.748545E+01 +3.222711E+01 +5.216630E+01 +2.285375E+01 +2.623641E+01 +7.051908E+01 +2.495413E+02 +5.010064E+01 +1.259701E+02 +3.728726E+01 +6.974440E+01 +2.652872E+01 +3.530919E+01 +3.747306E+01 +7.058235E+01 +2.681415E+01 +3.613314E+01 +7.296802E+01 +2.669214E+02 +5.202502E+01 +1.356733E+02 +3.333947E+01 +5.579355E+01 +2.361733E+01 +2.800800E+01 +5.785916E+01 +1.680561E+02 +4.093282E+01 +8.410711E+01 +2.377151E+01 +2.842464E+01 +1.681789E+01 +1.423646E+01 +3.422028E+01 +5.880493E+01 +2.415199E+01 +2.930240E+01 +8.890608E+00 +3.986356E+00 +6.140159E+00 +1.897764E+00 tally 3: -5.799161E+00 -1.702117E+00 -3.588837E-01 -7.127789E-03 -2.273477E+01 -2.606361E+01 -1.586822E+00 -1.296956E-01 -1.606466E+01 -1.300770E+01 -1.018209E+00 -5.281297E-02 -3.840128E+01 -7.415483E+01 -2.383738E+00 -2.877855E-01 -2.268388E+01 -2.583457E+01 -1.485208E+00 -1.122747E-01 -4.899435E+01 -1.204028E+02 -3.203505E+00 -5.163235E-01 -2.610714E+01 -3.423244E+01 -1.707156E+00 -1.476400E-01 -2.559242E+01 -3.293100E+01 -1.761813E+00 -1.597786E-01 -4.985698E+01 -1.248029E+02 -3.081386E+00 -4.824389E-01 -2.245777E+01 -2.536963E+01 -1.447127E+00 -1.065745E-01 -3.869628E+01 -7.516217E+01 -2.545419E+00 -3.270790E-01 -1.610401E+01 -1.303231E+01 -1.011897E+00 -5.274155E-02 -2.353410E+01 -2.781055E+01 -1.517873E+00 -1.184503E-01 -5.687356E+00 -1.636570E+00 -3.728435E-01 -7.203797E-03 +5.925339E+00 +1.788596E+00 +3.912632E-01 +8.061838E-03 +2.215544E+01 +2.471404E+01 +1.465191E+00 +1.092622E-01 +1.542988E+01 +1.195626E+01 +1.022876E+00 +5.356825E-02 +3.792029E+01 +7.218149E+01 +2.370476E+00 +2.839465E-01 +2.200154E+01 +2.432126E+01 +1.360836E+00 +9.402424E-02 +4.824980E+01 +1.168447E+02 +3.124366E+00 +4.907460E-01 +2.557420E+01 +3.282066E+01 +1.725855E+00 +1.519830E-01 +2.577963E+01 +3.341077E+01 +1.654042E+00 +1.386845E-01 +5.008220E+01 +1.257610E+02 +3.223857E+00 +5.237360E-01 +2.273380E+01 +2.595325E+01 +1.438369E+00 +1.050840E-01 +3.938822E+01 +7.789691E+01 +2.648324E+00 +3.559703E-01 +1.623604E+01 +1.327214E+01 +1.058882E+00 +5.680630E-02 +2.325730E+01 +2.717892E+01 +1.584276E+00 +1.275868E-01 +5.937929E+00 +1.774847E+00 +3.866918E-01 +7.994353E-03 tally 4: -3.060660E+00 -4.703581E-01 +3.063235E+00 +4.714106E-01 0.000000E+00 0.000000E+00 -1.451637E+00 -1.081522E-01 -4.402560E+00 -9.746218E-01 +1.425705E+00 +1.043616E-01 +4.355515E+00 +9.538346E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -160,14 +160,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.402560E+00 -9.746218E-01 -1.451637E+00 -1.081522E-01 -3.903491E+00 -7.713768E-01 -6.448935E+00 -2.089570E+00 +4.355515E+00 +9.538346E-01 +1.425705E+00 +1.043616E-01 +3.859174E+00 +7.519499E-01 +6.350310E+00 +2.024214E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -184,14 +184,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -6.448935E+00 -2.089570E+00 -3.903491E+00 -7.713768E-01 -5.075609E+00 -1.297182E+00 -7.371853E+00 -2.729133E+00 +6.350310E+00 +2.024214E+00 +3.859174E+00 +7.519499E-01 +4.993073E+00 +1.258264E+00 +7.194275E+00 +2.596886E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -208,14 +208,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.371853E+00 -2.729133E+00 -5.075609E+00 -1.297182E+00 -7.015514E+00 -2.477295E+00 -8.723726E+00 -3.828466E+00 +7.194275E+00 +2.596886E+00 +4.993073E+00 +1.258264E+00 +6.786617E+00 +2.312259E+00 +8.306978E+00 +3.459668E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -232,14 +232,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.723726E+00 -3.828466E+00 -7.015514E+00 -2.477295E+00 -7.735344E+00 -3.007547E+00 -9.106625E+00 -4.165807E+00 +8.306978E+00 +3.459668E+00 +6.786617E+00 +2.312259E+00 +7.603410E+00 +2.905228E+00 +8.791222E+00 +3.882935E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -256,14 +256,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.106625E+00 -4.165807E+00 -7.735344E+00 -3.007547E+00 -9.026526E+00 -4.098261E+00 -9.551542E+00 -4.586695E+00 +8.791222E+00 +3.882935E+00 +7.603410E+00 +2.905228E+00 +8.867113E+00 +3.938503E+00 +9.302808E+00 +4.340042E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -280,14 +280,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.551542E+00 -4.586695E+00 -9.026526E+00 -4.098261E+00 -9.344096E+00 -4.384840E+00 -9.405215E+00 -4.441966E+00 +9.302808E+00 +4.340042E+00 +8.867113E+00 +3.938503E+00 +9.270113E+00 +4.306513E+00 +9.263471E+00 +4.302184E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -304,14 +304,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.405215E+00 -4.441966E+00 -9.344096E+00 -4.384840E+00 -9.390313E+00 -4.435716E+00 -9.011690E+00 -4.080913E+00 +9.263471E+00 +4.302184E+00 +9.270113E+00 +4.306513E+00 +9.348712E+00 +4.388570E+00 +8.977713E+00 +4.047349E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -328,14 +328,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.011690E+00 -4.080913E+00 -9.390313E+00 -4.435716E+00 -9.140785E+00 -4.195868E+00 -8.003067E+00 -3.218771E+00 +8.977713E+00 +4.047349E+00 +9.348712E+00 +4.388570E+00 +9.234380E+00 +4.280666E+00 +8.036978E+00 +3.239853E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -352,14 +352,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.003067E+00 -3.218771E+00 -9.140785E+00 -4.195868E+00 -8.629258E+00 -3.736554E+00 -7.133986E+00 -2.557637E+00 +8.036978E+00 +3.239853E+00 +9.234380E+00 +4.280666E+00 +8.713633E+00 +3.808850E+00 +7.160878E+00 +2.572915E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -376,14 +376,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.133986E+00 -2.557637E+00 -8.629258E+00 -3.736554E+00 -7.284136E+00 -2.659936E+00 -5.069993E+00 -1.289638E+00 +7.160878E+00 +2.572915E+00 +8.713633E+00 +3.808850E+00 +7.378538E+00 +2.732122E+00 +5.145728E+00 +1.329190E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -400,14 +400,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.069993E+00 -1.289638E+00 -7.284136E+00 -2.659936E+00 -6.585377E+00 -2.178573E+00 -4.109746E+00 -8.535283E-01 +5.145728E+00 +1.329190E+00 +7.378538E+00 +2.732122E+00 +6.660125E+00 +2.228506E+00 +4.087925E+00 +8.435381E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -424,14 +424,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.109746E+00 -8.535283E-01 -6.585377E+00 -2.178573E+00 -4.394913E+00 -9.694834E-01 -1.455260E+00 -1.073327E-01 +4.087925E+00 +8.435381E-01 +6.660125E+00 +2.228506E+00 +4.466295E+00 +1.002320E+00 +1.468481E+00 +1.099604E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -448,12 +448,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.455260E+00 -1.073327E-01 -4.394913E+00 -9.694834E-01 -3.054512E+00 -4.687172E-01 +1.468481E+00 +1.099604E-01 +4.466295E+00 +1.002320E+00 +3.139355E+00 +4.955456E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -473,164 +473,164 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -5.798163E+00 -1.701480E+00 -7.719076E-01 -3.205800E-02 -2.272861E+01 -2.604939E+01 -3.183925E+00 -5.123120E-01 -1.606367E+01 -1.300597E+01 -2.209506E+00 -2.514085E-01 -3.839444E+01 -7.412912E+01 -5.235063E+00 -1.389014E+00 -2.268086E+01 -2.582733E+01 -3.074902E+00 -4.810618E-01 -4.898566E+01 -1.203589E+02 -6.606838E+00 -2.201101E+00 -2.609836E+01 -3.420917E+01 -3.518842E+00 -6.264238E-01 -2.558605E+01 -3.291399E+01 -3.686659E+00 -6.942431E-01 -4.984902E+01 -1.247644E+02 -6.876822E+00 -2.400434E+00 -2.245394E+01 -2.536044E+01 -3.098158E+00 -4.940204E-01 -3.868744E+01 -7.512715E+01 -5.302748E+00 -1.428609E+00 -1.610093E+01 -1.302770E+01 -2.252209E+00 -2.578778E-01 -2.352951E+01 -2.779963E+01 -3.249775E+00 -5.380883E-01 -5.685356E+00 -1.635162E+00 -7.886630E-01 -3.440650E-02 +5.925339E+00 +1.788596E+00 +8.954773E-01 +4.217679E-02 +2.215054E+01 +2.470273E+01 +2.944747E+00 +4.443186E-01 +1.542658E+01 +1.195085E+01 +1.950262E+00 +1.946340E-01 +3.791137E+01 +7.214779E+01 +4.955741E+00 +1.254830E+00 +2.200054E+01 +2.431894E+01 +3.031040E+00 +4.685971E-01 +4.823946E+01 +1.167941E+02 +6.226321E+00 +1.956308E+00 +2.556930E+01 +3.280828E+01 +3.582546E+00 +6.505962E-01 +2.577249E+01 +3.339204E+01 +3.316825E+00 +5.676842E-01 +5.007249E+01 +1.257124E+02 +6.462364E+00 +2.120157E+00 +2.273285E+01 +2.595106E+01 +2.960964E+00 +4.496277E-01 +3.937362E+01 +7.783849E+01 +5.339336E+00 +1.449257E+00 +1.623315E+01 +1.326746E+01 +2.289661E+00 +2.698618E-01 +2.325250E+01 +2.716827E+01 +3.253010E+00 +5.413837E-01 +5.937929E+00 +1.774847E+00 +9.208589E-01 +4.421403E-02 cmfd indices 1.400000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.154550E+00 -1.172635E+00 -1.171962E+00 -1.174888E+00 -1.182656E+00 -1.190779E+00 -1.200964E+00 -1.196775E+00 -1.190049E+00 -1.181514E+00 -1.180749E+00 -1.179370E+00 -1.177279E+00 -1.178924E+00 -1.177106E+00 -1.179987E+00 +1.125528E+00 +1.145509E+00 +1.158948E+00 +1.171983E+00 +1.180649E+00 +1.184072E+00 +1.188112E+00 +1.183095E+00 +1.182269E+00 +1.175467E+00 +1.175184E+00 +1.172637E+00 +1.171593E+00 +1.175439E+00 +1.174650E+00 +1.176474E+00 cmfd entropy -3.598911E+00 -3.600560E+00 -3.599978E+00 -3.601027E+00 -3.599502E+00 -3.598849E+00 -3.601916E+00 -3.605728E+00 -3.607212E+00 -3.612277E+00 -3.615627E+00 -3.618446E+00 -3.615292E+00 -3.612951E+00 -3.610620E+00 -3.607388E+00 +3.607059E+00 +3.604890E+00 +3.601329E+00 +3.597776E+00 +3.597360E+00 +3.597387E+00 +3.595379E+00 +3.596995E+00 +3.600901E+00 +3.601832E+00 +3.601426E+00 +3.604521E+00 +3.602848E+00 +3.603875E+00 +3.605213E+00 +3.606699E+00 cmfd balance -6.80696E-03 -7.03786E-03 -5.33837E-03 -5.39054E-03 -4.82209E-03 -4.46014E-03 -4.48076E-03 -3.31344E-03 -2.71476E-03 -2.03403E-03 -1.68070E-03 -1.38975E-03 -1.30457E-03 -1.29678E-03 -1.34009E-03 -1.43023E-03 +4.46212E-03 +4.66648E-03 +5.04274E-03 +5.21553E-03 +3.92498E-03 +2.97185E-03 +2.79785E-03 +2.66951E-03 +2.17472E-03 +1.98009E-03 +1.77035E-03 +1.51281E-03 +1.52807E-03 +1.33341E-03 +1.18155E-03 +1.07752E-03 cmfd dominance ratio -5.913E-01 -5.946E-01 -5.961E-01 -5.995E-01 -6.024E-01 -6.050E-01 -6.056E-01 -6.062E-01 -6.064E-01 -6.087E-01 -6.117E-01 -6.120E-01 +6.136E-01 +6.127E-01 +6.137E-01 +6.102E-01 +6.067E-01 +6.061E-01 +6.031E-01 +6.046E-01 +6.071E-01 6.089E-01 -6.074E-01 -6.052E-01 -6.030E-01 +6.073E-01 +6.080E-01 +6.080E-01 +6.090E-01 +6.092E-01 +6.094E-01 cmfd openmc source comparison -1.274461E-02 -9.191627E-03 -7.371466E-03 -4.977614E-03 -4.481864E-03 -3.396798E-03 -2.167863E-03 -4.137274E-03 -4.692749E-03 -2.955754E-03 -2.656269E-03 -2.241441E-03 -4.127496E-03 -3.040657E-03 -3.925292E-03 -3.183157E-03 +1.043027E-02 +1.278226E-02 +1.184867E-02 +1.017186E-02 +1.099696E-02 +7.955341E-03 +8.360344E-03 +6.875508E-03 +4.824018E-03 +4.915363E-03 +5.371647E-03 +4.593100E-03 +4.894955E-03 +4.928253E-03 +4.292171E-03 +4.018545E-03 cmfd source -1.525739E-02 -6.776716E-02 -4.352345E-02 -1.020209E-01 -6.379967E-02 -1.378464E-01 -7.334653E-02 -7.562170E-02 -1.318340E-01 -6.145426E-02 -1.073314E-01 -4.229800E-02 -6.258388E-02 -1.531527E-02 +1.600876E-02 +6.000305E-02 +4.248071E-02 +9.935789E-02 +5.768092E-02 +1.338593E-01 +7.417398E-02 +7.102984E-02 +1.382563E-01 +6.181889E-02 +1.142473E-01 +4.571447E-02 +6.864655E-02 +1.672206E-02 diff --git a/tests/regression_tests/cmfd_feed_rectlin/settings.xml b/tests/regression_tests/cmfd_feed_rectlin/settings.xml deleted file mode 100644 index 24b0b6ab508..00000000000 --- a/tests/regression_tests/cmfd_feed_rectlin/settings.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - eigenvalue - 20 - 10 - 1000 - - - - - box - -10 -1 -1 10 1 1 - - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - 10 - - diff --git a/tests/regression_tests/cmfd_feed_rectlin/tallies.xml b/tests/regression_tests/cmfd_feed_rectlin/tallies.xml deleted file mode 100644 index c869711147f..00000000000 --- a/tests/regression_tests/cmfd_feed_rectlin/tallies.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - regular - -10 -1 -1 - 10 1 1 - 10 1 1 - - - - mesh - 1 - - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_feed_ref_d/geometry.xml b/tests/regression_tests/cmfd_feed_ref_d/geometry.xml deleted file mode 100644 index 73ea679c4c2..00000000000 --- a/tests/regression_tests/cmfd_feed_ref_d/geometry.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - 0 - -1 2 -3 4 -5 6 - 1 - - - - - x-plane - 10 - vacuum - - - x-plane - -10 - vacuum - - - y-plane - 1 - reflective - - - y-plane - -1 - reflective - - - z-plane - 1 - reflective - - - z-plane - -1 - reflective - - - diff --git a/tests/regression_tests/cmfd_feed_ref_d/materials.xml b/tests/regression_tests/cmfd_feed_ref_d/materials.xml deleted file mode 100644 index 70580e3a8db..00000000000 --- a/tests/regression_tests/cmfd_feed_ref_d/materials.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/tests/regression_tests/cmfd_feed_ref_d/model.xml b/tests/regression_tests/cmfd_feed_ref_d/model.xml new file mode 100644 index 00000000000..b3fe853b269 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_ref_d/model.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 20 + 10 + + + -10.0 -1.0 -1.0 10.0 1.0 1.0 + + + 10 + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + 1 + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_feed_ref_d/results_true.dat b/tests/regression_tests/cmfd_feed_ref_d/results_true.dat index cf1e165b26a..9cc26b8cff8 100644 --- a/tests/regression_tests/cmfd_feed_ref_d/results_true.dat +++ b/tests/regression_tests/cmfd_feed_ref_d/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.184724E+00 9.807415E-03 +1.167869E+00 7.492916E-03 tally 1: -1.121178E+01 -1.261180E+01 -2.101384E+01 -4.433764E+01 -2.783041E+01 -7.777181E+01 -3.351124E+01 -1.125137E+02 -3.625716E+01 -1.319682E+02 -3.741849E+01 -1.403752E+02 -3.537964E+01 -1.255737E+02 -3.030185E+01 -9.227364E+01 -2.188275E+01 -4.810760E+01 -1.172353E+01 -1.379028E+01 +1.146821E+01 +1.318787E+01 +2.161476E+01 +4.685066E+01 +2.951084E+01 +8.733116E+01 +3.521523E+01 +1.242762E+02 +3.774181E+01 +1.426460E+02 +3.727924E+01 +1.391162E+02 +3.377236E+01 +1.143877E+02 +2.904590E+01 +8.453427E+01 +2.090941E+01 +4.384824E+01 +1.078680E+01 +1.168172E+01 tally 2: -1.146903E+00 -1.315387E+00 -8.067939E-01 -6.509164E-01 -2.070041E+00 -4.285068E+00 -1.468994E+00 -2.157944E+00 -2.703198E+00 -7.307278E+00 -1.895572E+00 -3.593192E+00 -3.567627E+00 -1.272796E+01 -2.541486E+00 -6.459152E+00 -3.937479E+00 -1.550374E+01 -2.770473E+00 -7.675520E+00 -3.960493E+00 -1.568551E+01 -2.792683E+00 -7.799079E+00 -3.243496E+00 -1.052027E+01 -2.296698E+00 -5.274821E+00 -2.794771E+00 -7.810744E+00 -1.953175E+00 -3.814893E+00 -2.187333E+00 -4.784426E+00 -1.544523E+00 -2.385551E+00 -1.199628E+00 -1.439107E+00 -8.356207E-01 -6.982620E-01 +1.136805E+00 +1.292326E+00 +7.987282E-01 +6.379667E-01 +2.266961E+00 +5.139112E+00 +1.613498E+00 +2.603376E+00 +3.046379E+00 +9.280427E+00 +2.182480E+00 +4.763219E+00 +3.568101E+00 +1.273134E+01 +2.532478E+00 +6.413444E+00 +3.989532E+00 +1.591637E+01 +2.848319E+00 +8.112921E+00 +3.853139E+00 +1.484668E+01 +2.718497E+00 +7.390223E+00 +3.478134E+00 +1.209742E+01 +2.467279E+00 +6.087465E+00 +2.952214E+00 +8.715569E+00 +2.103257E+00 +4.423688E+00 +1.917446E+00 +3.676599E+00 +1.378361E+00 +1.899878E+00 +1.048230E+00 +1.098785E+00 +7.511876E-01 +5.642828E-01 tally 3: -7.817283E-01 -6.110991E-01 -5.930048E-02 -3.516547E-03 -1.426340E+00 -2.034446E+00 -8.539269E-02 -7.291911E-03 -1.815669E+00 -3.296655E+00 -1.221590E-01 -1.492282E-02 -2.447185E+00 -5.988716E+00 -1.624833E-01 -2.640082E-02 -2.670094E+00 -7.129404E+00 -1.838315E-01 -3.379401E-02 -2.683021E+00 -7.198600E+00 -1.719714E-01 -2.957416E-02 -2.215470E+00 -4.908307E+00 -1.707854E-01 -2.916764E-02 -1.872360E+00 -3.505733E+00 -1.209730E-01 -1.463446E-02 -1.484189E+00 -2.202817E+00 -1.114849E-01 -1.242888E-02 -8.018794E-01 -6.430105E-01 -5.692846E-02 -3.240849E-03 +7.701212E-01 +5.930866E-01 +4.481580E-02 +2.008456E-03 +1.547321E+00 +2.394203E+00 +1.226538E-01 +1.504395E-02 +2.106393E+00 +4.436893E+00 +1.450617E-01 +2.104289E-02 +2.437675E+00 +5.942260E+00 +1.521379E-01 +2.314593E-02 +2.754657E+00 +7.588135E+00 +1.745458E-01 +3.046622E-02 +2.623856E+00 +6.884619E+00 +1.851600E-01 +3.428423E-02 +2.376884E+00 +5.649579E+00 +1.615728E-01 +2.610576E-02 +2.021851E+00 +4.087882E+00 +1.533172E-01 +2.350617E-02 +1.333182E+00 +1.777374E+00 +7.076179E-02 +5.007231E-03 +7.258458E-01 +5.268521E-01 +3.656026E-02 +1.336653E-03 tally 4: -1.404164E-01 -1.971677E-02 +1.667426E-01 +2.780308E-02 0.000000E+00 0.000000E+00 -1.383903E-01 -1.915186E-02 -2.626104E-01 -6.896424E-02 +1.292556E-01 +1.670700E-02 +2.813401E-01 +7.915227E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.626104E-01 -6.896424E-02 -1.383903E-01 -1.915186E-02 -2.300555E-01 -5.292554E-02 -3.213857E-01 -1.032888E-01 +2.813401E-01 +7.915227E-02 +1.292556E-01 +1.670700E-02 +2.670582E-01 +7.132006E-02 +4.055365E-01 +1.644599E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.213857E-01 -1.032888E-01 -2.300555E-01 -5.292554E-02 -3.621759E-01 -1.311714E-01 -4.326073E-01 -1.871490E-01 +4.055365E-01 +1.644599E-01 +2.670582E-01 +7.132006E-02 +3.848164E-01 +1.480837E-01 +4.809472E-01 +2.313102E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.326073E-01 -1.871490E-01 -3.621759E-01 -1.311714E-01 -4.274871E-01 -1.827452E-01 -4.701411E-01 -2.210326E-01 +4.809472E-01 +2.313102E-01 +3.848164E-01 +1.480837E-01 +4.543959E-01 +2.064756E-01 +5.106174E-01 +2.607301E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.701411E-01 -2.210326E-01 -4.274871E-01 -1.827452E-01 -4.867793E-01 -2.369540E-01 -5.027352E-01 -2.527427E-01 +5.106174E-01 +2.607301E-01 +4.543959E-01 +2.064756E-01 +4.543155E-01 +2.064026E-01 +4.626331E-01 +2.140294E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.027352E-01 -2.527427E-01 -4.867793E-01 -2.369540E-01 -4.679247E-01 -2.189535E-01 -4.504680E-01 -2.029214E-01 +4.626331E-01 +2.140294E-01 +4.543155E-01 +2.064026E-01 +4.827763E-01 +2.330729E-01 +4.442611E-01 +1.973679E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.504680E-01 -2.029214E-01 -4.679247E-01 -2.189535E-01 -4.341058E-01 -1.884478E-01 -3.622812E-01 -1.312477E-01 +4.442611E-01 +1.973679E-01 +4.827763E-01 +2.330729E-01 +4.630415E-01 +2.144074E-01 +3.886521E-01 +1.510505E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.622812E-01 -1.312477E-01 -4.341058E-01 -1.884478E-01 -3.743485E-01 -1.401368E-01 -2.666983E-01 -7.112801E-02 +3.886521E-01 +1.510505E-01 +4.630415E-01 +2.144074E-01 +3.535862E-01 +1.250232E-01 +2.530293E-01 +6.402384E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.666983E-01 -7.112801E-02 -3.743485E-01 -1.401368E-01 -2.832798E-01 -8.024744E-02 -1.469655E-01 -2.159885E-02 +2.530293E-01 +6.402384E-02 +3.535862E-01 +1.250232E-01 +2.465508E-01 +6.078730E-02 +1.197139E-01 +1.433141E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.469655E-01 -2.159885E-02 -2.832798E-01 -8.024744E-02 -1.515017E-01 -2.295275E-02 +1.197139E-01 +1.433141E-02 +2.465508E-01 +6.078730E-02 +1.369614E-01 +1.875841E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,119 +345,119 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -7.817283E-01 -6.110991E-01 -1.253966E-01 -1.572431E-02 -1.426340E+00 -2.034446E+00 -2.208824E-01 -4.878905E-02 -1.815669E+00 -3.296655E+00 -2.598719E-01 -6.753342E-02 -2.446230E+00 -5.984040E+00 -3.067264E-01 -9.408108E-02 -2.670094E+00 -7.129404E+00 -3.358723E-01 -1.128102E-01 -2.682092E+00 -7.193615E+00 -3.021784E-01 -9.131179E-02 -2.215470E+00 -4.908307E+00 -3.092112E-01 -9.561158E-02 -1.871290E+00 -3.501727E+00 -2.400626E-01 -5.763006E-02 -1.483119E+00 -2.199642E+00 -2.197799E-01 -4.830323E-02 -8.009200E-01 -6.414728E-01 -1.023113E-01 -1.046761E-02 +7.701212E-01 +5.930866E-01 +1.386254E-01 +1.921700E-02 +1.547321E+00 +2.394203E+00 +2.630318E-01 +6.918571E-02 +2.106393E+00 +4.436893E+00 +2.807911E-01 +7.884363E-02 +2.435870E+00 +5.933464E+00 +3.322093E-01 +1.103630E-01 +2.753652E+00 +7.582597E+00 +3.825961E-01 +1.463797E-01 +2.623856E+00 +6.884619E+00 +3.888719E-01 +1.512213E-01 +2.376884E+00 +5.649579E+00 +3.196211E-01 +1.021576E-01 +2.021851E+00 +4.087882E+00 +2.897873E-01 +8.397667E-02 +1.333182E+00 +1.777374E+00 +1.627096E-01 +2.647441E-02 +7.258458E-01 +5.268521E-01 +9.348575E-02 +8.739586E-03 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.165539E+00 -1.179703E+00 -1.191810E+00 -1.207373E+00 -1.203749E+00 -1.208059E+00 -1.208191E+00 -1.201767E+00 -1.201921E+00 -1.203758E+00 -1.209018E+00 +1.149087E+00 +1.156777E+00 +1.158641E+00 +1.159507E+00 +1.156564E+00 +1.160257E+00 +1.150344E+00 +1.149854E+00 +1.151616E+00 +1.164575E+00 +1.174683E+00 cmfd entropy -3.217563E+00 -3.209882E+00 -3.204676E+00 -3.212483E+00 -3.217256E+00 -3.216849E+00 -3.219070E+00 -3.217085E+00 -3.223663E+00 -3.230980E+00 -3.230377E+00 +3.216202E+00 +3.228703E+00 +3.220414E+00 +3.214361E+00 +3.215642E+00 +3.213607E+00 +3.212862E+00 +3.213128E+00 +3.213189E+00 +3.205465E+00 +3.202859E+00 cmfd balance -1.65304E-03 -2.29951E-03 -1.63426E-03 -1.40012E-03 -1.91396E-03 -1.62948E-03 -1.95633E-03 -2.03045E-03 -1.93004E-03 -2.33201E-03 -2.29894E-03 +3.08825E-03 +1.42554E-03 +1.21448E-03 +1.17859E-03 +1.06034E-03 +9.30949E-04 +1.35713E-03 +1.13694E-03 +1.14938E-03 +1.29296E-03 +1.46518E-03 cmfd dominance ratio -5.460E-01 -5.473E-01 -5.415E-01 -5.446E-01 -5.451E-01 -5.475E-01 -5.502E-01 -5.474E-01 -5.498E-01 -5.502E-01 -5.483E-01 +5.503E-01 +5.596E-01 +5.505E-01 +5.471E-01 +5.468E-01 +5.427E-01 +5.421E-01 +5.412E-01 +5.389E-01 +5.371E-01 +5.329E-01 cmfd openmc source comparison -6.484315E-03 -3.411419E-03 -4.321857E-03 -7.194272E-03 -9.907101E-03 -1.046661E-02 -1.050754E-02 -6.523687E-03 -7.212189E-03 -4.425062E-03 -2.540177E-03 +1.571006E-02 +6.945629E-03 +6.838511E-03 +6.183655E-03 +5.138825E-03 +4.362701E-03 +5.558586E-03 +4.188314E-03 +1.837101E-03 +2.737321E-03 +2.529244E-03 cmfd source -4.224343E-02 -7.503541E-02 -1.009853E-01 -1.238103E-01 -1.301388E-01 -1.425912E-01 -1.353339E-01 -1.134730E-01 -8.830826E-02 -4.808031E-02 +4.240947E-02 +8.226746E-02 +1.180848E-01 +1.328470E-01 +1.412449E-01 +1.424870E-01 +1.269297E-01 +1.096476E-01 +6.953001E-02 +3.455212E-02 diff --git a/tests/regression_tests/cmfd_feed_ref_d/settings.xml b/tests/regression_tests/cmfd_feed_ref_d/settings.xml deleted file mode 100644 index 24b0b6ab508..00000000000 --- a/tests/regression_tests/cmfd_feed_ref_d/settings.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - eigenvalue - 20 - 10 - 1000 - - - - - box - -10 -1 -1 10 1 1 - - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - 10 - - diff --git a/tests/regression_tests/cmfd_feed_ref_d/tallies.xml b/tests/regression_tests/cmfd_feed_ref_d/tallies.xml deleted file mode 100644 index c869711147f..00000000000 --- a/tests/regression_tests/cmfd_feed_ref_d/tallies.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - regular - -10 -1 -1 - 10 1 1 - 10 1 1 - - - - mesh - 1 - - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_feed_rolling_window/geometry.xml b/tests/regression_tests/cmfd_feed_rolling_window/geometry.xml deleted file mode 100644 index 73ea679c4c2..00000000000 --- a/tests/regression_tests/cmfd_feed_rolling_window/geometry.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - 0 - -1 2 -3 4 -5 6 - 1 - - - - - x-plane - 10 - vacuum - - - x-plane - -10 - vacuum - - - y-plane - 1 - reflective - - - y-plane - -1 - reflective - - - z-plane - 1 - reflective - - - z-plane - -1 - reflective - - - diff --git a/tests/regression_tests/cmfd_feed_rolling_window/materials.xml b/tests/regression_tests/cmfd_feed_rolling_window/materials.xml deleted file mode 100644 index 70580e3a8db..00000000000 --- a/tests/regression_tests/cmfd_feed_rolling_window/materials.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/tests/regression_tests/cmfd_feed_rolling_window/model.xml b/tests/regression_tests/cmfd_feed_rolling_window/model.xml new file mode 100644 index 00000000000..b3fe853b269 --- /dev/null +++ b/tests/regression_tests/cmfd_feed_rolling_window/model.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 20 + 10 + + + -10.0 -1.0 -1.0 10.0 1.0 1.0 + + + 10 + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + 1 + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_feed_rolling_window/results_true.dat b/tests/regression_tests/cmfd_feed_rolling_window/results_true.dat index a065289ec24..5ff4a132fd6 100644 --- a/tests/regression_tests/cmfd_feed_rolling_window/results_true.dat +++ b/tests/regression_tests/cmfd_feed_rolling_window/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.169526E+00 5.973537E-03 +1.173626E+00 1.098719E-02 tally 1: -1.115884E+01 -1.253283E+01 -2.176964E+01 -4.753045E+01 -2.988209E+01 -8.948736E+01 -3.426842E+01 -1.176956E+02 -3.817775E+01 -1.464502E+02 -3.802079E+01 -1.449155E+02 -3.407399E+01 -1.166067E+02 -2.938579E+01 -8.673128E+01 -2.126809E+01 -4.540856E+01 -1.105934E+01 -1.229825E+01 +1.101892E+01 +1.218768E+01 +2.036233E+01 +4.152577E+01 +2.937587E+01 +8.637268E+01 +3.502389E+01 +1.231700E+02 +3.804803E+01 +1.453948E+02 +3.822561E+01 +1.465677E+02 +3.456290E+01 +1.198651E+02 +2.904088E+01 +8.470264E+01 +2.111529E+01 +4.463713E+01 +1.147633E+01 +1.326012E+01 tally 2: -1.064631E+00 -1.133439E+00 -7.584662E-01 -5.752710E-01 -1.898252E+00 -3.603361E+00 -1.330629E+00 -1.770573E+00 -2.737585E+00 -7.494369E+00 -1.949437E+00 -3.800303E+00 -3.313845E+00 -1.098157E+01 -2.356303E+00 -5.552166E+00 -3.735566E+00 -1.395445E+01 -2.657859E+00 -7.064213E+00 -4.052274E+00 -1.642093E+01 -2.864885E+00 -8.207568E+00 -3.385112E+00 -1.145899E+01 -2.358075E+00 -5.560519E+00 -2.776429E+00 -7.708560E+00 -1.960468E+00 -3.843434E+00 -2.240243E+00 -5.018688E+00 -1.549641E+00 -2.401386E+00 -1.092006E+00 -1.192478E+00 -7.441585E-01 -5.537719E-01 +1.010478E+00 +1.021066E+00 +6.902031E-01 +4.763804E-01 +1.899891E+00 +3.609584E+00 +1.322615E+00 +1.749312E+00 +2.756419E+00 +7.597845E+00 +1.955934E+00 +3.825676E+00 +3.818740E+00 +1.458278E+01 +2.704746E+00 +7.315652E+00 +3.920857E+00 +1.537312E+01 +2.843144E+00 +8.083470E+00 +3.835060E+00 +1.470768E+01 +2.728705E+00 +7.445831E+00 +3.510590E+00 +1.232424E+01 +2.497237E+00 +6.236191E+00 +2.717388E+00 +7.384198E+00 +1.903638E+00 +3.623837E+00 +2.207863E+00 +4.874659E+00 +1.563588E+00 +2.444808E+00 +1.289027E+00 +1.661591E+00 +9.022714E-01 +8.140937E-01 tally 3: -7.295798E-01 -5.322866E-01 -4.986135E-02 -2.486155E-03 -1.280099E+00 -1.638654E+00 -9.022531E-02 -8.140606E-03 -1.859202E+00 -3.456630E+00 -1.234662E-01 -1.524390E-02 -2.274313E+00 -5.172502E+00 -1.234662E-01 -1.524390E-02 -2.548554E+00 -6.495129E+00 -1.531456E-01 -2.345357E-02 -2.773126E+00 -7.690228E+00 -1.733276E-01 -3.004244E-02 -2.270798E+00 -5.156524E+00 -1.673917E-01 -2.801998E-02 -1.887286E+00 -3.561849E+00 -1.507712E-01 -2.273196E-02 -1.480414E+00 -2.191625E+00 -1.127816E-01 -1.271970E-02 -7.126366E-01 -5.078509E-01 -6.054593E-02 -3.665809E-03 +6.593197E-01 +4.347024E-01 +5.216387E-02 +2.721069E-03 +1.266446E+00 +1.603885E+00 +8.298797E-02 +6.887003E-03 +1.888709E+00 +3.567222E+00 +1.398940E-01 +1.957033E-02 +2.616078E+00 +6.843867E+00 +1.588627E-01 +2.523735E-02 +2.733300E+00 +7.470927E+00 +1.944290E-01 +3.780262E-02 +2.643656E+00 +6.988917E+00 +1.612338E-01 +2.599633E-02 +2.410643E+00 +5.811199E+00 +1.754603E-01 +3.078631E-02 +1.838012E+00 +3.378288E+00 +1.126265E-01 +1.268473E-02 +1.500033E+00 +2.250100E+00 +1.102554E-01 +1.215626E-02 +8.750096E-01 +7.656418E-01 +6.757592E-02 +4.566505E-03 tally 4: -1.416041E-01 -2.005172E-02 +1.490605E-01 +2.221904E-02 0.000000E+00 0.000000E+00 -1.118431E-01 -1.250887E-02 -2.419761E-01 -5.855243E-02 +1.139233E-01 +1.297851E-02 +2.549497E-01 +6.499934E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.419761E-01 -5.855243E-02 -1.118431E-01 -1.250887E-02 -2.383966E-01 -5.683292E-02 -3.454391E-01 -1.193281E-01 +2.549497E-01 +6.499934E-02 +1.139233E-01 +1.297851E-02 +2.191337E-01 +4.801958E-02 +3.295187E-01 +1.085826E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.454391E-01 -1.193281E-01 -2.383966E-01 -5.683292E-02 -3.449676E-01 -1.190027E-01 -4.324309E-01 -1.869965E-01 +3.295187E-01 +1.085826E-01 +2.191337E-01 +4.801958E-02 +3.872400E-01 +1.499548E-01 +4.595835E-01 +2.112170E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.324309E-01 -1.869965E-01 -3.449676E-01 -1.190027E-01 -4.410209E-01 -1.944994E-01 -4.785286E-01 -2.289896E-01 +4.595835E-01 +2.112170E-01 +3.872400E-01 +1.499548E-01 +4.668106E-01 +2.179121E-01 +5.112307E-01 +2.613569E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.785286E-01 -2.289896E-01 -4.410209E-01 -1.944994E-01 -5.038795E-01 -2.538945E-01 -5.028063E-01 -2.528142E-01 +5.112307E-01 +2.613569E-01 +4.668106E-01 +2.179121E-01 +4.716605E-01 +2.224636E-01 +4.916148E-01 +2.416851E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.028063E-01 -2.528142E-01 -5.038795E-01 -2.538945E-01 -4.780368E-01 -2.285192E-01 -4.303602E-01 -1.852099E-01 +4.916148E-01 +2.416851E-01 +4.716605E-01 +2.224636E-01 +4.696777E-01 +2.205972E-01 +4.365150E-01 +1.905453E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.303602E-01 -1.852099E-01 -4.780368E-01 -2.285192E-01 -4.183673E-01 -1.750312E-01 -3.317104E-01 -1.100318E-01 +4.365150E-01 +1.905453E-01 +4.696777E-01 +2.205972E-01 +4.179902E-01 +1.747158E-01 +3.350564E-01 +1.122628E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -3.317104E-01 -1.100318E-01 -4.183673E-01 -1.750312E-01 -3.797671E-01 -1.442230E-01 -2.636003E-01 -6.948514E-02 +3.350564E-01 +1.122628E-01 +4.179902E-01 +1.747158E-01 +3.743487E-01 +1.401370E-01 +2.400661E-01 +5.763172E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.636003E-01 -6.948514E-02 -3.797671E-01 -1.442230E-01 -2.686240E-01 -7.215888E-02 -1.324766E-01 -1.755005E-02 +2.400661E-01 +5.763172E-02 +3.743487E-01 +1.401370E-01 +3.063657E-01 +9.385994E-02 +1.605078E-01 +2.576275E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.324766E-01 -1.755005E-02 -2.686240E-01 -7.215888E-02 -1.444839E-01 -2.087560E-02 +1.605078E-01 +2.576275E-02 +3.063657E-01 +9.385994E-02 +1.700639E-01 +2.892174E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,119 +345,119 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -7.285713E-01 -5.308161E-01 -1.056136E-01 -1.115423E-02 -1.280099E+00 -1.638654E+00 -1.717497E-01 -2.949797E-02 -1.859202E+00 -3.456630E+00 -2.285372E-01 -5.222927E-02 -2.274313E+00 -5.172502E+00 -2.636808E-01 -6.952757E-02 -2.547588E+00 -6.490203E+00 -2.914026E-01 -8.491545E-02 -2.773126E+00 -7.690228E+00 -3.908576E-01 -1.527696E-01 -2.269831E+00 -5.152135E+00 -3.279256E-01 -1.075352E-01 -1.886272E+00 -3.558024E+00 -2.679083E-01 -7.177487E-02 -1.479436E+00 -2.188731E+00 -2.362981E-01 -5.583681E-02 -7.126366E-01 -5.078509E-01 -1.015892E-01 -1.032038E-02 +6.593197E-01 +4.347024E-01 +1.314196E-01 +1.727112E-02 +1.266446E+00 +1.603885E+00 +2.002491E-01 +4.009970E-02 +1.888709E+00 +3.567222E+00 +2.444522E-01 +5.975686E-02 +2.616078E+00 +6.843867E+00 +3.234935E-01 +1.046481E-01 +2.733300E+00 +7.470927E+00 +3.309500E-01 +1.095279E-01 +2.643656E+00 +6.988917E+00 +4.025014E-01 +1.620074E-01 +2.410643E+00 +5.811199E+00 +3.050040E-01 +9.302747E-02 +1.838012E+00 +3.378288E+00 +2.800764E-01 +7.844279E-02 +1.500033E+00 +2.250100E+00 +2.324765E-01 +5.404531E-02 +8.750096E-01 +7.656418E-01 +1.256919E-01 +1.579844E-02 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.188625E+00 -1.172261E+00 -1.172154E+00 -1.176234E+00 -1.161072E+00 -1.174217E+00 -1.176208E+00 -1.183067E+00 -1.208406E+00 -1.220367E+00 -1.208889E+00 +1.166297E+00 +1.148237E+00 +1.162472E+00 +1.187078E+00 +1.188411E+00 +1.194879E+00 +1.216739E+00 +1.216829E+00 +1.196596E+00 +1.199223E+00 +1.211817E+00 cmfd entropy -3.216548E+00 -3.213244E+00 -3.220132E+00 -3.216556E+00 -3.218184E+00 -3.208592E+00 -3.220641E+00 -3.217076E+00 -3.216257E+00 -3.212578E+00 -3.230102E+00 +3.215349E+00 +3.225577E+00 +3.223357E+00 +3.208828E+00 +3.211072E+00 +3.206578E+00 +3.195799E+00 +3.198236E+00 +3.220074E+00 +3.230249E+00 +3.238015E+00 cmfd balance -1.65186E-03 -1.76715E-03 -2.25997E-03 -2.27924E-03 -1.67354E-03 -1.72671E-03 -1.79744E-03 -1.99065E-03 -2.56417E-03 -2.45718E-03 -3.26245E-03 +2.07468E-03 +2.39687E-03 +1.51020E-03 +2.07618E-03 +1.89367E-03 +2.00902E-03 +2.54856E-03 +2.43636E-03 +2.48527E-03 +3.07775E-03 +3.37967E-03 cmfd dominance ratio -5.445E-01 -5.466E-01 -5.539E-01 -5.547E-01 -5.569E-01 -5.518E-01 -5.553E-01 -5.544E-01 -5.474E-01 -5.355E-01 -5.460E-01 +5.505E-01 +5.558E-01 +5.584E-01 +5.477E-01 +5.477E-01 +5.426E-01 +5.335E-01 +5.305E-01 +5.427E-01 +5.484E-01 +5.465E-01 cmfd openmc source comparison -5.662096E-03 -3.660183E-03 -4.806643E-03 -2.475327E-03 -6.166988E-03 -2.205088E-03 -4.010491E-03 -6.270883E-03 -3.070427E-03 -5.679208E-03 -1.488803E-02 +5.598628E-03 +1.162952E-02 +1.083004E-02 +1.037470E-02 +5.649750E-03 +5.137914E-03 +3.868209E-03 +1.208756E-02 +5.398131E-03 +8.119598E-03 +4.573105E-03 cmfd source -4.111004E-02 -7.023296E-02 -1.023250E-01 -1.185886E-01 -1.386562E-01 -1.392823E-01 -1.290017E-01 -1.147469E-01 -9.733704E-02 -4.871933E-02 +4.219187E-02 +8.692096E-02 +1.061389E-01 +1.199181E-01 +1.377328E-01 +1.326161E-01 +1.345872E-01 +1.112871E-01 +7.569533E-02 +5.291175E-02 diff --git a/tests/regression_tests/cmfd_feed_rolling_window/settings.xml b/tests/regression_tests/cmfd_feed_rolling_window/settings.xml deleted file mode 100644 index 24b0b6ab508..00000000000 --- a/tests/regression_tests/cmfd_feed_rolling_window/settings.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - eigenvalue - 20 - 10 - 1000 - - - - - box - -10 -1 -1 10 1 1 - - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - 10 - - diff --git a/tests/regression_tests/cmfd_feed_rolling_window/tallies.xml b/tests/regression_tests/cmfd_feed_rolling_window/tallies.xml deleted file mode 100644 index c869711147f..00000000000 --- a/tests/regression_tests/cmfd_feed_rolling_window/tallies.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - regular - -10 -1 -1 - 10 1 1 - 10 1 1 - - - - mesh - 1 - - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_nofeed/geometry.xml b/tests/regression_tests/cmfd_nofeed/geometry.xml deleted file mode 100644 index 73ea679c4c2..00000000000 --- a/tests/regression_tests/cmfd_nofeed/geometry.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - 0 - -1 2 -3 4 -5 6 - 1 - - - - - x-plane - 10 - vacuum - - - x-plane - -10 - vacuum - - - y-plane - 1 - reflective - - - y-plane - -1 - reflective - - - z-plane - 1 - reflective - - - z-plane - -1 - reflective - - - diff --git a/tests/regression_tests/cmfd_nofeed/materials.xml b/tests/regression_tests/cmfd_nofeed/materials.xml deleted file mode 100644 index 70580e3a8db..00000000000 --- a/tests/regression_tests/cmfd_nofeed/materials.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/tests/regression_tests/cmfd_nofeed/model.xml b/tests/regression_tests/cmfd_nofeed/model.xml new file mode 100644 index 00000000000..b3fe853b269 --- /dev/null +++ b/tests/regression_tests/cmfd_nofeed/model.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 20 + 10 + + + -10.0 -1.0 -1.0 10.0 1.0 1.0 + + + 10 + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + 1 + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_nofeed/results_true.dat b/tests/regression_tests/cmfd_nofeed/results_true.dat index dac35871c6b..756aa457016 100644 --- a/tests/regression_tests/cmfd_nofeed/results_true.dat +++ b/tests/regression_tests/cmfd_nofeed/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.170405E+00 1.487119E-02 +1.172893E+00 8.095197E-03 tally 1: -1.172722E+01 -1.378635E+01 -2.122139E+01 -4.511390E+01 -2.936481E+01 -8.649521E+01 -3.553909E+01 -1.265901E+02 -3.862903E+01 -1.497314E+02 -3.683895E+01 -1.358679E+02 -3.373597E+01 -1.140439E+02 -2.810435E+01 -7.932253E+01 -2.098314E+01 -4.409819E+01 -1.105096E+01 -1.224007E+01 +1.156995E+01 +1.347019E+01 +2.120053E+01 +4.531200E+01 +2.995993E+01 +8.997889E+01 +3.498938E+01 +1.226414E+02 +3.794510E+01 +1.442188E+02 +3.798115E+01 +1.446436E+02 +3.415954E+01 +1.171635E+02 +2.960329E+01 +8.785532E+01 +2.182231E+01 +4.782353E+01 +1.147379E+01 +1.321150E+01 tally 2: -2.275408E+01 -2.603315E+01 -1.590700E+01 -1.273395E+01 -4.112322E+01 -8.498758E+01 -2.911800E+01 -4.264070E+01 -5.707453E+01 -1.638375E+02 -4.069300E+01 -8.336155E+01 -6.915962E+01 -2.399628E+02 -4.926800E+01 -1.218497E+02 -7.521027E+01 -2.842789E+02 -5.357900E+01 -1.443468E+02 -7.387401E+01 -2.738660E+02 -5.263400E+01 -1.390611E+02 -6.871266E+01 -2.368771E+02 -4.902000E+01 -1.205569E+02 -5.632046E+01 -1.592677E+02 -3.999300E+01 -8.035469E+01 -4.291289E+01 -9.245946E+01 -3.046000E+01 -4.661878E+01 -2.273666E+01 -2.598211E+01 -1.590800E+01 -1.271433E+01 +2.345900E+01 +2.783672E+01 +1.627300E+01 +1.339749E+01 +4.127267E+01 +8.563716E+01 +2.934800E+01 +4.334439E+01 +5.742644E+01 +1.658158E+02 +4.092600E+01 +8.423842E+01 +6.740126E+01 +2.279288E+02 +4.796500E+01 +1.154602E+02 +7.340327E+01 +2.701349E+02 +5.235900E+01 +1.374186E+02 +7.387392E+01 +2.740829E+02 +5.277400E+01 +1.398425E+02 +6.733428E+01 +2.274414E+02 +4.800100E+01 +1.156206E+02 +5.794970E+01 +1.685421E+02 +4.124600E+01 +8.540686E+01 +4.257013E+01 +9.092401E+01 +3.014500E+01 +4.566369E+01 +2.300274E+01 +2.659051E+01 +1.613400E+01 +1.307448E+01 tally 3: -1.529800E+01 -1.178010E+01 -1.016076E+00 -5.280687E-02 -2.803900E+01 -3.955010E+01 -1.861024E+00 -1.765351E-01 -3.919400E+01 -7.734526E+01 -2.540695E+00 -3.268959E-01 -4.749400E+01 -1.132677E+02 -3.087604E+00 -4.837647E-01 -5.156500E+01 -1.337335E+02 -3.371014E+00 -5.734875E-01 -5.070500E+01 -1.290569E+02 -3.292766E+00 -5.489854E-01 -4.723400E+01 -1.119247E+02 -2.949932E+00 -4.381745E-01 -3.847900E+01 -7.441953E+01 -2.522868E+00 -3.218962E-01 -2.933900E+01 -4.325593E+01 -1.818016E+00 -1.672765E-01 -1.534700E+01 -1.183573E+01 -9.564025E-01 -4.735079E-02 +1.564900E+01 +1.239852E+01 +1.086873E+00 +6.047264E-02 +2.821700E+01 +4.006730E+01 +1.855830E+00 +1.755984E-01 +3.946300E+01 +7.833997E+01 +2.523142E+00 +3.210725E-01 +4.622500E+01 +1.072588E+02 +2.919735E+00 +4.340292E-01 +5.033400E+01 +1.270010E+02 +3.243022E+00 +5.318534E-01 +5.082400E+01 +1.297502E+02 +3.313898E+00 +5.546608E-01 +4.623700E+01 +1.072944E+02 +2.887766E+00 +4.203084E-01 +3.975000E+01 +7.934279E+01 +2.567158E+00 +3.333121E-01 +2.903500E+01 +4.237270E+01 +1.852070E+00 +1.733821E-01 +1.557800E+01 +1.219084E+01 +9.951884E-01 +5.121758E-02 tally 4: -3.092000E+00 -4.809100E-01 +3.111000E+00 +4.872850E-01 0.000000E+00 0.000000E+00 -2.628000E+00 -3.509980E-01 -5.388000E+00 -1.458946E+00 +2.794000E+00 +3.972060E-01 +5.520000E+00 +1.535670E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.388000E+00 -1.458946E+00 -2.628000E+00 -3.509980E-01 -5.063000E+00 -1.292417E+00 -7.312000E+00 -2.686738E+00 +5.520000E+00 +1.535670E+00 +2.794000E+00 +3.972060E-01 +5.071000E+00 +1.305697E+00 +7.303000E+00 +2.685365E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.312000E+00 -2.686738E+00 -5.063000E+00 -1.292417E+00 -7.115000E+00 -2.542363E+00 -8.719000E+00 -3.819081E+00 +7.303000E+00 +2.685365E+00 +5.071000E+00 +1.305697E+00 +7.015000E+00 +2.471981E+00 +8.545000E+00 +3.670539E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.719000E+00 -3.819081E+00 -7.115000E+00 -2.542363E+00 -8.483000E+00 -3.615549E+00 -9.255000E+00 -4.303287E+00 +8.545000E+00 +3.670539E+00 +7.015000E+00 +2.471981E+00 +8.431000E+00 +3.570057E+00 +9.224000E+00 +4.268004E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.255000E+00 -4.303287E+00 -8.483000E+00 -3.615549E+00 -9.375000E+00 -4.416751E+00 -9.330000E+00 -4.375230E+00 +9.224000E+00 +4.268004E+00 +8.431000E+00 +3.570057E+00 +9.217000E+00 +4.259749E+00 +9.305000E+00 +4.340149E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.330000E+00 -4.375230E+00 -9.375000E+00 -4.416751E+00 -9.346000E+00 -4.379220E+00 -8.458000E+00 -3.585930E+00 +9.305000E+00 +4.340149E+00 +9.217000E+00 +4.259749E+00 +9.374000E+00 +4.415290E+00 +8.611000E+00 +3.718227E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.458000E+00 -3.585930E+00 -9.346000E+00 -4.379220E+00 -8.671000E+00 -3.770383E+00 -7.062000E+00 -2.505966E+00 +8.611000E+00 +3.718227E+00 +9.374000E+00 +4.415290E+00 +8.515000E+00 +3.639945E+00 +7.056000E+00 +2.501658E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.062000E+00 -2.505966E+00 -8.671000E+00 -3.770383E+00 -7.279000E+00 -2.663587E+00 -4.994000E+00 -1.261468E+00 +7.056000E+00 +2.501658E+00 +8.515000E+00 +3.639945E+00 +7.385000E+00 +2.737677E+00 +5.194000E+00 +1.356022E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -4.994000E+00 -1.261468E+00 -7.279000E+00 -2.663587E+00 -5.492000E+00 -1.515002E+00 -2.772000E+00 -3.896040E-01 +5.194000E+00 +1.356022E+00 +7.385000E+00 +2.737677E+00 +5.436000E+00 +1.481654E+00 +2.756000E+00 +3.843860E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.772000E+00 -3.896040E-01 -5.492000E+00 -1.515002E+00 -3.022000E+00 -4.608940E-01 +2.756000E+00 +3.843860E-01 +5.436000E+00 +1.481654E+00 +3.030000E+00 +4.643920E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,144 +345,144 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -1.529600E+01 -1.177689E+01 -2.229624E+00 -2.514699E-01 -2.803300E+01 -3.953329E+01 -3.889856E+00 -7.678274E-01 -3.918900E+01 -7.732686E+01 -5.211188E+00 -1.378173E+00 -4.748700E+01 -1.132339E+02 -6.595911E+00 -2.211528E+00 -5.155000E+01 -1.336522E+02 -6.673103E+00 -2.248462E+00 -5.069800E+01 -1.290196E+02 -6.907470E+00 -2.412919E+00 -4.722500E+01 -1.118824E+02 -6.200070E+00 -1.954544E+00 -3.847200E+01 -7.439145E+01 -5.385095E+00 -1.462192E+00 -2.933600E+01 -4.324744E+01 -4.014057E+00 -8.142088E-01 -1.534200E+01 -1.182781E+01 -2.076271E+00 -2.273431E-01 +1.564300E+01 +1.238861E+01 +2.090227E+00 +2.262627E-01 +2.821400E+01 +4.005826E+01 +3.870834E+00 +7.614623E-01 +3.945400E+01 +7.830326E+01 +5.290557E+00 +1.422339E+00 +4.621500E+01 +1.072116E+02 +6.144745E+00 +1.903309E+00 +5.032900E+01 +1.269756E+02 +6.867524E+00 +2.373593E+00 +5.081000E+01 +1.296784E+02 +6.456283E+00 +2.130767E+00 +4.623000E+01 +1.072613E+02 +5.931623E+00 +1.776451E+00 +3.974500E+01 +7.932288E+01 +5.339603E+00 +1.456812E+00 +2.902800E+01 +4.235232E+01 +4.102240E+00 +8.519551E-01 +1.557800E+01 +1.219084E+01 +2.137954E+00 +2.347770E-01 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.161531E+00 -1.181707E+00 -1.176063E+00 -1.168433E+00 -1.173170E+00 -1.174671E+00 -1.176457E+00 -1.177540E+00 -1.180826E+00 -1.174158E+00 -1.171305E+00 -1.172618E+00 -1.170171E+00 -1.173235E+00 -1.172599E+00 -1.177343E+00 +1.129918E+00 +1.148352E+00 +1.143137E+00 +1.145795E+00 +1.147285E+00 +1.148588E+00 +1.148151E+00 +1.162118E+00 +1.165380E+00 +1.162851E+00 +1.163379E+00 +1.166986E+00 +1.167838E+00 +1.171743E+00 +1.170398E+00 +1.169773E+00 cmfd entropy -3.206619E+00 -3.207385E+00 -3.208853E+00 -3.210825E+00 -3.214820E+00 -3.213490E+00 -3.212717E+00 -3.210590E+00 -3.211948E+00 -3.212156E+00 -3.212900E+00 -3.212275E+00 -3.212766E+00 -3.214205E+00 -3.212717E+00 -3.214169E+00 +3.224769E+00 +3.222795E+00 +3.221174E+00 +3.222164E+00 +3.221025E+00 +3.220967E+00 +3.223497E+00 +3.219213E+00 +3.221679E+00 +3.222084E+00 +3.222281E+00 +3.222540E+00 +3.224614E+00 +3.224193E+00 +3.224925E+00 +3.224367E+00 cmfd balance -4.99833E-03 -5.81289E-03 -3.45193E-03 -2.84521E-03 -3.72331E-03 -3.07942E-03 -2.58676E-03 -2.19354E-03 -2.11522E-03 -2.02671E-03 -1.71439E-03 -1.62909E-03 -1.43261E-03 -1.26201E-03 -1.40167E-03 -1.26141E-03 +3.90454E-03 +4.33180E-03 +3.77057E-03 +3.16391E-03 +3.11765E-03 +2.59886E-03 +2.81060E-03 +3.25473E-03 +2.68544E-03 +2.01716E-03 +1.89350E-03 +1.79159E-03 +1.51353E-03 +1.48514E-03 +1.50207E-03 +1.44045E-03 cmfd dominance ratio -5.283E-01 -5.304E-01 -5.310E-01 -5.324E-01 -5.372E-01 -5.369E-01 -5.367E-01 -5.341E-01 -5.353E-01 -5.375E-01 -5.379E-01 -5.372E-01 -5.379E-01 -5.393E-01 -5.384E-01 -5.382E-01 +5.539E-01 +5.522E-01 +5.491E-01 +5.511E-01 +5.506E-01 +5.523E-01 +5.523E-01 +5.473E-01 +5.478E-01 +5.461E-01 +5.462E-01 +5.459E-01 +5.475E-01 +5.463E-01 +5.466E-01 +5.469E-01 cmfd openmc source comparison -1.291827E-02 -9.488059E-03 -8.538280E-03 -6.820006E-03 -4.300032E-03 -5.486871E-03 -4.493389E-03 -4.913340E-03 -5.132196E-03 -3.342331E-03 -3.094995E-03 -3.553279E-03 -3.284811E-03 -2.492272E-03 -3.062765E-03 -2.632092E-03 +9.875240E-03 +1.119358E-02 +8.513903E-03 +7.728971E-03 +5.993771E-03 +5.837301E-03 +4.861789E-03 +5.624038E-03 +4.297229E-03 +4.029732E-03 +3.669197E-03 +3.598834E-03 +3.023310E-03 +3.347346E-03 +2.943658E-03 +2.764986E-03 cmfd source -4.280100E-02 -7.944783E-02 -1.091569E-01 -1.329540E-01 -1.451697E-01 -1.413526E-01 -1.258514E-01 -1.067698E-01 -7.656551E-02 -3.993138E-02 +4.561921E-02 +7.896381E-02 +1.084687E-01 +1.264057E-01 +1.408942E-01 +1.438180E-01 +1.247333E-01 +1.100896E-01 +7.897187E-02 +4.203556E-02 diff --git a/tests/regression_tests/cmfd_nofeed/settings.xml b/tests/regression_tests/cmfd_nofeed/settings.xml deleted file mode 100644 index 24b0b6ab508..00000000000 --- a/tests/regression_tests/cmfd_nofeed/settings.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - eigenvalue - 20 - 10 - 1000 - - - - - box - -10 -1 -1 10 1 1 - - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - 10 - - diff --git a/tests/regression_tests/cmfd_nofeed/tallies.xml b/tests/regression_tests/cmfd_nofeed/tallies.xml deleted file mode 100644 index c869711147f..00000000000 --- a/tests/regression_tests/cmfd_nofeed/tallies.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - regular - -10 -1 -1 - 10 1 1 - 10 1 1 - - - - mesh - 1 - - - - 1 - flux - - - diff --git a/tests/regression_tests/cmfd_restart/geometry.xml b/tests/regression_tests/cmfd_restart/geometry.xml deleted file mode 100644 index 73ea679c4c2..00000000000 --- a/tests/regression_tests/cmfd_restart/geometry.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - 0 - -1 2 -3 4 -5 6 - 1 - - - - - x-plane - 10 - vacuum - - - x-plane - -10 - vacuum - - - y-plane - 1 - reflective - - - y-plane - -1 - reflective - - - z-plane - 1 - reflective - - - z-plane - -1 - reflective - - - diff --git a/tests/regression_tests/cmfd_restart/materials.xml b/tests/regression_tests/cmfd_restart/materials.xml deleted file mode 100644 index 70580e3a8db..00000000000 --- a/tests/regression_tests/cmfd_restart/materials.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/tests/regression_tests/cmfd_restart/model.xml b/tests/regression_tests/cmfd_restart/model.xml new file mode 100644 index 00000000000..487e9b66dde --- /dev/null +++ b/tests/regression_tests/cmfd_restart/model.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 20 + 10 + + + -10.0 -1.0 -1.0 10.0 1.0 1.0 + + + + 15 20 + + 10 + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + + + 10 1 1 + -10.0 -1.0 -1.0 + 10.0 1.0 1.0 + + + 1 + + + 1 + flux + + + diff --git a/tests/regression_tests/cmfd_restart/results_true.dat b/tests/regression_tests/cmfd_restart/results_true.dat index 90d8820d0c0..f5f22d9acd1 100644 --- a/tests/regression_tests/cmfd_restart/results_true.dat +++ b/tests/regression_tests/cmfd_restart/results_true.dat @@ -1,117 +1,117 @@ k-combined: -1.159021E+00 8.924006E-03 +1.164262E+00 9.207592E-03 tally 1: -1.140162E+01 -1.306940E+01 -2.093739E+01 -4.404780E+01 -2.914408E+01 -8.521010E+01 -3.483677E+01 -1.216824E+02 -3.778463E+01 -1.429632E+02 -3.810371E+01 -1.455108E+02 -3.465248E+01 -1.207868E+02 -2.862033E+01 -8.218833E+01 -2.086025E+01 -4.365941E+01 -1.130798E+01 -1.286509E+01 +1.156972E+01 +1.339924E+01 +2.136306E+01 +4.567185E+01 +2.859527E+01 +8.195821E+01 +3.470754E+01 +1.207851E+02 +3.766403E+01 +1.422263E+02 +3.778821E+01 +1.432660E+02 +3.573197E+01 +1.278854E+02 +2.849979E+01 +8.135515E+01 +2.073803E+01 +4.303374E+01 +1.112117E+01 +1.242944E+01 tally 2: -2.234393E+01 -2.516414E+01 -1.555024E+01 -1.218205E+01 -4.087743E+01 -8.401702E+01 -2.883717E+01 -4.185393E+01 -5.635166E+01 -1.595225E+02 -3.998857E+01 -8.040398E+01 -6.887126E+01 -2.379185E+02 -4.903103E+01 -1.206174E+02 -7.452051E+01 -2.785675E+02 -5.295380E+01 -1.406900E+02 -7.495422E+01 -2.819070E+02 -5.333191E+01 -1.427474E+02 -6.921815E+01 -2.408568E+02 -4.928246E+01 -1.221076E+02 -5.668548E+01 -1.612556E+02 -4.035856E+01 -8.181159E+01 -4.259952E+01 -9.112630E+01 -3.026717E+01 -4.600625E+01 -2.310563E+01 -2.688378E+01 -1.615934E+01 -1.315528E+01 +2.388054E+01 +2.875255E+01 +1.667791E+01 +1.403426E+01 +4.224771E+01 +8.942109E+01 +2.993088E+01 +4.490335E+01 +5.689839E+01 +1.625557E+02 +4.043633E+01 +8.212299E+01 +6.764024E+01 +2.297126E+02 +4.807902E+01 +1.161468E+02 +7.314835E+01 +2.684645E+02 +5.203584E+01 +1.359261E+02 +7.375727E+01 +2.733105E+02 +5.252944E+01 +1.386205E+02 +6.909571E+01 +2.397721E+02 +4.922548E+01 +1.217465E+02 +5.685978E+01 +1.621746E+02 +4.051938E+01 +8.237277E+01 +4.185562E+01 +8.784067E+01 +2.983570E+01 +4.467414E+01 +2.238373E+01 +2.520356E+01 +1.566758E+01 +1.234103E+01 tally 3: -1.496375E+01 -1.128154E+01 -9.905641E-01 -5.125710E-02 -2.774937E+01 -3.877241E+01 -1.786861E+00 -1.627655E-01 -3.849739E+01 -7.453828E+01 -2.494135E+00 -3.158098E-01 -4.724085E+01 -1.119901E+02 -3.031174E+00 -4.653741E-01 -5.096719E+01 -1.303552E+02 -3.254375E+00 -5.351020E-01 -5.133808E+01 -1.322892E+02 -3.383595E+00 -5.798798E-01 -4.756072E+01 -1.137527E+02 -3.001917E+00 -4.558247E-01 -3.887437E+01 -7.593416E+01 -2.517908E+00 -3.221926E-01 -2.910687E+01 -4.255173E+01 -1.817765E+00 -1.678763E-01 -1.557241E+01 -1.222026E+01 -9.852737E-01 -5.002659E-02 +1.609520E+01 +1.307542E+01 +1.033429E+00 +5.510889E-02 +2.877073E+01 +4.149542E+01 +1.964219E+00 +1.954692E-01 +3.896816E+01 +7.629752E+01 +2.484053E+00 +3.103733E-01 +4.634285E+01 +1.079367E+02 +2.974750E+00 +4.468223E-01 +5.007964E+01 +1.259202E+02 +3.181802E+00 +5.103621E-01 +5.058915E+01 +1.286193E+02 +3.249442E+00 +5.337712E-01 +4.744464E+01 +1.131026E+02 +3.067644E+00 +4.736335E-01 +3.900632E+01 +7.634433E+01 +2.443552E+00 +3.028060E-01 +2.874166E+01 +4.146375E+01 +1.810421E+00 +1.671667E-01 +1.509222E+01 +1.145579E+01 +1.014919E+00 +5.391053E-02 tally 4: -3.047490E+00 -4.661458E-01 +3.148231E+00 +4.974555E-01 0.000000E+00 0.000000E+00 -2.635775E+00 -3.524426E-01 -5.357229E+00 -1.440049E+00 +2.805439E+00 +3.982239E-01 +5.574031E+00 +1.561105E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -128,14 +128,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.357229E+00 -1.440049E+00 -2.635775E+00 -3.524426E-01 -4.982072E+00 -1.251449E+00 -7.228146E+00 -2.620353E+00 +5.574031E+00 +1.561105E+00 +2.805439E+00 +3.982239E-01 +5.171038E+00 +1.344877E+00 +7.372031E+00 +2.725420E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -152,14 +152,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.228146E+00 -2.620353E+00 -4.982072E+00 -1.251449E+00 -7.082265E+00 -2.520047E+00 -8.736529E+00 -3.831244E+00 +7.372031E+00 +2.725420E+00 +5.171038E+00 +1.344877E+00 +6.946847E+00 +2.424850E+00 +8.496610E+00 +3.627542E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -176,14 +176,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.736529E+00 -3.831244E+00 -7.082265E+00 -2.520047E+00 -8.474631E+00 -3.607043E+00 -9.346623E+00 -4.390819E+00 +8.496610E+00 +3.627542E+00 +6.946847E+00 +2.424850E+00 +8.479501E+00 +3.607280E+00 +9.261869E+00 +4.305912E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -200,14 +200,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.346623E+00 -4.390819E+00 -8.474631E+00 -3.607043E+00 -9.496684E+00 -4.522478E+00 -9.532822E+00 -4.559003E+00 +9.261869E+00 +4.305912E+00 +8.479501E+00 +3.607280E+00 +9.232858E+00 +4.278432E+00 +9.306384E+00 +4.348594E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -224,14 +224,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -9.532822E+00 -4.559003E+00 -9.496684E+00 -4.522478E+00 -9.404949E+00 -4.446260E+00 -8.550930E+00 -3.668401E+00 +9.306384E+00 +4.348594E+00 +9.232858E+00 +4.278432E+00 +9.299764E+00 +4.347828E+00 +8.511976E+00 +3.639893E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -248,14 +248,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -8.550930E+00 -3.668401E+00 -9.404949E+00 -4.446260E+00 -8.785273E+00 -3.874792E+00 -7.128863E+00 -2.554326E+00 +8.511976E+00 +3.639893E+00 +9.299764E+00 +4.347828E+00 +8.726086E+00 +3.819567E+00 +7.147277E+00 +2.562747E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -272,14 +272,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.128863E+00 -2.554326E+00 -8.785273E+00 -3.874792E+00 -7.408549E+00 -2.755885E+00 -5.094992E+00 -1.305737E+00 +7.147277E+00 +2.562747E+00 +8.726086E+00 +3.819567E+00 +7.218790E+00 +2.612243E+00 +5.018287E+00 +1.263077E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -296,14 +296,14 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -5.094992E+00 -1.305737E+00 -7.408549E+00 -2.755885E+00 -5.532149E+00 -1.537289E+00 -2.812344E+00 -3.997146E-01 +5.018287E+00 +1.263077E+00 +7.218790E+00 +2.612243E+00 +5.443494E+00 +1.487018E+00 +2.732334E+00 +3.773047E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -320,12 +320,12 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -2.812344E+00 -3.997146E-01 -5.532149E+00 -1.537289E+00 -3.063251E+00 -4.728672E-01 +2.732334E+00 +3.773047E-01 +5.443494E+00 +1.487018E+00 +3.044773E+00 +4.655756E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -345,144 +345,144 @@ tally 4: 0.000000E+00 0.000000E+00 tally 5: -1.496000E+01 -1.127586E+01 -2.280081E+00 -2.675609E-01 -2.774503E+01 -3.876011E+01 -3.908836E+00 -7.703029E-01 -3.848706E+01 -7.449836E+01 -5.299924E+00 -1.422782E+00 -4.723172E+01 -1.119459E+02 -6.450156E+00 -2.105590E+00 -5.095931E+01 -1.303132E+02 -7.050681E+00 -2.515092E+00 -5.133412E+01 -1.322694E+02 -6.853429E+00 -2.384127E+00 -4.754621E+01 -1.136848E+02 -6.370026E+00 -2.058896E+00 -3.886829E+01 -7.591042E+01 -5.266816E+00 -1.400495E+00 -2.910277E+01 -4.253981E+01 -4.090844E+00 -8.442500E-01 -1.556949E+01 -1.221526E+01 -2.266123E+00 -2.641551E-01 +1.609029E+01 +1.306718E+01 +2.230601E+00 +2.559496E-01 +2.876780E+01 +4.148686E+01 +3.835952E+00 +7.456562E-01 +3.895738E+01 +7.625344E+01 +4.841024E+00 +1.197335E+00 +4.633595E+01 +1.079043E+02 +6.236821E+00 +1.963311E+00 +5.007472E+01 +1.258967E+02 +6.749745E+00 +2.297130E+00 +5.058336E+01 +1.285894E+02 +6.727612E+00 +2.315656E+00 +4.743869E+01 +1.130735E+02 +6.338193E+00 +2.042159E+00 +3.899838E+01 +7.631289E+01 +5.187573E+00 +1.359733E+00 +2.873434E+01 +4.144233E+01 +3.815610E+00 +7.367619E-01 +1.509020E+01 +1.145268E+01 +2.125767E+00 +2.341894E-01 cmfd indices 1.000000E+01 1.000000E+00 1.000000E+00 1.000000E+00 k cmfd -1.161531E+00 -1.182724E+00 -1.169653E+00 -1.164722E+00 -1.164583E+00 -1.162952E+00 -1.167024E+00 -1.164509E+00 -1.165693E+00 -1.170623E+00 -1.166618E+00 -1.170805E+00 -1.170962E+00 -1.170964E+00 -1.168224E+00 -1.169864E+00 +1.129918E+00 +1.143848E+00 +1.147976E+00 +1.151534E+00 +1.152378E+00 +1.148219E+00 +1.150402E+00 +1.154647E+00 +1.156159E+00 +1.160048E+00 +1.167441E+00 +1.168163E+00 +1.168629E+00 +1.164120E+00 +1.165051E+00 +1.169177E+00 cmfd entropy -3.206619E+00 -3.205815E+00 -3.208678E+00 -3.210820E+00 -3.217023E+00 -3.215014E+00 -3.214592E+00 -3.215913E+00 -3.214998E+00 -3.213644E+00 -3.210755E+00 -3.210496E+00 -3.212488E+00 -3.211553E+00 -3.212999E+00 -3.214052E+00 +3.224769E+00 +3.225945E+00 +3.227421E+00 +3.226174E+00 +3.224429E+00 +3.227049E+00 +3.230710E+00 +3.230315E+00 +3.226825E+00 +3.226655E+00 +3.226588E+00 +3.224155E+00 +3.223246E+00 +3.222640E+00 +3.223920E+00 +3.222838E+00 cmfd balance -4.99833E-03 -5.64677E-03 -3.62795E-03 -3.91962E-03 -3.87172E-03 -2.48450E-03 -3.15554E-03 -2.49335E-03 -2.31973E-03 -2.19156E-03 -2.31352E-03 -2.03401E-03 -1.80242E-03 -1.65868E-03 -1.47543E-03 -1.49706E-03 +3.90454E-03 +4.08089E-03 +3.46511E-03 +4.09535E-03 +2.62009E-03 +2.23559E-03 +2.54033E-03 +2.12799E-03 +2.25864E-03 +1.85766E-03 +1.49916E-03 +1.63471E-03 +1.48377E-03 +1.59800E-03 +1.37354E-03 +1.32853E-03 cmfd dominance ratio -5.283E-01 -5.289E-01 -5.305E-01 -5.327E-01 -5.377E-01 -5.360E-01 -5.353E-01 -4.983E-01 -5.379E-01 -5.370E-01 -5.359E-01 -5.349E-01 -5.364E-01 -5.347E-01 -5.360E-01 -5.378E-01 +5.539E-01 +5.537E-01 +5.536E-01 +5.515E-01 +5.512E-01 +5.514E-01 +5.518E-01 +5.507E-01 +5.500E-01 +5.497E-01 +5.477E-01 +5.461E-01 +5.444E-01 +5.445E-01 +5.454E-01 +5.441E-01 cmfd openmc source comparison -1.291827E-02 -1.027137E-02 -8.738370E-03 -6.854409E-03 -4.188357E-03 -4.941359E-03 -5.139239E-03 -4.244784E-03 -4.240559E-03 -3.375424E-03 -3.716858E-03 -3.595700E-03 -3.626952E-03 -3.999302E-03 -2.431760E-03 -1.673200E-03 +9.875240E-03 +1.106163E-02 +9.847628E-03 +6.065921E-03 +5.772039E-03 +4.615656E-03 +4.244331E-03 +3.694299E-03 +3.545814E-03 +3.213063E-03 +3.467537E-03 +3.383489E-03 +3.697591E-03 +3.937358E-03 +3.369124E-03 +3.190359E-03 cmfd source -4.185460E-02 -7.636314E-02 -1.075536E-01 -1.307167E-01 -1.400879E-01 -1.459944E-01 -1.297413E-01 -1.084649E-01 -7.772031E-02 -4.150306E-02 +4.360494E-02 +8.397599E-02 +1.074181E-01 +1.294531E-01 +1.385611E-01 +1.407934E-01 +1.325191E-01 +1.044311E-01 +7.660359E-02 +4.263941E-02 diff --git a/tests/regression_tests/cmfd_restart/settings.xml b/tests/regression_tests/cmfd_restart/settings.xml deleted file mode 100644 index ba5495911f9..00000000000 --- a/tests/regression_tests/cmfd_restart/settings.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - eigenvalue - 20 - 10 - 1000 - - - - - box - -10 -1 -1 10 1 1 - - - - - - 10 1 1 - -10.0 -1.0 -1.0 - 10.0 1.0 1.0 - - 10 - - - - diff --git a/tests/regression_tests/cmfd_restart/tallies.xml b/tests/regression_tests/cmfd_restart/tallies.xml deleted file mode 100644 index c869711147f..00000000000 --- a/tests/regression_tests/cmfd_restart/tallies.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - regular - -10 -1 -1 - 10 1 1 - 10 1 1 - - - - mesh - 1 - - - - 1 - flux - - - diff --git a/tests/regression_tests/complex_cell/geometry.xml b/tests/regression_tests/complex_cell/geometry.xml index a695396e012..638c7c9b831 100644 --- a/tests/regression_tests/complex_cell/geometry.xml +++ b/tests/regression_tests/complex_cell/geometry.xml @@ -19,7 +19,7 @@ - + diff --git a/tests/regression_tests/complex_cell/results_true.dat b/tests/regression_tests/complex_cell/results_true.dat index 927a7a519a2..3ce3d7cbc7f 100644 --- a/tests/regression_tests/complex_cell/results_true.dat +++ b/tests/regression_tests/complex_cell/results_true.dat @@ -1,11 +1,11 @@ k-combined: -2.490321E-01 1.083676E-03 +2.564169E-01 4.095378E-03 tally 1: -2.617769E+00 -1.371478E+00 -2.716496E+00 -1.476169E+00 -1.005297E+00 -2.026100E-01 -1.075286E-01 -2.316593E-03 +2.607144E+00 +1.360414E+00 +2.681079E+00 +1.439354E+00 +9.627534E-01 +1.855496E-01 +1.123751E-01 +2.530233E-03 diff --git a/tests/regression_tests/confidence_intervals/results_true.dat b/tests/regression_tests/confidence_intervals/results_true.dat index cb6c6f00a26..6a906d07e74 100644 --- a/tests/regression_tests/confidence_intervals/results_true.dat +++ b/tests/regression_tests/confidence_intervals/results_true.dat @@ -1,5 +1,5 @@ k-combined: -2.679617E-01 1.158917E-02 +2.759923E-01 6.988588E-03 tally 1: -6.693704E+01 -5.643483E+02 +6.167984E+01 +4.772717E+02 diff --git a/tests/regression_tests/cpp_driver/driver.cpp b/tests/regression_tests/cpp_driver/driver.cpp index 995d91e0849..48ed7f3171b 100644 --- a/tests/regression_tests/cpp_driver/driver.cpp +++ b/tests/regression_tests/cpp_driver/driver.cpp @@ -6,6 +6,7 @@ #include "openmc/cell.h" #include "openmc/error.h" #include "openmc/geometry.h" +#include "openmc/geometry_aux.h" #include "openmc/message_passing.h" #include "openmc/summary.h" #include "openmc/tallies/filter.h" @@ -31,11 +32,14 @@ int main(int argc, char** argv) { for (auto& entry : openmc::model::cell_map) { cell_indices.push_back(entry.second); } + // enable distribcells offsets for all cells + prepare_distribcell(&cell_indices); // sort to make sure the cell bins appear in the same // order as the test relying on the openmc exe std::sort(cell_indices.begin(), cell_indices.end()); cell_filter->set_cells(cell_indices); + // create a new tally auto tally = Tally::create(); std::vector filters = {cell_filter}; @@ -46,7 +50,7 @@ int main(int argc, char** argv) { // the lattice auto& root_univ = openmc::model::universes[openmc::model::root_universe]; auto& lattice_cell = openmc::model::cells[root_univ->cells_[0]]; - lattice_cell->set_temperature(300, 1, true); + lattice_cell->set_temperature(300.0, 0, true); // check that material-filled cells return no contained cells for (auto& cell : openmc::model::cells) { @@ -56,6 +60,9 @@ int main(int argc, char** argv) { } } + // set a higher temperature for only one of the lattice cells (ID is 4 in the model) + model::cells[model::cell_map[4]]->set_temperature(400.0, 3, true); + // the summary file will be used to check that // temperatures were set correctly so clear // error output can be provided diff --git a/tests/regression_tests/cpp_driver/inputs_true.dat b/tests/regression_tests/cpp_driver/inputs_true.dat index 84efa646723..5d067cb6854 100644 --- a/tests/regression_tests/cpp_driver/inputs_true.dat +++ b/tests/regression_tests/cpp_driver/inputs_true.dat @@ -1,44 +1,45 @@ - - - - - - - 4.0 4.0 - 2 2 - -4.0 -4.0 - -1 1 -1 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 1 - + + + + + + + + + + + + + + + + + + + + + + + + 4.0 4.0 + 2 2 + -4.0 -4.0 + +2 2 +2 2 + + + + + + + + + + eigenvalue + 100 + 10 + 1 + + diff --git a/tests/regression_tests/cpp_driver/results_true.dat b/tests/regression_tests/cpp_driver/results_true.dat index 47d47ff6b03..c2b0b8d6f36 100644 --- a/tests/regression_tests/cpp_driver/results_true.dat +++ b/tests/regression_tests/cpp_driver/results_true.dat @@ -1,11 +1,13 @@ k-combined: -1.902610E+00 1.901530E-02 +1.933305E+00 1.300360E-02 tally 1: -9.580351E+01 -1.031580E+03 -2.745984E+01 -8.430494E+01 -9.422158E+01 -9.919885E+02 -2.174849E+02 -5.292948E+03 +9.552846E+01 +1.019358E+03 +2.887973E+01 +9.308509E+01 +9.732441E+01 +1.059022E+03 +2.217326E+02 +5.486892E+03 +2.217326E+02 +5.486892E+03 diff --git a/tests/regression_tests/cpp_driver/test.py b/tests/regression_tests/cpp_driver/test.py index 42f0c2e5817..b80e82ee0e1 100644 --- a/tests/regression_tests/cpp_driver/test.py +++ b/tests/regression_tests/cpp_driver/test.py @@ -20,7 +20,7 @@ def cpp_driver(request): openmc_dir = Path(str(request.config.rootdir)) / 'build' with open('CMakeLists.txt', 'w') as f: f.write(textwrap.dedent(""" - cmake_minimum_required(VERSION 3.3 FATAL_ERROR) + cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(openmc_cpp_driver CXX) add_executable(cpp_driver driver.cpp) find_package(OpenMC REQUIRED HINTS {}) @@ -33,12 +33,14 @@ def cpp_driver(request): os.chdir(str(local_builddir)) if config['mpi']: - os.environ['CXX'] = 'mpicxx' + mpi_arg = "On" + else: + mpi_arg = "Off" try: print("Building driver") # Run cmake/make to build the shared libary - subprocess.run(['cmake', os.path.pardir], check=True) + subprocess.run(['cmake', os.path.pardir, f'-DOPENMC_USE_MPI={mpi_arg}'], check=True) subprocess.run(['make'], check=True) os.chdir(os.path.pardir) @@ -46,8 +48,8 @@ def cpp_driver(request): finally: # Remove local build directory when test is complete - shutil.rmtree('build') - os.remove('CMakeLists.txt') + shutil.rmtree(request.node.path.parent / 'build') + os.remove(request.node.path.parent / 'CMakeLists.txt') @pytest.fixture @@ -81,15 +83,18 @@ def model(): pincell_univ = openmc.Universe(cells=[fuel, cladding, moderator]) + # insert an additional cell to add another level to the geometry + extra_cell = openmc.Cell(fill=pincell_univ) + extra_univ = openmc.Universe(cells=[extra_cell]) + # lattice lattice = openmc.RectLattice() lattice.pitch = (4.0, 4.0) lattice.lower_left = (-4.0, -4.0) - lattice.universes = [[pincell_univ, pincell_univ], [pincell_univ, pincell_univ]] - lattice_region = openmc.model.rectangular_prism(8.0, - 8.0, - boundary_type='reflective') - lattice_cell = openmc.Cell(fill=lattice, region=lattice_region) + lattice.universes = [[extra_univ, extra_univ], [extra_univ, extra_univ]] + lattice_prism = openmc.model.RectangularPrism( + 8.0, 8.0, boundary_type='reflective') + lattice_cell = openmc.Cell(fill=lattice, region=-lattice_prism) model.geometry = openmc.Geometry([lattice_cell]) @@ -130,7 +135,8 @@ def _compare_results(self): for cell in cells.values(): if isinstance(cell.fill, openmc.Material): assert len(cell.temperature) == 4 - assert_allclose(cell.temperature, 300.0) + assert_allclose(cell.temperature[:3], 300.0) + assert_allclose(cell.temperature[-1:], 400.0) def test_cpp_driver(cpp_driver, model): diff --git a/tests/regression_tests/create_fission_neutrons/inputs_true.dat b/tests/regression_tests/create_fission_neutrons/inputs_true.dat index b0ca896476f..9e44a022497 100644 --- a/tests/regression_tests/create_fission_neutrons/inputs_true.dat +++ b/tests/regression_tests/create_fission_neutrons/inputs_true.dat @@ -1,37 +1,36 @@ - - - - - - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - -1 -1 -1 1 1 1 - - - - false - - - - - flux - - + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + -1 -1 -1 1 1 1 + + + + false + + + + flux + + + diff --git a/tests/regression_tests/create_fission_neutrons/test.py b/tests/regression_tests/create_fission_neutrons/test.py index f1c1d072cb0..0ca4a48b292 100755 --- a/tests/regression_tests/create_fission_neutrons/test.py +++ b/tests/regression_tests/create_fission_neutrons/test.py @@ -4,14 +4,14 @@ class CreateFissionNeutronsTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # Material is composed of H-1 and U-235 mat = openmc.Material(material_id=1, name='mat') mat.set_density('atom/b-cm', 0.069335) mat.add_nuclide('H1', 40.0) mat.add_nuclide('U235', 1.0) - materials_file = openmc.Materials([mat]) - materials_file.export_to_xml() + self._model.materials = openmc.Materials([mat]) # Cell is box with reflective boundary x1 = openmc.XPlane(surface_id=1, x0=-1) @@ -27,8 +27,7 @@ def _build_inputs(self): box.fill = mat root = openmc.Universe(universe_id=0, name='root universe') root.add_cell(box) - geometry = openmc.Geometry(root) - geometry.export_to_xml() + self._model.geometry = openmc.Geometry(root) # Set the running parameters settings_file = openmc.Settings() @@ -39,16 +38,16 @@ def _build_inputs(self): bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) watt_dist = openmc.stats.Watt() - settings_file.source = openmc.source.Source(space=uniform_dist, - energy=watt_dist) - settings_file.export_to_xml() + settings_file.source = openmc.IndependentSource(space=uniform_dist, + energy=watt_dist) + self._model.settings = settings_file # Create tallies tallies = openmc.Tallies() tally = openmc.Tally(1) tally.scores = ['flux'] tallies.append(tally) - tallies.export_to_xml() + self._model.tallies = tallies def _get_results(self): """Digest info in the statepoint and return as a string.""" @@ -66,5 +65,6 @@ def _get_results(self): def test_create_fission_neutrons(): - harness = CreateFissionNeutronsTestHarness('statepoint.10.h5') + harness = CreateFissionNeutronsTestHarness('statepoint.10.h5', + model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/dagmc/external/__init__.py b/tests/regression_tests/dagmc/external/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/dagmc/external/dagmc.h5m b/tests/regression_tests/dagmc/external/dagmc.h5m new file mode 120000 index 00000000000..92c41719c51 --- /dev/null +++ b/tests/regression_tests/dagmc/external/dagmc.h5m @@ -0,0 +1 @@ +../legacy/dagmc.h5m \ No newline at end of file diff --git a/tests/regression_tests/dagmc/external/inputs_true.dat b/tests/regression_tests/dagmc/external/inputs_true.dat new file mode 100644 index 00000000000..31f4c1f886d --- /dev/null +++ b/tests/regression_tests/dagmc/external/inputs_true.dat @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + 293 + + + + 1 + + + 1 + total + + + diff --git a/tests/regression_tests/dagmc/external/main.cpp b/tests/regression_tests/dagmc/external/main.cpp new file mode 100644 index 00000000000..3765cf79ae2 --- /dev/null +++ b/tests/regression_tests/dagmc/external/main.cpp @@ -0,0 +1,118 @@ +#include "openmc/capi.h" +#include "openmc/cross_sections.h" +#include "openmc/dagmc.h" +#include "openmc/error.h" +#include "openmc/geometry.h" +#include "openmc/geometry_aux.h" +#include "openmc/material.h" +#include "openmc/message_passing.h" +#include "openmc/nuclide.h" +#include + +int main(int argc, char* argv[]) +{ + using namespace openmc; + int openmc_err; + + // Initialise OpenMC +#ifdef OPENMC_MPI + MPI_Comm world = MPI_COMM_WORLD; + openmc_err = openmc_init(argc, argv, &world); +#else + openmc_err = openmc_init(argc, argv, nullptr); +#endif + if (openmc_err == -1) { + // This happens for the -h and -v flags + return EXIT_SUCCESS; + } else if (openmc_err) { + fatal_error(openmc_err_msg); + } + + // Create DAGMC ptr + std::string filename = "dagmc.h5m"; + std::shared_ptr dag_ptr = std::make_shared(); + moab::ErrorCode rval = dag_ptr->load_file(filename.c_str()); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to load file"); + } + + // Initialize acceleration data structures + rval = dag_ptr->init_OBBTree(); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to initialize OBB tree"); + } + + // Get rid of existing geometry + std::unordered_map nuclide_map_copy = + openmc::data::nuclide_map; + openmc::data::nuclides.clear(); + openmc::data::nuclide_map = nuclide_map_copy; + openmc::model::surfaces.clear(); + openmc::model::surface_map.clear(); + openmc::model::cells.clear(); + openmc::model::cell_map.clear(); + openmc::model::universes.clear(); + openmc::model::universe_map.clear(); + + // Update materials (emulate an external program) + for (auto& mat_ptr : openmc::model::materials) { + mat_ptr->set_temperature(300); + } + + // Create new DAGMC universe + openmc::model::universes.push_back( + std::make_unique(dag_ptr)); + model::universe_map[model::universes.back()->id_] = + model::universes.size() - 1; + + // Add cells to universes + openmc::populate_universes(); + + // Make sure implicit complement appears last + auto dag_univ = dynamic_cast(model::universes.back().get()); + int n = dag_univ->cells_.size(); + for (int i = 0; i < n - 1; ++i) { + if (dag_univ->cells_[i] == dag_univ->implicit_complement_idx()) { + fatal_error("Implicit complement cell should appear last in vector of " + "cells for DAGMC universe."); + } + } + if (dag_univ->cells_.back() != dag_univ->implicit_complement_idx()) { + fatal_error( + "Last cell in DAGMC universe is not an implicit complement cell."); + } + + // Set root universe + openmc::model::root_universe = openmc::find_root_universe(); + openmc::check_dagmc_root_univ(); + + // Final geometry setup and assign temperatures + openmc::finalize_geometry(); + + // Finalize cross sections having assigned temperatures + openmc::finalize_cross_sections(); + + // Check that we correctly assigned cell temperatures with non-void fill + for (auto& cell_ptr : openmc::model::cells) { + if (cell_ptr->material_.front() != openmc::C_NONE && + cell_ptr->temperature() != 300) { + fatal_error("Failed to set cell temperature"); + } + } + + // Run OpenMC + openmc_err = openmc_run(); + if (openmc_err) + fatal_error(openmc_err_msg); + + // Deallocate memory + openmc_err = openmc_finalize(); + if (openmc_err) + fatal_error(openmc_err_msg); + +#ifdef OPENMC_MPI + MPI_Finalize(); +#endif + + return EXIT_SUCCESS; +} diff --git a/tests/regression_tests/dagmc/external/results_true.dat b/tests/regression_tests/dagmc/external/results_true.dat new file mode 100644 index 00000000000..cda65693787 --- /dev/null +++ b/tests/regression_tests/dagmc/external/results_true.dat @@ -0,0 +1,5 @@ +k-combined: +9.118190E-01 3.615552E-02 +tally 1: +8.430103E+00 +1.442878E+01 diff --git a/tests/regression_tests/dagmc/external/test.py b/tests/regression_tests/dagmc/external/test.py new file mode 100644 index 00000000000..57bc9ea7fd6 --- /dev/null +++ b/tests/regression_tests/dagmc/external/test.py @@ -0,0 +1,128 @@ +from pathlib import Path +import os +import shutil +import subprocess +import textwrap + +import openmc +import openmc.lib +import pytest + +from tests.regression_tests import config +from tests.testing_harness import PyAPITestHarness + +pytestmark = pytest.mark.skipif( + not openmc.lib._dagmc_enabled(), + reason="DAGMC is not enabled.") + +# Test that an external DAGMC instance can be passed in through the C API + +@pytest.fixture +def cpp_driver(request): + """Compile the external source""" + + # Get build directory and write CMakeLists.txt file + openmc_dir = Path(str(request.config.rootdir)) / 'build' + with open('CMakeLists.txt', 'w') as f: + f.write(textwrap.dedent(""" + cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + project(openmc_cpp_driver CXX) + add_executable(main main.cpp) + find_package(OpenMC REQUIRED HINTS {}) + target_link_libraries(main OpenMC::libopenmc) + target_compile_features(main PUBLIC cxx_std_14) + set(CMAKE_CXX_FLAGS "-pedantic-errors") + add_compile_definitions(DAGMC=1) + """.format(openmc_dir))) + + # Create temporary build directory and change to there + local_builddir = Path('build') + local_builddir.mkdir(exist_ok=True) + os.chdir(local_builddir) + + mpi_arg = "On" if config['mpi'] else "Off" + + try: + # Run cmake/make to build the shared libary + subprocess.run(['cmake', os.path.pardir, f'-DOPENMC_USE_MPI={mpi_arg}'], check=True) + subprocess.run(['make'], check=True) + os.chdir(os.path.pardir) + + yield "./build/main" + + finally: + # Remove local build directory when test is complete + shutil.rmtree('build') + os.remove('CMakeLists.txt') + +@pytest.fixture +def model(): + model = openmc.model.Model() + + # Settings + model.settings.batches = 5 + model.settings.inactive = 0 + model.settings.particles = 100 + source_box = openmc.stats.Box([-4, -4, -4], + [ 4, 4, 4]) + source = openmc.IndependentSource(space=source_box) + model.settings.source = source + model.settings.temperature['default'] = 293 + + # Geometry + dag_univ = openmc.DAGMCUniverse("dagmc.h5m") + model.geometry = openmc.Geometry(dag_univ) + + # Tallies + tally = openmc.Tally() + tally.scores = ['total'] + tally.filters = [openmc.CellFilter(1)] + model.tallies = [tally] + + # Materials + u235 = openmc.Material(name="no-void fuel") + u235.add_nuclide('U235', 1.0, 'ao') + u235.set_density('g/cc', 11) + u235.id = 40 + water = openmc.Material(name="water") + water.add_nuclide('H1', 2.0, 'ao') + water.add_nuclide('O16', 1.0, 'ao') + water.set_density('g/cc', 1.0) + water.add_s_alpha_beta('c_H_in_H2O') + water.id = 41 + mats = openmc.Materials([u235, water]) + model.materials = mats + + return model + +class ExternalDAGMCTest(PyAPITestHarness): + def __init__(self, executable, statepoint_name, model): + super().__init__(statepoint_name, model) + self.executable = executable + + def _run_openmc(self): + """ + Just test if results generated with the external C++ API are + self-consistent with the internal python API. + We generate the "truth" results with the python API but + the main test produces the results file by running the + executable compiled from main.cpp. This future-proofs + the test - we only care that the two routes are equivalent. + """ + if config['update']: + # Generate the results file with internal python API + openmc.run(openmc_exec=config['exe'], event_based=config['event']) + elif config['mpi']: + mpi_args = [config['mpiexec'], '-n', config['mpi_np']] + # Run main cpp executable with MPI + openmc.run(openmc_exec=self.executable, + mpi_args=mpi_args, + event_based=config['event']) + else: + # Run main cpp executable + openmc.run(openmc_exec=self.executable, + event_based=config['event']) + +def test_external_dagmc(cpp_driver, model): + harness = ExternalDAGMCTest(cpp_driver, 'statepoint.5.h5', model) + harness.main() diff --git a/tests/regression_tests/dagmc/legacy/inputs_true.dat b/tests/regression_tests/dagmc/legacy/inputs_true.dat index 769a3384c3c..b06516cb1eb 100644 --- a/tests/regression_tests/dagmc/legacy/inputs_true.dat +++ b/tests/regression_tests/dagmc/legacy/inputs_true.dat @@ -1,36 +1,38 @@ - - - - - - - - - - - - - - - eigenvalue - 100 - 5 - 0 - - - -4 -4 -4 4 4 4 - - - true - - - - - 1 - - - 1 - total - - + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + + + + 1 + + + 1 + total + + + diff --git a/tests/regression_tests/dagmc/legacy/results_true.dat b/tests/regression_tests/dagmc/legacy/results_true.dat index e5127c8272d..cda65693787 100644 --- a/tests/regression_tests/dagmc/legacy/results_true.dat +++ b/tests/regression_tests/dagmc/legacy/results_true.dat @@ -1,5 +1,5 @@ k-combined: -8.426936E-01 5.715847E-02 +9.118190E-01 3.615552E-02 tally 1: -8.093843E+00 -1.328829E+01 +8.430103E+00 +1.442878E+01 diff --git a/tests/regression_tests/dagmc/legacy/test.py b/tests/regression_tests/dagmc/legacy/test.py index 5af18e5c8cf..884264f30ef 100644 --- a/tests/regression_tests/dagmc/legacy/test.py +++ b/tests/regression_tests/dagmc/legacy/test.py @@ -1,8 +1,13 @@ +from pathlib import Path + import openmc import openmc.lib +import h5py +import numpy as np import pytest -from tests.testing_harness import PyAPITestHarness + +from tests.testing_harness import PyAPITestHarness, config pytestmark = pytest.mark.skipif( not openmc.lib._dagmc_enabled(), @@ -10,8 +15,9 @@ @pytest.fixture def model(): + openmc.reset_auto_ids() - model = openmc.model.Model() + model = openmc.Model() # settings model.settings.batches = 5 @@ -20,11 +26,13 @@ def model(): source_box = openmc.stats.Box([-4, -4, -4], [ 4, 4, 4]) - source = openmc.Source(space=source_box) + source = openmc.IndependentSource(space=source_box) model.settings.source = source - model.settings.dagmc = True + # geometry + dag_univ = openmc.DAGMCUniverse(Path("dagmc.h5m")) + model.geometry = openmc.Geometry(dag_univ) # tally tally = openmc.Tally() @@ -50,6 +58,51 @@ def model(): return model + +def test_missing_material_id(model): + # remove the last material, which is identified by ID in the DAGMC file + model.materials = model.materials[:-1] + with pytest.raises(RuntimeError) as exec_info: + model.run() + exp_error_msg = "Material with name/ID '41' not found for volume (cell) 3" + assert exp_error_msg in str(exec_info.value) + + +def test_missing_material_name(model): + # remove the first material, which is identified by name in the DAGMC file + model.materials = model.materials[1:] + with pytest.raises(RuntimeError) as exec_info: + model.run() + exp_error_msg = "Material with name/ID 'no-void fuel' not found for volume (cell) 1" + assert exp_error_msg in str(exec_info.value) + + +def test_surf_source(model): + # create a surface source read on this model to ensure + # particles are being generated correctly + n = 100 + model.settings.surf_source_write = {'surface_ids': [1], 'max_particles': n} + + # If running in MPI mode, setup proper keyword arguments for run() + kwargs = {'openmc_exec': config['exe']} + if config['mpi']: + kwargs['mpi_args'] = [config['mpiexec'], '-n', config['mpi_np']] + model.run(**kwargs) + + with h5py.File('surface_source.h5') as fh: + assert fh.attrs['filetype'] == b'source' + arr = fh['source_bank'][...] + expected_size = n * int(config['mpi_np']) if config['mpi'] else n + assert arr.size == expected_size + + # check that all particles are on surface 1 (radius = 7) + xs = arr[:]['r']['x'] + ys = arr[:]['r']['y'] + rad = np.sqrt(xs**2 + ys**2) + assert np.allclose(rad, 7.0) + + def test_dagmc(model): harness = PyAPITestHarness('statepoint.5.h5', model) harness.main() + diff --git a/tests/regression_tests/dagmc/refl/inputs_true.dat b/tests/regression_tests/dagmc/refl/inputs_true.dat index 87ceb944d81..979eeb49206 100644 --- a/tests/regression_tests/dagmc/refl/inputs_true.dat +++ b/tests/regression_tests/dagmc/refl/inputs_true.dat @@ -1,23 +1,28 @@ - - eigenvalue - 100 - 5 - 0 - - - -4 -4 -4 4 4 4 - - - true - - - - - 1 - - - 1 - total - - + + + + + + + + eigenvalue + 100 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + + + + 2 + + + 1 + total + + + diff --git a/tests/regression_tests/dagmc/refl/results_true.dat b/tests/regression_tests/dagmc/refl/results_true.dat index bd1169835d9..533c62a9024 100644 --- a/tests/regression_tests/dagmc/refl/results_true.dat +++ b/tests/regression_tests/dagmc/refl/results_true.dat @@ -1,5 +1,5 @@ k-combined: -2.130286E+00 2.412252E-02 +2.035173E+00 3.967029E-02 tally 1: -1.177815E+01 -2.806871E+01 +1.064492E+01 +2.301019E+01 diff --git a/tests/regression_tests/dagmc/refl/test.py b/tests/regression_tests/dagmc/refl/test.py index c451b61250c..a13acc0256a 100644 --- a/tests/regression_tests/dagmc/refl/test.py +++ b/tests/regression_tests/dagmc/refl/test.py @@ -6,35 +6,33 @@ from tests.testing_harness import PyAPITestHarness pytestmark = pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), - reason="DAGMC CAD geometry is not enabled.") + not openmc.lib._uwuw_enabled(), + reason="UWUW is not enabled.") class UWUWTest(PyAPITestHarness): - - def _build_inputs(self): - model = openmc.model.Model() + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # settings - model.settings.batches = 5 - model.settings.inactive = 0 - model.settings.particles = 100 - - source = openmc.Source(space=Box([-4, -4, -4], - [ 4, 4, 4])) - model.settings.source = source + self._model.settings.batches = 5 + self._model.settings.inactive = 0 + self._model.settings.particles = 100 - model.settings.dagmc = True + source = openmc.IndependentSource(space=Box([-4, -4, -4], + [ 4, 4, 4])) + self._model.settings.source = source - model.settings.export_to_xml() + # geometry + dag_univ = openmc.DAGMCUniverse("dagmc.h5m", auto_geom_ids=True) + self._model.geometry = openmc.Geometry(dag_univ) # tally tally = openmc.Tally() tally.scores = ['total'] - tally.filters = [openmc.CellFilter(1)] - model.tallies = [tally] + tally.filters = [openmc.CellFilter(2)] + self._model.tallies = [tally] - model.tallies.export_to_xml() def test_refl(): - harness = UWUWTest('statepoint.5.h5') + harness = UWUWTest('statepoint.5.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/dagmc/universes/__init__.py b/tests/regression_tests/dagmc/universes/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/dagmc/universes/dagmc.h5m b/tests/regression_tests/dagmc/universes/dagmc.h5m new file mode 100644 index 00000000000..d5f884db274 Binary files /dev/null and b/tests/regression_tests/dagmc/universes/dagmc.h5m differ diff --git a/tests/regression_tests/dagmc/universes/inputs_true.dat b/tests/regression_tests/dagmc/universes/inputs_true.dat new file mode 100644 index 00000000000..babf43ff1d8 --- /dev/null +++ b/tests/regression_tests/dagmc/universes/inputs_true.dat @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 24.0 24.0 + 2 2 + -24.0 -24.0 + +1 1 +1 1 + + + + + + + + + + eigenvalue + 100 + 10 + 2 + + false + + + diff --git a/tests/regression_tests/dagmc/universes/results_true.dat b/tests/regression_tests/dagmc/universes/results_true.dat new file mode 100644 index 00000000000..f7bd016c155 --- /dev/null +++ b/tests/regression_tests/dagmc/universes/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +9.156561E-01 4.398617E-02 diff --git a/tests/regression_tests/dagmc/universes/test.py b/tests/regression_tests/dagmc/universes/test.py new file mode 100644 index 00000000000..a318275cd01 --- /dev/null +++ b/tests/regression_tests/dagmc/universes/test.py @@ -0,0 +1,84 @@ +import numpy as np + +import openmc +import openmc.lib + +import pytest +from tests.testing_harness import PyAPITestHarness + +pytestmark = pytest.mark.skipif( + not openmc.lib._dagmc_enabled(), + reason="DAGMC CAD geometry is not enabled.") + + +class DAGMCUniverseTest(PyAPITestHarness): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + ### MATERIALS ### + fuel = openmc.Material(name='no-void fuel') + fuel.set_density('g/cc', 10.29769) + fuel.add_nuclide('U234', 0.93120485) + fuel.add_nuclide('U235', 0.00055815) + fuel.add_nuclide('U238', 0.022408) + fuel.add_nuclide('O16', 0.045829) + + cladding = openmc.Material(name='clad') + cladding.set_density('g/cc', 6.55) + cladding.add_nuclide('Zr90', 0.021827) + cladding.add_nuclide('Zr91', 0.00476) + cladding.add_nuclide('Zr92', 0.0072758) + cladding.add_nuclide('Zr94', 0.0073734) + cladding.add_nuclide('Zr96', 0.0011879) + + water = openmc.Material(name='water') + water.set_density('g/cc', 0.740582) + water.add_nuclide('H1', 0.049457) + water.add_nuclide('O16', 0.024672) + water.add_nuclide('B10', 8.0042e-06) + water.add_nuclide('B11', 3.2218e-05) + water.add_s_alpha_beta('c_H_in_H2O') + + self._model.materials = openmc.Materials([fuel, cladding, water]) + + ### GEOMETRY ### + # create the DAGMC universe + pincell_univ = openmc.DAGMCUniverse(filename='dagmc.h5m', auto_geom_ids=True) + + # creates another DAGMC universe, this time with within a bounded cell + bound_pincell_universe = openmc.DAGMCUniverse(filename='dagmc.h5m').bounded_universe() + # uses the bound_dag_cell as the root argument to test the type checks in openmc.Geometry + bound_pincell_geometry = openmc.Geometry(root=bound_pincell_universe) + # assigns the bound_dag_geometry to the model to test the type checks in model.Geometry setter + self._model.geometry = bound_pincell_geometry + + # create a 2 x 2 lattice using the DAGMC pincell + pitch = np.asarray((24.0, 24.0)) + lattice = openmc.RectLattice() + lattice.pitch = pitch + lattice.universes = [[pincell_univ] * 2] * 2 + lattice.lower_left = -pitch + + left = openmc.XPlane(x0=-pitch[0], name='left', boundary_type='reflective') + right = openmc.XPlane(x0=pitch[0], name='right', boundary_type='reflective') + front = openmc.YPlane(y0=-pitch[1], name='front', boundary_type='reflective') + back = openmc.YPlane(y0=pitch[1], name='back', boundary_type='reflective') + # clip the DAGMC geometry at +/- 10 cm w/ CSG planes + bottom = openmc.ZPlane(z0=-10.0, name='bottom', boundary_type='reflective') + top = openmc.ZPlane(z0=10.0, name='top', boundary_type='reflective') + + bounding_region = +left & -right & +front & -back & +bottom & -top + bounding_cell = openmc.Cell(fill=lattice, region=bounding_region) + + self._model.geometry = openmc.Geometry([bounding_cell]) + + # settings + self._model.settings.particles = 100 + self._model.settings.batches = 10 + self._model.settings.inactive = 2 + self._model.settings.output = {'summary' : False} + + +def test_univ(): + harness = DAGMCUniverseTest('statepoint.10.h5', model=openmc.Model()) + harness.main() diff --git a/tests/regression_tests/dagmc/uwuw/inputs_true.dat b/tests/regression_tests/dagmc/uwuw/inputs_true.dat index 87ceb944d81..d7e4a12aa78 100644 --- a/tests/regression_tests/dagmc/uwuw/inputs_true.dat +++ b/tests/regression_tests/dagmc/uwuw/inputs_true.dat @@ -1,23 +1,28 @@ - - eigenvalue - 100 - 5 - 0 - - - -4 -4 -4 4 4 4 - - - true - - - - - 1 - - - 1 - total - - + + + + + + + + eigenvalue + 100 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + + + + 1 + + + 1 + total + + + diff --git a/tests/regression_tests/dagmc/uwuw/test.py b/tests/regression_tests/dagmc/uwuw/test.py index b4391d8e77e..bea464cfabc 100644 --- a/tests/regression_tests/dagmc/uwuw/test.py +++ b/tests/regression_tests/dagmc/uwuw/test.py @@ -6,35 +6,33 @@ from tests.testing_harness import PyAPITestHarness pytestmark = pytest.mark.skipif( - not openmc.lib._dagmc_enabled(), - reason="DAGMC CAD geometry is not enabled.") + not openmc.lib._uwuw_enabled(), + reason="UWUW is not enabled.") class UWUWTest(PyAPITestHarness): - - def _build_inputs(self): - model = openmc.model.Model() + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # settings - model.settings.batches = 5 - model.settings.inactive = 0 - model.settings.particles = 100 - - source = openmc.Source(space=Box([-4, -4, -4], - [ 4, 4, 4])) - model.settings.source = source + self._model.settings.batches = 5 + self._model.settings.inactive = 0 + self._model.settings.particles = 100 - model.settings.dagmc = True + source = openmc.IndependentSource(space=Box([-4, -4, -4], + [ 4, 4, 4])) + self._model.settings.source = source - model.settings.export_to_xml() + # geometry + dag_univ = openmc.DAGMCUniverse("dagmc.h5m") + self._model.geometry = openmc.Geometry(root=dag_univ) # tally tally = openmc.Tally() tally.scores = ['total'] tally.filters = [openmc.CellFilter(1)] - model.tallies = [tally] + self._model.tallies = [tally] - model.tallies.export_to_xml() def test_uwuw(): - harness = UWUWTest('statepoint.5.h5') + harness = UWUWTest('statepoint.5.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/density/results_true.dat b/tests/regression_tests/density/results_true.dat index 17d0730dfd2..c8e3b1ede81 100644 --- a/tests/regression_tests/density/results_true.dat +++ b/tests/regression_tests/density/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.097336E+00 2.305434E-02 +1.110057E+00 1.303260E-02 diff --git a/tests/regression_tests/deplete/last_step_reference_materials.xml b/tests/regression_tests/deplete/last_step_reference_materials.xml deleted file mode 100644 index fc9fd0cf5b3..00000000000 --- a/tests/regression_tests/deplete/last_step_reference_materials.xml +++ /dev/null @@ -1,1057 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/regression_tests/deplete/test_reference.h5 b/tests/regression_tests/deplete/test_reference.h5 deleted file mode 100644 index d478d628ef6..00000000000 Binary files a/tests/regression_tests/deplete/test_reference.h5 and /dev/null differ diff --git a/tests/regression_tests/deplete_decay_only/__init__.py b/tests/regression_tests/deplete_decay_only/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/deplete_decay_only/test.py b/tests/regression_tests/deplete_decay_only/test.py new file mode 100644 index 00000000000..4345b86b898 --- /dev/null +++ b/tests/regression_tests/deplete_decay_only/test.py @@ -0,0 +1,103 @@ +""" Transport-free depletion test suite """ + +from pathlib import Path +import shutil + +import numpy as np +import pytest +import openmc +import openmc.deplete +from openmc.deplete import CoupledOperator, IndependentOperator, MicroXS + + +@pytest.fixture(scope="module") +def model(): + fuel = openmc.Material(name="uo2") + fuel.add_element("U", 1, percent_type="ao", enrichment=4.25) + fuel.add_element("O", 2) + fuel.add_nuclide("Xe135_m1", 1) + fuel.add_nuclide("Cs135_m1", 1) + fuel.set_density("g/cc", 10.4) + + clad = openmc.Material(name="clad") + clad.add_element("Zr", 1) + clad.set_density("g/cc", 6) + + water = openmc.Material(name="water") + water.add_element("O", 1) + water.add_element("H", 2) + water.set_density("g/cc", 1.0) + water.add_s_alpha_beta("c_H_in_H2O") + + radii = [0.42, 0.45] + fuel.volume = np.pi * radii[0] ** 2 + + materials = openmc.Materials([fuel, clad, water]) + + pin_surfaces = [openmc.ZCylinder(r=r) for r in radii] + pin_univ = openmc.model.pin(pin_surfaces, materials) + bound_box = openmc.model.RectangularPrism(1.24, 1.24, boundary_type="reflective") + root_cell = openmc.Cell(fill=pin_univ, region=-bound_box) + geometry = openmc.Geometry([root_cell]) + + settings = openmc.Settings() + settings.particles = 1000 + settings.inactive = 5 + settings.batches = 10 + + return openmc.Model(geometry, materials, settings) + +@pytest.fixture(scope="module") +def micro_xs(): + micro_xs_file = Path(__file__).parents[2] / 'micro_xs_simple.csv' + return MicroXS.from_csv(micro_xs_file) + + +@pytest.fixture(scope="module") +def chain_file(): + return Path(__file__).parents[2] / 'chain_simple_decay.xml' + + +@pytest.mark.parametrize("operator_type", ["coupled", "independent"]) +def test_decay_only(run_in_tmpdir, operator_type, model, micro_xs, chain_file): + """Transport free system test suite. + + """ + # Create operator + if operator_type == "coupled": + op = CoupledOperator(model, chain_file=chain_file) + else: + op = IndependentOperator(openmc.Materials([model.materials[0]]), + [1e15], + [micro_xs], + chain_file) + + # Power and timesteps + dt = [917.4, 2262.6] # one Xe135_m1 half life and one Cs135_m1 half life + + # Perform simulation using the predictor algorithm + openmc.deplete.PredictorIntegrator(op, + dt, + power=0.0, + timestep_units='s').integrate() + + # Get path to test and reference results + path_test = op.output_dir / 'depletion_results.h5' + + # Load the reference/test results + res_test = openmc.deplete.Results(path_test) + + _, xe135m1_atoms = res_test.get_atoms('1', 'Xe135_m1') + _, xe135_atoms = res_test.get_atoms('1', 'Xe135') + _, cs135m1_atoms = res_test.get_atoms('1', 'Cs135_m1') + _, cs135_atoms = res_test.get_atoms('1', 'Cs135') + + tol = 1.0e-14 + assert xe135m1_atoms[0] == pytest.approx(xe135m1_atoms[1] * 2, rel=tol) + + # WARNING: this is generally not true as Xe135_m1 has two + # decay modes, and Xe135 will also decay, but we've modified the depletion chain so + # that Xe135_m1 only decays to Xe135, and that Xe135 has has no decay modes + assert xe135_atoms[1] == pytest.approx(xe135m1_atoms[1], rel=tol) + assert cs135m1_atoms[0] == pytest.approx(cs135m1_atoms[2] * 2, rel=tol) + assert cs135_atoms[2] == pytest.approx(cs135m1_atoms[2], rel=tol) diff --git a/tests/regression_tests/deplete_no_transport/__init__.py b/tests/regression_tests/deplete_no_transport/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/deplete_no_transport/test.py b/tests/regression_tests/deplete_no_transport/test.py new file mode 100644 index 00000000000..54c29cd5b70 --- /dev/null +++ b/tests/regression_tests/deplete_no_transport/test.py @@ -0,0 +1,206 @@ +""" Transport-free depletion test suite """ + +from pathlib import Path +import shutil + +import numpy as np +import pytest +import openmc +import openmc.deplete +from openmc.deplete import IndependentOperator, MicroXS + +from tests.regression_tests import config, assert_atoms_equal, \ + assert_reaction_rates_equal + + +@pytest.fixture(scope="module") +def fuel(): + fuel = openmc.Material(name="uo2") + fuel.add_element("U", 1, percent_type="ao", enrichment=4.25) + fuel.add_element("O", 2) + fuel.set_density("g/cc", 10.4) + fuel.depletable = True + + fuel.volume = np.pi * 0.42 ** 2 + + return fuel + +@pytest.fixture(scope="module") +def micro_xs(): + micro_xs_file = Path(__file__).parents[2] / 'micro_xs_simple.csv' + return MicroXS.from_csv(micro_xs_file) + + +@pytest.fixture(scope="module") +def chain_file(): + return Path(__file__).parents[2] / 'chain_simple.xml' + + +neutron_per_cm2_sec = 1164719970082145.0 + + +@pytest.mark.parametrize("multiproc, from_nuclides, normalization_mode, power, source_rate", [ + (True, True, 'source-rate', None, 1.0), + (False, True, 'source-rate', None, 1.0), + (True, True, 'fission-q', 174, None), + (False, True, 'fission-q', 174, None), + (True, False, 'source-rate', None, 1.0), + (False, False, 'source-rate', None, 1.0), + (True, False, 'fission-q', 174, None), + (False, False, 'fission-q', 174, None)]) +def test_against_self(run_in_tmpdir, + fuel, + micro_xs, + chain_file, + multiproc, + from_nuclides, + normalization_mode, + power, + source_rate): + """Transport free system test suite. + + Runs an OpenMC transport-free depletion calculation and verifies + that the outputs match a reference file. + + """ + # Create operator + flux = neutron_per_cm2_sec * fuel.volume + op = _create_operator(from_nuclides, + fuel, + flux, + micro_xs, + chain_file, + normalization_mode) + + # Power and timesteps + dt = [360] # single step + + # Perform simulation using the predictor algorithm + openmc.deplete.pool.USE_MULTIPROCESSING = multiproc + openmc.deplete.PredictorIntegrator(op, + dt, + power=power, + source_rates=source_rate, + timestep_units='s').integrate() + + # Get path to test and reference results + path_test = op.output_dir / 'depletion_results.h5' + if power is None: + ref_path = 'test_reference_source_rate.h5' + else: + ref_path = 'test_reference_fission_q.h5' + path_reference = Path(__file__).with_name(ref_path) + + # If updating results, do so and return + if config['update']: + shutil.copyfile(str(path_test), str(path_reference)) + return + + # Load the reference/test results + res_test = openmc.deplete.Results(path_test) + res_ref = openmc.deplete.Results(path_reference) + + # Assert same mats + _assert_same_mats(res_test, res_ref) + + tol = 1.0e-14 + assert_atoms_equal(res_ref, res_test, tol) + assert_reaction_rates_equal(res_ref, res_test, tol) + + +@pytest.mark.parametrize("multiproc, dt, time_units, time_type, atom_tol, rx_tol ", [ + (True, 360, 's', 'minutes', 2.0e-3, 3.0e-2), + (False, 360, 's', 'minutes', 2.0e-3, 3.0e-2), + (True, 4, 'h', 'hours', 2.0e-3, 6.0e-2), + (False, 4, 'h', 'hours', 2.0e-3, 6.0e-2), + (True, 5, 'd', 'days', 2.0e-3, 5.0e-2), + (False, 5, 'd', 'days', 2.0e-3, 5.0e-2), + (True, 100, 'd', 'months', 4.0e-3, 9.0e-2), + (False, 100, 'd', 'months', 4.0e-3, 9.0e-2)]) +def test_against_coupled(run_in_tmpdir, + fuel, + micro_xs, + chain_file, + multiproc, + dt, + time_units, + time_type, + atom_tol, + rx_tol): + # Create operator + flux = neutron_per_cm2_sec * fuel.volume + op = _create_operator(False, fuel, flux, micro_xs, chain_file, 'fission-q') + + # Power and timesteps + dt = [dt] # single step + + # Perform simulation using the predictor algorithm + openmc.deplete.pool.USE_MULTIPROCESSING = multiproc + openmc.deplete.PredictorIntegrator( + op, dt, power=174, timestep_units=time_units).integrate() + + # Get path to test and reference results + path_test = op.output_dir / 'depletion_results.h5' + + ref_path = f'test_reference_coupled_{time_type}.h5' + path_reference = Path(__file__).with_name(ref_path) + + # If updating results, do so and return + if config['update']: + shutil.copyfile(str(path_test), str(path_reference)) + return + + # Load the reference/test results + res_test = openmc.deplete.Results(path_test) + res_ref = openmc.deplete.Results(path_reference) + + # Assert same mats + _assert_same_mats(res_test, res_ref) + + assert_atoms_equal(res_ref, res_test, atom_tol) + assert_reaction_rates_equal(res_ref, res_test, rx_tol) + + +def _create_operator(from_nuclides, + fuel, + flux, + micro_xs, + chain_file, + normalization_mode): + if from_nuclides: + nuclides = {} + for nuc, dens in fuel.get_nuclide_atom_densities().items(): + nuclides[nuc] = dens + + op = IndependentOperator.from_nuclides(fuel.volume, + nuclides, + flux, + micro_xs, + chain_file, + normalization_mode=normalization_mode) + + else: + op = IndependentOperator(openmc.Materials([fuel]), + [flux], + [micro_xs], + chain_file, + normalization_mode=normalization_mode) + + return op + + +def _assert_same_mats(res_ref, res_test): + for mat in res_ref[0].index_mat: + assert mat in res_test[0].index_mat, \ + f"Material {mat} not in new results." + for nuc in res_ref[0].index_nuc: + assert nuc in res_test[0].index_nuc, \ + f"Nuclide {nuc} not in new results." + + for mat in res_test[0].index_mat: + assert mat in res_ref[0].index_mat, \ + f"Material {mat} not in old results." + for nuc in res_test[0].index_nuc: + assert nuc in res_ref[0].index_nuc, \ + f"Nuclide {nuc} not in old results." + diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_days.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_days.h5 new file mode 100644 index 00000000000..5fdc656d970 Binary files /dev/null and b/tests/regression_tests/deplete_no_transport/test_reference_coupled_days.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_hours.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_hours.h5 new file mode 100644 index 00000000000..65bfc19a91c Binary files /dev/null and b/tests/regression_tests/deplete_no_transport/test_reference_coupled_hours.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_minutes.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_minutes.h5 new file mode 100644 index 00000000000..294cb589f7b Binary files /dev/null and b/tests/regression_tests/deplete_no_transport/test_reference_coupled_minutes.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_months.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_months.h5 new file mode 100644 index 00000000000..ed62e461049 Binary files /dev/null and b/tests/regression_tests/deplete_no_transport/test_reference_coupled_months.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_fission_q.h5 b/tests/regression_tests/deplete_no_transport/test_reference_fission_q.h5 new file mode 100644 index 00000000000..9d32d89fe23 Binary files /dev/null and b/tests/regression_tests/deplete_no_transport/test_reference_fission_q.h5 differ diff --git a/tests/regression_tests/deplete_no_transport/test_reference_source_rate.h5 b/tests/regression_tests/deplete_no_transport/test_reference_source_rate.h5 new file mode 100644 index 00000000000..3f3b4aa2ac5 Binary files /dev/null and b/tests/regression_tests/deplete_no_transport/test_reference_source_rate.h5 differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/__init__.py b/tests/regression_tests/deplete_with_transfer_rates/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_feed.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_feed.h5 new file mode 100644 index 00000000000..b9be7634513 Binary files /dev/null and b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_feed.h5 differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal.h5 new file mode 100644 index 00000000000..4b24bed52ad Binary files /dev/null and b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal.h5 differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 new file mode 100644 index 00000000000..51173f778b9 Binary files /dev/null and b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_feed.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_feed.h5 new file mode 100644 index 00000000000..d53adc7d841 Binary files /dev/null and b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_feed.h5 differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_removal.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_removal.h5 new file mode 100644 index 00000000000..921755e1559 Binary files /dev/null and b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_removal.h5 differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 new file mode 100644 index 00000000000..469149f6742 Binary files /dev/null and b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 differ diff --git a/tests/regression_tests/deplete_with_transfer_rates/test.py b/tests/regression_tests/deplete_with_transfer_rates/test.py new file mode 100644 index 00000000000..669fd4bea01 --- /dev/null +++ b/tests/regression_tests/deplete_with_transfer_rates/test.py @@ -0,0 +1,87 @@ +""" TransferRates depletion test suite """ + +from pathlib import Path +import shutil +import sys + +import numpy as np +import pytest +import openmc +import openmc.deplete +from openmc.deplete import CoupledOperator + +from tests.regression_tests import config, assert_reaction_rates_equal, \ + assert_atoms_equal + + +@pytest.fixture +def model(): + f = openmc.Material(name="f") + f.add_element("U", 1, percent_type="ao", enrichment=4.25) + f.add_element("O", 2) + f.set_density("g/cc", 10.4) + + w = openmc.Material(name="w") + w.add_element("O", 1) + w.add_element("H", 2) + w.set_density("g/cc", 1.0) + w.depletable = True + + radii = [0.42, 0.45] + f.volume = np.pi * radii[0] ** 2 + w.volume = np.pi * (radii[1]**2 - radii[0]**2) + + materials = openmc.Materials([f, w]) + + surf_f = openmc.Sphere(r=radii[0]) + surf_w = openmc.Sphere(r=radii[1], boundary_type='reflective') + cell_f = openmc.Cell(fill=f, region=-surf_f) + cell_w = openmc.Cell(fill=w, region=+surf_f & -surf_w) + geometry = openmc.Geometry([cell_f, cell_w]) + + settings = openmc.Settings() + settings.particles = 100 + settings.inactive = 0 + settings.batches = 10 + + return openmc.Model(geometry, materials, settings) + +@pytest.mark.skipif(sys.version_info < (3, 9), reason="Requires Python 3.9+") +@pytest.mark.parametrize("rate, dest_mat, power, ref_result", [ + (1e-5, None, 0.0, 'no_depletion_only_removal'), + (-1e-5, None, 0.0, 'no_depletion_only_feed'), + (1e-5, None, 174.0, 'depletion_with_removal'), + (-1e-5, None, 174.0, 'depletion_with_feed'), + (-1e-5, 'w', 0.0, 'no_depletion_with_transfer'), + (1e-5, 'w', 174.0, 'depletion_with_transfer'), + ]) +def test_transfer_rates(run_in_tmpdir, model, rate, dest_mat, power, ref_result): + """Tests transfer_rates depletion class with transfer rates""" + + chain_file = Path(__file__).parents[2] / 'chain_simple.xml' + + transfer_elements = ['Xe'] + + op = CoupledOperator(model, chain_file) + op.round_number = True + integrator = openmc.deplete.PredictorIntegrator( + op, [1], power, timestep_units = 'd') + integrator.add_transfer_rate('f', transfer_elements, rate, + destination_material=dest_mat) + integrator.integrate() + + # Get path to test and reference results + path_test = op.output_dir / 'depletion_results.h5' + path_reference = Path(__file__).with_name(f'ref_{ref_result}.h5') + + # If updating results, do so and return + if config['update']: + shutil.copyfile(str(path_test), str(path_reference)) + return + + # Load the reference/test results + res_ref = openmc.deplete.Results(path_reference) + res_test = openmc.deplete.Results(path_test) + + assert_atoms_equal(res_ref, res_test, 1e-6) + assert_reaction_rates_equal(res_ref, res_test) diff --git a/tests/regression_tests/deplete_with_transport/__init__.py b/tests/regression_tests/deplete_with_transport/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/deplete/example_geometry.py b/tests/regression_tests/deplete_with_transport/example_geometry.py similarity index 100% rename from tests/regression_tests/deplete/example_geometry.py rename to tests/regression_tests/deplete_with_transport/example_geometry.py diff --git a/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml b/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml new file mode 100644 index 00000000000..f61595dd9fb --- /dev/null +++ b/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml @@ -0,0 +1,1049 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/regression_tests/deplete/test.py b/tests/regression_tests/deplete_with_transport/test.py similarity index 71% rename from tests/regression_tests/deplete/test.py rename to tests/regression_tests/deplete_with_transport/test.py index fcc2099cf9b..0f7ebf00f31 100644 --- a/tests/regression_tests/deplete/test.py +++ b/tests/regression_tests/deplete_with_transport/test.py @@ -3,6 +3,7 @@ from math import floor import shutil from pathlib import Path +from collections import defaultdict from difflib import unified_diff import numpy as np @@ -11,8 +12,8 @@ from openmc.data import JOULE_PER_EV import openmc.deplete -from tests.regression_tests import config -from example_geometry import generate_problem +from tests.regression_tests import config, assert_atoms_equal +from .example_geometry import generate_problem @pytest.fixture(scope="module") @@ -45,13 +46,15 @@ def test_full(run_in_tmpdir, problem, multiproc): settings.batches = 10 settings.inactive = 0 space = openmc.stats.Box(lower_left, upper_right) - settings.source = openmc.Source(space=space) + settings.source = openmc.IndependentSource(space=space) settings.seed = 1 settings.verbosity = 1 + model = openmc.Model(geometry=geometry, settings=settings) + # Create operator chain_file = Path(__file__).parents[2] / 'chain_simple.xml' - op = openmc.deplete.Operator(geometry, settings, chain_file) + op = openmc.deplete.CoupledOperator(model, chain_file) op.round_number = True # Power and timesteps @@ -75,54 +78,41 @@ def test_full(run_in_tmpdir, problem, multiproc): return # Load the reference/test results - res_test = openmc.deplete.ResultsList.from_hdf5(path_test) - res_ref = openmc.deplete.ResultsList.from_hdf5(path_reference) + res_test = openmc.deplete.Results(path_test) + res_ref = openmc.deplete.Results(path_reference) # Assert same mats - for mat in res_ref[0].mat_to_ind: - assert mat in res_test[0].mat_to_ind, \ + for mat in res_ref[0].index_mat: + assert mat in res_test[0].index_mat, \ "Material {} not in new results.".format(mat) - for nuc in res_ref[0].nuc_to_ind: - assert nuc in res_test[0].nuc_to_ind, \ + for nuc in res_ref[0].index_nuc: + assert nuc in res_test[0].index_nuc, \ "Nuclide {} not in new results.".format(nuc) - for mat in res_test[0].mat_to_ind: - assert mat in res_ref[0].mat_to_ind, \ + for mat in res_test[0].index_mat: + assert mat in res_ref[0].index_mat, \ "Material {} not in old results.".format(mat) - for nuc in res_test[0].nuc_to_ind: - assert nuc in res_ref[0].nuc_to_ind, \ + for nuc in res_test[0].index_nuc: + assert nuc in res_ref[0].index_nuc, \ "Nuclide {} not in old results.".format(nuc) - tol = 1.0e-6 - for mat in res_test[0].mat_to_ind: - for nuc in res_test[0].nuc_to_ind: - _, y_test = res_test.get_atoms(mat, nuc) - _, y_old = res_ref.get_atoms(mat, nuc) - - # Test each point - correct = True - for i, ref in enumerate(y_old): - if ref != y_test[i]: - if ref != 0.0: - correct = np.abs(y_test[i] - ref) / ref <= tol - else: - correct = False - - assert correct, "Discrepancy in mat {} and nuc {}\n{}\n{}".format( - mat, nuc, y_old, y_test) + assert_atoms_equal(res_ref, res_test, tol=1e-6) # Compare statepoint files with depletion results - t_test, k_test = res_test.get_eigenvalue() - t_ref, k_ref = res_ref.get_eigenvalue() + t_test, k_test = res_test.get_keff() + t_ref, k_ref = res_ref.get_keff() k_state = np.empty_like(k_ref) n_tallies = np.empty(N + 1, dtype=int) # Get statepoint files for all BOS points and EOL + runtimes = defaultdict(list) for n in range(N + 1): - statepoint = openmc.StatePoint("openmc_simulation_n{}.h5".format(n)) - k_n = statepoint.k_combined + statepoint = openmc.StatePoint(f"openmc_simulation_n{n}.h5") + for measure, time in statepoint.runtime.items(): + runtimes[measure].append(time) + k_n = statepoint.keff k_state[n] = [k_n.nominal_value, k_n.std_dev] n_tallies[n] = len(statepoint.tallies) # Look for exact match pulling from statepoint and depletion_results @@ -132,12 +122,27 @@ def test_full(run_in_tmpdir, problem, multiproc): # Check that no additional tallies are loaded from the files assert np.all(n_tallies == 0) + # Convert values in runtimes to arrays + runtimes = {k: np.array(v) for k, v in runtimes.items()} + + # Check that runtimes are qualitatively correct + assert runtimes['reading cross sections'][0] != 0 + assert runtimes['total initialization'][0] != 0 + assert np.all(runtimes['reading cross sections'][1:] == 0) + assert np.all(runtimes['total initialization'][1:] == 0) + assert np.all(runtimes['inactive batches'] == 0) + del runtimes['reading cross sections'] + del runtimes['total initialization'] + del runtimes['inactive batches'] + for measure, times in runtimes.items(): + assert np.all(times != 0) + def test_depletion_results_to_material(run_in_tmpdir, problem): """Checks openmc.Materials objects can be created from depletion results""" # Load the reference/test results path_reference = Path(__file__).with_name('test_reference.h5') - res_ref = openmc.deplete.ResultsList.from_hdf5(path_reference) + res_ref = openmc.deplete.Results(path_reference) # Firstly need to export materials.xml file for the initial simulation state geometry, lower_left, upper_right = problem @@ -170,7 +175,7 @@ def test_depletion_results_to_material(run_in_tmpdir, problem): diff_vs_expected = unified_diff(reference_lines, result_file_lines) # Check all lines match, printing errors along the way - success = True + success = True for line in diff_vs_expected: success = False print(line.rstrip()) diff --git a/tests/regression_tests/deplete_with_transport/test_reference.h5 b/tests/regression_tests/deplete_with_transport/test_reference.h5 new file mode 100644 index 00000000000..e8478250be6 Binary files /dev/null and b/tests/regression_tests/deplete_with_transport/test_reference.h5 differ diff --git a/tests/regression_tests/diff_tally/inputs_true.dat b/tests/regression_tests/diff_tally/inputs_true.dat index 909475f9624..3ec4154e82e 100644 --- a/tests/regression_tests/diff_tally/inputs_true.dat +++ b/tests/regression_tests/diff_tally/inputs_true.dat @@ -1,38 +1,187 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -50,12 +199,12 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -73,12 +222,12 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 @@ -100,12 +249,12 @@ 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 @@ -127,313 +276,163 @@ 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 3 - 0 - - - -160 -160 -183 160 160 183 - - - true - - - - - 1 3 - - - 0.0 0.625 20000000.0 - - - 1 - flux - 1 - - - 1 - flux - 2 - - - 1 - flux - 3 - - - 1 - flux - 4 - - - 1 - flux - 5 - - - 1 - total U235 - total absorption scatter fission nu-fission - 1 - - - 1 - total U235 - total absorption scatter fission nu-fission - 2 - - - 1 - total U235 - total absorption scatter fission nu-fission - 3 - - - 1 - total U235 - total absorption scatter fission nu-fission - 4 - - - 1 - total U235 - total absorption scatter fission nu-fission - 5 - - - 1 - absorption - analog - 1 - - - 1 - absorption - analog - 2 - - - 1 - absorption - analog - 3 - - - 1 - absorption - analog - 4 - - - 1 - absorption - analog - 5 - - - 1 2 - total U235 - nu-fission scatter - 1 - - - 1 2 - total U235 - nu-fission scatter - 2 - - - 1 2 - U235 - nu-fission scatter - 3 - - - 1 2 - U235 - nu-fission scatter - 4 - - - 1 2 - U235 - nu-fission scatter - 5 - - - - - - - + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 3 + 0 + + + -160 -160 -183 160 160 183 + + + true + + + + 1 3 + + + 0.0 0.625 20000000.0 + + + 1 + flux + 1 + + + 1 + flux + 2 + + + 1 + flux + 3 + + + 1 + flux + 4 + + + 1 + flux + 5 + + + 1 + total U235 + total absorption scatter fission nu-fission + 1 + + + 1 + total U235 + total absorption scatter fission nu-fission + 2 + + + 1 + total U235 + total absorption scatter fission nu-fission + 3 + + + 1 + total U235 + total absorption scatter fission nu-fission + 4 + + + 1 + total U235 + total absorption scatter fission nu-fission + 5 + + + 1 + absorption + analog + 1 + + + 1 + absorption + analog + 2 + + + 1 + absorption + analog + 3 + + + 1 + absorption + analog + 4 + + + 1 + absorption + analog + 5 + + + 1 2 + total U235 + nu-fission scatter + 1 + + + 1 2 + total U235 + nu-fission scatter + 2 + + + 1 2 + U235 + nu-fission scatter + 3 + + + 1 2 + U235 + nu-fission scatter + 4 + + + 1 2 + U235 + nu-fission scatter + 5 + + + + + + + + diff --git a/tests/regression_tests/diff_tally/results_true.dat b/tests/regression_tests/diff_tally/results_true.dat index 12157932fbf..14729c8214c 100644 --- a/tests/regression_tests/diff_tally/results_true.dat +++ b/tests/regression_tests/diff_tally/results_true.dat @@ -1,27 +1,27 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. -3,,density,flux,-8.9862333e+00,2.7508460e+00 -3,,density,flux,-1.9778752e+01,3.5926341e+00 -1,,density,flux,-2.6861000e-01,3.8449483e-02 -1,,density,flux,-3.7643515e-01,1.8991066e-01 -1,O16,nuclide_density,flux,-2.5795663e+00,1.6620453e+01 -1,O16,nuclide_density,flux,7.2861106e+00,1.5941849e+01 -1,U235,nuclide_density,flux,-2.2849358e+03,3.9506163e+02 -1,U235,nuclide_density,flux,-2.7845978e+03,5.6693457e+02 -1,,temperature,flux,-1.8666344e-04,1.1088646e-04 -1,,temperature,flux,9.2264971e-05,8.7268407e-05 -3,,density,total,-4.1447663e+00,1.1453915e+00 -3,,density,absorption,-6.0174688e-01,1.0525787e-01 -3,,density,scatter,-3.5430194e+00,1.0499557e+00 -3,,density,fission,-2.8547461e-01,6.7402688e-02 -3,,density,nu-fission,-6.9988357e-01,1.6360007e-01 -3,,density,total,-3.7715161e-01,1.0166405e-01 -3,,density,absorption,-3.3327322e-01,8.9912373e-02 -3,,density,scatter,-4.3878393e-02,1.3801869e-02 -3,,density,fission,-2.7256167e-01,7.1483193e-02 -3,,density,nu-fission,-6.6439453e-01,1.7417261e-01 -3,,density,total,-2.3838461e+00,4.2331432e+00 -3,,density,absorption,-5.7877951e-02,5.3522562e-02 -3,,density,scatter,-2.3259682e+00,4.1799423e+00 +3,,density,flux,-8.7368155e+00,1.5577812e+00 +3,,density,flux,-1.4842625e+01,2.2947682e+00 +1,,density,flux,-2.0922686e-01,4.9935069e-02 +1,,density,flux,-3.4582490e-01,1.7454386e-01 +1,O16,nuclide_density,flux,1.1301782e+01,2.2440389e+01 +1,O16,nuclide_density,flux,3.2481563e+00,3.2342885e+01 +1,U235,nuclide_density,flux,-1.5048665e+03,5.9045681e+02 +1,U235,nuclide_density,flux,-1.6193231e+03,9.7230073e+02 +1,,temperature,flux,-1.0891931e-04,2.3076849e-04 +1,,temperature,flux,-1.3563853e-04,2.0952841e-04 +3,,density,total,-3.9155374e+00,5.4862771e-01 +3,,density,absorption,-4.9210534e-01,3.4700776e-02 +3,,density,scatter,-3.4234320e+00,5.1443821e-01 +3,,density,fission,-3.1088949e-01,8.0540906e-02 +3,,density,nu-fission,-7.6137447e-01,1.9548876e-01 +3,,density,total,-3.8615156e-01,1.0175701e-01 +3,,density,absorption,-3.4458071e-01,9.3381192e-02 +3,,density,scatter,-4.1570854e-02,8.6942039e-03 +3,,density,fission,-2.9864832e-01,8.4711885e-02 +3,,density,nu-fission,-7.2797006e-01,2.0640455e-01 +3,,density,total,1.0491251e+01,9.1787723e+00 +3,,density,absorption,2.9819000e-01,3.0887165e-01 +3,,density,scatter,1.0193061e+01,8.8715930e+00 3,,density,fission,0.0000000e+00,0.0000000e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,total,0.0000000e+00,0.0000000e+00 @@ -29,19 +29,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 3,,density,scatter,0.0000000e+00,0.0000000e+00 3,,density,fission,0.0000000e+00,0.0000000e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,total,4.0520294e-01,3.3719992e-02 -1,,density,absorption,1.3915754e-02,1.3515385e-02 -1,,density,scatter,3.9128718e-01,2.2403876e-02 -1,,density,fission,2.4781454e-04,1.0189025e-02 -1,,density,nu-fission,1.2555927e-03,2.4804599e-02 -1,,density,total,5.1306892e-03,1.1784483e-02 -1,,density,absorption,6.1064429e-04,1.1572255e-02 -1,,density,scatter,4.5200449e-03,3.2228853e-04 -1,,density,fission,-1.5830325e-03,1.0334068e-02 -1,,density,nu-fission,-3.8226434e-03,2.5181192e-02 -1,,density,total,-6.6601129e-01,2.0465955e-01 -1,,density,absorption,-1.5334818e-02,4.0664980e-03 -1,,density,scatter,-6.5067647e-01,2.0153765e-01 +1,,density,total,4.7128871e-01,5.7197095e-02 +1,,density,absorption,2.1981833e-02,1.7427232e-02 +1,,density,scatter,4.4930687e-01,4.0030120e-02 +1,,density,fission,6.0712328e-03,1.3719512e-02 +1,,density,nu-fission,1.5474650e-02,3.3437103e-02 +1,,density,total,1.2203418e-02,1.5798741e-02 +1,,density,absorption,7.0228085e-03,1.5294984e-02 +1,,density,scatter,5.1806097e-03,5.0807003e-04 +1,,density,fission,4.1074923e-03,1.3759608e-02 +1,,density,nu-fission,1.0046778e-02,3.3529881e-02 +1,,density,total,-5.2100220e-01,2.7618985e-01 +1,,density,absorption,-1.1039048e-02,6.2043549e-03 +1,,density,scatter,-5.0996315e-01,2.7027892e-01 1,,density,fission,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 1,,density,total,0.0000000e+00,0.0000000e+00 @@ -49,19 +49,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,,density,scatter,0.0000000e+00,0.0000000e+00 1,,density,fission,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,O16,nuclide_density,total,4.3895711e+01,8.6765744e+00 -1,O16,nuclide_density,absorption,-7.3377277e-01,1.1652783e+00 -1,O16,nuclide_density,scatter,4.4629484e+01,7.5113743e+00 -1,O16,nuclide_density,fission,-1.0525946e+00,6.2358336e-01 -1,O16,nuclide_density,nu-fission,-2.5950001e+00,1.5266115e+00 -1,O16,nuclide_density,total,-1.0686783e+00,8.1661764e-01 -1,O16,nuclide_density,absorption,-1.0549848e+00,7.2501792e-01 -1,O16,nuclide_density,scatter,-1.3693500e-02,9.5152724e-02 -1,O16,nuclide_density,fission,-9.8026040e-01,6.2874064e-01 -1,O16,nuclide_density,nu-fission,-2.3899304e+00,1.5323042e+00 -1,O16,nuclide_density,total,4.3744802e+00,1.8346830e+01 -1,O16,nuclide_density,absorption,-7.6879459e-03,1.9447931e-01 -1,O16,nuclide_density,scatter,4.3821681e+00,1.8168908e+01 +1,O16,nuclide_density,total,5.5744608e+01,1.3811361e+01 +1,O16,nuclide_density,absorption,2.1284059e+00,3.3353171e+00 +1,O16,nuclide_density,scatter,5.3616202e+01,1.0494347e+01 +1,O16,nuclide_density,fission,6.6058671e-01,1.9263932e+00 +1,O16,nuclide_density,nu-fission,1.5973305e+00,4.6977280e+00 +1,O16,nuclide_density,total,9.8433784e-01,2.4053581e+00 +1,O16,nuclide_density,absorption,9.1167507e-01,2.2565683e+00 +1,O16,nuclide_density,scatter,7.2662768e-02,1.5198625e-01 +1,O16,nuclide_density,fission,6.8845700e-01,1.9451444e+00 +1,O16,nuclide_density,nu-fission,1.6768628e+00,4.7395897e+00 +1,O16,nuclide_density,total,8.1604245e+00,3.7248338e+01 +1,O16,nuclide_density,absorption,2.4903834e-01,4.5609671e-01 +1,O16,nuclide_density,scatter,7.9113862e+00,3.6811434e+01 1,O16,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,total,0.0000000e+00,0.0000000e+00 @@ -69,19 +69,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,U235,nuclide_density,total,-6.4251150e+02,2.3106826e+02 -1,U235,nuclide_density,absorption,1.5311660e+02,8.7788828e+01 -1,U235,nuclide_density,scatter,-7.9562811e+02,1.5432248e+02 -1,U235,nuclide_density,fission,2.3667219e+02,6.4506235e+01 -1,U235,nuclide_density,nu-fission,5.7770896e+02,1.5738708e+02 -1,U235,nuclide_density,total,4.1238071e+02,7.5208565e+01 -1,U235,nuclide_density,absorption,3.0507276e+02,7.3015316e+01 -1,U235,nuclide_density,scatter,1.0730795e+02,3.4182980e+00 -1,U235,nuclide_density,fission,2.3734641e+02,6.4221163e+01 -1,U235,nuclide_density,nu-fission,5.7953503e+02,1.5657365e+02 -1,U235,nuclide_density,total,-5.5174298e+03,1.1185254e+03 -1,U235,nuclide_density,absorption,-1.3416339e+02,3.2272881e+01 -1,U235,nuclide_density,scatter,-5.3832664e+03,1.0864829e+03 +1,U235,nuclide_density,total,-2.8654443e+02,3.3721470e+02 +1,U235,nuclide_density,absorption,2.0329180e+02,1.0522263e+02 +1,U235,nuclide_density,scatter,-4.8983623e+02,2.3237977e+02 +1,U235,nuclide_density,fission,2.6089045e+02,7.2578344e+01 +1,U235,nuclide_density,nu-fission,6.3692044e+02,1.7710877e+02 +1,U235,nuclide_density,total,4.5611633e+02,9.1682367e+01 +1,U235,nuclide_density,absorption,3.3831545e+02,8.5035501e+01 +1,U235,nuclide_density,scatter,1.1780088e+02,7.4128809e+00 +1,U235,nuclide_density,fission,2.6094461e+02,7.2102445e+01 +1,U235,nuclide_density,nu-fission,6.3705705e+02,1.7578950e+02 +1,U235,nuclide_density,total,-4.1342174e+03,1.4666097e+03 +1,U235,nuclide_density,absorption,-1.1329170e+02,3.5066579e+01 +1,U235,nuclide_density,scatter,-4.0209257e+03,1.4320401e+03 1,U235,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,total,0.0000000e+00,0.0000000e+00 @@ -89,19 +89,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,temperature,total,3.0892324e-05,5.5277596e-05 -1,,temperature,absorption,2.2324596e-05,2.6209954e-05 -1,,temperature,scatter,8.5677277e-06,6.2111314e-05 -1,,temperature,fission,-1.7715856e-05,1.2803586e-05 -1,,temperature,nu-fission,-4.3163971e-05,3.1203107e-05 -1,,temperature,total,-2.3895766e-05,1.6226810e-05 -1,,temperature,absorption,-2.2388970e-05,1.6503185e-05 -1,,temperature,scatter,-1.5067967e-06,8.6753589e-07 -1,,temperature,fission,-1.7806576e-05,1.2760443e-05 -1,,temperature,nu-fission,-4.3390060e-05,3.1095620e-05 -1,,temperature,total,1.3388075e-04,1.1361483e-04 -1,,temperature,absorption,1.3825063e-06,1.3898795e-06 -1,,temperature,scatter,1.3249824e-04,1.1224449e-04 +1,,temperature,total,5.3733744e-05,1.1785516e-04 +1,,temperature,absorption,-1.3987780e-05,1.9819801e-05 +1,,temperature,scatter,6.7721524e-05,9.9934995e-05 +1,,temperature,fission,-1.4882696e-05,1.6930666e-05 +1,,temperature,nu-fission,-3.6272065e-05,4.1250892e-05 +1,,temperature,total,-1.8119796e-05,2.2651409e-05 +1,,temperature,absorption,-1.7632076e-05,2.1825006e-05 +1,,temperature,scatter,-4.8771972e-07,1.4270133e-06 +1,,temperature,fission,-1.4890811e-05,1.6935899e-05 +1,,temperature,nu-fission,-3.6292215e-05,4.1263951e-05 +1,,temperature,total,-2.0776498e-04,2.9286552e-04 +1,,temperature,absorption,-3.9068381e-06,3.4912438e-06 +1,,temperature,scatter,-2.0385814e-04,2.8941307e-04 1,,temperature,fission,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 1,,temperature,total,0.0000000e+00,0.0000000e+00 @@ -109,68 +109,68 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,,temperature,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,fission,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,absorption,-4.3471777e-01,1.4851761e-01 -3,,density,absorption,4.8155520e-02,1.3781656e-01 -1,,density,absorption,9.4994508e-03,2.4533642e-03 -1,,density,absorption,-1.0306958e-02,3.9360517e-03 -1,O16,nuclide_density,absorption,-1.6745789e+00,6.7608522e-01 -1,O16,nuclide_density,absorption,1.2254539e+00,7.5421132e-01 -1,U235,nuclide_density,absorption,7.1093314e+01,1.0278274e+02 -1,U235,nuclide_density,absorption,-1.3158317e+02,1.0057325e+01 -1,,temperature,absorption,-2.8254564e-05,2.2125234e-05 -1,,temperature,absorption,1.3248119e-05,8.9856151e-06 +3,,density,absorption,-4.5579543e-01,5.5532252e-02 +3,,density,absorption,-1.3526251e-02,1.3917291e-01 +1,,density,absorption,3.8695654e-02,1.5823093e-02 +1,,density,absorption,-1.8171150e-02,1.2999773e-03 +1,O16,nuclide_density,absorption,2.0992238e+00,2.7230754e+00 +1,O16,nuclide_density,absorption,-6.8956953e-01,3.3064989e-01 +1,U235,nuclide_density,absorption,2.5000417e+02,7.3334295e+01 +1,U235,nuclide_density,absorption,-1.0832917e+02,1.1517513e+01 +1,,temperature,absorption,1.1819459e-05,4.2090670e-05 +1,,temperature,absorption,-7.2302974e-06,1.5200299e-05 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,-5.9591692e-01,1.8102644e-01 +3,,density,scatter,-7.6858714e-01,3.2467801e-01 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,-1.0186140e-04,6.5335918e-04 -3,,density,nu-fission,-7.7216010e-01,6.6235203e-02 -3,,density,scatter,-3.1141316e+00,8.7438594e-01 -3,,density,nu-fission,-7.4472975e-01,6.8932536e-02 -3,,density,scatter,-1.0613299e-02,1.4747505e-02 +3,,density,scatter,3.2513857e-04,3.2513857e-04 +3,,density,nu-fission,-6.4963717e-01,1.8008086e-01 +3,,density,scatter,-2.6911548e+00,2.6336008e-01 +3,,density,nu-fission,-6.3014524e-01,1.8056453e-01 +3,,density,scatter,-3.4247012e-02,2.2649385e-02 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,-2.3938461e+00,2.0442591e+00 +3,,density,scatter,1.0254549e+01,1.1054242e+01 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,scatter,0.0000000e+00,0.0000000e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,-3.8155549e-02,2.1549075e+00 +3,,density,scatter,2.5022850e-01,2.1207285e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,scatter,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,9.6114352e-03,3.0773624e-02 +1,,density,scatter,8.1153611e-03,3.1226564e-02 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-4.8445916e-04,4.1692636e-04 -1,,density,nu-fission,-2.0032982e-02,1.5628598e-02 -1,,density,scatter,3.8609205e-01,2.0651677e-02 -1,,density,nu-fission,-2.4325475e-02,1.6087936e-02 -1,,density,scatter,2.1127093e-03,1.1144847e-03 +1,,density,scatter,2.3728497e-04,9.7166041e-04 +1,,density,nu-fission,2.6248459e-02,3.9328080e-02 +1,,density,scatter,4.2447769e-01,1.2580873e-02 +1,,density,nu-fission,1.9600074e-02,3.8118776e-02 +1,,density,scatter,8.0978391e-03,2.6585488e-03 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-5.6312059e-01,1.2644279e-01 +1,,density,scatter,-3.8358302e-01,2.1525401e-01 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 1,,density,scatter,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-9.2583739e-02,1.3802271e-01 +1,,density,scatter,-1.1924803e-01,9.1254221e-02 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 1,,density,scatter,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,O16,nuclide_density,scatter,2.8010197e-02,9.9675258e-02 -1,O16,nuclide_density,nu-fission,-2.7133439e+00,1.9638343e+00 -1,O16,nuclide_density,scatter,-5.8699167e-02,2.9596632e-01 +1,O16,nuclide_density,scatter,-1.6577061e-01,1.0793192e-01 +1,O16,nuclide_density,nu-fission,2.4995074e+00,5.7946039e+00 +1,O16,nuclide_density,scatter,5.5800956e-01,5.7675606e-01 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,U235,nuclide_density,scatter,1.0007013e+01,5.9794002e+00 -1,U235,nuclide_density,nu-fission,4.3209054e+02,1.5648214e+02 -1,U235,nuclide_density,scatter,4.6100250e+01,2.3766583e+01 +1,U235,nuclide_density,scatter,5.8641633e+00,2.9488422e+00 +1,U235,nuclide_density,nu-fission,6.7444160e+02,1.1308014e+02 +1,U235,nuclide_density,scatter,1.1592472e+02,2.8886339e+01 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 -1,,temperature,scatter,1.9350898e-06,2.0685006e-06 -1,,temperature,nu-fission,-6.5233572e-05,6.4075926e-05 -1,,temperature,scatter,-7.6629325e-07,7.6629325e-07 +1,,temperature,scatter,-7.7511866e-07,6.4761261e-07 +1,,temperature,nu-fission,-9.5466386e-05,3.1033330e-05 +1,,temperature,scatter,-2.7127084e-06,2.0699253e-07 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 1,,temperature,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 diff --git a/tests/regression_tests/diff_tally/test.py b/tests/regression_tests/diff_tally/test.py index b688e6d2330..89460df9152 100644 --- a/tests/regression_tests/diff_tally/test.py +++ b/tests/regression_tests/diff_tally/test.py @@ -16,7 +16,7 @@ def __init__(self, *args, **kwargs): self._model.settings.batches = 3 self._model.settings.inactive = 0 self._model.settings.particles = 100 - self._model.settings.source = openmc.Source(space=openmc.stats.Box( + self._model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-160, -160, -183], [160, 160, 183])) self._model.settings.temperature['multipole'] = True @@ -103,9 +103,8 @@ def _get_results(self): sp = openmc.StatePoint(statepoint) # Extract the tally data as a Pandas DataFrame. - df = pd.DataFrame() - for t in sp.tallies.values(): - df = df.append(t.get_pandas_dataframe(), ignore_index=True) + tally_dfs = [t.get_pandas_dataframe() for t in sp.tallies.values()] + df = pd.concat(tally_dfs, ignore_index=True) # Extract the relevant data as a CSV string. cols = ('d_material', 'd_nuclide', 'd_variable', 'score', 'mean', diff --git a/tests/regression_tests/distribmat/inputs_true.dat b/tests/regression_tests/distribmat/inputs_true.dat index a1c1e831165..ade86999d0a 100644 --- a/tests/regression_tests/distribmat/inputs_true.dat +++ b/tests/regression_tests/distribmat/inputs_true.dat @@ -1,62 +1,61 @@ - - - - - - - 2.0 2.0 - 1 - 2 2 - -2.0 -2.0 - + + + + + + + + + + + + + + + + + + + + + + + 2.0 2.0 + 1 + 2 2 + -2.0 -2.0 + 11 11 11 11 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - -1 -1 -1 1 1 1 - - - - - - - 0 0 0 - 7 7 - 400 400 - - - 0 0 0 - 7 7 - 400 400 - - + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + -1 -1 -1 1 1 1 + + + + + + 400 400 + 0 0 0 + 7 7 + + + 400 400 + 0 0 0 + 7 7 + + + diff --git a/tests/regression_tests/distribmat/results_true.dat b/tests/regression_tests/distribmat/results_true.dat index a33cbec0f61..af7b27fe728 100644 --- a/tests/regression_tests/distribmat/results_true.dat +++ b/tests/regression_tests/distribmat/results_true.dat @@ -1,10 +1,10 @@ k-combined: -1.234870E+00 1.724266E-02 +1.257344E+00 6.246360E-04 Cell ID = 11 Name = Fill = [2, None, 3, 2] - Region = -9 + Region = -1 Rotation = None Translation = None Volume = None diff --git a/tests/regression_tests/distribmat/test.py b/tests/regression_tests/distribmat/test.py index 33f64ba0319..02f7e773e58 100644 --- a/tests/regression_tests/distribmat/test.py +++ b/tests/regression_tests/distribmat/test.py @@ -4,7 +4,8 @@ class DistribmatTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) #################### # Materials #################### @@ -22,8 +23,8 @@ def _build_inputs(self): light_fuel.set_density('g/cc', 2.0) light_fuel.add_nuclide('U235', 1.0) - mats_file = openmc.Materials([moderator, dense_fuel, light_fuel]) - mats_file.export_to_xml() + self._model.materials = openmc.Materials([moderator, dense_fuel, + light_fuel]) #################### # Geometry @@ -54,8 +55,7 @@ def _build_inputs(self): c101.region = +x0 & -x1 & +y0 & -y1 root_univ = openmc.Universe(universe_id=0, cells=[c101]) - geometry = openmc.Geometry(root_univ) - geometry.export_to_xml() + self._model.geometry = openmc.Geometry(root_univ) #################### # Settings @@ -65,9 +65,9 @@ def _build_inputs(self): sets_file.batches = 5 sets_file.inactive = 0 sets_file.particles = 1000 - sets_file.source = openmc.Source(space=openmc.stats.Box( + sets_file.source = openmc.IndependentSource(space=openmc.stats.Box( [-1, -1, -1], [1, 1, 1])) - sets_file.export_to_xml() + self._model.settings = sets_file #################### # Plots @@ -89,8 +89,7 @@ def _build_inputs(self): plot2.width = (7, 7) plot2.pixels = (400, 400) - plots = openmc.Plots([plot1, plot2]) - plots.export_to_xml() + self._model.plots = openmc.Plots([plot1, plot2]) def _get_results(self): outstr = super()._get_results() @@ -100,5 +99,5 @@ def _get_results(self): def test_distribmat(): - harness = DistribmatTestHarness('statepoint.5.h5') + harness = DistribmatTestHarness('statepoint.5.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat b/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat index 7348663e8d5..a3e67d62f69 100644 --- a/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat +++ b/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat @@ -1,31 +1,30 @@ - - - - - - - - - - - - - - eigenvalue - 1000 - 7 - 3 - 3 - - - -4.0 -4.0 -4.0 4.0 4.0 4.0 - - - - - - - flux - - + + + + + + + + + + + + + eigenvalue + 1000 + 7 + 3 + 3 + + + -4.0 -4.0 -4.0 4.0 4.0 4.0 + + + + + + flux + + + diff --git a/tests/regression_tests/eigenvalue_genperbatch/results_true.dat b/tests/regression_tests/eigenvalue_genperbatch/results_true.dat index 91d1c393a07..3f7ea801a1c 100644 --- a/tests/regression_tests/eigenvalue_genperbatch/results_true.dat +++ b/tests/regression_tests/eigenvalue_genperbatch/results_true.dat @@ -1,5 +1,5 @@ k-combined: -3.029569E-01 9.632511E-05 +3.037481E-01 1.247474E-04 tally 1: -3.226370E+01 -2.602467E+02 +3.211129E+01 +2.578396E+02 diff --git a/tests/regression_tests/eigenvalue_genperbatch/test.py b/tests/regression_tests/eigenvalue_genperbatch/test.py index 7e21c8d3674..17c6dff7f97 100644 --- a/tests/regression_tests/eigenvalue_genperbatch/test.py +++ b/tests/regression_tests/eigenvalue_genperbatch/test.py @@ -22,7 +22,7 @@ def model(): model.settings.batches = 7 model.settings.generations_per_batch = 3 space = openmc.stats.Box((-4.0, -4.0, -4.0), (4.0, 4.0, 4.)) - model.settings.source = openmc.Source(space=space) + model.settings.source = openmc.IndependentSource(space=space) t = openmc.Tally() t.scores = ['flux'] diff --git a/tests/regression_tests/eigenvalue_no_inactive/results_true.dat b/tests/regression_tests/eigenvalue_no_inactive/results_true.dat index 80d463a3c8a..2b102160812 100644 --- a/tests/regression_tests/eigenvalue_no_inactive/results_true.dat +++ b/tests/regression_tests/eigenvalue_no_inactive/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.066848E-01 7.260987E-03 +2.998284E-01 7.587782E-03 diff --git a/tests/regression_tests/energy_cutoff/inputs_true.dat b/tests/regression_tests/energy_cutoff/inputs_true.dat index bb02369dc58..af8f86b6762 100644 --- a/tests/regression_tests/energy_cutoff/inputs_true.dat +++ b/tests/regression_tests/energy_cutoff/inputs_true.dat @@ -1,42 +1,41 @@ - - - - - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - -1 -1 -1 1 1 1 - - - - - 4.0 - - - - - - 0.0 4.0 - - - 1 - flux - - + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + -1 -1 -1 1 1 1 + + + + + 4.0 + + + + + 0.0 4.0 + + + 1 + flux + + + diff --git a/tests/regression_tests/energy_cutoff/test.py b/tests/regression_tests/energy_cutoff/test.py index d76edd9a08e..9aca802fa35 100755 --- a/tests/regression_tests/energy_cutoff/test.py +++ b/tests/regression_tests/energy_cutoff/test.py @@ -4,7 +4,8 @@ class EnergyCutoffTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # Set energy cutoff energy_cutoff = 4.0 @@ -12,8 +13,7 @@ def _build_inputs(self): mat = openmc.Material(material_id=1, name='mat') mat.set_density('atom/b-cm', 0.069335) mat.add_nuclide('H1', 40.0) - materials_file = openmc.Materials([mat]) - materials_file.export_to_xml() + self._model.materials = openmc.Materials([mat]) # Cell is box with reflective boundary x1 = openmc.XPlane(surface_id=1, x0=-1) @@ -29,8 +29,7 @@ def _build_inputs(self): box.fill = mat root = openmc.Universe(universe_id=0, name='root universe') root.add_cell(box) - geometry = openmc.Geometry(root) - geometry.export_to_xml() + self._model.geometry = openmc.Geometry(root) # Set the running parameters settings_file = openmc.Settings() @@ -41,9 +40,9 @@ def _build_inputs(self): bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) watt_dist = openmc.stats.Watt() - settings_file.source = openmc.source.Source(space=uniform_dist, - energy=watt_dist) - settings_file.export_to_xml() + settings_file.source = openmc.IndependentSource(space=uniform_dist, + energy=watt_dist) + self._model.settings = settings_file # Tally flux under energy cutoff tallies = openmc.Tallies() @@ -52,7 +51,7 @@ def _build_inputs(self): energy_filter = openmc.filter.EnergyFilter((0.0, energy_cutoff)) tally.filters = [energy_filter] tallies.append(tally) - tallies.export_to_xml() + self._model.tallies = tallies def _get_results(self): """Digest info in the statepoint and return as a string.""" @@ -70,5 +69,5 @@ def _get_results(self): def test_energy_cutoff(): - harness = EnergyCutoffTestHarness('statepoint.10.h5') + harness = EnergyCutoffTestHarness('statepoint.10.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/energy_grid/results_true.dat b/tests/regression_tests/energy_grid/results_true.dat index b06742c1baa..deab1e28be5 100644 --- a/tests/regression_tests/energy_grid/results_true.dat +++ b/tests/regression_tests/energy_grid/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.317249E-01 1.079825E-02 +3.152586E-01 1.458068E-03 diff --git a/tests/regression_tests/energy_laws/inputs_true.dat b/tests/regression_tests/energy_laws/inputs_true.dat index 2320b21d5bf..4d8e825d1b5 100644 --- a/tests/regression_tests/energy_laws/inputs_true.dat +++ b/tests/regression_tests/energy_laws/inputs_true.dat @@ -1,23 +1,23 @@ - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + diff --git a/tests/regression_tests/entropy/results_true.dat b/tests/regression_tests/entropy/results_true.dat index 864905fa7c1..1c8b2908bc6 100644 --- a/tests/regression_tests/entropy/results_true.dat +++ b/tests/regression_tests/entropy/results_true.dat @@ -1,13 +1,13 @@ k-combined: -2.987050E-01 1.827430E-03 +3.070134E-01 3.900396E-03 entropy: 7.688862E+00 -8.184416E+00 -8.363034E+00 -8.174200E+00 -8.243373E+00 -8.298547E+00 -8.267346E+00 -8.253347E+00 -8.329508E+00 -8.363320E+00 +8.237960E+00 +8.314772E+00 +8.285254E+00 +8.271486E+00 +8.291355E+00 +8.253349E+00 +8.336726E+00 +8.284741E+00 +8.328102E+00 diff --git a/tests/regression_tests/entropy/test.py b/tests/regression_tests/entropy/test.py index 10a11e30089..af1fbd56a39 100644 --- a/tests/regression_tests/entropy/test.py +++ b/tests/regression_tests/entropy/test.py @@ -14,7 +14,7 @@ def _get_results(self): with StatePoint(statepoint) as sp: # Write out k-combined. outstr = 'k-combined:\n' - outstr += '{:12.6E} {:12.6E}\n'.format(sp.k_combined.n, sp.k_combined.s) + outstr += '{:12.6E} {:12.6E}\n'.format(sp.keff.n, sp.keff.s) # Write out entropy data. outstr += 'entropy:\n' diff --git a/tests/regression_tests/external_moab/__init__.py b/tests/regression_tests/external_moab/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/external_moab/inputs_true.dat b/tests/regression_tests/external_moab/inputs_true.dat new file mode 100644 index 00000000000..23b656bceeb --- /dev/null +++ b/tests/regression_tests/external_moab/inputs_true.dat @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + 0.0 0.0 0.0 + + + + 15000000.0 1.0 + + + + + + test_mesh_tets.h5m + + + 1 + + + 1 + flux + tracklength + + + diff --git a/tests/regression_tests/external_moab/main.cpp b/tests/regression_tests/external_moab/main.cpp new file mode 100644 index 00000000000..6e3709b6a10 --- /dev/null +++ b/tests/regression_tests/external_moab/main.cpp @@ -0,0 +1,98 @@ +#include "moab/Core.hpp" +#include "openmc/capi.h" +#include "openmc/error.h" +#include "openmc/mesh.h" +#include "openmc/tallies/filter_mesh.h" +#include "openmc/tallies/tally.h" +#include + +int main(int argc, char* argv[]) +{ + + using namespace openmc; + int openmc_err; + + // Initialise OpenMC + openmc_err = openmc_init(argc, argv, nullptr); + if (openmc_err == -1) { + // This happens for the -h and -v flags + return EXIT_SUCCESS; + } else if (openmc_err) { + fatal_error(openmc_err_msg); + } + + // Create MOAB interface + std::shared_ptr moabPtrLocal = + std::make_shared(); + + // Load unstructured mesh file + std::string filename = "test_mesh_tets.h5m"; + moab::ErrorCode rval = moabPtrLocal->load_file(filename.c_str()); + if (rval != moab::MB_SUCCESS) { + fatal_error("Failed to load the unstructured mesh file: " + filename); + } else { + std::cout << "Loaded external MOAB mesh from file " << filename + << std::endl; + } + + // Add a new unstructured mesh to openmc using new constructor + model::meshes.push_back(std::make_unique(moabPtrLocal)); + + // Check we now have 2 copies of the shared ptr + if (moabPtrLocal.use_count() != 2) { + fatal_error("Incorrect number of MOAB shared pointers"); + } + + // Auto-assign mesh ID + model::meshes.back()->set_id(C_NONE); + int mesh_id = model::meshes.back()->id_; + + // Check we now have 2 meshes and id was correctly set + if (model::meshes.size() != 2) + fatal_error("Wrong number of meshes."); + else if (mesh_id != 2) + fatal_error("Mesh ID is incorrect"); + + // Add a new mesh filter with auto-assigned ID + Filter* filter_ptr = Filter::create("mesh", C_NONE); + + // Upcast pointer type + MeshFilter* mesh_filter = dynamic_cast(filter_ptr); + + if (!mesh_filter) { + fatal_error("Failed to create mesh filter"); + } + + // Pass in the index of our mesh to the filter + int32_t mesh_idx = model::meshes.size() - 1; + mesh_filter->set_mesh(mesh_idx); + + // Create a tally with auto-assigned ID + model::tallies.push_back(make_unique(C_NONE)); + + // Set tally name - matches that in test.py + model::tallies.back()->name_ = "external mesh tally"; + + // Set tally filter to our mesh filter + std::vector filters(1, filter_ptr); + model::tallies.back()->set_filters(filters); + + // Set tally estimator + model::tallies.back()->estimator_ = TallyEstimator::TRACKLENGTH; + + // Set tally score + std::vector score_names(1, "flux"); + model::tallies.back()->set_scores(score_names); + + // Run OpenMC + openmc_err = openmc_run(); + if (openmc_err) + fatal_error(openmc_err_msg); + + // Deallocate memory + openmc_err = openmc_finalize(); + if (openmc_err) + fatal_error(openmc_err_msg); + + return EXIT_SUCCESS; +} diff --git a/tests/regression_tests/external_moab/test.py b/tests/regression_tests/external_moab/test.py new file mode 100644 index 00000000000..ce4e78a2c25 --- /dev/null +++ b/tests/regression_tests/external_moab/test.py @@ -0,0 +1,274 @@ +from pathlib import Path +import os +import shutil +import subprocess +from subprocess import CalledProcessError +import textwrap +import glob +from itertools import product + +import openmc +import openmc.lib +import numpy as np +import pytest + +from tests.regression_tests import config +from tests.testing_harness import PyAPITestHarness + +pytestmark = pytest.mark.skipif( + not openmc.lib._dagmc_enabled(), + reason="DAGMC is not enabled.") + +TETS_PER_VOXEL = 12 + +# Test that an external moab instance can be passed in through the C API + + +@pytest.fixture +def cpp_driver(request): + """Compile the external source""" + + # Get build directory and write CMakeLists.txt file + openmc_dir = Path(str(request.config.rootdir)) / 'build' + with open('CMakeLists.txt', 'w') as f: + f.write(textwrap.dedent(""" + cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + project(openmc_cpp_driver CXX) + add_executable(main main.cpp) + find_package(OpenMC REQUIRED HINTS {}) + target_link_libraries(main OpenMC::libopenmc) + target_compile_features(main PUBLIC cxx_std_14) + set(CMAKE_CXX_FLAGS "-pedantic-errors") + add_compile_definitions(DAGMC=1) + """.format(openmc_dir))) + + # Create temporary build directory and change to there + local_builddir = Path('build') + local_builddir.mkdir(exist_ok=True) + os.chdir(str(local_builddir)) + + if config['mpi']: + mpi_arg = "On" + else: + mpi_arg = "Off" + + try: + print("Building driver") + # Run cmake/make to build the shared libary + subprocess.run(['cmake', os.path.pardir, f'-DOPENMC_USE_MPI={mpi_arg}'], check=True) + subprocess.run(['make'], check=True) + os.chdir(os.path.pardir) + + yield "./build/main" + + finally: + # Remove local build directory when test is complete + shutil.rmtree('build') + os.remove('CMakeLists.txt') + + +class ExternalMoabTest(PyAPITestHarness): + def __init__(self, executable, statepoint_name, model): + super().__init__(statepoint_name, model) + self.executable = executable + + def _run_openmc(self): + if config['mpi']: + mpi_args = [config['mpiexec'], '-n', config['mpi_np']] + openmc.run(openmc_exec=self.executable, + mpi_args=mpi_args, + event_based=config['event']) + else: + openmc.run(openmc_exec=self.executable, + event_based=config['event']) + + # Override some methods to do nothing + def _get_results(self): + pass + + def _write_results(self, results_string): + pass + + def _overwrite_results(self): + pass + + def _test_output_created(self): + pass + + # Directly compare results of unstructured mesh with internal and + # external moab + def _compare_results(self): + + with openmc.StatePoint(self._sp_name) as sp: + # loop over the tallies and get data + + ext_data = [] + unstr_data = [] + + for tally in sp.tallies.values(): + + # Safety check that mesh filter is correct + if tally.contains_filter(openmc.MeshFilter): + flt = tally.find_filter(openmc.MeshFilter) + + if isinstance(flt.mesh, openmc.UnstructuredMesh): + + if tally.name == "external mesh tally": + ext_data = tally.get_reshaped_data(value='mean') + + elif tally.name == "unstructured mesh tally": + unstr_data = tally.get_reshaped_data(value='mean') + + # we expect these results to be the same to within at 8 + # decimal places + decimals = 8 + np.testing.assert_array_almost_equal(unstr_data, + ext_data, decimals) + + @staticmethod + def get_mesh_tally_data(tally): + data = tally.get_reshaped_data(value='mean') + std_dev = tally.get_reshaped_data(value='std_dev') + data.shape = (data.size, 1) + std_dev.shape = (std_dev.size, 1) + return np.sum(data, axis=1), np.sum(std_dev, axis=1) + + def _cleanup(self): + super()._cleanup() + output = glob.glob('tally*.vtk') + for f in output: + if os.path.exists(f): + os.remove(f) + + +def test_external_mesh(cpp_driver): + + # Materials + materials = openmc.Materials() + + fuel_mat = openmc.Material(name="fuel") + fuel_mat.add_nuclide("U235", 1.0) + fuel_mat.set_density('g/cc', 4.5) + materials.append(fuel_mat) + + zirc_mat = openmc.Material(name="zircaloy") + zirc_mat.add_element("Zr", 1.0) + zirc_mat.set_density("g/cc", 5.77) + materials.append(zirc_mat) + + water_mat = openmc.Material(name="water") + water_mat.add_nuclide("H1", 2.0) + water_mat.add_nuclide("O16", 1.0) + water_mat.set_density("atom/b-cm", 0.07416) + materials.append(water_mat) + + # Geometry + fuel_min_x = openmc.XPlane(-5.0, name="minimum x") + fuel_max_x = openmc.XPlane(5.0, name="maximum x") + + fuel_min_y = openmc.YPlane(-5.0, name="minimum y") + fuel_max_y = openmc.YPlane(5.0, name="maximum y") + + fuel_min_z = openmc.ZPlane(-5.0, name="minimum z") + fuel_max_z = openmc.ZPlane(5.0, name="maximum z") + + fuel_cell = openmc.Cell(name="fuel") + fuel_cell.region = +fuel_min_x & -fuel_max_x & \ + +fuel_min_y & -fuel_max_y & \ + +fuel_min_z & -fuel_max_z + fuel_cell.fill = fuel_mat + + clad_min_x = openmc.XPlane(-6.0, name="minimum x") + clad_max_x = openmc.XPlane(6.0, name="maximum x") + + clad_min_y = openmc.YPlane(-6.0, name="minimum y") + clad_max_y = openmc.YPlane(6.0, name="maximum y") + + clad_min_z = openmc.ZPlane(-6.0, name="minimum z") + clad_max_z = openmc.ZPlane(6.0, name="maximum z") + + clad_cell = openmc.Cell(name="clad") + clad_cell.region = (-fuel_min_x | +fuel_max_x | + -fuel_min_y | +fuel_max_y | + -fuel_min_z | +fuel_max_z) & \ + (+clad_min_x & -clad_max_x & + +clad_min_y & -clad_max_y & + +clad_min_z & -clad_max_z) + clad_cell.fill = zirc_mat + + bounds = (10, 10, 10) + + water_min_x = openmc.XPlane(x0=-bounds[0], + name="minimum x", + boundary_type='vacuum') + water_max_x = openmc.XPlane(x0=bounds[0], + name="maximum x", + boundary_type='vacuum') + + water_min_y = openmc.YPlane(y0=-bounds[1], + name="minimum y", + boundary_type='vacuum') + water_max_y = openmc.YPlane(y0=bounds[1], + name="maximum y", + boundary_type='vacuum') + + water_min_z = openmc.ZPlane(z0=-bounds[2], + name="minimum z", + boundary_type='vacuum') + water_max_z = openmc.ZPlane(z0=bounds[2], + name="maximum z", + boundary_type='vacuum') + + water_cell = openmc.Cell(name="water") + water_cell.region = (-clad_min_x | +clad_max_x | + -clad_min_y | +clad_max_y | + -clad_min_z | +clad_max_z) & \ + (+water_min_x & -water_max_x & + +water_min_y & -water_max_y & + +water_min_z & -water_max_z) + water_cell.fill = water_mat + + # create a containing universe + geometry = openmc.Geometry([fuel_cell, clad_cell, water_cell]) + + # Meshes + mesh_filename = "test_mesh_tets.h5m" + + # Create a normal unstructured mesh to compare to + uscd_mesh = openmc.UnstructuredMesh(mesh_filename, 'moab') + + # Create filters + uscd_filter = openmc.MeshFilter(mesh=uscd_mesh) + + # Tallies + tallies = openmc.Tallies() + uscd_tally = openmc.Tally(name="unstructured mesh tally") + uscd_tally.filters = [uscd_filter] + uscd_tally.scores = ['flux'] + uscd_tally.estimator = 'tracklength' + tallies.append(uscd_tally) + + # Settings + settings = openmc.Settings() + settings.run_mode = 'fixed source' + settings.particles = 100 + settings.batches = 10 + + # Source setup + space = openmc.stats.Point() + angle = openmc.stats.Monodirectional((-1.0, 0.0, 0.0)) + energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) + source = openmc.IndependentSource(space=space, energy=energy, angle=angle) + settings.source = source + + model = openmc.model.Model(geometry=geometry, + materials=materials, + tallies=tallies, + settings=settings) + + harness = ExternalMoabTest(cpp_driver, + 'statepoint.10.h5', + model) + + # Run open MC and check results + harness.main() diff --git a/tests/regression_tests/external_moab/test_mesh_tets.h5m b/tests/regression_tests/external_moab/test_mesh_tets.h5m new file mode 100644 index 00000000000..dc573142f6f Binary files /dev/null and b/tests/regression_tests/external_moab/test_mesh_tets.h5m differ diff --git a/tests/regression_tests/filter_cellinstance/inputs_true.dat b/tests/regression_tests/filter_cellinstance/inputs_true.dat index 5abf734333f..b17cc0eb59f 100644 --- a/tests/regression_tests/filter_cellinstance/inputs_true.dat +++ b/tests/regression_tests/filter_cellinstance/inputs_true.dat @@ -1,64 +1,64 @@ - - - - - - - - 2 2 - 4 4 - -4 -4 - -1 2 2 2 -2 1 2 2 -2 2 1 2 -2 2 2 1 - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - 0.0 0.0 0.0 - - - - - - - 3 0 3 1 3 2 3 3 3 4 3 5 3 6 3 7 3 8 3 9 3 10 3 11 2 0 2 1 2 2 2 3 - - - 2 3 2 2 2 1 2 0 3 11 3 10 3 9 3 8 3 7 3 6 3 5 3 4 3 3 3 2 3 1 3 0 - - - 1 - total - - - 2 - total - - + + + + + + + + + + + + + + + + + + + + 2 2 + 4 4 + -4 -4 + +2 3 3 3 +3 2 3 3 +3 3 2 3 +3 3 3 2 + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + 0.0 0.0 0.0 + + + + + + 4 0 4 1 4 2 4 3 4 4 4 5 4 6 4 7 4 8 4 9 4 10 4 11 2 0 2 1 2 2 2 3 3 0 3 1 3 2 3 3 + + + 3 3 3 2 3 1 3 0 2 3 2 2 2 1 2 0 4 11 4 10 4 9 4 8 4 7 4 6 4 5 4 4 4 3 4 2 4 1 4 0 + + + 1 + total + + + 2 + total + + + diff --git a/tests/regression_tests/filter_cellinstance/results_true.dat b/tests/regression_tests/filter_cellinstance/results_true.dat index 053ecf576e7..079b7d3d256 100644 --- a/tests/regression_tests/filter_cellinstance/results_true.dat +++ b/tests/regression_tests/filter_cellinstance/results_true.dat @@ -1,68 +1,84 @@ k-combined: -1.045340E+00 4.712608E-02 +1.050139E+00 1.886614E-02 tally 1: -7.410456E-02 -1.481523E-03 -1.225401E-01 -3.736978E-03 -1.383468E-01 -4.249085E-03 -1.197994E-01 -3.155257E-03 -2.966893E-01 -2.045198E-02 -1.570258E-01 -5.313506E-03 -1.655546E-01 -6.093224E-03 -2.749756E-01 -1.582780E-02 -1.184686E-01 -3.543719E-03 -1.354860E-01 -3.990719E-03 -1.299309E-01 -3.988554E-03 -6.794395E-02 -1.135006E-03 -1.061333E+01 -2.508486E+01 -2.767786E+01 -1.781264E+02 -2.898957E+01 -2.015188E+02 -9.951936E+00 -2.345815E+01 +9.724996E-02 +2.784804E-03 +1.146976E-01 +3.173782E-03 +1.698297E-01 +6.569993E-03 +1.158802E-01 +2.959280E-03 +2.533354E-01 +1.539905E-02 +1.908717E-01 +8.360058E-03 +1.738899E-01 +6.713494E-03 +3.172247E-01 +2.124184E-02 +1.363012E-01 +4.653519E-03 +1.698720E-01 +6.753819E-03 +9.934671E-02 +2.371660E-03 +6.038075E-02 +1.204656E-03 +1.038793E+01 +2.590382E+01 +2.841397E+01 +1.865709E+02 +2.786916E+01 +1.923869E+02 +1.085149E+01 +2.907194E+01 +1.038793E+01 +2.590382E+01 +2.841397E+01 +1.865709E+02 +2.786916E+01 +1.923869E+02 +1.085149E+01 +2.907194E+01 tally 2: -9.951936E+00 -2.345815E+01 -2.898957E+01 -2.015188E+02 -2.767786E+01 -1.781264E+02 -1.061333E+01 -2.508486E+01 -6.794395E-02 -1.135006E-03 -1.299309E-01 -3.988554E-03 -1.354860E-01 -3.990719E-03 -1.184686E-01 -3.543719E-03 -2.749756E-01 -1.582780E-02 -1.655546E-01 -6.093224E-03 -1.570258E-01 -5.313506E-03 -2.966893E-01 -2.045198E-02 -1.197994E-01 -3.155257E-03 -1.383468E-01 -4.249085E-03 -1.225401E-01 -3.736978E-03 -7.410456E-02 -1.481523E-03 +1.085149E+01 +2.907194E+01 +2.786916E+01 +1.923869E+02 +2.841397E+01 +1.865709E+02 +1.038793E+01 +2.590382E+01 +1.085149E+01 +2.907194E+01 +2.786916E+01 +1.923869E+02 +2.841397E+01 +1.865709E+02 +1.038793E+01 +2.590382E+01 +6.038075E-02 +1.204656E-03 +9.934671E-02 +2.371660E-03 +1.698720E-01 +6.753819E-03 +1.363012E-01 +4.653519E-03 +3.172247E-01 +2.124184E-02 +1.738899E-01 +6.713494E-03 +1.908717E-01 +8.360058E-03 +2.533354E-01 +1.539905E-02 +1.158802E-01 +2.959280E-03 +1.698297E-01 +6.569993E-03 +1.146976E-01 +3.173782E-03 +9.724996E-02 +2.784804E-03 diff --git a/tests/regression_tests/filter_cellinstance/test.py b/tests/regression_tests/filter_cellinstance/test.py index dc00394fc26..61f17d88a66 100644 --- a/tests/regression_tests/filter_cellinstance/test.py +++ b/tests/regression_tests/filter_cellinstance/test.py @@ -1,3 +1,4 @@ +from numpy.testing import assert_array_almost_equal import openmc import openmc.model import pytest @@ -5,6 +6,24 @@ from tests.testing_harness import PyAPITestHarness +class CellInstanceFilterTest(PyAPITestHarness): + + def _compare_results(self): + with openmc.StatePoint(self.statepoint_name) as sp: + # we expect the tally results for the instances of + # cells 2 and 3 to be the same as 2 is nested + # in a universe directly under 3 + t1 = sp.tallies[1] + f1 = sp.filters[1] + c2_bins = [tuple(tuple(i) for i in f1.bins if i[0] == 2)] + c2_mean = t1.get_values(filters=[openmc.CellInstanceFilter], filter_bins=c2_bins) + c3_bins = [tuple(tuple(i) for i in f1.bins if i[0] == 3)] + c3_mean = t1.get_values(filters=[openmc.CellInstanceFilter], filter_bins=c3_bins) + assert_array_almost_equal(c2_mean, c3_mean) + + return super()._compare_results() + + @pytest.fixture def model(): model = openmc.model.Model() @@ -22,24 +41,27 @@ def model(): cyl1 = openmc.ZCylinder(r=0.7) c1 = openmc.Cell(fill=m1, region=-cyl1) c2 = openmc.Cell(fill=m2, region=+cyl1) - u1 = openmc.Universe(cells=[c1, c2]) + # intermediate universe containing only cell 2 + u1 = openmc.Universe(cells=[c2]) + c3 = openmc.Cell(fill=u1) + u2 = openmc.Universe(cells=[c1, c3]) cyl2 = openmc.ZCylinder(r=0.5) - c3 = openmc.Cell(fill=m1, region=-cyl2) - c4 = openmc.Cell(fill=m2, region=+cyl2) - u2 = openmc.Universe(cells=[c3, c4]) + c4 = openmc.Cell(fill=m1, region=-cyl2) + c5 = openmc.Cell(fill=m2, region=+cyl2) + u3 = openmc.Universe(cells=[c4, c5]) lat = openmc.RectLattice() lat.lower_left = (-4, -4) lat.pitch = (2, 2) lat.universes = [ - [u1, u2, u2, u2], - [u2, u1, u2, u2], - [u2, u2, u1, u2], - [u2, u2, u2, u1] + [u2, u3, u3, u3], + [u3, u2, u3, u3], + [u3, u3, u2, u3], + [u3, u3, u3, u2] ] - box = openmc.model.rectangular_prism(8.0, 8.0, boundary_type='reflective') - main_cell = openmc.Cell(fill=lat, region=box) + box = openmc.model.RectangularPrism(8.0, 8.0, boundary_type='reflective') + main_cell = openmc.Cell(fill=lat, region=-box) model.geometry.root_universe = openmc.Universe(cells=[main_cell]) model.geometry.determine_paths() @@ -47,10 +69,11 @@ def model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) - instances = ([(c3, i) for i in range(c3.num_instances)] + - [(c2, i) for i in range(c2.num_instances)]) + instances = ([(c4, i) for i in range(c4.num_instances)] + + [(c2, i) for i in range(c2.num_instances)] + + [(c3, i) for i in range(c3.num_instances)]) f1 = openmc.CellInstanceFilter(instances) f2 = openmc.CellInstanceFilter(instances[::-1]) t1 = openmc.Tally() @@ -65,5 +88,5 @@ def model(): def test_cell_instance(model): - harness = PyAPITestHarness('statepoint.5.h5', model) + harness = CellInstanceFilterTest('statepoint.5.h5', model) harness.main() diff --git a/tests/regression_tests/filter_distribcell/case-3/results_true.dat b/tests/regression_tests/filter_distribcell/case-3/results_true.dat index c12903feda4..f30e858f06d 100644 --- a/tests/regression_tests/filter_distribcell/case-3/results_true.dat +++ b/tests/regression_tests/filter_distribcell/case-3/results_true.dat @@ -1 +1 @@ -d3ecf354b33d09064f43816325f33ec1229d1258255ee8413e83f7ba96ca921b8f4be738c10af99c5376bfe2b6be45976595634efcafddec0d9296eb45ffed3e \ No newline at end of file +1d09084dc41305687d53d1e800fb3d0ac3949aa4e1cb0bfbb327d0ec1ad4b74fc97ee73da84b910529296b858aab9b8a5d0924d17ca2cc373625e1a9e197aa94 \ No newline at end of file diff --git a/tests/regression_tests/filter_distribcell/case-4/geometry.xml b/tests/regression_tests/filter_distribcell/case-4/geometry.xml deleted file mode 100644 index c835218bc06..00000000000 --- a/tests/regression_tests/filter_distribcell/case-4/geometry.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - 1.0 - 3 -
0.0 0.0
- - 1 -1 1 - 1 -1 1 - 1 -
- - - - - -
diff --git a/tests/regression_tests/filter_distribcell/case-4/materials.xml b/tests/regression_tests/filter_distribcell/case-4/materials.xml deleted file mode 100644 index 2eb744fe642..00000000000 --- a/tests/regression_tests/filter_distribcell/case-4/materials.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/tests/regression_tests/filter_distribcell/case-4/model.xml b/tests/regression_tests/filter_distribcell/case-4/model.xml new file mode 100644 index 00000000000..8694219194b --- /dev/null +++ b/tests/regression_tests/filter_distribcell/case-4/model.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + 1.0 + 3 +
0.0 0.0
+ + 1 +1 1 + 1 +1 1 + 1 +
+ + + + + +
+ + eigenvalue + 1000 + 1 + 0 + + + -1.0 -1.0 -1.0 1.0 1.0 1.0 + + + + + + 101 + + + 1 + total + + +
diff --git a/tests/regression_tests/filter_distribcell/case-4/settings.xml b/tests/regression_tests/filter_distribcell/case-4/settings.xml deleted file mode 100644 index f3f0779bc94..00000000000 --- a/tests/regression_tests/filter_distribcell/case-4/settings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - eigenvalue - 1000 - 1 - 0 - - - -1 -1 -1 1 1 1 - - - diff --git a/tests/regression_tests/filter_distribcell/case-4/tallies.xml b/tests/regression_tests/filter_distribcell/case-4/tallies.xml deleted file mode 100644 index b923c030b83..00000000000 --- a/tests/regression_tests/filter_distribcell/case-4/tallies.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - distribcell - 101 - - - - 1 - total - - - diff --git a/tests/regression_tests/filter_energyfun/inputs_true.dat b/tests/regression_tests/filter_energyfun/inputs_true.dat index 0f506f3f5fd..4b7b74d28ec 100644 --- a/tests/regression_tests/filter_energyfun/inputs_true.dat +++ b/tests/regression_tests/filter_energyfun/inputs_true.dat @@ -1,35 +1,105 @@ - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - - 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 - 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 - - - Am241 - (n,gamma) - - - 1 - Am241 - (n,gamma) - - + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 + 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 + linear-linear + + + 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 + 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 + log-log + + + 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 + 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 + linear-log + + + 1e-05 0.369 1000.0 100000.0 600000.0 1000000.0 2000000.0 4000000.0 30000000.0 + 0.1 0.1 0.1333 0.158 0.18467 0.25618 0.4297 0.48 0.48 + log-linear + + + 0.0 5000000.0 10000000.0 15000000.0 + 0.2 0.7 0.7 0.2 + linear-linear + + + 0.0 5000000.0 10000000.0 15000000.0 + 0.2 0.7 0.7 0.2 + quadratic + + + 0.0 5000000.0 10000000.0 15000000.0 + 0.2 0.7 0.7 0.2 + cubic + + + 0.0 5000000.0 10000000.0 15000000.0 + 0.2 0.7 0.7 0.2 + histogram + + + Am241 + (n,gamma) + + + 1 + Am241 + (n,gamma) + + + 3 + Am241 + (n,gamma) + + + 4 + Am241 + (n,gamma) + + + 5 + Am241 + (n,gamma) + + + 6 + Am241 + (n,gamma) + + + 7 + Am241 + (n,gamma) + + + 8 + Am241 + (n,gamma) + + + 9 + Am241 + (n,gamma) + + + diff --git a/tests/regression_tests/filter_energyfun/results_true.dat b/tests/regression_tests/filter_energyfun/results_true.dat index a1fda93a810..0aadac82e94 100644 --- a/tests/regression_tests/filter_energyfun/results_true.dat +++ b/tests/regression_tests/filter_energyfun/results_true.dat @@ -1,2 +1,10 @@ energyfunction nuclide score mean std. dev. -0 d2effa26cb3cf2 Am241 ((n,gamma) / (n,gamma)) 1.74e-01 6.83e-03 +0 448ee8dfd19c4f Am241 ((n,gamma) / (n,gamma)) 1.74e-01 6.83e-03 + energyfunction nuclide score mean std. dev. +0 37e006ae6b2e74 Am241 (n,gamma) 8.16e-02 2.24e-03 + energyfunction nuclide score mean std. dev. +0 b4e2ac84068d2d Am241 (n,gamma) 8.19e-02 2.25e-03 + energyfunction nuclide score mean std. dev. +0 dacf88242512ea Am241 (n,gamma) 7.95e-02 2.19e-03 + energyfunction nuclide score mean std. dev. +0 fe168c70d9e078 Am241 (n,gamma) 1.06e-01 2.96e-03 diff --git a/tests/regression_tests/filter_energyfun/test.py b/tests/regression_tests/filter_energyfun/test.py index f61f05d785f..295b8ebd8ff 100644 --- a/tests/regression_tests/filter_energyfun/test.py +++ b/tests/regression_tests/filter_energyfun/test.py @@ -28,20 +28,66 @@ def model(): # Make an EnergyFunctionFilter directly from the x and y lists. filt1 = openmc.EnergyFunctionFilter(x, y) + # check interpolatoin property setter + assert filt1.interpolation == 'linear-linear' + + with pytest.raises(ValueError): + filt1.interpolation = '🥏' + # Also make a filter with the .from_tabulated1d constructor. Make sure # the filters are identical. tab1d = openmc.data.Tabulated1D(x, y) filt2 = openmc.EnergyFunctionFilter.from_tabulated1d(tab1d) assert filt1 == filt2, 'Error with the .from_tabulated1d constructor' + filt3 = openmc.EnergyFunctionFilter(x, y) + filt3.interpolation = 'log-log' + + filt4 = openmc.EnergyFunctionFilter(x, y) + filt4.interpolation = 'linear-log' + + filt5 = openmc.EnergyFunctionFilter(x, y) + filt5.interpolation = 'log-linear' + + # define a trapezoidal function for comparison + x = [0.0, 5e6, 1e7, 1.5e7] + y = [0.2, 0.7, 0.7, 0.2] + + filt6 = openmc.EnergyFunctionFilter(x, y) + + filt7 = openmc.EnergyFunctionFilter(x, y) + filt7.interpolation = 'quadratic' + + filt8 = openmc.EnergyFunctionFilter(x, y) + filt8.interpolation = 'cubic' + + filt9 = openmc.EnergyFunctionFilter(x, y) + filt9.interpolation = 'histogram' + + filters = [filt1, filt3, filt4, filt5, filt6, filt7, filt8, filt9] # Make tallies - tallies = [openmc.Tally(), openmc.Tally()] + tallies = [openmc.Tally() for _ in range(len(filters) + 1)] for t in tallies: t.scores = ['(n,gamma)'] t.nuclides = ['Am241'] - tallies[1].filters = [filt1] + + for t, f in zip(tallies[1:], filters): + t.filters = [f] + model.tallies.extend(tallies) + interpolation_vals = \ + list(openmc.EnergyFunctionFilter.INTERPOLATION_SCHEMES.keys()) + for i_val in interpolation_vals: + # breakpoint here is fake and unused + t1d = openmc.data.Tabulated1D(x, + y, + breakpoints=[1], + interpolation=[i_val]) + f = openmc.EnergyFunctionFilter.from_tabulated1d(t1d) + assert f.interpolation == \ + openmc.EnergyFunctionFilter.INTERPOLATION_SCHEMES[i_val] + return model @@ -50,13 +96,74 @@ def _get_results(self): # Read the statepoint file. sp = openmc.StatePoint(self._sp_name) + dataframes_string = "" # Use tally arithmetic to compute the branching ratio. br_tally = sp.tallies[2] / sp.tallies[1] + dataframes_string += br_tally.get_pandas_dataframe().to_string() + '\n' + + for t_id in (3, 4, 5, 6): + ef_tally = sp.tallies[t_id] + dataframes_string += ef_tally.get_pandas_dataframe().to_string() + '\n' # Output the tally in a Pandas DataFrame. - return br_tally.get_pandas_dataframe().to_string() + '\n' + return dataframes_string + + def _compare_results(self): + super()._compare_results() + + # Read the statepoint file. + sp = openmc.StatePoint(self._sp_name) + + # statepoint file round-trip checks + + # linear-linear interpolation tally + sp_lin_lin_tally = sp.get_tally(id=2) + sp_lin_lin_filt = sp_lin_lin_tally.find_filter(openmc.EnergyFunctionFilter) + + model_lin_lin_tally = self._model.tallies[1] + model_lin_lin_filt = model_lin_lin_tally.find_filter(openmc.EnergyFunctionFilter) + + assert sp_lin_lin_filt.interpolation == 'linear-linear' + assert all(sp_lin_lin_filt.energy == model_lin_lin_filt.energy) + assert all(sp_lin_lin_filt.y == model_lin_lin_filt.y) + + # log-log interpolation tally + sp_log_log_tally = sp.get_tally(id=3) + sp_log_log_filt = sp_log_log_tally.find_filter(openmc.EnergyFunctionFilter) + + model_log_log_tally = self._model.tallies[2] + model_log_log_filt = model_log_log_tally.find_filter(openmc.EnergyFunctionFilter) + + assert sp_log_log_filt.interpolation == 'log-log' + assert all(sp_log_log_filt.energy == model_log_log_filt.energy) + assert all(sp_log_log_filt.y == model_log_log_filt.y) + + # because the values of y are monotonically increasing, + # we expect the log-log tally to have a higher value + assert all(sp_lin_lin_tally.mean < sp_log_log_tally.mean) + + sp_lin_log_tally = self._model.tallies[3] + sp_lin_log_filt = sp_lin_log_tally.find_filter(openmc.EnergyFunctionFilter) + assert sp_lin_log_filt.interpolation == 'linear-log' + + sp_log_lin_tally = self._model.tallies[4] + sp_log_lin_filt = sp_log_lin_tally.find_filter(openmc.EnergyFunctionFilter) + assert sp_log_lin_filt.interpolation == 'log-linear' + + # check that the cubic interpolation provides a higher value + # than linear-linear + contrived_lin_lin_tally = sp.get_tally(id=6) + contrived_quadratic_tally = sp.get_tally(id=7) + contrived_cubic_tally = sp.get_tally(id=8) + + assert all(contrived_lin_lin_tally.mean < contrived_quadratic_tally.mean) + assert all(contrived_lin_lin_tally.mean < contrived_cubic_tally.mean) + # check that the histogram tally is less than the quadratic/cubic interpolations + histogram_tally = sp.get_tally(id=9) + assert all(histogram_tally.mean < contrived_quadratic_tally.mean) + assert all(histogram_tally.mean < contrived_cubic_tally.mean) def test_filter_energyfun(model): harness = FilterEnergyFunHarness('statepoint.5.h5', model) - harness.main() + harness.main() \ No newline at end of file diff --git a/tests/regression_tests/filter_mesh/inputs_true.dat b/tests/regression_tests/filter_mesh/inputs_true.dat index 37716c02e48..a58d58bab95 100644 --- a/tests/regression_tests/filter_mesh/inputs_true.dat +++ b/tests/regression_tests/filter_mesh/inputs_true.dat @@ -1,112 +1,151 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - - 5 - -7.5 - 7.5 - - - 5 5 - -7.5 -7.5 - 7.5 7.5 - - - 5 5 5 - -7.5 -7.5 -7.5 - 7.5 7.5 7.5 - - - -7.5 -6.617647058823529 -5.735294117647059 -4.852941176470589 -3.9705882352941178 -3.0882352941176467 -2.2058823529411766 -1.3235294117647065 -0.4411764705882355 0.4411764705882355 1.3235294117647065 2.2058823529411757 3.0882352941176467 3.9705882352941178 4.852941176470587 5.735294117647058 6.617647058823529 7.5 - -7.5 -6.617647058823529 -5.735294117647059 -4.852941176470589 -3.9705882352941178 -3.0882352941176467 -2.2058823529411766 -1.3235294117647065 -0.4411764705882355 0.4411764705882355 1.3235294117647065 2.2058823529411757 3.0882352941176467 3.9705882352941178 4.852941176470587 5.735294117647058 6.617647058823529 7.5 - 1.0 1.223224374241637 1.4962778697388448 1.8302835609029084 2.2388474634702153 2.7386127875258306 3.3499379133114306 4.09772570775871 5.012437964687018 6.131336292779302 7.500000000000001 - - - 1 - - - 1 - - - 2 - - - 2 - - - 3 - - - 3 - - - 4 - - - 4 - - - 1 - total - - - 5 - current - - - 2 - total - - - 6 - current - - - 3 - total - - - 7 - current - - - 4 - total - - - 8 - current - - + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + 5 + -7.5 + 7.5 + + + 5 5 + -7.5 -7.5 + 7.5 7.5 + + + 5 5 5 + -7.5 -7.5 -7.5 + 7.5 7.5 7.5 + + + -7.5 -6.617647058823529 -5.735294117647059 -4.852941176470589 -3.9705882352941178 -3.0882352941176467 -2.2058823529411766 -1.3235294117647065 -0.4411764705882355 0.4411764705882355 1.3235294117647065 2.2058823529411757 3.0882352941176467 3.9705882352941178 4.852941176470587 5.735294117647058 6.617647058823529 7.5 + -7.5 -6.617647058823529 -5.735294117647059 -4.852941176470589 -3.9705882352941178 -3.0882352941176467 -2.2058823529411766 -1.3235294117647065 -0.4411764705882355 0.4411764705882355 1.3235294117647065 2.2058823529411757 3.0882352941176467 3.9705882352941178 4.852941176470587 5.735294117647058 6.617647058823529 7.5 + 1.0 1.223224374241637 1.4962778697388448 1.8302835609029084 2.2388474634702153 2.7386127875258306 3.3499379133114306 4.09772570775871 5.012437964687018 6.131336292779302 7.500000000000001 + + + 0.0 0.4411764705882353 0.8823529411764706 1.3235294117647058 1.7647058823529411 2.2058823529411766 2.6470588235294117 3.0882352941176467 3.5294117647058822 3.9705882352941178 4.411764705882353 4.852941176470588 5.294117647058823 5.735294117647059 6.1764705882352935 6.617647058823529 7.0588235294117645 7.5 + 0.0 0.3490658503988659 0.6981317007977318 1.0471975511965976 1.3962634015954636 1.7453292519943295 2.0943951023931953 2.443460952792061 2.792526803190927 3.141592653589793 3.490658503988659 3.839724354387525 4.1887902047863905 4.537856055185257 4.886921905584122 5.235987755982989 5.585053606381854 5.93411945678072 6.283185307179586 + -7.5 -6.5625 -5.625 -4.6875 -3.75 -2.8125 -1.875 -0.9375 0.0 0.9375 1.875 2.8125 3.75 4.6875 5.625 6.5625 7.5 + 0.0 0.0 0.0 + + + 0.0 0.4411764705882353 0.8823529411764706 1.3235294117647058 1.7647058823529411 2.2058823529411766 2.6470588235294117 3.0882352941176467 3.5294117647058822 3.9705882352941178 4.411764705882353 4.852941176470588 5.294117647058823 5.735294117647059 6.1764705882352935 6.617647058823529 7.0588235294117645 7.5 + 0.0 0.39269908169872414 0.7853981633974483 1.1780972450961724 1.5707963267948966 1.9634954084936207 2.356194490192345 2.748893571891069 3.141592653589793 + 0.0 0.3490658503988659 0.6981317007977318 1.0471975511965976 1.3962634015954636 1.7453292519943295 2.0943951023931953 2.443460952792061 2.792526803190927 3.141592653589793 3.490658503988659 3.839724354387525 4.1887902047863905 4.537856055185257 4.886921905584122 5.235987755982989 5.585053606381854 5.93411945678072 6.283185307179586 + 0.0 0.0 0.0 + + + 1 + + + 1 + + + 2 + + + 2 + + + 3 + + + 3 + + + 4 + + + 4 + + + 5 + + + 5 + + + 6 + + + 6 + + + 1 + total + + + 7 + current + + + 2 + total + + + 8 + current + + + 3 + total + + + 9 + current + + + 4 + total + + + 10 + current + + + 5 + total + + + 11 + current + + + 6 + total + + + 12 + current + + + diff --git a/tests/regression_tests/filter_mesh/results_true.dat b/tests/regression_tests/filter_mesh/results_true.dat index 332c8b36cf3..a91eadb3563 100644 --- a/tests/regression_tests/filter_mesh/results_true.dat +++ b/tests/regression_tests/filter_mesh/results_true.dat @@ -1 +1 @@ -97cf099a24099d2af794752e145841a9ef9f24980c53ee71e3fdd400d4249a7e6f3f52f63132fe2fe8d1973604a72d87910ab13bc3721f7d0bec533b87756847 \ No newline at end of file +bd55ee25094f9ad04fda4439f58ef0fed718632c88b9fde411a484dc624dedcd45dee643e14d8b107d8b92757737b8bb3d9a667de5482457d6d8346afffdf657 \ No newline at end of file diff --git a/tests/regression_tests/filter_mesh/test.py b/tests/regression_tests/filter_mesh/test.py index c8aa871a83f..6214e0486c0 100644 --- a/tests/regression_tests/filter_mesh/test.py +++ b/tests/regression_tests/filter_mesh/test.py @@ -1,4 +1,5 @@ import numpy as np +from math import pi import openmc import pytest @@ -18,12 +19,12 @@ def model(): zr.add_nuclide('Zr90', 1.0) model.materials.extend([fuel, zr]) - box1 = openmc.model.rectangular_prism(10.0, 10.0) - box2 = openmc.model.rectangular_prism(20.0, 20.0, boundary_type='reflective') + box1 = openmc.model.RectangularPrism(10.0, 10.0) + box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective') top = openmc.ZPlane(z0=10.0, boundary_type='vacuum') bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=box1 & +bottom & -top) - cell2 = openmc.Cell(fill=zr, region=~box1 & box2 & +bottom & -top) + cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top) + cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top) model.geometry = openmc.Geometry([cell1, cell2]) model.settings.batches = 5 @@ -45,24 +46,60 @@ def model(): mesh_3d.dimension = [5, 5, 5] mesh_3d.lower_left = [-7.5, -7.5, -7.5] mesh_3d.upper_right = [7.5, 7.5, 7.5] + dx = dy = dz = 15 / 5 + reg_mesh_exp_vols = np.full(mesh_3d.dimension, dx*dy*dz) + np.testing.assert_equal(mesh_3d.volumes, reg_mesh_exp_vols) recti_mesh = openmc.RectilinearMesh() recti_mesh.x_grid = np.linspace(-7.5, 7.5, 18) recti_mesh.y_grid = np.linspace(-7.5, 7.5, 18) recti_mesh.z_grid = np.logspace(0, np.log10(7.5), 11) + dx = dy = 15 / 17 + dz = np.diff(np.logspace(0, np.log10(7.5), 11)) + dxdy = np.full(recti_mesh.dimension[:2], dx*dy) + recti_mesh_exp_vols = np.multiply.outer(dxdy, dz) + np.testing.assert_allclose(recti_mesh.volumes, recti_mesh_exp_vols) + + cyl_mesh = openmc.CylindricalMesh( + r_grid=np.linspace(0, 7.5, 18), + phi_grid=np.linspace(0, 2*pi, 19), + z_grid=np.linspace(-7.5, 7.5, 17), + ) + dr = 0.5 * np.diff(np.linspace(0, 7.5, 18)**2) + dp = np.full(cyl_mesh.dimension[1], 2*pi / 18) + dz = np.full(cyl_mesh.dimension[2], 15 / 16) + drdp = np.outer(dr, dp) + cyl_mesh_exp_vols = np.multiply.outer(drdp, dz) + np.testing.assert_allclose(cyl_mesh.volumes, cyl_mesh_exp_vols) + + sph_mesh = openmc.SphericalMesh( + r_grid=np.linspace(0, 7.5, 18), + theta_grid=np.linspace(0, pi, 9), + phi_grid=np.linspace(0, 2*pi, 19) + ) + dr = np.diff(np.linspace(0, 7.5, 18)**3) / 3 + dt = np.diff(-np.cos(np.linspace(0, pi, 9))) + dp = np.full(sph_mesh.dimension[2], 2*pi / 18) + drdt = np.outer(dr, dt) + sph_mesh_exp_vols = np.multiply.outer(drdt, dp) + np.testing.assert_allclose(sph_mesh.volumes, sph_mesh_exp_vols) # Create filters reg_filters = [ openmc.MeshFilter(mesh_1d), openmc.MeshFilter(mesh_2d), openmc.MeshFilter(mesh_3d), - openmc.MeshFilter(recti_mesh) + openmc.MeshFilter(recti_mesh), + openmc.MeshFilter(cyl_mesh), + openmc.MeshFilter(sph_mesh) ] surf_filters = [ openmc.MeshSurfaceFilter(mesh_1d), openmc.MeshSurfaceFilter(mesh_2d), openmc.MeshSurfaceFilter(mesh_3d), - openmc.MeshSurfaceFilter(recti_mesh) + openmc.MeshSurfaceFilter(recti_mesh), + openmc.MeshSurfaceFilter(cyl_mesh), + openmc.MeshSurfaceFilter(sph_mesh) ] # Create tallies diff --git a/tests/regression_tests/filter_meshborn/__init__.py b/tests/regression_tests/filter_meshborn/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/filter_meshborn/inputs_true.dat b/tests/regression_tests/filter_meshborn/inputs_true.dat new file mode 100644 index 00000000000..3ba38d56e60 --- /dev/null +++ b/tests/regression_tests/filter_meshborn/inputs_true.dat @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + fixed source + 2000 + 8 + + + 0.0 -10.0 -10.0 10.0 10.0 10.0 + + + + + + 2 2 1 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + 1 + + + 1 + + + 1 2 + scatter + + + 1 + scatter + + + 2 + scatter + + + scatter + + + diff --git a/tests/regression_tests/filter_meshborn/results_true.dat b/tests/regression_tests/filter_meshborn/results_true.dat new file mode 100644 index 00000000000..62f2707ffc3 --- /dev/null +++ b/tests/regression_tests/filter_meshborn/results_true.dat @@ -0,0 +1,54 @@ +tally 1: +0.000000E+00 +0.000000E+00 +2.631246E+01 +8.845079E+01 +0.000000E+00 +0.000000E+00 +2.450265E+00 +9.462266E-01 +0.000000E+00 +0.000000E+00 +3.878380E+02 +1.881752E+04 +0.000000E+00 +0.000000E+00 +2.932956E+01 +1.091674E+02 +0.000000E+00 +0.000000E+00 +1.837753E+00 +5.195343E-01 +0.000000E+00 +0.000000E+00 +2.944919E+01 +1.095819E+02 +0.000000E+00 +0.000000E+00 +2.921731E+01 +1.097387E+02 +0.000000E+00 +0.000000E+00 +4.019442E+02 +2.021184E+04 +tally 2: +2.876273E+01 +1.060244E+02 +4.171676E+02 +2.176683E+04 +3.128695E+01 +1.238772E+02 +4.311615E+02 +2.325871E+04 +tally 3: +0.000000E+00 +0.000000E+00 +4.452055E+02 +2.478148E+04 +0.000000E+00 +0.000000E+00 +4.631732E+02 +2.683862E+04 +tally 4: +9.083787E+02 +1.031695E+05 diff --git a/tests/regression_tests/filter_meshborn/test.py b/tests/regression_tests/filter_meshborn/test.py new file mode 100644 index 00000000000..ff4adbc9f04 --- /dev/null +++ b/tests/regression_tests/filter_meshborn/test.py @@ -0,0 +1,107 @@ +"""Test the meshborn filter using a fixed source calculation on a H1 sphere. + +""" + +from numpy.testing import assert_allclose +import numpy as np +import openmc +import pytest + +from tests.testing_harness import PyAPITestHarness + + +RTOL = 1.0e-7 +ATOL = 0.0 + + +@pytest.fixture +def model(): + """Sphere of H1 with one hemisphere containing the source (x>0) and one + hemisphere with no source (x<0). + + """ + openmc.reset_auto_ids() + model = openmc.Model() + + # Materials + h1 = openmc.Material() + h1.add_nuclide("H1", 1.0) + h1.set_density("g/cm3", 1.0) + model.materials = openmc.Materials([h1]) + + # Core geometry + r = 10.0 + sphere = openmc.Sphere(r=r, boundary_type="reflective") + core = openmc.Cell(fill=h1, region=-sphere) + model.geometry = openmc.Geometry([core]) + + # Settings + model.settings.run_mode = 'fixed source' + model.settings.particles = 2000 + model.settings.batches = 8 + distribution = openmc.stats.Box((0., -r, -r), (r, r, r)) + model.settings.source = openmc.IndependentSource(space=distribution) + + # Tallies + mesh = openmc.RegularMesh() + mesh.dimension = (2, 2, 1) + mesh.lower_left = (-r, -r, -r) + mesh.upper_right = (r, r, r) + + f_1 = openmc.MeshFilter(mesh) + f_2 = openmc.MeshBornFilter(mesh) + + t_1 = openmc.Tally(name="scatter") + t_1.filters = [f_1, f_2] + t_1.scores = ["scatter"] + + t_2 = openmc.Tally(name="scatter-mesh") + t_2.filters = [f_1] + t_2.scores = ["scatter"] + + t_3 = openmc.Tally(name="scatter-meshborn") + t_3.filters = [f_2] + t_3.scores = ["scatter"] + + t_4 = openmc.Tally(name="scatter-total") + t_4.scores = ["scatter"] + + model.tallies = [t_1, t_2, t_3, t_4] + + return model + + +class MeshBornFilterTest(PyAPITestHarness): + + def _compare_results(self): + """Additional unit tests on the tally results to check consistency.""" + with openmc.StatePoint(self.statepoint_name) as sp: + + t1 = sp.get_tally(name="scatter").mean.reshape(4, 4) + t2 = sp.get_tally(name="scatter-mesh").mean.reshape(4) + t3 = sp.get_tally(name="scatter-meshborn").mean.reshape(4) + t4 = sp.get_tally(name="scatter-total").mean.reshape(1) + + # Consistency between mesh+meshborn matrix tally and meshborn tally + for i in range(4): + assert_allclose(t1[:, i].sum(), t3[i], rtol=RTOL, atol=ATOL) + + # Consistency between mesh+meshborn matrix tally and mesh tally + for i in range(4): + assert_allclose(t1[i, :].sum(), t2[i], rtol=RTOL, atol=ATOL) + + # Mesh cells in x<0 do not contribute to meshborn + assert_allclose(t1[:, 0].sum(), np.zeros(4), rtol=RTOL, atol=ATOL) + assert_allclose(t1[:, 2].sum(), np.zeros(4), rtol=RTOL, atol=ATOL) + + # Consistency with total scattering + assert_allclose(t1.sum(), t4, rtol=RTOL, atol=ATOL) + assert_allclose(t2.sum(), t4, rtol=RTOL, atol=ATOL) + assert_allclose(t3.sum(), t4, rtol=RTOL, atol=ATOL) + + super()._compare_results() + + +def test_filter_meshborn(model): + harness = MeshBornFilterTest("statepoint.8.h5", model) + harness.main() diff --git a/tests/regression_tests/filter_translations/inputs_true.dat b/tests/regression_tests/filter_translations/inputs_true.dat index d38bec39f10..a80ccd87675 100644 --- a/tests/regression_tests/filter_translations/inputs_true.dat +++ b/tests/regression_tests/filter_translations/inputs_true.dat @@ -1,84 +1,83 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - - 3 4 5 - -9 -9 -9 - 9 9 9 - - - -9.0 0.0 9.0 - -9.0 -3.0 3.0 9.0 - -9.0 -4.5 0.0 4.5 9.0 - - - 3 4 5 - -19 -4 -9 - -1 14 9 - - - -19.0 -10.0 -1.0 - -4.0 2.0 8.0 14.0 - -9.0 -4.5 0.0 4.5 9.0 - - - 1 - - - 2 - - - 3 - - - 4 - - - 1 - total - - - 2 - total - - - 3 - total - - - 4 - total - - + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + 3 4 5 + -9 -9 -9 + 9 9 9 + + + -9.0 0.0 9.0 + -9.0 -3.0 3.0 9.0 + -9.0 -4.5 0.0 4.5 9.0 + + + 3 4 5 + -19 -4 -9 + -1 14 9 + + + -19.0 -10.0 -1.0 + -4.0 2.0 8.0 14.0 + -9.0 -4.5 0.0 4.5 9.0 + + + 1 + + + 2 + + + 3 + + + 4 + + + 1 + total + + + 2 + total + + + 3 + total + + + 4 + total + + + diff --git a/tests/regression_tests/filter_translations/results_true.dat b/tests/regression_tests/filter_translations/results_true.dat index e5e620b97d8..d257d71a691 100644 --- a/tests/regression_tests/filter_translations/results_true.dat +++ b/tests/regression_tests/filter_translations/results_true.dat @@ -1,342 +1,342 @@ k-combined: -7.952381E-01 3.714273E-02 +2.298294E-01 3.256961E-01 tally 1: -5.340506E-02 -5.744901E-04 -8.160966E-02 -1.360702E-03 -5.306458E-02 -5.712302E-04 -1.263577E-01 -3.302526E-03 -3.858930E-01 -3.008104E-02 -1.511449E-01 -4.656419E-03 -1.279399E-01 -3.429368E-03 -3.676349E-01 -2.739091E-02 -1.410822E-01 -4.100718E-03 -5.379722E-02 -5.997669E-04 -8.933947E-02 -1.635151E-03 -5.212766E-02 -5.497167E-04 -7.332108E-02 -1.098591E-03 -1.040477E-01 -2.211291E-03 -5.326449E-02 -5.881665E-04 -1.952299E-01 -7.733668E-03 -5.683168E-01 -6.600345E-02 -1.866765E-01 -7.004663E-03 -2.262997E-01 -1.033597E-02 -6.280081E-01 -7.932045E-02 -1.861170E-01 -6.952815E-03 -7.317076E-02 -1.109977E-03 -1.145829E-01 -2.646373E-03 -6.567032E-02 -8.836880E-04 -6.614241E-02 -8.902720E-04 -1.083575E-01 -2.356190E-03 -6.479323E-02 -8.604886E-04 -2.202887E-01 -9.846484E-03 -9.405324E-01 -2.263338E-01 -1.993991E-01 -7.984693E-03 -2.310168E-01 -1.084962E-02 -9.617014E-01 -2.432501E-01 -2.127786E-01 -9.085201E-03 -7.772444E-02 -1.217267E-03 -1.170744E-01 -2.791253E-03 -7.480464E-02 -1.126824E-03 -6.321842E-02 -8.234272E-04 -1.002360E-01 -2.026069E-03 -6.532157E-02 -8.622865E-04 -1.934126E-01 -7.639724E-03 -5.583838E-01 -6.274792E-02 -1.914812E-01 -7.440011E-03 -1.808706E-01 -6.774850E-03 -6.259735E-01 -7.874410E-02 -1.959623E-01 -7.771208E-03 -6.301362E-02 -8.178688E-04 -1.062362E-01 -2.292485E-03 -5.916939E-02 -7.078944E-04 -5.265976E-02 -5.634399E-04 -6.747063E-02 -9.141711E-04 -4.478697E-02 -4.077583E-04 -1.277486E-01 -3.308655E-03 -3.585674E-01 -2.641571E-02 -1.192882E-01 -2.901276E-03 -1.457696E-01 -4.299462E-03 -3.467377E-01 -2.463831E-02 -1.305729E-01 -3.605534E-03 -5.067715E-02 -5.273379E-04 -7.374940E-02 -1.102912E-03 -5.226497E-02 -5.649644E-04 +4.880089E-02 +4.894233E-04 +8.221192E-02 +1.373712E-03 +5.205261E-02 +5.584673E-04 +1.272758E-01 +3.371623E-03 +3.599375E-01 +2.655645E-02 +1.377572E-01 +3.835778E-03 +1.646205E-01 +5.916595E-03 +3.806765E-01 +2.947576E-02 +1.470573E-01 +4.360385E-03 +5.568294E-02 +6.368003E-04 +6.775790E-02 +9.447074E-04 +5.580909E-02 +6.303584E-04 +6.674847E-02 +9.080853E-04 +9.747628E-02 +1.934325E-03 +6.824062E-02 +9.908844E-04 +1.891692E-01 +7.211874E-03 +5.976566E-01 +7.206211E-02 +1.805640E-01 +6.599680E-03 +2.114692E-01 +9.202185E-03 +6.514433E-01 +8.523087E-02 +1.905740E-01 +7.287607E-03 +7.633486E-02 +1.216488E-03 +1.117747E-01 +2.538705E-03 +7.438042E-02 +1.127109E-03 +7.356007E-02 +1.090617E-03 +1.161258E-01 +2.734941E-03 +6.745417E-02 +9.371031E-04 +2.153323E-01 +9.293477E-03 +9.414362E-01 +2.261845E-01 +2.016933E-01 +8.270477E-03 +2.370758E-01 +1.150628E-02 +9.973982E-01 +2.489516E-01 +2.152505E-01 +9.424546E-03 +7.502684E-02 +1.208304E-03 +1.244515E-01 +3.168682E-03 +7.515812E-02 +1.151397E-03 +6.355178E-02 +8.423316E-04 +1.040915E-01 +2.224064E-03 +6.902234E-02 +9.843766E-04 +1.978591E-01 +7.894161E-03 +5.162186E-01 +5.357742E-02 +1.897326E-01 +7.231935E-03 +1.827950E-01 +6.839560E-03 +5.780661E-01 +6.799910E-02 +1.881215E-01 +7.093746E-03 +6.083700E-02 +7.861240E-04 +9.978991E-02 +2.022733E-03 +6.004653E-02 +7.428556E-04 +4.951220E-02 +4.952385E-04 +7.401227E-02 +1.124154E-03 +5.151090E-02 +5.339359E-04 +1.356118E-01 +3.711749E-03 +3.400140E-01 +2.367518E-02 +1.385305E-01 +4.060592E-03 +1.438711E-01 +4.191824E-03 +3.276170E-01 +2.210924E-02 +1.279501E-01 +3.435254E-03 +4.852204E-02 +4.919417E-04 +7.229090E-02 +1.062894E-03 +4.344414E-02 +3.825354E-04 tally 2: -2.442367E-01 -1.209459E-02 -2.543262E-01 -1.314598E-02 -5.639744E-01 -6.449959E-02 -6.415410E-01 -8.269091E-02 -2.631124E-01 -1.406544E-02 -2.513955E-01 -1.285616E-02 -3.570608E-01 -2.559924E-02 -2.978502E-01 -1.787722E-02 -1.142500E+00 -2.799696E-01 -1.072656E+00 -2.465813E-01 -3.720711E-01 -2.776168E-02 -3.520288E-01 -2.482313E-02 -3.406093E-01 -2.332649E-02 -3.186893E-01 -2.046998E-02 -1.039053E+00 -2.337911E-01 -1.055863E+00 -2.442418E-01 -3.636093E-01 -2.679467E-02 -3.514845E-01 -2.481131E-02 -2.356811E-01 -1.112305E-02 -2.424590E-01 -1.205945E-02 -5.851380E-01 -6.974618E-02 -5.788717E-01 -6.882684E-02 -2.430058E-01 -1.205907E-02 -2.390704E-01 -1.167330E-02 +2.379877E-01 +1.141258E-02 +2.376600E-01 +1.137350E-02 +6.546514E-01 +8.852321E-02 +5.823862E-01 +6.810779E-02 +2.692631E-01 +1.479426E-02 +2.360469E-01 +1.124950E-02 +3.534788E-01 +2.528363E-02 +3.247931E-01 +2.160130E-02 +1.181513E+00 +2.959140E-01 +1.078874E+00 +2.467321E-01 +3.743375E-01 +2.859905E-02 +3.468123E-01 +2.427809E-02 +3.203903E-01 +2.109786E-02 +3.315547E-01 +2.216053E-02 +1.039077E+00 +2.294722E-01 +1.091786E+00 +2.572834E-01 +3.615960E-01 +2.678347E-02 +3.323317E-01 +2.226424E-02 +2.519726E-01 +1.279098E-02 +2.332385E-01 +1.101251E-02 +5.587247E-01 +6.293355E-02 +5.426859E-01 +6.010041E-02 +2.332981E-01 +1.097940E-02 +2.239951E-01 +1.043440E-02 tally 3: -5.340506E-02 -5.744901E-04 -8.160966E-02 -1.360702E-03 -5.306458E-02 -5.712302E-04 -1.263577E-01 -3.302526E-03 -3.858930E-01 -3.008104E-02 -1.511449E-01 -4.656419E-03 -1.279399E-01 -3.429368E-03 -3.676349E-01 -2.739091E-02 -1.410822E-01 -4.100718E-03 -5.379722E-02 -5.997669E-04 -8.933947E-02 -1.635151E-03 -5.212766E-02 -5.497167E-04 -7.332108E-02 -1.098591E-03 -1.040477E-01 -2.211291E-03 -5.326449E-02 -5.881665E-04 -1.952299E-01 -7.733668E-03 -5.683168E-01 -6.600345E-02 -1.866765E-01 -7.004663E-03 -2.262997E-01 -1.033597E-02 -6.280081E-01 -7.932045E-02 -1.861170E-01 -6.952815E-03 -7.317076E-02 -1.109977E-03 -1.145829E-01 -2.646373E-03 -6.567032E-02 -8.836880E-04 -6.614241E-02 -8.902720E-04 -1.083575E-01 -2.356190E-03 -6.479323E-02 -8.604886E-04 -2.202887E-01 -9.846484E-03 -9.405324E-01 -2.263338E-01 -1.993991E-01 -7.984693E-03 -2.310168E-01 -1.084962E-02 -9.617014E-01 -2.432501E-01 -2.127786E-01 -9.085201E-03 -7.772444E-02 -1.217267E-03 -1.170744E-01 -2.791253E-03 -7.480464E-02 -1.126824E-03 -6.321842E-02 -8.234272E-04 -1.002360E-01 -2.026069E-03 -6.532157E-02 -8.622865E-04 -1.934126E-01 -7.639724E-03 -5.583838E-01 -6.274792E-02 -1.914812E-01 -7.440011E-03 -1.808706E-01 -6.774850E-03 -6.259735E-01 -7.874410E-02 -1.959623E-01 -7.771208E-03 -6.301362E-02 -8.178688E-04 -1.062362E-01 -2.292485E-03 -5.916939E-02 -7.078944E-04 -5.265976E-02 -5.634399E-04 -6.747063E-02 -9.141711E-04 -4.478697E-02 -4.077583E-04 -1.277486E-01 -3.308655E-03 -3.585674E-01 -2.641571E-02 -1.192882E-01 -2.901276E-03 -1.457696E-01 -4.299462E-03 -3.467377E-01 -2.463831E-02 -1.305729E-01 -3.605534E-03 -5.067715E-02 -5.273379E-04 -7.374940E-02 -1.102912E-03 -5.226497E-02 -5.649644E-04 +4.880089E-02 +4.894233E-04 +8.221192E-02 +1.373712E-03 +5.205261E-02 +5.584673E-04 +1.272758E-01 +3.371623E-03 +3.599375E-01 +2.655645E-02 +1.377572E-01 +3.835778E-03 +1.646205E-01 +5.916595E-03 +3.806765E-01 +2.947576E-02 +1.470573E-01 +4.360385E-03 +5.568294E-02 +6.368003E-04 +6.775790E-02 +9.447074E-04 +5.580909E-02 +6.303584E-04 +6.674847E-02 +9.080853E-04 +9.747628E-02 +1.934325E-03 +6.824062E-02 +9.908844E-04 +1.891692E-01 +7.211874E-03 +5.976566E-01 +7.206211E-02 +1.805640E-01 +6.599680E-03 +2.114692E-01 +9.202185E-03 +6.514433E-01 +8.523087E-02 +1.905740E-01 +7.287607E-03 +7.633486E-02 +1.216488E-03 +1.117747E-01 +2.538705E-03 +7.438042E-02 +1.127109E-03 +7.356007E-02 +1.090617E-03 +1.161258E-01 +2.734941E-03 +6.745417E-02 +9.371031E-04 +2.153323E-01 +9.293477E-03 +9.414362E-01 +2.261845E-01 +2.016933E-01 +8.270477E-03 +2.370758E-01 +1.150628E-02 +9.973982E-01 +2.489516E-01 +2.152505E-01 +9.424546E-03 +7.502684E-02 +1.208304E-03 +1.244515E-01 +3.168682E-03 +7.515812E-02 +1.151397E-03 +6.355178E-02 +8.423316E-04 +1.040915E-01 +2.224064E-03 +6.902234E-02 +9.843766E-04 +1.978591E-01 +7.894161E-03 +5.162186E-01 +5.357742E-02 +1.897326E-01 +7.231935E-03 +1.827950E-01 +6.839560E-03 +5.780661E-01 +6.799910E-02 +1.881215E-01 +7.093746E-03 +6.083700E-02 +7.861240E-04 +9.978991E-02 +2.022733E-03 +6.004653E-02 +7.428556E-04 +4.951220E-02 +4.952385E-04 +7.401227E-02 +1.124154E-03 +5.151090E-02 +5.339359E-04 +1.356118E-01 +3.711749E-03 +3.400140E-01 +2.367518E-02 +1.385305E-01 +4.060592E-03 +1.438711E-01 +4.191824E-03 +3.276170E-01 +2.210924E-02 +1.279501E-01 +3.435254E-03 +4.852204E-02 +4.919417E-04 +7.229090E-02 +1.062894E-03 +4.344414E-02 +3.825354E-04 tally 4: -2.442367E-01 -1.209459E-02 -2.543262E-01 -1.314598E-02 -5.639744E-01 -6.449959E-02 -6.415410E-01 -8.269091E-02 -2.631124E-01 -1.406544E-02 -2.513955E-01 -1.285616E-02 -3.570608E-01 -2.559924E-02 -2.978502E-01 -1.787722E-02 -1.142500E+00 -2.799696E-01 -1.072656E+00 -2.465813E-01 -3.720711E-01 -2.776168E-02 -3.520288E-01 -2.482313E-02 -3.406093E-01 -2.332649E-02 -3.186893E-01 -2.046998E-02 -1.039053E+00 -2.337911E-01 -1.055863E+00 -2.442418E-01 -3.636093E-01 -2.679467E-02 -3.514845E-01 -2.481131E-02 -2.356811E-01 -1.112305E-02 -2.424590E-01 -1.205945E-02 -5.851380E-01 -6.974618E-02 -5.788717E-01 -6.882684E-02 -2.430058E-01 -1.205907E-02 -2.390704E-01 -1.167330E-02 +2.379877E-01 +1.141258E-02 +2.376600E-01 +1.137350E-02 +6.546514E-01 +8.852321E-02 +5.823862E-01 +6.810779E-02 +2.692631E-01 +1.479426E-02 +2.360469E-01 +1.124950E-02 +3.534788E-01 +2.528363E-02 +3.247931E-01 +2.160130E-02 +1.181513E+00 +2.959140E-01 +1.078874E+00 +2.467321E-01 +3.743375E-01 +2.859905E-02 +3.468123E-01 +2.427809E-02 +3.203903E-01 +2.109786E-02 +3.315547E-01 +2.216053E-02 +1.039077E+00 +2.294722E-01 +1.091786E+00 +2.572834E-01 +3.615960E-01 +2.678347E-02 +3.323317E-01 +2.226424E-02 +2.519726E-01 +1.279098E-02 +2.332385E-01 +1.101251E-02 +5.587247E-01 +6.293355E-02 +5.426859E-01 +6.010041E-02 +2.332981E-01 +1.097940E-02 +2.239951E-01 +1.043440E-02 diff --git a/tests/regression_tests/filter_translations/test.py b/tests/regression_tests/filter_translations/test.py index d61667b0145..4f0fe7141bf 100644 --- a/tests/regression_tests/filter_translations/test.py +++ b/tests/regression_tests/filter_translations/test.py @@ -19,12 +19,12 @@ def model(): zr.add_nuclide('Zr90', 1.0) model.materials.extend([fuel, zr]) - box1 = openmc.model.rectangular_prism(10.0, 10.0) - box2 = openmc.model.rectangular_prism(20.0, 20.0, boundary_type='reflective') + box1 = openmc.model.RectangularPrism(10.0, 10.0) + box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective') top = openmc.ZPlane(z0=10.0, boundary_type='vacuum') bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=box1 & +bottom & -top) - cell2 = openmc.Cell(fill=zr, region=~box1 & box2 & +bottom & -top) + cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top) + cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top) model.geometry = openmc.Geometry([cell1, cell2]) model.settings.batches = 5 diff --git a/tests/regression_tests/fixed_source/inputs_true.dat b/tests/regression_tests/fixed_source/inputs_true.dat index f1aebb3b2bc..0fdb1466ec5 100644 --- a/tests/regression_tests/fixed_source/inputs_true.dat +++ b/tests/regression_tests/fixed_source/inputs_true.dat @@ -1,31 +1,30 @@ - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - 0.0 0.0 0.0 - - - 294 - - - - - flux - - + + + + + + + + + + + + + + fixed source + 100 + 10 + + + 0.0 0.0 0.0 + + + 294 + + + + flux + + + diff --git a/tests/regression_tests/fixed_source/test.py b/tests/regression_tests/fixed_source/test.py index 74908f87cda..b9ee2512536 100644 --- a/tests/regression_tests/fixed_source/test.py +++ b/tests/regression_tests/fixed_source/test.py @@ -48,8 +48,8 @@ def test_fixed_source(): model.settings.batches = 10 model.settings.particles = 100 model.settings.temperature = {'default': 294} - model.settings.source = openmc.Source(space=openmc.stats.Point(), - strength=10.0) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point(), + strength=10.0) tally = openmc.Tally() tally.scores = ['flux'] diff --git a/tests/regression_tests/infinite_cell/geometry.xml b/tests/regression_tests/infinite_cell/geometry.xml deleted file mode 100644 index 90bd2233bee..00000000000 --- a/tests/regression_tests/infinite_cell/geometry.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - 11 12 - 12 11 - - - - - - - diff --git a/tests/regression_tests/infinite_cell/model.xml b/tests/regression_tests/infinite_cell/model.xml new file mode 100644 index 00000000000..0f741a86d9b --- /dev/null +++ b/tests/regression_tests/infinite_cell/model.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + 2.0 2.0 + 12 + 2 2 + -2.0 -2.0 + +11 12 +12 11 + + + + + eigenvalue + 1000 + 10 + 5 + + + -4.0 -4.0 -4.0 4.0 4.0 4.0 + + + + diff --git a/tests/regression_tests/infinite_cell/results_true.dat b/tests/regression_tests/infinite_cell/results_true.dat index b73c733aeac..2c4ce082d51 100644 --- a/tests/regression_tests/infinite_cell/results_true.dat +++ b/tests/regression_tests/infinite_cell/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.537627E-02 2.349145E-03 +9.589951E-02 8.489144E-04 diff --git a/tests/regression_tests/iso_in_lab/inputs_true.dat b/tests/regression_tests/iso_in_lab/inputs_true.dat index 2a302ada67f..bb6494adafb 100644 --- a/tests/regression_tests/iso_in_lab/inputs_true.dat +++ b/tests/regression_tests/iso_in_lab/inputs_true.dat @@ -1,38 +1,199 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + U234 U235 U238 Xe135 O16 + + + + + + + + + Zr90 Zr91 Zr92 Zr94 Zr96 + + + + + + + + + H1 O16 B10 B11 + + + + + + + + + H1 O16 B10 B11 + + + + + + + + + + + + + + Fe54 Fe56 Fe57 Fe58 Ni58 Ni60 Mn55 Cr52 C0 Cu63 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 + + + + + + + + + + + + + + H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 + + + + + + + + + + + + + + H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -50,12 +211,12 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -73,12 +234,12 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 @@ -100,12 +261,12 @@ 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 @@ -127,195 +288,34 @@ 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - U234 U235 U238 Xe135 O16 - - - - - - - - - Zr90 Zr91 Zr92 Zr94 Zr96 - - - - - - - - - H1 O16 B10 B11 - - - - - - - - - H1 O16 B10 B11 - - - - - - - - - - - - - - Fe54 Fe56 Fe57 Fe58 Ni58 Ni60 Mn55 Cr52 C0 Cu63 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - - - H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - - H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 - - - - - - - - - - - - - - H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 - - - - - eigenvalue - 100 - 10 - 5 - - - -160 -160 -183 160 160 183 - - - + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -160 -160 -183 160 160 183 + + + + diff --git a/tests/regression_tests/iso_in_lab/results_true.dat b/tests/regression_tests/iso_in_lab/results_true.dat index ce9cf316f63..aaef2262342 100644 --- a/tests/regression_tests/iso_in_lab/results_true.dat +++ b/tests/regression_tests/iso_in_lab/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.050918E-01 3.355799E-02 +9.015537E-01 1.086850E-01 diff --git a/tests/regression_tests/lattice/results_true.dat b/tests/regression_tests/lattice/results_true.dat index ff0ff626f52..f3e937b36ea 100644 --- a/tests/regression_tests/lattice/results_true.dat +++ b/tests/regression_tests/lattice/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.068493E+00 1.318070E-01 +9.610829E-01 2.522714E-02 diff --git a/tests/regression_tests/lattice_hex/results_true.dat b/tests/regression_tests/lattice_hex/results_true.dat index 3d53292abd5..789bacc4045 100644 --- a/tests/regression_tests/lattice_hex/results_true.dat +++ b/tests/regression_tests/lattice_hex/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.522694E-01 1.422929E-02 +2.566607E-01 9.207770E-03 diff --git a/tests/regression_tests/lattice_hex_coincident/inputs_true.dat b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat index 0388a4f555f..ac82de0adf9 100644 --- a/tests/regression_tests/lattice_hex_coincident/inputs_true.dat +++ b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat @@ -1,81 +1,81 @@ - - - - - - - - - - - 1.4 - 11 -
0.0 0.0
- - 10 -10 10 - 9 -10 10 - 10 -
- - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 2 - - - -0.9899494936611666 -0.9899494936611666 0.0 0.9899494936611666 0.9899494936611666 10.0 - - - - false - - 22 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.4 + 3 +
0.0 0.0
+ + 2 +2 2 + 1 +2 2 + 2 +
+ + + + + + + + + + + + +
+ + eigenvalue + 1000 + 5 + 2 + + + -0.9899494936611666 -0.9899494936611666 0.0 0.9899494936611666 0.9899494936611666 10.0 + + + + false + + 22 + +
diff --git a/tests/regression_tests/lattice_hex_coincident/results_true.dat b/tests/regression_tests/lattice_hex_coincident/results_true.dat index 94115e6eee9..c134e123f91 100644 --- a/tests/regression_tests/lattice_hex_coincident/results_true.dat +++ b/tests/regression_tests/lattice_hex_coincident/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.901983E+00 1.772999E-02 +1.917792E+00 4.329425E-02 diff --git a/tests/regression_tests/lattice_hex_coincident/test.py b/tests/regression_tests/lattice_hex_coincident/test.py index 30bc470f269..f971098c06a 100644 --- a/tests/regression_tests/lattice_hex_coincident/test.py +++ b/tests/regression_tests/lattice_hex_coincident/test.py @@ -6,7 +6,8 @@ class HexLatticeCoincidentTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) materials = openmc.Materials() fuel_mat = openmc.Material() @@ -40,7 +41,7 @@ def _build_inputs(self): zirc.add_nuclide('Zr96', 1.131E-03, 'ao') materials.append(zirc) - materials.export_to_xml() + self._model.materials = materials ### Geometry ### pin_rad = 0.7 # cm @@ -103,10 +104,10 @@ def _build_inputs(self): inf_mat_univ = openmc.Universe(cells=[inf_mat,]) # a hex surface for the core to go inside of - hexprism = openmc.model.hexagonal_prism(edge_length=edge_length, - origin=(0.0, 0.0), - boundary_type = 'reflective', - orientation='x') + hexprism = openmc.model.HexagonalPrism(edge_length=edge_length, + origin=(0.0, 0.0), + boundary_type = 'reflective', + orientation='x') pincell_only_lattice = openmc.HexLattice(name="regular fuel assembly") pincell_only_lattice.center = (0., 0.) @@ -119,20 +120,19 @@ def _build_inputs(self): pincell_only_lattice.universes = [ring1, ring0] pincell_only_cell = openmc.Cell(name="container cell") - pincell_only_cell.region = hexprism & +fuel_btm & -fuel_top + pincell_only_cell.region = -hexprism & +fuel_btm & -fuel_top pincell_only_cell.fill = pincell_only_lattice root_univ = openmc.Universe(name="root universe", cells=[pincell_only_cell,]) - geom = openmc.Geometry(root_univ) - geom.export_to_xml() + self._model.geometry = openmc.Geometry(root_univ) ### Settings ### settings = openmc.Settings() settings.run_mode = 'eigenvalue' - source = openmc.Source() + source = openmc.IndependentSource() corner_dist = sqrt(2) * pin_rad ll = [-corner_dist, -corner_dist, 0.0] ur = [corner_dist, corner_dist, 10.0] @@ -144,8 +144,9 @@ def _build_inputs(self): settings.inactive = 2 settings.particles = 1000 settings.seed = 22 - settings.export_to_xml() + self._model.settings = settings def test_lattice_hex_coincident_surf(): - harness = HexLatticeCoincidentTestHarness('statepoint.5.h5') + harness = HexLatticeCoincidentTestHarness('statepoint.5.h5', + model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/lattice_hex_x/inputs_true.dat b/tests/regression_tests/lattice_hex_x/inputs_true.dat index b528a97b7c8..252fbfc0b5d 100644 --- a/tests/regression_tests/lattice_hex_x/inputs_true.dat +++ b/tests/regression_tests/lattice_hex_x/inputs_true.dat @@ -1,23 +1,53 @@ - - - - - - - - - - - - - - - - 1.235 5.0 - 4 -
0.0 0.0 5.0
- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.235 5.0 + 4 +
0.0 0.0 5.0
+ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 @@ -60,64 +90,34 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 -
- - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - -13.62546635287517 -13.62546635287517 0.0 13.62546635287517 13.62546635287517 10.0 - - - 22 - +
+ + + + + + + + + + + + + + + + +
+ + eigenvalue + 1000 + 10 + 5 + + + -13.62546635287517 -13.62546635287517 0.0 13.62546635287517 13.62546635287517 10.0 + + + 22 + + diff --git a/tests/regression_tests/lattice_hex_x/results_true.dat b/tests/regression_tests/lattice_hex_x/results_true.dat index b1177911eae..174dc70cd4e 100644 --- a/tests/regression_tests/lattice_hex_x/results_true.dat +++ b/tests/regression_tests/lattice_hex_x/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.345955E+00 3.225468E-02 +1.367975E+00 2.264887E-02 diff --git a/tests/regression_tests/lattice_hex_x/test.py b/tests/regression_tests/lattice_hex_x/test.py index ecb27c9c2f5..dd5c53d0c02 100644 --- a/tests/regression_tests/lattice_hex_x/test.py +++ b/tests/regression_tests/lattice_hex_x/test.py @@ -4,8 +4,8 @@ class HexLatticeOXTestHarness(PyAPITestHarness): - - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) materials = openmc.Materials() fuel_mat = openmc.Material(material_id=1, name="UO2") @@ -35,7 +35,7 @@ def _build_inputs(self): zirc.add_element('Zr', 4.23e-2) materials.append(zirc) - materials.export_to_xml() + self._model.materials = materials # Geometry # @@ -139,11 +139,11 @@ def _build_inputs(self): # a hex surface for the core to go inside of - hexprism = openmc.model.hexagonal_prism(edge_length=edge_length, - origin=(0.0, 0.0), - boundary_type='reflective', - orientation='x') - region = hexprism & +fuel_bottom & -fuel_top + hexprism = openmc.model.HexagonalPrism(edge_length=edge_length, + origin=(0.0, 0.0), + boundary_type='reflective', + orientation='x') + region = -hexprism & +fuel_bottom & -fuel_top inf_mat = openmc.Cell(cell_id=12) inf_mat.fill = coolant @@ -165,7 +165,7 @@ def _build_inputs(self): (4, 21), (5, 20), (4, 27), (5, 25), (4, 33)] for i, j in channels: universes[i][j] = abs_ch_univ - lattice = openmc.HexLattice(name="regular fuel assembly") + lattice = openmc.HexLattice(lattice_id=6, name="regular fuel assembly") lattice.orientation = "x" lattice.center = (0., 0., length/2.0) lattice.pitch = (assembly_pitch, length/2.0) @@ -180,15 +180,14 @@ def _build_inputs(self): root_univ = openmc.Universe(universe_id=5, name="root universe", cells=[assembly_cell]) - geom = openmc.Geometry(root_univ) - geom.export_to_xml() + self._model.geometry = openmc.Geometry(root_univ) # Settings # settings = openmc.Settings() settings.run_mode = 'eigenvalue' - source = openmc.Source() + source = openmc.IndependentSource() ll = [-edge_length, -edge_length, 0.0] ur = [edge_length, edge_length, 10.0] source.space = openmc.stats.Box(ll, ur) @@ -198,9 +197,9 @@ def _build_inputs(self): settings.inactive = 5 settings.particles = 1000 settings.seed = 22 - settings.export_to_xml() + self._model.settings = settings def test_lattice_hex_ox_surf(): - harness = HexLatticeOXTestHarness('statepoint.10.h5') + harness = HexLatticeOXTestHarness('statepoint.10.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/lattice_multiple/inputs_true.dat b/tests/regression_tests/lattice_multiple/inputs_true.dat index c92e841bc9c..b249d97c40e 100644 --- a/tests/regression_tests/lattice_multiple/inputs_true.dat +++ b/tests/regression_tests/lattice_multiple/inputs_true.dat @@ -1,53 +1,53 @@ - - - - - - - - - 1.2 1.2 - 1 - 2 2 - -1.2 -1.2 - + + + + + + + + + + + + + + + + + + + + + + + 1.2 1.2 + 1 + 2 2 + -1.2 -1.2 + 2 1 1 1 - - - 2.4 2.4 - 2 2 - -2.4 -2.4 - + + + 2.4 2.4 + 2 2 + -2.4 -2.4 + 4 4 4 4 - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + diff --git a/tests/regression_tests/lattice_multiple/results_true.dat b/tests/regression_tests/lattice_multiple/results_true.dat index 88b911e7812..7a06551bd84 100644 --- a/tests/regression_tests/lattice_multiple/results_true.dat +++ b/tests/regression_tests/lattice_multiple/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.859909E+00 1.768384E-02 +1.859911E+00 8.282311E-03 diff --git a/tests/regression_tests/lattice_multiple/test.py b/tests/regression_tests/lattice_multiple/test.py index c287c01027a..10d9e50bc68 100644 --- a/tests/regression_tests/lattice_multiple/test.py +++ b/tests/regression_tests/lattice_multiple/test.py @@ -42,8 +42,8 @@ def model(): lattice.pitch = (2*d, 2*d) lattice.universes = np.full((2, 2), inner_univ) - box = openmc.model.rectangular_prism(4*d, 4*d, boundary_type='reflective') - main_cell = openmc.Cell(fill=lattice, region=box) + box = openmc.model.RectangularPrism(4*d, 4*d, boundary_type='reflective') + main_cell = openmc.Cell(fill=lattice, region=-box) model.geometry = openmc.Geometry([main_cell]) model.settings.batches = 10 diff --git a/tests/regression_tests/lattice_rotated/inputs_true.dat b/tests/regression_tests/lattice_rotated/inputs_true.dat index 8ee34b4f397..1b7c74870ad 100644 --- a/tests/regression_tests/lattice_rotated/inputs_true.dat +++ b/tests/regression_tests/lattice_rotated/inputs_true.dat @@ -1,18 +1,35 @@ - - - - - - - - - - - 1.25 - 30 -
0.0 0.0
- + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.25 + 30 +
0.0 0.0
+ 2 1 1 1 2 1 @@ -22,50 +39,33 @@ 1 1 1 1 1 1 -
- - 1.25 1.25 - 30 - 4 4 - -2.5 -2.5 - +
+ + 1.25 1.25 + 30 + 4 4 + -2.5 -2.5 + 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 - - - - - - -
- - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - 0.0 0.0 0.0 - - - +
+ + + + + + + + eigenvalue + 1000 + 5 + 0 + + + 0.0 0.0 0.0 + + + + diff --git a/tests/regression_tests/lattice_rotated/results_true.dat b/tests/regression_tests/lattice_rotated/results_true.dat index d02656a3f93..eeaa268fb17 100644 --- a/tests/regression_tests/lattice_rotated/results_true.dat +++ b/tests/regression_tests/lattice_rotated/results_true.dat @@ -1,2 +1,2 @@ k-combined: -4.674233E-01 1.599236E-02 +4.426784E-01 6.627506E-03 diff --git a/tests/regression_tests/lattice_rotated/test.py b/tests/regression_tests/lattice_rotated/test.py index 9cab92e1e65..63641fb84a7 100644 --- a/tests/regression_tests/lattice_rotated/test.py +++ b/tests/regression_tests/lattice_rotated/test.py @@ -73,7 +73,7 @@ def rotated_lattice_model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) model.settings.export_to_xml() return model diff --git a/tests/regression_tests/mg_basic/inputs_true.dat b/tests/regression_tests/mg_basic/inputs_true.dat index 4f2fd3f0b0a..8c6faaf070d 100644 --- a/tests/regression_tests/mg_basic/inputs_true.dat +++ b/tests/regression_tests/mg_basic/inputs_true.dat @@ -1,64 +1,64 @@ - - - - - - - - - - - - - - - - - - 2g.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 - - - - false - - multi-group - - false - - + + + 2g.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 + + + + false + + multi-group + + false + + + diff --git a/tests/regression_tests/mg_basic_delayed/inputs_true.dat b/tests/regression_tests/mg_basic_delayed/inputs_true.dat index 9fb7afe7e21..e0bcad15cef 100644 --- a/tests/regression_tests/mg_basic_delayed/inputs_true.dat +++ b/tests/regression_tests/mg_basic_delayed/inputs_true.dat @@ -1,63 +1,63 @@ - - - - - - - - - - - - - - - - - - 2g.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 - - - - false - - multi-group - - false - - + + + 2g.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 + + + + false + + multi-group + + false + + + diff --git a/tests/regression_tests/mg_convert/inputs_true.dat b/tests/regression_tests/mg_convert/inputs_true.dat index 9db9b7d7c37..4e51ec80c52 100644 --- a/tests/regression_tests/mg_convert/inputs_true.dat +++ b/tests/regression_tests/mg_convert/inputs_true.dat @@ -1,29 +1,29 @@ - - - - - - - - - - ./mgxs.h5 - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -5 -5 -5 5 5 5 - - - multi-group - + + + mgxs.h5 + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -5 -5 -5 5 5 5 + + + multi-group + + diff --git a/tests/regression_tests/mg_convert/test.py b/tests/regression_tests/mg_convert/test.py index f22c15dc073..8099c89a29c 100755 --- a/tests/regression_tests/mg_convert/test.py +++ b/tests/regression_tests/mg_convert/test.py @@ -61,7 +61,8 @@ def build_mgxs_library(convert): class MGXSTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # Instantiate some Macroscopic Data uo2_data = openmc.Macroscopic('UO2') @@ -73,7 +74,7 @@ def _build_inputs(self): # Instantiate a Materials collection and export to XML materials_file = openmc.Materials([mat]) materials_file.cross_sections = "./mgxs.h5" - materials_file.export_to_xml() + self._model.materials = materials_file # Instantiate ZCylinder surfaces left = openmc.XPlane(surface_id=4, x0=-5., name='left') @@ -102,8 +103,7 @@ def _build_inputs(self): root.add_cells([fuel]) # Instantiate a Geometry, register the root Universe, and export to XML - geometry = openmc.Geometry(root) - geometry.export_to_xml() + self._model.geometry = openmc.Geometry(root) settings_file = openmc.Settings() settings_file.energy_mode = "multi-group" @@ -114,9 +114,9 @@ def _build_inputs(self): # Create an initial uniform spatial source distribution bounds = [-5, -5, -5, 5, 5, 5] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.source = openmc.source.Source(space=uniform_dist) + settings_file.source = openmc.IndependentSource(space=uniform_dist) - settings_file.export_to_xml() + self._model.settings = settings_file def _run_openmc(self): # Run multiple conversions to compare results @@ -145,7 +145,7 @@ def _run_openmc(self): # Write out k-combined. outstr += 'k-combined:\n' form = '{:12.6E} {:12.6E}\n' - outstr += form.format(sp.k_combined.n, sp.k_combined.s) + outstr += form.format(sp.keff.n, sp.keff.s) return outstr @@ -194,5 +194,5 @@ def update_results(self): def test_mg_convert(): - harness = MGXSTestHarness('statepoint.10.h5') + harness = MGXSTestHarness('statepoint.10.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/mg_legendre/inputs_true.dat b/tests/regression_tests/mg_legendre/inputs_true.dat index ad3b434e610..34ff7b6300d 100644 --- a/tests/regression_tests/mg_legendre/inputs_true.dat +++ b/tests/regression_tests/mg_legendre/inputs_true.dat @@ -1,33 +1,33 @@ - - - - - - - - 2g.h5 - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 - - - - false - - multi-group - - false - - + + + 2g.h5 + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + + + false + + multi-group + + false + + + diff --git a/tests/regression_tests/mg_max_order/inputs_true.dat b/tests/regression_tests/mg_max_order/inputs_true.dat index 2ac83852c93..b6d70dc4c01 100644 --- a/tests/regression_tests/mg_max_order/inputs_true.dat +++ b/tests/regression_tests/mg_max_order/inputs_true.dat @@ -1,34 +1,34 @@ - - - - - - - - 2g.h5 - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 - - - - false - - multi-group - 1 - - false - - + + + 2g.h5 + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + + + false + + multi-group + 1 + + false + + + diff --git a/tests/regression_tests/mg_survival_biasing/inputs_true.dat b/tests/regression_tests/mg_survival_biasing/inputs_true.dat index 5ece3ce9fd4..6529c60d83e 100644 --- a/tests/regression_tests/mg_survival_biasing/inputs_true.dat +++ b/tests/regression_tests/mg_survival_biasing/inputs_true.dat @@ -1,34 +1,34 @@ - - - - - - - - 2g.h5 - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 - - - - false - - multi-group - true - - false - - + + + 2g.h5 + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + + + false + + multi-group + true + + false + + + diff --git a/tests/regression_tests/mg_tallies/inputs_true.dat b/tests/regression_tests/mg_tallies/inputs_true.dat index 5629587222b..c526b65a205 100644 --- a/tests/regression_tests/mg_tallies/inputs_true.dat +++ b/tests/regression_tests/mg_tallies/inputs_true.dat @@ -1,165 +1,164 @@ - - - - - - - - 2g.h5 - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 - - - - false - - multi-group - - false - - - - - - 10 1 1 - 0.0 0.0 0.0 - 929.45 1000 1000 - - - 1 - - - 1 - - - 0.0 20000000.0 - - - 0.0 20000000.0 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 5 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - analog - - - 5 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - tracklength - - - 6 1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux scatter nu-scatter - analog - - - 6 1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - collision - - - 6 1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - tracklength - - - 6 1 2 - scatter nu-scatter nu-fission - - - 6 3 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux scatter nu-scatter - analog - - - 6 3 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - collision - - - 6 3 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux - tracklength - - - 6 3 4 - scatter nu-scatter nu-fission - - - 5 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - analog - - - 5 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - tracklength - - - 6 1 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate scatter nu-scatter - analog - - - 6 1 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - collision - - - 6 1 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - tracklength - - - 6 1 2 - mat_1 - scatter nu-scatter nu-fission - - - 6 3 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate scatter nu-scatter - analog - - - 6 3 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - collision - - - 6 3 - mat_1 - total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate - tracklength - - - 6 3 4 - mat_1 - scatter nu-scatter nu-fission - - + + + 2g.h5 + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + + + false + + multi-group + + false + + + + + 10 1 1 + 0.0 0.0 0.0 + 929.45 1000 1000 + + + 1 + + + 1 + + + 0.0 20000000.0 + + + 0.0 20000000.0 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 5 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + analog + + + 5 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + tracklength + + + 6 1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux scatter nu-scatter + analog + + + 6 1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + collision + + + 6 1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + tracklength + + + 6 1 2 + scatter nu-scatter nu-fission + + + 6 3 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux scatter nu-scatter + analog + + + 6 3 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + collision + + + 6 3 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate flux + tracklength + + + 6 3 4 + scatter nu-scatter nu-fission + + + 5 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + analog + + + 5 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + tracklength + + + 6 1 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate scatter nu-scatter + analog + + + 6 1 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + collision + + + 6 1 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + tracklength + + + 6 1 2 + mat_1 + scatter nu-scatter nu-fission + + + 6 3 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate scatter nu-scatter + analog + + + 6 3 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + collision + + + 6 3 + mat_1 + total absorption fission nu-fission inverse-velocity prompt-nu-fission delayed-nu-fission kappa-fission events decay-rate + tracklength + + + 6 3 4 + mat_1 + scatter nu-scatter nu-fission + + + diff --git a/tests/regression_tests/mg_temperature/build_2g.py b/tests/regression_tests/mg_temperature/build_2g.py index 1256ca0f7f2..f236031a727 100644 --- a/tests/regression_tests/mg_temperature/build_2g.py +++ b/tests/regression_tests/mg_temperature/build_2g.py @@ -1,297 +1,296 @@ -import openmc -import numpy as np - -names = ['H', 'O', 'Zr', 'U235', 'U238'] - - -def build_openmc_xs_lib(name, groups, temperatures, xsdict, micro=True): - """Build an Openm XSdata based on dictionary values""" - xsdata = openmc.XSdata(name, groups, temperatures=temperatures) - xsdata.order = 0 - for tt in temperatures: - xsdata.set_absorption(xsdict[tt]['absorption'][name], temperature=tt) - xsdata.set_scatter_matrix(xsdict[tt]['scatter'][name], temperature=tt) - xsdata.set_total(xsdict[tt]['total'][name], temperature=tt) - if (name in xsdict[tt]['nu-fission'].keys()): - xsdata.set_nu_fission(xsdict[tt]['nu-fission'][name], - temperature=tt) - xsdata.set_chi(np.array([1., 0.]), temperature=tt) - return xsdata - - -def create_micro_xs_dict(): - """Returns micro xs library""" - xs_micro = {} - reactions = ['absorption', 'total', 'scatter', 'nu-fission'] - # chi is unnecessary when energy bound is in thermal region - # Temperature 300K - # absorption - xs_micro[300] = {r: {} for r in reactions} - xs_micro[300]['absorption']['H'] = np.array([1.0285E-4, 0.0057]) - xs_micro[300]['absorption']['O'] = np.array([7.1654E-5, 3.0283E-6]) - xs_micro[300]['absorption']['Zr'] = np.array([4.5918E-5, 3.6303E-5]) - xs_micro[300]['absorption']['U235'] = np.array([0.0035, 0.1040]) - xs_micro[300]['absorption']['U238'] = np.array([0.0056, 0.0094]) - # nu-scatter matrix - xs_micro[300]['scatter']['H'] = np.array([[[0.0910, 0.01469], - [0.0, 0.3316]]]) - xs_micro[300]['scatter']['O'] = np.array([[[0.0814, 3.3235E-4], - [0.0, 0.0960]]]) - xs_micro[300]['scatter']['Zr'] = np.array([[[0.0311, 2.6373E-5], - [0.0, 0.0315]]]) - xs_micro[300]['scatter']['U235'] = np.array([[[0.0311, 2.6373E-5], - [0.0, 0.0315]]]) - xs_micro[300]['scatter']['U238'] = np.array([[[0.0551, 2.2341E-5], - [0.0, 0.0526]]]) - # nu-fission - xs_micro[300]['nu-fission']['U235'] = np.array([0.0059, 0.2160]) - xs_micro[300]['nu-fission']['U238'] = np.array([0.0019, 1.4627E-7]) - # total - xs_micro[300]['total']['H'] = xs_micro[300]['absorption']['H'] + \ - np.sum(xs_micro[300]['scatter']['H'][0], 1) - xs_micro[300]['total']['O'] = xs_micro[300]['absorption']['O'] + \ - np.sum(xs_micro[300]['scatter']['O'][0], 1) - - xs_micro[300]['total']['Zr'] = xs_micro[300]['absorption']['Zr'] + \ - np.sum(xs_micro[300]['scatter']['Zr'][0], 1) - - xs_micro[300]['total']['U235'] = xs_micro[300]['absorption']['U235'] + \ - np.sum(xs_micro[300]['scatter']['U235'][0], 1) - - xs_micro[300]['total']['U238'] = xs_micro[300]['absorption']['U238'] + \ - np.sum(xs_micro[300]['scatter']['U238'][0], 1) - - # Temperature 600K - xs_micro[600] = {r: {} for r in reactions} - # absorption - xs_micro[600]['absorption']['H'] = np.array([1.0356E-4, 0.0046]) - xs_micro[600]['absorption']['O'] = np.array([7.2678E-5, 2.4963E-6]) - xs_micro[600]['absorption']['Zr'] = np.array([4.7256E-5, 2.9757E-5]) - xs_micro[600]['absorption']['U235'] = np.array([0.0035, 0.0853]) - xs_micro[600]['absorption']['U238'] = np.array([0.0058, 0.0079]) - # nu-scatter matrix - xs_micro[600]['scatter']['H'] = np.array([[[0.0910, 0.0138], - [0.0, 0.3316]]]) - xs_micro[600]['scatter']['O'] = np.array([[[0.0814, 3.5367E-4], - [0.0, 0.0959]]]) - xs_micro[600]['scatter']['Zr'] = np.array([[[0.0311, 3.2293E-5], - [0.0, 0.0314]]]) - xs_micro[600]['scatter']['U235'] = np.array([[[0.0022, 1.9763E-6], - [9.1634E-8, 0.0039]]]) - xs_micro[600]['scatter']['U238'] = np.array([[[0.0556, 2.8803E-5], - [0.0, 0.0536]]]) - # nu-fission - xs_micro[600]['nu-fission']['U235'] = np.array([0.0059, 0.1767]) - xs_micro[600]['nu-fission']['U238'] = np.array([0.0019, 1.2405E-7]) - # total - xs_micro[600]['total']['H'] = xs_micro[600]['absorption']['H'] + \ - np.sum(xs_micro[600]['scatter']['H'][0], 1) - xs_micro[600]['total']['O'] = xs_micro[600]['absorption']['O'] + \ - np.sum(xs_micro[600]['scatter']['O'][0], 1) - - xs_micro[600]['total']['Zr'] = xs_micro[600]['absorption']['Zr'] + \ - np.sum(xs_micro[600]['scatter']['Zr'][0], 1) - - xs_micro[600]['total']['U235'] = xs_micro[600]['absorption']['U235'] + \ - np.sum(xs_micro[600]['scatter']['U235'][0], 1) - - xs_micro[600]['total']['U238'] = xs_micro[600]['absorption']['U238'] + \ - np.sum(xs_micro[600]['scatter']['U238'][0], 1) - - # Temperature 900K - xs_micro[900] = {r: {} for r in reactions} - # absorption - xs_micro[900]['absorption']['H'] = np.array([1.0529E-4, 0.0040]) - xs_micro[900]['absorption']['O'] = np.array([7.3055E-5, 2.1850E-6]) - xs_micro[900]['absorption']['Zr'] = np.array([4.7141E-5, 2.5941E-5]) - xs_micro[900]['absorption']['U235'] = np.array([0.0035, 0.0749]) - xs_micro[900]['absorption']['U238'] = np.array([0.0060, 0.0071]) - # total - xs_micro[900]['total']['H'] = np.array([0.2982, 0.7332]) - xs_micro[900]['total']['O'] = np.array([0.0885, 0.1004]) - xs_micro[900]['total']['Zr'] = np.array([0.0370, 0.0317]) - xs_micro[900]['total']['U235'] = np.array([0.0061, 0.0789]) - xs_micro[900]['total']['U238'] = np.array([0.0707, 0.0613]) - # nu-scatter matrix - xs_micro[900]['scatter']['H'] = np.array([[[0.0913, 0.0147], - [0.0, 0.4020]]]) - xs_micro[900]['scatter']['O'] = np.array([[[0.0812, 4.0413E-4], - [0.0, 0.0965]]]) - xs_micro[900]['scatter']['Zr'] = np.array([[[0.0311, 3.6735E-5], - [0.0, 0.0314]]]) - xs_micro[900]['scatter']['U235'] = np.array([[[0.0022, 2.9034E-6], - [1.3117E-8, 0.0039]]]) - xs_micro[900]['scatter']['U238'] = np.array([[[0.0560, 3.7619E-5], - [0.0, 0.0538]]]) - # nu-fission - xs_micro[900]['nu-fission']['U235'] = np.array([0.0059, 0.1545]) - xs_micro[900]['nu-fission']['U238'] = np.array([0.0019, 1.1017E-7]) - # total - xs_micro[900]['total']['H'] = xs_micro[900]['absorption']['H'] + \ - np.sum(xs_micro[900]['scatter']['H'][0], 1) - xs_micro[900]['total']['O'] = xs_micro[900]['absorption']['O'] + \ - np.sum(xs_micro[900]['scatter']['O'][0], 1) - - xs_micro[900]['total']['Zr'] = xs_micro[900]['absorption']['Zr'] + \ - np.sum(xs_micro[900]['scatter']['Zr'][0], 1) - - xs_micro[900]['total']['U235'] = xs_micro[900]['absorption']['U235'] + \ - np.sum(xs_micro[900]['scatter']['U235'][0], 1) - - xs_micro[900]['total']['U238'] = xs_micro[900]['absorption']['U238'] + \ - np.sum(xs_micro[900]['scatter']['U238'][0], 1) - - # roll axis for scatter matrix - for t in xs_micro: - for n in xs_micro[t]['scatter']: - xs_micro[t]['scatter'][n] = np.rollaxis(xs_micro[t]['scatter'][n], - 0, 3) - return xs_micro - - -def create_macro_dict(xs_micro): - """Create a dictionary with two group cross-section""" - xs_macro = {} - for t, d1 in xs_micro.items(): - xs_macro[t] = {} - for r, d2 in d1.items(): - temp = [] - xs_macro[t][r] = {} - for n, v in d2.items(): - temp.append(d2[n]) - # The name 'macro' is needed to store data at the same level - # of a xs_macro dictionary as for xs_micro and use it in - # function build_openmc_xs_lib - xs_macro[t][r]['macro'] = sum(temp) - return xs_macro - - -def create_openmc_2mg_libs(names): - """Built a micro/macro two group openmc MGXS libraries""" - # Initialized library params - group_edges = [0.0, 0.625, 20.0e6] - groups = openmc.mgxs.EnergyGroups(group_edges=group_edges) - mg_cross_sections_file_micro = openmc.MGXSLibrary(groups) - mg_cross_sections_file_macro = openmc.MGXSLibrary(groups) - # Building a micro mg library - micro_cs = create_micro_xs_dict() - for name in names: - mg_cross_sections_file_micro.add_xsdata(build_openmc_xs_lib(name, - groups, - [t for t in - micro_cs], - micro_cs)) - # Building a macro mg library - macro_xs = create_macro_dict(micro_cs) - mg_cross_sections_file_macro.add_xsdata(build_openmc_xs_lib('macro', - groups, - [t for t in - macro_xs], - macro_xs)) - # Exporting library to hdf5 files - mg_cross_sections_file_micro.export_to_hdf5('micro_2g.h5') - mg_cross_sections_file_macro.export_to_hdf5('macro_2g.h5') - # Returning the macro_xs dict is needed for analytical solution - return macro_xs - - -def analytical_solution_2g_therm(xsmin, xsmax=None, wgt=1.0): - """ Calculate eigenvalue based on analytical solution for eq Lf = (1/k)Qf - in two group for infinity dilution media in assumption of group - boundary in thermal spectra < 1.e+3 Ev - Parameters: - ---------- - xsmin : dict - macro cross-sections dictionary with minimum range temperature - xsmax : dict - macro cross-sections dictionary with maximum range temperature - by default: None not used for standalone temperature - wgt : float - weight for interpolation by default 1.0 - Returns: - ------- - keff : np.float64 - analytical eigenvalue of critical eq matrix - """ - if xsmax is None: - sa = xsmin['absorption']['macro'] - ss12 = xsmin['scatter']['macro'][0][1][0] - nsf = xsmin['nu-fission']['macro'] - else: - sa = xsmin['absorption']['macro'] * wgt + \ - xsmax['absorption']['macro'] * (1 - wgt) - ss12 = xsmin['scatter']['macro'][0][1][0] * wgt + \ - xsmax['scatter']['macro'][0][1][0] * (1 - wgt) - nsf = xsmin['nu-fission']['macro'] * wgt + \ - xsmax['nu-fission']['macro'] * (1 - wgt) - L = np.array([sa[0] + ss12, 0.0, -ss12, sa[1]]).reshape(2, 2) - Q = np.array([nsf[0], nsf[1], 0.0, 0.0]).reshape(2, 2) - arr = np.linalg.inv(L).dot(Q) - return np.amax(np.linalg.eigvals(arr)) - - -def build_inf_model(xsnames, xslibname, temperature, tempmethod='nearest'): - """ Building an infinite medium for openmc multi-group testing - Parameters: - ---------- - xsnames : list of str() - list with xs names - xslibname: - name of hdf5 file with cross-section library - temperature : float - value of a current temperature in K - tempmethod : {'nearest', 'interpolation'} - by default 'nearest' - """ - inf_medium = openmc.Material(name='test material', material_id=1) - inf_medium.set_density("sum") - for xs in xsnames: - inf_medium.add_nuclide(xs, 1) - INF = 11.1 - # Instantiate a Materials collection and export to XML - materials_file = openmc.Materials([inf_medium]) - materials_file.cross_sections = xslibname - materials_file.export_to_xml() - - # Instantiate boundary Planes - min_x = openmc.XPlane(boundary_type='reflective', x0=-INF) - max_x = openmc.XPlane(boundary_type='reflective', x0=INF) - min_y = openmc.YPlane(boundary_type='reflective', y0=-INF) - max_y = openmc.YPlane(boundary_type='reflective', y0=INF) - - # Instantiate a Cell - cell = openmc.Cell(cell_id=1, name='cell') - cell.temperature = temperature - # Register bounding Surfaces with the Cell - cell.region = +min_x & -max_x & +min_y & -max_y - - # Fill the Cell with the Material - cell.fill = inf_medium - - # Create root universe - root_universe = openmc.Universe(name='root universe', cells=[cell]) - - # Create Geometry and set root Universe - openmc_geometry = openmc.Geometry(root_universe) - - # Export to "geometry.xml" - openmc_geometry.export_to_xml() - - # OpenMC simulation parameters - batches = 200 - inactive = 5 - particles = 5000 - - # Instantiate a Settings object - settings_file = openmc.Settings() - settings_file.batches = batches - settings_file.inactive = inactive - settings_file.particles = particles - settings_file.energy_mode = 'multi-group' - settings_file.output = {'summary': False} - # Create an initial uniform spatial source distribution over fissionable zones - bounds = [-INF, -INF, -INF, INF, INF, INF] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) - settings_file.temperature = {'method': tempmethod} - settings_file.source = openmc.Source(space=uniform_dist) - settings_file.export_to_xml() +import openmc +import numpy as np + +names = ['H', 'O', 'Zr', 'U235', 'U238'] + + +def build_openmc_xs_lib(name, groups, temperatures, xsdict, micro=True): + """Build an Openm XSdata based on dictionary values""" + xsdata = openmc.XSdata(name, groups, temperatures=temperatures) + xsdata.order = 0 + for tt in temperatures: + xsdata.set_absorption(xsdict[tt]['absorption'][name], temperature=tt) + xsdata.set_scatter_matrix(xsdict[tt]['scatter'][name], temperature=tt) + xsdata.set_total(xsdict[tt]['total'][name], temperature=tt) + if (name in xsdict[tt]['nu-fission'].keys()): + xsdata.set_nu_fission(xsdict[tt]['nu-fission'][name], + temperature=tt) + xsdata.set_chi(np.array([1., 0.]), temperature=tt) + return xsdata + + +def create_micro_xs_dict(): + """Returns micro xs library""" + xs_micro = {} + reactions = ['absorption', 'total', 'scatter', 'nu-fission'] + # chi is unnecessary when energy bound is in thermal region + # Temperature 300K + # absorption + xs_micro[300] = {r: {} for r in reactions} + xs_micro[300]['absorption']['H'] = np.array([1.0285E-4, 0.0057]) + xs_micro[300]['absorption']['O'] = np.array([7.1654E-5, 3.0283E-6]) + xs_micro[300]['absorption']['Zr'] = np.array([4.5918E-5, 3.6303E-5]) + xs_micro[300]['absorption']['U235'] = np.array([0.0035, 0.1040]) + xs_micro[300]['absorption']['U238'] = np.array([0.0056, 0.0094]) + # nu-scatter matrix + xs_micro[300]['scatter']['H'] = np.array([[[0.0910, 0.01469], + [0.0, 0.3316]]]) + xs_micro[300]['scatter']['O'] = np.array([[[0.0814, 3.3235E-4], + [0.0, 0.0960]]]) + xs_micro[300]['scatter']['Zr'] = np.array([[[0.0311, 2.6373E-5], + [0.0, 0.0315]]]) + xs_micro[300]['scatter']['U235'] = np.array([[[0.0311, 2.6373E-5], + [0.0, 0.0315]]]) + xs_micro[300]['scatter']['U238'] = np.array([[[0.0551, 2.2341E-5], + [0.0, 0.0526]]]) + # nu-fission + xs_micro[300]['nu-fission']['U235'] = np.array([0.0059, 0.2160]) + xs_micro[300]['nu-fission']['U238'] = np.array([0.0019, 1.4627E-7]) + # total + xs_micro[300]['total']['H'] = xs_micro[300]['absorption']['H'] + \ + np.sum(xs_micro[300]['scatter']['H'][0], 1) + xs_micro[300]['total']['O'] = xs_micro[300]['absorption']['O'] + \ + np.sum(xs_micro[300]['scatter']['O'][0], 1) + + xs_micro[300]['total']['Zr'] = xs_micro[300]['absorption']['Zr'] + \ + np.sum(xs_micro[300]['scatter']['Zr'][0], 1) + + xs_micro[300]['total']['U235'] = xs_micro[300]['absorption']['U235'] + \ + np.sum(xs_micro[300]['scatter']['U235'][0], 1) + + xs_micro[300]['total']['U238'] = xs_micro[300]['absorption']['U238'] + \ + np.sum(xs_micro[300]['scatter']['U238'][0], 1) + + # Temperature 600K + xs_micro[600] = {r: {} for r in reactions} + # absorption + xs_micro[600]['absorption']['H'] = np.array([1.0356E-4, 0.0046]) + xs_micro[600]['absorption']['O'] = np.array([7.2678E-5, 2.4963E-6]) + xs_micro[600]['absorption']['Zr'] = np.array([4.7256E-5, 2.9757E-5]) + xs_micro[600]['absorption']['U235'] = np.array([0.0035, 0.0853]) + xs_micro[600]['absorption']['U238'] = np.array([0.0058, 0.0079]) + # nu-scatter matrix + xs_micro[600]['scatter']['H'] = np.array([[[0.0910, 0.0138], + [0.0, 0.3316]]]) + xs_micro[600]['scatter']['O'] = np.array([[[0.0814, 3.5367E-4], + [0.0, 0.0959]]]) + xs_micro[600]['scatter']['Zr'] = np.array([[[0.0311, 3.2293E-5], + [0.0, 0.0314]]]) + xs_micro[600]['scatter']['U235'] = np.array([[[0.0022, 1.9763E-6], + [9.1634E-8, 0.0039]]]) + xs_micro[600]['scatter']['U238'] = np.array([[[0.0556, 2.8803E-5], + [0.0, 0.0536]]]) + # nu-fission + xs_micro[600]['nu-fission']['U235'] = np.array([0.0059, 0.1767]) + xs_micro[600]['nu-fission']['U238'] = np.array([0.0019, 1.2405E-7]) + # total + xs_micro[600]['total']['H'] = xs_micro[600]['absorption']['H'] + \ + np.sum(xs_micro[600]['scatter']['H'][0], 1) + xs_micro[600]['total']['O'] = xs_micro[600]['absorption']['O'] + \ + np.sum(xs_micro[600]['scatter']['O'][0], 1) + + xs_micro[600]['total']['Zr'] = xs_micro[600]['absorption']['Zr'] + \ + np.sum(xs_micro[600]['scatter']['Zr'][0], 1) + + xs_micro[600]['total']['U235'] = xs_micro[600]['absorption']['U235'] + \ + np.sum(xs_micro[600]['scatter']['U235'][0], 1) + + xs_micro[600]['total']['U238'] = xs_micro[600]['absorption']['U238'] + \ + np.sum(xs_micro[600]['scatter']['U238'][0], 1) + + # Temperature 900K + xs_micro[900] = {r: {} for r in reactions} + # absorption + xs_micro[900]['absorption']['H'] = np.array([1.0529E-4, 0.0040]) + xs_micro[900]['absorption']['O'] = np.array([7.3055E-5, 2.1850E-6]) + xs_micro[900]['absorption']['Zr'] = np.array([4.7141E-5, 2.5941E-5]) + xs_micro[900]['absorption']['U235'] = np.array([0.0035, 0.0749]) + xs_micro[900]['absorption']['U238'] = np.array([0.0060, 0.0071]) + # total + xs_micro[900]['total']['H'] = np.array([0.2982, 0.7332]) + xs_micro[900]['total']['O'] = np.array([0.0885, 0.1004]) + xs_micro[900]['total']['Zr'] = np.array([0.0370, 0.0317]) + xs_micro[900]['total']['U235'] = np.array([0.0061, 0.0789]) + xs_micro[900]['total']['U238'] = np.array([0.0707, 0.0613]) + # nu-scatter matrix + xs_micro[900]['scatter']['H'] = np.array([[[0.0913, 0.0147], + [0.0, 0.4020]]]) + xs_micro[900]['scatter']['O'] = np.array([[[0.0812, 4.0413E-4], + [0.0, 0.0965]]]) + xs_micro[900]['scatter']['Zr'] = np.array([[[0.0311, 3.6735E-5], + [0.0, 0.0314]]]) + xs_micro[900]['scatter']['U235'] = np.array([[[0.0022, 2.9034E-6], + [1.3117E-8, 0.0039]]]) + xs_micro[900]['scatter']['U238'] = np.array([[[0.0560, 3.7619E-5], + [0.0, 0.0538]]]) + # nu-fission + xs_micro[900]['nu-fission']['U235'] = np.array([0.0059, 0.1545]) + xs_micro[900]['nu-fission']['U238'] = np.array([0.0019, 1.1017E-7]) + # total + xs_micro[900]['total']['H'] = xs_micro[900]['absorption']['H'] + \ + np.sum(xs_micro[900]['scatter']['H'][0], 1) + xs_micro[900]['total']['O'] = xs_micro[900]['absorption']['O'] + \ + np.sum(xs_micro[900]['scatter']['O'][0], 1) + + xs_micro[900]['total']['Zr'] = xs_micro[900]['absorption']['Zr'] + \ + np.sum(xs_micro[900]['scatter']['Zr'][0], 1) + + xs_micro[900]['total']['U235'] = xs_micro[900]['absorption']['U235'] + \ + np.sum(xs_micro[900]['scatter']['U235'][0], 1) + + xs_micro[900]['total']['U238'] = xs_micro[900]['absorption']['U238'] + \ + np.sum(xs_micro[900]['scatter']['U238'][0], 1) + + # roll axis for scatter matrix + for t in xs_micro: + for n in xs_micro[t]['scatter']: + xs_micro[t]['scatter'][n] = np.rollaxis(xs_micro[t]['scatter'][n], + 0, 3) + return xs_micro + + +def create_macro_dict(xs_micro): + """Create a dictionary with two group cross-section""" + xs_macro = {} + for t, d1 in xs_micro.items(): + xs_macro[t] = {} + for r, d2 in d1.items(): + temp = [] + xs_macro[t][r] = {} + for n, v in d2.items(): + temp.append(d2[n]) + # The name 'macro' is needed to store data at the same level + # of a xs_macro dictionary as for xs_micro and use it in + # function build_openmc_xs_lib + xs_macro[t][r]['macro'] = sum(temp) + return xs_macro + + +def create_openmc_2mg_libs(names): + """Built a micro/macro two group openmc MGXS libraries""" + # Initialized library params + group_edges = [0.0, 0.625, 20.0e6] + groups = openmc.mgxs.EnergyGroups(group_edges=group_edges) + mg_cross_sections_file_micro = openmc.MGXSLibrary(groups) + mg_cross_sections_file_macro = openmc.MGXSLibrary(groups) + # Building a micro mg library + micro_cs = create_micro_xs_dict() + for name in names: + mg_cross_sections_file_micro.add_xsdata(build_openmc_xs_lib(name, + groups, + [t for t in + micro_cs], + micro_cs)) + # Building a macro mg library + macro_xs = create_macro_dict(micro_cs) + mg_cross_sections_file_macro.add_xsdata(build_openmc_xs_lib('macro', + groups, + [t for t in + macro_xs], + macro_xs)) + # Exporting library to hdf5 files + mg_cross_sections_file_micro.export_to_hdf5('micro_2g.h5') + mg_cross_sections_file_macro.export_to_hdf5('macro_2g.h5') + # Returning the macro_xs dict is needed for analytical solution + return macro_xs + + +def analytical_solution_2g_therm(xsmin, xsmax=None, wgt=1.0): + """ Calculate eigenvalue based on analytical solution for eq Lf = (1/k)Qf + in two group for infinity dilution media in assumption of group + boundary in thermal spectra < 1.e+3 Ev + Parameters: + ---------- + xsmin : dict + macro cross-sections dictionary with minimum range temperature + xsmax : dict + macro cross-sections dictionary with maximum range temperature + by default: None not used for standalone temperature + wgt : float + weight for interpolation by default 1.0 + Returns: + ------- + keff : np.float64 + analytical eigenvalue of critical eq matrix + """ + if xsmax is None: + sa = xsmin['absorption']['macro'] + ss12 = xsmin['scatter']['macro'][0][1][0] + nsf = xsmin['nu-fission']['macro'] + else: + sa = xsmin['absorption']['macro'] * wgt + \ + xsmax['absorption']['macro'] * (1 - wgt) + ss12 = xsmin['scatter']['macro'][0][1][0] * wgt + \ + xsmax['scatter']['macro'][0][1][0] * (1 - wgt) + nsf = xsmin['nu-fission']['macro'] * wgt + \ + xsmax['nu-fission']['macro'] * (1 - wgt) + L = np.array([sa[0] + ss12, 0.0, -ss12, sa[1]]).reshape(2, 2) + Q = np.array([nsf[0], nsf[1], 0.0, 0.0]).reshape(2, 2) + arr = np.linalg.inv(L).dot(Q) + return np.amax(np.linalg.eigvals(arr)) + + +def build_inf_model(xsnames, xslibname, temperature, tempmethod='nearest'): + """ Building an infinite medium for openmc multi-group testing + Parameters: + ---------- + xsnames : list of str() + list with xs names + xslibname: + name of hdf5 file with cross-section library + temperature : float + value of a current temperature in K + tempmethod : {'nearest', 'interpolation'} + by default 'nearest' + """ + model = openmc.Model() + inf_medium = openmc.Material(name='test material', material_id=1) + inf_medium.set_density("sum") + for xs in xsnames: + inf_medium.add_nuclide(xs, 1) + INF = 11.1 + # Instantiate a Materials collection and export to XML + materials_file = openmc.Materials([inf_medium]) + materials_file.cross_sections = xslibname + model.materials = materials_file + + # Instantiate boundary Planes + min_x = openmc.XPlane(boundary_type='reflective', x0=-INF) + max_x = openmc.XPlane(boundary_type='reflective', x0=INF) + min_y = openmc.YPlane(boundary_type='reflective', y0=-INF) + max_y = openmc.YPlane(boundary_type='reflective', y0=INF) + + # Instantiate a Cell + cell = openmc.Cell(cell_id=1, name='cell') + cell.temperature = temperature + # Register bounding Surfaces with the Cell + cell.region = +min_x & -max_x & +min_y & -max_y + + # Fill the Cell with the Material + cell.fill = inf_medium + + # Create root universe + root_universe = openmc.Universe(name='root universe', cells=[cell]) + + # Create Geometry and set root Universe + model.geometry = openmc.Geometry(root_universe) + + # OpenMC simulation parameters + batches = 200 + inactive = 5 + particles = 5000 + + # Instantiate a Settings object + settings_file = openmc.Settings() + settings_file.batches = batches + settings_file.inactive = inactive + settings_file.particles = particles + settings_file.energy_mode = 'multi-group' + settings_file.output = {'summary': False} + # Create an initial uniform spatial source distribution over fissionable zones + bounds = [-INF, -INF, -INF, INF, INF, INF] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) + settings_file.temperature = {'method': tempmethod} + settings_file.source = openmc.IndependentSource(space=uniform_dist) + model.settings = settings_file + model.export_to_model_xml() diff --git a/tests/regression_tests/mg_temperature_multi/__init__.py b/tests/regression_tests/mg_temperature_multi/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/mg_temperature_multi/inputs_true.dat b/tests/regression_tests/mg_temperature_multi/inputs_true.dat new file mode 100644 index 00000000000..0c452cd520e --- /dev/null +++ b/tests/regression_tests/mg_temperature_multi/inputs_true.dat @@ -0,0 +1,56 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + multi-group + + + + 1 + + + 2 + + + 1 + flux + + + 2 + flux + + + diff --git a/tests/regression_tests/mg_temperature_multi/results_true.dat b/tests/regression_tests/mg_temperature_multi/results_true.dat new file mode 100644 index 00000000000..80c2f562250 --- /dev/null +++ b/tests/regression_tests/mg_temperature_multi/results_true.dat @@ -0,0 +1,8 @@ +k-combined: +1.337115E+00 7.221249E-03 +tally 1: +2.549066E+01 +1.299987E+02 +tally 2: +9.276778E+01 +1.721791E+03 diff --git a/tests/regression_tests/mg_temperature_multi/test.py b/tests/regression_tests/mg_temperature_multi/test.py new file mode 100755 index 00000000000..3117e29ba03 --- /dev/null +++ b/tests/regression_tests/mg_temperature_multi/test.py @@ -0,0 +1,167 @@ +import os + +import numpy as np +import openmc +import openmc.mgxs + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data + egroups = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] + groups = openmc.mgxs.EnergyGroups(egroups) + + # Instantiate the 7-group (C5G7) cross section data + uo2_xsdata = openmc.XSdata('UO2', groups, temperatures=[294.0, 600.0]) + uo2_xsdata.order = 0 + scatter_matrix = np.array([[ + [0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800] + ]]) + scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) + + # Original C5G7 data + uo2_xsdata.set_total([0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, 0.5644058], temperature=294.0) + uo2_xsdata.set_absorption([8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02, 3.0020E-02, 1.1126E-01, 2.8278E-01], temperature=294.0) + uo2_xsdata.set_scatter_matrix(scatter_matrix, temperature=294.0) + uo2_xsdata.set_fission([7.21206E-03, 8.19301E-04, 6.45320E-03, 1.85648E-02, 1.78084E-02, 8.30348E-02, 2.16004E-01], temperature=294.0) + uo2_xsdata.set_nu_fission([2.005998E-02, 2.027303E-03, 1.570599E-02, 4.518301E-02, 4.334208E-02, 2.020901E-01, 5.257105E-01], temperature=294.0) + uo2_xsdata.set_chi([5.8791E-01, 4.1176E-01, 3.3906E-04, 1.1761E-07, 0.0000E+00, 0.0000E+00, 0.0000E+00], temperature=294.0) + + # Altered C5G7 data (permuted Chi) + uo2_xsdata.set_total([0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, 0.5644058], temperature=600.0) + uo2_xsdata.set_absorption([8.0248E-03, 3.7174E-03, 2.6769E-02, 9.6236E-02, 3.0020E-02, 1.1126E-01, 2.8278E-01], temperature=600.0) + uo2_xsdata.set_scatter_matrix(scatter_matrix, temperature=600.0) + uo2_xsdata.set_fission([7.21206E-03, 8.19301E-04, 6.45320E-03, 1.85648E-02, 1.78084E-02, 8.30348E-02, 2.16004E-01], temperature=600.0) + uo2_xsdata.set_nu_fission([2.005998E-02, 2.027303E-03, 1.570599E-02, 4.518301E-02, 4.334208E-02, 2.020901E-01, 5.257105E-01], temperature=600.0) + uo2_xsdata.set_chi([4.1176E-01, 5.8791E-01, 3.3906E-04, 1.1761E-07, 0.0000E+00, 0.0000E+00, 0.0000E+00], temperature=600.0) + + h2o_xsdata = openmc.XSdata('LWTR', groups) + h2o_xsdata.order = 0 + h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435, + 0.718, 1.2544497, 2.650379]) + h2o_xsdata.set_absorption([6.0105E-04, 1.5793E-05, 3.3716E-04, + 1.9406E-03, 5.7416E-03, 1.5001E-02, + 3.7239E-02]) + scatter_matrix = np.array([[ + [0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000], + [0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010], + [0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034], + [0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390], + [0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000] + ]]) + scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) + h2o_xsdata.set_scatter_matrix(scatter_matrix) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + mg_cross_sections_file.add_xsdatas([uo2_xsdata, h2o_xsdata]) + mg_cross_sections_file.export_to_hdf5() + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_temperature_multi(): + ############################################################################### + # Create multigroup data + create_library() + + ############################################################################### + # Create materials for the problem + + # Instantiate some Macroscopic Data + uo2_data = openmc.Macroscopic('UO2') + h2o_data = openmc.Macroscopic('LWTR') + + # Instantiate some Materials and register the appropriate Macroscopic objects + uo2 = openmc.Material(name='UO2 fuel') + uo2.set_density('macro', 1.0) + uo2.add_macroscopic(uo2_data) + + water = openmc.Material(name='Water') + water.set_density('macro', 1.0) + water.add_macroscopic(h2o_data) + + # Instantiate a Materials collection and export to XML + materials = openmc.Materials([uo2, water]) + materials.cross_sections = "mgxs.h5" + + ############################################################################### + # Define problem geometry + + # Create a surface for the fuel outer radius + fuel_ir = openmc.ZCylinder(r=0.25, name='Fuel IR') + fuel_or = openmc.ZCylinder(r=0.54, name='Fuel OR') + + # Create a region represented as the inside of a rectangular prism + pitch = 1.26 + box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective') + + # Instantiate Cells + fuel_inner = openmc.Cell(fill=uo2, region=-fuel_ir, name='fuel inner') + fuel_inner.temperature = 600.0 + fuel_outer = openmc.Cell(fill=uo2, region=+fuel_ir & -fuel_or, name='fuel outer') + fuel_outer.temperature = 294.0 + moderator = openmc.Cell(fill=water, region=+fuel_or & -box, name='moderator') + + # Create a geometry with the two cells and export to XML + geometry = openmc.Geometry([fuel_inner, fuel_outer, moderator]) + + ############################################################################### + # Define problem settings + + # Instantiate a Settings object, set all runtime parameters, and export to XML + settings = openmc.Settings() + settings.energy_mode = "multi-group" + settings.batches = 10 + settings.inactive = 5 + settings.particles = 1000 + + # Create an initial uniform spatial source distribution over fissionable zones + lower_left = (-pitch/2, -pitch/2, -1) + upper_right = (pitch/2, pitch/2, 1) + uniform_dist = openmc.stats.Box(lower_left, upper_right) + settings.source = openmc.IndependentSource( + space=uniform_dist, constraints={'fissionable': True}) + + ############################################################################### + # Define tallies + + # Instantiate the energy group data + egroups = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] + + inner_filter = openmc.CellFilter(fuel_inner) + outer_filter = openmc.CellFilter(fuel_outer) + energy_filter = openmc.EnergyFilter(egroups) + + inner_tally = openmc.Tally(name="inner tally") + inner_tally.filters = [energy_filter] + inner_tally.filters = [inner_filter] + inner_tally.scores = ['flux'] + + outer_tally = openmc.Tally(name="outer tally") + outer_tally.filters = [energy_filter] + outer_tally.filters = [outer_filter] + outer_tally.scores = ['flux'] + + # Instantiate a Tallies collection and export to XML + tallies = openmc.Tallies([inner_tally, outer_tally]) + + # Generate model and run test + model = openmc.Model(geometry, materials, settings, tallies) + + harness = MGXSTestHarness('statepoint.10.h5', model=model) + harness.main() diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat index bc5c4b2d462..6c071263f3d 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat @@ -1,251 +1,253 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 3 - - - 2 - - - 3 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - analog - - - 1 2 7 - total - nu-fission - analog - - - 1 2 - total - flux - analog - - - 1 2 7 11 - total - nu-scatter - analog - - - 1 2 7 - total - nu-scatter - analog - - - 1 2 7 - total - scatter - analog - - - 15 2 - total - flux - tracklength - - - 15 2 - total - total - tracklength - - - 15 2 - total - flux - tracklength - - - 15 2 - total - absorption - tracklength - - - 15 2 - total - flux - analog - - - 15 2 7 - total - nu-fission - analog - - - 15 2 - total - flux - analog - - - 15 2 7 11 - total - nu-scatter - analog - - - 15 2 7 - total - nu-scatter - analog - - - 15 2 7 - total - scatter - analog - - - 29 2 - total - flux - tracklength - - - 29 2 - total - total - tracklength - - - 29 2 - total - flux - tracklength - - - 29 2 - total - absorption - tracklength - - - 29 2 - total - flux - analog - - - 29 2 7 - total - nu-fission - analog - - - 29 2 - total - flux - analog - - - 29 2 7 11 - total - nu-scatter - analog - - - 29 2 7 - total - nu-scatter - analog - - - 29 2 7 - total - scatter - analog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 3 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + analog + + + 1 2 7 + total + nu-fission + analog + + + 1 2 + total + flux + analog + + + 1 2 7 11 + total + nu-scatter + analog + + + 1 2 7 + total + nu-scatter + analog + + + 1 2 7 + total + scatter + analog + + + 15 2 + total + flux + tracklength + + + 15 2 + total + total + tracklength + + + 15 2 + total + flux + tracklength + + + 15 2 + total + absorption + tracklength + + + 15 2 + total + flux + analog + + + 15 2 7 + total + nu-fission + analog + + + 15 2 + total + flux + analog + + + 15 2 7 11 + total + nu-scatter + analog + + + 15 2 7 + total + nu-scatter + analog + + + 15 2 7 + total + scatter + analog + + + 29 2 + total + flux + tracklength + + + 29 2 + total + total + tracklength + + + 29 2 + total + flux + tracklength + + + 29 2 + total + absorption + tracklength + + + 29 2 + total + flux + analog + + + 29 2 7 + total + nu-fission + analog + + + 29 2 + total + flux + analog + + + 29 2 7 11 + total + nu-scatter + analog + + + 29 2 7 + total + nu-scatter + analog + + + 29 2 7 + total + scatter + analog + + + diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/results_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg/results_true.dat index b4de4c7756f..d9565953458 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/results_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.263928E+00 3.768356E-02 +1.158563E+00 3.354681E-02 diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/test.py b/tests/regression_tests/mgxs_library_ce_to_mg/test.py index 72f052e68e1..4dff6732357 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg/test.py @@ -48,15 +48,12 @@ def _run_openmc(self): # Modify materials and settings so we can run in MG mode self._model.materials.cross_sections = './mgxs.h5' self._model.settings.energy_mode = 'multi-group' + # Dont need tallies so clear them from the model + self._model.tallies = openmc.Tallies() # Write modified input files - self._model.settings.export_to_xml() - self._model.geometry.export_to_xml() - self._model.materials.export_to_xml() + self._model.export_to_model_xml() self._model.mgxs_file.export_to_hdf5() - # Dont need tallies.xml, so remove the file - if os.path.exists('tallies.xml'): - os.remove('tallies.xml') # Enforce closing statepoint and summary files so HDF5 # does not throw an error during the next OpenMC execution diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat index 576f279661f..ad3d50974b0 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat @@ -1,251 +1,253 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 3 - - - 2 - - - 3 - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - absorption - tracklength - - - 1 2 - total - flux - analog - - - 1 2 7 - U234 U235 U238 O16 - nu-fission - analog - - - 1 2 - total - flux - analog - - - 1 2 7 11 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 7 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 7 - U234 U235 U238 O16 - scatter - analog - - - 15 2 - total - flux - tracklength - - - 15 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 15 2 - total - flux - tracklength - - - 15 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - absorption - tracklength - - - 15 2 - total - flux - analog - - - 15 2 7 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - analog - - - 15 2 - total - flux - analog - - - 15 2 7 11 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 15 2 7 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 15 2 7 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 29 2 - total - flux - tracklength - - - 29 2 - H1 O16 B10 B11 - total - tracklength - - - 29 2 - total - flux - tracklength - - - 29 2 - H1 O16 B10 B11 - absorption - tracklength - - - 29 2 - total - flux - analog - - - 29 2 7 - H1 O16 B10 B11 - nu-fission - analog - - - 29 2 - total - flux - analog - - - 29 2 7 11 - H1 O16 B10 B11 - nu-scatter - analog - - - 29 2 7 - H1 O16 B10 B11 - nu-scatter - analog - - - 29 2 7 - H1 O16 B10 B11 - scatter - analog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 3 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + total + flux + analog + + + 1 2 7 + U234 U235 U238 O16 + nu-fission + analog + + + 1 2 + total + flux + analog + + + 1 2 7 11 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 7 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 7 + U234 U235 U238 O16 + scatter + analog + + + 15 2 + total + flux + tracklength + + + 15 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 15 2 + total + flux + tracklength + + + 15 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 15 2 + total + flux + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 15 2 + total + flux + analog + + + 15 2 7 11 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 29 2 + total + flux + tracklength + + + 29 2 + H1 O16 B10 B11 + total + tracklength + + + 29 2 + total + flux + tracklength + + + 29 2 + H1 O16 B10 B11 + absorption + tracklength + + + 29 2 + total + flux + analog + + + 29 2 7 + H1 O16 B10 B11 + nu-fission + analog + + + 29 2 + total + flux + analog + + + 29 2 7 11 + H1 O16 B10 B11 + nu-scatter + analog + + + 29 2 7 + H1 O16 B10 B11 + nu-scatter + analog + + + 29 2 7 + H1 O16 B10 B11 + scatter + analog + + + diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat index f2844ed2930..a4e9dafcc02 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.817369E-01 1.166296E-02 +6.025533E-01 1.157401E-02 diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py index b624140d4e5..ee0cdf0d926 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py @@ -48,15 +48,12 @@ def _run_openmc(self): # Modify materials and settings so we can run in MG mode self._model.materials.cross_sections = './mgxs.h5' self._model.settings.energy_mode = 'multi-group' + # Dont need tallies so clear them from the model + self._model.tallies = openmc.Tallies() # Write modified input files - self._model.settings.export_to_xml() - self._model.geometry.export_to_xml() - self._model.materials.export_to_xml() + self._model.export_to_model_xml() self._model.mgxs_file.export_to_hdf5() - # Dont need tallies.xml, so remove the file - if os.path.exists('tallies.xml'): - os.remove('tallies.xml') # Enforce closing statepoint and summary files so HDF5 # does not throw an error during the next OpenMC execution diff --git a/tests/regression_tests/mgxs_library_condense/inputs_true.dat b/tests/regression_tests/mgxs_library_condense/inputs_true.dat index 9661cd46be5..8606e9fdda3 100644 --- a/tests/regression_tests/mgxs_library_condense/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_condense/inputs_true.dat @@ -1,502 +1,534 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - - - - - 2 2 - -100.0 -100.0 - 100.0 100.0 - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 3 - - - 0.0 20000000.0 - - - 1 - - - 1 2 3 4 5 6 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 52 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 52 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 66 2 - total - current - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 77 2 - total - delayed-nu-fission - tracklength - - - 1 77 52 - total - delayed-nu-fission - analog - - - 1 77 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 77 2 - total - delayed-nu-fission - tracklength - - - 1 77 - total - delayed-nu-fission - tracklength - - - 1 77 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 77 2 5 - total - delayed-nu-fission - analog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + + + + 2 2 + -100.0 -100.0 + 100.0 100.0 + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 1 + + + 1 2 3 4 5 6 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 54 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 54 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 68 2 + total + current + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 54 + total + delayed-nu-fission + analog + + + 1 79 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 + total + delayed-nu-fission + tracklength + + + 1 79 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 79 2 5 + total + delayed-nu-fission + analog + + + diff --git a/tests/regression_tests/mgxs_library_condense/results_true.dat b/tests/regression_tests/mgxs_library_condense/results_true.dat index 6ba7c0755ee..ae5bff6e35b 100644 --- a/tests/regression_tests/mgxs_library_condense/results_true.dat +++ b/tests/regression_tests/mgxs_library_condense/results_true.dat @@ -1,364 +1,362 @@ mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.693468 0.019161 -2 1 2 1 1 total 0.694532 0.021411 -1 2 1 1 1 total 0.693746 0.023378 -3 2 2 1 1 total 0.697424 0.031315 +0 1 1 1 1 total 0.699306 0.028642 +2 1 2 1 1 total 0.687913 0.025966 +1 2 1 1 1 total 0.716035 0.018945 +3 2 2 1 1 total 0.702630 0.028574 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.439784 0.020575 -2 1 2 1 1 total 0.427837 0.025828 -1 2 1 1 1 total 0.423294 0.027075 -3 2 2 1 1 total 0.433094 0.032674 +0 1 1 1 1 total 0.443642 0.030984 +2 1 2 1 1 total 0.429968 0.028072 +1 2 1 1 1 total 0.461535 0.021345 +3 2 2 1 1 total 0.439454 0.031232 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.439784 0.020575 -2 1 2 1 1 total 0.427935 0.025836 -1 2 1 1 1 total 0.423294 0.027075 -3 2 2 1 1 total 0.433094 0.032674 +0 1 1 1 1 total 0.443642 0.030984 +2 1 2 1 1 total 0.429968 0.028072 +1 2 1 1 1 total 0.461535 0.021345 +3 2 2 1 1 total 0.439454 0.031232 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.021509 0.001396 -2 1 2 1 1 total 0.020854 0.001436 -1 2 1 1 1 total 0.021469 0.001983 -3 2 2 1 1 total 0.022046 0.001594 +0 1 1 1 1 total 0.021895 0.001041 +2 1 2 1 1 total 0.021903 0.001108 +1 2 1 1 1 total 0.024895 0.001401 +3 2 2 1 1 total 0.022105 0.001198 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.011598 0.001508 -2 1 2 1 1 total 0.010856 0.001613 -1 2 1 1 1 total 0.011622 0.002259 -3 2 2 1 1 total 0.012002 0.001685 +0 1 1 1 1 total 0.021883 0.001040 +2 1 2 1 1 total 0.021879 0.001108 +1 2 1 1 1 total 0.024875 0.001401 +3 2 2 1 1 total 0.022071 0.001197 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.009911 0.000667 -2 1 2 1 1 total 0.009998 0.000859 -1 2 1 1 1 total 0.009847 0.001153 -3 2 2 1 1 total 0.010044 0.000939 +0 1 1 1 1 total 0.011219 0.000958 +2 1 2 1 1 total 0.011437 0.001013 +1 2 1 1 1 total 0.012947 0.001437 +3 2 2 1 1 total 0.011756 0.001144 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.024369 0.001625 -2 1 2 1 1 total 0.024572 0.002095 -1 2 1 1 1 total 0.024189 0.002811 -3 2 2 1 1 total 0.024677 0.002291 +0 1 1 1 1 total 0.010676 0.000481 +2 1 2 1 1 total 0.010466 0.000446 +1 2 1 1 1 total 0.011948 0.000517 +3 2 2 1 1 total 0.010350 0.000547 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.026218 0.001180 +2 1 2 1 1 total 0.025724 0.001093 +1 2 1 1 1 total 0.029326 0.001262 +3 2 2 1 1 total 0.025451 0.001338 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 1.919781e+06 128933.976741 -2 1 2 1 1 total 1.936343e+06 166141.202022 -1 2 1 1 1 total 1.906964e+06 223076.300071 -3 2 2 1 1 total 1.945248e+06 181591.269295 +0 1 1 1 1 total 2.067337e+06 93152.452502 +2 1 2 1 1 total 2.026907e+06 86377.585629 +1 2 1 1 1 total 2.313358e+06 99980.823985 +3 2 2 1 1 total 2.004370e+06 105820.022073 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.671959 0.018153 -2 1 2 1 1 total 0.673678 0.020448 -1 2 1 1 1 total 0.672277 0.021882 -3 2 2 1 1 total 0.675378 0.030166 +0 1 1 1 1 total 0.677411 0.027731 +2 1 2 1 1 total 0.666009 0.025155 +1 2 1 1 1 total 0.691140 0.018119 +3 2 2 1 1 total 0.680525 0.027587 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.672619 0.022961 -2 1 2 1 1 total 0.687448 0.033696 -1 2 1 1 1 total 0.676738 0.023823 -3 2 2 1 1 total 0.673350 0.021595 +0 1 1 1 1 total 0.679832 0.030242 +2 1 2 1 1 total 0.663143 0.019259 +1 2 1 1 1 total 0.679503 0.027107 +3 2 2 1 1 total 0.681909 0.033506 mesh 1 group in group out legendre nuclide mean std. dev. x y z -0 1 1 1 1 1 P0 total 0.672619 0.023173 -1 1 1 1 1 1 P1 total 0.253684 0.007398 -2 1 1 1 1 1 P2 total 0.083914 0.004899 -3 1 1 1 1 1 P3 total 0.006851 0.005511 -8 1 2 1 1 1 P0 total 0.687265 0.033719 -9 1 2 1 1 1 P1 total 0.266694 0.014161 -10 1 2 1 1 1 P2 total 0.110092 0.005824 -11 1 2 1 1 1 P3 total 0.014970 0.004933 -4 2 1 1 1 1 P0 total 0.676738 0.023406 -5 2 1 1 1 1 P1 total 0.270452 0.013885 -6 2 1 1 1 1 P2 total 0.107918 0.005840 -7 2 1 1 1 1 P3 total 0.016160 0.004108 -12 2 2 1 1 1 P0 total 0.673350 0.021192 -13 2 2 1 1 1 P1 total 0.264330 0.009415 -14 2 2 1 1 1 P2 total 0.093703 0.004850 -15 2 2 1 1 1 P3 total 0.019800 0.005236 +0 1 1 1 1 1 P0 total 0.679832 0.030426 +1 1 1 1 1 1 P1 total 0.255665 0.011704 +2 1 1 1 1 1 P2 total 0.087020 0.005603 +3 1 1 1 1 1 P3 total 0.006425 0.005919 +8 1 2 1 1 1 P0 total 0.663143 0.019088 +9 1 2 1 1 1 P1 total 0.257945 0.010887 +10 1 2 1 1 1 P2 total 0.095395 0.006988 +11 1 2 1 1 1 P3 total 0.009816 0.003950 +4 2 1 1 1 1 P0 total 0.679503 0.026695 +5 2 1 1 1 1 P1 total 0.254500 0.009901 +6 2 1 1 1 1 P2 total 0.093289 0.005481 +7 2 1 1 1 1 P3 total 0.004631 0.004081 +12 2 2 1 1 1 P0 total 0.681909 0.032740 +13 2 2 1 1 1 P1 total 0.263176 0.012659 +14 2 2 1 1 1 P2 total 0.093102 0.006603 +15 2 2 1 1 1 P3 total 0.007938 0.005673 mesh 1 group in group out legendre nuclide mean std. dev. x y z -0 1 1 1 1 1 P0 total 0.672619 0.023173 -1 1 1 1 1 1 P1 total 0.253684 0.007398 -2 1 1 1 1 1 P2 total 0.083914 0.004899 -3 1 1 1 1 1 P3 total 0.006851 0.005511 -8 1 2 1 1 1 P0 total 0.687448 0.033656 -9 1 2 1 1 1 P1 total 0.266596 0.014177 -10 1 2 1 1 1 P2 total 0.110079 0.005826 -11 1 2 1 1 1 P3 total 0.015046 0.004973 -4 2 1 1 1 1 P0 total 0.676738 0.023406 -5 2 1 1 1 1 P1 total 0.270452 0.013885 -6 2 1 1 1 1 P2 total 0.107918 0.005840 -7 2 1 1 1 1 P3 total 0.016160 0.004108 -12 2 2 1 1 1 P0 total 0.673350 0.021192 -13 2 2 1 1 1 P1 total 0.264330 0.009415 -14 2 2 1 1 1 P2 total 0.093703 0.004850 -15 2 2 1 1 1 P3 total 0.019800 0.005236 - mesh 1 group in group out nuclide mean std. dev. - x y z -0 1 1 1 1 1 total 1.000000 0.036767 -2 1 2 1 1 1 total 1.000266 0.042769 -1 2 1 1 1 1 total 1.000000 0.034289 -3 2 2 1 1 1 total 1.000000 0.022887 +0 1 1 1 1 1 P0 total 0.679832 0.030426 +1 1 1 1 1 1 P1 total 0.255665 0.011704 +2 1 1 1 1 1 P2 total 0.087020 0.005603 +3 1 1 1 1 1 P3 total 0.006425 0.005919 +8 1 2 1 1 1 P0 total 0.663143 0.019088 +9 1 2 1 1 1 P1 total 0.257945 0.010887 +10 1 2 1 1 1 P2 total 0.095395 0.006988 +11 1 2 1 1 1 P3 total 0.009816 0.003950 +4 2 1 1 1 1 P0 total 0.679503 0.026695 +5 2 1 1 1 1 P1 total 0.254500 0.009901 +6 2 1 1 1 1 P2 total 0.093289 0.005481 +7 2 1 1 1 1 P3 total 0.004631 0.004081 +12 2 2 1 1 1 P0 total 0.681909 0.032740 +13 2 2 1 1 1 P1 total 0.263176 0.012659 +14 2 2 1 1 1 P2 total 0.093102 0.006603 +15 2 2 1 1 1 P3 total 0.007938 0.005673 + mesh 1 group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 total 1.0 0.041183 +2 1 2 1 1 1 total 1.0 0.021636 +1 2 1 1 1 1 total 1.0 0.046661 +3 2 2 1 1 1 total 1.0 0.041512 mesh 1 group in group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.025263 0.001825 -2 1 2 1 1 1 total 0.021868 0.001931 -1 2 1 1 1 1 total 0.025960 0.002413 -3 2 2 1 1 1 total 0.028694 0.002815 +0 1 1 1 1 1 total 0.027090 0.002808 +2 1 2 1 1 1 total 0.031522 0.004261 +1 2 1 1 1 1 total 0.021855 0.001457 +3 2 2 1 1 1 total 0.028262 0.002358 mesh 1 group in group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 1.0 0.036767 -2 1 2 1 1 1 total 1.0 0.042878 -1 2 1 1 1 1 total 1.0 0.034289 -3 2 2 1 1 1 total 1.0 0.022887 +0 1 1 1 1 1 total 1.0 0.041183 +2 1 2 1 1 1 total 1.0 0.021636 +1 2 1 1 1 1 total 1.0 0.046661 +3 2 2 1 1 1 total 1.0 0.041512 mesh 1 group in group out legendre nuclide mean std. dev. x y z -0 1 1 1 1 1 P0 total 0.671959 0.030658 -1 1 1 1 1 1 P1 total 0.253435 0.010587 -2 1 1 1 1 1 P2 total 0.083831 0.005499 -3 1 1 1 1 1 P3 total 0.006845 0.005509 -8 1 2 1 1 1 P0 total 0.673678 0.035391 -9 1 2 1 1 1 P1 total 0.261422 0.014724 -10 1 2 1 1 1 P2 total 0.107915 0.006058 -11 1 2 1 1 1 P3 total 0.014674 0.004843 -4 2 1 1 1 1 P0 total 0.672277 0.031784 -5 2 1 1 1 1 P1 total 0.268669 0.016287 -6 2 1 1 1 1 P2 total 0.107206 0.006753 -7 2 1 1 1 1 P3 total 0.016054 0.004114 -12 2 2 1 1 1 P0 total 0.675378 0.033896 -13 2 2 1 1 1 P1 total 0.265126 0.014021 -14 2 2 1 1 1 P2 total 0.093985 0.006096 -15 2 2 1 1 1 P3 total 0.019860 0.005309 +0 1 1 1 1 1 P0 total 0.677411 0.039336 +1 1 1 1 1 1 P1 total 0.254754 0.014995 +2 1 1 1 1 1 P2 total 0.086711 0.006439 +3 1 1 1 1 1 P3 total 0.006402 0.005903 +8 1 2 1 1 1 P0 total 0.666009 0.028990 +9 1 2 1 1 1 P1 total 0.259060 0.013824 +10 1 2 1 1 1 P2 total 0.095807 0.007684 +11 1 2 1 1 1 P3 total 0.009858 0.003980 +4 2 1 1 1 1 P0 total 0.691140 0.036991 +5 2 1 1 1 1 P1 total 0.258859 0.013782 +6 2 1 1 1 1 P2 total 0.094887 0.006555 +7 2 1 1 1 1 P3 total 0.004710 0.004154 +12 2 2 1 1 1 P0 total 0.680525 0.039486 +13 2 2 1 1 1 P1 total 0.262642 0.015259 +14 2 2 1 1 1 P2 total 0.092913 0.007251 +15 2 2 1 1 1 P3 total 0.007921 0.005668 mesh 1 group in group out legendre nuclide mean std. dev. x y z -0 1 1 1 1 1 P0 total 0.671959 0.039374 -1 1 1 1 1 1 P1 total 0.253435 0.014104 -2 1 1 1 1 1 P2 total 0.083831 0.006304 -3 1 1 1 1 1 P3 total 0.006845 0.005515 -8 1 2 1 1 1 P0 total 0.673857 0.045644 -9 1 2 1 1 1 P1 total 0.261492 0.018491 -10 1 2 1 1 1 P2 total 0.107944 0.007617 -11 1 2 1 1 1 P3 total 0.014678 0.004885 -4 2 1 1 1 1 P0 total 0.672277 0.039263 -5 2 1 1 1 1 P1 total 0.268669 0.018712 -6 2 1 1 1 1 P2 total 0.107206 0.007689 -7 2 1 1 1 1 P3 total 0.016054 0.004150 -12 2 2 1 1 1 P0 total 0.675378 0.037254 -13 2 2 1 1 1 P1 total 0.265126 0.015278 -14 2 2 1 1 1 P2 total 0.093985 0.006465 -15 2 2 1 1 1 P3 total 0.019860 0.005328 +0 1 1 1 1 1 P0 total 0.677411 0.048224 +1 1 1 1 1 1 P1 total 0.254754 0.018301 +2 1 1 1 1 1 P2 total 0.086711 0.007363 +3 1 1 1 1 1 P3 total 0.006402 0.005909 +8 1 2 1 1 1 P0 total 0.666009 0.032374 +9 1 2 1 1 1 P1 total 0.259060 0.014917 +10 1 2 1 1 1 P2 total 0.095807 0.007958 +11 1 2 1 1 1 P3 total 0.009858 0.003985 +4 2 1 1 1 1 P0 total 0.691140 0.049075 +5 2 1 1 1 1 P1 total 0.258859 0.018326 +6 2 1 1 1 1 P2 total 0.094887 0.007910 +7 2 1 1 1 1 P3 total 0.004710 0.004160 +12 2 2 1 1 1 P0 total 0.680525 0.048551 +13 2 2 1 1 1 P1 total 0.262642 0.018754 +14 2 2 1 1 1 P2 total 0.092913 0.008213 +15 2 2 1 1 1 P3 total 0.007921 0.005677 mesh 1 group out nuclide mean std. dev. x y z -0 1 1 1 1 total 1.0 0.080776 -2 1 2 1 1 total 1.0 0.117674 -1 2 1 1 1 total 1.0 0.160576 -3 2 2 1 1 total 1.0 0.151384 +0 1 1 1 1 total 1.0 0.103333 +2 1 2 1 1 total 1.0 0.118582 +1 2 1 1 1 total 1.0 0.112144 +3 2 2 1 1 total 1.0 0.130701 mesh 1 group out nuclide mean std. dev. x y z -0 1 1 1 1 total 1.0 0.080742 -2 1 2 1 1 total 1.0 0.117674 -1 2 1 1 1 total 1.0 0.160576 -3 2 2 1 1 total 1.0 0.150417 +0 1 1 1 1 total 1.0 0.103333 +2 1 2 1 1 total 1.0 0.118582 +1 2 1 1 1 total 1.0 0.112144 +3 2 2 1 1 total 1.0 0.130701 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 4.800872e-07 2.910230e-08 -2 1 2 1 1 total 5.007997e-07 3.613803e-08 -1 2 1 1 1 total 4.872635e-07 4.324235e-08 -3 2 2 1 1 total 4.890451e-07 2.833017e-08 +0 1 1 1 1 total 5.304285e-07 2.560239e-08 +2 1 2 1 1 total 4.940321e-07 2.410417e-08 +1 2 1 1 1 total 5.587365e-07 3.382787e-08 +3 2 2 1 1 total 5.232210e-07 2.482800e-08 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.024194 0.001614 -2 1 2 1 1 total 0.024397 0.002081 -1 2 1 1 1 total 0.024017 0.002793 -3 2 2 1 1 total 0.024501 0.002276 +0 1 1 1 1 total 0.026032 0.001172 +2 1 2 1 1 total 0.025542 0.001086 +1 2 1 1 1 total 0.029121 0.001254 +3 2 2 1 1 total 0.025271 0.001329 mesh 1 group in group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.024899 0.001762 -2 1 2 1 1 1 total 0.021868 0.001931 -1 2 1 1 1 1 total 0.025960 0.002413 -3 2 2 1 1 1 total 0.028508 0.002818 +0 1 1 1 1 1 total 0.027090 0.002808 +2 1 2 1 1 1 total 0.031522 0.004261 +1 2 1 1 1 1 total 0.021855 0.001457 +3 2 2 1 1 1 total 0.028262 0.002358 mesh 1 group in nuclide mean std. dev. x y surf -3 1 1 x-max in 1 total 4.520 0.122262 -2 1 1 x-max out 1 total 4.486 0.128841 +3 1 1 x-max in 1 total 4.280 0.164469 +2 1 1 x-max out 1 total 4.250 0.107135 1 1 1 x-min in 1 total 0.000 0.000000 0 1 1 x-min out 1 total 0.000 0.000000 -7 1 1 y-max in 1 total 4.406 0.116576 -6 1 1 y-max out 1 total 4.436 0.064637 +7 1 1 y-max in 1 total 4.364 0.105622 +6 1 1 y-max out 1 total 4.412 0.158019 5 1 1 y-min in 1 total 0.000 0.000000 4 1 1 y-min out 1 total 0.000 0.000000 -19 1 2 x-max in 1 total 4.460 0.122752 -18 1 2 x-max out 1 total 4.480 0.162721 +19 1 2 x-max in 1 total 4.388 0.102470 +18 1 2 x-max out 1 total 4.428 0.140228 17 1 2 x-min in 1 total 0.000 0.000000 16 1 2 x-min out 1 total 0.000 0.000000 23 1 2 y-max in 1 total 0.000 0.000000 22 1 2 y-max out 1 total 0.000 0.000000 -21 1 2 y-min in 1 total 4.436 0.064637 -20 1 2 y-min out 1 total 4.406 0.116576 +21 1 2 y-min in 1 total 4.412 0.158019 +20 1 2 y-min out 1 total 4.364 0.105622 11 2 1 x-max in 1 total 0.000 0.000000 10 2 1 x-max out 1 total 0.000 0.000000 -9 2 1 x-min in 1 total 4.486 0.128841 -8 2 1 x-min out 1 total 4.520 0.122262 -15 2 1 y-max in 1 total 4.548 0.156691 -14 2 1 y-max out 1 total 4.526 0.166571 +9 2 1 x-min in 1 total 4.250 0.107135 +8 2 1 x-min out 1 total 4.280 0.164469 +15 2 1 y-max in 1 total 4.402 0.182565 +14 2 1 y-max out 1 total 4.346 0.148189 13 2 1 y-min in 1 total 0.000 0.000000 12 2 1 y-min out 1 total 0.000 0.000000 27 2 2 x-max in 1 total 0.000 0.000000 26 2 2 x-max out 1 total 0.000 0.000000 -25 2 2 x-min in 1 total 4.480 0.162721 -24 2 2 x-min out 1 total 4.460 0.122752 +25 2 2 x-min in 1 total 4.428 0.140228 +24 2 2 x-min out 1 total 4.388 0.102470 31 2 2 y-max in 1 total 0.000 0.000000 30 2 2 y-max out 1 total 0.000 0.000000 -29 2 2 y-min in 1 total 4.526 0.166571 -28 2 2 y-min out 1 total 4.548 0.156691 +29 2 2 y-min in 1 total 4.346 0.148189 +28 2 2 y-min out 1 total 4.402 0.182565 mesh 1 group in nuclide mean std. dev. x y z -1 1 1 1 0 total 1.039567 0.052248 -0 1 1 1 1 total 0.289572 0.043864 -5 1 2 1 0 total 1.079961 0.085600 -4 1 2 1 1 total 0.304543 0.038994 -3 2 1 1 0 total 1.088126 0.082813 -2 2 1 1 1 total 0.304326 0.051269 -7 2 2 1 0 total 1.037036 0.121171 -6 2 2 1 1 total 0.308008 0.027855 +0 1 1 1 1 total 0.950616 0.095874 +2 1 2 1 1 total 0.932532 0.086323 +1 2 1 1 1 total 0.885723 0.041074 +3 2 2 1 1 total 0.951783 0.101570 mesh 1 group in nuclide mean std. dev. x y z -1 1 1 1 0 total 1.039567 0.052248 -0 1 1 1 1 total 0.289572 0.043864 -5 1 2 1 0 total 1.079555 0.085584 -4 1 2 1 1 total 0.304543 0.038994 -3 2 1 1 0 total 1.088126 0.082813 -2 2 1 1 1 total 0.304326 0.051269 -7 2 2 1 0 total 1.037036 0.121171 -6 2 2 1 1 total 0.308008 0.027855 +0 1 1 1 1 total 0.950616 0.095874 +2 1 2 1 1 total 0.932532 0.086323 +1 2 1 1 1 total 0.885723 0.041074 +3 2 2 1 1 total 0.951783 0.101570 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.000006 3.699363e-07 -1 1 1 1 2 1 total 0.000030 1.914853e-06 -2 1 1 1 3 1 total 0.000029 1.834339e-06 -3 1 1 1 4 1 total 0.000068 4.149880e-06 -4 1 1 1 5 1 total 0.000030 1.769320e-06 -5 1 1 1 6 1 total 0.000013 7.382097e-07 -12 1 2 1 1 1 total 0.000006 4.767315e-07 -13 1 2 1 2 1 total 0.000030 2.471571e-06 -14 1 2 1 3 1 total 0.000029 2.368041e-06 -15 1 2 1 4 1 total 0.000068 5.351482e-06 -16 1 2 1 5 1 total 0.000030 2.259042e-06 -17 1 2 1 6 1 total 0.000013 9.436237e-07 -6 2 1 1 1 1 total 0.000005 6.400406e-07 -7 2 1 1 2 1 total 0.000029 3.309040e-06 -8 2 1 1 3 1 total 0.000029 3.163385e-06 -9 2 1 1 4 1 total 0.000067 7.114281e-06 -10 2 1 1 5 1 total 0.000030 2.951164e-06 -11 2 1 1 6 1 total 0.000012 1.234794e-06 -18 2 2 1 1 1 total 0.000006 5.212824e-07 -19 2 2 1 2 1 total 0.000030 2.712206e-06 -20 2 2 1 3 1 total 0.000029 2.604912e-06 -21 2 2 1 4 1 total 0.000068 5.914482e-06 -22 2 2 1 5 1 total 0.000030 2.531950e-06 -23 2 2 1 6 1 total 0.000013 1.056326e-06 +0 1 1 1 1 1 total 0.000006 2.679142e-07 +1 1 1 1 2 1 total 0.000032 1.417723e-06 +2 1 1 1 3 1 total 0.000031 1.376260e-06 +3 1 1 1 4 1 total 0.000072 3.185580e-06 +4 1 1 1 5 1 total 0.000032 1.433425e-06 +5 1 1 1 6 1 total 0.000013 5.956400e-07 +12 1 2 1 1 1 total 0.000006 2.486865e-07 +13 1 2 1 2 1 total 0.000031 1.323941e-06 +14 1 2 1 3 1 total 0.000030 1.292803e-06 +15 1 2 1 4 1 total 0.000071 3.032740e-06 +16 1 2 1 5 1 total 0.000031 1.426193e-06 +17 1 2 1 6 1 total 0.000013 5.903673e-07 +6 2 1 1 1 1 total 0.000007 2.871910e-07 +7 2 1 1 2 1 total 0.000035 1.501590e-06 +8 2 1 1 3 1 total 0.000034 1.448170e-06 +9 2 1 1 4 1 total 0.000079 3.318195e-06 +10 2 1 1 5 1 total 0.000035 1.465737e-06 +11 2 1 1 6 1 total 0.000015 6.097547e-07 +18 2 2 1 1 1 total 0.000006 3.042761e-07 +19 2 2 1 2 1 total 0.000031 1.603780e-06 +20 2 2 1 3 1 total 0.000030 1.553523e-06 +21 2 2 1 4 1 total 0.000070 3.583849e-06 +22 2 2 1 5 1 total 0.000031 1.602620e-06 +23 2 2 1 6 1 total 0.000013 6.662067e-07 mesh 1 delayedgroup group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.0 0.000000 -1 1 1 1 2 1 total 0.0 0.000000 -2 1 1 1 3 1 total 0.0 0.000000 -3 1 1 1 4 1 total 1.0 1.414214 -4 1 1 1 5 1 total 1.0 1.414214 -5 1 1 1 6 1 total 0.0 0.000000 -12 1 2 1 1 1 total 0.0 0.000000 -13 1 2 1 2 1 total 0.0 0.000000 -14 1 2 1 3 1 total 0.0 0.000000 -15 1 2 1 4 1 total 0.0 0.000000 -16 1 2 1 5 1 total 0.0 0.000000 -17 1 2 1 6 1 total 0.0 0.000000 -6 2 1 1 1 1 total 0.0 0.000000 -7 2 1 1 2 1 total 0.0 0.000000 -8 2 1 1 3 1 total 0.0 0.000000 -9 2 1 1 4 1 total 0.0 0.000000 -10 2 1 1 5 1 total 0.0 0.000000 -11 2 1 1 6 1 total 0.0 0.000000 -18 2 2 1 1 1 total 0.0 0.000000 -19 2 2 1 2 1 total 1.0 1.414214 -20 2 2 1 3 1 total 0.0 0.000000 -21 2 2 1 4 1 total 0.0 0.000000 -22 2 2 1 5 1 total 0.0 0.000000 -23 2 2 1 6 1 total 0.0 0.000000 +0 1 1 1 1 1 total 0.0 0.0 +1 1 1 1 2 1 total 0.0 0.0 +2 1 1 1 3 1 total 0.0 0.0 +3 1 1 1 4 1 total 0.0 0.0 +4 1 1 1 5 1 total 0.0 0.0 +5 1 1 1 6 1 total 0.0 0.0 +12 1 2 1 1 1 total 0.0 0.0 +13 1 2 1 2 1 total 0.0 0.0 +14 1 2 1 3 1 total 0.0 0.0 +15 1 2 1 4 1 total 0.0 0.0 +16 1 2 1 5 1 total 0.0 0.0 +17 1 2 1 6 1 total 0.0 0.0 +6 2 1 1 1 1 total 0.0 0.0 +7 2 1 1 2 1 total 0.0 0.0 +8 2 1 1 3 1 total 0.0 0.0 +9 2 1 1 4 1 total 0.0 0.0 +10 2 1 1 5 1 total 0.0 0.0 +11 2 1 1 6 1 total 0.0 0.0 +18 2 2 1 1 1 total 0.0 0.0 +19 2 2 1 2 1 total 0.0 0.0 +20 2 2 1 3 1 total 0.0 0.0 +21 2 2 1 4 1 total 0.0 0.0 +22 2 2 1 5 1 total 0.0 0.0 +23 2 2 1 6 1 total 0.0 0.0 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.000227 0.000021 -1 1 1 1 2 1 total 0.001219 0.000109 -2 1 1 1 3 1 total 0.001191 0.000106 -3 1 1 1 4 1 total 0.002775 0.000243 -4 1 1 1 5 1 total 0.001249 0.000106 -5 1 1 1 6 1 total 0.000519 0.000044 -12 1 2 1 1 1 total 0.000227 0.000026 -13 1 2 1 2 1 total 0.001216 0.000140 -14 1 2 1 3 1 total 0.001187 0.000135 -15 1 2 1 4 1 total 0.002760 0.000309 -16 1 2 1 5 1 total 0.001236 0.000135 -17 1 2 1 6 1 total 0.000514 0.000056 -6 2 1 1 1 1 total 0.000227 0.000037 -7 2 1 1 2 1 total 0.001215 0.000194 -8 2 1 1 3 1 total 0.001184 0.000187 -9 2 1 1 4 1 total 0.002749 0.000428 -10 2 1 1 5 1 total 0.001227 0.000185 -11 2 1 1 6 1 total 0.000511 0.000077 -18 2 2 1 1 1 total 0.000227 0.000027 -19 2 2 1 2 1 total 0.001215 0.000145 -20 2 2 1 3 1 total 0.001185 0.000140 -21 2 2 1 4 1 total 0.002752 0.000321 -22 2 2 1 5 1 total 0.001229 0.000140 -23 2 2 1 6 1 total 0.000511 0.000058 +0 1 1 1 1 1 total 0.000227 0.000011 +1 1 1 1 2 1 total 0.001212 0.000058 +2 1 1 1 3 1 total 0.001180 0.000057 +3 1 1 1 4 1 total 0.002734 0.000131 +4 1 1 1 5 1 total 0.001215 0.000059 +5 1 1 1 6 1 total 0.000506 0.000024 +12 1 2 1 1 1 total 0.000227 0.000010 +13 1 2 1 2 1 total 0.001213 0.000052 +14 1 2 1 3 1 total 0.001182 0.000051 +15 1 2 1 4 1 total 0.002744 0.000120 +16 1 2 1 5 1 total 0.001223 0.000056 +17 1 2 1 6 1 total 0.000509 0.000023 +6 2 1 1 1 1 total 0.000227 0.000013 +7 2 1 1 2 1 total 0.001207 0.000067 +8 2 1 1 3 1 total 0.001173 0.000065 +9 2 1 1 4 1 total 0.002710 0.000150 +10 2 1 1 5 1 total 0.001195 0.000066 +11 2 1 1 6 1 total 0.000498 0.000027 +18 2 2 1 1 1 total 0.000227 0.000014 +19 2 2 1 2 1 total 0.001212 0.000073 +20 2 2 1 3 1 total 0.001180 0.000071 +21 2 2 1 4 1 total 0.002740 0.000163 +22 2 2 1 5 1 total 0.001221 0.000073 +23 2 2 1 6 1 total 0.000508 0.000030 mesh 1 delayedgroup nuclide mean std. dev. x y z -0 1 1 1 1 total 0.013357 0.001250 -1 1 1 1 2 total 0.032589 0.002884 -2 1 1 1 3 total 0.121105 0.010300 -3 1 1 1 4 total 0.306138 0.024490 -4 1 1 1 5 total 0.862757 0.061312 -5 1 1 1 6 total 2.897868 0.207582 -12 1 2 1 1 total 0.013356 0.001625 -13 1 2 1 2 total 0.032597 0.003869 -14 1 2 1 3 total 0.121088 0.014125 -15 1 2 1 4 total 0.305963 0.034783 -16 1 2 1 5 total 0.862125 0.093434 -17 1 2 1 6 total 2.895716 0.314825 -6 2 1 1 1 total 0.013355 0.002181 -7 2 1 1 2 total 0.032604 0.005141 -8 2 1 1 3 total 0.121074 0.018615 -9 2 1 1 4 total 0.305828 0.045169 -10 2 1 1 5 total 0.861633 0.116817 -11 2 1 1 6 total 2.894042 0.394847 -18 2 2 1 1 total 0.013355 0.001620 -19 2 2 1 2 total 0.032602 0.003798 -20 2 2 1 3 total 0.121077 0.013715 -21 2 2 1 4 total 0.305857 0.033214 -22 2 2 1 5 total 0.861740 0.086567 -23 2 2 1 6 total 2.894407 0.292238 - mesh 1 delayedgroup group in group out nuclide mean std. dev. - x y z -0 1 1 1 1 1 1 total 0.000000 0.000000 -1 1 1 1 2 1 1 total 0.000000 0.000000 -2 1 1 1 3 1 1 total 0.000000 0.000000 -3 1 1 1 4 1 1 total 0.000172 0.000172 -4 1 1 1 5 1 1 total 0.000192 0.000192 -5 1 1 1 6 1 1 total 0.000000 0.000000 -12 1 2 1 1 1 1 total 0.000000 0.000000 -13 1 2 1 2 1 1 total 0.000000 0.000000 -14 1 2 1 3 1 1 total 0.000000 0.000000 -15 1 2 1 4 1 1 total 0.000000 0.000000 -16 1 2 1 5 1 1 total 0.000000 0.000000 -17 1 2 1 6 1 1 total 0.000000 0.000000 -6 2 1 1 1 1 1 total 0.000000 0.000000 -7 2 1 1 2 1 1 total 0.000000 0.000000 -8 2 1 1 3 1 1 total 0.000000 0.000000 -9 2 1 1 4 1 1 total 0.000000 0.000000 -10 2 1 1 5 1 1 total 0.000000 0.000000 -11 2 1 1 6 1 1 total 0.000000 0.000000 -18 2 2 1 1 1 1 total 0.000000 0.000000 -19 2 2 1 2 1 1 total 0.000186 0.000186 -20 2 2 1 3 1 1 total 0.000000 0.000000 -21 2 2 1 4 1 1 total 0.000000 0.000000 -22 2 2 1 5 1 1 total 0.000000 0.000000 -23 2 2 1 6 1 1 total 0.000000 0.000000 +0 1 1 1 1 total 0.013354 0.000674 +1 1 1 1 2 total 0.032612 0.001720 +2 1 1 1 3 total 0.121057 0.006579 +3 1 1 1 4 total 0.305656 0.017398 +4 1 1 1 5 total 0.861000 0.053768 +5 1 1 1 6 total 2.891889 0.179407 +12 1 2 1 1 total 0.013354 0.000497 +13 1 2 1 2 total 0.032605 0.001150 +14 1 2 1 3 total 0.121071 0.004175 +15 1 2 1 4 total 0.305792 0.010484 +16 1 2 1 5 total 0.861500 0.032627 +17 1 2 1 6 total 2.893589 0.108347 +6 2 1 1 1 total 0.013352 0.000663 +7 2 1 1 2 total 0.032625 0.001570 +8 2 1 1 3 total 0.121029 0.005721 +9 2 1 1 4 total 0.305375 0.014144 +10 2 1 1 5 total 0.859955 0.039608 +11 2 1 1 6 total 2.888337 0.132844 +18 2 2 1 1 total 0.013354 0.000892 +19 2 2 1 2 total 0.032606 0.002209 +20 2 2 1 3 total 0.121069 0.008302 +21 2 2 1 4 total 0.305776 0.021416 +22 2 2 1 5 total 0.861442 0.063571 +23 2 2 1 6 total 2.893392 0.212640 + mesh 1 delayedgroup group in group out nuclide mean std. dev. + x y z +0 1 1 1 1 1 1 total 0.0 0.0 +1 1 1 1 2 1 1 total 0.0 0.0 +2 1 1 1 3 1 1 total 0.0 0.0 +3 1 1 1 4 1 1 total 0.0 0.0 +4 1 1 1 5 1 1 total 0.0 0.0 +5 1 1 1 6 1 1 total 0.0 0.0 +12 1 2 1 1 1 1 total 0.0 0.0 +13 1 2 1 2 1 1 total 0.0 0.0 +14 1 2 1 3 1 1 total 0.0 0.0 +15 1 2 1 4 1 1 total 0.0 0.0 +16 1 2 1 5 1 1 total 0.0 0.0 +17 1 2 1 6 1 1 total 0.0 0.0 +6 2 1 1 1 1 1 total 0.0 0.0 +7 2 1 1 2 1 1 total 0.0 0.0 +8 2 1 1 3 1 1 total 0.0 0.0 +9 2 1 1 4 1 1 total 0.0 0.0 +10 2 1 1 5 1 1 total 0.0 0.0 +11 2 1 1 6 1 1 total 0.0 0.0 +18 2 2 1 1 1 1 total 0.0 0.0 +19 2 2 1 2 1 1 total 0.0 0.0 +20 2 2 1 3 1 1 total 0.0 0.0 +21 2 2 1 4 1 1 total 0.0 0.0 +22 2 2 1 5 1 1 total 0.0 0.0 +23 2 2 1 6 1 1 total 0.0 0.0 diff --git a/tests/regression_tests/mgxs_library_correction/inputs_true.dat b/tests/regression_tests/mgxs_library_correction/inputs_true.dat index 8c1cd4d1657..ea2d1b714a2 100644 --- a/tests/regression_tests/mgxs_library_correction/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_correction/inputs_true.dat @@ -1,344 +1,346 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 0 - - - 2 - - - 3 - - - 1 2 - total - flux - analog - - - 1 2 3 4 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 3 4 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 3 12 - total - scatter - analog - - - 1 3 4 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 3 12 - total - scatter - analog - - - 1 2 3 - total - nu-scatter - analog - - - 1 3 4 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 19 2 - total - flux - analog - - - 19 2 3 4 - total - scatter - analog - - - 19 2 - total - flux - analog - - - 19 2 3 4 - total - nu-scatter - analog - - - 19 2 - total - flux - tracklength - - - 19 2 - total - scatter - tracklength - - - 19 2 3 12 - total - scatter - analog - - - 19 3 4 - total - scatter - analog - - - 19 2 - total - flux - analog - - - 19 2 - total - flux - tracklength - - - 19 2 - total - scatter - tracklength - - - 19 2 3 12 - total - scatter - analog - - - 19 2 3 - total - nu-scatter - analog - - - 19 3 4 - total - nu-scatter - analog - - - 19 2 - total - flux - analog - - - 37 2 - total - flux - analog - - - 37 2 3 4 - total - scatter - analog - - - 37 2 - total - flux - analog - - - 37 2 3 4 - total - nu-scatter - analog - - - 37 2 - total - flux - tracklength - - - 37 2 - total - scatter - tracklength - - - 37 2 3 12 - total - scatter - analog - - - 37 3 4 - total - scatter - analog - - - 37 2 - total - flux - analog - - - 37 2 - total - flux - tracklength - - - 37 2 - total - scatter - tracklength - - - 37 2 3 12 - total - scatter - analog - - - 37 2 3 - total - nu-scatter - analog - - - 37 3 4 - total - nu-scatter - analog - - - 37 2 - total - flux - analog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 0 + + + 2 + + + 3 + + + 1 2 + total + flux + analog + + + 1 2 3 4 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 3 4 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 3 12 + total + scatter + analog + + + 1 3 4 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 3 12 + total + scatter + analog + + + 1 2 3 + total + nu-scatter + analog + + + 1 3 4 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 19 2 + total + flux + analog + + + 19 2 3 4 + total + scatter + analog + + + 19 2 + total + flux + analog + + + 19 2 3 4 + total + nu-scatter + analog + + + 19 2 + total + flux + tracklength + + + 19 2 + total + scatter + tracklength + + + 19 2 3 12 + total + scatter + analog + + + 19 3 4 + total + scatter + analog + + + 19 2 + total + flux + analog + + + 19 2 + total + flux + tracklength + + + 19 2 + total + scatter + tracklength + + + 19 2 3 12 + total + scatter + analog + + + 19 2 3 + total + nu-scatter + analog + + + 19 3 4 + total + nu-scatter + analog + + + 19 2 + total + flux + analog + + + 37 2 + total + flux + analog + + + 37 2 3 4 + total + scatter + analog + + + 37 2 + total + flux + analog + + + 37 2 3 4 + total + nu-scatter + analog + + + 37 2 + total + flux + tracklength + + + 37 2 + total + scatter + tracklength + + + 37 2 3 12 + total + scatter + analog + + + 37 3 4 + total + scatter + analog + + + 37 2 + total + flux + analog + + + 37 2 + total + flux + tracklength + + + 37 2 + total + scatter + tracklength + + + 37 2 3 12 + total + scatter + analog + + + 37 2 3 + total + nu-scatter + analog + + + 37 3 4 + total + nu-scatter + analog + + + 37 2 + total + flux + analog + + + diff --git a/tests/regression_tests/mgxs_library_correction/results_true.dat b/tests/regression_tests/mgxs_library_correction/results_true.dat index 690c9e4dca2..ff4bd974634 100644 --- a/tests/regression_tests/mgxs_library_correction/results_true.dat +++ b/tests/regression_tests/mgxs_library_correction/results_true.dat @@ -1,60 +1,60 @@ material group in group out nuclide mean std. dev. -3 1 1 1 total 0.353219 0.011858 -2 1 1 2 total 0.000876 0.000554 +3 1 1 1 total 0.342252 0.023795 +2 1 1 2 total 0.000695 0.000327 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 0.367572 0.024736 +0 1 2 2 total 0.388426 0.020840 material group in group out nuclide mean std. dev. -3 1 1 1 total 0.353488 0.011854 -2 1 1 2 total 0.000876 0.000554 +3 1 1 1 total 0.342252 0.023795 +2 1 1 2 total 0.000695 0.000327 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 0.367572 0.024736 +0 1 2 2 total 0.388426 0.020840 material group in group out nuclide mean std. dev. -3 1 1 1 total 0.350138 0.017141 -2 1 1 2 total 0.000869 0.000551 +3 1 1 1 total 0.343021 0.031016 +2 1 1 2 total 0.000697 0.000329 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 0.378130 0.046663 +0 1 2 2 total 0.376544 0.025156 material group in group out nuclide mean std. dev. -3 1 1 1 total 0.350406 0.018910 -2 1 1 2 total 0.000869 0.000953 +3 1 1 1 total 0.343021 0.039761 +2 1 1 2 total 0.000697 0.000566 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 0.378130 0.057580 +0 1 2 2 total 0.376544 0.032140 material group in group out nuclide mean std. dev. -3 2 1 1 total 0.272853 0.018051 -2 2 1 2 total 0.000486 0.000486 +3 2 1 1 total 0.271174 0.022374 +2 2 1 2 total 0.000000 0.000000 1 2 2 1 total 0.000000 0.000000 -0 2 2 2 total 0.287308 0.063393 +0 2 2 2 total 0.295401 0.032831 material group in group out nuclide mean std. dev. -3 2 1 1 total 0.272853 0.018051 -2 2 1 2 total 0.000486 0.000486 +3 2 1 1 total 0.271174 0.022374 +2 2 1 2 total 0.000000 0.000000 1 2 2 1 total 0.000000 0.000000 -0 2 2 2 total 0.287308 0.063393 +0 2 2 2 total 0.295401 0.032831 material group in group out nuclide mean std. dev. -3 2 1 1 total 0.273465 0.021487 -2 2 1 2 total 0.000487 0.000487 +3 2 1 1 total 0.264654 0.028288 +2 2 1 2 total 0.000000 0.000000 1 2 2 1 total 0.000000 0.000000 -0 2 2 2 total 0.294966 0.065882 +0 2 2 2 total 0.295178 0.032530 material group in group out nuclide mean std. dev. -3 2 1 1 total 0.273465 0.025834 -2 2 1 2 total 0.000487 0.000843 +3 2 1 1 total 0.264654 0.036081 +2 2 1 2 total 0.000000 0.000000 1 2 2 1 total 0.000000 0.000000 -0 2 2 2 total 0.294966 0.089321 - material group in group out nuclide mean std. dev. -3 3 1 1 total 0.262301 0.012948 -2 3 1 2 total 0.029783 0.000974 -1 3 2 1 total 0.000000 0.000000 -0 3 2 2 total 1.418218 0.082199 - material group in group out nuclide mean std. dev. -3 3 1 1 total 0.262301 0.012948 -2 3 1 2 total 0.029783 0.000974 -1 3 2 1 total 0.000000 0.000000 -0 3 2 2 total 1.418218 0.082199 - material group in group out nuclide mean std. dev. -3 3 1 1 total 0.261486 0.022535 -2 3 1 2 total 0.029746 0.001063 -1 3 2 1 total 0.000000 0.000000 -0 3 2 2 total 1.432958 0.149985 - material group in group out nuclide mean std. dev. -3 3 1 1 total 0.261486 0.026061 -2 3 1 2 total 0.029746 0.001468 -1 3 2 1 total 0.000000 0.000000 -0 3 2 2 total 1.432958 0.178757 +0 2 2 2 total 0.295178 0.044676 + material group in group out nuclide mean std. dev. +3 3 1 1 total 0.257831 0.014436 +2 3 1 2 total 0.030826 0.000973 +1 3 2 1 total 0.000467 0.000467 +0 3 2 2 total 1.443057 0.119909 + material group in group out nuclide mean std. dev. +3 3 1 1 total 0.257831 0.014436 +2 3 1 2 total 0.030826 0.000973 +1 3 2 1 total 0.000467 0.000467 +0 3 2 2 total 1.443057 0.119909 + material group in group out nuclide mean std. dev. +3 3 1 1 total 0.267025 0.029512 +2 3 1 2 total 0.031268 0.001416 +1 3 2 1 total 0.000466 0.000467 +0 3 2 2 total 1.440250 0.164573 + material group in group out nuclide mean std. dev. +3 3 1 1 total 0.267025 0.032860 +2 3 1 2 total 0.031268 0.001768 +1 3 2 1 total 0.000466 0.000808 +0 3 2 2 total 1.440250 0.212183 diff --git a/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat b/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat index 602e04abe0a..f1a60533491 100644 --- a/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat @@ -1,17 +1,43 @@ - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -29,484 +55,490 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -10.71 -10.71 -1 10.71 10.71 1 - - - - - - - 1 - - - 0.0 20000000.0 - - - 0.0 20000000.0 - - - 1 - - - 3 - - - 1 2 3 4 5 6 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 2 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 73 2 - total - delayed-nu-fission - tracklength - - - 1 73 2 - total - delayed-nu-fission - analog - - - 1 73 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 73 2 - total - delayed-nu-fission - tracklength - - - 1 73 - total - delayed-nu-fission - tracklength - - - 1 73 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 73 2 5 - total - delayed-nu-fission - analog - - + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -10.71 -10.71 -1 10.71 10.71 1 + + + true + + + + + + 1 + + + 0.0 20000000.0 + + + 0.0 20000000.0 + + + 1 + + + 3 + + + 1 2 3 4 5 6 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 2 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 75 2 + total + delayed-nu-fission + tracklength + + + 1 75 2 + total + delayed-nu-fission + analog + + + 1 75 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 75 2 + total + delayed-nu-fission + tracklength + + + 1 75 + total + delayed-nu-fission + tracklength + + + 1 75 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 75 2 5 + total + delayed-nu-fission + analog + + + diff --git a/tests/regression_tests/mgxs_library_distribcell/results_true.dat b/tests/regression_tests/mgxs_library_distribcell/results_true.dat index d72632245ca..ef7cb2b96b6 100644 --- a/tests/regression_tests/mgxs_library_distribcell/results_true.dat +++ b/tests/regression_tests/mgxs_library_distribcell/results_true.dat @@ -1,97 +1,97 @@ sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.450382 0.010238 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.455527 0.009851 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.413436 0.011349 - sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.413276 0.011357 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.409242 0.011118 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.06484 0.002514 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.40929 0.011119 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.066934 0.002424 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.066764 0.002423 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.028638 0.002713 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.028358 0.002669 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.036203 0.001449 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.038576 0.001526 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.089088 0.003536 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.094817 0.003725 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 7.011996e+06 280281.488034 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 7.470225e+06 295170.385185 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.385542 0.008566 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.388593 0.008156 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.386602 0.013718 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.388874 0.013889 sum(distribcell) group in group out legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.386439 0.013702 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.036946 0.004896 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.016245 0.003818 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.005544 0.003119 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.388711 0.013887 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.046285 0.005155 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.023632 0.003772 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.006997 0.003207 sum(distribcell) group in group out legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.386602 0.013718 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.037106 0.004917 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.016398 0.003839 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.005688 0.003138 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.388874 0.013889 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.046237 0.005156 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.023571 0.003775 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.007058 0.003207 sum(distribcell) group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.000421 0.036026 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.000418 0.036246 sum(distribcell) group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.083975 0.005759 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.092139 0.005956 sum(distribcell) group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.0 0.035985 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.0 0.036242 sum(distribcell) group in group out legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.385542 0.016305 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.036860 0.004958 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.016207 0.003827 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.005531 0.003114 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.388593 0.016275 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.046271 0.005251 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.023624 0.003806 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.006995 0.003209 sum(distribcell) group in group out legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.385704 0.021424 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.036876 0.005135 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.016214 0.003873 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.005533 0.003122 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P0 total 0.388755 0.021528 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P1 total 0.046290 0.005515 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P2 total 0.023634 0.003903 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 P3 total 0.006998 0.003221 sum(distribcell) group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 1.0 0.090473 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 1.0 0.084366 sum(distribcell) group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 1.0 0.090571 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 1.0 0.084331 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 4.896403e-07 2.047455e-08 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 5.253873e-07 2.168462e-08 sum(distribcell) group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.088451 0.003512 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.094147 0.003701 sum(distribcell) group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.082789 0.005683 - sum(distribcell) group in legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 P0 total 5.212993 1.398847 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 P1 total 0.806252 0.027980 - sum(distribcell) group in legendre nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 P0 total 5.226298 1.407011 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 P1 total 0.806564 0.028011 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.091593 0.005919 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.814514 0.022129 + sum(distribcell) group in nuclide mean std. dev. +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.814419 0.022125 sum(distribcell) delayedgroup group in nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.000020 8.047454e-07 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.000108 4.184372e-06 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.000106 4.014315e-06 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 0.000246 9.085237e-06 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.000111 3.832957e-06 -5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.000046 1.601490e-06 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.000021 8.473275e-07 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.000115 4.405467e-06 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.000112 4.225826e-06 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 0.000259 9.559952e-06 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.000115 4.025369e-06 +5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.000048 1.682226e-06 sum(distribcell) delayedgroup group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 1.0 1.414214 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.0 0.000000 1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.0 0.000000 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.0 0.000000 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 1.0 0.708218 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 1.0 1.414214 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 1.0 1.000002 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 1.0 1.414214 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.0 0.000000 5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.0 0.000000 sum(distribcell) delayedgroup group in nuclide mean std. dev. 0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 total 0.000227 0.000012 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.001216 0.000062 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.001187 0.000060 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 0.002764 0.000138 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.001241 0.000060 -5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.000516 0.000025 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 total 0.001210 0.000062 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 total 0.001177 0.000060 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 total 0.002728 0.000136 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 total 0.001211 0.000059 +5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 total 0.000504 0.000025 sum(distribcell) delayedgroup nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.013356 0.000697 -1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 total 0.032593 0.001644 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 total 0.121097 0.005963 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 total 0.306056 0.014519 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 total 0.862463 0.037889 -5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 total 2.896867 0.127967 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 total 0.013353 0.000692 +1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 total 0.032613 0.001644 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 total 0.121054 0.005983 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 total 0.305630 0.014645 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 total 0.860903 0.038693 +5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 total 2.891558 0.130564 sum(distribcell) delayedgroup group in group out nuclide mean std. dev. -0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 1 total 0.000189 0.000189 +0 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 1 1 1 total 0.000000 0.000000 1 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 2 1 1 total 0.000000 0.000000 -2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 1 total 0.000000 0.000000 -3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 1 total 0.000807 0.000405 -4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 1 total 0.000191 0.000191 +2 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 3 1 1 total 0.000362 0.000256 +3 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 4 1 1 total 0.000185 0.000185 +4 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 5 1 1 total 0.000000 0.000000 5 ((0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, ...),) 6 1 1 total 0.000000 0.000000 diff --git a/tests/regression_tests/mgxs_library_distribcell/test.py b/tests/regression_tests/mgxs_library_distribcell/test.py index 3b601161afc..fd6c8e93866 100644 --- a/tests/regression_tests/mgxs_library_distribcell/test.py +++ b/tests/regression_tests/mgxs_library_distribcell/test.py @@ -68,8 +68,6 @@ def _get_results(self, hash_output=False): return outstr -@pytest.mark.xfail(sys.version_info < (3, 6), - reason="Pandas 1.0 API changed and requires Python 3.6+") def test_mgxs_library_distribcell(): model = pwr_assembly() harness = MGXSTestHarness('statepoint.10.h5', model) diff --git a/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat b/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat index 9661cd46be5..8606e9fdda3 100644 --- a/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat @@ -1,502 +1,534 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - - - - - 2 2 - -100.0 -100.0 - 100.0 100.0 - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 3 - - - 0.0 20000000.0 - - - 1 - - - 1 2 3 4 5 6 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 52 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 52 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 66 2 - total - current - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 77 2 - total - delayed-nu-fission - tracklength - - - 1 77 52 - total - delayed-nu-fission - analog - - - 1 77 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 77 2 - total - delayed-nu-fission - tracklength - - - 1 77 - total - delayed-nu-fission - tracklength - - - 1 77 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 77 2 5 - total - delayed-nu-fission - analog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + + + + 2 2 + -100.0 -100.0 + 100.0 100.0 + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 1 + + + 1 2 3 4 5 6 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 54 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 54 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 68 2 + total + current + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 54 + total + delayed-nu-fission + analog + + + 1 79 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 + total + delayed-nu-fission + tracklength + + + 1 79 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 79 2 5 + total + delayed-nu-fission + analog + + + diff --git a/tests/regression_tests/mgxs_library_hdf5/results_true.dat b/tests/regression_tests/mgxs_library_hdf5/results_true.dat index bcea46925f2..b2ef8eae921 100644 --- a/tests/regression_tests/mgxs_library_hdf5/results_true.dat +++ b/tests/regression_tests/mgxs_library_hdf5/results_true.dat @@ -1,202 +1,201 @@ domain=1 type=total -[5.62093429e-01 1.47762208e+00] -[1.25813379e-02 1.33969236e-01] +[5.52629207e-01 1.46792426e+00] +[2.73983948e-02 9.30468557e-02] domain=1 type=transport -[3.20646457e-01 1.15112225e+00] -[1.43813685e-02 1.38168210e-01] +[3.09650231e-01 1.14528468e+00] +[2.96126059e-02 1.01957125e-01] domain=1 type=nu-transport -[3.20646457e-01 1.15112225e+00] -[1.43813685e-02 1.38168210e-01] +[3.09650231e-01 1.14528468e+00] +[2.96126059e-02 1.01957125e-01] domain=1 type=absorption -[9.18204614e-03 9.50890834e-02] -[1.02291781e-03 9.51211716e-03] +[7.90251362e-03 9.52195503e-02] +[7.77996866e-04 5.32017792e-03] +domain=1 type=reduced absorption +[7.88836875e-03 9.52195503e-02] +[7.77877367e-04 5.32017792e-03] domain=1 type=capture -[6.76780024e-03 4.04282690e-02] -[1.01848835e-03 8.89313901e-03] +[5.66271991e-03 4.03380329e-02] +[7.65494411e-04 4.41129849e-03] domain=1 type=fission -[2.41424590e-03 5.46608144e-02] -[4.85861462e-05 5.74352403e-03] +[2.23979371e-03 5.48815174e-02] +[1.44808204e-04 3.21965557e-03] domain=1 type=nu-fission -[6.13719950e-03 1.33192007e-01] -[1.12501202e-04 1.39952450e-02] +[5.70078167e-03 1.33729794e-01] +[3.71908758e-04 7.84533474e-03] domain=1 type=kappa-fission -[4.70267044e+05 1.05716969e+07] -[9.26434576e+03 1.11082859e+06] +[4.36283087e+05 1.06143820e+07] +[2.81939099e+04 6.22698786e+05] domain=1 type=scatter -[5.52911383e-01 1.38253299e+00] -[1.21249866e-02 1.25146938e-01] +[5.44726693e-01 1.37270471e+00] +[2.67443307e-02 8.86578418e-02] domain=1 type=nu-scatter -[5.53262132e-01 1.38285128e+00] -[1.67013167e-02 1.47879104e-01] +[5.46058885e-01 1.38608802e+00] +[2.72733439e-02 9.59957737e-02] domain=1 type=scatter matrix -[[[5.38262098e-01 2.41446972e-01 9.56713637e-02 1.27736375e-02] - [1.50000342e-02 3.45918070e-03 -2.20959984e-03 -2.07635400e-03]] +[[[5.25081070e-01 2.42978975e-01 9.65459393e-02 8.62265123e-03] + [2.09778151e-02 5.67750504e-03 -1.86093418e-03 -1.63034937e-03]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.38285128e+00 3.05915919e-01 2.70982432e-02 -1.60336325e-02]]] -[[[1.67044118e-02 6.96661310e-03 4.42653888e-03 5.36446548e-03] - [2.18467018e-03 6.35479378e-04 8.96740238e-04 4.72822150e-04]] + [1.38608802e+00 2.92665071e-01 4.65545679e-02 3.43129413e-03]]] +[[[2.68584158e-02 1.12354079e-02 5.95151250e-03 5.08213314e-03] + [1.69810442e-03 1.03379654e-03 3.35798077e-04 8.28775769e-04]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.47879104e-01 3.12865012e-02 2.09135204e-02 2.10640949e-02]]] + [9.59957737e-02 3.98634629e-02 1.79245433e-02 2.53788407e-02]]] domain=1 type=nu-scatter matrix -[[[5.38262098e-01 2.41446972e-01 9.56713637e-02 1.27736375e-02] - [1.50000342e-02 3.45918070e-03 -2.20959984e-03 -2.07635400e-03]] +[[[5.25081070e-01 2.42978975e-01 9.65459393e-02 8.62265123e-03] + [2.09778151e-02 5.67750504e-03 -1.86093418e-03 -1.63034937e-03]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.38285128e+00 3.05915919e-01 2.70982432e-02 -1.60336325e-02]]] -[[[1.67044118e-02 6.96661310e-03 4.42653888e-03 5.36446548e-03] - [2.18467018e-03 6.35479378e-04 8.96740238e-04 4.72822150e-04]] + [1.38608802e+00 2.92665071e-01 4.65545679e-02 3.43129413e-03]]] +[[[2.68584158e-02 1.12354079e-02 5.95151250e-03 5.08213314e-03] + [1.69810442e-03 1.03379654e-03 3.35798077e-04 8.28775769e-04]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.47879104e-01 3.12865012e-02 2.09135204e-02 2.10640949e-02]]] + [9.59957737e-02 3.98634629e-02 1.79245433e-02 2.53788407e-02]]] domain=1 type=multiplicity matrix [[1.00000000e+00 1.00000000e+00] [0.00000000e+00 1.00000000e+00]] -[[2.96568009e-02 2.03415491e-01] - [0.00000000e+00 1.02759493e-01]] +[[4.49973217e-02 9.94834121e-02] + [0.00000000e+00 8.90267353e-02]] domain=1 type=nu-fission matrix -[[4.80904641e-03 0.00000000e+00] - [1.46971102e-01 0.00000000e+00]] -[[7.56765200e-04 0.00000000e+00] - [1.60726822e-02 0.00000000e+00]] +[[6.79725552e-03 0.00000000e+00] + [1.34226308e-01 0.00000000e+00]] +[[1.39232734e-03 0.00000000e+00] + [1.55126210e-02 0.00000000e+00]] domain=1 type=scatter probability matrix -[[9.72888016e-01 2.71119843e-02] +[[9.61583236e-01 3.84167637e-02] [0.00000000e+00 1.00000000e+00]] -[[2.87160386e-02 3.94014457e-03] - [0.00000000e+00 1.02759493e-01]] +[[4.25251594e-02 2.94881301e-03] + [0.00000000e+00 8.90267353e-02]] domain=1 type=consistent scatter matrix -[[[5.37920858e-01 2.41293903e-01 9.56107113e-02 1.27655394e-02] - [1.49905247e-02 3.45698770e-03 -2.20819902e-03 -2.07503766e-03]] +[[[5.23800056e-01 2.42386192e-01 9.63104011e-02 8.60161499e-03] + [2.09266366e-02 5.66365392e-03 -1.85639416e-03 -1.62637189e-03]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.38253299e+00 3.05845506e-01 2.70920060e-02 -1.60299421e-02]]] -[[[1.97798945e-02 8.43331598e-03 4.80888930e-03 5.36697350e-03] - [2.20321323e-03 6.38726086e-04 8.97229401e-04 4.74291433e-04]] + [1.37270471e+00 2.89839256e-01 4.61050623e-02 3.39816342e-03]]] +[[[3.46115177e-02 1.51137129e-02 7.17487890e-03 5.08248710e-03] + [1.90677851e-03 1.05813829e-03 3.43862086e-04 8.29548315e-04]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.89328242e-01 4.07787000e-02 2.10367544e-02 2.11038436e-02]]] + [1.50979688e-01 4.66032426e-02 1.81833349e-02 2.51354735e-02]]] domain=1 type=consistent nu-scatter matrix -[[[5.37920858e-01 2.41293903e-01 9.56107113e-02 1.27655394e-02] - [1.49905247e-02 3.45698770e-03 -2.20819902e-03 -2.07503766e-03]] +[[[5.23800056e-01 2.42386192e-01 9.63104011e-02 8.60161499e-03] + [2.09266366e-02 5.66365392e-03 -1.85639416e-03 -1.62637189e-03]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [1.38253299e+00 3.05845506e-01 2.70920060e-02 -1.60299421e-02]]] -[[[2.54114701e-02 1.10602545e-02 5.58260879e-03 5.38030958e-03] - [3.76196879e-03 9.49983195e-04 1.00338675e-03 6.34914473e-04]] + [1.37270471e+00 2.89839256e-01 4.61050623e-02 3.39816342e-03]]] +[[[4.18746126e-02 1.86381616e-02 8.38211969e-03 5.09720340e-03] + [2.82310416e-03 1.19879975e-03 3.90317811e-04 8.45179676e-04]] [[0.00000000e+00 0.00000000e+00 0.00000000e+00 0.00000000e+00] - [2.36703634e-01 5.14845104e-02 2.12201666e-02 2.11680319e-02]]] + [1.94240879e-01 5.32698778e-02 1.86408495e-02 2.51372940e-02]]] domain=1 type=chi [1.00000000e+00 0.00000000e+00] -[8.07756455e-02 0.00000000e+00] +[1.03333203e-01 0.00000000e+00] domain=1 type=chi-prompt [1.00000000e+00 0.00000000e+00] -[8.07424611e-02 0.00000000e+00] +[1.03333203e-01 0.00000000e+00] domain=1 type=inverse-velocity -[5.93306434e-08 2.99151552e-06] -[3.31163681e-09 2.75470068e-07] +[5.72461488e-08 3.00999757e-06] +[2.80644407e-09 1.80993426e-07] domain=1 type=prompt-nu-fission -[6.07803967e-03 1.32325631e-01] -[1.12229103e-04 1.39042100e-02] +[5.64594959e-03 1.32859920e-01] +[3.68364598e-04 7.79430310e-03] domain=1 type=prompt-nu-fission matrix -[[4.80904641e-03 0.00000000e+00] - [1.44441596e-01 0.00000000e+00]] -[[7.56765200e-04 0.00000000e+00] - [1.55945206e-02 0.00000000e+00]] +[[6.79725552e-03 0.00000000e+00] + [1.34226308e-01 0.00000000e+00]] +[[1.39232734e-03 0.00000000e+00] + [1.55126210e-02 0.00000000e+00]] domain=1 type=current -[[[0.00000000e+00 0.00000000e+00 3.87200000e+00 3.85800000e+00 - 0.00000000e+00 0.00000000e+00 3.79800000e+00 3.79400000e+00] - [0.00000000e+00 0.00000000e+00 6.14000000e-01 6.62000000e-01 - 0.00000000e+00 0.00000000e+00 6.38000000e-01 6.12000000e-01]] - - [[3.85800000e+00 3.87200000e+00 0.00000000e+00 0.00000000e+00 - 0.00000000e+00 0.00000000e+00 3.87000000e+00 3.85400000e+00] - [6.62000000e-01 6.14000000e-01 0.00000000e+00 0.00000000e+00 - 0.00000000e+00 0.00000000e+00 6.56000000e-01 6.94000000e-01]] - - [[0.00000000e+00 0.00000000e+00 3.77200000e+00 3.82200000e+00 - 3.79400000e+00 3.79800000e+00 0.00000000e+00 0.00000000e+00] - [0.00000000e+00 0.00000000e+00 7.08000000e-01 6.38000000e-01 - 6.12000000e-01 6.38000000e-01 0.00000000e+00 0.00000000e+00]] - - [[3.82200000e+00 3.77200000e+00 0.00000000e+00 0.00000000e+00 - 3.85400000e+00 3.87000000e+00 0.00000000e+00 0.00000000e+00] - [6.38000000e-01 7.08000000e-01 0.00000000e+00 0.00000000e+00 - 6.94000000e-01 6.56000000e-01 0.00000000e+00 0.00000000e+00]]] -[[[0.00000000e+00 0.00000000e+00 1.14952164e-01 1.04661359e-01 - 0.00000000e+00 0.00000000e+00 5.36097006e-02 1.14873844e-01] - [0.00000000e+00 0.00000000e+00 5.81893461e-02 6.31981012e-02 - 0.00000000e+00 0.00000000e+00 3.61109402e-02 1.98494332e-02]] - - [[1.04661359e-01 1.14952164e-01 0.00000000e+00 0.00000000e+00 - 0.00000000e+00 0.00000000e+00 1.52643375e-01 1.35003704e-01] - [6.31981012e-02 5.81893461e-02 0.00000000e+00 0.00000000e+00 - 0.00000000e+00 0.00000000e+00 6.66783323e-02 7.95361553e-02]] - - [[0.00000000e+00 0.00000000e+00 1.58946532e-01 1.20971071e-01 - 1.14873844e-01 5.36097006e-02 0.00000000e+00 0.00000000e+00] - [0.00000000e+00 0.00000000e+00 3.48425028e-02 2.08326667e-02 - 1.98494332e-02 3.61109402e-02 0.00000000e+00 0.00000000e+00]] - - [[1.20971071e-01 1.58946532e-01 0.00000000e+00 0.00000000e+00 - 1.35003704e-01 1.52643375e-01 0.00000000e+00 0.00000000e+00] - [2.08326667e-02 3.48425028e-02 0.00000000e+00 0.00000000e+00 - 7.95361553e-02 6.66783323e-02 0.00000000e+00 0.00000000e+00]]] +[[[0.00000000e+00 0.00000000e+00 3.54200000e+00 3.59000000e+00 + 0.00000000e+00 0.00000000e+00 3.73400000e+00 3.69000000e+00] + [0.00000000e+00 0.00000000e+00 7.08000000e-01 6.90000000e-01 + 0.00000000e+00 0.00000000e+00 6.78000000e-01 6.74000000e-01]] + + [[3.59000000e+00 3.54200000e+00 0.00000000e+00 0.00000000e+00 + 0.00000000e+00 0.00000000e+00 3.65200000e+00 3.73800000e+00] + [6.90000000e-01 7.08000000e-01 0.00000000e+00 0.00000000e+00 + 0.00000000e+00 0.00000000e+00 6.94000000e-01 6.64000000e-01]] + + [[0.00000000e+00 0.00000000e+00 3.76000000e+00 3.66600000e+00 + 3.69000000e+00 3.73400000e+00 0.00000000e+00 0.00000000e+00] + [0.00000000e+00 0.00000000e+00 6.68000000e-01 7.22000000e-01 + 6.74000000e-01 6.78000000e-01 0.00000000e+00 0.00000000e+00]] + + [[3.66600000e+00 3.76000000e+00 0.00000000e+00 0.00000000e+00 + 3.73800000e+00 3.65200000e+00 0.00000000e+00 0.00000000e+00] + [7.22000000e-01 6.68000000e-01 0.00000000e+00 0.00000000e+00 + 6.64000000e-01 6.94000000e-01 0.00000000e+00 0.00000000e+00]]] +[[[0.00000000e+00 0.00000000e+00 1.04230514e-01 1.61183126e-01 + 0.00000000e+00 0.00000000e+00 1.50419414e-01 1.00498756e-01] + [0.00000000e+00 0.00000000e+00 2.47790234e-02 3.27108545e-02 + 0.00000000e+00 0.00000000e+00 4.84148737e-02 3.24961536e-02]] + + [[1.61183126e-01 1.04230514e-01 0.00000000e+00 0.00000000e+00 + 0.00000000e+00 0.00000000e+00 1.44201248e-01 1.81229137e-01] + [3.27108545e-02 2.47790234e-02 0.00000000e+00 0.00000000e+00 + 0.00000000e+00 0.00000000e+00 3.41467422e-02 2.20454077e-02]] + + [[0.00000000e+00 0.00000000e+00 1.39355660e-01 9.70875893e-02 + 1.00498756e-01 1.50419414e-01 0.00000000e+00 0.00000000e+00] + [0.00000000e+00 0.00000000e+00 1.56204994e-02 3.27719392e-02 + 3.24961536e-02 4.84148737e-02 0.00000000e+00 0.00000000e+00]] + + [[9.70875893e-02 1.39355660e-01 0.00000000e+00 0.00000000e+00 + 1.81229137e-01 1.44201248e-01 0.00000000e+00 0.00000000e+00] + [3.27719392e-02 1.56204994e-02 0.00000000e+00 0.00000000e+00 + 2.20454077e-02 3.41467422e-02 0.00000000e+00 0.00000000e+00]]] domain=1 type=diffusion-coefficient -[[2.89572488e-01 6.04647594e+01] - [1.03956656e+00 1.39871892e+01]] -[[4.38638506e-02 2.26850956e+03] - [5.22481383e-02 1.22780818e+01]] +[1.07648340e+00 2.91048451e-01] +[1.02946730e-01 2.59101197e-02] domain=1 type=nu-diffusion-coefficient -[[2.89572488e-01 6.04647594e+01] - [1.03956656e+00 1.39871892e+01]] -[[4.38638506e-02 2.26850956e+03] - [5.22481383e-02 1.22780818e+01]] +[1.07648340e+00 2.91048451e-01] +[1.02946730e-01 2.59101197e-02] domain=1 type=delayed-nu-fission -[[1.37840363e-06 3.03296462e-05] - [8.45663047e-06 1.56552364e-04] - [8.84043266e-06 1.49458552e-04] - [2.28234463e-05 3.35098665e-04] - [1.25147617e-05 1.37385990e-04] - [5.13410858e-06 5.75504990e-05]] -[[2.55826273e-08 3.18690909e-06] - [1.59619691e-07 1.64498503e-05] - [2.08725713e-07 1.57044628e-05] - [7.35913253e-07 3.52107280e-05] - [6.08970534e-07 1.44359288e-05] - [2.44376821e-07 6.04715887e-06]] +[[1.27862358e-06 3.04521075e-05] + [7.84219053e-06 1.57184471e-04] + [8.19703020e-06 1.50062017e-04] + [2.11585246e-05 3.36451683e-04] + [1.15983232e-05 1.37940708e-04] + [4.75823112e-06 5.77828684e-05]] +[[8.24665595e-08 1.78649023e-06] + [5.11270396e-07 9.22131636e-06] + [5.43215007e-07 8.80347339e-06] + [1.44919046e-06 1.97381285e-05] + [8.56858673e-07 8.09236929e-06] + [3.49663884e-07 3.38986452e-06]] domain=1 type=chi-delayed [[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00] - [1.00000000e+00 0.00000000e+00] - [1.00000000e+00 0.00000000e+00] + [0.00000000e+00 0.00000000e+00] + [0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00] - [1.41421356e+00 0.00000000e+00] - [1.41421356e+00 0.00000000e+00] + [0.00000000e+00 0.00000000e+00] + [0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]] domain=1 type=beta -[[2.24598146e-04 2.27713712e-04] - [1.37792986e-03 1.17538858e-03] - [1.44046689e-03 1.12212854e-03] - [3.71886987e-03 2.51590672e-03] - [2.03916489e-03 1.03148825e-03] - [8.36555595e-04 4.32086733e-04]] -[[2.89454288e-06 2.65002712e-05] - [1.83788053e-05 1.36786298e-04] - [2.80459046e-05 1.30588139e-04] - [1.09140523e-04 2.92789605e-04] - [9.54156078e-05 1.20039834e-04] - [3.82194001e-05 5.02842563e-05]] +[[2.24289169e-04 2.27713711e-04] + [1.37563425e-03 1.17538857e-03] + [1.43787829e-03 1.12212853e-03] + [3.71151288e-03 2.51590669e-03] + [2.03451453e-03 1.03148823e-03] + [8.34662928e-04 4.32086724e-04]] +[[1.75760869e-05 1.28957660e-05] + [1.08591736e-04 6.65640010e-05] + [1.14785004e-04 6.35478047e-05] + [3.03169937e-04 1.42479528e-04] + [1.75476030e-04 5.84147049e-05] + [7.17094876e-05 2.44697107e-05]] domain=1 type=decay-rate -[1.33568264e-02 3.25888950e-02 1.21105369e-01 3.06137651e-01 - 8.62756682e-01 2.89786766e+00] -[1.25011470e-03 2.88396059e-03 1.03002481e-02 2.44903689e-02 - 6.13119717e-02 2.07581680e-01] +[1.33535692e-02 3.26115957e-02 1.21057117e-01 3.05655911e-01 + 8.60999995e-01 2.89188863e+00] +[6.74373067e-04 1.71978136e-03 6.57917554e-03 1.73982053e-02 + 5.37683207e-02 1.79407115e-01] domain=1 type=delayed-nu-fission matrix [[[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]] @@ -208,10 +207,10 @@ domain=1 type=delayed-nu-fission matrix [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] - [1.19201367e-03 0.00000000e+00]] + [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] - [1.33749216e-03 0.00000000e+00]] + [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]]] @@ -225,10 +224,10 @@ domain=1 type=delayed-nu-fission matrix [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] - [1.19567703e-03 0.00000000e+00]] + [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] - [1.34160260e-03 0.00000000e+00]] + [0.00000000e+00 0.00000000e+00]] [[0.00000000e+00 0.00000000e+00] [0.00000000e+00 0.00000000e+00]]] diff --git a/tests/regression_tests/mgxs_library_hdf5/test.py b/tests/regression_tests/mgxs_library_hdf5/test.py index 2f3c9d149de..06625c25f9e 100644 --- a/tests/regression_tests/mgxs_library_hdf5/test.py +++ b/tests/regression_tests/mgxs_library_hdf5/test.py @@ -54,6 +54,11 @@ def _get_results(self, hash_output=False): # Export the MGXS Library to an HDF5 file self.mgxs_lib.build_hdf5_store(directory='.') + # Test export of the MGXS Library to an Excel spreadsheet + for mgxs in self.mgxs_lib.all_mgxs.values(): + for xs in mgxs.values(): + xs.export_xs_data('mgxs', xs_type='macro', format='excel') + # Open the MGXS HDF5 file with h5py.File('mgxs.h5', 'r') as f: @@ -76,9 +81,8 @@ def _get_results(self, hash_output=False): def _cleanup(self): super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) + files = ['mgxs.h5', 'mgxs.xlsx'] + (os.remove(f) for f in files if os.path.exists(f)) def test_mgxs_library_hdf5(): diff --git a/tests/regression_tests/mgxs_library_histogram/inputs_true.dat b/tests/regression_tests/mgxs_library_histogram/inputs_true.dat index d1bd197a7c9..013fcd0fa5f 100644 --- a/tests/regression_tests/mgxs_library_histogram/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_histogram/inputs_true.dat @@ -1,269 +1,271 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - -1.0 -0.8181818181818181 -0.6363636363636364 -0.4545454545454546 -0.2727272727272727 -0.09090909090909083 0.09090909090909083 0.2727272727272727 0.4545454545454546 0.6363636363636365 0.8181818181818183 1.0 - - - 2 - - - 3 - - - 1 2 - total - flux - analog - - - 1 2 3 4 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 3 4 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 3 4 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 3 4 - total - scatter - analog - - - 1 2 3 - total - nu-scatter - analog - - - 17 2 - total - flux - analog - - - 17 2 3 4 - total - scatter - analog - - - 17 2 - total - flux - analog - - - 17 2 3 4 - total - nu-scatter - analog - - - 17 2 - total - flux - tracklength - - - 17 2 - total - scatter - tracklength - - - 17 2 3 4 - total - scatter - analog - - - 17 2 - total - flux - tracklength - - - 17 2 - total - scatter - tracklength - - - 17 2 3 4 - total - scatter - analog - - - 17 2 3 - total - nu-scatter - analog - - - 33 2 - total - flux - analog - - - 33 2 3 4 - total - scatter - analog - - - 33 2 - total - flux - analog - - - 33 2 3 4 - total - nu-scatter - analog - - - 33 2 - total - flux - tracklength - - - 33 2 - total - scatter - tracklength - - - 33 2 3 4 - total - scatter - analog - - - 33 2 - total - flux - tracklength - - - 33 2 - total - scatter - tracklength - - - 33 2 3 4 - total - scatter - analog - - - 33 2 3 - total - nu-scatter - analog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + -1.0 -0.8181818181818181 -0.6363636363636364 -0.4545454545454546 -0.2727272727272727 -0.09090909090909083 0.09090909090909083 0.2727272727272727 0.4545454545454546 0.6363636363636365 0.8181818181818183 1.0 + + + 2 + + + 3 + + + 1 2 + total + flux + analog + + + 1 2 3 4 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 3 4 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 3 4 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 3 4 + total + scatter + analog + + + 1 2 3 + total + nu-scatter + analog + + + 17 2 + total + flux + analog + + + 17 2 3 4 + total + scatter + analog + + + 17 2 + total + flux + analog + + + 17 2 3 4 + total + nu-scatter + analog + + + 17 2 + total + flux + tracklength + + + 17 2 + total + scatter + tracklength + + + 17 2 3 4 + total + scatter + analog + + + 17 2 + total + flux + tracklength + + + 17 2 + total + scatter + tracklength + + + 17 2 3 4 + total + scatter + analog + + + 17 2 3 + total + nu-scatter + analog + + + 33 2 + total + flux + analog + + + 33 2 3 4 + total + scatter + analog + + + 33 2 + total + flux + analog + + + 33 2 3 4 + total + nu-scatter + analog + + + 33 2 + total + flux + tracklength + + + 33 2 + total + scatter + tracklength + + + 33 2 3 4 + total + scatter + analog + + + 33 2 + total + flux + tracklength + + + 33 2 + total + scatter + tracklength + + + 33 2 3 4 + total + scatter + analog + + + 33 2 3 + total + nu-scatter + analog + + + diff --git a/tests/regression_tests/mgxs_library_histogram/results_true.dat b/tests/regression_tests/mgxs_library_histogram/results_true.dat index 74ae456e5c4..2fa94cef589 100644 --- a/tests/regression_tests/mgxs_library_histogram/results_true.dat +++ b/tests/regression_tests/mgxs_library_histogram/results_true.dat @@ -1,25 +1,25 @@ material group in group out mu bin nuclide mean std. dev. -33 1 1 1 1 total 0.028385 0.002919 -34 1 1 1 2 total 0.031890 0.001548 -35 1 1 1 3 total 0.027684 0.002596 -36 1 1 1 4 total 0.035920 0.003337 -37 1 1 1 5 total 0.034343 0.001897 -38 1 1 1 6 total 0.032591 0.002289 -39 1 1 1 7 total 0.033467 0.002209 -40 1 1 1 8 total 0.031714 0.002398 -41 1 1 1 9 total 0.033467 0.003343 -42 1 1 1 10 total 0.041001 0.002362 -43 1 1 1 11 total 0.060801 0.003580 +33 1 1 1 1 total 0.032861 0.003703 +34 1 1 1 2 total 0.026428 0.003637 +35 1 1 1 3 total 0.029210 0.001648 +36 1 1 1 4 total 0.032513 0.004770 +37 1 1 1 5 total 0.030949 0.003129 +38 1 1 1 6 total 0.027124 0.004029 +39 1 1 1 7 total 0.030079 0.002186 +40 1 1 1 8 total 0.037034 0.002198 +41 1 1 1 9 total 0.038251 0.003825 +42 1 1 1 10 total 0.039294 0.003626 +43 1 1 1 11 total 0.062593 0.005934 22 1 1 2 1 total 0.000000 0.000000 -23 1 1 2 2 total 0.000350 0.000351 -24 1 1 2 3 total 0.000175 0.000175 -25 1 1 2 4 total 0.000000 0.000000 -26 1 1 2 5 total 0.000175 0.000175 +23 1 1 2 2 total 0.000174 0.000174 +24 1 1 2 3 total 0.000348 0.000213 +25 1 1 2 4 total 0.000174 0.000174 +26 1 1 2 5 total 0.000000 0.000000 27 1 1 2 6 total 0.000000 0.000000 28 1 1 2 7 total 0.000000 0.000000 29 1 1 2 8 total 0.000000 0.000000 30 1 1 2 9 total 0.000000 0.000000 -31 1 1 2 10 total 0.000175 0.000175 +31 1 1 2 10 total 0.000000 0.000000 32 1 1 2 11 total 0.000000 0.000000 11 1 2 1 1 total 0.000000 0.000000 12 1 2 1 2 total 0.000000 0.000000 @@ -32,39 +32,39 @@ 19 1 2 1 9 total 0.000000 0.000000 20 1 2 1 10 total 0.000000 0.000000 21 1 2 1 11 total 0.000000 0.000000 -0 1 2 2 1 total 0.023599 0.005270 -1 1 2 2 2 total 0.036471 0.008401 -2 1 2 2 3 total 0.034325 0.003271 -3 1 2 2 4 total 0.030035 0.003674 -4 1 2 2 5 total 0.039688 0.001478 -5 1 2 2 6 total 0.033253 0.005499 -6 1 2 2 7 total 0.039688 0.004725 -7 1 2 2 8 total 0.031107 0.006458 -8 1 2 2 9 total 0.031107 0.005996 -9 1 2 2 10 total 0.052560 0.005543 -10 1 2 2 11 total 0.033253 0.002688 +0 1 2 2 1 total 0.032383 0.006826 +1 1 2 2 2 total 0.037146 0.001158 +2 1 2 2 3 total 0.036193 0.004463 +3 1 2 2 4 total 0.036193 0.007028 +4 1 2 2 5 total 0.038098 0.006769 +5 1 2 2 6 total 0.024764 0.004638 +6 1 2 2 7 total 0.034288 0.008049 +7 1 2 2 8 total 0.040003 0.007350 +8 1 2 2 9 total 0.032383 0.003211 +9 1 2 2 10 total 0.050480 0.005824 +10 1 2 2 11 total 0.045718 0.013291 material group in group out mu bin nuclide mean std. dev. -33 1 1 1 1 total 0.028385 0.002919 -34 1 1 1 2 total 0.031890 0.001548 -35 1 1 1 3 total 0.027860 0.002738 -36 1 1 1 4 total 0.035920 0.003337 -37 1 1 1 5 total 0.034343 0.001897 -38 1 1 1 6 total 0.032591 0.002289 -39 1 1 1 7 total 0.033467 0.002209 -40 1 1 1 8 total 0.031714 0.002398 -41 1 1 1 9 total 0.033467 0.003343 -42 1 1 1 10 total 0.041001 0.002362 -43 1 1 1 11 total 0.060801 0.003580 +33 1 1 1 1 total 0.032861 0.003703 +34 1 1 1 2 total 0.026428 0.003637 +35 1 1 1 3 total 0.029210 0.001648 +36 1 1 1 4 total 0.032513 0.004770 +37 1 1 1 5 total 0.030949 0.003129 +38 1 1 1 6 total 0.027124 0.004029 +39 1 1 1 7 total 0.030079 0.002186 +40 1 1 1 8 total 0.037034 0.002198 +41 1 1 1 9 total 0.038251 0.003825 +42 1 1 1 10 total 0.039294 0.003626 +43 1 1 1 11 total 0.062593 0.005934 22 1 1 2 1 total 0.000000 0.000000 -23 1 1 2 2 total 0.000350 0.000351 -24 1 1 2 3 total 0.000175 0.000175 -25 1 1 2 4 total 0.000000 0.000000 -26 1 1 2 5 total 0.000175 0.000175 +23 1 1 2 2 total 0.000174 0.000174 +24 1 1 2 3 total 0.000348 0.000213 +25 1 1 2 4 total 0.000174 0.000174 +26 1 1 2 5 total 0.000000 0.000000 27 1 1 2 6 total 0.000000 0.000000 28 1 1 2 7 total 0.000000 0.000000 29 1 1 2 8 total 0.000000 0.000000 30 1 1 2 9 total 0.000000 0.000000 -31 1 1 2 10 total 0.000175 0.000175 +31 1 1 2 10 total 0.000000 0.000000 32 1 1 2 11 total 0.000000 0.000000 11 1 2 1 1 total 0.000000 0.000000 12 1 2 1 2 total 0.000000 0.000000 @@ -77,39 +77,39 @@ 19 1 2 1 9 total 0.000000 0.000000 20 1 2 1 10 total 0.000000 0.000000 21 1 2 1 11 total 0.000000 0.000000 -0 1 2 2 1 total 0.023599 0.005270 -1 1 2 2 2 total 0.036471 0.008401 -2 1 2 2 3 total 0.034325 0.003271 -3 1 2 2 4 total 0.030035 0.003674 -4 1 2 2 5 total 0.039688 0.001478 -5 1 2 2 6 total 0.033253 0.005499 -6 1 2 2 7 total 0.039688 0.004725 -7 1 2 2 8 total 0.031107 0.006458 -8 1 2 2 9 total 0.031107 0.005996 -9 1 2 2 10 total 0.052560 0.005543 -10 1 2 2 11 total 0.033253 0.002688 +0 1 2 2 1 total 0.032383 0.006826 +1 1 2 2 2 total 0.037146 0.001158 +2 1 2 2 3 total 0.036193 0.004463 +3 1 2 2 4 total 0.036193 0.007028 +4 1 2 2 5 total 0.038098 0.006769 +5 1 2 2 6 total 0.024764 0.004638 +6 1 2 2 7 total 0.034288 0.008049 +7 1 2 2 8 total 0.040003 0.007350 +8 1 2 2 9 total 0.032383 0.003211 +9 1 2 2 10 total 0.050480 0.005824 +10 1 2 2 11 total 0.045718 0.013291 material group in group out mu bin nuclide mean std. dev. -33 1 1 1 1 total 0.028162 0.003056 -34 1 1 1 2 total 0.031639 0.001886 -35 1 1 1 3 total 0.027466 0.002746 -36 1 1 1 4 total 0.035637 0.003533 -37 1 1 1 5 total 0.034072 0.002221 -38 1 1 1 6 total 0.032334 0.002532 -39 1 1 1 7 total 0.033203 0.002475 -40 1 1 1 8 total 0.031465 0.002617 -41 1 1 1 9 total 0.033203 0.003510 -42 1 1 1 10 total 0.040678 0.002734 -43 1 1 1 11 total 0.060322 0.004120 +33 1 1 1 1 total 0.032927 0.003848 +34 1 1 1 2 total 0.026481 0.003736 +35 1 1 1 3 total 0.029268 0.001884 +36 1 1 1 4 total 0.032578 0.004885 +37 1 1 1 5 total 0.031010 0.003280 +38 1 1 1 6 total 0.027177 0.004124 +39 1 1 1 7 total 0.030139 0.002382 +40 1 1 1 8 total 0.037108 0.002485 +41 1 1 1 9 total 0.038327 0.004013 +42 1 1 1 10 total 0.039372 0.003833 +43 1 1 1 11 total 0.062717 0.006256 22 1 1 2 1 total 0.000000 0.000000 -23 1 1 2 2 total 0.000348 0.000348 -24 1 1 2 3 total 0.000174 0.000174 -25 1 1 2 4 total 0.000000 0.000000 -26 1 1 2 5 total 0.000174 0.000174 +23 1 1 2 2 total 0.000174 0.000174 +24 1 1 2 3 total 0.000348 0.000214 +25 1 1 2 4 total 0.000174 0.000174 +26 1 1 2 5 total 0.000000 0.000000 27 1 1 2 6 total 0.000000 0.000000 28 1 1 2 7 total 0.000000 0.000000 29 1 1 2 8 total 0.000000 0.000000 30 1 1 2 9 total 0.000000 0.000000 -31 1 1 2 10 total 0.000174 0.000174 +31 1 1 2 10 total 0.000000 0.000000 32 1 1 2 11 total 0.000000 0.000000 11 1 2 1 1 total 0.000000 0.000000 12 1 2 1 2 total 0.000000 0.000000 @@ -122,39 +122,39 @@ 19 1 2 1 9 total 0.000000 0.000000 20 1 2 1 10 total 0.000000 0.000000 21 1 2 1 11 total 0.000000 0.000000 -0 1 2 2 1 total 0.024246 0.005837 -1 1 2 2 2 total 0.037470 0.009265 -2 1 2 2 3 total 0.035266 0.004620 -3 1 2 2 4 total 0.030858 0.004684 -4 1 2 2 5 total 0.040777 0.003968 -5 1 2 2 6 total 0.034164 0.006431 -6 1 2 2 7 total 0.040777 0.006083 -7 1 2 2 8 total 0.031960 0.007230 -8 1 2 2 9 total 0.031960 0.006797 -9 1 2 2 10 total 0.054002 0.007483 -10 1 2 2 11 total 0.034164 0.004130 +0 1 2 2 1 total 0.031440 0.006860 +1 1 2 2 2 total 0.036063 0.002322 +2 1 2 2 3 total 0.035138 0.004763 +3 1 2 2 4 total 0.035138 0.007105 +4 1 2 2 5 total 0.036988 0.006894 +5 1 2 2 6 total 0.024042 0.004702 +6 1 2 2 7 total 0.033289 0.008036 +7 1 2 2 8 total 0.038837 0.007464 +8 1 2 2 9 total 0.031440 0.003585 +9 1 2 2 10 total 0.049009 0.006292 +10 1 2 2 11 total 0.044385 0.013144 material group in group out mu bin nuclide mean std. dev. -33 1 1 1 1 total 0.028174 0.003144 -34 1 1 1 2 total 0.031653 0.002058 -35 1 1 1 3 total 0.027479 0.002838 -36 1 1 1 4 total 0.035653 0.003654 -37 1 1 1 5 total 0.034088 0.002392 -38 1 1 1 6 total 0.032348 0.002668 -39 1 1 1 7 total 0.033218 0.002621 -40 1 1 1 8 total 0.031479 0.002742 -41 1 1 1 9 total 0.033218 0.003616 -42 1 1 1 10 total 0.040696 0.002931 -43 1 1 1 11 total 0.060349 0.004409 +33 1 1 1 1 total 0.032927 0.004236 +34 1 1 1 2 total 0.026481 0.003998 +35 1 1 1 3 total 0.029268 0.002455 +36 1 1 1 4 total 0.032578 0.005190 +37 1 1 1 5 total 0.031010 0.003679 +38 1 1 1 6 total 0.027177 0.004376 +39 1 1 1 7 total 0.030139 0.002881 +40 1 1 1 8 total 0.037108 0.003187 +41 1 1 1 9 total 0.038327 0.004511 +42 1 1 1 10 total 0.039372 0.004379 +43 1 1 1 11 total 0.062717 0.007108 22 1 1 2 1 total 0.000000 0.000000 -23 1 1 2 2 total 0.000348 0.000451 -24 1 1 2 3 total 0.000174 0.000225 -25 1 1 2 4 total 0.000000 0.000000 -26 1 1 2 5 total 0.000174 0.000225 +23 1 1 2 2 total 0.000174 0.000209 +24 1 1 2 3 total 0.000348 0.000315 +25 1 1 2 4 total 0.000174 0.000209 +26 1 1 2 5 total 0.000000 0.000000 27 1 1 2 6 total 0.000000 0.000000 28 1 1 2 7 total 0.000000 0.000000 29 1 1 2 8 total 0.000000 0.000000 30 1 1 2 9 total 0.000000 0.000000 -31 1 1 2 10 total 0.000174 0.000225 +31 1 1 2 10 total 0.000000 0.000000 32 1 1 2 11 total 0.000000 0.000000 11 1 2 1 1 total 0.000000 0.000000 12 1 2 1 2 total 0.000000 0.000000 @@ -167,29 +167,29 @@ 19 1 2 1 9 total 0.000000 0.000000 20 1 2 1 10 total 0.000000 0.000000 21 1 2 1 11 total 0.000000 0.000000 -0 1 2 2 1 total 0.024246 0.006112 -1 1 2 2 2 total 0.037470 0.009679 -2 1 2 2 3 total 0.035266 0.005319 -3 1 2 2 4 total 0.030858 0.005221 -4 1 2 2 5 total 0.040777 0.005003 -5 1 2 2 6 total 0.034164 0.006919 -6 1 2 2 7 total 0.040777 0.006803 -7 1 2 2 8 total 0.031960 0.007614 -8 1 2 2 9 total 0.031960 0.007205 -9 1 2 2 10 total 0.054002 0.008502 -10 1 2 2 11 total 0.034164 0.004856 +0 1 2 2 1 total 0.031440 0.007170 +1 1 2 2 2 total 0.036063 0.003334 +2 1 2 2 3 total 0.035138 0.005303 +3 1 2 2 4 total 0.035138 0.007478 +4 1 2 2 5 total 0.036988 0.007318 +5 1 2 2 6 total 0.024042 0.004965 +6 1 2 2 7 total 0.033289 0.008334 +7 1 2 2 8 total 0.038837 0.007896 +8 1 2 2 9 total 0.031440 0.004148 +9 1 2 2 10 total 0.049009 0.007083 +10 1 2 2 11 total 0.044385 0.013469 material group in group out mu bin nuclide mean std. dev. -33 2 1 1 1 total 0.025262 0.003309 -34 2 1 1 2 total 0.023805 0.004083 -35 2 1 1 3 total 0.027205 0.001631 -36 2 1 1 4 total 0.021376 0.003175 -37 2 1 1 5 total 0.017489 0.002412 -38 2 1 1 6 total 0.024291 0.002862 -39 2 1 1 7 total 0.029634 0.005250 -40 2 1 1 8 total 0.025262 0.001228 -41 2 1 1 9 total 0.028663 0.003403 -42 2 1 1 10 total 0.034493 0.004425 -43 2 1 1 11 total 0.052467 0.006227 +33 2 1 1 1 total 0.026798 0.002892 +34 2 1 1 2 total 0.021339 0.003475 +35 2 1 1 3 total 0.021835 0.003963 +36 2 1 1 4 total 0.018361 0.006133 +37 2 1 1 5 total 0.023820 0.003932 +38 2 1 1 6 total 0.025805 0.003808 +39 2 1 1 7 total 0.026798 0.002299 +40 2 1 1 8 total 0.029279 0.003939 +41 2 1 1 9 total 0.034738 0.004323 +42 2 1 1 10 total 0.032753 0.006086 +43 2 1 1 11 total 0.057069 0.003798 22 2 1 2 1 total 0.000000 0.000000 23 2 1 2 2 total 0.000000 0.000000 24 2 1 2 3 total 0.000000 0.000000 @@ -199,7 +199,7 @@ 28 2 1 2 7 total 0.000000 0.000000 29 2 1 2 8 total 0.000000 0.000000 30 2 1 2 9 total 0.000000 0.000000 -31 2 1 2 10 total 0.000486 0.000486 +31 2 1 2 10 total 0.000000 0.000000 32 2 1 2 11 total 0.000000 0.000000 11 2 2 1 1 total 0.000000 0.000000 12 2 2 1 2 total 0.000000 0.000000 @@ -212,29 +212,29 @@ 19 2 2 1 9 total 0.000000 0.000000 20 2 2 1 10 total 0.000000 0.000000 21 2 2 1 11 total 0.000000 0.000000 -0 2 2 2 1 total 0.032689 0.010313 -1 2 2 2 2 total 0.035958 0.011071 -2 2 2 2 3 total 0.019614 0.012398 -3 2 2 2 4 total 0.022883 0.009072 -4 2 2 2 5 total 0.009807 0.009926 -5 2 2 2 6 total 0.029420 0.011781 -6 2 2 2 7 total 0.032689 0.014602 -7 2 2 2 8 total 0.019614 0.006844 -8 2 2 2 9 total 0.032689 0.010313 -9 2 2 2 10 total 0.022883 0.009072 -10 2 2 2 11 total 0.029420 0.005650 +0 2 2 2 1 total 0.032254 0.009449 +1 2 2 2 2 total 0.018815 0.005569 +2 2 2 2 3 total 0.032254 0.009449 +3 2 2 2 4 total 0.024191 0.006844 +4 2 2 2 5 total 0.013439 0.008563 +5 2 2 2 6 total 0.024191 0.005365 +6 2 2 2 7 total 0.043005 0.010420 +7 2 2 2 8 total 0.032254 0.012710 +8 2 2 2 9 total 0.034942 0.007365 +9 2 2 2 10 total 0.021503 0.007051 +10 2 2 2 11 total 0.018815 0.008193 material group in group out mu bin nuclide mean std. dev. -33 2 1 1 1 total 0.025262 0.003309 -34 2 1 1 2 total 0.023805 0.004083 -35 2 1 1 3 total 0.027205 0.001631 -36 2 1 1 4 total 0.021376 0.003175 -37 2 1 1 5 total 0.017489 0.002412 -38 2 1 1 6 total 0.024291 0.002862 -39 2 1 1 7 total 0.029634 0.005250 -40 2 1 1 8 total 0.025262 0.001228 -41 2 1 1 9 total 0.028663 0.003403 -42 2 1 1 10 total 0.034493 0.004425 -43 2 1 1 11 total 0.052467 0.006227 +33 2 1 1 1 total 0.026798 0.002892 +34 2 1 1 2 total 0.021339 0.003475 +35 2 1 1 3 total 0.021835 0.003963 +36 2 1 1 4 total 0.018361 0.006133 +37 2 1 1 5 total 0.023820 0.003932 +38 2 1 1 6 total 0.025805 0.003808 +39 2 1 1 7 total 0.026798 0.002299 +40 2 1 1 8 total 0.029279 0.003939 +41 2 1 1 9 total 0.034738 0.004323 +42 2 1 1 10 total 0.032753 0.006086 +43 2 1 1 11 total 0.057069 0.003798 22 2 1 2 1 total 0.000000 0.000000 23 2 1 2 2 total 0.000000 0.000000 24 2 1 2 3 total 0.000000 0.000000 @@ -244,7 +244,7 @@ 28 2 1 2 7 total 0.000000 0.000000 29 2 1 2 8 total 0.000000 0.000000 30 2 1 2 9 total 0.000000 0.000000 -31 2 1 2 10 total 0.000486 0.000486 +31 2 1 2 10 total 0.000000 0.000000 32 2 1 2 11 total 0.000000 0.000000 11 2 2 1 1 total 0.000000 0.000000 12 2 2 1 2 total 0.000000 0.000000 @@ -257,29 +257,29 @@ 19 2 2 1 9 total 0.000000 0.000000 20 2 2 1 10 total 0.000000 0.000000 21 2 2 1 11 total 0.000000 0.000000 -0 2 2 2 1 total 0.032689 0.010313 -1 2 2 2 2 total 0.035958 0.011071 -2 2 2 2 3 total 0.019614 0.012398 -3 2 2 2 4 total 0.022883 0.009072 -4 2 2 2 5 total 0.009807 0.009926 -5 2 2 2 6 total 0.029420 0.011781 -6 2 2 2 7 total 0.032689 0.014602 -7 2 2 2 8 total 0.019614 0.006844 -8 2 2 2 9 total 0.032689 0.010313 -9 2 2 2 10 total 0.022883 0.009072 -10 2 2 2 11 total 0.029420 0.005650 +0 2 2 2 1 total 0.032254 0.009449 +1 2 2 2 2 total 0.018815 0.005569 +2 2 2 2 3 total 0.032254 0.009449 +3 2 2 2 4 total 0.024191 0.006844 +4 2 2 2 5 total 0.013439 0.008563 +5 2 2 2 6 total 0.024191 0.005365 +6 2 2 2 7 total 0.043005 0.010420 +7 2 2 2 8 total 0.032254 0.012710 +8 2 2 2 9 total 0.034942 0.007365 +9 2 2 2 10 total 0.021503 0.007051 +10 2 2 2 11 total 0.018815 0.008193 material group in group out mu bin nuclide mean std. dev. -33 2 1 1 1 total 0.025312 0.003469 -34 2 1 1 2 total 0.023852 0.004203 -35 2 1 1 3 total 0.027259 0.001971 -36 2 1 1 4 total 0.021418 0.003297 -37 2 1 1 5 total 0.017524 0.002518 -38 2 1 1 6 total 0.024339 0.003032 -39 2 1 1 7 total 0.029693 0.005395 -40 2 1 1 8 total 0.025312 0.001600 -41 2 1 1 9 total 0.028719 0.003602 -42 2 1 1 10 total 0.034561 0.004648 -43 2 1 1 11 total 0.052571 0.006591 +33 2 1 1 1 total 0.026249 0.003012 +34 2 1 1 2 total 0.020902 0.003500 +35 2 1 1 3 total 0.021388 0.003971 +36 2 1 1 4 total 0.017986 0.006048 +37 2 1 1 5 total 0.023333 0.003958 +38 2 1 1 6 total 0.025277 0.003858 +39 2 1 1 7 total 0.026249 0.002473 +40 2 1 1 8 total 0.028680 0.004017 +41 2 1 1 9 total 0.034027 0.004437 +42 2 1 1 10 total 0.032082 0.006091 +43 2 1 1 11 total 0.055901 0.004311 22 2 1 2 1 total 0.000000 0.000000 23 2 1 2 2 total 0.000000 0.000000 24 2 1 2 3 total 0.000000 0.000000 @@ -289,7 +289,7 @@ 28 2 1 2 7 total 0.000000 0.000000 29 2 1 2 8 total 0.000000 0.000000 30 2 1 2 9 total 0.000000 0.000000 -31 2 1 2 10 total 0.000487 0.000487 +31 2 1 2 10 total 0.000000 0.000000 32 2 1 2 11 total 0.000000 0.000000 11 2 2 1 1 total 0.000000 0.000000 12 2 2 1 2 total 0.000000 0.000000 @@ -302,29 +302,29 @@ 19 2 2 1 9 total 0.000000 0.000000 20 2 2 1 10 total 0.000000 0.000000 21 2 2 1 11 total 0.000000 0.000000 -0 2 2 2 1 total 0.033560 0.010222 -1 2 2 2 2 total 0.036916 0.010953 -2 2 2 2 3 total 0.020136 0.012619 -3 2 2 2 4 total 0.023492 0.009111 -4 2 2 2 5 total 0.010068 0.010157 -5 2 2 2 6 total 0.030204 0.011837 -6 2 2 2 7 total 0.033560 0.014735 -7 2 2 2 8 total 0.020136 0.006828 -8 2 2 2 9 total 0.033560 0.010222 -9 2 2 2 10 total 0.023492 0.009111 -10 2 2 2 11 total 0.030204 0.005242 +0 2 2 2 1 total 0.032230 0.009604 +1 2 2 2 2 total 0.018801 0.005658 +2 2 2 2 3 total 0.032230 0.009604 +3 2 2 2 4 total 0.024172 0.006964 +4 2 2 2 5 total 0.013429 0.008588 +5 2 2 2 6 total 0.024172 0.005520 +6 2 2 2 7 total 0.042973 0.010671 +7 2 2 2 8 total 0.032230 0.012821 +8 2 2 2 9 total 0.034915 0.007601 +9 2 2 2 10 total 0.021486 0.007142 +10 2 2 2 11 total 0.018801 0.008251 material group in group out mu bin nuclide mean std. dev. -33 2 1 1 1 total 0.025312 0.003700 -34 2 1 1 2 total 0.023852 0.004373 -35 2 1 1 3 total 0.027259 0.002407 -36 2 1 1 4 total 0.021418 0.003471 -37 2 1 1 5 total 0.017524 0.002670 -38 2 1 1 6 total 0.024339 0.003273 -39 2 1 1 7 total 0.029693 0.005602 -40 2 1 1 8 total 0.025312 0.002052 -41 2 1 1 9 total 0.028719 0.003886 -42 2 1 1 10 total 0.034561 0.004968 -43 2 1 1 11 total 0.052571 0.007110 +33 2 1 1 1 total 0.026249 0.003460 +34 2 1 1 2 total 0.020902 0.003754 +35 2 1 1 3 total 0.021388 0.004206 +36 2 1 1 4 total 0.017986 0.006160 +37 2 1 1 5 total 0.023333 0.004238 +38 2 1 1 6 total 0.025277 0.004192 +39 2 1 1 7 total 0.026249 0.003003 +40 2 1 1 8 total 0.028680 0.004427 +41 2 1 1 9 total 0.034027 0.004956 +42 2 1 1 10 total 0.032082 0.006437 +43 2 1 1 11 total 0.055901 0.005636 22 2 1 2 1 total 0.000000 0.000000 23 2 1 2 2 total 0.000000 0.000000 24 2 1 2 3 total 0.000000 0.000000 @@ -334,7 +334,7 @@ 28 2 1 2 7 total 0.000000 0.000000 29 2 1 2 8 total 0.000000 0.000000 30 2 1 2 9 total 0.000000 0.000000 -31 2 1 2 10 total 0.000487 0.000843 +31 2 1 2 10 total 0.000000 0.000000 32 2 1 2 11 total 0.000000 0.000000 11 2 2 1 1 total 0.000000 0.000000 12 2 2 1 2 total 0.000000 0.000000 @@ -347,40 +347,40 @@ 19 2 2 1 9 total 0.000000 0.000000 20 2 2 1 10 total 0.000000 0.000000 21 2 2 1 11 total 0.000000 0.000000 -0 2 2 2 1 total 0.033560 0.011889 -1 2 2 2 2 total 0.036916 0.012828 -2 2 2 2 3 total 0.020136 0.013135 -3 2 2 2 4 total 0.023492 0.010054 -4 2 2 2 5 total 0.010068 0.010319 -5 2 2 2 6 total 0.030204 0.013037 -6 2 2 2 7 total 0.033560 0.015937 -7 2 2 2 8 total 0.020136 0.007739 -8 2 2 2 9 total 0.033560 0.011889 -9 2 2 2 10 total 0.023492 0.010054 -10 2 2 2 11 total 0.030204 0.007573 +0 2 2 2 1 total 0.032230 0.010330 +1 2 2 2 2 total 0.018801 0.006077 +2 2 2 2 3 total 0.032230 0.010330 +3 2 2 2 4 total 0.024172 0.007526 +4 2 2 2 5 total 0.013429 0.008733 +5 2 2 2 6 total 0.024172 0.006213 +6 2 2 2 7 total 0.042973 0.011815 +7 2 2 2 8 total 0.032230 0.013373 +8 2 2 2 9 total 0.034915 0.008646 +9 2 2 2 10 total 0.021486 0.007579 +10 2 2 2 11 total 0.018801 0.008544 material group in group out mu bin nuclide mean std. dev. -33 3 1 1 1 total 0.008818 0.001587 -34 3 1 1 2 total 0.006389 0.000610 -35 3 1 1 3 total 0.007288 0.000775 -36 3 1 1 4 total 0.008008 0.001111 -37 3 1 1 5 total 0.007828 0.000452 -38 3 1 1 6 total 0.011247 0.000473 -39 3 1 1 7 total 0.039411 0.002111 -40 3 1 1 8 total 0.071443 0.002082 -41 3 1 1 9 total 0.115713 0.004165 -42 3 1 1 10 total 0.164662 0.005479 -43 3 1 1 11 total 0.214060 0.006189 -22 3 1 2 1 total 0.000360 0.000090 -23 3 1 2 2 total 0.000810 0.000169 -24 3 1 2 3 total 0.000810 0.000331 -25 3 1 2 4 total 0.001440 0.000332 -26 3 1 2 5 total 0.002339 0.000267 -27 3 1 2 6 total 0.003149 0.000256 -28 3 1 2 7 total 0.004409 0.000601 -29 3 1 2 8 total 0.004139 0.000398 -30 3 1 2 9 total 0.004769 0.000639 -31 3 1 2 10 total 0.004769 0.000453 -32 3 1 2 11 total 0.002789 0.000630 +33 3 1 1 1 total 0.007006 0.000692 +34 3 1 1 2 total 0.006819 0.000431 +35 3 1 1 3 total 0.005511 0.000591 +36 3 1 1 4 total 0.006165 0.000470 +37 3 1 1 5 total 0.007660 0.000919 +38 3 1 1 6 total 0.012237 0.000938 +39 3 1 1 7 total 0.040914 0.002235 +40 3 1 1 8 total 0.074356 0.001968 +41 3 1 1 9 total 0.121622 0.004662 +42 3 1 1 10 total 0.158707 0.004147 +43 3 1 1 11 total 0.200742 0.007791 +22 3 1 2 1 total 0.000187 0.000187 +23 3 1 2 2 total 0.001028 0.000096 +24 3 1 2 3 total 0.000841 0.000176 +25 3 1 2 4 total 0.000841 0.000310 +26 3 1 2 5 total 0.001308 0.000274 +27 3 1 2 6 total 0.003736 0.000538 +28 3 1 2 7 total 0.003830 0.000703 +29 3 1 2 8 total 0.006259 0.000452 +30 3 1 2 9 total 0.005231 0.000510 +31 3 1 2 10 total 0.005044 0.000440 +32 3 1 2 11 total 0.002522 0.000194 11 3 2 1 1 total 0.000000 0.000000 12 3 2 1 2 total 0.000000 0.000000 13 3 2 1 3 total 0.000000 0.000000 @@ -390,42 +390,42 @@ 17 3 2 1 7 total 0.000000 0.000000 18 3 2 1 8 total 0.000000 0.000000 19 3 2 1 9 total 0.000000 0.000000 -20 3 2 1 10 total 0.000000 0.000000 +20 3 2 1 10 total 0.000467 0.000467 21 3 2 1 11 total 0.000000 0.000000 -0 3 2 2 1 total 0.086327 0.004499 -1 3 2 2 2 total 0.088278 0.008634 -2 3 2 2 3 total 0.108275 0.008710 -3 3 2 2 4 total 0.115103 0.005859 -4 3 2 2 5 total 0.139489 0.012654 -5 3 2 2 6 total 0.152658 0.005193 -6 3 2 2 7 total 0.182897 0.007164 -7 3 2 2 8 total 0.202894 0.014663 -8 3 2 2 9 total 0.268249 0.019575 -9 3 2 2 10 total 0.294098 0.015467 -10 3 2 2 11 total 0.354088 0.012355 +0 3 2 2 1 total 0.084030 0.007630 +1 3 2 2 2 total 0.099902 0.010027 +2 3 2 2 3 total 0.112040 0.010928 +3 3 2 2 4 total 0.117642 0.008523 +4 3 2 2 5 total 0.139116 0.009002 +5 3 2 2 6 total 0.161057 0.013537 +6 3 2 2 7 total 0.180664 0.010135 +7 3 2 2 8 total 0.219411 0.014717 +8 3 2 2 9 total 0.239485 0.027005 +9 3 2 2 10 total 0.281033 0.021376 +10 3 2 2 11 total 0.369731 0.027200 material group in group out mu bin nuclide mean std. dev. -33 3 1 1 1 total 0.008818 0.001587 -34 3 1 1 2 total 0.006389 0.000610 -35 3 1 1 3 total 0.007288 0.000775 -36 3 1 1 4 total 0.008008 0.001111 -37 3 1 1 5 total 0.007828 0.000452 -38 3 1 1 6 total 0.011247 0.000473 -39 3 1 1 7 total 0.039411 0.002111 -40 3 1 1 8 total 0.071443 0.002082 -41 3 1 1 9 total 0.115713 0.004165 -42 3 1 1 10 total 0.164662 0.005479 -43 3 1 1 11 total 0.214060 0.006189 -22 3 1 2 1 total 0.000360 0.000090 -23 3 1 2 2 total 0.000810 0.000169 -24 3 1 2 3 total 0.000810 0.000331 -25 3 1 2 4 total 0.001440 0.000332 -26 3 1 2 5 total 0.002339 0.000267 -27 3 1 2 6 total 0.003149 0.000256 -28 3 1 2 7 total 0.004409 0.000601 -29 3 1 2 8 total 0.004139 0.000398 -30 3 1 2 9 total 0.004769 0.000639 -31 3 1 2 10 total 0.004769 0.000453 -32 3 1 2 11 total 0.002789 0.000630 +33 3 1 1 1 total 0.007006 0.000692 +34 3 1 1 2 total 0.006819 0.000431 +35 3 1 1 3 total 0.005511 0.000591 +36 3 1 1 4 total 0.006165 0.000470 +37 3 1 1 5 total 0.007660 0.000919 +38 3 1 1 6 total 0.012237 0.000938 +39 3 1 1 7 total 0.040914 0.002235 +40 3 1 1 8 total 0.074356 0.001968 +41 3 1 1 9 total 0.121622 0.004662 +42 3 1 1 10 total 0.158707 0.004147 +43 3 1 1 11 total 0.200742 0.007791 +22 3 1 2 1 total 0.000187 0.000187 +23 3 1 2 2 total 0.001028 0.000096 +24 3 1 2 3 total 0.000841 0.000176 +25 3 1 2 4 total 0.000841 0.000310 +26 3 1 2 5 total 0.001308 0.000274 +27 3 1 2 6 total 0.003736 0.000538 +28 3 1 2 7 total 0.003830 0.000703 +29 3 1 2 8 total 0.006259 0.000452 +30 3 1 2 9 total 0.005231 0.000510 +31 3 1 2 10 total 0.005044 0.000440 +32 3 1 2 11 total 0.002522 0.000194 11 3 2 1 1 total 0.000000 0.000000 12 3 2 1 2 total 0.000000 0.000000 13 3 2 1 3 total 0.000000 0.000000 @@ -435,42 +435,42 @@ 17 3 2 1 7 total 0.000000 0.000000 18 3 2 1 8 total 0.000000 0.000000 19 3 2 1 9 total 0.000000 0.000000 -20 3 2 1 10 total 0.000000 0.000000 +20 3 2 1 10 total 0.000467 0.000467 21 3 2 1 11 total 0.000000 0.000000 -0 3 2 2 1 total 0.086327 0.004499 -1 3 2 2 2 total 0.088278 0.008634 -2 3 2 2 3 total 0.108275 0.008710 -3 3 2 2 4 total 0.115103 0.005859 -4 3 2 2 5 total 0.139489 0.012654 -5 3 2 2 6 total 0.152658 0.005193 -6 3 2 2 7 total 0.182897 0.007164 -7 3 2 2 8 total 0.202894 0.014663 -8 3 2 2 9 total 0.268249 0.019575 -9 3 2 2 10 total 0.294098 0.015467 -10 3 2 2 11 total 0.354088 0.012355 +0 3 2 2 1 total 0.084030 0.007630 +1 3 2 2 2 total 0.099902 0.010027 +2 3 2 2 3 total 0.112040 0.010928 +3 3 2 2 4 total 0.117642 0.008523 +4 3 2 2 5 total 0.139116 0.009002 +5 3 2 2 6 total 0.161057 0.013537 +6 3 2 2 7 total 0.180664 0.010135 +7 3 2 2 8 total 0.219411 0.014717 +8 3 2 2 9 total 0.239485 0.027005 +9 3 2 2 10 total 0.281033 0.021376 +10 3 2 2 11 total 0.369731 0.027200 material group in group out mu bin nuclide mean std. dev. -33 3 1 1 1 total 0.008807 0.001589 -34 3 1 1 2 total 0.006381 0.000614 -35 3 1 1 3 total 0.007279 0.000779 -36 3 1 1 4 total 0.007998 0.001113 -37 3 1 1 5 total 0.007818 0.000461 -38 3 1 1 6 total 0.011233 0.000491 -39 3 1 1 7 total 0.039362 0.002160 -40 3 1 1 8 total 0.071354 0.002246 -41 3 1 1 9 total 0.115569 0.004381 -42 3 1 1 10 total 0.164456 0.005812 -43 3 1 1 11 total 0.213793 0.006684 -22 3 1 2 1 total 0.000359 0.000090 -23 3 1 2 2 total 0.000809 0.000169 -24 3 1 2 3 total 0.000809 0.000331 -25 3 1 2 4 total 0.001438 0.000332 -26 3 1 2 5 total 0.002337 0.000269 -27 3 1 2 6 total 0.003145 0.000259 -28 3 1 2 7 total 0.004403 0.000603 -29 3 1 2 8 total 0.004134 0.000400 -30 3 1 2 9 total 0.004763 0.000640 -31 3 1 2 10 total 0.004763 0.000456 -32 3 1 2 11 total 0.002786 0.000630 +33 3 1 1 1 total 0.007106 0.000737 +34 3 1 1 2 total 0.006917 0.000488 +35 3 1 1 3 total 0.005590 0.000624 +36 3 1 1 4 total 0.006254 0.000516 +37 3 1 1 5 total 0.007770 0.000964 +38 3 1 1 6 total 0.012412 0.001029 +39 3 1 1 7 total 0.041501 0.002618 +40 3 1 1 8 total 0.075421 0.003106 +41 3 1 1 9 total 0.123365 0.006125 +42 3 1 1 10 total 0.160981 0.006595 +43 3 1 1 11 total 0.203618 0.010185 +22 3 1 2 1 total 0.000190 0.000190 +23 3 1 2 2 total 0.001042 0.000103 +24 3 1 2 3 total 0.000853 0.000180 +25 3 1 2 4 total 0.000853 0.000316 +26 3 1 2 5 total 0.001327 0.000281 +27 3 1 2 6 total 0.003790 0.000559 +28 3 1 2 7 total 0.003885 0.000724 +29 3 1 2 8 total 0.006348 0.000500 +30 3 1 2 9 total 0.005306 0.000544 +31 3 1 2 10 total 0.005117 0.000475 +32 3 1 2 11 total 0.002558 0.000213 11 3 2 1 1 total 0.000000 0.000000 12 3 2 1 2 total 0.000000 0.000000 13 3 2 1 3 total 0.000000 0.000000 @@ -480,42 +480,42 @@ 17 3 2 1 7 total 0.000000 0.000000 18 3 2 1 8 total 0.000000 0.000000 19 3 2 1 9 total 0.000000 0.000000 -20 3 2 1 10 total 0.000000 0.000000 +20 3 2 1 10 total 0.000466 0.000467 21 3 2 1 11 total 0.000000 0.000000 -0 3 2 2 1 total 0.086966 0.006257 -1 3 2 2 2 total 0.088931 0.009752 -2 3 2 2 3 total 0.109076 0.010309 -3 3 2 2 4 total 0.115955 0.008241 -4 3 2 2 5 total 0.140521 0.014528 -5 3 2 2 6 total 0.153787 0.009249 -6 3 2 2 7 total 0.184250 0.011645 -7 3 2 2 8 total 0.204395 0.017916 -8 3 2 2 9 total 0.270233 0.023844 -9 3 2 2 10 total 0.296274 0.021418 -10 3 2 2 11 total 0.356708 0.021633 +0 3 2 2 1 total 0.083912 0.007782 +1 3 2 2 2 total 0.099762 0.010188 +2 3 2 2 3 total 0.111883 0.011115 +3 3 2 2 4 total 0.117477 0.008794 +4 3 2 2 5 total 0.138921 0.009363 +5 3 2 2 6 total 0.160831 0.013853 +6 3 2 2 7 total 0.180411 0.010676 +7 3 2 2 8 total 0.219104 0.015265 +8 3 2 2 9 total 0.239149 0.027341 +9 3 2 2 10 total 0.280639 0.021991 +10 3 2 2 11 total 0.369213 0.028038 material group in group out mu bin nuclide mean std. dev. -33 3 1 1 1 total 0.008807 0.001597 -34 3 1 1 2 total 0.006381 0.000625 -35 3 1 1 3 total 0.007279 0.000790 -36 3 1 1 4 total 0.007998 0.001123 -37 3 1 1 5 total 0.007818 0.000482 -38 3 1 1 6 total 0.011233 0.000531 -39 3 1 1 7 total 0.039362 0.002274 -40 3 1 1 8 total 0.071354 0.002589 -41 3 1 1 9 total 0.115569 0.004852 -42 3 1 1 10 total 0.164456 0.006526 -43 3 1 1 11 total 0.213793 0.007718 -22 3 1 2 1 total 0.000359 0.000092 -23 3 1 2 2 total 0.000809 0.000174 -24 3 1 2 3 total 0.000809 0.000333 -25 3 1 2 4 total 0.001438 0.000340 -26 3 1 2 5 total 0.002337 0.000295 -27 3 1 2 6 total 0.003145 0.000306 -28 3 1 2 7 total 0.004403 0.000645 -29 3 1 2 8 total 0.004134 0.000454 -30 3 1 2 9 total 0.004763 0.000686 -31 3 1 2 10 total 0.004763 0.000519 -32 3 1 2 11 total 0.002786 0.000646 +33 3 1 1 1 total 0.007106 0.000751 +34 3 1 1 2 total 0.006917 0.000509 +35 3 1 1 3 total 0.005590 0.000635 +36 3 1 1 4 total 0.006254 0.000532 +37 3 1 1 5 total 0.007770 0.000977 +38 3 1 1 6 total 0.012412 0.001060 +39 3 1 1 7 total 0.041501 0.002755 +40 3 1 1 8 total 0.075421 0.003475 +41 3 1 1 9 total 0.123365 0.006634 +42 3 1 1 10 total 0.160981 0.007387 +43 3 1 1 11 total 0.203618 0.011019 +22 3 1 2 1 total 0.000190 0.000190 +23 3 1 2 2 total 0.001042 0.000114 +24 3 1 2 3 total 0.000853 0.000185 +25 3 1 2 4 total 0.000853 0.000319 +26 3 1 2 5 total 0.001327 0.000288 +27 3 1 2 6 total 0.003790 0.000588 +28 3 1 2 7 total 0.003885 0.000748 +29 3 1 2 8 total 0.006348 0.000587 +30 3 1 2 9 total 0.005306 0.000601 +31 3 1 2 10 total 0.005117 0.000535 +32 3 1 2 11 total 0.002558 0.000246 11 3 2 1 1 total 0.000000 0.000000 12 3 2 1 2 total 0.000000 0.000000 13 3 2 1 3 total 0.000000 0.000000 @@ -525,16 +525,16 @@ 17 3 2 1 7 total 0.000000 0.000000 18 3 2 1 8 total 0.000000 0.000000 19 3 2 1 9 total 0.000000 0.000000 -20 3 2 1 10 total 0.000000 0.000000 +20 3 2 1 10 total 0.000466 0.000808 21 3 2 1 11 total 0.000000 0.000000 -0 3 2 2 1 total 0.086966 0.007070 -1 3 2 2 2 total 0.088931 0.010317 -2 3 2 2 3 total 0.109076 0.011105 -3 3 2 2 4 total 0.115955 0.009338 -4 3 2 2 5 total 0.140521 0.015472 -5 3 2 2 6 total 0.153787 0.010930 -6 3 2 2 7 total 0.184250 0.013575 -7 3 2 2 8 total 0.204395 0.019516 -8 3 2 2 9 total 0.270233 0.025947 -9 3 2 2 10 total 0.296274 0.024178 -10 3 2 2 11 total 0.356708 0.025503 +0 3 2 2 1 total 0.083912 0.008936 +1 3 2 2 2 total 0.099762 0.011448 +2 3 2 2 3 total 0.111883 0.012563 +3 3 2 2 4 total 0.117477 0.010731 +4 3 2 2 5 total 0.138921 0.011855 +5 3 2 2 6 total 0.160831 0.016211 +6 3 2 2 7 total 0.180411 0.014254 +7 3 2 2 8 total 0.219104 0.019093 +8 3 2 2 9 total 0.239149 0.030071 +9 3 2 2 10 total 0.280639 0.026447 +10 3 2 2 11 total 0.369213 0.034054 diff --git a/tests/regression_tests/mgxs_library_mesh/inputs_true.dat b/tests/regression_tests/mgxs_library_mesh/inputs_true.dat index 5cac8ecf428..bb9c99026d0 100644 --- a/tests/regression_tests/mgxs_library_mesh/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_mesh/inputs_true.dat @@ -1,482 +1,511 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - - 2 2 - -100.0 -100.0 - 100.0 100.0 - - - 1 - - - 0.0 20000000.0 - - - 0.0 20000000.0 - - - 1 - - - 3 - - - 1 - - - 1 2 3 4 5 6 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 2 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 66 2 - total - current - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 77 2 - total - delayed-nu-fission - tracklength - - - 1 77 2 - total - delayed-nu-fission - analog - - - 1 77 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 77 2 - total - delayed-nu-fission - tracklength - - - 1 77 - total - delayed-nu-fission - tracklength - - - 1 77 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 77 2 5 - total - delayed-nu-fission - analog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + 2 2 + -100.0 -100.0 + 100.0 100.0 + + + 1 + + + 0.0 20000000.0 + + + 0.0 20000000.0 + + + 1 + + + 3 + + + 1 + + + 1 2 3 4 5 6 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 2 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 68 2 + total + current + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 2 + total + delayed-nu-fission + analog + + + 1 79 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 79 2 + total + delayed-nu-fission + tracklength + + + 1 79 + total + delayed-nu-fission + tracklength + + + 1 79 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 79 2 5 + total + delayed-nu-fission + analog + + + diff --git a/tests/regression_tests/mgxs_library_mesh/results_true.dat b/tests/regression_tests/mgxs_library_mesh/results_true.dat index a56e8b0e962..b1e8ac003be 100644 --- a/tests/regression_tests/mgxs_library_mesh/results_true.dat +++ b/tests/regression_tests/mgxs_library_mesh/results_true.dat @@ -1,364 +1,362 @@ mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.102319 0.005483 -2 1 2 1 1 total 0.104659 0.002878 -1 2 1 1 1 total 0.107122 0.005105 -3 2 2 1 1 total 0.103856 0.003459 +0 1 1 1 1 total 0.102539 0.004894 +2 1 2 1 1 total 0.106476 0.007513 +1 2 1 1 1 total 0.101207 0.004814 +3 2 2 1 1 total 0.101733 0.004445 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.072455 0.005799 -2 1 2 1 1 total 0.072899 0.003254 -1 2 1 1 1 total 0.074187 0.005441 -3 2 2 1 1 total 0.074241 0.003779 +0 1 1 1 1 total 0.073423 0.005232 +2 1 2 1 1 total 0.077906 0.007749 +1 2 1 1 1 total 0.071315 0.005181 +3 2 2 1 1 total 0.071983 0.004856 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.072455 0.005799 -2 1 2 1 1 total 0.072912 0.003251 -1 2 1 1 1 total 0.074140 0.005442 -3 2 2 1 1 total 0.074192 0.003783 +0 1 1 1 1 total 0.073443 0.005235 +2 1 2 1 1 total 0.077909 0.007749 +1 2 1 1 1 total 0.071315 0.005181 +3 2 2 1 1 total 0.071928 0.004865 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.012943 0.000836 -2 1 2 1 1 total 0.013363 0.000553 -1 2 1 1 1 total 0.013980 0.000715 -3 2 2 1 1 total 0.013286 0.000621 +0 1 1 1 1 total 0.013089 0.000762 +2 1 2 1 1 total 0.013802 0.000950 +1 2 1 1 1 total 0.012818 0.000708 +3 2 2 1 1 total 0.012954 0.000699 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.001231 0.000979 -2 1 2 1 1 total 0.001332 0.000691 -1 2 1 1 1 total 0.001346 0.000770 -3 2 2 1 1 total 0.001258 0.000815 +0 1 1 1 1 total 0.013016 0.000761 +2 1 2 1 1 total 0.013715 0.000947 +1 2 1 1 1 total 0.012740 0.000707 +3 2 2 1 1 total 0.012886 0.000698 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.011712 0.000762 -2 1 2 1 1 total 0.012031 0.000468 -1 2 1 1 1 total 0.012635 0.000646 -3 2 2 1 1 total 0.012028 0.000556 +0 1 1 1 1 total 0.001244 0.000926 +2 1 2 1 1 total 0.001345 0.000851 +1 2 1 1 1 total 0.001196 0.000768 +3 2 2 1 1 total 0.001234 0.000843 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.030549 0.001995 -2 1 2 1 1 total 0.031338 0.001160 -1 2 1 1 1 total 0.032944 0.001703 -3 2 2 1 1 total 0.031480 0.001423 +0 1 1 1 1 total 0.011844 0.000690 +2 1 2 1 1 total 0.012457 0.000852 +1 2 1 1 1 total 0.011622 0.000636 +3 2 2 1 1 total 0.011719 0.000633 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 0.030919 0.001784 +2 1 2 1 1 total 0.032495 0.002202 +1 2 1 1 1 total 0.030363 0.001664 +3 2 2 1 1 total 0.030565 0.001671 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 2.265259e+06 147469.851100 -2 1 2 1 1 total 2.326873e+06 90605.035909 -1 2 1 1 1 total 2.443628e+06 124917.160682 -3 2 2 1 1 total 2.326322e+06 107513.428248 +0 1 1 1 1 total 2.290786e+06 133521.277651 +2 1 2 1 1 total 2.409292e+06 164752.430241 +1 2 1 1 1 total 2.247742e+06 123005.689035 +3 2 2 1 1 total 2.266603e+06 122428.448367 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.089376 0.004670 -2 1 2 1 1 total 0.091296 0.002370 -1 2 1 1 1 total 0.093142 0.004401 -3 2 2 1 1 total 0.090570 0.002842 +0 1 1 1 1 total 0.089450 0.004147 +2 1 2 1 1 total 0.092674 0.006571 +1 2 1 1 1 total 0.088389 0.004152 +3 2 2 1 1 total 0.088779 0.003763 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.089670 0.005421 -2 1 2 1 1 total 0.094557 0.003843 -1 2 1 1 1 total 0.094972 0.005963 -3 2 2 1 1 total 0.088538 0.002530 +0 1 1 1 1 total 0.089555 0.004061 +2 1 2 1 1 total 0.092658 0.006216 +1 2 1 1 1 total 0.088293 0.004423 +3 2 2 1 1 total 0.088717 0.004937 mesh 1 group in group out legendre nuclide mean std. dev. x y z -0 1 1 1 1 1 P0 total 0.089670 0.005421 -1 1 1 1 1 1 P1 total 0.029864 0.001887 -2 1 1 1 1 1 P2 total 0.015945 0.001296 -3 1 1 1 1 1 P3 total 0.009511 0.000946 -8 1 2 1 1 1 P0 total 0.094524 0.003835 -9 1 2 1 1 1 P1 total 0.031760 0.001520 -10 1 2 1 1 1 P2 total 0.017210 0.000821 -11 1 2 1 1 1 P3 total 0.009315 0.000631 -4 2 1 1 1 1 P0 total 0.094835 0.005973 -5 2 1 1 1 1 P1 total 0.032936 0.001884 -6 2 1 1 1 1 P2 total 0.017196 0.001626 -7 2 1 1 1 1 P3 total 0.010278 0.001345 -12 2 2 1 1 1 P0 total 0.088412 0.002491 -13 2 2 1 1 1 P1 total 0.029615 0.001524 -14 2 2 1 1 1 P2 total 0.016925 0.000613 -15 2 2 1 1 1 P3 total 0.009759 0.000466 +0 1 1 1 1 1 P0 total 0.089523 0.004070 +1 1 1 1 1 1 P1 total 0.029116 0.001851 +2 1 1 1 1 1 P2 total 0.016529 0.000827 +3 1 1 1 1 1 P3 total 0.009975 0.000731 +8 1 2 1 1 1 P0 total 0.092626 0.006233 +9 1 2 1 1 1 P1 total 0.028570 0.001899 +10 1 2 1 1 1 P2 total 0.015737 0.001986 +11 1 2 1 1 1 P3 total 0.008492 0.000859 +4 2 1 1 1 1 P0 total 0.088293 0.004423 +5 2 1 1 1 1 P1 total 0.029892 0.001916 +6 2 1 1 1 1 P2 total 0.016736 0.000714 +7 2 1 1 1 1 P3 total 0.009129 0.000509 +12 2 2 1 1 1 P0 total 0.088617 0.004889 +13 2 2 1 1 1 P1 total 0.029750 0.001954 +14 2 2 1 1 1 P2 total 0.016440 0.001320 +15 2 2 1 1 1 P3 total 0.009758 0.000538 mesh 1 group in group out legendre nuclide mean std. dev. x y z -0 1 1 1 1 1 P0 total 0.089670 0.005421 -1 1 1 1 1 1 P1 total 0.029864 0.001887 -2 1 1 1 1 1 P2 total 0.015945 0.001296 -3 1 1 1 1 1 P3 total 0.009511 0.000946 -8 1 2 1 1 1 P0 total 0.094557 0.003843 -9 1 2 1 1 1 P1 total 0.031747 0.001512 -10 1 2 1 1 1 P2 total 0.017201 0.000817 -11 1 2 1 1 1 P3 total 0.009329 0.000635 -4 2 1 1 1 1 P0 total 0.094972 0.005963 -5 2 1 1 1 1 P1 total 0.032983 0.001886 -6 2 1 1 1 1 P2 total 0.017162 0.001631 -7 2 1 1 1 1 P3 total 0.010240 0.001336 -12 2 2 1 1 1 P0 total 0.088538 0.002530 -13 2 2 1 1 1 P1 total 0.029663 0.001532 -14 2 2 1 1 1 P2 total 0.016931 0.000627 -15 2 2 1 1 1 P3 total 0.009762 0.000466 +0 1 1 1 1 1 P0 total 0.089555 0.004061 +1 1 1 1 1 1 P1 total 0.029096 0.001859 +2 1 1 1 1 1 P2 total 0.016532 0.000828 +3 1 1 1 1 1 P3 total 0.009986 0.000734 +8 1 2 1 1 1 P0 total 0.092658 0.006216 +9 1 2 1 1 1 P1 total 0.028567 0.001899 +10 1 2 1 1 1 P2 total 0.015721 0.001995 +11 1 2 1 1 1 P3 total 0.008496 0.000857 +4 2 1 1 1 1 P0 total 0.088293 0.004423 +5 2 1 1 1 1 P1 total 0.029892 0.001916 +6 2 1 1 1 1 P2 total 0.016736 0.000714 +7 2 1 1 1 1 P3 total 0.009129 0.000509 +12 2 2 1 1 1 P0 total 0.088717 0.004937 +13 2 2 1 1 1 P1 total 0.029805 0.001977 +14 2 2 1 1 1 P2 total 0.016448 0.001327 +15 2 2 1 1 1 P3 total 0.009752 0.000534 mesh 1 group in group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 1.000000 0.056046 -2 1 2 1 1 1 total 1.000346 0.042442 -1 2 1 1 1 1 total 1.001447 0.056345 -3 2 2 1 1 1 total 1.001422 0.026106 +0 1 1 1 1 1 total 1.000362 0.044694 +2 1 2 1 1 1 total 1.000346 0.059372 +1 2 1 1 1 1 total 1.000000 0.055277 +3 2 2 1 1 1 total 1.001132 0.057130 mesh 1 group in group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.031401 0.002755 -2 1 2 1 1 1 total 0.033268 0.001692 -1 2 1 1 1 1 total 0.033756 0.002609 -3 2 2 1 1 1 total 0.030234 0.001308 +0 1 1 1 1 1 total 0.031634 0.002236 +2 1 2 1 1 1 total 0.032561 0.002344 +1 2 1 1 1 1 total 0.030820 0.002579 +3 2 2 1 1 1 total 0.029308 0.002507 mesh 1 group in group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 1.0 0.056046 -2 1 2 1 1 1 total 1.0 0.042360 -1 2 1 1 1 1 total 1.0 0.056488 -3 2 2 1 1 1 total 1.0 0.025630 +0 1 1 1 1 1 total 1.0 0.044796 +2 1 2 1 1 1 total 1.0 0.059579 +1 2 1 1 1 1 total 1.0 0.055277 +3 2 2 1 1 1 total 1.0 0.056598 mesh 1 group in group out legendre nuclide mean std. dev. x y z -0 1 1 1 1 1 P0 total 0.089376 0.006848 -1 1 1 1 1 1 P1 total 0.029766 0.002346 -2 1 1 1 1 1 P2 total 0.015893 0.001493 -3 1 1 1 1 1 P3 total 0.009480 0.001043 -8 1 2 1 1 1 P0 total 0.091296 0.004536 -9 1 2 1 1 1 P1 total 0.030675 0.001712 -10 1 2 1 1 1 P2 total 0.016622 0.000925 -11 1 2 1 1 1 P3 total 0.008997 0.000662 -4 2 1 1 1 1 P0 total 0.093142 0.006860 -5 2 1 1 1 1 P1 total 0.032348 0.002224 -6 2 1 1 1 1 P2 total 0.016889 0.001722 -7 2 1 1 1 1 P3 total 0.010094 0.001376 -12 2 2 1 1 1 P0 total 0.090570 0.003669 -13 2 2 1 1 1 P1 total 0.030338 0.001794 -14 2 2 1 1 1 P2 total 0.017338 0.000806 -15 2 2 1 1 1 P3 total 0.009997 0.000559 +0 1 1 1 1 1 P0 total 0.089450 0.005766 +1 1 1 1 1 1 P1 total 0.029092 0.002277 +2 1 1 1 1 1 P2 total 0.016516 0.001119 +3 1 1 1 1 1 P3 total 0.009967 0.000861 +8 1 2 1 1 1 P0 total 0.092674 0.008583 +9 1 2 1 1 1 P1 total 0.028585 0.002630 +10 1 2 1 1 1 P2 total 0.015745 0.002226 +11 1 2 1 1 1 P3 total 0.008496 0.001015 +4 2 1 1 1 1 P0 total 0.088389 0.006412 +5 2 1 1 1 1 P1 total 0.029924 0.002479 +6 2 1 1 1 1 P2 total 0.016754 0.001133 +7 2 1 1 1 1 P3 total 0.009139 0.000699 +12 2 2 1 1 1 P0 total 0.088779 0.006278 +13 2 2 1 1 1 P1 total 0.029804 0.002360 +14 2 2 1 1 1 P2 total 0.016470 0.001510 +15 2 2 1 1 1 P3 total 0.009776 0.000691 mesh 1 group in group out legendre nuclide mean std. dev. x y z -0 1 1 1 1 1 P0 total 0.089376 0.008485 -1 1 1 1 1 1 P1 total 0.029766 0.002878 -2 1 1 1 1 1 P2 total 0.015893 0.001738 -3 1 1 1 1 1 P3 total 0.009480 0.001171 -8 1 2 1 1 1 P0 total 0.091328 0.005967 -9 1 2 1 1 1 P1 total 0.030686 0.002151 -10 1 2 1 1 1 P2 total 0.016628 0.001164 -11 1 2 1 1 1 P3 total 0.009000 0.000764 -4 2 1 1 1 1 P0 total 0.093277 0.008645 -5 2 1 1 1 1 P1 total 0.032394 0.002878 -6 2 1 1 1 1 P2 total 0.016913 0.001969 -7 2 1 1 1 1 P3 total 0.010109 0.001491 -12 2 2 1 1 1 P0 total 0.090699 0.004369 -13 2 2 1 1 1 P1 total 0.030381 0.001963 -14 2 2 1 1 1 P2 total 0.017362 0.000925 -15 2 2 1 1 1 P3 total 0.010011 0.000618 +0 1 1 1 1 1 P0 total 0.089483 0.007018 +1 1 1 1 1 1 P1 total 0.029103 0.002623 +2 1 1 1 1 1 P2 total 0.016522 0.001341 +3 1 1 1 1 1 P3 total 0.009971 0.000970 +8 1 2 1 1 1 P0 total 0.092706 0.010197 +9 1 2 1 1 1 P1 total 0.028595 0.003131 +10 1 2 1 1 1 P2 total 0.015750 0.002415 +11 1 2 1 1 1 P3 total 0.008499 0.001134 +4 2 1 1 1 1 P0 total 0.088389 0.008061 +5 2 1 1 1 1 P1 total 0.029924 0.002980 +6 2 1 1 1 1 P2 total 0.016754 0.001463 +7 2 1 1 1 1 P3 total 0.009139 0.000863 +12 2 2 1 1 1 P0 total 0.088880 0.008076 +13 2 2 1 1 1 P1 total 0.029838 0.002912 +14 2 2 1 1 1 P2 total 0.016489 0.001781 +15 2 2 1 1 1 P3 total 0.009787 0.000889 mesh 1 group out nuclide mean std. dev. x y z -0 1 1 1 1 total 1.0 0.105972 -2 1 2 1 1 total 1.0 0.060624 -1 2 1 1 1 total 1.0 0.084855 -3 2 2 1 1 total 1.0 0.053024 +0 1 1 1 1 total 1.0 0.088672 +2 1 2 1 1 total 1.0 0.069731 +1 2 1 1 1 total 1.0 0.109718 +3 2 2 1 1 total 1.0 0.108376 mesh 1 group out nuclide mean std. dev. x y z -0 1 1 1 1 total 1.0 0.108202 -2 1 2 1 1 total 1.0 0.058908 -1 2 1 1 1 total 1.0 0.085583 -3 2 2 1 1 total 1.0 0.052287 +0 1 1 1 1 total 1.0 0.091154 +2 1 2 1 1 total 1.0 0.069438 +1 2 1 1 1 total 1.0 0.109233 +3 2 2 1 1 total 1.0 0.108119 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 8.523138e-10 3.481466e-11 -2 1 2 1 1 total 9.044552e-10 2.851430e-11 -1 2 1 1 1 total 8.643697e-10 4.046801e-11 -3 2 2 1 1 total 8.667214e-10 1.753703e-11 +0 1 1 1 1 total 8.424136e-10 3.612697e-11 +2 1 2 1 1 total 8.884166e-10 6.324091e-11 +1 2 1 1 1 total 8.415613e-10 4.520088e-11 +3 2 2 1 1 total 8.557929e-10 2.898037e-11 mesh 1 group in nuclide mean std. dev. x y z -0 1 1 1 1 total 0.030356 0.001982 -2 1 2 1 1 total 0.031140 0.001152 -1 2 1 1 1 total 0.032736 0.001693 -3 2 2 1 1 total 0.031283 0.001414 +0 1 1 1 1 total 0.030724 0.001773 +2 1 2 1 1 total 0.032290 0.002188 +1 2 1 1 1 total 0.030172 0.001654 +3 2 2 1 1 total 0.030372 0.001661 mesh 1 group in group out nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.031233 0.002783 -2 1 2 1 1 1 total 0.033040 0.001647 -1 2 1 1 1 1 total 0.033581 0.002609 -3 2 2 1 1 1 total 0.030070 0.001287 +0 1 1 1 1 1 total 0.031468 0.002273 +2 1 2 1 1 1 total 0.032418 0.002330 +1 2 1 1 1 1 total 0.030706 0.002559 +3 2 2 1 1 1 total 0.029134 0.002487 mesh 1 group in nuclide mean std. dev. x y surf -3 1 1 x-max in 1 total 0.1816 0.006129 -2 1 1 x-max out 1 total 0.2718 0.095077 +3 1 1 x-max in 1 total 0.1884 0.010255 +2 1 1 x-max out 1 total 0.1798 0.009646 1 1 1 x-min in 1 total 0.0000 0.000000 0 1 1 x-min out 1 total 0.0000 0.000000 -7 1 1 y-max in 1 total 0.1790 0.011921 -6 1 1 y-max out 1 total 0.2290 0.034821 +7 1 1 y-max in 1 total 0.1822 0.014739 +6 1 1 y-max out 1 total 0.1806 0.019423 5 1 1 y-min in 1 total 0.0000 0.000000 4 1 1 y-min out 1 total 0.0000 0.000000 -19 1 2 x-max in 1 total 0.1872 0.012447 -18 1 2 x-max out 1 total 0.1952 0.015948 +19 1 2 x-max in 1 total 0.1780 0.012514 +18 1 2 x-max out 1 total 0.1886 0.014979 17 1 2 x-min in 1 total 0.0000 0.000000 16 1 2 x-min out 1 total 0.0000 0.000000 23 1 2 y-max in 1 total 0.0000 0.000000 22 1 2 y-max out 1 total 0.0000 0.000000 -21 1 2 y-min in 1 total 0.2290 0.034821 -20 1 2 y-min out 1 total 0.1790 0.011921 +21 1 2 y-min in 1 total 0.1806 0.019423 +20 1 2 y-min out 1 total 0.1822 0.014739 11 2 1 x-max in 1 total 0.0000 0.000000 10 2 1 x-max out 1 total 0.0000 0.000000 -9 2 1 x-min in 1 total 0.2718 0.095077 -8 2 1 x-min out 1 total 0.1816 0.006129 -15 2 1 y-max in 1 total 0.1778 0.009484 -14 2 1 y-max out 1 total 0.2326 0.042782 +9 2 1 x-min in 1 total 0.1798 0.009646 +8 2 1 x-min out 1 total 0.1884 0.010255 +15 2 1 y-max in 1 total 0.1812 0.009583 +14 2 1 y-max out 1 total 0.1858 0.012018 13 2 1 y-min in 1 total 0.0000 0.000000 12 2 1 y-min out 1 total 0.0000 0.000000 27 2 2 x-max in 1 total 0.0000 0.000000 -26 2 2 x-max out 1 total 0.0260 0.026000 -25 2 2 x-min in 1 total 0.1952 0.015948 -24 2 2 x-min out 1 total 0.1872 0.012447 +26 2 2 x-max out 1 total 0.0000 0.000000 +25 2 2 x-min in 1 total 0.1886 0.014979 +24 2 2 x-min out 1 total 0.1780 0.012514 31 2 2 y-max in 1 total 0.0000 0.000000 -30 2 2 y-max out 1 total 0.0244 0.024400 -29 2 2 y-min in 1 total 0.2326 0.042782 -28 2 2 y-min out 1 total 0.1778 0.009484 - mesh 1 group in legendre nuclide mean std. dev. - x y z -0 1 1 1 1 P0 total 26.352505 16.110503 -1 1 1 1 1 P1 total 4.600555 0.424935 -4 1 2 1 1 P0 total 32.890094 15.569252 -5 1 2 1 1 P1 total 4.572518 0.218792 -2 2 1 1 1 P0 total 27.128188 17.388447 -3 2 1 1 1 P1 total 4.493168 0.383445 -6 2 2 1 1 P0 total 21.584163 5.964683 -7 2 2 1 1 P1 total 4.489908 0.236773 - mesh 1 group in legendre nuclide mean std. dev. - x y z -0 1 1 1 1 P0 total 26.352505 16.110503 -1 1 1 1 1 P1 total 4.600555 0.424935 -4 1 2 1 1 P0 total 32.996545 15.690979 -5 1 2 1 1 P1 total 4.571696 0.218502 -2 2 1 1 1 P0 total 27.434506 17.764465 -3 2 1 1 1 P1 total 4.496020 0.383903 -6 2 2 1 1 P0 total 21.761315 6.095339 -7 2 2 1 1 P1 total 4.492825 0.237270 +30 2 2 y-max out 1 total 0.0000 0.000000 +29 2 2 y-min in 1 total 0.1858 0.012018 +28 2 2 y-min out 1 total 0.1812 0.009583 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 4.539911 0.323493 +2 1 2 1 1 total 4.278655 0.425575 +1 2 1 1 1 total 4.674097 0.339600 +3 2 2 1 1 total 4.630700 0.312366 + mesh 1 group in nuclide mean std. dev. + x y z +0 1 1 1 1 total 4.538654 0.323497 +2 1 2 1 1 total 4.278494 0.425550 +1 2 1 1 1 total 4.674097 0.339600 +3 2 2 1 1 total 4.634259 0.313464 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.000007 4.371033e-07 -1 1 1 1 2 1 total 0.000035 2.256193e-06 -2 1 1 1 3 1 total 0.000033 2.153958e-06 -3 1 1 1 4 1 total 0.000075 4.829351e-06 -4 1 1 1 5 1 total 0.000031 1.979966e-06 -5 1 1 1 6 1 total 0.000013 8.294008e-07 -12 1 2 1 1 1 total 0.000007 2.763697e-07 -13 1 2 1 2 1 total 0.000036 1.426535e-06 -14 1 2 1 3 1 total 0.000034 1.361895e-06 -15 1 2 1 4 1 total 0.000077 3.053480e-06 -16 1 2 1 5 1 total 0.000031 1.251884e-06 -17 1 2 1 6 1 total 0.000013 5.244097e-07 -6 2 1 1 1 1 total 0.000007 3.644103e-07 -7 2 1 1 2 1 total 0.000038 1.880974e-06 -8 2 1 1 3 1 total 0.000036 1.795741e-06 -9 2 1 1 4 1 total 0.000080 4.026199e-06 -10 2 1 1 5 1 total 0.000033 1.650685e-06 -11 2 1 1 6 1 total 0.000014 6.914661e-07 -18 2 2 1 1 1 total 0.000007 3.263844e-07 -19 2 2 1 2 1 total 0.000036 1.684696e-06 -20 2 2 1 3 1 total 0.000034 1.608357e-06 -21 2 2 1 4 1 total 0.000076 3.606069e-06 -22 2 2 1 5 1 total 0.000031 1.478437e-06 -23 2 2 1 6 1 total 0.000013 6.193123e-07 +0 1 1 1 1 1 total 0.000007 3.997262e-07 +1 1 1 1 2 1 total 0.000035 2.063264e-06 +2 1 1 1 3 1 total 0.000034 1.969771e-06 +3 1 1 1 4 1 total 0.000075 4.416388e-06 +4 1 1 1 5 1 total 0.000031 1.810657e-06 +5 1 1 1 6 1 total 0.000013 7.584779e-07 +12 1 2 1 1 1 total 0.000007 4.931656e-07 +13 1 2 1 2 1 total 0.000037 2.545569e-06 +14 1 2 1 3 1 total 0.000035 2.430221e-06 +15 1 2 1 4 1 total 0.000079 5.448757e-06 +16 1 2 1 5 1 total 0.000032 2.233913e-06 +17 1 2 1 6 1 total 0.000014 9.357785e-07 +6 2 1 1 1 1 total 0.000007 3.618632e-07 +7 2 1 1 2 1 total 0.000035 1.867826e-06 +8 2 1 1 3 1 total 0.000033 1.783189e-06 +9 2 1 1 4 1 total 0.000074 3.998058e-06 +10 2 1 1 5 1 total 0.000030 1.639147e-06 +11 2 1 1 6 1 total 0.000013 6.866331e-07 +18 2 2 1 1 1 total 0.000007 3.603080e-07 +19 2 2 1 2 1 total 0.000035 1.859799e-06 +20 2 2 1 3 1 total 0.000033 1.775526e-06 +21 2 2 1 4 1 total 0.000075 3.980875e-06 +22 2 2 1 5 1 total 0.000031 1.632103e-06 +23 2 2 1 6 1 total 0.000013 6.836821e-07 mesh 1 delayedgroup group out nuclide mean std. dev. x y z 0 1 1 1 1 1 total 0.0 0.000000 -1 1 1 1 2 1 total 1.0 1.414214 -2 1 1 1 3 1 total 1.0 1.414214 -3 1 1 1 4 1 total 1.0 0.579241 +1 1 1 1 2 1 total 1.0 0.866877 +2 1 1 1 3 1 total 1.0 0.866877 +3 1 1 1 4 1 total 1.0 1.414214 4 1 1 1 5 1 total 1.0 1.414214 5 1 1 1 6 1 total 0.0 0.000000 -12 1 2 1 1 1 total 1.0 1.414214 +12 1 2 1 1 1 total 0.0 0.000000 13 1 2 1 2 1 total 0.0 0.000000 -14 1 2 1 3 1 total 1.0 0.866166 -15 1 2 1 4 1 total 1.0 0.868547 -16 1 2 1 5 1 total 1.0 0.873899 +14 1 2 1 3 1 total 0.0 0.000000 +15 1 2 1 4 1 total 1.0 0.579346 +16 1 2 1 5 1 total 1.0 1.414214 17 1 2 1 6 1 total 1.0 1.414214 -6 2 1 1 1 1 total 0.0 0.000000 -7 2 1 1 2 1 total 1.0 0.654642 -8 2 1 1 3 1 total 1.0 1.414214 -9 2 1 1 4 1 total 1.0 1.414214 +6 2 1 1 1 1 total 1.0 1.414214 +7 2 1 1 2 1 total 1.0 1.414214 +8 2 1 1 3 1 total 1.0 0.874781 +9 2 1 1 4 1 total 0.0 0.000000 10 2 1 1 5 1 total 0.0 0.000000 11 2 1 1 6 1 total 0.0 0.000000 -18 2 2 1 1 1 total 1.0 0.867501 -19 2 2 1 2 1 total 0.0 0.000000 -20 2 2 1 3 1 total 0.0 0.000000 -21 2 2 1 4 1 total 1.0 0.867501 +18 2 2 1 1 1 total 1.0 1.414214 +19 2 2 1 2 1 total 1.0 0.867902 +20 2 2 1 3 1 total 1.0 1.414214 +21 2 2 1 4 1 total 1.0 1.414214 22 2 2 1 5 1 total 1.0 1.414214 -23 2 2 1 6 1 total 1.0 1.414214 +23 2 2 1 6 1 total 0.0 0.000000 mesh 1 delayedgroup group in nuclide mean std. dev. x y z -0 1 1 1 1 1 total 0.000221 0.000018 -1 1 1 1 2 1 total 0.001141 0.000091 -2 1 1 1 3 1 total 0.001090 0.000087 -3 1 1 1 4 1 total 0.002443 0.000194 -4 1 1 1 5 1 total 0.001002 0.000080 -5 1 1 1 6 1 total 0.000420 0.000033 -12 1 2 1 1 1 total 0.000221 0.000011 -13 1 2 1 2 1 total 0.001142 0.000059 -14 1 2 1 3 1 total 0.001090 0.000056 -15 1 2 1 4 1 total 0.002444 0.000126 -16 1 2 1 5 1 total 0.001002 0.000052 -17 1 2 1 6 1 total 0.000420 0.000022 -6 2 1 1 1 1 total 0.000221 0.000013 -7 2 1 1 2 1 total 0.001140 0.000065 -8 2 1 1 3 1 total 0.001088 0.000062 -9 2 1 1 4 1 total 0.002440 0.000140 -10 2 1 1 5 1 total 0.001000 0.000057 -11 2 1 1 6 1 total 0.000419 0.000024 -18 2 2 1 1 1 total 0.000219 0.000014 -19 2 2 1 2 1 total 0.001132 0.000072 -20 2 2 1 3 1 total 0.001081 0.000069 -21 2 2 1 4 1 total 0.002424 0.000155 -22 2 2 1 5 1 total 0.000994 0.000064 -23 2 2 1 6 1 total 0.000416 0.000027 +0 1 1 1 1 1 total 0.000221 0.000016 +1 1 1 1 2 1 total 0.001138 0.000084 +2 1 1 1 3 1 total 0.001087 0.000080 +3 1 1 1 4 1 total 0.002437 0.000180 +4 1 1 1 5 1 total 0.000999 0.000074 +5 1 1 1 6 1 total 0.000418 0.000031 +12 1 2 1 1 1 total 0.000221 0.000014 +13 1 2 1 2 1 total 0.001138 0.000073 +14 1 2 1 3 1 total 0.001087 0.000069 +15 1 2 1 4 1 total 0.002436 0.000155 +16 1 2 1 5 1 total 0.000999 0.000064 +17 1 2 1 6 1 total 0.000418 0.000027 +6 2 1 1 1 1 total 0.000220 0.000014 +7 2 1 1 2 1 total 0.001137 0.000070 +8 2 1 1 3 1 total 0.001086 0.000067 +9 2 1 1 4 1 total 0.002435 0.000150 +10 2 1 1 5 1 total 0.000998 0.000062 +11 2 1 1 6 1 total 0.000418 0.000026 +18 2 2 1 1 1 total 0.000221 0.000015 +19 2 2 1 2 1 total 0.001141 0.000078 +20 2 2 1 3 1 total 0.001089 0.000074 +21 2 2 1 4 1 total 0.002442 0.000167 +22 2 2 1 5 1 total 0.001001 0.000068 +23 2 2 1 6 1 total 0.000419 0.000029 mesh 1 delayedgroup nuclide mean std. dev. x y z -0 1 1 1 1 total 0.013336 0.001054 -1 1 1 1 2 total 0.032739 0.002588 -2 1 1 1 3 total 0.120780 0.009548 -3 1 1 1 4 total 0.302780 0.023936 -4 1 1 1 5 total 0.849490 0.067157 -5 1 1 1 6 total 2.853000 0.225544 -12 1 2 1 1 total 0.013336 0.000716 -13 1 2 1 2 total 0.032739 0.001758 -14 1 2 1 3 total 0.120780 0.006485 -15 1 2 1 4 total 0.302780 0.016257 -16 1 2 1 5 total 0.849490 0.045611 -17 1 2 1 6 total 2.853000 0.153186 -6 2 1 1 1 total 0.013336 0.000744 -7 2 1 1 2 total 0.032739 0.001827 -8 2 1 1 3 total 0.120780 0.006740 -9 2 1 1 4 total 0.302780 0.016897 -10 2 1 1 5 total 0.849490 0.047407 -11 2 1 1 6 total 2.853000 0.159216 -18 2 2 1 1 total 0.013336 0.000872 -19 2 2 1 2 total 0.032739 0.002141 -20 2 2 1 3 total 0.120780 0.007899 -21 2 2 1 4 total 0.302780 0.019803 -22 2 2 1 5 total 0.849490 0.055560 -23 2 2 1 6 total 2.853000 0.186598 +0 1 1 1 1 total 0.013336 0.000997 +1 1 1 1 2 total 0.032739 0.002447 +2 1 1 1 3 total 0.120780 0.009028 +3 1 1 1 4 total 0.302780 0.022633 +4 1 1 1 5 total 0.849490 0.063500 +5 1 1 1 6 total 2.853000 0.213262 +12 1 2 1 1 total 0.013336 0.000866 +13 1 2 1 2 total 0.032739 0.002126 +14 1 2 1 3 total 0.120780 0.007843 +15 1 2 1 4 total 0.302780 0.019661 +16 1 2 1 5 total 0.849490 0.055163 +17 1 2 1 6 total 2.853000 0.185263 +6 2 1 1 1 total 0.013336 0.000814 +7 2 1 1 2 total 0.032739 0.001999 +8 2 1 1 3 total 0.120780 0.007373 +9 2 1 1 4 total 0.302780 0.018483 +10 2 1 1 5 total 0.849490 0.051857 +11 2 1 1 6 total 2.853000 0.174163 +18 2 2 1 1 total 0.013336 0.000896 +19 2 2 1 2 total 0.032739 0.002200 +20 2 2 1 3 total 0.120780 0.008117 +21 2 2 1 4 total 0.302780 0.020349 +22 2 2 1 5 total 0.849490 0.057091 +23 2 2 1 6 total 2.853000 0.191738 mesh 1 delayedgroup group in group out nuclide mean std. dev. x y z 0 1 1 1 1 1 1 total 0.000000 0.000000 -1 1 1 1 2 1 1 total 0.000029 0.000030 -2 1 1 1 3 1 1 total 0.000028 0.000028 -3 1 1 1 4 1 1 total 0.000083 0.000034 -4 1 1 1 5 1 1 total 0.000028 0.000028 +1 1 1 1 2 1 1 total 0.000056 0.000034 +2 1 1 1 3 1 1 total 0.000056 0.000034 +3 1 1 1 4 1 1 total 0.000029 0.000029 +4 1 1 1 5 1 1 total 0.000026 0.000026 5 1 1 1 6 1 1 total 0.000000 0.000000 -12 1 2 1 1 1 1 total 0.000029 0.000029 +12 1 2 1 1 1 1 total 0.000000 0.000000 13 1 2 1 2 1 1 total 0.000000 0.000000 -14 1 2 1 3 1 1 total 0.000052 0.000032 -15 1 2 1 4 1 1 total 0.000055 0.000034 -16 1 2 1 5 1 1 total 0.000059 0.000037 -17 1 2 1 6 1 1 total 0.000033 0.000033 -6 2 1 1 1 1 1 total 0.000000 0.000000 -7 2 1 1 2 1 1 total 0.000113 0.000053 -8 2 1 1 3 1 1 total 0.000034 0.000034 -9 2 1 1 4 1 1 total 0.000029 0.000029 +14 1 2 1 3 1 1 total 0.000000 0.000000 +15 1 2 1 4 1 1 total 0.000079 0.000033 +16 1 2 1 5 1 1 total 0.000032 0.000032 +17 1 2 1 6 1 1 total 0.000032 0.000032 +6 2 1 1 1 1 1 total 0.000029 0.000029 +7 2 1 1 2 1 1 total 0.000027 0.000027 +8 2 1 1 3 1 1 total 0.000058 0.000036 +9 2 1 1 4 1 1 total 0.000000 0.000000 10 2 1 1 5 1 1 total 0.000000 0.000000 11 2 1 1 6 1 1 total 0.000000 0.000000 -18 2 2 1 1 1 1 total 0.000053 0.000033 -19 2 2 1 2 1 1 total 0.000000 0.000000 -20 2 2 1 3 1 1 total 0.000000 0.000000 -21 2 2 1 4 1 1 total 0.000053 0.000033 -22 2 2 1 5 1 1 total 0.000031 0.000031 -23 2 2 1 6 1 1 total 0.000025 0.000025 +18 2 2 1 1 1 1 total 0.000027 0.000027 +19 2 2 1 2 1 1 total 0.000056 0.000035 +20 2 2 1 3 1 1 total 0.000028 0.000028 +21 2 2 1 4 1 1 total 0.000030 0.000030 +22 2 2 1 5 1 1 total 0.000033 0.000033 +23 2 2 1 6 1 1 total 0.000000 0.000000 diff --git a/tests/regression_tests/mgxs_library_mesh/test.py b/tests/regression_tests/mgxs_library_mesh/test.py index 3660d3eb74d..89c68a75a33 100644 --- a/tests/regression_tests/mgxs_library_mesh/test.py +++ b/tests/regression_tests/mgxs_library_mesh/test.py @@ -19,12 +19,12 @@ def model(): zr.add_nuclide('Zr90', 1.0) model.materials.extend([fuel, zr]) - box1 = openmc.model.rectangular_prism(10.0, 10.0) - box2 = openmc.model.rectangular_prism(20.0, 20.0, boundary_type='reflective') + box1 = openmc.model.RectangularPrism(10.0, 10.0) + box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective') top = openmc.ZPlane(z0=10.0, boundary_type='vacuum') bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=box1 & +bottom & -top) - cell2 = openmc.Cell(fill=zr, region=~box1 & box2 & +bottom & -top) + cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top) + cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top) model.geometry = openmc.Geometry([cell1, cell2]) model.settings.batches = 5 diff --git a/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat index 0d9dbf8215d..5cad36b7ea3 100644 --- a/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat @@ -1,1862 +1,1954 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 3 - - - 0.0 20000000.0 - - - 1 2 3 4 5 6 - - - 2 - - - 3 - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - absorption - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - total - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - total - nu-scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - nu-fission - analog - - - 1 2 5 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - scatter - tracklength - - - 1 2 5 28 - total - scatter - analog - - - 1 2 5 - total - nu-scatter - analog - - - 1 52 - total - nu-fission - analog - - - 1 5 - total - nu-fission - analog - - - 1 52 - total - prompt-nu-fission - analog - - - 1 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - total - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,elastic) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,level) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,2n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,na) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,nc) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,gamma) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,a) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,Xa) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - heating - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - damage-energy - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,n1) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - total - (n,a0) - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - total - (n,nc) - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - (n,n1) - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - total - (n,2n) - analog - - - 1 2 - total - flux - tracklength - - - 1 106 2 - total - delayed-nu-fission - tracklength - - - 1 106 52 - total - delayed-nu-fission - analog - - - 1 106 5 - total - delayed-nu-fission - analog - - - 1 2 - total - nu-fission - tracklength - - - 1 106 2 - total - delayed-nu-fission - tracklength - - - 1 106 - total - delayed-nu-fission - tracklength - - - 1 106 - total - decay-rate - tracklength - - - 1 2 - total - flux - analog - - - 1 106 2 5 - total - delayed-nu-fission - analog - - - 120 2 - total - flux - tracklength - - - 120 2 - total - total - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - total - tracklength - - - 120 2 - total - flux - analog - - - 120 5 6 - total - scatter - analog - - - 120 2 - total - flux - tracklength - - - 120 2 - total - total - tracklength - - - 120 2 - total - flux - analog - - - 120 5 6 - total - nu-scatter - analog - - - 120 2 - total - flux - tracklength - - - 120 2 - total - absorption - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - absorption - tracklength - - - 120 2 - total - fission - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - fission - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - nu-fission - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - kappa-fission - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - scatter - tracklength - - - 120 2 - total - flux - analog - - - 120 2 - total - nu-scatter - analog - - - 120 2 - total - flux - analog - - - 120 2 5 28 - total - scatter - analog - - - 120 2 - total - flux - analog - - - 120 2 5 28 - total - nu-scatter - analog - - - 120 2 5 - total - nu-scatter - analog - - - 120 2 5 - total - scatter - analog - - - 120 2 - total - flux - analog - - - 120 2 5 - total - nu-fission - analog - - - 120 2 5 - total - scatter - analog - - - 120 2 - total - flux - tracklength - - - 120 2 - total - scatter - tracklength - - - 120 2 5 28 - total - scatter - analog - - - 120 2 - total - flux - tracklength - - - 120 2 - total - scatter - tracklength - - - 120 2 5 28 - total - scatter - analog - - - 120 2 5 - total - nu-scatter - analog - - - 120 52 - total - nu-fission - analog - - - 120 5 - total - nu-fission - analog - - - 120 52 - total - prompt-nu-fission - analog - - - 120 5 - total - prompt-nu-fission - analog - - - 120 2 - total - flux - tracklength - - - 120 2 - total - inverse-velocity - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - prompt-nu-fission - tracklength - - - 120 2 - total - flux - analog - - - 120 2 5 - total - prompt-nu-fission - analog - - - 120 2 - total - flux - tracklength - - - 120 2 - total - total - tracklength - - - 120 2 - total - flux - analog - - - 120 5 6 - total - scatter - analog - - - 120 2 - total - flux - tracklength - - - 120 2 - total - total - tracklength - - - 120 2 - total - flux - analog - - - 120 5 6 - total - nu-scatter - analog - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,elastic) - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,level) - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,2n) - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,na) - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,nc) - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,gamma) - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,a) - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,Xa) - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - heating - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - damage-energy - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,n1) - tracklength - - - 120 2 - total - flux - tracklength - - - 120 2 - total - (n,a0) - tracklength - - - 120 2 - total - flux - analog - - - 120 2 5 - total - (n,nc) - analog - - - 120 2 - total - flux - analog - - - 120 2 5 - total - (n,n1) - analog - - - 120 2 - total - flux - analog - - - 120 2 5 - total - (n,2n) - analog - - - 120 2 - total - flux - tracklength - - - 120 106 2 - total - delayed-nu-fission - tracklength - - - 120 106 52 - total - delayed-nu-fission - analog - - - 120 106 5 - total - delayed-nu-fission - analog - - - 120 2 - total - nu-fission - tracklength - - - 120 106 2 - total - delayed-nu-fission - tracklength - - - 120 106 - total - delayed-nu-fission - tracklength - - - 120 106 - total - decay-rate - tracklength - - - 120 2 - total - flux - analog - - - 120 106 2 5 - total - delayed-nu-fission - analog - - - 239 2 - total - flux - tracklength - - - 239 2 - total - total - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - total - tracklength - - - 239 2 - total - flux - analog - - - 239 5 6 - total - scatter - analog - - - 239 2 - total - flux - tracklength - - - 239 2 - total - total - tracklength - - - 239 2 - total - flux - analog - - - 239 5 6 - total - nu-scatter - analog - - - 239 2 - total - flux - tracklength - - - 239 2 - total - absorption - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - absorption - tracklength - - - 239 2 - total - fission - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - fission - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - nu-fission - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - kappa-fission - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - scatter - tracklength - - - 239 2 - total - flux - analog - - - 239 2 - total - nu-scatter - analog - - - 239 2 - total - flux - analog - - - 239 2 5 28 - total - scatter - analog - - - 239 2 - total - flux - analog - - - 239 2 5 28 - total - nu-scatter - analog - - - 239 2 5 - total - nu-scatter - analog - - - 239 2 5 - total - scatter - analog - - - 239 2 - total - flux - analog - - - 239 2 5 - total - nu-fission - analog - - - 239 2 5 - total - scatter - analog - - - 239 2 - total - flux - tracklength - - - 239 2 - total - scatter - tracklength - - - 239 2 5 28 - total - scatter - analog - - - 239 2 - total - flux - tracklength - - - 239 2 - total - scatter - tracklength - - - 239 2 5 28 - total - scatter - analog - - - 239 2 5 - total - nu-scatter - analog - - - 239 52 - total - nu-fission - analog - - - 239 5 - total - nu-fission - analog - - - 239 52 - total - prompt-nu-fission - analog - - - 239 5 - total - prompt-nu-fission - analog - - - 239 2 - total - flux - tracklength - - - 239 2 - total - inverse-velocity - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - prompt-nu-fission - tracklength - - - 239 2 - total - flux - analog - - - 239 2 5 - total - prompt-nu-fission - analog - - - 239 2 - total - flux - tracklength - - - 239 2 - total - total - tracklength - - - 239 2 - total - flux - analog - - - 239 5 6 - total - scatter - analog - - - 239 2 - total - flux - tracklength - - - 239 2 - total - total - tracklength - - - 239 2 - total - flux - analog - - - 239 5 6 - total - nu-scatter - analog - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,elastic) - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,level) - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,2n) - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,na) - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,nc) - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,gamma) - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,a) - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,Xa) - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - heating - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - damage-energy - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,n1) - tracklength - - - 239 2 - total - flux - tracklength - - - 239 2 - total - (n,a0) - tracklength - - - 239 2 - total - flux - analog - - - 239 2 5 - total - (n,nc) - analog - - - 239 2 - total - flux - analog - - - 239 2 5 - total - (n,n1) - analog - - - 239 2 - total - flux - analog - - - 239 2 5 - total - (n,2n) - analog - - - 239 2 - total - flux - tracklength - - - 239 106 2 - total - delayed-nu-fission - tracklength - - - 239 106 52 - total - delayed-nu-fission - analog - - - 239 106 5 - total - delayed-nu-fission - analog - - - 239 2 - total - nu-fission - tracklength - - - 239 106 2 - total - delayed-nu-fission - tracklength - - - 239 106 - total - delayed-nu-fission - tracklength - - - 239 106 - total - decay-rate - tracklength - - - 239 2 - total - flux - analog - - - 239 106 2 5 - total - delayed-nu-fission - analog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 1 2 3 4 5 6 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + (n,3n) + tracklength + + + 1 2 + total + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + absorption + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + total + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + total + nu-scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + nu-fission + analog + + + 1 2 5 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + scatter + tracklength + + + 1 2 5 30 + total + scatter + analog + + + 1 2 5 + total + nu-scatter + analog + + + 1 54 + total + nu-fission + analog + + + 1 5 + total + nu-fission + analog + + + 1 54 + total + prompt-nu-fission + analog + + + 1 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + total + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,elastic) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,level) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,2n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,na) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,nc) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,gamma) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,a) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,Xa) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + heating + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + damage-energy + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,n1) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + total + (n,a0) + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + total + (n,nc) + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + (n,n1) + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + total + (n,2n) + analog + + + 1 2 + total + flux + tracklength + + + 1 108 2 + total + delayed-nu-fission + tracklength + + + 1 108 54 + total + delayed-nu-fission + analog + + + 1 108 5 + total + delayed-nu-fission + analog + + + 1 2 + total + nu-fission + tracklength + + + 1 108 2 + total + delayed-nu-fission + tracklength + + + 1 108 + total + delayed-nu-fission + tracklength + + + 1 108 + total + decay-rate + tracklength + + + 1 2 + total + flux + analog + + + 1 108 2 5 + total + delayed-nu-fission + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + analog + + + 122 5 6 + total + scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + analog + + + 122 5 6 + total + nu-scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + absorption + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + absorption + tracklength + + + 122 2 + total + (n,2n) + tracklength + + + 122 2 + total + (n,3n) + tracklength + + + 122 2 + total + (n,4n) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + absorption + tracklength + + + 122 2 + total + fission + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + fission + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + nu-fission + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + kappa-fission + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + scatter + tracklength + + + 122 2 + total + flux + analog + + + 122 2 + total + nu-scatter + analog + + + 122 2 + total + flux + analog + + + 122 2 5 30 + total + scatter + analog + + + 122 2 + total + flux + analog + + + 122 2 5 30 + total + nu-scatter + analog + + + 122 2 5 + total + nu-scatter + analog + + + 122 2 5 + total + scatter + analog + + + 122 2 + total + flux + analog + + + 122 2 5 + total + nu-fission + analog + + + 122 2 5 + total + scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + scatter + tracklength + + + 122 2 5 30 + total + scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + scatter + tracklength + + + 122 2 5 30 + total + scatter + analog + + + 122 2 5 + total + nu-scatter + analog + + + 122 54 + total + nu-fission + analog + + + 122 5 + total + nu-fission + analog + + + 122 54 + total + prompt-nu-fission + analog + + + 122 5 + total + prompt-nu-fission + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + inverse-velocity + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + prompt-nu-fission + tracklength + + + 122 2 + total + flux + analog + + + 122 2 5 + total + prompt-nu-fission + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + analog + + + 122 5 6 + total + scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + total + tracklength + + + 122 2 + total + flux + analog + + + 122 5 6 + total + nu-scatter + analog + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,elastic) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,level) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,2n) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,na) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,nc) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,gamma) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,a) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,Xa) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + heating + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + damage-energy + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,n1) + tracklength + + + 122 2 + total + flux + tracklength + + + 122 2 + total + (n,a0) + tracklength + + + 122 2 + total + flux + analog + + + 122 2 5 + total + (n,nc) + analog + + + 122 2 + total + flux + analog + + + 122 2 5 + total + (n,n1) + analog + + + 122 2 + total + flux + analog + + + 122 2 5 + total + (n,2n) + analog + + + 122 2 + total + flux + tracklength + + + 122 108 2 + total + delayed-nu-fission + tracklength + + + 122 108 54 + total + delayed-nu-fission + analog + + + 122 108 5 + total + delayed-nu-fission + analog + + + 122 2 + total + nu-fission + tracklength + + + 122 108 2 + total + delayed-nu-fission + tracklength + + + 122 108 + total + delayed-nu-fission + tracklength + + + 122 108 + total + decay-rate + tracklength + + + 122 2 + total + flux + analog + + + 122 108 2 5 + total + delayed-nu-fission + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + analog + + + 243 5 6 + total + scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + analog + + + 243 5 6 + total + nu-scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + absorption + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + absorption + tracklength + + + 243 2 + total + (n,2n) + tracklength + + + 243 2 + total + (n,3n) + tracklength + + + 243 2 + total + (n,4n) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + absorption + tracklength + + + 243 2 + total + fission + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + fission + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + nu-fission + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + kappa-fission + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + scatter + tracklength + + + 243 2 + total + flux + analog + + + 243 2 + total + nu-scatter + analog + + + 243 2 + total + flux + analog + + + 243 2 5 30 + total + scatter + analog + + + 243 2 + total + flux + analog + + + 243 2 5 30 + total + nu-scatter + analog + + + 243 2 5 + total + nu-scatter + analog + + + 243 2 5 + total + scatter + analog + + + 243 2 + total + flux + analog + + + 243 2 5 + total + nu-fission + analog + + + 243 2 5 + total + scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + scatter + tracklength + + + 243 2 5 30 + total + scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + scatter + tracklength + + + 243 2 5 30 + total + scatter + analog + + + 243 2 5 + total + nu-scatter + analog + + + 243 54 + total + nu-fission + analog + + + 243 5 + total + nu-fission + analog + + + 243 54 + total + prompt-nu-fission + analog + + + 243 5 + total + prompt-nu-fission + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + inverse-velocity + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + prompt-nu-fission + tracklength + + + 243 2 + total + flux + analog + + + 243 2 5 + total + prompt-nu-fission + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + analog + + + 243 5 6 + total + scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + total + tracklength + + + 243 2 + total + flux + analog + + + 243 5 6 + total + nu-scatter + analog + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,elastic) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,level) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,2n) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,na) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,nc) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,gamma) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,a) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,Xa) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + heating + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + damage-energy + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,n1) + tracklength + + + 243 2 + total + flux + tracklength + + + 243 2 + total + (n,a0) + tracklength + + + 243 2 + total + flux + analog + + + 243 2 5 + total + (n,nc) + analog + + + 243 2 + total + flux + analog + + + 243 2 5 + total + (n,n1) + analog + + + 243 2 + total + flux + analog + + + 243 2 5 + total + (n,2n) + analog + + + 243 2 + total + flux + tracklength + + + 243 108 2 + total + delayed-nu-fission + tracklength + + + 243 108 54 + total + delayed-nu-fission + analog + + + 243 108 5 + total + delayed-nu-fission + analog + + + 243 2 + total + nu-fission + tracklength + + + 243 108 2 + total + delayed-nu-fission + tracklength + + + 243 108 + total + delayed-nu-fission + tracklength + + + 243 108 + total + decay-rate + tracklength + + + 243 2 + total + flux + analog + + + 243 108 2 5 + total + delayed-nu-fission + analog + + + diff --git a/tests/regression_tests/mgxs_library_no_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_no_nuclides/results_true.dat index f2f66b0d094..c0dba7c0fb5 100644 --- a/tests/regression_tests/mgxs_library_no_nuclides/results_true.dat +++ b/tests/regression_tests/mgxs_library_no_nuclides/results_true.dat @@ -1,329 +1,333 @@ total material group in nuclide mean std. dev. -1 1 1 total 0.416386 0.014741 -0 1 2 total 0.658651 0.060521 +1 1 1 total 0.413814 0.018434 +0 1 2 total 0.663001 0.012535 transport material group in nuclide mean std. dev. -1 1 1 total 0.378343 0.016533 -0 1 2 total 0.641137 0.060797 +1 1 1 total 0.369730 0.019494 +0 1 2 total 0.643777 0.018246 nu-transport material group in nuclide mean std. dev. -1 1 1 total 0.378437 0.016556 -0 1 2 total 0.641137 0.060797 +1 1 1 total 0.369730 0.019494 +0 1 2 total 0.643777 0.018246 absorption material group in nuclide mean std. dev. -1 1 1 total 0.027335 0.002038 -0 1 2 total 0.263007 0.029616 +1 1 1 total 0.026013 0.001851 +0 1 2 total 0.267233 0.007475 +reduced absorption + material group in nuclide mean std. dev. +1 1 1 total 0.025932 0.001850 +0 1 2 total 0.267233 0.007475 capture material group in nuclide mean std. dev. -1 1 1 total 0.019722 0.001980 -0 1 2 total 0.071284 0.032059 +1 1 1 total 0.018869 0.001758 +0 1 2 total 0.072358 0.008204 fission material group in nuclide mean std. dev. -1 1 1 total 0.007613 0.000245 -0 1 2 total 0.191723 0.021698 +1 1 1 total 0.007144 0.000317 +0 1 2 total 0.194875 0.005528 nu-fission material group in nuclide mean std. dev. -1 1 1 total 0.019339 0.000628 -0 1 2 total 0.467173 0.052872 +1 1 1 total 0.018243 0.000827 +0 1 2 total 0.474851 0.013471 kappa-fission material group in nuclide mean std. dev. -1 1 1 total 1.482697e+06 4.755501e+04 -0 1 2 total 3.708035e+07 4.196524e+06 +1 1 1 total 1.391782e+06 6.192598e+04 +0 1 2 total 3.768981e+07 1.069211e+06 scatter material group in nuclide mean std. dev. -1 1 1 total 0.389051 0.013216 -0 1 2 total 0.395644 0.031715 +1 1 1 total 0.387802 0.017462 +0 1 2 total 0.395768 0.007541 nu-scatter material group in nuclide mean std. dev. -1 1 1 total 0.392313 0.009662 -0 1 2 total 0.385086 0.024132 +1 1 1 total 0.387032 0.024325 +0 1 2 total 0.407651 0.016266 scatter matrix material group in group out legendre nuclide mean std. dev. -12 1 1 1 P0 total 0.391262 0.009858 -13 1 1 1 P1 total 0.038043 0.007486 -14 1 1 1 P2 total 0.019717 0.003619 -15 1 1 1 P3 total 0.018917 0.001007 -8 1 1 2 P0 total 0.000876 0.000554 -9 1 1 2 P1 total -0.000275 0.000386 -10 1 1 2 P2 total 0.000074 0.000114 -11 1 1 2 P3 total 0.000141 0.000113 +12 1 1 1 P0 total 0.386336 0.024297 +13 1 1 1 P1 total 0.044084 0.006343 +14 1 1 1 P2 total 0.027336 0.006403 +15 1 1 1 P3 total 0.011672 0.004897 +8 1 1 2 P0 total 0.000695 0.000327 +9 1 1 2 P1 total -0.000359 0.000201 +10 1 1 2 P2 total -0.000047 0.000081 +11 1 1 2 P3 total 0.000239 0.000099 4 1 2 1 P0 total 0.000000 0.000000 5 1 2 1 P1 total 0.000000 0.000000 6 1 2 1 P2 total 0.000000 0.000000 7 1 2 1 P3 total 0.000000 0.000000 -0 1 2 2 P0 total 0.385086 0.024132 -1 1 2 2 P1 total 0.019196 0.005279 -2 1 2 2 P2 total -0.005654 0.006088 -3 1 2 2 P3 total 0.002768 0.007045 +0 1 2 2 P0 total 0.407651 0.016266 +1 1 2 2 P1 total 0.021192 0.013171 +2 1 2 2 P2 total 0.010327 0.017230 +3 1 2 2 P3 total 0.005148 0.013732 nu-scatter matrix material group in group out legendre nuclide mean std. dev. -12 1 1 1 P0 total 0.391437 0.009813 -13 1 1 1 P1 total 0.037949 0.007537 -14 1 1 1 P2 total 0.019705 0.003623 -15 1 1 1 P3 total 0.018991 0.001065 -8 1 1 2 P0 total 0.000876 0.000554 -9 1 1 2 P1 total -0.000275 0.000386 -10 1 1 2 P2 total 0.000074 0.000114 -11 1 1 2 P3 total 0.000141 0.000113 +12 1 1 1 P0 total 0.386336 0.024297 +13 1 1 1 P1 total 0.044084 0.006343 +14 1 1 1 P2 total 0.027336 0.006403 +15 1 1 1 P3 total 0.011672 0.004897 +8 1 1 2 P0 total 0.000695 0.000327 +9 1 1 2 P1 total -0.000359 0.000201 +10 1 1 2 P2 total -0.000047 0.000081 +11 1 1 2 P3 total 0.000239 0.000099 4 1 2 1 P0 total 0.000000 0.000000 5 1 2 1 P1 total 0.000000 0.000000 6 1 2 1 P2 total 0.000000 0.000000 7 1 2 1 P3 total 0.000000 0.000000 -0 1 2 2 P0 total 0.385086 0.024132 -1 1 2 2 P1 total 0.019196 0.005279 -2 1 2 2 P2 total -0.005654 0.006088 -3 1 2 2 P3 total 0.002768 0.007045 +0 1 2 2 P0 total 0.407651 0.016266 +1 1 2 2 P1 total 0.021192 0.013171 +2 1 2 2 P2 total 0.010327 0.017230 +3 1 2 2 P3 total 0.005148 0.013732 multiplicity matrix - material group in group out nuclide mean std. dev. -3 1 1 1 total 1.000448 0.020416 -2 1 1 2 total 1.000000 0.894427 -1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 1.000000 0.085266 + material group in group out nuclide mean std. dev. +3 1 1 1 total 1.0 0.064268 +2 1 1 2 total 1.0 0.661438 +1 1 2 1 total 0.0 0.000000 +0 1 2 2 total 1.0 0.050545 nu-fission matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.017516 0.001935 +3 1 1 1 total 0.024633 0.002205 2 1 1 2 total 0.000000 0.000000 -1 1 2 1 total 0.498681 0.013398 +1 1 2 1 total 0.435159 0.014743 0 1 2 2 total 0.000000 0.000000 scatter probability matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.997766 0.020541 -2 1 1 2 total 0.002234 0.001413 +3 1 1 1 total 0.998203 0.064101 +2 1 1 2 total 0.001797 0.000844 1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 1.000000 0.085266 +0 1 2 2 total 1.000000 0.050545 consistent scatter matrix material group in group out legendre nuclide mean std. dev. -12 1 1 1 P0 total 0.388182 0.015419 -13 1 1 1 P1 total 0.037744 0.007517 -14 1 1 1 P2 total 0.019562 0.003641 -15 1 1 1 P3 total 0.018769 0.001154 -8 1 1 2 P0 total 0.000869 0.000551 -9 1 1 2 P1 total -0.000273 0.000383 -10 1 1 2 P2 total 0.000073 0.000113 -11 1 1 2 P3 total 0.000140 0.000112 +12 1 1 1 P0 total 0.387105 0.030361 +13 1 1 1 P1 total 0.044172 0.006684 +14 1 1 1 P2 total 0.027391 0.006543 +15 1 1 1 P3 total 0.011695 0.004937 +8 1 1 2 P0 total 0.000697 0.000329 +9 1 1 2 P1 total -0.000360 0.000202 +10 1 1 2 P2 total -0.000047 0.000082 +11 1 1 2 P3 total 0.000239 0.000100 4 1 2 1 P0 total 0.000000 0.000000 5 1 2 1 P1 total 0.000000 0.000000 6 1 2 1 P2 total 0.000000 0.000000 7 1 2 1 P3 total 0.000000 0.000000 -0 1 2 2 P0 total 0.395644 0.046302 -1 1 2 2 P1 total 0.019723 0.005763 -2 1 2 2 P2 total -0.005809 0.006281 -3 1 2 2 P3 total 0.002843 0.007244 +0 1 2 2 P0 total 0.395768 0.021378 +1 1 2 2 P1 total 0.020575 0.012809 +2 1 2 2 P2 total 0.010026 0.016732 +3 1 2 2 P3 total 0.004998 0.013333 consistent nu-scatter matrix material group in group out legendre nuclide mean std. dev. -12 1 1 1 P0 total 0.388355 0.017343 -13 1 1 1 P1 total 0.037760 0.007560 -14 1 1 1 P2 total 0.019571 0.003664 -15 1 1 1 P3 total 0.018777 0.001216 -8 1 1 2 P0 total 0.000869 0.000953 -9 1 1 2 P1 total -0.000273 0.000454 -10 1 1 2 P2 total 0.000073 0.000131 -11 1 1 2 P3 total 0.000140 0.000168 +12 1 1 1 P0 total 0.387105 0.039252 +13 1 1 1 P1 total 0.044172 0.007262 +14 1 1 1 P2 total 0.027391 0.006776 +15 1 1 1 P3 total 0.011695 0.004994 +8 1 1 2 P0 total 0.000697 0.000566 +9 1 1 2 P1 total -0.000360 0.000313 +10 1 1 2 P2 total -0.000047 0.000087 +11 1 1 2 P3 total 0.000239 0.000187 4 1 2 1 P0 total 0.000000 0.000000 5 1 2 1 P1 total 0.000000 0.000000 6 1 2 1 P2 total 0.000000 0.000000 7 1 2 1 P3 total 0.000000 0.000000 -0 1 2 2 P0 total 0.395644 0.057288 -1 1 2 2 P1 total 0.019723 0.006004 -2 1 2 2 P2 total -0.005809 0.006300 -3 1 2 2 P3 total 0.002843 0.007248 +0 1 2 2 P0 total 0.395768 0.029278 +1 1 2 2 P1 total 0.020575 0.012851 +2 1 2 2 P2 total 0.010026 0.016739 +3 1 2 2 P3 total 0.004998 0.013335 chi material group out nuclide mean std. dev. -1 1 1 total 1.0 0.029903 +1 1 1 total 1.0 0.039887 0 1 2 total 0.0 0.000000 chi-prompt material group out nuclide mean std. dev. -1 1 1 total 1.0 0.028494 +1 1 1 total 1.0 0.039887 0 1 2 total 0.0 0.000000 inverse-velocity material group in nuclide mean std. dev. -1 1 1 total 6.148626e-08 3.647428e-09 -0 1 2 total 2.844242e-06 3.098231e-07 +1 1 1 total 5.956290e-08 2.255751e-09 +0 1 2 total 2.886630e-06 7.418452e-08 prompt-nu-fission material group in nuclide mean std. dev. -1 1 1 total 0.019154 0.000623 -0 1 2 total 0.464134 0.052528 +1 1 1 total 0.018067 0.000817 +0 1 2 total 0.471762 0.013383 prompt-nu-fission matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.017516 0.001935 +3 1 1 1 total 0.024633 0.002205 2 1 1 2 total 0.000000 0.000000 -1 1 2 1 total 0.495450 0.012592 +1 1 2 1 total 0.435159 0.014743 0 1 2 2 total 0.000000 0.000000 diffusion-coefficient - material group in legendre nuclide mean std. dev. -2 1 1 P0 total 13.267434 9.377780 -3 1 1 P1 total 0.881035 0.050823 -0 1 2 P0 total 1.242844 0.316720 -1 1 2 P1 total 0.519910 0.064395 + material group in nuclide mean std. dev. +1 1 1 total 0.901559 0.047536 +0 1 2 total 0.517778 0.014675 nu-diffusion-coefficient - material group in legendre nuclide mean std. dev. -2 1 1 P0 total 13.360612 9.496523 -3 1 1 P1 total 0.880816 0.050843 -0 1 2 P0 total 1.242844 0.316720 -1 1 2 P1 total 0.519910 0.064395 + material group in nuclide mean std. dev. +1 1 1 total 0.901559 0.047536 +0 1 2 total 0.517778 0.014675 (n,elastic) material group in nuclide mean std. dev. -1 1 1 total 0.361427 0.011879 -0 1 2 total 0.395644 0.031715 +1 1 1 total 0.360179 0.016169 +0 1 2 total 0.395768 0.007541 (n,level) material group in nuclide mean std. dev. -1 1 1 total 0.000549 0.000035 +1 1 1 total 0.000568 0.000028 0 1 2 total 0.000000 0.000000 (n,2n) material group in nuclide mean std. dev. -1 1 1 total 0.000058 0.000012 +1 1 1 total 0.000079 0.000042 0 1 2 total 0.000000 0.000000 (n,na) material group in nuclide mean std. dev. -1 1 1 total 4.608391e-11 2.324841e-11 +1 1 1 total 8.510945e-07 8.515320e-07 0 1 2 total 0.000000e+00 0.000000e+00 (n,nc) material group in nuclide mean std. dev. -1 1 1 total 0.008349 0.000869 +1 1 1 total 0.008258 0.000928 0 1 2 total 0.000000 0.000000 (n,gamma) material group in nuclide mean std. dev. -1 1 1 total 0.019640 0.001935 -0 1 2 total 0.071284 0.007918 +1 1 1 total 0.018749 0.001838 +0 1 2 total 0.072358 0.001951 (n,a) material group in nuclide mean std. dev. -1 1 1 total 0.000082 0.000016 +1 1 1 total 0.000119 0.000023 0 1 2 total 0.000000 0.000000 (n,Xa) - material group in nuclide mean std. dev. -1 1 1 total 0.000082 0.000016 -0 1 2 total 0.000000 0.000000 + material group in nuclide mean std. dev. +1 1 1 total 0.00012 0.000022 +0 1 2 total 0.00000 0.000000 heating - material group in nuclide mean std. dev. -1 1 1 total 1.302118e+06 4.240633e+04 -0 1 2 total 3.235834e+07 3.683247e+06 + material group in nuclide mean std. dev. +1 1 1 total 1.216089e+06 54827.397330 +0 1 2 total 3.262993e+07 904277.817101 damage-energy material group in nuclide mean std. dev. -1 1 1 total 2323.848080 106.914413 -0 1 2 total 1349.749682 152.756195 +1 1 1 total 2317.176742 165.734097 +0 1 2 total 1371.933922 38.919660 (n,n1) material group in nuclide mean std. dev. -1 1 1 total 0.011709 0.000412 +1 1 1 total 0.012055 0.000759 0 1 2 total 0.000000 0.000000 (n,a0) material group in nuclide mean std. dev. -1 1 1 total 0.000076 0.000018 +1 1 1 total 0.000109 0.000028 0 1 2 total 0.000000 0.000000 (n,nc) matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.007009 0.000797 +3 1 1 1 total 0.009563 0.001002 2 1 1 2 total 0.000000 0.000000 1 1 2 1 total 0.000000 0.000000 0 1 2 2 total 0.000000 0.000000 (n,n1) matrix - material group in group out nuclide mean std. dev. -3 1 1 1 total 0.01209 0.00108 -2 1 1 2 total 0.00000 0.00000 -1 1 2 1 total 0.00000 0.00000 -0 1 2 2 total 0.00000 0.00000 -(n,2n) matrix material group in group out nuclide mean std. dev. -3 1 1 1 total 0.000175 0.000175 -2 1 1 2 total 0.000000 0.000000 -1 1 2 1 total 0.000000 0.000000 -0 1 2 2 total 0.000000 0.000000 +3 1 1 1 total 0.013909 0.00145 +2 1 1 2 total 0.000000 0.00000 +1 1 2 1 total 0.000000 0.00000 +0 1 2 2 total 0.000000 0.00000 +(n,2n) matrix + material group in group out nuclide mean std. dev. +3 1 1 1 total 0.0 0.0 +2 1 1 2 total 0.0 0.0 +1 1 2 1 total 0.0 0.0 +0 1 2 2 total 0.0 0.0 delayed-nu-fission material delayedgroup group in nuclide mean std. dev. -1 1 1 1 total 0.000004 1.358228e-07 -3 1 2 1 total 0.000027 8.873679e-07 -5 1 3 1 total 0.000028 1.017223e-06 -7 1 4 1 total 0.000071 3.064066e-06 -9 1 5 1 total 0.000039 2.180731e-06 -11 1 6 1 total 0.000016 8.808101e-07 -0 1 1 2 total 0.000106 1.203961e-05 -2 1 2 2 total 0.000549 6.214477e-05 -4 1 3 2 total 0.000524 5.932882e-05 -6 1 4 2 total 0.001175 1.330202e-04 -8 1 5 2 total 0.000482 5.453651e-05 -10 1 6 2 total 0.000202 2.284515e-05 +1 1 1 1 total 0.000004 1.857100e-07 +3 1 2 1 total 0.000025 1.293123e-06 +5 1 3 1 total 0.000026 1.448812e-06 +7 1 4 1 total 0.000068 4.132525e-06 +9 1 5 1 total 0.000037 2.670208e-06 +11 1 6 1 total 0.000015 1.084541e-06 +0 1 1 2 total 0.000108 3.067510e-06 +2 1 2 2 total 0.000558 1.583355e-05 +4 1 3 2 total 0.000533 1.511609e-05 +6 1 4 2 total 0.001195 3.389154e-05 +8 1 5 2 total 0.000490 1.389508e-05 +10 1 6 2 total 0.000205 5.820598e-06 chi-delayed material delayedgroup group out nuclide mean std. dev. -1 1 1 1 total 0.0 0.000000 -3 1 2 1 total 1.0 1.414214 -5 1 3 1 total 0.0 0.000000 -7 1 4 1 total 1.0 1.414214 -9 1 5 1 total 1.0 1.414214 -11 1 6 1 total 0.0 0.000000 -0 1 1 2 total 0.0 0.000000 -2 1 2 2 total 0.0 0.000000 -4 1 3 2 total 0.0 0.000000 -6 1 4 2 total 0.0 0.000000 -8 1 5 2 total 0.0 0.000000 -10 1 6 2 total 0.0 0.000000 +1 1 1 1 total 0.0 0.0 +3 1 2 1 total 0.0 0.0 +5 1 3 1 total 0.0 0.0 +7 1 4 1 total 0.0 0.0 +9 1 5 1 total 0.0 0.0 +11 1 6 1 total 0.0 0.0 +0 1 1 2 total 0.0 0.0 +2 1 2 2 total 0.0 0.0 +4 1 3 2 total 0.0 0.0 +6 1 4 2 total 0.0 0.0 +8 1 5 2 total 0.0 0.0 +10 1 6 2 total 0.0 0.0 beta material delayedgroup group in nuclide mean std. dev. -1 1 1 1 total 0.000225 0.000006 -3 1 2 1 total 0.001373 0.000038 -5 1 3 1 total 0.001433 0.000045 -7 1 4 1 total 0.003692 0.000142 -9 1 5 1 total 0.002016 0.000106 -11 1 6 1 total 0.000827 0.000043 -0 1 1 2 total 0.000228 0.000032 -2 1 2 2 total 0.001175 0.000163 -4 1 3 2 total 0.001122 0.000156 -6 1 4 2 total 0.002516 0.000349 -8 1 5 2 total 0.001031 0.000143 -10 1 6 2 total 0.000432 0.000060 +1 1 1 1 total 0.000223 0.000009 +3 1 2 1 total 0.001375 0.000067 +5 1 3 1 total 0.001439 0.000076 +7 1 4 1 total 0.003724 0.000217 +9 1 5 1 total 0.002049 0.000142 +11 1 6 1 total 0.000840 0.000058 +0 1 1 2 total 0.000228 0.000008 +2 1 2 2 total 0.001175 0.000041 +4 1 3 2 total 0.001122 0.000040 +6 1 4 2 total 0.002516 0.000089 +8 1 5 2 total 0.001031 0.000036 +10 1 6 2 total 0.000432 0.000015 decay-rate material delayedgroup nuclide mean std. dev. -0 1 1 total 0.013356 0.001466 -1 1 2 total 0.032598 0.003432 -2 1 3 total 0.121086 0.012382 -3 1 4 total 0.305945 0.029907 -4 1 5 total 0.862061 0.077144 -5 1 6 total 2.895499 0.260691 +0 1 1 total 0.013353 0.000379 +1 1 2 total 0.032612 0.001002 +2 1 3 total 0.121056 0.003938 +3 1 4 total 0.305642 0.010892 +4 1 5 total 0.860947 0.036893 +5 1 6 total 2.891708 0.122310 delayed-nu-fission matrix - material delayedgroup group in group out nuclide mean std. dev. -3 1 1 1 1 total 0.000000 0.000000 -7 1 2 1 1 total 0.000000 0.000000 -11 1 3 1 1 total 0.000000 0.000000 -15 1 4 1 1 total 0.000000 0.000000 -19 1 5 1 1 total 0.000000 0.000000 -23 1 6 1 1 total 0.000000 0.000000 -2 1 1 1 2 total 0.000000 0.000000 -6 1 2 1 2 total 0.000000 0.000000 -10 1 3 1 2 total 0.000000 0.000000 -14 1 4 1 2 total 0.000000 0.000000 -18 1 5 1 2 total 0.000000 0.000000 -22 1 6 1 2 total 0.000000 0.000000 -1 1 1 2 1 total 0.000000 0.000000 -5 1 2 2 1 total 0.001133 0.001133 -9 1 3 2 1 total 0.000000 0.000000 -13 1 4 2 1 total 0.000988 0.000989 -17 1 5 2 1 total 0.001109 0.001109 -21 1 6 2 1 total 0.000000 0.000000 -0 1 1 2 2 total 0.000000 0.000000 -4 1 2 2 2 total 0.000000 0.000000 -8 1 3 2 2 total 0.000000 0.000000 -12 1 4 2 2 total 0.000000 0.000000 -16 1 5 2 2 total 0.000000 0.000000 -20 1 6 2 2 total 0.000000 0.000000 + material delayedgroup group in group out nuclide mean std. dev. +3 1 1 1 1 total 0.0 0.0 +7 1 2 1 1 total 0.0 0.0 +11 1 3 1 1 total 0.0 0.0 +15 1 4 1 1 total 0.0 0.0 +19 1 5 1 1 total 0.0 0.0 +23 1 6 1 1 total 0.0 0.0 +2 1 1 1 2 total 0.0 0.0 +6 1 2 1 2 total 0.0 0.0 +10 1 3 1 2 total 0.0 0.0 +14 1 4 1 2 total 0.0 0.0 +18 1 5 1 2 total 0.0 0.0 +22 1 6 1 2 total 0.0 0.0 +1 1 1 2 1 total 0.0 0.0 +5 1 2 2 1 total 0.0 0.0 +9 1 3 2 1 total 0.0 0.0 +13 1 4 2 1 total 0.0 0.0 +17 1 5 2 1 total 0.0 0.0 +21 1 6 2 1 total 0.0 0.0 +0 1 1 2 2 total 0.0 0.0 +4 1 2 2 2 total 0.0 0.0 +8 1 3 2 2 total 0.0 0.0 +12 1 4 2 2 total 0.0 0.0 +16 1 5 2 2 total 0.0 0.0 +20 1 6 2 2 total 0.0 0.0 total material group in nuclide mean std. dev. -1 2 1 total 0.312441 0.009893 -0 2 2 total 0.300527 0.023155 +1 2 1 total 0.313574 0.016009 +0 2 2 total 0.300858 0.005911 transport material group in nuclide mean std. dev. -1 2 1 total 0.275347 0.016021 -0 2 2 total 0.300167 0.026917 +1 2 1 total 0.266154 0.017348 +0 2 2 total 0.300597 0.011062 nu-transport material group in nuclide mean std. dev. -1 2 1 total 0.275347 0.016021 -0 2 2 total 0.300167 0.026917 +1 2 1 total 0.266154 0.017348 +0 2 2 total 0.300597 0.011062 absorption + material group in nuclide mean std. dev. +1 2 1 total 0.00150 0.000118 +0 2 2 total 0.00542 0.000201 +reduced absorption material group in nuclide mean std. dev. -1 2 1 total 0.001395 0.000129 -0 2 2 total 0.005202 0.000498 +1 2 1 total 0.001481 0.000119 +0 2 2 total 0.005420 0.000201 capture - material group in nuclide mean std. dev. -1 2 1 total 0.001395 0.000129 -0 2 2 total 0.005202 0.000498 + material group in nuclide mean std. dev. +1 2 1 total 0.00150 0.000118 +0 2 2 total 0.00542 0.000201 fission material group in nuclide mean std. dev. 1 2 1 total 0.0 0.0 @@ -338,54 +342,54 @@ kappa-fission 0 2 2 total 0.0 0.0 scatter material group in nuclide mean std. dev. -1 2 1 total 0.311046 0.009880 -0 2 2 total 0.295325 0.022678 +1 2 1 total 0.312074 0.015934 +0 2 2 total 0.295438 0.005743 nu-scatter material group in nuclide mean std. dev. -1 2 1 total 0.310433 0.013519 -0 2 2 total 0.287667 0.061288 +1 2 1 total 0.318594 0.023203 +0 2 2 total 0.295662 0.031486 scatter matrix - material group in group out legendre nuclide mean std. dev. -12 2 1 1 P0 total 3.099468e-01 1.368691e-02 -13 2 1 1 P1 total 3.709418e-02 1.260219e-02 -14 2 1 1 P2 total 2.620103e-02 2.237097e-03 -15 2 1 1 P3 total 1.039112e-02 2.917283e-03 -8 2 1 2 P0 total 4.858100e-04 4.860246e-04 -9 2 1 2 P1 total 3.762752e-04 3.764414e-04 -10 2 1 2 P2 total 1.942506e-04 1.943364e-04 -11 2 1 2 P3 total -9.482181e-08 9.486370e-08 -4 2 2 1 P0 total 0.000000e+00 0.000000e+00 -5 2 2 1 P1 total 0.000000e+00 0.000000e+00 -6 2 2 1 P2 total 0.000000e+00 0.000000e+00 -7 2 2 1 P3 total 0.000000e+00 0.000000e+00 -0 2 2 2 P0 total 2.876667e-01 6.128794e-02 -1 2 2 2 P1 total -2.172735e-03 1.616275e-02 -2 2 2 2 P2 total 9.596560e-03 1.756046e-02 -3 2 2 2 P3 total -5.006322e-03 1.249952e-02 + material group in group out legendre nuclide mean std. dev. +12 2 1 1 P0 total 0.318594 0.023203 +13 2 1 1 P1 total 0.047420 0.006684 +14 2 1 1 P2 total 0.029426 0.008048 +15 2 1 1 P3 total 0.007335 0.004092 +8 2 1 2 P0 total 0.000000 0.000000 +9 2 1 2 P1 total 0.000000 0.000000 +10 2 1 2 P2 total 0.000000 0.000000 +11 2 1 2 P3 total 0.000000 0.000000 +4 2 2 1 P0 total 0.000000 0.000000 +5 2 2 1 P1 total 0.000000 0.000000 +6 2 2 1 P2 total 0.000000 0.000000 +7 2 2 1 P3 total 0.000000 0.000000 +0 2 2 2 P0 total 0.295662 0.031486 +1 2 2 2 P1 total 0.000261 0.009350 +2 2 2 2 P2 total -0.004912 0.007866 +3 2 2 2 P3 total -0.018278 0.012339 nu-scatter matrix - material group in group out legendre nuclide mean std. dev. -12 2 1 1 P0 total 3.099468e-01 1.368691e-02 -13 2 1 1 P1 total 3.709418e-02 1.260219e-02 -14 2 1 1 P2 total 2.620103e-02 2.237097e-03 -15 2 1 1 P3 total 1.039112e-02 2.917283e-03 -8 2 1 2 P0 total 4.858100e-04 4.860246e-04 -9 2 1 2 P1 total 3.762752e-04 3.764414e-04 -10 2 1 2 P2 total 1.942506e-04 1.943364e-04 -11 2 1 2 P3 total -9.482181e-08 9.486370e-08 -4 2 2 1 P0 total 0.000000e+00 0.000000e+00 -5 2 2 1 P1 total 0.000000e+00 0.000000e+00 -6 2 2 1 P2 total 0.000000e+00 0.000000e+00 -7 2 2 1 P3 total 0.000000e+00 0.000000e+00 -0 2 2 2 P0 total 2.876667e-01 6.128794e-02 -1 2 2 2 P1 total -2.172735e-03 1.616275e-02 -2 2 2 2 P2 total 9.596560e-03 1.756046e-02 -3 2 2 2 P3 total -5.006322e-03 1.249952e-02 + material group in group out legendre nuclide mean std. dev. +12 2 1 1 P0 total 0.318594 0.023203 +13 2 1 1 P1 total 0.047420 0.006684 +14 2 1 1 P2 total 0.029426 0.008048 +15 2 1 1 P3 total 0.007335 0.004092 +8 2 1 2 P0 total 0.000000 0.000000 +9 2 1 2 P1 total 0.000000 0.000000 +10 2 1 2 P2 total 0.000000 0.000000 +11 2 1 2 P3 total 0.000000 0.000000 +4 2 2 1 P0 total 0.000000 0.000000 +5 2 2 1 P1 total 0.000000 0.000000 +6 2 2 1 P2 total 0.000000 0.000000 +7 2 2 1 P3 total 0.000000 0.000000 +0 2 2 2 P0 total 0.295662 0.031486 +1 2 2 2 P1 total 0.000261 0.009350 +2 2 2 2 P2 total -0.004912 0.007866 +3 2 2 2 P3 total -0.018278 0.012339 multiplicity matrix material group in group out nuclide mean std. dev. -3 2 1 1 total 1.0 0.046178 -2 2 1 2 total 1.0 1.414214 +3 2 1 1 total 1.0 0.071770 +2 2 1 2 total 0.0 0.000000 1 2 2 1 total 0.0 0.000000 -0 2 2 2 total 1.0 0.204230 +0 2 2 2 total 1.0 0.103652 nu-fission matrix material group in group out nuclide mean std. dev. 3 2 1 1 total 0.0 0.0 @@ -393,47 +397,47 @@ nu-fission matrix 1 2 2 1 total 0.0 0.0 0 2 2 2 total 0.0 0.0 scatter probability matrix - material group in group out nuclide mean std. dev. -3 2 1 1 total 0.998435 0.046097 -2 2 1 2 total 0.001565 0.001566 -1 2 2 1 total 0.000000 0.000000 -0 2 2 2 total 1.000000 0.204230 + material group in group out nuclide mean std. dev. +3 2 1 1 total 1.0 0.071770 +2 2 1 2 total 0.0 0.000000 +1 2 2 1 total 0.0 0.000000 +0 2 2 2 total 1.0 0.103652 consistent scatter matrix - material group in group out legendre nuclide mean std. dev. -12 2 1 1 P0 total 3.105594e-01 1.740367e-02 -13 2 1 1 P1 total 3.716750e-02 1.269205e-02 -14 2 1 1 P2 total 2.625282e-02 2.417618e-03 -15 2 1 1 P3 total 1.041166e-02 2.945041e-03 -8 2 1 2 P0 total 4.867703e-04 4.872749e-04 -9 2 1 2 P1 total 3.770190e-04 3.774098e-04 -10 2 1 2 P2 total 1.946345e-04 1.948363e-04 -11 2 1 2 P3 total -9.500924e-08 9.510772e-08 -4 2 2 1 P0 total 0.000000e+00 0.000000e+00 -5 2 2 1 P1 total 0.000000e+00 0.000000e+00 -6 2 2 1 P2 total 0.000000e+00 0.000000e+00 -7 2 2 1 P3 total 0.000000e+00 0.000000e+00 -0 2 2 2 P0 total 2.953250e-01 6.443681e-02 -1 2 2 2 P1 total -2.230578e-03 1.659337e-02 -2 2 2 2 P2 total 9.852041e-03 1.803392e-02 -3 2 2 2 P3 total -5.139601e-03 1.283456e-02 + material group in group out legendre nuclide mean std. dev. +12 2 1 1 P0 total 0.312074 0.027487 +13 2 1 1 P1 total 0.046450 0.006939 +14 2 1 1 P2 total 0.028824 0.008012 +15 2 1 1 P3 total 0.007185 0.004024 +8 2 1 2 P0 total 0.000000 0.000000 +9 2 1 2 P1 total 0.000000 0.000000 +10 2 1 2 P2 total 0.000000 0.000000 +11 2 1 2 P3 total 0.000000 0.000000 +4 2 2 1 P0 total 0.000000 0.000000 +5 2 2 1 P1 total 0.000000 0.000000 +6 2 2 1 P2 total 0.000000 0.000000 +7 2 2 1 P3 total 0.000000 0.000000 +0 2 2 2 P0 total 0.295438 0.031157 +1 2 2 2 P1 total 0.000261 0.009343 +2 2 2 2 P2 total -0.004909 0.007859 +3 2 2 2 P3 total -0.018264 0.012327 consistent nu-scatter matrix - material group in group out legendre nuclide mean std. dev. -12 2 1 1 P0 total 3.105594e-01 2.255119e-02 -13 2 1 1 P1 total 3.716750e-02 1.280757e-02 -14 2 1 1 P2 total 2.625282e-02 2.704548e-03 -15 2 1 1 P3 total 1.041166e-02 2.984029e-03 -8 2 1 2 P0 total 4.867703e-04 8.434023e-04 -9 2 1 2 P1 total 3.770190e-04 6.532417e-04 -10 2 1 2 P2 total 1.946345e-04 3.372334e-04 -11 2 1 2 P3 total -9.500924e-08 1.646177e-07 -4 2 2 1 P0 total 0.000000e+00 0.000000e+00 -5 2 2 1 P1 total 0.000000e+00 0.000000e+00 -6 2 2 1 P2 total 0.000000e+00 0.000000e+00 -7 2 2 1 P3 total 0.000000e+00 0.000000e+00 -0 2 2 2 P0 total 2.953250e-01 8.826037e-02 -1 2 2 2 P1 total -2.230578e-03 1.659963e-02 -2 2 2 2 P2 total 9.852041e-03 1.814582e-02 -3 2 2 2 P3 total -5.139601e-03 1.287741e-02 + material group in group out legendre nuclide mean std. dev. +12 2 1 1 P0 total 0.312074 0.035456 +13 2 1 1 P1 total 0.046450 0.007699 +14 2 1 1 P2 total 0.028824 0.008274 +15 2 1 1 P3 total 0.007185 0.004057 +8 2 1 2 P0 total 0.000000 0.000000 +9 2 1 2 P1 total 0.000000 0.000000 +10 2 1 2 P2 total 0.000000 0.000000 +11 2 1 2 P3 total 0.000000 0.000000 +4 2 2 1 P0 total 0.000000 0.000000 +5 2 2 1 P1 total 0.000000 0.000000 +6 2 2 1 P2 total 0.000000 0.000000 +7 2 2 1 P3 total 0.000000 0.000000 +0 2 2 2 P0 total 0.295438 0.043686 +1 2 2 2 P1 total 0.000261 0.009343 +2 2 2 2 P2 total -0.004909 0.007876 +3 2 2 2 P3 total -0.018264 0.012471 chi material group out nuclide mean std. dev. 1 2 1 total 0.0 0.0 @@ -444,8 +448,8 @@ chi-prompt 0 2 2 total 0.0 0.0 inverse-velocity material group in nuclide mean std. dev. -1 2 1 total 6.397171e-08 3.117086e-09 -0 2 2 total 2.875630e-06 2.751730e-07 +1 2 1 total 6.076563e-08 2.727519e-09 +0 2 2 total 2.996176e-06 1.110139e-07 prompt-nu-fission material group in nuclide mean std. dev. 1 2 1 total 0.0 0.0 @@ -457,74 +461,70 @@ prompt-nu-fission matrix 1 2 2 1 total 0.0 0.0 0 2 2 2 total 0.0 0.0 diffusion-coefficient - material group in legendre nuclide mean std. dev. -2 2 1 P0 total 133.637358 904.804108 -3 2 1 P1 total 1.210594 0.082668 -0 2 2 P0 total 34.754997 241.483530 -1 2 2 P1 total 1.110491 0.131041 + material group in nuclide mean std. dev. +1 2 1 total 1.252406 0.081631 +0 2 2 total 1.108904 0.040809 nu-diffusion-coefficient - material group in legendre nuclide mean std. dev. -2 2 1 P0 total 133.637358 904.804108 -3 2 1 P1 total 1.210594 0.082668 -0 2 2 P0 total 34.754997 241.483530 -1 2 2 P1 total 1.110491 0.131041 + material group in nuclide mean std. dev. +1 2 1 total 1.252406 0.081631 +0 2 2 total 1.108904 0.040809 (n,elastic) material group in nuclide mean std. dev. -1 2 1 total 0.301494 0.009403 -0 2 2 total 0.295325 0.022678 +1 2 1 total 0.302664 0.015531 +0 2 2 total 0.295438 0.005743 (n,level) material group in nuclide mean std. dev. 1 2 1 total 0.0 0.0 0 2 2 total 0.0 0.0 (n,2n) material group in nuclide mean std. dev. -1 2 1 total 0.000005 0.000003 +1 2 1 total 0.000019 0.000017 0 2 2 total 0.000000 0.000000 (n,na) material group in nuclide mean std. dev. -1 2 1 total 1.085156e-09 6.357350e-10 +1 2 1 total 4.892570e-09 4.436228e-09 0 2 2 total 0.000000e+00 0.000000e+00 (n,nc) material group in nuclide mean std. dev. -1 2 1 total 0.001947 0.000276 +1 2 1 total 0.001998 0.000408 0 2 2 total 0.000000 0.000000 (n,gamma) material group in nuclide mean std. dev. -1 2 1 total 0.001392 0.000128 -0 2 2 total 0.005201 0.000498 +1 2 1 total 0.001497 0.000118 +0 2 2 total 0.005419 0.000201 (n,a) material group in nuclide mean std. dev. -1 2 1 total 8.373873e-07 5.295954e-08 -0 2 2 total 2.735007e-07 2.100237e-08 +1 2 1 total 9.546292e-07 9.180854e-08 +0 2 2 total 2.736059e-07 5.318732e-09 (n,Xa) material group in nuclide mean std. dev. -1 2 1 total 8.384725e-07 5.277215e-08 -0 2 2 total 2.735007e-07 2.100237e-08 +1 2 1 total 9.595218e-07 9.558005e-08 +0 2 2 total 2.736059e-07 5.318732e-09 heating material group in nuclide mean std. dev. -1 2 1 total 2151.700349 142.319459 -0 2 2 total 1.947222 0.155279 +1 2 1 total 2551.878627 212.765665 +0 2 2 total 2.332139 0.087384 damage-energy - material group in nuclide mean std. dev. -1 2 1 total 1591.760682 90.145807 -0 2 2 total 0.284888 0.026354 + material group in nuclide mean std. dev. +1 2 1 total 1585.677533 130.382718 +0 2 2 total 0.295108 0.010079 (n,n1) material group in nuclide mean std. dev. -1 2 1 total 0.002962 0.00032 -0 2 2 total 0.000000 0.00000 +1 2 1 total 0.002835 0.000246 +0 2 2 total 0.000000 0.000000 (n,a0) material group in nuclide mean std. dev. -1 2 1 total 7.199126e-07 5.011215e-08 -0 2 2 total 2.732253e-07 2.098122e-08 +1 2 1 total 7.169006e-07 6.251188e-08 +0 2 2 total 2.733303e-07 5.313375e-09 (n,nc) matrix material group in group out nuclide mean std. dev. -3 2 1 1 total 0.002915 0.000493 +3 2 1 1 total 0.001489 0.001491 2 2 1 2 total 0.000000 0.000000 1 2 2 1 total 0.000000 0.000000 0 2 2 2 total 0.000000 0.000000 (n,n1) matrix material group in group out nuclide mean std. dev. -3 2 1 1 total 0.002429 0.001332 +3 2 1 1 total 0.001985 0.000507 2 2 1 2 total 0.000000 0.000000 1 2 2 1 total 0.000000 0.000000 0 2 2 2 total 0.000000 0.000000 @@ -612,24 +612,28 @@ delayed-nu-fission matrix 20 2 6 2 2 total 0.0 0.0 total material group in nuclide mean std. dev. -1 3 1 total 0.684512 0.015513 -0 3 2 total 2.038387 0.113839 +1 3 1 total 0.682896 0.024140 +0 3 2 total 2.032938 0.085675 transport material group in nuclide mean std. dev. -1 3 1 total 0.291947 0.019086 -0 3 2 total 1.464248 0.116005 +1 3 1 total 0.298986 0.026905 +0 3 2 total 1.471887 0.096907 nu-transport material group in nuclide mean std. dev. -1 3 1 total 0.291947 0.019086 -0 3 2 total 1.464248 0.116005 +1 3 1 total 0.298986 0.026905 +0 3 2 total 1.471887 0.096907 absorption material group in nuclide mean std. dev. -1 3 1 total 0.000715 0.000032 -0 3 2 total 0.031290 0.001882 +1 3 1 total 0.000693 0.000020 +0 3 2 total 0.031171 0.001403 +reduced absorption + material group in nuclide mean std. dev. +1 3 1 total 0.000693 0.000020 +0 3 2 total 0.031171 0.001403 capture material group in nuclide mean std. dev. -1 3 1 total 0.000715 0.000032 -0 3 2 total 0.031290 0.001882 +1 3 1 total 0.000693 0.000020 +0 3 2 total 0.031171 0.001403 fission material group in nuclide mean std. dev. 1 3 1 total 0.0 0.0 @@ -644,54 +648,54 @@ kappa-fission 0 3 2 total 0.0 0.0 scatter material group in nuclide mean std. dev. -1 3 1 total 0.683797 0.015496 -0 3 2 total 2.007097 0.111979 +1 3 1 total 0.682202 0.024123 +0 3 2 total 2.001768 0.084281 nu-scatter material group in nuclide mean std. dev. -1 3 1 total 0.684650 0.017888 -0 3 2 total 1.992357 0.090997 +1 3 1 total 0.672567 0.017434 +0 3 2 total 2.004576 0.129211 scatter matrix material group in group out legendre nuclide mean std. dev. -12 3 1 1 P0 total 0.654867 0.017215 -13 3 1 1 P1 total 0.392566 0.011118 -14 3 1 1 P2 total 0.165345 0.005121 -15 3 1 1 P3 total 0.016963 0.003137 -8 3 1 2 P0 total 0.029783 0.000974 -9 3 1 2 P1 total 0.008810 0.000479 -10 3 1 2 P2 total -0.002652 0.000630 -11 3 1 2 P3 total -0.002872 0.000517 -4 3 2 1 P0 total 0.000000 0.000000 -5 3 2 1 P1 total 0.000000 0.000000 -6 3 2 1 P2 total 0.000000 0.000000 -7 3 2 1 P3 total 0.000000 0.000000 -0 3 2 2 P0 total 1.992357 0.090997 -1 3 2 2 P1 total 0.526383 0.022569 -2 3 2 2 P2 total 0.108016 0.009047 -3 3 2 2 P3 total 0.016856 0.010707 +12 3 1 1 P0 total 0.641741 0.016600 +13 3 1 1 P1 total 0.383841 0.011878 +14 3 1 1 P2 total 0.149909 0.005512 +15 3 1 1 P3 total 0.004238 0.002485 +8 3 1 2 P0 total 0.030826 0.000973 +9 3 1 2 P1 total 0.009943 0.000415 +10 3 1 2 P2 total -0.003002 0.000628 +11 3 1 2 P3 total -0.004234 0.000393 +4 3 2 1 P0 total 0.000467 0.000467 +5 3 2 1 P1 total 0.000345 0.000345 +6 3 2 1 P2 total 0.000149 0.000149 +7 3 2 1 P3 total -0.000047 0.000047 +0 3 2 2 P0 total 2.004109 0.129225 +1 3 2 2 P1 total 0.511363 0.043448 +2 3 2 2 P2 total 0.108599 0.014070 +3 3 2 2 P3 total 0.035733 0.021921 nu-scatter matrix material group in group out legendre nuclide mean std. dev. -12 3 1 1 P0 total 0.654867 0.017215 -13 3 1 1 P1 total 0.392566 0.011118 -14 3 1 1 P2 total 0.165345 0.005121 -15 3 1 1 P3 total 0.016963 0.003137 -8 3 1 2 P0 total 0.029783 0.000974 -9 3 1 2 P1 total 0.008810 0.000479 -10 3 1 2 P2 total -0.002652 0.000630 -11 3 1 2 P3 total -0.002872 0.000517 -4 3 2 1 P0 total 0.000000 0.000000 -5 3 2 1 P1 total 0.000000 0.000000 -6 3 2 1 P2 total 0.000000 0.000000 -7 3 2 1 P3 total 0.000000 0.000000 -0 3 2 2 P0 total 1.992357 0.090997 -1 3 2 2 P1 total 0.526383 0.022569 -2 3 2 2 P2 total 0.108016 0.009047 -3 3 2 2 P3 total 0.016856 0.010707 +12 3 1 1 P0 total 0.641741 0.016600 +13 3 1 1 P1 total 0.383841 0.011878 +14 3 1 1 P2 total 0.149909 0.005512 +15 3 1 1 P3 total 0.004238 0.002485 +8 3 1 2 P0 total 0.030826 0.000973 +9 3 1 2 P1 total 0.009943 0.000415 +10 3 1 2 P2 total -0.003002 0.000628 +11 3 1 2 P3 total -0.004234 0.000393 +4 3 2 1 P0 total 0.000467 0.000467 +5 3 2 1 P1 total 0.000345 0.000345 +6 3 2 1 P2 total 0.000149 0.000149 +7 3 2 1 P3 total -0.000047 0.000047 +0 3 2 2 P0 total 2.004109 0.129225 +1 3 2 2 P1 total 0.511363 0.043448 +2 3 2 2 P2 total 0.108599 0.014070 +3 3 2 2 P3 total 0.035733 0.021921 multiplicity matrix material group in group out nuclide mean std. dev. -3 3 1 1 total 1.0 0.020014 -2 3 1 2 total 1.0 0.034047 -1 3 2 1 total 0.0 0.000000 -0 3 2 2 total 1.0 0.048455 +3 3 1 1 total 1.0 0.022200 +2 3 1 2 total 1.0 0.033880 +1 3 2 1 total 1.0 1.414214 +0 3 2 2 total 1.0 0.066922 nu-fission matrix material group in group out nuclide mean std. dev. 3 3 1 1 total 0.0 0.0 @@ -700,46 +704,46 @@ nu-fission matrix 0 3 2 2 total 0.0 0.0 scatter probability matrix material group in group out nuclide mean std. dev. -3 3 1 1 total 0.956499 0.018759 -2 3 1 2 total 0.043501 0.001202 -1 3 2 1 total 0.000000 0.000000 -0 3 2 2 total 1.000000 0.048455 +3 3 1 1 total 0.954167 0.020729 +2 3 1 2 total 0.045833 0.001296 +1 3 2 1 total 0.000233 0.000233 +0 3 2 2 total 0.999767 0.066899 consistent scatter matrix material group in group out legendre nuclide mean std. dev. -12 3 1 1 P0 total 0.654051 0.019602 -13 3 1 1 P1 total 0.392076 0.012456 -14 3 1 1 P2 total 0.165139 0.005640 -15 3 1 1 P3 total 0.016942 0.003143 -8 3 1 2 P0 total 0.029746 0.001063 -9 3 1 2 P1 total 0.008799 0.000495 -10 3 1 2 P2 total -0.002648 0.000631 -11 3 1 2 P3 total -0.002868 0.000518 -4 3 2 1 P0 total 0.000000 0.000000 -5 3 2 1 P1 total 0.000000 0.000000 -6 3 2 1 P2 total 0.000000 0.000000 -7 3 2 1 P3 total 0.000000 0.000000 -0 3 2 2 P0 total 2.007097 0.148316 -1 3 2 2 P1 total 0.530278 0.038286 -2 3 2 2 P2 total 0.108815 0.011091 -3 3 2 2 P3 total 0.016981 0.010831 +12 3 1 1 P0 total 0.650935 0.027014 +13 3 1 1 P1 total 0.389340 0.017459 +14 3 1 1 P2 total 0.152056 0.007457 +15 3 1 1 P3 total 0.004299 0.002525 +8 3 1 2 P0 total 0.031268 0.001416 +9 3 1 2 P1 total 0.010085 0.000533 +10 3 1 2 P2 total -0.003045 0.000645 +11 3 1 2 P3 total -0.004295 0.000423 +4 3 2 1 P0 total 0.000466 0.000467 +5 3 2 1 P1 total 0.000344 0.000345 +6 3 2 1 P2 total 0.000148 0.000149 +7 3 2 1 P3 total -0.000047 0.000047 +0 3 2 2 P0 total 2.001301 0.158219 +1 3 2 2 P1 total 0.510647 0.049275 +2 3 2 2 P2 total 0.108446 0.014900 +3 3 2 2 P3 total 0.035683 0.021951 consistent nu-scatter matrix material group in group out legendre nuclide mean std. dev. -12 3 1 1 P0 total 0.654051 0.023571 -13 3 1 1 P1 total 0.392076 0.014722 -14 3 1 1 P2 total 0.165139 0.006537 -15 3 1 1 P3 total 0.016942 0.003161 -8 3 1 2 P0 total 0.029746 0.001468 -9 3 1 2 P1 total 0.008799 0.000579 -10 3 1 2 P2 total -0.002648 0.000637 -11 3 1 2 P3 total -0.002868 0.000528 -4 3 2 1 P0 total 0.000000 0.000000 -5 3 2 1 P1 total 0.000000 0.000000 -6 3 2 1 P2 total 0.000000 0.000000 -7 3 2 1 P3 total 0.000000 0.000000 -0 3 2 2 P0 total 2.007097 0.177359 -1 3 2 2 P1 total 0.530278 0.046109 -2 3 2 2 P2 total 0.108815 0.012281 -3 3 2 2 P3 total 0.016981 0.010862 +12 3 1 1 P0 total 0.650935 0.030637 +13 3 1 1 P1 total 0.389340 0.019481 +14 3 1 1 P2 total 0.152056 0.008185 +15 3 1 1 P3 total 0.004299 0.002526 +8 3 1 2 P0 total 0.031268 0.001768 +9 3 1 2 P1 total 0.010085 0.000633 +10 3 1 2 P2 total -0.003045 0.000653 +11 3 1 2 P3 total -0.004295 0.000447 +4 3 2 1 P0 total 0.000466 0.000808 +5 3 2 1 P1 total 0.000344 0.000597 +6 3 2 1 P2 total 0.000148 0.000257 +7 3 2 1 P3 total -0.000047 0.000081 +0 3 2 2 P0 total 2.001301 0.207294 +1 3 2 2 P1 total 0.510647 0.059966 +2 3 2 2 P2 total 0.108446 0.016574 +3 3 2 2 P3 total 0.035683 0.022080 chi material group out nuclide mean std. dev. 1 3 1 total 0.0 0.0 @@ -750,8 +754,8 @@ chi-prompt 0 3 2 total 0.0 0.0 inverse-velocity material group in nuclide mean std. dev. -1 3 1 total 6.447396e-08 2.866174e-09 -0 3 2 total 3.006811e-06 1.808751e-07 +1 3 1 total 6.023693e-08 1.678511e-09 +0 3 2 total 2.995346e-06 1.347817e-07 prompt-nu-fission material group in nuclide mean std. dev. 1 3 1 total 0.0 0.0 @@ -763,65 +767,61 @@ prompt-nu-fission matrix 1 3 2 1 total 0.0 0.0 0 3 2 2 total 0.0 0.0 diffusion-coefficient - material group in legendre nuclide mean std. dev. -2 3 1 P0 total 11.244053 8.794903 -3 3 1 P1 total 1.141761 0.081143 -0 3 2 P0 total -2.888333 3.736106 -1 3 2 P1 total 0.227648 0.021613 + material group in nuclide mean std. dev. +1 3 1 total 1.114881 0.100326 +0 3 2 total 0.226467 0.014910 nu-diffusion-coefficient - material group in legendre nuclide mean std. dev. -2 3 1 P0 total 11.244053 8.794903 -3 3 1 P1 total 1.141761 0.081143 -0 3 2 P0 total -2.888333 3.736106 -1 3 2 P1 total 0.227648 0.021613 + material group in nuclide mean std. dev. +1 3 1 total 1.114881 0.100326 +0 3 2 total 0.226467 0.014910 (n,elastic) material group in nuclide mean std. dev. -1 3 1 total 0.683777 0.015496 -0 3 2 total 2.007097 0.111979 +1 3 1 total 0.682168 0.024125 +0 3 2 total 2.001768 0.084281 (n,level) - material group in nuclide mean std. dev. -1 3 1 total 0.00002 0.000006 -0 3 2 total 0.00000 0.000000 + material group in nuclide mean std. dev. +1 3 1 total 0.000033 0.000019 +0 3 2 total 0.000000 0.000000 (n,2n) material group in nuclide mean std. dev. 1 3 1 total 0.0 0.0 0 3 2 total 0.0 0.0 (n,na) material group in nuclide mean std. dev. -1 3 1 total 3.714897e-11 2.058007e-11 +1 3 1 total 9.967562e-07 9.970492e-07 0 3 2 total 0.000000e+00 0.000000e+00 (n,nc) - material group in nuclide mean std. dev. -1 3 1 total 0.0 0.0 -0 3 2 total 0.0 0.0 + material group in nuclide mean std. dev. +1 3 1 total 8.867935e-07 8.870902e-07 +0 3 2 total 0.000000e+00 0.000000e+00 (n,gamma) material group in nuclide mean std. dev. -1 3 1 total 0.000234 0.000010 -0 3 2 total 0.010896 0.000655 +1 3 1 total 0.000219 0.000006 +0 3 2 total 0.010855 0.000488 (n,a) material group in nuclide mean std. dev. -1 3 1 total 0.000481 0.000022 -0 3 2 total 0.020394 0.001227 +1 3 1 total 0.000474 0.000015 +0 3 2 total 0.020316 0.000914 (n,Xa) material group in nuclide mean std. dev. -1 3 1 total 0.000481 0.000022 -0 3 2 total 0.020394 0.001227 +1 3 1 total 0.000475 0.000015 +0 3 2 total 0.020316 0.000914 heating material group in nuclide mean std. dev. -1 3 1 total 64982.284489 3654.924951 -0 3 2 total 49786.819570 2967.698779 +1 3 1 total 77986.174023 6103.108384 +0 3 2 total 59060.658662 3576.641806 damage-energy material group in nuclide mean std. dev. -1 3 1 total 1147.965123 36.313921 -0 3 2 total 332.961479 20.030541 +1 3 1 total 1107.847239 59.901669 +0 3 2 total 331.691439 14.926212 (n,n1) - material group in nuclide mean std. dev. -1 3 1 total 7.030461e-07 2.133325e-07 -0 3 2 total 0.000000e+00 0.000000e+00 + material group in nuclide mean std. dev. +1 3 1 total 0.000001 3.988839e-07 +0 3 2 total 0.000000 0.000000e+00 (n,a0) material group in nuclide mean std. dev. -1 3 1 total 0.000068 0.000011 -0 3 2 total 0.001283 0.000077 +1 3 1 total 0.000084 0.000016 +0 3 2 total 0.001278 0.000058 (n,nc) matrix material group in group out nuclide mean std. dev. 3 3 1 1 total 0.0 0.0 diff --git a/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat index f29a41f3d73..9b3a22510b1 100644 --- a/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat @@ -1,1679 +1,1771 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -0.63 -0.63 -1 0.63 0.63 1 - - - - - - - 1 - - - 0.0 0.625 20000000.0 - - - 0.0 0.625 20000000.0 - - - 1 - - - 3 - - - 0.0 20000000.0 - - - 2 - - - 3 - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - absorption - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - absorption - tracklength - - - 1 2 - U234 U235 U238 O16 - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - nu-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - kappa-fission - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - scatter - tracklength - - - 1 2 - total - flux - analog - - - 1 2 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 28 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 5 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 5 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - nu-fission - analog - - - 1 2 5 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - scatter - tracklength - - - 1 2 5 28 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - scatter - tracklength - - - 1 2 5 28 - U234 U235 U238 O16 - scatter - analog - - - 1 2 5 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 52 - U234 U235 U238 O16 - nu-fission - analog - - - 1 5 - U234 U235 U238 O16 - nu-fission - analog - - - 1 52 - U234 U235 U238 O16 - prompt-nu-fission - analog - - - 1 5 - U234 U235 U238 O16 - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - inverse-velocity - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - prompt-nu-fission - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - prompt-nu-fission - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - U234 U235 U238 O16 - scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - total - tracklength - - - 1 2 - total - flux - analog - - - 1 5 6 - U234 U235 U238 O16 - nu-scatter - analog - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,elastic) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,level) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,2n) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,na) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,nc) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,gamma) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,a) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,Xa) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - heating - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - damage-energy - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,n1) - tracklength - - - 1 2 - total - flux - tracklength - - - 1 2 - U234 U235 U238 O16 - (n,a0) - tracklength - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - (n,nc) - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - (n,n1) - analog - - - 1 2 - total - flux - analog - - - 1 2 5 - U234 U235 U238 O16 - (n,2n) - analog - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 104 2 - total - flux - analog - - - 104 5 6 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 104 2 - total - flux - analog - - - 104 5 6 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - absorption - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - absorption - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - fission - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - fission - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - kappa-fission - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - tracklength - - - 104 2 - total - flux - analog - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 104 2 - total - flux - analog - - - 104 2 5 28 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 104 2 - total - flux - analog - - - 104 2 5 28 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 104 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 104 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 104 2 - total - flux - analog - - - 104 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - analog - - - 104 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - tracklength - - - 104 2 5 28 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - tracklength - - - 104 2 5 28 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 104 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 104 52 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - analog - - - 104 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-fission - analog - - - 104 52 - Zr90 Zr91 Zr92 Zr94 Zr96 - prompt-nu-fission - analog - - - 104 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - prompt-nu-fission - analog - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - inverse-velocity - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - prompt-nu-fission - tracklength - - - 104 2 - total - flux - analog - - - 104 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - prompt-nu-fission - analog - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 104 2 - total - flux - analog - - - 104 5 6 - Zr90 Zr91 Zr92 Zr94 Zr96 - scatter - analog - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - total - tracklength - - - 104 2 - total - flux - analog - - - 104 5 6 - Zr90 Zr91 Zr92 Zr94 Zr96 - nu-scatter - analog - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,elastic) - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,level) - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,2n) - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,na) - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,nc) - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,gamma) - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,a) - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,Xa) - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - heating - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - damage-energy - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,n1) - tracklength - - - 104 2 - total - flux - tracklength - - - 104 2 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,a0) - tracklength - - - 104 2 - total - flux - analog - - - 104 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,nc) - analog - - - 104 2 - total - flux - analog - - - 104 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,n1) - analog - - - 104 2 - total - flux - analog - - - 104 2 5 - Zr90 Zr91 Zr92 Zr94 Zr96 - (n,2n) - analog - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - total - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - total - tracklength - - - 207 2 - total - flux - analog - - - 207 5 6 - H1 O16 B10 B11 - scatter - analog - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - total - tracklength - - - 207 2 - total - flux - analog - - - 207 5 6 - H1 O16 B10 B11 - nu-scatter - analog - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - absorption - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - absorption - tracklength - - - 207 2 - H1 O16 B10 B11 - fission - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - fission - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - nu-fission - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - kappa-fission - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - scatter - tracklength - - - 207 2 - total - flux - analog - - - 207 2 - H1 O16 B10 B11 - nu-scatter - analog - - - 207 2 - total - flux - analog - - - 207 2 5 28 - H1 O16 B10 B11 - scatter - analog - - - 207 2 - total - flux - analog - - - 207 2 5 28 - H1 O16 B10 B11 - nu-scatter - analog - - - 207 2 5 - H1 O16 B10 B11 - nu-scatter - analog - - - 207 2 5 - H1 O16 B10 B11 - scatter - analog - - - 207 2 - total - flux - analog - - - 207 2 5 - H1 O16 B10 B11 - nu-fission - analog - - - 207 2 5 - H1 O16 B10 B11 - scatter - analog - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - scatter - tracklength - - - 207 2 5 28 - H1 O16 B10 B11 - scatter - analog - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - scatter - tracklength - - - 207 2 5 28 - H1 O16 B10 B11 - scatter - analog - - - 207 2 5 - H1 O16 B10 B11 - nu-scatter - analog - - - 207 52 - H1 O16 B10 B11 - nu-fission - analog - - - 207 5 - H1 O16 B10 B11 - nu-fission - analog - - - 207 52 - H1 O16 B10 B11 - prompt-nu-fission - analog - - - 207 5 - H1 O16 B10 B11 - prompt-nu-fission - analog - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - inverse-velocity - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - prompt-nu-fission - tracklength - - - 207 2 - total - flux - analog - - - 207 2 5 - H1 O16 B10 B11 - prompt-nu-fission - analog - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - total - tracklength - - - 207 2 - total - flux - analog - - - 207 5 6 - H1 O16 B10 B11 - scatter - analog - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - total - tracklength - - - 207 2 - total - flux - analog - - - 207 5 6 - H1 O16 B10 B11 - nu-scatter - analog - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,elastic) - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,level) - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,2n) - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,na) - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,nc) - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,gamma) - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,a) - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,Xa) - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - heating - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - damage-energy - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,n1) - tracklength - - - 207 2 - total - flux - tracklength - - - 207 2 - H1 O16 B10 B11 - (n,a0) - tracklength - - - 207 2 - total - flux - analog - - - 207 2 5 - H1 O16 B10 B11 - (n,nc) - analog - - - 207 2 - total - flux - analog - - - 207 2 5 - H1 O16 B10 B11 - (n,n1) - analog - - - 207 2 - total - flux - analog - - - 207 2 5 - H1 O16 B10 B11 - (n,2n) - analog - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,2n) + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,3n) + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,4n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + U234 U235 U238 O16 + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + nu-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + kappa-fission + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + scatter + tracklength + + + 1 2 + total + flux + analog + + + 1 2 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 30 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 5 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 5 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + nu-fission + analog + + + 1 2 5 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + scatter + tracklength + + + 1 2 5 30 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + scatter + tracklength + + + 1 2 5 30 + U234 U235 U238 O16 + scatter + analog + + + 1 2 5 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 54 + U234 U235 U238 O16 + nu-fission + analog + + + 1 5 + U234 U235 U238 O16 + nu-fission + analog + + + 1 54 + U234 U235 U238 O16 + prompt-nu-fission + analog + + + 1 5 + U234 U235 U238 O16 + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + inverse-velocity + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + prompt-nu-fission + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + prompt-nu-fission + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + U234 U235 U238 O16 + scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + analog + + + 1 5 6 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,elastic) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,level) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,2n) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,na) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,nc) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,gamma) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,a) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,Xa) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + heating + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + damage-energy + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,n1) + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + (n,a0) + tracklength + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + (n,nc) + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + (n,n1) + analog + + + 1 2 + total + flux + analog + + + 1 2 5 + U234 U235 U238 O16 + (n,2n) + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + analog + + + 106 5 6 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + analog + + + 106 5 6 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,2n) + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,3n) + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,4n) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + fission + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + fission + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + kappa-fission + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + tracklength + + + 106 2 + total + flux + analog + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 + total + flux + analog + + + 106 2 5 30 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + analog + + + 106 2 5 30 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + tracklength + + + 106 2 5 30 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + tracklength + + + 106 2 5 30 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 54 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 106 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 106 54 + Zr90 Zr91 Zr92 Zr94 Zr96 + prompt-nu-fission + analog + + + 106 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + prompt-nu-fission + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + inverse-velocity + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + prompt-nu-fission + tracklength + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + prompt-nu-fission + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + analog + + + 106 5 6 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 106 2 + total + flux + analog + + + 106 5 6 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,elastic) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,level) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,2n) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,na) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,nc) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,gamma) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,a) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,Xa) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + heating + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + damage-energy + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,n1) + tracklength + + + 106 2 + total + flux + tracklength + + + 106 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,a0) + tracklength + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,nc) + analog + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,n1) + analog + + + 106 2 + total + flux + analog + + + 106 2 5 + Zr90 Zr91 Zr92 Zr94 Zr96 + (n,2n) + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + analog + + + 211 5 6 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + analog + + + 211 5 6 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + absorption + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + absorption + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,2n) + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,3n) + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,4n) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + absorption + tracklength + + + 211 2 + H1 O16 B10 B11 + fission + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + fission + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + nu-fission + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + kappa-fission + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + scatter + tracklength + + + 211 2 + total + flux + analog + + + 211 2 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 + total + flux + analog + + + 211 2 5 30 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + analog + + + 211 2 5 30 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 5 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 5 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + nu-fission + analog + + + 211 2 5 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + scatter + tracklength + + + 211 2 5 30 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + scatter + tracklength + + + 211 2 5 30 + H1 O16 B10 B11 + scatter + analog + + + 211 2 5 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 54 + H1 O16 B10 B11 + nu-fission + analog + + + 211 5 + H1 O16 B10 B11 + nu-fission + analog + + + 211 54 + H1 O16 B10 B11 + prompt-nu-fission + analog + + + 211 5 + H1 O16 B10 B11 + prompt-nu-fission + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + inverse-velocity + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + prompt-nu-fission + tracklength + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + prompt-nu-fission + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + analog + + + 211 5 6 + H1 O16 B10 B11 + scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + total + tracklength + + + 211 2 + total + flux + analog + + + 211 5 6 + H1 O16 B10 B11 + nu-scatter + analog + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,elastic) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,level) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,2n) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,na) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,nc) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,gamma) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,a) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,Xa) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + heating + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + damage-energy + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,n1) + tracklength + + + 211 2 + total + flux + tracklength + + + 211 2 + H1 O16 B10 B11 + (n,a0) + tracklength + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + (n,nc) + analog + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + (n,n1) + analog + + + 211 2 + total + flux + analog + + + 211 2 5 + H1 O16 B10 B11 + (n,2n) + analog + + + diff --git a/tests/regression_tests/mgxs_library_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_nuclides/results_true.dat index ddc7fa46e24..c2188997d7e 100644 --- a/tests/regression_tests/mgxs_library_nuclides/results_true.dat +++ b/tests/regression_tests/mgxs_library_nuclides/results_true.dat @@ -1 +1 @@ -bf460584607a2a7b2f3fca008762839f5b3a5bbc85721a990eb568df5d0417c4f4eca3e0c2c12380c0761e15faeccc662af1876171ff8de0102ba86c81b4bd04 \ No newline at end of file +4ae3b5a70ad72b1be261aee3ab19e0261d1c12f4d4ca50b712d1ba76041bd5387c69fa9fa326619ad588db206cd9aaf464b0025d71ea9b8b1137af0102bca87f \ No newline at end of file diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/__init__.py b/tests/regression_tests/mgxs_library_specific_nuclides/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat new file mode 100644 index 00000000000..1372741c947 --- /dev/null +++ b/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + + + + 1 2 3 + + + 0.0 0.625 20000000.0 + + + 1 + + + 0.0 0.625 20000000.0 + + + 1 + + + 3 + + + 0.0 20000000.0 + + + 2 + + + 3 + + + 383 2 + total + flux + tracklength + + + 1 2 + U235 total + total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0) + tracklength + + + 383 2 + total + flux + analog + + + 1 5 6 + U235 total + scatter nu-scatter + analog + + + 1 2 + U235 total + nu-scatter + analog + + + 1 2 5 30 + U235 total + scatter nu-scatter + analog + + + 1 2 5 + U235 total + nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n) + analog + + + 1 54 + U235 total + nu-fission prompt-nu-fission + analog + + + 1 5 + U235 total + nu-fission prompt-nu-fission + analog + + + 106 2 + Zr90 total + total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0) + tracklength + + + 106 5 6 + Zr90 total + scatter nu-scatter + analog + + + 106 2 + Zr90 total + nu-scatter + analog + + + 106 2 5 30 + Zr90 total + scatter nu-scatter + analog + + + 106 2 5 + Zr90 total + nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n) + analog + + + 106 54 + Zr90 total + nu-fission prompt-nu-fission + analog + + + 106 5 + Zr90 total + nu-fission prompt-nu-fission + analog + + + 251 2 + H1 total + total absorption (n,2n) (n,3n) (n,4n) fission nu-fission kappa-fission scatter inverse-velocity prompt-nu-fission (n,elastic) (n,level) (n,na) (n,nc) (n,gamma) (n,a) (n,Xa) heating damage-energy (n,n1) (n,a0) + tracklength + + + 251 5 6 + H1 total + scatter nu-scatter + analog + + + 251 2 + H1 total + nu-scatter + analog + + + 251 2 5 30 + H1 total + scatter nu-scatter + analog + + + 251 2 5 + H1 total + nu-scatter scatter nu-fission prompt-nu-fission (n,nc) (n,n1) (n,2n) + analog + + + 251 54 + H1 total + nu-fission prompt-nu-fission + analog + + + 251 5 + H1 total + nu-fission prompt-nu-fission + analog + + + diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_specific_nuclides/results_true.dat new file mode 100644 index 00000000000..eaf56b96669 --- /dev/null +++ b/tests/regression_tests/mgxs_library_specific_nuclides/results_true.dat @@ -0,0 +1 @@ +08d5c199c51496f86fdd739bf7ee0e143a9a159da0f4d364ec970557e5c1fc92a202d906dcae91812e665fd2e88dd7db1e4913ef6b91f456f23b52093c83f483 \ No newline at end of file diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/test.py b/tests/regression_tests/mgxs_library_specific_nuclides/test.py new file mode 100644 index 00000000000..61910e539e8 --- /dev/null +++ b/tests/regression_tests/mgxs_library_specific_nuclides/test.py @@ -0,0 +1,71 @@ +import hashlib + +import openmc +import openmc.mgxs +from openmc.examples import pwr_pin_cell + +from tests.testing_harness import PyAPITestHarness + + +class MGXSTestHarness(PyAPITestHarness): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + # Initialize a two-group structure + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + + # Initialize MGXS Library for a few cross section types + self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) + self.mgxs_lib.by_nuclide = True + + # Test relevant MGXS types + relevant_MGXS_TYPES = [item for item in openmc.mgxs.MGXS_TYPES + if item != 'current'] + # Add in a subset of openmc.mgxs.ARBITRARY_VECTOR_TYPES and + # openmc.mgxs.ARBITRARY_MATRIX_TYPES so we can see the code works, + # but not use too much resources + relevant_MGXS_TYPES += [ + "(n,elastic)", "(n,level)", "(n,2n)", "(n,na)", "(n,nc)", + "(n,gamma)", "(n,a)", "(n,Xa)", "heating", "damage-energy", + "(n,n1)", "(n,a0)", "(n,nc) matrix", "(n,n1) matrix", + "(n,2n) matrix"] + self.mgxs_lib.mgxs_types = tuple(relevant_MGXS_TYPES) + self.mgxs_lib.energy_groups = energy_groups + self.mgxs_lib.legendre_order = 3 + self.mgxs_lib.domain_type = 'material' + self.mgxs_lib.nuclides = ['U235', 'Zr90', 'H1'] + self.mgxs_lib.build_library() + + # Add tallies + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=True) + + def _get_results(self, hash_output=True): + """Digest info in the statepoint and return as a string.""" + + # Read the statepoint file. + sp = openmc.StatePoint(self._sp_name) + + # Load the MGXS library from the statepoint + self.mgxs_lib.load_from_statepoint(sp) + + # Build a string from Pandas Dataframe for each MGXS + outstr = '' + for domain in self.mgxs_lib.domains: + for mgxs_type in self.mgxs_lib.mgxs_types: + mgxs = self.mgxs_lib.get_mgxs(domain, mgxs_type) + df = mgxs.get_pandas_dataframe() + outstr += df.to_string() + '\n' + + # Hash the results if necessary + if hash_output: + sha512 = hashlib.sha512() + sha512.update(outstr.encode('utf-8')) + outstr = sha512.hexdigest() + + return outstr + + +def test_mgxs_library_specific_nuclides(): + model = pwr_pin_cell() + harness = MGXSTestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/microxs/__init.py__ b/tests/regression_tests/microxs/__init.py__ new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/microxs/test.py b/tests/regression_tests/microxs/test.py new file mode 100644 index 00000000000..a35150a1b80 --- /dev/null +++ b/tests/regression_tests/microxs/test.py @@ -0,0 +1,67 @@ +"""Test one-group cross section generation""" +from pathlib import Path + +import numpy as np +import pytest +import openmc +from openmc.deplete import MicroXS, get_microxs_and_flux + +from tests.regression_tests import config + +CHAIN_FILE = Path(__file__).parents[2] / "chain_simple.xml" + +@pytest.fixture(scope="module") +def model(): + fuel = openmc.Material(name="uo2") + fuel.add_element("U", 1, percent_type="ao", enrichment=4.25) + fuel.add_element("O", 2) + fuel.set_density("g/cc", 10.4) + + clad = openmc.Material(name="clad") + clad.add_element("Zr", 1) + clad.set_density("g/cc", 6) + + water = openmc.Material(name="water") + water.add_element("O", 1) + water.add_element("H", 2) + water.set_density("g/cc", 1.0) + water.add_s_alpha_beta("c_H_in_H2O") + + radii = [0.42, 0.45] + fuel.volume = np.pi * radii[0] ** 2 + + materials = openmc.Materials([fuel, clad, water]) + + pin_surfaces = [openmc.ZCylinder(r=r) for r in radii] + pin_univ = openmc.model.pin(pin_surfaces, materials) + bound_box = openmc.model.RectangularPrism(1.24, 1.24, boundary_type="reflective") + root_cell = openmc.Cell(fill=pin_univ, region=-bound_box) + geometry = openmc.Geometry([root_cell]) + + settings = openmc.Settings() + settings.particles = 1000 + settings.inactive = 5 + settings.batches = 10 + + return openmc.Model(geometry, materials, settings) + + +@pytest.mark.parametrize("domain_type", ["materials", "mesh"]) +def test_from_model(model, domain_type): + if domain_type == 'materials': + domains = model.materials[:1] + elif domain_type == 'mesh': + mesh = openmc.RegularMesh() + mesh.lower_left = (-0.62, -0.62) + mesh.upper_right = (0.62, 0.62) + mesh.dimension = (3, 3) + domains = mesh + nuclides = ['U234', 'U235', 'U238', 'U236', 'O16', 'O17', 'I135', 'Xe135', + 'Xe136', 'Cs135', 'Gd157', 'Gd156'] + _, test_xs = get_microxs_and_flux(model, domains, nuclides, chain_file=CHAIN_FILE) + if config['update']: + test_xs[0].to_csv(f'test_reference_{domain_type}.csv') + + ref_xs = MicroXS.from_csv(f'test_reference_{domain_type}.csv') + + np.testing.assert_allclose(test_xs[0].data, ref_xs.data, rtol=1e-11) diff --git a/tests/regression_tests/microxs/test_reference_materials.csv b/tests/regression_tests/microxs/test_reference_materials.csv new file mode 100644 index 00000000000..3e679f98071 --- /dev/null +++ b/tests/regression_tests/microxs/test_reference_materials.csv @@ -0,0 +1,25 @@ +nuclides,reactions,groups,xs +U234,"(n,gamma)",1,21.418670317831076 +U234,fission,1,0.5014588470882162 +U235,"(n,gamma)",1,10.343944102483215 +U235,fission,1,47.46718472611895 +U238,"(n,gamma)",1,0.8741166723597229 +U238,fission,1,0.10829568455139067 +U236,"(n,gamma)",1,9.08348678468935 +U236,fission,1,0.3325287927011424 +O16,"(n,gamma)",1,7.548646353912426e-05 +O16,fission,1,0.0 +O17,"(n,gamma)",1,0.00040184862213103105 +O17,fission,1,0.0 +I135,"(n,gamma)",1,6.691256508942912 +I135,fission,1,0.0 +Xe135,"(n,gamma)",1,223998.6418566729 +Xe135,fission,1,0.0 +Xe136,"(n,gamma)",1,0.022934362666193503 +Xe136,fission,1,0.0 +Cs135,"(n,gamma)",1,2.2845395222353204 +Cs135,fission,1,0.0 +Gd157,"(n,gamma)",1,12582.07962003624 +Gd157,fission,1,0.0 +Gd156,"(n,gamma)",1,2.942112751533234 +Gd156,fission,1,0.0 diff --git a/tests/regression_tests/microxs/test_reference_mesh.csv b/tests/regression_tests/microxs/test_reference_mesh.csv new file mode 100644 index 00000000000..1882372b11a --- /dev/null +++ b/tests/regression_tests/microxs/test_reference_mesh.csv @@ -0,0 +1,25 @@ +nuclides,reactions,groups,xs +U234,"(n,gamma)",1,27.027171724208227 +U234,fission,1,0.04333740860093498 +U235,"(n,gamma)",1,12.683875995776193 +U235,fission,1,4.2596665957162605 +U238,"(n,gamma)",1,4.479719141496804 +U238,fission,1,0.009460665924409056 +U236,"(n,gamma)",1,8.469286849810802 +U236,fission,1,0.027373590840715795 +O16,"(n,gamma)",1,7.478160204479271e-05 +O16,fission,1,0.0 +O17,"(n,gamma)",1,0.0004743959164164789 +O17,fission,1,0.0 +I135,"(n,gamma)",1,8.33959524761822 +I135,fission,1,0.0 +Xe135,"(n,gamma)",1,282068.447252079 +Xe135,fission,1,0.0 +Xe136,"(n,gamma)",1,0.02888928065916194 +Xe136,fission,1,0.0 +Cs135,"(n,gamma)",1,2.5863526577468408 +Cs135,fission,1,0.0 +Gd157,"(n,gamma)",1,16518.24083307153 +Gd157,fission,1,0.0 +Gd156,"(n,gamma)",1,2.838514589417232 +Gd156,fission,1,0.0 diff --git a/tests/regression_tests/model_xml/__init__.py b/tests/regression_tests/model_xml/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat b/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat new file mode 100644 index 00000000000..7e2a0cf628f --- /dev/null +++ b/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 10000 + 10 + 5 + + + -4.0 -4.0 -4.0 4.0 4.0 4.0 + + + + diff --git a/tests/regression_tests/model_xml/energy_laws_inputs_true.dat b/tests/regression_tests/model_xml/energy_laws_inputs_true.dat new file mode 100644 index 00000000000..4d8e825d1b5 --- /dev/null +++ b/tests/regression_tests/model_xml/energy_laws_inputs_true.dat @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + diff --git a/tests/regression_tests/model_xml/inputs_true.dat b/tests/regression_tests/model_xml/inputs_true.dat new file mode 100644 index 00000000000..c1ef1366586 --- /dev/null +++ b/tests/regression_tests/model_xml/inputs_true.dat @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + fixed source + 10000 + 1 + + + 0 0 0 + + + + 14000000.0 1.0 + + + ttb + true + + 1000.0 + + + + + 16 + + + neutron photon electron positron + + + 1 2 + current + + + 2 + Al27 total + total (n,gamma) + tracklength + + + 2 + Al27 total + total heating (n,gamma) + collision + + + 2 + Al27 total + total heating (n,gamma) + analog + + + diff --git a/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat b/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat new file mode 100644 index 00000000000..b249d97c40e --- /dev/null +++ b/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + 1.2 1.2 + 1 + 2 2 + -1.2 -1.2 + +2 1 +1 1 + + + 2.4 2.4 + 2 2 + -2.4 -2.4 + +4 4 +4 4 + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + diff --git a/tests/regression_tests/model_xml/photon_production_inputs_true.dat b/tests/regression_tests/model_xml/photon_production_inputs_true.dat new file mode 100644 index 00000000000..ee6cb88622b --- /dev/null +++ b/tests/regression_tests/model_xml/photon_production_inputs_true.dat @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + fixed source + 10000 + 1 + + + 0 0 0 + + + + 14000000.0 1.0 + + + ttb + true + + 1000.0 + + + + + 1 + + + neutron photon electron positron + + + 1 2 + current + + + 2 + Al27 total + total (n,gamma) + tracklength + + + 2 + Al27 total + total heating (n,gamma) + collision + + + 2 + Al27 total + total heating (n,gamma) + analog + + + diff --git a/tests/regression_tests/model_xml/test.py b/tests/regression_tests/model_xml/test.py new file mode 100644 index 00000000000..c67a72ed372 --- /dev/null +++ b/tests/regression_tests/model_xml/test.py @@ -0,0 +1,100 @@ +from difflib import unified_diff +import glob +import filecmp +import os +from pathlib import Path + +import openmc +import pytest + +from tests.testing_harness import PyAPITestHarness, colorize + +# use a few models from other tests to make sure the same results are +# produced when using a single model.xml file as input +from ..adj_cell_rotation.test import model as adj_cell_rotation_model +from ..lattice_multiple.test import model as lattice_multiple_model +from ..energy_laws.test import model as energy_laws_model +from ..photon_production.test import model as photon_production_model + + +class ModelXMLTestHarness(PyAPITestHarness): + """Accept a results file to check against and assume inputs_true is the contents of a model.xml file. + """ + def __init__(self, model=None, inputs_true=None, results_true=None): + statepoint_name = f'statepoint.{model.settings.batches}.h5' + super().__init__(statepoint_name, model, inputs_true) + + self.results_true = 'results_true.dat' if results_true is None else results_true + + def _build_inputs(self): + self._model.export_to_model_xml() + + def _get_inputs(self): + return open('model.xml').read() + + def _compare_results(self): + """Make sure the current results agree with the reference.""" + compare = filecmp.cmp('results_test.dat', self.results_true) + if not compare: + expected = open(self.results_true).readlines() + actual = open('results_test.dat').readlines() + diff = unified_diff(expected, actual, self.results_true, + 'results_test.dat') + print('Result differences:') + print(''.join(colorize(diff))) + os.rename('results_test.dat', 'results_error.dat') + assert compare, 'Results do not agree' + + def _cleanup(self): + super()._cleanup() + if os.path.exists('model.xml'): + os.remove('model.xml') + + +test_names = [ + 'adj_cell_rotation', + 'lattice_multiple', + 'energy_laws', + 'photon_production' +] + + +@pytest.mark.parametrize("test_name", test_names, ids=lambda test: test) +def test_model_xml(test_name, request): + openmc.reset_auto_ids() + + test_path = '../' + test_name + results = test_path + "/results_true.dat" + inputs = test_name + "_inputs_true.dat" + model_name = test_name + "_model" + harness = ModelXMLTestHarness(request.getfixturevalue(model_name), inputs, results) + harness.main() + +def test_input_arg(run_in_tmpdir): + + pincell = openmc.examples.pwr_pin_cell() + + pincell.settings.particles = 100 + + # export to separate XML files and run + pincell.export_to_xml() + openmc.run() + + # make sure the executable isn't falling back on the separate XMLs + for f in glob.glob('*.xml'): + os.remove(f) + # now export to a single XML file with a custom name + pincell.export_to_model_xml('pincell.xml') + assert Path('pincell.xml').exists() + + # run by specifying that single file + openmc.run(path_input='pincell.xml') + + # check that this works for plotting too + openmc.plot_geometry(path_input='pincell.xml') + + # now ensure we get an error for an incorrect filename, + # even in the presence of other, valid XML files + pincell.export_to_model_xml() + with pytest.raises(RuntimeError, match='ex-em-ell.xml'): + openmc.run(path_input='ex-em-ell.xml') \ No newline at end of file diff --git a/tests/regression_tests/multipole/inputs_true.dat b/tests/regression_tests/multipole/inputs_true.dat index 3bbcc20247c..7bea669307c 100644 --- a/tests/regression_tests/multipole/inputs_true.dat +++ b/tests/regression_tests/multipole/inputs_true.dat @@ -1,55 +1,54 @@ - - - - - - - 2.0 2.0 - 1 - 2 2 - -2.0 -2.0 - + + + + + + + + + + + + + + + + + + + + 2.0 2.0 + 1 + 2 2 + -2.0 -2.0 + 11 11 11 11 - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - -1 -1 -1 1 1 1 - - - true - 1000 - - - - - U235 O16 total - total fission (n,gamma) elastic (n,p) - - + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + -1 -1 -1 1 1 1 + + + true + 1000 + + + + U235 O16 total + total fission (n,gamma) elastic (n,p) + + + diff --git a/tests/regression_tests/multipole/results_true.dat b/tests/regression_tests/multipole/results_true.dat index 955f88a4a07..8e82655ce50 100644 --- a/tests/regression_tests/multipole/results_true.dat +++ b/tests/regression_tests/multipole/results_true.dat @@ -1,36 +1,36 @@ k-combined: -1.377711E+00 1.297376E-02 +1.354889E+00 8.437211E-03 tally 1: -3.861112E+00 -2.991150E+00 -2.787756E+00 -1.559383E+00 -5.422517E-01 -5.899488E-02 -4.575965E-01 -4.201819E-02 +3.869969E+00 +3.000421E+00 +2.800393E+00 +1.570851E+00 +5.399091E-01 +5.842233E-02 +4.577147E-01 +4.203362E-02 0.000000E+00 0.000000E+00 -2.250654E+01 -1.013609E+02 +2.286465E+01 +1.045869E+02 0.000000E+00 0.000000E+00 -6.830189E-04 -9.338756E-08 -2.248753E+01 -1.011895E+02 -1.147267E-05 -4.624497E-11 -3.580777E+02 -2.567385E+04 -2.787756E+00 -1.559383E+00 -2.157976E+00 -9.322753E-01 -3.530401E+02 -2.495723E+04 -1.147267E-05 -4.624497E-11 +6.971793E-04 +9.724819E-08 +2.283955E+01 +1.043576E+02 +4.659256E-06 +2.170865E-11 +3.663230E+02 +2.685383E+04 +2.800393E+00 +1.570851E+00 +2.204999E+00 +9.728014E-01 +3.612213E+02 +2.611152E+04 +4.659256E-06 +2.170865E-11 Cell ID = 11 Name = diff --git a/tests/regression_tests/multipole/test.py b/tests/regression_tests/multipole/test.py index 4c4353c8412..2f7369a9db5 100644 --- a/tests/regression_tests/multipole/test.py +++ b/tests/regression_tests/multipole/test.py @@ -53,7 +53,7 @@ def make_model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-1, -1, -1], [1, 1, 1])) model.settings.temperature = {'tolerance': 1000, 'multipole': True} diff --git a/tests/regression_tests/ncrystal/__init__.py b/tests/regression_tests/ncrystal/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/ncrystal/inputs_true.dat b/tests/regression_tests/ncrystal/inputs_true.dat new file mode 100644 index 00000000000..ecbc3c54f40 --- /dev/null +++ b/tests/regression_tests/ncrystal/inputs_true.dat @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + fixed source + 100000 + 10 + + + 0 0 -20 + + + + 0.012 1.0 + + + + + + 1 + + + 0.0 0.017453292519943295 0.03490658503988659 0.05235987755982989 0.06981317007977318 0.08726646259971647 0.10471975511965978 0.12217304763960307 0.13962634015954636 0.15707963267948966 0.17453292519943295 0.19198621771937624 0.20943951023931956 0.22689280275926285 0.24434609527920614 0.2617993877991494 0.2792526803190927 0.29670597283903605 0.3141592653589793 0.33161255787892263 0.3490658503988659 0.3665191429188092 0.3839724354387525 0.4014257279586958 0.4188790204786391 0.4363323129985824 0.4537856055185257 0.47123889803846897 0.4886921905584123 0.5061454830783556 0.5235987755982988 0.5410520681182421 0.5585053606381855 0.5759586531581288 0.5934119456780721 0.6108652381980153 0.6283185307179586 0.6457718232379019 0.6632251157578453 0.6806784082777885 0.6981317007977318 0.7155849933176751 0.7330382858376184 0.7504915783575618 0.767944870877505 0.7853981633974483 0.8028514559173916 0.8203047484373349 0.8377580409572782 0.8552113334772214 0.8726646259971648 0.8901179185171081 0.9075712110370514 0.9250245035569946 0.9424777960769379 0.9599310885968813 0.9773843811168246 0.9948376736367679 1.0122909661567112 1.0297442586766545 1.0471975511965976 1.064650843716541 1.0821041362364843 1.0995574287564276 1.117010721276371 1.1344640137963142 1.1519173063162575 1.1693705988362009 1.1868238913561442 1.2042771838760873 1.2217304763960306 1.239183768915974 1.2566370614359172 1.2740903539558606 1.2915436464758039 1.3089969389957472 1.3264502315156905 1.3439035240356338 1.361356816555577 1.3788101090755203 1.3962634015954636 1.413716694115407 1.4311699866353502 1.4486232791552935 1.4660765716752369 1.4835298641951802 1.5009831567151235 1.5184364492350666 1.53588974175501 1.5533430342749532 1.5707963267948966 1.5882496193148399 1.6057029118347832 1.6231562043547265 1.6406094968746698 1.6580627893946132 1.6755160819145565 1.6929693744344996 1.710422666954443 1.7278759594743862 1.7453292519943295 1.7627825445142729 1.7802358370342162 1.7976891295541595 1.8151424220741028 1.8325957145940461 1.8500490071139892 1.8675022996339325 1.8849555921538759 1.9024088846738192 1.9198621771937625 1.9373154697137058 1.9547687622336491 1.9722220547535925 1.9896753472735358 2.007128639793479 2.0245819323134224 2.0420352248333655 2.059488517353309 2.076941809873252 2.0943951023931953 2.111848394913139 2.129301687433082 2.1467549799530254 2.1642082724729685 2.181661564992912 2.199114857512855 2.2165681500327987 2.234021442552742 2.251474735072685 2.2689280275926285 2.2863813201125716 2.303834612632515 2.321287905152458 2.3387411976724017 2.356194490192345 2.3736477827122884 2.3911010752322315 2.4085543677521746 2.426007660272118 2.443460952792061 2.4609142453120048 2.478367537831948 2.4958208303518914 2.5132741228718345 2.530727415391778 2.548180707911721 2.5656340004316642 2.5830872929516078 2.600540585471551 2.6179938779914944 2.6354471705114375 2.652900463031381 2.670353755551324 2.6878070480712677 2.705260340591211 2.722713633111154 2.7401669256310974 2.7576202181510405 2.775073510670984 2.792526803190927 2.8099800957108707 2.827433388230814 2.8448866807507573 2.8623399732707004 2.8797932657906435 2.897246558310587 2.91469985083053 2.9321531433504737 2.949606435870417 2.9670597283903604 2.9845130209103035 3.001966313430247 3.01941960595019 3.036872898470133 3.0543261909900767 3.07177948351002 3.0892327760299634 3.1066860685499065 3.12413936106985 3.141592653589793 + + + 1 + + + 1 2 3 + current + + + diff --git a/tests/regression_tests/ncrystal/results_true.dat b/tests/regression_tests/ncrystal/results_true.dat new file mode 100644 index 00000000000..3ef0306fdf4 --- /dev/null +++ b/tests/regression_tests/ncrystal/results_true.dat @@ -0,0 +1,181 @@ + surface polar low [rad] polar high [rad] cellfrom nuclide score mean std. dev. +0 1 0.00e+00 1.75e-02 1 total current 9.82e-01 1.43e-04 +1 1 1.75e-02 3.49e-02 1 total current 0.00e+00 0.00e+00 +2 1 3.49e-02 5.24e-02 1 total current 1.00e-06 1.00e-06 +3 1 5.24e-02 6.98e-02 1 total current 0.00e+00 0.00e+00 +4 1 6.98e-02 8.73e-02 1 total current 0.00e+00 0.00e+00 +5 1 8.73e-02 1.05e-01 1 total current 1.00e-06 1.00e-06 +6 1 1.05e-01 1.22e-01 1 total current 0.00e+00 0.00e+00 +7 1 1.22e-01 1.40e-01 1 total current 1.00e-06 1.00e-06 +8 1 1.40e-01 1.57e-01 1 total current 1.00e-06 1.00e-06 +9 1 1.57e-01 1.75e-01 1 total current 1.00e-06 1.00e-06 +10 1 1.75e-01 1.92e-01 1 total current 0.00e+00 0.00e+00 +11 1 1.92e-01 2.09e-01 1 total current 2.00e-06 1.33e-06 +12 1 2.09e-01 2.27e-01 1 total current 0.00e+00 0.00e+00 +13 1 2.27e-01 2.44e-01 1 total current 1.00e-06 1.00e-06 +14 1 2.44e-01 2.62e-01 1 total current 1.00e-06 1.00e-06 +15 1 2.62e-01 2.79e-01 1 total current 2.00e-06 1.33e-06 +16 1 2.79e-01 2.97e-01 1 total current 0.00e+00 0.00e+00 +17 1 2.97e-01 3.14e-01 1 total current 2.00e-06 2.00e-06 +18 1 3.14e-01 3.32e-01 1 total current 1.00e-06 1.00e-06 +19 1 3.32e-01 3.49e-01 1 total current 1.00e-06 1.00e-06 +20 1 3.49e-01 3.67e-01 1 total current 2.00e-06 1.33e-06 +21 1 3.67e-01 3.84e-01 1 total current 0.00e+00 0.00e+00 +22 1 3.84e-01 4.01e-01 1 total current 2.00e-06 1.33e-06 +23 1 4.01e-01 4.19e-01 1 total current 2.00e-06 1.33e-06 +24 1 4.19e-01 4.36e-01 1 total current 1.00e-06 1.00e-06 +25 1 4.36e-01 4.54e-01 1 total current 2.00e-06 2.00e-06 +26 1 4.54e-01 4.71e-01 1 total current 5.00e-06 2.24e-06 +27 1 4.71e-01 4.89e-01 1 total current 4.00e-06 1.63e-06 +28 1 4.89e-01 5.06e-01 1 total current 3.00e-06 1.53e-06 +29 1 5.06e-01 5.24e-01 1 total current 3.00e-06 1.53e-06 +30 1 5.24e-01 5.41e-01 1 total current 3.00e-06 1.53e-06 +31 1 5.41e-01 5.59e-01 1 total current 7.00e-06 2.13e-06 +32 1 5.59e-01 5.76e-01 1 total current 3.00e-06 1.53e-06 +33 1 5.76e-01 5.93e-01 1 total current 3.00e-06 1.53e-06 +34 1 5.93e-01 6.11e-01 1 total current 2.00e-06 1.33e-06 +35 1 6.11e-01 6.28e-01 1 total current 2.00e-06 1.33e-06 +36 1 6.28e-01 6.46e-01 1 total current 3.00e-06 2.13e-06 +37 1 6.46e-01 6.63e-01 1 total current 3.00e-06 1.53e-06 +38 1 6.63e-01 6.81e-01 1 total current 2.00e-06 1.33e-06 +39 1 6.81e-01 6.98e-01 1 total current 3.00e-06 1.53e-06 +40 1 6.98e-01 7.16e-01 1 total current 1.00e-06 1.00e-06 +41 1 7.16e-01 7.33e-01 1 total current 6.00e-06 2.67e-06 +42 1 7.33e-01 7.50e-01 1 total current 6.00e-06 2.21e-06 +43 1 7.50e-01 7.68e-01 1 total current 7.00e-06 3.35e-06 +44 1 7.68e-01 7.85e-01 1 total current 6.00e-06 2.67e-06 +45 1 7.85e-01 8.03e-01 1 total current 6.00e-06 2.21e-06 +46 1 8.03e-01 8.20e-01 1 total current 7.00e-06 2.13e-06 +47 1 8.20e-01 8.38e-01 1 total current 5.00e-06 2.24e-06 +48 1 8.38e-01 8.55e-01 1 total current 3.00e-06 1.53e-06 +49 1 8.55e-01 8.73e-01 1 total current 8.00e-06 3.27e-06 +50 1 8.73e-01 8.90e-01 1 total current 7.00e-06 2.13e-06 +51 1 8.90e-01 9.08e-01 1 total current 6.00e-06 2.21e-06 +52 1 9.08e-01 9.25e-01 1 total current 4.00e-06 2.21e-06 +53 1 9.25e-01 9.42e-01 1 total current 1.20e-05 3.27e-06 +54 1 9.42e-01 9.60e-01 1 total current 8.00e-06 3.89e-06 +55 1 9.60e-01 9.77e-01 1 total current 1.20e-05 4.42e-06 +56 1 9.77e-01 9.95e-01 1 total current 7.00e-06 3.67e-06 +57 1 9.95e-01 1.01e+00 1 total current 1.20e-05 3.89e-06 +58 1 1.01e+00 1.03e+00 1 total current 9.00e-06 2.33e-06 +59 1 1.03e+00 1.05e+00 1 total current 6.00e-06 2.67e-06 +60 1 1.05e+00 1.06e+00 1 total current 7.00e-06 2.13e-06 +61 1 1.06e+00 1.08e+00 1 total current 5.00e-06 2.24e-06 +62 1 1.08e+00 1.10e+00 1 total current 1.20e-05 2.91e-06 +63 1 1.10e+00 1.12e+00 1 total current 1.30e-05 3.35e-06 +64 1 1.12e+00 1.13e+00 1 total current 9.00e-06 3.14e-06 +65 1 1.13e+00 1.15e+00 1 total current 1.20e-05 3.89e-06 +66 1 1.15e+00 1.17e+00 1 total current 6.00e-06 2.21e-06 +67 1 1.17e+00 1.19e+00 1 total current 5.11e-03 4.20e-05 +68 1 1.19e+00 1.20e+00 1 total current 8.00e-06 3.27e-06 +69 1 1.20e+00 1.22e+00 1 total current 1.30e-05 4.48e-06 +70 1 1.22e+00 1.24e+00 1 total current 1.20e-05 3.89e-06 +71 1 1.24e+00 1.26e+00 1 total current 1.50e-05 4.28e-06 +72 1 1.26e+00 1.27e+00 1 total current 7.00e-06 3.00e-06 +73 1 1.27e+00 1.29e+00 1 total current 1.60e-05 3.71e-06 +74 1 1.29e+00 1.31e+00 1 total current 9.00e-06 3.79e-06 +75 1 1.31e+00 1.33e+00 1 total current 1.30e-05 2.60e-06 +76 1 1.33e+00 1.34e+00 1 total current 1.60e-05 3.06e-06 +77 1 1.34e+00 1.36e+00 1 total current 1.40e-05 2.67e-06 +78 1 1.36e+00 1.38e+00 1 total current 1.40e-05 6.86e-06 +79 1 1.38e+00 1.40e+00 1 total current 1.50e-05 4.28e-06 +80 1 1.40e+00 1.41e+00 1 total current 3.26e-03 6.93e-05 +81 1 1.41e+00 1.43e+00 1 total current 1.40e-05 3.71e-06 +82 1 1.43e+00 1.45e+00 1 total current 1.30e-05 3.00e-06 +83 1 1.45e+00 1.47e+00 1 total current 1.30e-05 3.67e-06 +84 1 1.47e+00 1.48e+00 1 total current 1.70e-05 5.59e-06 +85 1 1.48e+00 1.50e+00 1 total current 1.70e-05 3.67e-06 +86 1 1.50e+00 1.52e+00 1 total current 1.40e-05 3.40e-06 +87 1 1.52e+00 1.54e+00 1 total current 2.50e-05 4.53e-06 +88 1 1.54e+00 1.55e+00 1 total current 1.30e-05 5.39e-06 +89 1 1.55e+00 1.57e+00 1 total current 1.80e-05 4.67e-06 +90 1 1.57e+00 1.59e+00 1 total current 1.40e-05 4.52e-06 +91 1 1.59e+00 1.61e+00 1 total current 1.70e-05 4.23e-06 +92 1 1.61e+00 1.62e+00 1 total current 1.40e-05 3.71e-06 +93 1 1.62e+00 1.64e+00 1 total current 1.00e-05 2.11e-06 +94 1 1.64e+00 1.66e+00 1 total current 2.00e-05 4.22e-06 +95 1 1.66e+00 1.68e+00 1 total current 2.30e-05 5.59e-06 +96 1 1.68e+00 1.69e+00 1 total current 1.70e-05 6.51e-06 +97 1 1.69e+00 1.71e+00 1 total current 1.30e-05 3.00e-06 +98 1 1.71e+00 1.73e+00 1 total current 1.50e-05 4.01e-06 +99 1 1.73e+00 1.75e+00 1 total current 1.70e-05 3.96e-06 +100 1 1.75e+00 1.76e+00 1 total current 1.80e-05 5.12e-06 +101 1 1.76e+00 1.78e+00 1 total current 2.50e-05 6.54e-06 +102 1 1.78e+00 1.80e+00 1 total current 1.80e-05 3.59e-06 +103 1 1.80e+00 1.82e+00 1 total current 1.50e-05 4.01e-06 +104 1 1.82e+00 1.83e+00 1 total current 1.10e-05 4.07e-06 +105 1 1.83e+00 1.85e+00 1 total current 1.50e-05 4.01e-06 +106 1 1.85e+00 1.87e+00 1 total current 1.90e-05 4.82e-06 +107 1 1.87e+00 1.88e+00 1 total current 2.20e-05 3.89e-06 +108 1 1.88e+00 1.90e+00 1 total current 2.10e-05 3.79e-06 +109 1 1.90e+00 1.92e+00 1 total current 1.50e-05 3.42e-06 +110 1 1.92e+00 1.94e+00 1 total current 2.20e-05 5.12e-06 +111 1 1.94e+00 1.95e+00 1 total current 2.10e-05 5.86e-06 +112 1 1.95e+00 1.97e+00 1 total current 2.60e-05 4.27e-06 +113 1 1.97e+00 1.99e+00 1 total current 2.20e-05 4.16e-06 +114 1 1.99e+00 2.01e+00 1 total current 2.40e-05 5.42e-06 +115 1 2.01e+00 2.02e+00 1 total current 1.60e-05 4.52e-06 +116 1 2.02e+00 2.04e+00 1 total current 1.30e-05 3.35e-06 +117 1 2.04e+00 2.06e+00 1 total current 1.90e-05 4.07e-06 +118 1 2.06e+00 2.08e+00 1 total current 1.30e-05 3.00e-06 +119 1 2.08e+00 2.09e+00 1 total current 1.40e-05 4.00e-06 +120 1 2.09e+00 2.11e+00 1 total current 3.10e-05 5.47e-06 +121 1 2.11e+00 2.13e+00 1 total current 2.30e-05 5.39e-06 +122 1 2.13e+00 2.15e+00 1 total current 2.20e-05 4.67e-06 +123 1 2.15e+00 2.16e+00 1 total current 1.70e-05 4.48e-06 +124 1 2.16e+00 2.18e+00 1 total current 1.60e-05 4.00e-06 +125 1 2.18e+00 2.20e+00 1 total current 1.80e-05 4.16e-06 +126 1 2.20e+00 2.22e+00 1 total current 1.80e-05 4.42e-06 +127 1 2.22e+00 2.23e+00 1 total current 1.80e-05 5.54e-06 +128 1 2.23e+00 2.25e+00 1 total current 1.90e-05 4.33e-06 +129 1 2.25e+00 2.27e+00 1 total current 1.00e-05 3.33e-06 +130 1 2.27e+00 2.29e+00 1 total current 1.80e-05 4.42e-06 +131 1 2.29e+00 2.30e+00 1 total current 4.15e-03 5.40e-05 +132 1 2.30e+00 2.32e+00 1 total current 1.90e-05 2.33e-06 +133 1 2.32e+00 2.34e+00 1 total current 2.30e-05 3.96e-06 +134 1 2.34e+00 2.36e+00 1 total current 1.90e-05 3.48e-06 +135 1 2.36e+00 2.37e+00 1 total current 1.60e-05 3.71e-06 +136 1 2.37e+00 2.39e+00 1 total current 1.60e-05 4.27e-06 +137 1 2.39e+00 2.41e+00 1 total current 2.30e-05 4.48e-06 +138 1 2.41e+00 2.43e+00 1 total current 2.10e-05 3.48e-06 +139 1 2.43e+00 2.44e+00 1 total current 1.60e-05 2.21e-06 +140 1 2.44e+00 2.46e+00 1 total current 9.00e-06 2.77e-06 +141 1 2.46e+00 2.48e+00 1 total current 1.30e-05 3.00e-06 +142 1 2.48e+00 2.50e+00 1 total current 2.70e-05 3.67e-06 +143 1 2.50e+00 2.51e+00 1 total current 1.90e-05 4.07e-06 +144 1 2.51e+00 2.53e+00 1 total current 1.20e-05 4.16e-06 +145 1 2.53e+00 2.55e+00 1 total current 1.30e-05 2.13e-06 +146 1 2.55e+00 2.57e+00 1 total current 1.10e-05 2.33e-06 +147 1 2.57e+00 2.58e+00 1 total current 1.50e-05 3.07e-06 +148 1 2.58e+00 2.60e+00 1 total current 1.20e-05 2.49e-06 +149 1 2.60e+00 2.62e+00 1 total current 1.80e-05 5.54e-06 +150 1 2.62e+00 2.64e+00 1 total current 1.30e-05 3.67e-06 +151 1 2.64e+00 2.65e+00 1 total current 1.60e-05 3.40e-06 +152 1 2.65e+00 2.67e+00 1 total current 7.00e-06 3.35e-06 +153 1 2.67e+00 2.69e+00 1 total current 1.00e-05 2.98e-06 +154 1 2.69e+00 2.71e+00 1 total current 7.00e-06 3.35e-06 +155 1 2.71e+00 2.72e+00 1 total current 1.20e-05 2.91e-06 +156 1 2.72e+00 2.74e+00 1 total current 9.00e-06 2.33e-06 +157 1 2.74e+00 2.76e+00 1 total current 1.00e-05 3.33e-06 +158 1 2.76e+00 2.78e+00 1 total current 1.10e-05 3.14e-06 +159 1 2.78e+00 2.79e+00 1 total current 1.00e-05 3.33e-06 +160 1 2.79e+00 2.81e+00 1 total current 1.40e-05 4.76e-06 +161 1 2.81e+00 2.83e+00 1 total current 8.00e-06 2.91e-06 +162 1 2.83e+00 2.84e+00 1 total current 5.00e-06 2.69e-06 +163 1 2.84e+00 2.86e+00 1 total current 6.00e-06 2.21e-06 +164 1 2.86e+00 2.88e+00 1 total current 5.00e-06 1.67e-06 +165 1 2.88e+00 2.90e+00 1 total current 4.00e-06 2.21e-06 +166 1 2.90e+00 2.91e+00 1 total current 7.00e-06 2.13e-06 +167 1 2.91e+00 2.93e+00 1 total current 6.00e-06 2.67e-06 +168 1 2.93e+00 2.95e+00 1 total current 7.00e-06 2.13e-06 +169 1 2.95e+00 2.97e+00 1 total current 5.00e-06 1.67e-06 +170 1 2.97e+00 2.98e+00 1 total current 3.00e-06 1.53e-06 +171 1 2.98e+00 3.00e+00 1 total current 6.00e-06 2.21e-06 +172 1 3.00e+00 3.02e+00 1 total current 3.00e-06 1.53e-06 +173 1 3.02e+00 3.04e+00 1 total current 1.00e-05 2.98e-06 +174 1 3.04e+00 3.05e+00 1 total current 2.00e-06 1.33e-06 +175 1 3.05e+00 3.07e+00 1 total current 1.00e-06 1.00e-06 +176 1 3.07e+00 3.09e+00 1 total current 2.00e-06 1.33e-06 +177 1 3.09e+00 3.11e+00 1 total current 0.00e+00 0.00e+00 +178 1 3.11e+00 3.12e+00 1 total current 1.00e-06 1.00e-06 +179 1 3.12e+00 3.14e+00 1 total current 0.00e+00 0.00e+00 \ No newline at end of file diff --git a/tests/regression_tests/ncrystal/test.py b/tests/regression_tests/ncrystal/test.py new file mode 100644 index 00000000000..e1c1e5ed6f0 --- /dev/null +++ b/tests/regression_tests/ncrystal/test.py @@ -0,0 +1,105 @@ +from math import pi +import filecmp +from difflib import unified_diff + +import numpy as np +import openmc +import openmc.lib +import pytest + +from tests.testing_harness import PyAPITestHarness + +pytestmark = pytest.mark.skipif( + not openmc.lib._ncrystal_enabled(), + reason="NCrystal materials are not enabled.") + + +def pencil_beam_model(cfg, E0, N): + """Return an openmc.Model() object for a monoenergetic pencil + beam hitting a 1 mm sphere filled with the material defined by + the cfg string, and compute the angular distribution""" + + # Material definition + + m1 = openmc.Material.from_ncrystal(cfg) + materials = openmc.Materials([m1]) + + # Geometry definition + + sample_sphere = openmc.Sphere(r=0.1) + outer_sphere = openmc.Sphere(r=100, boundary_type="vacuum") + cell1 = openmc.Cell(region=-sample_sphere, fill=m1) + cell2_region = +sample_sphere & -outer_sphere + cell2 = openmc.Cell(region=cell2_region, fill=None) + geometry = openmc.Geometry([cell1, cell2]) + + # Source definition + + source = openmc.IndependentSource() + source.space = openmc.stats.Point((0, 0, -20)) + source.angle = openmc.stats.Monodirectional(reference_uvw=(0, 0, 1)) + source.energy = openmc.stats.Discrete([E0], [1.0]) + + # Execution settings + + settings = openmc.Settings() + settings.source = source + settings.run_mode = "fixed source" + settings.batches = 10 + settings.particles = N + + # Tally definition + + tally1 = openmc.Tally(name="angular distribution") + tally1.scores = ["current"] + filter1 = openmc.SurfaceFilter(sample_sphere) + filter2 = openmc.PolarFilter(np.linspace(0, pi, 180+1)) + filter3 = openmc.CellFromFilter(cell1) + tally1.filters = [filter1, filter2, filter3] + tallies = openmc.Tallies([tally1]) + + return openmc.Model(geometry, materials, settings, tallies) + + +class NCrystalTest(PyAPITestHarness): + def _get_results(self): + """Digest info in the statepoint and return as a string.""" + + # Read the statepoint file. + with openmc.StatePoint(self._sp_name) as sp: + tal = sp.get_tally(name='angular distribution') + df = tal.get_pandas_dataframe() + return df.to_string() + + +def test_ncrystal(): + n_particles = 100000 + T = 293.6 # K + E0 = 0.012 # eV + cfg = 'Al_sg225.ncmat' + test = pencil_beam_model(cfg, E0, n_particles) + harness = NCrystalTest('statepoint.10.h5', model=test) + harness.main() + + +def test_cfg_from_xml(): + """Make sure the cfg string is read by from_xml method""" + n_particles = 100000 + E0 = 0.012 # eV + cfg = 'Al_sg225.ncmat' + model = pencil_beam_model(cfg, E0, n_particles) + #export the original material generated with cfg string + model.materials.export_to_xml('materials.xml.orig') + expected = open('materials.xml.orig', 'r').readlines() + #read back the original material + mats_from_xml = openmc.Materials.from_xml('materials.xml.orig') + #export again + mats_from_xml.export_to_xml('materials.xml.after') + actual = open('materials.xml.after', 'r').readlines() + compare = filecmp.cmp('materials.xml.orig','materials.xml.after') + if not compare: + diff = unified_diff(expected, actual, 'materials.xml.orig', + 'materials.xml.after') + print('Input differences:') + print(''.join(diff)) + assert compare, 'Materials not read correctly from XML' diff --git a/tests/regression_tests/output/results_true.dat b/tests/regression_tests/output/results_true.dat index fe46748c80d..bbf03de9437 100644 --- a/tests/regression_tests/output/results_true.dat +++ b/tests/regression_tests/output/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.987050E-01 1.827430E-03 +3.070134E-01 3.900396E-03 diff --git a/tests/regression_tests/particle_restart_eigval/results_true.dat b/tests/regression_tests/particle_restart_eigval/results_true.dat index 64101d7706f..bd81920caea 100644 --- a/tests/regression_tests/particle_restart_eigval/results_true.dat +++ b/tests/regression_tests/particle_restart_eigval/results_true.dat @@ -3,14 +3,14 @@ current batch: current generation: 1.000000E+00 particle id: -9.020000E+02 +2.540000E+02 run mode: eigenvalue particle weight: 1.000000E+00 particle energy: -3.691964E+06 +2.220048E+06 particle xyz: --5.047439E+01 2.730535E+01 -2.619863E+01 +-4.820850E+01 2.432936E+01 4.397668E+01 particle uvw: --6.278670E-01 1.419818E-01 -7.652609E-01 +-3.148565E-01 9.184190E-01 2.395245E-01 diff --git a/tests/regression_tests/particle_restart_eigval/test.py b/tests/regression_tests/particle_restart_eigval/test.py index e526e500385..f9d22edb8a2 100644 --- a/tests/regression_tests/particle_restart_eigval/test.py +++ b/tests/regression_tests/particle_restart_eigval/test.py @@ -2,5 +2,5 @@ def test_particle_restart_eigval(): - harness = ParticleRestartTestHarness('particle_11_902.h5') + harness = ParticleRestartTestHarness('particle_11_254.h5') harness.main() diff --git a/tests/regression_tests/periodic/inputs_true.dat b/tests/regression_tests/periodic/inputs_true.dat index c1f6d156318..65e1b5ce309 100644 --- a/tests/regression_tests/periodic/inputs_true.dat +++ b/tests/regression_tests/periodic/inputs_true.dat @@ -1,37 +1,37 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 4 - 0 - - - 0 0 0 5 5 0 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 4 + 0 + + + 0 0 0 5 5 0 + + + + diff --git a/tests/regression_tests/periodic/results_true.dat b/tests/regression_tests/periodic/results_true.dat index 6d58baccb0c..2189597e112 100644 --- a/tests/regression_tests/periodic/results_true.dat +++ b/tests/regression_tests/periodic/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.654583E+00 1.501286E-02 +1.623300E+00 2.572983E-02 diff --git a/tests/regression_tests/periodic/test.py b/tests/regression_tests/periodic/test.py index 51a70a6aa7e..73fe8a83e44 100644 --- a/tests/regression_tests/periodic/test.py +++ b/tests/regression_tests/periodic/test.py @@ -42,7 +42,7 @@ def box_model(): model.settings.particles = 1000 model.settings.batches = 4 model.settings.inactive = 0 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( (0, 0, 0), (5, 5, 0)) ) return model diff --git a/tests/regression_tests/periodic_6fold/inputs_true.dat b/tests/regression_tests/periodic_6fold/inputs_true.dat index 35bbcc04759..f7f413d092b 100644 --- a/tests/regression_tests/periodic_6fold/inputs_true.dat +++ b/tests/regression_tests/periodic_6fold/inputs_true.dat @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 4 - 0 - - - 0 0 0 5 5 0 - - - + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 4 + 0 + + + 0 0 0 5 5 0 + + + + diff --git a/tests/regression_tests/periodic_6fold/results_true.dat b/tests/regression_tests/periodic_6fold/results_true.dat index def4d0c7ab8..e60182809aa 100644 --- a/tests/regression_tests/periodic_6fold/results_true.dat +++ b/tests/regression_tests/periodic_6fold/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.845885E+00 1.472487E-02 +1.858730E+00 6.824588E-03 diff --git a/tests/regression_tests/periodic_6fold/test.py b/tests/regression_tests/periodic_6fold/test.py index 555ab24f9fa..272c65df57f 100644 --- a/tests/regression_tests/periodic_6fold/test.py +++ b/tests/regression_tests/periodic_6fold/test.py @@ -1,5 +1,6 @@ +from math import sin, cos, pi + import openmc -import numpy as np import pytest from tests.testing_harness import PyAPITestHarness @@ -24,17 +25,14 @@ def model(): # (it essentially defines a circle of half-cylinders), but it is # designed so that periodic and reflective BCs will give different # answers. - theta1 = (-1/6 + 1/2) * np.pi - theta2 = (1/6 - 1/2) * np.pi - plane1 = openmc.Plane(a=np.cos(theta1), b=np.sin(theta1), - boundary_type='periodic') - plane2 = openmc.Plane(a=np.cos(theta2), b=np.sin(theta2), - boundary_type='periodic') + theta1 = (-1/6 + 1/2) * pi + theta2 = (1/6 - 1/2) * pi + plane1 = openmc.Plane(a=cos(theta1), b=sin(theta1), boundary_type='periodic') + plane2 = openmc.Plane(a=cos(theta2), b=sin(theta2), boundary_type='periodic') - x_max = openmc.XPlane(x0=5., boundary_type='reflective') + x_max = openmc.XPlane(5., boundary_type='reflective') - z_cyl = openmc.ZCylinder(x0=3*np.cos(np.pi/6), y0=3*np.sin(np.pi/6), - r=2.0) + z_cyl = openmc.ZCylinder(x0=3*cos(pi/6), y0=3*sin(pi/6), r=2.0) outside_cyl = openmc.Cell(1, fill=water, region=( +plane1 & +plane2 & -x_max & +z_cyl)) @@ -48,7 +46,7 @@ def model(): model.settings.particles = 1000 model.settings.batches = 4 model.settings.inactive = 0 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( (0, 0, 0), (5, 5, 0)) ) return model diff --git a/tests/regression_tests/periodic_hex/inputs_true.dat b/tests/regression_tests/periodic_hex/inputs_true.dat index 00e539d4bfb..188c8dfa93f 100644 --- a/tests/regression_tests/periodic_hex/inputs_true.dat +++ b/tests/regression_tests/periodic_hex/inputs_true.dat @@ -1,24 +1,24 @@ - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + diff --git a/tests/regression_tests/periodic_hex/results_true.dat b/tests/regression_tests/periodic_hex/results_true.dat index 16512ec23f2..584089a15de 100644 --- a/tests/regression_tests/periodic_hex/results_true.dat +++ b/tests/regression_tests/periodic_hex/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.271604E+00 1.159996E-02 +2.284468E+00 2.781588E-02 diff --git a/tests/regression_tests/periodic_hex/test.py b/tests/regression_tests/periodic_hex/test.py index a21819b1ada..db9f6cfd5b0 100644 --- a/tests/regression_tests/periodic_hex/test.py +++ b/tests/regression_tests/periodic_hex/test.py @@ -12,8 +12,8 @@ def hex_model(): fuel.add_nuclide('U235', 1.0) fuel.set_density('g/cc', 4.5) - hex_region = openmc.model.hexagonal_prism(10.0, boundary_type='periodic') - cell = openmc.Cell(fill=fuel, region=hex_region) + hex_prism = openmc.model.HexagonalPrism(10.0, boundary_type='periodic') + cell = openmc.Cell(fill=fuel, region=-hex_prism) model.geometry = openmc.Geometry([cell]) # Define settings diff --git a/tests/regression_tests/photon_production/inputs_true.dat b/tests/regression_tests/photon_production/inputs_true.dat index 09f1fd290fd..ee6cb88622b 100644 --- a/tests/regression_tests/photon_production/inputs_true.dat +++ b/tests/regression_tests/photon_production/inputs_true.dat @@ -1,68 +1,67 @@ - - - - - - - - - - - - - - - - - - - fixed source - 10000 - 1 - - - 0 0 0 - - - - 14000000.0 1.0 - - - ttb - true - - 1000.0 - - - - - - 1 - - - neutron photon electron positron - - - 1 2 - current - - - 2 - Al27 total - total (n,gamma) - tracklength - - - 2 - Al27 total - total heating (n,gamma) - collision - - - 2 - Al27 total - total heating (n,gamma) - analog - - + + + + + + + + + + + + + + + + + + fixed source + 10000 + 1 + + + 0 0 0 + + + + 14000000.0 1.0 + + + ttb + true + + 1000.0 + + + + + 1 + + + neutron photon electron positron + + + 1 2 + current + + + 2 + Al27 total + total (n,gamma) + tracklength + + + 2 + Al27 total + total heating (n,gamma) + collision + + + 2 + Al27 total + total heating (n,gamma) + analog + + + diff --git a/tests/regression_tests/photon_production/results_true.dat b/tests/regression_tests/photon_production/results_true.dat index 0502dce740b..398deeed8b0 100644 --- a/tests/regression_tests/photon_production/results_true.dat +++ b/tests/regression_tests/photon_production/results_true.dat @@ -1,8 +1,8 @@ tally 1: 8.610000E-01 7.413210E-01 -9.503000E-01 -9.030701E-01 +9.493000E-01 +9.011705E-01 0.000000E+00 0.000000E+00 0.000000E+00 @@ -16,12 +16,12 @@ tally 2: 1.573004E+00 4.296434E-04 1.845934E-07 -8.124327E-01 -6.600469E-01 +2.337049E-01 +5.461796E-02 0.000000E+00 0.000000E+00 -8.124327E-01 -6.600469E-01 +2.337049E-01 +5.461796E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -53,40 +53,40 @@ tally 3: 4.104374E+12 4.296582E-04 1.846062E-07 -8.034000E-01 -6.454516E-01 -6.951747E+03 -4.832678E+07 +2.286000E-01 +5.225796E-02 +7.054033E+03 +4.975938E+07 0.000000E+00 0.000000E+00 -8.034000E-01 -6.454516E-01 -6.951747E+03 -4.832678E+07 +2.286000E-01 +5.225796E-02 +7.054033E+03 +4.975938E+07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.762393E+05 -3.106028E+10 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.762393E+05 -3.106028E+10 0.000000E+00 0.000000E+00 +1.764573E+05 +3.113718E+10 0.000000E+00 0.000000E+00 -7.631073E+03 -5.823328E+07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -7.631073E+03 -5.823328E+07 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +7.691658E+03 +5.916160E+07 0.000000E+00 0.000000E+00 tally 4: @@ -102,16 +102,16 @@ tally 4: 4.104374E+12 0.000000E+00 0.000000E+00 -2.294000E-01 -5.262436E-02 -6.947074E+03 -4.826184E+07 +2.286000E-01 +5.225796E-02 +7.054033E+03 +4.975938E+07 0.000000E+00 0.000000E+00 -8.034000E-01 -6.454516E-01 -6.951747E+03 -4.832678E+07 +2.286000E-01 +5.225796E-02 +7.054033E+03 +4.975938E+07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -122,8 +122,8 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -1.762393E+05 -3.106028E+10 +1.764573E+05 +3.113718E+10 0.000000E+00 0.000000E+00 0.000000E+00 @@ -134,7 +134,7 @@ tally 4: 0.000000E+00 0.000000E+00 0.000000E+00 -7.631073E+03 -5.823328E+07 +7.691658E+03 +5.916160E+07 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/photon_production/test.py b/tests/regression_tests/photon_production/test.py index 107b53bbb60..150448a12f4 100644 --- a/tests/regression_tests/photon_production/test.py +++ b/tests/regression_tests/photon_production/test.py @@ -27,7 +27,7 @@ def model(): inner_cyl_right.fill = mat model.geometry = openmc.Geometry([inner_cyl_left, inner_cyl_right, outer_cyl]) - source = openmc.Source() + source = openmc.IndependentSource() source.space = openmc.stats.Point((0, 0, 0)) source.angle = openmc.stats.Monodirectional() source.energy = openmc.stats.Discrete([14.0e6], [1.0]) diff --git a/tests/regression_tests/photon_production_fission/inputs_true.dat b/tests/regression_tests/photon_production_fission/inputs_true.dat index c317f6273e3..fa379b39e10 100644 --- a/tests/regression_tests/photon_production_fission/inputs_true.dat +++ b/tests/regression_tests/photon_production_fission/inputs_true.dat @@ -1,49 +1,48 @@ - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 2 - - - 0 0 0 - - - true - - - - - neutron photon - - - 1 - U235 total - fission heating-local - tracklength - - - 1 - U235 total - fission heating heating-local - collision - - - 1 - U235 total - fission heating heating-local - analog - - + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 2 + + + 0 0 0 + + + true + + + + neutron photon + + + 1 + U235 total + fission heating-local + tracklength + + + 1 + U235 total + fission heating heating-local + collision + + + 1 + U235 total + fission heating heating-local + analog + + + diff --git a/tests/regression_tests/photon_production_fission/results_true.dat b/tests/regression_tests/photon_production_fission/results_true.dat index c3ad3c803f0..1aa08b1476e 100644 --- a/tests/regression_tests/photon_production_fission/results_true.dat +++ b/tests/regression_tests/photon_production_fission/results_true.dat @@ -1,12 +1,12 @@ k-combined: -2.268512E+00 8.628052E-03 +2.272421E+00 4.418825E-02 tally 1: -2.657963E+00 -2.355039E+00 +2.665301E+00 +2.369839E+00 0.000000E+00 0.000000E+00 -2.657963E+00 -2.355039E+00 +2.665301E+00 +2.369839E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -18,52 +18,52 @@ tally 1: 0.000000E+00 0.000000E+00 tally 2: -2.640348E+00 -2.323851E+00 -4.246717E+08 -6.011634E+16 +2.637532E+00 +2.320051E+00 +4.231377E+08 +5.971498E+16 0.000000E+00 0.000000E+00 -2.640348E+00 -2.323851E+00 -4.246717E+08 -6.011634E+16 +2.637532E+00 +2.320051E+00 +4.231377E+08 +5.971498E+16 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.355438E+06 -1.849734E+12 +2.448745E+06 +2.005297E+12 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.355438E+06 -1.849734E+12 +2.448745E+06 +2.005297E+12 0.000000E+00 0.000000E+00 tally 3: -2.654437E+00 -2.348704E+00 -4.246717E+08 -6.011634E+16 +2.660000E+00 +2.358558E+00 +4.231377E+08 +5.971498E+16 0.000000E+00 0.000000E+00 -2.654437E+00 -2.348704E+00 -4.246717E+08 -6.011634E+16 +2.660000E+00 +2.358558E+00 +4.231377E+08 +5.971498E+16 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.173264E+06 -1.574708E+12 +2.448745E+06 +2.005297E+12 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.355438E+06 -1.849734E+12 +2.448745E+06 +2.005297E+12 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/photon_production_fission/test.py b/tests/regression_tests/photon_production_fission/test.py index 595d3c2d6c2..96665b30867 100644 --- a/tests/regression_tests/photon_production_fission/test.py +++ b/tests/regression_tests/photon_production_fission/test.py @@ -20,7 +20,7 @@ def model(): model.settings.batches = 5 model.settings.inactive = 2 model.settings.photon_transport = True - model.settings.source = openmc.Source(space=openmc.stats.Point((0, 0, 0))) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point((0, 0, 0))) particle_filter = openmc.ParticleFilter(['neutron', 'photon']) tally_tracklength = openmc.Tally() diff --git a/tests/regression_tests/photon_source/inputs_true.dat b/tests/regression_tests/photon_source/inputs_true.dat index f7c9c24b4f1..3d2e0524350 100644 --- a/tests/regression_tests/photon_source/inputs_true.dat +++ b/tests/regression_tests/photon_source/inputs_true.dat @@ -1,45 +1,44 @@ - - - - - - - - - - - - - - - - - fixed source - 10000 - 1 - - - 0 0 0 - - - - 10000000.0 1.0 - - - ttb - true - - 1000.0 - - - - - - photon - - - 1 - flux (n,gamma) - - + + + + + + + + + + + + + + + + fixed source + 10000 + 1 + + + 0 0 0 + + + + 10000000.0 1.0 + + + ttb + true + + 1000.0 + + + + + photon + + + 1 + flux (n,gamma) + + + diff --git a/tests/regression_tests/photon_source/results_true.dat b/tests/regression_tests/photon_source/results_true.dat index a8ec212eb8a..fcc75cbca84 100644 --- a/tests/regression_tests/photon_source/results_true.dat +++ b/tests/regression_tests/photon_source/results_true.dat @@ -1,5 +1,5 @@ tally 1: -2.256359E+02 -5.091156E+04 +2.263938E+02 +5.125417E+04 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/photon_source/test.py b/tests/regression_tests/photon_source/test.py index a2bfb903848..c2eb1476de2 100644 --- a/tests/regression_tests/photon_source/test.py +++ b/tests/regression_tests/photon_source/test.py @@ -7,22 +7,21 @@ class SourceTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) mat = openmc.Material() mat.set_density('g/cm3', 0.998207) mat.add_element('H', 0.111894) mat.add_element('O', 0.888106) - materials = openmc.Materials([mat]) - materials.export_to_xml() + self._model.materials = openmc.Materials([mat]) sphere = openmc.Sphere(r=1.0e9, boundary_type='reflective') inside_sphere = openmc.Cell() inside_sphere.region = -sphere inside_sphere.fill = mat - geometry = openmc.Geometry([inside_sphere]) - geometry.export_to_xml() + self._model.geometry = openmc.Geometry([inside_sphere]) - source = openmc.Source() + source = openmc.IndependentSource() source.space = openmc.stats.Point((0, 0, 0)) source.angle = openmc.stats.Isotropic() source.energy = openmc.stats.Discrete([10.0e6], [1.0]) @@ -36,16 +35,16 @@ def _build_inputs(self): settings.cutoff = {'energy_photon' : 1000.0} settings.run_mode = 'fixed source' settings.source = source - settings.export_to_xml() + self._model.settings = settings particle_filter = openmc.ParticleFilter('photon') tally = openmc.Tally() tally.filters = [particle_filter] tally.scores = ['flux', '(n,gamma)'] tallies = openmc.Tallies([tally]) - tallies.export_to_xml() + self._model.tallies = tallies def test_photon_source(): - harness = SourceTestHarness('statepoint.1.h5') + harness = SourceTestHarness('statepoint.1.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/plot/geometry.xml b/tests/regression_tests/plot/geometry.xml deleted file mode 100644 index 83619d9f786..00000000000 --- a/tests/regression_tests/plot/geometry.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/tests/regression_tests/plot/model.xml b/tests/regression_tests/plot/model.xml new file mode 100644 index 00000000000..a63ff95daad --- /dev/null +++ b/tests/regression_tests/plot/model.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + plot + 1 + + 5 4 3 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + + + -10.0 10.0 + -10.0 10.0 + -10.0 0.0 5.0 7.5 8.75 10.0 + + + 2 + + + 1 + total + + + + + 0.0 0.0 0.0 + 25.0 25.0 + 200 200 + + + + + 0.0 0.0 0.0 + 25.0 25.0 + 200 200 + + + + + 0.0 0.0 0.0 + 25.0 25.0 + 200 200 + 0 0 0 + + + 0.0 0.0 0.0 + 20.0 20.0 10.0 + 100 100 10 + + + diff --git a/tests/regression_tests/plot/plots.xml b/tests/regression_tests/plot/plots.xml deleted file mode 100644 index ce63da1442d..00000000000 --- a/tests/regression_tests/plot/plots.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - 0. 0. 0. - 25 25 - 200 200 - - - - - - 0. 0. 0. - 25 25 - 200 200 - - - - - - 0. 0. 0. - 25 25 - 200 200 - 0 0 0 - - - - 100 100 10 - 0. 0. 0. - 20 20 10 - - - diff --git a/tests/regression_tests/plot/results_true.dat b/tests/regression_tests/plot/results_true.dat index 54b6a253f0f..1be60ad4fa1 100644 --- a/tests/regression_tests/plot/results_true.dat +++ b/tests/regression_tests/plot/results_true.dat @@ -1 +1 @@ -a8192f6029cf99748816fab2618fa48e180656eba313940ccdfff3e56890a5dadd13bf92cd7e3be6a4b535bca5e2a58a905fcfba018fb922273f8be6dfc19859 \ No newline at end of file +6385d2969ed54d47a09f75112595fc034a16f551346c92d87ed9e7841881baaee8e56190c347e97c3f919ef677bb5b858960d60fe985a00e2848a3bfbef7a12b \ No newline at end of file diff --git a/tests/regression_tests/plot/test.py b/tests/regression_tests/plot/test.py index a6f7306a0e7..30d9ab0d08e 100644 --- a/tests/regression_tests/plot/test.py +++ b/tests/regression_tests/plot/test.py @@ -1,61 +1,8 @@ -import glob -import hashlib -import os - -import h5py -import openmc - -from tests.testing_harness import TestHarness +from tests.testing_harness import PlotTestHarness from tests.regression_tests import config -class PlotTestHarness(TestHarness): - """Specialized TestHarness for running OpenMC plotting tests.""" - def __init__(self, plot_names): - super().__init__(None) - self._plot_names = plot_names - - def _run_openmc(self): - openmc.plot_geometry(openmc_exec=config['exe']) - - def _test_output_created(self): - """Make sure *.ppm has been created.""" - for fname in self._plot_names: - assert os.path.exists(fname), 'Plot output file does not exist.' - - def _cleanup(self): - super()._cleanup() - for fname in self._plot_names: - if os.path.exists(fname): - os.remove(fname) - - def _get_results(self): - """Return a string hash of the plot files.""" - outstr = bytes() - - for fname in self._plot_names: - if fname.endswith('.ppm'): - # Add PPM output to results - with open(fname, 'rb') as fh: - outstr += fh.read() - elif fname.endswith('.h5'): - # Add voxel data to results - with h5py.File(fname, 'r') as fh: - outstr += fh.attrs['filetype'] - outstr += fh.attrs['num_voxels'].tobytes() - outstr += fh.attrs['lower_left'].tobytes() - outstr += fh.attrs['voxel_width'].tobytes() - outstr += fh['data'][()].tobytes() - - # Hash the information and return. - sha512 = hashlib.sha512() - sha512.update(outstr) - outstr = sha512.hexdigest() - - return outstr - - def test_plot(): - harness = PlotTestHarness(('plot_1.ppm', 'plot_2.ppm', 'plot_3.ppm', + harness = PlotTestHarness(('plot_1.png', 'plot_2.png', 'plot_3.png', 'plot_4.h5')) harness.main() diff --git a/tests/regression_tests/plot_overlaps/geometry.xml b/tests/regression_tests/plot_overlaps/geometry.xml deleted file mode 100644 index 7a9f1fb41f3..00000000000 --- a/tests/regression_tests/plot_overlaps/geometry.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/tests/regression_tests/plot_overlaps/materials.xml b/tests/regression_tests/plot_overlaps/materials.xml deleted file mode 100644 index 90b3542675e..00000000000 --- a/tests/regression_tests/plot_overlaps/materials.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/tests/regression_tests/plot_overlaps/model.xml b/tests/regression_tests/plot_overlaps/model.xml new file mode 100644 index 00000000000..e3b65d45d4c --- /dev/null +++ b/tests/regression_tests/plot_overlaps/model.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + plot + 1 + + 5 4 3 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + + + 0.0 0.0 0.0 + 25.0 25.0 + 200 200 + + true + + + + 0.0 0.0 0.0 + 25.0 25.0 + 200 200 + + true + 255 211 0 + + + 0.0 0.0 0.0 + 25.0 25.0 + 200 200 + 0 0 0 + + + 0.0 0.0 0.0 + 20.0 20.0 10.0 + 100 100 10 + + + diff --git a/tests/regression_tests/plot_overlaps/plots.xml b/tests/regression_tests/plot_overlaps/plots.xml deleted file mode 100644 index 28064f58fbc..00000000000 --- a/tests/regression_tests/plot_overlaps/plots.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - 0. 0. 0. - 25 25 - 200 200 - - - true - - - - 0. 0. 0. - 25 25 - 200 200 - - true - 255 211 0 - - - - 0. 0. 0. - 25 25 - 200 200 - 0 0 0 - - - - 100 100 10 - 0. 0. 0. - 20 20 10 - - - diff --git a/tests/regression_tests/plot_overlaps/results_true.dat b/tests/regression_tests/plot_overlaps/results_true.dat index 90ec8924a01..93ee6769fc7 100644 --- a/tests/regression_tests/plot_overlaps/results_true.dat +++ b/tests/regression_tests/plot_overlaps/results_true.dat @@ -1 +1 @@ -566103831cb8273b0578565c39d30e479664e2b1783d877b45b42cf4f3af0b01671b6db423114b09a74bbe1ddf51a7db565ff2118d6d1ee987b52318773b719a \ No newline at end of file +125ce40fbff3e02e7f5f36a92a2e37abce9407154c825b6617242a4685dfc33c63041145b1f3114334338fbb86188331195ddc319ffce58fab2943d8e60f6da3 \ No newline at end of file diff --git a/tests/regression_tests/plot_overlaps/settings.xml b/tests/regression_tests/plot_overlaps/settings.xml deleted file mode 100644 index adf256d2d48..00000000000 --- a/tests/regression_tests/plot_overlaps/settings.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - plot - - - 5 4 3 - -10 -10 -10 - 10 10 10 - - 1 - - diff --git a/tests/regression_tests/plot_overlaps/test.py b/tests/regression_tests/plot_overlaps/test.py index 62236081b39..0828c6e2551 100644 --- a/tests/regression_tests/plot_overlaps/test.py +++ b/tests/regression_tests/plot_overlaps/test.py @@ -1,61 +1,8 @@ -import glob -import hashlib -import os - -import h5py -import openmc - -from tests.testing_harness import TestHarness +from tests.testing_harness import PlotTestHarness from tests.regression_tests import config -class PlotTestHarness(TestHarness): - """Specialized TestHarness for running OpenMC plotting tests.""" - def __init__(self, plot_names): - super().__init__(None) - self._plot_names = plot_names - - def _run_openmc(self): - openmc.plot_geometry(openmc_exec=config['exe']) - - def _test_output_created(self): - """Make sure *.ppm has been created.""" - for fname in self._plot_names: - assert os.path.exists(fname), 'Plot output file does not exist.' - - def _cleanup(self): - super()._cleanup() - for fname in self._plot_names: - if os.path.exists(fname): - os.remove(fname) - - def _get_results(self): - """Return a string hash of the plot files.""" - outstr = bytes() - - for fname in self._plot_names: - if fname.endswith('.ppm'): - # Add PPM output to results - with open(fname, 'rb') as fh: - outstr += fh.read() - elif fname.endswith('.h5'): - # Add voxel data to results - with h5py.File(fname, 'r') as fh: - outstr += fh.attrs['filetype'] - outstr += fh.attrs['num_voxels'].tobytes() - outstr += fh.attrs['lower_left'].tobytes() - outstr += fh.attrs['voxel_width'].tobytes() - outstr += fh['data'][()].tobytes() - - # Hash the information and return. - sha512 = hashlib.sha512() - sha512.update(outstr) - outstr = sha512.hexdigest() - - return outstr - - def test_plot_overlap(): - harness = PlotTestHarness(('plot_1.ppm', 'plot_2.ppm', 'plot_3.ppm', + harness = PlotTestHarness(('plot_1.png', 'plot_2.png', 'plot_3.png', 'plot_4.h5')) harness.main() diff --git a/tests/regression_tests/plot_projections/__init__.py b/tests/regression_tests/plot_projections/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/plot_projections/geometry.xml b/tests/regression_tests/plot_projections/geometry.xml new file mode 100644 index 00000000000..a648dfe92fc --- /dev/null +++ b/tests/regression_tests/plot_projections/geometry.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/tests/regression_tests/plot/materials.xml b/tests/regression_tests/plot_projections/materials.xml similarity index 80% rename from tests/regression_tests/plot/materials.xml rename to tests/regression_tests/plot_projections/materials.xml index 90b3542675e..35f0de31288 100644 --- a/tests/regression_tests/plot/materials.xml +++ b/tests/regression_tests/plot_projections/materials.xml @@ -8,12 +8,12 @@ - + - + diff --git a/tests/regression_tests/plot_projections/plots.xml b/tests/regression_tests/plot_projections/plots.xml new file mode 100644 index 00000000000..85689da1475 --- /dev/null +++ b/tests/regression_tests/plot_projections/plots.xml @@ -0,0 +1,55 @@ + + + + + 0. 0. 0. + 20. 20. 20. + 200 200 + + + + 70 + + + + 0. 0. 0. + 10. 10. 0. + 25 25 + 200 200 + + 90 + 4 + example1 + + + + 0. 0. 0. + 20. 20. 20. + 200 200 + 240 240 240 + example2.png + 2 + + + + 0. 0. 0. + 0. 10.0 20. + 200 200 + 110 240 240 + example3.png + + + + 0. 0. 0. + 10. 10. 10. + 25 25 + 200 200 + 25.0 + 2 + orthographic_example1 + + + + + + diff --git a/tests/regression_tests/plot_projections/results_true.dat b/tests/regression_tests/plot_projections/results_true.dat new file mode 100644 index 00000000000..1a67da3002a --- /dev/null +++ b/tests/regression_tests/plot_projections/results_true.dat @@ -0,0 +1 @@ +24fb0f41ee018ea086962dbd6bcd0b536d11d4b34644bfef4f0e74f8b462fe41a84af39c7ff79046d5d7cfe209084eac54712fa0ec01038e97eb43df1abd0334 \ No newline at end of file diff --git a/tests/regression_tests/plot/settings.xml b/tests/regression_tests/plot_projections/settings.xml similarity index 100% rename from tests/regression_tests/plot/settings.xml rename to tests/regression_tests/plot_projections/settings.xml diff --git a/tests/regression_tests/plot/tallies.xml b/tests/regression_tests/plot_projections/tallies.xml similarity index 100% rename from tests/regression_tests/plot/tallies.xml rename to tests/regression_tests/plot_projections/tallies.xml diff --git a/tests/regression_tests/plot_projections/test.py b/tests/regression_tests/plot_projections/test.py new file mode 100644 index 00000000000..cf18503f4b8 --- /dev/null +++ b/tests/regression_tests/plot_projections/test.py @@ -0,0 +1,6 @@ +from tests.testing_harness import PlotTestHarness +from tests.regression_tests import config + +def test_plot(): + harness = PlotTestHarness(('plot_1.png', 'example1.png', 'example2.png', 'example3.png', 'orthographic_example1.png')) + harness.main() diff --git a/tests/regression_tests/plot_voxel/geometry.xml b/tests/regression_tests/plot_voxel/geometry.xml deleted file mode 100644 index 83619d9f786..00000000000 --- a/tests/regression_tests/plot_voxel/geometry.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/tests/regression_tests/plot_voxel/materials.xml b/tests/regression_tests/plot_voxel/materials.xml deleted file mode 100644 index 90b3542675e..00000000000 --- a/tests/regression_tests/plot_voxel/materials.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/tests/regression_tests/plot_voxel/model.xml b/tests/regression_tests/plot_voxel/model.xml new file mode 100644 index 00000000000..7b0e854c570 --- /dev/null +++ b/tests/regression_tests/plot_voxel/model.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + plot + 1 + + 5 4 3 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + + + 0.0 0.0 0.0 + 20.0 20.0 10.0 + 50 50 10 + + + diff --git a/tests/regression_tests/plot_voxel/plots.xml b/tests/regression_tests/plot_voxel/plots.xml deleted file mode 100644 index 833329b4273..00000000000 --- a/tests/regression_tests/plot_voxel/plots.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - 50 50 10 - 0. 0. 0. - 20 20 10 - - - diff --git a/tests/regression_tests/plot_voxel/settings.xml b/tests/regression_tests/plot_voxel/settings.xml deleted file mode 100644 index adf256d2d48..00000000000 --- a/tests/regression_tests/plot_voxel/settings.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - plot - - - 5 4 3 - -10 -10 -10 - 10 10 10 - - 1 - - diff --git a/tests/regression_tests/plot_voxel/test.py b/tests/regression_tests/plot_voxel/test.py index 3b7a6bef28c..e034decf79e 100644 --- a/tests/regression_tests/plot_voxel/test.py +++ b/tests/regression_tests/plot_voxel/test.py @@ -1,62 +1,11 @@ -import glob -import hashlib -import os -from subprocess import check_call - -import h5py -import openmc import pytest -from tests.testing_harness import TestHarness +from tests.testing_harness import PlotTestHarness from tests.regression_tests import config vtk = pytest.importorskip('vtk') -class PlotVoxelTestHarness(TestHarness): - """Specialized TestHarness for running OpenMC voxel plot tests.""" - def __init__(self, plot_names): - super().__init__(None) - self._plot_names = plot_names - - def _run_openmc(self): - openmc.plot_geometry(openmc_exec=config['exe']) - - check_call(['../../../scripts/openmc-voxel-to-vtk'] + - glob.glob('plot_4.h5')) - - def _test_output_created(self): - """Make sure *.ppm has been created.""" - for fname in self._plot_names: - assert os.path.exists(fname), 'Plot output file does not exist.' - - def _cleanup(self): - super()._cleanup() - for fname in self._plot_names: - if os.path.exists(fname): - os.remove(fname) - - def _get_results(self): - """Return a string hash of the plot files.""" - outstr = bytes() - - for fname in self._plot_names: - if fname.endswith('.h5'): - # Add voxel data to results - with h5py.File(fname, 'r') as fh: - outstr += fh.attrs['filetype'] - outstr += fh.attrs['num_voxels'].tobytes() - outstr += fh.attrs['lower_left'].tobytes() - outstr += fh.attrs['voxel_width'].tobytes() - outstr += fh['data'][()].tobytes() - - # Hash the information and return. - sha512 = hashlib.sha512() - sha512.update(outstr) - outstr = sha512.hexdigest() - - return outstr - def test_plot_voxel(): - harness = PlotVoxelTestHarness(('plot_4.h5', 'plot.vti')) + harness = PlotTestHarness(('plot_4.h5', 'plot.vti'), voxel_convert_checks=['plot_4.h5']) harness.main() diff --git a/tests/regression_tests/ptables_off/results_true.dat b/tests/regression_tests/ptables_off/results_true.dat index 7c1d187bb6d..1652088ce87 100644 --- a/tests/regression_tests/ptables_off/results_true.dat +++ b/tests/regression_tests/ptables_off/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.042885E-01 1.073889E-02 +2.978318E-01 1.560055E-03 diff --git a/tests/regression_tests/pulse_height/__init__.py b/tests/regression_tests/pulse_height/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/pulse_height/inputs_true.dat b/tests/regression_tests/pulse_height/inputs_true.dat new file mode 100644 index 00000000000..544ddb09788 --- /dev/null +++ b/tests/regression_tests/pulse_height/inputs_true.dat @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + fixed source + 100 + 5 + + + 0.0 0.0 0.0 + + + 1000000.0 1.0 + + + true + + + + 1 + + + 0.0 10000.0 20000.0 30000.0 40000.0 50000.0 60000.0 70000.0 80000.0 90000.0 100000.0 110000.0 120000.0 130000.0 140000.0 150000.0 160000.0 170000.0 180000.0 190000.0 200000.0 210000.0 220000.0 230000.0 240000.0 250000.0 260000.0 270000.0 280000.0 290000.0 300000.0 310000.0 320000.0 330000.0 340000.0 350000.0 360000.0 370000.0 380000.0 390000.0 400000.0 410000.0 420000.0 430000.0 440000.0 450000.0 460000.0 470000.0 480000.0 490000.0 500000.0 510000.0 520000.0 530000.0 540000.0 550000.0 560000.0 570000.0 580000.0 590000.0 600000.0 610000.0 620000.0 630000.0 640000.0 650000.0 660000.0 670000.0 680000.0 690000.0 700000.0 710000.0 720000.0 730000.0 740000.0 750000.0 760000.0 770000.0 780000.0 790000.0 800000.0 810000.0 820000.0 830000.0 840000.0 850000.0 860000.0 870000.0 880000.0 890000.0 900000.0 910000.0 920000.0 930000.0 940000.0 950000.0 960000.0 970000.0 980000.0 990000.0 1000000.0 + + + 1 2 + pulse-height + + + diff --git a/tests/regression_tests/pulse_height/results_true.dat b/tests/regression_tests/pulse_height/results_true.dat new file mode 100644 index 00000000000..c57e8ff1c83 --- /dev/null +++ b/tests/regression_tests/pulse_height/results_true.dat @@ -0,0 +1,201 @@ +tally 1: +4.140000E+00 +3.443000E+00 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +3.000000E-02 +5.000000E-04 +2.000000E-02 +4.000000E-04 +2.000000E-02 +4.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.000000E-02 +3.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.000000E-02 +6.000000E-04 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +2.000000E-02 +2.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +2.000000E-02 +4.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.000000E-02 +2.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +3.000000E-02 +5.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.000000E-02 +2.000000E-04 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +2.000000E-02 +2.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +2.000000E-02 +2.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +3.000000E-02 +5.000000E-04 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +1.000000E-02 +1.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.000000E-02 +2.000000E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.000000E-01 +8.600000E-03 diff --git a/tests/regression_tests/pulse_height/test.py b/tests/regression_tests/pulse_height/test.py new file mode 100644 index 00000000000..90d960f6640 --- /dev/null +++ b/tests/regression_tests/pulse_height/test.py @@ -0,0 +1,53 @@ +import numpy as np +import openmc +import pytest + +from tests.testing_harness import PyAPITestHarness + + +@pytest.fixture +def sphere_model(): + + model = openmc.model.Model() + + # Define materials + NaI = openmc.Material() + NaI.set_density('g/cc', 3.7) + NaI.add_element('Na', 1.0) + NaI.add_element('I', 1.0) + + model.materials = openmc.Materials([NaI]) + + # Define geometry: two spheres in each other + s1 = openmc.Sphere(r=1) + s2 = openmc.Sphere(r=2, boundary_type='vacuum') + inner_sphere = openmc.Cell(name='inner sphere', fill=NaI, region=-s1) + outer_sphere = openmc.Cell(name='outer sphere', region=+s1 & -s2) + model.geometry = openmc.Geometry([inner_sphere, outer_sphere]) + + # Define settings + model.settings.run_mode = 'fixed source' + model.settings.batches = 5 + model.settings.particles = 100 + model.settings.photon_transport = True + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Point(), + energy=openmc.stats.Discrete([1e6], [1]), + particle='photon' + ) + + # Define tallies + tally = openmc.Tally(name="pht tally") + tally.scores = ['pulse-height'] + cell_filter = openmc.CellFilter(inner_sphere) + energy_filter = openmc.EnergyFilter(np.linspace(0, 1_000_000, 101)) + tally.filters = [cell_filter, energy_filter] + model.tallies = [tally] + + return model + + + +def test_pulse_height(sphere_model): + harness = PyAPITestHarness('statepoint.5.h5', sphere_model) + harness.main() diff --git a/tests/regression_tests/quadric_surfaces/results_true.dat b/tests/regression_tests/quadric_surfaces/results_true.dat index 8dc59df0294..382c4241e08 100644 --- a/tests/regression_tests/quadric_surfaces/results_true.dat +++ b/tests/regression_tests/quadric_surfaces/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.213534E+00 1.386061E-02 +1.193830E+00 1.824184E-02 diff --git a/tests/regression_tests/random_ray_basic/__init__.py b/tests/regression_tests/random_ray_basic/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/random_ray_basic/inputs_true.dat b/tests/regression_tests/random_ray_basic/inputs_true.dat new file mode 100644 index 00000000000..97b7906f7b2 --- /dev/null +++ b/tests/regression_tests/random_ray_basic/inputs_true.dat @@ -0,0 +1,108 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.126 0.126 + 10 10 + -0.63 -0.63 + +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 + + + 1.26 1.26 + 2 2 + -1.26 -1.26 + +2 2 +2 5 + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + multi-group + + 100.0 + 20.0 + + + -1.26 -1.26 -1 1.26 1.26 1 + + + + + + + 2 2 + -1.26 -1.26 + 1.26 1.26 + + + 1 + + + 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 + + + 1 2 + flux fission nu-fission + analog + + + diff --git a/tests/regression_tests/random_ray_basic/results_true.dat b/tests/regression_tests/random_ray_basic/results_true.dat new file mode 100644 index 00000000000..802e78a828b --- /dev/null +++ b/tests/regression_tests/random_ray_basic/results_true.dat @@ -0,0 +1,171 @@ +k-combined: +8.400322E-01 8.023349E-03 +tally 1: +1.260220E+00 +3.179889E-01 +1.484289E-01 +4.411066E-03 +3.612463E-01 +2.612843E-02 +7.086707E-01 +1.006119E-01 +3.342483E-02 +2.238499E-04 +8.134936E-02 +1.325949E-03 +4.194328E-01 +3.558669E-02 +4.287776E-03 +3.717447E-06 +1.043559E-02 +2.201986E-05 +5.878720E-01 +7.045887E-02 +6.147757E-03 +7.701173E-06 +1.496241E-02 +4.561699E-05 +1.768113E+00 +6.356917E-01 +6.513486E-03 +8.628535E-06 +1.585272E-02 +5.111136E-05 +5.063704E+00 +5.152401E+00 +2.440293E-03 +1.196869E-06 +6.038334E-03 +7.328193E-06 +3.253717E+00 +2.117655E+00 +1.389120E-02 +3.859385E-05 +3.863767E-02 +2.985798E-04 +1.876994E+00 +7.046366E-01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +8.390875E-01 +1.408791E-01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.513839E-01 +4.139640E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +6.682186E-01 +9.116003E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.849034E+00 +6.944337E-01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.523425E+00 +4.112118E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.821432E+00 +1.592568E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.159618E+00 +2.694138E-01 +1.354028E-01 +3.672094E-03 +3.295432E-01 +2.175122E-02 +6.880334E-01 +9.491215E-02 +3.234611E-02 +2.097782E-04 +7.872396E-02 +1.242596E-03 +4.184841E-01 +3.536436E-02 +4.274305E-03 +3.687209E-06 +1.040280E-02 +2.184074E-05 +5.810180E-01 +6.872944E-02 +6.060273E-03 +7.476500E-06 +1.474949E-02 +4.428617E-05 +1.782580E+00 +6.457892E-01 +6.552384E-03 +8.730345E-06 +1.594739E-02 +5.171444E-05 +5.278155E+00 +5.596601E+00 +2.546878E-03 +1.303010E-06 +6.302072E-03 +7.978072E-06 +3.420419E+00 +2.340454E+00 +1.465798E-02 +4.299061E-05 +4.077042E-02 +3.325951E-04 +1.279417E+00 +3.278133E-01 +1.509073E-01 +4.561836E-03 +3.672782E-01 +2.702150E-02 +7.212777E-01 +1.042487E-01 +3.411552E-02 +2.332877E-04 +8.303035E-02 +1.381852E-03 +4.269473E-01 +3.685202E-02 +4.378540E-03 +3.872997E-06 +1.065649E-02 +2.294124E-05 +5.973530E-01 +7.266946E-02 +6.260881E-03 +7.976490E-06 +1.523773E-02 +4.724780E-05 +1.795373E+00 +6.547440E-01 +6.635941E-03 +8.945067E-06 +1.615075E-02 +5.298634E-05 +5.161876E+00 +5.353441E+00 +2.505311E-03 +1.261399E-06 +6.199218E-03 +7.723296E-06 +3.344042E+00 +2.236603E+00 +1.443089E-02 +4.166228E-05 +4.013879E-02 +3.223186E-04 diff --git a/tests/regression_tests/random_ray_basic/test.py b/tests/regression_tests/random_ray_basic/test.py new file mode 100644 index 00000000000..1727a63716c --- /dev/null +++ b/tests/regression_tests/random_ray_basic/test.py @@ -0,0 +1,232 @@ +import os + +import numpy as np +import openmc + +from tests.testing_harness import TolerantPyAPITestHarness + + +class MGXSTestHarness(TolerantPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +def random_ray_model() -> openmc.Model: + ############################################################################### + # Create multigroup data + + # Instantiate the energy group data + group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] + groups = openmc.mgxs.EnergyGroups(group_edges) + + # Instantiate the 7-group (C5G7) cross section data + uo2_xsdata = openmc.XSdata('UO2', groups) + uo2_xsdata.order = 0 + uo2_xsdata.set_total( + [0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, + 0.5644058]) + uo2_xsdata.set_absorption([8.0248e-03, 3.7174e-03, 2.6769e-02, 9.6236e-02, + 3.0020e-02, 1.1126e-01, 2.8278e-01]) + scatter_matrix = np.array( + [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]) + scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) + uo2_xsdata.set_scatter_matrix(scatter_matrix) + uo2_xsdata.set_fission([7.21206e-03, 8.19301e-04, 6.45320e-03, + 1.85648e-02, 1.78084e-02, 8.30348e-02, + 2.16004e-01]) + uo2_xsdata.set_nu_fission([2.005998e-02, 2.027303e-03, 1.570599e-02, + 4.518301e-02, 4.334208e-02, 2.020901e-01, + 5.257105e-01]) + uo2_xsdata.set_chi([5.8791e-01, 4.1176e-01, 3.3906e-04, 1.1761e-07, 0.0000e+00, + 0.0000e+00, 0.0000e+00]) + + h2o_xsdata = openmc.XSdata('LWTR', groups) + h2o_xsdata.order = 0 + h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435, + 0.718, 1.2544497, 2.650379]) + h2o_xsdata.set_absorption([6.0105e-04, 1.5793e-05, 3.3716e-04, + 1.9406e-03, 5.7416e-03, 1.5001e-02, + 3.7239e-02]) + scatter_matrix = np.array( + [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000], + [0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010], + [0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034], + [0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390], + [0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]) + scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) + h2o_xsdata.set_scatter_matrix(scatter_matrix) + + mg_cross_sections = openmc.MGXSLibrary(groups) + mg_cross_sections.add_xsdatas([uo2_xsdata, h2o_xsdata]) + mg_cross_sections.export_to_hdf5() + + ############################################################################### + # Create materials for the problem + + # Instantiate some Materials and register the appropriate macroscopic data + uo2 = openmc.Material(name='UO2 fuel') + uo2.set_density('macro', 1.0) + uo2.add_macroscopic('UO2') + + water = openmc.Material(name='Water') + water.set_density('macro', 1.0) + water.add_macroscopic('LWTR') + + # Instantiate a Materials collection and export to XML + materials = openmc.Materials([uo2, water]) + materials.cross_sections = "mgxs.h5" + + ############################################################################### + # Define problem geometry + + ######################################## + # Define an unbounded pincell universe + + pitch = 1.26 + + # Create a surface for the fuel outer radius + fuel_or = openmc.ZCylinder(r=0.54, name='Fuel OR') + inner_ring_a = openmc.ZCylinder(r=0.33, name='inner ring a') + inner_ring_b = openmc.ZCylinder(r=0.45, name='inner ring b') + outer_ring_a = openmc.ZCylinder(r=0.60, name='outer ring a') + outer_ring_b = openmc.ZCylinder(r=0.69, name='outer ring b') + + # Instantiate Cells + fuel_a = openmc.Cell(fill=uo2, region=-inner_ring_a, name='fuel inner a') + fuel_b = openmc.Cell(fill=uo2, region=+inner_ring_a & -inner_ring_b, name='fuel inner b') + fuel_c = openmc.Cell(fill=uo2, region=+inner_ring_b & -fuel_or, name='fuel inner c') + moderator_a = openmc.Cell(fill=water, region=+fuel_or & -outer_ring_a, name='moderator inner a') + moderator_b = openmc.Cell(fill=water, region=+outer_ring_a & -outer_ring_b, name='moderator outer b') + moderator_c = openmc.Cell(fill=water, region=+outer_ring_b, name='moderator outer c') + + # Create pincell universe + pincell_base = openmc.Universe() + + # Register Cells with Universe + pincell_base.add_cells([fuel_a, fuel_b, fuel_c, moderator_a, moderator_b, moderator_c]) + + # Create planes for azimuthal sectors + azimuthal_planes = [] + for i in range(8): + angle = 2 * i * openmc.pi / 8 + normal_vector = (-openmc.sin(angle), openmc.cos(angle), 0) + azimuthal_planes.append(openmc.Plane(a=normal_vector[0], b=normal_vector[1], c=normal_vector[2], d=0)) + + # Create a cell for each azimuthal sector + azimuthal_cells = [] + for i in range(8): + azimuthal_cell = openmc.Cell(name=f'azimuthal_cell_{i}') + azimuthal_cell.fill = pincell_base + azimuthal_cell.region = +azimuthal_planes[i] & -azimuthal_planes[(i+1) % 8] + azimuthal_cells.append(azimuthal_cell) + + # Create a geometry with the azimuthal universes + pincell = openmc.Universe(cells=azimuthal_cells) + + ######################################## + # Define a moderator lattice universe + + moderator_infinite = openmc.Cell(fill=water, name='moderator infinite') + mu = openmc.Universe() + mu.add_cells([moderator_infinite]) + + lattice = openmc.RectLattice() + lattice.lower_left = [-pitch/2.0, -pitch/2.0] + lattice.pitch = [pitch/10.0, pitch/10.0] + lattice.universes = np.full((10, 10), mu) + + mod_lattice_cell = openmc.Cell(fill=lattice) + + mod_lattice_uni = openmc.Universe() + + mod_lattice_uni.add_cells([mod_lattice_cell]) + + ######################################## + # Define 2x2 outer lattice + lattice2x2 = openmc.RectLattice() + lattice2x2.lower_left = (-pitch, -pitch) + lattice2x2.pitch = (pitch, pitch) + lattice2x2.universes = [ + [pincell, pincell], + [pincell, mod_lattice_uni] + ] + + ######################################## + # Define cell containing lattice and other stuff + box = openmc.model.RectangularPrism(pitch*2, pitch*2, boundary_type='reflective') + + assembly = openmc.Cell(fill=lattice2x2, region=-box, name='assembly') + + # Create a geometry with the top-level cell + geometry = openmc.Geometry([assembly]) + + ############################################################################### + # Define problem settings + + # Instantiate a Settings object, set all runtime parameters, and export to XML + settings = openmc.Settings() + settings.energy_mode = "multi-group" + settings.batches = 10 + settings.inactive = 5 + settings.particles = 100 + + # Create an initial uniform spatial source distribution over fissionable zones + lower_left = (-pitch, -pitch, -1) + upper_right = (pitch, pitch, 1) + uniform_dist = openmc.stats.Box(lower_left, upper_right) + rr_source = openmc.IndependentSource(space=uniform_dist) + + settings.random_ray['distance_active'] = 100.0 + settings.random_ray['distance_inactive'] = 20.0 + settings.random_ray['ray_source'] = rr_source + + ############################################################################### + # Define tallies + + # Create a mesh that will be used for tallying + mesh = openmc.RegularMesh() + mesh.dimension = (2, 2) + mesh.lower_left = (-pitch, -pitch) + mesh.upper_right = (pitch, pitch) + + # Create a mesh filter that can be used in a tally + mesh_filter = openmc.MeshFilter(mesh) + + # Create an energy group filter as well + energy_filter = openmc.EnergyFilter(group_edges) + + # Now use the mesh filter in a tally and indicate what scores are desired + tally = openmc.Tally(name="Mesh tally") + tally.filters = [mesh_filter, energy_filter] + tally.scores = ['flux', 'fission', 'nu-fission'] + tally.estimator = 'analog' + + # Instantiate a Tallies collection and export to XML + tallies = openmc.Tallies([tally]) + + ############################################################################### + # Exporting to OpenMC model + ############################################################################### + + model = openmc.Model() + model.geometry = geometry + model.materials = materials + model.settings = settings + model.tallies = tallies + return model + + +def test_random_ray_basic(): + harness = MGXSTestHarness('statepoint.10.h5', random_ray_model()) + harness.main() diff --git a/tests/regression_tests/random_ray_vacuum/__init__.py b/tests/regression_tests/random_ray_vacuum/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/random_ray_vacuum/inputs_true.dat b/tests/regression_tests/random_ray_vacuum/inputs_true.dat new file mode 100644 index 00000000000..4ef10942005 --- /dev/null +++ b/tests/regression_tests/random_ray_vacuum/inputs_true.dat @@ -0,0 +1,108 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.126 0.126 + 10 10 + -0.63 -0.63 + +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 + + + 1.26 1.26 + 2 2 + -1.26 -1.26 + +2 2 +2 5 + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + multi-group + + 100.0 + 20.0 + + + -1.26 -1.26 -1 1.26 1.26 1 + + + + + + + 2 2 + -1.26 -1.26 + 1.26 1.26 + + + 1 + + + 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 + + + 1 2 + flux fission nu-fission + analog + + + diff --git a/tests/regression_tests/random_ray_vacuum/results_true.dat b/tests/regression_tests/random_ray_vacuum/results_true.dat new file mode 100644 index 00000000000..744ce6cef28 --- /dev/null +++ b/tests/regression_tests/random_ray_vacuum/results_true.dat @@ -0,0 +1,171 @@ +k-combined: +1.010455E-01 1.585558E-02 +tally 1: +1.849176E-01 +7.634332E-03 +2.181815E-02 +1.062861E-04 +5.310100E-02 +6.295730E-04 +4.048251E-02 +3.851890E-04 +1.893676E-03 +8.448769E-07 +4.608828E-03 +5.004529E-06 +4.063643E-03 +4.022442E-06 +4.112970E-05 +4.186661E-10 +1.001015E-04 +2.479919E-09 +7.467029E-03 +1.178864E-05 +7.688748E-05 +1.266903E-09 +1.871288E-04 +7.504350E-09 +3.870644E-02 +3.010745E-04 +1.375240E-04 +3.807356E-09 +3.347099E-04 +2.255298E-08 +4.524967E-01 +4.098857E-02 +2.437418E-04 +1.190325E-08 +6.031220E-04 +7.288126E-08 +4.989226E-01 +4.993728E-02 +2.374296E-03 +1.135824E-06 +6.603983E-03 +8.787258E-06 +3.899991E-01 +3.308783E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +7.108982E-02 +1.144390E-03 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.295259E-03 +6.352159E-06 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.852001E-03 +1.984406E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.414391E-02 +3.905201E-04 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.571668E-01 +1.323140E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.752932E-01 +1.517930E-02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.465446E-01 +4.901884E-03 +1.700791E-02 +6.587674E-05 +4.139385E-02 +3.902131E-04 +3.424032E-02 +2.841338E-04 +1.598985E-03 +6.216312E-07 +3.891610E-03 +3.682159E-06 +4.067582E-03 +4.209468E-06 +4.152829E-05 +4.494649E-10 +1.010715E-04 +2.662352E-09 +7.526712E-03 +1.225032E-05 +7.769969E-05 +1.328443E-09 +1.891055E-04 +7.868877E-09 +4.008649E-02 +3.246821E-04 +1.417944E-04 +4.070719E-09 +3.451035E-04 +2.411301E-08 +4.859902E-01 +4.747592E-02 +2.606214E-04 +1.369749E-08 +6.448895E-04 +8.386705E-08 +5.475198E-01 +6.061269E-02 +2.625477E-03 +1.405458E-06 +7.302631E-03 +1.087327E-05 +1.909660E-01 +8.147906E-03 +2.269063E-02 +1.149570E-04 +5.522446E-02 +6.809342E-04 +4.196583E-02 +4.141620E-04 +1.980406E-03 +9.227119E-07 +4.819913E-03 +5.465576E-06 +4.247004E-03 +4.420116E-06 +4.341806E-05 +4.691518E-10 +1.056709E-04 +2.778965E-09 +7.742814E-03 +1.272112E-05 +8.039606E-05 +1.389209E-09 +1.956679E-04 +8.228817E-09 +3.982370E-02 +3.190931E-04 +1.427171E-04 +4.103942E-09 +3.473492E-04 +2.430981E-08 +4.849535E-01 +4.707014E-02 +2.678327E-04 +1.438540E-08 +6.627333E-04 +8.807897E-08 +5.493457E-01 +6.069440E-02 +2.717400E-03 +1.501450E-06 +7.558312E-03 +1.161591E-05 diff --git a/tests/regression_tests/random_ray_vacuum/test.py b/tests/regression_tests/random_ray_vacuum/test.py new file mode 100644 index 00000000000..e9ca2252144 --- /dev/null +++ b/tests/regression_tests/random_ray_vacuum/test.py @@ -0,0 +1,235 @@ +import os + +import numpy as np +import openmc + +from tests.testing_harness import TolerantPyAPITestHarness + + +class MGXSTestHarness(TolerantPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +def random_ray_model() -> openmc.Model: + ############################################################################### + # Create multigroup data + + # Instantiate the energy group data + group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] + groups = openmc.mgxs.EnergyGroups(group_edges) + + # Instantiate the 7-group (C5G7) cross section data + uo2_xsdata = openmc.XSdata('UO2', groups) + uo2_xsdata.order = 0 + uo2_xsdata.set_total( + [0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, + 0.5644058]) + uo2_xsdata.set_absorption([8.0248e-03, 3.7174e-03, 2.6769e-02, 9.6236e-02, + 3.0020e-02, 1.1126e-01, 2.8278e-01]) + scatter_matrix = np.array( + [[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]]) + scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) + uo2_xsdata.set_scatter_matrix(scatter_matrix) + uo2_xsdata.set_fission([7.21206e-03, 8.19301e-04, 6.45320e-03, + 1.85648e-02, 1.78084e-02, 8.30348e-02, + 2.16004e-01]) + uo2_xsdata.set_nu_fission([2.005998e-02, 2.027303e-03, 1.570599e-02, + 4.518301e-02, 4.334208e-02, 2.020901e-01, + 5.257105e-01]) + uo2_xsdata.set_chi([5.8791e-01, 4.1176e-01, 3.3906e-04, 1.1761e-07, 0.0000e+00, + 0.0000e+00, 0.0000e+00]) + + h2o_xsdata = openmc.XSdata('LWTR', groups) + h2o_xsdata.order = 0 + h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435, + 0.718, 1.2544497, 2.650379]) + h2o_xsdata.set_absorption([6.0105e-04, 1.5793e-05, 3.3716e-04, + 1.9406e-03, 5.7416e-03, 1.5001e-02, + 3.7239e-02]) + scatter_matrix = np.array( + [[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000], + [0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010], + [0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034], + [0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390], + [0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200], + [0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]]) + scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) + h2o_xsdata.set_scatter_matrix(scatter_matrix) + + mg_cross_sections = openmc.MGXSLibrary(groups) + mg_cross_sections.add_xsdatas([uo2_xsdata, h2o_xsdata]) + mg_cross_sections.export_to_hdf5() + + ############################################################################### + # Create materials for the problem + + # Instantiate some Materials and register the appropriate Macroscopic objects + uo2 = openmc.Material(name='UO2 fuel') + uo2.set_density('macro', 1.0) + uo2.add_macroscopic('UO2') + + water = openmc.Material(name='Water') + water.set_density('macro', 1.0) + water.add_macroscopic('LWTR') + + # Instantiate a Materials collection and export to XML + materials = openmc.Materials([uo2, water]) + materials.cross_sections = "mgxs.h5" + + ############################################################################### + # Define problem geometry + + ######################################## + # Define an unbounded pincell universe + + pitch = 1.26 + + # Create a surface for the fuel outer radius + fuel_or = openmc.ZCylinder(r=0.54, name='Fuel OR') + inner_ring_a = openmc.ZCylinder(r=0.33, name='inner ring a') + inner_ring_b = openmc.ZCylinder(r=0.45, name='inner ring b') + outer_ring_a = openmc.ZCylinder(r=0.60, name='outer ring a') + outer_ring_b = openmc.ZCylinder(r=0.69, name='outer ring b') + + # Instantiate Cells + fuel_a = openmc.Cell(fill=uo2, region=-inner_ring_a, name='fuel inner a') + fuel_b = openmc.Cell(fill=uo2, region=+inner_ring_a & -inner_ring_b, name='fuel inner b') + fuel_c = openmc.Cell(fill=uo2, region=+inner_ring_b & -fuel_or, name='fuel inner c') + moderator_a = openmc.Cell(fill=water, region=+fuel_or & -outer_ring_a, name='moderator inner a') + moderator_b = openmc.Cell(fill=water, region=+outer_ring_a & -outer_ring_b, name='moderator outer b') + moderator_c = openmc.Cell(fill=water, region=+outer_ring_b, name='moderator outer c') + + # Create pincell universe + pincell_base = openmc.Universe() + + # Register Cells with Universe + pincell_base.add_cells([fuel_a, fuel_b, fuel_c, moderator_a, moderator_b, moderator_c]) + + # Create planes for azimuthal sectors + azimuthal_planes = [] + for i in range(8): + angle = 2 * i * openmc.pi / 8 + normal_vector = (-openmc.sin(angle), openmc.cos(angle), 0) + azimuthal_planes.append(openmc.Plane(a=normal_vector[0], b=normal_vector[1], c=normal_vector[2], d=0)) + + # Create a cell for each azimuthal sector + azimuthal_cells = [] + for i in range(8): + azimuthal_cell = openmc.Cell(name=f'azimuthal_cell_{i}') + azimuthal_cell.fill = pincell_base + azimuthal_cell.region = +azimuthal_planes[i] & -azimuthal_planes[(i+1) % 8] + azimuthal_cells.append(azimuthal_cell) + + # Create a geometry with the azimuthal universes + pincell = openmc.Universe(cells=azimuthal_cells) + + ######################################## + # Define a moderator lattice universe + + moderator_infinite = openmc.Cell(fill=water, name='moderator infinite') + mu = openmc.Universe() + mu.add_cells([moderator_infinite]) + + lattice = openmc.RectLattice() + lattice.lower_left = [-pitch/2.0, -pitch/2.0] + lattice.pitch = [pitch/10.0, pitch/10.0] + lattice.universes = np.full((10, 10), mu) + + mod_lattice_cell = openmc.Cell(fill=lattice) + + mod_lattice_uni = openmc.Universe() + + mod_lattice_uni.add_cells([mod_lattice_cell]) + + ######################################## + # Define 2x2 outer lattice + lattice2x2 = openmc.RectLattice() + lattice2x2.lower_left = [-pitch, -pitch] + lattice2x2.pitch = [pitch, pitch] + lattice2x2.universes = [ + [pincell, pincell], + [pincell, mod_lattice_uni] + ] + + ######################################## + # Define cell containing lattice and other stuff + box = openmc.model.RectangularPrism(pitch*2, pitch*2, boundary_type='vacuum') + + assembly = openmc.Cell(fill=lattice2x2, region=-box, name='assembly') + + root = openmc.Universe(name='root universe') + root.add_cell(assembly) + + # Create a geometry with the two cells and export to XML + geometry = openmc.Geometry(root) + + ############################################################################### + # Define problem settings + + # Instantiate a Settings object, set all runtime parameters, and export to XML + settings = openmc.Settings() + settings.energy_mode = "multi-group" + settings.batches = 10 + settings.inactive = 5 + settings.particles = 100 + + # Create an initial uniform spatial source distribution over fissionable zones + lower_left = (-pitch, -pitch, -1) + upper_right = (pitch, pitch, 1) + uniform_dist = openmc.stats.Box(lower_left, upper_right) + rr_source = openmc.IndependentSource(space=uniform_dist) + + settings.random_ray['distance_active'] = 100.0 + settings.random_ray['distance_inactive'] = 20.0 + settings.random_ray['ray_source'] = rr_source + + ############################################################################### + # Define tallies + + # Create a mesh that will be used for tallying + mesh = openmc.RegularMesh() + mesh.dimension = (2, 2) + mesh.lower_left = (-pitch, -pitch) + mesh.upper_right = (pitch, pitch) + + # Create a mesh filter that can be used in a tally + mesh_filter = openmc.MeshFilter(mesh) + + # Create an energy group filter as well + energy_filter = openmc.EnergyFilter(group_edges) + + # Now use the mesh filter in a tally and indicate what scores are desired + tally = openmc.Tally(name="Mesh tally") + tally.filters = [mesh_filter, energy_filter] + tally.scores = ['flux', 'fission', 'nu-fission'] + tally.estimator = 'analog' + + # Instantiate a Tallies collection and export to XML + tallies = openmc.Tallies([tally]) + + ############################################################################### + # Exporting to OpenMC model + ############################################################################### + + model = openmc.Model() + model.geometry = geometry + model.materials = materials + model.settings = settings + model.tallies = tallies + return model + + +def test_random_ray_vacuum(): + harness = MGXSTestHarness('statepoint.10.h5', random_ray_model()) + harness.main() diff --git a/tests/regression_tests/reflective_plane/results_true.dat b/tests/regression_tests/reflective_plane/results_true.dat index a55747acc43..a1acfaad7ed 100644 --- a/tests/regression_tests/reflective_plane/results_true.dat +++ b/tests/regression_tests/reflective_plane/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.275423E+00 4.746681E-03 +2.276857E+00 8.776678E-03 diff --git a/tests/regression_tests/resonance_scattering/inputs_true.dat b/tests/regression_tests/resonance_scattering/inputs_true.dat index 57a5e1a4b9c..dba4535c2b4 100644 --- a/tests/regression_tests/resonance_scattering/inputs_true.dat +++ b/tests/regression_tests/resonance_scattering/inputs_true.dat @@ -1,34 +1,34 @@ - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - -4 -4 -4 4 4 4 - - - - true - rvs - 1.0 - 210.0 - U238 U235 Pu239 - - + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + -4 -4 -4 4 4 4 + + + + true + rvs + 1.0 + 210.0 + U238 U235 Pu239 + + + diff --git a/tests/regression_tests/resonance_scattering/results_true.dat b/tests/regression_tests/resonance_scattering/results_true.dat index 2535885fbfe..8316e720e26 100644 --- a/tests/regression_tests/resonance_scattering/results_true.dat +++ b/tests/regression_tests/resonance_scattering/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.463226E+00 1.142843E-02 +1.462509E+00 2.205413E-02 diff --git a/tests/regression_tests/resonance_scattering/test.py b/tests/regression_tests/resonance_scattering/test.py index e77dd925829..24629b12b72 100644 --- a/tests/regression_tests/resonance_scattering/test.py +++ b/tests/regression_tests/resonance_scattering/test.py @@ -4,7 +4,8 @@ class ResonanceScatteringTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # Materials mat = openmc.Material(material_id=1) mat.set_density('g/cc', 1.0) @@ -13,15 +14,13 @@ def _build_inputs(self): mat.add_nuclide('Pu239', 0.02) mat.add_nuclide('H1', 20.0) - mats_file = openmc.Materials([mat]) - mats_file.export_to_xml() + self._model.materials = openmc.Materials([mat]) # Geometry dumb_surface = openmc.XPlane(100, boundary_type='reflective') c1 = openmc.Cell(cell_id=1, fill=mat, region=-dumb_surface) root_univ = openmc.Universe(universe_id=0, cells=[c1]) - geometry = openmc.Geometry(root_univ) - geometry.export_to_xml() + self._model.geometry = openmc.Geometry(root_univ) # Resonance elastic scattering settings res_scat_settings = { @@ -36,12 +35,13 @@ def _build_inputs(self): settings.batches = 10 settings.inactive = 5 settings.particles = 1000 - settings.source = openmc.source.Source( + settings.source = openmc.IndependentSource( space=openmc.stats.Box([-4, -4, -4], [4, 4, 4])) settings.resonance_scattering = res_scat_settings - settings.export_to_xml() + self._model.settings = settings def test_resonance_scattering(): - harness = ResonanceScatteringTestHarness('statepoint.10.h5') + harness = ResonanceScatteringTestHarness('statepoint.10.h5', + model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/rotation/results_true.dat b/tests/regression_tests/rotation/results_true.dat index f4a3cfcccbd..0fb8ba981fc 100644 --- a/tests/regression_tests/rotation/results_true.dat +++ b/tests/regression_tests/rotation/results_true.dat @@ -1,2 +1,2 @@ k-combined: -4.132181E-01 1.130226E-02 +4.175600E-01 1.117465E-02 diff --git a/tests/regression_tests/salphabeta/inputs_true.dat b/tests/regression_tests/salphabeta/inputs_true.dat index 29d8065cf1c..ef0e843c2f9 100644 --- a/tests/regression_tests/salphabeta/inputs_true.dat +++ b/tests/regression_tests/salphabeta/inputs_true.dat @@ -1,60 +1,60 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 400 - 5 - 0 - - - -4 -4 -4 4 4 4 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 400 + 5 + 0 + + + -4 -4 -4 4 4 4 + + + + diff --git a/tests/regression_tests/salphabeta/results_true.dat b/tests/regression_tests/salphabeta/results_true.dat index ea893abedf7..d5c7f66e909 100644 --- a/tests/regression_tests/salphabeta/results_true.dat +++ b/tests/regression_tests/salphabeta/results_true.dat @@ -1,2 +1,2 @@ k-combined: -8.214162E-01 2.262777E-02 +8.694866E-01 2.033328E-02 diff --git a/tests/regression_tests/salphabeta/test.py b/tests/regression_tests/salphabeta/test.py index fd0486118fa..11bf3bc842a 100644 --- a/tests/regression_tests/salphabeta/test.py +++ b/tests/regression_tests/salphabeta/test.py @@ -67,7 +67,7 @@ def make_model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 400 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-4, -4, -4], [4, 4, 4])) return model diff --git a/tests/regression_tests/score_current/inputs_true.dat b/tests/regression_tests/score_current/inputs_true.dat index 2b81f508f14..9ea8e5e4ae1 100644 --- a/tests/regression_tests/score_current/inputs_true.dat +++ b/tests/regression_tests/score_current/inputs_true.dat @@ -1,55 +1,54 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - - 3 3 3 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - 1 - - - 0.0 0.253 20000000.0 - - - 1 - current - - - 1 2 - current - - + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + 3 3 3 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + 1 + + + 0.0 0.253 20000000.0 + + + 1 + current + + + 1 2 + current + + + diff --git a/tests/regression_tests/score_current/results_true.dat b/tests/regression_tests/score_current/results_true.dat index 6793466954f..ff939301d02 100644 --- a/tests/regression_tests/score_current/results_true.dat +++ b/tests/regression_tests/score_current/results_true.dat @@ -1,58 +1,58 @@ k-combined: -7.952381E-01 3.714273E-02 +2.298294E-01 3.256961E-01 tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.400000E-01 -4.016000E-03 -1.760000E-01 -6.368000E-03 +1.150000E-01 +2.753000E-03 +1.820000E-01 +6.756000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.140000E-01 -2.714000E-03 -1.590000E-01 -5.517000E-03 -1.800000E-01 -6.524000E-03 +1.110000E-01 +2.601000E-03 +1.530000E-01 +4.865000E-03 +1.910000E-01 +7.535000E-03 0.000000E+00 0.000000E+00 -6.700000E-02 -9.270000E-04 -1.570000E-01 -5.131000E-03 -1.760000E-01 -6.368000E-03 -1.400000E-01 -4.016000E-03 -1.570000E-01 -5.019000E-03 -1.210000E-01 -2.997000E-03 +7.100000E-02 +1.079000E-03 +1.500000E-01 +4.606000E-03 +1.820000E-01 +6.756000E-03 +1.150000E-01 +2.753000E-03 +1.610000E-01 +5.383000E-03 +1.230000E-01 +3.141000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.780000E-01 -6.838000E-03 -2.440000E-01 -1.203200E-02 -2.120000E-01 -9.028000E-03 +1.370000E-01 +3.951000E-03 +2.600000E-01 +1.366400E-02 +1.930000E-01 +7.573000E-03 0.000000E+00 0.000000E+00 -8.800000E-02 -1.644000E-03 -2.360000E-01 -1.139000E-02 -1.210000E-01 -2.997000E-03 -1.570000E-01 -5.019000E-03 +8.500000E-02 +1.533000E-03 +2.040000E-01 +8.426000E-03 +1.230000E-01 +3.141000E-03 +1.610000E-01 +5.383000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -61,430 +61,430 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.070000E-01 -2.375000E-03 -1.490000E-01 -4.621000E-03 -1.640000E-01 -5.476000E-03 +1.250000E-01 +3.311000E-03 +1.620000E-01 +5.346000E-03 +1.860000E-01 +6.932000E-03 0.000000E+00 0.000000E+00 -5.800000E-02 -7.240000E-04 -1.290000E-01 -3.357000E-03 +7.100000E-02 +1.083000E-03 +1.630000E-01 +5.617000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.470000E-01 -4.583000E-03 -2.610000E-01 -1.376900E-02 +1.800000E-01 +7.002000E-03 +2.980000E-01 +1.815000E-02 +1.530000E-01 +4.865000E-03 +1.110000E-01 +2.601000E-03 +1.890000E-01 +7.605000E-03 +1.330000E-01 +3.743000E-03 +1.790000E-01 +6.495000E-03 +0.000000E+00 +0.000000E+00 +1.080000E-01 +2.718000E-03 +2.160000E-01 +9.662000E-03 +2.980000E-01 +1.815000E-02 +1.800000E-01 +7.002000E-03 +2.650000E-01 +1.435500E-02 1.590000E-01 -5.517000E-03 -1.140000E-01 -2.714000E-03 -1.630000E-01 -5.645000E-03 -1.090000E-01 -2.419000E-03 -1.820000E-01 -6.750000E-03 +5.285000E-03 +2.600000E-01 +1.366400E-02 +1.370000E-01 +3.951000E-03 +2.670000E-01 +1.469300E-02 +1.940000E-01 +7.678000E-03 +2.390000E-01 +1.155500E-02 +0.000000E+00 +0.000000E+00 +2.410000E-01 +1.255900E-02 +5.510000E-01 +7.358900E-02 +1.590000E-01 +5.285000E-03 +2.650000E-01 +1.435500E-02 0.000000E+00 0.000000E+00 -1.060000E-01 -2.530000E-03 -2.230000E-01 -1.002300E-02 -2.610000E-01 -1.376900E-02 -1.470000E-01 -4.583000E-03 -2.820000E-01 -1.613400E-02 -1.800000E-01 -6.690000E-03 -2.440000E-01 -1.203200E-02 -1.780000E-01 -6.838000E-03 -2.870000E-01 -1.696700E-02 -1.800000E-01 -6.556000E-03 -2.430000E-01 -1.211900E-02 0.000000E+00 0.000000E+00 -2.130000E-01 -9.451000E-03 -5.570000E-01 -7.415500E-02 -1.800000E-01 -6.690000E-03 -2.820000E-01 -1.613400E-02 +1.620000E-01 +5.346000E-03 +1.250000E-01 +3.311000E-03 +1.870000E-01 +7.083000E-03 +1.410000E-01 +3.999000E-03 +2.040000E-01 +8.438000E-03 0.000000E+00 0.000000E+00 +9.300000E-02 +1.829000E-03 +2.240000E-01 +1.015800E-02 0.000000E+00 0.000000E+00 -1.490000E-01 -4.621000E-03 -1.070000E-01 -2.375000E-03 -1.500000E-01 -4.604000E-03 -1.100000E-01 -2.552000E-03 -1.800000E-01 -6.518000E-03 0.000000E+00 0.000000E+00 -1.050000E-01 -2.345000E-03 -2.150000E-01 -9.355000E-03 +1.500000E-01 +4.522000E-03 +1.630000E-01 +5.439000E-03 +1.330000E-01 +3.743000E-03 +1.890000E-01 +7.605000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.340000E-01 -3.818000E-03 -1.690000E-01 -5.911000E-03 -1.090000E-01 -2.419000E-03 -1.630000E-01 -5.645000E-03 +1.650000E-01 +5.615000E-03 0.000000E+00 0.000000E+00 +7.100000E-02 +1.191000E-03 +1.550000E-01 +5.011000E-03 +1.630000E-01 +5.439000E-03 +1.500000E-01 +4.522000E-03 +1.680000E-01 +5.966000E-03 +1.290000E-01 +3.515000E-03 +1.940000E-01 +7.678000E-03 +2.670000E-01 +1.469300E-02 0.000000E+00 0.000000E+00 -1.860000E-01 -6.998000E-03 0.000000E+00 0.000000E+00 -7.200000E-02 -1.090000E-03 -1.720000E-01 -6.062000E-03 -1.690000E-01 -5.911000E-03 -1.340000E-01 -3.818000E-03 -1.600000E-01 -5.454000E-03 -1.060000E-01 -2.328000E-03 -1.800000E-01 -6.556000E-03 -2.870000E-01 -1.696700E-02 +1.810000E-01 +6.765000E-03 0.000000E+00 0.000000E+00 +1.080000E-01 +2.694000E-03 +2.070000E-01 +8.673000E-03 +1.290000E-01 +3.515000E-03 +1.680000E-01 +5.966000E-03 0.000000E+00 0.000000E+00 -2.060000E-01 -8.670000E-03 0.000000E+00 0.000000E+00 -1.100000E-01 -2.558000E-03 -2.340000E-01 -1.113000E-02 -1.060000E-01 -2.328000E-03 -1.600000E-01 -5.454000E-03 +1.410000E-01 +3.999000E-03 +1.870000E-01 +7.083000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.100000E-01 -2.552000E-03 -1.500000E-01 -4.604000E-03 +1.870000E-01 +7.213000E-03 0.000000E+00 0.000000E+00 +8.200000E-02 +1.536000E-03 +1.760000E-01 +6.550000E-03 0.000000E+00 0.000000E+00 -1.730000E-01 -6.077000E-03 0.000000E+00 0.000000E+00 -6.200000E-02 -8.400000E-04 -1.340000E-01 -3.634000E-03 +1.750000E-01 +6.163000E-03 +2.570000E-01 +1.347100E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.600000E-01 -5.202000E-03 -2.170000E-01 -9.735000E-03 +1.560000E-01 +4.914000E-03 +2.350000E-01 +1.135900E-02 +1.500000E-01 +4.606000E-03 +7.100000E-02 +1.079000E-03 +1.530000E-01 +4.837000E-03 +5.600000E-02 +7.260000E-04 +2.570000E-01 +1.347100E-02 +1.750000E-01 +6.163000E-03 +2.460000E-01 +1.235000E-02 +1.420000E-01 +4.326000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.490000E-01 -4.565000E-03 -2.360000E-01 -1.145400E-02 -1.570000E-01 -5.131000E-03 -6.700000E-02 -9.270000E-04 -1.460000E-01 -4.382000E-03 -6.800000E-02 -1.030000E-03 -2.170000E-01 -9.735000E-03 -1.600000E-01 -5.202000E-03 -2.130000E-01 -9.111000E-03 -1.360000E-01 -4.056000E-03 +1.830000E-01 +7.133000E-03 +5.110000E-01 +5.696100E-02 +2.040000E-01 +8.426000E-03 +8.500000E-02 +1.533000E-03 +2.100000E-01 +8.928000E-03 +9.100000E-02 +1.807000E-03 +1.420000E-01 +4.326000E-03 +2.460000E-01 +1.235000E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.070000E-01 -8.827000E-03 -4.970000E-01 -5.443700E-02 -2.360000E-01 -1.139000E-02 -8.800000E-02 -1.644000E-03 -1.890000E-01 -7.267000E-03 -1.000000E-01 -2.154000E-03 -1.360000E-01 -4.056000E-03 -2.130000E-01 -9.111000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +1.430000E-01 +4.207000E-03 +2.120000E-01 +9.278000E-03 +1.630000E-01 +5.617000E-03 +7.100000E-02 +1.083000E-03 +1.770000E-01 +6.293000E-03 +7.900000E-02 +1.495000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.400000E-01 -3.972000E-03 -2.360000E-01 -1.118200E-02 -1.290000E-01 -3.357000E-03 -5.800000E-02 -7.240000E-04 -1.650000E-01 -5.497000E-03 -4.500000E-02 -4.390000E-04 +2.300000E-01 +1.081000E-02 +5.200000E-01 +5.835000E-02 +2.350000E-01 +1.135900E-02 +1.560000E-01 +4.914000E-03 +2.370000E-01 +1.142300E-02 +1.360000E-01 +3.882000E-03 +2.160000E-01 +9.662000E-03 +1.080000E-01 +2.718000E-03 +2.090000E-01 +8.841000E-03 +1.030000E-01 +2.271000E-03 +5.200000E-01 +5.835000E-02 +2.300000E-01 +1.081000E-02 +5.110000E-01 +5.615900E-02 +2.430000E-01 +1.228300E-02 +5.110000E-01 +5.696100E-02 +1.830000E-01 +7.133000E-03 +5.130000E-01 +6.002100E-02 +2.420000E-01 +1.209200E-02 +5.510000E-01 +7.358900E-02 +2.410000E-01 +1.255900E-02 +5.140000E-01 +5.890200E-02 +2.100000E-01 +1.004600E-02 +2.430000E-01 +1.228300E-02 +5.110000E-01 +5.615900E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.120000E-01 +9.278000E-03 +1.430000E-01 +4.207000E-03 2.380000E-01 -1.167000E-02 -5.080000E-01 -5.729800E-02 -2.360000E-01 -1.145400E-02 -1.490000E-01 -4.565000E-03 -2.400000E-01 -1.169000E-02 -1.700000E-01 -5.850000E-03 -2.230000E-01 -1.002300E-02 -1.060000E-01 -2.530000E-03 -2.020000E-01 -8.370000E-03 -1.010000E-01 -2.179000E-03 -5.080000E-01 -5.729800E-02 -2.380000E-01 -1.167000E-02 -4.940000E-01 -5.315400E-02 -2.280000E-01 -1.061000E-02 -4.970000E-01 -5.443700E-02 -2.070000E-01 -8.827000E-03 -5.320000E-01 -6.384600E-02 +1.133600E-02 +1.640000E-01 +5.444000E-03 2.240000E-01 -1.040600E-02 -5.570000E-01 -7.415500E-02 -2.130000E-01 -9.451000E-03 -5.020000E-01 -5.764600E-02 -2.250000E-01 -1.096300E-02 -2.280000E-01 -1.061000E-02 -4.940000E-01 -5.315400E-02 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -2.360000E-01 -1.118200E-02 -1.400000E-01 -3.972000E-03 -2.130000E-01 -9.133000E-03 -1.660000E-01 -5.668000E-03 -2.150000E-01 -9.355000E-03 -1.050000E-01 -2.345000E-03 -2.110000E-01 -8.999000E-03 +1.015800E-02 +9.300000E-02 +1.829000E-03 +1.950000E-01 +7.705000E-03 1.030000E-01 2.191000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.590000E-01 -5.087000E-03 -2.500000E-01 -1.274600E-02 -1.700000E-01 -5.850000E-03 -2.400000E-01 -1.169000E-02 +1.680000E-01 +5.878000E-03 +2.230000E-01 +1.049900E-02 +1.360000E-01 +3.882000E-03 +2.370000E-01 +1.142300E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.720000E-01 -6.062000E-03 -7.200000E-02 -1.090000E-03 -1.440000E-01 -4.264000E-03 -7.000000E-02 -1.284000E-03 -2.500000E-01 -1.274600E-02 -1.590000E-01 -5.087000E-03 -2.530000E-01 -1.284500E-02 -1.390000E-01 -4.087000E-03 -2.240000E-01 -1.040600E-02 -5.320000E-01 -6.384600E-02 +1.550000E-01 +5.011000E-03 +7.100000E-02 +1.191000E-03 +1.510000E-01 +4.845000E-03 +6.400000E-02 +9.460000E-04 +2.230000E-01 +1.049900E-02 +1.680000E-01 +5.878000E-03 +2.490000E-01 +1.255900E-02 +1.280000E-01 +3.448000E-03 +2.420000E-01 +1.209200E-02 +5.130000E-01 +6.002100E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.340000E-01 -1.113000E-02 -1.100000E-01 -2.558000E-03 2.070000E-01 -8.695000E-03 -1.160000E-01 -3.278000E-03 -1.390000E-01 -4.087000E-03 -2.530000E-01 -1.284500E-02 +8.673000E-03 +1.080000E-01 +2.694000E-03 +2.000000E-01 +8.202000E-03 +9.600000E-02 +2.024000E-03 +1.280000E-01 +3.448000E-03 +2.490000E-01 +1.255900E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.660000E-01 -5.668000E-03 -2.130000E-01 -9.133000E-03 +1.640000E-01 +5.444000E-03 +2.380000E-01 +1.133600E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.340000E-01 -3.634000E-03 -6.200000E-02 -8.400000E-04 -1.600000E-01 -5.186000E-03 -5.400000E-02 -6.340000E-04 +1.760000E-01 +6.550000E-03 +8.200000E-02 +1.536000E-03 +1.670000E-01 +5.653000E-03 +4.900000E-02 +5.630000E-04 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.120000E-01 -2.592000E-03 -1.720000E-01 -6.066000E-03 +1.320000E-01 +3.626000E-03 +1.510000E-01 +4.831000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.220000E-01 -3.024000E-03 1.370000E-01 -3.775000E-03 -6.800000E-02 -1.030000E-03 -1.460000E-01 -4.382000E-03 -1.600000E-01 -5.186000E-03 +3.855000E-03 +1.610000E-01 +5.233000E-03 +5.600000E-02 +7.260000E-04 +1.530000E-01 +4.837000E-03 +1.610000E-01 +5.261000E-03 0.000000E+00 0.000000E+00 -1.720000E-01 -6.066000E-03 -1.120000E-01 -2.592000E-03 -1.260000E-01 -3.360000E-03 -1.250000E-01 -3.287000E-03 +1.510000E-01 +4.831000E-03 +1.320000E-01 +3.626000E-03 +1.490000E-01 +4.731000E-03 +1.320000E-01 +3.514000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.580000E-01 -5.108000E-03 -2.510000E-01 -1.270100E-02 -1.000000E-01 -2.154000E-03 -1.890000E-01 -7.267000E-03 -1.710000E-01 -5.975000E-03 +1.550000E-01 +4.921000E-03 +2.410000E-01 +1.168300E-02 +9.100000E-02 +1.807000E-03 +2.100000E-01 +8.928000E-03 +2.090000E-01 +8.775000E-03 0.000000E+00 0.000000E+00 -1.250000E-01 -3.287000E-03 -1.260000E-01 -3.360000E-03 +1.320000E-01 +3.514000E-03 +1.490000E-01 +4.731000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -493,160 +493,160 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.230000E-01 -3.143000E-03 -1.300000E-01 -3.454000E-03 -4.500000E-02 -4.390000E-04 -1.650000E-01 -5.497000E-03 -1.380000E-01 -3.946000E-03 +1.150000E-01 +2.891000E-03 +1.560000E-01 +5.154000E-03 +7.900000E-02 +1.495000E-03 +1.770000E-01 +6.293000E-03 +1.600000E-01 +5.352000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.840000E-01 -6.872000E-03 -2.440000E-01 -1.221200E-02 +1.610000E-01 +5.273000E-03 +2.310000E-01 +1.098100E-02 +1.610000E-01 +5.233000E-03 1.370000E-01 -3.775000E-03 -1.220000E-01 -3.024000E-03 -1.560000E-01 -4.952000E-03 -1.210000E-01 -3.039000E-03 -1.010000E-01 -2.179000E-03 -2.020000E-01 -8.370000E-03 -1.800000E-01 -6.542000E-03 +3.855000E-03 +1.760000E-01 +6.482000E-03 +1.340000E-01 +3.882000E-03 +1.030000E-01 +2.271000E-03 +2.090000E-01 +8.841000E-03 +1.830000E-01 +6.761000E-03 0.000000E+00 0.000000E+00 -2.440000E-01 -1.221200E-02 -1.840000E-01 -6.872000E-03 -2.430000E-01 -1.197500E-02 +2.310000E-01 +1.098100E-02 +1.610000E-01 +5.273000E-03 +2.620000E-01 +1.380600E-02 1.700000E-01 -6.050000E-03 -2.510000E-01 -1.270100E-02 -1.580000E-01 -5.108000E-03 -2.750000E-01 -1.589500E-02 -1.680000E-01 -5.858000E-03 +5.970000E-03 +2.410000E-01 +1.168300E-02 +1.550000E-01 +4.921000E-03 2.250000E-01 -1.096300E-02 -5.020000E-01 -5.764600E-02 -2.260000E-01 -1.039600E-02 +1.014100E-02 +1.370000E-01 +3.805000E-03 +2.100000E-01 +1.004600E-02 +5.140000E-01 +5.890200E-02 +2.320000E-01 +1.093000E-02 0.000000E+00 0.000000E+00 1.700000E-01 -6.050000E-03 -2.430000E-01 -1.197500E-02 +5.970000E-03 +2.620000E-01 +1.380600E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.300000E-01 -3.454000E-03 -1.230000E-01 -3.143000E-03 -1.590000E-01 -5.219000E-03 -1.270000E-01 -3.447000E-03 +1.560000E-01 +5.154000E-03 +1.150000E-01 +2.891000E-03 +1.430000E-01 +4.163000E-03 +1.120000E-01 +2.640000E-03 1.030000E-01 2.191000E-03 -2.110000E-01 -8.999000E-03 -2.090000E-01 -9.091000E-03 +1.950000E-01 +7.705000E-03 +1.760000E-01 +6.392000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.150000E-01 -2.821000E-03 -1.610000E-01 -5.499000E-03 -1.210000E-01 -3.039000E-03 -1.560000E-01 -4.952000E-03 +9.200000E-02 +1.822000E-03 +1.370000E-01 +3.843000E-03 +1.340000E-01 +3.882000E-03 +1.760000E-01 +6.482000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -7.000000E-02 -1.284000E-03 -1.440000E-01 -4.264000E-03 -1.580000E-01 -5.002000E-03 +6.400000E-02 +9.460000E-04 +1.510000E-01 +4.845000E-03 +1.800000E-01 +6.520000E-03 0.000000E+00 0.000000E+00 -1.610000E-01 -5.499000E-03 -1.150000E-01 -2.821000E-03 -1.630000E-01 -5.583000E-03 -1.270000E-01 -3.315000E-03 -1.680000E-01 -5.858000E-03 -2.750000E-01 -1.589500E-02 +1.370000E-01 +3.843000E-03 +9.200000E-02 +1.822000E-03 +1.300000E-01 +3.604000E-03 +1.170000E-01 +2.789000E-03 +1.370000E-01 +3.805000E-03 +2.250000E-01 +1.014100E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.160000E-01 -3.278000E-03 -2.070000E-01 -8.695000E-03 -1.840000E-01 -6.908000E-03 +9.600000E-02 +2.024000E-03 +2.000000E-01 +8.202000E-03 +1.820000E-01 +6.660000E-03 0.000000E+00 0.000000E+00 -1.270000E-01 -3.315000E-03 -1.630000E-01 -5.583000E-03 +1.170000E-01 +2.789000E-03 +1.300000E-01 +3.604000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.270000E-01 -3.447000E-03 -1.590000E-01 -5.219000E-03 +1.120000E-01 +2.640000E-03 +1.430000E-01 +4.163000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.400000E-02 -6.340000E-04 -1.600000E-01 -5.186000E-03 -1.920000E-01 -7.646000E-03 +4.900000E-02 +5.630000E-04 +1.670000E-01 +5.653000E-03 +1.670000E-01 +5.701000E-03 0.000000E+00 0.000000E+00 tally 2: @@ -660,12 +660,12 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.400000E-01 -4.016000E-03 +1.150000E-01 +2.753000E-03 0.000000E+00 0.000000E+00 -1.760000E-01 -6.368000E-03 +1.820000E-01 +6.756000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -676,44 +676,44 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.140000E-01 -2.714000E-03 +1.110000E-01 +2.601000E-03 0.000000E+00 0.000000E+00 -1.590000E-01 -5.517000E-03 +1.530000E-01 +4.865000E-03 0.000000E+00 0.000000E+00 -1.800000E-01 -6.524000E-03 +1.910000E-01 +7.535000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -6.700000E-02 -9.270000E-04 +7.100000E-02 +1.079000E-03 0.000000E+00 0.000000E+00 -1.570000E-01 -5.131000E-03 +1.500000E-01 +4.606000E-03 0.000000E+00 0.000000E+00 -1.760000E-01 -6.368000E-03 +1.820000E-01 +6.756000E-03 0.000000E+00 0.000000E+00 -1.400000E-01 -4.016000E-03 +1.150000E-01 +2.753000E-03 0.000000E+00 0.000000E+00 -1.570000E-01 -5.019000E-03 +1.610000E-01 +5.383000E-03 0.000000E+00 0.000000E+00 -1.210000E-01 -2.997000E-03 +1.230000E-01 +3.141000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -724,36 +724,36 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.780000E-01 -6.838000E-03 +1.370000E-01 +3.951000E-03 0.000000E+00 0.000000E+00 -2.440000E-01 -1.203200E-02 +2.600000E-01 +1.366400E-02 0.000000E+00 0.000000E+00 -2.120000E-01 -9.028000E-03 +1.930000E-01 +7.573000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.800000E-02 -1.644000E-03 +8.500000E-02 +1.533000E-03 0.000000E+00 0.000000E+00 -2.360000E-01 -1.139000E-02 +2.040000E-01 +8.426000E-03 0.000000E+00 0.000000E+00 -1.210000E-01 -2.997000E-03 +1.230000E-01 +3.141000E-03 0.000000E+00 0.000000E+00 -1.570000E-01 -5.019000E-03 +1.610000E-01 +5.383000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -772,28 +772,28 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.070000E-01 -2.375000E-03 +1.250000E-01 +3.311000E-03 0.000000E+00 0.000000E+00 -1.490000E-01 -4.621000E-03 +1.620000E-01 +5.346000E-03 0.000000E+00 0.000000E+00 -1.640000E-01 -5.476000E-03 +1.860000E-01 +6.932000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.800000E-02 -7.240000E-04 +7.100000E-02 +1.083000E-03 0.000000E+00 0.000000E+00 -1.290000E-01 -3.357000E-03 +1.630000E-01 +5.617000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -804,100 +804,100 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.470000E-01 -4.583000E-03 +1.800000E-01 +7.002000E-03 0.000000E+00 0.000000E+00 -2.610000E-01 -1.376900E-02 +2.980000E-01 +1.815000E-02 0.000000E+00 0.000000E+00 -1.590000E-01 -5.517000E-03 +1.530000E-01 +4.865000E-03 0.000000E+00 0.000000E+00 -1.140000E-01 -2.714000E-03 +1.110000E-01 +2.601000E-03 0.000000E+00 0.000000E+00 -1.630000E-01 -5.645000E-03 +1.890000E-01 +7.605000E-03 0.000000E+00 0.000000E+00 -1.090000E-01 -2.419000E-03 +1.330000E-01 +3.743000E-03 0.000000E+00 0.000000E+00 -1.820000E-01 -6.750000E-03 +1.790000E-01 +6.495000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.060000E-01 -2.530000E-03 +1.080000E-01 +2.718000E-03 0.000000E+00 0.000000E+00 -2.230000E-01 -1.002300E-02 +2.160000E-01 +9.662000E-03 0.000000E+00 0.000000E+00 -2.610000E-01 -1.376900E-02 +2.980000E-01 +1.815000E-02 0.000000E+00 0.000000E+00 -1.470000E-01 -4.583000E-03 +1.800000E-01 +7.002000E-03 0.000000E+00 0.000000E+00 -2.820000E-01 -1.613400E-02 +2.650000E-01 +1.435500E-02 0.000000E+00 0.000000E+00 -1.800000E-01 -6.690000E-03 +1.590000E-01 +5.285000E-03 0.000000E+00 0.000000E+00 -2.440000E-01 -1.203200E-02 +2.600000E-01 +1.366400E-02 0.000000E+00 0.000000E+00 -1.780000E-01 -6.838000E-03 +1.370000E-01 +3.951000E-03 0.000000E+00 0.000000E+00 -2.870000E-01 -1.696700E-02 +2.670000E-01 +1.469300E-02 0.000000E+00 0.000000E+00 -1.800000E-01 -6.556000E-03 +1.940000E-01 +7.678000E-03 0.000000E+00 0.000000E+00 -2.430000E-01 -1.211900E-02 +2.390000E-01 +1.155500E-02 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.130000E-01 -9.451000E-03 +2.410000E-01 +1.255900E-02 0.000000E+00 0.000000E+00 -5.570000E-01 -7.415500E-02 +5.510000E-01 +7.358900E-02 0.000000E+00 0.000000E+00 -1.800000E-01 -6.690000E-03 +1.590000E-01 +5.285000E-03 0.000000E+00 0.000000E+00 -2.820000E-01 -1.613400E-02 +2.650000E-01 +1.435500E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -908,36 +908,36 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.490000E-01 -4.621000E-03 +1.620000E-01 +5.346000E-03 0.000000E+00 0.000000E+00 -1.070000E-01 -2.375000E-03 +1.250000E-01 +3.311000E-03 0.000000E+00 0.000000E+00 -1.500000E-01 -4.604000E-03 +1.870000E-01 +7.083000E-03 0.000000E+00 0.000000E+00 -1.100000E-01 -2.552000E-03 +1.410000E-01 +3.999000E-03 0.000000E+00 0.000000E+00 -1.800000E-01 -6.518000E-03 +2.040000E-01 +8.438000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.050000E-01 -2.345000E-03 +9.300000E-02 +1.829000E-03 0.000000E+00 0.000000E+00 -2.150000E-01 -9.355000E-03 +2.240000E-01 +1.015800E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -948,20 +948,20 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.340000E-01 -3.818000E-03 +1.500000E-01 +4.522000E-03 0.000000E+00 0.000000E+00 -1.690000E-01 -5.911000E-03 +1.630000E-01 +5.439000E-03 0.000000E+00 0.000000E+00 -1.090000E-01 -2.419000E-03 +1.330000E-01 +3.743000E-03 0.000000E+00 0.000000E+00 -1.630000E-01 -5.645000E-03 +1.890000E-01 +7.605000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -972,44 +972,44 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.860000E-01 -6.998000E-03 +1.650000E-01 +5.615000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -7.200000E-02 -1.090000E-03 +7.100000E-02 +1.191000E-03 0.000000E+00 0.000000E+00 -1.720000E-01 -6.062000E-03 +1.550000E-01 +5.011000E-03 0.000000E+00 0.000000E+00 -1.690000E-01 -5.911000E-03 +1.630000E-01 +5.439000E-03 0.000000E+00 0.000000E+00 -1.340000E-01 -3.818000E-03 +1.500000E-01 +4.522000E-03 0.000000E+00 0.000000E+00 -1.600000E-01 -5.454000E-03 +1.680000E-01 +5.966000E-03 0.000000E+00 0.000000E+00 -1.060000E-01 -2.328000E-03 +1.290000E-01 +3.515000E-03 0.000000E+00 0.000000E+00 -1.800000E-01 -6.556000E-03 +1.940000E-01 +7.678000E-03 0.000000E+00 0.000000E+00 -2.870000E-01 -1.696700E-02 +2.670000E-01 +1.469300E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1020,28 +1020,28 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -2.060000E-01 -8.670000E-03 +1.810000E-01 +6.765000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.100000E-01 -2.558000E-03 +1.080000E-01 +2.694000E-03 0.000000E+00 0.000000E+00 -2.340000E-01 -1.113000E-02 +2.070000E-01 +8.673000E-03 0.000000E+00 0.000000E+00 -1.060000E-01 -2.328000E-03 +1.290000E-01 +3.515000E-03 0.000000E+00 0.000000E+00 -1.600000E-01 -5.454000E-03 +1.680000E-01 +5.966000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1052,12 +1052,12 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.100000E-01 -2.552000E-03 +1.410000E-01 +3.999000E-03 0.000000E+00 0.000000E+00 -1.500000E-01 -4.604000E-03 +1.870000E-01 +7.083000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1068,20 +1068,20 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.730000E-01 -6.077000E-03 +1.870000E-01 +7.213000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -6.200000E-02 -8.400000E-04 +8.200000E-02 +1.536000E-03 0.000000E+00 0.000000E+00 -1.340000E-01 -3.634000E-03 +1.760000E-01 +6.550000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1092,12 +1092,12 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.600000E-01 -5.202000E-03 +1.750000E-01 +6.163000E-03 0.000000E+00 0.000000E+00 -2.170000E-01 -9.735000E-03 +2.570000E-01 +1.347100E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1108,44 +1108,44 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.490000E-01 -4.565000E-03 +1.560000E-01 +4.914000E-03 0.000000E+00 0.000000E+00 -2.360000E-01 -1.145400E-02 +2.350000E-01 +1.135900E-02 0.000000E+00 0.000000E+00 -1.570000E-01 -5.131000E-03 +1.500000E-01 +4.606000E-03 0.000000E+00 0.000000E+00 -6.700000E-02 -9.270000E-04 +7.100000E-02 +1.079000E-03 0.000000E+00 0.000000E+00 -1.460000E-01 -4.382000E-03 +1.530000E-01 +4.837000E-03 0.000000E+00 0.000000E+00 -6.800000E-02 -1.030000E-03 +5.600000E-02 +7.260000E-04 0.000000E+00 0.000000E+00 -2.170000E-01 -9.735000E-03 +2.570000E-01 +1.347100E-02 0.000000E+00 0.000000E+00 -1.600000E-01 -5.202000E-03 +1.750000E-01 +6.163000E-03 0.000000E+00 0.000000E+00 -2.130000E-01 -9.111000E-03 +2.460000E-01 +1.235000E-02 0.000000E+00 0.000000E+00 -1.360000E-01 -4.056000E-03 +1.420000E-01 +4.326000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1156,36 +1156,36 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -2.070000E-01 -8.827000E-03 +1.830000E-01 +7.133000E-03 0.000000E+00 0.000000E+00 -4.970000E-01 -5.443700E-02 +5.110000E-01 +5.696100E-02 0.000000E+00 0.000000E+00 -2.360000E-01 -1.139000E-02 +2.040000E-01 +8.426000E-03 0.000000E+00 0.000000E+00 -8.800000E-02 -1.644000E-03 +8.500000E-02 +1.533000E-03 0.000000E+00 0.000000E+00 -1.890000E-01 -7.267000E-03 +2.100000E-01 +8.928000E-03 0.000000E+00 0.000000E+00 -1.000000E-01 -2.154000E-03 +9.100000E-02 +1.807000E-03 0.000000E+00 0.000000E+00 -1.360000E-01 -4.056000E-03 +1.420000E-01 +4.326000E-03 0.000000E+00 0.000000E+00 -2.130000E-01 -9.111000E-03 +2.460000E-01 +1.235000E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1204,28 +1204,28 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.400000E-01 -3.972000E-03 +1.430000E-01 +4.207000E-03 0.000000E+00 0.000000E+00 -2.360000E-01 -1.118200E-02 +2.120000E-01 +9.278000E-03 0.000000E+00 0.000000E+00 -1.290000E-01 -3.357000E-03 +1.630000E-01 +5.617000E-03 0.000000E+00 0.000000E+00 -5.800000E-02 -7.240000E-04 +7.100000E-02 +1.083000E-03 0.000000E+00 0.000000E+00 -1.650000E-01 -5.497000E-03 +1.770000E-01 +6.293000E-03 0.000000E+00 0.000000E+00 -4.500000E-02 -4.390000E-04 +7.900000E-02 +1.495000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1236,100 +1236,100 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -2.380000E-01 -1.167000E-02 +2.300000E-01 +1.081000E-02 0.000000E+00 0.000000E+00 -5.080000E-01 -5.729800E-02 +5.200000E-01 +5.835000E-02 0.000000E+00 0.000000E+00 -2.360000E-01 -1.145400E-02 +2.350000E-01 +1.135900E-02 0.000000E+00 0.000000E+00 -1.490000E-01 -4.565000E-03 +1.560000E-01 +4.914000E-03 0.000000E+00 0.000000E+00 -2.400000E-01 -1.169000E-02 +2.370000E-01 +1.142300E-02 0.000000E+00 0.000000E+00 -1.700000E-01 -5.850000E-03 +1.360000E-01 +3.882000E-03 0.000000E+00 0.000000E+00 -2.230000E-01 -1.002300E-02 +2.160000E-01 +9.662000E-03 0.000000E+00 0.000000E+00 -1.060000E-01 -2.530000E-03 +1.080000E-01 +2.718000E-03 0.000000E+00 0.000000E+00 -2.020000E-01 -8.370000E-03 +2.090000E-01 +8.841000E-03 0.000000E+00 0.000000E+00 -1.010000E-01 -2.179000E-03 +1.030000E-01 +2.271000E-03 0.000000E+00 0.000000E+00 -5.080000E-01 -5.729800E-02 +5.200000E-01 +5.835000E-02 0.000000E+00 0.000000E+00 -2.380000E-01 -1.167000E-02 +2.300000E-01 +1.081000E-02 0.000000E+00 0.000000E+00 -4.940000E-01 -5.315400E-02 +5.110000E-01 +5.615900E-02 0.000000E+00 0.000000E+00 -2.280000E-01 -1.061000E-02 +2.430000E-01 +1.228300E-02 0.000000E+00 0.000000E+00 -4.970000E-01 -5.443700E-02 +5.110000E-01 +5.696100E-02 0.000000E+00 0.000000E+00 -2.070000E-01 -8.827000E-03 +1.830000E-01 +7.133000E-03 0.000000E+00 0.000000E+00 -5.320000E-01 -6.384600E-02 +5.130000E-01 +6.002100E-02 0.000000E+00 0.000000E+00 -2.240000E-01 -1.040600E-02 +2.420000E-01 +1.209200E-02 0.000000E+00 0.000000E+00 -5.570000E-01 -7.415500E-02 +5.510000E-01 +7.358900E-02 0.000000E+00 0.000000E+00 -2.130000E-01 -9.451000E-03 +2.410000E-01 +1.255900E-02 0.000000E+00 0.000000E+00 -5.020000E-01 -5.764600E-02 +5.140000E-01 +5.890200E-02 0.000000E+00 0.000000E+00 -2.250000E-01 -1.096300E-02 +2.100000E-01 +1.004600E-02 0.000000E+00 0.000000E+00 -2.280000E-01 -1.061000E-02 +2.430000E-01 +1.228300E-02 0.000000E+00 0.000000E+00 -4.940000E-01 -5.315400E-02 +5.110000E-01 +5.615900E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1340,32 +1340,32 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -2.360000E-01 -1.118200E-02 +2.120000E-01 +9.278000E-03 0.000000E+00 0.000000E+00 -1.400000E-01 -3.972000E-03 +1.430000E-01 +4.207000E-03 0.000000E+00 0.000000E+00 -2.130000E-01 -9.133000E-03 +2.380000E-01 +1.133600E-02 0.000000E+00 0.000000E+00 -1.660000E-01 -5.668000E-03 +1.640000E-01 +5.444000E-03 0.000000E+00 0.000000E+00 -2.150000E-01 -9.355000E-03 +2.240000E-01 +1.015800E-02 0.000000E+00 0.000000E+00 -1.050000E-01 -2.345000E-03 +9.300000E-02 +1.829000E-03 0.000000E+00 0.000000E+00 -2.110000E-01 -8.999000E-03 +1.950000E-01 +7.705000E-03 0.000000E+00 0.000000E+00 1.030000E-01 @@ -1380,20 +1380,20 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.590000E-01 -5.087000E-03 +1.680000E-01 +5.878000E-03 0.000000E+00 0.000000E+00 -2.500000E-01 -1.274600E-02 +2.230000E-01 +1.049900E-02 0.000000E+00 0.000000E+00 -1.700000E-01 -5.850000E-03 +1.360000E-01 +3.882000E-03 0.000000E+00 0.000000E+00 -2.400000E-01 -1.169000E-02 +2.370000E-01 +1.142300E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1404,44 +1404,44 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.720000E-01 -6.062000E-03 +1.550000E-01 +5.011000E-03 0.000000E+00 0.000000E+00 -7.200000E-02 -1.090000E-03 +7.100000E-02 +1.191000E-03 0.000000E+00 0.000000E+00 -1.440000E-01 -4.264000E-03 +1.510000E-01 +4.845000E-03 0.000000E+00 0.000000E+00 -7.000000E-02 -1.284000E-03 +6.400000E-02 +9.460000E-04 0.000000E+00 0.000000E+00 -2.500000E-01 -1.274600E-02 +2.230000E-01 +1.049900E-02 0.000000E+00 0.000000E+00 -1.590000E-01 -5.087000E-03 +1.680000E-01 +5.878000E-03 0.000000E+00 0.000000E+00 -2.530000E-01 -1.284500E-02 +2.490000E-01 +1.255900E-02 0.000000E+00 0.000000E+00 -1.390000E-01 -4.087000E-03 +1.280000E-01 +3.448000E-03 0.000000E+00 0.000000E+00 -2.240000E-01 -1.040600E-02 +2.420000E-01 +1.209200E-02 0.000000E+00 0.000000E+00 -5.320000E-01 -6.384600E-02 +5.130000E-01 +6.002100E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1452,28 +1452,28 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -2.340000E-01 -1.113000E-02 +2.070000E-01 +8.673000E-03 0.000000E+00 0.000000E+00 -1.100000E-01 -2.558000E-03 +1.080000E-01 +2.694000E-03 0.000000E+00 0.000000E+00 -2.070000E-01 -8.695000E-03 +2.000000E-01 +8.202000E-03 0.000000E+00 0.000000E+00 -1.160000E-01 -3.278000E-03 +9.600000E-02 +2.024000E-03 0.000000E+00 0.000000E+00 -1.390000E-01 -4.087000E-03 +1.280000E-01 +3.448000E-03 0.000000E+00 0.000000E+00 -2.530000E-01 -1.284500E-02 +2.490000E-01 +1.255900E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1484,12 +1484,12 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.660000E-01 -5.668000E-03 +1.640000E-01 +5.444000E-03 0.000000E+00 0.000000E+00 -2.130000E-01 -9.133000E-03 +2.380000E-01 +1.133600E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1500,20 +1500,20 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.340000E-01 -3.634000E-03 +1.760000E-01 +6.550000E-03 0.000000E+00 0.000000E+00 -6.200000E-02 -8.400000E-04 +8.200000E-02 +1.536000E-03 0.000000E+00 0.000000E+00 -1.600000E-01 -5.186000E-03 +1.670000E-01 +5.653000E-03 0.000000E+00 0.000000E+00 -5.400000E-02 -6.340000E-04 +4.900000E-02 +5.630000E-04 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1524,12 +1524,12 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.120000E-01 -2.592000E-03 +1.320000E-01 +3.626000E-03 0.000000E+00 0.000000E+00 -1.720000E-01 -6.066000E-03 +1.510000E-01 +4.831000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1540,44 +1540,44 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.220000E-01 -3.024000E-03 +1.370000E-01 +3.855000E-03 0.000000E+00 0.000000E+00 -1.370000E-01 -3.775000E-03 +1.610000E-01 +5.233000E-03 0.000000E+00 0.000000E+00 -6.800000E-02 -1.030000E-03 +5.600000E-02 +7.260000E-04 0.000000E+00 0.000000E+00 -1.460000E-01 -4.382000E-03 +1.530000E-01 +4.837000E-03 0.000000E+00 0.000000E+00 -1.600000E-01 -5.186000E-03 +1.610000E-01 +5.261000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.720000E-01 -6.066000E-03 +1.510000E-01 +4.831000E-03 0.000000E+00 0.000000E+00 -1.120000E-01 -2.592000E-03 +1.320000E-01 +3.626000E-03 0.000000E+00 0.000000E+00 -1.260000E-01 -3.360000E-03 +1.490000E-01 +4.731000E-03 0.000000E+00 0.000000E+00 -1.250000E-01 -3.287000E-03 +1.320000E-01 +3.514000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1588,36 +1588,36 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.580000E-01 -5.108000E-03 +1.550000E-01 +4.921000E-03 0.000000E+00 0.000000E+00 -2.510000E-01 -1.270100E-02 +2.410000E-01 +1.168300E-02 0.000000E+00 0.000000E+00 -1.000000E-01 -2.154000E-03 +9.100000E-02 +1.807000E-03 0.000000E+00 0.000000E+00 -1.890000E-01 -7.267000E-03 +2.100000E-01 +8.928000E-03 0.000000E+00 0.000000E+00 -1.710000E-01 -5.975000E-03 +2.090000E-01 +8.775000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.250000E-01 -3.287000E-03 +1.320000E-01 +3.514000E-03 0.000000E+00 0.000000E+00 -1.260000E-01 -3.360000E-03 +1.490000E-01 +4.731000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1636,24 +1636,24 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.230000E-01 -3.143000E-03 +1.150000E-01 +2.891000E-03 0.000000E+00 0.000000E+00 -1.300000E-01 -3.454000E-03 +1.560000E-01 +5.154000E-03 0.000000E+00 0.000000E+00 -4.500000E-02 -4.390000E-04 +7.900000E-02 +1.495000E-03 0.000000E+00 0.000000E+00 -1.650000E-01 -5.497000E-03 +1.770000E-01 +6.293000E-03 0.000000E+00 0.000000E+00 -1.380000E-01 -3.946000E-03 +1.600000E-01 +5.352000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1668,88 +1668,88 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.840000E-01 -6.872000E-03 +1.610000E-01 +5.273000E-03 0.000000E+00 0.000000E+00 -2.440000E-01 -1.221200E-02 +2.310000E-01 +1.098100E-02 0.000000E+00 0.000000E+00 -1.370000E-01 -3.775000E-03 +1.610000E-01 +5.233000E-03 0.000000E+00 0.000000E+00 -1.220000E-01 -3.024000E-03 +1.370000E-01 +3.855000E-03 0.000000E+00 0.000000E+00 -1.560000E-01 -4.952000E-03 +1.760000E-01 +6.482000E-03 0.000000E+00 0.000000E+00 -1.210000E-01 -3.039000E-03 +1.340000E-01 +3.882000E-03 0.000000E+00 0.000000E+00 -1.010000E-01 -2.179000E-03 +1.030000E-01 +2.271000E-03 0.000000E+00 0.000000E+00 -2.020000E-01 -8.370000E-03 +2.090000E-01 +8.841000E-03 0.000000E+00 0.000000E+00 -1.800000E-01 -6.542000E-03 +1.830000E-01 +6.761000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.440000E-01 -1.221200E-02 +2.310000E-01 +1.098100E-02 0.000000E+00 0.000000E+00 -1.840000E-01 -6.872000E-03 +1.610000E-01 +5.273000E-03 0.000000E+00 0.000000E+00 -2.430000E-01 -1.197500E-02 +2.620000E-01 +1.380600E-02 0.000000E+00 0.000000E+00 1.700000E-01 -6.050000E-03 +5.970000E-03 0.000000E+00 0.000000E+00 -2.510000E-01 -1.270100E-02 +2.410000E-01 +1.168300E-02 0.000000E+00 0.000000E+00 -1.580000E-01 -5.108000E-03 +1.550000E-01 +4.921000E-03 0.000000E+00 0.000000E+00 -2.750000E-01 -1.589500E-02 +2.250000E-01 +1.014100E-02 0.000000E+00 0.000000E+00 -1.680000E-01 -5.858000E-03 +1.370000E-01 +3.805000E-03 0.000000E+00 0.000000E+00 -2.250000E-01 -1.096300E-02 +2.100000E-01 +1.004600E-02 0.000000E+00 0.000000E+00 -5.020000E-01 -5.764600E-02 +5.140000E-01 +5.890200E-02 0.000000E+00 0.000000E+00 -2.260000E-01 -1.039600E-02 +2.320000E-01 +1.093000E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1757,11 +1757,11 @@ tally 2: 0.000000E+00 0.000000E+00 1.700000E-01 -6.050000E-03 +5.970000E-03 0.000000E+00 0.000000E+00 -2.430000E-01 -1.197500E-02 +2.620000E-01 +1.380600E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1772,32 +1772,32 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.300000E-01 -3.454000E-03 +1.560000E-01 +5.154000E-03 0.000000E+00 0.000000E+00 -1.230000E-01 -3.143000E-03 +1.150000E-01 +2.891000E-03 0.000000E+00 0.000000E+00 -1.590000E-01 -5.219000E-03 +1.430000E-01 +4.163000E-03 0.000000E+00 0.000000E+00 -1.270000E-01 -3.447000E-03 +1.120000E-01 +2.640000E-03 0.000000E+00 0.000000E+00 1.030000E-01 2.191000E-03 0.000000E+00 0.000000E+00 -2.110000E-01 -8.999000E-03 +1.950000E-01 +7.705000E-03 0.000000E+00 0.000000E+00 -2.090000E-01 -9.091000E-03 +1.760000E-01 +6.392000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1812,20 +1812,20 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.150000E-01 -2.821000E-03 +9.200000E-02 +1.822000E-03 0.000000E+00 0.000000E+00 -1.610000E-01 -5.499000E-03 +1.370000E-01 +3.843000E-03 0.000000E+00 0.000000E+00 -1.210000E-01 -3.039000E-03 +1.340000E-01 +3.882000E-03 0.000000E+00 0.000000E+00 -1.560000E-01 -4.952000E-03 +1.760000E-01 +6.482000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1836,44 +1836,44 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -7.000000E-02 -1.284000E-03 +6.400000E-02 +9.460000E-04 0.000000E+00 0.000000E+00 -1.440000E-01 -4.264000E-03 +1.510000E-01 +4.845000E-03 0.000000E+00 0.000000E+00 -1.580000E-01 -5.002000E-03 +1.800000E-01 +6.520000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.610000E-01 -5.499000E-03 +1.370000E-01 +3.843000E-03 0.000000E+00 0.000000E+00 -1.150000E-01 -2.821000E-03 +9.200000E-02 +1.822000E-03 0.000000E+00 0.000000E+00 -1.630000E-01 -5.583000E-03 +1.300000E-01 +3.604000E-03 0.000000E+00 0.000000E+00 -1.270000E-01 -3.315000E-03 +1.170000E-01 +2.789000E-03 0.000000E+00 0.000000E+00 -1.680000E-01 -5.858000E-03 +1.370000E-01 +3.805000E-03 0.000000E+00 0.000000E+00 -2.750000E-01 -1.589500E-02 +2.250000E-01 +1.014100E-02 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1884,28 +1884,28 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.160000E-01 -3.278000E-03 +9.600000E-02 +2.024000E-03 0.000000E+00 0.000000E+00 -2.070000E-01 -8.695000E-03 +2.000000E-01 +8.202000E-03 0.000000E+00 0.000000E+00 -1.840000E-01 -6.908000E-03 +1.820000E-01 +6.660000E-03 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.270000E-01 -3.315000E-03 +1.170000E-01 +2.789000E-03 0.000000E+00 0.000000E+00 -1.630000E-01 -5.583000E-03 +1.300000E-01 +3.604000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1916,12 +1916,12 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -1.270000E-01 -3.447000E-03 +1.120000E-01 +2.640000E-03 0.000000E+00 0.000000E+00 -1.590000E-01 -5.219000E-03 +1.430000E-01 +4.163000E-03 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1932,16 +1932,16 @@ tally 2: 0.000000E+00 0.000000E+00 0.000000E+00 -5.400000E-02 -6.340000E-04 +4.900000E-02 +5.630000E-04 0.000000E+00 0.000000E+00 -1.600000E-01 -5.186000E-03 +1.670000E-01 +5.653000E-03 0.000000E+00 0.000000E+00 -1.920000E-01 -7.646000E-03 +1.670000E-01 +5.701000E-03 0.000000E+00 0.000000E+00 0.000000E+00 diff --git a/tests/regression_tests/score_current/test.py b/tests/regression_tests/score_current/test.py index 1309584d2ce..a338a662669 100644 --- a/tests/regression_tests/score_current/test.py +++ b/tests/regression_tests/score_current/test.py @@ -16,12 +16,12 @@ def model(): zr.add_nuclide('Zr90', 1.0) model.materials.extend([fuel, zr]) - box1 = openmc.model.rectangular_prism(10.0, 10.0) - box2 = openmc.model.rectangular_prism(20.0, 20.0, boundary_type='reflective') + box1 = openmc.model.RectangularPrism(10.0, 10.0) + box2 = openmc.model.RectangularPrism(20.0, 20.0, boundary_type='reflective') top = openmc.ZPlane(z0=10.0, boundary_type='vacuum') bottom = openmc.ZPlane(z0=-10.0, boundary_type='vacuum') - cell1 = openmc.Cell(fill=fuel, region=box1 & +bottom & -top) - cell2 = openmc.Cell(fill=zr, region=~box1 & box2 & +bottom & -top) + cell1 = openmc.Cell(fill=fuel, region=-box1 & +bottom & -top) + cell2 = openmc.Cell(fill=zr, region=+box1 & -box2 & +bottom & -top) model.geometry = openmc.Geometry([cell1, cell2]) model.settings.batches = 5 diff --git a/tests/regression_tests/seed/results_true.dat b/tests/regression_tests/seed/results_true.dat index 1f70e15137d..bcd7118253a 100644 --- a/tests/regression_tests/seed/results_true.dat +++ b/tests/regression_tests/seed/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.961599E-01 2.921488E-03 +3.069730E-01 2.632099E-03 diff --git a/tests/regression_tests/source/inputs_true.dat b/tests/regression_tests/source/inputs_true.dat index de81a41791b..c1a616dd109 100644 --- a/tests/regression_tests/source/inputs_true.dat +++ b/tests/regression_tests/source/inputs_true.dat @@ -1,79 +1,150 @@ - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - - - -4.0 -1.0 3.0 0.2 0.3 0.5 - - - -2.0 0.0 2.0 0.2 0.3 0.2 - - - - - -1.0 0.0 1.0 0.5 0.25 0.25 - - - - - - - - -4.0 -4.0 -4.0 4.0 4.0 4.0 - - - - - - - 1.2 -2.3 0.781 - - - - 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - - - - - - 0.7853981633974483 1.5707963267948966 2.356194490192345 0.3 0.4 0.3 - - - - - - 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - - - - - - - -2.0 0.0 2.0 0.2 0.3 0.2 - - - - - 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - - + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + + + -4.0 -1.0 3.0 0.2 0.3 0.5 + + + -2.0 0.0 2.0 0.2 0.3 0.2 + + + + + -1.0 0.0 1.0 0.5 0.25 0.25 + + + + + + + + -4.0 -4.0 -4.0 4.0 4.0 4.0 + + + + + + + 1.2 -2.3 0.781 + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + + + 0.7071067811865476 0.0 -0.7071067811865475 0.3 0.4 0.3 + + + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + + + + -2.0 0.0 2.0 0.2 0.3 0.2 + + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + + + + -2.0 0.0 2.0 0.2 0.3 0.2 + + + + + + + + + + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + + + + + 0.7071067811865476 0.0 -0.7071067811865475 0.3 0.4 0.3 + + + + + + + + + + + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + diff --git a/tests/regression_tests/source/results_true.dat b/tests/regression_tests/source/results_true.dat index 66b610b3a80..94d9ced1551 100644 --- a/tests/regression_tests/source/results_true.dat +++ b/tests/regression_tests/source/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.033600E-01 1.676108E-03 +3.054101E-01 1.167865E-03 diff --git a/tests/regression_tests/source/test.py b/tests/regression_tests/source/test.py index 91316acc620..c1f4dccff94 100644 --- a/tests/regression_tests/source/test.py +++ b/tests/regression_tests/source/test.py @@ -1,4 +1,4 @@ -from math import pi +from math import pi, cos import numpy as np import openmc @@ -7,12 +7,12 @@ class SourceTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) mat1 = openmc.Material(material_id=1, temperature=294) mat1.set_density('g/cm3', 4.5) mat1.add_nuclide(openmc.Nuclide('U235'), 1.0) - materials = openmc.Materials([mat1]) - materials.export_to_xml() + self._model.materials = openmc.Materials([mat1]) sphere = openmc.Sphere(surface_id=1, r=10.0, boundary_type='vacuum') inside_sphere = openmc.Cell(cell_id=1) @@ -21,25 +21,31 @@ def _build_inputs(self): root = openmc.Universe(universe_id=0) root.add_cell(inside_sphere) - geometry = openmc.Geometry() - geometry.root_universe = root - geometry.export_to_xml() + self._model.geometry = openmc.Geometry(root) # Create an array of different sources x_dist = openmc.stats.Uniform(-3., 3.) y_dist = openmc.stats.Discrete([-4., -1., 3.], [0.2, 0.3, 0.5]) z_dist = openmc.stats.Tabular([-2., 0., 2.], [0.2, 0.3, 0.2]) r_dist = openmc.stats.Uniform(2., 3.) - theta_dist = openmc.stats.Discrete([pi/4, pi/2, 3*pi/4], - [0.3, 0.4, 0.3]) + r_dist1 = openmc.stats.PowerLaw(2., 3., 1.) + r_dist2 = openmc.stats.PowerLaw(2., 3., 2.) + cos_theta_dist = openmc.stats.Discrete([cos(pi/4), 0.0, cos(3*pi/4)], + [0.3, 0.4, 0.3]) phi_dist = openmc.stats.Uniform(0.0, 2*pi) spatial1 = openmc.stats.CartesianIndependent(x_dist, y_dist, z_dist) spatial2 = openmc.stats.Box([-4., -4., -4.], [4., 4., 4.]) spatial3 = openmc.stats.Point([1.2, -2.3, 0.781]) - spatial4 = openmc.stats.SphericalIndependent(r_dist, theta_dist, - phi_dist, + spatial4 = openmc.stats.SphericalIndependent(r_dist, cos_theta_dist, + phi_dist, origin=(1., 1., 0.)) - spatial5 = openmc.stats.CylindricalIndependent(r_dist, phi_dist, + spatial5 = openmc.stats.CylindricalIndependent(r_dist, phi_dist, + z_dist, + origin=(1., 1., 0.)) + spatial6 = openmc.stats.SphericalIndependent(r_dist2, cos_theta_dist, + phi_dist, + origin=(1., 1., 0.)) + spatial7 = openmc.stats.CylindricalIndependent(r_dist1, phi_dist, z_dist, origin=(1., 1., 0.)) @@ -49,27 +55,36 @@ def _build_inputs(self): angle2 = openmc.stats.Monodirectional(reference_uvw=[0., 1., 0.]) angle3 = openmc.stats.Isotropic() - E = np.logspace(0, 7) + # Note that the definition for E is equivalent to logspace(0, 7) but we + # manually take powers because of last-digit differences that may cause + # test failures with different versions of numpy + E = np.array([10**x for x in np.linspace(0, 7)]) p = np.sin(np.linspace(0., pi)) p /= sum(np.diff(E)*p[:-1]) energy1 = openmc.stats.Maxwell(1.2895e6) energy2 = openmc.stats.Watt(0.988e6, 2.249e-6) energy3 = openmc.stats.Tabular(E, p, interpolation='histogram') + energy4 = openmc.stats.Mixture([1, 2, 3], [energy1, energy2, energy3]) + + time1 = openmc.stats.Uniform(2, 5) - source1 = openmc.Source(spatial1, angle1, energy1, strength=0.5) - source2 = openmc.Source(spatial2, angle2, energy2, strength=0.3) - source3 = openmc.Source(spatial3, angle3, energy3, strength=0.1) - source4 = openmc.Source(spatial4, angle3, energy3, strength=0.1) - source5 = openmc.Source(spatial5, angle3, energy3, strength=0.1) + source1 = openmc.IndependentSource(spatial1, angle1, energy1, strength=0.3) + source2 = openmc.IndependentSource(spatial2, angle2, energy2, strength=0.1) + source3 = openmc.IndependentSource(spatial3, angle3, energy3, strength=0.1) + source4 = openmc.IndependentSource(spatial4, angle3, energy3, strength=0.1) + source5 = openmc.IndependentSource(spatial5, angle3, energy3, strength=0.1) + source6 = openmc.IndependentSource(spatial5, angle3, energy4, strength=0.1) + source7 = openmc.IndependentSource(spatial6, angle3, energy4, time1, strength=0.1) + source8 = openmc.IndependentSource(spatial7, angle3, energy4, time1, strength=0.1) settings = openmc.Settings() settings.batches = 10 settings.inactive = 5 settings.particles = 1000 - settings.source = [source1, source2, source3, source4, source5] - settings.export_to_xml() + settings.source = [source1, source2, source3, source4, source5, source6, source7, source8] + self._model.settings = settings def test_source(): - harness = SourceTestHarness('statepoint.10.h5') + harness = SourceTestHarness('statepoint.10.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/source_dlopen/inputs_true.dat b/tests/regression_tests/source_dlopen/inputs_true.dat index 23878ac207d..28d1e06e2bd 100644 --- a/tests/regression_tests/source_dlopen/inputs_true.dat +++ b/tests/regression_tests/source_dlopen/inputs_true.dat @@ -1,23 +1,35 @@ - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - 0 - - + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + 0 + + + + + 1 + + + 0.0 2000.0 1000000.0 + + + 1 2 + flux + + + diff --git a/tests/regression_tests/source_dlopen/results_true.dat b/tests/regression_tests/source_dlopen/results_true.dat index e69de29bb2d..1cddaf802ca 100644 --- a/tests/regression_tests/source_dlopen/results_true.dat +++ b/tests/regression_tests/source_dlopen/results_true.dat @@ -0,0 +1,5 @@ +tally 1: +1.445856E+04 +2.090732E+07 +0.000000E+00 +0.000000E+00 diff --git a/tests/regression_tests/source_dlopen/source_sampling.cpp b/tests/regression_tests/source_dlopen/source_sampling.cpp index 2c6de6d85e0..fc61ef1fdd8 100644 --- a/tests/regression_tests/source_dlopen/source_sampling.cpp +++ b/tests/regression_tests/source_dlopen/source_sampling.cpp @@ -5,8 +5,7 @@ #include "openmc/random_lcg.h" #include "openmc/source.h" -class CustomSource : public openmc::Source -{ +class CustomSource : public openmc::Source { openmc::SourceSite sample(uint64_t* seed) const { openmc::SourceSite particle; @@ -20,16 +19,17 @@ class CustomSource : public openmc::Source particle.r.z = 0.; // angle particle.u = {1.0, 0.0, 0.0}; - particle.E = 14.08e6; + particle.E = 1.00e3; particle.delayed_group = 0; return particle; } }; -// A function to create a unique pointer to an instance of this class when generated -// via a plugin call using dlopen/dlsym. -// You must have external C linkage here otherwise dlopen will not find the file -extern "C" std::unique_ptr openmc_create_source(std::string parameters) +// A function to create a unique pointer to an instance of this class when +// generated via a plugin call using dlopen/dlsym. You must have external C +// linkage here otherwise dlopen will not find the file +extern "C" std::unique_ptr openmc_create_source( + std::string parameters) { return std::make_unique(); } diff --git a/tests/regression_tests/source_dlopen/test.py b/tests/regression_tests/source_dlopen/test.py index 41690224dfb..88ff9dd8509 100644 --- a/tests/regression_tests/source_dlopen/test.py +++ b/tests/regression_tests/source_dlopen/test.py @@ -18,7 +18,7 @@ def compile_source(request): openmc_dir = Path(str(request.config.rootdir)) / 'build' with open('CMakeLists.txt', 'w') as f: f.write(textwrap.dedent(""" - cmake_minimum_required(VERSION 3.3 FATAL_ERROR) + cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(openmc_sources CXX) add_library(source SHARED source_sampling.cpp) find_package(OpenMC REQUIRED HINTS {}) @@ -61,8 +61,18 @@ def model(): model.settings.particles = 1000 model.settings.run_mode = 'fixed source' + tally = openmc.Tally() + mat_filter = openmc.MaterialFilter([natural_lead]) + # energy filter with two bins 0 eV - 1 keV and 1 keV - 1 MeV the second bin + # of the energy filter (last two entries in the tally results) should be + # zero + energy_filter = openmc.EnergyFilter([0.0, 2e3, 1e6]) + tally.filters = [mat_filter, energy_filter] + tally.scores = ['flux'] + model.tallies = openmc.Tallies([tally]) + # custom source from shared library - source = openmc.Source() + source = openmc.CompiledSource() source.library = 'build/libsource.so' model.settings.source = source diff --git a/tests/regression_tests/source_file/results_true.dat b/tests/regression_tests/source_file/results_true.dat index 0d8600fedcb..264e3d580d4 100644 --- a/tests/regression_tests/source_file/results_true.dat +++ b/tests/regression_tests/source_file/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.009416E-01 3.229998E-03 +2.983135E-01 5.116978E-03 diff --git a/tests/regression_tests/source_mcpl_file/__init__.py b/tests/regression_tests/source_mcpl_file/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/source_mcpl_file/geometry.xml b/tests/regression_tests/source_mcpl_file/geometry.xml new file mode 100644 index 00000000000..bc56030e18b --- /dev/null +++ b/tests/regression_tests/source_mcpl_file/geometry.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/regression_tests/source_mcpl_file/materials.xml b/tests/regression_tests/source_mcpl_file/materials.xml new file mode 100644 index 00000000000..2472a747174 --- /dev/null +++ b/tests/regression_tests/source_mcpl_file/materials.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tests/regression_tests/source_mcpl_file/results_true.dat b/tests/regression_tests/source_mcpl_file/results_true.dat new file mode 100644 index 00000000000..264e3d580d4 --- /dev/null +++ b/tests/regression_tests/source_mcpl_file/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +2.983135E-01 5.116978E-03 diff --git a/tests/regression_tests/source_mcpl_file/settings.xml b/tests/regression_tests/source_mcpl_file/settings.xml new file mode 100644 index 00000000000..47b010bffea --- /dev/null +++ b/tests/regression_tests/source_mcpl_file/settings.xml @@ -0,0 +1,15 @@ + + + + + + 10 + 5 + 1000 + + + + -4 -4 -4 4 4 4 + + + diff --git a/tests/regression_tests/source_mcpl_file/test.py b/tests/regression_tests/source_mcpl_file/test.py new file mode 100644 index 00000000000..84ec005ae16 --- /dev/null +++ b/tests/regression_tests/source_mcpl_file/test.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python +import openmc.lib +import pytest +import glob +import os + +from tests.testing_harness import * +pytestmark = pytest.mark.skipif( + not openmc.lib._mcpl_enabled(), + reason="MCPL is not enabled.") + +settings1=""" + + + + + 10 + 5 + 1000 + + + + -4 -4 -4 4 4 4 + + + +""" + +settings2 = """ + + + 10 + 5 + 1000 + + + source.10.{} + + +""" + + +class SourceFileTestHarness(TestHarness): + def execute_test(self): + """Run OpenMC with the appropriate arguments and check the outputs.""" + try: + self._run_openmc() + self._test_output_created() + self._run_openmc_restart() + results = self._get_results() + self._write_results(results) + self._compare_results() + finally: + self._cleanup() + + def update_results(self): + """Update the results_true using the current version of OpenMC.""" + try: + self._run_openmc() + self._test_output_created() + self._run_openmc_restart() + results = self._get_results() + self._write_results(results) + self._overwrite_results() + finally: + self._cleanup() + + def _test_output_created(self): + """Make sure statepoint and source files have been created.""" + statepoint = glob.glob(os.path.join(os.getcwd(), self._sp_name)) + assert len(statepoint) == 1, 'Either multiple or no statepoint files ' \ + 'exist.' + assert statepoint[0].endswith('h5'), \ + 'Statepoint file is not a HDF5 file.' + + source = glob.glob(os.path.join(os.getcwd(), 'source.10.mcpl*')) + assert len(source) == 1, 'Either multiple or no source files exist.' + assert source[0].endswith('mcpl') or source[0].endswith('mcpl.gz'), \ + 'Source file is not a MCPL file.' + + def _run_openmc_restart(self): + # Get the name of the source file. + source = glob.glob(os.path.join(os.getcwd(), 'source.10.*')) + + # Write the new settings.xml file. + with open('settings.xml','w') as fh: + fh.write(settings2.format(source[0].split('.')[-1])) + + # Run OpenMC. + self._run_openmc() + + def _cleanup(self): + TestHarness._cleanup(self) + output = glob.glob(os.path.join(os.getcwd(), 'source.*')) + with open('settings.xml','w') as fh: + fh.write(settings1) + + +def test_source_file(): + harness = SourceFileTestHarness('statepoint.10.h5') + harness.main() diff --git a/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat b/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat index f4a0eba737c..6cf3473f9f7 100644 --- a/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat +++ b/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat @@ -1,23 +1,35 @@ - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - 0 - - + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + 0 + + + + + 1 + + + 0.0 2000.0 1000000.0 + + + 1 2 + flux + + + diff --git a/tests/regression_tests/source_parameterized_dlopen/results_true.dat b/tests/regression_tests/source_parameterized_dlopen/results_true.dat index e69de29bb2d..1cddaf802ca 100644 --- a/tests/regression_tests/source_parameterized_dlopen/results_true.dat +++ b/tests/regression_tests/source_parameterized_dlopen/results_true.dat @@ -0,0 +1,5 @@ +tally 1: +1.445856E+04 +2.090732E+07 +0.000000E+00 +0.000000E+00 diff --git a/tests/regression_tests/source_parameterized_dlopen/test.py b/tests/regression_tests/source_parameterized_dlopen/test.py index c613cde4b3b..1cc253528cb 100644 --- a/tests/regression_tests/source_parameterized_dlopen/test.py +++ b/tests/regression_tests/source_parameterized_dlopen/test.py @@ -18,7 +18,7 @@ def compile_source(request): openmc_dir = Path(str(request.config.rootdir)) / 'build' with open('CMakeLists.txt', 'w') as f: f.write(textwrap.dedent(""" - cmake_minimum_required(VERSION 3.3 FATAL_ERROR) + cmake_minimum_required(VERSION 3.10 FATAL_ERROR) project(openmc_sources CXX) add_library(source SHARED parameterized_source_sampling.cpp) find_package(OpenMC REQUIRED HINTS {}) @@ -61,8 +61,17 @@ def model(): model.settings.particles = 1000 model.settings.run_mode = 'fixed source' + tally = openmc.Tally() + mat_filter = openmc.MaterialFilter([natural_lead]) + # energy filter with two bins 0 eV - 1 keV and 1 keV - 1 MeV + # the second bin shouldn't have any results + energy_filter = openmc.EnergyFilter([0.0, 2e3, 1e6]) + tally.filters = [mat_filter, energy_filter] + tally.scores = ['flux'] + model.tallies = openmc.Tallies([tally]) + # custom source from shared library - source = openmc.Source() + source = openmc.CompiledSource() source.library = 'build/libsource.so' source.parameters = '1e3' model.settings.source = source diff --git a/tests/regression_tests/sourcepoint_batch/results_true.dat b/tests/regression_tests/sourcepoint_batch/results_true.dat index 4cd4e623d7d..2770f25ed17 100644 --- a/tests/regression_tests/sourcepoint_batch/results_true.dat +++ b/tests/regression_tests/sourcepoint_batch/results_true.dat @@ -1,3 +1,3 @@ k-combined: -3.003690E-01 3.923324E-03 --5.424825E+00 -4.990262E+00 -6.395029E+00 +3.074376E-01 3.049465E-03 +3.667754E+00 -7.701697E+00 2.213664E+00 diff --git a/tests/regression_tests/sourcepoint_latest/results_true.dat b/tests/regression_tests/sourcepoint_latest/results_true.dat index fe46748c80d..bbf03de9437 100644 --- a/tests/regression_tests/sourcepoint_latest/results_true.dat +++ b/tests/regression_tests/sourcepoint_latest/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.987050E-01 1.827430E-03 +3.070134E-01 3.900396E-03 diff --git a/tests/regression_tests/sourcepoint_restart/results_true.dat b/tests/regression_tests/sourcepoint_restart/results_true.dat index 965dc45b176..b6d85872d1e 100644 --- a/tests/regression_tests/sourcepoint_restart/results_true.dat +++ b/tests/regression_tests/sourcepoint_restart/results_true.dat @@ -1,126 +1,158 @@ k-combined: -2.987050E-01 1.827430E-03 +3.070134E-01 3.900396E-03 tally 1: -1.400000E-02 -5.000000E-05 -5.637968E-03 -7.140222E-06 +1.300000E-02 +4.700000E-05 +5.741381E-03 +9.030024E-06 +0.000000E+00 +0.000000E+00 +3.067112E-04 +9.407179E-08 +1.000000E-03 +1.000000E-06 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 -8.891645E-04 -4.440759E-07 0.000000E+00 0.000000E+00 +2.600000E-02 +1.420000E-04 +1.268989E-02 +3.464490E-05 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 +1.000000E-03 +1.000000E-06 +1.535009E-03 +1.224718E-06 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 +3.200000E-02 +2.760000E-04 +1.248507E-02 +3.714039E-05 0.000000E+00 0.000000E+00 -1.800000E-02 -7.200000E-05 -8.618270E-03 -1.620709E-05 +9.208601E-04 +4.708050E-07 0.000000E+00 0.000000E+00 -2.884266E-04 -8.318989E-08 0.000000E+00 0.000000E+00 -8.903211E-04 -7.926717E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.300000E-02 -2.290000E-04 -1.685675E-02 -6.105228E-05 +1.900000E-02 +7.500000E-05 +8.218811E-03 +1.462963E-05 0.000000E+00 0.000000E+00 -6.007379E-04 -3.608860E-07 +9.070399E-04 +2.743247E-07 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 +9.047443E-04 +8.185622E-07 1.000000E-03 1.000000E-06 -2.884266E-04 -8.318989E-08 -1.500000E-02 -6.300000E-05 -7.665313E-03 -1.617331E-05 0.000000E+00 0.000000E+00 +1.200000E-02 +5.000000E-05 +3.938144E-03 +5.245641E-06 0.000000E+00 0.000000E+00 +3.067112E-04 +9.407179E-08 +1.000000E-03 +1.000000E-06 +5.897816E-04 +3.478423E-07 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 +2.000000E-02 +1.260000E-04 +9.079852E-03 +2.657486E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.100000E-02 -6.900000E-05 -5.663296E-03 -1.118218E-05 0.000000E+00 0.000000E+00 -1.198138E-03 -8.972573E-07 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 -1.000000E-03 -1.000000E-06 -0.000000E+00 -0.000000E+00 -1.300000E-02 -6.300000E-05 -5.687181E-03 -1.121031E-05 -0.000000E+00 -0.000000E+00 -5.963216E-04 -1.778036E-07 0.000000E+00 0.000000E+00 +3.100000E-02 +2.010000E-04 +1.336346E-02 +3.645780E-05 0.000000E+00 0.000000E+00 +2.102710E-03 +1.524522E-06 +1.000000E-03 +1.000000E-06 +9.083133E-04 +4.632477E-07 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 +2.300000E-02 +1.090000E-04 +1.334578E-02 +3.590708E-05 0.000000E+00 0.000000E+00 -1.500000E-02 -6.100000E-05 -1.040584E-02 -2.402892E-05 +6.031628E-04 +3.638054E-07 +1.000000E-03 +1.000000E-06 +1.530605E-03 +1.035684E-06 +2.000000E-03 +2.000000E-06 +6.082927E-04 +1.850231E-07 +1.400000E-02 +4.200000E-05 +7.257468E-03 +1.221578E-05 0.000000E+00 0.000000E+00 -5.879206E-04 -1.728865E-07 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 -8.903211E-04 -7.926717E-07 -1.000000E-03 -1.000000E-06 +8.980536E-04 +4.507660E-07 +2.000000E-03 +4.000000E-06 0.000000E+00 0.000000E+00 -4.200000E-02 -3.880000E-04 -1.781042E-02 -7.329257E-05 +9.000000E-03 +2.700000E-05 +5.193169E-03 +1.187321E-05 0.000000E+00 0.000000E+00 -5.990419E-04 -1.794256E-07 +3.054379E-04 +9.329231E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -129,12 +161,14 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -2.200000E-02 -1.220000E-04 -9.854350E-03 -2.671897E-05 +1.000000E-02 +2.400000E-05 +5.170002E-03 +7.361546E-06 0.000000E+00 0.000000E+00 +6.003287E-04 +1.802529E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -143,12 +177,12 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +2.800000E-02 +1.720000E-04 +1.699195E-02 +6.267008E-05 0.000000E+00 0.000000E+00 -1.200000E-02 -4.400000E-05 -5.595730E-03 -9.201460E-06 0.000000E+00 0.000000E+00 0.000000E+00 @@ -159,240 +193,254 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +2.800000E-02 +1.980000E-04 +1.338750E-02 +4.565234E-05 0.000000E+00 0.000000E+00 -6.000000E-03 -1.000000E-05 -2.391548E-03 -1.608867E-06 +9.183134E-04 +4.676871E-07 +1.000000E-03 +1.000000E-06 +1.537188E-03 +2.362946E-06 +2.000000E-03 +4.000000E-06 0.000000E+00 0.000000E+00 +2.900000E-02 +1.950000E-04 +1.178615E-02 +3.130999E-05 0.000000E+00 0.000000E+00 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 +1.179563E-03 +1.391369E-06 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 -2.600000E-02 -1.920000E-04 -1.211360E-02 -3.507456E-05 +1.500000E-02 +6.500000E-05 +5.706064E-03 +9.729293E-06 0.000000E+00 0.000000E+00 -8.763472E-04 -4.224562E-07 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 -1.799697E-03 -1.260606E-06 -2.000000E-03 -2.000000E-06 0.000000E+00 0.000000E+00 -3.500000E-02 -2.750000E-04 -1.685749E-02 -6.486072E-05 0.000000E+00 0.000000E+00 -9.011069E-04 -8.119936E-07 0.000000E+00 0.000000E+00 -1.494965E-03 -1.523738E-06 3.000000E-03 -5.000000E-06 -2.995479E-04 -8.972896E-08 -2.600000E-02 -1.600000E-04 -1.275573E-02 -3.540061E-05 +9.000000E-06 +1.516642E-03 +1.579637E-06 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 -2.000000E-03 -2.000000E-06 -1.794352E-03 -1.254260E-06 -2.000000E-03 -2.000000E-06 0.000000E+00 0.000000E+00 -1.000000E-02 -3.800000E-05 -4.799173E-03 -8.824671E-06 0.000000E+00 0.000000E+00 +5.897816E-04 +3.478423E-07 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 +2.900000E-02 +1.970000E-04 +1.274851E-02 +3.511219E-05 0.000000E+00 0.000000E+00 +9.057666E-04 +4.601298E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -9.000000E-03 -3.100000E-05 -4.430081E-03 -6.185529E-06 0.000000E+00 0.000000E+00 +1.800000E-02 +7.600000E-05 +8.803642E-03 +1.730938E-05 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -3.291067E-03 -4.033124E-06 -1.000000E-03 -1.000000E-06 -5.971427E-04 -1.782961E-07 -2.800000E-02 -1.660000E-04 -1.217803E-02 -3.047875E-05 +3.074376E-04 +9.451786E-08 0.000000E+00 0.000000E+00 -9.011069E-04 -8.119936E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.900000E-02 +1.830000E-04 +1.245316E-02 +3.378176E-05 0.000000E+00 0.000000E+00 -3.300000E-02 -2.930000E-04 -1.600563E-02 -6.991498E-05 +6.016020E-04 +1.810324E-07 0.000000E+00 0.000000E+00 -5.962677E-04 -1.777713E-07 0.000000E+00 0.000000E+00 -8.958696E-04 -4.469905E-07 -2.000000E-03 -2.000000E-06 0.000000E+00 0.000000E+00 -1.800000E-02 -8.200000E-05 -8.048487E-03 -1.779097E-05 0.000000E+00 0.000000E+00 -2.994940E-04 -8.969666E-08 +1.000000E-03 +1.000000E-06 +6.090190E-04 +1.854692E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +6.031628E-04 +3.638054E-07 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 -3.000000E-03 -5.000000E-06 -2.664923E-03 -2.009218E-06 +1.900000E-02 +8.700000E-05 +8.781239E-03 +1.676750E-05 0.000000E+00 0.000000E+00 +6.128755E-04 +1.878102E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -6.007379E-04 -3.608860E-07 -1.000000E-03 -1.000000E-06 0.000000E+00 0.000000E+00 -1.600000E-02 -7.000000E-05 -7.128932E-03 -1.345969E-05 0.000000E+00 0.000000E+00 -6.007379E-04 -3.608860E-07 +3.500000E-02 +2.930000E-04 +1.372494E-02 +4.750881E-05 +0.000000E+00 +0.000000E+00 +9.090396E-04 +2.755502E-07 0.000000E+00 0.000000E+00 +5.897816E-04 +3.478423E-07 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 +3.700000E-02 +3.270000E-04 +1.492073E-02 +5.134793E-05 0.000000E+00 0.000000E+00 +6.134225E-04 +3.762872E-07 +1.000000E-03 +1.000000E-06 +3.074376E-04 +9.451786E-08 +1.000000E-03 +1.000000E-06 +6.148751E-04 +3.780714E-07 +3.500000E-02 +2.810000E-04 +1.728232E-02 +6.621096E-05 0.000000E+00 0.000000E+00 -3.200000E-02 -2.360000E-04 -1.452343E-02 -4.653003E-05 +1.214477E-03 +3.688425E-07 0.000000E+00 0.000000E+00 -2.995479E-04 -8.972896E-08 +1.481145E-03 +1.482321E-06 +1.000000E-03 +1.000000E-06 +3.015814E-04 +9.095135E-08 +8.000000E-03 +1.800000E-05 +3.359923E-03 +3.081200E-06 0.000000E+00 0.000000E+00 +3.067112E-04 +9.407179E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.000000E-02 -2.160000E-04 -1.327819E-02 -4.230384E-05 0.000000E+00 0.000000E+00 -8.958157E-04 -2.675003E-07 +7.000000E-03 +1.500000E-05 +3.660087E-03 +3.561493E-06 0.000000E+00 0.000000E+00 -5.768531E-04 -3.327596E-07 +9.203130E-04 +4.713637E-07 1.000000E-03 1.000000E-06 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 -2.100000E-02 -1.150000E-04 -1.005499E-02 -2.671941E-05 0.000000E+00 0.000000E+00 -1.192535E-03 -7.110852E-07 +3.500000E-02 +2.630000E-04 +1.425810E-02 +4.231681E-05 +0.000000E+00 0.000000E+00 +1.516059E-03 +4.597939E-07 0.000000E+00 -2.995479E-04 -8.972896E-08 +0.000000E+00 +1.221752E-03 +1.492677E-06 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 -1.200000E-02 -4.600000E-05 -6.223479E-03 -9.948264E-06 +2.300000E-02 +1.110000E-04 +1.184871E-02 +2.918189E-05 0.000000E+00 0.000000E+00 -2.884266E-04 -8.318989E-08 +6.016020E-04 +1.810324E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -401,94 +449,62 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.100000E-02 -3.500000E-05 -5.341464E-03 -7.422119E-06 +1.600000E-02 +6.600000E-05 +7.879913E-03 +1.566560E-05 0.000000E+00 0.000000E+00 +9.039098E-04 +2.724298E-07 0.000000E+00 0.000000E+00 +3.067112E-04 +9.407179E-08 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 +9.000000E-03 +1.900000E-05 +4.256120E-03 +4.431220E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.700000E-02 -8.500000E-05 -7.089406E-03 -1.347399E-05 0.000000E+00 0.000000E+00 -5.768531E-04 -3.327596E-07 0.000000E+00 0.000000E+00 -8.764011E-04 -4.224885E-07 -1.000000E-03 -1.000000E-06 0.000000E+00 0.000000E+00 -2.300000E-02 -1.430000E-04 -1.185149E-02 -3.938904E-05 +6.000000E-03 +1.200000E-05 +2.739774E-03 +2.333986E-06 0.000000E+00 0.000000E+00 -2.080112E-03 -1.332746E-06 0.000000E+00 0.000000E+00 -1.198138E-03 -8.972573E-07 -1.000000E-03 -1.000000E-06 -5.989880E-04 -3.587866E-07 -3.000000E-02 -2.020000E-04 -1.190088E-02 -2.985574E-05 0.000000E+00 0.000000E+00 -5.971427E-04 -1.782961E-07 0.000000E+00 0.000000E+00 -2.651470E-03 -2.516819E-06 -4.000000E-03 -6.000000E-06 0.000000E+00 0.000000E+00 -1.200000E-02 -3.800000E-05 -5.332038E-03 -7.371181E-06 0.000000E+00 0.000000E+00 -3.003690E-04 -9.022151E-08 +1.400000E-02 +6.800000E-05 +7.182805E-03 +1.822340E-05 0.000000E+00 0.000000E+00 -2.995479E-04 -8.972896E-08 -1.000000E-03 -1.000000E-06 -2.995479E-04 -8.972896E-08 -3.000000E-03 -3.000000E-06 -2.087327E-03 -1.859777E-06 0.000000E+00 0.000000E+00 -2.967737E-04 -8.807464E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -497,62 +513,58 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -3.100000E-02 -2.510000E-04 -1.448290E-02 -4.809715E-05 +1.500000E-02 +6.300000E-05 +5.734575E-03 +9.207711E-06 0.000000E+00 0.000000E+00 -1.162053E-03 -8.367836E-07 +6.070193E-04 +1.842437E-07 0.000000E+00 0.000000E+00 -1.475335E-03 -1.140030E-06 +8.846723E-04 +7.826452E-07 1.000000E-03 1.000000E-06 -2.884266E-04 -8.318989E-08 -3.200000E-02 -2.220000E-04 -1.427003E-02 -4.164437E-05 0.000000E+00 0.000000E+00 -8.855692E-04 -2.614860E-07 +2.000000E-02 +8.800000E-05 +9.416733E-03 +2.020354E-05 0.000000E+00 0.000000E+00 +6.003287E-04 +1.802529E-07 0.000000E+00 0.000000E+00 +6.031628E-04 +3.638054E-07 0.000000E+00 0.000000E+00 +3.015814E-04 +9.095135E-08 +7.000000E-03 +1.500000E-05 +2.413278E-03 +1.439032E-06 0.000000E+00 0.000000E+00 -1.000000E-02 -2.400000E-05 -3.864325E-03 -4.535592E-06 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 -2.967737E-04 -8.807464E-08 0.000000E+00 0.000000E+00 -2.065114E-03 -1.468511E-06 -3.000000E-03 -3.000000E-06 -0.000000E+00 -0.000000E+00 -1.000000E-03 -1.000000E-06 -1.170401E-03 -6.850581E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +7.000000E-03 +1.500000E-05 +4.226919E-03 +4.173413E-06 0.000000E+00 0.000000E+00 0.000000E+00 @@ -561,142 +573,146 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-02 -3.000000E-05 -4.121850E-03 -5.320749E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.300000E-02 +1.590000E-04 +1.125341E-02 +3.890966E-05 0.000000E+00 0.000000E+00 +5.964722E-04 +1.779119E-07 0.000000E+00 0.000000E+00 +8.846723E-04 +7.826452E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.100000E-02 -2.170000E-04 -1.483273E-02 -4.914676E-05 +3.200000E-02 +2.260000E-04 +1.458976E-02 +4.416780E-05 0.000000E+00 0.000000E+00 -8.763472E-04 -4.224562E-07 +1.814806E-03 +9.096012E-07 +1.000000E-03 +1.000000E-06 +6.031628E-04 +3.638054E-07 0.000000E+00 0.000000E+00 -3.003690E-04 -9.022151E-08 0.000000E+00 0.000000E+00 +3.100000E-02 +2.050000E-04 +1.241089E-02 +3.545088E-05 0.000000E+00 0.000000E+00 -3.300000E-02 -2.310000E-04 -1.399272E-02 -4.084044E-05 +1.515620E-03 +1.191731E-06 0.000000E+00 0.000000E+00 -1.499382E-03 -1.168447E-06 -1.000000E-03 -1.000000E-06 -8.930414E-04 -4.419952E-07 +6.121491E-04 +1.873641E-07 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 -1.600000E-02 -7.000000E-05 -7.077099E-03 -1.371332E-05 +1.000000E-02 +2.600000E-05 +3.936862E-03 +3.749154E-06 0.000000E+00 0.000000E+00 -2.994940E-04 -8.969666E-08 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 -1.497740E-03 -2.243224E-06 -2.000000E-03 -4.000000E-06 0.000000E+00 0.000000E+00 -1.000000E-02 -3.400000E-05 -3.528506E-03 -4.251243E-06 0.000000E+00 0.000000E+00 -5.879206E-04 -1.728865E-07 0.000000E+00 0.000000E+00 +1.100000E-02 +4.700000E-05 +5.084641E-03 +9.248485E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -4.000000E-03 -6.000000E-06 -9.002859E-04 -4.506150E-07 0.000000E+00 0.000000E+00 -8.939164E-04 -4.425201E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.500000E-02 +1.770000E-04 +1.021860E-02 +3.099521E-05 0.000000E+00 0.000000E+00 +3.074376E-04 +9.451786E-08 0.000000E+00 0.000000E+00 +9.086007E-04 +4.570977E-07 +2.000000E-03 +2.000000E-06 +3.054379E-04 +9.329231E-08 1.500000E-02 -5.500000E-05 -7.400046E-03 -1.140009E-05 +5.300000E-05 +7.584986E-03 +1.188822E-05 0.000000E+00 0.000000E+00 -5.990419E-04 -1.794256E-07 +6.128755E-04 +1.878102E-07 +1.000000E-03 +1.000000E-06 +6.108758E-04 +3.731692E-07 0.000000E+00 0.000000E+00 -8.903211E-04 -7.926717E-07 0.000000E+00 0.000000E+00 +1.800000E-02 +8.600000E-05 +6.672457E-03 +1.369871E-05 0.000000E+00 0.000000E+00 -1.800000E-02 -7.400000E-05 -7.695028E-03 -1.396744E-05 +6.141488E-04 +1.885896E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -5.990959E-04 -3.589159E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.400000E-02 -1.260000E-04 -1.220791E-02 -3.565074E-05 +1.100000E-02 +2.700000E-05 +3.927884E-03 +3.728010E-06 0.000000E+00 0.000000E+00 -2.995479E-04 -8.972896E-08 +3.074376E-04 +9.451786E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -705,22 +721,12 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -9.000000E-03 -2.500000E-05 -3.572884E-03 -4.101061E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.935474E-04 -3.522985E-07 -1.000000E-03 -1.000000E-06 -2.967737E-04 -8.807464E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -731,52 +737,60 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +9.000000E-03 +1.900000E-05 +4.217645E-03 +4.306910E-06 0.000000E+00 0.000000E+00 +6.128755E-04 +1.878102E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-02 -3.800000E-05 -5.382607E-03 -1.128619E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -2.994940E-04 -8.969666E-08 +1.700000E-02 +7.700000E-05 +7.235504E-03 +1.301737E-05 0.000000E+00 0.000000E+00 +3.054379E-04 +9.329231E-08 +0.000000E+00 +0.000000E+00 +1.531736E-03 +8.439742E-07 +3.000000E-03 +3.000000E-06 +3.074376E-04 +9.451786E-08 +9.000000E-03 +1.900000E-05 +3.018298E-03 +2.174671E-06 0.000000E+00 0.000000E+00 -1.200000E-02 -4.600000E-05 -6.554978E-03 -9.995681E-06 0.000000E+00 0.000000E+00 -2.884266E-04 -8.318989E-08 0.000000E+00 0.000000E+00 -2.994940E-04 -8.969666E-08 +6.141488E-04 +1.885896E-07 +1.000000E-03 +1.000000E-06 +3.074376E-04 +9.451786E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -7.000000E-03 -1.100000E-05 -3.868525E-03 -3.829197E-06 0.000000E+00 0.000000E+00 -5.935474E-04 -3.522985E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -785,12 +799,12 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -5.989880E-04 -3.587866E-07 0.000000E+00 0.000000E+00 +2.000000E-03 +2.000000E-06 +1.203204E-03 +7.241295E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -801,12 +815,12 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -2.994940E-04 -8.969666E-08 0.000000E+00 0.000000E+00 +7.000000E-03 +1.500000E-05 +4.818843E-03 +6.474375E-06 0.000000E+00 0.000000E+00 0.000000E+00 @@ -817,60 +831,48 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.100000E-02 -3.100000E-05 -4.132972E-03 -4.495389E-06 0.000000E+00 0.000000E+00 -2.967737E-04 -8.807464E-08 +2.400000E-02 +1.180000E-04 +1.088639E-02 +2.567229E-05 0.000000E+00 0.000000E+00 -6.007379E-04 -3.608860E-07 -1.000000E-03 -1.000000E-06 -2.967737E-04 -8.807464E-08 -2.000000E-02 -9.200000E-05 -8.597951E-03 -1.801722E-05 +3.067112E-04 +9.407179E-08 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +1.300000E-02 +5.100000E-05 +6.002667E-03 +1.149916E-05 0.000000E+00 0.000000E+00 -1.200000E-02 -3.200000E-05 -6.509749E-03 -9.403130E-06 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 -3.003690E-04 -9.022151E-08 +3.067112E-04 +9.407179E-08 0.000000E+00 0.000000E+00 -5.990959E-04 -3.589159E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -2.884266E-04 -8.318989E-08 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -895,54 +897,52 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +1.300000E-02 +4.700000E-05 +5.486562E-03 +7.965488E-06 0.000000E+00 0.000000E+00 -7.000000E-03 -2.100000E-05 -3.890163E-03 -6.545535E-06 +3.054379E-04 +9.329231E-08 0.000000E+00 0.000000E+00 -2.995479E-04 -8.972896E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +8.000000E-03 +1.800000E-05 +3.334317E-03 +3.609712E-06 0.000000E+00 0.000000E+00 -1.300000E-02 -4.300000E-05 -6.485840E-03 -1.112994E-05 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.000000E-02 +1.080000E-04 +9.741552E-03 +2.552400E-05 0.000000E+00 0.000000E+00 -1.500000E-02 -4.900000E-05 -7.442524E-03 -1.164759E-05 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 -2.994940E-04 -8.969666E-08 +1.800986E-03 +1.622276E-06 1.000000E-03 1.000000E-06 -5.768531E-04 -3.327596E-07 -0.000000E+00 -0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -962,11 +962,11 @@ tally 1: 0.000000E+00 0.000000E+00 tally 2: -5.649702E-01 -6.385502E-02 -6.158199E-01 -7.586795E-02 -3.579551E+00 -2.563396E+00 -3.982345E+01 -3.172536E+02 +5.818100E-01 +6.772558E-02 +6.344749E-01 +8.054355E-02 +3.690180E+00 +2.724752E+00 +4.102635E+01 +3.367908E+02 diff --git a/tests/regression_tests/statepoint_batch/results_true.dat b/tests/regression_tests/statepoint_batch/results_true.dat index cde417d0e68..f5c855d7778 100644 --- a/tests/regression_tests/statepoint_batch/results_true.dat +++ b/tests/regression_tests/statepoint_batch/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.985923E-01 2.864193E-03 +3.048864E-01 1.689118E-03 diff --git a/tests/regression_tests/statepoint_restart/results_true.dat b/tests/regression_tests/statepoint_restart/results_true.dat index 0809b902e4a..aebc971f49c 100644 --- a/tests/regression_tests/statepoint_restart/results_true.dat +++ b/tests/regression_tests/statepoint_restart/results_true.dat @@ -1,95 +1,132 @@ k-combined: -2.987050E-01 1.827430E-03 +3.070134E-01 3.900396E-03 tally 1: -1.400000E-02 -5.000000E-05 -1.400000E-02 -5.000000E-05 -5.637968E-03 -7.140222E-06 +1.300000E-02 +4.700000E-05 +1.300000E-02 +4.700000E-05 +5.741381E-03 +9.030024E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.891645E-04 -4.440759E-07 +3.067112E-04 +9.407179E-08 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.600000E-02 +1.420000E-04 +2.600000E-02 +1.420000E-04 +1.268989E-02 +3.464490E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +1.535009E-03 +1.224718E-06 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 -1.800000E-02 -7.200000E-05 -1.800000E-02 -7.200000E-05 -8.618270E-03 -1.620709E-05 +3.200000E-02 +2.760000E-04 +3.200000E-02 +2.760000E-04 +1.248507E-02 +3.714039E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.884266E-04 -8.318989E-08 +9.208601E-04 +4.708050E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.903211E-04 -7.926717E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.300000E-02 -2.290000E-04 -3.300000E-02 -2.290000E-04 -1.685675E-02 -6.105228E-05 0.000000E+00 0.000000E+00 +1.900000E-02 +7.500000E-05 +1.900000E-02 +7.500000E-05 +8.218811E-03 +1.462963E-05 0.000000E+00 0.000000E+00 -6.007379E-04 -3.608860E-07 0.000000E+00 0.000000E+00 +9.070399E-04 +2.743247E-07 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 +0.000000E+00 +0.000000E+00 +9.047443E-04 +8.185622E-07 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 -2.884266E-04 -8.318989E-08 -1.500000E-02 -6.300000E-05 -1.500000E-02 -6.300000E-05 -7.665313E-03 -1.617331E-05 -0.000000E+00 0.000000E+00 0.000000E+00 +1.200000E-02 +5.000000E-05 +1.200000E-02 +5.000000E-05 +3.938144E-03 +5.245641E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +3.067112E-04 +9.407179E-08 +1.000000E-03 +1.000000E-06 +2.000000E-03 +4.000000E-06 +5.897816E-04 +3.478423E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 +2.000000E-02 +1.260000E-04 +2.000000E-02 +1.260000E-04 +9.079852E-03 +2.657486E-05 0.000000E+00 0.000000E+00 0.000000E+00 @@ -97,90 +134,103 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.100000E-02 -6.900000E-05 -1.100000E-02 -6.900000E-05 -5.663296E-03 -1.118218E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.198138E-03 -8.972573E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 0.000000E+00 0.000000E+00 -1.300000E-02 -6.300000E-05 -1.300000E-02 -6.300000E-05 -5.687181E-03 -1.121031E-05 0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 -5.963216E-04 -1.778036E-07 +3.100000E-02 +2.010000E-04 +3.100000E-02 +2.010000E-04 +1.336346E-02 +3.645780E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.102710E-03 +1.524522E-06 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +9.083133E-04 +4.632477E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 +2.300000E-02 +1.090000E-04 +2.300000E-02 +1.090000E-04 +1.334578E-02 +3.590708E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +6.031628E-04 +3.638054E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +1.530605E-03 +1.035684E-06 +2.000000E-03 +2.000000E-06 +2.000000E-03 +2.000000E-06 +6.082927E-04 +1.850231E-07 +1.400000E-02 +4.200000E-05 +1.400000E-02 +4.200000E-05 +7.257468E-03 +1.221578E-05 0.000000E+00 0.000000E+00 -1.500000E-02 -6.100000E-05 -1.500000E-02 -6.100000E-05 -1.040584E-02 -2.402892E-05 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 -5.879206E-04 -1.728865E-07 0.000000E+00 0.000000E+00 +8.980536E-04 +4.507660E-07 +2.000000E-03 +4.000000E-06 +2.000000E-03 +4.000000E-06 0.000000E+00 0.000000E+00 -8.903211E-04 -7.926717E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 +9.000000E-03 +2.700000E-05 +9.000000E-03 +2.700000E-05 +5.193169E-03 +1.187321E-05 0.000000E+00 0.000000E+00 -4.200000E-02 -3.880000E-04 -4.200000E-02 -3.880000E-04 -1.781042E-02 -7.329257E-05 0.000000E+00 0.000000E+00 +3.054379E-04 +9.329231E-08 0.000000E+00 0.000000E+00 -5.990419E-04 -1.794256E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -191,16 +241,18 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +1.000000E-02 +2.400000E-05 +1.000000E-02 +2.400000E-05 +5.170002E-03 +7.361546E-06 0.000000E+00 0.000000E+00 -2.200000E-02 -1.220000E-04 -2.200000E-02 -1.220000E-04 -9.854350E-03 -2.671897E-05 0.000000E+00 0.000000E+00 +6.003287E-04 +1.802529E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -213,16 +265,16 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +2.800000E-02 +1.720000E-04 +2.800000E-02 +1.720000E-04 +1.699195E-02 +6.267008E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.200000E-02 -4.400000E-05 -1.200000E-02 -4.400000E-05 -5.595730E-03 -9.201460E-06 0.000000E+00 0.000000E+00 0.000000E+00 @@ -237,122 +289,114 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +2.800000E-02 +1.980000E-04 +2.800000E-02 +1.980000E-04 +1.338750E-02 +4.565234E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -6.000000E-03 -1.000000E-05 -6.000000E-03 -1.000000E-05 -2.391548E-03 -1.608867E-06 +9.183134E-04 +4.676871E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +1.537188E-03 +2.362946E-06 +2.000000E-03 +4.000000E-06 +2.000000E-03 +4.000000E-06 0.000000E+00 0.000000E+00 +2.900000E-02 +1.950000E-04 +2.900000E-02 +1.950000E-04 +1.178615E-02 +3.130999E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 +1.179563E-03 +1.391369E-06 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 -2.600000E-02 -1.920000E-04 -2.600000E-02 -1.920000E-04 -1.211360E-02 -3.507456E-05 -0.000000E+00 -0.000000E+00 +1.500000E-02 +6.500000E-05 +1.500000E-02 +6.500000E-05 +5.706064E-03 +9.729293E-06 0.000000E+00 0.000000E+00 -8.763472E-04 -4.224562E-07 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 -1.799697E-03 -1.260606E-06 -2.000000E-03 -2.000000E-06 -2.000000E-03 -2.000000E-06 0.000000E+00 0.000000E+00 -3.500000E-02 -2.750000E-04 -3.500000E-02 -2.750000E-04 -1.685749E-02 -6.486072E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -9.011069E-04 -8.119936E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.494965E-03 -1.523738E-06 3.000000E-03 -5.000000E-06 +9.000000E-06 3.000000E-03 -5.000000E-06 -2.995479E-04 -8.972896E-08 -2.600000E-02 -1.600000E-04 -2.600000E-02 -1.600000E-04 -1.275573E-02 -3.540061E-05 +9.000000E-06 +1.516642E-03 +1.579637E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 -2.000000E-03 -2.000000E-06 -2.000000E-03 -2.000000E-06 -1.794352E-03 -1.254260E-06 -2.000000E-03 -2.000000E-06 -2.000000E-03 -2.000000E-06 0.000000E+00 0.000000E+00 -1.000000E-02 -3.800000E-05 -1.000000E-02 -3.800000E-05 -4.799173E-03 -8.824671E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +5.897816E-04 +3.478423E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 +2.900000E-02 +1.970000E-04 +2.900000E-02 +1.970000E-04 +1.274851E-02 +3.511219E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +9.057666E-04 +4.601298E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -361,42 +405,24 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -9.000000E-03 -3.100000E-05 -9.000000E-03 -3.100000E-05 -4.430081E-03 -6.185529E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +1.800000E-02 +7.600000E-05 +1.800000E-02 +7.600000E-05 +8.803642E-03 +1.730938E-05 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -2.000000E-03 -4.000000E-06 -3.291067E-03 -4.033124E-06 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -5.971427E-04 -1.782961E-07 -2.800000E-02 -1.660000E-04 -2.800000E-02 -1.660000E-04 -1.217803E-02 -3.047875E-05 0.000000E+00 0.000000E+00 +3.074376E-04 +9.451786E-08 0.000000E+00 0.000000E+00 -9.011069E-04 -8.119936E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -407,44 +433,36 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +2.900000E-02 +1.830000E-04 +2.900000E-02 +1.830000E-04 +1.245316E-02 +3.378176E-05 0.000000E+00 0.000000E+00 -3.300000E-02 -2.930000E-04 -3.300000E-02 -2.930000E-04 -1.600563E-02 -6.991498E-05 0.000000E+00 0.000000E+00 +6.016020E-04 +1.810324E-07 0.000000E+00 0.000000E+00 -5.962677E-04 -1.777713E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.958696E-04 -4.469905E-07 -2.000000E-03 -2.000000E-06 -2.000000E-03 -2.000000E-06 0.000000E+00 0.000000E+00 -1.800000E-02 -8.200000E-05 -1.800000E-02 -8.200000E-05 -8.048487E-03 -1.779097E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.994940E-04 -8.969666E-08 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +6.090190E-04 +1.854692E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -455,72 +473,122 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +6.031628E-04 +3.638054E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 -3.000000E-03 -5.000000E-06 -3.000000E-03 -5.000000E-06 -2.664923E-03 -2.009218E-06 +1.900000E-02 +8.700000E-05 +1.900000E-02 +8.700000E-05 +8.781239E-03 +1.676750E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +6.128755E-04 +1.878102E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -6.007379E-04 -3.608860E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 0.000000E+00 0.000000E+00 -1.600000E-02 -7.000000E-05 -1.600000E-02 -7.000000E-05 -7.128932E-03 -1.345969E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -6.007379E-04 -3.608860E-07 +3.500000E-02 +2.930000E-04 +3.500000E-02 +2.930000E-04 +1.372494E-02 +4.750881E-05 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.090396E-04 +2.755502E-07 +0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +5.897816E-04 +3.478423E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +0.000000E+00 0.000000E+00 +3.700000E-02 +3.270000E-04 +3.700000E-02 +3.270000E-04 +1.492073E-02 +5.134793E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +6.134225E-04 +3.762872E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +3.074376E-04 +9.451786E-08 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +6.148751E-04 +3.780714E-07 +3.500000E-02 +2.810000E-04 +3.500000E-02 +2.810000E-04 +1.728232E-02 +6.621096E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.200000E-02 -2.360000E-04 -3.200000E-02 -2.360000E-04 -1.452343E-02 -4.653003E-05 +1.214477E-03 +3.688425E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.995479E-04 -8.972896E-08 +1.481145E-03 +1.482321E-06 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +3.015814E-04 +9.095135E-08 +8.000000E-03 +1.800000E-05 +8.000000E-03 +1.800000E-05 +3.359923E-03 +3.081200E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +3.067112E-04 +9.407179E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -529,71 +597,70 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -3.000000E-02 -2.160000E-04 -3.000000E-02 -2.160000E-04 -1.327819E-02 -4.230384E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.958157E-04 -2.675003E-07 +7.000000E-03 +1.500000E-05 +7.000000E-03 +1.500000E-05 +3.660087E-03 +3.561493E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.768531E-04 -3.327596E-07 +9.203130E-04 +4.713637E-07 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 -2.100000E-02 -1.150000E-04 -2.100000E-02 -1.150000E-04 -1.005499E-02 -2.671941E-05 -0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.192535E-03 -7.110852E-07 0.000000E+00 +3.500000E-02 +2.630000E-04 +3.500000E-02 +2.630000E-04 +1.425810E-02 +4.231681E-05 0.000000E+00 0.000000E+00 0.000000E+00 -2.995479E-04 -8.972896E-08 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 0.000000E+00 +1.516059E-03 +4.597939E-07 0.000000E+00 -1.200000E-02 -4.600000E-05 -1.200000E-02 -4.600000E-05 -6.223479E-03 -9.948264E-06 0.000000E+00 0.000000E+00 0.000000E+00 +1.221752E-03 +1.492677E-06 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 0.000000E+00 -2.884266E-04 -8.318989E-08 0.000000E+00 +2.300000E-02 +1.110000E-04 +2.300000E-02 +1.110000E-04 +1.184871E-02 +2.918189E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +6.016020E-04 +1.810324E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -601,138 +668,95 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.100000E-02 -3.500000E-05 -1.100000E-02 -3.500000E-05 -5.341464E-03 -7.422119E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +1.600000E-02 +6.600000E-05 +1.600000E-02 +6.600000E-05 +7.879913E-03 +1.566560E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +9.039098E-04 +2.724298E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +3.067112E-04 +9.407179E-08 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 0.000000E+00 0.000000E+00 +9.000000E-03 +1.900000E-05 +9.000000E-03 +1.900000E-05 +4.256120E-03 +4.431220E-06 0.000000E+00 0.000000E+00 0.000000E+00 -1.700000E-02 -8.500000E-05 -1.700000E-02 -8.500000E-05 -7.089406E-03 -1.347399E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.768531E-04 -3.327596E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.764011E-04 -4.224885E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 0.000000E+00 0.000000E+00 -2.300000E-02 -1.430000E-04 -2.300000E-02 -1.430000E-04 -1.185149E-02 -3.938904E-05 -0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.080112E-03 -1.332746E-06 0.000000E+00 0.000000E+00 +6.000000E-03 +1.200000E-05 +6.000000E-03 +1.200000E-05 +2.739774E-03 +2.333986E-06 0.000000E+00 0.000000E+00 -1.198138E-03 -8.972573E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -5.989880E-04 -3.587866E-07 -3.000000E-02 -2.020000E-04 -3.000000E-02 -2.020000E-04 -1.190088E-02 -2.985574E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.971427E-04 -1.782961E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.651470E-03 -2.516819E-06 -4.000000E-03 -6.000000E-06 -4.000000E-03 -6.000000E-06 0.000000E+00 0.000000E+00 -1.200000E-02 -3.800000E-05 -1.200000E-02 -3.800000E-05 -5.332038E-03 -7.371181E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.003690E-04 -9.022151E-08 0.000000E+00 0.000000E+00 +1.400000E-02 +6.800000E-05 +1.400000E-02 +6.800000E-05 +7.182805E-03 +1.822340E-05 0.000000E+00 0.000000E+00 -2.995479E-04 -8.972896E-08 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.995479E-04 -8.972896E-08 -3.000000E-03 -3.000000E-06 -3.000000E-03 -3.000000E-06 -2.087327E-03 -1.859777E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.967737E-04 -8.807464E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -745,88 +769,84 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -3.100000E-02 -2.510000E-04 -3.100000E-02 -2.510000E-04 -1.448290E-02 -4.809715E-05 +1.500000E-02 +6.300000E-05 +1.500000E-02 +6.300000E-05 +5.734575E-03 +9.207711E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.162053E-03 -8.367836E-07 +6.070193E-04 +1.842437E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.475335E-03 -1.140030E-06 +8.846723E-04 +7.826452E-07 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 -2.884266E-04 -8.318989E-08 -3.200000E-02 -2.220000E-04 -3.200000E-02 -2.220000E-04 -1.427003E-02 -4.164437E-05 0.000000E+00 0.000000E+00 +2.000000E-02 +8.800000E-05 +2.000000E-02 +8.800000E-05 +9.416733E-03 +2.020354E-05 0.000000E+00 0.000000E+00 -8.855692E-04 -2.614860E-07 0.000000E+00 0.000000E+00 +6.003287E-04 +1.802529E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +6.031628E-04 +3.638054E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +3.015814E-04 +9.095135E-08 +7.000000E-03 +1.500000E-05 +7.000000E-03 +1.500000E-05 +2.413278E-03 +1.439032E-06 0.000000E+00 0.000000E+00 -1.000000E-02 -2.400000E-05 -1.000000E-02 -2.400000E-05 -3.864325E-03 -4.535592E-06 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 -2.967737E-04 -8.807464E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.065114E-03 -1.468511E-06 -3.000000E-03 -3.000000E-06 -3.000000E-03 -3.000000E-06 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -1.170401E-03 -6.850581E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +7.000000E-03 +1.500000E-05 +7.000000E-03 +1.500000E-05 +4.226919E-03 +4.173413E-06 0.000000E+00 0.000000E+00 0.000000E+00 @@ -841,116 +861,112 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-02 -3.000000E-05 -1.000000E-02 -3.000000E-05 -4.121850E-03 -5.320749E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.300000E-02 +1.590000E-04 +2.300000E-02 +1.590000E-04 +1.125341E-02 +3.890966E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +5.964722E-04 +1.779119E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +8.846723E-04 +7.826452E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.100000E-02 -2.170000E-04 -3.100000E-02 -2.170000E-04 -1.483273E-02 -4.914676E-05 +3.200000E-02 +2.260000E-04 +3.200000E-02 +2.260000E-04 +1.458976E-02 +4.416780E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.763472E-04 -4.224562E-07 +1.814806E-03 +9.096012E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +6.031628E-04 +3.638054E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.003690E-04 -9.022151E-08 0.000000E+00 0.000000E+00 +3.100000E-02 +2.050000E-04 +3.100000E-02 +2.050000E-04 +1.241089E-02 +3.545088E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -3.300000E-02 -2.310000E-04 -3.300000E-02 -2.310000E-04 -1.399272E-02 -4.084044E-05 +1.515620E-03 +1.191731E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.499382E-03 -1.168447E-06 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -8.930414E-04 -4.419952E-07 +6.121491E-04 +1.873641E-07 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 0.000000E+00 0.000000E+00 -1.600000E-02 -7.000000E-05 -1.600000E-02 -7.000000E-05 -7.077099E-03 -1.371332E-05 +1.000000E-02 +2.600000E-05 +1.000000E-02 +2.600000E-05 +3.936862E-03 +3.749154E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.994940E-04 -8.969666E-08 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.497740E-03 -2.243224E-06 -2.000000E-03 -4.000000E-06 -2.000000E-03 -4.000000E-06 0.000000E+00 0.000000E+00 -1.000000E-02 -3.400000E-05 -1.000000E-02 -3.400000E-05 -3.528506E-03 -4.251243E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.879206E-04 -1.728865E-07 0.000000E+00 0.000000E+00 +1.100000E-02 +4.700000E-05 +1.100000E-02 +4.700000E-05 +5.084641E-03 +9.248485E-06 0.000000E+00 0.000000E+00 0.000000E+00 @@ -961,90 +977,98 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -4.000000E-03 -6.000000E-06 -4.000000E-03 -6.000000E-06 -9.002859E-04 -4.506150E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.939164E-04 -4.425201E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.500000E-02 +1.770000E-04 +2.500000E-02 +1.770000E-04 +1.021860E-02 +3.099521E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +3.074376E-04 +9.451786E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +9.086007E-04 +4.570977E-07 +2.000000E-03 +2.000000E-06 +2.000000E-03 +2.000000E-06 +3.054379E-04 +9.329231E-08 1.500000E-02 -5.500000E-05 +5.300000E-05 1.500000E-02 -5.500000E-05 -7.400046E-03 -1.140009E-05 +5.300000E-05 +7.584986E-03 +1.188822E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.990419E-04 -1.794256E-07 +6.128755E-04 +1.878102E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +6.108758E-04 +3.731692E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -8.903211E-04 -7.926717E-07 0.000000E+00 0.000000E+00 +1.800000E-02 +8.600000E-05 +1.800000E-02 +8.600000E-05 +6.672457E-03 +1.369871E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.800000E-02 -7.400000E-05 -1.800000E-02 -7.400000E-05 -7.695028E-03 -1.396744E-05 +6.141488E-04 +1.885896E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -5.990959E-04 -3.589159E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.400000E-02 -1.260000E-04 -2.400000E-02 -1.260000E-04 -1.220791E-02 -3.565074E-05 +1.100000E-02 +2.700000E-05 +1.100000E-02 +2.700000E-05 +3.927884E-03 +3.728010E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.995479E-04 -8.972896E-08 +3.074376E-04 +9.451786E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1057,12 +1081,6 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -9.000000E-03 -2.500000E-05 -9.000000E-03 -2.500000E-05 -3.572884E-03 -4.101061E-06 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1073,14 +1091,6 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -5.935474E-04 -3.522985E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.967737E-04 -8.807464E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1095,76 +1105,88 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +9.000000E-03 +1.900000E-05 +9.000000E-03 +1.900000E-05 +4.217645E-03 +4.306910E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +6.128755E-04 +1.878102E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-02 -3.800000E-05 -1.000000E-02 -3.800000E-05 -5.382607E-03 -1.128619E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.994940E-04 -8.969666E-08 +1.700000E-02 +7.700000E-05 +1.700000E-02 +7.700000E-05 +7.235504E-03 +1.301737E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +3.054379E-04 +9.329231E-08 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.531736E-03 +8.439742E-07 +3.000000E-03 +3.000000E-06 +3.000000E-03 +3.000000E-06 +3.074376E-04 +9.451786E-08 +9.000000E-03 +1.900000E-05 +9.000000E-03 +1.900000E-05 +3.018298E-03 +2.174671E-06 0.000000E+00 0.000000E+00 -1.200000E-02 -4.600000E-05 -1.200000E-02 -4.600000E-05 -6.554978E-03 -9.995681E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.884266E-04 -8.318989E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.994940E-04 -8.969666E-08 +6.141488E-04 +1.885896E-07 +1.000000E-03 +1.000000E-06 +1.000000E-03 +1.000000E-06 +3.074376E-04 +9.451786E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -7.000000E-03 -1.100000E-05 -7.000000E-03 -1.100000E-05 -3.868525E-03 -3.829197E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.935474E-04 -3.522985E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1177,14 +1199,14 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -5.989880E-04 -3.587866E-07 0.000000E+00 0.000000E+00 +2.000000E-03 +2.000000E-06 +2.000000E-03 +2.000000E-06 +1.203204E-03 +7.241295E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1201,14 +1223,14 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.994940E-04 -8.969666E-08 0.000000E+00 0.000000E+00 +7.000000E-03 +1.500000E-05 +7.000000E-03 +1.500000E-05 +4.818843E-03 +6.474375E-06 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1225,86 +1247,68 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 -1.100000E-02 -3.100000E-05 -1.100000E-02 -3.100000E-05 -4.132972E-03 -4.495389E-06 0.000000E+00 0.000000E+00 +2.400000E-02 +1.180000E-04 +2.400000E-02 +1.180000E-04 +1.088639E-02 +2.567229E-05 0.000000E+00 0.000000E+00 -2.967737E-04 -8.807464E-08 0.000000E+00 0.000000E+00 +3.067112E-04 +9.407179E-08 0.000000E+00 0.000000E+00 -6.007379E-04 -3.608860E-07 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.967737E-04 -8.807464E-08 -2.000000E-02 -9.200000E-05 -2.000000E-02 -9.200000E-05 -8.597951E-03 -1.801722E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +1.300000E-02 +5.100000E-05 +1.300000E-02 +5.100000E-05 +6.002667E-03 +1.149916E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 -1.200000E-02 -3.200000E-05 -1.200000E-02 -3.200000E-05 -6.509749E-03 -9.403130E-06 0.000000E+00 0.000000E+00 +3.067112E-04 +9.407179E-08 0.000000E+00 0.000000E+00 -3.003690E-04 -9.022151E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.990959E-04 -3.589159E-07 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 -1.000000E-03 -1.000000E-06 -1.000000E-03 -1.000000E-06 -2.884266E-04 -8.318989E-08 0.000000E+00 0.000000E+00 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1341,22 +1345,22 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +1.300000E-02 +4.700000E-05 +1.300000E-02 +4.700000E-05 +5.486562E-03 +7.965488E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -7.000000E-03 -2.100000E-05 -7.000000E-03 -2.100000E-05 -3.890163E-03 -6.545535E-06 +3.054379E-04 +9.329231E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.995479E-04 -8.972896E-08 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1365,22 +1369,22 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +8.000000E-03 +1.800000E-05 +8.000000E-03 +1.800000E-05 +3.334317E-03 +3.609712E-06 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.300000E-02 -4.300000E-05 -1.300000E-02 -4.300000E-05 -6.485840E-03 -1.112994E-05 +2.948908E-04 +8.696057E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -5.989880E-04 -3.587866E-07 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1389,32 +1393,28 @@ tally 1: 0.000000E+00 0.000000E+00 0.000000E+00 +2.000000E-02 +1.080000E-04 +2.000000E-02 +1.080000E-04 +9.741552E-03 +2.552400E-05 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -1.500000E-02 -4.900000E-05 -1.500000E-02 -4.900000E-05 -7.442524E-03 -1.164759E-05 +3.015814E-04 +9.095135E-08 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 -2.994940E-04 -8.969666E-08 +1.800986E-03 +1.622276E-06 1.000000E-03 1.000000E-06 1.000000E-03 1.000000E-06 -5.768531E-04 -3.327596E-07 -0.000000E+00 -0.000000E+00 -0.000000E+00 -0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 @@ -1442,11 +1442,11 @@ tally 1: 0.000000E+00 0.000000E+00 tally 2: -5.649702E-01 -6.385502E-02 -6.158199E-01 -7.586795E-02 -3.579551E+00 -2.563396E+00 -3.982345E+01 -3.172536E+02 +5.818100E-01 +6.772558E-02 +6.344749E-01 +8.054355E-02 +3.690180E+00 +2.724752E+00 +4.102635E+01 +3.367908E+02 diff --git a/tests/regression_tests/statepoint_restart/test.py b/tests/regression_tests/statepoint_restart/test.py index 4575607f7d8..82e514da877 100644 --- a/tests/regression_tests/statepoint_restart/test.py +++ b/tests/regression_tests/statepoint_restart/test.py @@ -1,11 +1,10 @@ -import glob -import os +from pathlib import Path import openmc from tests.testing_harness import TestHarness from tests.regression_tests import config - +from tests import cdtemp class StatepointRestartTestHarness(TestHarness): def __init__(self, final_sp, restart_sp): @@ -42,7 +41,7 @@ def update_results(self): def _run_openmc_restart(self): # Get the name of the statepoint file. - statepoint = glob.glob(os.path.join(os.getcwd(), self._restart_sp)) + statepoint = list(Path.cwd().glob(self._restart_sp)) assert len(statepoint) == 1 statepoint = statepoint[0] @@ -59,3 +58,37 @@ def test_statepoint_restart(): harness = StatepointRestartTestHarness('statepoint.10.h5', 'statepoint.07.h5') harness.main() + + +def test_batch_check(request, capsys): + xmls = list(request.path.parent.glob('*.xml')) + + with cdtemp(xmls): + model = openmc.Model.from_xml() + model.settings.particles = 100 + + # run the model + sp_file = model.run(export_model_xml=False) + assert sp_file is not None + + # run a restart with the resulting statepoint + # and the settings unchanged + model.settings.batches = 6 + # ensure we capture output only from the next run + capsys.readouterr() + sp_file = model.run(export_model_xml=False, restart_file=sp_file) + # indicates that a new statepoint file was not created + assert sp_file is None + + output = capsys.readouterr().out + assert "WARNING" in output + assert "The number of batches specified for simulation" in output + + # update the number of batches and run again, + # this restart run should be successful + model.settings.batches = 15 + model.settings.statepoint = {} + sp_file = model.run(export_model_xml=False, restart_file=sp_file) + + sp = openmc.StatePoint(sp_file) + assert sp.n_batches == 15 diff --git a/tests/regression_tests/statepoint_sourcesep/results_true.dat b/tests/regression_tests/statepoint_sourcesep/results_true.dat index fe46748c80d..bbf03de9437 100644 --- a/tests/regression_tests/statepoint_sourcesep/results_true.dat +++ b/tests/regression_tests/statepoint_sourcesep/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.987050E-01 1.827430E-03 +3.070134E-01 3.900396E-03 diff --git a/tests/regression_tests/surface_source/inputs_true_read.dat b/tests/regression_tests/surface_source/inputs_true_read.dat index 3a122c737b8..14a55f0bf04 100644 --- a/tests/regression_tests/surface_source/inputs_true_read.dat +++ b/tests/regression_tests/surface_source/inputs_true_read.dat @@ -1,34 +1,33 @@ - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - surface_source_true.h5 - - 1 - - - - - 3 - - - 1 - flux - - + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + surface_source_true.h5 + + 1 + + + + 3 + + + 1 + flux + + + diff --git a/tests/regression_tests/surface_source/inputs_true_write.dat b/tests/regression_tests/surface_source/inputs_true_write.dat index 48dde9900a3..5c85de6318b 100644 --- a/tests/regression_tests/surface_source/inputs_true_write.dat +++ b/tests/regression_tests/surface_source/inputs_true_write.dat @@ -1,40 +1,39 @@ - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - 0 0 0 - - - - 1 - 1000 - - 1 - - - - - 3 - - - 1 - flux - - + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + 0 0 0 + + + + 1 + 1000 + + 1 + + + + 3 + + + 1 + flux + + + diff --git a/tests/regression_tests/surface_source/surface_source_true.h5 b/tests/regression_tests/surface_source/surface_source_true.h5 index 22edb898b57..f2055d09dc3 100644 Binary files a/tests/regression_tests/surface_source/surface_source_true.h5 and b/tests/regression_tests/surface_source/surface_source_true.h5 differ diff --git a/tests/regression_tests/surface_source/test.py b/tests/regression_tests/surface_source/test.py index dc60cfd3c72..a25b40064d8 100644 --- a/tests/regression_tests/surface_source/test.py +++ b/tests/regression_tests/surface_source/test.py @@ -7,6 +7,7 @@ import openmc from tests.testing_harness import PyAPITestHarness +from tests.regression_tests import config @pytest.fixture @@ -44,7 +45,7 @@ def model(request): if surf_source_op == 'write': point = openmc.stats.Point((0, 0, 0)) - pt_src = openmc.Source(space=point) + pt_src = openmc.IndependentSource(space=point) openmc_model.settings.source = pt_src openmc_model.settings.surf_source_write = {'surface_ids': [1], @@ -118,10 +119,14 @@ def _cleanup(self): @pytest.mark.surf_source_op('write') def test_surface_source_write(model): + # Test result is based on 1 MPI process + np = config['mpi_np'] + config['mpi_np'] = '1' harness = SurfaceSourceTestHarness('statepoint.10.h5', model, 'inputs_true_write.dat') harness.main() + config['mpi_np'] = np @pytest.mark.surf_source_op('read') diff --git a/tests/regression_tests/surface_tally/inputs_true.dat b/tests/regression_tests/surface_tally/inputs_true.dat index 96639a07610..192c2e89f40 100644 --- a/tests/regression_tests/surface_tally/inputs_true.dat +++ b/tests/regression_tests/surface_tally/inputs_true.dat @@ -1,103 +1,105 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 0 - - - -0.62992 -0.62992 -1 0.62992 0.62992 1 - - - - - - - 13 - - - 14 - - - 0.0 4000000.0 20000000.0 - - - 0.0 0.7853981633974483 3.141592653589793 - - - 0.0 0.7853981633974483 3.141592653589793 - - - 1 - - - 14 - - - 13 - - - 2 - - - 3 - - - 5 6 1 2 3 - current - - - 5 4 1 2 3 - current - - - 7 8 1 2 3 - current - - - 7 4 1 2 3 - current - - - 4 1 2 3 - current - - - 10 1 2 3 - current - - - 11 1 - current - - - 11 1 - current - - + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 0 + + + -0.62992 -0.62992 -1 0.62992 0.62992 1 + + + true + + + + + + 1 + + + 2 + + + 0.0 4000000.0 20000000.0 + + + 0.0 0.7853981633974483 3.141592653589793 + + + 0.0 0.7853981633974483 3.141592653589793 + + + 1 + + + 2 + + + 1 + + + 2 + + + 3 + + + 5 6 1 2 3 + current + + + 5 4 1 2 3 + current + + + 7 8 1 2 3 + current + + + 7 4 1 2 3 + current + + + 4 1 2 3 + current + + + 10 1 2 3 + current + + + 11 1 + current + + + 11 1 + current + + + diff --git a/tests/regression_tests/surface_tally/results_true.dat b/tests/regression_tests/surface_tally/results_true.dat index cfd70a0137c..8b27fa19280 100644 --- a/tests/regression_tests/surface_tally/results_true.dat +++ b/tests/regression_tests/surface_tally/results_true.dat @@ -1,52 +1,52 @@ mean,std. dev. -1.9600000e-02,1.5719768e-03 -7.3700000e-02,1.9382122e-03 -1.7130000e-01,4.0907755e-03 -6.3490000e-01,8.8197380e-03 -2.5000000e-03,5.2174919e-04 -6.0000000e-03,1.6799471e-03 -1.0600000e-02,1.8749815e-03 -4.0200000e-02,1.6852300e-03 -1.9600000e-02,1.5719768e-03 -7.3700000e-02,1.9382122e-03 -1.7130000e-01,4.0907755e-03 -6.3490000e-01,8.8197380e-03 -2.5000000e-03,5.2174919e-04 -6.0000000e-03,1.6799471e-03 -1.0600000e-02,1.8749815e-03 -4.0200000e-02,1.6852300e-03 -4.7000000e-03,9.1954095e-04 -4.5400000e-02,2.4413111e-03 -4.2800000e-02,2.2150997e-03 -4.2460000e-01,7.3017502e-03 -0.0000000e+00,0.0000000e+00 -1.6000000e-03,2.6666667e-04 -4.0000000e-04,1.6329932e-04 -1.5700000e-02,1.1551816e-03 --4.7000000e-03,9.1954095e-04 --4.5400000e-02,2.4413111e-03 --4.2800000e-02,2.2150997e-03 --4.2460000e-01,7.3017502e-03 -0.0000000e+00,0.0000000e+00 --1.6000000e-03,2.6666667e-04 --4.0000000e-04,1.6329932e-04 --1.5700000e-02,1.1551816e-03 -1.4900000e-02,1.5235193e-03 -2.8300000e-02,2.0925795e-03 -1.2850000e-01,4.0613353e-03 -2.1030000e-01,5.4955538e-03 -2.5000000e-03,5.2174919e-04 -4.4000000e-03,1.4847372e-03 -1.0200000e-02,1.8903263e-03 -2.4500000e-02,1.7966017e-03 -0.0000000e+00,0.0000000e+00 --3.0900000e-02,2.0518285e-03 -0.0000000e+00,0.0000000e+00 --3.4370000e-01,4.5093730e-03 -0.0000000e+00,0.0000000e+00 --2.9000000e-03,8.0897741e-04 -0.0000000e+00,0.0000000e+00 --2.2200000e-02,2.0210009e-03 +2.1200000e-02,1.8366636e-03 +7.4900000e-02,2.2083176e-03 +1.6220000e-01,2.8079253e-03 +6.4010000e-01,8.6838931e-03 +2.1000000e-03,3.7859389e-04 +5.6000000e-03,6.8637534e-04 +1.1700000e-02,1.4456832e-03 +4.1700000e-02,2.7041121e-03 +2.1200000e-02,1.8366636e-03 +7.4900000e-02,2.2083176e-03 +1.6220000e-01,2.8079253e-03 +6.4010000e-01,8.6838931e-03 +2.1000000e-03,3.7859389e-04 +5.6000000e-03,6.8637534e-04 +1.1700000e-02,1.4456832e-03 +4.1700000e-02,2.7041121e-03 +5.2000000e-03,5.9254629e-04 +3.9200000e-02,2.5508169e-03 +4.0200000e-02,1.9310331e-03 +4.1360000e-01,8.0072190e-03 +0.0000000e+00,0.0000000e+00 +1.9000000e-03,3.7859389e-04 +1.0000000e-04,1.0000000e-04 +1.6400000e-02,1.2840907e-03 +-5.2000000e-03,5.9254629e-04 +-3.9200000e-02,2.5508169e-03 +-4.0200000e-02,1.9310331e-03 +-4.1360000e-01,8.0072190e-03 +0.0000000e+00,0.0000000e+00 +-1.9000000e-03,3.7859389e-04 +-1.0000000e-04,1.0000000e-04 +-1.6400000e-02,1.2840907e-03 +1.6000000e-02,2.1602469e-03 +3.5700000e-02,2.9441090e-03 +1.2200000e-01,3.5932035e-03 +2.2650000e-01,9.2463206e-03 +2.1000000e-03,3.7859389e-04 +3.7000000e-03,8.1717671e-04 +1.1600000e-02,1.4772347e-03 +2.5300000e-02,1.9723083e-03 +0.0000000e+00,0.0000000e+00 +-2.9700000e-02,2.4587711e-03 +0.0000000e+00,0.0000000e+00 +-3.5090000e-01,3.7161808e-03 +0.0000000e+00,0.0000000e+00 +-2.1000000e-03,4.8189441e-04 +0.0000000e+00,0.0000000e+00 +-2.1400000e-02,1.7397318e-03 0.0000000e+00,0.0000000e+00 0.0000000e+00,0.0000000e+00 0.0000000e+00,0.0000000e+00 diff --git a/tests/regression_tests/surface_tally/test.py b/tests/regression_tests/surface_tally/test.py index 96199ec2a43..e496ac0f65c 100644 --- a/tests/regression_tests/surface_tally/test.py +++ b/tests/regression_tests/surface_tally/test.py @@ -6,7 +6,8 @@ class SurfaceTallyTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # Instantiate some Materials and register the appropriate Nuclides uo2 = openmc.Material(name='UO2 fuel at 2.4% wt enrichment') uo2.set_density('g/cc', 10.0) @@ -21,8 +22,7 @@ def _build_inputs(self): borated_water.add_nuclide('O16', 1.0) # Instantiate a Materials collection and export to XML - materials_file = openmc.Materials([uo2, borated_water]) - materials_file.export_to_xml() + self._model.materials = openmc.Materials([uo2, borated_water]) # Instantiate ZCylinder surfaces fuel_or = openmc.ZCylinder(surface_id=1, x0=0, y0=0, r=1, @@ -61,8 +61,7 @@ def _build_inputs(self): root_univ.add_cell(root_cell) # Instantiate a Geometry, register the root Universe - geometry = openmc.Geometry(root_univ) - geometry.export_to_xml() + self._model.geometry = openmc.Geometry(root_univ) # Instantiate a Settings object, set all runtime parameters settings_file = openmc.Settings() @@ -73,10 +72,10 @@ def _build_inputs(self): # Create an initial uniform spatial source distribution bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:],\ - only_fissionable=True) - settings_file.source = openmc.source.Source(space=uniform_dist) - settings_file.export_to_xml() + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:],) + settings_file.source = openmc.IndependentSource( + space=uniform_dist, constraints={'fissionable': True}) + self._model.settings = settings_file # Tallies file tallies_file = openmc.Tallies() @@ -107,19 +106,19 @@ def _build_inputs(self): # Create partial current tallies from water to fuel # Filters - cell_from_filter = openmc.CellFromFilter(water) + mat_from_filter = openmc.MaterialFromFilter(borated_water) cell_filter = openmc.CellFilter(fuel) # Cell to cell filters for partial current cell_to_cell_tally = openmc.Tally(name=str('water_to_fuel_1')) - cell_to_cell_tally.filters = [cell_from_filter, cell_filter, \ + cell_to_cell_tally.filters = [mat_from_filter, cell_filter, \ energy_filter, polar_filter, azimuthal_filter] cell_to_cell_tally.scores = ['current'] tallies_file.append(cell_to_cell_tally) # Cell from + surface filters for partial current cell_to_cell_tally = openmc.Tally(name=str('water_to_fuel_2')) - cell_to_cell_tally.filters = [cell_from_filter, surface_filter, \ + cell_to_cell_tally.filters = [mat_from_filter, surface_filter, \ energy_filter, polar_filter, azimuthal_filter] cell_to_cell_tally.scores = ['current'] tallies_file.append(cell_to_cell_tally) @@ -156,7 +155,7 @@ def _build_inputs(self): surf_tally3.scores = ['current'] tallies_file.append(surf_tally3) - tallies_file.export_to_xml() + self._model.tallies = tallies_file def _get_results(self): """Digest info in the statepoint and return as a string.""" @@ -164,9 +163,8 @@ def _get_results(self): sp = openmc.StatePoint(self._sp_name) # Extract the tally data as a Pandas DataFrame. - df = pd.DataFrame() - for t in sp.tallies.values(): - df = df.append(t.get_pandas_dataframe(), ignore_index=True) + tally_dfs = [t.get_pandas_dataframe() for t in sp.tallies.values()] + df = pd.concat(tally_dfs, ignore_index=True) # Extract the relevant data as a CSV string. cols = ('mean', 'std. dev.') @@ -175,5 +173,5 @@ def _get_results(self): def test_surface_tally(): - harness = SurfaceTallyTestHarness('statepoint.10.h5') + harness = SurfaceTallyTestHarness('statepoint.10.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/survival_biasing/results_true.dat b/tests/regression_tests/survival_biasing/results_true.dat index b9868f3d3ab..74027220170 100644 --- a/tests/regression_tests/survival_biasing/results_true.dat +++ b/tests/regression_tests/survival_biasing/results_true.dat @@ -1,20 +1,20 @@ k-combined: -9.826269E-01 1.626276E-02 +9.879232E-01 8.097582E-03 tally 1: -4.212303E+01 -3.550855E+02 -1.760388E+01 -6.205773E+01 -2.165888E+00 -9.392975E-01 -1.873459E+00 -7.025989E-01 -4.850267E+00 -4.708899E+00 -3.397795E-02 -2.310621E-04 -3.628554E+08 -2.635633E+16 +4.295331E+01 +3.691096E+02 +1.802724E+01 +6.501934E+01 +2.193500E+00 +9.627609E-01 +1.893529E+00 +7.174104E-01 +4.902380E+00 +4.808570E+00 +3.418014E-02 +2.337353E-04 +3.667128E+08 +2.690758E+16 tally 2: -1.760388E+01 -6.205773E+01 +1.802724E+01 +6.501934E+01 diff --git a/tests/regression_tests/tallies/inputs_true.dat b/tests/regression_tests/tallies/inputs_true.dat index bc9efe97efd..2ce36c5dfcd 100644 --- a/tests/regression_tests/tallies/inputs_true.dat +++ b/tests/regression_tests/tallies/inputs_true.dat @@ -1,38 +1,187 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -50,12 +199,12 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -73,12 +222,12 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 @@ -100,12 +249,12 @@ 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 @@ -127,402 +276,228 @@ 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 400 - 5 - 0 - - - -160 -160 -183 160 160 183 - - - - - - - 2 2 - -182.07 -182.07 - 182.07 182.07 - - - -3.14159 -1.885 -0.6283 0.6283 1.885 3.14159 - - - 1 - - - 10 21 22 23 - - - 1 2 3 4 5 6 - - - 0.0 0.253 1000.0 1000000.0 20000000.0 - - - 0.0 0.253 1000.0 1000000.0 20000000.0 - - - 1 2 3 4 - - - -1.0 -0.5 0.0 0.5 1.0 - - - 0.0 0.6283 1.2566 1.885 2.5132 3.14159 - - - 4 - - - 4 - - - 1 2 3 4 6 8 - - - 1 2 5 3 6 - - - 10 21 22 23 60 - - - 21 22 23 27 28 29 60 - - - 1 - flux - tracklength - - - 1 - flux - analog - - - 1 2 - flux - tracklength - - - 3 - total - - - 4 - U235 O16 total - delayed-nu-fission decay-rate - - - 5 - total - - - 6 - scatter - - - 5 6 - scatter nu-fission - - - 7 - total - - - 8 - scatter nu-scatter - - - 8 2 - scatter nu-scatter - - - 9 - flux - tracklength - - - 9 - flux - analog - - - 9 2 - flux - tracklength - - - 10 - scatter nu-scatter - analog - - - 11 - scatter nu-scatter flux total - analog - - - 11 - flux total - collision - - - 11 - flux total - tracklength - - - 12 - total - - - 15 - scatter - - - 13 - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - tracklength - - - 13 - U235 O16 total - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - tracklength - - - 13 - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - analog - - - 13 - U235 O16 total - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - analog - - - 13 - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - collision - - - 13 - U235 O16 total - absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate - collision - - - 14 - flux - tracklength - - - 14 - flux - analog - - - 14 - flux - collision - - - 13 - all - total - tracklength - - - 13 - all - total - collision - - - 2 - all - total - tracklength - - - 2 - U235 - total - tracklength - - - H1-production H2-production H3-production He3-production He4-production heating damage-energy - - + + + + + + + + + + + + + + + + + + + + + eigenvalue + 400 + 5 + 0 + + + -160 -160 -183 160 160 183 + + + + + + 2 2 + -182.07 -182.07 + 182.07 182.07 + + + -3.14159 -1.885 -0.6283 0.6283 1.885 3.14159 + + + 1 + + + 10 21 22 23 + + + 1 2 3 4 5 6 + + + 0.0 0.253 1000.0 1000000.0 20000000.0 + + + 0.0 0.253 1000.0 1000000.0 20000000.0 + + + 1 2 3 4 + + + -1.0 -0.5 0.0 0.5 1.0 + + + 0.0 0.6283 1.2566 1.885 2.5132 3.14159 + + + 4 + + + 4 + + + 1 2 3 4 6 8 + + + 1 2 5 3 6 + + + 10 21 22 23 60 + + + 21 22 23 27 28 29 60 + + + 1 + flux + tracklength + + + 1 + flux + analog + + + 1 2 + flux + tracklength + + + 3 + total + + + 4 + U235 O16 total + delayed-nu-fission decay-rate + + + 5 + total + + + 6 + scatter + + + 5 6 + scatter nu-fission + + + 7 + total + + + 8 + scatter nu-scatter + + + 8 2 + scatter nu-scatter + + + 9 + flux + tracklength + + + 9 + flux + analog + + + 9 2 + flux + tracklength + + + 10 + scatter nu-scatter + analog + + + 11 + scatter nu-scatter flux total + analog + + + 11 + flux total + collision + + + 11 + flux total + tracklength + + + 12 + total + + + 15 + scatter + + + 13 + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + tracklength + + + 13 + U235 O16 total + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + tracklength + + + 13 + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + analog + + + 13 + U235 O16 total + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + analog + + + 13 + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + collision + + + 13 + U235 O16 total + absorption delayed-nu-fission events fission inverse-velocity kappa-fission (n,2n) (n,n1) (n,gamma) nu-fission scatter elastic total prompt-nu-fission fission-q-prompt fission-q-recoverable decay-rate + collision + + + 14 + flux + tracklength + + + 14 + flux + analog + + + 14 + flux + collision + + + H1-production H2-production H3-production He3-production He4-production heating damage-energy + + + diff --git a/tests/regression_tests/tallies/results_true.dat b/tests/regression_tests/tallies/results_true.dat index f6403191dec..3dda0f9b211 100644 --- a/tests/regression_tests/tallies/results_true.dat +++ b/tests/regression_tests/tallies/results_true.dat @@ -1 +1 @@ -22cd0d5d2764367e2a3ca2b715d0863ac7afd33cbd4f0b2707722e6267d95d3bc07026c9a7fdbc8260c69c40a6617b6e1c831de5f9c4a7cb89c4efa6b74bea76 \ No newline at end of file +ddfbb0a6f5498eb8ff33bb10beb64e244b015861919eb4837bd82855e5fd87c3ff97dfa382d3d60afa81c48d9f857fba8e0b99263e7b35587f8adb75be1fc0ec \ No newline at end of file diff --git a/tests/regression_tests/tallies/test.py b/tests/regression_tests/tallies/test.py index 7746a4e2419..d20067ed33f 100644 --- a/tests/regression_tests/tallies/test.py +++ b/tests/regression_tests/tallies/test.py @@ -13,7 +13,7 @@ def test_tallies(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 400 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-160, -160, -183], [160, 160, 183])) azimuthal_bins = (-3.14159, -1.8850, -0.6283, 0.6283, 1.8850, 3.14159) @@ -40,7 +40,7 @@ def test_tallies(): cellborn_tally = Tally() cellborn_tally.filters = [ - CellbornFilter((model.geometry.get_all_cells()[10], + CellBornFilter((model.geometry.get_all_cells()[10], model.geometry.get_all_cells()[21], 22, 23))] # Test both Cell objects and ids cellborn_tally.scores = ['total'] @@ -154,17 +154,6 @@ def test_tallies(): flux_tallies[1].estimator = 'analog' flux_tallies[2].estimator = 'collision' - all_nuclide_tallies = [Tally() for i in range(4)] - for t in all_nuclide_tallies: - t.filters = [cell_filter] - t.estimator = 'tracklength' - t.nuclides = ['all'] - t.scores = ['total'] - all_nuclide_tallies[1].estimator = 'collision' - all_nuclide_tallies[2].filters = [mesh_filter] - all_nuclide_tallies[3].filters = [mesh_filter] - all_nuclide_tallies[3].nuclides = ['U235'] - fusion_tally = Tally() fusion_tally.scores = ['H1-production', 'H2-production', 'H3-production', 'He3-production', 'He4-production', 'heating', 'damage-energy'] @@ -180,11 +169,10 @@ def test_tallies(): cellborn_tally, dg_tally, energy_tally, energyout_tally, transfer_tally, material_tally, mu_tally1, mu_tally2, polar_tally1, polar_tally2, polar_tally3, legendre_tally, - harmonics_tally, harmonics_tally2, harmonics_tally3, + harmonics_tally, harmonics_tally2, harmonics_tally3, universe_tally, collision_tally] model.tallies += score_tallies model.tallies += flux_tallies - model.tallies += all_nuclide_tallies model.tallies.append(fusion_tally) harness.main() diff --git a/tests/regression_tests/tally_aggregation/inputs_true.dat b/tests/regression_tests/tally_aggregation/inputs_true.dat index 80356f7119f..9f4f9565524 100644 --- a/tests/regression_tests/tally_aggregation/inputs_true.dat +++ b/tests/regression_tests/tally_aggregation/inputs_true.dat @@ -1,57 +1,56 @@ - - - - - - 1.2 1.2 - 1 - 2 2 - -1.2 -1.2 - + + + + + + + + + + + + + + + + + + + + + + 1.2 1.2 + 1 + 2 2 + -1.2 -1.2 + 1 1 1 1 - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 10 - 5 - - - - - 0.0 0.253 1000.0 1000000.0 20000000.0 - - - 1 - - - 1 2 - U234 U235 U238 - nu-fission total - - + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + + 0.0 0.253 1000.0 1000000.0 20000000.0 + + + 1 + + + 1 2 + U234 U235 U238 + nu-fission total + + + diff --git a/tests/regression_tests/tally_aggregation/results_true.dat b/tests/regression_tests/tally_aggregation/results_true.dat index dcfd6a3d5f1..172adbfe132 100644 --- a/tests/regression_tests/tally_aggregation/results_true.dat +++ b/tests/regression_tests/tally_aggregation/results_true.dat @@ -1,97 +1,97 @@ -[[1.61005568e-05 5.28458444e-04] - [3.11780303e-01 1.69630677e-01] - [1.81039700e-02 7.17920004e-01]], [[1.63277473e-05 5.35624141e-04] - [3.22999594e-01 1.75065732e-01] - [1.85187755e-02 7.21594286e-01]], [[1.57790723e-05 5.78478805e-04] - [3.12060993e-01 1.69379533e-01] - [1.76156994e-02 6.98879633e-01]], [[1.61290396e-05 5.22145640e-04] - [3.31165486e-01 1.79249843e-01] - [1.83392363e-02 7.18096451e-01]][[2.50705992e-07 4.15411769e-05] - [8.88683714e-03 4.34823604e-03] - [4.29294550e-04 5.11665109e-03]], [[2.63489203e-07 4.09119777e-05] - [9.55602586e-03 4.69484865e-03] - [5.15000077e-04 8.20227964e-03]], [[2.84827298e-07 5.23693876e-05] - [5.93669503e-03 2.98039486e-03] - [3.50362785e-04 7.11933781e-03]], [[4.95292791e-07 5.21837231e-05] - [1.16451396e-02 5.73252446e-03] - [9.30056985e-04 9.25360540e-03]][[1.02765520e-06 8.06605975e-04] - [1.11927207e+00 5.54627433e-01] - [1.39118344e-06 5.06998814e-01]], [[1.96296376e-06 1.04095045e-03] - [1.40593050e-01 9.80871419e-02] - [2.94926461e-05 7.87053204e-01]], [[1.51074017e-05 2.29954879e-04] - [1.31358252e-02 2.98161818e-02] - [3.29647853e-04 1.12152170e+00]], [[4.62383953e-05 8.71957301e-05] - [5.00543423e-03 1.07950266e-02] - [7.22171494e-02 4.40916661e-01]][[1.65326728e-08 1.23379346e-05] - [1.83866310e-02 9.02061647e-03] - [2.18217041e-08 6.58579737e-03]], [[1.43989927e-07 9.33223265e-05] - [1.75029172e-03 1.13330217e-03] - [1.23529292e-05 1.09908191e-02]], [[2.08663931e-07 1.58492255e-06] - [1.05313289e-04 1.28418774e-04] - [5.57808071e-06 5.56265934e-03]], [[6.27833201e-07 1.16609909e-06] - [6.57036438e-05 1.44789485e-04] - [1.19878908e-03 5.88707758e-03]][[0.27264715 0.26047652]], [[0.28262955 0.2668458 ]], [[0.27358033 0.26010361]], [[0.29041746 0.27500692]], [[0.0346119 0.22582686]], [[0.03577981 0.2250003 ]], [[0.03407193 0.21859532]], [[0.03616086 0.21675882]], [[0.00335479 0.28896656]], [[0.0034114 0.29075928]], [[0.00329103 0.27971624]], [[0.00342335 0.29212575]], [[0.01928653 0.1128092 ]], [[0.01971393 0.11459026]], [[0.01874918 0.11042247]], [[0.01951918 0.11397695]][[0.00882784 0.00523284]], [[0.00954756 0.00573915]], [[0.00588879 0.00376804]], [[0.01158894 0.00708702]], [[0.00102019 0.00250541]], [[0.00039966 0.00688 ]], [[0.00074982 0.00526868]], [[0.00114059 0.00638128]], [[6.09921974e-05 2.73214859e-03]], [[3.87113119e-05 2.37272080e-03]], [[5.95581496e-05 3.24982165e-03]], [[4.85413262e-05 2.70257139e-03]], [[0.00042997 0.00199114]], [[0.00051547 0.00184897]], [[0.00035135 0.00265556]], [[0.00093133 0.00449926]][[1.97530308e-04] - [4.07797300e-01] - [1.25128841e-01]], [[2.03241058e-04] - [4.22641844e-01] - [1.26630264e-01]], [[1.97625201e-04] - [4.09151448e-01] - [1.24334865e-01]], [[2.09237063e-04] - [4.34308908e-01] - [1.30906235e-01]], [[0.00025338] - [0.05895582] - [0.20122956]], [[0.00025148] - [0.06049907] - [0.20002955]], [[0.00030465] - [0.05796949] - [0.1943931 ]], [[0.0002334 ] - [0.0612558 ] - [0.19143048]], [[6.03164990e-05] - [1.07108991e-02] - [2.81550134e-01]], [[6.33746662e-05] - [1.09155142e-02] - [2.83191794e-01]], [[5.93920816e-05] - [1.04611857e-02] - [2.72486696e-01]], [[6.19790342e-05] - [1.08644079e-02] - [2.84622720e-01]], [[3.33318949e-05] - [3.94695980e-03] - [1.28115439e-01]], [[3.38512144e-05] - [4.00889317e-03] - [1.30261451e-01]], [[3.25875003e-05] - [3.85839921e-03] - [1.25280669e-01]], [[3.36635158e-05] - [3.98620867e-03] - [1.29476251e-01]][[5.95890211e-06] - [9.82689936e-03] - [2.95727478e-03]], [[6.38330878e-06] - [1.06352939e-02] - [3.31424633e-03]], [[4.06559013e-06] - [6.56685481e-03] - [2.39841401e-03]], [[7.70978183e-06] - [1.29088618e-02] - [4.22973219e-03]], [[4.11055418e-05] - [1.14182019e-03] - [2.45201819e-03]], [[4.04069587e-05] - [4.94079821e-04] - [6.87374133e-03]], [[5.21912212e-05] - [9.93748247e-04] - [5.22790507e-03]], [[5.16019951e-05] - [1.34628791e-03] - [6.34086376e-03]], [[5.94620921e-07] - [9.14728767e-05] - [2.73129792e-03]], [[4.54875038e-07] - [5.53436452e-05] - [2.37239108e-03]], [[1.35682209e-06] - [1.04960334e-04] - [3.24867195e-03]], [[3.92515745e-07] - [7.16616524e-05] - [2.70205715e-03]], [[4.52300861e-07] - [5.43990642e-05] - [2.03630956e-03]], [[4.28365958e-07] - [5.07914928e-05] - [1.91880908e-03]], [[5.83372364e-07] - [7.04771264e-05] - [2.67777413e-03]], [[1.01270175e-06] - [1.21552065e-04] - [4.59302934e-03]] \ No newline at end of file +[[1.6001087e-05 5.4190949e-04] + [3.2669968e-01 1.7730523e-01] + [1.8149266e-02 7.1525113e-01]], [[1.6239097e-05 5.7499676e-04] + [3.1268633e-01 1.7004165e-01] + [1.8873778e-02 7.0217885e-01]], [[1.6693071e-05 5.4106379e-04] + [3.3370208e-01 1.8051505e-01] + [1.9081306e-02 7.3647547e-01]], [[1.6725399e-05 5.1680146e-04] + [3.2854628e-01 1.7757185e-01] + [1.9529646e-02 7.1005198e-01]][[2.4751834e-07 4.3304565e-05] + [8.6840718e-03 4.3442535e-03] + [3.7054051e-04 6.5678133e-03]], [[4.0830852e-07 4.9612204e-05] + [1.2104241e-02 5.9708675e-03] + [7.1398189e-04 8.2408482e-03]], [[2.6546344e-07 2.5234256e-05] + [6.5083211e-03 3.2185071e-03] + [4.2935150e-04 5.1707774e-03]], [[2.7845203e-07 3.4453402e-05] + [3.3125427e-03 1.7749508e-03] + [6.0407731e-04 7.5353872e-03]][[1.0455251e-06 8.1938339e-04] + [1.1392765e+00 5.6434761e-01] + [1.4142831e-06 5.1213654e-01]], [[2.2009815e-06 1.0418935e-03] + [1.4422554e-01 1.0070647e-01] + [3.9488382e-05 7.9236390e-01]], [[1.4606612e-05 2.2374470e-04] + [1.2962842e-02 2.9268594e-02] + [3.1339824e-04 1.1056439e+00]], [[4.7805535e-05 8.9749934e-05] + [5.1694597e-03 1.1111105e-02] + [7.5279695e-02 4.5381305e-01]][[1.4955183e-08 1.1461548e-05] + [1.6454649e-02 8.1236707e-03] + [2.0028007e-08 6.8264819e-03]], [[1.6334486e-07 7.7617340e-05] + [2.1161584e-03 1.4078445e-03] + [1.4742097e-05 6.9350862e-03]], [[1.7444757e-07 1.9026095e-06] + [1.4084092e-04 2.0345990e-04] + [5.9546175e-06 8.6038812e-03]], [[5.6449127e-07 1.0110585e-06] + [5.9158873e-05 1.2485325e-04] + [1.0936497e-03 5.0836702e-03]][[0.2866239 0.2725595]], [[0.2729156 0.258831 ]], [[0.2920724 0.2755922]], [[0.287667 0.2703207]], [[0.035617 0.2232707]], [[0.0353082 0.2224423]], [[0.0370072 0.2288263]], [[0.0363348 0.219573 ]], [[0.0033013 0.2850034]], [[0.0032726 0.2771099]], [[0.0034234 0.2951295]], [[0.0032935 0.2778935]], [[0.0193227 0.1122647]], [[0.0200799 0.1144123]], [[0.0202971 0.1179836]], [[0.0207973 0.1203534]][[0.0086351 0.0061876]], [[0.0120688 0.0074831]], [[0.0064221 0.0035246]], [[0.0030483 0.0024267]], [[0.0009185 0.0033896]], [[0.0009223 0.0039584]], [[0.0010541 0.0038599]], [[0.0012934 0.0028331]], [[6.5126963e-05 2.8486593e-03]], [[7.1110242e-05 4.3424340e-03]], [[5.8911409e-05 2.4296178e-03]], [[8.4278765e-05 6.4182190e-03]], [[0.0003712 0.0020298]], [[0.0007152 0.0036115]], [[0.0004298 0.0019677]], [[0.0006046 0.0021965]][[2.0694650e-04] + [4.2868191e-01] + [1.3029457e-01]], [[1.9694048e-04] + [4.0809445e-01] + [1.2345525e-01]], [[2.1012645e-04] + [4.3670571e-01] + [1.3074883e-01]], [[2.0641548e-04] + [4.3014207e-01] + [1.2763930e-01]], [[0.0002584] + [0.0608867] + [0.1977426]], [[0.0003026] + [0.0602368] + [0.1972111]], [[0.0002509] + [0.0624699] + [0.2031126]], [[0.0002322] + [0.0613385] + [0.1943371]], [[5.9349736e-05] + [1.0506741e-02] + [2.7773865e-01]], [[5.7855564e-05] + [1.0389781e-02] + [2.6993483e-01]], [[6.1819700e-05] + [1.0910874e-02] + [2.8758020e-01]], [[5.9326317e-05] + [1.0424040e-02] + [2.7070367e-01]], [[3.3192167e-05] + [3.9295320e-03] + [1.2762462e-01]], [[3.3882691e-05] + [4.0069157e-03] + [1.3045143e-01]], [[3.4882103e-05] + [4.1306182e-03] + [1.3411514e-01]], [[3.5598508e-05] + [4.2134987e-03] + [1.3690156e-01]][[6.4505980e-06] + [9.6369034e-03] + [4.4700460e-03]], [[8.2880772e-06] + [1.3456171e-02] + [4.5368708e-03]], [[3.9384462e-06] + [7.1570638e-03] + [1.5629142e-03]], [[2.3565894e-06] + [3.4040401e-03] + [1.8956916e-03]], [[4.2806047e-05] + [1.1841015e-03] + [3.3058802e-03]], [[4.8905696e-05] + [1.0360139e-03] + [3.9298937e-03]], [[2.4911390e-05] + [1.2173305e-03] + [3.8114473e-03]], [[3.4347869e-05] + [1.5820360e-03] + [2.6824612e-03]], [[1.0809230e-06] + [1.0316180e-04] + [2.8475354e-03]], [[6.4150814e-07] + [1.1179425e-04] + [4.3415770e-03]], [[7.3848139e-07] + [9.3111666e-05] + [2.4285475e-03]], [[1.2349384e-06] + [1.7152843e-04] + [6.4164799e-03]], [[4.5871493e-07] + [5.4732075e-05] + [2.0627309e-03]], [[8.1649994e-07] + [9.7699188e-05] + [3.6803256e-03]], [[4.5174850e-07] + [5.3913784e-05] + [2.0133571e-03]], [[5.0962865e-07] + [6.0338032e-05] + [2.2773911e-03]] \ No newline at end of file diff --git a/tests/regression_tests/tally_aggregation/test.py b/tests/regression_tests/tally_aggregation/test.py index 70a948be670..08d91166064 100644 --- a/tests/regression_tests/tally_aggregation/test.py +++ b/tests/regression_tests/tally_aggregation/test.py @@ -1,5 +1,4 @@ -import hashlib - +import numpy as np import openmc import pytest @@ -34,8 +33,8 @@ def model(): [pin, pin], [pin, pin], ] - box = openmc.model.rectangular_prism(2*d, 2*d, boundary_type='reflective') - main_cell = openmc.Cell(fill=lattice, region=box) + box = openmc.model.RectangularPrism(2*d, 2*d, boundary_type='reflective') + main_cell = openmc.Cell(fill=lattice, region=-box) model.geometry = openmc.Geometry([main_cell]) model.settings.batches = 10 @@ -67,25 +66,28 @@ def _get_results(self, hash_output=False): # Perform tally aggregations across filter bins, nuclides and scores outstr = '' - # Sum across all energy filter bins - tally_sum = tally.summation(filter_type=openmc.EnergyFilter) - outstr += ', '.join(map(str, tally_sum.mean)) - outstr += ', '.join(map(str, tally_sum.std_dev)) - - # Sum across all distribcell filter bins - tally_sum = tally.summation(filter_type=openmc.DistribcellFilter) - outstr += ', '.join(map(str, tally_sum.mean)) - outstr += ', '.join(map(str, tally_sum.std_dev)) - - # Sum across all nuclides - tally_sum = tally.summation(nuclides=['U234', 'U235', 'U238']) - outstr += ', '.join(map(str, tally_sum.mean)) - outstr += ', '.join(map(str, tally_sum.std_dev)) - - # Sum across all scores - tally_sum = tally.summation(scores=['nu-fission', 'total']) - outstr += ', '.join(map(str, tally_sum.mean)) - outstr += ', '.join(map(str, tally_sum.std_dev)) + # This test occasionally fails in CI due to differences in the 8th + # significant digit. Lowering precision to 7 digits prevents failures + with np.printoptions(precision=7): + # Sum across all energy filter bins + tally_sum = tally.summation(filter_type=openmc.EnergyFilter) + outstr += ', '.join(map(str, tally_sum.mean)) + outstr += ', '.join(map(str, tally_sum.std_dev)) + + # Sum across all distribcell filter bins + tally_sum = tally.summation(filter_type=openmc.DistribcellFilter) + outstr += ', '.join(map(str, tally_sum.mean)) + outstr += ', '.join(map(str, tally_sum.std_dev)) + + # Sum across all nuclides + tally_sum = tally.summation(nuclides=['U234', 'U235', 'U238']) + outstr += ', '.join(map(str, tally_sum.mean)) + outstr += ', '.join(map(str, tally_sum.std_dev)) + + # Sum across all scores + tally_sum = tally.summation(scores=['nu-fission', 'total']) + outstr += ', '.join(map(str, tally_sum.mean)) + outstr += ', '.join(map(str, tally_sum.std_dev)) return outstr diff --git a/tests/regression_tests/tally_arithmetic/inputs_true.dat b/tests/regression_tests/tally_arithmetic/inputs_true.dat index fbbf94fa900..7669b4d0360 100644 --- a/tests/regression_tests/tally_arithmetic/inputs_true.dat +++ b/tests/regression_tests/tally_arithmetic/inputs_true.dat @@ -1,56 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 1000 - 5 - 0 - - - - - 2 2 - -10.0 -10.0 - 10.0 10.0 - - - 1 2 - - - 0.0 10.0 20000000.0 - - - 1 - - - 2 1 - U234 U235 - nu-fission total - - - 1 3 - U238 U235 - total fission - - + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 5 + 0 + + + + 2 2 + -10.0 -10.0 + 10.0 10.0 + + + 1 2 + + + 0.0 10.0 20000000.0 + + + 1 + + + 2 1 + U234 U235 + nu-fission total + + + 1 3 + U238 U235 + total fission + + + diff --git a/tests/regression_tests/tally_arithmetic/results_true.dat b/tests/regression_tests/tally_arithmetic/results_true.dat index 473dd5ee7f6..143930dd419 100644 --- a/tests/regression_tests/tally_arithmetic/results_true.dat +++ b/tests/regression_tests/tally_arithmetic/results_true.dat @@ -1,49 +1,49 @@ -[2.18485e-07 1.40714e-13 1.90835e-04 1.22906e-10 2.14194e-07 1.70920e-07 - 1.87087e-04 1.49289e-04 5.77324e-03 3.71823e-09 2.98131e-03 1.92010e-09 - 5.65986e-03 4.51638e-03 2.92276e-03 2.33227e-03 1.77087e-07 1.04308e-13 - 1.54676e-04 9.11076e-11 1.53337e-07 1.20737e-07 1.33931e-04 1.05457e-04 - 4.67935e-03 2.75624e-09 2.41642e-03 1.42333e-09 4.05176e-03 3.19035e-03 - 2.09234e-03 1.64750e-03 2.32566e-07 1.53743e-13 2.03133e-04 1.34286e-10 - 2.42559e-07 1.94114e-07 2.11862e-04 1.69548e-04 6.14530e-03 4.06249e-09 - 3.17345e-03 2.09788e-09 6.40937e-03 5.12926e-03 3.30981e-03 2.64876e-03 - 2.15237e-07 1.23240e-13 1.87998e-04 1.07643e-10 1.85758e-07 1.46699e-07 - 1.62249e-04 1.28134e-04 5.68742e-03 3.25649e-09 2.93699e-03 1.68166e-09 - 4.90845e-03 3.87638e-03 2.53473e-03 2.00177e-03 2.47477e-03 4.87068e-05 - 1.06189e-02 2.08993e-04 1.26298e-04 3.02426e-05 5.41924e-04 1.29766e-04 - 2.77770e-02 5.46688e-04 4.83214e-02 9.51031e-04 1.41757e-03 3.39445e-04 - 2.46604e-03 5.90506e-04 2.31220e-03 4.16752e-05 9.92129e-03 1.78822e-04 - 1.15514e-04 2.68262e-05 4.95652e-04 1.15107e-04 2.59523e-02 4.67766e-04 - 4.51471e-02 8.13735e-04 1.29654e-03 3.01100e-04 2.25548e-03 5.23800e-04 - 2.30792e-03 4.67592e-05 9.90296e-03 2.00637e-04 1.15169e-04 2.57221e-05 - 4.94175e-04 1.10370e-04 2.59043e-02 5.24828e-04 4.50637e-02 9.13003e-04 - 1.29267e-03 2.88707e-04 2.24876e-03 5.02241e-04 2.35337e-03 4.59723e-05 - 1.00979e-02 1.97260e-04 1.17182e-04 2.59928e-05 5.02809e-04 1.11531e-04 - 2.64144e-02 5.15997e-04 4.59510e-02 8.97639e-04 1.31526e-03 2.91745e-04 - 2.28805e-03 5.07527e-04][2.18485e-07 1.40714e-13 1.90835e-04 1.22906e-10 2.14194e-07 1.70920e-07 - 1.87087e-04 1.49289e-04 5.77324e-03 3.71823e-09 2.98131e-03 1.92010e-09 - 5.65986e-03 4.51638e-03 2.92276e-03 2.33227e-03 1.77087e-07 1.04308e-13 - 1.54676e-04 9.11076e-11 1.53337e-07 1.20737e-07 1.33931e-04 1.05457e-04 - 4.67935e-03 2.75624e-09 2.41642e-03 1.42333e-09 4.05176e-03 3.19035e-03 - 2.09234e-03 1.64750e-03 2.32566e-07 1.53743e-13 2.03133e-04 1.34286e-10 - 2.42559e-07 1.94114e-07 2.11862e-04 1.69548e-04 6.14530e-03 4.06249e-09 - 3.17345e-03 2.09788e-09 6.40937e-03 5.12926e-03 3.30981e-03 2.64876e-03 - 2.15237e-07 1.23240e-13 1.87998e-04 1.07643e-10 1.85758e-07 1.46699e-07 - 1.62249e-04 1.28134e-04 5.68742e-03 3.25649e-09 2.93699e-03 1.68166e-09 - 4.90845e-03 3.87638e-03 2.53473e-03 2.00177e-03 2.47477e-03 4.87068e-05 - 1.06189e-02 2.08993e-04 1.26298e-04 3.02426e-05 5.41924e-04 1.29766e-04 - 2.77770e-02 5.46688e-04 4.83214e-02 9.51031e-04 1.41757e-03 3.39445e-04 - 2.46604e-03 5.90506e-04 2.31220e-03 4.16752e-05 9.92129e-03 1.78822e-04 - 1.15514e-04 2.68262e-05 4.95652e-04 1.15107e-04 2.59523e-02 4.67766e-04 - 4.51471e-02 8.13735e-04 1.29654e-03 3.01100e-04 2.25548e-03 5.23800e-04 - 2.30792e-03 4.67592e-05 9.90296e-03 2.00637e-04 1.15169e-04 2.57221e-05 - 4.94175e-04 1.10370e-04 2.59043e-02 5.24828e-04 4.50637e-02 9.13003e-04 - 1.29267e-03 2.88707e-04 2.24876e-03 5.02241e-04 2.35337e-03 4.59723e-05 - 1.00979e-02 1.97260e-04 1.17182e-04 2.59928e-05 5.02809e-04 1.11531e-04 - 2.64144e-02 5.15997e-04 4.59510e-02 8.97639e-04 1.31526e-03 2.91745e-04 - 2.28805e-03 5.07527e-04][0.00566 0.00452 0.00292 0.00233 0.00405 0.00319 0.00209 0.00165 0.00641 - 0.00513 0.00331 0.00265 0.00491 0.00388 0.00253 0.002 0.00142 0.00034 - 0.00247 0.00059 0.0013 0.0003 0.00226 0.00052 0.00129 0.00029 0.00225 - 0.0005 0.00132 0.00029 0.00229 0.00051][0.00019 0.00019 0.00298 0.00292 0.00015 0.00013 0.00242 0.00209 0.0002 - 0.00021 0.00317 0.00331 0.00019 0.00016 0.00294 0.00253 0.01062 0.00054 - 0.04832 0.00247 0.00992 0.0005 0.04515 0.00226 0.0099 0.00049 0.04506 - 0.00225 0.0101 0.0005 0.04595 0.00229][0.00292 0.00209 0.00331 0.00253 0.00247 0.00226 0.00225 0.00229] \ No newline at end of file +[2.04229e-07 1.28343e-13 1.79333e-04 1.12698e-10 1.89952e-07 1.51210e-07 + 1.66796e-04 1.32777e-04 6.13215e-03 3.85362e-09 3.14746e-03 1.97795e-09 + 5.70345e-03 4.54021e-03 2.92742e-03 2.33037e-03 2.10575e-07 1.28419e-13 + 1.84905e-04 1.12764e-10 1.89188e-07 1.50221e-07 1.66125e-04 1.31908e-04 + 6.32269e-03 3.85587e-09 3.24526e-03 1.97911e-09 5.68054e-03 4.51051e-03 + 2.91566e-03 2.31512e-03 1.96696e-07 1.26388e-13 1.72718e-04 1.10981e-10 + 1.91283e-07 1.53449e-07 1.67964e-04 1.34743e-04 5.90596e-03 3.79491e-09 + 3.03136e-03 1.94782e-09 5.74342e-03 4.60742e-03 2.94794e-03 2.36486e-03 + 2.06016e-07 1.35264e-13 1.80901e-04 1.18775e-10 2.05873e-07 1.65814e-07 + 1.80776e-04 1.45600e-04 6.18579e-03 4.06142e-09 3.17499e-03 2.08461e-09 + 6.18150e-03 4.97869e-03 3.17279e-03 2.55542e-03 2.36089e-03 4.46651e-05 + 1.02263e-02 1.93469e-04 1.18179e-04 2.62375e-05 5.11897e-04 1.13649e-04 + 2.56040e-02 4.84394e-04 4.55595e-02 8.61927e-04 1.28165e-03 2.84546e-04 + 2.28056e-03 5.06320e-04 2.29877e-03 4.53056e-05 9.95724e-03 1.96244e-04 + 1.14803e-04 2.57898e-05 4.97276e-04 1.11710e-04 2.49302e-02 4.91340e-04 + 4.43606e-02 8.74289e-04 1.24504e-03 2.79691e-04 2.21542e-03 4.97680e-04 + 2.31940e-03 4.34238e-05 1.00466e-02 1.88093e-04 1.17620e-04 2.69280e-05 + 5.09479e-04 1.16640e-04 2.51540e-02 4.70932e-04 4.47588e-02 8.37974e-04 + 1.27560e-03 2.92034e-04 2.26979e-03 5.19644e-04 2.19212e-03 4.53914e-05 + 9.49530e-03 1.96615e-04 1.09609e-04 2.41615e-05 4.74778e-04 1.04657e-04 + 2.37736e-02 4.92271e-04 4.23026e-02 8.75944e-04 1.18871e-03 2.62032e-04 + 2.11519e-03 4.66257e-04][2.04229e-07 1.28343e-13 1.79333e-04 1.12698e-10 1.89952e-07 1.51210e-07 + 1.66796e-04 1.32777e-04 6.13215e-03 3.85362e-09 3.14746e-03 1.97795e-09 + 5.70345e-03 4.54021e-03 2.92742e-03 2.33037e-03 2.10575e-07 1.28419e-13 + 1.84905e-04 1.12764e-10 1.89188e-07 1.50221e-07 1.66125e-04 1.31908e-04 + 6.32269e-03 3.85587e-09 3.24526e-03 1.97911e-09 5.68054e-03 4.51051e-03 + 2.91566e-03 2.31512e-03 1.96696e-07 1.26388e-13 1.72718e-04 1.10981e-10 + 1.91283e-07 1.53449e-07 1.67964e-04 1.34743e-04 5.90596e-03 3.79491e-09 + 3.03136e-03 1.94782e-09 5.74342e-03 4.60742e-03 2.94794e-03 2.36486e-03 + 2.06016e-07 1.35264e-13 1.80901e-04 1.18775e-10 2.05873e-07 1.65814e-07 + 1.80776e-04 1.45600e-04 6.18579e-03 4.06142e-09 3.17499e-03 2.08461e-09 + 6.18150e-03 4.97869e-03 3.17279e-03 2.55542e-03 2.36089e-03 4.46651e-05 + 1.02263e-02 1.93469e-04 1.18179e-04 2.62375e-05 5.11897e-04 1.13649e-04 + 2.56040e-02 4.84394e-04 4.55595e-02 8.61927e-04 1.28165e-03 2.84546e-04 + 2.28056e-03 5.06320e-04 2.29877e-03 4.53056e-05 9.95724e-03 1.96244e-04 + 1.14803e-04 2.57898e-05 4.97276e-04 1.11710e-04 2.49302e-02 4.91340e-04 + 4.43606e-02 8.74289e-04 1.24504e-03 2.79691e-04 2.21542e-03 4.97680e-04 + 2.31940e-03 4.34238e-05 1.00466e-02 1.88093e-04 1.17620e-04 2.69280e-05 + 5.09479e-04 1.16640e-04 2.51540e-02 4.70932e-04 4.47588e-02 8.37974e-04 + 1.27560e-03 2.92034e-04 2.26979e-03 5.19644e-04 2.19212e-03 4.53914e-05 + 9.49530e-03 1.96615e-04 1.09609e-04 2.41615e-05 4.74778e-04 1.04657e-04 + 2.37736e-02 4.92271e-04 4.23026e-02 8.75944e-04 1.18871e-03 2.62032e-04 + 2.11519e-03 4.66257e-04][0.0057 0.00454 0.00293 0.00233 0.00568 0.00451 0.00292 0.00232 0.00574 + 0.00461 0.00295 0.00236 0.00618 0.00498 0.00317 0.00256 0.00128 0.00028 + 0.00228 0.00051 0.00125 0.00028 0.00222 0.0005 0.00128 0.00029 0.00227 + 0.00052 0.00119 0.00026 0.00212 0.00047][0.00018 0.00017 0.00315 0.00293 0.00018 0.00017 0.00325 0.00292 0.00017 + 0.00017 0.00303 0.00295 0.00018 0.00018 0.00317 0.00317 0.01023 0.00051 + 0.04556 0.00228 0.00996 0.0005 0.04436 0.00222 0.01005 0.00051 0.04476 + 0.00227 0.0095 0.00047 0.0423 0.00212][0.00293 0.00292 0.00295 0.00317 0.00228 0.00222 0.00227 0.00212] \ No newline at end of file diff --git a/tests/regression_tests/tally_assumesep/results_true.dat b/tests/regression_tests/tally_assumesep/results_true.dat index 5728cfc0414..9d7cbf9c3d4 100644 --- a/tests/regression_tests/tally_assumesep/results_true.dat +++ b/tests/regression_tests/tally_assumesep/results_true.dat @@ -1,11 +1,11 @@ k-combined: -6.353587E-01 1.925016E-02 +5.683578E-01 1.129170E-02 tally 1: -7.878503E+00 -1.242768E+01 +6.753950E+00 +9.188305E+00 tally 2: -2.687214E-01 -1.487262E-02 +2.278558E-01 +1.052944E-02 tally 3: -1.344654E+01 -3.630145E+01 +1.179091E+01 +2.795539E+01 diff --git a/tests/regression_tests/tally_nuclides/results_true.dat b/tests/regression_tests/tally_nuclides/results_true.dat index ad385b82a05..7f9641fc8f5 100644 --- a/tests/regression_tests/tally_nuclides/results_true.dat +++ b/tests/regression_tests/tally_nuclides/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.655280E-01 1.463557E-02 +1.132463E+00 5.721067E-02 tally 1: -6.932814E+00 -9.650528E+00 -1.591338E+00 -5.075076E-01 -1.541515E+00 -4.761914E-01 -5.341475E+00 -5.732892E+00 -6.932814E+00 -9.650528E+00 -1.591338E+00 -5.075076E-01 -1.541515E+00 -4.761914E-01 -5.341475E+00 -5.732892E+00 +7.310528E+00 +1.080411E+01 +1.664215E+00 +5.567756E-01 +1.609340E+00 +5.205634E-01 +5.646313E+00 +6.459724E+00 +7.310528E+00 +1.080411E+01 +1.664215E+00 +5.567756E-01 +1.609340E+00 +5.205634E-01 +5.646313E+00 +6.459724E+00 tally 2: -6.932814E+00 -9.650528E+00 -1.591338E+00 -5.075076E-01 -1.541515E+00 -4.761914E-01 -5.341475E+00 -5.732892E+00 +7.310528E+00 +1.080411E+01 +1.664215E+00 +5.567756E-01 +1.609340E+00 +5.205634E-01 +5.646313E+00 +6.459724E+00 diff --git a/tests/regression_tests/tally_nuclides/tallies.xml b/tests/regression_tests/tally_nuclides/tallies.xml index 3440dbf2171..ea25596a4f4 100644 --- a/tests/regression_tests/tally_nuclides/tallies.xml +++ b/tests/regression_tests/tally_nuclides/tallies.xml @@ -2,7 +2,7 @@ - all + Pu239 total total absorption fission scatter diff --git a/tests/regression_tests/tally_slice_merge/inputs_true.dat b/tests/regression_tests/tally_slice_merge/inputs_true.dat index 6f421b1d95b..356962f8e4f 100644 --- a/tests/regression_tests/tally_slice_merge/inputs_true.dat +++ b/tests/regression_tests/tally_slice_merge/inputs_true.dat @@ -1,38 +1,187 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 @@ -50,12 +199,12 @@ 1 1 1 1 1 2 1 1 2 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - 1.26 1.26 - 17 17 - -10.71 -10.71 - + + + 1.26 1.26 + 17 17 + -10.71 -10.71 + 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 @@ -73,12 +222,12 @@ 3 3 3 3 3 4 3 3 4 3 3 4 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 @@ -100,12 +249,12 @@ 5 5 5 5 5 5 5 6 6 6 6 6 6 6 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 - - - 21.42 21.42 - 21 21 - -224.91 -224.91 - + + + 21.42 21.42 + 21 21 + -224.91 -224.91 + 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 @@ -127,222 +276,72 @@ 7 7 7 7 7 7 7 8 8 8 8 8 8 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - -160 -160 -183 160 160 183 - - - - - - - - 2 2 - -50.0 -50.0 - 50.0 50.0 - - - 21 27 - - - 0.0 0.625 20000000.0 - - - 21 - - - 1 - - - 16 8 - U235 U238 - fission nu-fission - tracklength - - - 6 8 - U235 U238 - fission nu-fission - tracklength - - - 7 8 - U235 U238 - fission nu-fission - tracklength - - + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -160 -160 -183 160 160 183 + + + + + + + 2 2 + -50.0 -50.0 + 50.0 50.0 + + + 21 27 + + + 0.0 0.625 20000000.0 + + + 21 + + + 1 + + + 16 8 + U235 U238 + fission nu-fission + tracklength + + + 6 8 + U235 U238 + fission nu-fission + tracklength + + + 7 8 + U235 U238 + fission nu-fission + tracklength + + + diff --git a/tests/regression_tests/tally_slice_merge/results_true.dat b/tests/regression_tests/tally_slice_merge/results_true.dat index 84b296d64c2..58b15fc18d9 100644 --- a/tests/regression_tests/tally_slice_merge/results_true.dat +++ b/tests/regression_tests/tally_slice_merge/results_true.dat @@ -1,45 +1,45 @@ cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U235 fission 1.77e-01 1.81e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U235 nu-fission 4.32e-01 4.42e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U238 fission 2.43e-07 2.40e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U238 nu-fission 6.07e-07 5.97e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 6.25e-01 2.00e+07 U235 fission 3.03e-02 1.93e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 6.25e-01 2.00e+07 U235 nu-fission 7.41e-02 4.67e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 6.25e-01 2.00e+07 U238 fission 1.65e-02 1.61e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 6.25e-01 2.00e+07 U238 nu-fission 4.61e-02 4.87e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-01 U235 fission 1.31e-01 2.54e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-01 U235 nu-fission 3.18e-01 6.19e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-01 U238 fission 1.80e-07 3.46e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 0.00e+00 6.25e-01 U238 nu-fission 4.49e-07 8.62e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 6.25e-01 2.00e+07 U235 fission 2.34e-02 1.23e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 6.25e-01 2.00e+07 U235 nu-fission 5.72e-02 2.99e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 6.25e-01 2.00e+07 U238 fission 1.24e-02 9.35e-04 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 27 6.25e-01 2.00e+07 U238 nu-fission 3.44e-02 2.73e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. -0 21 0.00e+00 6.25e-01 U235 fission 1.77e-01 1.81e-02 -1 21 0.00e+00 6.25e-01 U235 nu-fission 4.32e-01 4.42e-02 -2 21 0.00e+00 6.25e-01 U238 fission 2.43e-07 2.40e-08 -3 21 0.00e+00 6.25e-01 U238 nu-fission 6.07e-07 5.97e-08 -4 21 6.25e-01 2.00e+07 U235 fission 3.03e-02 1.93e-03 -5 21 6.25e-01 2.00e+07 U235 nu-fission 7.41e-02 4.67e-03 -6 21 6.25e-01 2.00e+07 U238 fission 1.65e-02 1.61e-03 -7 21 6.25e-01 2.00e+07 U238 nu-fission 4.61e-02 4.87e-03 -8 27 0.00e+00 6.25e-01 U235 fission 1.31e-01 2.54e-02 -9 27 0.00e+00 6.25e-01 U235 nu-fission 3.18e-01 6.19e-02 -10 27 0.00e+00 6.25e-01 U238 fission 1.80e-07 3.46e-08 -11 27 0.00e+00 6.25e-01 U238 nu-fission 4.49e-07 8.62e-08 -12 27 6.25e-01 2.00e+07 U235 fission 2.34e-02 1.23e-03 -13 27 6.25e-01 2.00e+07 U235 nu-fission 5.72e-02 2.99e-03 -14 27 6.25e-01 2.00e+07 U238 fission 1.24e-02 9.35e-04 -15 27 6.25e-01 2.00e+07 U238 nu-fission 3.44e-02 2.73e-03 +0 21 0.00e+00 6.25e-01 U235 fission 1.75e-01 1.20e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-01 U235 nu-fission 4.26e-01 2.92e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-01 U238 fission 2.41e-07 1.61e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-01 U238 nu-fission 6.00e-07 4.01e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 6.25e-01 2.00e+07 U235 fission 2.89e-02 2.07e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 6.25e-01 2.00e+07 U235 nu-fission 7.07e-02 5.06e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 6.25e-01 2.00e+07 U238 fission 1.41e-02 5.76e-04 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 6.25e-01 2.00e+07 U238 nu-fission 3.95e-02 1.90e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-01 U235 fission 1.51e-01 1.17e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-01 U235 nu-fission 3.69e-01 2.86e-02 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-01 U238 fission 2.07e-07 1.47e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 0.00e+00 6.25e-01 U238 nu-fission 5.17e-07 3.66e-08 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 6.25e-01 2.00e+07 U235 fission 2.57e-02 2.43e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 6.25e-01 2.00e+07 U235 nu-fission 6.30e-02 5.92e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 6.25e-01 2.00e+07 U238 fission 1.47e-02 1.41e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 27 6.25e-01 2.00e+07 U238 nu-fission 4.12e-02 4.02e-03 cell energy low [eV] energy high [eV] nuclide score mean std. dev. +0 21 0.00e+00 6.25e-01 U235 fission 1.75e-01 1.20e-02 +1 21 0.00e+00 6.25e-01 U235 nu-fission 4.26e-01 2.92e-02 +2 21 0.00e+00 6.25e-01 U238 fission 2.41e-07 1.61e-08 +3 21 0.00e+00 6.25e-01 U238 nu-fission 6.00e-07 4.01e-08 +4 21 6.25e-01 2.00e+07 U235 fission 2.89e-02 2.07e-03 +5 21 6.25e-01 2.00e+07 U235 nu-fission 7.07e-02 5.06e-03 +6 21 6.25e-01 2.00e+07 U238 fission 1.41e-02 5.76e-04 +7 21 6.25e-01 2.00e+07 U238 nu-fission 3.95e-02 1.90e-03 +8 27 0.00e+00 6.25e-01 U235 fission 1.51e-01 1.17e-02 +9 27 0.00e+00 6.25e-01 U235 nu-fission 3.69e-01 2.86e-02 +10 27 0.00e+00 6.25e-01 U238 fission 2.07e-07 1.47e-08 +11 27 0.00e+00 6.25e-01 U238 nu-fission 5.17e-07 3.66e-08 +12 27 6.25e-01 2.00e+07 U235 fission 2.57e-02 2.43e-03 +13 27 6.25e-01 2.00e+07 U235 nu-fission 6.30e-02 5.92e-03 +14 27 6.25e-01 2.00e+07 U238 fission 1.47e-02 1.41e-03 +15 27 6.25e-01 2.00e+07 U238 nu-fission 4.12e-02 4.02e-03 sum(distribcell) energy low [eV] energy high [eV] nuclide score mean std. dev. 0 (0, 100, 2000, 30000) 0.00e+00 6.25e-01 U235 fission 0.00e+00 0.00e+00 1 (0, 100, 2000, 30000) 0.00e+00 6.25e-01 U235 nu-fission 0.00e+00 0.00e+00 2 (0, 100, 2000, 30000) 0.00e+00 6.25e-01 U238 fission 0.00e+00 0.00e+00 3 (0, 100, 2000, 30000) 0.00e+00 6.25e-01 U238 nu-fission 0.00e+00 0.00e+00 -4 (0, 100, 2000, 30000) 6.25e-01 2.00e+07 U235 fission 0.00e+00 0.00e+00 -5 (0, 100, 2000, 30000) 6.25e-01 2.00e+07 U235 nu-fission 0.00e+00 0.00e+00 -6 (0, 100, 2000, 30000) 6.25e-01 2.00e+07 U238 fission 0.00e+00 0.00e+00 -7 (0, 100, 2000, 30000) 6.25e-01 2.00e+07 U238 nu-fission 0.00e+00 0.00e+00 +4 (0, 100, 2000, 30000) 6.25e-01 2.00e+07 U235 fission 9.53e-07 9.53e-07 +5 (0, 100, 2000, 30000) 6.25e-01 2.00e+07 U235 nu-fission 2.37e-06 2.37e-06 +6 (0, 100, 2000, 30000) 6.25e-01 2.00e+07 U238 fission 1.25e-08 1.25e-08 +7 (0, 100, 2000, 30000) 6.25e-01 2.00e+07 U238 nu-fission 3.15e-08 3.15e-08 8 (500, 5000, 50000) 0.00e+00 6.25e-01 U235 fission 0.00e+00 0.00e+00 9 (500, 5000, 50000) 0.00e+00 6.25e-01 U235 nu-fission 0.00e+00 0.00e+00 10 (500, 5000, 50000) 0.00e+00 6.25e-01 U238 fission 0.00e+00 0.00e+00 @@ -49,19 +49,19 @@ 14 (500, 5000, 50000) 6.25e-01 2.00e+07 U238 fission 0.00e+00 0.00e+00 15 (500, 5000, 50000) 6.25e-01 2.00e+07 U238 nu-fission 0.00e+00 0.00e+00 sum(mesh) energy low [eV] energy high [eV] nuclide score mean std. dev. -0 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U235 fission 2.75e-02 4.32e-03 -1 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U235 nu-fission 6.71e-02 1.05e-02 -2 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U238 fission 3.78e-08 5.83e-09 -3 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U238 nu-fission 9.42e-08 1.45e-08 -4 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U235 fission 3.96e-03 7.84e-04 -5 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U235 nu-fission 9.71e-03 1.91e-03 -6 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U238 fission 3.92e-03 8.53e-04 -7 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U238 nu-fission 1.08e-02 2.25e-03 -8 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U235 fission 5.42e-02 2.50e-02 -9 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U235 nu-fission 1.32e-01 6.10e-02 -10 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U238 fission 7.47e-08 3.42e-08 -11 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U238 nu-fission 1.86e-07 8.53e-08 -12 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U235 fission 6.58e-03 2.03e-03 -13 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U235 nu-fission 1.61e-02 4.95e-03 -14 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U238 fission 3.74e-03 1.12e-03 -15 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U238 nu-fission 1.05e-02 3.20e-03 +0 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U235 fission 6.73e-03 3.04e-03 +1 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U235 nu-fission 1.64e-02 7.40e-03 +2 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U238 fission 8.80e-09 3.84e-09 +3 ((1, 1), (1, 2)) 0.00e+00 6.25e-01 U238 nu-fission 2.19e-08 9.56e-09 +4 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U235 fission 9.89e-04 3.53e-04 +5 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U235 nu-fission 2.42e-03 8.60e-04 +6 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U238 fission 5.01e-04 2.13e-04 +7 ((1, 1), (1, 2)) 6.25e-01 2.00e+07 U238 nu-fission 1.36e-03 5.86e-04 +8 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U235 fission 1.63e-02 4.21e-03 +9 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U235 nu-fission 3.98e-02 1.02e-02 +10 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U238 fission 2.28e-08 5.90e-09 +11 ((2, 1), (2, 2)) 0.00e+00 6.25e-01 U238 nu-fission 5.67e-08 1.47e-08 +12 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U235 fission 1.79e-03 4.31e-04 +13 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U235 nu-fission 4.37e-03 1.05e-03 +14 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U238 fission 7.51e-04 2.51e-04 +15 ((2, 1), (2, 2)) 6.25e-01 2.00e+07 U238 nu-fission 2.02e-03 6.71e-04 diff --git a/tests/regression_tests/time_cutoff/__init__.py b/tests/regression_tests/time_cutoff/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/time_cutoff/inputs_true.dat b/tests/regression_tests/time_cutoff/inputs_true.dat new file mode 100644 index 00000000000..7d3e94f50f9 --- /dev/null +++ b/tests/regression_tests/time_cutoff/inputs_true.dat @@ -0,0 +1,34 @@ + + + + + + + + + + fixed source + 100 + 10 + + + 0.0 0.0 0.0 + + + 10000.0 1.0 + + + + 1e-07 + + + + + 0.0 1e-07 2e-07 + + + 1 + flux + + + diff --git a/tests/regression_tests/time_cutoff/results_true.dat b/tests/regression_tests/time_cutoff/results_true.dat new file mode 100644 index 00000000000..1cafceb772e --- /dev/null +++ b/tests/regression_tests/time_cutoff/results_true.dat @@ -0,0 +1,5 @@ +tally 1: +2.000000E+03 +4.000000E+05 +0.000000E+00 +0.000000E+00 diff --git a/tests/regression_tests/time_cutoff/test.py b/tests/regression_tests/time_cutoff/test.py new file mode 100755 index 00000000000..9554a6e2a00 --- /dev/null +++ b/tests/regression_tests/time_cutoff/test.py @@ -0,0 +1,42 @@ +import openmc +import pytest + +from tests.testing_harness import PyAPITestHarness + + +@pytest.fixture +def time_model(): + model = openmc.Model() + time_cutoff = 1e-7 + + # A single sphere + s1 = openmc.Sphere(r=200, boundary_type='vacuum') + sphere = openmc.Cell() + sphere.region = -s1 + model.geometry = openmc.Geometry([sphere]) + + # Set the running parameters + settings_file = openmc.Settings() + settings_file.run_mode = 'fixed source' + settings_file.batches = 10 + settings_file.particles = 100 + settings_file.cutoff = {'time_neutron': time_cutoff} + settings_file.source = openmc.IndependentSource( + space=openmc.stats.Point(), energy=openmc.stats.Discrete([1e4], [1])) + model.settings = settings_file + + # Tally flux under time cutoff + tallies = openmc.Tallies() + tally = openmc.Tally() + tally.scores = ['flux'] + time_filter = openmc.TimeFilter([0, time_cutoff, 2*time_cutoff]) + tally.filters = [time_filter] + tallies.append(tally) + model.tallies = tallies + + return model + + +def test_time_cutoff(time_model): + harness = PyAPITestHarness('statepoint.10.h5', time_model) + harness.main() diff --git a/tests/regression_tests/torus/__init__.py b/tests/regression_tests/torus/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/torus/inputs_true.dat b/tests/regression_tests/torus/inputs_true.dat new file mode 100644 index 00000000000..a5c7a8d7aee --- /dev/null +++ b/tests/regression_tests/torus/inputs_true.dat @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + diff --git a/tests/regression_tests/torus/large_major/__init__.py b/tests/regression_tests/torus/large_major/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/torus/large_major/inputs_true.dat b/tests/regression_tests/torus/large_major/inputs_true.dat new file mode 100644 index 00000000000..fa7deb29a87 --- /dev/null +++ b/tests/regression_tests/torus/large_major/inputs_true.dat @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + -1000.0 0 0 + + + + + + flux + + + diff --git a/tests/regression_tests/torus/large_major/results_true.dat b/tests/regression_tests/torus/large_major/results_true.dat new file mode 100644 index 00000000000..cb9f54970ca --- /dev/null +++ b/tests/regression_tests/torus/large_major/results_true.dat @@ -0,0 +1,3 @@ +tally 1: +9.675396E+02 +9.363406E+04 diff --git a/tests/regression_tests/torus/large_major/test.py b/tests/regression_tests/torus/large_major/test.py new file mode 100644 index 00000000000..1ce1ab2cac8 --- /dev/null +++ b/tests/regression_tests/torus/large_major/test.py @@ -0,0 +1,41 @@ +import openmc +import pytest + +from tests.testing_harness import PyAPITestHarness + + +@pytest.fixture +def model(): + model = openmc.Model() + tungsten = openmc.Material() + tungsten.set_density('g/cm3', 1.0) + tungsten.add_nuclide('W184', 1.0) + ss = openmc.Material() + ss.set_density('g/cm3', 5.0) + ss.add_nuclide('Fe56', 1.0) + model.materials.extend([tungsten, ss]) + + # Create nested torii with very large major radii + R = 1000.0 + vacuum = openmc.ZTorus(a=R, b=30.0, c=30.0) + first_wall = openmc.ZTorus(a=R, b=35.0, c=35.0) + vessel = openmc.ZTorus(a=R, b=40.0, c=40.0, boundary_type='vacuum') + cell1 = openmc.Cell(region=-vacuum) + cell2 = openmc.Cell(fill=tungsten, region=+vacuum & -first_wall) + cell3 = openmc.Cell(fill=ss, region=+first_wall & -vessel) + model.geometry = openmc.Geometry([cell1, cell2, cell3]) + + model.settings.run_mode ='fixed source' + model.settings.particles = 1000 + model.settings.batches = 10 + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point((-R, 0, 0,))) + + tally = openmc.Tally() + tally.scores = ['flux'] + model.tallies.append(tally) + return model + + +def test_torus_large_major(model): + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/torus/results_true.dat b/tests/regression_tests/torus/results_true.dat new file mode 100644 index 00000000000..42fb209cce3 --- /dev/null +++ b/tests/regression_tests/torus/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +7.667201E-01 1.136882E-02 diff --git a/tests/regression_tests/torus/test.py b/tests/regression_tests/torus/test.py new file mode 100644 index 00000000000..8970a5cc77d --- /dev/null +++ b/tests/regression_tests/torus/test.py @@ -0,0 +1,39 @@ +import openmc +import pytest + +from tests.testing_harness import PyAPITestHarness + + +@pytest.fixture +def model(): + model = openmc.Model() + fuel = openmc.Material() + fuel.set_density('g/cm3', 12.0) + fuel.add_nuclide('U235', 1.0) + al = openmc.Material() + al.set_density('g/cm3', 1.0) + al.add_nuclide('H1', 1.0) + model.materials.extend([fuel, al]) + + # 🍩🍩🍩 + zt = openmc.ZTorus(a=3, b=1.5, c=1) + xt = openmc.XTorus(x0=6, a=3, b=1.5, c=1) + yt = openmc.YTorus(x0=6, a=6, b=1, c=0.75) + box = openmc.model.RectangularParallelepiped(-5, 14, -5, 5, -8, 8, + boundary_type='vacuum') + + xt_cell = openmc.Cell(fill=fuel, region=-xt) + yt_cell = openmc.Cell(fill=fuel, region=-yt) + zt_cell = openmc.Cell(fill=fuel, region=-zt) + outer_cell = openmc.Cell(fill=al, region=-box & +xt & +yt & +zt) + model.geometry = openmc.Geometry([xt_cell, yt_cell, zt_cell, outer_cell]) + + model.settings.particles = 1000 + model.settings.batches = 10 + model.settings.inactive = 5 + return model + + +def test_torus(model): + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/trace/results_true.dat b/tests/regression_tests/trace/results_true.dat index fe46748c80d..bbf03de9437 100644 --- a/tests/regression_tests/trace/results_true.dat +++ b/tests/regression_tests/trace/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.987050E-01 1.827430E-03 +3.070134E-01 3.900396E-03 diff --git a/tests/regression_tests/track_output/geometry.xml b/tests/regression_tests/track_output/geometry.xml deleted file mode 100644 index 5b16fe26cdd..00000000000 --- a/tests/regression_tests/track_output/geometry.xml +++ /dev/null @@ -1,305 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -12.2682 -12.2682 - 1.63576 1.63576 - - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 - 2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 - 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - - - - -12.2682 -12.2682 - 1.63576 1.63576 - - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 - 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 - 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - - - - - - - -12.2682 -12.2682 - 1.63576 1.63576 - - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 - 2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 3 2 2 2 2 2 2 2 1 2 2 2 - 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - - - - - - - - - -12.2682 -12.2682 - 1.63576 1.63576 - - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - - - - -12.2682 -12.2682 - 1.63576 1.63576 - - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - - - - - - - -12.2682 -12.2682 - 1.63576 1.63576 - - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 - 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 - 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 - - - - - - - - - - -12.2682 -12.2682 - 1.63576 1.63576 - - 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 - 2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - - - - - - - - -12.2682 -12.2682 - 1.63576 1.63576 - - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - - - - - - - - - - -12.2682 -12.2682 - 1.63576 1.63576 - - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 - - - - - - - - - - - - - - - - - - - -85.8774 -85.8774 - 24.5364 24.5364 - - 999 999 130 140 150 999 999 - 999 220 230 240 250 260 999 - 130 320 777 222 333 360 150 - 410 240 444 111 666 240 470 - 510 520 888 555 998 560 570 - 999 620 630 240 650 660 999 - 999 999 510 740 570 999 999 - - - - - - - - diff --git a/tests/regression_tests/track_output/materials.xml b/tests/regression_tests/track_output/materials.xml deleted file mode 100644 index 5dc9a647554..00000000000 --- a/tests/regression_tests/track_output/materials.xml +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/regression_tests/track_output/model.xml b/tests/regression_tests/track_output/model.xml new file mode 100644 index 00000000000..36ccb2b4682 --- /dev/null +++ b/tests/regression_tests/track_output/model.xml @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.63576 1.63576 + 15 15 + -12.2682 -12.2682 + +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 +2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 +2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + 1.63576 1.63576 + 15 15 + -12.2682 -12.2682 + +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + 1.63576 1.63576 + 15 15 + -12.2682 -12.2682 + +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 +2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 +2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 + + + 1.63576 1.63576 + 15 15 + -12.2682 -12.2682 + +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 +2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 3 2 2 2 2 2 2 2 3 2 2 2 +2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + 1.63576 1.63576 + 15 15 + -12.2682 -12.2682 + +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + 1.63576 1.63576 + 15 15 + -12.2682 -12.2682 + +2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 +2 2 2 1 1 1 1 1 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + 1.63576 1.63576 + 15 15 + -12.2682 -12.2682 + +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 + + + 1.63576 1.63576 + 15 15 + -12.2682 -12.2682 + +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 +2 2 2 1 2 2 2 2 2 2 2 1 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 1 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 1 2 2 1 2 2 2 1 2 2 1 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 3 2 2 2 2 2 2 2 1 2 2 2 +2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + 1.63576 1.63576 + 15 15 + -12.2682 -12.2682 + +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 1 1 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 +2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 + + + 24.5364 24.5364 + 7 7 + -85.8774 -85.8774 + +999 999 130 140 150 999 999 +999 220 230 240 250 260 999 +130 320 777 222 333 360 150 +410 240 444 111 666 240 470 +510 520 888 555 998 560 570 +999 620 630 240 650 660 999 +999 999 510 740 570 999 999 + + + + + + + + + + + + eigenvalue + 100 + 2 + 0 + + + -1.0 -1.0 -1.0 1.0 1.0 1.0 + + + 1 1 1 1 1 30 2 1 60 + + diff --git a/tests/regression_tests/track_output/results_true.dat b/tests/regression_tests/track_output/results_true.dat index 1d0ca803992..148b54a30b0 100644 --- a/tests/regression_tests/track_output/results_true.dat +++ b/tests/regression_tests/track_output/results_true.dat @@ -1,9 +1,218 @@ - - - - - - - - - +neutron [((-9.663085e-01, -6.616522e-01, -9.863690e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 0.000000e+00, 1.000000e+00, 23, 2403, 1) + ((-1.281491e+00, -4.879529e-01, -7.708709e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 1.323629e-10, 1.000000e+00, 22, 2403, 3) + ((-1.368452e+00, -4.400285e-01, -7.114141e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 1.688824e-10, 1.000000e+00, 21, 2403, 2) + ((-2.150539e+00, -9.015151e-03, -1.766823e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 4.973246e-10, 1.000000e+00, 22, 2403, 3) + ((-2.237499e+00, 3.890922e-02, -1.172255e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 5.338441e-10, 1.000000e+00, 23, 2403, 1) + ((-2.453640e+00, 1.580257e-01, 3.055504e-02), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 6.246136e-10, 1.000000e+00, 23, 2402, 1) + ((-2.767485e+00, 3.309877e-01, 2.451383e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 7.564146e-10, 1.000000e+00, 22, 2402, 3) + ((-2.825099e+00, 3.627392e-01, 2.845305e-01), (-6.842434e-01, 3.658561e-01, 6.308409e-01), 5.292729e+06, 7.806100e-10, 1.000000e+00, 22, 2402, 3) + ((-3.274427e+00, 6.029890e-01, 6.987901e-01), (-6.842434e-01, 3.658561e-01, 6.308409e-01), 5.292729e+06, 9.878481e-10, 1.000000e+00, 23, 2402, 1) + ((-3.676327e+00, 8.178800e-01, 1.069324e+00), (-6.842434e-01, 3.658561e-01, 6.308409e-01), 5.292729e+06, 1.173212e-09, 1.000000e+00, 23, 2416, 1) + ((-4.089400e+00, 1.038745e+00, 1.450158e+00), (-6.842434e-01, 3.658561e-01, 6.308409e-01), 5.292729e+06, 1.363728e-09, 1.000000e+00, 23, 2415, 1) + ((-4.456639e+00, 1.235102e+00, 1.788735e+00), (-6.842434e-01, 3.658561e-01, 6.308409e-01), 5.292729e+06, 1.533105e-09, 1.000000e+00, 22, 2415, 3) + ((-4.536974e+00, 1.278056e+00, 1.862800e+00), (-6.842434e-01, 3.658561e-01, 6.308409e-01), 5.292729e+06, 1.570157e-09, 1.000000e+00, 21, 2415, 2) + ((-5.410401e+00, 1.745067e+00, 2.668060e+00), (-6.842434e-01, 3.658561e-01, 6.308409e-01), 5.292729e+06, 1.972998e-09, 1.000000e+00, 22, 2415, 3) + ((-5.490736e+00, 1.788021e+00, 2.742125e+00), (-6.842434e-01, 3.658561e-01, 6.308409e-01), 5.292729e+06, 2.010050e-09, 1.000000e+00, 23, 2415, 1) + ((-5.576301e+00, 1.833771e+00, 2.821012e+00), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 2.049514e-09, 1.000000e+00, 23, 2415, 1) + ((-5.725160e+00, 1.896661e+00, 2.330311e+00), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 2.227030e-09, 1.000000e+00, 23, 2414, 1) + ((-6.116514e+00, 2.061999e+00, 1.040248e+00), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 2.693724e-09, 1.000000e+00, 22, 2414, 3) + ((-6.534762e+00, 2.238699e+00, -3.384686e-01), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 3.192489e-09, 1.000000e+00, 23, 2414, 1) + ((-7.043525e+00, 2.453640e+00, -2.015560e+00), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 3.799195e-09, 1.000000e+00, 23, 2428, 1) + ((-7.360920e+00, 2.587732e+00, -3.061825e+00), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 4.177692e-09, 1.000000e+00, 11, 1757, 1) + ((-8.996680e+00, 3.278803e+00, -8.453960e+00), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 6.128354e-09, 1.000000e+00, 23, 2427, 1) + ((-9.220205e+00, 3.373238e+00, -9.190791e+00), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 6.394910e-09, 1.000000e+00, 22, 2427, 3) + ((-9.320244e+00, 3.415502e+00, -9.520561e+00), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 6.514208e-09, 1.000000e+00, 21, 2427, 2) + ((-1.005591e+01, 3.726304e+00, -1.194562e+01), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 7.391498e-09, 1.000000e+00, 22, 2427, 3) + ((-1.015595e+01, 3.768569e+00, -1.227539e+01), (-2.881377e-01, 1.217316e-01, -9.498200e-01), 4.458753e+06, 7.510796e-09, 1.000000e+00, 23, 2427, 1) + ((-1.062054e+01, 3.964848e+00, -1.380687e+01), (-5.395885e-01, 2.109921e-01, -8.150623e-01), 4.068754e+06, 8.064826e-09, 1.000000e+00, 23, 2427, 1) + ((-1.063244e+01, 3.969501e+00, -1.382484e+01), (-5.395885e-01, 2.109921e-01, -8.150623e-01), 4.068754e+06, 8.072756e-09, 1.000000e+00, 23, 2426, 1) + ((-1.093907e+01, 4.089400e+00, -1.428802e+01), (-5.395885e-01, 2.109921e-01, -8.150623e-01), 4.068754e+06, 8.277097e-09, 1.000000e+00, 23, 2437, 1) + ((-1.108410e+01, 4.146112e+00, -1.450710e+01), (4.855193e-01, 3.316053e-01, -8.088937e-01), 8.856868e+05, 8.373750e-09, 1.000000e+00, 23, 2437, 1) + ((-1.080173e+01, 4.338973e+00, -1.497755e+01), (2.818553e-01, 5.419536e-02, -9.579251e-01), 7.653670e+05, 8.820862e-09, 1.000000e+00, 23, 2437, 1) + ((-1.063244e+01, 4.371524e+00, -1.555290e+01), (2.818553e-01, 5.419536e-02, -9.579251e-01), 7.653670e+05, 9.317522e-09, 1.000000e+00, 23, 2438, 1) + ((-1.041266e+01, 4.413783e+00, -1.629984e+01), (2.686183e-01, -3.269476e-01, -9.060626e-01), 6.562001e+05, 9.962308e-09, 1.000000e+00, 23, 2438, 1) + ((-1.016754e+01, 4.115428e+00, -1.712667e+01), (-6.340850e-01, -7.142137e-01, -2.963697e-01), 7.155058e+04, 1.077718e-08, 1.000000e+00, 23, 2438, 1) + ((-1.019064e+01, 4.089400e+00, -1.713747e+01), (-6.340850e-01, -7.142137e-01, -2.963697e-01), 7.155058e+04, 1.087569e-08, 1.000000e+00, 23, 2427, 1) + ((-1.024915e+01, 4.023496e+00, -1.716481e+01), (1.827568e-01, -7.452255e-01, -6.412791e-01), 2.628504e+04, 1.112511e-08, 1.000000e+00, 23, 2427, 1) + ((-1.018199e+01, 3.749638e+00, -1.740047e+01), (1.827568e-01, -7.452255e-01, -6.412791e-01), 2.628504e+04, 1.276389e-08, 1.000000e+00, 22, 2427, 3) + ((-1.015866e+01, 3.654498e+00, -1.748234e+01), (1.827568e-01, -7.452255e-01, -6.412791e-01), 2.628504e+04, 1.333321e-08, 1.000000e+00, 21, 2427, 2) + ((-1.009978e+01, 3.414404e+00, -1.768895e+01), (1.735861e-01, -9.678731e-01, 1.819053e-01), 2.620416e+04, 1.476994e-08, 1.000000e+00, 21, 2427, 2) + ((-9.994809e+00, 2.829099e+00, -1.757894e+01), (4.635724e-01, 5.558106e-01, 6.900545e-01), 2.214649e+04, 1.747088e-08, 1.000000e+00, 21, 2427, 2) + ((-9.553365e+00, 3.358379e+00, -1.692183e+01), (-5.990363e-01, 3.483710e-01, -7.209668e-01), 1.813617e+04, 2.209726e-08, 1.000000e+00, 21, 2427, 2) + ((-1.011854e+01, 3.687059e+00, -1.760205e+01), (-5.990363e-01, 3.483710e-01, -7.209668e-01), 1.813617e+04, 2.716243e-08, 1.000000e+00, 22, 2427, 3) + ((-1.020058e+01, 3.734765e+00, -1.770077e+01), (-5.990363e-01, 3.483710e-01, -7.209668e-01), 1.813617e+04, 2.789760e-08, 1.000000e+00, 23, 2427, 1) + ((-1.063244e+01, 3.985917e+00, -1.822054e+01), (-5.990363e-01, 3.483710e-01, -7.209668e-01), 1.813617e+04, 3.176800e-08, 1.000000e+00, 23, 2426, 1) + ((-1.081038e+01, 4.089400e+00, -1.843470e+01), (-5.990363e-01, 3.483710e-01, -7.209668e-01), 1.813617e+04, 3.336273e-08, 1.000000e+00, 23, 2437, 1) + ((-1.081564e+01, 4.092455e+00, -1.844103e+01), (-6.690877e-01, 6.718700e-01, -3.176671e-01), 1.355236e+04, 3.340982e-08, 1.000000e+00, 23, 2437, 1) + ((-1.096190e+01, 4.239327e+00, -1.851047e+01), (-5.904492e-01, 8.058629e-01, 4.421237e-02), 1.153343e+04, 3.476743e-08, 1.000000e+00, 23, 2437, 1) + ((-1.109457e+01, 4.420404e+00, -1.850054e+01), (-5.904492e-01, 8.058629e-01, 4.421237e-02), 1.153343e+04, 3.628014e-08, 1.000000e+00, 22, 2437, 3) + ((-1.113484e+01, 4.475368e+00, -1.849752e+01), (-3.382310e-01, -9.403895e-01, -3.560132e-02), 1.114105e+04, 3.673931e-08, 1.000000e+00, 22, 2437, 3) + ((-1.117187e+01, 4.372425e+00, -1.850142e+01), (-3.382310e-01, -9.403895e-01, -3.560132e-02), 1.114105e+04, 3.748914e-08, 1.000000e+00, 23, 2437, 1) + ((-1.127367e+01, 4.089400e+00, -1.851213e+01), (-3.382310e-01, -9.403895e-01, -3.560132e-02), 1.114105e+04, 3.955064e-08, 1.000000e+00, 23, 2426, 1) + ((-1.135375e+01, 3.866733e+00, -1.852056e+01), (-3.382310e-01, -9.403895e-01, -3.560132e-02), 1.114105e+04, 4.117251e-08, 1.000000e+00, 22, 2426, 3) + ((-1.138419e+01, 3.782113e+00, -1.852377e+01), (-3.382310e-01, -9.403895e-01, -3.560132e-02), 1.114105e+04, 4.178887e-08, 1.000000e+00, 21, 2426, 2) + ((-1.172456e+01, 2.835777e+00, -1.855959e+01), (-3.382310e-01, -9.403895e-01, -3.560132e-02), 1.114105e+04, 4.868184e-08, 1.000000e+00, 22, 2426, 3) + ((-1.175499e+01, 2.751157e+00, -1.856280e+01), (-3.382310e-01, -9.403895e-01, -3.560132e-02), 1.114105e+04, 4.929820e-08, 1.000000e+00, 23, 2426, 1) + ((-1.179525e+01, 2.639224e+00, -1.856703e+01), (-4.738733e-01, -7.934600e-01, 3.819231e-01), 8.873828e+03, 5.011351e-08, 1.000000e+00, 23, 2426, 1) + ((-1.190609e+01, 2.453640e+00, -1.847770e+01), (-4.738733e-01, -7.934600e-01, 3.819231e-01), 8.873828e+03, 5.190861e-08, 1.000000e+00, 23, 2411, 1) + ((-1.222017e+01, 1.927741e+00, -1.822457e+01), (-5.716267e-01, 2.823908e-01, 7.703884e-01), 1.028345e+03, 5.699551e-08, 1.000000e+00, 23, 2411, 1) + ((-1.226820e+01, 1.951470e+00, -1.815983e+01), (-5.716267e-01, 2.823908e-01, 7.703884e-01), 1.028345e+03, 5.888995e-08, 1.000000e+00, 23, 2100, 1) + ((-1.236181e+01, 1.997712e+00, -1.803368e+01), (1.748787e-01, 6.613493e-01, 7.294070e-01), 4.250133e+02, 6.258186e-08, 1.000000e+00, 23, 2100, 1) + ((-1.234968e+01, 2.043587e+00, -1.798308e+01), (-6.043263e-01, 1.493281e-01, 7.826180e-01), 4.022525e+02, 6.501444e-08, 1.000000e+00, 23, 2100, 1) + ((-1.276513e+01, 2.146245e+00, -1.744506e+01), (-6.043263e-01, 1.493281e-01, 7.826180e-01), 4.022525e+02, 8.979603e-08, 1.000000e+00, 22, 2100, 3) + ((-1.313233e+01, 2.236980e+00, -1.696953e+01), (-6.043263e-01, 1.493281e-01, 7.826180e-01), 4.022525e+02, 1.116994e-07, 1.000000e+00, 23, 2100, 1) + ((-1.318468e+01, 2.249916e+00, -1.690173e+01), (-8.862976e-01, -6.402442e-02, 4.586692e-01), 3.113244e+02, 1.148223e-07, 1.000000e+00, 23, 2100, 1) + ((-1.363685e+01, 2.217253e+00, -1.666773e+01), (5.149966e-01, 4.184610e-01, -7.481102e-01), 2.471907e+02, 1.357269e-07, 1.000000e+00, 23, 2100, 1) + ((-1.334593e+01, 2.453640e+00, -1.709033e+01), (5.149966e-01, 4.184610e-01, -7.481102e-01), 2.471907e+02, 1.617034e-07, 1.000000e+00, 23, 2101, 1) + ((-1.308145e+01, 2.668542e+00, -1.747452e+01), (5.149966e-01, 4.184610e-01, -7.481102e-01), 2.471907e+02, 1.853189e-07, 1.000000e+00, 22, 2101, 3) + ((-1.304150e+01, 2.701005e+00, -1.753256e+01), (-1.624676e-01, -9.847331e-01, 6.248920e-02), 2.387811e+02, 1.888862e-07, 1.000000e+00, 22, 2101, 3) + ((-1.304665e+01, 2.669815e+00, -1.753058e+01), (-1.624676e-01, -9.847331e-01, 6.248920e-02), 2.387811e+02, 1.903682e-07, 1.000000e+00, 23, 2101, 1) + ((-1.308231e+01, 2.453640e+00, -1.751686e+01), (-1.624676e-01, -9.847331e-01, 6.248920e-02), 2.387811e+02, 2.006392e-07, 1.000000e+00, 23, 2100, 1) + ((-1.311790e+01, 2.237916e+00, -1.750317e+01), (-1.624676e-01, -9.847331e-01, 6.248920e-02), 2.387811e+02, 2.108888e-07, 1.000000e+00, 22, 2100, 3) + ((-1.313266e+01, 2.148507e+00, -1.749750e+01), (-1.624676e-01, -9.847331e-01, 6.248920e-02), 2.387811e+02, 2.151369e-07, 1.000000e+00, 21, 2100, 2) + ((-1.320190e+01, 1.728791e+00, -1.747087e+01), (1.090151e-01, 4.333767e-01, -8.945950e-01), 2.357642e+02, 2.350787e-07, 1.000000e+00, 21, 2100, 2) + ((-1.309582e+01, 2.150526e+00, -1.834143e+01), (1.090151e-01, 4.333767e-01, -8.945950e-01), 2.357642e+02, 2.808996e-07, 1.000000e+00, 22, 2100, 3) + ((-1.307365e+01, 2.238628e+00, -1.852329e+01), (1.090151e-01, 4.333767e-01, -8.945950e-01), 2.357642e+02, 2.904717e-07, 1.000000e+00, 23, 2100, 1) + ((-1.301957e+01, 2.453640e+00, -1.896713e+01), (1.090151e-01, 4.333767e-01, -8.945950e-01), 2.357642e+02, 3.138324e-07, 1.000000e+00, 23, 2101, 1) + ((-1.297913e+01, 2.614390e+00, -1.929896e+01), (6.012134e-01, 7.985735e-01, -2.868317e-02), 4.041011e+01, 3.312976e-07, 1.000000e+00, 23, 2101, 1) + ((-1.295975e+01, 2.640133e+00, -1.929988e+01), (6.762805e-01, -5.875192e-01, 4.443713e-01), 3.527833e+01, 3.349640e-07, 1.000000e+00, 23, 2101, 1) + ((-1.282907e+01, 2.526604e+00, -1.921402e+01), (-1.767101e-01, -9.842348e-01, 7.448995e-03), 6.258032e+00, 3.584852e-07, 1.000000e+00, 23, 2101, 1) + ((-1.284217e+01, 2.453640e+00, -1.921346e+01), (-1.767101e-01, -9.842348e-01, 7.448995e-03), 6.258032e+00, 3.799102e-07, 1.000000e+00, 23, 2100, 1) + ((-1.288683e+01, 2.204886e+00, -1.921158e+01), (-1.767101e-01, -9.842348e-01, 7.448995e-03), 6.258032e+00, 4.529534e-07, 1.000000e+00, 22, 2100, 3) + ((-1.290264e+01, 2.116831e+00, -1.921091e+01), (-1.767101e-01, -9.842348e-01, 7.448995e-03), 6.258032e+00, 4.788097e-07, 1.000000e+00, 21, 2100, 2) + ((-1.308145e+01, 1.120923e+00, -1.920338e+01), (-1.767101e-01, -9.842348e-01, 7.448995e-03), 6.258032e+00, 7.712448e-07, 1.000000e+00, 22, 2100, 3) + ((-1.309726e+01, 1.032868e+00, -1.920271e+01), (-1.767101e-01, -9.842348e-01, 7.448995e-03), 6.258032e+00, 7.971010e-07, 1.000000e+00, 23, 2100, 1) + ((-1.312690e+01, 8.677798e-01, -1.920146e+01), (-6.009065e-01, -7.617185e-01, 2.422732e-01), 3.971935e+00, 8.455768e-07, 1.000000e+00, 23, 2100, 1) + ((-1.316626e+01, 8.178800e-01, -1.918559e+01), (-6.009065e-01, -7.617185e-01, 2.422732e-01), 3.971935e+00, 8.693415e-07, 1.000000e+00, 23, 2099, 1) + ((-1.324019e+01, 7.241633e-01, -1.915578e+01), (-9.367321e-01, -1.471894e-01, -3.175976e-01), 2.365289e+00, 9.139738e-07, 1.000000e+00, 23, 2099, 1) + ((-1.348497e+01, 6.857011e-01, -1.923877e+01), (-9.722929e-01, 2.325825e-01, -2.349230e-02), 1.799413e+00, 1.036815e-06, 1.000000e+00, 23, 2099, 1) + ((-1.390396e+01, 7.859275e-01, -1.924890e+01), (-9.722929e-01, 2.325825e-01, -2.349230e-02), 1.799413e+00, 1.269071e-06, 1.000000e+00, 23, 2114, 1) + ((-1.403754e+01, 8.178800e-01, -1.925212e+01), (-9.722929e-01, 2.325825e-01, -2.349230e-02), 1.799413e+00, 1.343115e-06, 1.000000e+00, 23, 2115, 1) + ((-1.504223e+01, 1.058212e+00, -1.927640e+01), (-4.085804e-01, -2.719942e-01, -8.712526e-01), 1.628266e+00, 1.900041e-06, 1.000000e+00, 23, 2115, 1) + ((-1.523744e+01, 9.282558e-01, -1.969268e+01), (-6.666265e-01, 3.934879e-01, -6.330690e-01), 4.946445e-01, 2.170751e-06, 1.000000e+00, 23, 2115, 1) + ((-1.553972e+01, 1.106680e+00, -1.997974e+01), (-6.666265e-01, 3.934879e-01, -6.330690e-01), 4.946445e-01, 2.636878e-06, 1.000000e+00, 23, 2129, 1) + ((-1.585973e+01, 1.295571e+00, -2.028364e+01), (-6.666265e-01, 3.934879e-01, -6.330690e-01), 4.946445e-01, 3.130348e-06, 1.000000e+00, 22, 2129, 3) + ((-1.593583e+01, 1.340489e+00, -2.035590e+01), (-6.666265e-01, 3.934879e-01, -6.330690e-01), 4.946445e-01, 3.247693e-06, 1.000000e+00, 21, 2129, 2) + ((-1.647184e+01, 1.656882e+00, -2.086494e+01), (6.457458e-01, -1.162934e-01, -7.546444e-01), 4.958073e-01, 4.074258e-06, 1.000000e+00, 21, 2129, 2) + ((-1.585080e+01, 1.545037e+00, -2.159072e+01), (6.457458e-01, -1.162934e-01, -7.546444e-01), 4.958073e-01, 5.061748e-06, 1.000000e+00, 22, 2129, 3) + ((-1.576406e+01, 1.529415e+00, -2.169209e+01), (6.457458e-01, -1.162934e-01, -7.546444e-01), 4.958073e-01, 5.199673e-06, 1.000000e+00, 23, 2129, 1) + ((-1.553972e+01, 1.489015e+00, -2.195425e+01), (6.457458e-01, -1.162934e-01, -7.546444e-01), 4.958073e-01, 5.556377e-06, 1.000000e+00, 23, 2115, 1) + ((-1.546081e+01, 1.474803e+00, -2.204648e+01), (3.257038e-01, -9.420596e-01, -8.025439e-02), 3.076319e-01, 5.681853e-06, 1.000000e+00, 23, 2115, 1) + ((-1.543563e+01, 1.401988e+00, -2.205268e+01), (-3.677195e-01, -8.784218e-01, -3.052172e-01), 8.422973e-02, 5.782605e-06, 1.000000e+00, 23, 2115, 1) + ((-1.553972e+01, 1.153338e+00, -2.213907e+01), (-3.677195e-01, -8.784218e-01, -3.052172e-01), 8.422973e-02, 6.487752e-06, 1.000000e+00, 23, 2129, 1) + ((-1.565955e+01, 8.670807e-01, -2.223854e+01), (1.611814e-01, 2.692337e-01, -9.494913e-01), 8.559448e-02, 7.299552e-06, 1.000000e+00, 23, 2129, 1) + ((-1.563263e+01, 9.120446e-01, -2.239711e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 7.712256e-06, 1.000000e+00, 23, 2129, 1) + ((-1.592604e+01, 1.214620e+00, -2.249695e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 9.406032e-06, 1.000000e+00, 22, 2129, 3) + ((-1.598742e+01, 1.277922e+00, -2.251784e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 9.760391e-06, 1.000000e+00, 21, 2129, 2) + ((-1.670388e+01, 2.016770e+00, -2.276163e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 1.389636e-05, 1.000000e+00, 22, 2129, 3) + ((-1.676526e+01, 2.080073e+00, -2.278252e+01), (-6.773989e-01, 6.985688e-01, -2.305048e-01), 3.418159e-02, 1.425072e-05, 1.000000e+00, 23, 2129, 1) + ((-1.681575e+01, 2.132139e+00, -2.279970e+01), (4.286076e-02, -9.409799e-01, -3.357375e-01), 1.813618e-02, 1.454218e-05, 1.000000e+00, 23, 2129, 1) + ((-1.681374e+01, 2.087933e+00, -2.281547e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 1.479439e-05, 1.000000e+00, 23, 2129, 1) + ((-1.682083e+01, 2.021795e+00, -2.287841e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 1.532970e-05, 1.000000e+00, 22, 2129, 3) + ((-1.684417e+01, 1.804084e+00, -2.308558e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 1.709181e-05, 1.000000e+00, 21, 2129, 2) + ((-1.686879e+01, 1.574384e+00, -2.330417e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 1.895097e-05, 1.000000e+00, 22, 2129, 3) + ((-1.689212e+01, 1.356673e+00, -2.351134e+01), (-7.741702e-02, -7.222450e-01, -6.872909e-01), 1.529603e-02, 2.071308e-05, 1.000000e+00, 23, 2129, 1) + ((-1.689233e+01, 1.354754e+00, -2.351317e+01), (6.002458e-01, 4.967948e-01, 6.268172e-01), 8.602342e-03, 2.072861e-05, 1.000000e+00, 23, 2129, 1) + ((-1.689148e+01, 1.355453e+00, -2.351229e+01), (6.002458e-01, 4.967948e-01, 6.268172e-01), 8.602342e-03, 2.073958e-05, 1.000000e+00, 22, 2129, 3) + ((-1.682182e+01, 1.413107e+00, -2.343954e+01), (6.002458e-01, 4.967948e-01, 6.268172e-01), 8.602342e-03, 2.164421e-05, 1.000000e+00, 21, 2129, 2) + ((-1.636364e+01, 1.792326e+00, -2.296107e+01), (9.641593e-01, -1.162836e-01, 2.384846e-01), 7.837617e-03, 2.759442e-05, 1.000000e+00, 21, 2129, 2) + ((-1.598564e+01, 1.746738e+00, -2.286758e+01), (9.641593e-01, -1.162836e-01, 2.384846e-01), 7.837617e-03, 3.079609e-05, 0.000000e+00, 21, 2129, 2)] +neutron [((-9.469716e-01, -2.580266e-01, 1.414357e-01), (1.438873e-01, 2.365819e-01, 9.608983e-01), 9.724461e+05, 0.000000e+00, 1.000000e+00, 23, 2403, 1) + ((-9.064818e-01, -1.914524e-01, 4.118326e-01), (9.231638e-01, 3.100833e-01, 2.271937e-01), 1.746594e+05, 2.064696e-10, 1.000000e+00, 23, 2403, 1) + ((-8.178800e-01, -1.616918e-01, 4.336377e-01), (9.231638e-01, 3.100833e-01, 2.271937e-01), 1.746594e+05, 3.725262e-10, 1.000000e+00, 11, 1756, 1) + ((-3.834875e-01, -1.578285e-02, 5.405432e-01), (-5.547498e-01, -6.358598e-02, 8.295839e-01), 1.474011e+05, 1.186660e-09, 1.000000e+00, 11, 1756, 1) + ((-7.999329e-01, -6.351625e-02, 1.163304e+00), (-5.476898e-01, 2.985279e-03, 8.366761e-01), 1.467299e+05, 2.600465e-09, 1.000000e+00, 11, 1756, 1) + ((-8.178800e-01, -6.341842e-02, 1.190721e+00), (-5.476898e-01, 2.985279e-03, 8.366761e-01), 1.467299e+05, 2.662321e-09, 1.000000e+00, 23, 2403, 1) + ((-1.035984e+00, -6.222961e-02, 1.523906e+00), (-5.476898e-01, 2.985279e-03, 8.366761e-01), 1.467299e+05, 3.414026e-09, 1.000000e+00, 22, 2403, 3) + ((-1.124618e+00, -6.174649e-02, 1.659308e+00), (-5.476898e-01, 2.985279e-03, 8.366761e-01), 1.467299e+05, 3.719509e-09, 1.000000e+00, 21, 2403, 2) + ((-1.705404e+00, -5.858082e-02, 2.546543e+00), (-3.196694e-01, -8.974451e-01, 3.039799e-01), 1.460188e+05, 5.721217e-09, 1.000000e+00, 21, 2403, 2) + ((-1.851116e+00, -4.676544e-01, 2.685103e+00), (-3.196694e-01, -8.974451e-01, 3.039799e-01), 1.460188e+05, 6.583734e-09, 1.000000e+00, 22, 2403, 3) + ((-1.880791e+00, -5.509662e-01, 2.713322e+00), (-3.196694e-01, -8.974451e-01, 3.039799e-01), 1.460188e+05, 6.759394e-09, 1.000000e+00, 23, 2403, 1) + ((-1.948026e+00, -7.397227e-01, 2.777257e+00), (-8.068708e-01, -5.218555e-01, -2.768147e-01), 6.012975e+04, 7.157380e-09, 1.000000e+00, 23, 2403, 1) + ((-2.068870e+00, -8.178800e-01, 2.735799e+00), (-8.068708e-01, -5.218555e-01, -2.768147e-01), 6.012975e+04, 7.598974e-09, 1.000000e+00, 23, 2388, 1) + ((-2.111345e+00, -8.453511e-01, 2.721228e+00), (-4.440083e-01, -4.097242e-01, 7.968580e-01), 7.445994e+03, 7.754188e-09, 1.000000e+00, 23, 2388, 1) + ((-2.453640e+00, -1.161216e+00, 3.335542e+00), (-4.440083e-01, -4.097242e-01, 7.968580e-01), 7.445994e+03, 1.421339e-08, 1.000000e+00, 23, 2387, 1) + ((-2.715369e+00, -1.402736e+00, 3.805265e+00), (-4.440083e-01, -4.097242e-01, 7.968580e-01), 7.445994e+03, 1.915229e-08, 1.000000e+00, 22, 2387, 3) + ((-2.785083e+00, -1.467067e+00, 3.930380e+00), (-4.440083e-01, -4.097242e-01, 7.968580e-01), 7.445994e+03, 2.046780e-08, 1.000000e+00, 21, 2387, 2) + ((-2.940196e+00, -1.610203e+00, 4.208760e+00), (-7.727102e-01, 4.333905e-01, -4.637797e-01), 6.395532e+03, 2.339483e-08, 1.000000e+00, 21, 2387, 2) + ((-3.600602e+00, -1.239800e+00, 3.812386e+00), (-7.727102e-01, 4.333905e-01, -4.637797e-01), 6.395532e+03, 3.112139e-08, 1.000000e+00, 22, 2387, 3) + ((-3.682067e+00, -1.194109e+00, 3.763490e+00), (-7.727102e-01, 4.333905e-01, -4.637797e-01), 6.395532e+03, 3.207450e-08, 1.000000e+00, 23, 2387, 1) + ((-4.089400e+00, -9.656478e-01, 3.519009e+00), (-7.727102e-01, 4.333905e-01, -4.637797e-01), 6.395532e+03, 3.684019e-08, 1.000000e+00, 23, 2386, 1) + ((-4.185927e+00, -9.115084e-01, 3.461074e+00), (4.334152e-01, -1.576729e-02, -9.010564e-01), 2.532713e+01, 3.796953e-08, 1.000000e+00, 23, 2386, 1) + ((-4.089400e+00, -9.150200e-01, 3.260397e+00), (4.334152e-01, -1.576729e-02, -9.010564e-01), 2.532713e+01, 6.996444e-08, 1.000000e+00, 23, 2387, 1) + ((-3.920090e+00, -9.211794e-01, 2.908406e+00), (9.094673e-01, -3.659267e-01, -1.974002e-01), 9.547085e+00, 1.260840e-07, 1.000000e+00, 23, 2387, 1) + ((-3.729948e+00, -9.976834e-01, 2.867135e+00), (-2.916959e-01, -6.494657e-01, -7.022164e-01), 8.590591e+00, 1.750036e-07, 1.000000e+00, 23, 2387, 1) + ((-3.744933e+00, -1.031047e+00, 2.831062e+00), (-2.916959e-01, -6.494657e-01, -7.022164e-01), 8.590591e+00, 1.876753e-07, 0.000000e+00, 23, 2387, 1)] +neutron [((6.474155e+00, -5.192870e+00, 5.413003e+00), (-9.112559e-01, 3.950037e-01, 1.165536e-01), 2.052226e+06, 4.450859e-05, 1.000000e+00, 21, 2367, 2) + ((6.037250e+00, -5.003484e+00, 5.468885e+00), (-9.112559e-01, 3.950037e-01, 1.165536e-01), 2.052226e+06, 4.450883e-05, 1.000000e+00, 22, 2367, 3) + ((5.942573e+00, -4.962444e+00, 5.480995e+00), (-9.112559e-01, 3.950037e-01, 1.165536e-01), 2.052226e+06, 4.450889e-05, 1.000000e+00, 23, 2367, 1) + ((5.861800e+00, -4.927431e+00, 5.491326e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.450893e-05, 1.000000e+00, 23, 2367, 1) + ((5.725160e+00, -4.971424e+00, 5.491002e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.450903e-05, 1.000000e+00, 23, 2366, 1) + ((5.494150e+00, -5.045802e+00, 5.490454e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.450919e-05, 1.000000e+00, 22, 2366, 3) + ((5.392865e+00, -5.078412e+00, 5.490213e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.450927e-05, 1.000000e+00, 21, 2366, 2) + ((4.612759e+00, -5.329579e+00, 5.488362e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.450982e-05, 1.000000e+00, 22, 2366, 3) + ((4.511474e+00, -5.362189e+00, 5.488121e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.450989e-05, 1.000000e+00, 23, 2366, 1) + ((4.089400e+00, -5.498082e+00, 5.487119e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.451019e-05, 1.000000e+00, 23, 2365, 1) + ((3.384113e+00, -5.725160e+00, 5.485445e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.451069e-05, 1.000000e+00, 23, 2351, 1) + ((2.453640e+00, -6.024740e+00, 5.483237e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.451136e-05, 1.000000e+00, 23, 2350, 1) + ((2.086813e+00, -6.142846e+00, 5.482366e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.451162e-05, 1.000000e+00, 22, 2350, 3) + ((1.993594e+00, -6.172859e+00, 5.482145e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.451168e-05, 1.000000e+00, 21, 2350, 2) + ((1.325704e+00, -6.387896e+00, 5.480560e+00), (8.986086e-01, -4.380574e-01, -2.466265e-02), 9.775839e+05, 4.451216e-05, 1.000000e+00, 21, 2350, 2) + ((2.061403e+00, -6.746538e+00, 5.460368e+00), (-7.778764e-01, 2.051975e-01, -5.939716e-01), 7.813219e+05, 4.451276e-05, 1.000000e+00, 21, 2350, 2) + ((1.122794e+00, -6.498940e+00, 4.743664e+00), (-7.778764e-01, 2.051975e-01, -5.939716e-01), 7.813219e+05, 4.451375e-05, 1.000000e+00, 22, 2350, 3) + ((1.036483e+00, -6.476172e+00, 4.677758e+00), (-7.778764e-01, 2.051975e-01, -5.939716e-01), 7.813219e+05, 4.451384e-05, 1.000000e+00, 23, 2350, 1) + ((8.178800e-01, -6.418507e+00, 4.510837e+00), (-7.778764e-01, 2.051975e-01, -5.939716e-01), 7.813219e+05, 4.451407e-05, 1.000000e+00, 23, 2349, 1) + ((5.725264e-01, -6.353784e+00, 4.323490e+00), (-7.778764e-01, 2.051975e-01, -5.939716e-01), 7.813219e+05, 4.451432e-05, 1.000000e+00, 22, 2349, 3) + ((4.668297e-01, -6.325902e+00, 4.242782e+00), (-7.778764e-01, 2.051975e-01, -5.939716e-01), 7.813219e+05, 4.451444e-05, 1.000000e+00, 21, 2349, 2) + ((-2.989816e-01, -6.123888e+00, 3.658023e+00), (-7.778764e-01, 2.051975e-01, -5.939716e-01), 7.813219e+05, 4.451524e-05, 1.000000e+00, 22, 2349, 3) + ((-4.046782e-01, -6.096006e+00, 3.577315e+00), (-7.778764e-01, 2.051975e-01, -5.939716e-01), 7.813219e+05, 4.451535e-05, 1.000000e+00, 23, 2349, 1) + ((-8.040445e-01, -5.990656e+00, 3.272367e+00), (-7.989001e-01, -1.890553e-01, -5.709787e-01), 6.637114e+05, 4.451577e-05, 1.000000e+00, 23, 2349, 1) + ((-8.178800e-01, -5.993930e+00, 3.262478e+00), (-7.989001e-01, -1.890553e-01, -5.709787e-01), 6.637114e+05, 4.451579e-05, 1.000000e+00, 23, 2348, 1) + ((-1.077910e+00, -6.055465e+00, 3.076633e+00), (-4.487118e-01, 1.670254e-01, -8.779295e-01), 4.550608e+05, 4.451608e-05, 1.000000e+00, 23, 2348, 1) + ((-1.215611e+00, -6.004208e+00, 2.807214e+00), (7.872329e-01, 4.481433e-01, -4.235941e-01), 3.544207e+03, 4.451641e-05, 1.000000e+00, 23, 2348, 1) + ((-1.100296e+00, -5.938564e+00, 2.745166e+00), (8.468456e-01, 5.310954e-01, 2.811230e-02), 2.812308e+03, 4.451819e-05, 1.000000e+00, 23, 2348, 1) + ((-8.178800e-01, -5.761448e+00, 2.754541e+00), (8.468456e-01, 5.310954e-01, 2.811230e-02), 2.812308e+03, 4.452273e-05, 1.000000e+00, 23, 2349, 1) + ((-7.600184e-01, -5.725160e+00, 2.756462e+00), (8.468456e-01, 5.310954e-01, 2.811230e-02), 2.812308e+03, 4.452366e-05, 1.000000e+00, 23, 2363, 1) + ((-2.947156e-01, -5.433347e+00, 2.771908e+00), (8.468456e-01, 5.310954e-01, 2.811230e-02), 2.812308e+03, 4.453115e-05, 1.000000e+00, 22, 2363, 3) + ((-2.073333e-01, -5.378546e+00, 2.774809e+00), (8.468456e-01, 5.310954e-01, 2.811230e-02), 2.812308e+03, 4.453256e-05, 1.000000e+00, 21, 2363, 2) + ((-1.746705e-01, -5.358062e+00, 2.775893e+00), (5.278774e-01, 5.459205e-01, 6.506276e-01), 2.806481e+03, 4.453309e-05, 1.000000e+00, 21, 2363, 2) + ((-8.681718e-02, -5.267205e+00, 2.884176e+00), (-8.975500e-01, 8.968076e-04, -4.409119e-01), 2.764929e+03, 4.453536e-05, 1.000000e+00, 21, 2363, 2) + ((-3.684221e-01, -5.266924e+00, 2.745840e+00), (-8.975500e-01, 8.968076e-04, -4.409119e-01), 2.764929e+03, 4.453967e-05, 1.000000e+00, 22, 2363, 3) + ((-4.840903e-01, -5.266809e+00, 2.689019e+00), (-8.975500e-01, 8.968076e-04, -4.409119e-01), 2.764929e+03, 4.454144e-05, 1.000000e+00, 23, 2363, 1) + ((-8.178800e-01, -5.266475e+00, 2.525049e+00), (-8.975500e-01, 8.968076e-04, -4.409119e-01), 2.764929e+03, 4.454656e-05, 1.000000e+00, 23, 2362, 1) + ((-1.151175e+00, -5.266142e+00, 2.361321e+00), (-8.975500e-01, 8.968076e-04, -4.409119e-01), 2.764929e+03, 4.455166e-05, 1.000000e+00, 22, 2362, 3) + ((-1.266464e+00, -5.266027e+00, 2.304687e+00), (-8.975500e-01, 8.968076e-04, -4.409119e-01), 2.764929e+03, 4.455343e-05, 1.000000e+00, 21, 2362, 2) + ((-2.005772e+00, -5.265288e+00, 1.941509e+00), (-8.975500e-01, 8.968076e-04, -4.409119e-01), 2.764929e+03, 4.456475e-05, 1.000000e+00, 22, 2362, 3) + ((-2.121061e+00, -5.265173e+00, 1.884875e+00), (-8.975500e-01, 8.968076e-04, -4.409119e-01), 2.764929e+03, 4.456652e-05, 1.000000e+00, 23, 2362, 1) + ((-2.393759e+00, -5.264900e+00, 1.750915e+00), (-9.607392e-01, -1.749373e-01, 2.153533e-01), 1.619469e+03, 4.457070e-05, 1.000000e+00, 23, 2362, 1) + ((-2.453640e+00, -5.275804e+00, 1.764337e+00), (-9.607392e-01, -1.749373e-01, 2.153533e-01), 1.619469e+03, 4.457182e-05, 1.000000e+00, 23, 2361, 1) + ((-2.470658e+00, -5.278903e+00, 1.768152e+00), (-6.728606e-01, -2.916408e-01, -6.798561e-01), 4.873672e+02, 4.457214e-05, 1.000000e+00, 23, 2361, 1) + ((-3.463692e+00, -5.709318e+00, 7.647939e-01), (-2.249302e-01, -9.330150e-01, -2.808728e-01), 1.790901e+02, 4.462047e-05, 1.000000e+00, 23, 2361, 1) + ((-3.467511e+00, -5.725160e+00, 7.600247e-01), (-2.249302e-01, -9.330150e-01, -2.808728e-01), 1.790901e+02, 4.462139e-05, 1.000000e+00, 23, 2347, 1) + ((-3.533785e+00, -6.000066e+00, 6.772677e-01), (-2.249302e-01, -9.330150e-01, -2.808728e-01), 1.790901e+02, 4.463730e-05, 1.000000e+00, 22, 2347, 3) + ((-3.562245e+00, -6.118119e+00, 6.417291e-01), (-2.249302e-01, -9.330150e-01, -2.808728e-01), 1.790901e+02, 4.464414e-05, 1.000000e+00, 21, 2347, 2) + ((-3.723934e+00, -6.788806e+00, 4.398272e-01), (-2.249302e-01, -9.330150e-01, -2.808728e-01), 1.790901e+02, 4.468297e-05, 1.000000e+00, 22, 2347, 3) + ((-3.752394e+00, -6.906859e+00, 4.042885e-01), (-2.249302e-01, -9.330150e-01, -2.808728e-01), 1.790901e+02, 4.468981e-05, 1.000000e+00, 23, 2347, 1) + ((-3.848515e+00, -7.305571e+00, 2.842613e-01), (6.498448e-01, -3.243413e-01, -6.873896e-01), 2.328979e+01, 4.471290e-05, 1.000000e+00, 23, 2347, 1) + ((-3.737619e+00, -7.360920e+00, 1.669579e-01), (6.498448e-01, -3.243413e-01, -6.873896e-01), 2.328979e+01, 4.473846e-05, 1.000000e+00, 11, 1750, 1) + ((-3.574308e+00, -7.442429e+00, -5.788041e-03), (6.794505e-01, 3.157106e-01, -6.623246e-01), 1.590416e+01, 4.477611e-05, 1.000000e+00, 11, 1750, 1) + ((-3.398889e+00, -7.360920e+00, -1.767852e-01), (6.794505e-01, 3.157106e-01, -6.623246e-01), 1.590416e+01, 4.482292e-05, 1.000000e+00, 23, 2347, 1) + ((-2.904712e+00, -7.131298e+00, -6.585068e-01), (-4.836985e-02, -2.819627e-01, -9.582053e-01), 2.610202e+00, 4.495477e-05, 1.000000e+00, 23, 2347, 1) + ((-2.923579e+00, -7.241285e+00, -1.032280e+00), (-6.089807e-01, -2.347428e-01, -7.576532e-01), 1.671268e+00, 4.512933e-05, 1.000000e+00, 23, 2347, 1) + ((-3.012516e+00, -7.275567e+00, -1.142930e+00), (3.221931e-01, -5.406104e-01, -7.771306e-01), 1.275709e-01, 4.521100e-05, 1.000000e+00, 23, 2347, 1) + ((-2.984032e+00, -7.323360e+00, -1.211633e+00), (-8.629564e-01, -1.719529e-01, -4.751195e-01), 1.897424e-02, 4.538995e-05, 1.000000e+00, 23, 2347, 1) + ((-3.172528e+00, -7.360920e+00, -1.315413e+00), (-8.629564e-01, -1.719529e-01, -4.751195e-01), 1.897424e-02, 4.653641e-05, 1.000000e+00, 11, 1750, 1) + ((-3.602328e+00, -7.446562e+00, -1.552049e+00), (-1.530190e-01, -7.092235e-01, 6.881767e-01), 1.306951e-02, 4.915052e-05, 1.000000e+00, 11, 1750, 1) + ((-3.625236e+00, -7.552741e+00, -1.449021e+00), (-1.976867e-01, 2.826475e-01, 9.386322e-01), 2.145548e-02, 5.009730e-05, 1.000000e+00, 11, 1750, 1) + ((-3.636290e+00, -7.536936e+00, -1.396537e+00), (1.266676e-01, 2.265353e-01, -9.657314e-01), 1.815564e-02, 5.037329e-05, 1.000000e+00, 11, 1750, 1) + ((-3.621792e+00, -7.511008e+00, -1.507069e+00), (-4.275550e-01, 8.441443e-01, 3.234457e-01), 1.848049e-02, 5.098741e-05, 1.000000e+00, 11, 1750, 1) + ((-3.697811e+00, -7.360920e+00, -1.449560e+00), (-4.275550e-01, 8.441443e-01, 3.234457e-01), 1.848049e-02, 5.193300e-05, 1.000000e+00, 23, 2347, 1) + ((-3.703436e+00, -7.349814e+00, -1.445305e+00), (-7.832167e-01, 5.713670e-01, 2.451762e-01), 1.861705e-02, 5.200297e-05, 1.000000e+00, 23, 2347, 1) + ((-3.823243e+00, -7.262414e+00, -1.407801e+00), (-9.917106e-01, 5.069164e-02, 1.180695e-01), 4.703334e-02, 5.281350e-05, 1.000000e+00, 23, 2347, 1) + ((-4.089400e+00, -7.248809e+00, -1.376113e+00), (-9.917106e-01, 5.069164e-02, 1.180695e-01), 4.703334e-02, 5.370820e-05, 1.000000e+00, 23, 2346, 1) + ((-4.131081e+00, -7.246679e+00, -1.371151e+00), (9.108632e-01, -4.018526e-01, 9.403556e-02), 8.057393e-02, 5.384831e-05, 1.000000e+00, 23, 2346, 1) + ((-4.089400e+00, -7.265067e+00, -1.366848e+00), (9.108632e-01, -4.018526e-01, 9.403556e-02), 8.057393e-02, 5.396486e-05, 1.000000e+00, 23, 2347, 1) + ((-3.872134e+00, -7.360920e+00, -1.344418e+00), (9.108632e-01, -4.018526e-01, 9.403556e-02), 8.057393e-02, 5.457240e-05, 1.000000e+00, 11, 1750, 1) + ((-3.673062e+00, -7.448746e+00, -1.323866e+00), (2.976906e-01, 8.174443e-01, -4.931178e-01), 5.538060e-02, 5.512905e-05, 1.000000e+00, 11, 1750, 1) + ((-3.658580e+00, -7.408978e+00, -1.347855e+00), (-5.409120e-01, 8.345378e-01, -1.046943e-01), 8.122576e-02, 5.527851e-05, 1.000000e+00, 11, 1750, 1) + ((-3.682981e+00, -7.371331e+00, -1.352578e+00), (-5.409120e-01, 8.345378e-01, -1.046943e-01), 8.122576e-02, 5.539295e-05, 0.000000e+00, 11, 1750, 1)] diff --git a/tests/regression_tests/track_output/settings.xml b/tests/regression_tests/track_output/settings.xml deleted file mode 100644 index 299ee72c533..00000000000 --- a/tests/regression_tests/track_output/settings.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - eigenvalue - 2 - 0 - 100 - - - - - -1 -1 -1 1 1 1 - - - - - 1 1 1 - 1 1 2 - - - diff --git a/tests/regression_tests/track_output/test.py b/tests/regression_tests/track_output/test.py index a5300a4aede..62526117dfb 100644 --- a/tests/regression_tests/track_output/test.py +++ b/tests/regression_tests/track_output/test.py @@ -1,11 +1,13 @@ import glob import os +from pathlib import Path from subprocess import call -import shutil +import numpy as np +import openmc import pytest -from tests.testing_harness import TestHarness +from tests.testing_harness import TestHarness, config class TrackTestHarness(TestHarness): @@ -13,26 +15,33 @@ def _test_output_created(self): """Make sure statepoint.* and track* have been created.""" TestHarness._test_output_created(self) - outputs = glob.glob('track_1_1_*.h5') - assert len(outputs) == 2, 'Expected two track files.' + if config['mpi'] and int(config['mpi_np']) > 1: + outputs = Path.cwd().glob('tracks_p*.h5') + assert len(list(outputs)) == int(config['mpi_np']) + else: + assert Path('tracks.h5').is_file() def _get_results(self): - """Digest info in the statepoint and return as a string.""" - # Run the track-to-vtk conversion script. - call(['../../../scripts/openmc-track-to-vtk', '-o', 'poly'] + - glob.glob('track_1_1_*.h5')) + """Get data from track file and return as a string.""" - # Make sure the vtk file was created then return it's contents. - assert os.path.isfile('poly.pvtp'), 'poly.pvtp file not found.' + # For MPI mode, combine track files + if config['mpi']: + call(['../../../scripts/openmc-track-combine', '-o', 'tracks.h5'] + + glob.glob('tracks_p*.h5')) - with open('poly.pvtp', 'r') as fin: - outstr = fin.read() + # Get string of track file information + outstr = '' + tracks = openmc.Tracks('tracks.h5') + for track in tracks: + with np.printoptions(formatter={'float_kind': '{:.6e}'.format}): + for ptrack in track: + outstr += f"{ptrack.particle} {ptrack.states}\n" return outstr def _cleanup(self): TestHarness._cleanup(self) - output = glob.glob('track*') + glob.glob('poly*') + output = glob.glob('tracks*') + glob.glob('poly*') for f in output: if os.path.exists(f): os.remove(f) diff --git a/tests/regression_tests/translation/results_true.dat b/tests/regression_tests/translation/results_true.dat index 32897b8e756..f832aa29643 100644 --- a/tests/regression_tests/translation/results_true.dat +++ b/tests/regression_tests/translation/results_true.dat @@ -1,2 +1,2 @@ k-combined: -4.003951E-01 7.739871E-03 +4.087580E-01 4.466279E-03 diff --git a/tests/regression_tests/trigger_batch_interval/results_true.dat b/tests/regression_tests/trigger_batch_interval/results_true.dat index 2fcfaa10a7c..0571d6c4f9e 100644 --- a/tests/regression_tests/trigger_batch_interval/results_true.dat +++ b/tests/regression_tests/trigger_batch_interval/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.764624E-01 8.747085E-03 +9.767929E-01 5.327552E-03 tally 1: -1.408588E+01 -1.985937E+01 -3.194837E+00 -1.021391E+00 -3.096170E+00 -9.592197E-01 -1.089104E+01 -1.187349E+01 -1.408588E+01 -1.985937E+01 -3.194837E+00 -1.021391E+00 -3.096170E+00 -9.592197E-01 -1.089104E+01 -1.187349E+01 +1.405471E+01 +1.976444E+01 +3.186139E+00 +1.015515E+00 +3.088643E+00 +9.542994E-01 +1.086857E+01 +1.182011E+01 +1.405471E+01 +1.976444E+01 +3.186139E+00 +1.015515E+00 +3.088643E+00 +9.542994E-01 +1.086857E+01 +1.182011E+01 tally 2: -1.408588E+01 -1.985937E+01 -3.194837E+00 -1.021391E+00 -3.096170E+00 -9.592197E-01 -1.089104E+01 -1.187349E+01 +1.405471E+01 +1.976444E+01 +3.186139E+00 +1.015515E+00 +3.088643E+00 +9.542994E-01 +1.086857E+01 +1.182011E+01 diff --git a/tests/regression_tests/trigger_batch_interval/tallies.xml b/tests/regression_tests/trigger_batch_interval/tallies.xml index 3440dbf2171..ea25596a4f4 100644 --- a/tests/regression_tests/trigger_batch_interval/tallies.xml +++ b/tests/regression_tests/trigger_batch_interval/tallies.xml @@ -2,7 +2,7 @@ - all + Pu239 total total absorption fission scatter diff --git a/tests/regression_tests/trigger_no_batch_interval/results_true.dat b/tests/regression_tests/trigger_no_batch_interval/results_true.dat index 2fcfaa10a7c..0571d6c4f9e 100644 --- a/tests/regression_tests/trigger_no_batch_interval/results_true.dat +++ b/tests/regression_tests/trigger_no_batch_interval/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.764624E-01 8.747085E-03 +9.767929E-01 5.327552E-03 tally 1: -1.408588E+01 -1.985937E+01 -3.194837E+00 -1.021391E+00 -3.096170E+00 -9.592197E-01 -1.089104E+01 -1.187349E+01 -1.408588E+01 -1.985937E+01 -3.194837E+00 -1.021391E+00 -3.096170E+00 -9.592197E-01 -1.089104E+01 -1.187349E+01 +1.405471E+01 +1.976444E+01 +3.186139E+00 +1.015515E+00 +3.088643E+00 +9.542994E-01 +1.086857E+01 +1.182011E+01 +1.405471E+01 +1.976444E+01 +3.186139E+00 +1.015515E+00 +3.088643E+00 +9.542994E-01 +1.086857E+01 +1.182011E+01 tally 2: -1.408588E+01 -1.985937E+01 -3.194837E+00 -1.021391E+00 -3.096170E+00 -9.592197E-01 -1.089104E+01 -1.187349E+01 +1.405471E+01 +1.976444E+01 +3.186139E+00 +1.015515E+00 +3.088643E+00 +9.542994E-01 +1.086857E+01 +1.182011E+01 diff --git a/tests/regression_tests/trigger_no_batch_interval/tallies.xml b/tests/regression_tests/trigger_no_batch_interval/tallies.xml index 3440dbf2171..ea25596a4f4 100644 --- a/tests/regression_tests/trigger_no_batch_interval/tallies.xml +++ b/tests/regression_tests/trigger_no_batch_interval/tallies.xml @@ -2,7 +2,7 @@ - all + Pu239 total total absorption fission scatter diff --git a/tests/regression_tests/trigger_no_status/results_true.dat b/tests/regression_tests/trigger_no_status/results_true.dat index e95f05ccb65..fb6c0086ab2 100644 --- a/tests/regression_tests/trigger_no_status/results_true.dat +++ b/tests/regression_tests/trigger_no_status/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.688702E-01 2.263104E-02 +9.682315E-01 3.302924E-03 tally 1: -7.069810E+00 -1.000691E+01 -1.597648E+00 -5.109653E-01 -1.547262E+00 -4.792189E-01 -5.472161E+00 -5.995488E+00 -7.069810E+00 -1.000691E+01 -1.597648E+00 -5.109653E-01 -1.547262E+00 -4.792189E-01 -5.472161E+00 -5.995488E+00 +7.046510E+00 +9.932168E+00 +1.591675E+00 +5.067777E-01 +1.541572E+00 +4.753743E-01 +5.454835E+00 +5.951990E+00 +7.046510E+00 +9.932168E+00 +1.591675E+00 +5.067777E-01 +1.541572E+00 +4.753743E-01 +5.454835E+00 +5.951990E+00 tally 2: -7.069810E+00 -1.000691E+01 -1.597648E+00 -5.109653E-01 -1.547262E+00 -4.792189E-01 -5.472161E+00 -5.995488E+00 +7.046510E+00 +9.932168E+00 +1.591675E+00 +5.067777E-01 +1.541572E+00 +4.753743E-01 +5.454835E+00 +5.951990E+00 diff --git a/tests/regression_tests/trigger_no_status/tallies.xml b/tests/regression_tests/trigger_no_status/tallies.xml index 3440dbf2171..ea25596a4f4 100644 --- a/tests/regression_tests/trigger_no_status/tallies.xml +++ b/tests/regression_tests/trigger_no_status/tallies.xml @@ -2,7 +2,7 @@ - all + Pu239 total total absorption fission scatter diff --git a/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat b/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat index 2c422697b9d..6f0b629eb62 100644 --- a/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat +++ b/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat @@ -1,35 +1,34 @@ - - - - - - - - - - - - - - eigenvalue - 400 - 15 - 10 - - 0.003 - std_dev - - - true - 1000 - 1 - - 1 - - - - - flux - - + + + + + + + + + + + + + eigenvalue + 400 + 15 + 10 + + 0.003 + std_dev + + + true + 1000 + 1 + + 1 + + + + flux + + + diff --git a/tests/regression_tests/trigger_statepoint_restart/results_true.dat b/tests/regression_tests/trigger_statepoint_restart/results_true.dat index 3ab555d734e..3e6619d74db 100644 --- a/tests/regression_tests/trigger_statepoint_restart/results_true.dat +++ b/tests/regression_tests/trigger_statepoint_restart/results_true.dat @@ -1,5 +1,5 @@ k-combined: -2.963805E-01 2.986351E-03 +3.014717E-01 2.864764E-03 tally 1: -8.017826E+01 -6.436316E+02 +8.946107E+01 +7.281263E+02 diff --git a/tests/regression_tests/trigger_statepoint_restart/test.py b/tests/regression_tests/trigger_statepoint_restart/test.py index 8d4d5619266..8144c1d0b0a 100644 --- a/tests/regression_tests/trigger_statepoint_restart/test.py +++ b/tests/regression_tests/trigger_statepoint_restart/test.py @@ -90,7 +90,7 @@ def execute_test(self): assert spfile with openmc.StatePoint(spfile) as sp: sp_batchno_1 = sp.current_batch - k_combined_1 = sp.k_combined + keff_1 = sp.keff assert sp_batchno_1 > 5 print('Last batch no = %d' % sp_batchno_1) self._write_inputs(self._get_inputs()) @@ -108,13 +108,13 @@ def execute_test(self): assert spfile with openmc.StatePoint(spfile) as sp: sp_batchno_2 = sp.current_batch - k_combined_2 = sp.k_combined + keff_2 = sp.keff assert sp_batchno_2 > 5 assert sp_batchno_1 == sp_batchno_2, \ 'Different final batch number after restart' # need str() here as uncertainties.ufloat instances are always different - assert str(k_combined_1) == str(k_combined_2), \ - 'Different final k_combined after restart' + assert str(keff_1) == str(keff_2), \ + 'Different final keff after restart' self._write_inputs(self._get_inputs()) self._compare_inputs() self._test_output_created() diff --git a/tests/regression_tests/trigger_tallies/results_true.dat b/tests/regression_tests/trigger_tallies/results_true.dat index 2fcfaa10a7c..0571d6c4f9e 100644 --- a/tests/regression_tests/trigger_tallies/results_true.dat +++ b/tests/regression_tests/trigger_tallies/results_true.dat @@ -1,28 +1,28 @@ k-combined: -9.764624E-01 8.747085E-03 +9.767929E-01 5.327552E-03 tally 1: -1.408588E+01 -1.985937E+01 -3.194837E+00 -1.021391E+00 -3.096170E+00 -9.592197E-01 -1.089104E+01 -1.187349E+01 -1.408588E+01 -1.985937E+01 -3.194837E+00 -1.021391E+00 -3.096170E+00 -9.592197E-01 -1.089104E+01 -1.187349E+01 +1.405471E+01 +1.976444E+01 +3.186139E+00 +1.015515E+00 +3.088643E+00 +9.542994E-01 +1.086857E+01 +1.182011E+01 +1.405471E+01 +1.976444E+01 +3.186139E+00 +1.015515E+00 +3.088643E+00 +9.542994E-01 +1.086857E+01 +1.182011E+01 tally 2: -1.408588E+01 -1.985937E+01 -3.194837E+00 -1.021391E+00 -3.096170E+00 -9.592197E-01 -1.089104E+01 -1.187349E+01 +1.405471E+01 +1.976444E+01 +3.186139E+00 +1.015515E+00 +3.088643E+00 +9.542994E-01 +1.086857E+01 +1.182011E+01 diff --git a/tests/regression_tests/trigger_tallies/tallies.xml b/tests/regression_tests/trigger_tallies/tallies.xml index 0d66e1538e6..ffe8a1a9e3c 100644 --- a/tests/regression_tests/trigger_tallies/tallies.xml +++ b/tests/regression_tests/trigger_tallies/tallies.xml @@ -2,7 +2,7 @@ - all + Pu239 total total absorption fission scatter diff --git a/tests/regression_tests/triso/inputs_true.dat b/tests/regression_tests/triso/inputs_true.dat index 2ea049465ce..37f37af7871 100644 --- a/tests/regression_tests/triso/inputs_true.dat +++ b/tests/regression_tests/triso/inputs_true.dat @@ -1,442 +1,442 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.3333333333333333 0.3333333333333333 0.3333333333333333 - 38 - 3 3 3 - -0.5 -0.5 -0.5 - -17 18 19 -14 15 16 -11 12 13 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.3333333333333333 0.3333333333333333 0.3333333333333333 + 30 + 3 3 3 + -0.5 -0.5 -0.5 + +9 10 11 +6 7 8 +3 4 5 -26 27 28 -23 24 25 -20 21 22 +18 19 20 +15 16 17 +12 13 14 -35 36 37 -32 33 34 -29 30 31 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 4 - 0 - - - 0.0 0.0 0.0 - - - +27 28 29 +24 25 26 +21 22 23 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 4 + 0 + + + 0.0 0.0 0.0 + + + + diff --git a/tests/regression_tests/triso/results_true.dat b/tests/regression_tests/triso/results_true.dat index fc95e33fce8..fa1842e547d 100644 --- a/tests/regression_tests/triso/results_true.dat +++ b/tests/regression_tests/triso/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.653488E+00 2.128233E-02 +1.716873E+00 5.266107E-02 diff --git a/tests/regression_tests/triso/test.py b/tests/regression_tests/triso/test.py index c447156913b..3fa5e3c60d2 100644 --- a/tests/regression_tests/triso/test.py +++ b/tests/regression_tests/triso/test.py @@ -1,7 +1,3 @@ -import random -from math import sqrt - -import numpy as np import openmc import openmc.model @@ -9,7 +5,8 @@ class TRISOTestHarness(PyAPITestHarness): - def _build_inputs(self): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # Define TRISO matrials fuel = openmc.Material() fuel.set_density('g/cm3', 10.5) @@ -64,8 +61,8 @@ def _build_inputs(self): box = openmc.Cell(region=box_region) outer_radius = 422.5*1e-4 - centers = openmc.model.pack_spheres(radius=outer_radius, - region=box_region, num_spheres=100) + centers = openmc.model.pack_spheres( + radius=outer_radius, region=box_region, num_spheres=100, seed=1) trisos = [openmc.model.TRISO(outer_radius, inner_univ, c) for c in centers] @@ -78,20 +75,19 @@ def _build_inputs(self): box.fill = lattice root = openmc.Universe(0, cells=[box]) - geom = openmc.Geometry(root) - geom.export_to_xml() + self._model.geometry = openmc.Geometry(root) settings = openmc.Settings() settings.batches = 4 settings.inactive = 0 settings.particles = 100 - settings.source = openmc.Source(space=openmc.stats.Point()) - settings.export_to_xml() + settings.source = openmc.IndependentSource(space=openmc.stats.Point()) + self._model.settings = settings - mats = openmc.Materials([fuel, porous_carbon, ipyc, sic, opyc, graphite]) - mats.export_to_xml() + self._model.materials = openmc.Materials([fuel, porous_carbon, ipyc, + sic, opyc, graphite]) def test_triso(): - harness = TRISOTestHarness('statepoint.4.h5') + harness = TRISOTestHarness('statepoint.4.h5', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/uniform_fs/results_true.dat b/tests/regression_tests/uniform_fs/results_true.dat index ebf06a8d3e9..46654b49b43 100644 --- a/tests/regression_tests/uniform_fs/results_true.dat +++ b/tests/regression_tests/uniform_fs/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.643255E-01 1.041799E-02 +3.685309E-01 1.861720E-03 diff --git a/tests/regression_tests/universe/results_true.dat b/tests/regression_tests/universe/results_true.dat index fe46748c80d..bbf03de9437 100644 --- a/tests/regression_tests/universe/results_true.dat +++ b/tests/regression_tests/universe/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.987050E-01 1.827430E-03 +3.070134E-01 3.900396E-03 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true.dat b/tests/regression_tests/unstructured_mesh/inputs_true.dat new file mode 100644 index 00000000000..07486d3e0ee --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/inputs_true.dat @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_hexes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true0.dat b/tests/regression_tests/unstructured_mesh/inputs_true0.dat index 7411e9b9408..c6b28d890ed 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true0.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true0.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true1.dat b/tests/regression_tests/unstructured_mesh/inputs_true1.dat index e85aab11930..40183c89bc8 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true1.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true1.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true10.dat b/tests/regression_tests/unstructured_mesh/inputs_true10.dat index 628e5e7bccc..81dfbdc52d9 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true10.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true10.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true11.dat b/tests/regression_tests/unstructured_mesh/inputs_true11.dat index 1c0a579e547..b224a3ebc36 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true11.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true11.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true12.dat b/tests/regression_tests/unstructured_mesh/inputs_true12.dat index a75344435f5..a18aee627ce 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true12.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true12.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + tracklength + + + 2 + flux + tracklength + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true13.dat b/tests/regression_tests/unstructured_mesh/inputs_true13.dat index c62c3c91130..0e9123c9036 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true13.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true13.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + tracklength + + + 2 + flux + tracklength + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true14.dat b/tests/regression_tests/unstructured_mesh/inputs_true14.dat index b7ac4c048c8..9d4db490451 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true14.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true14.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + tracklength + + + 2 + flux + tracklength + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true15.dat b/tests/regression_tests/unstructured_mesh/inputs_true15.dat index 1d96efc7d38..eab97b95227 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true15.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true15.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - tracklength - - - 2 - flux - tracklength - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + tracklength + + + 2 + flux + tracklength + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true2.dat b/tests/regression_tests/unstructured_mesh/inputs_true2.dat index a2a2d4a27aa..3521ac7b81e 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true2.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true2.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true3.dat b/tests/regression_tests/unstructured_mesh/inputs_true3.dat index c96f9020163..a376b401d6c 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true3.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true3.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true4.dat b/tests/regression_tests/unstructured_mesh/inputs_true4.dat index a39452da7cd..843632fdd63 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true4.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true4.dat @@ -1,92 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.exo - - - 9 - - - 10 - - - 9 - flux - tracklength - - - 10 - flux - tracklength - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.exo + + + 9 + + + 10 + + + 9 + flux + tracklength + + + 10 + flux + tracklength + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true5.dat b/tests/regression_tests/unstructured_mesh/inputs_true5.dat index 288b7d1fcbb..dc9129d98aa 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true5.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true5.dat @@ -1,92 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.exo - - - 11 - - - 12 - - - 11 - flux - tracklength - - - 12 - flux - tracklength - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.exo + + + 11 + + + 12 + + + 11 + flux + tracklength + + + 12 + flux + tracklength + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true6.dat b/tests/regression_tests/unstructured_mesh/inputs_true6.dat index 883e6cbf48c..82bc3070372 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true6.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true6.dat @@ -1,92 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.exo - - - 13 - - - 14 - - - 13 - flux - tracklength - - - 14 - flux - tracklength - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.exo + + + 13 + + + 14 + + + 13 + flux + tracklength + + + 14 + flux + tracklength + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true7.dat b/tests/regression_tests/unstructured_mesh/inputs_true7.dat index 267966e3ca9..b982c40d055 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true7.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true7.dat @@ -1,92 +1,91 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 100 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.exo - - - 15 - - - 16 - - - 15 - flux - tracklength - - - 16 - flux - tracklength - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.exo + + + 15 + + + 16 + + + 15 + flux + tracklength + + + 16 + flux + tracklength + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true8.dat b/tests/regression_tests/unstructured_mesh/inputs_true8.dat index 9a7ad57113c..7994e1add76 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true8.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true8.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets_w_holes.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true9.dat b/tests/regression_tests/unstructured_mesh/inputs_true9.dat index 8aedad23774..4fff123d7d4 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true9.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true9.dat @@ -1,91 +1,90 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 10 - - - - - 0.0 1.0 - - - 0.0 1.0 - - - - 15000000.0 1.0 - - - - - - - 10 10 10 - -10.0 -10.0 -10.0 - 10.0 10.0 10.0 - - - test_mesh_tets.e - - - 1 - - - 2 - - - 1 - flux - collision - - - 2 - flux - collision - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 10 + + + + + 1.0 1.0 + + + 0.0 1.0 + + + + 15000000.0 1.0 + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.e + + + 1 + + + 2 + + + 1 + flux + collision + + + 2 + flux + collision + + + diff --git a/tests/regression_tests/unstructured_mesh/results_true.dat b/tests/regression_tests/unstructured_mesh/results_true.dat deleted file mode 100644 index c93eadfdba9..00000000000 --- a/tests/regression_tests/unstructured_mesh/results_true.dat +++ /dev/null @@ -1,26002 +0,0 @@ -tally 1: -4.873713E-02 -2.881006E-04 -7.388548E-02 -6.421281E-04 -8.309847E-02 -8.079791E-04 -8.802030E-02 -8.590396E-04 -6.935977E-02 -5.711723E-04 -7.203243E-02 -5.847086E-04 -8.146742E-02 -8.422730E-04 -7.112287E-02 -5.331461E-04 -6.944025E-02 -6.220640E-04 -4.605581E-02 -3.052058E-04 -7.341445E-02 -6.319466E-04 -9.013420E-02 -1.083246E-03 -1.221831E-01 -1.761591E-03 -1.244445E-01 -1.714565E-03 -1.324446E-01 -2.041161E-03 -1.110879E-01 -1.399393E-03 -1.484356E-01 -2.412924E-03 -1.243711E-01 -1.740278E-03 -1.011503E-01 -1.167740E-03 -6.361036E-02 -4.887610E-04 -6.774704E-02 -6.414084E-04 -8.554708E-02 -9.422426E-04 -1.400424E-01 -2.238846E-03 -1.573053E-01 -2.687261E-03 -1.640744E-01 -2.864310E-03 -1.305526E-01 -1.848808E-03 -1.688498E-01 -3.171592E-03 -1.886270E-01 -3.972143E-03 -1.198794E-01 -1.610468E-03 -7.781359E-02 -8.133302E-04 -8.003923E-02 -7.488868E-04 -1.533578E-01 -2.662538E-03 -2.008234E-01 -4.137147E-03 -2.073409E-01 -4.520687E-03 -1.975748E-01 -4.160887E-03 -2.267844E-01 -5.491338E-03 -1.881489E-01 -3.776524E-03 -1.546827E-01 -2.713647E-03 -1.390602E-01 -2.088805E-03 -9.507737E-02 -1.035204E-03 -9.443902E-02 -9.783367E-04 -1.528603E-01 -2.521963E-03 -2.009995E-01 -4.414632E-03 -2.303894E-01 -5.751985E-03 -2.273601E-01 -5.379286E-03 -2.086601E-01 -4.747259E-03 -1.587188E-01 -2.863534E-03 -1.656423E-01 -2.826265E-03 -1.358638E-01 -2.045306E-03 -9.729054E-02 -1.078500E-03 -1.007280E-01 -1.185702E-03 -1.587021E-01 -2.754745E-03 -1.900019E-01 -3.874093E-03 -1.874138E-01 -4.177562E-03 -2.233840E-01 -5.748107E-03 -2.044120E-01 -4.806449E-03 -1.840480E-01 -3.872224E-03 -2.000442E-01 -4.610770E-03 -1.260142E-01 -1.809723E-03 -8.400216E-02 -8.434010E-04 -5.900093E-02 -3.850176E-04 -1.411568E-01 -2.471608E-03 -1.744586E-01 -3.239802E-03 -1.834956E-01 -3.972256E-03 -2.120173E-01 -4.965877E-03 -1.896203E-01 -3.727876E-03 -1.768841E-01 -3.517246E-03 -1.329247E-01 -1.981664E-03 -9.206320E-02 -1.061169E-03 -8.660878E-02 -8.546437E-04 -7.697726E-02 -7.926443E-04 -1.161555E-01 -1.548200E-03 -1.386967E-01 -2.047818E-03 -1.482373E-01 -2.537385E-03 -1.929067E-01 -4.259826E-03 -1.371938E-01 -1.949236E-03 -1.308202E-01 -2.027747E-03 -1.135428E-01 -1.560189E-03 -1.215934E-01 -1.672414E-03 -4.697342E-02 -3.377074E-04 -4.963529E-02 -3.397352E-04 -8.476039E-02 -8.774056E-04 -1.108440E-01 -1.411371E-03 -1.054914E-01 -1.252891E-03 -1.453762E-01 -2.358977E-03 -9.293716E-02 -9.683367E-04 -1.224872E-01 -1.612325E-03 -8.334352E-02 -7.907688E-04 -7.546069E-02 -7.025010E-04 -5.962134E-02 -6.951755E-04 -3.107769E-02 -1.723123E-04 -8.479467E-02 -9.620488E-04 -8.295926E-02 -7.769636E-04 -8.805824E-02 -8.500302E-04 -8.616294E-02 -8.661213E-04 -7.861089E-02 -6.835617E-04 -7.593919E-02 -7.633339E-04 -7.303400E-02 -6.464593E-04 -7.512486E-02 -6.007484E-04 -5.595863E-02 -4.403603E-04 -6.015811E-02 -4.297440E-04 -8.867588E-02 -8.521129E-04 -1.103542E-01 -1.469796E-03 -1.153731E-01 -1.606650E-03 -1.280835E-01 -1.791883E-03 -1.434578E-01 -2.215626E-03 -1.104920E-01 -1.470286E-03 -9.385805E-02 -1.114787E-03 -1.169307E-01 -1.600595E-03 -6.083594E-02 -4.303510E-04 -8.816849E-02 -8.791686E-04 -1.350912E-01 -2.127521E-03 -2.026574E-01 -4.456203E-03 -2.082171E-01 -4.587768E-03 -2.291899E-01 -5.560114E-03 -2.040384E-01 -4.355166E-03 -2.081784E-01 -5.172938E-03 -1.958644E-01 -4.308708E-03 -1.535028E-01 -2.754667E-03 -6.265531E-02 -4.662647E-04 -1.239416E-01 -1.608329E-03 -1.655136E-01 -3.098331E-03 -2.152185E-01 -5.116031E-03 -2.663061E-01 -7.502107E-03 -3.072160E-01 -9.873652E-03 -2.453306E-01 -6.585229E-03 -2.577460E-01 -6.982524E-03 -2.470375E-01 -6.761678E-03 -1.492132E-01 -2.465269E-03 -1.115903E-01 -1.444496E-03 -8.901752E-02 -9.826260E-04 -1.849459E-01 -3.824332E-03 -3.139129E-01 -1.040826E-02 -3.209843E-01 -1.072304E-02 -3.074029E-01 -9.805249E-03 -3.289037E-01 -1.137280E-02 -3.333668E-01 -1.140301E-02 -2.305636E-01 -5.572002E-03 -1.911618E-01 -3.897249E-03 -1.239342E-01 -1.745528E-03 -1.463546E-01 -2.897280E-03 -2.041194E-01 -4.264966E-03 -2.781505E-01 -8.222869E-03 -3.535732E-01 -1.290897E-02 -3.736359E-01 -1.424372E-02 -3.507573E-01 -1.268186E-02 -3.537878E-01 -1.317025E-02 -2.797764E-01 -8.141471E-03 -2.257660E-01 -5.307299E-03 -1.248875E-01 -1.867307E-03 -1.334027E-01 -1.952356E-03 -2.190936E-01 -5.220949E-03 -2.880627E-01 -9.292540E-03 -3.683567E-01 -1.398170E-02 -3.451428E-01 -1.245893E-02 -3.602954E-01 -1.357760E-02 -3.363047E-01 -1.177859E-02 -2.658735E-01 -8.042327E-03 -1.720687E-01 -3.616340E-03 -9.348145E-02 -9.216558E-04 -1.303415E-01 -2.064085E-03 -1.757103E-01 -3.440908E-03 -2.442374E-01 -6.810297E-03 -2.858542E-01 -8.698701E-03 -3.349866E-01 -1.174757E-02 -2.840415E-01 -8.265549E-03 -2.763234E-01 -8.045873E-03 -2.478361E-01 -6.589169E-03 -1.766169E-01 -3.338895E-03 -1.236805E-01 -1.649583E-03 -1.307918E-01 -1.796440E-03 -1.756810E-01 -3.938136E-03 -2.071625E-01 -4.889011E-03 -2.332393E-01 -5.650908E-03 -2.524899E-01 -7.236764E-03 -2.393364E-01 -5.985752E-03 -2.142983E-01 -4.994425E-03 -2.132056E-01 -4.981318E-03 -1.437349E-01 -2.274574E-03 -1.142901E-01 -1.631508E-03 -7.809219E-02 -7.844820E-04 -1.076778E-01 -1.505283E-03 -1.787646E-01 -3.437697E-03 -1.664344E-01 -2.938475E-03 -1.868305E-01 -3.942399E-03 -2.065932E-01 -4.503697E-03 -1.644873E-01 -3.015461E-03 -1.553155E-01 -2.637052E-03 -1.523517E-01 -2.641268E-03 -8.646767E-02 -8.586764E-04 -4.575304E-02 -2.880831E-04 -8.659752E-02 -1.007122E-03 -1.086638E-01 -1.418859E-03 -1.206844E-01 -1.631006E-03 -1.553521E-01 -2.699733E-03 -1.023448E-01 -1.229544E-03 -1.236892E-01 -1.719554E-03 -1.059603E-01 -1.474144E-03 -9.843445E-02 -1.147384E-03 -6.598215E-02 -6.724344E-04 -8.999660E-02 -1.129810E-03 -1.016655E-01 -1.128618E-03 -1.115822E-01 -1.437827E-03 -1.649326E-01 -3.015499E-03 -1.937529E-01 -4.048175E-03 -1.852317E-01 -3.668098E-03 -1.620688E-01 -2.937845E-03 -1.290063E-01 -1.922280E-03 -1.208701E-01 -1.669032E-03 -4.421440E-02 -2.483126E-04 -1.159755E-01 -1.426808E-03 -1.459714E-01 -2.613102E-03 -1.778589E-01 -3.427022E-03 -2.346134E-01 -5.940704E-03 -3.063520E-01 -1.009182E-02 -2.950770E-01 -9.132939E-03 -2.583166E-01 -7.253540E-03 -2.101808E-01 -5.272950E-03 -1.850368E-01 -3.730831E-03 -7.244837E-02 -5.806488E-04 -1.441504E-01 -2.203647E-03 -2.206693E-01 -5.103470E-03 -3.047901E-01 -9.751684E-03 -3.531926E-01 -1.351362E-02 -3.945357E-01 -1.624582E-02 -4.621245E-01 -2.215536E-02 -4.200516E-01 -1.926381E-02 -3.397496E-01 -1.264644E-02 -2.045791E-01 -4.443989E-03 -1.132779E-01 -1.665634E-03 -1.168744E-01 -1.466979E-03 -2.665743E-01 -7.799994E-03 -4.108479E-01 -1.764683E-02 -5.099245E-01 -2.656607E-02 -5.375292E-01 -2.986206E-02 -5.477580E-01 -3.184925E-02 -5.060566E-01 -2.644067E-02 -3.917491E-01 -1.649179E-02 -2.631839E-01 -7.172646E-03 -1.393797E-01 -2.179333E-03 -1.415608E-01 -2.582853E-03 -2.695963E-01 -8.100051E-03 -4.591315E-01 -2.150436E-02 -5.838830E-01 -3.565296E-02 -6.933462E-01 -4.933765E-02 -6.498992E-01 -4.329824E-02 -5.274087E-01 -2.893644E-02 -4.644714E-01 -2.208542E-02 -2.784825E-01 -8.228619E-03 -1.756971E-01 -3.435838E-03 -1.841108E-01 -3.753742E-03 -2.556216E-01 -6.993979E-03 -4.539882E-01 -2.105903E-02 -5.644697E-01 -3.353269E-02 -6.477708E-01 -4.262528E-02 -6.274586E-01 -4.094566E-02 -4.871803E-01 -2.460107E-02 -3.651460E-01 -1.537598E-02 -2.377974E-01 -6.036841E-03 -1.492687E-01 -2.421537E-03 -1.449703E-01 -2.190902E-03 -2.414255E-01 -6.387083E-03 -4.115719E-01 -1.783179E-02 -4.694990E-01 -2.282330E-02 -5.311416E-01 -2.970750E-02 -5.218655E-01 -2.795428E-02 -4.993270E-01 -2.574782E-02 -3.564483E-01 -1.422766E-02 -2.266457E-01 -5.534879E-03 -1.952576E-01 -4.177312E-03 -1.042590E-01 -1.176129E-03 -1.697991E-01 -3.286179E-03 -2.717221E-01 -8.156353E-03 -3.954295E-01 -1.626070E-02 -3.609317E-01 -1.316825E-02 -4.028309E-01 -1.737150E-02 -3.598743E-01 -1.378511E-02 -2.960368E-01 -9.045648E-03 -1.916245E-01 -4.182938E-03 -1.400504E-01 -2.146240E-03 -7.940300E-02 -7.986853E-04 -1.200054E-01 -1.726710E-03 -2.148774E-01 -4.835765E-03 -2.268851E-01 -5.713301E-03 -3.111988E-01 -1.041879E-02 -2.623195E-01 -7.661642E-03 -2.331769E-01 -5.928043E-03 -2.156752E-01 -5.033537E-03 -1.882320E-01 -3.956427E-03 -9.864956E-02 -1.084355E-03 -6.087770E-02 -5.179666E-04 -1.086978E-01 -1.313619E-03 -1.344587E-01 -1.970449E-03 -1.740701E-01 -3.313694E-03 -1.804922E-01 -3.525957E-03 -1.724149E-01 -3.543590E-03 -1.399028E-01 -2.273390E-03 -1.456847E-01 -2.524033E-03 -1.194497E-01 -1.524909E-03 -6.585025E-02 -6.225934E-04 -8.228757E-02 -8.696950E-04 -9.653270E-02 -9.897964E-04 -1.628236E-01 -3.163363E-03 -2.294784E-01 -5.585206E-03 -2.013744E-01 -4.481916E-03 -1.904412E-01 -4.042826E-03 -1.614976E-01 -2.818448E-03 -1.577143E-01 -2.732044E-03 -1.102866E-01 -1.529048E-03 -7.446456E-02 -6.633761E-04 -1.435986E-01 -2.237722E-03 -1.897248E-01 -4.132042E-03 -2.294338E-01 -5.931694E-03 -3.421437E-01 -1.221982E-02 -3.839244E-01 -1.553491E-02 -3.266968E-01 -1.088442E-02 -3.198477E-01 -1.080985E-02 -2.628059E-01 -7.789175E-03 -1.734962E-01 -3.443215E-03 -1.286647E-01 -1.955856E-03 -1.691938E-01 -3.460989E-03 -2.825603E-01 -8.930867E-03 -3.393298E-01 -1.245987E-02 -4.719879E-01 -2.299342E-02 -5.453030E-01 -3.116166E-02 -5.283745E-01 -2.875357E-02 -4.717010E-01 -2.274570E-02 -3.543923E-01 -1.356917E-02 -2.286992E-01 -5.495781E-03 -1.503321E-01 -2.412737E-03 -1.914802E-01 -4.228512E-03 -2.663347E-01 -7.478291E-03 -4.945846E-01 -2.581416E-02 -7.132283E-01 -5.214747E-02 -8.772549E-01 -8.070787E-02 -9.215230E-01 -8.643514E-02 -7.136543E-01 -5.309880E-02 -4.683027E-01 -2.335474E-02 -2.848724E-01 -8.819567E-03 -1.962746E-01 -4.034279E-03 -1.963942E-01 -4.150202E-03 -3.081918E-01 -1.036112E-02 -5.313924E-01 -2.943772E-02 -8.980200E-01 -8.439371E-02 -1.404070E+00 -1.986543E-01 -1.242684E+00 -1.571634E-01 -8.663320E-01 -7.587086E-02 -5.654541E-01 -3.252262E-02 -3.281152E-01 -1.090032E-02 -2.044034E-01 -4.517108E-03 -2.006195E-01 -4.176414E-03 -3.100848E-01 -1.042288E-02 -5.422115E-01 -3.004711E-02 -9.330393E-01 -8.964243E-02 -1.277607E+00 -1.657398E-01 -1.173275E+00 -1.409364E-01 -8.049595E-01 -6.791702E-02 -4.739057E-01 -2.461174E-02 -3.052609E-01 -9.872506E-03 -2.088298E-01 -4.793522E-03 -2.133326E-01 -4.862481E-03 -2.680060E-01 -7.625628E-03 -4.610074E-01 -2.155754E-02 -6.717074E-01 -4.626196E-02 -8.563743E-01 -7.430382E-02 -8.419238E-01 -7.436332E-02 -6.475334E-01 -4.244410E-02 -4.496406E-01 -2.101233E-02 -3.081348E-01 -1.046704E-02 -1.619249E-01 -3.062437E-03 -1.415369E-01 -2.255371E-03 -2.064850E-01 -4.712501E-03 -3.464136E-01 -1.293262E-02 -4.719265E-01 -2.272450E-02 -6.461406E-01 -4.354686E-02 -5.185955E-01 -2.909923E-02 -4.946850E-01 -2.606769E-02 -3.812863E-01 -1.500761E-02 -2.715616E-01 -7.844887E-03 -1.440914E-01 -2.297969E-03 -1.220110E-01 -1.727820E-03 -1.988195E-01 -4.845577E-03 -2.623807E-01 -7.651539E-03 -3.140727E-01 -1.024276E-02 -3.576120E-01 -1.349203E-02 -3.350431E-01 -1.214172E-02 -3.623127E-01 -1.392899E-02 -2.727478E-01 -8.086348E-03 -2.149275E-01 -5.361115E-03 -1.314584E-01 -1.963133E-03 -9.162433E-02 -9.983184E-04 -1.361470E-01 -2.027658E-03 -1.761731E-01 -3.389541E-03 -1.989963E-01 -4.594834E-03 -1.950142E-01 -4.102131E-03 -2.134629E-01 -4.672913E-03 -1.986280E-01 -4.090736E-03 -1.587464E-01 -2.850886E-03 -1.139834E-01 -1.491308E-03 -9.993253E-02 -1.150993E-03 -7.801279E-02 -7.470217E-04 -1.374998E-01 -1.969932E-03 -1.804494E-01 -3.568829E-03 -2.466413E-01 -6.594134E-03 -2.341345E-01 -5.848688E-03 -1.995756E-01 -4.362592E-03 -1.602288E-01 -3.066421E-03 -1.562435E-01 -2.552603E-03 -1.104688E-01 -1.359308E-03 -1.007842E-01 -1.139355E-03 -1.261199E-01 -1.847741E-03 -1.775287E-01 -3.680466E-03 -2.767100E-01 -8.008082E-03 -3.400792E-01 -1.195930E-02 -3.935631E-01 -1.640831E-02 -3.523748E-01 -1.302259E-02 -2.906020E-01 -9.059548E-03 -2.537932E-01 -6.876862E-03 -1.861336E-01 -3.787655E-03 -1.313071E-01 -2.065327E-03 -1.591139E-01 -2.819971E-03 -2.386577E-01 -6.457612E-03 -3.911616E-01 -1.594274E-02 -5.394472E-01 -3.061236E-02 -6.866890E-01 -4.817139E-02 -6.283365E-01 -4.055448E-02 -5.748601E-01 -3.459526E-02 -4.435554E-01 -2.009979E-02 -3.296444E-01 -1.154923E-02 -1.967361E-01 -4.169679E-03 -1.739968E-01 -3.208983E-03 -3.082977E-01 -9.811520E-03 -5.382503E-01 -3.058501E-02 -8.367621E-01 -7.291096E-02 -1.211062E+00 -1.496807E-01 -1.258748E+00 -1.608596E-01 -9.427524E-01 -9.038319E-02 -6.071099E-01 -3.854873E-02 -3.709298E-01 -1.478349E-02 -2.098170E-01 -4.835442E-03 -2.119024E-01 -4.712157E-03 -3.552855E-01 -1.323431E-02 -6.321647E-01 -4.077718E-02 -1.246141E+00 -1.565725E-01 -4.380951E+00 -1.942648E+00 -4.247605E+00 -1.810085E+00 -1.281712E+00 -1.683930E-01 -6.221859E-01 -3.919458E-02 -3.675010E-01 -1.432994E-02 -1.841643E-01 -3.510340E-03 -2.146914E-01 -5.048810E-03 -3.256950E-01 -1.139212E-02 -6.810729E-01 -4.813808E-02 -1.247489E+00 -1.574970E-01 -4.442262E+00 -1.985510E+00 -4.257415E+00 -1.821021E+00 -1.235711E+00 -1.535743E-01 -6.900244E-01 -4.832224E-02 -3.697406E-01 -1.425051E-02 -2.012083E-01 -4.510582E-03 -1.912047E-01 -4.273539E-03 -3.451744E-01 -1.225531E-02 -5.600376E-01 -3.307491E-02 -8.544790E-01 -7.409781E-02 -1.325242E+00 -1.782579E-01 -1.346957E+00 -1.841487E-01 -9.214797E-01 -8.688521E-02 -4.797898E-01 -2.328018E-02 -3.426011E-01 -1.225085E-02 -1.774389E-01 -3.518562E-03 -1.554220E-01 -2.654272E-03 -2.668481E-01 -7.631552E-03 -4.104944E-01 -1.755636E-02 -5.095732E-01 -2.660987E-02 -6.919120E-01 -4.918083E-02 -7.159855E-01 -5.218821E-02 -6.006622E-01 -3.710972E-02 -4.366095E-01 -2.004334E-02 -2.694762E-01 -7.978724E-03 -1.656914E-01 -3.089952E-03 -1.756674E-01 -3.399731E-03 -2.115494E-01 -4.962007E-03 -2.931609E-01 -9.634091E-03 -3.427335E-01 -1.230723E-02 -3.926075E-01 -1.686560E-02 -4.266016E-01 -1.861013E-02 -3.380544E-01 -1.177601E-02 -3.203345E-01 -1.042122E-02 -2.107818E-01 -4.975737E-03 -1.190587E-01 -1.667581E-03 -1.043469E-01 -1.388459E-03 -1.409254E-01 -2.165664E-03 -1.158111E-01 -1.584653E-03 -2.204672E-01 -5.077689E-03 -2.548870E-01 -6.790565E-03 -2.560290E-01 -6.703128E-03 -2.273470E-01 -5.548064E-03 -1.544622E-01 -2.859247E-03 -1.514176E-01 -2.580868E-03 -9.401839E-02 -9.957536E-04 -8.183741E-02 -1.018095E-03 -1.494302E-01 -2.610469E-03 -1.724667E-01 -3.163766E-03 -1.906518E-01 -3.886725E-03 -2.093021E-01 -4.547285E-03 -2.192608E-01 -5.381555E-03 -2.142120E-01 -5.229554E-03 -1.818979E-01 -3.730168E-03 -1.593537E-01 -2.930097E-03 -1.006301E-01 -1.243388E-03 -1.363959E-01 -2.201651E-03 -1.921074E-01 -4.287698E-03 -2.807569E-01 -8.586780E-03 -3.032112E-01 -9.281779E-03 -3.488735E-01 -1.290376E-02 -3.912428E-01 -1.651860E-02 -4.032276E-01 -1.745809E-02 -2.909627E-01 -9.146241E-03 -1.775633E-01 -3.593723E-03 -1.331733E-01 -1.922430E-03 -1.524251E-01 -2.694091E-03 -2.697127E-01 -7.768392E-03 -4.166062E-01 -1.776536E-02 -5.663715E-01 -3.298425E-02 -6.244007E-01 -3.998959E-02 -6.599368E-01 -4.570158E-02 -5.685603E-01 -3.382373E-02 -3.800938E-01 -1.547625E-02 -2.603056E-01 -7.053095E-03 -1.706694E-01 -3.148614E-03 -1.731386E-01 -3.384991E-03 -3.109075E-01 -1.033479E-02 -5.771187E-01 -3.413152E-02 -8.606415E-01 -7.510241E-02 -1.294303E+00 -1.706906E-01 -1.313399E+00 -1.767631E-01 -7.817706E-01 -6.342406E-02 -5.927279E-01 -3.756882E-02 -3.708410E-01 -1.458571E-02 -1.723505E-01 -3.356435E-03 -2.304233E-01 -5.998040E-03 -3.750987E-01 -1.501277E-02 -6.734152E-01 -4.746505E-02 -1.310995E+00 -1.732589E-01 -4.421199E+00 -1.964531E+00 -4.214183E+00 -1.786748E+00 -1.223434E+00 -1.530503E-01 -5.926626E-01 -3.641847E-02 -3.153714E-01 -1.019858E-02 -2.037244E-01 -4.381188E-03 -1.863505E-01 -3.684332E-03 -3.648623E-01 -1.378365E-02 -6.164882E-01 -3.893164E-02 -1.178969E+00 -1.417606E-01 -4.221345E+00 -1.789744E+00 -4.317433E+00 -1.872379E+00 -1.243011E+00 -1.581634E-01 -6.866745E-01 -4.754022E-02 -3.586774E-01 -1.301597E-02 -2.322214E-01 -5.492154E-03 -1.791966E-01 -3.463117E-03 -3.076717E-01 -9.716616E-03 -4.906144E-01 -2.470769E-02 -8.471037E-01 -7.406279E-02 -1.363587E+00 -1.889087E-01 -1.335963E+00 -1.803764E-01 -8.600227E-01 -7.530944E-02 -5.437258E-01 -3.114706E-02 -3.713934E-01 -1.456554E-02 -1.995931E-01 -4.422520E-03 -1.343031E-01 -2.012284E-03 -2.572828E-01 -6.840867E-03 -4.435747E-01 -2.050887E-02 -5.766007E-01 -3.437038E-02 -7.346272E-01 -5.540755E-02 -7.053071E-01 -5.111709E-02 -6.063267E-01 -3.981091E-02 -4.094521E-01 -1.801684E-02 -2.832627E-01 -8.238241E-03 -1.618924E-01 -3.067045E-03 -1.257079E-01 -1.802188E-03 -2.209365E-01 -5.343615E-03 -2.538278E-01 -7.109201E-03 -3.620261E-01 -1.396948E-02 -4.303042E-01 -1.872503E-02 -4.036624E-01 -1.774648E-02 -3.185915E-01 -1.192555E-02 -2.959360E-01 -9.265211E-03 -2.254861E-01 -5.671747E-03 -1.339005E-01 -2.034506E-03 -1.251282E-01 -1.754100E-03 -1.155042E-01 -1.606166E-03 -1.603827E-01 -2.694604E-03 -2.425425E-01 -6.218648E-03 -2.827714E-01 -8.247692E-03 -2.354428E-01 -5.778596E-03 -1.964531E-01 -4.365869E-03 -1.620035E-01 -3.000138E-03 -1.402609E-01 -2.252442E-03 -7.770439E-02 -7.584947E-04 -8.904883E-02 -9.832411E-04 -1.364994E-01 -2.060968E-03 -1.556202E-01 -3.013917E-03 -1.794759E-01 -3.609302E-03 -2.027676E-01 -4.271217E-03 -1.910134E-01 -3.830997E-03 -2.102956E-01 -4.746179E-03 -2.069806E-01 -4.732181E-03 -1.280198E-01 -1.803469E-03 -8.851884E-02 -1.050264E-03 -1.411243E-01 -2.309051E-03 -2.058752E-01 -4.840657E-03 -2.589000E-01 -7.354104E-03 -2.346176E-01 -5.819008E-03 -3.064791E-01 -9.995356E-03 -3.537650E-01 -1.318436E-02 -3.442248E-01 -1.225618E-02 -2.856280E-01 -9.047308E-03 -1.556316E-01 -2.976492E-03 -9.305931E-02 -9.568946E-04 -1.918345E-01 -3.871787E-03 -3.083654E-01 -1.109476E-02 -4.076303E-01 -1.807424E-02 -4.595063E-01 -2.220396E-02 -5.684770E-01 -3.345901E-02 -5.734059E-01 -3.325457E-02 -4.719375E-01 -2.393976E-02 -3.033874E-01 -1.029056E-02 -2.394489E-01 -6.540160E-03 -1.431584E-01 -2.691530E-03 -1.857128E-01 -3.720812E-03 -3.401652E-01 -1.213267E-02 -4.998027E-01 -2.627877E-02 -6.660538E-01 -4.542647E-02 -8.594730E-01 -7.625343E-02 -8.531451E-01 -7.416582E-02 -6.787742E-01 -4.744554E-02 -4.724654E-01 -2.328201E-02 -3.030469E-01 -9.464288E-03 -1.840238E-01 -3.680486E-03 -2.172436E-01 -4.932506E-03 -3.724089E-01 -1.512940E-02 -5.834908E-01 -3.595138E-02 -8.787419E-01 -7.754496E-02 -1.235501E+00 -1.556040E-01 -1.186802E+00 -1.419219E-01 -8.626663E-01 -7.644446E-02 -5.366263E-01 -2.954661E-02 -3.177208E-01 -1.051791E-02 -1.844215E-01 -3.676916E-03 -1.932190E-01 -4.023337E-03 -3.693850E-01 -1.452218E-02 -5.443615E-01 -3.020527E-02 -8.889578E-01 -8.111822E-02 -1.273207E+00 -1.655818E-01 -1.247526E+00 -1.585006E-01 -8.324980E-01 -7.213823E-02 -4.899464E-01 -2.450485E-02 -3.370823E-01 -1.208260E-02 -1.809043E-01 -3.714864E-03 -1.615415E-01 -2.906239E-03 -2.937828E-01 -9.651929E-03 -4.913048E-01 -2.639344E-02 -6.850176E-01 -4.797579E-02 -8.755910E-01 -7.958162E-02 -8.703001E-01 -7.730840E-02 -6.973913E-01 -5.089360E-02 -4.203999E-01 -1.844697E-02 -3.140340E-01 -1.039993E-02 -1.441709E-01 -2.488125E-03 -1.350197E-01 -2.064659E-03 -2.543930E-01 -7.177543E-03 -3.348117E-01 -1.259149E-02 -4.679892E-01 -2.273369E-02 -6.434887E-01 -4.331187E-02 -5.381700E-01 -2.974074E-02 -4.555945E-01 -2.167655E-02 -3.401588E-01 -1.191694E-02 -2.681734E-01 -7.550804E-03 -1.704519E-01 -3.365024E-03 -9.745304E-02 -1.232312E-03 -1.678994E-01 -3.221936E-03 -2.605430E-01 -7.393204E-03 -3.128187E-01 -1.138967E-02 -3.712111E-01 -1.460808E-02 -3.609117E-01 -1.331179E-02 -3.321706E-01 -1.170549E-02 -2.480901E-01 -6.266952E-03 -2.002359E-01 -4.338795E-03 -1.162468E-01 -1.536532E-03 -7.239001E-02 -5.815144E-04 -1.163546E-01 -1.453456E-03 -1.636165E-01 -3.201377E-03 -1.973025E-01 -4.660155E-03 -2.100585E-01 -5.039148E-03 -2.171398E-01 -5.070524E-03 -1.995065E-01 -4.193481E-03 -1.813545E-01 -3.549108E-03 -1.365406E-01 -2.182883E-03 -8.101165E-02 -7.758114E-04 -7.133170E-02 -5.967128E-04 -1.319234E-01 -1.933536E-03 -1.445023E-01 -2.409485E-03 -1.495938E-01 -2.481635E-03 -1.801306E-01 -3.481001E-03 -1.733442E-01 -3.171024E-03 -1.725688E-01 -3.165238E-03 -1.518925E-01 -2.585745E-03 -1.077414E-01 -1.395636E-03 -7.934204E-02 -7.147327E-04 -1.062269E-01 -1.354440E-03 -1.751122E-01 -3.623982E-03 -2.203107E-01 -5.413498E-03 -2.341057E-01 -5.605200E-03 -2.669322E-01 -7.526239E-03 -2.746743E-01 -7.646941E-03 -2.389916E-01 -6.235257E-03 -1.587546E-01 -2.827472E-03 -1.498724E-01 -2.673613E-03 -1.051763E-01 -1.391507E-03 -1.424360E-01 -2.468775E-03 -2.608608E-01 -7.055429E-03 -3.154162E-01 -1.024928E-02 -3.674104E-01 -1.418521E-02 -3.976162E-01 -1.732640E-02 -4.746502E-01 -2.349709E-02 -3.662445E-01 -1.447515E-02 -2.506236E-01 -6.593606E-03 -2.161204E-01 -4.801367E-03 -1.306963E-01 -1.975560E-03 -1.770351E-01 -3.932818E-03 -2.635109E-01 -7.772472E-03 -4.024536E-01 -1.731960E-02 -4.701442E-01 -2.265515E-02 -5.561475E-01 -3.235124E-02 -5.523785E-01 -3.142962E-02 -5.071292E-01 -2.592728E-02 -3.746613E-01 -1.518899E-02 -2.620776E-01 -7.439402E-03 -1.561701E-01 -2.901626E-03 -1.722037E-01 -3.249117E-03 -2.729386E-01 -8.041848E-03 -4.157578E-01 -1.761081E-02 -5.608817E-01 -3.221445E-02 -7.027459E-01 -5.154772E-02 -6.902150E-01 -4.817212E-02 -5.174043E-01 -2.771951E-02 -4.297342E-01 -1.970980E-02 -2.927718E-01 -9.421566E-03 -1.860039E-01 -3.719139E-03 -1.510489E-01 -2.673423E-03 -2.992366E-01 -9.425407E-03 -4.569637E-01 -2.187717E-02 -5.810709E-01 -3.569290E-02 -6.664391E-01 -4.607395E-02 -6.898814E-01 -4.853841E-02 -5.306547E-01 -2.907467E-02 -4.138514E-01 -1.844067E-02 -2.836181E-01 -9.090950E-03 -1.827952E-01 -3.670505E-03 -1.339105E-01 -1.976730E-03 -2.247962E-01 -5.455936E-03 -3.775577E-01 -1.529613E-02 -4.605234E-01 -2.228303E-02 -5.731045E-01 -3.426291E-02 -5.698592E-01 -3.415653E-02 -4.700203E-01 -2.298571E-02 -3.419079E-01 -1.254302E-02 -2.594048E-01 -7.486049E-03 -1.403745E-01 -2.288996E-03 -1.307053E-01 -2.306039E-03 -2.305399E-01 -5.746901E-03 -2.866663E-01 -8.437990E-03 -3.547902E-01 -1.415343E-02 -3.903305E-01 -1.721878E-02 -3.995569E-01 -1.663856E-02 -3.597994E-01 -1.369907E-02 -3.084707E-01 -1.005451E-02 -1.929703E-01 -4.111212E-03 -1.226805E-01 -1.616264E-03 -9.707080E-02 -1.277801E-03 -1.349714E-01 -2.412097E-03 -1.706592E-01 -3.112630E-03 -2.431900E-01 -6.662780E-03 -2.719484E-01 -7.972869E-03 -2.782047E-01 -8.195264E-03 -2.198394E-01 -5.159833E-03 -1.847153E-01 -3.606258E-03 -1.655937E-01 -3.412468E-03 -1.132640E-01 -1.342051E-03 -6.977329E-02 -6.061071E-04 -8.063628E-02 -7.877860E-04 -1.369291E-01 -2.216310E-03 -1.527061E-01 -2.661389E-03 -1.808807E-01 -3.626051E-03 -1.723708E-01 -3.227953E-03 -1.570487E-01 -2.824199E-03 -1.402935E-01 -2.196525E-03 -1.046978E-01 -1.394771E-03 -7.765529E-02 -6.990073E-04 -5.309912E-02 -4.179704E-04 -8.113995E-02 -8.093210E-04 -1.004879E-01 -1.274755E-03 -1.474015E-01 -2.957775E-03 -1.227188E-01 -1.661445E-03 -1.367411E-01 -2.049836E-03 -1.257025E-01 -1.739859E-03 -9.595806E-02 -1.143520E-03 -5.932828E-02 -4.443026E-04 -6.214003E-02 -4.698384E-04 -1.047908E-01 -1.265030E-03 -1.389236E-01 -2.066555E-03 -1.441238E-01 -2.187643E-03 -1.954745E-01 -4.024829E-03 -2.018960E-01 -4.436820E-03 -2.304400E-01 -5.702269E-03 -1.889259E-01 -3.911134E-03 -1.651129E-01 -2.907211E-03 -1.266147E-01 -1.798632E-03 -9.726395E-02 -1.038410E-03 -1.239366E-01 -2.020884E-03 -1.692392E-01 -3.039249E-03 -2.262593E-01 -5.810761E-03 -2.371783E-01 -6.148422E-03 -2.724207E-01 -7.965467E-03 -2.754620E-01 -8.212118E-03 -2.616121E-01 -7.738784E-03 -2.416846E-01 -6.508644E-03 -1.823329E-01 -4.244589E-03 -1.153662E-01 -1.541320E-03 -1.498687E-01 -2.427094E-03 -2.294988E-01 -5.678440E-03 -2.337590E-01 -6.042902E-03 -3.165064E-01 -1.047831E-02 -3.372589E-01 -1.176332E-02 -3.369130E-01 -1.214308E-02 -3.077673E-01 -9.854791E-03 -2.727368E-01 -8.153505E-03 -2.291204E-01 -5.762201E-03 -1.449108E-01 -2.631818E-03 -1.222645E-01 -1.652033E-03 -2.342919E-01 -6.080976E-03 -2.867658E-01 -9.143890E-03 -3.284926E-01 -1.110468E-02 -3.721608E-01 -1.458209E-02 -3.943281E-01 -1.624417E-02 -3.127115E-01 -1.090060E-02 -2.181120E-01 -5.081861E-03 -2.038850E-01 -4.541180E-03 -1.471756E-01 -2.612669E-03 -1.356517E-01 -2.315498E-03 -2.039418E-01 -4.569034E-03 -2.379673E-01 -6.028728E-03 -2.912334E-01 -8.794159E-03 -3.675708E-01 -1.388797E-02 -3.830007E-01 -1.493415E-02 -3.497252E-01 -1.323190E-02 -2.129266E-01 -5.366850E-03 -2.051774E-01 -5.235913E-03 -1.495687E-01 -2.578269E-03 -1.007903E-01 -1.213029E-03 -1.942201E-01 -4.152027E-03 -2.691558E-01 -7.844599E-03 -2.833552E-01 -8.562033E-03 -3.539964E-01 -1.296456E-02 -3.313330E-01 -1.152405E-02 -2.882665E-01 -9.275609E-03 -2.606018E-01 -7.326373E-03 -2.170792E-01 -5.088581E-03 -1.175397E-01 -1.425662E-03 -9.291662E-02 -1.030694E-03 -1.502293E-01 -2.605564E-03 -1.683973E-01 -3.164858E-03 -2.300104E-01 -5.597737E-03 -2.921841E-01 -9.137452E-03 -3.105624E-01 -1.077940E-02 -2.457323E-01 -6.748662E-03 -1.935480E-01 -4.153509E-03 -1.781340E-01 -3.735545E-03 -8.549182E-02 -7.932774E-04 -7.995611E-02 -6.914994E-04 -1.120022E-01 -1.608931E-03 -1.666393E-01 -3.351392E-03 -1.763892E-01 -3.781795E-03 -2.215879E-01 -5.446848E-03 -1.973224E-01 -4.088057E-03 -1.807076E-01 -3.807788E-03 -1.497413E-01 -2.510679E-03 -1.258135E-01 -1.824079E-03 -7.256548E-02 -6.032346E-04 -5.802787E-02 -4.068274E-04 -8.087439E-02 -8.125859E-04 -9.445601E-02 -1.220157E-03 -1.278262E-01 -1.976480E-03 -1.447187E-01 -2.496284E-03 -1.492610E-01 -2.453885E-03 -1.294170E-01 -1.822523E-03 -8.046777E-02 -7.104920E-04 -8.863832E-02 -9.206404E-04 -4.044133E-02 -2.016136E-04 -3.647497E-02 -1.736207E-04 -7.726524E-02 -7.189629E-04 -6.850678E-02 -5.399094E-04 -7.120540E-02 -6.049792E-04 -9.914070E-02 -1.178916E-03 -9.212489E-02 -1.014142E-03 -8.081211E-02 -7.572737E-04 -6.454690E-02 -5.539457E-04 -4.993214E-02 -3.161361E-04 -3.464406E-02 -1.743401E-04 -5.195266E-02 -3.077352E-04 -1.032248E-01 -1.231336E-03 -1.140722E-01 -1.517037E-03 -9.270288E-02 -1.194042E-03 -1.199421E-01 -1.713870E-03 -1.129313E-01 -1.491867E-03 -1.104339E-01 -1.526039E-03 -1.080665E-01 -1.372021E-03 -8.160995E-02 -6.843931E-04 -6.342734E-02 -5.271807E-04 -9.331087E-02 -1.097048E-03 -1.185250E-01 -1.534560E-03 -1.349132E-01 -2.447610E-03 -1.304714E-01 -2.217664E-03 -1.581891E-01 -2.862519E-03 -1.584546E-01 -2.780212E-03 -1.538480E-01 -2.634437E-03 -1.637997E-01 -2.992391E-03 -1.181898E-01 -1.765232E-03 -8.541970E-02 -8.382310E-04 -9.823634E-02 -1.116285E-03 -1.486333E-01 -2.343453E-03 -1.631008E-01 -2.995222E-03 -1.755338E-01 -3.448102E-03 -1.754730E-01 -3.227041E-03 -1.842652E-01 -3.637768E-03 -1.577573E-01 -2.654428E-03 -1.401177E-01 -2.280343E-03 -1.341096E-01 -1.900302E-03 -8.035023E-02 -8.312873E-04 -1.063904E-01 -1.375093E-03 -1.216848E-01 -1.721657E-03 -2.004753E-01 -4.510521E-03 -1.889712E-01 -3.847826E-03 -2.081610E-01 -4.756630E-03 -2.301263E-01 -5.717347E-03 -2.048600E-01 -4.561616E-03 -1.542754E-01 -2.639748E-03 -1.321829E-01 -1.993402E-03 -9.014640E-02 -9.359911E-04 -7.974780E-02 -8.078227E-04 -1.252435E-01 -1.711334E-03 -1.570584E-01 -2.959866E-03 -2.039016E-01 -4.591866E-03 -2.189983E-01 -5.090456E-03 -2.191556E-01 -5.055427E-03 -2.006583E-01 -4.702936E-03 -1.427473E-01 -2.173216E-03 -1.024856E-01 -1.223983E-03 -8.494077E-02 -9.050889E-04 -1.043652E-01 -1.259550E-03 -1.135027E-01 -1.445575E-03 -1.600726E-01 -2.607556E-03 -1.831531E-01 -4.043413E-03 -2.007142E-01 -4.477475E-03 -1.767643E-01 -3.298936E-03 -1.522826E-01 -2.841107E-03 -1.288167E-01 -1.944141E-03 -1.129177E-01 -1.466746E-03 -9.166114E-02 -1.059245E-03 -7.278205E-02 -7.174163E-04 -1.368554E-01 -2.140442E-03 -1.576875E-01 -2.802493E-03 -1.490721E-01 -2.494952E-03 -2.062740E-01 -4.926381E-03 -1.707643E-01 -3.221954E-03 -1.793503E-01 -3.661578E-03 -1.255583E-01 -1.994441E-03 -1.011375E-01 -1.127338E-03 -5.944771E-02 -5.079367E-04 -6.143141E-02 -4.850205E-04 -8.747215E-02 -9.029610E-04 -1.135806E-01 -1.572457E-03 -1.258766E-01 -1.776739E-03 -1.460430E-01 -2.470050E-03 -1.449479E-01 -2.231440E-03 -1.295714E-01 -1.929423E-03 -1.137994E-01 -1.612784E-03 -8.730775E-02 -8.683726E-04 -6.186674E-02 -4.521535E-04 -4.404648E-02 -3.596329E-04 -6.609800E-02 -5.725272E-04 -8.204018E-02 -7.710094E-04 -9.063221E-02 -1.005713E-03 -9.594152E-02 -1.071929E-03 -8.648906E-02 -9.624176E-04 -6.818770E-02 -5.453348E-04 -5.887333E-02 -4.783382E-04 -6.201530E-02 -4.304358E-04 -4.838730E-02 -3.281581E-04 -tally 2: -2.393627E-03 -2.636290E-06 -2.222156E-03 -1.516148E-06 -2.867439E-03 -2.178580E-06 -7.923009E-03 -1.131939E-05 -3.986634E-03 -4.120137E-06 -7.826419E-03 -1.381669E-05 -6.138176E-03 -7.147428E-06 -3.876880E-03 -2.697208E-06 -2.980562E-03 -3.407321E-06 -1.774473E-03 -8.936196E-07 -2.805366E-03 -2.770194E-06 -3.942385E-03 -3.541964E-06 -4.287920E-03 -3.508749E-06 -7.477034E-03 -1.023581E-05 -1.829256E-03 -9.746709E-07 -5.062973E-03 -5.540060E-06 -4.594275E-03 -5.704022E-06 -3.405515E-03 -3.312460E-06 -9.423220E-03 -1.189576E-05 -1.066888E-02 -2.047020E-05 -7.596120E-03 -1.097485E-05 -5.727684E-03 -9.708804E-06 -4.299383E-03 -3.708395E-06 -9.513211E-03 -1.464618E-05 -5.378401E-03 -5.129879E-06 -5.096252E-03 -3.430859E-06 -7.146855E-03 -1.124612E-05 -6.572738E-03 -7.596525E-06 -7.380131E-03 -9.633384E-06 -6.219137E-03 -8.163623E-06 -6.908868E-03 -8.615668E-06 -7.350963E-03 -1.116403E-05 -5.438361E-03 -6.022683E-06 -4.233493E-03 -5.102016E-06 -9.383252E-03 -1.536263E-05 -1.199002E-02 -2.034238E-05 -7.934135E-03 -8.959239E-06 -8.511914E-03 -1.022394E-05 -6.162682E-03 -4.504202E-06 -6.648149E-03 -5.723838E-06 -7.264317E-03 -8.981506E-06 -1.037779E-02 -1.703942E-05 -4.759363E-03 -3.403173E-06 -9.522407E-03 -1.428157E-05 -7.387030E-03 -1.550312E-05 -4.844392E-03 -8.366311E-06 -6.843631E-03 -8.685895E-06 -7.764489E-03 -8.325268E-06 -5.854513E-03 -5.702341E-06 -7.087671E-03 -1.025951E-05 -2.415844E-03 -2.739481E-06 -3.086207E-03 -1.914733E-06 -3.654957E-03 -3.442162E-06 -4.643653E-03 -7.197439E-06 -1.156734E-02 -1.759634E-05 -7.348653E-03 -9.450024E-06 -7.852217E-03 -9.889996E-06 -4.188787E-03 -2.746400E-06 -4.526053E-03 -3.421811E-06 -7.133876E-03 -5.514540E-06 -7.642743E-03 -1.296144E-05 -3.436567E-03 -5.211995E-06 -2.358938E-03 -1.100467E-06 -4.225043E-03 -3.484328E-06 -6.975938E-03 -1.402542E-05 -2.948552E-03 -2.413285E-06 -7.430097E-03 -9.911242E-06 -9.344383E-03 -1.730038E-05 -5.155130E-03 -4.067305E-06 -9.223392E-03 -1.460017E-05 -6.706254E-03 -1.105767E-05 -6.585388E-03 -9.369522E-06 -5.779745E-03 -9.335364E-06 -8.502853E-03 -1.535431E-05 -3.196086E-03 -2.721454E-06 -4.062636E-03 -4.530161E-06 -4.949408E-03 -4.754719E-06 -8.697214E-03 -1.269695E-05 -7.720575E-03 -1.111572E-05 -9.096811E-03 -1.174536E-05 -8.395332E-03 -1.344990E-05 -4.327467E-03 -4.178301E-06 -8.098133E-03 -2.129072E-05 -8.641159E-03 -1.993637E-05 -4.910339E-03 -4.798040E-06 -9.222729E-03 -1.731644E-05 -2.362293E-03 -1.920887E-06 -6.474215E-03 -7.989801E-06 -5.093903E-03 -4.638782E-06 -5.190870E-03 -4.064962E-06 -9.156062E-03 -1.062935E-05 -8.084833E-03 -1.278518E-05 -6.006837E-03 -5.037849E-06 -2.770574E-03 -1.880169E-06 -8.452309E-03 -1.160057E-05 -3.397900E-03 -2.727237E-06 -2.289237E-03 -1.800828E-06 -4.695731E-03 -3.765699E-06 -4.924545E-03 -5.339278E-06 -3.924491E-03 -3.534032E-06 -5.847744E-03 -5.832921E-06 -5.289218E-03 -4.574845E-06 -6.846305E-03 -7.758157E-06 -1.047199E-02 -2.215876E-05 -4.108674E-03 -4.661482E-06 -3.645438E-03 -3.482466E-06 -7.403892E-03 -9.076272E-06 -9.992980E-03 -1.850054E-05 -5.443023E-03 -6.695689E-06 -3.847833E-03 -4.206098E-06 -2.277807E-03 -2.917797E-06 -3.224646E-03 -2.590833E-06 -2.712146E-03 -1.564363E-06 -2.511703E-03 -2.073210E-06 -2.851624E-03 -2.406321E-06 -6.419364E-03 -8.208048E-06 -3.583974E-03 -2.129485E-06 -4.071264E-03 -3.984855E-06 -4.533579E-03 -3.713304E-06 -4.578848E-03 -5.079242E-06 -5.611098E-03 -6.817450E-06 -5.466353E-03 -4.988832E-06 -6.854470E-03 -7.459449E-06 -1.157268E-02 -2.134366E-05 -7.273077E-03 -9.732982E-06 -8.349702E-03 -1.250149E-05 -5.050822E-03 -6.018695E-06 -2.514025E-03 -1.130420E-06 -3.427587E-03 -3.225038E-06 -3.873162E-03 -2.996903E-06 -7.323374E-03 -8.254236E-06 -6.098103E-03 -7.253404E-06 -6.739636E-03 -8.349945E-06 -9.485072E-03 -1.713563E-05 -5.984992E-03 -9.163531E-06 -8.834991E-03 -1.335810E-05 -4.066934E-03 -3.579803E-06 -1.652658E-02 -4.834880E-05 -7.000637E-03 -1.069231E-05 -7.937972E-03 -1.290117E-05 -3.766475E-03 -2.867345E-06 -2.461271E-03 -1.788656E-06 -7.788544E-03 -1.121555E-05 -9.541095E-03 -2.231145E-05 -7.679962E-03 -9.840343E-06 -5.742139E-03 -4.940156E-06 -5.062263E-03 -4.779159E-06 -1.289208E-02 -2.955604E-05 -1.544740E-02 -3.866639E-05 -1.954402E-02 -4.721734E-05 -9.149250E-03 -1.133509E-05 -1.090073E-02 -2.153530E-05 -4.758115E-03 -3.459784E-06 -6.236554E-03 -7.454691E-06 -1.032788E-02 -1.596371E-05 -1.444275E-02 -3.574908E-05 -6.464816E-03 -6.384836E-06 -8.737589E-03 -1.139821E-05 -1.522241E-02 -3.688054E-05 -1.106278E-02 -2.001640E-05 -1.657751E-03 -7.896422E-07 -9.985083E-03 -2.005574E-05 -1.652296E-02 -4.365058E-05 -1.302377E-02 -2.178742E-05 -9.435666E-03 -1.687352E-05 -6.711506E-03 -6.885294E-06 -1.142166E-02 -1.609449E-05 -1.419856E-02 -2.849773E-05 -8.442366E-03 -1.011801E-05 -1.071637E-02 -1.610076E-05 -4.476911E-03 -3.961715E-06 -7.809454E-03 -1.419144E-05 -1.181657E-02 -2.104822E-05 -1.373873E-02 -2.251824E-05 -8.797909E-03 -9.748724E-06 -1.504789E-02 -4.195617E-05 -7.006137E-03 -6.669697E-06 -9.537389E-03 -1.849189E-05 -1.780900E-02 -4.302041E-05 -1.724591E-02 -3.993250E-05 -9.881865E-03 -1.435848E-05 -1.212976E-02 -2.281306E-05 -1.155598E-02 -2.437179E-05 -1.323280E-02 -2.884432E-05 -8.626223E-03 -1.632385E-05 -8.459408E-03 -1.577691E-05 -5.796477E-03 -8.302775E-06 -7.329870E-03 -9.181815E-06 -5.899442E-03 -9.585863E-06 -3.270135E-03 -2.283602E-06 -1.256169E-02 -2.107461E-05 -1.234423E-02 -1.770300E-05 -7.478528E-03 -9.995232E-06 -9.809248E-03 -1.705587E-05 -1.508701E-02 -4.933892E-05 -9.484511E-03 -1.383716E-05 -9.906783E-03 -1.637085E-05 -1.682365E-02 -3.925758E-05 -1.258622E-02 -2.571505E-05 -1.501752E-02 -3.834255E-05 -8.820664E-03 -1.146570E-05 -9.142316E-03 -1.367354E-05 -1.607994E-02 -3.440957E-05 -1.819921E-02 -4.213322E-05 -1.049376E-02 -1.508696E-05 -1.125487E-02 -1.829361E-05 -1.255946E-02 -2.400912E-05 -1.494753E-02 -2.880665E-05 -9.906163E-03 -1.714469E-05 -9.801065E-03 -1.600484E-05 -9.144471E-03 -1.267827E-05 -9.284445E-03 -1.370415E-05 -7.423687E-03 -7.432654E-06 -5.839529E-03 -7.346711E-06 -1.203215E-02 -1.827698E-05 -1.168395E-02 -2.279351E-05 -8.086186E-03 -1.615505E-05 -7.899387E-03 -1.190799E-05 -1.297481E-02 -2.625448E-05 -1.012733E-02 -1.604797E-05 -7.655395E-03 -8.264047E-06 -6.482761E-03 -7.546581E-06 -9.071892E-03 -1.344566E-05 -1.012199E-02 -1.652283E-05 -9.504897E-03 -1.476924E-05 -5.662581E-03 -5.323904E-06 -7.382282E-03 -1.000786E-05 -6.180783E-03 -7.844120E-06 -2.197420E-03 -1.391522E-06 -6.007425E-03 -7.959122E-06 -7.715644E-03 -1.608319E-05 -5.247749E-03 -7.416762E-06 -1.694277E-03 -6.578326E-07 -5.339576E-03 -5.097832E-06 -6.019786E-03 -5.618274E-06 -4.786336E-03 -7.186037E-06 -6.122950E-03 -5.610674E-06 -8.057029E-03 -1.204366E-05 -6.301473E-03 -6.965375E-06 -4.120695E-03 -3.695383E-06 -5.874479E-03 -6.599197E-06 -6.691277E-03 -7.819406E-06 -5.109849E-03 -6.563614E-06 -8.391296E-03 -9.940452E-06 -5.839507E-03 -5.521558E-06 -4.596793E-03 -4.130860E-06 -5.374245E-03 -1.030905E-05 -1.632711E-03 -8.301397E-07 -3.126223E-03 -2.656593E-06 -3.937711E-03 -3.000478E-06 -1.156184E-02 -2.627381E-05 -5.611109E-03 -6.000471E-06 -6.252306E-03 -8.525688E-06 -9.821256E-03 -2.080867E-05 -6.202478E-03 -9.705719E-06 -9.744072E-03 -1.419879E-05 -4.563774E-03 -5.256907E-06 -8.587477E-03 -1.097640E-05 -7.671018E-03 -1.047414E-05 -7.311535E-03 -8.520205E-06 -5.701036E-03 -7.538301E-06 -2.627195E-03 -1.584039E-06 -9.969461E-03 -1.489942E-05 -7.095469E-03 -8.576195E-06 -1.168498E-02 -2.716853E-05 -1.070319E-02 -2.148367E-05 -1.016441E-02 -1.786630E-05 -1.292596E-02 -2.389182E-05 -1.217737E-02 -2.769412E-05 -1.181009E-02 -2.340802E-05 -1.574105E-02 -3.124980E-05 -1.232805E-02 -2.754960E-05 -1.188839E-02 -2.281613E-05 -6.603428E-03 -7.994872E-06 -9.606012E-03 -1.590439E-05 -1.440947E-02 -3.393244E-05 -1.302185E-02 -2.781063E-05 -1.299900E-02 -2.077190E-05 -9.475720E-03 -1.345778E-05 -1.146355E-02 -2.243784E-05 -1.349840E-02 -2.573754E-05 -7.739444E-03 -8.409802E-06 -1.466716E-02 -2.433264E-05 -1.806287E-02 -4.053139E-05 -8.810509E-03 -1.132204E-05 -1.024195E-02 -1.779935E-05 -2.025420E-02 -5.383414E-05 -1.707065E-02 -3.895805E-05 -1.038874E-02 -1.447558E-05 -1.204454E-02 -2.594328E-05 -1.354337E-02 -2.168067E-05 -1.483635E-02 -2.755558E-05 -1.192445E-02 -3.329659E-05 -2.158708E-02 -6.668840E-05 -1.234119E-02 -2.669020E-05 -1.410581E-02 -3.302957E-05 -8.354805E-03 -9.152126E-06 -9.135582E-03 -1.272798E-05 -1.639890E-02 -3.260235E-05 -1.941356E-02 -4.768472E-05 -9.432927E-03 -1.518984E-05 -8.177517E-03 -1.165366E-05 -9.416129E-03 -1.296249E-05 -8.128386E-03 -8.608672E-06 -1.105831E-02 -1.814734E-05 -1.401062E-02 -3.340952E-05 -1.142672E-02 -2.129460E-05 -9.161476E-03 -1.306319E-05 -9.794446E-03 -1.416201E-05 -9.135097E-03 -1.706236E-05 -1.853399E-02 -3.920131E-05 -1.227701E-02 -2.106422E-05 -1.056602E-02 -2.102108E-05 -8.267866E-03 -1.184427E-05 -1.303652E-02 -3.007847E-05 -1.109107E-02 -1.508434E-05 -1.255273E-02 -3.715445E-05 -1.568071E-02 -3.587957E-05 -1.697298E-02 -4.299097E-05 -2.038316E-02 -6.095075E-05 -1.285306E-02 -2.307142E-05 -1.201762E-02 -3.129200E-05 -1.499546E-02 -3.208959E-05 -2.043263E-02 -5.689094E-05 -1.189038E-02 -2.042718E-05 -1.950482E-02 -5.269872E-05 -1.134487E-02 -2.521302E-05 -1.878263E-02 -4.929885E-05 -1.873654E-02 -5.934321E-05 -1.419859E-02 -2.646755E-05 -1.651980E-02 -4.148598E-05 -1.314908E-02 -2.182046E-05 -1.021903E-02 -1.717431E-05 -1.208532E-02 -2.496385E-05 -1.982124E-02 -4.519007E-05 -2.237475E-02 -7.384327E-05 -1.168783E-02 -2.197925E-05 -1.121917E-02 -1.848105E-05 -1.176886E-02 -1.989856E-05 -1.028612E-02 -2.002048E-05 -6.441121E-03 -1.208678E-05 -9.334858E-03 -1.685718E-05 -1.221526E-02 -2.734816E-05 -8.109247E-03 -1.518336E-05 -8.368313E-03 -1.063729E-05 -8.855930E-03 -1.170749E-05 -1.172890E-02 -1.956774E-05 -9.863812E-03 -1.315788E-05 -5.592525E-03 -6.344568E-06 -8.987555E-03 -2.234382E-05 -3.266822E-03 -2.479505E-06 -6.189326E-03 -8.824564E-06 -5.844977E-03 -5.169490E-06 -7.046630E-03 -1.052376E-05 -6.579857E-03 -8.415446E-06 -1.093757E-02 -1.570418E-05 -1.534199E-03 -4.843955E-07 -3.972367E-03 -3.930212E-06 -9.061215E-03 -1.261741E-05 -8.800538E-03 -1.921110E-05 -3.225443E-03 -3.493463E-06 -5.742921E-03 -7.524467E-06 -8.894549E-03 -9.527470E-06 -1.014672E-02 -2.120305E-05 -5.364672E-03 -6.378322E-06 -1.066153E-02 -1.712472E-05 -6.130226E-03 -6.243703E-06 -4.018022E-03 -2.930167E-06 -4.956188E-03 -4.356249E-06 -6.252583E-03 -6.885470E-06 -8.007253E-03 -8.821722E-06 -6.639119E-03 -8.933356E-06 -1.463344E-02 -3.442332E-05 -1.038024E-02 -1.880148E-05 -1.206043E-02 -2.558498E-05 -4.570005E-03 -3.726957E-06 -1.242332E-02 -2.230997E-05 -1.977578E-02 -4.435986E-05 -1.061292E-02 -2.445701E-05 -1.424423E-02 -3.432092E-05 -9.396166E-03 -1.401917E-05 -1.392713E-02 -2.180224E-05 -1.424206E-02 -2.481086E-05 -1.709208E-02 -4.686642E-05 -1.878028E-02 -4.097819E-05 -1.586170E-02 -3.899306E-05 -1.186469E-02 -2.666019E-05 -1.771802E-02 -4.244451E-05 -2.012793E-02 -4.893656E-05 -1.650347E-02 -3.934790E-05 -1.148512E-02 -1.454575E-05 -1.749383E-02 -5.245021E-05 -1.225617E-02 -3.059339E-05 -1.346221E-02 -2.189743E-05 -2.304004E-02 -5.757458E-05 -2.222990E-02 -5.924120E-05 -1.952055E-02 -4.455112E-05 -2.382543E-02 -8.732633E-05 -1.530886E-02 -4.091608E-05 -1.339459E-02 -2.841021E-05 -1.625542E-02 -3.786269E-05 -2.338447E-02 -6.870429E-05 -1.490538E-02 -3.792400E-05 -1.790848E-02 -4.535348E-05 -1.122685E-02 -2.253480E-05 -1.330235E-02 -2.292380E-05 -2.135308E-02 -5.586248E-05 -1.695542E-02 -3.629907E-05 -1.155426E-02 -1.914452E-05 -1.571691E-02 -3.489736E-05 -1.572803E-02 -4.611373E-05 -1.284552E-02 -2.456383E-05 -1.901269E-02 -4.808607E-05 -2.485036E-02 -8.880235E-05 -1.465112E-02 -3.185430E-05 -2.020800E-02 -4.881856E-05 -1.401589E-02 -2.430294E-05 -9.002706E-03 -1.229314E-05 -1.992235E-02 -4.240852E-05 -2.006701E-02 -4.842321E-05 -1.641971E-02 -4.817406E-05 -1.595751E-02 -4.338042E-05 -1.853727E-02 -4.393578E-05 -2.192942E-02 -6.739913E-05 -1.867919E-02 -5.139172E-05 -2.177355E-02 -5.751645E-05 -1.184805E-02 -2.240654E-05 -2.099274E-02 -5.999346E-05 -1.322643E-02 -2.131002E-05 -1.656305E-02 -4.169252E-05 -2.381731E-02 -9.074804E-05 -2.704019E-02 -1.044920E-04 -1.801171E-02 -4.035920E-05 -1.967092E-02 -5.363932E-05 -1.168953E-02 -1.754128E-05 -1.832249E-02 -3.962019E-05 -1.704595E-02 -3.468261E-05 -1.265896E-02 -2.389931E-05 -1.393723E-02 -3.209713E-05 -1.201908E-02 -2.196652E-05 -1.121588E-02 -1.970440E-05 -1.427491E-02 -2.765834E-05 -2.153384E-02 -5.860763E-05 -1.776842E-02 -3.609550E-05 -7.672472E-03 -1.269710E-05 -1.265904E-02 -2.534380E-05 -1.278354E-02 -2.508897E-05 -1.391779E-02 -4.666810E-05 -2.101476E-02 -6.314023E-05 -1.153450E-02 -1.634642E-05 -7.257174E-03 -7.518882E-06 -1.927707E-02 -5.477085E-05 -9.781524E-03 -2.152387E-05 -9.945925E-03 -2.025565E-05 -1.389600E-02 -2.298270E-05 -1.494296E-02 -3.352071E-05 -1.367151E-02 -2.896436E-05 -1.028864E-02 -1.588654E-05 -1.473101E-02 -2.707095E-05 -1.455944E-02 -2.781560E-05 -9.476864E-03 -1.561347E-05 -1.102794E-02 -1.772767E-05 -9.572498E-03 -1.064449E-05 -1.064989E-02 -1.750406E-05 -6.954816E-03 -6.367916E-06 -7.557762E-03 -9.032801E-06 -1.211805E-02 -1.920718E-05 -1.845178E-02 -5.873218E-05 -7.793790E-03 -1.112683E-05 -5.371627E-03 -5.960823E-06 -1.235046E-02 -2.103259E-05 -9.750089E-03 -1.543672E-05 -8.995748E-03 -1.080595E-05 -5.259436E-03 -1.260414E-05 -4.013446E-03 -6.247425E-06 -8.493091E-03 -1.154191E-05 -8.658736E-03 -1.173196E-05 -5.707568E-03 -4.449143E-06 -6.897118E-03 -1.114446E-05 -1.178625E-02 -1.974305E-05 -9.315402E-03 -1.290580E-05 -8.406166E-03 -1.025434E-05 -9.901055E-03 -1.667960E-05 -1.146925E-02 -2.215717E-05 -5.969641E-03 -6.447141E-06 -5.949865E-03 -8.960001E-06 -6.092588E-03 -5.866966E-06 -5.286804E-03 -4.484612E-06 -4.962451E-03 -8.039594E-06 -9.068920E-03 -1.020218E-05 -8.393955E-03 -1.320876E-05 -9.622928E-03 -1.423650E-05 -8.529527E-03 -9.768501E-06 -1.200903E-02 -2.384159E-05 -1.259390E-02 -2.566463E-05 -1.039659E-02 -1.406860E-05 -1.729423E-02 -3.541882E-05 -1.557253E-02 -3.014897E-05 -1.194539E-02 -2.560525E-05 -9.677750E-03 -1.383701E-05 -1.167374E-02 -1.893076E-05 -1.273338E-02 -2.292756E-05 -1.535190E-02 -3.729267E-05 -1.508233E-02 -2.812628E-05 -1.684483E-02 -3.431291E-05 -2.196642E-02 -6.517979E-05 -1.835655E-02 -4.270904E-05 -1.427403E-02 -2.810685E-05 -1.296891E-02 -3.425248E-05 -1.678523E-02 -5.402550E-05 -1.824967E-02 -5.634714E-05 -1.959838E-02 -4.878209E-05 -1.406357E-02 -2.175952E-05 -1.401524E-02 -2.275436E-05 -1.788740E-02 -3.919852E-05 -1.598923E-02 -2.974737E-05 -1.525101E-02 -3.383079E-05 -2.077298E-02 -5.733559E-05 -1.623945E-02 -5.546589E-05 -1.233338E-02 -2.483742E-05 -2.022717E-02 -5.714772E-05 -2.102155E-02 -5.635658E-05 -2.171802E-02 -5.725283E-05 -2.133014E-02 -5.962681E-05 -1.179614E-02 -2.066294E-05 -1.970629E-02 -4.561315E-05 -2.645275E-02 -9.399736E-05 -2.354050E-02 -6.803919E-05 -1.525552E-02 -2.858970E-05 -2.070256E-02 -5.101418E-05 -1.947053E-02 -4.695688E-05 -2.302697E-02 -7.365548E-05 -1.913354E-02 -4.496174E-05 -2.105937E-02 -5.760147E-05 -1.965231E-02 -4.417453E-05 -1.995841E-02 -5.444455E-05 -1.084572E-02 -1.610270E-05 -1.332954E-02 -2.257737E-05 -2.183162E-02 -5.722081E-05 -2.309396E-02 -6.057606E-05 -9.499018E-03 -1.386623E-05 -1.726231E-02 -3.538973E-05 -1.918548E-02 -5.089001E-05 -1.973649E-02 -5.391374E-05 -1.451999E-02 -3.154997E-05 -1.853969E-02 -4.789122E-05 -1.931149E-02 -4.543759E-05 -1.524463E-02 -3.367646E-05 -1.366351E-02 -2.193771E-05 -1.277601E-02 -2.556554E-05 -2.419813E-02 -6.652057E-05 -2.472332E-02 -7.514840E-05 -1.216343E-02 -1.994778E-05 -1.684175E-02 -4.956582E-05 -1.339179E-02 -2.283730E-05 -1.780869E-02 -4.714950E-05 -1.281070E-02 -3.243018E-05 -1.377308E-02 -3.117101E-05 -5.215885E-03 -4.980057E-06 -8.389167E-03 -9.063809E-06 -9.223056E-03 -1.174158E-05 -1.034179E-02 -1.248975E-05 -1.925913E-02 -6.207101E-05 -1.950035E-02 -4.864558E-05 -7.340878E-03 -8.419462E-06 -1.607559E-02 -3.378180E-05 -1.350363E-02 -2.299601E-05 -1.775362E-02 -4.047509E-05 -9.317817E-03 -1.104227E-05 -1.531705E-02 -4.269706E-05 -1.565342E-02 -3.305222E-05 -1.391485E-02 -2.938257E-05 -1.313236E-02 -2.426377E-05 -1.070285E-02 -1.778239E-05 -1.570769E-02 -2.778648E-05 -1.722250E-02 -3.454670E-05 -1.045335E-02 -1.595923E-05 -9.750797E-03 -1.489157E-05 -8.756572E-03 -1.522794E-05 -1.314662E-02 -2.457130E-05 -1.370416E-02 -3.418084E-05 -1.098248E-02 -2.064375E-05 -9.200090E-03 -1.182484E-05 -1.567874E-02 -3.315221E-05 -6.763240E-03 -8.877038E-06 -8.410342E-03 -8.599497E-06 -1.335894E-02 -2.549323E-05 -1.565848E-02 -3.152726E-05 -4.913273E-03 -5.986876E-06 -9.624242E-03 -1.314215E-05 -7.547191E-03 -9.843029E-06 -9.081341E-03 -1.527721E-05 -5.698591E-03 -6.688189E-06 -9.964477E-03 -1.260472E-05 -9.144787E-03 -1.380216E-05 -2.922066E-03 -3.175247E-06 -6.106620E-03 -6.365824E-06 -4.141014E-03 -5.277155E-06 -1.500883E-02 -2.794044E-05 -1.313811E-02 -2.817445E-05 -5.537395E-03 -6.121500E-06 -6.214355E-03 -7.107250E-06 -9.970886E-03 -1.328943E-05 -1.158117E-02 -2.364707E-05 -8.759169E-03 -1.211573E-05 -1.307338E-02 -2.576745E-05 -6.194517E-03 -9.257741E-06 -8.087970E-03 -1.366458E-05 -8.727779E-03 -1.125895E-05 -7.481614E-03 -9.784879E-06 -7.811272E-03 -1.168412E-05 -7.288542E-03 -8.415727E-06 -1.395237E-02 -3.211289E-05 -1.345304E-02 -2.404425E-05 -1.075854E-02 -1.527000E-05 -9.524531E-03 -1.516407E-05 -1.703097E-02 -3.823359E-05 -1.787871E-02 -5.611642E-05 -1.180236E-02 -1.719343E-05 -1.146997E-02 -2.095613E-05 -1.152446E-02 -1.653464E-05 -1.398187E-02 -2.396242E-05 -1.526339E-02 -3.893414E-05 -1.206190E-02 -2.128747E-05 -1.578188E-02 -3.704679E-05 -1.775426E-02 -3.663474E-05 -1.962916E-02 -5.493244E-05 -1.511991E-02 -3.404611E-05 -1.133202E-02 -2.452193E-05 -1.623663E-02 -3.459453E-05 -1.586922E-02 -3.841963E-05 -1.786175E-02 -4.289114E-05 -1.326353E-02 -2.595816E-05 -1.445145E-02 -2.990583E-05 -1.509105E-02 -2.887493E-05 -1.761108E-02 -3.799916E-05 -1.671644E-02 -3.638132E-05 -1.692226E-02 -3.667379E-05 -1.123264E-02 -2.662808E-05 -1.119900E-02 -1.598286E-05 -1.930512E-02 -4.893797E-05 -2.291023E-02 -7.500981E-05 -1.093046E-02 -2.227226E-05 -2.121672E-02 -7.861749E-05 -9.618950E-03 -1.801199E-05 -1.213716E-02 -2.201469E-05 -1.856853E-02 -4.365656E-05 -1.665627E-02 -3.787320E-05 -1.301603E-02 -3.128189E-05 -1.971201E-02 -6.183556E-05 -2.240750E-02 -7.011853E-05 -2.216291E-02 -6.809313E-05 -1.153008E-02 -2.676316E-05 -1.676451E-02 -4.351892E-05 -2.591571E-02 -8.037903E-05 -2.037389E-02 -4.959375E-05 -1.495140E-02 -2.829832E-05 -1.051363E-02 -2.065167E-05 -1.979307E-02 -5.604015E-05 -2.624329E-02 -8.019430E-05 -1.335982E-02 -2.844614E-05 -1.612983E-02 -6.010017E-05 -1.728825E-02 -4.711910E-05 -2.429057E-02 -7.415431E-05 -1.616100E-02 -3.084388E-05 -1.338558E-02 -3.228322E-05 -1.340928E-02 -3.387569E-05 -1.708924E-02 -4.087477E-05 -1.336049E-02 -2.477778E-05 -1.587999E-02 -3.626669E-05 -1.935273E-02 -4.723278E-05 -2.470520E-02 -7.859676E-05 -1.475079E-02 -3.640394E-05 -1.679996E-02 -3.695619E-05 -1.042709E-02 -1.967458E-05 -1.968690E-02 -5.949834E-05 -1.327946E-02 -2.828789E-05 -2.199912E-02 -6.466489E-05 -1.849493E-02 -3.808605E-05 -1.601814E-02 -3.868414E-05 -8.360208E-03 -8.722194E-06 -1.048244E-02 -1.553938E-05 -1.355191E-02 -3.191766E-05 -2.019710E-02 -5.689596E-05 -1.515848E-02 -3.149152E-05 -2.234350E-02 -6.679195E-05 -2.213825E-02 -7.381934E-05 -1.917888E-02 -4.731955E-05 -1.084756E-02 -1.986509E-05 -1.609220E-02 -3.078859E-05 -1.473280E-02 -3.933279E-05 -1.529880E-02 -3.127194E-05 -1.639564E-02 -4.529775E-05 -1.443123E-02 -3.075459E-05 -1.882187E-02 -5.273612E-05 -1.460498E-02 -3.301670E-05 -1.236974E-02 -2.302425E-05 -1.547979E-02 -5.040930E-05 -8.943072E-03 -1.146125E-05 -1.038577E-02 -2.359524E-05 -9.957494E-03 -1.246302E-05 -8.165810E-03 -1.286712E-05 -9.730475E-03 -1.696051E-05 -1.144342E-02 -1.696256E-05 -1.018757E-02 -1.502940E-05 -6.455273E-03 -6.892868E-06 -1.173241E-02 -1.925350E-05 -1.116334E-02 -1.482619E-05 -5.399877E-03 -4.405606E-06 -3.959202E-03 -4.471062E-06 -9.736729E-03 -1.616042E-05 -4.414460E-03 -5.308331E-06 -5.659090E-03 -4.225962E-06 -4.260578E-03 -3.519428E-06 -1.063057E-02 -2.671737E-05 -9.252412E-03 -1.335948E-05 -7.509662E-03 -1.033233E-05 -5.631650E-03 -4.603917E-06 -7.374915E-03 -9.613999E-06 -1.017301E-02 -1.890382E-05 -4.657208E-03 -4.110749E-06 -8.263045E-03 -9.144029E-06 -5.083557E-03 -3.617645E-06 -5.753770E-03 -6.399330E-06 -3.157208E-03 -2.023717E-06 -2.929392E-03 -1.415512E-06 -3.306531E-03 -3.326325E-06 -7.308585E-03 -7.051788E-06 -2.131441E-03 -3.159885E-06 -6.056253E-03 -6.146480E-06 -3.197345E-03 -1.906328E-06 -7.156591E-03 -8.158604E-06 -1.008394E-02 -1.612226E-05 -1.360120E-02 -3.007127E-05 -1.087460E-02 -1.978085E-05 -8.751267E-03 -1.202395E-05 -1.327913E-02 -2.254308E-05 -1.549315E-02 -3.493369E-05 -1.276663E-02 -2.254426E-05 -1.422943E-02 -3.266120E-05 -7.543284E-03 -8.425611E-06 -1.148895E-02 -2.316672E-05 -1.075957E-02 -1.733122E-05 -1.228568E-02 -2.274310E-05 -1.298949E-02 -3.103013E-05 -1.687551E-02 -3.373288E-05 -1.174671E-02 -1.478816E-05 -1.298113E-02 -2.280689E-05 -1.375075E-02 -3.564635E-05 -1.865407E-02 -4.650386E-05 -1.316565E-02 -3.034949E-05 -1.644195E-02 -3.039939E-05 -1.167304E-02 -1.910205E-05 -1.119646E-02 -2.041134E-05 -2.051982E-02 -5.295597E-05 -1.446398E-02 -2.483661E-05 -1.663221E-02 -4.310298E-05 -1.774865E-02 -3.613160E-05 -1.551828E-02 -3.922463E-05 -1.987068E-02 -5.088653E-05 -1.111420E-02 -2.006407E-05 -1.756540E-02 -4.468660E-05 -1.151848E-02 -1.953188E-05 -1.430522E-02 -3.322674E-05 -8.678157E-03 -1.516243E-05 -1.189921E-02 -1.954174E-05 -1.667314E-02 -5.548567E-05 -2.197194E-02 -6.943126E-05 -2.047457E-02 -4.730016E-05 -2.145796E-02 -5.503501E-05 -1.433861E-02 -3.407856E-05 -1.789249E-02 -4.132722E-05 -1.497597E-02 -3.790603E-05 -1.784518E-02 -5.989398E-05 -1.348223E-02 -2.451114E-05 -1.850761E-02 -4.354345E-05 -9.460668E-03 -1.235477E-05 -1.608153E-02 -3.627464E-05 -2.158938E-02 -7.192126E-05 -2.591114E-02 -7.881538E-05 -1.615323E-02 -3.735540E-05 -1.456875E-02 -2.959443E-05 -1.713879E-02 -3.971707E-05 -2.011125E-02 -5.426015E-05 -1.600843E-02 -3.860238E-05 -2.349989E-02 -6.721393E-05 -9.675390E-03 -1.720621E-05 -1.321534E-02 -2.201319E-05 -1.388877E-02 -3.752647E-05 -9.338560E-03 -1.222660E-05 -1.872993E-02 -4.179060E-05 -1.729197E-02 -4.763909E-05 -1.433923E-02 -3.648874E-05 -1.982945E-02 -5.208569E-05 -9.529878E-03 -1.355652E-05 -1.902053E-02 -4.097824E-05 -9.167842E-03 -1.041942E-05 -1.571952E-02 -4.188405E-05 -9.716564E-03 -2.414735E-05 -1.423573E-02 -3.524484E-05 -1.148788E-02 -2.604718E-05 -1.545038E-02 -3.289072E-05 -1.724229E-02 -4.091912E-05 -2.114484E-02 -5.448881E-05 -1.201008E-02 -1.761314E-05 -1.049205E-02 -1.851795E-05 -1.007470E-02 -1.508850E-05 -1.216162E-02 -1.779226E-05 -9.172443E-03 -1.542767E-05 -1.158129E-02 -2.700118E-05 -8.634939E-03 -1.235312E-05 -9.968731E-03 -1.636632E-05 -8.806160E-03 -1.312756E-05 -7.282738E-03 -7.675380E-06 -1.501313E-02 -3.403794E-05 -1.772683E-02 -3.946856E-05 -6.797082E-03 -6.826066E-06 -6.203754E-03 -6.576663E-06 -1.255269E-02 -2.273841E-05 -9.325891E-03 -1.968887E-05 -5.665941E-03 -7.672343E-06 -9.482040E-03 -1.321433E-05 -5.895438E-03 -7.290209E-06 -4.028986E-03 -3.562047E-06 -9.179212E-03 -1.479180E-05 -5.065510E-03 -7.876080E-06 -9.623638E-03 -1.331451E-05 -8.243023E-03 -1.155595E-05 -6.785547E-03 -8.869686E-06 -6.830346E-03 -6.869962E-06 -5.952624E-03 -7.591589E-06 -1.262730E-02 -2.795731E-05 -7.222793E-03 -7.969191E-06 -7.364474E-03 -9.912407E-06 -4.073203E-03 -3.221529E-06 -6.307497E-03 -8.387738E-06 -6.770719E-03 -9.965921E-06 -7.935928E-03 -9.247514E-06 -8.991810E-03 -1.001059E-05 -5.746536E-03 -5.204627E-06 -4.632325E-03 -3.055561E-06 -7.410656E-03 -9.676112E-06 -7.030579E-03 -9.078592E-06 -9.940893E-03 -2.033444E-05 -4.593423E-03 -3.918985E-06 -3.958315E-03 -2.344423E-06 -4.956734E-03 -6.309001E-06 -7.499601E-03 -8.403664E-06 -4.748645E-03 -4.199540E-06 -5.390021E-03 -5.915551E-06 -8.712210E-03 -1.738886E-05 -8.103852E-03 -9.180564E-06 -1.025459E-02 -1.310828E-05 -1.184291E-02 -1.833442E-05 -5.755536E-03 -5.404194E-06 -8.221201E-03 -9.335727E-06 -9.828395E-03 -1.545245E-05 -1.152575E-02 -1.759013E-05 -5.829495E-03 -7.232703E-06 -1.218356E-02 -2.664254E-05 -6.170466E-03 -7.308485E-06 -7.313197E-03 -7.829261E-06 -1.367693E-02 -3.155396E-05 -1.355349E-02 -2.093247E-05 -1.169703E-02 -1.533618E-05 -1.225998E-02 -3.530234E-05 -1.125463E-02 -1.795265E-05 -9.696736E-03 -1.412411E-05 -1.093214E-02 -1.673039E-05 -1.278387E-02 -2.130505E-05 -8.880561E-03 -1.364130E-05 -1.181523E-02 -1.870304E-05 -9.189492E-03 -1.453491E-05 -9.455271E-03 -1.423365E-05 -1.776658E-02 -4.257355E-05 -1.296514E-02 -2.121667E-05 -1.003865E-02 -1.487795E-05 -1.359312E-02 -2.765495E-05 -1.162264E-02 -2.140342E-05 -1.033131E-02 -1.304998E-05 -1.542205E-02 -3.650649E-05 -1.535565E-02 -3.683101E-05 -9.763595E-03 -1.309061E-05 -1.726548E-02 -4.632789E-05 -1.043992E-02 -1.651951E-05 -6.110039E-03 -6.694762E-06 -1.985635E-02 -6.510789E-05 -8.438493E-03 -9.248252E-06 -1.851818E-02 -4.904640E-05 -1.995254E-02 -5.020531E-05 -1.335907E-02 -2.466345E-05 -1.649899E-02 -3.318908E-05 -1.452837E-02 -3.635670E-05 -1.935287E-02 -5.575704E-05 -1.319131E-02 -2.791021E-05 -1.492064E-02 -3.073511E-05 -1.131605E-02 -2.493004E-05 -1.462680E-02 -2.849063E-05 -1.962759E-02 -5.083607E-05 -1.701425E-02 -4.167266E-05 -7.965972E-03 -1.229258E-05 -1.458100E-02 -2.718206E-05 -1.026138E-02 -2.113714E-05 -1.308429E-02 -2.003268E-05 -9.038340E-03 -9.340773E-06 -1.586616E-02 -3.218048E-05 -6.515114E-03 -9.139171E-06 -1.003265E-02 -1.250538E-05 -7.477346E-03 -9.170786E-06 -8.376990E-03 -1.161182E-05 -1.829624E-02 -3.702430E-05 -1.569831E-02 -2.881524E-05 -1.105450E-02 -2.103495E-05 -1.042629E-02 -1.723138E-05 -9.998085E-03 -1.227071E-05 -1.516738E-02 -3.324549E-05 -1.090125E-02 -1.985519E-05 -1.432278E-02 -3.386798E-05 -8.418229E-03 -1.050672E-05 -1.108353E-02 -1.739127E-05 -7.787352E-03 -1.084467E-05 -6.757477E-03 -8.314301E-06 -1.266965E-02 -2.014700E-05 -1.223368E-02 -1.816810E-05 -1.000405E-02 -2.132755E-05 -1.260170E-02 -2.392494E-05 -9.344763E-03 -1.208588E-05 -1.243003E-02 -2.215004E-05 -8.842577E-03 -1.468191E-05 -1.171609E-02 -2.634512E-05 -7.361574E-03 -1.005220E-05 -4.937175E-03 -3.421412E-06 -8.801345E-03 -1.258402E-05 -8.660082E-03 -1.317890E-05 -1.066110E-02 -2.285362E-05 -8.182265E-03 -1.352232E-05 -1.194368E-02 -2.542532E-05 -5.247990E-03 -7.113477E-06 -1.329855E-02 -2.805232E-05 -1.667204E-02 -4.715717E-05 -5.516192E-03 -4.861602E-06 -8.032885E-03 -9.526962E-06 -8.923177E-03 -1.221885E-05 -7.273785E-03 -7.646285E-06 -9.997748E-03 -1.389196E-05 -1.049460E-02 -1.325998E-05 -1.231591E-02 -1.779583E-05 -1.187687E-02 -1.777669E-05 -4.027367E-03 -5.095043E-06 -5.883273E-03 -1.010000E-05 -5.881059E-03 -5.701541E-06 -6.065490E-03 -8.604636E-06 -1.853273E-03 -1.189336E-06 -4.775189E-03 -6.494172E-06 -4.633358E-03 -4.183400E-06 -4.180683E-03 -5.129026E-06 -4.541541E-03 -5.646520E-06 -7.074233E-04 -2.834238E-07 -2.724695E-03 -2.217855E-06 -1.700068E-03 -8.357081E-07 -3.833078E-03 -2.656428E-06 -6.572586E-03 -8.866295E-06 -5.292952E-03 -3.867444E-06 -3.517788E-03 -2.530088E-06 -2.740599E-03 -2.004521E-06 -5.438345E-03 -8.165786E-06 -3.641025E-03 -3.113878E-06 -4.966383E-03 -7.623277E-06 -3.292270E-03 -2.722033E-06 -4.468651E-03 -5.017784E-06 -2.625164E-03 -1.543702E-06 -3.246447E-03 -2.141940E-06 -6.765655E-03 -9.017921E-06 -6.472797E-03 -5.971218E-06 -5.166553E-03 -3.916196E-06 -4.715011E-03 -4.421483E-06 -8.868545E-03 -1.033407E-05 -9.454655E-03 -1.287272E-05 -7.378309E-03 -9.793455E-06 -8.294983E-03 -1.242029E-05 -9.030433E-03 -1.660734E-05 -5.691832E-03 -4.629989E-06 -6.844709E-03 -1.039079E-05 -6.076908E-03 -6.364980E-06 -1.018307E-02 -1.478904E-05 -8.398207E-03 -1.353213E-05 -1.038657E-02 -1.650576E-05 -1.318384E-02 -2.408888E-05 -8.015055E-03 -1.126916E-05 -1.030145E-02 -1.582573E-05 -6.890267E-03 -8.319222E-06 -7.150937E-03 -7.850470E-06 -4.889144E-03 -3.720968E-06 -8.323465E-03 -1.115383E-05 -9.054557E-03 -1.439423E-05 -1.406749E-02 -2.792472E-05 -1.188336E-02 -2.280525E-05 -1.029778E-02 -1.535135E-05 -6.586615E-03 -8.689373E-06 -6.989279E-03 -6.602524E-06 -8.696264E-03 -1.699910E-05 -1.215054E-02 -1.809626E-05 -9.660496E-03 -1.576109E-05 -6.998390E-03 -6.984012E-06 -4.566410E-03 -4.700686E-06 -7.914312E-03 -8.046281E-06 -1.119024E-02 -1.682956E-05 -8.557711E-03 -1.169180E-05 -1.116108E-02 -2.002096E-05 -1.596243E-02 -3.319159E-05 -1.417800E-02 -2.698476E-05 -1.370714E-02 -3.345511E-05 -6.571905E-03 -1.170061E-05 -9.528663E-03 -1.906413E-05 -1.285473E-02 -1.987588E-05 -1.051645E-02 -2.095546E-05 -6.496841E-03 -6.085712E-06 -1.535496E-02 -3.318420E-05 -1.422914E-02 -2.578886E-05 -1.481483E-02 -2.681040E-05 -3.973095E-03 -3.122718E-06 -1.132021E-02 -1.735904E-05 -3.004322E-03 -4.387582E-06 -7.360833E-03 -1.310893E-05 -1.047617E-02 -1.750773E-05 -1.122781E-02 -2.131611E-05 -5.694910E-03 -7.234627E-06 -7.668968E-03 -8.067750E-06 -4.449311E-03 -4.768775E-06 -3.787286E-03 -2.624668E-06 -1.002060E-02 -1.749285E-05 -1.395365E-02 -2.967710E-05 -8.499007E-03 -1.449296E-05 -9.187712E-03 -1.502460E-05 -9.842313E-03 -1.218596E-05 -1.196667E-02 -1.597317E-05 -9.851299E-03 -1.503088E-05 -7.735045E-03 -9.286037E-06 -1.079491E-02 -1.766380E-05 -1.091930E-02 -1.648255E-05 -1.108268E-02 -1.578770E-05 -8.120340E-03 -1.291411E-05 -1.246096E-02 -2.528446E-05 -1.202701E-02 -1.816947E-05 -8.319659E-03 -1.340429E-05 -6.275166E-03 -6.982397E-06 -9.030250E-03 -1.174300E-05 -8.187094E-03 -1.235622E-05 -5.549210E-03 -5.420156E-06 -6.789734E-03 -7.904257E-06 -4.425697E-03 -3.919582E-06 -6.512926E-03 -7.118649E-06 -6.535547E-03 -1.403886E-05 -7.543231E-03 -1.205568E-05 -7.377749E-03 -1.142071E-05 -6.797258E-03 -7.523771E-06 -7.181352E-03 -8.290755E-06 -7.045510E-03 -1.013770E-05 -8.236912E-03 -1.265044E-05 -7.857392E-03 -1.143180E-05 -2.604005E-03 -2.317099E-06 -6.968220E-03 -1.347326E-05 -6.200344E-03 -7.619475E-06 -6.667622E-03 -1.088132E-05 -2.645846E-03 -1.854304E-06 -5.207931E-03 -4.574122E-06 -5.239891E-03 -5.012226E-06 -9.605662E-03 -1.784435E-05 -4.891233E-03 -6.117222E-06 -6.504651E-03 -1.229520E-05 -4.837232E-03 -6.126627E-06 -5.744494E-03 -9.825890E-06 -4.153989E-03 -5.541638E-06 -2.163062E-03 -2.727406E-06 -7.562241E-03 -1.683819E-05 -4.906111E-03 -7.696070E-06 -4.582205E-03 -7.559853E-06 -4.360889E-03 -6.753941E-06 -2.573412E-03 -2.074263E-06 -7.341817E-03 -1.510923E-05 -1.348516E-04 -1.818494E-08 -2.140265E-03 -2.186708E-06 -5.132621E-03 -6.802003E-06 -3.951538E-03 -5.966124E-06 -3.677707E-03 -4.225767E-06 -1.976184E-03 -9.056492E-07 -4.382040E-04 -1.920227E-07 -1.818577E-03 -1.643089E-06 -1.584983E-03 -1.096049E-06 -3.083453E-03 -3.167381E-06 -2.957748E-03 -3.417374E-06 -4.181554E-03 -3.122268E-06 -8.205844E-03 -1.339216E-05 -8.373927E-03 -1.673225E-05 -4.491527E-03 -6.082578E-06 -6.731608E-03 -1.117129E-05 -4.850830E-03 -4.259080E-06 -7.231407E-03 -8.438356E-06 -5.959383E-03 -1.199394E-05 -8.812537E-03 -1.137742E-05 -5.064971E-03 -5.265762E-06 -6.088263E-03 -5.366214E-06 -1.231967E-02 -2.529922E-05 -6.664708E-03 -6.756574E-06 -7.146824E-03 -6.992158E-06 -7.597362E-03 -8.315013E-06 -8.302133E-03 -1.025085E-05 -7.908279E-03 -8.283137E-06 -4.910695E-03 -4.757721E-06 -7.465751E-03 -1.337654E-05 -6.657558E-03 -7.888053E-06 -5.401779E-03 -5.483988E-06 -3.267001E-03 -2.915272E-06 -6.045569E-03 -6.294647E-06 -1.070370E-02 -1.951887E-05 -7.552609E-03 -7.432950E-06 -8.877234E-03 -1.068410E-05 -1.075436E-02 -1.493748E-05 -5.659998E-03 -5.370515E-06 -8.655450E-03 -1.139402E-05 -6.300286E-03 -8.630445E-06 -8.360752E-03 -1.357159E-05 -5.594374E-03 -5.201663E-06 -5.933381E-03 -5.223719E-06 -5.436755E-03 -5.337268E-06 -5.498344E-03 -4.605588E-06 -1.006944E-02 -1.688863E-05 -6.917860E-03 -8.432437E-06 -1.165526E-02 -1.802342E-05 -1.077532E-02 -2.444899E-05 -4.239569E-03 -2.886382E-06 -6.796744E-03 -5.792939E-06 -6.662910E-03 -5.729331E-06 -7.255977E-03 -1.065759E-05 -2.894086E-03 -1.903304E-06 -6.311066E-03 -4.912946E-06 -1.099018E-02 -2.054283E-05 -7.241143E-03 -7.442478E-06 -4.567091E-03 -3.071464E-06 -6.773593E-03 -5.905000E-06 -8.327525E-03 -9.451448E-06 -1.069359E-02 -1.514720E-05 -3.670959E-03 -3.304885E-06 -9.124065E-03 -1.471763E-05 -3.861446E-03 -3.151454E-06 -6.221877E-03 -1.027786E-05 -5.254419E-03 -6.135711E-06 -7.702917E-03 -1.051860E-05 -5.115541E-03 -6.357416E-06 -5.321924E-03 -4.501815E-06 -7.639895E-03 -1.792277E-05 -5.676732E-03 -4.933198E-06 -7.917058E-03 -1.103359E-05 -6.987672E-03 -8.124731E-06 -7.605775E-03 -1.154995E-05 -1.077244E-02 -2.439257E-05 -5.513601E-03 -7.937817E-06 -8.315505E-03 -9.181773E-06 -5.719492E-03 -6.912423E-06 -4.809607E-03 -6.393160E-06 -5.490138E-03 -6.557157E-06 -2.585724E-03 -1.337147E-06 -3.578006E-03 -2.074822E-06 -6.644166E-03 -9.849481E-06 -5.073345E-03 -6.101950E-06 -8.583604E-03 -1.928242E-05 -6.278182E-03 -8.352587E-06 -7.476949E-03 -1.201282E-05 -4.477112E-03 -4.894391E-06 -9.059255E-03 -1.429652E-05 -3.030949E-03 -1.590060E-06 -5.686827E-03 -5.262592E-06 -4.734421E-03 -6.896077E-06 -2.912353E-03 -1.875480E-06 -6.517175E-03 -6.330268E-06 -9.203829E-03 -1.181214E-05 -5.012765E-03 -5.129300E-06 -7.823830E-03 -1.330136E-05 -5.110174E-03 -4.376566E-06 -7.379964E-03 -8.333357E-06 -5.468869E-03 -6.083600E-06 -7.519458E-03 -1.048700E-05 -4.611391E-03 -3.814525E-06 -7.062996E-03 -1.181993E-05 -3.837864E-03 -3.789477E-06 -6.759816E-03 -8.026354E-06 -5.672758E-03 -4.924437E-06 -8.864970E-03 -1.097704E-05 -5.305515E-03 -6.789690E-06 -4.264513E-03 -5.260234E-06 -5.512145E-03 -8.119123E-06 -5.053780E-03 -5.404719E-06 -7.029594E-03 -9.741504E-06 -2.374002E-03 -1.449069E-06 -2.256464E-03 -1.391425E-06 -4.548643E-03 -7.978885E-06 -2.810872E-03 -2.456200E-06 -4.084882E-03 -6.257623E-06 -6.517591E-03 -9.674764E-06 -6.200630E-03 -9.438817E-06 -2.745907E-03 -1.809511E-06 -3.972065E-03 -3.245352E-06 -5.942817E-03 -7.352165E-06 -3.263414E-03 -3.353913E-06 -8.153438E-03 -1.079966E-05 -7.165596E-03 -1.017019E-05 -4.251216E-03 -2.817736E-06 -8.011851E-03 -1.068301E-05 -9.752890E-04 -7.589177E-07 -3.469946E-03 -2.493177E-06 -6.811986E-03 -8.722919E-06 -5.394586E-03 -6.424939E-06 -5.872081E-03 -8.499852E-06 -8.818832E-03 -1.189657E-05 -7.866284E-03 -8.632785E-06 -8.116334E-03 -1.347044E-05 -2.423674E-03 -2.219673E-06 -7.457717E-03 -9.186735E-06 -6.773921E-03 -1.764821E-05 -6.930098E-03 -1.011624E-05 -8.618704E-03 -1.022187E-05 -1.184609E-02 -2.438262E-05 -8.878289E-03 -1.326793E-05 -5.073855E-03 -4.038299E-06 -9.760737E-03 -1.548967E-05 -7.965991E-03 -1.151518E-05 -5.975862E-03 -1.006202E-05 -7.122347E-03 -8.079230E-06 -7.180618E-03 -7.951754E-06 -5.027224E-03 -6.787710E-06 -1.109603E-02 -1.848734E-05 -1.295024E-02 -3.036716E-05 -8.023705E-03 -8.286741E-06 -1.144577E-02 -2.665312E-05 -1.019084E-02 -1.881473E-05 -1.361484E-02 -2.576942E-05 -9.013737E-03 -1.466391E-05 -1.147532E-02 -2.462687E-05 -1.225257E-02 -2.181790E-05 -8.159645E-03 -1.259135E-05 -4.127139E-03 -2.557351E-06 -5.325669E-03 -6.365360E-06 -1.347774E-02 -2.661460E-05 -7.265261E-03 -1.252096E-05 -1.373140E-02 -2.385999E-05 -1.262611E-02 -2.245356E-05 -9.465554E-03 -2.262286E-05 -8.452943E-03 -1.155915E-05 -4.998547E-03 -7.068774E-06 -7.648621E-03 -9.105026E-06 -9.203837E-03 -1.311626E-05 -1.107019E-02 -1.950577E-05 -1.315936E-02 -2.410764E-05 -7.844275E-03 -9.659512E-06 -9.825100E-03 -1.724414E-05 -1.047811E-02 -1.262306E-05 -1.207238E-02 -2.752816E-05 -1.085843E-02 -1.470096E-05 -1.594894E-02 -4.046810E-05 -1.497569E-02 -2.863883E-05 -1.030144E-02 -2.348225E-05 -6.125370E-03 -7.226790E-06 -1.405421E-02 -4.764046E-05 -1.625035E-02 -3.353624E-05 -9.577818E-03 -1.794568E-05 -1.448263E-02 -2.770743E-05 -1.029916E-02 -1.861537E-05 -9.183850E-03 -1.591847E-05 -9.237708E-03 -1.576843E-05 -1.079813E-02 -1.581077E-05 -1.260676E-02 -3.554547E-05 -2.054039E-02 -5.879657E-05 -7.345172E-03 -8.644617E-06 -9.151035E-03 -1.651766E-05 -1.271524E-02 -2.302768E-05 -1.487615E-02 -3.960752E-05 -7.259983E-03 -1.107807E-05 -5.855371E-03 -4.857225E-06 -7.570428E-03 -9.406879E-06 -5.643592E-03 -7.265176E-06 -1.113252E-02 -1.652636E-05 -1.101056E-02 -1.732233E-05 -7.781992E-03 -7.475792E-06 -1.014997E-02 -1.698223E-05 -7.547933E-03 -1.219150E-05 -4.922153E-03 -4.916764E-06 -6.063790E-03 -7.031316E-06 -8.119766E-03 -1.484039E-05 -5.084706E-03 -4.983059E-06 -5.431730E-03 -5.048229E-06 -8.720640E-03 -1.061184E-05 -8.480299E-03 -1.325453E-05 -1.209019E-02 -2.053697E-05 -1.028370E-02 -2.394843E-05 -8.037695E-03 -1.000534E-05 -9.075446E-03 -1.720138E-05 -5.348851E-03 -5.241839E-06 -6.061215E-03 -7.799859E-06 -9.501216E-03 -1.498369E-05 -1.649742E-02 -3.974159E-05 -8.337027E-03 -1.677761E-05 -1.156020E-02 -1.673947E-05 -1.046774E-02 -2.653737E-05 -7.675581E-03 -8.456541E-06 -9.617224E-03 -1.794211E-05 -1.268842E-02 -2.897864E-05 -9.844835E-03 -1.818849E-05 -9.330947E-03 -1.549578E-05 -5.838065E-03 -7.948493E-06 -8.798788E-03 -1.342636E-05 -9.306629E-03 -1.318598E-05 -4.920602E-03 -4.823960E-06 -1.710686E-03 -7.729255E-07 -2.859179E-03 -1.745176E-06 -4.456373E-03 -4.366517E-06 -2.395798E-03 -1.736746E-06 -7.027745E-03 -1.682294E-05 -4.030298E-03 -4.530935E-06 -2.803361E-03 -2.792072E-06 -6.688412E-03 -1.091671E-05 -7.703157E-03 -8.772855E-06 -4.949493E-03 -3.982137E-06 -7.365244E-03 -1.073387E-05 -9.386372E-03 -1.134513E-05 -9.003757E-03 -1.332391E-05 -7.974051E-03 -1.354602E-05 -1.137434E-02 -1.857838E-05 -1.143520E-02 -2.117358E-05 -3.030499E-03 -2.165815E-06 -4.867784E-03 -3.911154E-06 -5.246175E-03 -6.161091E-06 -5.832426E-03 -5.525543E-06 -7.382520E-03 -9.067048E-06 -1.188676E-02 -1.778783E-05 -1.199313E-02 -2.082141E-05 -1.266957E-02 -1.962424E-05 -1.533876E-02 -3.337162E-05 -7.389726E-03 -1.341338E-05 -7.529503E-03 -1.564696E-05 -1.491955E-02 -2.945644E-05 -1.074068E-02 -1.373117E-05 -1.472706E-02 -3.572507E-05 -1.199986E-02 -3.422317E-05 -8.514133E-03 -1.135618E-05 -1.634996E-02 -4.087320E-05 -1.955740E-02 -5.492009E-05 -1.126909E-02 -1.541148E-05 -1.586435E-02 -3.446303E-05 -1.700178E-02 -4.898376E-05 -1.703540E-02 -3.720395E-05 -1.967755E-02 -4.525544E-05 -1.330271E-02 -2.702604E-05 -1.888903E-02 -4.979443E-05 -2.004837E-02 -5.083025E-05 -1.435878E-02 -3.285995E-05 -1.930301E-02 -5.509308E-05 -1.628120E-02 -3.580789E-05 -1.727344E-02 -4.342335E-05 -1.216615E-02 -1.983233E-05 -1.700189E-02 -4.670523E-05 -1.269439E-02 -2.172602E-05 -2.010215E-02 -5.553642E-05 -2.319103E-02 -6.565091E-05 -1.414047E-02 -3.346494E-05 -2.027618E-02 -5.626720E-05 -1.646954E-02 -3.312557E-05 -2.251086E-02 -5.995831E-05 -1.610985E-02 -3.156849E-05 -1.377020E-02 -2.853634E-05 -1.669701E-02 -3.307612E-05 -1.159986E-02 -1.816147E-05 -1.261975E-02 -1.769023E-05 -2.134097E-02 -5.752884E-05 -1.841902E-02 -4.295167E-05 -2.422207E-02 -7.083744E-05 -1.543392E-02 -4.221173E-05 -2.157215E-02 -6.548409E-05 -2.644384E-02 -8.410907E-05 -2.311629E-02 -6.681868E-05 -2.395484E-02 -6.437514E-05 -1.922089E-02 -4.174544E-05 -1.663494E-02 -3.328109E-05 -9.964643E-03 -1.255907E-05 -1.150794E-02 -1.961340E-05 -1.939308E-02 -4.712734E-05 -1.787616E-02 -4.675712E-05 -2.319516E-02 -6.969066E-05 -1.741640E-02 -5.935363E-05 -1.789596E-02 -4.474293E-05 -2.512717E-02 -7.989830E-05 -1.220933E-02 -1.607761E-05 -1.359674E-02 -2.403775E-05 -1.590621E-02 -4.874402E-05 -1.664365E-02 -3.902009E-05 -1.028716E-02 -1.812738E-05 -1.543365E-02 -3.451753E-05 -1.719718E-02 -5.881162E-05 -1.666983E-02 -4.833689E-05 -1.586040E-02 -3.290082E-05 -1.592280E-02 -2.852261E-05 -2.560930E-02 -8.694469E-05 -2.095050E-02 -5.412080E-05 -1.939382E-02 -4.569593E-05 -1.830391E-02 -4.667520E-05 -1.549161E-02 -4.356136E-05 -1.284248E-02 -2.163546E-05 -1.082843E-02 -1.936706E-05 -1.108300E-02 -2.032165E-05 -1.963227E-02 -5.789246E-05 -1.883825E-02 -5.273957E-05 -1.630332E-02 -3.434978E-05 -1.574688E-02 -3.564693E-05 -1.794394E-02 -3.918955E-05 -2.060232E-02 -5.819679E-05 -1.732204E-02 -4.346625E-05 -1.922985E-02 -4.636825E-05 -1.116057E-02 -1.992936E-05 -1.216817E-02 -1.947069E-05 -8.811885E-03 -1.441275E-05 -1.603072E-02 -3.965729E-05 -1.459394E-02 -2.864759E-05 -1.150127E-02 -2.431776E-05 -1.146459E-02 -2.593052E-05 -1.120930E-02 -2.027939E-05 -1.077685E-02 -1.909421E-05 -1.564605E-02 -5.177856E-05 -1.438847E-02 -2.596269E-05 -1.575101E-02 -2.945546E-05 -5.164090E-03 -4.380072E-06 -5.313984E-03 -4.984595E-06 -3.270078E-03 -3.714857E-06 -4.763025E-03 -5.471147E-06 -5.854797E-03 -4.013420E-06 -7.497916E-03 -9.530633E-06 -4.307122E-03 -4.511481E-06 -2.673595E-03 -1.496751E-06 -7.668976E-03 -1.208726E-05 -6.666645E-03 -9.107345E-06 -4.278473E-03 -3.613729E-06 -5.196607E-03 -6.165915E-06 -9.012663E-03 -1.072065E-05 -7.125950E-03 -1.021884E-05 -1.110525E-02 -1.609758E-05 -6.452393E-03 -6.522408E-06 -1.614916E-02 -2.933964E-05 -1.252957E-02 -2.095707E-05 -9.931672E-03 -1.358529E-05 -1.307449E-02 -2.442977E-05 -5.859693E-03 -6.187229E-06 -6.811267E-03 -6.011900E-06 -1.636036E-02 -4.227062E-05 -9.529154E-03 -1.673527E-05 -9.884570E-03 -1.607810E-05 -1.162560E-02 -2.293323E-05 -6.582499E-03 -8.254458E-06 -1.846807E-02 -3.840513E-05 -9.921319E-03 -1.528378E-05 -1.451278E-02 -3.842835E-05 -1.536970E-02 -4.453795E-05 -1.597714E-02 -3.763051E-05 -1.416499E-02 -2.488034E-05 -1.579940E-02 -3.618366E-05 -1.729494E-02 -4.587947E-05 -1.591255E-02 -3.608980E-05 -1.155321E-02 -2.053226E-05 -1.599423E-02 -3.545225E-05 -1.125966E-02 -2.267289E-05 -2.172447E-02 -5.857701E-05 -1.372075E-02 -3.321713E-05 -1.816373E-02 -4.485596E-05 -1.857039E-02 -4.872304E-05 -1.742011E-02 -3.730490E-05 -1.568977E-02 -3.029088E-05 -2.829373E-02 -1.168965E-04 -2.157357E-02 -7.579178E-05 -2.125484E-02 -6.473902E-05 -2.196378E-02 -7.339057E-05 -1.819373E-02 -4.494748E-05 -2.152003E-02 -5.928285E-05 -1.856070E-02 -4.410267E-05 -2.207371E-02 -6.449028E-05 -2.386394E-02 -6.969242E-05 -2.457216E-02 -1.102599E-04 -2.058268E-02 -5.017858E-05 -1.907854E-02 -4.286270E-05 -2.340706E-02 -8.278475E-05 -2.388190E-02 -6.533857E-05 -2.860789E-02 -9.992731E-05 -1.998933E-02 -5.361464E-05 -2.707938E-02 -9.662902E-05 -2.019340E-02 -5.415561E-05 -3.109482E-02 -1.022004E-04 -2.253924E-02 -7.055172E-05 -2.374030E-02 -6.831307E-05 -2.529035E-02 -8.295294E-05 -2.739289E-02 -8.546620E-05 -2.273185E-02 -6.442166E-05 -2.785353E-02 -8.812366E-05 -3.191849E-02 -1.234987E-04 -2.739246E-02 -9.446447E-05 -1.372157E-02 -2.877717E-05 -1.714263E-02 -4.531432E-05 -1.958677E-02 -4.920099E-05 -1.932218E-02 -4.756040E-05 -1.938252E-02 -5.565524E-05 -2.128472E-02 -6.581062E-05 -1.818983E-02 -4.440473E-05 -2.522476E-02 -9.504815E-05 -2.108060E-02 -6.460391E-05 -2.301325E-02 -6.325908E-05 -2.425505E-02 -7.889282E-05 -2.312674E-02 -8.098059E-05 -1.450662E-02 -3.120847E-05 -1.518342E-02 -2.854939E-05 -2.375891E-02 -6.170759E-05 -2.191567E-02 -5.656277E-05 -1.717224E-02 -4.219605E-05 -1.584923E-02 -2.801671E-05 -2.292044E-02 -6.761182E-05 -2.565035E-02 -9.677221E-05 -1.979804E-02 -4.912546E-05 -2.534051E-02 -8.007940E-05 -3.425993E-02 -1.487128E-04 -2.139063E-02 -5.051176E-05 -1.422774E-02 -2.343122E-05 -2.541660E-02 -8.204787E-05 -1.717071E-02 -3.842694E-05 -1.456931E-02 -2.599937E-05 -2.407397E-02 -7.826348E-05 -2.982739E-02 -1.099192E-04 -1.812330E-02 -4.520557E-05 -1.506065E-02 -3.120742E-05 -1.957887E-02 -5.130992E-05 -2.577824E-02 -8.648590E-05 -1.959134E-02 -6.907548E-05 -2.361937E-02 -6.849830E-05 -1.277061E-02 -2.340598E-05 -1.244142E-02 -2.267140E-05 -9.333247E-03 -1.041879E-05 -7.908182E-03 -9.293981E-06 -1.463279E-02 -3.362978E-05 -1.366375E-02 -2.733021E-05 -1.213165E-02 -1.941620E-05 -1.142127E-02 -1.911366E-05 -1.101989E-02 -1.602290E-05 -1.634784E-02 -3.444363E-05 -1.399007E-02 -2.474094E-05 -1.355244E-02 -2.255801E-05 -8.699738E-03 -1.229441E-05 -6.242338E-03 -7.967030E-06 -1.101667E-02 -2.565058E-05 -8.204914E-03 -1.826875E-05 -1.073981E-02 -1.693632E-05 -1.272259E-02 -2.077325E-05 -3.495009E-03 -2.520678E-06 -8.225887E-03 -1.254359E-05 -1.009530E-02 -1.562680E-05 -1.178865E-02 -2.042891E-05 -8.663517E-03 -1.609834E-05 -1.169582E-02 -2.164100E-05 -7.396443E-03 -1.192095E-05 -3.652278E-03 -3.129723E-06 -1.045202E-02 -2.112608E-05 -1.037936E-02 -1.718392E-05 -4.516079E-03 -3.575143E-06 -1.095270E-02 -1.774093E-05 -4.883767E-03 -5.927447E-06 -6.503683E-03 -7.716956E-06 -4.663924E-03 -5.713440E-06 -6.283619E-03 -4.627844E-06 -1.015268E-02 -1.309267E-05 -9.180971E-03 -1.527190E-05 -1.951120E-02 -4.198333E-05 -1.915689E-02 -5.707669E-05 -1.373893E-02 -2.451846E-05 -1.700799E-02 -4.037549E-05 -8.089066E-03 -1.170312E-05 -1.428411E-02 -2.720105E-05 -1.592720E-02 -3.708704E-05 -1.631763E-02 -3.412617E-05 -1.129445E-02 -1.941873E-05 -1.915612E-02 -4.735245E-05 -1.422466E-02 -3.019642E-05 -1.623769E-02 -4.050190E-05 -3.000266E-02 -1.011980E-04 -2.431859E-02 -7.075474E-05 -1.997843E-02 -5.249597E-05 -2.330404E-02 -6.963217E-05 -2.446833E-02 -7.157726E-05 -2.086381E-02 -6.071597E-05 -2.692405E-02 -8.142503E-05 -3.334489E-02 -1.331416E-04 -2.459016E-02 -7.539450E-05 -2.490317E-02 -6.829414E-05 -3.465734E-02 -1.336723E-04 -2.655747E-02 -8.402121E-05 -2.461979E-02 -7.593460E-05 -2.071273E-02 -5.109741E-05 -1.963799E-02 -4.721624E-05 -2.830417E-02 -1.108014E-04 -2.011415E-02 -4.210370E-05 -2.710260E-02 -9.007571E-05 -2.284700E-02 -6.898714E-05 -3.401467E-02 -1.508203E-04 -3.114460E-02 -1.181041E-04 -3.240556E-02 -1.301155E-04 -2.879980E-02 -1.090167E-04 -3.128129E-02 -1.046425E-04 -1.710639E-02 -3.063073E-05 -2.380055E-02 -6.611900E-05 -2.461530E-02 -6.805558E-05 -2.334066E-02 -6.791023E-05 -2.377977E-02 -7.167847E-05 -3.617503E-02 -1.573371E-04 -1.872815E-02 -5.621939E-05 -1.775203E-02 -4.642358E-05 -2.771547E-02 -8.299647E-05 -3.061731E-02 -1.020731E-04 -2.507147E-02 -7.334317E-05 -3.870082E-02 -1.721376E-04 -2.186224E-02 -6.325183E-05 -2.007397E-02 -5.062141E-05 -1.912434E-02 -4.450748E-05 -3.143924E-02 -1.217065E-04 -2.928610E-02 -1.369102E-04 -2.498862E-02 -9.234430E-05 -3.196385E-02 -1.380535E-04 -2.888275E-02 -9.066905E-05 -2.680537E-02 -9.933885E-05 -3.510043E-02 -1.418994E-04 -2.849205E-02 -9.541143E-05 -3.088469E-02 -1.124620E-04 -2.410541E-02 -7.456599E-05 -2.652028E-02 -7.737605E-05 -3.100674E-02 -1.204077E-04 -2.627656E-02 -7.414914E-05 -3.172017E-02 -1.179298E-04 -3.654420E-02 -1.501200E-04 -2.437387E-02 -8.465163E-05 -2.329587E-02 -8.609453E-05 -2.851454E-02 -9.764789E-05 -2.727184E-02 -1.020548E-04 -2.887669E-02 -9.379474E-05 -2.486065E-02 -6.980906E-05 -1.336139E-02 -3.237058E-05 -1.783830E-02 -4.308671E-05 -1.984536E-02 -4.793066E-05 -1.663979E-02 -3.245507E-05 -1.629628E-02 -3.780856E-05 -2.783691E-02 -9.185991E-05 -1.901340E-02 -4.331876E-05 -1.589227E-02 -3.023585E-05 -1.511908E-02 -3.924720E-05 -2.103836E-02 -5.685631E-05 -1.846361E-02 -5.596947E-05 -2.921881E-02 -1.027479E-04 -1.582650E-02 -2.965346E-05 -1.468540E-02 -2.895302E-05 -9.775043E-03 -1.581144E-05 -1.531973E-02 -3.646605E-05 -1.629584E-02 -4.077722E-05 -1.301406E-02 -2.211695E-05 -1.400095E-02 -2.464499E-05 -1.812501E-02 -5.136800E-05 -1.883997E-02 -4.846725E-05 -1.310098E-02 -2.076611E-05 -1.641887E-02 -3.214577E-05 -2.575947E-02 -7.664609E-05 -1.393085E-02 -2.533855E-05 -1.176890E-02 -1.965214E-05 -1.001319E-02 -1.752840E-05 -5.440474E-03 -5.776297E-06 -1.602659E-02 -3.187961E-05 -1.220713E-02 -2.605586E-05 -7.910828E-03 -1.235157E-05 -6.370403E-03 -7.314863E-06 -1.200010E-02 -2.093134E-05 -1.051384E-02 -2.114633E-05 -8.728632E-03 -1.217334E-05 -9.023232E-03 -1.429000E-05 -9.324890E-03 -1.238002E-05 -9.724819E-03 -1.340545E-05 -7.999095E-03 -1.507108E-05 -1.196325E-02 -2.492866E-05 -1.708992E-02 -4.187497E-05 -1.252870E-02 -2.576528E-05 -1.245286E-02 -2.205925E-05 -1.710226E-02 -4.820652E-05 -1.077670E-02 -2.779337E-05 -8.954749E-03 -1.459088E-05 -1.587508E-02 -5.891538E-05 -1.256231E-02 -3.626849E-05 -1.456161E-02 -2.677457E-05 -1.442492E-02 -2.873208E-05 -1.513933E-02 -2.781837E-05 -1.983944E-02 -4.742520E-05 -1.796161E-02 -5.099223E-05 -1.372378E-02 -2.143333E-05 -2.054995E-02 -5.149337E-05 -1.901284E-02 -4.203203E-05 -1.545044E-02 -3.240467E-05 -1.613542E-02 -3.093719E-05 -1.748080E-02 -3.676025E-05 -1.983930E-02 -5.826899E-05 -2.077484E-02 -5.311470E-05 -2.156771E-02 -7.349191E-05 -1.910656E-02 -5.646548E-05 -2.216856E-02 -5.896630E-05 -2.363877E-02 -6.273768E-05 -2.287745E-02 -6.142836E-05 -2.078760E-02 -5.965409E-05 -2.096805E-02 -6.106318E-05 -2.748905E-02 -8.547689E-05 -3.051782E-02 -1.062831E-04 -2.439885E-02 -6.963272E-05 -2.385521E-02 -7.024650E-05 -2.722803E-02 -8.442159E-05 -2.779212E-02 -9.251750E-05 -3.008247E-02 -1.087302E-04 -2.911535E-02 -9.162499E-05 -2.377217E-02 -6.480525E-05 -2.478405E-02 -8.301183E-05 -2.916643E-02 -1.151040E-04 -3.299041E-02 -1.251473E-04 -3.387553E-02 -1.275181E-04 -3.185326E-02 -1.151563E-04 -2.738559E-02 -8.510575E-05 -3.552781E-02 -1.467678E-04 -2.050637E-02 -4.879306E-05 -2.837699E-02 -8.517767E-05 -2.623559E-02 -7.322670E-05 -3.299486E-02 -1.475369E-04 -2.852314E-02 -1.058243E-04 -3.897511E-02 -1.782398E-04 -3.453237E-02 -1.467871E-04 -2.695630E-02 -9.399806E-05 -2.993587E-02 -1.069727E-04 -3.357367E-02 -1.220837E-04 -3.533685E-02 -1.307797E-04 -3.768880E-02 -1.706168E-04 -2.378269E-02 -8.193354E-05 -2.476389E-02 -6.667890E-05 -1.835306E-02 -3.678306E-05 -2.760875E-02 -1.044222E-04 -3.364777E-02 -1.294893E-04 -2.689602E-02 -8.234805E-05 -2.994600E-02 -1.038678E-04 -3.354397E-02 -1.250106E-04 -2.806016E-02 -1.032022E-04 -3.628839E-02 -1.512597E-04 -3.254567E-02 -1.229982E-04 -3.532092E-02 -1.401948E-04 -2.079706E-02 -5.214734E-05 -2.220721E-02 -6.771925E-05 -2.792774E-02 -9.954429E-05 -2.945320E-02 -1.043290E-04 -3.367757E-02 -1.278353E-04 -3.498071E-02 -1.439058E-04 -3.069969E-02 -1.094894E-04 -2.802931E-02 -9.732849E-05 -3.379486E-02 -1.251030E-04 -3.112018E-02 -1.419631E-04 -2.905240E-02 -9.457676E-05 -3.204785E-02 -1.232863E-04 -2.256002E-02 -6.449945E-05 -2.013216E-02 -4.579187E-05 -2.378756E-02 -7.502656E-05 -1.850227E-02 -4.559569E-05 -2.577098E-02 -8.077705E-05 -2.622626E-02 -8.900068E-05 -2.011102E-02 -5.119938E-05 -1.881459E-02 -5.303212E-05 -2.333357E-02 -8.135744E-05 -2.169922E-02 -5.260477E-05 -2.865567E-02 -1.072530E-04 -3.018313E-02 -1.180560E-04 -1.619341E-02 -3.631507E-05 -2.048742E-02 -6.014736E-05 -1.648517E-02 -3.461260E-05 -2.016257E-02 -5.377223E-05 -1.821956E-02 -4.021256E-05 -2.158168E-02 -6.922336E-05 -1.520759E-02 -3.087500E-05 -1.460640E-02 -2.484693E-05 -2.423578E-02 -9.468824E-05 -1.422992E-02 -2.626671E-05 -2.233711E-02 -6.453963E-05 -2.201935E-02 -6.607908E-05 -9.865297E-03 -1.253449E-05 -1.407603E-02 -2.374027E-05 -1.554488E-02 -3.357059E-05 -1.104207E-02 -1.800945E-05 -1.152633E-02 -1.752515E-05 -1.628689E-02 -3.825834E-05 -1.961306E-03 -1.509555E-06 -7.317970E-03 -1.170313E-05 -8.045927E-03 -1.128636E-05 -7.690351E-03 -9.455253E-06 -1.305182E-02 -2.924924E-05 -8.478606E-03 -1.183524E-05 -8.368030E-03 -9.397112E-06 -6.954808E-03 -5.988757E-06 -1.478825E-02 -2.903770E-05 -1.329221E-02 -2.352890E-05 -1.153738E-02 -2.279952E-05 -1.243207E-02 -2.027409E-05 -9.794691E-03 -2.519096E-05 -1.301443E-02 -2.673139E-05 -7.744527E-03 -8.512395E-06 -1.094360E-02 -1.898404E-05 -1.322530E-02 -2.416304E-05 -1.130737E-02 -2.067371E-05 -1.475002E-02 -2.641761E-05 -1.707041E-02 -4.061788E-05 -1.873188E-02 -3.858649E-05 -2.599435E-02 -7.840083E-05 -1.356899E-02 -3.303086E-05 -1.640959E-02 -4.231153E-05 -1.712330E-02 -4.025543E-05 -2.408636E-02 -6.859578E-05 -1.647314E-02 -3.975609E-05 -2.116131E-02 -5.516930E-05 -1.843826E-02 -4.250156E-05 -1.528596E-02 -3.432942E-05 -1.872595E-02 -4.482976E-05 -2.278412E-02 -7.039773E-05 -1.646460E-02 -3.454420E-05 -2.813905E-02 -1.098347E-04 -1.918135E-02 -4.628739E-05 -2.880134E-02 -1.294280E-04 -2.929725E-02 -1.035423E-04 -2.521557E-02 -8.873832E-05 -1.598874E-02 -3.488466E-05 -2.763380E-02 -9.554358E-05 -2.869939E-02 -9.202942E-05 -2.713151E-02 -8.978531E-05 -1.987710E-02 -4.592695E-05 -2.437199E-02 -8.143180E-05 -2.321959E-02 -6.492177E-05 -3.341995E-02 -1.498991E-04 -3.725498E-02 -1.896851E-04 -2.546980E-02 -7.669037E-05 -3.217017E-02 -1.220964E-04 -3.340259E-02 -1.408478E-04 -2.814856E-02 -9.960802E-05 -3.512673E-02 -1.528623E-04 -3.192684E-02 -1.177255E-04 -4.396846E-02 -2.179530E-04 -2.532908E-02 -9.266623E-05 -2.547875E-02 -7.493150E-05 -2.198311E-02 -5.696022E-05 -2.752789E-02 -8.630574E-05 -2.765173E-02 -8.761218E-05 -2.779760E-02 -1.213200E-04 -3.155525E-02 -1.104115E-04 -3.217963E-02 -1.396421E-04 -2.812793E-02 -1.067509E-04 -3.145703E-02 -1.323921E-04 -3.473095E-02 -1.271199E-04 -3.132386E-02 -1.050335E-04 -2.550248E-02 -7.173055E-05 -2.519509E-02 -8.292973E-05 -2.719586E-02 -9.875000E-05 -3.129909E-02 -1.364716E-04 -2.405862E-02 -6.392928E-05 -3.794317E-02 -1.796683E-04 -2.411060E-02 -7.563523E-05 -3.925533E-02 -1.941205E-04 -2.464678E-02 -8.141818E-05 -2.681802E-02 -8.985410E-05 -4.257422E-02 -2.011050E-04 -3.169616E-02 -1.228099E-04 -2.070267E-02 -8.295562E-05 -1.875182E-02 -4.519138E-05 -2.746689E-02 -8.527112E-05 -3.193689E-02 -1.260160E-04 -3.274412E-02 -1.277208E-04 -3.159605E-02 -1.244039E-04 -2.739115E-02 -9.148770E-05 -2.496372E-02 -7.319379E-05 -2.543741E-02 -8.751995E-05 -3.092377E-02 -1.322133E-04 -3.099099E-02 -1.159996E-04 -3.339925E-02 -1.244687E-04 -1.992237E-02 -5.132256E-05 -2.014907E-02 -4.750167E-05 -2.144112E-02 -6.724888E-05 -3.234934E-02 -1.819994E-04 -2.676069E-02 -9.670530E-05 -2.163370E-02 -5.007717E-05 -1.255610E-02 -2.744980E-05 -1.686689E-02 -4.406712E-05 -2.491027E-02 -8.641625E-05 -2.180394E-02 -5.962243E-05 -2.074450E-02 -7.196276E-05 -2.673557E-02 -9.943740E-05 -1.141559E-02 -2.064868E-05 -1.086445E-02 -1.772569E-05 -1.994739E-02 -6.095357E-05 -1.294529E-02 -2.949692E-05 -1.279449E-02 -2.013615E-05 -1.695923E-02 -5.267358E-05 -1.003362E-02 -1.892494E-05 -1.177407E-02 -3.074621E-05 -1.427717E-02 -3.062012E-05 -1.772566E-02 -4.566137E-05 -1.448022E-02 -2.786842E-05 -1.885150E-02 -4.869026E-05 -6.234737E-03 -6.766915E-06 -8.586280E-03 -1.484755E-05 -6.177392E-03 -1.214223E-05 -5.323791E-03 -4.680794E-06 -1.176080E-02 -2.484279E-05 -1.114881E-02 -1.645519E-05 -6.273419E-03 -6.143891E-06 -5.166701E-03 -3.867691E-06 -8.069436E-03 -1.040414E-05 -4.713136E-03 -5.175457E-06 -1.199780E-02 -1.859984E-05 -8.029148E-03 -8.699198E-06 -5.632949E-03 -5.837510E-06 -9.206218E-03 -1.575125E-05 -9.680753E-03 -1.846461E-05 -1.155184E-02 -2.188509E-05 -1.074904E-02 -1.891184E-05 -1.181458E-02 -2.456277E-05 -1.127047E-02 -2.593399E-05 -1.356860E-02 -2.814265E-05 -5.544832E-03 -6.946307E-06 -9.942970E-03 -1.675490E-05 -1.631004E-02 -3.536433E-05 -1.506925E-02 -2.482344E-05 -1.182795E-02 -1.897537E-05 -1.482385E-02 -3.899302E-05 -1.209032E-02 -1.754837E-05 -1.195251E-02 -2.049614E-05 -1.038664E-02 -1.424835E-05 -1.422392E-02 -2.932993E-05 -1.541884E-02 -3.247431E-05 -1.631665E-02 -4.604922E-05 -1.384486E-02 -3.663157E-05 -1.878261E-02 -4.189792E-05 -1.586209E-02 -3.733994E-05 -2.018001E-02 -5.531326E-05 -1.737200E-02 -4.051342E-05 -1.867979E-02 -4.835331E-05 -1.873274E-02 -7.026344E-05 -3.092919E-02 -1.440764E-04 -1.756290E-02 -4.330757E-05 -1.677922E-02 -3.960529E-05 -1.917939E-02 -5.218395E-05 -2.058760E-02 -5.104735E-05 -1.950686E-02 -4.503102E-05 -1.898111E-02 -5.123138E-05 -2.095898E-02 -6.978821E-05 -2.496761E-02 -7.344351E-05 -2.216966E-02 -6.981877E-05 -1.539258E-02 -3.355552E-05 -2.090036E-02 -5.893204E-05 -2.830594E-02 -9.908163E-05 -2.079711E-02 -5.700234E-05 -2.438388E-02 -7.315541E-05 -2.071811E-02 -5.920090E-05 -3.238056E-02 -1.338963E-04 -1.998547E-02 -4.982584E-05 -2.456523E-02 -7.090598E-05 -3.010218E-02 -9.569115E-05 -2.615311E-02 -8.034083E-05 -2.193093E-02 -6.501139E-05 -2.230235E-02 -6.810904E-05 -2.787441E-02 -9.364266E-05 -3.363819E-02 -1.294292E-04 -2.455137E-02 -7.174173E-05 -2.515678E-02 -6.839428E-05 -2.184998E-02 -5.948214E-05 -3.240910E-02 -1.297175E-04 -2.930001E-02 -9.691693E-05 -2.531952E-02 -7.468705E-05 -3.926456E-02 -1.746326E-04 -3.138940E-02 -1.141098E-04 -2.053774E-02 -4.616986E-05 -1.863850E-02 -5.063978E-05 -2.488227E-02 -8.135984E-05 -2.946035E-02 -9.621222E-05 -1.816353E-02 -4.227005E-05 -2.739033E-02 -9.425769E-05 -2.235176E-02 -7.322516E-05 -2.512226E-02 -7.712444E-05 -2.093974E-02 -5.655060E-05 -1.951079E-02 -4.907052E-05 -3.008712E-02 -9.648471E-05 -2.695713E-02 -8.322148E-05 -2.032086E-02 -4.478975E-05 -1.588968E-02 -3.284638E-05 -2.795370E-02 -9.478738E-05 -3.242775E-02 -1.467751E-04 -1.851414E-02 -5.030367E-05 -1.699040E-02 -4.048405E-05 -2.381562E-02 -8.005819E-05 -2.396088E-02 -7.106899E-05 -1.334683E-02 -2.033683E-05 -2.683684E-02 -9.730671E-05 -3.212945E-02 -1.268600E-04 -2.413721E-02 -7.785437E-05 -1.278877E-02 -2.285665E-05 -2.017408E-02 -5.101405E-05 -2.425974E-02 -8.238864E-05 -1.559733E-02 -4.134474E-05 -2.323747E-02 -5.912862E-05 -3.185441E-02 -1.214009E-04 -1.297541E-02 -3.542303E-05 -1.620965E-02 -3.785927E-05 -2.077217E-02 -5.048348E-05 -2.084714E-02 -5.308615E-05 -2.198650E-02 -6.677202E-05 -2.713339E-02 -7.996952E-05 -1.008900E-02 -1.493544E-05 -7.515252E-03 -6.938048E-06 -1.725580E-02 -4.511463E-05 -1.861578E-02 -4.706579E-05 -1.192562E-02 -1.706496E-05 -1.539067E-02 -3.704392E-05 -1.563574E-02 -3.149768E-05 -1.617709E-02 -3.434601E-05 -1.421795E-02 -2.693384E-05 -9.544761E-03 -1.420198E-05 -1.920816E-02 -4.315771E-05 -2.104112E-02 -6.953280E-05 -8.386327E-03 -1.191493E-05 -8.722802E-03 -1.610480E-05 -1.338316E-02 -2.795188E-05 -1.139681E-02 -2.426741E-05 -1.023902E-02 -1.793399E-05 -1.031055E-02 -1.727351E-05 -7.202274E-03 -8.248223E-06 -5.930048E-03 -5.651618E-06 -7.496873E-03 -1.049976E-05 -1.159952E-02 -1.637372E-05 -1.149358E-02 -2.129416E-05 -1.751957E-02 -3.876503E-05 -1.304134E-02 -2.268145E-05 -6.423719E-03 -1.030715E-05 -1.229584E-02 -1.921824E-05 -1.597047E-02 -2.887519E-05 -7.728575E-03 -8.694018E-06 -1.102992E-02 -1.663289E-05 -9.958745E-03 -1.518594E-05 -9.321102E-03 -1.260439E-05 -9.226395E-03 -1.473519E-05 -1.071198E-02 -1.716096E-05 -1.209027E-02 -2.012204E-05 -1.299345E-02 -2.535948E-05 -1.377877E-02 -2.712220E-05 -1.505661E-02 -3.492299E-05 -1.496534E-02 -3.555281E-05 -1.674256E-02 -3.935472E-05 -9.494973E-03 -1.562850E-05 -9.878116E-03 -1.686202E-05 -1.512689E-02 -2.756935E-05 -2.271723E-02 -7.190876E-05 -1.204699E-02 -2.702913E-05 -1.339825E-02 -2.817955E-05 -1.767135E-02 -4.942115E-05 -1.480386E-02 -6.975977E-05 -1.636386E-02 -3.439959E-05 -1.220265E-02 -2.153744E-05 -1.347844E-02 -2.910724E-05 -1.359228E-02 -3.101663E-05 -9.728835E-03 -1.507092E-05 -1.528103E-02 -3.443965E-05 -2.096063E-02 -6.754181E-05 -2.094364E-02 -6.023053E-05 -1.266226E-02 -2.412451E-05 -2.535680E-02 -7.344640E-05 -2.598994E-02 -9.953050E-05 -2.060213E-02 -7.034543E-05 -1.788607E-02 -3.674071E-05 -1.148154E-02 -1.909188E-05 -2.245671E-02 -6.003250E-05 -2.763268E-02 -9.551846E-05 -2.267967E-02 -6.032826E-05 -1.916473E-02 -4.604843E-05 -1.294451E-02 -1.970613E-05 -1.934618E-02 -4.918252E-05 -2.293529E-02 -7.197108E-05 -1.496065E-02 -2.444659E-05 -2.226558E-02 -5.644756E-05 -1.948569E-02 -4.450894E-05 -2.081785E-02 -5.246988E-05 -1.522522E-02 -3.455714E-05 -2.719218E-02 -8.650624E-05 -3.018717E-02 -1.279696E-04 -1.871704E-02 -6.935361E-05 -2.067645E-02 -5.026583E-05 -2.040699E-02 -4.591994E-05 -2.662203E-02 -8.511265E-05 -1.360877E-02 -2.453053E-05 -2.047026E-02 -5.992658E-05 -2.099358E-02 -6.877382E-05 -1.757234E-02 -4.380517E-05 -2.023155E-02 -5.570688E-05 -1.620245E-02 -3.127153E-05 -2.718760E-02 -1.061924E-04 -1.747980E-02 -4.190787E-05 -1.548489E-02 -3.376610E-05 -2.645660E-02 -9.074843E-05 -1.786629E-02 -4.215277E-05 -1.474131E-02 -2.581817E-05 -1.388717E-02 -2.989188E-05 -2.441704E-02 -7.084896E-05 -2.104368E-02 -5.681421E-05 -2.433800E-02 -7.895153E-05 -1.597437E-02 -3.483039E-05 -1.412656E-02 -2.566245E-05 -1.687717E-02 -3.771639E-05 -2.190482E-02 -8.253917E-05 -1.386107E-02 -3.378072E-05 -1.256494E-02 -2.033235E-05 -1.458675E-02 -2.616735E-05 -1.633493E-02 -3.166210E-05 -2.288089E-02 -6.714973E-05 -2.398060E-02 -7.693950E-05 -1.834264E-02 -4.444484E-05 -2.286357E-02 -5.661515E-05 -1.648013E-02 -4.331697E-05 -1.300614E-02 -2.342646E-05 -1.426626E-02 -2.966175E-05 -2.218616E-02 -7.311082E-05 -1.244578E-02 -2.216996E-05 -2.287835E-02 -6.924841E-05 -1.752439E-02 -4.165478E-05 -2.103286E-02 -5.842027E-05 -1.533084E-02 -3.870604E-05 -1.829172E-02 -5.193773E-05 -1.756896E-02 -4.997547E-05 -2.219401E-02 -5.804587E-05 -1.083994E-02 -1.562087E-05 -1.144466E-02 -2.086121E-05 -1.743653E-02 -3.615221E-05 -9.676259E-03 -1.226729E-05 -1.296315E-02 -2.293653E-05 -1.353945E-02 -3.069949E-05 -7.066700E-03 -7.777520E-06 -8.915397E-03 -1.286545E-05 -1.337770E-02 -2.968336E-05 -1.210357E-02 -2.373080E-05 -1.021357E-02 -1.742336E-05 -1.615799E-02 -4.003564E-05 -9.037428E-03 -1.958275E-05 -3.183370E-03 -2.393571E-06 -8.515537E-03 -1.434148E-05 -8.594763E-03 -1.144929E-05 -6.557583E-03 -6.809462E-06 -9.324712E-03 -1.284671E-05 -6.075741E-03 -8.217443E-06 -7.732948E-03 -1.254995E-05 -9.364155E-03 -1.391050E-05 -1.033625E-02 -1.710810E-05 -1.643522E-02 -5.092731E-05 -1.913240E-02 -5.188056E-05 -4.699889E-03 -4.253342E-06 -3.667145E-03 -3.051204E-06 -6.956946E-03 -7.413590E-06 -9.143993E-03 -1.510114E-05 -5.630486E-03 -7.481628E-06 -8.090881E-03 -1.407277E-05 -6.451248E-03 -9.019754E-06 -8.432893E-03 -1.236291E-05 -7.535742E-03 -9.713557E-06 -4.055813E-03 -2.764876E-06 -6.361136E-03 -7.935395E-06 -7.066013E-03 -9.687252E-06 -8.347614E-03 -1.322030E-05 -5.583607E-03 -6.318991E-06 -9.734817E-03 -1.915868E-05 -9.117770E-03 -1.299951E-05 -5.466583E-03 -5.814486E-06 -6.377661E-03 -5.982386E-06 -1.066356E-02 -1.915872E-05 -1.205945E-02 -1.894758E-05 -9.934821E-03 -1.678379E-05 -1.138156E-02 -2.321476E-05 -1.063324E-02 -1.739239E-05 -8.377153E-03 -1.072894E-05 -1.600249E-02 -3.173041E-05 -1.442818E-02 -3.650694E-05 -1.643458E-02 -2.935759E-05 -1.937762E-02 -5.539763E-05 -8.400592E-03 -1.059830E-05 -1.497133E-02 -3.316378E-05 -1.469275E-02 -3.001660E-05 -1.502203E-02 -2.852008E-05 -9.750216E-03 -1.395013E-05 -1.497859E-02 -2.421550E-05 -2.111839E-02 -6.023324E-05 -1.358782E-02 -2.820256E-05 -1.250078E-02 -2.294909E-05 -1.058650E-02 -1.688760E-05 -1.488385E-02 -2.666627E-05 -1.927781E-02 -5.429379E-05 -1.208022E-02 -2.250992E-05 -1.497153E-02 -2.676884E-05 -1.244590E-02 -2.756211E-05 -9.989045E-03 -1.303571E-05 -8.894574E-03 -1.174122E-05 -1.938283E-02 -4.239857E-05 -1.804394E-02 -3.515511E-05 -1.337739E-02 -2.482975E-05 -1.487943E-02 -3.347708E-05 -1.110033E-02 -2.136237E-05 -1.333452E-02 -2.308294E-05 -1.635319E-02 -3.229248E-05 -8.693802E-03 -1.542452E-05 -1.031414E-02 -2.112585E-05 -1.838966E-02 -4.539908E-05 -2.354073E-02 -7.698141E-05 -1.080321E-02 -1.831625E-05 -2.112481E-02 -6.253585E-05 -2.050287E-02 -5.388829E-05 -1.779381E-02 -3.937477E-05 -1.477468E-02 -2.411115E-05 -1.293051E-02 -2.250585E-05 -1.609738E-02 -3.396791E-05 -2.681377E-02 -8.749523E-05 -1.670204E-02 -4.359534E-05 -2.206205E-02 -6.377754E-05 -1.873639E-02 -5.703093E-05 -1.889950E-02 -5.052682E-05 -1.824219E-02 -6.072963E-05 -9.270805E-03 -9.959479E-06 -1.684688E-02 -3.370730E-05 -1.521705E-02 -2.961236E-05 -1.701708E-02 -4.241891E-05 -1.338529E-02 -2.440114E-05 -2.037312E-02 -5.462555E-05 -1.229143E-02 -1.878363E-05 -1.429618E-02 -3.043241E-05 -1.452304E-02 -3.335612E-05 -1.081202E-02 -1.892516E-05 -1.166461E-02 -2.163556E-05 -9.237578E-03 -1.212749E-05 -1.315603E-02 -2.637907E-05 -1.701531E-02 -4.938074E-05 -1.071566E-02 -1.400306E-05 -6.882737E-03 -1.095801E-05 -9.693556E-03 -1.516152E-05 -1.473076E-02 -4.380304E-05 -1.172802E-02 -2.661846E-05 -1.044100E-02 -1.616180E-05 -1.321485E-02 -2.517015E-05 -1.034434E-02 -2.118831E-05 -1.604723E-02 -3.547683E-05 -1.309313E-02 -2.716364E-05 -1.410482E-02 -2.701123E-05 -1.932682E-02 -4.094043E-05 -1.570824E-02 -3.228547E-05 -1.071500E-02 -2.525484E-05 -9.230951E-03 -1.398163E-05 -1.889558E-02 -4.381257E-05 -1.401925E-02 -2.692560E-05 -9.335801E-03 -1.384367E-05 -1.635939E-02 -3.876884E-05 -9.920998E-03 -1.367019E-05 -1.029500E-02 -1.637783E-05 -8.294680E-03 -1.093734E-05 -1.266183E-02 -2.587245E-05 -1.407777E-02 -2.856187E-05 -1.854542E-02 -4.825382E-05 -5.748894E-03 -8.790611E-06 -6.718806E-03 -1.183924E-05 -8.894787E-03 -1.306300E-05 -9.405707E-03 -1.288762E-05 -8.792692E-03 -1.122248E-05 -1.103181E-02 -1.580934E-05 -2.659005E-03 -1.548241E-06 -7.016434E-03 -7.516622E-06 -7.803753E-03 -1.013698E-05 -5.086094E-03 -7.063507E-06 -6.912737E-03 -6.574511E-06 -6.396947E-03 -6.066584E-06 -3.808735E-03 -2.749937E-06 -1.756683E-03 -8.375727E-07 -5.851836E-03 -1.028488E-05 -4.947448E-03 -5.127717E-06 -2.630989E-03 -1.428143E-06 -2.910935E-03 -1.681876E-06 -1.838842E-03 -8.992911E-07 -1.293684E-03 -6.685764E-07 -3.339457E-03 -3.028553E-06 -4.580626E-03 -4.624997E-06 -8.307235E-03 -1.674431E-05 -4.486573E-03 -3.705825E-06 -1.144529E-02 -2.352240E-05 -4.880878E-03 -3.852879E-06 -1.005985E-02 -1.391072E-05 -5.741160E-03 -7.136284E-06 -3.844734E-03 -3.016161E-06 -4.765015E-03 -4.225164E-06 -9.903891E-03 -1.243668E-05 -6.186072E-03 -7.288467E-06 -5.025861E-03 -4.672189E-06 -9.762213E-03 -1.357133E-05 -7.207433E-03 -1.732068E-05 -7.775127E-03 -1.904290E-05 -8.549835E-03 -9.367660E-06 -7.175698E-03 -7.187069E-06 -9.296385E-03 -1.322855E-05 -1.130874E-02 -1.956313E-05 -6.989995E-03 -7.487382E-06 -9.825026E-03 -1.567524E-05 -8.647918E-03 -1.652352E-05 -1.087355E-02 -1.533263E-05 -8.616514E-03 -1.142788E-05 -7.352790E-03 -1.365573E-05 -1.138586E-02 -2.265717E-05 -8.641472E-03 -1.322858E-05 -1.041352E-02 -1.315105E-05 -7.829927E-03 -1.004051E-05 -1.425328E-02 -2.580893E-05 -8.892806E-03 -1.300336E-05 -7.287566E-03 -1.259700E-05 -1.443032E-02 -3.334244E-05 -1.017849E-02 -1.483161E-05 -1.467996E-02 -3.045887E-05 -5.224154E-03 -5.244222E-06 -9.725108E-03 -1.589220E-05 -7.665836E-03 -1.588331E-05 -1.010342E-02 -1.784078E-05 -9.419018E-03 -1.369817E-05 -8.670373E-03 -1.032775E-05 -1.138937E-02 -1.811885E-05 -1.798735E-02 -4.793175E-05 -1.065784E-02 -1.799829E-05 -1.308082E-02 -2.484335E-05 -1.240918E-02 -2.570768E-05 -1.745339E-02 -5.770116E-05 -9.113925E-03 -1.349884E-05 -1.402932E-02 -2.482802E-05 -1.888352E-02 -4.563824E-05 -1.225796E-02 -2.638006E-05 -6.431220E-03 -8.855282E-06 -4.770081E-03 -4.250052E-06 -1.089652E-02 -1.611332E-05 -8.433574E-03 -1.309921E-05 -8.737584E-03 -1.411637E-05 -1.265065E-02 -2.849634E-05 -6.191713E-03 -9.561153E-06 -1.006364E-02 -1.497675E-05 -5.975885E-03 -7.218506E-06 -8.088755E-03 -1.058200E-05 -1.148407E-02 -1.800324E-05 -8.621138E-03 -1.060417E-05 -6.466931E-03 -5.559033E-06 -5.921299E-03 -7.337435E-06 -1.106199E-02 -1.985630E-05 -1.358816E-02 -2.266472E-05 -9.249095E-03 -1.326487E-05 -1.231097E-02 -2.413051E-05 -1.262777E-02 -2.135896E-05 -1.340058E-02 -2.838546E-05 -5.482441E-03 -5.699830E-06 -9.399780E-03 -1.217503E-05 -1.326355E-02 -3.084524E-05 -1.091665E-02 -1.571125E-05 -9.066945E-03 -1.253097E-05 -1.007715E-02 -1.495997E-05 -1.420187E-02 -3.247816E-05 -8.867918E-03 -1.783720E-05 -1.035797E-02 -1.618714E-05 -1.051439E-02 -1.905852E-05 -9.663711E-03 -1.733227E-05 -6.083326E-03 -8.227985E-06 -8.498983E-03 -1.203506E-05 -6.305066E-03 -7.288313E-06 -7.022938E-03 -1.842350E-05 -5.300040E-03 -6.674218E-06 -1.192288E-02 -2.251146E-05 -1.268268E-02 -2.376464E-05 -1.105252E-02 -1.907200E-05 -1.141409E-02 -2.122429E-05 -6.863367E-03 -9.680619E-06 -9.454583E-03 -1.410784E-05 -6.678539E-03 -7.419299E-06 -5.435679E-03 -5.223001E-06 -5.839983E-03 -7.472675E-06 -4.126792E-03 -4.743950E-06 -6.770400E-03 -9.680068E-06 -6.192936E-03 -7.071171E-06 -5.115501E-03 -7.222293E-06 -9.291347E-03 -2.204886E-05 -9.263101E-03 -2.093887E-05 -4.871234E-03 -4.945479E-06 -7.362790E-03 -1.225470E-05 -4.662289E-03 -6.432463E-06 -3.023591E-03 -2.882907E-06 -3.141104E-03 -2.308920E-06 -4.357737E-03 -7.258711E-06 -6.160322E-03 -8.985831E-06 -2.171491E-03 -1.749207E-06 -6.561643E-03 -8.803272E-06 -7.571781E-03 -1.203184E-05 -7.440169E-03 -1.110403E-05 -5.648646E-03 -5.494924E-06 -5.357281E-03 -6.204706E-06 -1.090071E-02 -2.058466E-05 -8.383241E-03 -1.206302E-05 -5.676127E-03 -7.724753E-06 -7.425364E-03 -1.054573E-05 -5.486371E-03 -8.048247E-06 -8.635014E-03 -1.394706E-05 -9.041685E-03 -1.478222E-05 -8.430211E-03 -1.309974E-05 -9.019663E-03 -1.451788E-05 -1.031929E-02 -1.746481E-05 -8.473885E-03 -1.174896E-05 -7.773439E-03 -1.036634E-05 -6.249343E-03 -6.064341E-06 -7.095661E-03 -1.120516E-05 -8.128270E-03 -7.992625E-06 -8.497285E-03 -1.303653E-05 -9.777637E-03 -1.235924E-05 -9.741495E-03 -1.557086E-05 -7.393292E-03 -1.285346E-05 -9.196281E-03 -1.458607E-05 -8.847877E-03 -1.117609E-05 -9.688267E-03 -1.592845E-05 -8.380207E-03 -9.989138E-06 -6.280642E-03 -9.051451E-06 -5.915732E-03 -6.877346E-06 -7.178298E-03 -7.637799E-06 -1.393362E-02 -3.213127E-05 -1.124851E-02 -1.946971E-05 -7.778231E-03 -8.216708E-06 -1.100977E-02 -1.616695E-05 -9.914677E-03 -1.920656E-05 -1.140639E-02 -1.803697E-05 -9.289048E-03 -2.453446E-05 -1.333524E-02 -2.981179E-05 -1.511863E-02 -3.813471E-05 -1.309031E-02 -3.606896E-05 -9.646063E-03 -1.776204E-05 -1.508239E-02 -3.051447E-05 -1.260645E-02 -2.587693E-05 -1.462482E-02 -3.353264E-05 -1.521268E-02 -3.209409E-05 -1.468435E-02 -2.541208E-05 -1.071159E-02 -1.974334E-05 -2.153100E-02 -5.966820E-05 -1.732644E-02 -4.011287E-05 -1.667843E-02 -3.822452E-05 -1.463217E-02 -3.010523E-05 -1.656645E-02 -5.475637E-05 -1.067989E-02 -1.830023E-05 -8.824628E-03 -1.045690E-05 -2.286417E-02 -6.960907E-05 -1.839696E-02 -4.509087E-05 -1.925060E-02 -3.941153E-05 -2.258451E-02 -6.336171E-05 -1.439116E-02 -3.414902E-05 -1.155750E-02 -1.864626E-05 -1.259396E-02 -2.399348E-05 -1.558812E-02 -4.045055E-05 -1.722120E-02 -4.143410E-05 -1.762002E-02 -3.632759E-05 -7.874101E-03 -8.254184E-06 -1.768575E-02 -3.461006E-05 -1.146683E-02 -1.794910E-05 -9.688500E-03 -1.346720E-05 -2.241492E-02 -6.339022E-05 -1.934312E-02 -4.482690E-05 -1.794148E-02 -3.870190E-05 -1.579372E-02 -3.004235E-05 -1.087259E-02 -1.529755E-05 -1.257568E-02 -2.258086E-05 -1.388017E-02 -3.225403E-05 -1.427934E-02 -2.832685E-05 -1.576751E-02 -4.828020E-05 -9.333555E-03 -1.323683E-05 -1.295220E-02 -2.221784E-05 -1.292944E-02 -2.650558E-05 -1.321910E-02 -2.608639E-05 -1.867794E-02 -5.342650E-05 -1.187778E-02 -2.004699E-05 -1.570348E-02 -3.839194E-05 -7.349983E-03 -1.280817E-05 -1.048335E-02 -1.591520E-05 -1.281254E-02 -2.311657E-05 -9.441415E-03 -1.884897E-05 -7.817420E-03 -1.075829E-05 -7.050894E-03 -8.992796E-06 -1.439696E-02 -2.646431E-05 -9.666048E-03 -1.691859E-05 -1.384058E-02 -2.171361E-05 -1.483968E-02 -2.360714E-05 -6.696329E-03 -8.201920E-06 -1.461109E-02 -3.484250E-05 -1.152968E-02 -2.487151E-05 -1.235571E-02 -1.863282E-05 -1.071843E-02 -2.007060E-05 -1.192423E-02 -2.405436E-05 -5.175335E-03 -5.686680E-06 -6.167308E-03 -6.085033E-06 -6.512706E-03 -7.423219E-06 -1.084502E-02 -2.042988E-05 -1.426237E-02 -3.199412E-05 -9.833550E-03 -1.401763E-05 -1.066371E-02 -2.034673E-05 -1.088205E-02 -1.432050E-05 -1.322884E-03 -6.133009E-07 -3.131323E-03 -2.085873E-06 -7.577039E-03 -1.169415E-05 -3.697020E-03 -2.265535E-06 -8.463691E-04 -7.163407E-07 -4.936343E-03 -4.470816E-06 -2.785210E-03 -2.057770E-06 -4.647148E-03 -1.334765E-05 -4.739139E-03 -4.910528E-06 -2.212737E-03 -9.823784E-07 -3.179311E-03 -2.106597E-06 -5.139877E-03 -6.883127E-06 -6.756613E-03 -1.192459E-05 -9.019603E-03 -1.454516E-05 -7.170921E-03 -1.179166E-05 -1.332204E-02 -2.272315E-05 -1.045555E-02 -1.579302E-05 -1.471762E-02 -2.957336E-05 -6.940743E-03 -6.167781E-06 -9.285093E-03 -1.234474E-05 -5.274768E-03 -9.733764E-06 -9.363326E-03 -1.064273E-05 -1.124025E-02 -1.812349E-05 -1.242897E-02 -2.335802E-05 -1.381362E-02 -3.426304E-05 -9.040314E-03 -1.768352E-05 -8.800291E-03 -1.233677E-05 -6.219799E-03 -6.238154E-06 -9.482593E-03 -1.409322E-05 -1.380779E-02 -2.529043E-05 -1.200427E-02 -2.953271E-05 -1.419132E-02 -3.098266E-05 -1.353906E-02 -2.607804E-05 -1.431241E-02 -2.799048E-05 -1.223915E-02 -2.748804E-05 -1.852083E-02 -5.311250E-05 -1.887810E-02 -5.774443E-05 -1.277722E-02 -2.643979E-05 -8.077414E-03 -1.128725E-05 -1.339142E-02 -2.294610E-05 -1.301300E-02 -2.073634E-05 -1.397830E-02 -3.029223E-05 -1.892762E-02 -4.920518E-05 -1.535394E-02 -4.149745E-05 -1.298011E-02 -2.187906E-05 -1.905806E-02 -4.036737E-05 -1.706919E-02 -3.990119E-05 -1.435454E-02 -2.543584E-05 -1.937779E-02 -5.201021E-05 -2.323117E-02 -6.155812E-05 -1.994685E-02 -5.377319E-05 -1.320573E-02 -2.175679E-05 -1.591133E-02 -3.535892E-05 -2.108852E-02 -6.407539E-05 -1.839423E-02 -4.410414E-05 -2.011863E-02 -4.580140E-05 -1.883453E-02 -4.495207E-05 -2.134485E-02 -5.276746E-05 -1.725640E-02 -4.465566E-05 -2.590341E-02 -8.438375E-05 -2.198626E-02 -5.942456E-05 -1.721832E-02 -3.710932E-05 -1.867389E-02 -4.165207E-05 -2.535786E-02 -8.231711E-05 -2.435788E-02 -7.524302E-05 -2.417986E-02 -7.690249E-05 -3.527942E-02 -1.503529E-04 -2.545610E-02 -7.903560E-05 -2.898461E-02 -1.038511E-04 -2.650130E-02 -7.765544E-05 -3.220034E-02 -1.339104E-04 -2.615617E-02 -8.054223E-05 -1.575566E-02 -3.464485E-05 -1.721242E-02 -3.933144E-05 -2.529147E-02 -7.224719E-05 -2.161550E-02 -5.729706E-05 -3.254276E-02 -1.237101E-04 -2.601524E-02 -7.880812E-05 -2.030934E-02 -5.449343E-05 -2.529817E-02 -7.746587E-05 -2.459558E-02 -7.049178E-05 -2.743013E-02 -1.051976E-04 -2.818835E-02 -9.687328E-05 -3.082240E-02 -1.199245E-04 -1.534318E-02 -3.153431E-05 -1.798131E-02 -4.183178E-05 -1.329898E-02 -2.483181E-05 -1.519124E-02 -3.090643E-05 -2.253493E-02 -6.110325E-05 -1.932903E-02 -5.403216E-05 -2.343651E-02 -6.986521E-05 -1.851194E-02 -4.830851E-05 -2.854734E-02 -1.149020E-04 -3.554508E-02 -1.594168E-04 -2.420896E-02 -8.063001E-05 -2.438815E-02 -6.949914E-05 -1.424242E-02 -3.042725E-05 -1.883095E-02 -4.453941E-05 -1.803807E-02 -5.353218E-05 -1.472433E-02 -2.708169E-05 -2.645673E-02 -1.277462E-04 -1.659156E-02 -4.460790E-05 -1.884914E-02 -5.255122E-05 -1.323181E-02 -3.012118E-05 -2.078655E-02 -7.250952E-05 -1.929529E-02 -4.896056E-05 -1.365072E-02 -2.296122E-05 -1.548320E-02 -3.361702E-05 -1.963984E-02 -5.182163E-05 -1.938728E-02 -4.745111E-05 -1.852813E-02 -4.964750E-05 -1.254203E-02 -2.416303E-05 -1.598636E-02 -3.867130E-05 -1.557994E-02 -3.560554E-05 -8.834017E-03 -1.069678E-05 -9.484032E-03 -1.565529E-05 -1.303143E-02 -2.234676E-05 -2.200867E-02 -5.927220E-05 -1.598709E-02 -2.961814E-05 -1.402800E-02 -2.779038E-05 -4.378255E-03 -4.055161E-06 -6.657558E-03 -8.689849E-06 -5.742424E-03 -6.994090E-06 -1.690917E-03 -9.618234E-07 -6.422205E-03 -6.220083E-06 -1.098008E-02 -1.552449E-05 -4.852648E-03 -6.005700E-06 -4.131316E-03 -2.940200E-06 -5.377384E-03 -9.958808E-06 -7.493944E-03 -1.136740E-05 -5.679683E-03 -5.334788E-06 -9.041948E-03 -1.233892E-05 -1.621598E-02 -3.896922E-05 -9.707536E-03 -1.580953E-05 -9.796285E-03 -1.170913E-05 -1.038632E-02 -1.400251E-05 -1.854616E-02 -3.938948E-05 -1.637195E-02 -3.459637E-05 -1.090541E-02 -1.920540E-05 -1.554833E-02 -3.590212E-05 -4.272073E-03 -3.682734E-06 -9.074265E-03 -9.996509E-06 -1.177873E-02 -2.562780E-05 -1.154733E-02 -1.708677E-05 -2.122244E-02 -5.095551E-05 -1.703089E-02 -4.517001E-05 -1.005035E-02 -1.266093E-05 -1.780384E-02 -3.747413E-05 -1.376515E-02 -3.253018E-05 -1.530894E-02 -2.892052E-05 -2.606504E-02 -7.859853E-05 -2.255541E-02 -6.286365E-05 -1.918774E-02 -4.676979E-05 -2.519231E-02 -7.640422E-05 -1.664088E-02 -4.401309E-05 -1.584636E-02 -3.452858E-05 -2.616309E-02 -8.630269E-05 -2.255699E-02 -5.940173E-05 -2.236967E-02 -6.994996E-05 -2.248979E-02 -5.377855E-05 -2.341480E-02 -6.489990E-05 -2.206893E-02 -5.500117E-05 -3.339387E-02 -1.332827E-04 -2.791990E-02 -9.540192E-05 -2.717893E-02 -9.827563E-05 -2.822648E-02 -9.247065E-05 -2.172258E-02 -6.122060E-05 -2.728508E-02 -9.267319E-05 -2.826253E-02 -1.031269E-04 -2.187117E-02 -5.283388E-05 -2.020422E-02 -6.258085E-05 -2.760119E-02 -8.854689E-05 -2.549801E-02 -7.868954E-05 -3.220341E-02 -1.492987E-04 -3.173533E-02 -1.221411E-04 -3.585220E-02 -1.462868E-04 -2.903224E-02 -9.451319E-05 -3.829574E-02 -1.873248E-04 -3.086935E-02 -1.256218E-04 -3.176725E-02 -1.374912E-04 -2.621060E-02 -7.855573E-05 -3.291329E-02 -1.248943E-04 -2.777869E-02 -9.696220E-05 -2.695184E-02 -8.169195E-05 -3.242055E-02 -1.203522E-04 -3.779282E-02 -1.712919E-04 -3.692252E-02 -1.722327E-04 -2.748845E-02 -9.639756E-05 -3.175151E-02 -1.162038E-04 -3.286221E-02 -1.232662E-04 -3.712727E-02 -1.594838E-04 -4.431598E-02 -2.588766E-04 -2.816960E-02 -9.502113E-05 -2.976286E-02 -1.142861E-04 -2.180841E-02 -6.585707E-05 -2.719208E-02 -8.542344E-05 -3.801560E-02 -1.668348E-04 -3.413937E-02 -1.429112E-04 -3.175514E-02 -1.235214E-04 -4.203652E-02 -2.192502E-04 -4.877746E-02 -2.744258E-04 -5.692679E-02 -3.692246E-04 -4.818489E-02 -2.687441E-04 -5.535578E-02 -3.290118E-04 -3.156612E-02 -1.123567E-04 -2.679829E-02 -7.787807E-05 -2.954264E-02 -1.270123E-04 -2.476226E-02 -8.030343E-05 -3.814973E-02 -1.578272E-04 -4.016143E-02 -2.884730E-04 -4.229195E-02 -2.061337E-04 -2.947005E-02 -1.041482E-04 -3.357567E-02 -1.360735E-04 -4.664871E-02 -2.552612E-04 -4.112621E-02 -2.176987E-04 -3.595856E-02 -1.956542E-04 -1.913431E-02 -5.063581E-05 -2.330523E-02 -6.230393E-05 -2.045993E-02 -5.592751E-05 -2.473756E-02 -7.625570E-05 -3.674309E-02 -1.672365E-04 -3.204595E-02 -1.157121E-04 -2.629494E-02 -8.519728E-05 -3.002442E-02 -1.205283E-04 -3.236353E-02 -1.309526E-04 -3.239381E-02 -1.479481E-04 -2.659107E-02 -1.086535E-04 -3.565570E-02 -1.622239E-04 -1.031682E-02 -1.492807E-05 -1.580618E-02 -2.893579E-05 -1.666675E-02 -4.393186E-05 -2.024456E-02 -4.734254E-05 -1.651767E-02 -4.977631E-05 -1.887559E-02 -4.409518E-05 -1.508773E-02 -4.644738E-05 -1.388725E-02 -2.554677E-05 -2.369485E-02 -7.387938E-05 -1.868167E-02 -4.664973E-05 -1.516685E-02 -3.321346E-05 -1.963316E-02 -4.662537E-05 -7.052241E-03 -1.080582E-05 -1.204334E-02 -2.356212E-05 -7.618798E-03 -1.308303E-05 -1.218334E-02 -2.230559E-05 -1.192185E-02 -2.127660E-05 -1.044557E-02 -1.520178E-05 -4.348002E-03 -4.867274E-06 -9.181379E-03 -1.456359E-05 -8.481267E-03 -1.556887E-05 -5.867984E-03 -5.323949E-06 -1.523208E-02 -3.002171E-05 -8.902081E-03 -1.728737E-05 -1.212351E-02 -2.267329E-05 -1.158769E-02 -1.826918E-05 -5.557893E-03 -6.873951E-06 -1.030077E-02 -1.814127E-05 -1.216476E-02 -2.168097E-05 -1.280341E-02 -2.462766E-05 -7.553244E-03 -7.549456E-06 -9.275611E-03 -9.489655E-06 -7.606773E-03 -8.958010E-06 -9.160622E-03 -1.424787E-05 -1.133109E-02 -1.611610E-05 -7.409008E-03 -1.208115E-05 -2.084102E-02 -5.449907E-05 -2.465743E-02 -1.037751E-04 -2.310657E-02 -6.292924E-05 -2.801769E-02 -8.512445E-05 -2.049117E-02 -6.630728E-05 -1.395829E-02 -3.118581E-05 -2.735901E-02 -9.218170E-05 -2.177632E-02 -5.817883E-05 -1.932991E-02 -6.388604E-05 -2.326591E-02 -8.330336E-05 -2.546379E-02 -9.605909E-05 -1.830716E-02 -5.090147E-05 -3.960142E-02 -1.859660E-04 -2.348343E-02 -6.600054E-05 -2.909393E-02 -1.040812E-04 -3.586926E-02 -1.451039E-04 -2.269127E-02 -6.430762E-05 -2.691696E-02 -8.449728E-05 -4.229624E-02 -2.362055E-04 -4.471419E-02 -2.231402E-04 -3.407449E-02 -1.370223E-04 -3.586700E-02 -1.483496E-04 -3.803403E-02 -1.652852E-04 -3.820565E-02 -1.619415E-04 -2.921534E-02 -1.128913E-04 -4.098638E-02 -1.981151E-04 -3.611801E-02 -1.596274E-04 -4.036543E-02 -1.787815E-04 -3.018584E-02 -1.080246E-04 -4.026732E-02 -1.932383E-04 -4.637639E-02 -3.369042E-04 -4.901208E-02 -2.912517E-04 -5.221514E-02 -2.936532E-04 -5.298382E-02 -3.167761E-04 -4.141488E-02 -1.913012E-04 -5.078383E-02 -2.957356E-04 -3.104830E-02 -1.114729E-04 -4.570836E-02 -2.306958E-04 -2.697314E-02 -8.551540E-05 -3.590745E-02 -1.369825E-04 -4.416767E-02 -2.348955E-04 -3.878026E-02 -1.683331E-04 -3.635274E-02 -1.469492E-04 -5.095760E-02 -3.033151E-04 -5.419363E-02 -3.231656E-04 -6.111133E-02 -4.092896E-04 -5.080100E-02 -2.813520E-04 -6.152776E-02 -4.073105E-04 -3.751766E-02 -1.468483E-04 -3.277827E-02 -1.186335E-04 -3.710633E-02 -1.751177E-04 -5.323020E-02 -3.420073E-04 -3.201431E-02 -1.550803E-04 -5.882138E-02 -4.307388E-04 -4.562728E-02 -2.741025E-04 -4.436946E-02 -2.582142E-04 -4.128151E-02 -1.889531E-04 -5.761773E-02 -4.256437E-04 -4.986009E-02 -2.652036E-04 -5.753376E-02 -3.668636E-04 -3.464308E-02 -1.308318E-04 -3.597366E-02 -1.880711E-04 -3.783475E-02 -1.677422E-04 -4.507477E-02 -2.257889E-04 -3.512550E-02 -1.623708E-04 -4.440361E-02 -2.237977E-04 -4.763862E-02 -2.507592E-04 -4.245582E-02 -2.037194E-04 -3.865696E-02 -1.809637E-04 -4.216341E-02 -1.962900E-04 -5.099828E-02 -2.952246E-04 -5.108812E-02 -2.920996E-04 -2.655713E-02 -8.104377E-05 -3.189652E-02 -1.226231E-04 -3.163248E-02 -1.587616E-04 -2.509589E-02 -9.570491E-05 -4.297892E-02 -2.277676E-04 -3.642828E-02 -1.647058E-04 -3.007066E-02 -1.231652E-04 -3.132243E-02 -1.486680E-04 -3.188231E-02 -1.196363E-04 -4.753178E-02 -2.731076E-04 -2.908004E-02 -1.035304E-04 -2.727262E-02 -9.600226E-05 -1.855747E-02 -5.837677E-05 -2.435306E-02 -7.097335E-05 -2.204917E-02 -6.488149E-05 -2.268670E-02 -6.926881E-05 -2.470896E-02 -8.507493E-05 -2.736268E-02 -9.366711E-05 -1.453619E-02 -2.821293E-05 -1.989468E-02 -5.291966E-05 -2.569258E-02 -8.578609E-05 -2.226465E-02 -6.565828E-05 -2.252517E-02 -7.081452E-05 -1.855256E-02 -4.738776E-05 -1.203698E-02 -2.579555E-05 -1.218962E-02 -2.270495E-05 -1.171765E-02 -2.354905E-05 -8.779187E-03 -1.212571E-05 -1.425888E-02 -2.553189E-05 -1.169957E-02 -2.644501E-05 -1.052860E-02 -1.949914E-05 -5.907471E-03 -5.068540E-06 -1.275403E-02 -2.624760E-05 -1.148436E-02 -1.794213E-05 -1.018673E-02 -1.501340E-05 -1.783660E-02 -4.785080E-05 -1.016197E-02 -2.293166E-05 -8.941927E-03 -1.192991E-05 -6.602581E-03 -1.272161E-05 -1.174062E-02 -2.147543E-05 -1.526300E-02 -3.260204E-05 -1.686817E-02 -4.102027E-05 -1.467939E-02 -2.968059E-05 -1.601430E-02 -4.562808E-05 -9.165391E-03 -2.688624E-05 -9.663957E-03 -1.372277E-05 -1.287992E-02 -2.365195E-05 -9.579531E-03 -1.375180E-05 -2.469585E-02 -8.049487E-05 -2.845287E-02 -1.112732E-04 -1.767051E-02 -4.658157E-05 -2.485448E-02 -9.432058E-05 -1.238872E-02 -2.846828E-05 -1.889711E-02 -4.468197E-05 -3.099403E-02 -1.059405E-04 -2.259916E-02 -7.077471E-05 -2.695314E-02 -9.575430E-05 -2.211342E-02 -5.413822E-05 -2.224612E-02 -7.249655E-05 -1.773084E-02 -4.592694E-05 -3.194210E-02 -1.064003E-04 -2.971760E-02 -9.736956E-05 -3.499652E-02 -1.826230E-04 -4.850239E-02 -2.738683E-04 -3.305773E-02 -1.168139E-04 -3.506155E-02 -1.587282E-04 -3.676758E-02 -1.484870E-04 -4.676291E-02 -2.525569E-04 -3.590431E-02 -1.478484E-04 -3.835973E-02 -1.689943E-04 -4.592471E-02 -2.353405E-04 -4.213441E-02 -2.024568E-04 -4.148586E-02 -1.780338E-04 -4.501161E-02 -2.189422E-04 -4.546973E-02 -2.294416E-04 -5.445339E-02 -3.211478E-04 -4.091696E-02 -1.919828E-04 -4.547941E-02 -2.523329E-04 -5.386399E-02 -3.097517E-04 -5.805028E-02 -3.886410E-04 -4.323647E-02 -2.210891E-04 -5.481511E-02 -3.380385E-04 -5.588950E-02 -3.728116E-04 -4.521068E-02 -2.655202E-04 -4.323965E-02 -1.976109E-04 -4.853174E-02 -2.734839E-04 -5.925107E-02 -4.092840E-04 -6.126965E-02 -3.889545E-04 -5.496039E-02 -3.536070E-04 -5.043703E-02 -3.116190E-04 -5.642187E-02 -3.765290E-04 -6.063856E-02 -4.379295E-04 -5.195487E-02 -3.214080E-04 -6.938655E-02 -5.412456E-04 -6.384563E-02 -4.345441E-04 -7.340916E-02 -5.829419E-04 -4.160832E-02 -1.915303E-04 -4.400244E-02 -2.364017E-04 -5.387088E-02 -3.278923E-04 -5.794972E-02 -3.768932E-04 -4.823866E-02 -2.869653E-04 -5.581812E-02 -3.628216E-04 -5.507172E-02 -3.230172E-04 -6.302356E-02 -4.527401E-04 -5.707918E-02 -3.888513E-04 -4.754358E-02 -2.594617E-04 -6.541199E-02 -4.781326E-04 -6.028104E-02 -4.146449E-04 -3.451579E-02 -1.431485E-04 -3.241942E-02 -1.223581E-04 -4.685494E-02 -2.525308E-04 -4.111890E-02 -2.121316E-04 -4.153961E-02 -1.996497E-04 -5.816750E-02 -3.609870E-04 -3.677652E-02 -1.668470E-04 -4.696518E-02 -2.600495E-04 -3.377120E-02 -1.501347E-04 -4.376838E-02 -2.325356E-04 -5.222808E-02 -3.054620E-04 -5.928320E-02 -4.267763E-04 -2.991812E-02 -1.056949E-04 -3.616946E-02 -1.524179E-04 -3.177703E-02 -1.168362E-04 -4.705585E-02 -2.646056E-04 -3.665252E-02 -1.695105E-04 -4.766781E-02 -2.674389E-04 -3.202832E-02 -1.073493E-04 -2.751650E-02 -9.309837E-05 -4.818224E-02 -2.392320E-04 -3.403290E-02 -1.418131E-04 -4.574016E-02 -2.354785E-04 -4.773050E-02 -2.476124E-04 -1.973857E-02 -5.421533E-05 -2.110340E-02 -6.009155E-05 -2.365572E-02 -6.648519E-05 -2.131581E-02 -5.365256E-05 -2.548189E-02 -8.296044E-05 -2.738380E-02 -8.103041E-05 -1.857273E-02 -4.206503E-05 -2.430428E-02 -7.766038E-05 -1.413939E-02 -2.821225E-05 -2.111430E-02 -5.198944E-05 -2.690085E-02 -9.577166E-05 -3.477173E-02 -1.518451E-04 -1.694126E-02 -4.610916E-05 -1.802237E-02 -4.677578E-05 -1.547843E-02 -3.071140E-05 -1.258621E-02 -2.676730E-05 -1.480772E-02 -2.870448E-05 -1.612853E-02 -3.275094E-05 -1.269558E-02 -2.294471E-05 -1.222544E-02 -1.845380E-05 -1.456829E-02 -3.311358E-05 -9.857513E-03 -1.669207E-05 -1.626604E-02 -4.458605E-05 -1.611973E-02 -3.998382E-05 -1.971005E-02 -6.046116E-05 -1.431380E-02 -2.594436E-05 -1.824132E-02 -5.495026E-05 -1.868711E-02 -5.257059E-05 -1.452558E-02 -2.646510E-05 -1.767521E-02 -4.157062E-05 -1.224286E-02 -2.048681E-05 -1.303634E-02 -2.950766E-05 -1.330541E-02 -2.767230E-05 -1.068270E-02 -1.441894E-05 -1.784826E-02 -4.556976E-05 -1.384211E-02 -2.825659E-05 -1.729138E-02 -3.675164E-05 -2.243899E-02 -6.004831E-05 -2.715655E-02 -9.746046E-05 -2.570504E-02 -8.920071E-05 -1.697516E-02 -3.974905E-05 -1.660121E-02 -3.254815E-05 -2.224450E-02 -5.768880E-05 -2.530951E-02 -9.164893E-05 -1.840321E-02 -4.291921E-05 -2.017760E-02 -6.034117E-05 -2.049468E-02 -4.717679E-05 -2.282381E-02 -6.631028E-05 -2.767431E-02 -8.578573E-05 -3.024946E-02 -1.035261E-04 -3.587885E-02 -1.385980E-04 -4.511890E-02 -2.188810E-04 -2.993143E-02 -1.172685E-04 -4.054681E-02 -1.947113E-04 -3.798858E-02 -1.756458E-04 -4.431323E-02 -2.215003E-04 -3.189602E-02 -1.184446E-04 -3.858052E-02 -1.789441E-04 -4.477428E-02 -2.243938E-04 -4.703586E-02 -2.423313E-04 -3.435009E-02 -1.302766E-04 -4.912269E-02 -2.876019E-04 -3.586050E-02 -1.601671E-04 -5.202288E-02 -2.962633E-04 -4.354503E-02 -2.302813E-04 -4.484413E-02 -2.193914E-04 -4.626090E-02 -2.295773E-04 -5.272085E-02 -3.140576E-04 -4.016476E-02 -1.851520E-04 -4.698312E-02 -2.700090E-04 -7.091623E-02 -6.301431E-04 -4.767851E-02 -2.507174E-04 -4.786618E-02 -2.609399E-04 -4.038170E-02 -1.767402E-04 -4.773992E-02 -2.552553E-04 -6.553326E-02 -4.533702E-04 -4.409668E-02 -2.246932E-04 -5.516788E-02 -3.459366E-04 -5.575453E-02 -3.327095E-04 -6.234876E-02 -4.350389E-04 -4.468174E-02 -2.279110E-04 -5.066531E-02 -2.919067E-04 -7.038547E-02 -5.211120E-04 -6.314941E-02 -4.264819E-04 -4.552569E-02 -2.253455E-04 -4.441783E-02 -2.383583E-04 -5.471130E-02 -3.515655E-04 -5.570461E-02 -3.610859E-04 -4.732130E-02 -2.515536E-04 -5.830395E-02 -4.045076E-04 -4.928927E-02 -2.534507E-04 -4.443354E-02 -2.155311E-04 -4.739067E-02 -2.296684E-04 -4.805589E-02 -2.422571E-04 -6.278404E-02 -4.449155E-04 -6.952048E-02 -5.145532E-04 -2.516418E-02 -7.500451E-05 -3.118980E-02 -1.112167E-04 -4.421923E-02 -2.460515E-04 -4.297090E-02 -2.413819E-04 -3.779702E-02 -1.857046E-04 -5.299210E-02 -3.257368E-04 -4.026655E-02 -1.807099E-04 -4.206085E-02 -2.256535E-04 -4.079656E-02 -1.987081E-04 -3.610266E-02 -1.649391E-04 -4.381846E-02 -2.263935E-04 -4.980200E-02 -2.864882E-04 -2.860174E-02 -1.712915E-04 -2.445643E-02 -1.020759E-04 -3.878477E-02 -2.026049E-04 -2.480236E-02 -6.838491E-05 -2.734325E-02 -9.461308E-05 -3.693833E-02 -1.822458E-04 -2.490103E-02 -7.329360E-05 -2.677818E-02 -8.305017E-05 -3.264724E-02 -1.437491E-04 -3.715999E-02 -2.239488E-04 -2.373224E-02 -6.329401E-05 -3.900048E-02 -1.863015E-04 -1.125664E-02 -2.181811E-05 -2.161924E-02 -7.195899E-05 -1.744174E-02 -4.273755E-05 -1.238666E-02 -2.145334E-05 -2.141496E-02 -5.796334E-05 -3.027096E-02 -9.721558E-05 -2.034339E-02 -5.581306E-05 -1.730093E-02 -4.542569E-05 -2.661993E-02 -8.452374E-05 -2.161864E-02 -5.465888E-05 -1.450249E-02 -2.452960E-05 -2.302180E-02 -6.121219E-05 -6.340596E-03 -5.499932E-06 -9.140384E-03 -1.585008E-05 -1.397492E-02 -2.598945E-05 -1.189682E-02 -2.167082E-05 -1.311861E-02 -2.016097E-05 -1.750898E-02 -4.671329E-05 -9.795781E-03 -1.975542E-05 -1.094278E-02 -1.976709E-05 -1.639501E-02 -3.446322E-05 -7.320291E-03 -7.206036E-06 -1.849111E-02 -4.335473E-05 -1.434342E-02 -2.991316E-05 -1.167361E-02 -1.759595E-05 -9.859610E-03 -1.289330E-05 -1.133762E-02 -1.561793E-05 -1.865540E-02 -4.343736E-05 -1.350518E-02 -2.129333E-05 -1.358916E-02 -2.271382E-05 -9.345990E-03 -1.288554E-05 -1.065558E-02 -1.661140E-05 -8.770677E-03 -1.373474E-05 -1.321675E-02 -2.139500E-05 -1.306520E-02 -2.539346E-05 -1.129556E-02 -2.247168E-05 -2.256971E-02 -6.489740E-05 -2.030940E-02 -5.625582E-05 -2.024779E-02 -5.494975E-05 -1.906346E-02 -4.047418E-05 -2.207434E-02 -6.757473E-05 -1.730595E-02 -3.788068E-05 -2.519625E-02 -9.116269E-05 -2.094102E-02 -5.386236E-05 -2.252706E-02 -7.123740E-05 -2.249589E-02 -6.348244E-05 -1.677894E-02 -4.502916E-05 -1.191569E-02 -2.092636E-05 -3.193092E-02 -1.066907E-04 -3.474315E-02 -1.354003E-04 -3.428457E-02 -1.357392E-04 -5.095478E-02 -3.135854E-04 -2.785938E-02 -1.094102E-04 -2.524070E-02 -7.421058E-05 -3.410453E-02 -1.325498E-04 -4.419349E-02 -2.287531E-04 -3.121966E-02 -1.145504E-04 -3.172565E-02 -1.576778E-04 -3.732684E-02 -1.794004E-04 -2.798822E-02 -9.904213E-05 -3.829890E-02 -1.745254E-04 -3.669187E-02 -1.481631E-04 -3.831832E-02 -1.640348E-04 -4.717292E-02 -2.431524E-04 -3.246900E-02 -1.090875E-04 -3.181397E-02 -1.110646E-04 -3.422430E-02 -1.455143E-04 -4.595899E-02 -2.593546E-04 -2.943781E-02 -1.144304E-04 -4.083225E-02 -2.153138E-04 -4.861114E-02 -2.668189E-04 -4.566953E-02 -2.275971E-04 -4.762605E-02 -2.702276E-04 -3.885235E-02 -1.678236E-04 -4.746492E-02 -2.732016E-04 -6.187919E-02 -3.977228E-04 -3.385168E-02 -1.655806E-04 -3.779606E-02 -1.742919E-04 -4.344441E-02 -2.144777E-04 -4.983722E-02 -2.780628E-04 -3.805659E-02 -1.869986E-04 -3.881150E-02 -1.693755E-04 -5.243613E-02 -3.131126E-04 -4.108551E-02 -1.935253E-04 -3.562260E-02 -1.423362E-04 -3.787549E-02 -1.654425E-04 -4.885818E-02 -2.578691E-04 -5.332653E-02 -3.213342E-04 -4.348495E-02 -2.331286E-04 -4.663540E-02 -2.474672E-04 -3.285731E-02 -1.375774E-04 -4.576846E-02 -2.311007E-04 -3.184404E-02 -1.192332E-04 -3.998156E-02 -1.844262E-04 -5.607513E-02 -3.422109E-04 -4.953587E-02 -2.676057E-04 -3.693477E-02 -1.700381E-04 -2.948894E-02 -1.003101E-04 -5.540578E-02 -3.851845E-04 -5.314370E-02 -3.109412E-04 -4.109329E-02 -1.998923E-04 -5.093669E-02 -3.059425E-04 -4.209028E-02 -2.361378E-04 -4.465662E-02 -2.120794E-04 -2.708725E-02 -9.631361E-05 -3.635562E-02 -1.595262E-04 -4.238804E-02 -1.947726E-04 -3.974596E-02 -1.806688E-04 -2.982744E-02 -1.207685E-04 -3.283297E-02 -1.354648E-04 -3.271957E-02 -1.397951E-04 -2.724542E-02 -1.015777E-04 -3.609538E-02 -1.698517E-04 -3.335710E-02 -1.624664E-04 -2.079895E-02 -5.610101E-05 -2.603309E-02 -9.493586E-05 -2.597898E-02 -9.783976E-05 -3.135251E-02 -1.402609E-04 -2.775791E-02 -9.666104E-05 -3.244893E-02 -1.414683E-04 -1.736161E-02 -4.120267E-05 -2.103660E-02 -6.662057E-05 -2.254942E-02 -6.127994E-05 -2.617237E-02 -9.655322E-05 -1.879302E-02 -4.046759E-05 -2.239207E-02 -7.270900E-05 -1.582884E-02 -3.421542E-05 -1.701627E-02 -3.287993E-05 -1.586730E-02 -3.071759E-05 -1.637662E-02 -4.285548E-05 -1.575516E-02 -2.967636E-05 -1.749637E-02 -4.429182E-05 -1.377991E-02 -2.869990E-05 -1.666042E-02 -3.900259E-05 -1.590173E-02 -4.041443E-05 -1.533466E-02 -3.740187E-05 -1.242820E-02 -2.230617E-05 -2.005763E-02 -5.559139E-05 -1.888435E-02 -5.293569E-05 -1.437606E-02 -2.992754E-05 -1.160735E-02 -2.488650E-05 -1.903862E-02 -4.929965E-05 -1.792944E-02 -4.623131E-05 -1.925927E-02 -4.967790E-05 -1.197483E-02 -1.865556E-05 -7.572584E-03 -1.282465E-05 -1.344056E-02 -2.673348E-05 -1.049282E-02 -1.487580E-05 -1.018581E-02 -1.491092E-05 -9.650534E-03 -1.458568E-05 -7.696745E-03 -8.956471E-06 -6.117465E-03 -6.145859E-06 -7.711888E-03 -1.379326E-05 -7.178538E-03 -8.529096E-06 -7.013352E-03 -9.358596E-06 -5.223833E-03 -4.743484E-06 -1.958755E-02 -5.840140E-05 -1.514889E-02 -3.048083E-05 -1.420009E-02 -3.392782E-05 -1.779423E-02 -4.000672E-05 -9.916829E-03 -1.600897E-05 -1.084516E-02 -1.883449E-05 -1.721403E-02 -3.892250E-05 -1.697631E-02 -5.336366E-05 -1.126561E-02 -1.779695E-05 -1.183784E-02 -2.042908E-05 -1.279900E-02 -2.278884E-05 -1.221352E-02 -2.185990E-05 -2.126137E-02 -5.259427E-05 -1.948422E-02 -7.413728E-05 -2.691940E-02 -7.987754E-05 -2.366460E-02 -7.849119E-05 -1.493129E-02 -3.458121E-05 -2.528845E-02 -7.805956E-05 -1.941301E-02 -4.532019E-05 -3.315469E-02 -1.407045E-04 -1.764622E-02 -4.338977E-05 -1.952377E-02 -5.147550E-05 -2.600704E-02 -9.058738E-05 -2.442799E-02 -7.377464E-05 -2.298511E-02 -6.212241E-05 -2.519641E-02 -9.638931E-05 -3.975880E-02 -1.694798E-04 -3.835063E-02 -1.723954E-04 -2.433477E-02 -7.177972E-05 -2.711003E-02 -1.279711E-04 -3.083661E-02 -1.018837E-04 -4.207502E-02 -2.089394E-04 -2.844391E-02 -9.560578E-05 -2.835547E-02 -8.648090E-05 -5.190679E-02 -2.829647E-04 -3.607591E-02 -1.406622E-04 -2.726024E-02 -9.295552E-05 -2.334992E-02 -7.837059E-05 -2.556006E-02 -8.066549E-05 -3.157571E-02 -1.018377E-04 -2.717890E-02 -9.754656E-05 -3.812328E-02 -1.529731E-04 -3.196833E-02 -1.246738E-04 -3.749985E-02 -1.546562E-04 -1.861417E-02 -4.193655E-05 -2.827800E-02 -8.681001E-05 -3.521111E-02 -1.537273E-04 -3.631214E-02 -1.510528E-04 -3.010902E-02 -1.101278E-04 -2.898513E-02 -1.002289E-04 -3.759216E-02 -1.686797E-04 -3.924809E-02 -1.926092E-04 -3.000742E-02 -1.032469E-04 -3.063104E-02 -1.058005E-04 -3.016836E-02 -1.406736E-04 -3.811226E-02 -2.142070E-04 -3.067660E-02 -1.137129E-04 -2.919174E-02 -9.744001E-05 -4.351818E-02 -2.481411E-04 -3.459089E-02 -1.418237E-04 -2.354519E-02 -7.125933E-05 -2.341512E-02 -7.530145E-05 -3.423411E-02 -1.362388E-04 -3.807351E-02 -1.835906E-04 -3.060066E-02 -1.306426E-04 -3.887634E-02 -1.767107E-04 -2.972630E-02 -1.452173E-04 -2.761804E-02 -8.313790E-05 -2.564981E-02 -1.041595E-04 -2.302814E-02 -5.748532E-05 -3.430159E-02 -1.266003E-04 -3.080546E-02 -1.097842E-04 -1.862840E-02 -4.692046E-05 -2.212362E-02 -5.769304E-05 -3.055531E-02 -1.529521E-04 -2.289574E-02 -8.233761E-05 -2.656172E-02 -8.446802E-05 -3.583300E-02 -1.541747E-04 -2.557682E-02 -7.916517E-05 -2.097606E-02 -5.055022E-05 -2.228757E-02 -5.988269E-05 -1.816051E-02 -3.901578E-05 -2.325555E-02 -7.127170E-05 -2.918248E-02 -1.039399E-04 -1.305527E-02 -2.604090E-05 -1.318002E-02 -2.893713E-05 -1.574393E-02 -3.521171E-05 -1.414192E-02 -3.552473E-05 -1.633140E-02 -3.849962E-05 -1.643542E-02 -4.093687E-05 -1.215108E-02 -2.596067E-05 -1.663208E-02 -4.623828E-05 -1.519499E-02 -2.784484E-05 -1.392851E-02 -2.190759E-05 -2.267580E-02 -6.466320E-05 -2.215409E-02 -7.872980E-05 -1.106097E-02 -1.935578E-05 -1.318957E-02 -2.458468E-05 -1.432387E-02 -2.771689E-05 -1.302310E-02 -2.533330E-05 -1.818189E-02 -4.776340E-05 -1.401528E-02 -2.698770E-05 -3.589051E-03 -3.157955E-06 -9.717553E-03 -1.921247E-05 -8.432737E-03 -1.168760E-05 -8.867899E-03 -2.125223E-05 -1.176987E-02 -2.796774E-05 -1.387858E-02 -2.900888E-05 -7.333775E-03 -9.493537E-06 -5.494780E-03 -7.270347E-06 -8.505259E-03 -1.106187E-05 -5.349113E-03 -6.272249E-06 -7.278213E-03 -7.362414E-06 -8.521400E-03 -1.020574E-05 -8.308309E-03 -1.075116E-05 -8.167064E-03 -1.109423E-05 -5.533013E-03 -6.466675E-06 -5.112442E-03 -8.851249E-06 -5.870076E-03 -6.648936E-06 -3.929558E-03 -2.494118E-06 -1.248728E-02 -2.662149E-05 -7.689572E-03 -1.632791E-05 -1.064286E-02 -1.731638E-05 -8.865827E-03 -2.182318E-05 -1.060594E-02 -1.974250E-05 -1.107000E-02 -1.741690E-05 -1.046576E-02 -1.304525E-05 -8.923758E-03 -1.382295E-05 -6.048588E-03 -6.515013E-06 -1.140457E-02 -1.772344E-05 -1.071605E-02 -2.320839E-05 -1.108521E-02 -2.146136E-05 -1.372658E-02 -3.150815E-05 -1.185879E-02 -2.592177E-05 -1.328057E-02 -2.007755E-05 -2.366818E-02 -6.240710E-05 -1.310524E-02 -2.483124E-05 -1.756288E-02 -3.846799E-05 -1.953925E-02 -4.224682E-05 -2.714173E-02 -9.200317E-05 -2.089836E-02 -5.417932E-05 -1.880252E-02 -4.633361E-05 -1.825440E-02 -4.676871E-05 -1.703893E-02 -3.290578E-05 -1.536560E-02 -2.501324E-05 -1.723409E-02 -4.375407E-05 -2.378506E-02 -6.856927E-05 -2.116439E-02 -5.565273E-05 -1.694042E-02 -5.241605E-05 -1.860566E-02 -4.783232E-05 -1.867229E-02 -4.443429E-05 -2.347238E-02 -6.225289E-05 -1.240017E-02 -2.472321E-05 -1.834566E-02 -5.076889E-05 -2.345212E-02 -6.899204E-05 -1.744726E-02 -4.012671E-05 -2.139472E-02 -5.719986E-05 -2.881782E-02 -1.041089E-04 -2.249258E-02 -6.622191E-05 -3.099210E-02 -1.124327E-04 -2.723683E-02 -1.077003E-04 -2.961326E-02 -1.107622E-04 -2.886855E-02 -1.209198E-04 -3.359957E-02 -1.450335E-04 -1.842677E-02 -4.144114E-05 -2.067987E-02 -5.241403E-05 -2.384292E-02 -8.392423E-05 -2.523377E-02 -7.399318E-05 -1.482060E-02 -2.934033E-05 -1.685267E-02 -4.268337E-05 -2.474266E-02 -6.858025E-05 -2.464842E-02 -7.502593E-05 -1.931712E-02 -6.623063E-05 -2.571146E-02 -8.499419E-05 -1.919509E-02 -5.019677E-05 -2.194688E-02 -6.974387E-05 -2.021151E-02 -5.705824E-05 -1.939673E-02 -5.393718E-05 -2.366200E-02 -7.358565E-05 -3.181441E-02 -1.136270E-04 -1.839678E-02 -3.699144E-05 -1.988625E-02 -6.005553E-05 -2.730155E-02 -9.038604E-05 -1.977072E-02 -5.242521E-05 -1.499223E-02 -2.966075E-05 -2.040274E-02 -6.508672E-05 -1.411627E-02 -2.586129E-05 -1.706927E-02 -3.713346E-05 -1.171754E-02 -1.971987E-05 -2.013780E-02 -5.939024E-05 -2.029685E-02 -6.146855E-05 -2.908889E-02 -1.037204E-04 -1.740582E-02 -3.597993E-05 -1.564902E-02 -6.335090E-05 -1.991302E-02 -4.746765E-05 -1.756837E-02 -4.867597E-05 -2.061727E-02 -6.000022E-05 -2.574876E-02 -8.243095E-05 -1.191200E-02 -1.934272E-05 -2.009666E-02 -4.813195E-05 -1.746764E-02 -5.388627E-05 -1.239022E-02 -2.424386E-05 -2.173442E-02 -4.983400E-05 -1.517203E-02 -3.068246E-05 -1.329712E-02 -2.150332E-05 -2.354363E-02 -8.627378E-05 -1.532883E-02 -3.270327E-05 -1.472157E-02 -3.319558E-05 -1.938773E-02 -4.827508E-05 -2.165397E-02 -6.469989E-05 -1.271540E-02 -1.967861E-05 -1.665138E-02 -4.718665E-05 -9.283413E-03 -1.143878E-05 -1.046201E-02 -2.072362E-05 -1.673621E-02 -3.707353E-05 -1.445073E-02 -2.924329E-05 -7.634313E-03 -1.179099E-05 -7.070615E-03 -8.043539E-06 -1.155338E-02 -1.871310E-05 -8.618350E-03 -1.431974E-05 -9.424572E-03 -1.207411E-05 -8.545662E-03 -1.247473E-05 -3.838707E-03 -4.805334E-06 -5.882837E-03 -4.922359E-06 -8.145896E-03 -1.250575E-05 -5.962503E-03 -5.532809E-06 -1.116529E-02 -3.223331E-05 -1.080742E-02 -1.791118E-05 -4.327838E-03 -3.722361E-06 -3.132066E-03 -2.831681E-06 -5.985652E-03 -5.243244E-06 -6.402910E-03 -9.755445E-06 -5.996163E-03 -1.017758E-05 -7.516797E-03 -1.133864E-05 -1.109701E-03 -5.874266E-07 -3.145346E-03 -2.131176E-06 -3.071793E-03 -3.203751E-06 -5.112008E-03 -6.623440E-06 -1.057799E-02 -2.219886E-05 -4.499437E-03 -4.252659E-06 -8.765798E-03 -1.784490E-05 -8.921959E-03 -1.351279E-05 -7.502480E-03 -1.202219E-05 -7.196379E-03 -9.204669E-06 -5.832796E-03 -1.016451E-05 -7.038191E-03 -6.254164E-06 -9.382421E-03 -1.566041E-05 -1.345656E-02 -3.028211E-05 -6.337258E-03 -7.407982E-06 -8.543843E-03 -1.265584E-05 -1.381261E-02 -2.802183E-05 -1.190749E-02 -1.793613E-05 -9.437321E-03 -1.194730E-05 -9.732419E-03 -1.651545E-05 -1.500610E-02 -3.340884E-05 -1.678411E-02 -3.491286E-05 -1.028094E-02 -1.374135E-05 -1.485088E-02 -3.057123E-05 -8.964661E-03 -1.485585E-05 -1.226822E-02 -2.015578E-05 -1.042577E-02 -1.589161E-05 -6.708855E-03 -9.646613E-06 -1.277453E-02 -2.203458E-05 -7.224932E-03 -8.275023E-06 -1.255069E-02 -2.759249E-05 -1.234545E-02 -2.557302E-05 -1.676381E-02 -3.443801E-05 -2.225843E-02 -7.382383E-05 -9.664194E-03 -1.388455E-05 -1.384208E-02 -2.485536E-05 -1.170741E-02 -2.722875E-05 -1.298519E-02 -2.278333E-05 -1.219523E-02 -2.170852E-05 -1.455145E-02 -2.652917E-05 -1.803860E-02 -4.551654E-05 -1.716760E-02 -3.418763E-05 -1.512094E-02 -3.308210E-05 -1.040105E-02 -1.595604E-05 -1.796769E-02 -3.949154E-05 -1.872289E-02 -4.103439E-05 -9.077191E-03 -1.199908E-05 -1.631540E-02 -3.369350E-05 -1.526935E-02 -3.456559E-05 -2.236068E-02 -7.214380E-05 -8.845141E-03 -2.279004E-05 -1.352347E-02 -2.540469E-05 -1.484395E-02 -3.807417E-05 -1.804445E-02 -4.342710E-05 -1.007944E-02 -1.452963E-05 -1.467548E-02 -4.429846E-05 -2.042873E-02 -5.671423E-05 -1.758792E-02 -5.925658E-05 -1.761311E-02 -4.685220E-05 -2.004514E-02 -5.536859E-05 -1.238507E-02 -2.340619E-05 -1.046525E-02 -1.737035E-05 -1.444879E-02 -3.355825E-05 -8.277840E-03 -1.437311E-05 -1.079506E-02 -1.848135E-05 -1.561308E-02 -4.224535E-05 -1.137179E-02 -2.608300E-05 -1.280633E-02 -2.210100E-05 -1.162328E-02 -2.231053E-05 -1.296251E-02 -2.730055E-05 -1.389949E-02 -3.026765E-05 -1.411889E-02 -3.201101E-05 -8.232902E-03 -1.404323E-05 -1.242929E-02 -2.465073E-05 -9.545643E-03 -1.867285E-05 -9.740853E-03 -1.452865E-05 -1.306805E-02 -2.407394E-05 -1.010373E-02 -1.920540E-05 -8.546938E-03 -1.818086E-05 -9.873382E-03 -2.146517E-05 -1.643827E-02 -5.513889E-05 -1.117018E-02 -2.390203E-05 -9.216643E-03 -1.323340E-05 -1.434946E-02 -2.862359E-05 -1.245343E-02 -2.322243E-05 -1.212911E-02 -2.285075E-05 -9.836707E-03 -1.645734E-05 -1.201364E-02 -2.024192E-05 -1.596859E-02 -3.442108E-05 -1.368837E-02 -2.688655E-05 -1.015380E-02 -1.592459E-05 -9.892082E-03 -1.321377E-05 -1.360812E-02 -3.262388E-05 -1.003913E-02 -1.400775E-05 -1.478387E-02 -3.871602E-05 -9.205053E-03 -1.179337E-05 -9.383339E-03 -1.300416E-05 -7.080640E-03 -8.203597E-06 -6.507205E-03 -7.055020E-06 -8.843528E-03 -1.233759E-05 -1.087757E-02 -1.436248E-05 -9.075363E-03 -1.538346E-05 -4.079253E-03 -4.032406E-06 -6.146524E-03 -1.072823E-05 -7.605892E-03 -2.021674E-05 -6.737771E-03 -8.340942E-06 -7.791360E-03 -1.322504E-05 -4.367729E-03 -5.871757E-06 -5.112041E-03 -7.704614E-06 -6.685377E-03 -8.598228E-06 -5.332365E-03 -6.964174E-06 -2.025949E-03 -1.106713E-06 -7.308916E-03 -1.083527E-05 -2.657078E-03 -2.018754E-06 -3.845964E-03 -3.282949E-06 -7.906876E-03 -1.309640E-05 -3.020084E-03 -2.116323E-06 -4.987032E-03 -5.707520E-06 -1.202747E-02 -3.060476E-05 -7.093728E-03 -7.508046E-06 -7.422432E-03 -8.656078E-06 -9.077236E-03 -2.478476E-05 -6.891522E-03 -1.220166E-05 -5.076941E-03 -4.237107E-06 -8.523515E-03 -1.390735E-05 -6.414767E-03 -9.365735E-06 -9.380022E-03 -1.462751E-05 -8.456230E-03 -1.199551E-05 -9.158278E-03 -1.192449E-05 -2.298967E-03 -1.013954E-06 -7.058890E-03 -6.383597E-06 -4.876567E-03 -3.760010E-06 -1.316587E-02 -2.644816E-05 -8.359774E-03 -1.081163E-05 -1.469243E-02 -3.486053E-05 -7.460324E-03 -7.746075E-06 -7.025833E-03 -7.150545E-06 -4.599519E-03 -5.621223E-06 -1.754686E-02 -5.599449E-05 -8.496819E-03 -1.519010E-05 -1.334303E-02 -2.243087E-05 -1.273838E-02 -2.372539E-05 -1.041534E-02 -2.066977E-05 -9.140508E-03 -1.075841E-05 -1.657971E-02 -4.469598E-05 -1.247039E-02 -2.906265E-05 -1.297140E-02 -2.473045E-05 -1.664008E-02 -4.158991E-05 -1.836946E-02 -4.883353E-05 -1.411162E-02 -4.313628E-05 -1.406170E-02 -2.454496E-05 -2.270767E-02 -6.143414E-05 -1.567617E-02 -3.204306E-05 -1.611804E-02 -3.752055E-05 -1.312188E-02 -2.232058E-05 -1.726062E-02 -4.888466E-05 -2.260453E-02 -5.912727E-05 -2.295104E-02 -7.305721E-05 -2.082979E-02 -5.212405E-05 -3.139636E-02 -1.124507E-04 -1.701985E-02 -5.917730E-05 -1.573079E-02 -3.833147E-05 -1.648501E-02 -4.521319E-05 -1.295769E-02 -2.000518E-05 -1.538561E-02 -3.581006E-05 -2.113104E-02 -5.954145E-05 -1.269260E-02 -1.914463E-05 -1.597644E-02 -2.898818E-05 -1.749472E-02 -4.995488E-05 -1.170597E-02 -2.494586E-05 -1.972148E-02 -5.486069E-05 -2.930071E-02 -1.089599E-04 -1.284182E-02 -2.296682E-05 -1.568134E-02 -3.876494E-05 -1.557912E-02 -3.819947E-05 -1.760851E-02 -3.904704E-05 -1.450774E-02 -4.086604E-05 -1.375807E-02 -3.319496E-05 -1.290194E-02 -2.142172E-05 -1.402767E-02 -2.932888E-05 -1.769773E-02 -4.995015E-05 -1.419402E-02 -3.040909E-05 -1.675459E-02 -3.235864E-05 -1.976178E-02 -5.009760E-05 -1.675838E-02 -3.910658E-05 -1.689170E-02 -3.464763E-05 -1.284022E-02 -2.649261E-05 -1.316325E-02 -2.377493E-05 -1.455084E-02 -2.510139E-05 -1.102459E-02 -1.885880E-05 -8.350866E-03 -8.396386E-06 -8.651131E-03 -1.124192E-05 -1.376705E-02 -2.764081E-05 -1.428569E-02 -3.790437E-05 -1.724679E-02 -3.366818E-05 -1.584053E-02 -3.651487E-05 -1.193033E-02 -2.181873E-05 -1.984626E-02 -5.592598E-05 -1.214395E-02 -1.945894E-05 -1.365596E-02 -2.557166E-05 -1.898643E-02 -5.157604E-05 -1.455388E-02 -2.799320E-05 -1.182403E-02 -2.115918E-05 -8.626630E-03 -1.007433E-05 -1.197781E-02 -1.983881E-05 -1.005772E-02 -1.640145E-05 -1.873799E-02 -4.930639E-05 -1.693176E-02 -3.650659E-05 -8.818286E-03 -1.286259E-05 -1.139988E-02 -1.621095E-05 -1.028933E-02 -1.453198E-05 -8.404568E-03 -9.460915E-06 -1.275744E-02 -2.774096E-05 -1.168183E-02 -1.973529E-05 -8.454758E-03 -1.146522E-05 -8.323601E-03 -8.829709E-06 -7.495546E-03 -8.715799E-06 -5.296323E-03 -6.046794E-06 -9.891852E-03 -1.398584E-05 -9.955102E-03 -1.943758E-05 -8.059482E-03 -1.695389E-05 -9.676780E-03 -1.658395E-05 -4.834433E-03 -5.897640E-06 -6.636064E-03 -7.609925E-06 -7.619866E-03 -1.212597E-05 -2.894660E-03 -1.856127E-06 -7.553124E-03 -1.223718E-05 -2.300404E-03 -1.121136E-06 -7.327033E-03 -9.105655E-06 -4.846398E-03 -4.166167E-06 -8.315901E-03 -1.319751E-05 -7.221182E-03 -7.485967E-06 -5.462020E-03 -3.502442E-06 -9.453474E-03 -1.071037E-05 -1.293719E-02 -2.483879E-05 -1.321412E-02 -2.574150E-05 -1.359066E-02 -2.348428E-05 -9.882529E-03 -1.691834E-05 -1.409150E-02 -3.523994E-05 -1.070054E-02 -1.906767E-05 -1.266239E-02 -1.972906E-05 -1.432889E-02 -3.545618E-05 -1.011895E-02 -1.360275E-05 -1.025183E-02 -1.608180E-05 -5.529921E-03 -7.911985E-06 -1.629012E-02 -3.223742E-05 -1.114479E-02 -2.101499E-05 -1.215717E-02 -1.846892E-05 -1.689915E-02 -4.620696E-05 -1.139613E-02 -1.742241E-05 -1.213431E-02 -2.199183E-05 -1.846118E-02 -5.474736E-05 -1.709853E-02 -3.678232E-05 -1.735796E-02 -4.553680E-05 -1.853277E-02 -4.646147E-05 -1.763467E-02 -4.466597E-05 -1.818218E-02 -4.824198E-05 -1.872596E-02 -6.942835E-05 -2.022757E-02 -5.512053E-05 -1.699277E-02 -3.870609E-05 -1.055491E-02 -1.687463E-05 -1.377011E-02 -2.394912E-05 -1.684636E-02 -3.614976E-05 -2.147831E-02 -6.616404E-05 -1.730285E-02 -3.913079E-05 -1.957720E-02 -5.565960E-05 -1.855637E-02 -4.612437E-05 -2.805186E-02 -1.029670E-04 -2.418902E-02 -6.781295E-05 -2.188652E-02 -6.579480E-05 -1.771569E-02 -4.195257E-05 -2.256760E-02 -6.456468E-05 -1.918774E-02 -5.286254E-05 -2.960608E-02 -1.004602E-04 -2.712839E-02 -8.980797E-05 -2.794452E-02 -1.254679E-04 -3.008968E-02 -1.089661E-04 -3.649934E-02 -1.734688E-04 -2.937679E-02 -1.082854E-04 -3.282797E-02 -1.345859E-04 -4.521759E-02 -2.543431E-04 -2.398232E-02 -7.384139E-05 -3.254161E-02 -1.265125E-04 -3.001705E-02 -1.111357E-04 -2.399317E-02 -6.646668E-05 -3.503715E-02 -1.480964E-04 -3.148980E-02 -1.398976E-04 -2.604556E-02 -9.628490E-05 -3.036652E-02 -1.264006E-04 -2.939357E-02 -1.170192E-04 -3.743087E-02 -1.775840E-04 -3.085132E-02 -1.134780E-04 -4.147944E-02 -1.996575E-04 -3.527838E-02 -1.521337E-04 -2.366172E-02 -6.804925E-05 -2.713514E-02 -1.027237E-04 -2.174215E-02 -5.749073E-05 -2.675659E-02 -8.382558E-05 -2.359986E-02 -7.430600E-05 -2.367000E-02 -7.298151E-05 -3.227569E-02 -1.232973E-04 -2.733957E-02 -1.003086E-04 -3.002721E-02 -9.578465E-05 -3.707352E-02 -1.507472E-04 -2.382487E-02 -6.891582E-05 -2.959048E-02 -1.054578E-04 -1.869568E-02 -4.658988E-05 -2.597326E-02 -8.064723E-05 -2.153451E-02 -5.840127E-05 -1.628961E-02 -4.271967E-05 -2.741092E-02 -8.522384E-05 -2.733756E-02 -9.324995E-05 -2.864715E-02 -1.013597E-04 -3.455306E-02 -1.448078E-04 -3.347393E-02 -1.327937E-04 -3.527874E-02 -1.637966E-04 -2.441550E-02 -8.480735E-05 -2.623780E-02 -8.256558E-05 -1.716091E-02 -5.253723E-05 -1.324941E-02 -2.243910E-05 -2.246659E-02 -6.057114E-05 -2.192475E-02 -5.668645E-05 -2.272490E-02 -7.122633E-05 -3.254641E-02 -1.485757E-04 -1.504227E-02 -2.731302E-05 -1.654008E-02 -4.044070E-05 -2.442456E-02 -8.014611E-05 -2.260914E-02 -6.419431E-05 -1.988931E-02 -6.266967E-05 -3.422754E-02 -1.464931E-04 -1.176286E-02 -1.819119E-05 -1.090258E-02 -1.835148E-05 -1.428818E-02 -2.432816E-05 -9.647717E-03 -2.418655E-05 -1.343547E-02 -2.294350E-05 -1.672666E-02 -4.724036E-05 -1.498173E-02 -2.999368E-05 -1.209667E-02 -2.648058E-05 -1.777083E-02 -3.928551E-05 -1.906246E-02 -4.800003E-05 -1.227253E-02 -2.454598E-05 -2.054852E-02 -5.627860E-05 -1.401620E-02 -3.395841E-05 -1.618774E-02 -3.315176E-05 -9.366645E-03 -1.322093E-05 -1.271711E-02 -2.946682E-05 -1.514436E-02 -3.698271E-05 -1.357568E-02 -2.661503E-05 -6.059837E-03 -6.072503E-06 -7.510121E-03 -8.006288E-06 -1.105528E-02 -2.101618E-05 -4.887318E-03 -5.427586E-06 -8.183502E-03 -1.217955E-05 -9.960866E-03 -1.427453E-05 -1.302537E-02 -2.752410E-05 -1.432159E-02 -3.046582E-05 -1.362132E-02 -3.362721E-05 -1.728813E-02 -4.356686E-05 -1.882553E-02 -4.115052E-05 -2.022059E-02 -5.094537E-05 -9.935622E-03 -1.476612E-05 -1.423961E-02 -2.791015E-05 -1.078457E-02 -3.254092E-05 -1.010483E-02 -1.743918E-05 -1.145080E-02 -2.471476E-05 -1.537588E-02 -3.948184E-05 -3.025085E-02 -1.211946E-04 -2.522059E-02 -8.250671E-05 -2.231553E-02 -6.323615E-05 -2.348918E-02 -6.900725E-05 -2.273346E-02 -5.949276E-05 -1.817883E-02 -4.693722E-05 -2.354895E-02 -7.506897E-05 -2.667415E-02 -1.051466E-04 -1.923174E-02 -4.215181E-05 -2.251124E-02 -6.197340E-05 -2.212823E-02 -7.382044E-05 -2.627751E-02 -1.262016E-04 -2.639401E-02 -8.435288E-05 -2.355251E-02 -6.467494E-05 -1.824258E-02 -4.508497E-05 -2.658510E-02 -7.928794E-05 -2.675987E-02 -1.019694E-04 -2.294475E-02 -7.019770E-05 -2.982020E-02 -1.172018E-04 -2.650631E-02 -7.994237E-05 -3.317163E-02 -1.365190E-04 -4.086398E-02 -2.004161E-04 -2.796562E-02 -1.066212E-04 -3.652322E-02 -1.878727E-04 -3.754838E-02 -1.647330E-04 -3.743316E-02 -1.789631E-04 -2.670365E-02 -8.773372E-05 -2.985106E-02 -9.743471E-05 -3.608668E-02 -1.610685E-04 -4.205670E-02 -1.842040E-04 -3.922858E-02 -1.953706E-04 -4.448502E-02 -2.469956E-04 -4.693316E-02 -2.454100E-04 -4.848290E-02 -2.671676E-04 -4.023569E-02 -1.713754E-04 -4.294287E-02 -2.063518E-04 -4.004042E-02 -1.923766E-04 -4.357533E-02 -2.186888E-04 -3.728630E-02 -1.990696E-04 -4.083902E-02 -1.919817E-04 -3.857997E-02 -1.821259E-04 -4.901557E-02 -2.767777E-04 -5.790464E-02 -3.872461E-04 -3.900935E-02 -1.730109E-04 -4.875435E-02 -2.872844E-04 -5.468952E-02 -3.456684E-04 -4.179342E-02 -2.001437E-04 -5.381510E-02 -3.724283E-04 -4.237622E-02 -1.941664E-04 -5.150719E-02 -2.908123E-04 -2.903885E-02 -1.031896E-04 -3.589197E-02 -1.392764E-04 -6.487280E-02 -5.024965E-04 -3.912537E-02 -1.856374E-04 -3.458921E-02 -1.576917E-04 -4.382484E-02 -2.169611E-04 -5.176404E-02 -2.803853E-04 -5.379322E-02 -3.067204E-04 -4.070213E-02 -1.816834E-04 -4.088864E-02 -1.878390E-04 -3.237349E-02 -1.191717E-04 -3.712382E-02 -1.504938E-04 -3.997504E-02 -1.782786E-04 -3.267526E-02 -1.297525E-04 -4.125020E-02 -1.924418E-04 -3.958215E-02 -1.901035E-04 -4.006168E-02 -1.832588E-04 -3.769986E-02 -1.717343E-04 -5.100625E-02 -2.898618E-04 -3.840461E-02 -1.682447E-04 -3.871359E-02 -1.824587E-04 -4.283505E-02 -2.070659E-04 -2.126415E-02 -4.973731E-05 -2.889038E-02 -1.088896E-04 -2.104568E-02 -6.548850E-05 -2.848041E-02 -1.298630E-04 -3.029276E-02 -1.138285E-04 -2.862761E-02 -9.675198E-05 -2.647642E-02 -8.418245E-05 -2.861468E-02 -1.081191E-04 -3.468627E-02 -1.277418E-04 -3.349950E-02 -1.317290E-04 -3.982514E-02 -1.794172E-04 -3.268932E-02 -1.255468E-04 -1.912998E-02 -4.577703E-05 -2.085203E-02 -6.226159E-05 -1.828176E-02 -4.944577E-05 -2.381226E-02 -8.891365E-05 -2.311077E-02 -6.656845E-05 -2.473067E-02 -7.334387E-05 -1.375348E-02 -2.283618E-05 -1.804582E-02 -4.143497E-05 -2.006609E-02 -4.873691E-05 -1.884382E-02 -4.819154E-05 -1.080497E-02 -1.376297E-05 -1.726756E-02 -3.375398E-05 -1.609526E-02 -3.821013E-05 -1.411969E-02 -2.227160E-05 -9.192959E-03 -1.631434E-05 -9.217380E-03 -1.968772E-05 -1.468647E-02 -2.623946E-05 -1.488244E-02 -3.525990E-05 -1.269069E-02 -2.294212E-05 -7.765318E-03 -1.103799E-05 -1.558612E-02 -3.323429E-05 -1.740029E-02 -5.933208E-05 -8.717198E-03 -1.192243E-05 -9.978251E-03 -1.485392E-05 -8.720289E-03 -1.149015E-05 -1.020781E-02 -2.305230E-05 -1.149654E-02 -1.940965E-05 -1.788016E-02 -4.220362E-05 -1.110418E-02 -1.718658E-05 -2.482931E-02 -1.001964E-04 -1.645044E-02 -4.054796E-05 -1.894652E-02 -4.678890E-05 -1.434380E-02 -3.165754E-05 -1.258510E-02 -2.725122E-05 -2.869257E-02 -1.023938E-04 -1.622348E-02 -4.537915E-05 -2.185647E-02 -5.507321E-05 -1.954237E-02 -4.309665E-05 -2.035261E-02 -6.714277E-05 -2.087253E-02 -4.818549E-05 -1.582401E-02 -3.291377E-05 -2.671073E-02 -9.777211E-05 -2.512135E-02 -7.547644E-05 -2.506727E-02 -7.485132E-05 -1.404823E-02 -2.446571E-05 -2.280451E-02 -6.346040E-05 -2.677285E-02 -8.686426E-05 -2.736182E-02 -1.019696E-04 -4.245358E-02 -2.031516E-04 -3.781676E-02 -1.657018E-04 -3.988823E-02 -1.948658E-04 -4.639548E-02 -2.606408E-04 -2.998045E-02 -1.078111E-04 -3.116186E-02 -1.123729E-04 -5.002484E-02 -3.007452E-04 -4.018989E-02 -2.134973E-04 -3.706873E-02 -1.705493E-04 -4.841352E-02 -3.006314E-04 -4.754905E-02 -2.640563E-04 -4.364220E-02 -2.190548E-04 -5.500865E-02 -3.565984E-04 -5.532256E-02 -3.576995E-04 -5.047039E-02 -2.937072E-04 -5.060213E-02 -3.044944E-04 -6.416214E-02 -4.414515E-04 -4.420142E-02 -2.374155E-04 -7.189342E-02 -5.468649E-04 -6.014136E-02 -3.940429E-04 -6.349933E-02 -4.207906E-04 -8.074317E-02 -7.419627E-04 -5.500576E-02 -3.305937E-04 -6.217792E-02 -4.170384E-04 -5.168117E-02 -2.909656E-04 -6.458066E-02 -4.333028E-04 -5.398600E-02 -3.328720E-04 -6.745198E-02 -5.123388E-04 -7.585366E-02 -6.172453E-04 -7.667038E-02 -6.845297E-04 -8.031109E-02 -7.564824E-04 -7.073034E-02 -5.458581E-04 -7.573691E-02 -6.181860E-04 -7.610572E-02 -6.320225E-04 -9.472534E-02 -1.007312E-03 -8.942164E-02 -8.735772E-04 -6.678710E-02 -5.406900E-04 -6.813491E-02 -4.871261E-04 -6.435084E-02 -4.334073E-04 -6.618817E-02 -4.692824E-04 -8.000303E-02 -7.136374E-04 -7.211464E-02 -6.123883E-04 -9.166818E-02 -8.952483E-04 -5.925322E-02 -4.492782E-04 -9.608215E-02 -9.616517E-04 -9.591584E-02 -9.489183E-04 -6.551541E-02 -4.745820E-04 -9.550949E-02 -9.531681E-04 -5.425472E-02 -3.720953E-04 -6.247517E-02 -4.393993E-04 -5.896488E-02 -4.002445E-04 -5.123472E-02 -2.943668E-04 -7.803224E-02 -6.809156E-04 -6.717709E-02 -5.320659E-04 -4.752627E-02 -2.528912E-04 -4.731481E-02 -2.339422E-04 -6.377650E-02 -5.060539E-04 -6.343027E-02 -4.521666E-04 -5.104223E-02 -3.253849E-04 -6.842536E-02 -5.197571E-04 -3.944396E-02 -2.024706E-04 -3.774197E-02 -1.745573E-04 -3.016158E-02 -1.057402E-04 -2.940171E-02 -1.161392E-04 -5.428473E-02 -3.726778E-04 -3.466389E-02 -1.374879E-04 -2.493688E-02 -9.144503E-05 -4.409357E-02 -2.282136E-04 -3.898092E-02 -1.692947E-04 -4.161525E-02 -2.078651E-04 -4.453363E-02 -2.219554E-04 -4.844461E-02 -2.561895E-04 -1.992414E-02 -5.397706E-05 -1.350002E-02 -2.916535E-05 -2.067487E-02 -4.903837E-05 -2.325603E-02 -8.788747E-05 -2.013029E-02 -5.389647E-05 -3.203793E-02 -1.247710E-04 -1.965175E-02 -5.312061E-05 -2.463239E-02 -8.315266E-05 -2.236927E-02 -6.414213E-05 -2.615164E-02 -7.702130E-05 -3.011875E-02 -1.090074E-04 -3.242536E-02 -1.289377E-04 -1.086798E-02 -1.760814E-05 -1.502391E-02 -3.139067E-05 -2.028244E-02 -5.583147E-05 -1.735464E-02 -4.295725E-05 -1.595857E-02 -2.787063E-05 -2.051018E-02 -5.355572E-05 -1.177619E-02 -1.717906E-05 -1.084749E-02 -1.707026E-05 -1.825630E-02 -5.376844E-05 -1.670967E-02 -3.402950E-05 -1.517723E-02 -3.554202E-05 -2.351000E-02 -7.935893E-05 -1.408337E-02 -2.327322E-05 -1.414777E-02 -2.697883E-05 -1.345682E-02 -2.740309E-05 -1.807340E-02 -5.667578E-05 -1.943061E-02 -4.787161E-05 -1.781260E-02 -6.060590E-05 -1.822299E-02 -4.962172E-05 -2.071085E-02 -5.813369E-05 -1.228031E-02 -2.872901E-05 -1.195238E-02 -1.942759E-05 -2.092949E-02 -5.642842E-05 -1.529365E-02 -3.149749E-05 -2.339941E-02 -7.277783E-05 -2.913166E-02 -1.578357E-04 -1.733543E-02 -4.484055E-05 -2.332788E-02 -5.763144E-05 -2.815285E-02 -1.152065E-04 -2.037972E-02 -4.949376E-05 -3.118074E-02 -1.103084E-04 -2.652943E-02 -7.950175E-05 -2.821700E-02 -9.085185E-05 -2.985586E-02 -1.075718E-04 -2.519195E-02 -7.329635E-05 -2.548988E-02 -7.800201E-05 -4.334204E-02 -2.354327E-04 -4.370525E-02 -2.090531E-04 -4.006925E-02 -2.178363E-04 -4.954585E-02 -2.700073E-04 -4.092841E-02 -2.238665E-04 -2.776415E-02 -8.914334E-05 -4.493102E-02 -2.333231E-04 -5.357023E-02 -3.291447E-04 -3.963439E-02 -1.816002E-04 -5.209753E-02 -3.068180E-04 -4.986170E-02 -2.874548E-04 -4.594257E-02 -2.466016E-04 -7.630622E-02 -6.261797E-04 -5.881534E-02 -3.747957E-04 -6.780811E-02 -4.976784E-04 -8.984762E-02 -8.898655E-04 -5.491164E-02 -3.345133E-04 -5.735501E-02 -3.771763E-04 -7.877228E-02 -6.794994E-04 -9.906424E-02 -1.046741E-03 -5.785970E-02 -4.133043E-04 -7.848689E-02 -6.870125E-04 -1.047444E-01 -1.223298E-03 -7.404855E-02 -5.854937E-04 -9.032228E-02 -8.427419E-04 -8.401933E-02 -7.146695E-04 -8.655196E-02 -8.118612E-04 -1.130946E-01 -1.398959E-03 -9.597180E-02 -1.024696E-03 -1.173027E-01 -1.427372E-03 -1.057440E-01 -1.169551E-03 -1.236176E-01 -1.570398E-03 -1.126957E-01 -1.332155E-03 -1.492376E-01 -2.275171E-03 -1.540101E-01 -2.443893E-03 -1.715020E-01 -3.018404E-03 -7.291542E-02 -5.897697E-04 -7.660305E-02 -6.300479E-04 -9.197170E-02 -8.994110E-04 -9.982203E-02 -1.045655E-03 -1.033399E-01 -1.152382E-03 -1.139526E-01 -1.408827E-03 -8.350520E-02 -7.494750E-04 -9.839459E-02 -1.011369E-03 -1.077860E-01 -1.279212E-03 -1.228340E-01 -1.621769E-03 -1.144053E-01 -1.334188E-03 -1.571539E-01 -2.565349E-03 -6.233439E-02 -4.263330E-04 -6.563411E-02 -5.048147E-04 -6.507814E-02 -4.812141E-04 -6.362658E-02 -4.417375E-04 -7.986988E-02 -7.190156E-04 -8.970255E-02 -8.714050E-04 -5.717855E-02 -3.416545E-04 -5.668804E-02 -3.415895E-04 -7.197316E-02 -5.676520E-04 -7.136224E-02 -5.599617E-04 -8.054458E-02 -7.445675E-04 -1.023397E-01 -1.107780E-03 -4.458142E-02 -2.130924E-04 -5.439535E-02 -3.275861E-04 -5.080989E-02 -2.798307E-04 -3.946665E-02 -1.879310E-04 -6.271593E-02 -4.257844E-04 -4.965993E-02 -2.741721E-04 -4.221851E-02 -1.992549E-04 -3.585135E-02 -1.543110E-04 -4.558668E-02 -2.566453E-04 -3.888908E-02 -1.783945E-04 -4.502379E-02 -2.492156E-04 -5.625550E-02 -3.626058E-04 -2.128686E-02 -5.310350E-05 -2.848081E-02 -1.032351E-04 -3.198369E-02 -1.191780E-04 -3.220035E-02 -1.276802E-04 -3.463447E-02 -1.270326E-04 -3.109004E-02 -1.168059E-04 -2.332999E-02 -6.452643E-05 -2.117480E-02 -5.228816E-05 -2.838827E-02 -1.161483E-04 -2.329241E-02 -6.809020E-05 -2.459549E-02 -7.138168E-05 -2.765800E-02 -9.045558E-05 -1.370243E-02 -3.338519E-05 -1.582736E-02 -3.857108E-05 -1.914636E-02 -4.789559E-05 -1.905516E-02 -4.419778E-05 -1.810520E-02 -3.877471E-05 -2.115307E-02 -7.229884E-05 -1.882956E-02 -4.805493E-05 -9.281049E-03 -1.409203E-05 -1.706945E-02 -3.299567E-05 -2.172381E-02 -5.595328E-05 -1.104074E-02 -1.584618E-05 -1.946919E-02 -4.863958E-05 -1.238685E-02 -2.066688E-05 -1.378714E-02 -2.843856E-05 -1.670520E-02 -3.555438E-05 -2.766185E-02 -9.046517E-05 -1.691132E-02 -3.290270E-05 -1.927098E-02 -5.061316E-05 -1.202893E-02 -1.958457E-05 -1.922540E-02 -4.323737E-05 -1.274015E-02 -2.175309E-05 -1.524415E-02 -3.024778E-05 -1.567541E-02 -4.050037E-05 -1.898211E-02 -6.605988E-05 -2.223387E-02 -5.741257E-05 -2.452031E-02 -8.066778E-05 -2.491977E-02 -8.109453E-05 -2.610295E-02 -7.731723E-05 -1.803031E-02 -3.613025E-05 -2.184838E-02 -6.008277E-05 -2.576522E-02 -7.561914E-05 -3.038022E-02 -1.150600E-04 -2.471237E-02 -7.123333E-05 -3.173089E-02 -1.261453E-04 -3.197437E-02 -1.411443E-04 -2.786611E-02 -8.928073E-05 -4.565549E-02 -2.352807E-04 -3.535175E-02 -1.583088E-04 -4.110758E-02 -2.035220E-04 -5.345474E-02 -3.515666E-04 -3.820824E-02 -1.563980E-04 -3.254512E-02 -1.163872E-04 -4.763741E-02 -2.544110E-04 -5.216626E-02 -2.867256E-04 -4.162668E-02 -2.258042E-04 -5.349959E-02 -3.167588E-04 -5.268155E-02 -3.037455E-04 -4.827712E-02 -2.530854E-04 -7.203623E-02 -5.807994E-04 -5.256504E-02 -2.870331E-04 -7.227033E-02 -5.557721E-04 -8.778648E-02 -8.961223E-04 -5.726539E-02 -3.647823E-04 -5.856701E-02 -3.711206E-04 -8.418818E-02 -8.420171E-04 -1.110902E-01 -1.311451E-03 -6.849413E-02 -4.990580E-04 -8.795189E-02 -8.053436E-04 -1.002509E-01 -1.136773E-03 -8.057346E-02 -7.326604E-04 -8.129820E-02 -6.905078E-04 -7.847809E-02 -7.619983E-04 -9.737274E-02 -1.035174E-03 -1.154716E-01 -1.385047E-03 -9.040089E-02 -8.570313E-04 -1.211664E-01 -1.547158E-03 -1.031330E-01 -1.146280E-03 -1.249586E-01 -1.649464E-03 -7.259655E-02 -5.736210E-04 -9.951286E-02 -1.046118E-03 -1.634971E-01 -2.756448E-03 -1.297207E-01 -1.735289E-03 -6.477036E-02 -5.010788E-04 -7.479236E-02 -6.145152E-04 -9.983365E-02 -1.091064E-03 -1.057264E-01 -1.249917E-03 -8.524281E-02 -7.807948E-04 -1.159165E-01 -1.434680E-03 -7.914697E-02 -6.791950E-04 -9.369015E-02 -9.476358E-04 -9.819988E-02 -1.022095E-03 -9.686028E-02 -1.016599E-03 -1.294766E-01 -1.810274E-03 -1.296189E-01 -1.785443E-03 -5.535491E-02 -4.100726E-04 -5.475647E-02 -3.309264E-04 -7.075605E-02 -6.187772E-04 -6.387417E-02 -4.196497E-04 -7.578685E-02 -6.019889E-04 -8.903112E-02 -9.119475E-04 -6.385945E-02 -4.650950E-04 -5.390120E-02 -3.165606E-04 -5.744329E-02 -3.580388E-04 -5.920600E-02 -3.893593E-04 -7.525234E-02 -6.092966E-04 -8.573764E-02 -7.942436E-04 -2.797792E-02 -8.517754E-05 -3.790894E-02 -1.764825E-04 -4.239936E-02 -2.094748E-04 -4.003024E-02 -1.918379E-04 -5.137956E-02 -3.003587E-04 -3.883708E-02 -2.005906E-04 -2.858632E-02 -9.126637E-05 -3.012004E-02 -9.617653E-05 -4.160100E-02 -1.981616E-04 -4.247458E-02 -1.951666E-04 -3.989011E-02 -1.920698E-04 -5.270057E-02 -4.088719E-04 -1.934929E-02 -4.412789E-05 -2.359082E-02 -7.371994E-05 -2.394998E-02 -6.675994E-05 -2.637339E-02 -8.517554E-05 -2.328326E-02 -6.212789E-05 -3.651578E-02 -1.464186E-04 -2.140441E-02 -5.613878E-05 -2.241671E-02 -6.918410E-05 -2.337122E-02 -6.432183E-05 -2.144477E-02 -6.203786E-05 -3.024192E-02 -1.083505E-04 -3.331930E-02 -1.347081E-04 -1.564695E-02 -3.553327E-05 -1.812645E-02 -3.940659E-05 -2.235798E-02 -6.269701E-05 -1.419345E-02 -3.096864E-05 -2.228629E-02 -7.578567E-05 -1.860794E-02 -4.332178E-05 -1.533239E-02 -3.896858E-05 -1.580257E-02 -3.874692E-05 -2.185955E-02 -7.842950E-05 -1.195136E-02 -1.715334E-05 -1.691111E-02 -5.345113E-05 -1.575376E-02 -3.654434E-05 -1.594875E-02 -2.957220E-05 -1.223541E-02 -2.476765E-05 -1.370590E-02 -2.764042E-05 -2.661246E-02 -1.016998E-04 -2.080371E-02 -4.813282E-05 -2.468736E-02 -6.974038E-05 -1.405638E-02 -2.572385E-05 -2.459760E-02 -7.159383E-05 -1.228308E-02 -1.773752E-05 -1.017949E-02 -1.885833E-05 -2.024611E-02 -5.718430E-05 -1.797631E-02 -4.281825E-05 -1.570780E-02 -3.056781E-05 -1.271841E-02 -2.456995E-05 -2.932023E-02 -9.261980E-05 -3.237241E-02 -1.211680E-04 -2.105195E-02 -5.549955E-05 -2.483667E-02 -7.162437E-05 -2.011907E-02 -5.130375E-05 -1.983609E-02 -4.987791E-05 -1.492495E-02 -3.087968E-05 -2.870495E-02 -9.962637E-05 -2.722358E-02 -8.845542E-05 -2.118986E-02 -5.204535E-05 -4.348038E-02 -2.209404E-04 -3.712818E-02 -1.689129E-04 -4.138693E-02 -1.981821E-04 -4.470777E-02 -2.289185E-04 -2.764424E-02 -9.090079E-05 -2.655560E-02 -9.474172E-05 -4.524862E-02 -2.292538E-04 -5.164196E-02 -2.774634E-04 -3.466551E-02 -1.631603E-04 -3.563208E-02 -1.379234E-04 -4.211986E-02 -1.930478E-04 -3.079625E-02 -1.135265E-04 -5.465211E-02 -3.301887E-04 -4.860409E-02 -2.888426E-04 -7.075978E-02 -5.108370E-04 -6.867881E-02 -5.424435E-04 -3.427613E-02 -1.426574E-04 -5.955830E-02 -3.940963E-04 -6.828982E-02 -4.738886E-04 -6.525289E-02 -4.898769E-04 -3.737982E-02 -1.638396E-04 -5.286730E-02 -3.082087E-04 -6.158083E-02 -4.216724E-04 -4.980750E-02 -2.726737E-04 -5.696575E-02 -3.692634E-04 -5.058820E-02 -2.744701E-04 -6.726109E-02 -4.926664E-04 -7.839336E-02 -6.590448E-04 -7.010209E-02 -5.719905E-04 -8.384171E-02 -7.652328E-04 -6.937383E-02 -5.168671E-04 -9.468263E-02 -9.868090E-04 -5.004326E-02 -2.785169E-04 -6.606152E-02 -4.541359E-04 -9.675798E-02 -1.063286E-03 -7.230289E-02 -5.573682E-04 -6.543974E-02 -5.078440E-04 -5.267920E-02 -3.176937E-04 -8.194553E-02 -6.982175E-04 -9.613453E-02 -1.079846E-03 -6.113228E-02 -4.004864E-04 -8.522953E-02 -7.810809E-04 -5.316859E-02 -3.091340E-04 -7.827195E-02 -6.540396E-04 -5.463776E-02 -3.503148E-04 -5.071284E-02 -3.191021E-04 -8.557140E-02 -7.639230E-04 -7.700044E-02 -6.547991E-04 -5.105846E-02 -2.888427E-04 -5.004859E-02 -2.887941E-04 -5.147919E-02 -3.256217E-04 -5.538533E-02 -3.360110E-04 -6.140039E-02 -4.129538E-04 -5.936836E-02 -4.315037E-04 -4.930384E-02 -2.889606E-04 -4.619680E-02 -2.419601E-04 -4.445739E-02 -2.331544E-04 -4.824154E-02 -2.469526E-04 -6.974394E-02 -5.056104E-04 -6.084953E-02 -3.932556E-04 -3.577286E-02 -1.452599E-04 -3.166228E-02 -1.303590E-04 -3.862777E-02 -1.632780E-04 -3.916934E-02 -1.779181E-04 -3.625045E-02 -1.745839E-04 -4.231134E-02 -2.225093E-04 -3.359703E-02 -1.419870E-04 -4.006089E-02 -1.707049E-04 -3.658866E-02 -1.730857E-04 -3.341254E-02 -1.297042E-04 -4.263417E-02 -2.215026E-04 -3.955323E-02 -1.921082E-04 -2.174079E-02 -5.222197E-05 -2.442434E-02 -8.243601E-05 -2.914443E-02 -1.214208E-04 -1.824800E-02 -4.893719E-05 -3.091152E-02 -1.051207E-04 -2.972565E-02 -1.063333E-04 -3.002196E-02 -1.026816E-04 -1.967353E-02 -5.819743E-05 -2.921034E-02 -1.035681E-04 -2.329404E-02 -7.915033E-05 -2.537416E-02 -9.811049E-05 -2.636605E-02 -8.177530E-05 -9.035064E-03 -1.555651E-05 -1.655675E-02 -4.002782E-05 -1.372662E-02 -3.244904E-05 -1.311878E-02 -2.619244E-05 -1.611214E-02 -3.084313E-05 -1.574836E-02 -3.450927E-05 -7.693366E-03 -1.606361E-05 -1.135596E-02 -1.801519E-05 -1.342059E-02 -2.516888E-05 -1.160985E-02 -2.390704E-05 -1.383386E-02 -2.800471E-05 -1.971360E-02 -8.842562E-05 -1.183879E-02 -1.932907E-05 -8.105380E-03 -1.234549E-05 -1.271210E-02 -2.405656E-05 -1.537131E-02 -3.137697E-05 -1.591997E-02 -3.769775E-05 -1.088552E-02 -1.713348E-05 -1.515322E-02 -3.039160E-05 -1.275379E-02 -2.585038E-05 -8.475047E-03 -1.032301E-05 -1.017506E-02 -2.019761E-05 -1.192565E-02 -2.149550E-05 -8.221048E-03 -8.986302E-06 -1.307738E-02 -2.107929E-05 -1.086073E-02 -1.558009E-05 -2.199295E-02 -5.739512E-05 -1.994568E-02 -5.494728E-05 -1.534082E-02 -3.625194E-05 -1.764761E-02 -4.067341E-05 -1.796742E-02 -4.680639E-05 -2.032190E-02 -5.017032E-05 -1.749541E-02 -4.866856E-05 -1.732369E-02 -4.955885E-05 -1.681732E-02 -3.837118E-05 -1.769405E-02 -5.487143E-05 -2.888259E-02 -1.026998E-04 -2.098585E-02 -6.932453E-05 -3.313341E-02 -1.351006E-04 -3.207197E-02 -1.295024E-04 -2.459220E-02 -8.336446E-05 -2.450985E-02 -6.648377E-05 -3.117162E-02 -1.195002E-04 -4.003079E-02 -2.123347E-04 -2.176609E-02 -6.269817E-05 -2.994428E-02 -1.235590E-04 -3.524085E-02 -1.599016E-04 -2.408409E-02 -6.486120E-05 -4.186261E-02 -1.804413E-04 -4.461985E-02 -2.229520E-04 -3.815900E-02 -1.674626E-04 -4.651996E-02 -2.353452E-04 -4.372936E-02 -2.126895E-04 -3.471725E-02 -1.536658E-04 -3.777496E-02 -1.682954E-04 -4.542053E-02 -2.887036E-04 -3.302349E-02 -1.252640E-04 -3.007472E-02 -1.103699E-04 -4.167073E-02 -1.843542E-04 -3.435406E-02 -1.576055E-04 -5.142055E-02 -2.840339E-04 -4.459791E-02 -2.437118E-04 -5.240798E-02 -3.061931E-04 -6.184982E-02 -3.987655E-04 -4.185540E-02 -2.035740E-04 -4.274424E-02 -1.929214E-04 -4.853301E-02 -2.820023E-04 -7.063952E-02 -5.492235E-04 -4.633212E-02 -2.687210E-04 -5.821695E-02 -3.976817E-04 -6.625094E-02 -4.940422E-04 -6.129214E-02 -4.099540E-04 -3.772075E-02 -1.660719E-04 -3.714570E-02 -1.541156E-04 -4.493005E-02 -2.310471E-04 -4.557412E-02 -2.432878E-04 -4.065422E-02 -1.871281E-04 -5.417420E-02 -3.505844E-04 -3.708658E-02 -1.717372E-04 -5.130291E-02 -3.077258E-04 -3.417926E-02 -1.492890E-04 -3.377463E-02 -1.256710E-04 -5.369283E-02 -3.432927E-04 -4.836021E-02 -2.588228E-04 -3.269371E-02 -1.286374E-04 -2.896989E-02 -1.123018E-04 -4.848291E-02 -2.612160E-04 -4.333314E-02 -2.292463E-04 -3.759979E-02 -1.680559E-04 -5.061237E-02 -2.724683E-04 -3.926039E-02 -1.797325E-04 -3.938137E-02 -1.851970E-04 -3.570566E-02 -1.506562E-04 -4.159909E-02 -2.157074E-04 -5.099360E-02 -2.844970E-04 -4.605309E-02 -2.508391E-04 -2.500341E-02 -7.363724E-05 -3.039879E-02 -1.123549E-04 -3.534598E-02 -1.698480E-04 -3.702744E-02 -1.486744E-04 -3.410129E-02 -1.365716E-04 -3.991621E-02 -1.846954E-04 -3.186334E-02 -1.158884E-04 -3.268754E-02 -1.178259E-04 -2.428429E-02 -7.876563E-05 -2.495449E-02 -7.906081E-05 -3.551756E-02 -1.519603E-04 -3.018593E-02 -9.724962E-05 -2.032098E-02 -4.781656E-05 -3.017998E-02 -1.313561E-04 -2.424929E-02 -6.480258E-05 -1.950042E-02 -4.417513E-05 -2.943418E-02 -9.948664E-05 -2.707621E-02 -1.035208E-04 -1.957350E-02 -4.711947E-05 -1.583335E-02 -2.891313E-05 -2.972335E-02 -1.047751E-04 -1.739423E-02 -4.376709E-05 -1.705633E-02 -3.892027E-05 -2.121975E-02 -5.891607E-05 -1.002146E-02 -2.339078E-05 -1.405706E-02 -3.175594E-05 -1.011207E-02 -1.585291E-05 -1.573069E-02 -3.554827E-05 -1.518567E-02 -3.047833E-05 -1.617187E-02 -3.397385E-05 -7.920296E-03 -1.026935E-05 -1.007121E-02 -1.858100E-05 -1.510615E-02 -3.313591E-05 -8.793659E-03 -1.446961E-05 -1.205856E-02 -2.648093E-05 -8.862721E-03 -1.309660E-05 -1.096965E-02 -1.673476E-05 -9.547722E-03 -1.233633E-05 -1.206088E-02 -1.968307E-05 -1.373042E-02 -2.332622E-05 -7.956349E-03 -9.952553E-06 -1.135126E-02 -2.254375E-05 -8.206639E-03 -1.278801E-05 -8.323868E-03 -9.465618E-06 -5.007925E-03 -3.901625E-06 -1.175607E-02 -2.482648E-05 -1.115574E-02 -1.628158E-05 -1.194446E-02 -2.092004E-05 -1.597054E-02 -4.823093E-05 -2.068463E-02 -6.502935E-05 -1.091363E-02 -1.741992E-05 -1.977283E-02 -6.091082E-05 -1.302782E-02 -3.043481E-05 -9.410139E-03 -1.600990E-05 -2.280622E-02 -8.006568E-05 -1.891920E-02 -4.976676E-05 -1.429805E-02 -3.039093E-05 -1.718931E-02 -4.113244E-05 -1.888654E-02 -4.574971E-05 -1.694065E-02 -4.597734E-05 -2.282444E-02 -7.094719E-05 -1.988920E-02 -4.882297E-05 -2.742750E-02 -8.906026E-05 -2.101679E-02 -5.924755E-05 -1.895054E-02 -4.827704E-05 -1.764949E-02 -3.979458E-05 -2.040100E-02 -5.014728E-05 -2.987304E-02 -1.026215E-04 -1.943000E-02 -5.159278E-05 -2.438024E-02 -8.804424E-05 -1.861542E-02 -5.122973E-05 -2.192303E-02 -7.333728E-05 -2.042748E-02 -5.322568E-05 -1.860799E-02 -4.480883E-05 -2.511896E-02 -8.995213E-05 -2.543363E-02 -7.306514E-05 -2.559384E-02 -7.149326E-05 -2.813173E-02 -8.655606E-05 -1.981717E-02 -5.094262E-05 -3.244910E-02 -1.169817E-04 -2.278981E-02 -6.510336E-05 -2.089376E-02 -5.410560E-05 -4.419213E-02 -2.403809E-04 -3.061708E-02 -1.062702E-04 -2.717980E-02 -8.418003E-05 -2.722963E-02 -1.052169E-04 -3.623076E-02 -1.607841E-04 -3.979211E-02 -1.939688E-04 -2.474544E-02 -8.590714E-05 -3.372593E-02 -1.249071E-04 -2.961528E-02 -1.048999E-04 -3.445466E-02 -1.406914E-04 -2.454390E-02 -6.874037E-05 -2.368906E-02 -7.545364E-05 -3.410678E-02 -1.304264E-04 -2.229870E-02 -5.686464E-05 -2.886351E-02 -1.132080E-04 -2.149789E-02 -5.426448E-05 -3.009295E-02 -1.146713E-04 -3.196558E-02 -1.284969E-04 -2.870373E-02 -1.154291E-04 -2.864913E-02 -1.010245E-04 -2.270198E-02 -5.519665E-05 -2.760090E-02 -9.328867E-05 -2.484231E-02 -7.506549E-05 -2.750137E-02 -8.791015E-05 -3.435235E-02 -1.548738E-04 -2.827137E-02 -9.747974E-05 -2.704164E-02 -8.477548E-05 -3.021819E-02 -1.103214E-04 -3.294793E-02 -1.535995E-04 -4.645100E-02 -2.665607E-04 -1.872361E-02 -5.132776E-05 -2.760454E-02 -9.345927E-05 -3.258565E-02 -1.242178E-04 -3.666600E-02 -1.621867E-04 -2.545558E-02 -7.466531E-05 -2.185810E-02 -5.238791E-05 -3.105333E-02 -1.301601E-04 -3.170709E-02 -1.068496E-04 -1.858402E-02 -4.089794E-05 -2.136675E-02 -8.120782E-05 -2.443102E-02 -6.744651E-05 -2.220457E-02 -6.176678E-05 -2.702281E-02 -8.511652E-05 -2.446488E-02 -7.312450E-05 -2.589652E-02 -8.029643E-05 -2.337286E-02 -6.920676E-05 -2.906370E-02 -9.769604E-05 -1.361898E-02 -2.599329E-05 -1.718829E-02 -4.532911E-05 -2.553342E-02 -8.882028E-05 -1.945946E-02 -5.218395E-05 -1.097230E-02 -2.337563E-05 -2.298715E-02 -7.077749E-05 -2.181520E-02 -7.357036E-05 -1.664629E-02 -3.440840E-05 -1.886608E-02 -6.788750E-05 -1.789466E-02 -3.954208E-05 -1.813733E-02 -4.477178E-05 -1.319469E-02 -3.100847E-05 -1.940763E-02 -6.158493E-05 -1.149667E-02 -1.737857E-05 -2.405005E-02 -9.854391E-05 -1.421017E-02 -2.890108E-05 -1.029738E-02 -1.683759E-05 -1.065410E-02 -1.640087E-05 -9.811218E-03 -1.720212E-05 -1.158507E-02 -1.760286E-05 -1.432482E-02 -2.834073E-05 -3.465902E-03 -3.161524E-06 -1.038868E-02 -2.168047E-05 -1.116866E-02 -1.793978E-05 -8.524850E-03 -9.322322E-06 -1.237537E-02 -3.617368E-05 -1.465218E-02 -3.350573E-05 -7.514724E-03 -9.368017E-06 -2.560189E-03 -1.617445E-06 -8.383240E-03 -1.252593E-05 -9.446758E-03 -1.648768E-05 -7.696663E-03 -8.060991E-06 -9.311783E-03 -1.189977E-05 -6.939672E-03 -8.850888E-06 -5.252459E-03 -4.564362E-06 -7.234899E-03 -1.328951E-05 -8.665099E-03 -1.300142E-05 -9.793568E-03 -2.082520E-05 -8.825280E-03 -1.579613E-05 -1.194803E-02 -1.908193E-05 -1.074524E-02 -2.172388E-05 -1.481905E-02 -2.964893E-05 -1.294498E-02 -3.011738E-05 -8.115330E-03 -1.173017E-05 -1.093458E-02 -1.599591E-05 -1.415025E-02 -2.928045E-05 -8.999567E-03 -1.238982E-05 -7.873894E-03 -9.521432E-06 -7.526246E-03 -7.594924E-06 -1.349525E-02 -3.958103E-05 -1.459461E-02 -3.194364E-05 -1.198421E-02 -2.138597E-05 -1.015128E-02 -1.539096E-05 -1.747797E-02 -3.561184E-05 -2.401867E-02 -7.148091E-05 -1.586654E-02 -3.323231E-05 -1.800611E-02 -4.401522E-05 -1.463450E-02 -2.989044E-05 -1.683853E-02 -3.902727E-05 -1.359168E-02 -2.739250E-05 -9.625117E-03 -1.469220E-05 -1.294386E-02 -2.799895E-05 -1.103469E-02 -2.133672E-05 -1.869882E-02 -4.772681E-05 -1.503975E-02 -2.896451E-05 -1.677894E-02 -4.314601E-05 -2.258467E-02 -1.041456E-04 -1.878411E-02 -4.558049E-05 -1.310146E-02 -2.541487E-05 -1.653039E-02 -3.204738E-05 -1.927088E-02 -5.304249E-05 -8.390867E-03 -1.408823E-05 -1.750394E-02 -4.947439E-05 -1.909888E-02 -5.305029E-05 -1.321359E-02 -3.195949E-05 -1.767250E-02 -4.284184E-05 -1.766010E-02 -4.445269E-05 -1.752133E-02 -3.470706E-05 -2.024733E-02 -5.360810E-05 -1.219423E-02 -1.890812E-05 -1.433551E-02 -2.552372E-05 -1.488366E-02 -3.633706E-05 -1.309982E-02 -2.303088E-05 -1.409845E-02 -2.964092E-05 -1.364964E-02 -2.674995E-05 -2.346093E-02 -7.742790E-05 -1.619070E-02 -3.640820E-05 -1.814514E-02 -4.174971E-05 -2.088143E-02 -7.915120E-05 -2.104482E-02 -4.999110E-05 -2.108577E-02 -5.080473E-05 -1.346978E-02 -2.428984E-05 -1.812802E-02 -3.900263E-05 -1.634894E-02 -3.058475E-05 -1.823343E-02 -4.657246E-05 -1.701022E-02 -3.432397E-05 -1.436832E-02 -2.643066E-05 -1.883466E-02 -4.651260E-05 -1.591237E-02 -3.845574E-05 -1.590406E-02 -3.248073E-05 -1.054631E-02 -1.655070E-05 -2.057489E-02 -5.055329E-05 -1.697824E-02 -3.893444E-05 -1.770103E-02 -4.383559E-05 -2.134851E-02 -6.780393E-05 -1.403120E-02 -2.708815E-05 -1.449734E-02 -2.419619E-05 -1.239576E-02 -2.043627E-05 -1.415699E-02 -2.224645E-05 -1.888682E-02 -4.935465E-05 -2.160682E-02 -6.329152E-05 -2.247940E-02 -7.810124E-05 -9.606213E-03 -1.667840E-05 -2.476229E-02 -8.144159E-05 -1.725175E-02 -3.611282E-05 -1.207190E-02 -1.626596E-05 -1.353421E-02 -2.329766E-05 -1.059055E-02 -1.677463E-05 -9.737491E-03 -1.431106E-05 -6.593375E-03 -7.399377E-06 -7.039159E-03 -1.176702E-05 -1.413677E-02 -3.138472E-05 -1.094329E-02 -2.263303E-05 -6.672931E-03 -6.045366E-06 -1.032380E-02 -2.352298E-05 -8.848889E-03 -1.498309E-05 -1.268157E-02 -2.766060E-05 -7.349115E-03 -1.091693E-05 -1.228088E-02 -2.189060E-05 -1.067250E-02 -1.715732E-05 -1.212246E-02 -2.269620E-05 -4.674814E-03 -3.219220E-06 -8.219501E-03 -1.509768E-05 -1.073016E-02 -2.022852E-05 -9.406782E-03 -1.697200E-05 -7.646611E-03 -1.456233E-05 -1.080915E-02 -2.357182E-05 -6.308610E-03 -8.327166E-06 -7.590107E-03 -8.423541E-06 -1.348669E-02 -2.807690E-05 -1.095856E-02 -2.888898E-05 -5.395294E-03 -5.989965E-06 -6.079841E-03 -7.580064E-06 -7.505564E-03 -8.646729E-06 -6.201233E-03 -6.428779E-06 -1.063698E-02 -1.939413E-05 -7.313889E-03 -9.141624E-06 -9.430810E-03 -1.648005E-05 -4.842603E-03 -4.844512E-06 -5.427814E-03 -4.345647E-06 -6.437292E-03 -1.207973E-05 -8.251158E-03 -1.318350E-05 -8.809423E-03 -1.058811E-05 -5.856619E-03 -4.969559E-06 -6.991101E-03 -6.849651E-06 -5.629621E-03 -5.550323E-06 -2.585500E-03 -1.553122E-06 -1.066559E-02 -1.715979E-05 -3.085260E-03 -6.253271E-06 -9.034984E-03 -1.521387E-05 -6.190606E-03 -9.176053E-06 -9.871403E-03 -1.358973E-05 -9.739545E-03 -1.286586E-05 -7.798343E-03 -9.886920E-06 -8.149958E-03 -1.041850E-05 -2.102030E-02 -6.158217E-05 -1.435765E-02 -3.237028E-05 -7.642569E-03 -7.907376E-06 -1.123406E-02 -1.955695E-05 -1.457081E-02 -3.914562E-05 -1.788958E-02 -5.996510E-05 -1.769436E-02 -4.502383E-05 -1.240825E-02 -2.303672E-05 -1.715444E-02 -4.328672E-05 -1.566180E-02 -3.978890E-05 -1.487883E-02 -3.400964E-05 -8.561200E-03 -1.036201E-05 -2.295904E-02 -5.920445E-05 -1.388508E-02 -3.937752E-05 -1.678190E-02 -4.497456E-05 -2.154484E-02 -5.386125E-05 -6.765444E-03 -7.415266E-06 -1.215420E-02 -2.091620E-05 -2.017061E-02 -7.287759E-05 -1.909053E-02 -5.506644E-05 -1.735888E-02 -3.831995E-05 -1.991557E-02 -4.972306E-05 -1.790749E-02 -4.112227E-05 -1.407457E-02 -3.094925E-05 -2.974572E-02 -1.118172E-04 -1.708785E-02 -4.386435E-05 -2.659193E-02 -9.219939E-05 -3.035144E-02 -1.010119E-04 -1.546737E-02 -3.391982E-05 -1.887938E-02 -4.714248E-05 -1.653679E-02 -4.949250E-05 -2.110944E-02 -5.597556E-05 -2.409526E-02 -6.448595E-05 -2.230819E-02 -5.707848E-05 -1.670895E-02 -3.363955E-05 -1.501463E-02 -2.702669E-05 -1.631677E-02 -3.749166E-05 -1.693626E-02 -4.121173E-05 -2.622206E-02 -7.529216E-05 -2.377917E-02 -7.407839E-05 -1.384279E-02 -2.857021E-05 -2.126418E-02 -7.856414E-05 -1.911630E-02 -4.652883E-05 -2.184179E-02 -5.852148E-05 -1.866708E-02 -6.033622E-05 -1.172279E-02 -3.314139E-05 -1.311652E-02 -2.727134E-05 -1.670812E-02 -4.624330E-05 -1.830609E-02 -5.348783E-05 -8.513210E-03 -1.188353E-05 -1.897475E-02 -4.496529E-05 -1.598385E-02 -3.154883E-05 -1.811274E-02 -4.681726E-05 -1.851236E-02 -4.861112E-05 -1.207908E-02 -2.020737E-05 -1.762593E-02 -4.600809E-05 -1.426171E-02 -3.389465E-05 -1.390938E-02 -4.304132E-05 -1.119665E-02 -2.002203E-05 -7.985862E-03 -1.299182E-05 -1.682922E-02 -3.705605E-05 -1.031217E-02 -1.306045E-05 -1.806448E-02 -4.605140E-05 -1.608612E-02 -3.278234E-05 -7.379583E-03 -7.040180E-06 -1.449866E-02 -3.734314E-05 -1.126405E-02 -1.862160E-05 -1.434466E-02 -3.067276E-05 -1.321482E-02 -2.270946E-05 -1.175946E-02 -2.009819E-05 -8.940307E-03 -1.544249E-05 -1.025576E-02 -1.330247E-05 -1.007614E-02 -1.877197E-05 -8.436802E-03 -1.196625E-05 -2.085623E-02 -4.953759E-05 -1.670794E-02 -3.716863E-05 -1.187761E-02 -1.890192E-05 -1.850976E-02 -4.429493E-05 -4.944517E-03 -5.165715E-06 -8.128340E-03 -1.296218E-05 -1.004447E-02 -2.214422E-05 -9.963052E-03 -1.184842E-05 -7.100471E-03 -8.005623E-06 -8.470273E-03 -9.214382E-06 -1.033575E-02 -1.452750E-05 -9.624022E-03 -1.558452E-05 -8.869432E-03 -1.517840E-05 -1.644470E-02 -3.397196E-05 -7.598019E-03 -8.133919E-06 -8.945737E-03 -9.377464E-06 -5.254834E-03 -4.575273E-06 -7.542267E-03 -7.505652E-06 -9.629827E-03 -1.342434E-05 -1.060266E-02 -1.838055E-05 -3.984507E-03 -2.782462E-06 -6.823286E-03 -7.715504E-06 -8.192618E-03 -1.009785E-05 -6.740618E-03 -6.753208E-06 -1.002813E-02 -1.566585E-05 -1.402360E-02 -2.627061E-05 -9.551680E-03 -1.549743E-05 -8.410173E-03 -1.532161E-05 -9.576682E-03 -1.926642E-05 -1.644285E-02 -3.894395E-05 -9.352112E-03 -1.947845E-05 -9.522578E-03 -1.480589E-05 -1.000109E-02 -1.623473E-05 -1.271924E-02 -2.496798E-05 -1.245375E-02 -2.043780E-05 -1.519888E-02 -3.853835E-05 -6.618627E-03 -6.345424E-06 -7.617580E-03 -8.381516E-06 -7.713051E-03 -1.245806E-05 -8.903456E-03 -2.254781E-05 -1.402208E-02 -2.721848E-05 -1.177140E-02 -1.953130E-05 -1.553072E-02 -2.893580E-05 -1.482066E-02 -3.081970E-05 -9.853191E-03 -1.543282E-05 -1.186384E-02 -2.281665E-05 -1.908232E-02 -6.119132E-05 -1.778254E-02 -3.849134E-05 -1.611496E-02 -4.189813E-05 -1.421950E-02 -3.103442E-05 -2.000883E-02 -5.088716E-05 -1.245870E-02 -2.904861E-05 -2.474667E-02 -7.684411E-05 -1.941450E-02 -4.850566E-05 -1.968721E-02 -4.734318E-05 -2.432138E-02 -7.957731E-05 -1.944046E-02 -4.206030E-05 -2.088512E-02 -5.312412E-05 -2.457361E-02 -7.162438E-05 -2.803303E-02 -9.243404E-05 -2.233188E-02 -6.441041E-05 -2.574667E-02 -7.744780E-05 -2.097121E-02 -5.650314E-05 -2.655826E-02 -8.660847E-05 -3.014326E-02 -9.991619E-05 -2.918919E-02 -9.452555E-05 -2.056057E-02 -5.184372E-05 -2.990570E-02 -1.037648E-04 -2.737932E-02 -8.833139E-05 -2.356419E-02 -7.644776E-05 -3.458839E-02 -1.364027E-04 -3.248751E-02 -1.186240E-04 -3.228724E-02 -1.162923E-04 -2.982979E-02 -1.051045E-04 -2.749198E-02 -9.013699E-05 -2.265201E-02 -7.821751E-05 -2.861490E-02 -8.974738E-05 -3.877353E-02 -1.862085E-04 -2.264214E-02 -6.419386E-05 -2.565522E-02 -8.379023E-05 -3.327436E-02 -1.251213E-04 -3.365022E-02 -1.304927E-04 -3.331544E-02 -1.267184E-04 -3.940664E-02 -2.082874E-04 -3.417164E-02 -1.331489E-04 -3.695924E-02 -1.695935E-04 -3.660181E-02 -1.980269E-04 -3.049799E-02 -1.104243E-04 -3.359904E-02 -1.326383E-04 -2.972450E-02 -9.587313E-05 -2.323160E-02 -6.471218E-05 -1.839074E-02 -4.208719E-05 -2.714264E-02 -9.372657E-05 -2.872170E-02 -1.078922E-04 -3.679226E-02 -1.459261E-04 -2.377295E-02 -6.705585E-05 -3.481909E-02 -1.319533E-04 -3.638325E-02 -1.510511E-04 -2.047379E-02 -4.974814E-05 -3.932322E-02 -1.843858E-04 -1.516217E-02 -3.326445E-05 -2.722332E-02 -9.017263E-05 -1.892837E-02 -4.765562E-05 -1.649353E-02 -4.048523E-05 -2.604495E-02 -7.686911E-05 -2.994865E-02 -1.202039E-04 -1.882216E-02 -4.312602E-05 -1.766775E-02 -4.354878E-05 -2.897250E-02 -9.600078E-05 -2.918339E-02 -9.787984E-05 -2.599062E-02 -8.583368E-05 -3.616458E-02 -1.785317E-04 -1.716456E-02 -4.424230E-05 -2.976397E-02 -1.196639E-04 -2.137198E-02 -5.435882E-05 -1.498606E-02 -2.867869E-05 -2.026381E-02 -6.453877E-05 -2.108149E-02 -4.938367E-05 -1.505838E-02 -2.707808E-05 -1.913971E-02 -5.184273E-05 -2.583671E-02 -9.189443E-05 -2.089460E-02 -5.910541E-05 -2.539127E-02 -8.107037E-05 -2.284066E-02 -6.852612E-05 -9.835860E-03 -1.246182E-05 -1.766679E-02 -4.158408E-05 -1.105611E-02 -1.647013E-05 -1.530049E-02 -3.919500E-05 -1.429716E-02 -3.352166E-05 -1.357586E-02 -3.091775E-05 -1.403296E-02 -3.179172E-05 -1.978070E-02 -4.850759E-05 -2.453097E-02 -8.428665E-05 -1.939330E-02 -4.556576E-05 -1.086518E-02 -1.408645E-05 -1.579821E-02 -2.749151E-05 -6.361591E-03 -6.898179E-06 -7.702358E-03 -9.157872E-06 -1.066424E-02 -1.306101E-05 -9.634515E-03 -1.294132E-05 -1.081282E-02 -2.088218E-05 -1.644232E-02 -3.681578E-05 -9.494639E-03 -1.279154E-05 -5.636874E-03 -4.703193E-06 -1.434790E-02 -2.701384E-05 -1.369675E-02 -2.567531E-05 -1.234911E-02 -2.590620E-05 -1.416398E-02 -2.960800E-05 -1.122603E-02 -2.610403E-05 -1.184891E-02 -2.685267E-05 -1.469060E-02 -3.133618E-05 -2.298108E-02 -7.360049E-05 -1.696881E-02 -4.073271E-05 -1.829044E-02 -4.488597E-05 -8.021195E-03 -1.042375E-05 -7.483229E-03 -7.662752E-06 -9.938980E-03 -1.473587E-05 -6.186154E-03 -7.146893E-06 -1.873257E-02 -5.084856E-05 -1.274591E-02 -1.901691E-05 -1.717315E-02 -4.508495E-05 -2.587324E-02 -7.720386E-05 -1.352804E-02 -2.480610E-05 -1.759894E-02 -3.784552E-05 -1.498671E-02 -2.624849E-05 -2.471517E-02 -8.403653E-05 -2.938643E-02 -1.151484E-04 -2.091784E-02 -5.415805E-05 -1.642239E-02 -3.265718E-05 -2.253062E-02 -7.550922E-05 -1.773827E-02 -4.843752E-05 -1.778692E-02 -4.982541E-05 -3.337468E-02 -1.392002E-04 -3.682265E-02 -1.607062E-04 -2.911908E-02 -1.003985E-04 -2.664232E-02 -8.588222E-05 -2.953127E-02 -1.183748E-04 -2.406807E-02 -7.188877E-05 -3.628487E-02 -1.515959E-04 -3.071907E-02 -1.118121E-04 -3.755060E-02 -1.884817E-04 -3.845138E-02 -2.043330E-04 -4.208968E-02 -1.887229E-04 -2.650790E-02 -1.045695E-04 -4.879444E-02 -2.746335E-04 -3.995698E-02 -1.935956E-04 -3.437302E-02 -1.339692E-04 -4.424777E-02 -2.155808E-04 -4.000509E-02 -1.787367E-04 -3.942601E-02 -1.823141E-04 -5.484106E-02 -3.357163E-04 -5.027689E-02 -2.971747E-04 -5.028897E-02 -2.941870E-04 -5.290232E-02 -3.200207E-04 -3.871560E-02 -1.936856E-04 -4.561909E-02 -2.445140E-04 -5.329116E-02 -3.392022E-04 -6.411682E-02 -4.525641E-04 -4.491390E-02 -2.298662E-04 -4.543173E-02 -2.388585E-04 -4.973450E-02 -2.830273E-04 -4.837326E-02 -2.678945E-04 -5.988650E-02 -4.209610E-04 -5.451978E-02 -3.358217E-04 -7.335314E-02 -6.137308E-04 -7.801463E-02 -6.544817E-04 -5.589338E-02 -3.522166E-04 -5.916022E-02 -3.858273E-04 -4.698963E-02 -3.027433E-04 -5.895924E-02 -3.790017E-04 -4.172371E-02 -2.119338E-04 -3.894831E-02 -1.648204E-04 -5.343858E-02 -3.103206E-04 -4.977655E-02 -3.012635E-04 -6.585931E-02 -4.493935E-04 -5.729670E-02 -3.590518E-04 -5.609196E-02 -3.629946E-04 -6.500048E-02 -4.440662E-04 -4.327539E-02 -2.067690E-04 -5.097662E-02 -2.815490E-04 -4.628356E-02 -2.348648E-04 -4.666148E-02 -2.514991E-04 -3.669329E-02 -1.552102E-04 -4.034392E-02 -1.825094E-04 -5.718186E-02 -3.730299E-04 -3.997528E-02 -2.286198E-04 -5.850080E-02 -4.179988E-04 -3.979728E-02 -1.855473E-04 -6.121586E-02 -4.774824E-04 -5.116923E-02 -2.889253E-04 -4.642274E-02 -2.436217E-04 -5.061482E-02 -2.853049E-04 -3.070349E-02 -1.198974E-04 -4.050110E-02 -1.836951E-04 -2.876275E-02 -1.060796E-04 -3.061263E-02 -1.137168E-04 -4.146381E-02 -1.869894E-04 -4.129877E-02 -1.932088E-04 -3.448209E-02 -1.434523E-04 -3.610442E-02 -1.605801E-04 -4.093512E-02 -1.814782E-04 -4.568118E-02 -2.299954E-04 -3.364878E-02 -1.376802E-04 -3.936126E-02 -1.675197E-04 -1.952985E-02 -4.623048E-05 -2.129951E-02 -6.166111E-05 -2.459526E-02 -8.426675E-05 -1.884092E-02 -4.164051E-05 -3.428763E-02 -1.417068E-04 -3.407514E-02 -1.241486E-04 -3.064802E-02 -1.103630E-04 -2.019877E-02 -7.059498E-05 -3.794436E-02 -1.883194E-04 -3.266721E-02 -1.280477E-04 -2.490808E-02 -7.281690E-05 -3.064961E-02 -1.125362E-04 -1.514239E-02 -2.910925E-05 -1.569321E-02 -3.950962E-05 -1.817240E-02 -4.154077E-05 -1.593815E-02 -3.459272E-05 -2.573968E-02 -8.029098E-05 -2.193871E-02 -6.210741E-05 -1.234720E-02 -1.843394E-05 -1.130766E-02 -2.245547E-05 -1.418762E-02 -3.357410E-05 -1.391485E-02 -2.559415E-05 -1.331696E-02 -2.115069E-05 -1.903725E-02 -4.411480E-05 -2.293870E-02 -6.557987E-05 -2.241944E-02 -7.768129E-05 -8.399478E-03 -1.343754E-05 -1.217880E-02 -2.018185E-05 -1.416256E-02 -2.227003E-05 -1.520064E-02 -2.978679E-05 -1.664846E-02 -4.183492E-05 -1.339491E-02 -2.674827E-05 -9.628607E-03 -1.279454E-05 -1.158026E-02 -1.554728E-05 -1.367791E-02 -2.379966E-05 -1.376699E-02 -2.264472E-05 -1.833088E-02 -4.495911E-05 -2.473484E-02 -1.122059E-04 -1.980130E-02 -4.468138E-05 -2.937836E-02 -1.114018E-04 -2.021222E-02 -4.559590E-05 -2.115889E-02 -5.272398E-05 -2.751444E-02 -8.716393E-05 -3.118255E-02 -1.201980E-04 -3.295258E-02 -1.221249E-04 -3.264934E-02 -1.357065E-04 -2.388443E-02 -6.703731E-05 -2.649789E-02 -7.940354E-05 -4.696656E-02 -2.514244E-04 -4.553686E-02 -2.438972E-04 -3.908818E-02 -1.840355E-04 -4.402566E-02 -2.377775E-04 -3.875910E-02 -1.778735E-04 -3.543152E-02 -1.527725E-04 -6.193982E-02 -4.578553E-04 -4.402817E-02 -2.274373E-04 -3.677275E-02 -1.884320E-04 -5.902021E-02 -3.951715E-04 -4.943375E-02 -2.711632E-04 -3.724773E-02 -1.641879E-04 -4.993443E-02 -2.771281E-04 -7.563062E-02 -6.734531E-04 -4.553601E-02 -2.283737E-04 -5.336189E-02 -3.085766E-04 -6.930581E-02 -5.723133E-04 -4.674295E-02 -2.785390E-04 -8.412725E-02 -7.467027E-04 -6.681883E-02 -4.824696E-04 -8.430398E-02 -7.823907E-04 -9.943266E-02 -1.106796E-03 -8.916803E-02 -8.767378E-04 -7.239961E-02 -6.787255E-04 -8.722424E-02 -9.332353E-04 -1.031401E-01 -1.218166E-03 -7.299280E-02 -5.585065E-04 -8.196460E-02 -7.464830E-04 -7.514349E-02 -6.162898E-04 -7.409781E-02 -6.092201E-04 -1.155025E-01 -1.496467E-03 -1.069759E-01 -1.259983E-03 -1.226295E-01 -1.569654E-03 -1.503421E-01 -2.355624E-03 -1.080703E-01 -1.309087E-03 -1.129782E-01 -1.371142E-03 -8.048452E-02 -7.348043E-04 -1.058381E-01 -1.164709E-03 -6.615819E-02 -4.794240E-04 -7.980754E-02 -6.987820E-04 -1.120426E-01 -1.285452E-03 -1.016962E-01 -1.116490E-03 -1.045603E-01 -1.203503E-03 -9.692551E-02 -1.029307E-03 -1.510121E-01 -2.326069E-03 -1.459994E-01 -2.277384E-03 -8.473854E-02 -7.832629E-04 -1.294853E-01 -1.741522E-03 -6.032354E-02 -3.886121E-04 -6.987142E-02 -5.446194E-04 -7.739481E-02 -6.779391E-04 -6.202592E-02 -4.288928E-04 -1.105924E-01 -1.283621E-03 -9.239492E-02 -9.223732E-04 -6.604268E-02 -4.595692E-04 -7.012590E-02 -5.276378E-04 -9.125615E-02 -8.968665E-04 -8.440076E-02 -7.298457E-04 -6.290364E-02 -4.350725E-04 -9.542023E-02 -1.023159E-03 -3.785503E-02 -1.773114E-04 -5.510138E-02 -3.186315E-04 -4.425845E-02 -2.296502E-04 -5.216949E-02 -3.102279E-04 -5.711604E-02 -3.708531E-04 -6.348926E-02 -4.437737E-04 -3.531423E-02 -1.381941E-04 -4.676905E-02 -2.710798E-04 -5.132004E-02 -2.836163E-04 -4.379959E-02 -2.484735E-04 -5.314318E-02 -3.059228E-04 -6.677411E-02 -5.104497E-04 -2.953361E-02 -1.221048E-04 -3.348688E-02 -1.218024E-04 -3.189405E-02 -1.283561E-04 -3.066128E-02 -1.074943E-04 -2.627008E-02 -7.434735E-05 -4.099188E-02 -1.844425E-04 -2.657946E-02 -8.006763E-05 -2.677024E-02 -9.837536E-05 -2.297001E-02 -6.348807E-05 -2.847736E-02 -1.016726E-04 -3.650898E-02 -1.905274E-04 -3.678596E-02 -1.737202E-04 -9.741068E-03 -1.427221E-05 -2.112559E-02 -7.299641E-05 -1.626433E-02 -3.325133E-05 -1.556047E-02 -3.623423E-05 -2.005845E-02 -4.817075E-05 -2.235018E-02 -6.309213E-05 -1.555635E-02 -3.399168E-05 -8.473936E-03 -1.206918E-05 -2.003025E-02 -5.771667E-05 -1.619274E-02 -3.694213E-05 -2.398087E-02 -8.309002E-05 -2.048279E-02 -5.775057E-05 -1.959187E-02 -4.755352E-05 -1.817346E-02 -4.751135E-05 -1.533477E-02 -4.769982E-05 -1.889382E-02 -4.706002E-05 -1.855621E-02 -4.644130E-05 -3.121451E-02 -1.173056E-04 -1.135235E-02 -2.022523E-05 -1.457214E-02 -3.250403E-05 -1.330384E-02 -2.287686E-05 -1.426049E-02 -2.827899E-05 -2.255732E-02 -6.597520E-05 -1.409157E-02 -2.947510E-05 -2.387117E-02 -7.502115E-05 -3.498075E-02 -1.588586E-04 -2.661630E-02 -9.051962E-05 -3.141346E-02 -1.130104E-04 -2.363639E-02 -7.247261E-05 -2.949581E-02 -1.015620E-04 -3.405344E-02 -1.368730E-04 -3.067699E-02 -1.186942E-04 -2.860325E-02 -1.027432E-04 -3.136948E-02 -1.261067E-04 -2.884168E-02 -9.121556E-05 -3.172681E-02 -1.271781E-04 -6.082138E-02 -3.967354E-04 -4.665628E-02 -2.447254E-04 -3.873489E-02 -1.666752E-04 -5.112906E-02 -2.817112E-04 -3.867668E-02 -1.713578E-04 -4.211970E-02 -1.934977E-04 -6.886477E-02 -4.937257E-04 -7.019363E-02 -5.620739E-04 -5.569741E-02 -3.372249E-04 -5.856502E-02 -3.766765E-04 -5.390171E-02 -3.381837E-04 -4.680414E-02 -2.500022E-04 -1.026456E-01 -1.147075E-03 -8.535063E-02 -7.808065E-04 -8.630449E-02 -8.031445E-04 -1.052149E-01 -1.184292E-03 -7.701701E-02 -6.253512E-04 -7.834187E-02 -6.672354E-04 -1.359360E-01 -1.907855E-03 -1.460384E-01 -2.190423E-03 -1.080390E-01 -1.234268E-03 -1.317673E-01 -1.856930E-03 -9.690172E-02 -1.006627E-03 -9.258404E-02 -9.457422E-04 -1.832246E-01 -3.427961E-03 -2.054091E-01 -4.398902E-03 -1.593682E-01 -2.662133E-03 -1.880778E-01 -3.629787E-03 -2.013148E-01 -4.265877E-03 -1.990549E-01 -4.200017E-03 -5.469090E-01 -3.082757E-02 -5.552625E-01 -3.233826E-02 -2.571401E-01 -6.723483E-03 -8.548854E-01 -7.413280E-02 -5.209393E-01 -2.787584E-02 -5.093657E-01 -2.715480E-02 -1.566145E-01 -2.600405E-03 -1.993120E-01 -4.010479E-03 -1.707332E-01 -2.996975E-03 -1.840203E-01 -3.525950E-03 -5.686602E-01 -3.269532E-02 -5.046470E-01 -2.580015E-02 -1.740098E-01 -3.137069E-03 -1.748447E-01 -3.287313E-03 -5.281969E-01 -2.835860E-02 -5.218758E-01 -2.764449E-02 -2.811590E-01 -8.077168E-03 -7.835313E-01 -6.174409E-02 -8.916676E-02 -8.704144E-04 -1.147415E-01 -1.428848E-03 -1.059630E-01 -1.142821E-03 -9.640793E-02 -9.919169E-04 -1.380046E-01 -2.013093E-03 -1.453872E-01 -2.230703E-03 -8.067716E-02 -7.607075E-04 -7.414787E-02 -5.831873E-04 -1.108173E-01 -1.334816E-03 -9.716310E-02 -1.050788E-03 -1.058275E-01 -1.176253E-03 -1.234077E-01 -1.611857E-03 -4.645374E-02 -2.489769E-04 -5.612855E-02 -3.674944E-04 -5.305509E-02 -3.127379E-04 -4.929601E-02 -2.809620E-04 -6.549144E-02 -4.537754E-04 -6.303494E-02 -4.236715E-04 -3.880272E-02 -1.704460E-04 -3.861758E-02 -1.663017E-04 -5.862395E-02 -3.858310E-04 -4.737923E-02 -2.823280E-04 -5.280787E-02 -3.043443E-04 -5.249474E-02 -3.019614E-04 -2.485904E-02 -6.701075E-05 -2.926990E-02 -9.417758E-05 -3.125676E-02 -1.037311E-04 -3.289406E-02 -1.368340E-04 -4.071134E-02 -1.830700E-04 -4.109741E-02 -2.038834E-04 -2.347652E-02 -7.157581E-05 -2.072441E-02 -5.807283E-05 -4.102695E-02 -2.107954E-04 -2.166639E-02 -5.788402E-05 -3.219359E-02 -1.250457E-04 -2.832465E-02 -9.610853E-05 -1.624643E-02 -3.730962E-05 -1.725120E-02 -4.481115E-05 -1.578099E-02 -3.024585E-05 -1.571746E-02 -3.035996E-05 -1.731202E-02 -3.502473E-05 -1.643420E-02 -3.632173E-05 -1.040551E-02 -1.294862E-05 -1.127727E-02 -2.039819E-05 -1.438022E-02 -2.857038E-05 -1.260556E-02 -2.928756E-05 -2.034502E-02 -6.038560E-05 -1.640843E-02 -3.872409E-05 -2.122181E-02 -6.703870E-05 -1.545958E-02 -2.933443E-05 -1.550763E-02 -3.859489E-05 -1.928201E-02 -4.243101E-05 -2.196809E-02 -5.810938E-05 -2.193973E-02 -5.702613E-05 -1.517387E-02 -3.300117E-05 -1.732347E-02 -3.857976E-05 -1.415891E-02 -2.906573E-05 -1.407775E-02 -3.402531E-05 -2.277203E-02 -7.764043E-05 -1.580648E-02 -4.707367E-05 -2.763176E-02 -9.424628E-05 -2.372205E-02 -6.537717E-05 -2.585656E-02 -7.555138E-05 -3.438842E-02 -1.498651E-04 -1.953849E-02 -4.797528E-05 -2.039273E-02 -6.513710E-05 -3.691903E-02 -1.454538E-04 -3.217932E-02 -1.398798E-04 -2.774657E-02 -8.279249E-05 -2.820457E-02 -9.228219E-05 -3.106567E-02 -1.239322E-04 -1.804981E-02 -4.099893E-05 -5.969428E-02 -3.940876E-04 -5.835174E-02 -4.018253E-04 -5.448605E-02 -3.344901E-04 -6.458561E-02 -4.749467E-04 -4.505232E-02 -2.290467E-04 -4.529186E-02 -2.210661E-04 -6.923883E-02 -5.074459E-04 -6.905166E-02 -5.269603E-04 -4.247615E-02 -2.080915E-04 -5.430061E-02 -3.320737E-04 -6.603377E-02 -5.144612E-04 -5.251003E-02 -3.190205E-04 -1.030147E-01 -1.109176E-03 -8.155464E-02 -7.067482E-04 -8.922744E-02 -8.197146E-04 -1.284288E-01 -1.811686E-03 -9.277212E-02 -8.820708E-04 -7.960421E-02 -7.018415E-04 -1.101447E-01 -1.238620E-03 -1.594606E-01 -2.631417E-03 -7.676797E-02 -6.249548E-04 -9.678537E-02 -1.039683E-03 -1.315012E-01 -1.823501E-03 -9.822710E-02 -1.049106E-03 -2.200833E-01 -4.944909E-03 -1.814148E-01 -3.455606E-03 -2.808713E-01 -7.998623E-03 -8.607047E-01 -7.471518E-02 -1.510873E-01 -2.350444E-03 -1.952158E-01 -3.987281E-03 -2.563955E-01 -6.736419E-03 -8.288790E-01 -6.935905E-02 -1.663306E-01 -2.909230E-03 -2.069533E-01 -4.392557E-03 -8.171538E-01 -6.926168E-02 -2.771724E-01 -7.947364E-03 -1.718421E-01 -3.078316E-03 -1.912710E-01 -3.901809E-03 -4.978656E-01 -2.591511E-02 -4.943901E-01 -2.504533E-02 -2.519316E-01 -6.571958E-03 -7.930433E-01 -6.483055E-02 -1.486665E-01 -2.270454E-03 -2.161805E-01 -4.796812E-03 -1.737906E-01 -3.149960E-03 -1.909929E-01 -3.837468E-03 -5.280144E-01 -2.824797E-02 -5.994269E-01 -3.679537E-02 -8.367283E-02 -8.246835E-04 -9.345285E-02 -9.180702E-04 -1.084220E-01 -1.234841E-03 -1.132694E-01 -1.417334E-03 -1.213506E-01 -1.536611E-03 -1.485290E-01 -2.261244E-03 -7.557519E-02 -6.112603E-04 -7.935833E-02 -6.583374E-04 -1.009825E-01 -1.083491E-03 -7.954123E-02 -7.044944E-04 -1.118116E-01 -1.371403E-03 -1.197452E-01 -1.570554E-03 -5.190598E-02 -3.551665E-04 -5.730111E-02 -3.980792E-04 -6.248836E-02 -4.466985E-04 -6.019178E-02 -4.124940E-04 -7.202094E-02 -5.415764E-04 -7.189177E-02 -5.472909E-04 -3.981535E-02 -1.797809E-04 -4.820928E-02 -2.773872E-04 -5.050408E-02 -2.801362E-04 -5.149907E-02 -3.058260E-04 -6.167709E-02 -3.980579E-04 -6.251960E-02 -4.234132E-04 -2.843012E-02 -8.808063E-05 -2.337612E-02 -6.606638E-05 -2.936391E-02 -9.914901E-05 -3.131118E-02 -1.224255E-04 -3.590121E-02 -1.554613E-04 -3.734616E-02 -1.611929E-04 -2.718818E-02 -8.275683E-05 -2.355063E-02 -6.269602E-05 -3.417456E-02 -1.470468E-04 -2.761636E-02 -8.857401E-05 -2.817665E-02 -9.358473E-05 -4.330547E-02 -2.125793E-04 -1.281131E-02 -2.508003E-05 -1.558497E-02 -4.131225E-05 -1.604825E-02 -3.789735E-05 -1.198312E-02 -2.201855E-05 -1.841476E-02 -4.406610E-05 -2.191664E-02 -5.706023E-05 -1.037877E-02 -1.403046E-05 -1.142906E-02 -1.784198E-05 -2.165180E-02 -7.328897E-05 -1.781165E-02 -3.964227E-05 -1.706685E-02 -3.626318E-05 -2.611118E-02 -8.937284E-05 -1.889982E-02 -5.096931E-05 -1.354993E-02 -3.469204E-05 -1.092599E-02 -1.697195E-05 -1.380052E-02 -2.909184E-05 -2.326409E-02 -7.737047E-05 -2.386034E-02 -7.722570E-05 -1.642655E-02 -4.387424E-05 -1.696224E-02 -3.657599E-05 -1.094347E-02 -1.803801E-05 -1.156552E-02 -2.421906E-05 -1.583036E-02 -3.257752E-05 -1.517584E-02 -3.200691E-05 -3.827074E-02 -1.889669E-04 -2.449951E-02 -7.459613E-05 -2.623209E-02 -8.154118E-05 -2.849776E-02 -9.089323E-05 -2.334185E-02 -6.201992E-05 -2.654520E-02 -9.694536E-05 -3.237617E-02 -1.167467E-04 -3.675105E-02 -1.763620E-04 -2.004612E-02 -5.066812E-05 -2.903446E-02 -9.486419E-05 -3.334691E-02 -1.228445E-04 -2.623258E-02 -7.799037E-05 -4.888525E-02 -2.729676E-04 -3.600959E-02 -1.553932E-04 -5.438364E-02 -3.353294E-04 -5.232566E-02 -2.992982E-04 -3.034775E-02 -1.324830E-04 -4.164626E-02 -2.036943E-04 -5.059600E-02 -2.935825E-04 -5.879411E-02 -3.888487E-04 -3.938426E-02 -2.093554E-04 -4.838794E-02 -2.715001E-04 -4.972503E-02 -2.740094E-04 -4.955213E-02 -2.667621E-04 -6.113745E-02 -4.048275E-04 -5.341164E-02 -3.153602E-04 -5.975662E-02 -3.838000E-04 -8.595500E-02 -8.321615E-04 -6.107919E-02 -3.898803E-04 -5.530668E-02 -3.235594E-04 -7.580790E-02 -6.272237E-04 -9.941256E-02 -1.054222E-03 -6.091493E-02 -3.907622E-04 -6.317933E-02 -4.235462E-04 -1.014991E-01 -1.038642E-03 -7.701856E-02 -6.147885E-04 -1.112163E-01 -1.265790E-03 -7.536078E-02 -5.769678E-04 -1.302318E-01 -1.742411E-03 -1.635988E-01 -2.867432E-03 -7.255186E-02 -6.284552E-04 -1.087261E-01 -1.292949E-03 -1.071717E-01 -1.182413E-03 -1.275727E-01 -1.701949E-03 -7.308862E-02 -5.588046E-04 -8.677475E-02 -7.923200E-04 -1.598968E-01 -2.752916E-03 -1.090514E-01 -1.267867E-03 -9.373573E-02 -9.468462E-04 -8.656897E-02 -7.993780E-04 -1.556811E-01 -2.570483E-03 -1.563481E-01 -2.547541E-03 -1.019280E-01 -1.066946E-03 -1.407263E-01 -2.139026E-03 -9.439261E-02 -9.727226E-04 -1.162727E-01 -1.469225E-03 -8.572873E-02 -7.472360E-04 -8.412598E-02 -7.378763E-04 -1.184615E-01 -1.447843E-03 -1.129877E-01 -1.387240E-03 -7.089346E-02 -5.210102E-04 -7.106181E-02 -5.601420E-04 -9.767580E-02 -1.010123E-03 -8.639404E-02 -7.865066E-04 -8.288207E-02 -7.425178E-04 -8.992435E-02 -9.501100E-04 -6.866676E-02 -5.516503E-04 -6.325590E-02 -4.342044E-04 -7.431495E-02 -6.348268E-04 -7.599335E-02 -5.991771E-04 -7.274975E-02 -5.571106E-04 -6.766739E-02 -5.249260E-04 -3.181945E-02 -1.159273E-04 -4.099202E-02 -1.863511E-04 -4.739506E-02 -2.375175E-04 -4.566762E-02 -2.462349E-04 -4.309564E-02 -2.169367E-04 -4.968602E-02 -2.836430E-04 -2.554238E-02 -7.130377E-05 -3.399568E-02 -1.313338E-04 -4.489588E-02 -2.608490E-04 -3.609823E-02 -1.664739E-04 -3.688252E-02 -1.524824E-04 -4.371937E-02 -2.194516E-04 -2.432742E-02 -6.816206E-05 -2.481126E-02 -7.715594E-05 -3.225220E-02 -1.297648E-04 -2.820482E-02 -8.756926E-05 -2.911932E-02 -9.466605E-05 -3.374238E-02 -1.328376E-04 -2.602288E-02 -8.674133E-05 -2.044276E-02 -4.796182E-05 -2.621162E-02 -8.521865E-05 -3.451732E-02 -1.272449E-04 -2.497288E-02 -7.862985E-05 -3.797623E-02 -1.934870E-04 -1.693158E-02 -3.957575E-05 -2.516921E-02 -7.540607E-05 -1.916047E-02 -5.115510E-05 -1.903519E-02 -5.491559E-05 -1.655257E-02 -2.970206E-05 -1.806193E-02 -4.421369E-05 -1.074232E-02 -1.704622E-05 -9.240900E-03 -1.255060E-05 -1.183407E-02 -1.748671E-05 -9.219696E-03 -1.609190E-05 -1.034386E-02 -1.462148E-05 -1.114705E-02 -1.850428E-05 -1.297960E-02 -2.423078E-05 -1.184491E-02 -2.140225E-05 -1.658431E-02 -4.388936E-05 -1.318219E-02 -2.389643E-05 -1.560221E-02 -3.262330E-05 -1.536994E-02 -2.967325E-05 -1.474070E-02 -2.850636E-05 -1.423540E-02 -2.724881E-05 -1.128414E-02 -1.691587E-05 -7.509669E-03 -1.138736E-05 -1.063708E-02 -1.760414E-05 -1.145186E-02 -2.083540E-05 -1.762181E-02 -4.474974E-05 -2.084088E-02 -6.507170E-05 -2.057308E-02 -5.516523E-05 -2.241191E-02 -7.120840E-05 -1.269523E-02 -2.005337E-05 -1.660064E-02 -3.697642E-05 -3.182773E-02 -1.204858E-04 -3.242190E-02 -1.182654E-04 -2.434893E-02 -7.105045E-05 -2.652135E-02 -7.481704E-05 -1.907560E-02 -5.087922E-05 -2.190903E-02 -6.429867E-05 -3.105119E-02 -1.183209E-04 -2.464967E-02 -7.797261E-05 -2.817912E-02 -9.460889E-05 -4.586402E-02 -2.494422E-04 -3.145613E-02 -1.306566E-04 -3.581523E-02 -1.371038E-04 -3.824846E-02 -1.899412E-04 -4.263531E-02 -1.873636E-04 -3.042311E-02 -1.167731E-04 -2.732643E-02 -7.846176E-05 -4.050189E-02 -1.908935E-04 -3.434384E-02 -1.361814E-04 -4.495849E-02 -2.646832E-04 -4.092138E-02 -2.017353E-04 -5.344413E-02 -3.250472E-04 -4.697795E-02 -2.453442E-04 -3.679979E-02 -1.575515E-04 -3.908452E-02 -1.742990E-04 -4.284114E-02 -2.154331E-04 -4.380058E-02 -2.263026E-04 -3.985455E-02 -1.829559E-04 -3.394862E-02 -1.228745E-04 -4.744764E-02 -2.814058E-04 -3.949446E-02 -1.946576E-04 -6.109758E-02 -4.065478E-04 -5.344244E-02 -3.173404E-04 -5.996641E-02 -3.831573E-04 -7.955351E-02 -6.865984E-04 -4.384271E-02 -1.999570E-04 -6.435559E-02 -4.377030E-04 -4.969051E-02 -2.811028E-04 -5.599815E-02 -3.868544E-04 -4.163040E-02 -2.191546E-04 -4.845338E-02 -2.687605E-04 -7.016148E-02 -5.682673E-04 -6.371981E-02 -4.441518E-04 -6.553775E-02 -4.702345E-04 -5.818627E-02 -3.716053E-04 -7.301288E-02 -5.661570E-04 -6.855403E-02 -4.925246E-04 -4.751877E-02 -3.119215E-04 -6.178405E-02 -4.942348E-04 -5.778084E-02 -3.682642E-04 -6.794905E-02 -4.813721E-04 -4.580484E-02 -2.283874E-04 -4.833285E-02 -2.496503E-04 -6.283852E-02 -4.289179E-04 -5.868559E-02 -3.829967E-04 -4.942181E-02 -2.770674E-04 -4.633288E-02 -2.530825E-04 -6.521627E-02 -4.531563E-04 -6.926577E-02 -4.930307E-04 -4.947134E-02 -2.743687E-04 -5.599354E-02 -3.625867E-04 -4.586533E-02 -2.169603E-04 -6.057563E-02 -3.949284E-04 -3.269565E-02 -1.324708E-04 -3.688715E-02 -1.561195E-04 -4.607386E-02 -2.561957E-04 -4.286297E-02 -2.186313E-04 -3.835517E-02 -1.807457E-04 -3.101308E-02 -1.258603E-04 -4.256564E-02 -2.156265E-04 -3.995257E-02 -1.962160E-04 -3.999004E-02 -1.700193E-04 -4.593940E-02 -2.325862E-04 -2.746637E-02 -1.056011E-04 -2.945679E-02 -1.039840E-04 -4.237269E-02 -1.976737E-04 -3.339233E-02 -1.438661E-04 -3.371702E-02 -1.468814E-04 -3.238843E-02 -1.164792E-04 -2.064297E-02 -5.618891E-05 -2.155723E-02 -6.462578E-05 -2.273621E-02 -5.819206E-05 -1.964446E-02 -5.147180E-05 -2.401285E-02 -7.795637E-05 -2.729940E-02 -9.076729E-05 -2.213041E-02 -6.949614E-05 -1.338392E-02 -2.465408E-05 -2.431872E-02 -7.724266E-05 -2.524967E-02 -1.026115E-04 -2.737266E-02 -9.841098E-05 -2.112771E-02 -5.889604E-05 -1.496282E-02 -4.007026E-05 -1.889629E-02 -5.468925E-05 -1.783224E-02 -4.566541E-05 -8.331789E-03 -9.954892E-06 -1.796677E-02 -3.918970E-05 -1.970964E-02 -4.450042E-05 -1.137654E-02 -1.965594E-05 -8.407972E-03 -1.166241E-05 -1.447552E-02 -2.605420E-05 -8.376429E-03 -1.246530E-05 -1.335436E-02 -3.392789E-05 -1.200101E-02 -2.280708E-05 -1.602954E-02 -3.739523E-05 -9.669299E-03 -1.679999E-05 -1.566345E-02 -3.502619E-05 -1.588366E-02 -3.186835E-05 -1.901368E-02 -4.343637E-05 -2.267083E-02 -7.178904E-05 -9.004042E-03 -1.176762E-05 -1.804933E-02 -4.338938E-05 -1.071906E-02 -1.634166E-05 -9.615294E-03 -1.267674E-05 -1.558814E-02 -2.851576E-05 -1.376105E-02 -2.761523E-05 -1.902761E-02 -6.150446E-05 -1.854745E-02 -5.066723E-05 -1.702864E-02 -4.027369E-05 -2.099003E-02 -6.424422E-05 -2.011904E-02 -5.529868E-05 -1.661724E-02 -3.837653E-05 -1.373297E-02 -2.945958E-05 -1.569666E-02 -3.146459E-05 -1.202400E-02 -1.784017E-05 -1.532156E-02 -4.083467E-05 -1.855533E-02 -4.148169E-05 -2.388887E-02 -7.104659E-05 -3.029475E-02 -1.112701E-04 -3.479830E-02 -1.457081E-04 -2.993443E-02 -1.034283E-04 -2.618538E-02 -8.150737E-05 -1.973658E-02 -5.388325E-05 -1.908984E-02 -4.925317E-05 -2.558471E-02 -7.645976E-05 -3.057900E-02 -1.526871E-04 -2.038898E-02 -6.028856E-05 -1.936824E-02 -5.652676E-05 -1.860724E-02 -4.433157E-05 -1.859342E-02 -6.046452E-05 -3.104650E-02 -1.107731E-04 -2.791826E-02 -8.517252E-05 -2.550906E-02 -7.911190E-05 -3.228374E-02 -1.235126E-04 -2.983461E-02 -1.169772E-04 -2.340715E-02 -7.962272E-05 -2.472431E-02 -7.854176E-05 -3.116101E-02 -1.113261E-04 -2.726866E-02 -8.448946E-05 -2.872167E-02 -1.004750E-04 -3.032428E-02 -1.229901E-04 -3.053428E-02 -1.122910E-04 -3.083822E-02 -1.483669E-04 -2.064536E-02 -5.782771E-05 -3.181149E-02 -1.187295E-04 -4.583432E-02 -2.558159E-04 -2.666121E-02 -9.350519E-05 -3.358219E-02 -1.192091E-04 -2.369325E-02 -8.059778E-05 -3.102351E-02 -1.289691E-04 -2.820355E-02 -1.068875E-04 -3.480350E-02 -1.443944E-04 -3.560608E-02 -1.469841E-04 -4.990478E-02 -3.032798E-04 -3.784020E-02 -1.765328E-04 -3.316256E-02 -1.290263E-04 -4.033997E-02 -1.799350E-04 -3.929687E-02 -1.626134E-04 -3.235240E-02 -1.382862E-04 -3.388379E-02 -1.425521E-04 -3.879634E-02 -1.814360E-04 -3.990331E-02 -1.937058E-04 -2.486877E-02 -7.060573E-05 -2.847067E-02 -8.714105E-05 -4.490738E-02 -2.182380E-04 -3.277939E-02 -1.222614E-04 -2.300113E-02 -6.725020E-05 -3.241132E-02 -1.183039E-04 -3.117719E-02 -1.083016E-04 -2.675135E-02 -8.558799E-05 -3.944468E-02 -1.742389E-04 -4.399132E-02 -2.295328E-04 -2.087405E-02 -4.684764E-05 -1.956671E-02 -4.488034E-05 -3.135372E-02 -1.064232E-04 -1.852589E-02 -4.046644E-05 -2.367532E-02 -7.100616E-05 -2.728169E-02 -9.976058E-05 -2.896959E-02 -9.844663E-05 -2.865198E-02 -1.092590E-04 -3.163730E-02 -1.082131E-04 -3.268958E-02 -1.309514E-04 -2.046897E-02 -4.893795E-05 -2.472680E-02 -7.874493E-05 -2.926292E-02 -1.081766E-04 -3.002458E-02 -1.013573E-04 -1.360951E-02 -2.635847E-05 -2.311727E-02 -6.168251E-05 -3.020182E-02 -1.206713E-04 -2.697417E-02 -8.378246E-05 -1.334960E-02 -2.306197E-05 -1.590087E-02 -4.689125E-05 -2.011479E-02 -6.965285E-05 -1.633667E-02 -3.972970E-05 -2.002848E-02 -4.881276E-05 -2.201774E-02 -5.990084E-05 -1.590141E-02 -4.489842E-05 -1.287558E-02 -2.913250E-05 -1.902193E-02 -5.067435E-05 -1.740647E-02 -4.536926E-05 -2.127020E-02 -6.939263E-05 -1.655808E-02 -3.850014E-05 -1.186084E-02 -2.566137E-05 -1.183085E-02 -2.088219E-05 -1.691039E-02 -4.357920E-05 -6.413071E-03 -5.791752E-06 -1.069744E-02 -1.593929E-05 -9.843254E-03 -1.483187E-05 -6.822909E-03 -6.785866E-06 -4.540728E-03 -3.073065E-06 -1.381635E-02 -3.287951E-05 -9.881421E-03 -1.765396E-05 -5.794819E-03 -6.579960E-06 -1.064665E-02 -1.825529E-05 -9.708618E-03 -2.420624E-05 -3.867809E-03 -3.463878E-06 -1.036922E-02 -1.880088E-05 -1.209814E-02 -2.247120E-05 -6.289728E-03 -9.053460E-06 -1.121820E-02 -2.376217E-05 -6.107387E-03 -9.842112E-06 -6.679042E-03 -7.917785E-06 -4.610676E-03 -3.822313E-06 -8.094200E-03 -1.556770E-05 -1.289830E-02 -2.263732E-05 -1.240554E-02 -2.182216E-05 -1.709643E-02 -4.443205E-05 -1.240518E-02 -1.925823E-05 -1.427630E-02 -3.038114E-05 -1.316587E-02 -2.528125E-05 -1.051316E-02 -1.998843E-05 -1.171370E-02 -1.977243E-05 -1.035585E-02 -1.603691E-05 -7.844703E-03 -1.578836E-05 -1.090930E-02 -1.495715E-05 -8.811473E-03 -9.095511E-06 -1.164754E-02 -2.113385E-05 -1.218588E-02 -2.577136E-05 -9.989257E-03 -1.768442E-05 -1.346846E-02 -3.232091E-05 -1.442996E-02 -2.734716E-05 -9.319830E-03 -1.357660E-05 -8.976517E-03 -1.130996E-05 -1.111410E-02 -1.774598E-05 -7.097237E-03 -9.606334E-06 -7.668810E-03 -9.333553E-06 -7.744641E-03 -1.065587E-05 -7.076161E-03 -1.063617E-05 -9.841337E-03 -1.147612E-05 -9.084818E-03 -1.406836E-05 -2.026892E-02 -5.186751E-05 -2.132295E-02 -5.072988E-05 -2.033996E-02 -4.765789E-05 -2.446954E-02 -7.232017E-05 -1.029334E-02 -1.244212E-05 -1.235238E-02 -2.298965E-05 -1.681496E-02 -3.708751E-05 -2.101172E-02 -5.242154E-05 -1.722265E-02 -4.432357E-05 -1.352905E-02 -2.104447E-05 -2.195095E-02 -5.623046E-05 -2.089078E-02 -5.825067E-05 -2.311666E-02 -7.574537E-05 -1.562461E-02 -4.452838E-05 -3.307359E-02 -1.363268E-04 -2.572970E-02 -8.059205E-05 -2.345159E-02 -6.488182E-05 -2.554049E-02 -8.362508E-05 -2.006928E-02 -5.496633E-05 -2.259482E-02 -7.740649E-05 -1.761243E-02 -4.766457E-05 -1.125462E-02 -1.662484E-05 -1.806884E-02 -4.002727E-05 -1.875035E-02 -3.963856E-05 -2.507230E-02 -7.918744E-05 -1.948387E-02 -4.675980E-05 -2.102608E-02 -5.253998E-05 -2.725383E-02 -8.911499E-05 -1.527724E-02 -2.634360E-05 -2.318415E-02 -6.853391E-05 -1.953638E-02 -4.357651E-05 -2.681123E-02 -9.518790E-05 -1.619023E-02 -3.280100E-05 -2.160140E-02 -5.673289E-05 -2.207700E-02 -6.204249E-05 -1.851529E-02 -4.084658E-05 -2.064003E-02 -5.523222E-05 -1.936444E-02 -5.709920E-05 -2.135402E-02 -6.226947E-05 -1.913624E-02 -5.176876E-05 -1.979246E-02 -4.760307E-05 -2.697598E-02 -1.023961E-04 -1.163038E-02 -1.840715E-05 -1.922611E-02 -4.751185E-05 -1.370913E-02 -2.686855E-05 -1.541222E-02 -3.013601E-05 -2.247424E-02 -5.214783E-05 -1.763181E-02 -3.495488E-05 -9.375723E-03 -1.593258E-05 -1.436433E-02 -3.431677E-05 -1.300122E-02 -2.534320E-05 -1.428291E-02 -3.109112E-05 -1.320134E-02 -2.937454E-05 -1.496684E-02 -2.934259E-05 -1.257843E-02 -3.153056E-05 -1.573087E-02 -3.089207E-05 -1.074581E-02 -1.656493E-05 -8.983048E-03 -1.169670E-05 -1.588106E-02 -3.644142E-05 -1.135062E-02 -1.548990E-05 -1.342453E-02 -4.068693E-05 -7.143669E-03 -1.309838E-05 -1.911833E-02 -5.539347E-05 -1.578655E-02 -3.784881E-05 -1.010592E-02 -2.000143E-05 -2.107750E-02 -5.152671E-05 -1.352516E-02 -2.742309E-05 -1.298482E-02 -2.958789E-05 -8.061759E-03 -1.027922E-05 -1.145755E-02 -1.975699E-05 -7.630008E-03 -9.001956E-06 -1.110176E-02 -1.756811E-05 -7.622179E-03 -1.192472E-05 -1.157431E-02 -3.153358E-05 -1.329349E-02 -2.758940E-05 -7.723627E-03 -1.213940E-05 -6.430868E-03 -5.865444E-06 -6.666510E-03 -6.225385E-06 -3.314737E-03 -2.247442E-06 -5.145333E-03 -3.979329E-06 -6.496136E-03 -9.042875E-06 -3.832205E-03 -4.079904E-06 -1.091525E-02 -2.123166E-05 -1.100375E-02 -2.753282E-05 -6.452706E-03 -9.971091E-06 -5.931053E-03 -8.601691E-06 -9.574695E-03 -1.435980E-05 -6.378307E-03 -9.114546E-06 -1.035293E-02 -2.113676E-05 -5.515936E-03 -4.201853E-06 -5.579006E-03 -4.124072E-06 -9.045101E-03 -2.746668E-05 -7.146555E-03 -1.150230E-05 -6.281008E-03 -5.825971E-06 -5.295060E-03 -6.107698E-06 -4.285052E-03 -3.897963E-06 -1.261316E-02 -3.054847E-05 -1.248209E-02 -3.143433E-05 -1.216297E-02 -1.827405E-05 -1.257515E-02 -2.571939E-05 -8.877488E-03 -1.136667E-05 -1.224337E-02 -2.556328E-05 -1.610471E-02 -3.359843E-05 -1.376758E-02 -2.898825E-05 -1.066381E-02 -1.891264E-05 -1.370280E-02 -3.200949E-05 -1.218455E-02 -2.842079E-05 -1.205249E-02 -2.816694E-05 -1.292481E-02 -2.311574E-05 -1.500071E-02 -5.524516E-05 -1.629889E-02 -3.414163E-05 -1.715035E-02 -4.138447E-05 -7.880253E-03 -8.429037E-06 -1.066213E-02 -2.491824E-05 -1.071709E-02 -1.648251E-05 -1.278476E-02 -2.151462E-05 -2.029414E-02 -5.704631E-05 -1.835961E-02 -3.756414E-05 -1.086076E-02 -1.970149E-05 -1.953320E-02 -6.822321E-05 -1.727515E-02 -4.272841E-05 -2.113792E-02 -5.363596E-05 -1.255464E-02 -2.618423E-05 -1.849104E-02 -3.910212E-05 -1.080830E-02 -1.627578E-05 -1.065175E-02 -1.245618E-05 -1.729833E-02 -4.769086E-05 -1.229654E-02 -2.017586E-05 -2.000316E-02 -5.539455E-05 -1.490083E-02 -2.662412E-05 -1.257552E-02 -2.450638E-05 -2.265863E-02 -5.948942E-05 -1.592510E-02 -3.967897E-05 -1.671764E-02 -3.518609E-05 -2.134651E-02 -6.970473E-05 -1.145479E-02 -2.341492E-05 -1.110701E-02 -1.473716E-05 -1.365215E-02 -2.532562E-05 -1.569347E-02 -3.022408E-05 -1.740868E-02 -4.263025E-05 -2.046954E-02 -5.236013E-05 -2.088018E-02 -4.754884E-05 -2.143648E-02 -5.630377E-05 -2.321051E-02 -7.417245E-05 -1.393331E-02 -2.372413E-05 -1.272764E-02 -2.686784E-05 -1.996763E-02 -6.034803E-05 -1.543709E-02 -3.597724E-05 -1.374704E-02 -2.238864E-05 -1.485050E-02 -3.200278E-05 -1.630595E-02 -3.026169E-05 -1.885152E-02 -5.848418E-05 -1.903463E-02 -4.081588E-05 -2.873487E-02 -1.002249E-04 -2.191651E-02 -7.843435E-05 -2.375413E-02 -7.774516E-05 -1.237198E-02 -2.127422E-05 -1.942702E-02 -4.732051E-05 -2.103354E-02 -6.483331E-05 -1.285994E-02 -2.290156E-05 -1.249524E-02 -2.455002E-05 -1.236581E-02 -2.393541E-05 -1.379145E-02 -2.529751E-05 -1.562825E-02 -4.587015E-05 -2.641863E-02 -9.120767E-05 -2.733140E-02 -1.071137E-04 -1.919060E-02 -5.181037E-05 -2.129817E-02 -5.796235E-05 -1.260439E-02 -1.817703E-05 -1.848829E-02 -4.798194E-05 -1.216642E-02 -2.707330E-05 -1.410959E-02 -2.525781E-05 -9.453654E-03 -1.551579E-05 -9.766342E-03 -1.477317E-05 -1.836540E-02 -5.242882E-05 -1.804249E-02 -4.602986E-05 -1.853466E-02 -4.366676E-05 -1.525913E-02 -3.246161E-05 -1.673660E-02 -3.399297E-05 -1.837090E-02 -4.346348E-05 -1.396823E-02 -3.367275E-05 -9.246854E-03 -1.212445E-05 -1.410130E-02 -3.106294E-05 -1.307073E-02 -2.149583E-05 -9.704033E-03 -1.660514E-05 -1.044410E-02 -1.303462E-05 -1.166356E-02 -2.043704E-05 -1.318169E-02 -2.754937E-05 -1.812814E-02 -4.404582E-05 -1.552606E-02 -3.211975E-05 -1.585862E-02 -3.414359E-05 -1.446034E-02 -2.967784E-05 -7.649239E-03 -1.381600E-05 -6.893844E-03 -7.460924E-06 -1.354488E-02 -2.777125E-05 -1.007415E-02 -1.536552E-05 -8.075475E-03 -1.134760E-05 -1.130634E-02 -1.578798E-05 -6.590888E-03 -9.273749E-06 -7.448105E-03 -8.982164E-06 -5.823642E-03 -5.865562E-06 -9.093169E-03 -9.535064E-06 -4.848224E-03 -3.763431E-06 -9.282171E-03 -1.433250E-05 -1.127548E-02 -2.124250E-05 -9.878278E-03 -2.325491E-05 -1.039485E-02 -2.066791E-05 -1.155396E-02 -2.135511E-05 -1.450572E-02 -3.456258E-05 -1.246739E-02 -2.299204E-05 -1.290333E-02 -2.343647E-05 -1.121371E-02 -1.743282E-05 -5.468489E-03 -5.451707E-06 -1.180352E-02 -2.521651E-05 -1.416461E-02 -3.062871E-05 -1.076659E-02 -2.220002E-05 -2.448020E-02 -1.177322E-04 -1.517807E-02 -2.911032E-05 -1.031229E-02 -1.643057E-05 -1.200918E-02 -2.501705E-05 -1.613952E-02 -3.362754E-05 -1.378304E-02 -2.726242E-05 -1.857986E-02 -5.056092E-05 -1.576878E-02 -3.540682E-05 -1.910927E-02 -4.403442E-05 -1.829771E-02 -4.616084E-05 -1.164328E-02 -2.237054E-05 -1.680617E-02 -5.383688E-05 -2.087579E-02 -7.699421E-05 -2.381231E-02 -8.579600E-05 -1.885763E-02 -4.911360E-05 -2.649401E-02 -7.833957E-05 -1.350269E-02 -2.364349E-05 -1.757223E-02 -4.850663E-05 -2.411131E-02 -7.298399E-05 -2.774250E-02 -9.193073E-05 -2.282427E-02 -5.981367E-05 -2.721816E-02 -9.146779E-05 -2.832490E-02 -1.002337E-04 -2.942107E-02 -1.083982E-04 -2.629534E-02 -7.761525E-05 -2.690294E-02 -9.295211E-05 -2.031569E-02 -5.738480E-05 -2.590631E-02 -8.501230E-05 -3.031225E-02 -1.054523E-04 -2.423433E-02 -6.759709E-05 -3.382137E-02 -1.369015E-04 -2.496378E-02 -7.510237E-05 -2.672791E-02 -9.783698E-05 -2.507828E-02 -7.618011E-05 -1.769181E-02 -3.552782E-05 -2.096115E-02 -5.131019E-05 -3.063827E-02 -1.178430E-04 -3.120124E-02 -1.130478E-04 -2.031644E-02 -7.092047E-05 -2.760866E-02 -8.532139E-05 -2.786328E-02 -8.451452E-05 -2.700290E-02 -9.059845E-05 -3.660807E-02 -1.468682E-04 -3.105005E-02 -1.103431E-04 -3.734607E-02 -1.551359E-04 -3.447674E-02 -1.455364E-04 -2.264216E-02 -5.558419E-05 -2.211961E-02 -5.818600E-05 -3.130555E-02 -1.297184E-04 -3.457400E-02 -1.544678E-04 -2.687511E-02 -9.290746E-05 -3.047806E-02 -1.034500E-04 -3.560765E-02 -1.552412E-04 -3.095201E-02 -1.306105E-04 -3.230749E-02 -1.340962E-04 -2.928305E-02 -1.168468E-04 -4.265647E-02 -2.076643E-04 -3.298446E-02 -1.507110E-04 -2.986290E-02 -1.139639E-04 -3.435605E-02 -1.436737E-04 -3.052232E-02 -1.060392E-04 -3.396111E-02 -1.269448E-04 -3.167642E-02 -1.425279E-04 -2.821678E-02 -9.529119E-05 -4.113237E-02 -1.985887E-04 -3.525258E-02 -1.581696E-04 -3.297968E-02 -1.288343E-04 -2.799503E-02 -1.215560E-04 -4.104348E-02 -2.019357E-04 -3.825115E-02 -1.695340E-04 -2.776267E-02 -8.959306E-05 -3.443399E-02 -1.543941E-04 -2.347389E-02 -6.957205E-05 -2.325934E-02 -7.017456E-05 -2.441186E-02 -8.613195E-05 -1.983392E-02 -5.161177E-05 -2.710281E-02 -8.919133E-05 -2.744420E-02 -8.533228E-05 -2.193886E-02 -6.175359E-05 -1.830518E-02 -5.544200E-05 -2.341425E-02 -7.903797E-05 -2.450511E-02 -8.157422E-05 -2.452935E-02 -7.643569E-05 -3.274389E-02 -1.348587E-04 -9.730875E-03 -1.447356E-05 -1.623715E-02 -3.017421E-05 -1.516567E-02 -3.422832E-05 -1.065832E-02 -1.723340E-05 -1.938164E-02 -4.958486E-05 -1.489311E-02 -2.833615E-05 -1.617585E-02 -3.768666E-05 -1.471840E-02 -3.108380E-05 -1.804409E-02 -4.531066E-05 -2.150485E-02 -6.386092E-05 -1.088027E-02 -2.181372E-05 -1.017312E-02 -2.124217E-05 -1.432834E-02 -2.609903E-05 -1.583698E-02 -3.341095E-05 -9.743784E-03 -1.280783E-05 -7.846675E-03 -7.302042E-06 -9.804358E-03 -1.279367E-05 -1.297038E-02 -2.247676E-05 -1.204029E-02 -2.186972E-05 -8.944589E-03 -1.610694E-05 -1.437621E-02 -2.903841E-05 -1.162625E-02 -1.600570E-05 -5.705942E-03 -6.026539E-06 -9.949459E-03 -1.121060E-05 -1.355078E-02 -3.639982E-05 -1.253062E-02 -2.184327E-05 -1.128093E-02 -2.186156E-05 -1.351097E-02 -3.128150E-05 -1.302602E-02 -2.954976E-05 -1.581710E-02 -2.880115E-05 -8.299998E-03 -1.148143E-05 -1.419270E-02 -3.823010E-05 -8.195314E-03 -1.206128E-05 -1.089466E-02 -1.659227E-05 -1.434916E-02 -2.871463E-05 -1.677690E-02 -5.753038E-05 -2.577031E-02 -8.627098E-05 -2.327382E-02 -8.071762E-05 -2.476661E-02 -7.787162E-05 -2.107385E-02 -5.721321E-05 -1.990587E-02 -5.438566E-05 -1.715009E-02 -3.760846E-05 -2.840951E-02 -9.042931E-05 -2.308683E-02 -6.425853E-05 -2.068224E-02 -5.497174E-05 -2.518837E-02 -7.159468E-05 -1.844753E-02 -5.256599E-05 -2.195768E-02 -5.682427E-05 -4.576470E-02 -2.500482E-04 -3.107728E-02 -1.163017E-04 -3.132822E-02 -1.179930E-04 -3.352262E-02 -1.295829E-04 -2.943942E-02 -9.539846E-05 -3.672963E-02 -1.518887E-04 -3.639000E-02 -1.578688E-04 -3.932185E-02 -1.696900E-04 -3.126478E-02 -1.158570E-04 -3.784245E-02 -1.552955E-04 -3.346893E-02 -1.329769E-04 -3.045629E-02 -1.110202E-04 -4.501003E-02 -2.328334E-04 -5.330472E-02 -3.651809E-04 -4.289711E-02 -2.197266E-04 -3.259040E-02 -1.193252E-04 -4.449895E-02 -2.225829E-04 -4.124007E-02 -1.878125E-04 -4.737006E-02 -2.432331E-04 -4.433616E-02 -2.209854E-04 -5.530206E-02 -3.206482E-04 -6.256960E-02 -4.281638E-04 -5.285253E-02 -3.112894E-04 -4.439981E-02 -2.141823E-04 -5.016707E-02 -2.707515E-04 -6.882017E-02 -4.979869E-04 -4.465718E-02 -2.306648E-04 -3.888039E-02 -1.657354E-04 -5.385073E-02 -3.147914E-04 -4.640933E-02 -2.345368E-04 -7.051618E-02 -6.268651E-04 -4.375120E-02 -2.369745E-04 -6.068695E-02 -4.021878E-04 -6.068536E-02 -3.839552E-04 -3.602602E-02 -1.670809E-04 -4.995017E-02 -2.763744E-04 -4.392495E-02 -2.564028E-04 -5.093161E-02 -3.505664E-04 -4.432335E-02 -2.193425E-04 -4.855910E-02 -2.650606E-04 -5.176805E-02 -3.189213E-04 -4.890781E-02 -2.548831E-04 -6.554400E-02 -5.204569E-04 -6.588153E-02 -4.746561E-04 -6.675922E-02 -5.163608E-04 -7.271786E-02 -5.798664E-04 -4.837626E-02 -2.803260E-04 -5.224310E-02 -3.238220E-04 -4.580609E-02 -2.616101E-04 -5.119315E-02 -2.907515E-04 -4.372268E-02 -2.158620E-04 -4.124410E-02 -2.181852E-04 -4.882021E-02 -2.584581E-04 -5.914423E-02 -3.994010E-04 -4.163873E-02 -1.967708E-04 -3.798723E-02 -1.675576E-04 -6.178751E-02 -4.293350E-04 -5.052828E-02 -2.945947E-04 -3.889945E-02 -1.723031E-04 -4.778867E-02 -2.787658E-04 -2.556412E-02 -7.318557E-05 -3.450636E-02 -1.552235E-04 -2.997657E-02 -1.090031E-04 -2.250800E-02 -7.954622E-05 -3.846568E-02 -1.836107E-04 -3.701622E-02 -1.828496E-04 -3.972718E-02 -1.850244E-04 -2.403274E-02 -8.024833E-05 -3.407142E-02 -1.362787E-04 -3.563489E-02 -1.418007E-04 -2.285168E-02 -6.135475E-05 -3.573895E-02 -1.429096E-04 -1.944631E-02 -4.643790E-05 -2.223553E-02 -6.647009E-05 -2.178313E-02 -5.702943E-05 -1.885794E-02 -4.219512E-05 -2.626415E-02 -7.357902E-05 -2.590102E-02 -7.754226E-05 -1.790062E-02 -4.192871E-05 -1.566226E-02 -3.285418E-05 -2.611458E-02 -8.677724E-05 -2.644054E-02 -7.951101E-05 -1.688067E-02 -3.275169E-05 -2.281883E-02 -7.048130E-05 -1.383028E-02 -2.557495E-05 -1.750718E-02 -3.486088E-05 -1.458508E-02 -2.726606E-05 -1.229121E-02 -2.297397E-05 -1.858922E-02 -4.177321E-05 -1.787571E-02 -4.327284E-05 -6.566818E-03 -9.185537E-06 -1.448563E-02 -2.622240E-05 -1.621707E-02 -3.406357E-05 -1.085556E-02 -1.536032E-05 -1.333272E-02 -2.646991E-05 -1.453289E-02 -2.893412E-05 -1.518348E-02 -4.580967E-05 -1.404090E-02 -2.660292E-05 -1.349000E-02 -3.442831E-05 -1.633780E-02 -4.356999E-05 -1.600602E-02 -3.943089E-05 -1.590141E-02 -3.641474E-05 -1.086814E-02 -1.688254E-05 -1.698352E-02 -4.714162E-05 -1.318224E-02 -2.638496E-05 -1.119975E-02 -1.718066E-05 -1.575614E-02 -3.441783E-05 -1.418915E-02 -2.794370E-05 -1.971441E-02 -5.386951E-05 -2.749934E-02 -9.685175E-05 -2.450793E-02 -8.361790E-05 -3.096368E-02 -1.517345E-04 -1.966521E-02 -5.193037E-05 -1.488285E-02 -2.767080E-05 -2.628867E-02 -8.549789E-05 -3.222975E-02 -1.197226E-04 -3.578145E-02 -1.651405E-04 -2.717256E-02 -9.455312E-05 -2.846483E-02 -1.022437E-04 -2.373681E-02 -7.165349E-05 -4.893242E-02 -2.730109E-04 -3.477536E-02 -1.404582E-04 -4.928227E-02 -2.924560E-04 -4.544606E-02 -2.179936E-04 -3.160536E-02 -1.247483E-04 -4.089837E-02 -1.816429E-04 -6.363669E-02 -4.595645E-04 -5.951940E-02 -3.700880E-04 -3.810687E-02 -1.688583E-04 -5.679150E-02 -3.460302E-04 -5.729570E-02 -3.719866E-04 -5.082871E-02 -2.938785E-04 -7.469781E-02 -6.673208E-04 -6.652451E-02 -4.877821E-04 -6.401348E-02 -4.744885E-04 -5.622051E-02 -3.395523E-04 -6.073961E-02 -3.833605E-04 -6.232929E-02 -4.148823E-04 -7.969677E-02 -6.803601E-04 -8.037601E-02 -7.230061E-04 -7.865258E-02 -6.933305E-04 -9.845581E-02 -1.080566E-03 -6.878501E-02 -5.274776E-04 -7.015010E-02 -5.143444E-04 -1.156668E-01 -1.410105E-03 -1.192152E-01 -1.498896E-03 -7.577104E-02 -6.219937E-04 -8.184079E-02 -7.335058E-04 -1.139638E-01 -1.401155E-03 -8.075065E-02 -6.916698E-04 -1.437821E-01 -2.126013E-03 -8.850980E-02 -8.276893E-04 -1.464407E-01 -2.249915E-03 -1.357666E-01 -1.907685E-03 -8.903971E-02 -8.785322E-04 -1.035557E-01 -1.229512E-03 -9.987363E-02 -1.066492E-03 -1.408315E-01 -2.126682E-03 -7.775073E-02 -6.482580E-04 -9.217616E-02 -9.279523E-04 -1.346724E-01 -1.896751E-03 -8.733262E-02 -8.612501E-04 -9.983468E-02 -1.028984E-03 -9.096031E-02 -9.623493E-04 -1.646266E-01 -2.794929E-03 -1.304703E-01 -1.750382E-03 -8.811642E-02 -8.019013E-04 -1.067542E-01 -1.239326E-03 -4.255870E-02 -2.117948E-04 -6.657200E-02 -4.734337E-04 -6.716890E-02 -5.510834E-04 -4.697673E-02 -2.522950E-04 -9.074058E-02 -9.095881E-04 -7.248365E-02 -5.562525E-04 -5.894139E-02 -3.919992E-04 -4.322527E-02 -2.007041E-04 -8.846643E-02 -8.126375E-04 -8.094023E-02 -7.286166E-04 -5.884744E-02 -3.735579E-04 -6.484926E-02 -4.588123E-04 -4.890138E-02 -2.886686E-04 -5.972248E-02 -4.039813E-04 -4.560235E-02 -2.196157E-04 -4.488985E-02 -2.203187E-04 -6.734006E-02 -5.380869E-04 -5.510066E-02 -3.247707E-04 -4.520538E-02 -2.496589E-04 -4.217127E-02 -2.278109E-04 -5.551062E-02 -3.500669E-04 -4.092402E-02 -1.766989E-04 -4.298954E-02 -2.252953E-04 -4.437029E-02 -2.305532E-04 -3.704655E-02 -2.009774E-04 -3.598121E-02 -1.524807E-04 -3.045852E-02 -1.197202E-04 -2.601757E-02 -8.242731E-05 -3.357946E-02 -1.363746E-04 -3.932253E-02 -1.907001E-04 -2.390507E-02 -6.834171E-05 -2.346501E-02 -7.056602E-05 -3.597630E-02 -1.581562E-04 -3.090953E-02 -1.047491E-04 -2.070578E-02 -5.748122E-05 -3.347346E-02 -1.259074E-04 -1.513003E-02 -3.897988E-05 -1.367854E-02 -2.775960E-05 -1.645455E-02 -3.040738E-05 -1.324152E-02 -2.645298E-05 -1.588183E-02 -3.062863E-05 -1.734153E-02 -4.637284E-05 -1.634443E-02 -5.133843E-05 -1.119328E-02 -1.753195E-05 -1.323203E-02 -3.022286E-05 -1.135797E-02 -1.802055E-05 -1.090441E-02 -1.701011E-05 -1.759035E-02 -4.033287E-05 -2.242877E-02 -6.151790E-05 -1.946253E-02 -5.767287E-05 -1.450600E-02 -3.658456E-05 -2.053561E-02 -7.347202E-05 -2.172703E-02 -6.439721E-05 -1.970458E-02 -4.600512E-05 -1.750068E-02 -4.248050E-05 -2.615060E-02 -8.063501E-05 -1.471555E-02 -3.115498E-05 -1.390462E-02 -3.029928E-05 -2.277300E-02 -6.669696E-05 -1.701430E-02 -3.723197E-05 -3.366433E-02 -1.230840E-04 -2.650631E-02 -9.335504E-05 -2.977659E-02 -1.071113E-04 -3.153286E-02 -1.137530E-04 -2.593564E-02 -7.559506E-05 -2.027223E-02 -6.394080E-05 -3.666363E-02 -1.619679E-04 -4.008059E-02 -1.775008E-04 -2.019835E-02 -5.995987E-05 -3.269994E-02 -1.328649E-04 -4.298198E-02 -2.261101E-04 -3.478624E-02 -1.430238E-04 -5.024091E-02 -3.090307E-04 -5.399488E-02 -3.370022E-04 -4.802423E-02 -2.449581E-04 -4.962540E-02 -2.661791E-04 -4.714200E-02 -2.609694E-04 -5.413235E-02 -3.323523E-04 -7.865185E-02 -6.448405E-04 -6.245568E-02 -4.162905E-04 -4.774685E-02 -2.886302E-04 -6.062406E-02 -4.267779E-04 -6.732377E-02 -5.175823E-04 -5.345323E-02 -3.251415E-04 -1.081562E-01 -1.271390E-03 -1.021968E-01 -1.089652E-03 -9.531149E-02 -1.008862E-03 -1.099951E-01 -1.318432E-03 -8.728617E-02 -7.926236E-04 -6.759692E-02 -4.951495E-04 -1.622908E-01 -2.679920E-03 -1.297048E-01 -1.704599E-03 -1.105751E-01 -1.365137E-03 -1.338049E-01 -1.961877E-03 -1.135987E-01 -1.340952E-03 -9.047766E-02 -8.460145E-04 -5.706400E-01 -3.358746E-02 -5.767616E-01 -3.370236E-02 -1.875657E-01 -3.661666E-03 -1.871296E-01 -3.729992E-03 -2.210728E-01 -4.924615E-03 -1.665143E-01 -2.811366E-03 -8.372362E-01 -7.140730E-02 -2.631175E-01 -6.985957E-03 -5.750239E-01 -3.400521E-02 -4.828940E-01 -2.485485E-02 -1.859770E-01 -3.523984E-03 -1.672669E-01 -2.904958E-03 -2.375331E-01 -5.780405E-03 -7.840038E-01 -6.231709E-02 -2.132004E-01 -4.651951E-03 -1.326778E-01 -1.947761E-03 -8.211106E-01 -6.821312E-02 -2.477970E-01 -6.338987E-03 -2.133989E-01 -4.688136E-03 -1.689238E-01 -2.975501E-03 -7.799516E-01 -6.145987E-02 -2.571652E-01 -6.720137E-03 -1.616850E-01 -2.755887E-03 -1.967353E-01 -3.935902E-03 -8.257842E-02 -7.608737E-04 -1.275267E-01 -1.697194E-03 -9.926640E-02 -1.068598E-03 -8.218999E-02 -7.531509E-04 -1.532040E-01 -2.576896E-03 -1.294690E-01 -1.713096E-03 -7.154094E-02 -5.360062E-04 -7.586730E-02 -7.229435E-04 -1.259416E-01 -1.689821E-03 -9.056538E-02 -9.471446E-04 -8.469906E-02 -7.604134E-04 -1.005850E-01 -1.057108E-03 -4.463277E-02 -2.328840E-04 -5.523748E-02 -3.372196E-04 -5.232544E-02 -2.999576E-04 -4.417355E-02 -2.638798E-04 -5.782793E-02 -3.530500E-04 -5.944743E-02 -4.220391E-04 -3.657199E-02 -1.400109E-04 -3.808082E-02 -1.658520E-04 -6.410370E-02 -4.501663E-04 -4.310905E-02 -2.075429E-04 -4.755667E-02 -2.801406E-04 -4.959581E-02 -2.962253E-04 -2.252513E-02 -6.049713E-05 -2.991518E-02 -9.529790E-05 -2.664048E-02 -8.582855E-05 -2.475820E-02 -1.017459E-04 -3.488574E-02 -1.383218E-04 -2.890941E-02 -9.208222E-05 -2.098791E-02 -5.427914E-05 -1.943877E-02 -4.588171E-05 -3.481570E-02 -1.557210E-04 -2.398110E-02 -7.150967E-05 -2.011861E-02 -5.252956E-05 -2.839521E-02 -9.935802E-05 -1.502686E-02 -3.105045E-05 -1.609461E-02 -3.412102E-05 -2.098494E-02 -4.964297E-05 -1.885164E-02 -4.396914E-05 -1.991326E-02 -6.264911E-05 -1.856961E-02 -5.669686E-05 -1.440755E-02 -2.776990E-05 -1.370375E-02 -2.537463E-05 -1.757189E-02 -4.061709E-05 -1.902797E-02 -4.188635E-05 -1.135542E-02 -1.840125E-05 -1.821693E-02 -5.706852E-05 -1.966443E-02 -6.182591E-05 -1.098595E-02 -1.890446E-05 -1.880596E-02 -4.985208E-05 -2.224492E-02 -6.056638E-05 -1.938365E-02 -5.095134E-05 -2.004141E-02 -4.931528E-05 -1.584800E-02 -3.117640E-05 -8.716172E-03 -1.000356E-05 -1.306598E-02 -2.437620E-05 -1.303208E-02 -2.038909E-05 -1.496313E-02 -2.545249E-05 -9.598787E-03 -1.772891E-05 -3.131961E-02 -1.312684E-04 -2.918177E-02 -1.061777E-04 -3.088357E-02 -1.333663E-04 -3.322098E-02 -1.522259E-04 -1.912743E-02 -4.246859E-05 -2.493296E-02 -7.677374E-05 -3.831962E-02 -1.658539E-04 -3.935899E-02 -1.741789E-04 -2.392516E-02 -6.888699E-05 -3.042757E-02 -1.017878E-04 -3.071050E-02 -1.067951E-04 -3.345411E-02 -1.329032E-04 -5.446194E-02 -3.217845E-04 -4.790665E-02 -2.591914E-04 -4.370165E-02 -2.303527E-04 -4.427824E-02 -2.343428E-04 -4.182303E-02 -1.991080E-04 -4.098398E-02 -1.789986E-04 -6.431595E-02 -4.788578E-04 -6.788255E-02 -4.777967E-04 -4.412014E-02 -2.235134E-04 -5.533021E-02 -3.194019E-04 -5.464587E-02 -3.422291E-04 -5.703799E-02 -3.461325E-04 -1.119858E-01 -1.361306E-03 -9.089503E-02 -9.100663E-04 -9.511706E-02 -1.044926E-03 -1.074655E-01 -1.234547E-03 -7.705184E-02 -6.240812E-04 -6.897178E-02 -4.976520E-04 -1.412576E-01 -2.058554E-03 -1.216520E-01 -1.524026E-03 -8.791442E-02 -8.344056E-04 -1.037643E-01 -1.183835E-03 -8.708765E-02 -7.895562E-04 -8.580552E-02 -7.861920E-04 -7.918410E-01 -6.387826E-02 -2.447419E-01 -6.181230E-03 -4.587452E-01 -2.121897E-02 -5.203331E-01 -2.787312E-02 -1.850399E-01 -3.508673E-03 -1.651942E-01 -2.817305E-03 -5.838903E-01 -3.492429E-02 -5.155122E-01 -2.720158E-02 -1.904412E-01 -3.741626E-03 -1.981500E-01 -4.136229E-03 -2.022324E-01 -4.246984E-03 -1.652234E-01 -2.873591E-03 -5.115500E-01 -2.708582E-02 -5.791183E-01 -3.432760E-02 -8.107545E-01 -6.659574E-02 -2.634253E-01 -6.999531E-03 -4.915877E-01 -2.533318E-02 -5.693871E-01 -3.325807E-02 -1.791869E-01 -3.312861E-03 -1.858183E-01 -3.543802E-03 -2.123169E-01 -4.557530E-03 -1.672616E-01 -2.835857E-03 -1.711699E-01 -3.060667E-03 -1.758571E-01 -3.190864E-03 -9.235761E-02 -9.669475E-04 -1.140668E-01 -1.438348E-03 -1.377681E-01 -1.929906E-03 -1.011292E-01 -1.113302E-03 -1.364692E-01 -1.951502E-03 -1.414788E-01 -2.087246E-03 -7.454906E-02 -6.183963E-04 -7.314067E-02 -5.725364E-04 -1.053516E-01 -1.161166E-03 -8.265045E-02 -7.800060E-04 -9.317212E-02 -9.511500E-04 -9.087762E-02 -9.141004E-04 -5.226230E-02 -3.109563E-04 -5.578744E-02 -3.618499E-04 -6.973131E-02 -5.043558E-04 -6.157852E-02 -4.070680E-04 -6.811553E-02 -5.258915E-04 -7.611557E-02 -6.131989E-04 -5.088876E-02 -3.182936E-04 -5.436219E-02 -3.078199E-04 -5.597453E-02 -3.396588E-04 -4.107053E-02 -1.911728E-04 -4.290228E-02 -2.123049E-04 -5.788555E-02 -4.117326E-04 -2.353071E-02 -6.995800E-05 -3.463664E-02 -1.422097E-04 -2.918840E-02 -1.004566E-04 -2.736799E-02 -9.048433E-05 -3.463497E-02 -1.286836E-04 -4.726762E-02 -2.541389E-04 -2.411585E-02 -6.917613E-05 -2.704813E-02 -8.764995E-05 -2.810800E-02 -8.757217E-05 -2.291436E-02 -6.377954E-05 -3.013851E-02 -1.161125E-04 -2.972621E-02 -9.625050E-05 -1.751438E-02 -6.055922E-05 -2.205862E-02 -7.232896E-05 -1.960773E-02 -4.550316E-05 -1.937614E-02 -4.905471E-05 -2.518721E-02 -8.112827E-05 -2.590049E-02 -7.419054E-05 -1.339646E-02 -2.029891E-05 -2.067244E-02 -4.823190E-05 -2.295710E-02 -6.620610E-05 -8.933646E-03 -1.197590E-05 -2.088372E-02 -5.448793E-05 -1.573345E-02 -2.834414E-05 -1.618549E-02 -3.394500E-05 -1.562728E-02 -4.232429E-05 -1.762718E-02 -4.646038E-05 -1.691115E-02 -4.088904E-05 -1.778865E-02 -4.585630E-05 -1.699861E-02 -3.633558E-05 -1.474531E-02 -2.687795E-05 -1.191135E-02 -1.966547E-05 -1.368911E-02 -2.475254E-05 -8.726049E-03 -1.080420E-05 -1.855900E-02 -4.086770E-05 -1.042736E-02 -1.532968E-05 -2.750891E-02 -9.887827E-05 -2.557586E-02 -8.191188E-05 -2.651219E-02 -9.860563E-05 -2.544872E-02 -7.883150E-05 -2.096053E-02 -5.337477E-05 -1.819029E-02 -3.850870E-05 -3.202501E-02 -1.153271E-04 -2.876516E-02 -9.848331E-05 -2.271111E-02 -7.379330E-05 -2.854025E-02 -9.337598E-05 -2.824372E-02 -1.030571E-04 -2.318994E-02 -6.966557E-05 -4.138096E-02 -1.938864E-04 -3.680662E-02 -1.462240E-04 -3.808984E-02 -1.773752E-04 -4.968859E-02 -2.697606E-04 -3.120957E-02 -1.068433E-04 -3.625725E-02 -1.561439E-04 -4.266936E-02 -2.044742E-04 -5.527178E-02 -3.492180E-04 -3.492336E-02 -1.434781E-04 -3.345516E-02 -1.260850E-04 -5.316011E-02 -3.146473E-04 -3.770174E-02 -1.639797E-04 -7.987130E-02 -6.938936E-04 -5.700087E-02 -3.483872E-04 -7.902435E-02 -7.070267E-04 -8.115977E-02 -7.037262E-04 -5.028735E-02 -2.816840E-04 -5.862112E-02 -3.890181E-04 -8.026709E-02 -6.991067E-04 -8.844060E-02 -8.768540E-04 -6.027542E-02 -3.820896E-04 -5.955846E-02 -4.114052E-04 -7.223606E-02 -5.860849E-04 -8.036129E-02 -7.080829E-04 -1.251201E-01 -1.753212E-03 -9.518009E-02 -1.007169E-03 -1.499658E-01 -2.357452E-03 -1.582289E-01 -2.673309E-03 -9.723433E-02 -1.085206E-03 -9.223640E-02 -9.320231E-04 -1.244253E-01 -1.604811E-03 -1.389205E-01 -2.073518E-03 -8.898557E-02 -8.481843E-04 -8.699525E-02 -8.194442E-04 -1.194952E-01 -1.512778E-03 -8.679982E-02 -8.002571E-04 -1.529795E-01 -2.441631E-03 -1.087018E-01 -1.206359E-03 -1.572820E-01 -2.488454E-03 -1.378974E-01 -1.949060E-03 -1.016220E-01 -1.073888E-03 -1.189492E-01 -1.535660E-03 -9.307965E-02 -9.698515E-04 -9.538400E-02 -9.813891E-04 -9.106730E-02 -8.805352E-04 -8.371498E-02 -7.560974E-04 -1.021881E-01 -1.077841E-03 -9.309692E-02 -9.810570E-04 -6.954893E-02 -5.308895E-04 -7.248184E-02 -6.039844E-04 -8.357871E-02 -7.377145E-04 -7.117434E-02 -5.362599E-04 -9.546800E-02 -9.918303E-04 -8.154604E-02 -6.899246E-04 -5.541527E-02 -3.261092E-04 -5.781147E-02 -3.640210E-04 -7.071250E-02 -5.530093E-04 -7.012881E-02 -5.436620E-04 -5.986681E-02 -4.315165E-04 -7.228996E-02 -5.573189E-04 -4.764962E-02 -2.567629E-04 -4.978411E-02 -3.039433E-04 -5.251712E-02 -3.236802E-04 -3.942522E-02 -1.927267E-04 -5.510943E-02 -3.217347E-04 -5.118639E-02 -3.171944E-04 -4.252043E-02 -1.916953E-04 -4.412672E-02 -2.246415E-04 -4.088117E-02 -1.787513E-04 -3.610456E-02 -1.564509E-04 -3.814757E-02 -1.686026E-04 -4.627344E-02 -2.494575E-04 -1.994893E-02 -5.126553E-05 -3.216228E-02 -1.182156E-04 -2.950065E-02 -1.138201E-04 -2.866289E-02 -1.160231E-04 -3.983095E-02 -1.721863E-04 -4.012198E-02 -1.784164E-04 -2.106311E-02 -4.994977E-05 -2.781446E-02 -1.039157E-04 -3.488260E-02 -1.405115E-04 -2.875112E-02 -9.762388E-05 -3.224104E-02 -1.323284E-04 -3.641337E-02 -1.501812E-04 -1.480062E-02 -3.027272E-05 -1.408753E-02 -3.690601E-05 -1.944937E-02 -4.432175E-05 -1.283324E-02 -2.250887E-05 -2.073256E-02 -5.466671E-05 -2.186071E-02 -5.661539E-05 -1.133978E-02 -1.956348E-05 -1.049553E-02 -1.718390E-05 -1.539596E-02 -3.369585E-05 -2.039324E-02 -5.820403E-05 -1.043006E-02 -1.903901E-05 -2.777446E-02 -1.204671E-04 -1.484365E-02 -2.996962E-05 -1.109804E-02 -1.818652E-05 -9.835588E-03 -1.388426E-05 -1.478128E-02 -3.969614E-05 -1.020395E-02 -1.717436E-05 -1.487209E-02 -3.915846E-05 -9.230116E-03 -1.588076E-05 -8.372399E-03 -1.186179E-05 -8.663998E-03 -1.212384E-05 -1.164683E-02 -2.389782E-05 -1.148782E-02 -1.884731E-05 -9.267384E-03 -2.342255E-05 -2.492427E-02 -7.177126E-05 -1.937892E-02 -5.238888E-05 -1.533925E-02 -3.007374E-05 -2.897108E-02 -9.563790E-05 -1.504253E-02 -4.162972E-05 -1.506486E-02 -3.027445E-05 -2.421349E-02 -6.937729E-05 -1.981713E-02 -4.308765E-05 -2.688788E-02 -8.996617E-05 -2.298292E-02 -6.356151E-05 -2.521588E-02 -9.500495E-05 -1.944459E-02 -4.357545E-05 -4.894435E-02 -2.638450E-04 -3.864018E-02 -1.798269E-04 -3.849780E-02 -1.779556E-04 -4.806157E-02 -2.545276E-04 -2.419299E-02 -8.084015E-05 -2.835677E-02 -9.629003E-05 -3.964564E-02 -1.838380E-04 -4.177908E-02 -1.949235E-04 -3.068221E-02 -1.216833E-04 -3.203560E-02 -1.147717E-04 -3.493031E-02 -1.439593E-04 -3.780820E-02 -1.626400E-04 -5.390584E-02 -3.457131E-04 -3.911344E-02 -1.787461E-04 -5.600310E-02 -3.942394E-04 -5.721857E-02 -3.841430E-04 -3.425794E-02 -1.301099E-04 -4.896944E-02 -2.649497E-04 -5.468018E-02 -3.296430E-04 -5.960549E-02 -4.028002E-04 -4.289904E-02 -2.047984E-04 -3.417711E-02 -1.286477E-04 -5.147540E-02 -3.225127E-04 -4.429517E-02 -2.370511E-04 -5.333104E-02 -3.409602E-04 -6.102677E-02 -4.290957E-04 -7.075039E-02 -5.312660E-04 -7.760160E-02 -6.260977E-04 -5.110208E-02 -2.931608E-04 -6.284669E-02 -4.546881E-04 -6.386212E-02 -5.062176E-04 -7.791663E-02 -6.553468E-04 -4.847427E-02 -2.698567E-04 -5.036036E-02 -2.562333E-04 -6.628275E-02 -4.863329E-04 -5.107250E-02 -3.360646E-04 -5.438547E-02 -3.250878E-04 -5.955142E-02 -3.888695E-04 -6.613363E-02 -4.562672E-04 -7.873757E-02 -6.608787E-04 -4.633363E-02 -2.332785E-04 -6.000714E-02 -4.102538E-04 -5.607310E-02 -3.721702E-04 -7.224050E-02 -5.754880E-04 -5.604428E-02 -3.636927E-04 -4.542882E-02 -2.350087E-04 -6.010895E-02 -3.888132E-04 -5.026253E-02 -3.056826E-04 -5.083017E-02 -2.951657E-04 -4.774445E-02 -2.553998E-04 -6.166209E-02 -4.248389E-04 -5.750738E-02 -3.545368E-04 -5.475371E-02 -3.742657E-04 -5.136434E-02 -3.013480E-04 -4.625465E-02 -2.735615E-04 -5.057347E-02 -3.133161E-04 -4.695282E-02 -2.640479E-04 -3.979050E-02 -1.911432E-04 -5.106567E-02 -2.846885E-04 -4.782744E-02 -3.086692E-04 -2.945927E-02 -1.037190E-04 -3.548884E-02 -1.667740E-04 -4.339365E-02 -2.324267E-04 -3.578638E-02 -1.439546E-04 -4.531719E-02 -2.379087E-04 -4.291461E-02 -2.163748E-04 -2.831504E-02 -9.351629E-05 -2.425588E-02 -6.929284E-05 -3.519439E-02 -1.401196E-04 -3.174238E-02 -1.187918E-04 -2.505587E-02 -7.333276E-05 -3.252855E-02 -1.518816E-04 -2.315654E-02 -6.200895E-05 -2.574270E-02 -7.613474E-05 -2.520902E-02 -7.303619E-05 -2.985551E-02 -9.745575E-05 -2.508447E-02 -9.702485E-05 -2.448965E-02 -6.790622E-05 -1.765762E-02 -3.709919E-05 -1.979233E-02 -4.686113E-05 -2.477181E-02 -7.217121E-05 -2.046923E-02 -5.529696E-05 -1.619249E-02 -3.536888E-05 -3.084138E-02 -1.038251E-04 -1.430547E-02 -2.813880E-05 -1.024198E-02 -1.564502E-05 -1.440933E-02 -2.677391E-05 -1.139030E-02 -1.562766E-05 -1.706815E-02 -3.602648E-05 -1.960477E-02 -5.223127E-05 -1.075038E-02 -1.946902E-05 -8.176023E-03 -9.795109E-06 -1.400712E-02 -2.798724E-05 -9.098651E-03 -2.320760E-05 -1.621999E-02 -5.890457E-05 -1.662025E-02 -5.381012E-05 -1.501846E-02 -3.187427E-05 -1.115569E-02 -2.112610E-05 -8.934007E-03 -1.127244E-05 -1.053736E-02 -2.738972E-05 -1.687632E-02 -3.758437E-05 -1.176928E-02 -1.998369E-05 -1.090722E-02 -2.070033E-05 -1.922176E-02 -4.611119E-05 -6.410110E-03 -7.146719E-06 -3.860269E-03 -5.922652E-06 -6.045740E-03 -5.074973E-06 -4.971635E-03 -3.431959E-06 -2.426203E-02 -7.370761E-05 -2.680359E-02 -8.998719E-05 -1.630553E-02 -3.567524E-05 -1.914533E-02 -4.240964E-05 -1.508665E-02 -2.912142E-05 -1.672855E-02 -3.656656E-05 -1.451039E-02 -2.817950E-05 -1.687413E-02 -4.142926E-05 -1.597006E-02 -4.478288E-05 -1.688899E-02 -3.586099E-05 -1.833640E-02 -5.132894E-05 -2.002488E-02 -5.326859E-05 -1.914416E-02 -5.599172E-05 -2.207570E-02 -7.740090E-05 -2.366938E-02 -6.568915E-05 -2.649512E-02 -1.020488E-04 -1.483135E-02 -2.984413E-05 -1.887848E-02 -4.268175E-05 -3.001817E-02 -1.047979E-04 -2.212608E-02 -6.788700E-05 -2.058642E-02 -5.920693E-05 -2.072658E-02 -5.071607E-05 -1.860802E-02 -4.555855E-05 -1.666833E-02 -3.918400E-05 -2.410251E-02 -7.518781E-05 -2.431099E-02 -9.040361E-05 -3.409049E-02 -1.428531E-04 -3.176194E-02 -1.054320E-04 -3.008617E-02 -1.140028E-04 -3.827724E-02 -1.656866E-04 -3.578801E-02 -1.469705E-04 -3.205988E-02 -1.211102E-04 -2.718611E-02 -8.166121E-05 -3.164768E-02 -1.161478E-04 -2.324305E-02 -6.697244E-05 -2.947200E-02 -1.259054E-04 -2.746439E-02 -9.282287E-05 -2.653377E-02 -8.108059E-05 -4.445537E-02 -2.152169E-04 -4.052651E-02 -1.733821E-04 -3.053999E-02 -1.118515E-04 -4.177700E-02 -2.106180E-04 -3.721658E-02 -1.614887E-04 -4.250554E-02 -2.125286E-04 -3.259794E-02 -1.259532E-04 -3.279076E-02 -1.281014E-04 -3.769459E-02 -1.592958E-04 -3.620173E-02 -1.496207E-04 -3.630649E-02 -1.531507E-04 -3.419905E-02 -1.389163E-04 -3.811683E-02 -1.632070E-04 -3.778477E-02 -1.788000E-04 -3.255090E-02 -1.292645E-04 -4.054674E-02 -2.009707E-04 -3.396471E-02 -1.380670E-04 -2.970522E-02 -1.194017E-04 -2.926855E-02 -1.209863E-04 -2.414836E-02 -7.131380E-05 -2.902285E-02 -9.925626E-05 -3.804797E-02 -1.754536E-04 -2.561987E-02 -7.861985E-05 -2.621638E-02 -8.635601E-05 -3.392178E-02 -1.612402E-04 -2.949056E-02 -1.075244E-04 -2.861194E-02 -9.347554E-05 -3.281854E-02 -1.750223E-04 -2.528376E-02 -8.170461E-05 -2.855965E-02 -1.276904E-04 -2.210588E-02 -6.285379E-05 -1.501664E-02 -3.174414E-05 -2.485082E-02 -8.044179E-05 -2.609565E-02 -9.700928E-05 -3.800572E-02 -1.865757E-04 -1.880640E-02 -4.090279E-05 -2.909814E-02 -1.043206E-04 -3.180763E-02 -1.216425E-04 -1.518998E-02 -2.699690E-05 -2.630226E-02 -9.511365E-05 -2.282938E-02 -6.428433E-05 -2.493692E-02 -7.780311E-05 -1.137087E-02 -2.156846E-05 -1.680608E-02 -3.976947E-05 -2.724734E-02 -8.526080E-05 -3.353531E-02 -1.249343E-04 -1.997488E-02 -5.686628E-05 -1.952335E-02 -5.168354E-05 -2.332315E-02 -6.296001E-05 -1.903421E-02 -4.970639E-05 -1.988764E-02 -4.758272E-05 -2.237483E-02 -6.308654E-05 -2.024263E-02 -6.708430E-05 -1.794493E-02 -3.980589E-05 -1.605168E-02 -3.661129E-05 -1.264028E-02 -2.003973E-05 -1.316289E-02 -3.041847E-05 -2.132558E-02 -7.506854E-05 -1.515922E-02 -4.400695E-05 -1.165029E-02 -3.144519E-05 -1.431392E-02 -3.510266E-05 -9.378262E-03 -1.745913E-05 -1.348722E-02 -2.279535E-05 -1.219541E-02 -2.124436E-05 -9.186874E-03 -1.308201E-05 -5.510134E-03 -6.127474E-06 -1.018457E-02 -2.037011E-05 -7.480002E-03 -8.821059E-06 -1.284192E-02 -2.896216E-05 -1.251268E-02 -2.241281E-05 -1.134027E-02 -1.937376E-05 -9.348782E-03 -1.387252E-05 -1.595911E-02 -3.477329E-05 -1.611731E-02 -4.121294E-05 -5.771625E-03 -5.262561E-06 -1.339971E-02 -2.328961E-05 -4.724286E-03 -7.486861E-06 -7.887185E-03 -1.309912E-05 -1.017668E-02 -1.329563E-05 -9.929419E-03 -2.048058E-05 -1.172543E-02 -2.164855E-05 -8.748399E-03 -1.455014E-05 -7.388493E-03 -1.213908E-05 -9.357160E-03 -1.459184E-05 -1.182596E-02 -2.754657E-05 -1.376694E-02 -2.808688E-05 -8.736677E-03 -1.261523E-05 -1.058599E-02 -2.132582E-05 -8.904592E-03 -1.412855E-05 -8.871956E-03 -1.042407E-05 -4.818722E-03 -5.533432E-06 -7.132170E-03 -1.066330E-05 -1.265366E-02 -2.062988E-05 -1.146186E-02 -1.978609E-05 -1.727631E-02 -6.317086E-05 -9.722001E-03 -1.628574E-05 -1.808415E-02 -4.814964E-05 -2.313210E-02 -7.257429E-05 -6.096746E-03 -8.507143E-06 -1.095433E-02 -2.574564E-05 -1.144512E-02 -2.130606E-05 -1.709946E-02 -3.435958E-05 -5.794154E-03 -4.298264E-06 -1.345102E-02 -2.470605E-05 -1.674615E-02 -3.806453E-05 -1.058112E-02 -1.675643E-05 -1.487609E-02 -2.876672E-05 -1.727197E-02 -4.888253E-05 -2.720121E-02 -8.232238E-05 -3.268443E-02 -1.194042E-04 -1.427634E-02 -2.639442E-05 -2.055060E-02 -5.261649E-05 -1.637582E-02 -3.886105E-05 -2.416272E-02 -6.712570E-05 -1.431266E-02 -2.383080E-05 -1.632066E-02 -3.444426E-05 -2.435113E-02 -8.254028E-05 -2.015885E-02 -5.481740E-05 -1.973867E-02 -5.116489E-05 -1.865655E-02 -4.752313E-05 -3.165189E-02 -1.474543E-04 -3.338700E-02 -1.226611E-04 -1.856968E-02 -4.098217E-05 -2.747306E-02 -8.290244E-05 -3.019952E-02 -1.096277E-04 -2.941793E-02 -9.471376E-05 -1.359209E-02 -2.775872E-05 -1.604302E-02 -3.176242E-05 -2.130560E-02 -6.015704E-05 -2.273639E-02 -7.032069E-05 -2.128699E-02 -6.074255E-05 -1.492456E-02 -3.510276E-05 -2.424866E-02 -6.867482E-05 -2.858266E-02 -9.553376E-05 -1.423686E-02 -2.731632E-05 -2.183114E-02 -5.075377E-05 -1.790750E-02 -4.419157E-05 -2.189439E-02 -5.678221E-05 -1.528824E-02 -2.994220E-05 -1.591232E-02 -3.345909E-05 -2.006375E-02 -5.328672E-05 -1.926568E-02 -5.794406E-05 -1.995889E-02 -5.771200E-05 -2.190352E-02 -6.226272E-05 -2.344085E-02 -7.170778E-05 -1.490160E-02 -3.189456E-05 -1.964283E-02 -4.674552E-05 -1.729274E-02 -5.276904E-05 -2.041435E-02 -6.736760E-05 -1.278262E-02 -2.244619E-05 -1.454136E-02 -3.039925E-05 -9.619956E-03 -1.773332E-05 -1.228153E-02 -2.003326E-05 -9.672849E-03 -1.662330E-05 -1.711969E-02 -5.651042E-05 -1.584751E-02 -3.641664E-05 -1.935632E-02 -5.597824E-05 -1.126109E-02 -1.753857E-05 -1.782849E-02 -4.695997E-05 -1.381158E-02 -2.666475E-05 -1.219375E-02 -1.818815E-05 -1.066559E-02 -2.272800E-05 -1.442020E-02 -2.898674E-05 -1.020932E-02 -1.446241E-05 -1.118415E-02 -1.992502E-05 -8.105784E-03 -1.344204E-05 -1.498438E-02 -4.583095E-05 -1.019191E-02 -1.878658E-05 -1.933752E-02 -5.597403E-05 -1.355162E-02 -2.693353E-05 -1.009187E-02 -1.416651E-05 -1.762231E-02 -4.342948E-05 -8.265997E-03 -1.115148E-05 -7.740105E-03 -9.350881E-06 -6.132761E-03 -5.990846E-06 -8.311803E-03 -1.337310E-05 -1.148410E-02 -2.801843E-05 -1.254654E-02 -2.859306E-05 -5.729723E-03 -7.417371E-06 -3.329556E-03 -2.852362E-06 -8.995510E-03 -1.519541E-05 -9.885451E-03 -1.504316E-05 -8.000781E-03 -1.318972E-05 -8.116139E-03 -1.599393E-05 -5.483106E-03 -5.909268E-06 -7.119776E-03 -7.398166E-06 -5.696562E-03 -8.267139E-06 -3.253311E-03 -3.490487E-06 -7.617341E-03 -1.591870E-05 -4.477136E-03 -4.507128E-06 -4.186692E-03 -4.522007E-06 -9.913744E-03 -1.537264E-05 -5.097688E-03 -5.151058E-06 -3.958711E-03 -4.681053E-06 -8.278901E-03 -1.024219E-05 -8.835906E-03 -1.016849E-05 -8.456874E-03 -1.177568E-05 -1.261330E-02 -3.084433E-05 -4.949744E-03 -4.615766E-06 -3.553617E-03 -2.732540E-06 -9.121684E-03 -1.577246E-05 -1.008197E-02 -2.084343E-05 -1.384668E-02 -3.110319E-05 -6.699315E-03 -6.544515E-06 -9.247650E-03 -1.217430E-05 -1.382529E-02 -2.309065E-05 -1.239699E-02 -2.979052E-05 -7.678409E-03 -9.823153E-06 -1.313584E-02 -2.664709E-05 -1.402449E-02 -3.295040E-05 -1.404510E-02 -2.328440E-05 -1.395545E-02 -3.064026E-05 -6.468889E-03 -1.142683E-05 -1.117536E-02 -2.247013E-05 -7.150789E-03 -7.587094E-06 -1.607791E-02 -4.401441E-05 -1.397191E-02 -2.767660E-05 -1.377649E-02 -3.853853E-05 -9.740469E-03 -1.610242E-05 -1.439220E-02 -3.310057E-05 -1.312482E-02 -2.812275E-05 -9.319391E-03 -1.598131E-05 -1.513017E-02 -3.596580E-05 -1.246425E-02 -2.621144E-05 -1.701677E-02 -4.718452E-05 -1.345504E-02 -2.750081E-05 -1.915828E-02 -6.206762E-05 -1.487706E-02 -3.498164E-05 -1.808302E-02 -5.043185E-05 -1.413342E-02 -3.559061E-05 -1.138146E-02 -1.786839E-05 -1.140044E-02 -1.941117E-05 -1.554299E-02 -2.899451E-05 -1.350147E-02 -2.424308E-05 -2.075976E-02 -7.307325E-05 -1.356231E-02 -2.080054E-05 -1.518370E-02 -3.316853E-05 -1.189204E-02 -1.901003E-05 -2.058005E-02 -5.143687E-05 -2.045751E-02 -5.497205E-05 -1.513733E-02 -2.666165E-05 -1.753330E-02 -3.936189E-05 -1.683976E-02 -3.581825E-05 -1.511066E-02 -2.645123E-05 -1.175520E-02 -1.609321E-05 -1.932866E-02 -4.358405E-05 -2.152647E-02 -5.525043E-05 -1.359163E-02 -2.720874E-05 -1.591814E-02 -3.441323E-05 -1.498891E-02 -3.242215E-05 -1.394632E-02 -2.541758E-05 -1.898119E-02 -4.729644E-05 -1.689587E-02 -3.933248E-05 -1.435155E-02 -2.582993E-05 -1.316763E-02 -2.353008E-05 -1.157136E-02 -1.833702E-05 -1.655168E-02 -3.162804E-05 -1.516917E-02 -4.365366E-05 -2.271626E-02 -6.252949E-05 -2.415893E-02 -6.451266E-05 -1.132077E-02 -1.979205E-05 -1.218269E-02 -1.887580E-05 -1.457860E-02 -2.603959E-05 -1.799378E-02 -3.831940E-05 -1.973304E-02 -5.131280E-05 -1.650072E-02 -4.421326E-05 -1.309761E-02 -2.093703E-05 -9.968119E-03 -1.734048E-05 -2.388636E-02 -8.126332E-05 -1.459477E-02 -3.488715E-05 -2.918991E-02 -9.400845E-05 -2.039305E-02 -4.974054E-05 -1.348400E-02 -3.490462E-05 -1.687564E-02 -4.279173E-05 -1.513373E-02 -2.823507E-05 -1.994888E-02 -5.071283E-05 -1.764059E-02 -4.346435E-05 -1.859116E-02 -5.299840E-05 -1.380401E-02 -2.348130E-05 -1.635474E-02 -3.937702E-05 -2.064198E-02 -5.607997E-05 -1.842824E-02 -4.282589E-05 -2.078636E-02 -5.236688E-05 -1.710805E-02 -3.985969E-05 -1.543166E-02 -3.277155E-05 -1.311119E-02 -2.103436E-05 -1.223030E-02 -1.772840E-05 -1.428400E-02 -2.879115E-05 -1.711044E-02 -3.871812E-05 -1.431954E-02 -2.831455E-05 -7.837091E-03 -1.187250E-05 -7.756280E-03 -8.554725E-06 -7.995791E-03 -1.095905E-05 -8.605179E-03 -1.177231E-05 -8.958756E-03 -1.332678E-05 -1.034574E-02 -2.171120E-05 -6.001176E-03 -7.941410E-06 -1.257551E-02 -2.312537E-05 -4.129076E-03 -2.677243E-06 -8.501326E-03 -1.658402E-05 -5.816010E-03 -5.905913E-06 -7.839173E-03 -8.421697E-06 -5.918322E-03 -9.025041E-06 -5.736561E-03 -7.633742E-06 -9.243956E-03 -1.198288E-05 -8.562607E-03 -9.900387E-06 -8.517736E-03 -1.400152E-05 -8.058111E-03 -8.346635E-06 -6.429181E-03 -8.483646E-06 -9.766782E-03 -1.860263E-05 -8.854052E-03 -1.734509E-05 -8.929637E-03 -1.491512E-05 -5.233001E-03 -5.925028E-06 -9.295152E-03 -1.768126E-05 -1.257918E-02 -2.632079E-05 -1.127993E-02 -1.815069E-05 -1.522302E-02 -3.459869E-05 -2.039110E-02 -6.104303E-05 -7.018288E-03 -8.011469E-06 -1.296372E-02 -2.439899E-05 -1.344461E-02 -3.144942E-05 -1.591259E-02 -3.662184E-05 -1.592134E-02 -3.534978E-05 -1.397292E-02 -2.673400E-05 -1.387726E-02 -2.413584E-05 -1.403292E-02 -2.450220E-05 -1.623686E-02 -3.934040E-05 -1.455326E-02 -3.956697E-05 -1.848869E-02 -4.594096E-05 -1.562335E-02 -2.895160E-05 -1.934214E-02 -6.527205E-05 -2.762082E-02 -1.002001E-04 -1.646443E-02 -4.757237E-05 -1.974118E-02 -5.871473E-05 -1.812863E-02 -4.571190E-05 -2.841456E-02 -1.256913E-04 -1.572056E-02 -3.604561E-05 -1.479375E-02 -4.114818E-05 -2.139729E-02 -5.158299E-05 -1.827112E-02 -4.755220E-05 -2.918330E-02 -9.121760E-05 -1.800084E-02 -4.226384E-05 -2.357640E-02 -6.593693E-05 -2.849119E-02 -1.014082E-04 -2.107159E-02 -6.738763E-05 -2.185077E-02 -6.120235E-05 -1.870103E-02 -5.126759E-05 -2.228030E-02 -5.885366E-05 -1.218959E-02 -1.923700E-05 -1.518833E-02 -2.980819E-05 -2.131881E-02 -6.164198E-05 -1.857691E-02 -5.149996E-05 -1.967993E-02 -4.929073E-05 -2.037752E-02 -5.254462E-05 -2.428694E-02 -7.415972E-05 -2.311199E-02 -5.830300E-05 -1.781340E-02 -5.016711E-05 -2.109282E-02 -5.439384E-05 -2.646402E-02 -7.981598E-05 -2.872928E-02 -1.157883E-04 -2.296882E-02 -5.600052E-05 -2.145069E-02 -6.153603E-05 -3.194172E-02 -1.130937E-04 -2.556185E-02 -8.976008E-05 -2.450563E-02 -7.657853E-05 -2.632135E-02 -8.318821E-05 -2.937358E-02 -9.572656E-05 -2.779408E-02 -9.729157E-05 -2.029619E-02 -5.815728E-05 -2.107188E-02 -5.405801E-05 -2.864120E-02 -9.187238E-05 -3.189900E-02 -1.158697E-04 -2.174543E-02 -6.126120E-05 -1.866666E-02 -3.831554E-05 -4.074514E-02 -2.019874E-04 -3.077997E-02 -1.155565E-04 -2.845511E-02 -9.760556E-05 -2.358164E-02 -7.014622E-05 -3.662127E-02 -1.520968E-04 -3.309700E-02 -1.256130E-04 -2.775361E-02 -1.078304E-04 -3.177889E-02 -1.327385E-04 -2.523394E-02 -8.921547E-05 -3.189185E-02 -1.647022E-04 -2.967954E-02 -1.071890E-04 -2.119897E-02 -5.752892E-05 -3.434445E-02 -1.342008E-04 -2.714518E-02 -8.681886E-05 -2.897958E-02 -9.065153E-05 -2.696222E-02 -8.540024E-05 -2.987888E-02 -9.648932E-05 -2.811456E-02 -9.230152E-05 -2.638667E-02 -8.721739E-05 -3.440902E-02 -1.421180E-04 -2.352488E-02 -7.481613E-05 -3.172354E-02 -1.853144E-04 -2.170608E-02 -6.022568E-05 -1.913037E-02 -5.905188E-05 -3.295652E-02 -1.433947E-04 -2.543187E-02 -9.035364E-05 -1.729217E-02 -3.824473E-05 -1.983528E-02 -6.034582E-05 -3.265521E-02 -1.315037E-04 -2.437483E-02 -7.364625E-05 -1.554696E-02 -3.206723E-05 -2.145024E-02 -5.715848E-05 -1.057830E-02 -1.743678E-05 -1.046397E-02 -1.560587E-05 -9.479417E-03 -1.712347E-05 -1.254587E-02 -3.235855E-05 -1.579355E-02 -4.509260E-05 -1.484926E-02 -2.799512E-05 -1.228686E-02 -2.031169E-05 -1.212962E-02 -2.512835E-05 -1.657642E-02 -4.655608E-05 -1.385236E-02 -2.324629E-05 -1.422372E-02 -4.206039E-05 -1.285229E-02 -2.234088E-05 -1.063684E-02 -2.048991E-05 -1.054286E-02 -1.650301E-05 -7.250865E-03 -8.349919E-06 -4.846842E-03 -5.611575E-06 -6.655706E-03 -8.978424E-06 -1.009164E-02 -1.254527E-05 -8.369823E-03 -8.564886E-06 -7.078759E-03 -7.850385E-06 -6.511893E-03 -7.778046E-06 -9.070684E-03 -1.106525E-05 -6.662311E-03 -5.901628E-06 -5.341082E-03 -4.512027E-06 -2.019250E-02 -5.835499E-05 -1.804537E-02 -4.752474E-05 -2.143023E-02 -6.883510E-05 -1.472836E-02 -3.235428E-05 -2.050065E-02 -5.392162E-05 -1.244535E-02 -2.314093E-05 -1.512563E-02 -2.709722E-05 -1.844357E-02 -4.096498E-05 -1.230849E-02 -2.204180E-05 -1.094959E-02 -1.878473E-05 -1.443675E-02 -2.665387E-05 -1.322804E-02 -2.121836E-05 -2.663562E-02 -9.639039E-05 -3.653391E-02 -1.705389E-04 -2.009980E-02 -5.226492E-05 -2.269292E-02 -7.235254E-05 -2.630232E-02 -8.600830E-05 -2.058472E-02 -6.670991E-05 -2.641568E-02 -9.197032E-05 -2.754053E-02 -1.038311E-04 -3.121142E-02 -1.199600E-04 -2.717065E-02 -9.654646E-05 -2.242629E-02 -1.009563E-04 -2.075151E-02 -5.816770E-05 -3.942214E-02 -1.987805E-04 -3.882076E-02 -1.939596E-04 -2.920978E-02 -1.084721E-04 -2.600676E-02 -8.334881E-05 -2.923234E-02 -1.017212E-04 -3.586528E-02 -1.334235E-04 -3.797598E-02 -1.702103E-04 -3.232846E-02 -1.218180E-04 -3.377761E-02 -1.378231E-04 -4.192066E-02 -2.072314E-04 -2.738955E-02 -8.865239E-05 -3.568104E-02 -1.804686E-04 -3.548082E-02 -1.615200E-04 -5.031302E-02 -3.122101E-04 -3.009267E-02 -1.144558E-04 -3.199905E-02 -1.145847E-04 -3.777360E-02 -1.663536E-04 -3.384202E-02 -1.350575E-04 -4.560705E-02 -2.708256E-04 -3.136124E-02 -1.138594E-04 -4.666445E-02 -2.341642E-04 -4.832203E-02 -2.735704E-04 -2.846160E-02 -9.724755E-05 -3.958876E-02 -1.723911E-04 -3.564894E-02 -1.460291E-04 -5.846112E-02 -3.948391E-04 -3.546238E-02 -1.608118E-04 -3.537206E-02 -1.460004E-04 -5.554597E-02 -3.566908E-04 -5.109455E-02 -3.208060E-04 -5.520597E-02 -3.527162E-04 -4.201987E-02 -1.917230E-04 -6.660358E-02 -4.711986E-04 -5.432898E-02 -3.242512E-04 -4.089084E-02 -1.879065E-04 -3.784277E-02 -1.557193E-04 -5.046288E-02 -2.834904E-04 -5.513093E-02 -3.595041E-04 -3.711842E-02 -1.494648E-04 -4.392972E-02 -2.015209E-04 -4.988699E-02 -2.634722E-04 -3.989393E-02 -1.816607E-04 -5.144002E-02 -2.769398E-04 -4.565016E-02 -2.355239E-04 -6.482286E-02 -4.539075E-04 -4.470289E-02 -2.139336E-04 -4.617957E-02 -2.463023E-04 -4.418753E-02 -2.283032E-04 -4.649993E-02 -2.511721E-04 -4.930410E-02 -2.838380E-04 -3.882151E-02 -1.837693E-04 -2.680799E-02 -8.238578E-05 -5.755520E-02 -4.130996E-04 -4.496883E-02 -2.557734E-04 -3.602591E-02 -1.512327E-04 -2.530643E-02 -9.160435E-05 -4.057178E-02 -1.911452E-04 -3.912871E-02 -1.943839E-04 -2.823744E-02 -1.084509E-04 -3.870972E-02 -1.741549E-04 -2.669650E-02 -9.821873E-05 -3.580275E-02 -1.589657E-04 -2.195198E-02 -5.837423E-05 -2.079687E-02 -6.448549E-05 -3.002400E-02 -1.160249E-04 -2.957314E-02 -1.189151E-04 -2.377935E-02 -6.808549E-05 -1.839041E-02 -4.555435E-05 -3.430294E-02 -1.387042E-04 -2.592718E-02 -9.050017E-05 -1.535960E-02 -3.794370E-05 -2.078265E-02 -7.317160E-05 -1.576237E-02 -2.996656E-05 -2.216535E-02 -6.517900E-05 -1.811146E-02 -4.238302E-05 -1.455371E-02 -3.667385E-05 -2.634667E-02 -8.364438E-05 -1.996539E-02 -4.953189E-05 -1.816175E-02 -3.710475E-05 -1.218979E-02 -2.484826E-05 -2.442424E-02 -8.794676E-05 -2.372381E-02 -7.702420E-05 -2.231590E-02 -9.784571E-05 -2.172844E-02 -5.916333E-05 -1.145998E-02 -1.962910E-05 -1.702504E-02 -5.111810E-05 -6.914654E-03 -8.875412E-06 -1.075152E-02 -2.522276E-05 -1.773996E-02 -4.090619E-05 -9.269666E-03 -1.495738E-05 -1.266630E-02 -2.461812E-05 -1.423043E-02 -3.464040E-05 -1.459824E-02 -3.078483E-05 -9.387052E-03 -1.202926E-05 -9.667799E-03 -1.454321E-05 -9.447707E-03 -1.271935E-05 -1.549107E-02 -2.931692E-05 -1.961989E-02 -5.758509E-05 -1.679927E-02 -4.376812E-05 -1.729049E-02 -4.546154E-05 -2.214419E-02 -5.744861E-05 -1.574631E-02 -3.404805E-05 -1.512389E-02 -2.852541E-05 -1.564070E-02 -2.961719E-05 -1.156911E-02 -1.664384E-05 -1.199574E-02 -1.963095E-05 -1.575890E-02 -3.865614E-05 -8.533212E-03 -1.165342E-05 -2.974207E-02 -1.029138E-04 -3.078702E-02 -1.267340E-04 -2.895029E-02 -9.417641E-05 -2.705881E-02 -1.080454E-04 -2.385421E-02 -7.531760E-05 -2.083704E-02 -6.502784E-05 -3.429066E-02 -1.504413E-04 -3.503625E-02 -1.408918E-04 -2.706075E-02 -8.947448E-05 -3.189758E-02 -1.230472E-04 -2.544089E-02 -8.519294E-05 -2.520959E-02 -8.797041E-05 -5.070461E-02 -3.189504E-04 -4.884044E-02 -2.572701E-04 -3.547633E-02 -1.862450E-04 -4.388084E-02 -2.567378E-04 -3.492269E-02 -1.420917E-04 -2.806485E-02 -1.009649E-04 -5.059445E-02 -2.907485E-04 -4.808491E-02 -2.424314E-04 -4.942392E-02 -3.097207E-04 -3.897127E-02 -1.994484E-04 -3.839420E-02 -1.746523E-04 -3.244417E-02 -1.184480E-04 -5.623036E-02 -3.492166E-04 -6.425888E-02 -4.935669E-04 -4.877756E-02 -2.579133E-04 -4.955342E-02 -2.926551E-04 -5.396104E-02 -3.055339E-04 -5.871614E-02 -3.961828E-04 -6.708244E-02 -4.826510E-04 -5.278021E-02 -2.835069E-04 -6.918022E-02 -5.087677E-04 -5.576575E-02 -3.607685E-04 -4.871576E-02 -2.820267E-04 -4.103199E-02 -1.970300E-04 -7.773659E-02 -6.470582E-04 -8.599878E-02 -8.479845E-04 -6.886056E-02 -5.267028E-04 -5.721217E-02 -3.681350E-04 -7.713996E-02 -6.425519E-04 -5.865857E-02 -4.103676E-04 -9.128533E-02 -9.001212E-04 -6.876681E-02 -4.977191E-04 -8.130881E-02 -7.186877E-04 -7.550488E-02 -6.383683E-04 -6.074888E-02 -4.148348E-04 -5.625163E-02 -3.768206E-04 -7.967025E-02 -7.546239E-04 -1.062008E-01 -1.178026E-03 -7.335119E-02 -5.749705E-04 -4.820386E-02 -2.843684E-04 -8.285561E-02 -7.331262E-04 -6.377785E-02 -4.639306E-04 -6.793437E-02 -5.094372E-04 -5.119790E-02 -2.807423E-04 -9.613221E-02 -9.824061E-04 -7.536222E-02 -5.822997E-04 -4.761788E-02 -2.477789E-04 -6.084099E-02 -4.333532E-04 -4.906915E-02 -3.040989E-04 -7.222981E-02 -6.031356E-04 -4.171024E-02 -1.905756E-04 -4.528343E-02 -2.268220E-04 -6.279446E-02 -4.327452E-04 -5.128421E-02 -2.753808E-04 -6.231043E-02 -4.457498E-04 -4.764799E-02 -2.670171E-04 -6.361492E-02 -4.379323E-04 -5.965053E-02 -3.939821E-04 -5.490029E-02 -3.380966E-04 -6.827868E-02 -4.968827E-04 -3.309475E-02 -1.331187E-04 -4.603502E-02 -2.672301E-04 -3.793331E-02 -1.804286E-04 -2.266265E-02 -5.756031E-05 -5.949869E-02 -3.999807E-04 -3.963197E-02 -1.762880E-04 -3.899893E-02 -1.642926E-04 -3.082622E-02 -1.074710E-04 -5.463795E-02 -3.382616E-04 -4.577997E-02 -2.244114E-04 -2.946043E-02 -1.104054E-04 -3.390553E-02 -1.311928E-04 -2.012911E-02 -4.877248E-05 -3.010504E-02 -1.111957E-04 -2.530155E-02 -8.217373E-05 -2.188500E-02 -5.370079E-05 -3.794688E-02 -1.630376E-04 -3.361882E-02 -1.162902E-04 -2.106804E-02 -5.229501E-05 -2.245974E-02 -5.982159E-05 -2.505198E-02 -8.478230E-05 -2.287601E-02 -6.940045E-05 -2.246447E-02 -6.064445E-05 -2.014030E-02 -4.596852E-05 -1.547790E-02 -2.802405E-05 -1.827409E-02 -3.706838E-05 -1.250681E-02 -2.504890E-05 -1.523959E-02 -3.397988E-05 -1.959572E-02 -4.638773E-05 -2.192689E-02 -6.243400E-05 -1.209982E-02 -1.817250E-05 -1.262662E-02 -2.516249E-05 -1.684816E-02 -3.966147E-05 -6.158783E-03 -6.145844E-06 -1.336232E-02 -2.474390E-05 -1.990714E-02 -5.523583E-05 -2.459172E-02 -7.004859E-05 -1.772252E-02 -4.853898E-05 -1.485696E-02 -2.873818E-05 -1.413071E-02 -3.178019E-05 -3.091676E-02 -1.063557E-04 -2.309515E-02 -6.359073E-05 -1.550213E-02 -4.421294E-05 -2.192641E-02 -6.676847E-05 -1.438379E-02 -2.502494E-05 -9.323835E-03 -1.058149E-05 -1.950987E-02 -5.777120E-05 -1.128375E-02 -1.672801E-05 -2.835693E-02 -1.026638E-04 -3.616127E-02 -1.505209E-04 -2.584643E-02 -7.628678E-05 -3.372488E-02 -1.431161E-04 -2.972258E-02 -1.013165E-04 -2.718135E-02 -9.239632E-05 -4.046046E-02 -2.091323E-04 -3.184363E-02 -1.406831E-04 -2.906162E-02 -9.931921E-05 -3.473938E-02 -1.672263E-04 -3.247790E-02 -1.200800E-04 -2.283247E-02 -6.591169E-05 -5.157721E-02 -2.857973E-04 -5.318589E-02 -3.355446E-04 -5.396648E-02 -3.222881E-04 -3.455908E-02 -1.577620E-04 -4.000627E-02 -1.811544E-04 -3.827765E-02 -1.701640E-04 -6.111711E-02 -4.195077E-04 -4.813123E-02 -2.551093E-04 -5.248302E-02 -3.053078E-04 -6.395395E-02 -4.882393E-04 -4.085525E-02 -2.131190E-04 -4.537763E-02 -2.817462E-04 -9.621518E-02 -9.753697E-04 -8.338063E-02 -7.366007E-04 -9.141446E-02 -9.402148E-04 -6.429772E-02 -4.457199E-04 -6.537278E-02 -4.627356E-04 -6.465671E-02 -4.504472E-04 -8.801279E-02 -8.983416E-04 -7.192007E-02 -5.371364E-04 -6.236850E-02 -5.079591E-04 -7.006768E-02 -5.856072E-04 -6.331101E-02 -4.271617E-04 -5.772433E-02 -3.721594E-04 -1.415443E-01 -2.106304E-03 -1.333977E-01 -1.819393E-03 -9.668520E-02 -1.012563E-03 -7.876408E-02 -7.180366E-04 -1.082944E-01 -1.226100E-03 -7.858017E-02 -6.820487E-04 -1.233753E-01 -1.710493E-03 -8.940326E-02 -8.711409E-04 -1.097575E-01 -1.284214E-03 -1.079765E-01 -1.255092E-03 -8.764292E-02 -8.394106E-04 -8.007939E-02 -7.022808E-04 -1.214238E-01 -1.596170E-03 -1.421555E-01 -2.105744E-03 -9.333869E-02 -9.022978E-04 -7.506639E-02 -6.221271E-04 -1.304706E-01 -1.799634E-03 -7.986544E-02 -7.526969E-04 -9.702135E-02 -9.836576E-04 -7.294081E-02 -5.906372E-04 -1.297603E-01 -1.782812E-03 -9.082392E-02 -8.669323E-04 -6.578070E-02 -5.122022E-04 -8.815494E-02 -8.142597E-04 -8.155167E-02 -7.217382E-04 -1.018109E-01 -1.086157E-03 -7.197825E-02 -5.331106E-04 -5.627838E-02 -3.449520E-04 -9.010939E-02 -8.605735E-04 -7.405764E-02 -5.833698E-04 -6.370311E-02 -4.307727E-04 -5.655449E-02 -4.002735E-04 -7.828799E-02 -6.754020E-04 -6.189231E-02 -4.227420E-04 -6.662691E-02 -5.039861E-04 -5.981533E-02 -4.042598E-04 -4.616563E-02 -2.512572E-04 -5.126904E-02 -2.954937E-04 -4.940896E-02 -3.013823E-04 -3.651484E-02 -1.509448E-04 -6.169343E-02 -4.343928E-04 -5.276526E-02 -3.035402E-04 -3.757296E-02 -1.669063E-04 -3.701904E-02 -1.472772E-04 -5.041077E-02 -2.708039E-04 -3.789204E-02 -1.599636E-04 -3.750354E-02 -1.758214E-04 -3.841079E-02 -1.623123E-04 -2.067644E-02 -6.321573E-05 -2.854616E-02 -9.473813E-05 -2.444174E-02 -7.627675E-05 -1.711406E-02 -4.015948E-05 -3.249873E-02 -1.518375E-04 -3.257016E-02 -1.207336E-04 -2.196857E-02 -6.460695E-05 -2.336435E-02 -6.693447E-05 -3.087108E-02 -1.244672E-04 -2.930263E-02 -1.042844E-04 -2.973494E-02 -9.755987E-05 -2.663199E-02 -7.916063E-05 -8.110891E-03 -9.147184E-06 -1.596974E-02 -3.945176E-05 -1.126941E-02 -1.972987E-05 -1.498580E-02 -2.597248E-05 -2.296704E-02 -6.870338E-05 -1.864901E-02 -4.568849E-05 -9.655003E-03 -1.218230E-05 -8.917615E-03 -1.497980E-05 -1.991649E-02 -4.425777E-05 -1.938334E-02 -4.450084E-05 -1.468869E-02 -2.783700E-05 -1.990846E-02 -4.552853E-05 -1.774831E-02 -4.009193E-05 -1.266322E-02 -2.320002E-05 -1.658764E-02 -3.986878E-05 -1.698328E-02 -4.091919E-05 -2.128494E-02 -6.048618E-05 -2.030808E-02 -5.574087E-05 -1.270134E-02 -2.233463E-05 -1.683769E-02 -3.536069E-05 -9.809511E-03 -1.445622E-05 -8.599393E-03 -1.081146E-05 -1.931983E-02 -6.640579E-05 -2.037581E-02 -5.286217E-05 -3.532151E-02 -1.703716E-04 -2.959688E-02 -1.000744E-04 -2.794173E-02 -9.833908E-05 -2.721311E-02 -8.705508E-05 -2.259018E-02 -6.498840E-05 -2.999787E-02 -1.185856E-04 -4.036794E-02 -2.072046E-04 -3.144378E-02 -1.169125E-04 -2.933694E-02 -1.105938E-04 -3.942738E-02 -1.729860E-04 -3.260874E-02 -1.481232E-04 -2.353895E-02 -7.836100E-05 -5.876129E-02 -3.975363E-04 -4.766425E-02 -2.519722E-04 -4.033714E-02 -1.807849E-04 -4.729862E-02 -2.401753E-04 -4.304677E-02 -2.096845E-04 -3.822586E-02 -1.740610E-04 -5.685525E-02 -3.389362E-04 -5.053276E-02 -3.049584E-04 -4.125673E-02 -1.768692E-04 -4.228077E-02 -2.108012E-04 -4.501666E-02 -2.298865E-04 -3.308537E-02 -1.337489E-04 -9.085434E-02 -8.630952E-04 -8.043671E-02 -6.998250E-04 -6.790115E-02 -5.151102E-04 -9.822017E-02 -1.054933E-03 -6.615956E-02 -4.705198E-04 -5.651598E-02 -3.870178E-04 -9.749998E-02 -1.051885E-03 -8.349892E-02 -7.963070E-04 -6.591239E-02 -4.655083E-04 -6.485664E-02 -4.646649E-04 -5.727855E-02 -3.614456E-04 -5.982342E-02 -3.951869E-04 -1.437862E-01 -2.121299E-03 -1.381644E-01 -1.981530E-03 -1.258886E-01 -1.695067E-03 -1.148436E-01 -1.441218E-03 -9.597117E-02 -1.101364E-03 -8.065670E-02 -7.548241E-04 -1.190394E-01 -1.472809E-03 -1.202733E-01 -1.590349E-03 -9.488301E-02 -9.917086E-04 -8.590582E-02 -8.395527E-04 -8.538615E-02 -7.662543E-04 -6.840866E-02 -5.508149E-04 -1.309341E-01 -1.788800E-03 -1.431432E-01 -2.124925E-03 -1.253592E-01 -1.673315E-03 -1.027124E-01 -1.115422E-03 -1.257192E-01 -1.618975E-03 -1.009903E-01 -1.140739E-03 -8.317957E-02 -7.328749E-04 -8.230977E-02 -7.081126E-04 -1.122030E-01 -1.312445E-03 -9.156529E-02 -9.645560E-04 -7.593394E-02 -6.433631E-04 -7.347627E-02 -5.887314E-04 -9.176044E-02 -8.793675E-04 -9.196817E-02 -9.288935E-04 -8.602817E-02 -7.934807E-04 -6.540851E-02 -5.134819E-04 -7.784855E-02 -7.374549E-04 -7.145641E-02 -5.431170E-04 -6.586554E-02 -4.742469E-04 -6.889110E-02 -5.369623E-04 -5.852275E-02 -3.823255E-04 -5.130633E-02 -2.938484E-04 -5.009392E-02 -2.807458E-04 -5.334814E-02 -3.079752E-04 -4.264743E-02 -1.994080E-04 -4.606571E-02 -2.446337E-04 -4.932925E-02 -2.518310E-04 -3.172175E-02 -1.173609E-04 -4.799012E-02 -2.513615E-04 -5.034796E-02 -2.882966E-04 -3.398215E-02 -1.394103E-04 -3.801944E-02 -1.702277E-04 -3.688050E-02 -1.492715E-04 -2.945875E-02 -1.064246E-04 -3.293199E-02 -1.292973E-04 -5.057135E-02 -2.972879E-04 -2.902424E-02 -1.009778E-04 -2.994301E-02 -1.055013E-04 -3.820998E-02 -1.811607E-04 -2.790027E-02 -1.186505E-04 -3.074064E-02 -1.078519E-04 -3.248893E-02 -1.169499E-04 -2.353194E-02 -8.076603E-05 -1.809505E-02 -4.072324E-05 -3.396351E-02 -1.453516E-04 -2.286807E-02 -5.496448E-05 -1.987060E-02 -5.376353E-05 -3.044601E-02 -1.115521E-04 -1.248945E-02 -2.198679E-05 -1.803171E-02 -4.771632E-05 -1.378131E-02 -4.134383E-05 -1.555134E-02 -4.721156E-05 -2.534113E-02 -8.351023E-05 -1.500299E-02 -2.635770E-05 -1.071802E-02 -2.136252E-05 -1.137076E-02 -1.975771E-05 -1.456502E-02 -2.501472E-05 -9.727505E-03 -1.483236E-05 -1.454436E-02 -2.710978E-05 -1.978067E-02 -5.285365E-05 -1.360981E-02 -2.336372E-05 -9.847294E-03 -1.509563E-05 -1.524613E-02 -3.552566E-05 -1.773316E-02 -4.971550E-05 -1.867569E-02 -4.914571E-05 -1.751220E-02 -3.467782E-05 -1.304981E-02 -3.349123E-05 -1.082428E-02 -1.865766E-05 -9.584944E-03 -1.325745E-05 -9.180830E-03 -1.262337E-05 -1.640308E-02 -3.160798E-05 -9.874242E-03 -1.450077E-05 -2.800307E-02 -9.021643E-05 -2.465166E-02 -8.472087E-05 -2.134009E-02 -5.841535E-05 -2.840708E-02 -9.453242E-05 -1.817238E-02 -4.004063E-05 -2.108886E-02 -5.388334E-05 -3.062270E-02 -1.286139E-04 -2.538387E-02 -8.871389E-05 -1.989607E-02 -5.232630E-05 -3.196356E-02 -1.567584E-04 -2.768337E-02 -8.817683E-05 -1.657009E-02 -3.128845E-05 -6.221175E-02 -5.006436E-04 -4.068999E-02 -2.287368E-04 -3.891057E-02 -1.725015E-04 -3.661313E-02 -1.700136E-04 -4.325252E-02 -2.377359E-04 -3.132785E-02 -1.053139E-04 -4.447018E-02 -2.340749E-04 -4.887097E-02 -2.828548E-04 -3.659403E-02 -1.932574E-04 -3.839512E-02 -1.702624E-04 -3.434064E-02 -1.413220E-04 -3.562809E-02 -1.569627E-04 -6.182234E-02 -4.171544E-04 -6.100628E-02 -4.051419E-04 -6.647923E-02 -4.900740E-04 -7.287500E-02 -5.551039E-04 -4.730174E-02 -2.512478E-04 -5.228155E-02 -3.234257E-04 -6.367674E-02 -4.355277E-04 -6.127620E-02 -5.160754E-04 -4.996635E-02 -2.866391E-04 -4.386223E-02 -2.253152E-04 -5.319524E-02 -3.262631E-04 -5.127473E-02 -2.891196E-04 -1.048530E-01 -1.182483E-03 -8.170362E-02 -7.286542E-04 -7.965260E-02 -6.956308E-04 -8.522862E-02 -7.597262E-04 -6.792526E-02 -5.514875E-04 -5.653238E-02 -4.231108E-04 -8.040674E-02 -7.324397E-04 -6.538609E-02 -5.208188E-04 -6.236588E-02 -4.356839E-04 -6.164613E-02 -4.180417E-04 -7.331991E-02 -6.180767E-04 -5.657072E-02 -3.533489E-04 -7.827811E-02 -6.870284E-04 -7.791072E-02 -6.465127E-04 -1.083139E-01 -1.260161E-03 -8.407475E-02 -7.634468E-04 -6.669029E-02 -4.841099E-04 -7.629250E-02 -6.708847E-04 -6.145772E-02 -4.524294E-04 -6.227290E-02 -4.295289E-04 -6.532027E-02 -4.771341E-04 -5.543686E-02 -3.242450E-04 -6.507036E-02 -4.562060E-04 -6.918175E-02 -5.208846E-04 -5.915840E-02 -4.026369E-04 -7.574284E-02 -6.257363E-04 -6.443876E-02 -4.697084E-04 -4.704047E-02 -2.420667E-04 -6.871095E-02 -5.703679E-04 -7.652879E-02 -6.996775E-04 -4.488343E-02 -2.199039E-04 -4.340162E-02 -2.117909E-04 -5.505629E-02 -3.299335E-04 -5.395493E-02 -3.792417E-04 -4.982738E-02 -2.664394E-04 -5.864743E-02 -4.020406E-04 -3.700812E-02 -1.675101E-04 -3.590296E-02 -1.636877E-04 -3.701403E-02 -2.028641E-04 -3.559772E-02 -1.412606E-04 -4.420940E-02 -2.126895E-04 -3.967986E-02 -1.668324E-04 -2.751914E-02 -1.031787E-04 -3.350726E-02 -1.282541E-04 -3.400056E-02 -1.396521E-04 -2.928242E-02 -1.253649E-04 -3.696302E-02 -1.675271E-04 -2.971538E-02 -1.050504E-04 -2.147157E-02 -6.672784E-05 -2.068698E-02 -5.314224E-05 -3.024410E-02 -1.161314E-04 -2.564259E-02 -8.893011E-05 -2.244324E-02 -6.402041E-05 -3.352393E-02 -1.269472E-04 -2.503002E-02 -1.001149E-04 -2.271412E-02 -6.142137E-05 -2.662779E-02 -8.519648E-05 -2.760352E-02 -9.770118E-05 -3.168086E-02 -1.170083E-04 -2.636525E-02 -8.041298E-05 -1.168923E-02 -2.309996E-05 -1.341095E-02 -2.785722E-05 -9.527042E-03 -1.301984E-05 -8.579383E-03 -1.158986E-05 -1.770829E-02 -3.709440E-05 -1.285206E-02 -2.277856E-05 -5.715674E-03 -5.170007E-06 -7.751126E-03 -1.014219E-05 -1.566218E-02 -2.874454E-05 -1.550600E-02 -4.482121E-05 -1.310088E-02 -2.996692E-05 -1.266810E-02 -2.452354E-05 -1.328220E-02 -2.441758E-05 -9.553257E-03 -1.316655E-05 -1.072874E-02 -2.962475E-05 -1.419443E-02 -2.691293E-05 -1.389066E-02 -2.460204E-05 -1.520080E-02 -2.942326E-05 -9.725298E-03 -1.180312E-05 -9.645833E-03 -1.760954E-05 -8.964384E-03 -1.441525E-05 -7.797734E-03 -7.875870E-06 -1.222531E-02 -2.143962E-05 -9.811025E-03 -1.223418E-05 -2.347719E-02 -7.632207E-05 -2.624065E-02 -8.577440E-05 -1.872843E-02 -5.642768E-05 -2.884633E-02 -1.120462E-04 -1.331677E-02 -2.169139E-05 -2.073785E-02 -6.410937E-05 -2.069105E-02 -5.558996E-05 -2.409694E-02 -8.187520E-05 -1.689558E-02 -4.223843E-05 -1.624061E-02 -3.418316E-05 -2.151976E-02 -5.877173E-05 -2.360183E-02 -9.731432E-05 -3.349038E-02 -1.331399E-04 -3.071585E-02 -1.134216E-04 -3.064437E-02 -1.380256E-04 -3.411658E-02 -1.385980E-04 -1.902680E-02 -4.966952E-05 -2.548619E-02 -8.563915E-05 -2.627494E-02 -8.806514E-05 -3.156158E-02 -1.348057E-04 -2.555848E-02 -8.827726E-05 -2.109045E-02 -5.840881E-05 -3.141908E-02 -1.092575E-04 -2.542704E-02 -7.869948E-05 -4.409974E-02 -2.370516E-04 -4.511455E-02 -2.385642E-04 -3.493033E-02 -1.329289E-04 -3.573369E-02 -1.645671E-04 -3.658071E-02 -1.701779E-04 -2.875736E-02 -1.063832E-04 -4.612939E-02 -2.341592E-04 -4.488569E-02 -2.371072E-04 -3.283008E-02 -1.266329E-04 -4.421310E-02 -2.144763E-04 -3.688239E-02 -1.597994E-04 -3.783217E-02 -1.715032E-04 -7.381035E-02 -5.788223E-04 -5.920057E-02 -3.764365E-04 -5.566865E-02 -3.245756E-04 -5.294945E-02 -3.171578E-04 -5.308993E-02 -3.020899E-04 -4.015025E-02 -1.763785E-04 -5.449993E-02 -4.477957E-04 -6.098529E-02 -4.698598E-04 -4.562321E-02 -2.217931E-04 -4.372709E-02 -2.205027E-04 -5.027493E-02 -3.024221E-04 -5.350904E-02 -3.184156E-04 -4.989979E-02 -2.950952E-04 -5.166796E-02 -2.972852E-04 -5.157410E-02 -3.015135E-04 -4.679395E-02 -2.264100E-04 -4.534145E-02 -2.596978E-04 -4.610982E-02 -2.659116E-04 -4.420313E-02 -2.280910E-04 -4.382650E-02 -2.133009E-04 -4.090414E-02 -1.993174E-04 -3.320114E-02 -1.287562E-04 -4.502626E-02 -2.259113E-04 -3.962180E-02 -1.762251E-04 -4.967895E-02 -3.145518E-04 -4.494669E-02 -2.411637E-04 -4.339354E-02 -2.011700E-04 -4.176613E-02 -2.014202E-04 -4.442877E-02 -2.331921E-04 -3.398932E-02 -1.379211E-04 -3.482327E-02 -1.541052E-04 -3.556969E-02 -1.558964E-04 -3.691095E-02 -1.643955E-04 -2.226522E-02 -6.975395E-05 -3.915757E-02 -1.657456E-04 -2.866444E-02 -9.309362E-05 -2.855915E-02 -1.131346E-04 -2.537276E-02 -7.948738E-05 -3.789334E-02 -1.685996E-04 -2.751514E-02 -9.186058E-05 -3.178599E-02 -1.355963E-04 -3.907421E-02 -2.055557E-04 -2.791323E-02 -1.069896E-04 -3.339152E-02 -1.362152E-04 -2.050184E-02 -4.863200E-05 -2.291794E-02 -8.183025E-05 -2.124223E-02 -7.063324E-05 -2.399149E-02 -7.407918E-05 -1.796496E-02 -3.936797E-05 -2.078322E-02 -6.098637E-05 -3.024688E-02 -1.288165E-04 -2.239542E-02 -6.306787E-05 -2.616525E-02 -8.655425E-05 -2.919821E-02 -1.113037E-04 -1.673318E-02 -3.601539E-05 -1.608480E-02 -3.314965E-05 -2.821455E-02 -8.921863E-05 -1.974153E-02 -4.431146E-05 -2.003418E-02 -5.758763E-05 -2.061128E-02 -6.512772E-05 -1.559522E-02 -3.594737E-05 -1.934663E-02 -5.001512E-05 -1.075360E-02 -1.792213E-05 -8.194926E-03 -1.028496E-05 -2.034805E-02 -5.444881E-05 -1.609037E-02 -3.970183E-05 -1.347309E-02 -2.123107E-05 -1.407160E-02 -3.569412E-05 -1.624142E-02 -3.714221E-05 -1.299629E-02 -2.459818E-05 -1.122458E-02 -2.237869E-05 -1.211612E-02 -2.219160E-05 -1.408358E-02 -4.218855E-05 -6.735065E-03 -8.482615E-06 -6.793305E-03 -7.845095E-06 -8.478782E-03 -1.709477E-05 -1.133766E-02 -1.980469E-05 -9.653050E-03 -1.415133E-05 -5.831329E-03 -8.381192E-06 -6.218892E-03 -7.102476E-06 -7.592811E-03 -9.310767E-06 -6.506941E-03 -1.095631E-05 -9.452991E-03 -1.264596E-05 -4.768636E-03 -3.507810E-06 -2.077918E-02 -5.890772E-05 -1.762060E-02 -3.525407E-05 -1.205428E-02 -2.724892E-05 -1.469350E-02 -2.710234E-05 -8.551477E-03 -8.546946E-06 -1.223789E-02 -2.595121E-05 -1.076533E-02 -2.013472E-05 -1.864688E-02 -4.804170E-05 -1.271229E-02 -2.770046E-05 -1.016698E-02 -1.439334E-05 -1.713823E-02 -4.788386E-05 -1.253277E-02 -2.231383E-05 -3.154747E-02 -1.214804E-04 -1.749980E-02 -3.647612E-05 -1.830338E-02 -4.569688E-05 -2.308843E-02 -6.321283E-05 -1.594268E-02 -4.383360E-05 -2.466928E-02 -8.077902E-05 -2.901767E-02 -1.088029E-04 -2.554390E-02 -8.895350E-05 -2.146121E-02 -5.921450E-05 -1.943347E-02 -4.952984E-05 -1.991855E-02 -5.703083E-05 -1.411715E-02 -3.539989E-05 -2.706714E-02 -1.408378E-04 -2.476826E-02 -8.960297E-05 -3.280672E-02 -1.342648E-04 -2.769569E-02 -8.949765E-05 -2.254343E-02 -7.118925E-05 -2.821645E-02 -1.008088E-04 -2.332049E-02 -7.198089E-05 -3.472802E-02 -1.359900E-04 -2.098228E-02 -6.775921E-05 -2.011754E-02 -4.899916E-05 -2.887549E-02 -1.210569E-04 -2.169717E-02 -5.971602E-05 -4.083980E-02 -2.063696E-04 -2.682109E-02 -9.162241E-05 -4.087409E-02 -1.874734E-04 -3.397314E-02 -1.355352E-04 -2.503682E-02 -7.832902E-05 -3.341902E-02 -1.279805E-04 -3.470031E-02 -1.457506E-04 -3.434771E-02 -1.308149E-04 -1.924341E-02 -5.117189E-05 -2.610217E-02 -8.124782E-05 -2.672020E-02 -8.422537E-05 -2.913338E-02 -1.020506E-04 -3.799748E-02 -1.583935E-04 -2.396284E-02 -7.323177E-05 -4.085381E-02 -1.817575E-04 -3.429492E-02 -1.389255E-04 -2.955640E-02 -9.833007E-05 -3.550154E-02 -1.507005E-04 -3.041263E-02 -1.000878E-04 -3.068456E-02 -1.089623E-04 -2.480886E-02 -6.953343E-05 -2.214997E-02 -5.427501E-05 -2.822289E-02 -1.091821E-04 -2.246583E-02 -6.845501E-05 -3.548869E-02 -1.564383E-04 -3.342714E-02 -1.555114E-04 -3.584609E-02 -1.533905E-04 -2.543087E-02 -6.947810E-05 -3.395479E-02 -1.360453E-04 -3.067172E-02 -1.109996E-04 -2.290343E-02 -6.048129E-05 -1.985458E-02 -4.438216E-05 -3.051514E-02 -1.050122E-04 -2.086630E-02 -6.348306E-05 -2.009163E-02 -5.579571E-05 -2.312023E-02 -7.424842E-05 -2.349909E-02 -7.517591E-05 -2.465382E-02 -7.402420E-05 -2.149996E-02 -6.067745E-05 -2.388756E-02 -6.487269E-05 -1.918145E-02 -4.328933E-05 -1.951810E-02 -4.931597E-05 -1.743909E-02 -3.923120E-05 -1.959452E-02 -4.325142E-05 -1.836248E-02 -3.960818E-05 -1.633324E-02 -3.551742E-05 -1.863545E-02 -4.322646E-05 -2.548530E-02 -8.566650E-05 -1.370389E-02 -3.068862E-05 -1.702755E-02 -3.470486E-05 -2.110298E-02 -5.769891E-05 -1.950441E-02 -4.624026E-05 -1.773108E-02 -3.976096E-05 -2.121981E-02 -6.568857E-05 -1.052851E-02 -1.559210E-05 -1.304079E-02 -2.231298E-05 -1.944748E-02 -4.683893E-05 -1.445243E-02 -2.703435E-05 -1.597053E-02 -3.429994E-05 -1.650649E-02 -6.011419E-05 -8.568107E-03 -1.035370E-05 -5.963022E-03 -7.941116E-06 -1.005055E-02 -1.089546E-05 -9.025557E-03 -1.235125E-05 -1.058696E-02 -1.548458E-05 -1.428111E-02 -3.101021E-05 -6.332158E-03 -7.284553E-06 -1.107873E-02 -1.880555E-05 -9.074481E-03 -1.488548E-05 -8.633788E-03 -1.494006E-05 -9.852689E-03 -2.277679E-05 -1.279962E-02 -3.267960E-05 -1.096915E-02 -1.703897E-05 -6.543158E-03 -6.896083E-06 -7.823512E-03 -1.199583E-05 -6.285302E-03 -8.223945E-06 -7.196837E-03 -8.695066E-06 -6.939525E-03 -8.067024E-06 -4.593174E-03 -3.678022E-06 -4.766649E-03 -6.980855E-06 -4.492564E-03 -4.106885E-06 -5.836560E-03 -5.166762E-06 -4.091860E-03 -3.202729E-06 -2.851717E-03 -1.441790E-06 -1.131813E-02 -1.990562E-05 -8.044232E-03 -9.338147E-06 -9.601976E-03 -1.551372E-05 -1.271494E-02 -2.673243E-05 -6.142371E-03 -6.616946E-06 -7.543735E-03 -1.129556E-05 -1.054461E-02 -1.314345E-05 -1.244849E-02 -1.966250E-05 -9.734137E-03 -1.778830E-05 -1.360778E-02 -2.168963E-05 -8.980518E-03 -9.981098E-06 -5.673726E-03 -6.390047E-06 -1.495065E-02 -3.570344E-05 -1.139512E-02 -2.213315E-05 -1.578970E-02 -3.505969E-05 -1.629500E-02 -3.158196E-05 -1.481063E-02 -3.260955E-05 -1.632506E-02 -3.683693E-05 -1.058030E-02 -1.860245E-05 -1.014653E-02 -1.703372E-05 -1.053471E-02 -1.946614E-05 -1.087794E-02 -1.741794E-05 -1.749138E-02 -4.059625E-05 -1.441949E-02 -4.081297E-05 -2.238698E-02 -8.411387E-05 -1.355243E-02 -2.880517E-05 -2.176689E-02 -7.043906E-05 -1.938423E-02 -5.171647E-05 -1.365868E-02 -3.105929E-05 -1.615560E-02 -3.821091E-05 -1.688664E-02 -4.289252E-05 -1.314826E-02 -2.645963E-05 -1.505920E-02 -3.910868E-05 -1.696322E-02 -4.410507E-05 -1.531505E-02 -2.627391E-05 -1.302530E-02 -2.447578E-05 -2.215989E-02 -5.624695E-05 -1.558271E-02 -3.591163E-05 -1.660587E-02 -4.451639E-05 -2.152716E-02 -6.525487E-05 -1.897151E-02 -5.231568E-05 -1.728826E-02 -5.214345E-05 -1.902678E-02 -5.314163E-05 -2.333937E-02 -8.182246E-05 -9.443854E-03 -1.172248E-05 -1.198026E-02 -2.003714E-05 -2.138685E-02 -6.175227E-05 -1.274599E-02 -2.433959E-05 -1.947534E-02 -5.207291E-05 -1.815170E-02 -4.398794E-05 -3.169585E-02 -1.333543E-04 -1.905286E-02 -4.657423E-05 -1.494275E-02 -3.505332E-05 -1.763876E-02 -4.461835E-05 -1.182033E-02 -2.214931E-05 -1.968821E-02 -5.319218E-05 -1.722391E-02 -3.689380E-05 -1.164039E-02 -2.017520E-05 -1.987702E-02 -4.962563E-05 -1.593272E-02 -4.198443E-05 -1.295575E-02 -3.292363E-05 -1.574293E-02 -3.434465E-05 -2.730586E-02 -8.253402E-05 -2.116215E-02 -5.127586E-05 -1.343828E-02 -2.408890E-05 -1.857254E-02 -4.513774E-05 -1.500919E-02 -3.231350E-05 -1.678659E-02 -3.962936E-05 -1.488856E-02 -2.386764E-05 -1.230601E-02 -2.575268E-05 -2.037392E-02 -5.965465E-05 -1.096474E-02 -1.759636E-05 -2.187484E-02 -6.525702E-05 -1.374639E-02 -2.555749E-05 -1.511590E-02 -3.826384E-05 -1.563929E-02 -3.222315E-05 -1.684288E-02 -4.027516E-05 -1.773599E-02 -6.209617E-05 -1.720006E-02 -3.431594E-05 -1.841885E-02 -4.086225E-05 -1.218119E-02 -2.095533E-05 -1.065430E-02 -1.713440E-05 -1.058773E-02 -1.668419E-05 -1.135705E-02 -1.500764E-05 -1.158632E-02 -2.852635E-05 -8.247777E-03 -1.228385E-05 -1.907771E-02 -4.597570E-05 -1.777609E-02 -4.816332E-05 -1.285738E-02 -2.710713E-05 -1.336306E-02 -2.768885E-05 -7.498631E-03 -1.438567E-05 -1.168505E-02 -2.200300E-05 -8.575921E-03 -8.903420E-06 -6.935145E-03 -9.218014E-06 -9.998062E-03 -1.881829E-05 -8.939471E-03 -1.098615E-05 -7.860596E-03 -1.449285E-05 -1.082459E-02 -1.896980E-05 -5.782585E-03 -5.702033E-06 -1.004504E-02 -2.149248E-05 -7.503097E-03 -1.089878E-05 -6.843525E-03 -9.834532E-06 -1.381318E-03 -8.252352E-07 -5.676320E-03 -7.883845E-06 -5.874523E-03 -3.759183E-06 -4.793821E-03 -2.805686E-06 -6.125800E-03 -6.903423E-06 -8.300434E-03 -1.293197E-05 -8.058716E-03 -1.160479E-05 -6.964643E-03 -9.276538E-06 -3.462172E-03 -2.364550E-06 -4.968406E-03 -4.433251E-06 -6.306240E-03 -6.070974E-06 -6.018210E-03 -7.366216E-06 -8.837800E-03 -9.688936E-06 -5.096909E-03 -4.382163E-06 -3.815130E-03 -6.161058E-06 -4.515200E-03 -4.595497E-06 -6.864810E-03 -1.010895E-05 -6.423468E-03 -9.143165E-06 -9.538660E-03 -1.560977E-05 -1.261072E-02 -2.250707E-05 -1.026530E-02 -1.637414E-05 -9.557506E-03 -1.527890E-05 -8.827930E-03 -1.066139E-05 -5.478962E-03 -5.569868E-06 -9.080187E-03 -1.204024E-05 -1.528742E-02 -3.325338E-05 -1.337087E-02 -1.956015E-05 -1.675398E-02 -4.575869E-05 -1.281954E-02 -3.179463E-05 -8.332353E-03 -1.484699E-05 -1.617850E-02 -3.768574E-05 -1.581638E-02 -5.060008E-05 -1.558998E-02 -3.489775E-05 -1.170539E-02 -1.670388E-05 -9.403406E-03 -1.210849E-05 -6.538447E-03 -7.590433E-06 -1.533222E-02 -3.995585E-05 -9.660974E-03 -1.337453E-05 -1.612761E-02 -3.190924E-05 -1.123730E-02 -1.881522E-05 -6.517842E-03 -9.004602E-06 -1.039422E-02 -1.944508E-05 -1.196688E-02 -2.077099E-05 -1.825266E-02 -5.884867E-05 -1.114412E-02 -1.635734E-05 -6.855502E-03 -9.696697E-06 -7.937283E-03 -1.011203E-05 -1.305061E-02 -2.491232E-05 -2.084992E-02 -5.566232E-05 -9.019271E-03 -1.005494E-05 -1.029368E-02 -1.905328E-05 -1.763980E-02 -4.024339E-05 -9.329184E-03 -1.252705E-05 -1.325489E-02 -2.563636E-05 -1.556775E-02 -3.949834E-05 -2.061223E-02 -6.392049E-05 -1.758113E-02 -3.625999E-05 -1.157256E-02 -2.047838E-05 -8.563192E-03 -1.228712E-05 -1.031763E-02 -1.411955E-05 -1.512631E-02 -4.654173E-05 -1.486827E-02 -2.864290E-05 -2.251974E-02 -5.878585E-05 -1.538325E-02 -2.676876E-05 -1.352613E-02 -3.627305E-05 -1.449237E-02 -3.612781E-05 -1.192626E-02 -2.019597E-05 -1.304918E-02 -2.426503E-05 -1.605822E-02 -3.012824E-05 -1.727927E-02 -3.755550E-05 -9.669506E-03 -1.630871E-05 -1.276773E-02 -2.526258E-05 -1.428968E-02 -3.134862E-05 -1.703682E-02 -4.403612E-05 -1.839993E-02 -4.005997E-05 -1.709877E-02 -3.494229E-05 -1.020568E-02 -2.306756E-05 -1.556313E-02 -2.961997E-05 -1.367798E-02 -2.209767E-05 -1.479845E-02 -2.697536E-05 -1.064351E-02 -1.544937E-05 -1.457069E-02 -3.339049E-05 -1.022585E-02 -1.440893E-05 -1.072359E-02 -1.406891E-05 -2.091105E-02 -5.324749E-05 -1.381809E-02 -3.338254E-05 -1.600746E-02 -3.282400E-05 -1.918686E-02 -4.509327E-05 -1.087716E-02 -1.741352E-05 -1.712809E-02 -3.956314E-05 -1.312095E-02 -1.981242E-05 -1.874899E-02 -4.287445E-05 -1.113725E-02 -2.004136E-05 -7.103716E-03 -7.213595E-06 -1.369370E-02 -3.063256E-05 -9.195487E-03 -1.412638E-05 -1.141322E-02 -1.860950E-05 -1.114463E-02 -1.989362E-05 -1.766608E-02 -3.977019E-05 -1.831950E-02 -5.100972E-05 -9.842311E-03 -1.641174E-05 -1.050669E-02 -1.611304E-05 -9.275886E-03 -1.425314E-05 -1.489107E-02 -2.846318E-05 -1.024738E-02 -1.638704E-05 -1.238766E-02 -2.905937E-05 -8.220882E-03 -1.610701E-05 -7.911660E-03 -1.204791E-05 -6.724074E-03 -8.382502E-06 -7.246664E-03 -1.223989E-05 -9.981199E-03 -1.983647E-05 -7.195641E-03 -1.261848E-05 -5.805501E-03 -6.427362E-06 -7.853739E-03 -1.109259E-05 -5.029358E-03 -4.590158E-06 -7.362545E-03 -9.705721E-06 -6.742269E-03 -5.672589E-06 -8.306759E-03 -1.150294E-05 -2.269532E-03 -1.413152E-06 -5.728846E-03 -6.054291E-06 -6.497853E-03 -7.598936E-06 -5.211040E-03 -7.706367E-06 -1.091775E-02 -2.620541E-05 -7.186930E-03 -7.840316E-06 -5.773406E-03 -6.737773E-06 -8.315747E-03 -1.614189E-05 -1.045710E-02 -1.408567E-05 -1.373927E-02 -2.417114E-05 -4.474588E-03 -2.860895E-06 -7.106756E-03 -8.922176E-06 -1.703428E-02 -3.411039E-05 -7.032210E-03 -5.972986E-06 -7.519022E-03 -9.923714E-06 -1.019763E-02 -1.870985E-05 -1.003939E-02 -1.665677E-05 -5.257180E-03 -7.163497E-06 -6.709259E-03 -1.080672E-05 -6.660210E-03 -8.371462E-06 -1.339388E-02 -2.963406E-05 -2.041319E-02 -6.283530E-05 -1.277136E-02 -2.113278E-05 -1.095487E-02 -1.788661E-05 -1.210895E-02 -2.269317E-05 -9.526669E-03 -1.459758E-05 -1.595135E-02 -4.590455E-05 -1.583142E-02 -3.433698E-05 -1.814067E-02 -5.361094E-05 -2.020117E-02 -5.966829E-05 -1.078165E-02 -2.464395E-05 -1.503699E-02 -3.786272E-05 -1.636813E-02 -3.872799E-05 -2.272579E-02 -7.702949E-05 -1.895617E-02 -5.205980E-05 -1.364788E-02 -2.639491E-05 -1.991314E-02 -7.408716E-05 -1.011963E-02 -1.544567E-05 -1.853803E-02 -4.673643E-05 -1.601464E-02 -3.647742E-05 -2.688432E-02 -8.994718E-05 -1.910229E-02 -4.828596E-05 -1.310107E-02 -2.599395E-05 -2.493961E-02 -8.021464E-05 -2.136141E-02 -5.184829E-05 -2.544806E-02 -7.994724E-05 -1.143679E-02 -1.661591E-05 -1.709579E-02 -4.337367E-05 -2.083317E-02 -5.556329E-05 -1.866022E-02 -4.397347E-05 -3.145206E-02 -1.280431E-04 -2.210382E-02 -5.769121E-05 -1.823923E-02 -4.074602E-05 -1.528594E-02 -3.104999E-05 -1.711154E-02 -4.112452E-05 -1.507762E-02 -2.770618E-05 -2.206514E-02 -6.022082E-05 -2.319277E-02 -5.836530E-05 -1.896072E-02 -4.024144E-05 -1.655441E-02 -4.163720E-05 -1.804406E-02 -4.084019E-05 -2.452803E-02 -7.291599E-05 -2.802970E-02 -1.259325E-04 -2.453139E-02 -7.079239E-05 -2.489486E-02 -6.688553E-05 -2.178711E-02 -7.105053E-05 -1.906738E-02 -4.476745E-05 -2.527667E-02 -8.182112E-05 -2.331217E-02 -6.232971E-05 -2.781953E-02 -9.708263E-05 -1.997547E-02 -4.443113E-05 -2.088515E-02 -5.171598E-05 -2.303205E-02 -8.024769E-05 -1.915503E-02 -4.593806E-05 -2.571317E-02 -8.223527E-05 -1.506654E-02 -3.035107E-05 -2.999022E-02 -1.183624E-04 -2.875220E-02 -1.019916E-04 -1.859536E-02 -4.941826E-05 -2.237740E-02 -6.098459E-05 -1.818345E-02 -4.548133E-05 -2.387148E-02 -8.542723E-05 -1.893980E-02 -4.021031E-05 -2.098013E-02 -5.353962E-05 -2.652625E-02 -8.621445E-05 -1.979268E-02 -5.173051E-05 -2.005599E-02 -5.014567E-05 -1.869207E-02 -4.863434E-05 -2.062895E-02 -5.960259E-05 -2.035386E-02 -4.757091E-05 -1.380341E-02 -2.450580E-05 -1.716354E-02 -4.220694E-05 -1.514915E-02 -2.661478E-05 -9.617277E-03 -1.245420E-05 -1.625088E-02 -3.575586E-05 -1.556949E-02 -3.732096E-05 -1.713751E-02 -3.918991E-05 -1.288808E-02 -2.331234E-05 -1.411636E-02 -2.581158E-05 -8.295504E-03 -1.118839E-05 -1.490088E-02 -3.193897E-05 -1.120118E-02 -1.562213E-05 -1.159281E-02 -1.980721E-05 -1.203548E-02 -2.711369E-05 -1.339573E-02 -2.158602E-05 -1.280581E-02 -2.079765E-05 -1.083998E-02 -1.727408E-05 -1.315255E-02 -2.519274E-05 -1.207379E-02 -2.152665E-05 -1.232904E-02 -2.825538E-05 -1.209938E-02 -2.379986E-05 -7.347293E-03 -8.920021E-06 -1.420050E-02 -2.556068E-05 -1.406290E-02 -2.882913E-05 -1.226796E-02 -2.904134E-05 -1.529742E-02 -3.412784E-05 -9.361135E-03 -1.953641E-05 -7.653780E-03 -9.090398E-06 -1.172034E-02 -1.741493E-05 -6.481510E-03 -6.366134E-06 -1.483462E-02 -3.419849E-05 -7.287071E-03 -9.994231E-06 -7.014536E-03 -8.683589E-06 -3.914638E-03 -3.851978E-06 -1.039507E-02 -1.247058E-05 -1.449371E-02 -3.268737E-05 -6.107315E-03 -1.275657E-05 -5.912533E-03 -5.291900E-06 -1.241975E-02 -2.776459E-05 -1.652474E-02 -3.478228E-05 -9.924557E-03 -2.111611E-05 -1.112655E-02 -2.134337E-05 -1.490879E-02 -4.120682E-05 -1.214873E-02 -1.828276E-05 -1.878471E-02 -4.595384E-05 -1.068338E-02 -2.052816E-05 -9.957982E-03 -1.661273E-05 -8.679245E-03 -1.539340E-05 -7.944462E-03 -1.238828E-05 -9.333064E-03 -1.407498E-05 -2.180639E-02 -5.625519E-05 -2.409216E-02 -8.351837E-05 -2.095008E-02 -5.330117E-05 -2.458431E-02 -7.696318E-05 -1.741223E-02 -4.634669E-05 -2.052947E-02 -5.641630E-05 -2.507271E-02 -7.084493E-05 -2.192019E-02 -5.996923E-05 -1.687601E-02 -3.734411E-05 -2.188351E-02 -5.331644E-05 -2.625531E-02 -8.987505E-05 -1.947839E-02 -5.362737E-05 -2.561506E-02 -8.555702E-05 -3.072429E-02 -1.057779E-04 -2.548154E-02 -8.649311E-05 -2.215408E-02 -5.389914E-05 -2.857258E-02 -9.992187E-05 -2.271191E-02 -6.458178E-05 -3.417289E-02 -1.353676E-04 -2.406069E-02 -7.233156E-05 -2.858289E-02 -1.096000E-04 -3.086685E-02 -1.088635E-04 -1.806766E-02 -4.316705E-05 -2.440571E-02 -6.395626E-05 -3.255341E-02 -1.376111E-04 -4.078794E-02 -1.950454E-04 -2.169319E-02 -5.623674E-05 -2.222088E-02 -7.931181E-05 -3.507566E-02 -1.330312E-04 -3.153876E-02 -1.223922E-04 -3.739825E-02 -1.655348E-04 -3.186914E-02 -1.164407E-04 -3.186332E-02 -1.211760E-04 -3.046668E-02 -1.045865E-04 -2.468913E-02 -7.595312E-05 -2.725403E-02 -9.530282E-05 -3.669370E-02 -1.633028E-04 -4.142607E-02 -2.202378E-04 -2.274887E-02 -6.024427E-05 -2.852673E-02 -1.084379E-04 -3.552692E-02 -1.550998E-04 -1.953889E-02 -4.742931E-05 -4.288258E-02 -2.326284E-04 -3.527647E-02 -1.532875E-04 -3.831735E-02 -1.712470E-04 -3.740668E-02 -1.804477E-04 -3.067443E-02 -1.226235E-04 -2.859755E-02 -9.502065E-05 -3.656012E-02 -1.473474E-04 -4.428469E-02 -2.135422E-04 -3.876237E-02 -1.826793E-04 -3.168779E-02 -1.136526E-04 -4.132746E-02 -1.944335E-04 -3.080999E-02 -1.075137E-04 -3.809598E-02 -1.579372E-04 -3.950419E-02 -1.784657E-04 -5.023062E-02 -3.049706E-04 -4.789752E-02 -2.554387E-04 -3.458880E-02 -1.324150E-04 -4.090067E-02 -1.965130E-04 -3.045883E-02 -1.164732E-04 -3.897593E-02 -1.862204E-04 -1.900547E-02 -4.239429E-05 -2.523518E-02 -8.151515E-05 -3.480501E-02 -1.535823E-04 -2.911328E-02 -1.131135E-04 -3.135787E-02 -1.158315E-04 -2.364659E-02 -7.666160E-05 -3.489798E-02 -1.613478E-04 -3.305825E-02 -1.226465E-04 -3.424037E-02 -1.511504E-04 -3.144976E-02 -1.315971E-04 -2.386686E-02 -9.966283E-05 -2.343488E-02 -7.865295E-05 -1.809482E-02 -3.639503E-05 -1.592339E-02 -3.078924E-05 -3.395399E-02 -1.387775E-04 -2.173542E-02 -6.688037E-05 -1.139408E-02 -1.661367E-05 -1.191973E-02 -1.884978E-05 -2.149843E-02 -5.543388E-05 -2.139730E-02 -5.948238E-05 -1.878719E-02 -3.863865E-05 -2.861748E-02 -9.903233E-05 -1.663769E-02 -3.586183E-05 -2.392378E-02 -7.633777E-05 -1.826846E-02 -4.768962E-05 -1.258024E-02 -2.584217E-05 -1.836655E-02 -4.161069E-05 -1.896044E-02 -4.007711E-05 -1.782079E-02 -3.615894E-05 -1.682346E-02 -3.435373E-05 -1.864611E-02 -4.004514E-05 -2.027124E-02 -4.802356E-05 -1.572197E-02 -4.060890E-05 -1.809973E-02 -5.222844E-05 -8.922954E-03 -1.541312E-05 -1.042804E-02 -1.919810E-05 -1.663952E-02 -3.230801E-05 -1.416041E-02 -3.240599E-05 -1.364911E-02 -2.047968E-05 -1.466030E-02 -2.789488E-05 -7.525078E-03 -8.889694E-06 -6.730764E-03 -9.941085E-06 -1.007468E-02 -1.767697E-05 -1.050555E-02 -1.620042E-05 -8.346548E-03 -1.182646E-05 -9.053361E-03 -1.420984E-05 -1.665200E-02 -5.444887E-05 -1.527178E-02 -2.919176E-05 -1.380005E-02 -2.920152E-05 -9.043029E-03 -1.785555E-05 -1.950145E-02 -4.990311E-05 -1.401098E-02 -2.753310E-05 -1.823652E-02 -4.520948E-05 -1.710659E-02 -4.707810E-05 -1.381860E-02 -3.468506E-05 -1.372395E-02 -3.175759E-05 -1.525561E-02 -3.615913E-05 -1.061450E-02 -1.832455E-05 -2.040145E-02 -5.544400E-05 -2.550363E-02 -8.291428E-05 -1.927840E-02 -6.340108E-05 -1.775966E-02 -3.592996E-05 -1.876698E-02 -5.056466E-05 -1.520416E-02 -3.176693E-05 -2.911719E-02 -1.110393E-04 -2.789335E-02 -1.015992E-04 -2.154244E-02 -6.800841E-05 -2.176042E-02 -6.210896E-05 -2.465235E-02 -8.769146E-05 -2.163089E-02 -6.884278E-05 -4.263944E-02 -2.012458E-04 -3.780523E-02 -1.771907E-04 -3.718152E-02 -1.480234E-04 -3.477776E-02 -1.409494E-04 -3.400758E-02 -1.358091E-04 -2.463564E-02 -6.885284E-05 -3.580510E-02 -1.389221E-04 -2.581734E-02 -7.795599E-05 -4.453340E-02 -2.222774E-04 -3.924298E-02 -2.048002E-04 -2.186414E-02 -7.503195E-05 -2.414346E-02 -6.884988E-05 -4.920381E-02 -2.986041E-04 -4.271226E-02 -2.407998E-04 -3.511456E-02 -1.659456E-04 -3.959546E-02 -1.811704E-04 -4.332790E-02 -2.327770E-04 -3.005794E-02 -1.236765E-04 -4.201285E-02 -1.831068E-04 -3.539806E-02 -1.349359E-04 -4.860033E-02 -2.640914E-04 -3.738028E-02 -1.608258E-04 -3.344288E-02 -1.192143E-04 -3.329781E-02 -1.262633E-04 -5.050402E-02 -3.082255E-04 -6.167912E-02 -4.537041E-04 -4.061325E-02 -2.373203E-04 -4.113180E-02 -2.244264E-04 -4.273661E-02 -2.061457E-04 -3.909923E-02 -1.794019E-04 -4.467948E-02 -2.422984E-04 -3.644554E-02 -1.488516E-04 -6.208616E-02 -4.066650E-04 -5.622731E-02 -3.479864E-04 -3.604649E-02 -1.527817E-04 -4.489847E-02 -2.244948E-04 -4.852333E-02 -2.452380E-04 -5.916579E-02 -3.675786E-04 -5.027889E-02 -3.063063E-04 -5.223329E-02 -3.266355E-04 -5.303921E-02 -3.002831E-04 -4.084190E-02 -2.089059E-04 -4.269058E-02 -1.927344E-04 -4.181196E-02 -1.890866E-04 -4.239920E-02 -2.054052E-04 -4.178606E-02 -2.121443E-04 -3.962721E-02 -1.900681E-04 -3.998106E-02 -1.671101E-04 -4.097110E-02 -1.864628E-04 -5.252376E-02 -2.919653E-04 -4.986589E-02 -2.923184E-04 -4.281919E-02 -2.017141E-04 -5.707825E-02 -3.443945E-04 -4.193701E-02 -1.801946E-04 -3.890873E-02 -1.604416E-04 -2.771300E-02 -8.201460E-05 -4.516255E-02 -2.288159E-04 -3.504308E-02 -1.480297E-04 -3.354671E-02 -1.345202E-04 -4.155997E-02 -1.900709E-04 -2.311887E-02 -6.056166E-05 -4.403743E-02 -2.374715E-04 -1.996468E-02 -5.260666E-05 -3.196737E-02 -1.421833E-04 -4.035771E-02 -1.965928E-04 -3.317174E-02 -1.529423E-04 -2.357781E-02 -6.449390E-05 -2.467934E-02 -6.935734E-05 -4.424222E-02 -2.197069E-04 -3.398377E-02 -1.404692E-04 -2.969392E-02 -9.932175E-05 -2.586642E-02 -8.639774E-05 -2.018938E-02 -4.704545E-05 -2.460053E-02 -8.337921E-05 -2.140944E-02 -5.566819E-05 -1.750162E-02 -4.330128E-05 -1.823667E-02 -3.807392E-05 -2.182322E-02 -5.835666E-05 -1.996510E-02 -4.925786E-05 -2.054306E-02 -5.967285E-05 -2.448060E-02 -6.724552E-05 -2.420255E-02 -7.171101E-05 -2.224533E-02 -7.074407E-05 -2.688010E-02 -1.048025E-04 -1.252593E-02 -1.992438E-05 -1.627058E-02 -3.557197E-05 -1.458375E-02 -2.939085E-05 -6.673846E-03 -7.665690E-06 -1.782098E-02 -4.530371E-05 -1.873366E-02 -5.530746E-05 -1.014089E-02 -1.628821E-05 -9.132953E-03 -1.379610E-05 -1.363905E-02 -2.661815E-05 -1.338513E-02 -2.253429E-05 -8.423240E-03 -1.911938E-05 -1.484012E-02 -4.135636E-05 -1.418073E-02 -3.323365E-05 -1.543051E-02 -2.985655E-05 -1.632770E-02 -3.517623E-05 -2.008031E-02 -5.274018E-05 -1.602450E-02 -3.958879E-05 -1.750372E-02 -3.314152E-05 -1.219742E-02 -2.258004E-05 -1.433533E-02 -3.618336E-05 -9.075804E-03 -1.317139E-05 -7.380199E-03 -7.236358E-06 -1.782556E-02 -3.957064E-05 -1.184192E-02 -2.021154E-05 -2.859581E-02 -1.054928E-04 -2.697349E-02 -9.676496E-05 -2.792217E-02 -1.147611E-04 -1.382301E-02 -2.417383E-05 -2.411827E-02 -7.056685E-05 -1.982700E-02 -4.766108E-05 -2.818071E-02 -9.359800E-05 -2.219449E-02 -6.075282E-05 -2.314416E-02 -6.478789E-05 -2.443285E-02 -8.381567E-05 -2.019536E-02 -5.428133E-05 -1.353132E-02 -2.740754E-05 -4.406952E-02 -2.190081E-04 -3.446584E-02 -1.346151E-04 -3.753184E-02 -1.527576E-04 -3.033111E-02 -1.034049E-04 -2.855894E-02 -9.711291E-05 -2.771557E-02 -8.771393E-05 -3.898957E-02 -1.908877E-04 -4.305288E-02 -1.970134E-04 -3.486097E-02 -1.545961E-04 -3.499273E-02 -1.436152E-04 -3.110132E-02 -1.127757E-04 -3.008751E-02 -1.139676E-04 -6.319815E-02 -4.327893E-04 -5.504272E-02 -3.344552E-04 -4.591545E-02 -2.365710E-04 -3.617316E-02 -1.560924E-04 -5.218885E-02 -3.077972E-04 -4.686114E-02 -2.529342E-04 -5.728060E-02 -4.031273E-04 -3.978176E-02 -1.860198E-04 -5.004767E-02 -3.136544E-04 -4.523333E-02 -2.208929E-04 -3.194586E-02 -1.141458E-04 -3.721301E-02 -1.553134E-04 -7.477681E-02 -6.639195E-04 -6.780397E-02 -4.776195E-04 -6.358469E-02 -4.696106E-04 -6.032980E-02 -4.286567E-04 -5.153943E-02 -2.983568E-04 -5.818770E-02 -4.058262E-04 -6.750249E-02 -5.176461E-04 -5.373447E-02 -3.160363E-04 -6.782408E-02 -5.197564E-04 -5.101341E-02 -3.150794E-04 -3.969145E-02 -1.890305E-04 -4.675755E-02 -2.829176E-04 -4.899174E-02 -2.593746E-04 -7.529462E-02 -5.829369E-04 -5.523513E-02 -3.275402E-04 -3.691494E-02 -1.532620E-04 -6.863824E-02 -5.261979E-04 -5.665568E-02 -3.399426E-04 -5.021140E-02 -2.920406E-04 -5.159035E-02 -3.147743E-04 -8.420431E-02 -7.633948E-04 -6.502238E-02 -5.063282E-04 -4.930238E-02 -2.812855E-04 -4.815381E-02 -2.482742E-04 -4.967200E-02 -2.680540E-04 -5.523567E-02 -3.370328E-04 -4.300524E-02 -2.081672E-04 -3.836521E-02 -1.711214E-04 -5.253824E-02 -3.333353E-04 -4.027059E-02 -1.822925E-04 -3.645004E-02 -1.495178E-04 -3.990377E-02 -1.790132E-04 -4.399597E-02 -2.136921E-04 -4.313937E-02 -2.093007E-04 -3.431599E-02 -1.398795E-04 -4.051219E-02 -1.961233E-04 -4.595652E-02 -2.564444E-04 -3.332030E-02 -1.206481E-04 -4.197497E-02 -2.029057E-04 -3.566567E-02 -1.599693E-04 -3.563813E-02 -1.390992E-04 -3.428900E-02 -1.439048E-04 -3.548443E-02 -1.582734E-04 -3.147837E-02 -1.431168E-04 -3.473859E-02 -1.320531E-04 -3.340003E-02 -1.534631E-04 -2.995214E-02 -1.115961E-04 -3.783601E-02 -1.612451E-04 -2.593349E-02 -7.511302E-05 -2.220229E-02 -5.650585E-05 -2.396506E-02 -6.330344E-05 -2.415591E-02 -7.979178E-05 -3.230518E-02 -1.226469E-04 -3.148292E-02 -1.291525E-04 -2.555369E-02 -7.214626E-05 -2.008785E-02 -5.277321E-05 -2.623915E-02 -1.052699E-04 -1.687230E-02 -3.802212E-05 -1.828669E-02 -5.222647E-05 -2.568728E-02 -1.046345E-04 -1.666034E-02 -3.189735E-05 -1.441649E-02 -2.909234E-05 -1.961081E-02 -5.252583E-05 -1.446604E-02 -2.906063E-05 -2.499966E-02 -7.290861E-05 -2.036936E-02 -5.610925E-05 -9.247556E-03 -1.678837E-05 -1.093088E-02 -2.167681E-05 -1.260502E-02 -2.987668E-05 -9.613002E-03 -1.269981E-05 -1.504319E-02 -4.123453E-05 -1.804155E-02 -4.790967E-05 -1.950375E-02 -5.823817E-05 -1.292954E-02 -2.425508E-05 -9.979565E-03 -1.879915E-05 -1.627001E-02 -4.007960E-05 -1.727217E-02 -3.779588E-05 -1.821599E-02 -4.516560E-05 -1.246029E-02 -2.877178E-05 -7.419932E-03 -1.075442E-05 -1.027139E-02 -1.750906E-05 -6.011548E-03 -5.357981E-06 -1.284150E-02 -2.684216E-05 -7.873217E-03 -1.261811E-05 -3.056254E-02 -1.119101E-04 -2.367459E-02 -7.012832E-05 -3.125473E-02 -1.349511E-04 -2.032722E-02 -6.005633E-05 -1.966372E-02 -4.807430E-05 -1.888280E-02 -4.353141E-05 -3.148229E-02 -1.087028E-04 -2.569052E-02 -8.345601E-05 -1.988235E-02 -5.083043E-05 -3.033509E-02 -1.353984E-04 -2.455111E-02 -8.578087E-05 -2.292969E-02 -6.706042E-05 -3.506638E-02 -1.418820E-04 -2.811805E-02 -8.950254E-05 -3.758364E-02 -1.763474E-04 -4.852969E-02 -3.045767E-04 -3.345491E-02 -1.265446E-04 -3.311976E-02 -1.271997E-04 -4.406586E-02 -2.049053E-04 -3.977663E-02 -1.944792E-04 -3.568273E-02 -1.393831E-04 -4.714003E-02 -2.666571E-04 -3.938142E-02 -1.784684E-04 -3.504464E-02 -1.619498E-04 -6.038764E-02 -4.057914E-04 -5.523867E-02 -3.480079E-04 -5.012020E-02 -2.738532E-04 -5.300843E-02 -3.225930E-04 -4.819845E-02 -2.912996E-04 -4.192723E-02 -2.042929E-04 -5.437230E-02 -3.831173E-04 -4.855340E-02 -2.801897E-04 -5.632430E-02 -3.684549E-04 -3.908351E-02 -1.754220E-04 -3.723203E-02 -1.565670E-04 -3.662475E-02 -1.409549E-04 -7.828360E-02 -6.808841E-04 -6.139852E-02 -4.032303E-04 -6.455776E-02 -4.632098E-04 -4.996191E-02 -2.795507E-04 -5.586957E-02 -3.475409E-04 -4.296598E-02 -2.317524E-04 -6.386330E-02 -4.717762E-04 -5.291090E-02 -3.247736E-04 -5.483498E-02 -3.421555E-04 -4.502506E-02 -2.409819E-04 -5.510776E-02 -3.436300E-04 -4.165980E-02 -1.924264E-04 -5.979906E-02 -3.843900E-04 -5.815532E-02 -3.901796E-04 -6.144432E-02 -4.159903E-04 -5.918684E-02 -3.926095E-04 -7.241076E-02 -5.527725E-04 -5.729097E-02 -3.531500E-04 -5.051843E-02 -2.810907E-04 -5.618582E-02 -3.776148E-04 -5.589932E-02 -3.335647E-04 -6.161520E-02 -4.831295E-04 -5.389348E-02 -3.065669E-04 -4.348189E-02 -2.135964E-04 -4.695822E-02 -2.384098E-04 -6.006602E-02 -3.844395E-04 -4.864361E-02 -2.423012E-04 -4.186798E-02 -1.902022E-04 -4.797983E-02 -2.448734E-04 -4.768596E-02 -2.637688E-04 -4.383760E-02 -2.023880E-04 -3.729270E-02 -2.011170E-04 -4.671060E-02 -2.774443E-04 -4.261256E-02 -2.074667E-04 -3.057615E-02 -1.013174E-04 -3.642349E-02 -1.538488E-04 -2.640419E-02 -8.839937E-05 -5.298488E-02 -3.147305E-04 -2.462926E-02 -7.609382E-05 -3.274348E-02 -1.347060E-04 -4.085845E-02 -2.061636E-04 -3.613681E-02 -1.608827E-04 -3.188424E-02 -1.170448E-04 -3.090210E-02 -1.209556E-04 -4.916591E-02 -2.638816E-04 -3.463680E-02 -1.731202E-04 -2.473796E-02 -8.278777E-05 -2.876733E-02 -1.050578E-04 -2.818020E-02 -9.186488E-05 -2.922451E-02 -9.710630E-05 -2.867494E-02 -1.008386E-04 -2.048136E-02 -5.645393E-05 -2.709023E-02 -9.906565E-05 -2.060958E-02 -6.002022E-05 -2.400813E-02 -7.048793E-05 -2.041445E-02 -5.660380E-05 -3.022382E-02 -1.232007E-04 -2.428404E-02 -7.261848E-05 -1.317267E-02 -4.498520E-05 -1.725417E-02 -4.131436E-05 -1.439809E-02 -2.877223E-05 -1.849952E-02 -3.964099E-05 -1.298598E-02 -2.510194E-05 -1.158199E-02 -1.753824E-05 -2.399736E-02 -7.914398E-05 -1.618716E-02 -3.923219E-05 -1.582299E-02 -3.446241E-05 -1.281460E-02 -2.948723E-05 -1.687823E-02 -3.916635E-05 -1.992356E-02 -5.363759E-05 -9.964687E-03 -2.281351E-05 -9.741073E-03 -1.461704E-05 -1.016266E-02 -1.578045E-05 -1.165241E-02 -1.448412E-05 -1.645559E-02 -3.314741E-05 -1.019874E-02 -1.584348E-05 -1.400560E-02 -2.950132E-05 -1.339261E-02 -2.462337E-05 -9.864617E-03 -2.007031E-05 -1.033312E-02 -1.570664E-05 -1.150186E-02 -1.612123E-05 -8.165735E-03 -9.980334E-06 -1.039922E-02 -2.137334E-05 -7.778314E-03 -1.402972E-05 -2.352819E-02 -7.324745E-05 -1.832670E-02 -5.260061E-05 -1.958916E-02 -4.738463E-05 -2.752632E-02 -1.321234E-04 -1.290240E-02 -2.435598E-05 -1.180814E-02 -1.989960E-05 -1.968230E-02 -4.672576E-05 -2.074128E-02 -5.154692E-05 -1.506303E-02 -2.974396E-05 -2.158432E-02 -6.994225E-05 -2.106432E-02 -6.601892E-05 -1.297999E-02 -2.683746E-05 -4.398209E-02 -2.260240E-04 -3.493420E-02 -1.634600E-04 -3.877993E-02 -1.929775E-04 -2.663088E-02 -8.262555E-05 -2.385591E-02 -7.188146E-05 -2.756789E-02 -8.724472E-05 -4.223824E-02 -2.331366E-04 -3.372408E-02 -1.376633E-04 -2.877054E-02 -1.172152E-04 -2.505284E-02 -6.877934E-05 -2.710121E-02 -9.089126E-05 -2.491989E-02 -7.126133E-05 -4.605415E-02 -2.550818E-04 -3.674502E-02 -1.551214E-04 -3.682502E-02 -1.637234E-04 -4.294065E-02 -2.131753E-04 -3.770825E-02 -1.835164E-04 -3.445084E-02 -1.375944E-04 -3.954845E-02 -1.848016E-04 -4.320951E-02 -2.332661E-04 -2.976462E-02 -1.143727E-04 -3.263580E-02 -1.287108E-04 -4.185045E-02 -1.965114E-04 -3.879064E-02 -1.631517E-04 -6.117745E-02 -4.170051E-04 -5.208900E-02 -2.961117E-04 -5.034441E-02 -2.985461E-04 -4.763203E-02 -2.520770E-04 -4.424593E-02 -2.210065E-04 -4.633482E-02 -2.857246E-04 -6.172917E-02 -4.365884E-04 -4.667374E-02 -2.416468E-04 -4.615839E-02 -2.447158E-04 -4.202865E-02 -1.984881E-04 -3.687271E-02 -1.549029E-04 -3.781817E-02 -1.658791E-04 -5.350156E-02 -3.106556E-04 -5.738403E-02 -3.535711E-04 -5.581047E-02 -3.600168E-04 -5.548481E-02 -3.477589E-04 -5.976117E-02 -4.066921E-04 -3.679728E-02 -1.797632E-04 -4.181607E-02 -2.319380E-04 -4.475783E-02 -2.471295E-04 -5.073065E-02 -2.731166E-04 -4.282973E-02 -2.376864E-04 -3.923270E-02 -1.868782E-04 -3.175293E-02 -1.204289E-04 -3.821514E-02 -1.563696E-04 -4.698886E-02 -2.394623E-04 -4.501447E-02 -2.402396E-04 -3.789686E-02 -1.636683E-04 -4.356985E-02 -2.501184E-04 -3.738072E-02 -1.625968E-04 -3.207025E-02 -1.387594E-04 -3.204040E-02 -1.219128E-04 -4.516239E-02 -2.412503E-04 -4.133319E-02 -1.807484E-04 -2.760180E-02 -8.957336E-05 -4.274635E-02 -2.203768E-04 -3.183938E-02 -1.177784E-04 -3.431517E-02 -1.538918E-04 -3.335945E-02 -1.452163E-04 -3.036081E-02 -1.173248E-04 -3.231608E-02 -1.473817E-04 -3.026666E-02 -1.062646E-04 -2.381248E-02 -6.812346E-05 -2.438669E-02 -7.616674E-05 -2.657091E-02 -8.997086E-05 -2.155185E-02 -7.092421E-05 -2.241945E-02 -5.990905E-05 -3.070897E-02 -1.109960E-04 -2.580881E-02 -7.863309E-05 -2.134721E-02 -6.345767E-05 -3.007460E-02 -1.199346E-04 -2.158487E-02 -5.631137E-05 -2.267038E-02 -6.523479E-05 -2.199756E-02 -6.744627E-05 -1.920160E-02 -4.676740E-05 -1.927293E-02 -5.882526E-05 -1.309800E-02 -2.176798E-05 -1.864318E-02 -4.222760E-05 -2.427004E-02 -7.787837E-05 -2.143559E-02 -5.842615E-05 -1.187245E-02 -3.400806E-05 -1.386855E-02 -2.215090E-05 -1.089761E-02 -1.742663E-05 -1.054008E-02 -1.719743E-05 -1.573092E-02 -2.947697E-05 -1.260841E-02 -2.538616E-05 -9.335769E-03 -1.220699E-05 -9.218607E-03 -1.346226E-05 -1.232919E-02 -2.739036E-05 -1.540769E-02 -3.545632E-05 -1.047417E-02 -1.403218E-05 -8.091074E-03 -9.942405E-06 -9.757397E-03 -1.839030E-05 -1.147311E-02 -2.272680E-05 -6.625367E-03 -9.542469E-06 -1.132951E-02 -2.290402E-05 -1.276799E-02 -2.736073E-05 -1.641171E-02 -4.522620E-05 -1.038484E-02 -2.444781E-05 -1.059856E-02 -2.086366E-05 -1.070727E-02 -3.120073E-05 -9.434079E-03 -2.288235E-05 -1.260589E-02 -2.115523E-05 -8.609571E-03 -1.014235E-05 -1.906718E-02 -4.342750E-05 -1.697807E-02 -3.746587E-05 -1.655549E-02 -3.279717E-05 -2.335945E-02 -8.680066E-05 -1.947075E-02 -4.582833E-05 -2.334564E-02 -6.827484E-05 -1.970475E-02 -5.161446E-05 -2.176597E-02 -8.091171E-05 -1.794831E-02 -4.826888E-05 -1.453865E-02 -2.543285E-05 -2.285340E-02 -7.733631E-05 -1.495227E-02 -3.812970E-05 -2.993202E-02 -1.105328E-04 -2.591986E-02 -7.889731E-05 -2.891690E-02 -1.170195E-04 -2.591958E-02 -8.245187E-05 -2.472591E-02 -6.792489E-05 -1.984583E-02 -4.399055E-05 -2.723781E-02 -1.063286E-04 -2.214049E-02 -6.647832E-05 -1.976025E-02 -4.630788E-05 -2.362519E-02 -9.840049E-05 -2.147637E-02 -5.680267E-05 -1.716604E-02 -3.707514E-05 -3.853916E-02 -1.905886E-04 -3.220009E-02 -1.166545E-04 -3.072451E-02 -1.105417E-04 -3.416322E-02 -1.445852E-04 -3.081335E-02 -1.205464E-04 -2.381824E-02 -7.421006E-05 -2.919176E-02 -1.443329E-04 -3.165320E-02 -1.643449E-04 -2.399334E-02 -7.031311E-05 -2.931290E-02 -1.089751E-04 -2.541529E-02 -9.960904E-05 -2.496511E-02 -9.522684E-05 -4.191717E-02 -2.319644E-04 -4.194175E-02 -2.515421E-04 -4.029489E-02 -2.034800E-04 -2.949880E-02 -1.001309E-04 -3.311240E-02 -2.069653E-04 -3.311074E-02 -1.645850E-04 -2.609443E-02 -7.829184E-05 -2.523310E-02 -7.753633E-05 -3.376196E-02 -1.542562E-04 -3.370657E-02 -1.584460E-04 -2.316126E-02 -6.322560E-05 -2.849745E-02 -1.006036E-04 -4.156928E-02 -1.941410E-04 -3.356649E-02 -1.323048E-04 -3.504110E-02 -1.432793E-04 -4.188246E-02 -2.087133E-04 -2.686062E-02 -1.008920E-04 -3.264472E-02 -1.519956E-04 -3.182824E-02 -1.190821E-04 -3.230472E-02 -1.432567E-04 -3.014385E-02 -1.104329E-04 -3.127630E-02 -1.124605E-04 -3.215046E-02 -1.161615E-04 -3.028866E-02 -1.020886E-04 -3.771125E-02 -1.568073E-04 -3.370873E-02 -1.337798E-04 -4.025498E-02 -1.918052E-04 -2.635483E-02 -7.350768E-05 -2.361243E-02 -7.420144E-05 -3.747673E-02 -2.016310E-04 -2.747199E-02 -8.499093E-05 -3.168249E-02 -1.354519E-04 -2.123972E-02 -5.349966E-05 -2.029422E-02 -4.819609E-05 -2.757353E-02 -9.520625E-05 -3.241854E-02 -1.263115E-04 -2.339411E-02 -8.048390E-05 -2.881367E-02 -9.755501E-05 -2.959500E-02 -1.180648E-04 -2.255464E-02 -6.753101E-05 -4.047075E-02 -1.783640E-04 -3.116618E-02 -1.271595E-04 -2.360487E-02 -7.555159E-05 -2.020519E-02 -5.400702E-05 -2.646647E-02 -7.518930E-05 -2.547209E-02 -9.058727E-05 -1.278101E-02 -2.432873E-05 -2.394671E-02 -7.236070E-05 -1.399890E-02 -2.909745E-05 -1.693268E-02 -4.013852E-05 -1.661474E-02 -3.646989E-05 -1.683699E-02 -3.576439E-05 -1.878683E-02 -4.752490E-05 -1.779186E-02 -5.032257E-05 -1.615460E-02 -3.517429E-05 -1.467092E-02 -2.974604E-05 -1.693919E-02 -3.956534E-05 -1.570365E-02 -3.373372E-05 -1.503755E-02 -3.242993E-05 -1.350241E-02 -2.471502E-05 -1.132128E-02 -2.210554E-05 -1.394835E-02 -2.288474E-05 -7.707010E-03 -1.408651E-05 -1.105673E-02 -1.950348E-05 -1.597153E-02 -2.996363E-05 -1.072279E-02 -1.642956E-05 -9.931403E-03 -1.596209E-05 -3.110131E-03 -1.979116E-06 -1.465778E-02 -2.665954E-05 -8.711776E-03 -1.658595E-05 -3.336279E-03 -3.121041E-06 -1.220546E-02 -2.078425E-05 -1.225808E-02 -2.498648E-05 -5.941201E-03 -5.858248E-06 -8.017505E-03 -9.987361E-06 -1.032012E-02 -1.689346E-05 -1.122116E-02 -2.547015E-05 -7.303253E-03 -1.021165E-05 -1.018508E-02 -1.390217E-05 -6.537846E-03 -1.231905E-05 -3.757225E-03 -2.146236E-06 -6.253529E-03 -8.259456E-06 -8.429652E-03 -1.132331E-05 -6.846152E-03 -1.089548E-05 -1.540905E-02 -4.707146E-05 -1.380105E-02 -2.885252E-05 -1.506988E-02 -3.657193E-05 -1.379370E-02 -2.325176E-05 -9.540645E-03 -2.912938E-05 -1.053361E-02 -1.745746E-05 -8.796644E-03 -1.302715E-05 -9.798877E-03 -1.776907E-05 -1.287457E-02 -2.307421E-05 -1.194402E-02 -2.276268E-05 -7.875525E-03 -1.292927E-05 -5.533880E-03 -9.384723E-06 -1.864321E-02 -4.177596E-05 -1.252461E-02 -2.176958E-05 -1.644030E-02 -4.131255E-05 -1.697179E-02 -3.953043E-05 -9.140492E-03 -1.319242E-05 -9.958402E-03 -1.459665E-05 -1.425287E-02 -3.897232E-05 -1.522358E-02 -3.028879E-05 -1.361118E-02 -2.815573E-05 -1.173677E-02 -3.088583E-05 -1.617474E-02 -3.012921E-05 -1.598127E-02 -3.641752E-05 -1.724536E-02 -3.982285E-05 -2.253691E-02 -6.632574E-05 -2.268227E-02 -5.893945E-05 -2.582333E-02 -9.202078E-05 -1.982485E-02 -6.093449E-05 -1.544437E-02 -3.045457E-05 -1.968776E-02 -5.933245E-05 -2.092753E-02 -6.834686E-05 -1.664629E-02 -4.979724E-05 -1.855281E-02 -6.404621E-05 -2.195650E-02 -6.222690E-05 -2.186198E-02 -5.700014E-05 -2.078639E-02 -4.826480E-05 -2.147531E-02 -5.352146E-05 -2.309193E-02 -6.508444E-05 -2.306719E-02 -7.442212E-05 -2.181171E-02 -6.065432E-05 -2.787754E-02 -1.071646E-04 -2.038266E-02 -6.322425E-05 -2.066861E-02 -6.321760E-05 -2.341755E-02 -6.599464E-05 -1.940287E-02 -5.285084E-05 -2.311451E-02 -6.931733E-05 -2.685211E-02 -9.869681E-05 -2.577665E-02 -9.741583E-05 -2.127713E-02 -7.233352E-05 -3.534780E-02 -1.462501E-04 -2.985988E-02 -1.001501E-04 -2.157060E-02 -5.933210E-05 -2.112991E-02 -6.091345E-05 -1.791858E-02 -4.849939E-05 -2.317059E-02 -5.941629E-05 -1.585209E-02 -3.680922E-05 -1.761272E-02 -4.005327E-05 -2.673873E-02 -8.415236E-05 -2.195005E-02 -7.869690E-05 -2.169063E-02 -6.115181E-05 -1.902034E-02 -4.602942E-05 -2.149684E-02 -6.272837E-05 -2.152317E-02 -5.647475E-05 -1.267811E-02 -2.551472E-05 -1.902212E-02 -4.501454E-05 -1.468929E-02 -2.854665E-05 -2.098348E-02 -5.162857E-05 -1.448437E-02 -3.165154E-05 -1.385842E-02 -2.946322E-05 -2.214565E-02 -6.004180E-05 -1.824698E-02 -3.872549E-05 -1.212354E-02 -2.133339E-05 -2.018308E-02 -5.701150E-05 -2.166624E-02 -5.196544E-05 -2.142212E-02 -5.674884E-05 -1.267848E-02 -2.171626E-05 -1.758911E-02 -4.711902E-05 -1.111921E-02 -2.058872E-05 -1.517506E-02 -2.980149E-05 -1.147226E-02 -1.573079E-05 -1.249264E-02 -2.217903E-05 -1.604063E-02 -3.750625E-05 -1.275295E-02 -2.494568E-05 -1.612605E-02 -3.577658E-05 -1.249864E-02 -3.018969E-05 -1.188510E-02 -2.704321E-05 -1.571000E-02 -3.615816E-05 -1.235323E-02 -2.593348E-05 -1.676586E-02 -4.472755E-05 -1.093806E-02 -1.930162E-05 -1.176929E-02 -2.511180E-05 -1.397747E-02 -2.813515E-05 -9.701315E-03 -1.930872E-05 -1.399983E-02 -3.413054E-05 -1.986885E-02 -5.082098E-05 -8.243555E-03 -1.200852E-05 -1.024429E-02 -1.296572E-05 -1.258003E-02 -1.952799E-05 -1.610829E-02 -3.961341E-05 -1.010586E-02 -1.549208E-05 -1.252095E-02 -2.770018E-05 -8.230588E-03 -1.450505E-05 -8.380929E-03 -1.203824E-05 -8.828715E-03 -1.191588E-05 -6.588527E-03 -7.910780E-06 -6.380189E-03 -6.533479E-06 -5.052056E-03 -5.336338E-06 -3.648351E-03 -2.706990E-06 -2.149471E-03 -1.225876E-06 -9.270100E-03 -1.169691E-05 -1.117400E-02 -2.249063E-05 -5.230590E-03 -4.655893E-06 -7.224676E-03 -1.008003E-05 -3.887357E-03 -3.670860E-06 -3.183273E-03 -1.847498E-06 -3.708170E-03 -2.623818E-06 -5.854425E-03 -1.020941E-05 -5.406569E-03 -5.391988E-06 -9.036302E-03 -1.748353E-05 -8.903194E-03 -1.445005E-05 -9.987482E-03 -2.075751E-05 -8.426663E-03 -1.155563E-05 -8.912136E-03 -1.175066E-05 -4.122838E-03 -3.170046E-06 -4.845177E-03 -4.237971E-06 -6.822194E-03 -1.051328E-05 -4.425000E-03 -4.417976E-06 -7.424172E-03 -9.891741E-06 -4.992950E-03 -5.945799E-06 -7.149030E-03 -1.123994E-05 -4.625444E-03 -5.049047E-06 -1.123851E-02 -2.017630E-05 -1.074541E-02 -1.709195E-05 -1.430110E-02 -3.117294E-05 -9.806637E-03 -1.530391E-05 -1.043812E-02 -1.609521E-05 -1.012866E-02 -1.391247E-05 -1.428192E-02 -2.902409E-05 -1.605416E-02 -3.562493E-05 -9.063095E-03 -1.372032E-05 -9.587205E-03 -1.473939E-05 -9.634515E-03 -1.858518E-05 -1.164975E-02 -2.656325E-05 -1.361864E-02 -2.518422E-05 -1.167329E-02 -2.323748E-05 -1.622385E-02 -3.856234E-05 -1.214097E-02 -2.153842E-05 -1.381854E-02 -2.815505E-05 -1.415211E-02 -4.135908E-05 -1.568971E-02 -3.813496E-05 -1.198123E-02 -2.333564E-05 -8.499425E-03 -1.126897E-05 -1.312625E-02 -3.325212E-05 -1.172860E-02 -2.042689E-05 -1.005348E-02 -1.782865E-05 -1.548579E-02 -3.103766E-05 -1.744521E-02 -3.960003E-05 -1.654740E-02 -3.986988E-05 -1.620467E-02 -3.009003E-05 -1.948116E-02 -5.036150E-05 -1.418148E-02 -2.971887E-05 -1.337833E-02 -2.666872E-05 -1.314218E-02 -2.648418E-05 -1.436798E-02 -2.490823E-05 -9.444986E-03 -1.101269E-05 -1.962001E-02 -8.135189E-05 -1.158154E-02 -1.952295E-05 -1.471099E-02 -3.133120E-05 -1.541812E-02 -3.170497E-05 -1.674531E-02 -4.322938E-05 -1.669392E-02 -3.544709E-05 -1.333115E-02 -3.211381E-05 -1.738951E-02 -4.841020E-05 -1.007222E-02 -1.774930E-05 -1.295078E-02 -2.638113E-05 -1.271717E-02 -2.298976E-05 -1.404483E-02 -2.889248E-05 -1.576832E-02 -3.529377E-05 -1.252846E-02 -2.718789E-05 -2.519173E-02 -8.963887E-05 -1.493179E-02 -3.748831E-05 -1.259822E-02 -2.429153E-05 -1.224327E-02 -1.829117E-05 -1.391862E-02 -2.860704E-05 -8.357253E-03 -1.029121E-05 -1.570825E-02 -3.413707E-05 -1.359733E-02 -2.641606E-05 -1.091443E-02 -1.715332E-05 -8.155749E-03 -1.261821E-05 -1.313846E-02 -2.597075E-05 -8.293564E-03 -1.056976E-05 -1.638901E-02 -3.229628E-05 -1.331850E-02 -3.096114E-05 -1.103350E-02 -1.929035E-05 -1.727217E-02 -4.051979E-05 -9.518809E-03 -1.410510E-05 -1.300800E-02 -2.937228E-05 -1.046353E-02 -1.575334E-05 -1.036019E-02 -1.658144E-05 -8.892217E-03 -1.726775E-05 -9.649910E-03 -1.409080E-05 -1.146930E-02 -2.018867E-05 -8.918398E-03 -1.307570E-05 -1.525733E-02 -3.596673E-05 -1.004009E-02 -1.246514E-05 -1.066698E-02 -2.185894E-05 -7.770912E-03 -1.480934E-05 -7.264717E-03 -8.442828E-06 -6.706343E-03 -6.852573E-06 -5.559456E-03 -4.744752E-06 -5.773360E-03 -7.781275E-06 -1.331078E-02 -3.353599E-05 -8.788678E-03 -1.329146E-05 -4.884040E-03 -4.077409E-06 -8.675118E-03 -1.319086E-05 -4.761159E-03 -3.796641E-06 -5.277064E-03 -5.807731E-06 -1.108365E-02 -1.916299E-05 -5.331867E-03 -3.733672E-06 -7.054526E-03 -6.862094E-06 -5.863290E-03 -8.388015E-06 -7.544134E-03 -1.042553E-05 -5.750484E-03 -5.095339E-06 -5.249358E-03 -3.213161E-06 -7.899479E-03 -9.484436E-06 -4.160278E-03 -4.806702E-06 -7.679996E-03 -2.071836E-05 -6.241972E-03 -1.620756E-05 -5.913948E-03 -7.527048E-06 -4.733716E-03 -5.631878E-06 -2.903451E-03 -2.658722E-06 -3.127420E-03 -2.299870E-06 -2.273717E-03 -1.344135E-06 -6.534306E-03 -1.124316E-05 -7.835003E-03 -1.715904E-05 -4.882363E-03 -4.758963E-06 -3.720325E-03 -3.452423E-06 -1.428452E-03 -1.333526E-06 -3.504443E-03 -2.552735E-06 -8.268492E-03 -1.053438E-05 -9.457152E-03 -1.477101E-05 -4.409644E-03 -4.661365E-06 -5.391744E-03 -4.980226E-06 -7.357835E-03 -8.692158E-06 -4.819563E-03 -3.684180E-06 -7.257471E-03 -8.300854E-06 -8.234387E-03 -1.648552E-05 -7.005187E-03 -8.215133E-06 -8.218179E-03 -1.271584E-05 -4.248638E-03 -4.615897E-06 -6.471659E-03 -7.110986E-06 -8.889291E-03 -1.460347E-05 -8.616060E-03 -1.124291E-05 -8.973876E-03 -1.442105E-05 -6.214996E-03 -1.237961E-05 -6.199460E-03 -8.437599E-06 -2.474487E-03 -1.269623E-06 -1.303002E-02 -3.064014E-05 -1.148543E-02 -2.273454E-05 -1.266333E-02 -2.372659E-05 -1.058814E-02 -2.391393E-05 -5.834966E-03 -9.147127E-06 -5.517822E-03 -5.264691E-06 -1.270359E-02 -2.820747E-05 -1.820335E-02 -4.287032E-05 -1.202094E-02 -2.800408E-05 -7.736254E-03 -1.836141E-05 -6.145051E-03 -6.272679E-06 -7.726439E-03 -1.228446E-05 -1.411190E-02 -2.865658E-05 -6.550872E-03 -6.014982E-06 -2.088300E-02 -7.573466E-05 -1.388048E-02 -3.669556E-05 -1.132008E-02 -1.910843E-05 -1.611954E-02 -3.536212E-05 -1.481933E-02 -3.146401E-05 -1.247993E-02 -2.294126E-05 -1.394123E-02 -2.867543E-05 -1.072461E-02 -1.866919E-05 -8.610956E-03 -1.120688E-05 -8.083860E-03 -8.161992E-06 -1.162751E-02 -1.795366E-05 -9.128039E-03 -1.252646E-05 -9.364221E-03 -1.603445E-05 -8.294106E-03 -1.019170E-05 -5.833363E-03 -4.941650E-06 -9.811611E-03 -1.274458E-05 -1.603475E-02 -3.880395E-05 -1.271422E-02 -2.182851E-05 -1.519349E-02 -3.269445E-05 -9.595042E-03 -1.801667E-05 -7.059973E-03 -7.819618E-06 -5.876271E-03 -1.068936E-05 -1.340147E-02 -3.113903E-05 -4.145261E-03 -3.270808E-06 -1.596720E-02 -3.465819E-05 -1.433346E-02 -2.905578E-05 -8.468040E-03 -1.341062E-05 -1.395194E-02 -2.559614E-05 -1.200470E-02 -1.982352E-05 -1.665933E-02 -3.793148E-05 -1.726359E-02 -3.968046E-05 -6.540447E-03 -5.939253E-06 -8.142400E-03 -1.045929E-05 -6.566817E-03 -8.688594E-06 -1.015592E-02 -1.244647E-05 -1.077665E-02 -1.554617E-05 -1.360651E-02 -3.317478E-05 -1.060123E-02 -1.533418E-05 -3.815593E-03 -2.480255E-06 -9.569339E-03 -1.129499E-05 -9.012545E-03 -1.643164E-05 -1.246360E-02 -3.026280E-05 -8.297915E-03 -9.462041E-06 -5.099837E-03 -5.488747E-06 -8.276566E-03 -1.499072E-05 -3.692279E-03 -3.276555E-06 -8.083217E-03 -1.216780E-05 -9.547609E-03 -1.541880E-05 -1.043999E-02 -1.447586E-05 -9.984558E-03 -1.393147E-05 -6.036500E-03 -1.256268E-05 -5.023445E-03 -4.154969E-06 -7.024538E-03 -1.085504E-05 -7.537608E-03 -1.160621E-05 -5.017595E-03 -4.922120E-06 -5.050436E-03 -4.024516E-06 -3.123518E-03 -1.695608E-06 -3.831129E-03 -3.485286E-06 -5.964101E-03 -9.872984E-06 -3.809889E-03 -3.837033E-06 -4.120333E-03 -3.567476E-06 -3.925178E-03 -5.899336E-06 -3.890602E-03 -8.542757E-06 -6.033356E-03 -7.736141E-06 -4.271392E-03 -3.643602E-06 -2.282046E-03 -1.281394E-06 -6.262911E-03 -1.134696E-05 -4.313813E-03 -4.443331E-06 -1.308832E-03 -4.103970E-07 -2.590108E-03 -2.620429E-06 -5.831777E-03 -4.892875E-06 -5.376268E-03 -5.205758E-06 -9.496856E-03 -1.606537E-05 -7.245952E-03 -7.095242E-06 -7.623819E-03 -1.187689E-05 -5.536252E-03 -5.148443E-06 -1.245396E-02 -2.199505E-05 -7.641760E-03 -1.306388E-05 -1.005116E-02 -1.904677E-05 -1.159156E-02 -2.899326E-05 -1.114868E-02 -2.094752E-05 -1.010147E-02 -1.978005E-05 -8.874213E-03 -1.298622E-05 -1.283785E-02 -2.632677E-05 -5.598145E-03 -4.564302E-06 -4.874451E-03 -6.380741E-06 -4.166868E-03 -4.546806E-06 -5.450652E-03 -4.552973E-06 -9.123569E-03 -1.521157E-05 -1.341420E-02 -2.773663E-05 -9.949075E-03 -1.548877E-05 -1.128600E-02 -1.714535E-05 -9.944157E-03 -1.206624E-05 -9.339838E-03 -1.587210E-05 -1.407135E-02 -3.845557E-05 -1.079969E-02 -1.419090E-05 -1.806763E-02 -5.775082E-05 -1.538811E-02 -3.591506E-05 -9.283522E-03 -1.519392E-05 -8.256501E-03 -1.262631E-05 -1.236476E-02 -1.963613E-05 -2.020990E-02 -5.409171E-05 -1.152596E-02 -2.039197E-05 -1.050303E-02 -2.499041E-05 -1.326414E-02 -2.783213E-05 -7.696971E-03 -9.711977E-06 -1.473705E-02 -2.646008E-05 -1.062292E-02 -1.576562E-05 -1.707377E-02 -4.212601E-05 -8.778679E-03 -1.128995E-05 -9.710118E-03 -1.623481E-05 -7.636475E-03 -1.094355E-05 -1.387905E-02 -2.941626E-05 -1.776651E-02 -4.396460E-05 -1.818565E-02 -4.350858E-05 -1.761749E-02 -4.630235E-05 -2.043671E-02 -6.064648E-05 -1.635160E-02 -4.147100E-05 -1.364022E-02 -2.386011E-05 -1.724650E-02 -5.086651E-05 -1.457393E-02 -3.218203E-05 -1.625704E-02 -4.109869E-05 -1.536770E-02 -3.150971E-05 -1.415214E-02 -2.531338E-05 -1.764117E-02 -3.839917E-05 -1.856292E-02 -4.105079E-05 -1.122011E-02 -2.240362E-05 -1.237537E-02 -1.904481E-05 -1.725511E-02 -3.218693E-05 -1.246019E-02 -2.168729E-05 -2.268477E-02 -6.638152E-05 -1.772582E-02 -4.134691E-05 -1.846727E-02 -4.453692E-05 -2.211594E-02 -6.148331E-05 -1.337994E-02 -2.272968E-05 -1.800735E-02 -4.594283E-05 -1.767634E-02 -3.572802E-05 -2.109287E-02 -7.624418E-05 -2.116135E-02 -5.023945E-05 -1.511244E-02 -3.916543E-05 -2.555283E-02 -8.270634E-05 -2.320248E-02 -6.856995E-05 -1.490210E-02 -3.025554E-05 -1.650536E-02 -3.349063E-05 -2.005340E-02 -6.329046E-05 -1.876604E-02 -4.632276E-05 -2.017935E-02 -5.608622E-05 -1.623543E-02 -3.183867E-05 -1.059288E-02 -1.746867E-05 -1.923413E-02 -5.626395E-05 -1.874482E-02 -5.158196E-05 -1.436557E-02 -3.262805E-05 -1.736130E-02 -4.360560E-05 -2.044766E-02 -5.055246E-05 -1.508312E-02 -3.245600E-05 -1.328001E-02 -2.673879E-05 -1.466660E-02 -2.878429E-05 -1.289951E-02 -2.132152E-05 -1.410955E-02 -2.671457E-05 -1.814074E-02 -4.435357E-05 -2.012953E-02 -5.472686E-05 -1.186784E-02 -2.108638E-05 -1.158902E-02 -2.017687E-05 -9.605924E-03 -1.492077E-05 -1.409567E-02 -2.579784E-05 -1.311103E-02 -2.570267E-05 -1.707665E-02 -4.130920E-05 -1.248159E-02 -2.515719E-05 -2.097524E-02 -5.151201E-05 -1.444457E-02 -2.981175E-05 -1.072187E-02 -1.803695E-05 -9.014009E-03 -1.215827E-05 -9.559055E-03 -1.537581E-05 -1.354384E-02 -2.184405E-05 -4.828517E-03 -6.482158E-06 -6.253387E-03 -5.785292E-06 -1.379191E-02 -2.710641E-05 -1.011815E-02 -1.374848E-05 -1.342278E-02 -3.152030E-05 -8.883639E-03 -1.651249E-05 -1.847885E-02 -6.016422E-05 -8.586243E-03 -1.066056E-05 -6.968205E-03 -8.792141E-06 -1.218017E-02 -2.375039E-05 -4.288567E-03 -2.617468E-06 -6.568856E-03 -6.417620E-06 -9.364388E-03 -1.515485E-05 -7.810927E-03 -9.503941E-06 -1.316444E-02 -2.494672E-05 -8.772821E-03 -1.075467E-05 -9.114583E-03 -1.293064E-05 -5.120610E-03 -5.597666E-06 -1.156077E-02 -2.090644E-05 -1.044752E-02 -1.460984E-05 -4.306774E-03 -7.024156E-06 -6.743680E-03 -9.397053E-06 -1.132063E-02 -2.916783E-05 -9.875394E-03 -1.234227E-05 -8.066518E-03 -1.631648E-05 -1.197445E-02 -2.795662E-05 -1.196930E-02 -2.592654E-05 -1.424965E-02 -2.937215E-05 -9.362177E-03 -1.637802E-05 -1.115631E-02 -2.100489E-05 -6.612368E-03 -1.091592E-05 -1.030811E-02 -2.480048E-05 -1.024176E-02 -1.540918E-05 -8.799976E-03 -1.413045E-05 -1.817266E-02 -5.223457E-05 -1.320418E-02 -2.287606E-05 -1.190482E-02 -2.042598E-05 -1.296875E-02 -2.780267E-05 -1.250433E-02 -2.092242E-05 -1.114237E-02 -1.800945E-05 -1.312112E-02 -2.394975E-05 -1.206217E-02 -2.206129E-05 -1.913237E-02 -5.391475E-05 -2.015987E-02 -4.368668E-05 -1.126423E-02 -1.875823E-05 -1.360231E-02 -2.402648E-05 -1.853506E-02 -4.518491E-05 -1.582011E-02 -3.202477E-05 -1.750058E-02 -4.932715E-05 -1.849790E-02 -5.325631E-05 -2.129000E-02 -5.323882E-05 -1.294333E-02 -2.153410E-05 -2.386151E-02 -7.053393E-05 -2.237759E-02 -6.198345E-05 -1.402168E-02 -3.040550E-05 -2.166707E-02 -7.200843E-05 -1.815377E-02 -4.704586E-05 -2.159074E-02 -9.800484E-05 -2.096789E-02 -5.417603E-05 -2.036776E-02 -5.114163E-05 -1.950805E-02 -5.196224E-05 -1.203115E-02 -2.466652E-05 -2.375017E-02 -7.101139E-05 -2.078435E-02 -4.980028E-05 -1.967736E-02 -5.349609E-05 -1.492202E-02 -3.151061E-05 -2.448505E-02 -7.345642E-05 -2.875745E-02 -9.624049E-05 -1.308936E-02 -2.260928E-05 -1.883770E-02 -5.294121E-05 -2.132133E-02 -6.019067E-05 -2.681408E-02 -8.810170E-05 -1.857403E-02 -3.926673E-05 -1.774032E-02 -4.025585E-05 -2.588771E-02 -8.059759E-05 -2.050194E-02 -4.648784E-05 -2.612192E-02 -8.558295E-05 -1.686319E-02 -3.786866E-05 -2.745753E-02 -9.703052E-05 -2.602614E-02 -7.340705E-05 -2.099702E-02 -6.252305E-05 -2.411550E-02 -6.674417E-05 -2.570206E-02 -6.917677E-05 -2.753425E-02 -1.088979E-04 -2.289782E-02 -6.832742E-05 -1.728790E-02 -4.390010E-05 -2.345865E-02 -7.335296E-05 -1.670224E-02 -4.918814E-05 -2.958698E-02 -1.008389E-04 -2.262155E-02 -8.019776E-05 -2.171260E-02 -5.857256E-05 -2.739550E-02 -9.699654E-05 -1.898108E-02 -5.073772E-05 -2.158139E-02 -5.640212E-05 -2.653056E-02 -9.005949E-05 -2.557757E-02 -8.651930E-05 -1.719263E-02 -3.746877E-05 -1.270461E-02 -2.702019E-05 -2.371990E-02 -6.567867E-05 -2.133774E-02 -5.624387E-05 -2.412439E-02 -8.327847E-05 -2.144516E-02 -5.810134E-05 -2.096771E-02 -5.764847E-05 -2.010218E-02 -6.106688E-05 -2.662466E-02 -1.031716E-04 -2.128503E-02 -6.330504E-05 -2.077576E-02 -5.659759E-05 -1.910625E-02 -4.810183E-05 -1.994507E-02 -5.522830E-05 -1.318359E-02 -2.202071E-05 -1.847673E-02 -3.890771E-05 -1.525363E-02 -3.383373E-05 -2.323360E-02 -7.009641E-05 -2.160465E-02 -6.270896E-05 -2.815837E-02 -9.926554E-05 -2.825700E-02 -1.156243E-04 -1.661438E-02 -3.352935E-05 -1.707558E-02 -4.079662E-05 -1.663970E-02 -5.171770E-05 -1.537161E-02 -3.951696E-05 -1.515887E-02 -2.815234E-05 -1.262479E-02 -2.666049E-05 -2.270831E-02 -7.402779E-05 -1.637425E-02 -3.359896E-05 -1.433044E-02 -3.016015E-05 -1.086052E-02 -2.105095E-05 -1.827948E-02 -5.404440E-05 -1.512356E-02 -4.090325E-05 -1.341869E-02 -3.777277E-05 -1.144273E-02 -2.320403E-05 -1.032338E-02 -2.111004E-05 -1.324432E-02 -2.369582E-05 -1.323267E-02 -2.312589E-05 -7.378365E-03 -1.207116E-05 -1.198900E-02 -2.410816E-05 -1.143776E-02 -1.697429E-05 -5.960596E-03 -5.491388E-06 -8.671020E-03 -1.423578E-05 -1.046649E-02 -1.660152E-05 -1.015412E-02 -1.356611E-05 -4.437919E-03 -4.449282E-06 -8.070532E-03 -1.158768E-05 -1.339134E-02 -2.307637E-05 -1.588497E-02 -3.768975E-05 -9.869781E-03 -2.027492E-05 -1.346984E-02 -2.839713E-05 -1.481565E-02 -2.641963E-05 -1.622974E-02 -3.155688E-05 -1.228654E-02 -2.276535E-05 -9.854382E-03 -2.229720E-05 -8.655941E-03 -1.144096E-05 -8.579998E-03 -1.286624E-05 -1.701319E-02 -3.924030E-05 -9.817319E-03 -1.540490E-05 -2.169451E-02 -7.317248E-05 -2.105716E-02 -5.189702E-05 -1.963335E-02 -5.619116E-05 -2.183187E-02 -6.185293E-05 -1.721212E-02 -3.966296E-05 -1.657518E-02 -3.547912E-05 -1.888518E-02 -5.599282E-05 -1.856419E-02 -5.261571E-05 -2.022215E-02 -6.235701E-05 -1.750049E-02 -3.437263E-05 -2.144519E-02 -5.816976E-05 -1.487741E-02 -2.693460E-05 -1.556861E-02 -3.808581E-05 -2.287702E-02 -6.471426E-05 -1.502995E-02 -3.547384E-05 -2.333943E-02 -7.259310E-05 -1.682037E-02 -3.512266E-05 -1.559563E-02 -3.813310E-05 -2.534274E-02 -7.364335E-05 -2.480122E-02 -7.936460E-05 -1.877264E-02 -4.302495E-05 -2.255108E-02 -6.304951E-05 -1.327871E-02 -2.341276E-05 -1.978158E-02 -5.064958E-05 -2.719711E-02 -8.697999E-05 -3.450441E-02 -1.360084E-04 -2.418992E-02 -8.130715E-05 -2.755861E-02 -9.435699E-05 -2.906789E-02 -1.164895E-04 -2.492886E-02 -9.051357E-05 -2.149004E-02 -5.322652E-05 -1.882200E-02 -4.828092E-05 -3.559788E-02 -1.520518E-04 -2.750436E-02 -8.574229E-05 -2.225856E-02 -5.803244E-05 -2.338675E-02 -7.020780E-05 -3.715161E-02 -1.672352E-04 -2.832183E-02 -9.613959E-05 -3.620891E-02 -1.820751E-04 -1.842315E-02 -4.292893E-05 -3.073714E-02 -1.167359E-04 -2.239778E-02 -6.910113E-05 -3.816869E-02 -1.838537E-04 -3.039700E-02 -1.010395E-04 -2.746450E-02 -9.520787E-05 -2.678376E-02 -8.958685E-05 -1.959265E-02 -4.827447E-05 -2.161190E-02 -5.224194E-05 -2.866820E-02 -9.300929E-05 -3.051657E-02 -1.108463E-04 -2.779434E-02 -9.578374E-05 -2.381065E-02 -7.364073E-05 -3.580671E-02 -1.702522E-04 -3.245610E-02 -1.420184E-04 -3.074561E-02 -1.162297E-04 -2.368174E-02 -7.463994E-05 -3.053229E-02 -1.165041E-04 -2.791292E-02 -9.751321E-05 -1.851477E-02 -4.170606E-05 -2.647316E-02 -8.255669E-05 -2.688714E-02 -9.392494E-05 -3.140666E-02 -1.096021E-04 -2.467545E-02 -7.718465E-05 -1.941157E-02 -5.524811E-05 -3.374306E-02 -1.292663E-04 -2.025089E-02 -5.179623E-05 -2.535741E-02 -7.702579E-05 -2.469316E-02 -7.765177E-05 -2.952585E-02 -9.607704E-05 -2.637948E-02 -7.897857E-05 -2.244297E-02 -6.198303E-05 -2.299365E-02 -6.928750E-05 -2.384571E-02 -7.218845E-05 -3.265249E-02 -1.473318E-04 -2.949982E-02 -1.044208E-04 -2.330464E-02 -7.007243E-05 -1.937666E-02 -4.990461E-05 -1.836576E-02 -3.977508E-05 -2.200706E-02 -5.431158E-05 -1.760216E-02 -3.954597E-05 -2.161653E-02 -5.051231E-05 -2.685593E-02 -8.262522E-05 -2.031027E-02 -5.469024E-05 -1.729977E-02 -3.470083E-05 -2.245610E-02 -6.463192E-05 -2.480332E-02 -6.706820E-05 -1.636383E-02 -3.512895E-05 -1.629117E-02 -3.227987E-05 -1.777456E-02 -3.877314E-05 -1.523888E-02 -2.794713E-05 -1.933720E-02 -5.130630E-05 -2.073569E-02 -5.667785E-05 -2.159324E-02 -5.953356E-05 -2.252773E-02 -7.064923E-05 -1.497171E-02 -3.139235E-05 -1.702700E-02 -3.702921E-05 -1.197831E-02 -2.110040E-05 -1.326288E-02 -2.668205E-05 -9.877691E-03 -1.417188E-05 -9.222468E-03 -1.493126E-05 -1.916119E-02 -5.100381E-05 -1.618530E-02 -3.741295E-05 -9.744935E-03 -1.312151E-05 -4.205073E-03 -5.238984E-06 -1.606532E-02 -3.801359E-05 -1.115862E-02 -2.015015E-05 -1.312318E-02 -3.970688E-05 -1.092582E-02 -1.677629E-05 -8.988789E-03 -1.272128E-05 -1.116462E-02 -1.435361E-05 -1.177363E-02 -2.013606E-05 -1.392896E-02 -3.825189E-05 -7.595272E-03 -1.080161E-05 -1.243058E-02 -1.937258E-05 -8.823743E-03 -1.585993E-05 -1.072892E-02 -2.225554E-05 -9.610737E-03 -1.152464E-05 -7.143175E-03 -1.112162E-05 -9.471167E-03 -1.466213E-05 -1.060489E-02 -1.784667E-05 -2.767925E-02 -9.174943E-05 -1.613735E-02 -3.391468E-05 -1.980520E-02 -6.099070E-05 -2.710790E-02 -1.005842E-04 -1.498945E-02 -3.548209E-05 -2.090399E-02 -6.229284E-05 -1.867828E-02 -5.023418E-05 -2.101525E-02 -5.304849E-05 -1.495603E-02 -3.564927E-05 -2.206499E-02 -8.477764E-05 -1.774373E-02 -4.204463E-05 -1.321048E-02 -2.339091E-05 -3.032303E-02 -1.133561E-04 -2.906158E-02 -1.116010E-04 -1.416547E-02 -3.074243E-05 -2.396880E-02 -6.563656E-05 -2.277934E-02 -6.079700E-05 -1.978949E-02 -5.275993E-05 -2.518782E-02 -7.984951E-05 -2.706826E-02 -9.202956E-05 -2.708490E-02 -9.059865E-05 -1.986295E-02 -4.689709E-05 -2.616568E-02 -8.883803E-05 -2.130847E-02 -6.518411E-05 -2.806912E-02 -8.769554E-05 -3.084102E-02 -1.172123E-04 -2.897371E-02 -1.021030E-04 -2.903836E-02 -1.108727E-04 -2.605433E-02 -8.468280E-05 -2.332233E-02 -6.130579E-05 -3.234471E-02 -1.225845E-04 -3.300429E-02 -1.500123E-04 -2.311117E-02 -6.190932E-05 -2.436504E-02 -7.178823E-05 -3.008481E-02 -1.005979E-04 -1.928369E-02 -4.312116E-05 -3.011679E-02 -1.179304E-04 -4.008683E-02 -1.751489E-04 -3.496459E-02 -1.796935E-04 -3.097461E-02 -1.095044E-04 -2.638565E-02 -8.181552E-05 -2.620917E-02 -8.987429E-05 -3.998881E-02 -1.948994E-04 -3.258728E-02 -1.341640E-04 -2.561706E-02 -9.239575E-05 -2.588589E-02 -8.721515E-05 -2.944746E-02 -1.052164E-04 -2.989662E-02 -1.085775E-04 -4.206933E-02 -1.998885E-04 -4.066845E-02 -1.897463E-04 -3.508215E-02 -1.528988E-04 -3.120069E-02 -1.132167E-04 -3.286119E-02 -1.352262E-04 -2.909519E-02 -9.371026E-05 -3.840859E-02 -1.674324E-04 -2.454802E-02 -8.382699E-05 -3.347874E-02 -1.411597E-04 -3.060526E-02 -1.367041E-04 -3.069666E-02 -1.180094E-04 -2.561383E-02 -8.330685E-05 -2.628522E-02 -7.556832E-05 -3.582384E-02 -1.465406E-04 -2.376316E-02 -6.457049E-05 -2.495648E-02 -7.422669E-05 -3.093179E-02 -1.305765E-04 -2.264932E-02 -6.586890E-05 -2.047598E-02 -6.261296E-05 -1.933007E-02 -4.833006E-05 -3.257759E-02 -1.237865E-04 -2.571050E-02 -9.464525E-05 -2.463103E-02 -7.258362E-05 -2.557654E-02 -9.353236E-05 -2.284662E-02 -6.268018E-05 -2.491527E-02 -7.859483E-05 -1.681318E-02 -3.501371E-05 -1.365219E-02 -2.989006E-05 -2.210617E-02 -7.141867E-05 -1.271132E-02 -2.094510E-05 -1.683888E-02 -3.625752E-05 -2.058113E-02 -5.450372E-05 -1.739717E-02 -3.555630E-05 -1.829530E-02 -4.644023E-05 -1.776594E-02 -4.124796E-05 -1.418883E-02 -2.672278E-05 -1.760442E-02 -4.591128E-05 -1.891750E-02 -4.822430E-05 -2.178972E-02 -6.432900E-05 -1.443029E-02 -3.016588E-05 -2.256303E-02 -6.869229E-05 -2.251806E-02 -6.650662E-05 -1.323995E-02 -2.512378E-05 -1.335985E-02 -2.654692E-05 -1.740401E-02 -4.340090E-05 -1.330095E-02 -2.489342E-05 -1.207888E-02 -2.391548E-05 -1.667832E-02 -4.429778E-05 -1.489741E-02 -3.841273E-05 -1.143220E-02 -2.495364E-05 -1.240317E-02 -2.477660E-05 -1.342275E-02 -2.581056E-05 -1.621941E-02 -4.158232E-05 -1.159374E-02 -2.088416E-05 -9.404397E-03 -1.695010E-05 -1.056534E-02 -1.863945E-05 -1.162004E-02 -2.136658E-05 -1.095144E-02 -1.546737E-05 -1.144118E-02 -2.034439E-05 -1.322456E-02 -2.558634E-05 -1.172292E-02 -1.883806E-05 -8.086459E-03 -8.879405E-06 -9.613483E-03 -1.997653E-05 -9.179038E-03 -1.284128E-05 -1.897153E-02 -6.588307E-05 -1.524499E-02 -3.816344E-05 -1.007550E-02 -2.293895E-05 -1.297928E-02 -3.448976E-05 -6.475985E-03 -7.421175E-06 -7.302236E-03 -9.360854E-06 -1.268448E-02 -2.201962E-05 -1.331579E-02 -2.325496E-05 -1.816213E-02 -4.264316E-05 -1.951988E-02 -5.119100E-05 -1.565522E-02 -3.615086E-05 -2.309450E-02 -9.333193E-05 -1.557690E-02 -3.930051E-05 -9.451777E-03 -1.526280E-05 -2.041329E-02 -5.032056E-05 -2.673356E-02 -9.468703E-05 -1.094269E-02 -1.894088E-05 -1.679176E-02 -3.840079E-05 -1.732446E-02 -4.238174E-05 -1.027564E-02 -2.013019E-05 -1.861457E-02 -4.141552E-05 -2.507166E-02 -6.889370E-05 -2.041729E-02 -4.876339E-05 -2.283941E-02 -6.377266E-05 -1.892643E-02 -4.163099E-05 -2.187765E-02 -5.763946E-05 -2.028538E-02 -6.131503E-05 -2.103645E-02 -5.318838E-05 -1.715798E-02 -3.499249E-05 -1.485800E-02 -3.358359E-05 -1.984948E-02 -5.445579E-05 -1.703301E-02 -4.679668E-05 -3.309820E-02 -1.234499E-04 -2.275776E-02 -6.157529E-05 -3.261448E-02 -1.319771E-04 -2.554946E-02 -8.196680E-05 -2.004888E-02 -4.990133E-05 -1.939965E-02 -6.076153E-05 -2.548646E-02 -8.064466E-05 -2.855104E-02 -1.012305E-04 -2.762007E-02 -1.037910E-04 -1.839340E-02 -4.279463E-05 -1.686751E-02 -4.608015E-05 -2.084644E-02 -5.002926E-05 -4.132950E-02 -1.846233E-04 -3.460120E-02 -1.298466E-04 -3.552467E-02 -1.570092E-04 -2.933106E-02 -9.609808E-05 -2.684190E-02 -7.922498E-05 -2.487139E-02 -6.891792E-05 -3.728495E-02 -1.689194E-04 -2.818457E-02 -8.676068E-05 -3.441368E-02 -1.333471E-04 -2.818973E-02 -1.038355E-04 -2.356477E-02 -6.812284E-05 -2.343339E-02 -6.179023E-05 -4.344270E-02 -2.389724E-04 -4.294905E-02 -2.093287E-04 -3.836620E-02 -1.778263E-04 -2.841149E-02 -8.871119E-05 -4.014563E-02 -1.768024E-04 -2.920772E-02 -1.000217E-04 -2.615172E-02 -8.720279E-05 -2.000501E-02 -4.816703E-05 -4.057421E-02 -1.875221E-04 -2.445887E-02 -8.924764E-05 -2.817821E-02 -8.605351E-05 -2.110986E-02 -5.069715E-05 -2.927821E-02 -9.308711E-05 -3.362175E-02 -1.332596E-04 -3.475808E-02 -1.323338E-04 -3.289085E-02 -1.244729E-04 -3.022584E-02 -1.318809E-04 -3.196364E-02 -1.297968E-04 -1.687072E-02 -3.179809E-05 -1.801683E-02 -4.078604E-05 -2.960756E-02 -1.160952E-04 -3.466058E-02 -1.382880E-04 -2.412524E-02 -9.376449E-05 -3.370586E-02 -1.749860E-04 -1.744924E-02 -4.569761E-05 -2.327075E-02 -7.176336E-05 -2.067060E-02 -5.038568E-05 -2.065122E-02 -5.674893E-05 -1.185396E-02 -1.904589E-05 -1.187338E-02 -1.832962E-05 -1.361451E-02 -2.819447E-05 -1.785195E-02 -4.401066E-05 -2.526233E-02 -8.640741E-05 -1.793604E-02 -5.730915E-05 -1.571041E-02 -3.175367E-05 -1.678219E-02 -3.936420E-05 -1.486918E-02 -3.526965E-05 -2.794130E-02 -1.195339E-04 -1.996768E-02 -7.226779E-05 -1.162384E-02 -2.197081E-05 -2.096325E-02 -5.793563E-05 -1.837867E-02 -4.515139E-05 -1.703731E-02 -3.926907E-05 -1.268651E-02 -2.343106E-05 -1.879725E-02 -4.716744E-05 -1.709910E-02 -3.710250E-05 -1.228622E-02 -3.339394E-05 -1.352711E-02 -2.975058E-05 -1.155424E-02 -1.880536E-05 -1.121092E-02 -2.205103E-05 -1.476077E-02 -3.330714E-05 -1.255099E-02 -2.385469E-05 -1.347481E-02 -2.408221E-05 -1.470344E-02 -2.583766E-05 -9.187814E-03 -1.701394E-05 -1.028524E-02 -2.190585E-05 -1.204921E-02 -2.386486E-05 -1.214004E-02 -1.925520E-05 -1.294814E-02 -2.325545E-05 -1.470310E-02 -3.633457E-05 -7.703457E-03 -8.319661E-06 -9.053019E-03 -1.860099E-05 -3.939164E-03 -3.269741E-06 -9.533908E-03 -1.325293E-05 -1.227483E-02 -2.491268E-05 -1.259791E-02 -2.146362E-05 -4.323047E-03 -3.283543E-06 -9.255709E-03 -2.197638E-05 -4.603184E-03 -3.514783E-06 -4.229364E-03 -6.002727E-06 -1.275699E-02 -2.227133E-05 -1.051975E-02 -1.875691E-05 -1.939046E-02 -4.923847E-05 -1.621043E-02 -4.902401E-05 -1.162276E-02 -2.501804E-05 -1.178308E-02 -2.464996E-05 -1.264103E-02 -2.350170E-05 -1.829675E-02 -4.158987E-05 -1.935990E-02 -4.658558E-05 -2.050484E-02 -5.542682E-05 -1.261518E-02 -2.496199E-05 -2.338316E-02 -6.665179E-05 -1.422276E-02 -2.677276E-05 -1.418978E-02 -3.508840E-05 -3.161101E-02 -1.103014E-04 -2.806809E-02 -9.416094E-05 -1.970337E-02 -5.207680E-05 -2.017517E-02 -5.029958E-05 -2.476977E-02 -9.671590E-05 -1.993423E-02 -5.639950E-05 -2.220619E-02 -5.949033E-05 -2.663071E-02 -8.742719E-05 -1.716007E-02 -3.560277E-05 -1.620846E-02 -3.298124E-05 -2.027814E-02 -5.137992E-05 -2.241055E-02 -6.475298E-05 -3.149111E-02 -1.240574E-04 -3.301990E-02 -1.297806E-04 -2.289529E-02 -7.022820E-05 -2.770187E-02 -1.305531E-04 -2.647167E-02 -8.125885E-05 -2.470047E-02 -6.618469E-05 -1.972532E-02 -5.720249E-05 -2.301743E-02 -6.802664E-05 -1.851738E-02 -4.051694E-05 -1.781820E-02 -3.908008E-05 -2.011234E-02 -4.945371E-05 -1.788427E-02 -4.535953E-05 -3.355984E-02 -1.399308E-04 -3.141513E-02 -1.324421E-04 -3.123214E-02 -1.131961E-04 -2.990237E-02 -1.043368E-04 -2.483001E-02 -7.814014E-05 -2.780841E-02 -9.315514E-05 -2.944866E-02 -1.125594E-04 -3.115948E-02 -1.382235E-04 -3.135984E-02 -1.125014E-04 -2.632324E-02 -9.453811E-05 -3.001476E-02 -1.041868E-04 -2.694256E-02 -8.321200E-05 -2.693560E-02 -7.578608E-05 -3.360780E-02 -1.359544E-04 -3.373802E-02 -1.372586E-04 -2.236018E-02 -6.411192E-05 -2.962695E-02 -1.020105E-04 -2.783038E-02 -9.884369E-05 -2.407145E-02 -7.259162E-05 -2.611296E-02 -9.023141E-05 -3.127878E-02 -1.135229E-04 -2.950226E-02 -9.691197E-05 -2.305590E-02 -6.460450E-05 -2.321268E-02 -7.274626E-05 -2.804961E-02 -9.491270E-05 -2.841803E-02 -1.054470E-04 -2.423205E-02 -7.810874E-05 -2.714164E-02 -9.975157E-05 -2.873229E-02 -1.122814E-04 -2.098758E-02 -5.056677E-05 -2.557067E-02 -8.748635E-05 -2.267297E-02 -8.906984E-05 -2.139317E-02 -5.463244E-05 -2.294894E-02 -7.412557E-05 -1.571457E-02 -3.620884E-05 -2.240494E-02 -5.721050E-05 -2.805329E-02 -9.134972E-05 -3.310961E-02 -1.309241E-04 -1.731055E-02 -3.757453E-05 -1.519094E-02 -3.101001E-05 -3.089642E-02 -1.273235E-04 -2.655794E-02 -1.020322E-04 -1.930391E-02 -4.470231E-05 -1.322122E-02 -2.280479E-05 -2.267352E-02 -6.781380E-05 -2.377301E-02 -7.062640E-05 -1.061766E-02 -1.383149E-05 -1.989374E-02 -6.361786E-05 -2.625067E-02 -9.026084E-05 -2.498518E-02 -8.804371E-05 -2.106620E-02 -5.099756E-05 -1.201370E-02 -2.098230E-05 -2.562363E-02 -8.111943E-05 -1.462361E-02 -2.865648E-05 -2.187381E-02 -5.860668E-05 -1.613482E-02 -4.384305E-05 -1.621606E-02 -3.449398E-05 -1.444365E-02 -3.579161E-05 -1.323646E-02 -2.542031E-05 -1.061139E-02 -1.881978E-05 -8.801940E-03 -1.018150E-05 -1.139983E-02 -2.019736E-05 -1.681598E-02 -3.690065E-05 -1.399493E-02 -3.175563E-05 -1.420691E-02 -2.466458E-05 -1.368415E-02 -2.617814E-05 -4.389391E-03 -3.790342E-06 -8.841774E-03 -1.306452E-05 -6.705949E-03 -6.428293E-06 -3.807333E-03 -3.521598E-06 -8.526487E-03 -1.179686E-05 -6.365036E-03 -6.849920E-06 -9.633887E-03 -1.541102E-05 -1.123781E-02 -1.889506E-05 -6.073970E-03 -7.042592E-06 -5.473005E-03 -4.622656E-06 -9.289202E-03 -1.795737E-05 -1.030725E-02 -2.040465E-05 -6.753476E-03 -7.775016E-06 -5.874996E-03 -7.699447E-06 -4.803223E-03 -5.048987E-06 -9.387232E-03 -2.256112E-05 -6.779777E-03 -7.696560E-06 -7.302784E-03 -1.204717E-05 -1.858153E-02 -4.240154E-05 -1.133429E-02 -1.757188E-05 -1.090884E-02 -1.956959E-05 -1.761310E-02 -4.472462E-05 -1.208597E-02 -2.241660E-05 -8.447260E-03 -1.837826E-05 -2.154735E-02 -7.183466E-05 -1.059584E-02 -1.725144E-05 -1.078223E-02 -1.741743E-05 -1.142825E-02 -1.725056E-05 -8.052096E-03 -1.288141E-05 -8.852506E-03 -1.479325E-05 -1.503791E-02 -2.827810E-05 -1.427595E-02 -2.627358E-05 -1.151486E-02 -1.821048E-05 -1.479919E-02 -3.026089E-05 -1.396424E-02 -2.976716E-05 -1.102878E-02 -1.569768E-05 -1.486600E-02 -4.640833E-05 -2.329305E-02 -6.388242E-05 -1.077778E-02 -2.630229E-05 -1.187595E-02 -2.158652E-05 -1.706939E-02 -3.589833E-05 -9.894219E-03 -1.748099E-05 -2.294330E-02 -6.429613E-05 -2.112393E-02 -5.525797E-05 -1.888943E-02 -4.229674E-05 -1.872573E-02 -5.200290E-05 -2.190997E-02 -6.830515E-05 -1.857860E-02 -5.271689E-05 -1.824118E-02 -4.252719E-05 -1.695109E-02 -4.377846E-05 -1.942043E-02 -4.638640E-05 -2.430706E-02 -8.617790E-05 -1.728181E-02 -4.311630E-05 -1.163790E-02 -2.136880E-05 -2.488767E-02 -7.230908E-05 -2.919997E-02 -9.955761E-05 -2.584993E-02 -1.031623E-04 -2.268255E-02 -6.949158E-05 -3.146416E-02 -1.268057E-04 -2.236165E-02 -6.966628E-05 -2.724737E-02 -9.874601E-05 -2.224496E-02 -7.784128E-05 -2.189895E-02 -6.090239E-05 -1.839473E-02 -4.209614E-05 -2.542360E-02 -8.396121E-05 -2.052856E-02 -4.913619E-05 -3.120344E-02 -1.291172E-04 -2.944557E-02 -1.038017E-04 -3.259220E-02 -1.571837E-04 -2.454004E-02 -8.331616E-05 -2.553435E-02 -9.440752E-05 -2.541943E-02 -9.586937E-05 -2.061350E-02 -7.364042E-05 -2.329153E-02 -9.064116E-05 -2.078416E-02 -4.749189E-05 -2.761182E-02 -8.657370E-05 -2.266317E-02 -6.326775E-05 -2.686321E-02 -1.043542E-04 -2.182754E-02 -7.805811E-05 -2.766205E-02 -9.723951E-05 -1.892390E-02 -5.005671E-05 -2.382207E-02 -6.769044E-05 -2.015930E-02 -6.032256E-05 -1.427037E-02 -3.798052E-05 -1.767507E-02 -6.512871E-05 -2.123882E-02 -4.907487E-05 -2.157816E-02 -6.678135E-05 -1.919870E-02 -5.942855E-05 -2.192776E-02 -5.912113E-05 -1.744859E-02 -5.000179E-05 -1.577374E-02 -3.368332E-05 -2.305821E-02 -6.854360E-05 -2.058939E-02 -5.959718E-05 -1.350163E-02 -3.072943E-05 -1.774684E-02 -4.504160E-05 -1.929554E-02 -5.149838E-05 -1.225057E-02 -1.846451E-05 -1.522995E-02 -3.345735E-05 -1.488842E-02 -2.657892E-05 -1.308637E-02 -2.575083E-05 -1.550443E-02 -4.365385E-05 -1.262294E-02 -2.496948E-05 -2.022153E-02 -5.150955E-05 -2.016439E-02 -5.276144E-05 -1.850133E-02 -4.648369E-05 -9.903588E-03 -1.610212E-05 -1.242472E-02 -2.311415E-05 -1.448322E-02 -3.103193E-05 -1.821292E-02 -6.275309E-05 -1.275608E-02 -5.475363E-05 -1.800193E-02 -4.234061E-05 -8.782455E-03 -1.649077E-05 -1.220656E-02 -2.499398E-05 -1.247528E-02 -3.099809E-05 -4.915298E-03 -5.476965E-06 -9.391788E-03 -1.606380E-05 -6.771266E-03 -8.450336E-06 -5.095855E-03 -3.842657E-06 -1.019612E-02 -1.603701E-05 -1.266368E-02 -2.593740E-05 -1.437121E-03 -9.237680E-07 -7.738730E-03 -1.337549E-05 -1.101810E-02 -1.737730E-05 -3.189798E-03 -4.831494E-06 -8.313307E-03 -1.236384E-05 -4.760766E-03 -2.835247E-06 -8.211101E-03 -1.004626E-05 -4.023937E-03 -3.045420E-06 -3.795398E-03 -3.753905E-06 -6.439348E-03 -6.445882E-06 -8.789930E-03 -9.641461E-06 -1.003210E-02 -1.871561E-05 -7.188383E-03 -7.745644E-06 -8.884373E-03 -1.210321E-05 -4.201731E-03 -3.267512E-06 -6.156152E-03 -6.439386E-06 -6.368503E-03 -6.063000E-06 -5.865149E-03 -6.343581E-06 -8.242843E-03 -1.255409E-05 -6.079907E-03 -8.904171E-06 -1.068165E-02 -1.977482E-05 -9.934550E-03 -1.529904E-05 -9.391801E-03 -1.672164E-05 -9.638027E-03 -1.793124E-05 -1.056323E-02 -2.728241E-05 -7.672750E-03 -1.245311E-05 -5.340667E-03 -9.209395E-06 -1.355760E-02 -6.094725E-05 -8.047003E-03 -9.586050E-06 -1.285221E-02 -3.064011E-05 -1.569140E-02 -3.403460E-05 -1.271345E-02 -2.195068E-05 -1.226525E-02 -2.591890E-05 -1.571067E-02 -3.670153E-05 -1.000122E-02 -2.251836E-05 -1.263608E-02 -2.857491E-05 -1.467989E-02 -3.065952E-05 -1.992801E-02 -5.197568E-05 -1.634631E-02 -3.854791E-05 -9.765387E-03 -1.929348E-05 -1.567478E-02 -4.572326E-05 -1.122681E-02 -1.875141E-05 -1.438219E-02 -2.962331E-05 -2.198487E-02 -5.569638E-05 -1.350017E-02 -2.505385E-05 -1.864402E-02 -5.207299E-05 -1.588104E-02 -4.725574E-05 -1.091009E-02 -1.886410E-05 -2.047245E-02 -6.638244E-05 -1.595713E-02 -4.444025E-05 -1.240157E-02 -1.827292E-05 -8.920440E-03 -1.437145E-05 -1.325339E-02 -2.805692E-05 -1.008187E-02 -1.747750E-05 -1.944508E-02 -6.365499E-05 -2.320316E-02 -7.205046E-05 -2.067013E-02 -4.788913E-05 -1.843860E-02 -4.912723E-05 -2.314076E-02 -7.987697E-05 -2.082200E-02 -6.799905E-05 -1.477196E-02 -2.747397E-05 -1.645001E-02 -3.474675E-05 -2.251395E-02 -7.952533E-05 -1.283424E-02 -2.565340E-05 -1.302741E-02 -2.183293E-05 -1.627063E-02 -3.188570E-05 -1.694690E-02 -4.854666E-05 -1.768424E-02 -4.519650E-05 -1.688309E-02 -3.658427E-05 -2.081183E-02 -4.936469E-05 -1.521899E-02 -3.630188E-05 -1.538105E-02 -4.012152E-05 -1.852161E-02 -4.542222E-05 -2.027891E-02 -7.078559E-05 -1.530632E-02 -4.004295E-05 -1.251099E-02 -2.014674E-05 -1.766586E-02 -3.643771E-05 -1.011259E-02 -1.798254E-05 -1.785577E-02 -4.209205E-05 -1.591733E-02 -2.948407E-05 -1.973149E-02 -5.858390E-05 -2.318672E-02 -6.821666E-05 -1.606927E-02 -3.208169E-05 -1.561903E-02 -3.274947E-05 -8.671178E-03 -1.320312E-05 -1.321121E-02 -2.770105E-05 -1.276830E-02 -2.392358E-05 -8.675945E-03 -1.600673E-05 -1.631955E-02 -3.628609E-05 -1.268176E-02 -2.698295E-05 -1.305170E-02 -3.392622E-05 -1.151833E-02 -2.146481E-05 -1.382454E-02 -2.543511E-05 -1.268190E-02 -2.770093E-05 -1.670138E-02 -4.515019E-05 -1.411501E-02 -2.397072E-05 -1.054121E-02 -1.734424E-05 -1.038572E-02 -1.525222E-05 -1.239423E-02 -1.885637E-05 -8.231991E-03 -1.095003E-05 -1.346736E-02 -2.994113E-05 -1.282791E-02 -2.684630E-05 -1.377004E-02 -3.238869E-05 -1.142596E-02 -1.735764E-05 -1.062508E-02 -1.743282E-05 -1.257942E-02 -2.057274E-05 -1.169000E-02 -2.474569E-05 -6.423798E-03 -8.173196E-06 -7.740555E-03 -1.569990E-05 -8.666292E-03 -1.364526E-05 -1.430519E-02 -3.144468E-05 -1.034424E-02 -1.702524E-05 -1.041966E-02 -1.828082E-05 -7.823260E-03 -1.110455E-05 -7.252199E-03 -9.925677E-06 -2.994718E-03 -1.593375E-06 -1.048984E-02 -2.573976E-05 -5.641360E-03 -5.936595E-06 -5.229774E-03 -7.041393E-06 -9.930813E-03 -1.689201E-05 -4.386542E-03 -4.754619E-06 -5.133633E-03 -4.043150E-06 -3.269722E-03 -1.970563E-06 -4.951504E-03 -6.193676E-06 -4.410157E-03 -4.926957E-06 -8.875217E-03 -1.522029E-05 -6.496616E-03 -8.828653E-06 -5.733530E-03 -7.478095E-06 -4.584225E-03 -3.801824E-06 -5.014833E-03 -4.595598E-06 -4.918988E-03 -9.258105E-06 -5.483056E-03 -9.195257E-06 -5.228430E-03 -7.940306E-06 -5.117645E-03 -7.631754E-06 -5.072391E-03 -5.531082E-06 -3.632197E-03 -2.983079E-06 -4.693965E-03 -5.099544E-06 -2.051996E-03 -1.135888E-06 -7.304764E-03 -1.039220E-05 -3.647755E-03 -4.449912E-06 -3.476959E-03 -2.187942E-06 -9.489533E-03 -2.316279E-05 -5.751162E-03 -8.659685E-06 -4.963073E-03 -5.706592E-06 -6.138111E-03 -1.068804E-05 -9.307217E-03 -1.519475E-05 -4.545925E-03 -6.535861E-06 -8.294344E-03 -1.556852E-05 -7.173393E-03 -9.233319E-06 -1.078215E-02 -1.572789E-05 -9.705333E-03 -3.544244E-05 -7.945812E-03 -1.276101E-05 -1.168294E-02 -2.467022E-05 -6.645644E-03 -7.587545E-06 -5.760001E-03 -9.365634E-06 -8.601051E-03 -1.363162E-05 -8.005982E-03 -1.328267E-05 -1.261419E-02 -3.207736E-05 -5.901262E-03 -6.935112E-06 -6.430185E-03 -9.087951E-06 -6.884844E-03 -8.313889E-06 -4.278770E-03 -3.441959E-06 -1.137804E-02 -2.133967E-05 -1.214381E-02 -2.232652E-05 -1.740437E-02 -3.543180E-05 -1.246386E-02 -2.766736E-05 -1.214083E-02 -1.935442E-05 -1.166031E-02 -2.273794E-05 -1.042912E-02 -2.534376E-05 -1.253440E-02 -2.906078E-05 -3.580466E-03 -2.034018E-06 -9.607729E-03 -1.395640E-05 -9.100903E-03 -1.455039E-05 -5.382398E-03 -1.056575E-05 -1.720209E-02 -4.611390E-05 -1.189486E-02 -2.081478E-05 -2.098921E-02 -5.268336E-05 -1.295792E-02 -2.491469E-05 -1.359035E-02 -2.476233E-05 -1.320672E-02 -2.504384E-05 -1.004322E-02 -1.517085E-05 -6.328234E-03 -7.222517E-06 -7.696931E-03 -8.736384E-06 -9.062335E-03 -1.635044E-05 -1.220397E-02 -2.109811E-05 -9.542900E-03 -1.414586E-05 -2.001020E-02 -5.728709E-05 -1.200225E-02 -1.611148E-05 -1.851644E-02 -5.098601E-05 -1.159430E-02 -2.048997E-05 -1.198809E-02 -2.688531E-05 -1.067777E-02 -1.707832E-05 -1.686877E-02 -4.601130E-05 -1.514223E-02 -3.020548E-05 -9.412452E-03 -1.296937E-05 -8.734687E-03 -1.791696E-05 -7.182753E-03 -7.961564E-06 -7.131070E-03 -8.835775E-06 -1.176780E-02 -2.003672E-05 -1.238591E-02 -1.851917E-05 -1.482210E-02 -4.681620E-05 -8.008500E-03 -8.162099E-06 -1.099128E-02 -1.643104E-05 -1.234719E-02 -2.252478E-05 -9.121398E-03 -1.338217E-05 -9.649799E-03 -1.957300E-05 -1.239326E-02 -2.066867E-05 -7.925470E-03 -9.921111E-06 -6.952410E-03 -1.209167E-05 -1.305189E-02 -2.993481E-05 -1.011683E-02 -1.814412E-05 -9.138673E-03 -1.288657E-05 -9.613647E-03 -1.454996E-05 -9.587432E-03 -1.425997E-05 -4.100970E-03 -3.581979E-06 -6.384398E-03 -9.449653E-06 -5.332770E-03 -4.810910E-06 -8.205597E-03 -1.367429E-05 -4.458035E-03 -3.530187E-06 -3.214674E-03 -1.992488E-06 -6.119990E-03 -6.950277E-06 -4.194752E-03 -3.822292E-06 -7.270772E-03 -8.358483E-06 -7.963665E-03 -1.211727E-05 -1.139690E-02 -2.688370E-05 -1.072253E-02 -1.923075E-05 -9.310029E-03 -2.222401E-05 -6.635931E-03 -6.447355E-06 -6.067077E-03 -9.323989E-06 -6.686810E-03 -6.491688E-06 -7.266522E-03 -7.228635E-06 -2.677445E-03 -2.282809E-06 -7.272519E-03 -9.053976E-06 -5.368115E-03 -6.336538E-06 -3.059467E-03 -2.284551E-06 -3.148000E-03 -2.437724E-06 -3.588594E-03 -3.284908E-06 -4.456313E-03 -7.520958E-06 -2.798347E-03 -2.236317E-06 -6.840217E-03 -9.048482E-06 -1.575769E-03 -9.897286E-07 -2.611268E-03 -1.755955E-06 -1.750700E-03 -1.182162E-06 -2.239940E-03 -2.450046E-06 -1.507196E-03 -1.074090E-06 -6.865521E-03 -7.835832E-06 -2.312288E-03 -2.250952E-06 -4.625802E-03 -5.487129E-06 -2.141186E-03 -9.777142E-07 -1.364855E-03 -9.688473E-07 -3.118005E-03 -3.532909E-06 -2.850409E-03 -1.719105E-06 -3.414722E-03 -2.946427E-06 -5.867545E-03 -6.300551E-06 -3.511602E-03 -3.730751E-06 -2.231751E-03 -2.052805E-06 -2.099977E-03 -1.555011E-06 -2.936833E-03 -2.400849E-06 -5.147373E-03 -6.410685E-06 -9.334636E-03 -1.426974E-05 -5.355177E-03 -5.994759E-06 -5.939796E-03 -1.063177E-05 -5.190027E-03 -5.190207E-06 -5.258137E-03 -4.118191E-06 -6.041649E-03 -6.155598E-06 -5.622082E-03 -4.644624E-06 -1.149290E-02 -2.616444E-05 -7.309708E-03 -8.042562E-06 -3.694461E-03 -3.564990E-06 -6.879292E-03 -1.011779E-05 -9.522458E-03 -1.559720E-05 -5.391999E-03 -4.832231E-06 -5.698037E-03 -5.073533E-06 -1.893957E-03 -1.407429E-06 -7.904603E-03 -1.129256E-05 -5.420913E-03 -6.627464E-06 -6.982381E-03 -6.809893E-06 -6.325870E-03 -7.532835E-06 -4.682244E-03 -3.460830E-06 -6.920599E-03 -8.574244E-06 -3.733359E-03 -3.700527E-06 -4.030359E-03 -3.986131E-06 -5.047907E-03 -4.426148E-06 -9.528005E-03 -1.550618E-05 -7.877900E-03 -1.006685E-05 -9.780723E-03 -1.657015E-05 -4.812077E-03 -4.098229E-06 -7.016687E-03 -7.149177E-06 -4.037284E-03 -3.400182E-06 -3.277155E-03 -2.337977E-06 -6.137543E-03 -6.092367E-06 -6.278125E-03 -9.707219E-06 -2.576720E-03 -3.914988E-06 -4.835272E-03 -7.752895E-06 -6.736014E-03 -7.302508E-06 -6.970854E-03 -6.682760E-06 -6.313642E-03 -5.551521E-06 -7.635449E-03 -8.984939E-06 -8.683849E-03 -1.560378E-05 -7.530787E-03 -9.173765E-06 -1.569516E-02 -3.949851E-05 -1.097068E-02 -2.119987E-05 -7.309184E-03 -7.015811E-06 -8.665715E-03 -1.546974E-05 -7.723895E-03 -1.518562E-05 -4.905466E-03 -4.093288E-06 -1.077564E-02 -2.805109E-05 -8.569399E-03 -1.273736E-05 -1.038612E-02 -1.719585E-05 -7.354212E-03 -8.198097E-06 -9.350739E-03 -1.720908E-05 -4.787259E-03 -6.741535E-06 -7.220875E-03 -8.792305E-06 -5.379919E-03 -5.042148E-06 -8.788109E-03 -1.266781E-05 -7.402327E-03 -7.894813E-06 -4.207623E-03 -3.460121E-06 -7.902663E-03 -9.560483E-06 -5.174573E-03 -4.082169E-06 -1.104658E-02 -2.127916E-05 -5.782523E-03 -5.112492E-06 -3.632634E-03 -2.502751E-06 -5.337278E-03 -4.486802E-06 -4.249421E-03 -4.213447E-06 -7.491058E-03 -9.439118E-06 -5.243136E-03 -5.575342E-06 -1.237618E-02 -2.148757E-05 -8.041605E-03 -1.026055E-05 -6.349704E-03 -1.417430E-05 -6.087425E-03 -8.075635E-06 -4.602367E-03 -3.651645E-06 -4.154919E-03 -5.935728E-06 -1.040123E-02 -1.813267E-05 -8.425233E-03 -1.322959E-05 -5.094732E-03 -6.066657E-06 -3.282128E-03 -2.438795E-06 -4.478721E-03 -5.352957E-06 -4.621930E-03 -3.979448E-06 -3.591134E-03 -3.542812E-06 -3.931582E-03 -3.195193E-06 -7.517289E-03 -1.202563E-05 -4.445629E-03 -3.532948E-06 -5.122199E-03 -4.733178E-06 -6.079088E-03 -5.645343E-06 -5.005001E-03 -5.722868E-06 -4.017636E-03 -3.624033E-06 -3.326000E-03 -2.420695E-06 -3.011641E-03 -3.505638E-06 -2.136977E-03 -8.951049E-07 -1.175447E-03 -4.124064E-07 -7.823514E-03 -1.228293E-05 -4.920698E-03 -4.693144E-06 -3.285795E-03 -2.440402E-06 -4.028141E-03 -3.884837E-06 -2.781317E-03 -1.300197E-06 -3.926044E-03 -3.109193E-06 -4.628411E-03 -5.325271E-06 -4.051196E-03 -3.567334E-06 -3.272251E-03 -4.622968E-06 -3.143217E-03 -2.173404E-06 -2.374311E-03 -1.308003E-06 -1.326934E-03 -9.031223E-07 -3.522915E-03 -4.391282E-06 -5.770000E-04 -1.329958E-07 -2.830130E-03 -3.011060E-06 -2.210339E-03 -1.635883E-06 -3.721215E-03 -3.080210E-06 -6.120484E-03 -5.355595E-06 -3.678377E-03 -3.709180E-06 -2.413835E-03 -1.404139E-06 -5.860060E-03 -6.753555E-06 -6.142222E-03 -6.895111E-06 -4.689827E-03 -4.987858E-06 -3.810291E-03 -3.578451E-06 -4.720787E-03 -7.371870E-06 -1.759885E-03 -1.135197E-06 -4.523542E-03 -5.744713E-06 -4.512130E-03 -5.150402E-06 -8.505535E-03 -9.989819E-06 -8.615921E-03 -1.014660E-05 -6.886961E-03 -6.750505E-06 -6.626919E-03 -8.244527E-06 -9.376957E-03 -1.235456E-05 -9.638288E-03 -1.489772E-05 -1.001130E-02 -1.552242E-05 -1.028076E-02 -1.757757E-05 -3.716261E-03 -3.414503E-06 -1.351126E-02 -2.981345E-05 -7.730660E-03 -1.296080E-05 -8.324008E-03 -1.413367E-05 -9.824794E-03 -1.737391E-05 -8.406562E-03 -1.011462E-05 -6.244264E-03 -9.615840E-06 -5.753008E-03 -5.938129E-06 -1.161932E-02 -1.759635E-05 -7.019897E-03 -6.911798E-06 -1.124973E-02 -2.227076E-05 -9.974498E-03 -1.531239E-05 -1.750036E-02 -3.960636E-05 -1.123801E-02 -2.603078E-05 -6.620195E-03 -8.846067E-06 -8.621539E-03 -1.476285E-05 -1.144148E-02 -2.816625E-05 -9.236578E-03 -2.087006E-05 -1.022756E-02 -2.015506E-05 -8.313712E-03 -1.245193E-05 -8.472316E-03 -1.040768E-05 -1.100682E-02 -1.897584E-05 -7.072576E-03 -7.806879E-06 -8.257296E-03 -1.365708E-05 -8.677246E-03 -1.251818E-05 -1.847630E-03 -1.221029E-06 -3.514354E-03 -2.801550E-06 -4.635307E-03 -4.312440E-06 -1.719934E-02 -3.993958E-05 -1.168750E-02 -1.940685E-05 -1.392387E-02 -2.505551E-05 -9.162097E-03 -2.003276E-05 -1.068024E-02 -1.620043E-05 -6.143827E-03 -6.330015E-06 -9.757303E-03 -1.665448E-05 -1.205259E-02 -2.076304E-05 -1.099561E-02 -1.990285E-05 -8.729352E-03 -1.425139E-05 -5.036499E-03 -3.597216E-06 -4.573901E-03 -4.390016E-06 -1.098170E-02 -1.803805E-05 -1.450456E-02 -2.780429E-05 -6.373863E-03 -6.571288E-06 -9.888037E-03 -1.449978E-05 -1.253128E-02 -2.292463E-05 -1.075201E-02 -1.610392E-05 -8.884084E-03 -1.322461E-05 -5.357264E-03 -5.936993E-06 -1.493177E-02 -2.673706E-05 -5.699430E-03 -5.340117E-06 -8.188668E-03 -1.253943E-05 -4.838650E-03 -3.385865E-06 -1.000094E-02 -1.476818E-05 -1.063068E-02 -1.693667E-05 -9.830500E-03 -1.503630E-05 -1.025245E-02 -1.763545E-05 -1.028864E-02 -1.849793E-05 -5.900779E-03 -6.170864E-06 -1.177015E-02 -2.226737E-05 -7.509689E-03 -8.719533E-06 -1.206431E-02 -2.678780E-05 -9.200857E-03 -1.643527E-05 -5.468133E-03 -4.453812E-06 -7.516784E-03 -9.212924E-06 -1.111732E-02 -1.394083E-05 -1.179677E-02 -1.966452E-05 -4.112066E-03 -2.360474E-06 -4.867401E-03 -6.026552E-06 -8.104035E-03 -1.092048E-05 -1.016367E-02 -1.245298E-05 -8.572029E-03 -1.314727E-05 -5.230427E-03 -4.291571E-06 -1.462827E-02 -3.660743E-05 -1.133693E-02 -1.987800E-05 -8.632273E-03 -1.741700E-05 -9.505339E-03 -1.209742E-05 -3.350003E-03 -1.830051E-06 -1.189483E-02 -1.823139E-05 -6.269531E-03 -9.062971E-06 -5.745106E-03 -7.814173E-06 -5.494288E-03 -5.220575E-06 -8.224322E-03 -1.417410E-05 -7.485116E-03 -7.578271E-06 -4.217646E-03 -3.209044E-06 -9.597899E-03 -1.579356E-05 -9.222350E-03 -1.143785E-05 -5.917673E-03 -5.975846E-06 -4.191188E-03 -2.824383E-06 -5.746277E-03 -5.928494E-06 -5.146451E-03 -4.826427E-06 -3.536845E-03 -2.903999E-06 -2.348669E-03 -2.151234E-06 -7.673915E-03 -1.147821E-05 -4.006830E-03 -3.592361E-06 -4.896990E-03 -5.179793E-06 -5.024089E-03 -5.234216E-06 -6.039638E-03 -6.322254E-06 -8.201689E-03 -1.116771E-05 -6.614252E-03 -1.021009E-05 -4.191696E-03 -4.388316E-06 -1.128526E-02 -1.976083E-05 -1.067513E-02 -1.823942E-05 -3.764982E-03 -3.222515E-06 -3.948813E-03 -4.451513E-06 -1.000152E-02 -2.107330E-05 -6.164282E-03 -1.724834E-05 -1.006014E-02 -2.134032E-05 -1.286695E-02 -3.067989E-05 -8.978723E-03 -1.251581E-05 -5.346415E-03 -5.350269E-06 -3.635013E-03 -4.204044E-06 -6.583641E-03 -8.886395E-06 -6.112499E-03 -7.100313E-06 -9.075416E-03 -1.361298E-05 -9.360748E-03 -1.479673E-05 -1.287873E-02 -2.436676E-05 -1.196275E-02 -1.944035E-05 -9.130004E-03 -1.555860E-05 -9.992520E-03 -1.245497E-05 -1.115802E-02 -1.670908E-05 -1.081540E-02 -1.882462E-05 -1.372827E-02 -2.757409E-05 -8.020036E-03 -1.222038E-05 -6.290610E-03 -4.837074E-06 -1.576319E-02 -3.661568E-05 -1.430139E-02 -3.954353E-05 -1.550808E-02 -5.413485E-05 -9.529567E-03 -2.562847E-05 -1.252063E-02 -2.284038E-05 -8.998915E-03 -1.107600E-05 -1.128710E-02 -3.131513E-05 -8.894334E-03 -1.612799E-05 -9.936476E-03 -1.499512E-05 -1.085220E-02 -1.879083E-05 -7.842398E-03 -1.147755E-05 -9.478975E-03 -1.366773E-05 -8.870185E-03 -1.264668E-05 -1.265677E-02 -3.003173E-05 -7.082798E-03 -9.455651E-06 -6.207587E-03 -1.035866E-05 -9.389246E-03 -1.904336E-05 -6.809780E-03 -1.110927E-05 -1.415613E-02 -3.324858E-05 -1.411282E-02 -2.597041E-05 -1.427512E-02 -3.295595E-05 -1.943942E-02 -5.877560E-05 -8.220965E-03 -9.356934E-06 -9.250583E-03 -1.365956E-05 -1.656914E-02 -3.475091E-05 -1.843152E-02 -4.655130E-05 -1.153837E-02 -1.618003E-05 -1.196430E-02 -2.260049E-05 -1.575201E-02 -2.932265E-05 -1.575583E-02 -3.216253E-05 -1.342670E-02 -3.092689E-05 -1.018784E-02 -1.786160E-05 -1.303515E-02 -2.169915E-05 -1.219880E-02 -3.353411E-05 -7.032946E-03 -7.709601E-06 -1.229650E-02 -2.705058E-05 -1.615409E-02 -3.472477E-05 -1.821028E-02 -3.933712E-05 -1.470364E-02 -2.795706E-05 -1.050280E-02 -2.133231E-05 -1.154231E-02 -1.968046E-05 -7.645500E-03 -1.039514E-05 -1.741509E-02 -3.584004E-05 -8.821919E-03 -1.428153E-05 -1.857457E-02 -4.195598E-05 -1.552507E-02 -2.892265E-05 -7.183282E-03 -9.228195E-06 -1.217604E-02 -1.939061E-05 -1.541421E-02 -3.334972E-05 -2.052820E-02 -5.660936E-05 -9.353019E-03 -1.426621E-05 -1.251082E-02 -2.228447E-05 -1.368721E-02 -2.531714E-05 -1.226667E-02 -2.368414E-05 -1.371101E-02 -2.448795E-05 -1.201033E-02 -2.393841E-05 -1.280636E-02 -2.115640E-05 -1.264839E-02 -2.387771E-05 -9.055229E-03 -1.568024E-05 -9.856570E-03 -1.373965E-05 -1.373503E-02 -2.764304E-05 -1.700784E-02 -3.483410E-05 -1.212809E-02 -2.883883E-05 -1.598449E-02 -4.084533E-05 -1.457711E-02 -2.808561E-05 -1.586485E-02 -3.242222E-05 -1.605131E-02 -4.105521E-05 -1.119495E-02 -1.615746E-05 -1.324399E-02 -2.727755E-05 -9.867968E-03 -1.269902E-05 -1.261254E-02 -2.302293E-05 -1.153152E-02 -1.778319E-05 -9.627863E-03 -1.562429E-05 -9.050432E-03 -2.011089E-05 -1.012233E-02 -1.405672E-05 -8.911922E-03 -1.231699E-05 -1.264744E-02 -3.182267E-05 -1.122935E-02 -1.396398E-05 -1.004271E-02 -2.482202E-05 -7.894125E-03 -1.026568E-05 -8.738637E-03 -1.294773E-05 -1.219349E-02 -2.177467E-05 -9.967898E-03 -1.619041E-05 -7.763622E-03 -1.314523E-05 -7.889504E-03 -1.517342E-05 -7.877888E-03 -9.676691E-06 -7.292674E-03 -8.328724E-06 -9.035083E-03 -1.302638E-05 -9.363679E-03 -1.575034E-05 -9.640810E-03 -1.648917E-05 -6.094059E-03 -5.041308E-06 -4.386721E-03 -4.583987E-06 -8.186442E-03 -1.162059E-05 -6.547204E-03 -5.040030E-06 -4.382851E-03 -3.779716E-06 -4.722787E-03 -2.981327E-06 -1.235870E-02 -2.314605E-05 -1.222127E-02 -2.292500E-05 -7.743975E-03 -1.242313E-05 -5.687154E-03 -5.021930E-06 -7.628599E-03 -1.334325E-05 -8.144837E-03 -9.544871E-06 -8.964376E-03 -1.242765E-05 -9.619105E-03 -1.533853E-05 -1.084215E-02 -2.414197E-05 -6.098310E-03 -6.403053E-06 -3.971375E-03 -2.559046E-06 -4.956486E-03 -4.314077E-06 -1.650323E-02 -3.308582E-05 -1.785233E-02 -4.022948E-05 -1.226233E-02 -2.222264E-05 -1.324548E-02 -2.290739E-05 -1.170726E-02 -2.043035E-05 -1.128481E-02 -1.783746E-05 -1.446854E-02 -2.465804E-05 -1.308709E-02 -2.086517E-05 -1.532165E-02 -3.175587E-05 -1.176741E-02 -2.528693E-05 -6.104662E-03 -5.418027E-06 -5.028482E-03 -7.038340E-06 -1.452720E-02 -2.907362E-05 -2.155983E-02 -5.793543E-05 -8.953378E-03 -1.144318E-05 -1.193284E-02 -1.941045E-05 -1.898089E-02 -4.676936E-05 -8.078140E-03 -1.008669E-05 -1.345743E-02 -3.010294E-05 -1.166065E-02 -2.971259E-05 -2.140319E-02 -6.942386E-05 -1.156518E-02 -2.123401E-05 -1.063148E-02 -1.679318E-05 -1.035058E-02 -1.786819E-05 -1.141576E-02 -1.488341E-05 -2.132304E-02 -6.407400E-05 -1.417013E-02 -2.428688E-05 -1.578758E-02 -4.383560E-05 -1.510669E-02 -4.330783E-05 -1.061421E-02 -2.120867E-05 -9.836246E-03 -1.836620E-05 -1.170301E-02 -2.304010E-05 -2.297562E-02 -7.378766E-05 -2.077496E-02 -6.096800E-05 -8.479570E-03 -1.315595E-05 -1.334700E-02 -2.778150E-05 -1.518804E-02 -2.768676E-05 -1.665283E-02 -3.264844E-05 -1.337650E-02 -2.908404E-05 -1.642169E-02 -3.787016E-05 -1.532468E-02 -3.092775E-05 -1.264533E-02 -1.889367E-05 -1.570062E-02 -2.982615E-05 -1.201853E-02 -1.991814E-05 -1.956945E-02 -4.268136E-05 -1.749406E-02 -3.890385E-05 -9.761579E-03 -1.266596E-05 -1.131974E-02 -1.669105E-05 -1.583139E-02 -3.408051E-05 -1.813736E-02 -4.024179E-05 -1.749162E-02 -4.075339E-05 -1.806084E-02 -4.998400E-05 -1.798603E-02 -3.527089E-05 -1.363365E-02 -2.545698E-05 -1.735765E-02 -3.680633E-05 -1.313196E-02 -2.758452E-05 -1.257866E-02 -2.792705E-05 -1.371026E-02 -2.875442E-05 -1.449637E-02 -2.956474E-05 -1.184945E-02 -2.021992E-05 -1.160263E-02 -1.677863E-05 -1.486874E-02 -2.727812E-05 -1.334215E-02 -2.696922E-05 -8.375076E-03 -1.127780E-05 -1.398722E-02 -2.987500E-05 -1.431399E-02 -2.337988E-05 -1.685216E-02 -4.010946E-05 -1.220900E-02 -2.279807E-05 -1.359371E-02 -3.406479E-05 -1.497337E-02 -3.514338E-05 -1.077240E-02 -1.570437E-05 -1.286688E-02 -2.067034E-05 -1.804016E-02 -3.897670E-05 -1.720304E-02 -3.923736E-05 -1.248667E-02 -2.229239E-05 -9.872479E-03 -1.547272E-05 -1.404898E-02 -3.940008E-05 -1.102828E-02 -2.118933E-05 -9.527731E-03 -1.232685E-05 -1.183452E-02 -2.230399E-05 -1.235818E-02 -2.095622E-05 -9.045793E-03 -1.310065E-05 -7.573693E-03 -7.912407E-06 -7.098140E-03 -1.002223E-05 -1.087704E-02 -1.644644E-05 -1.403508E-02 -2.293868E-05 -1.102953E-02 -2.108622E-05 -1.278029E-02 -2.765609E-05 -1.000153E-02 -1.489998E-05 -1.023204E-02 -1.425642E-05 -1.077781E-02 -1.616312E-05 -1.504135E-02 -3.226364E-05 -8.290904E-03 -1.302393E-05 -1.081631E-02 -1.596914E-05 -1.061779E-02 -1.936956E-05 -9.609920E-03 -1.233187E-05 -7.536017E-03 -8.104937E-06 -1.064514E-02 -1.960743E-05 -4.303700E-03 -3.157059E-06 -4.544730E-03 -3.063284E-06 -9.403522E-03 -1.530342E-05 -6.146303E-03 -5.481247E-06 -5.504300E-03 -4.029062E-06 -2.514628E-03 -2.046696E-06 -1.150234E-02 -3.434888E-05 -6.476274E-03 -8.282595E-06 -5.180114E-03 -8.533421E-06 -6.593161E-03 -7.470575E-06 -1.087271E-02 -2.875725E-05 -1.114108E-02 -1.774790E-05 -9.707234E-03 -2.320447E-05 -7.474544E-03 -7.620487E-06 -1.189904E-02 -1.770896E-05 -8.306981E-03 -1.023805E-05 -1.044243E-02 -2.358835E-05 -7.956950E-03 -1.442236E-05 -6.383279E-03 -9.306381E-06 -6.540012E-03 -7.870617E-06 -7.547221E-03 -8.818582E-06 -8.118902E-03 -1.018402E-05 -1.219458E-02 -2.121863E-05 -9.183066E-03 -1.021558E-05 -8.537042E-03 -2.163043E-05 -9.801780E-03 -1.896248E-05 -7.436543E-03 -6.348631E-06 -8.783038E-03 -1.450508E-05 -1.198218E-02 -2.299991E-05 -1.176673E-02 -1.772108E-05 -7.610905E-03 -1.295193E-05 -1.236441E-02 -2.279242E-05 -1.374811E-02 -2.984764E-05 -8.276450E-03 -9.063020E-06 -2.838721E-02 -8.556398E-05 -1.876318E-02 -4.502643E-05 -1.545136E-02 -3.024495E-05 -1.307062E-02 -3.391324E-05 -1.321284E-02 -2.975134E-05 -1.195812E-02 -2.014099E-05 -2.398471E-02 -7.682355E-05 -1.699635E-02 -4.513757E-05 -1.109010E-02 -1.505508E-05 -1.463044E-02 -3.130849E-05 -1.445299E-02 -3.424691E-05 -1.847738E-02 -4.339745E-05 -2.269521E-02 -6.754400E-05 -1.622681E-02 -3.412820E-05 -1.867140E-02 -4.737811E-05 -1.704633E-02 -5.070683E-05 -2.137995E-02 -5.989756E-05 -1.262222E-02 -2.579396E-05 -1.649755E-02 -3.278397E-05 -1.021540E-02 -1.333464E-05 -1.399361E-02 -4.091195E-05 -1.481283E-02 -2.778259E-05 -1.110529E-02 -1.543650E-05 -1.370454E-02 -2.585161E-05 -2.187939E-02 -5.698664E-05 -2.156023E-02 -5.655243E-05 -1.819754E-02 -4.650955E-05 -1.667214E-02 -4.523740E-05 -1.212974E-02 -1.755527E-05 -1.664077E-02 -4.676917E-05 -1.598420E-02 -3.367421E-05 -2.197091E-02 -6.311844E-05 -1.554809E-02 -4.350026E-05 -1.662573E-02 -3.639737E-05 -1.377054E-02 -2.979629E-05 -1.718171E-02 -6.738915E-05 -2.224715E-02 -5.208199E-05 -2.028701E-02 -5.025768E-05 -2.346558E-02 -7.283542E-05 -2.047816E-02 -5.352208E-05 -2.103499E-02 -5.936660E-05 -1.795967E-02 -4.651152E-05 -2.451667E-02 -7.714718E-05 -2.018245E-02 -4.706972E-05 -1.870240E-02 -5.089247E-05 -1.414303E-02 -2.510243E-05 -1.249731E-02 -1.910688E-05 -1.461191E-02 -2.931018E-05 -1.772779E-02 -3.502831E-05 -2.405954E-02 -7.243269E-05 -1.698120E-02 -5.235943E-05 -1.363172E-02 -2.557442E-05 -2.085610E-02 -5.559729E-05 -1.434576E-02 -2.498955E-05 -2.151921E-02 -5.863979E-05 -1.804978E-02 -3.738678E-05 -1.626456E-02 -3.204521E-05 -1.416110E-02 -2.454304E-05 -1.349966E-02 -2.225683E-05 -1.376360E-02 -2.288533E-05 -1.304562E-02 -2.360964E-05 -1.204823E-02 -2.235548E-05 -1.581808E-02 -3.833344E-05 -1.458683E-02 -2.424983E-05 -1.532417E-02 -3.313140E-05 -1.674514E-02 -3.698941E-05 -8.820684E-03 -1.237269E-05 -1.325954E-02 -2.839297E-05 -1.346247E-02 -2.329594E-05 -1.218804E-02 -2.010088E-05 -7.816904E-03 -8.061895E-06 -1.115974E-02 -1.481199E-05 -1.126424E-02 -1.437812E-05 -1.155465E-02 -2.043504E-05 -1.330918E-02 -2.482809E-05 -1.359646E-02 -2.349457E-05 -6.879034E-03 -6.482253E-06 -1.025078E-02 -1.436298E-05 -1.124296E-02 -1.766927E-05 -9.157794E-03 -1.732026E-05 -1.080917E-02 -1.759748E-05 -1.224046E-02 -1.895136E-05 -1.132499E-02 -1.940702E-05 -1.055316E-02 -1.421109E-05 -6.950077E-03 -8.886009E-06 -1.146153E-02 -2.328053E-05 -6.534133E-03 -9.046637E-06 -5.113551E-03 -7.352574E-06 -1.096783E-02 -1.762871E-05 -8.670928E-03 -1.642712E-05 -6.666016E-03 -7.936419E-06 -4.024813E-03 -3.317441E-06 -6.604655E-03 -6.471414E-06 -7.218922E-03 -7.914816E-06 -7.543650E-03 -1.006296E-05 -8.390292E-03 -1.280688E-05 -6.833212E-03 -9.885211E-06 -8.859184E-03 -1.491876E-05 -4.271802E-03 -4.619779E-06 -8.415017E-03 -1.758541E-05 -7.880304E-03 -1.207340E-05 -6.190265E-03 -5.244062E-06 -1.255358E-02 -3.409848E-05 -4.588111E-03 -6.615112E-06 -7.290138E-03 -8.053715E-06 -2.708550E-03 -1.222054E-06 -7.971324E-03 -1.019545E-05 -2.186309E-03 -3.012755E-06 -1.730168E-02 -4.007549E-05 -9.437870E-03 -1.374155E-05 -8.710815E-03 -1.058748E-05 -6.876864E-03 -1.161077E-05 -1.183718E-02 -2.088043E-05 -1.317392E-02 -2.144719E-05 -1.202134E-02 -2.244800E-05 -1.219063E-02 -1.871706E-05 -9.457262E-03 -1.576600E-05 -8.456836E-03 -1.009365E-05 -6.722846E-03 -7.231603E-06 -9.056257E-03 -1.228372E-05 -1.680554E-02 -5.472386E-05 -1.583876E-02 -4.084512E-05 -1.451889E-02 -2.656784E-05 -1.154750E-02 -2.200804E-05 -8.960773E-03 -1.608168E-05 -1.021117E-02 -2.175200E-05 -1.537603E-02 -3.295291E-05 -1.346321E-02 -3.199823E-05 -1.020297E-02 -2.083570E-05 -1.574785E-02 -3.797866E-05 -1.224712E-02 -2.543224E-05 -1.213857E-02 -2.596422E-05 -1.978514E-02 -5.572712E-05 -1.721724E-02 -3.343383E-05 -1.917708E-02 -6.017423E-05 -1.746870E-02 -4.670195E-05 -1.601664E-02 -3.757776E-05 -1.391434E-02 -2.787908E-05 -2.112923E-02 -6.179734E-05 -1.494974E-02 -3.147270E-05 -2.027112E-02 -5.409774E-05 -1.762825E-02 -3.716705E-05 -1.490183E-02 -2.636325E-05 -1.144233E-02 -1.895260E-05 -2.252480E-02 -6.008716E-05 -2.061068E-02 -4.967689E-05 -1.978565E-02 -5.823807E-05 -1.627207E-02 -3.508510E-05 -2.308648E-02 -7.339685E-05 -9.920567E-03 -1.588060E-05 -1.582116E-02 -3.710173E-05 -1.359849E-02 -3.693990E-05 -2.449553E-02 -7.939873E-05 -1.712995E-02 -3.401990E-05 -1.578519E-02 -2.835653E-05 -1.996773E-02 -5.153308E-05 -1.784633E-02 -3.372557E-05 -2.328886E-02 -7.016669E-05 -1.908795E-02 -5.601183E-05 -2.149293E-02 -6.345938E-05 -2.432779E-02 -7.634443E-05 -2.394049E-02 -6.577991E-05 -1.506740E-02 -3.094281E-05 -1.388336E-02 -2.886613E-05 -1.614618E-02 -3.561899E-05 -1.595134E-02 -4.065708E-05 -1.340027E-02 -2.204671E-05 -1.472267E-02 -2.861240E-05 -1.790210E-02 -5.856300E-05 -2.646480E-02 -1.056654E-04 -1.880864E-02 -4.142515E-05 -1.426154E-02 -2.963840E-05 -1.165132E-02 -2.176252E-05 -1.428324E-02 -2.725319E-05 -1.588976E-02 -3.970327E-05 -1.833160E-02 -4.559784E-05 -1.772585E-02 -4.748240E-05 -1.848953E-02 -5.090661E-05 -1.272374E-02 -2.030829E-05 -1.412613E-02 -3.146328E-05 -1.649479E-02 -4.133012E-05 -1.209661E-02 -4.450673E-05 -1.369084E-02 -2.392580E-05 -1.531641E-02 -3.089017E-05 -1.580566E-02 -3.194323E-05 -1.132108E-02 -1.399526E-05 -8.190342E-03 -9.145143E-06 -7.902353E-03 -1.504796E-05 -1.258132E-02 -2.292738E-05 -6.958024E-03 -9.709387E-06 -1.037667E-02 -1.407859E-05 -1.201319E-02 -2.053522E-05 -9.379406E-03 -1.510952E-05 -1.279685E-02 -2.736611E-05 -1.191802E-02 -2.186093E-05 -6.155316E-03 -6.209415E-06 -8.817944E-03 -1.322568E-05 -7.497837E-03 -1.365620E-05 -9.976490E-03 -1.734874E-05 -7.558291E-03 -1.424385E-05 -8.801002E-03 -1.425950E-05 -9.075301E-03 -1.401503E-05 -5.681746E-03 -5.798447E-06 -4.827386E-03 -3.466370E-06 -5.884691E-03 -5.754861E-06 -1.211858E-02 -2.621006E-05 -5.629512E-03 -6.112612E-06 -5.768978E-03 -5.711093E-06 -1.075576E-02 -1.954724E-05 -5.977668E-03 -7.957209E-06 -6.775985E-03 -8.582096E-06 -3.503043E-03 -2.684132E-06 -8.113430E-03 -1.099167E-05 -8.263729E-03 -1.412028E-05 -3.781179E-03 -3.287824E-06 -8.368219E-03 -9.803361E-06 -1.068347E-02 -1.390398E-05 -1.118234E-02 -1.591023E-05 -1.016006E-02 -2.761365E-05 -6.634695E-03 -7.415821E-06 -1.042368E-02 -1.700083E-05 -1.024339E-02 -1.630692E-05 -5.465831E-03 -6.271754E-06 -1.117655E-02 -1.998616E-05 -8.708982E-03 -1.145629E-05 -3.321055E-03 -3.386533E-06 -8.951176E-03 -1.175568E-05 -7.413974E-03 -1.358203E-05 -1.289235E-02 -2.359140E-05 -9.817553E-03 -1.518261E-05 -9.879433E-03 -1.602972E-05 -1.177378E-02 -2.259438E-05 -5.796294E-03 -6.245744E-06 -1.138092E-02 -2.136416E-05 -8.927027E-03 -9.348267E-06 -9.673957E-03 -1.246216E-05 -1.280715E-02 -4.429778E-05 -8.808327E-03 -1.178528E-05 -7.125501E-03 -7.483806E-06 -4.620428E-03 -9.310180E-06 -1.680437E-02 -3.451199E-05 -2.026938E-02 -4.346902E-05 -1.635252E-02 -5.026111E-05 -1.278583E-02 -2.192134E-05 -1.301566E-02 -2.384432E-05 -9.286694E-03 -1.400657E-05 -1.107901E-02 -1.953576E-05 -1.150656E-02 -2.102378E-05 -1.772830E-02 -3.480088E-05 -1.063150E-02 -1.401509E-05 -1.374475E-02 -2.299888E-05 -6.867995E-03 -1.027748E-05 -1.580376E-02 -3.847030E-05 -1.668637E-02 -3.953893E-05 -1.442844E-02 -3.008408E-05 -1.827058E-02 -4.753438E-05 -1.440759E-02 -3.206648E-05 -1.592968E-02 -4.677348E-05 -1.718273E-02 -3.488836E-05 -1.688712E-02 -4.196255E-05 -2.047044E-02 -4.959256E-05 -1.306218E-02 -3.057713E-05 -8.848692E-03 -1.833823E-05 -1.117548E-02 -2.553563E-05 -2.169142E-02 -6.306137E-05 -2.218276E-02 -5.572871E-05 -1.802302E-02 -4.705313E-05 -1.782656E-02 -4.017437E-05 -1.925947E-02 -4.703183E-05 -1.641263E-02 -3.693267E-05 -1.516396E-02 -3.126646E-05 -1.512145E-02 -3.336386E-05 -1.579023E-02 -3.449473E-05 -1.368503E-02 -3.144328E-05 -1.108096E-02 -1.983330E-05 -1.447670E-02 -3.832266E-05 -1.831886E-02 -3.928136E-05 -1.893457E-02 -5.869250E-05 -1.764892E-02 -5.005397E-05 -1.637340E-02 -3.702753E-05 -9.686698E-03 -1.449037E-05 -1.006947E-02 -1.933484E-05 -1.884484E-02 -4.561680E-05 -1.468883E-02 -2.792875E-05 -1.670400E-02 -3.477624E-05 -1.632153E-02 -3.402425E-05 -9.187335E-03 -1.053828E-05 -9.985824E-03 -1.585776E-05 -1.303759E-02 -3.027649E-05 -1.872005E-02 -5.130980E-05 -1.633753E-02 -4.260466E-05 -1.020425E-02 -1.707335E-05 -1.320758E-02 -2.695180E-05 -1.208449E-02 -3.007055E-05 -1.286574E-02 -2.373357E-05 -1.095090E-02 -2.877553E-05 -1.692473E-02 -4.961965E-05 -1.190920E-02 -2.375507E-05 -5.682089E-03 -4.636856E-06 -1.035844E-02 -1.997872E-05 -9.666688E-03 -1.483243E-05 -1.613905E-02 -3.984840E-05 -1.572095E-02 -3.368762E-05 -1.108904E-02 -1.539438E-05 -1.486260E-02 -4.070529E-05 -1.042750E-02 -1.813263E-05 -1.042360E-02 -1.689881E-05 -8.718623E-03 -1.199955E-05 -1.039440E-02 -1.674301E-05 -5.162509E-03 -6.408708E-06 -9.563193E-03 -1.362142E-05 -6.648598E-03 -1.021485E-05 -1.122742E-02 -1.540873E-05 -7.837929E-03 -1.128828E-05 -1.114590E-02 -2.553030E-05 -1.141215E-02 -2.510840E-05 -1.152836E-02 -2.344713E-05 -7.971937E-03 -1.506387E-05 -1.248527E-02 -2.125446E-05 -6.066628E-03 -9.574143E-06 -1.087280E-02 -1.688717E-05 -9.550524E-03 -1.250483E-05 -5.306519E-03 -4.846453E-06 -7.512202E-03 -8.651766E-06 -7.508820E-03 -8.634705E-06 -5.185887E-03 -4.163304E-06 -1.379038E-02 -3.492367E-05 -9.235196E-03 -1.206055E-05 -1.392051E-02 -3.803496E-05 -7.049846E-03 -9.147756E-06 -5.323140E-03 -4.281730E-06 -8.229124E-03 -1.548991E-05 -7.235167E-03 -1.441034E-05 -2.366009E-03 -3.874657E-06 -5.945679E-03 -1.067197E-05 -5.871383E-03 -5.656813E-06 -9.732147E-03 -2.269675E-05 -6.582049E-03 -7.833573E-06 -3.066363E-03 -3.098185E-06 -5.796032E-03 -6.625438E-06 -8.122368E-03 -9.655803E-06 -1.121766E-02 -1.750086E-05 -1.036527E-02 -1.842391E-05 -5.944076E-03 -6.439480E-06 -2.283818E-03 -1.352210E-06 -1.446587E-03 -7.807258E-07 -4.944507E-03 -3.694344E-06 -3.281169E-03 -2.925608E-06 -9.286754E-03 -1.260048E-05 -1.272772E-02 -2.464058E-05 -1.270753E-02 -3.173555E-05 -1.419952E-02 -2.835999E-05 -9.671107E-03 -1.686465E-05 -9.583433E-03 -1.323773E-05 -1.186931E-02 -2.163029E-05 -1.267789E-02 -2.021594E-05 -8.275560E-03 -9.163723E-06 -1.062420E-02 -1.977462E-05 -1.198470E-02 -1.979838E-05 -1.324773E-02 -2.853129E-05 -1.727253E-02 -3.432691E-05 -1.381997E-02 -2.842333E-05 -1.578301E-02 -3.356518E-05 -1.555696E-02 -3.183947E-05 -8.166265E-03 -8.629223E-06 -1.747785E-02 -4.250397E-05 -9.541135E-03 -1.246077E-05 -1.393808E-02 -3.012112E-05 -1.209324E-02 -2.429593E-05 -1.079402E-02 -2.325836E-05 -1.374417E-02 -2.491779E-05 -9.500289E-03 -1.572888E-05 -1.222769E-02 -2.456217E-05 -1.097825E-02 -1.938425E-05 -1.410107E-02 -2.407486E-05 -2.024375E-02 -6.980050E-05 -1.220648E-02 -3.245536E-05 -1.137633E-02 -1.667373E-05 -1.038617E-02 -1.405080E-05 -1.243797E-02 -2.413125E-05 -9.998308E-03 -1.605906E-05 -8.805567E-03 -1.128015E-05 -1.388695E-02 -3.039013E-05 -1.242352E-02 -2.040627E-05 -2.645008E-02 -8.679965E-05 -2.076456E-02 -5.640973E-05 -1.805209E-02 -4.120924E-05 -1.246120E-02 -3.006639E-05 -1.810150E-02 -4.756486E-05 -1.472448E-02 -3.309142E-05 -2.571400E-02 -8.648041E-05 -1.341319E-02 -3.280431E-05 -1.535941E-02 -4.819536E-05 -2.373309E-02 -7.918529E-05 -5.757795E-03 -4.733061E-06 -1.174264E-02 -2.108284E-05 -1.884131E-02 -4.721518E-05 -1.750610E-02 -4.223243E-05 -1.716739E-02 -3.617002E-05 -1.252851E-02 -2.099071E-05 -1.388277E-02 -3.109337E-05 -1.350362E-02 -3.082057E-05 -1.238489E-02 -3.728424E-05 -9.966253E-03 -2.035860E-05 -2.285240E-02 -8.446864E-05 -1.327084E-02 -3.045931E-05 -1.193699E-02 -2.204142E-05 -6.923219E-03 -9.602029E-06 -1.838247E-02 -4.807008E-05 -1.863076E-02 -4.604209E-05 -1.334000E-02 -2.761396E-05 -1.141315E-02 -2.474696E-05 -2.286809E-02 -1.083380E-04 -1.645875E-02 -3.520343E-05 -1.229791E-02 -2.380600E-05 -1.284486E-02 -2.254139E-05 -1.854605E-02 -4.752272E-05 -1.049692E-02 -1.983824E-05 -7.207727E-03 -7.286730E-06 -1.686364E-02 -3.977916E-05 -1.314115E-02 -2.189974E-05 -1.520236E-02 -3.635654E-05 -1.096706E-02 -2.475645E-05 -7.932651E-03 -1.085523E-05 -1.515150E-02 -4.556316E-05 -1.171402E-02 -3.284784E-05 -1.087897E-02 -1.567310E-05 -8.199381E-03 -9.564718E-06 -9.456870E-03 -1.207744E-05 -8.827517E-03 -1.658191E-05 -5.512807E-03 -6.038391E-06 -8.573999E-03 -1.207656E-05 -1.047145E-02 -1.674083E-05 -9.666379E-03 -1.231732E-05 -1.046000E-02 -1.782331E-05 -6.009504E-03 -6.261797E-06 -1.111917E-02 -1.768100E-05 -1.105060E-02 -1.934982E-05 -5.280218E-03 -7.191057E-06 -7.637218E-03 -9.728555E-06 -1.009144E-02 -1.219856E-05 -4.974619E-03 -4.499916E-06 -6.589686E-03 -1.040697E-05 -7.787208E-03 -1.023212E-05 -6.068811E-03 -5.842725E-06 -3.416649E-03 -3.146550E-06 -9.213350E-03 -2.154615E-05 -6.752158E-03 -9.801770E-06 -4.758057E-03 -6.649209E-06 -6.129868E-03 -8.342508E-06 -2.783932E-03 -2.140712E-06 -6.308493E-03 -1.039901E-05 -2.249137E-03 -1.153739E-06 -2.514780E-03 -1.593412E-06 -6.018183E-03 -8.965827E-06 -3.234291E-03 -2.042484E-06 -7.860270E-03 -1.035245E-05 -3.414591E-03 -2.249770E-06 -7.941000E-03 -1.449758E-05 -3.591791E-03 -2.245391E-06 -7.807797E-03 -1.011270E-05 -7.726893E-03 -1.478217E-05 -2.506930E-03 -2.954554E-06 -5.955023E-03 -7.260418E-06 -5.294809E-03 -8.225926E-06 -2.802166E-03 -1.996795E-06 -2.404798E-03 -1.266950E-06 -4.125341E-03 -2.979146E-06 -7.417991E-03 -8.566910E-06 -8.158248E-03 -1.230927E-05 -7.976311E-03 -1.332178E-05 -8.873852E-03 -1.480843E-05 -9.373684E-03 -1.259336E-05 -8.214068E-03 -1.186084E-05 -6.962685E-03 -7.715598E-06 -8.834013E-03 -1.972166E-05 -5.435947E-03 -4.590835E-06 -5.487949E-03 -5.939754E-06 -6.678491E-03 -8.355182E-06 -4.058912E-03 -5.880001E-06 -1.360573E-02 -2.671641E-05 -1.143610E-02 -2.018223E-05 -7.702740E-03 -1.433952E-05 -5.873725E-03 -6.789166E-06 -1.088086E-02 -3.437425E-05 -7.089361E-03 -1.461407E-05 -8.765624E-03 -1.242854E-05 -9.453645E-03 -1.575322E-05 -1.001462E-02 -1.448625E-05 -1.282490E-02 -2.290074E-05 -8.545890E-03 -1.273760E-05 -7.387390E-03 -9.140356E-06 -1.399357E-02 -2.449459E-05 -1.337581E-02 -3.113825E-05 -1.423915E-02 -2.729711E-05 -6.580885E-03 -8.347839E-06 -7.779718E-03 -1.007558E-05 -7.480792E-03 -1.083253E-05 -1.275448E-02 -2.722719E-05 -1.292106E-02 -2.421066E-05 -9.755948E-03 -1.426055E-05 -9.117272E-03 -1.368142E-05 -7.455531E-03 -8.688003E-06 -1.042236E-02 -1.801425E-05 -1.296287E-02 -2.809397E-05 -1.390180E-02 -2.674920E-05 -1.265490E-02 -3.041327E-05 -1.269961E-02 -2.824134E-05 -1.133938E-02 -1.625519E-05 -9.821144E-03 -2.178670E-05 -1.530578E-02 -3.585772E-05 -1.299672E-02 -2.588612E-05 -1.544212E-02 -3.143850E-05 -8.347818E-03 -1.132876E-05 -1.393101E-02 -2.890996E-05 -6.639867E-03 -7.587375E-06 -1.839132E-02 -4.637735E-05 -1.188258E-02 -1.953879E-05 -1.588672E-02 -3.134987E-05 -1.425154E-02 -2.751603E-05 -4.920276E-03 -4.432356E-06 -1.374206E-02 -2.842285E-05 -1.673110E-02 -4.601232E-05 -1.254973E-02 -2.188833E-05 -6.444727E-03 -5.222041E-06 -1.023529E-02 -1.572480E-05 -1.087382E-02 -1.692895E-05 -9.038702E-03 -1.572012E-05 -1.398299E-02 -2.818260E-05 -8.766186E-03 -1.494609E-05 -1.321841E-02 -2.007819E-05 -1.562133E-02 -3.892744E-05 -8.289134E-03 -1.177987E-05 -8.947084E-03 -1.094585E-05 -1.594810E-02 -3.949297E-05 -1.285384E-02 -2.278617E-05 -5.689452E-03 -7.280228E-06 -9.766401E-03 -2.148390E-05 -8.496573E-03 -8.437729E-06 -7.991945E-03 -9.550933E-06 -9.608813E-03 -1.425597E-05 -1.052303E-02 -1.935336E-05 -8.548009E-03 -1.333735E-05 -7.337588E-03 -9.975447E-06 -1.423505E-02 -3.258201E-05 -1.136654E-02 -2.510870E-05 -7.860115E-03 -8.206414E-06 -8.309608E-03 -1.504702E-05 -1.110051E-02 -2.051470E-05 -6.172688E-03 -9.409184E-06 -9.740436E-03 -1.437599E-05 -8.997021E-03 -1.150131E-05 -1.279849E-02 -3.206319E-05 -1.028663E-02 -1.505898E-05 -1.122879E-02 -1.673337E-05 -8.223903E-03 -9.720008E-06 -8.464761E-03 -1.103940E-05 -6.670166E-03 -6.071848E-06 -4.620811E-03 -6.527856E-06 -3.824735E-03 -3.340845E-06 -5.634323E-03 -5.012909E-06 -3.166012E-03 -3.619323E-06 -9.167802E-03 -1.056621E-05 -3.221327E-03 -1.773076E-06 -5.412502E-03 -5.413007E-06 -6.702745E-03 -8.187361E-06 -4.863392E-03 -3.807791E-06 -4.405641E-03 -4.058186E-06 -6.131083E-03 -7.250341E-06 -4.913764E-03 -5.744987E-06 -4.588314E-03 -3.202328E-06 -6.804591E-03 -8.479426E-06 -7.252910E-03 -8.758909E-06 -4.312950E-03 -3.434388E-06 -1.807777E-03 -1.380521E-06 -4.671070E-03 -5.538033E-06 -7.067950E-03 -1.174764E-05 -2.930719E-03 -1.441738E-06 -1.279222E-03 -1.078804E-06 -3.507572E-03 -5.821750E-06 -9.678721E-03 -2.476852E-05 -2.874671E-03 -2.470595E-06 -2.182691E-03 -1.629987E-06 -3.621537E-03 -9.191521E-06 -1.740159E-03 -6.544183E-07 -3.203873E-03 -3.602845E-06 -2.890800E-03 -2.526106E-06 -3.068561E-03 -4.213711E-06 -6.078860E-03 -7.760574E-06 -7.287103E-03 -7.524310E-06 -7.509754E-03 -2.547783E-05 -2.646412E-03 -2.157075E-06 -6.255289E-03 -6.947406E-06 -4.941751E-03 -7.943248E-06 -9.224779E-03 -1.410566E-05 -4.906800E-03 -4.350073E-06 -7.923221E-03 -1.421559E-05 -2.900094E-03 -1.652857E-06 -3.445014E-03 -1.996755E-06 -2.978919E-03 -3.704572E-06 -8.310828E-03 -1.128557E-05 -8.914816E-03 -1.105293E-05 -6.453823E-03 -7.530365E-06 -8.529848E-03 -1.250596E-05 -1.241639E-02 -1.968019E-05 -3.654989E-03 -2.852818E-06 -6.194753E-03 -4.637962E-06 -7.168410E-03 -9.747482E-06 -7.074135E-03 -8.723001E-06 -3.088414E-03 -2.165114E-06 -4.736900E-03 -4.690360E-06 -5.496866E-03 -6.084993E-06 -9.992636E-03 -2.331975E-05 -5.785665E-03 -9.290287E-06 -9.268775E-03 -1.727651E-05 -1.110749E-02 -2.320101E-05 -6.035119E-03 -6.006884E-06 -6.097186E-03 -8.477525E-06 -9.286855E-03 -1.325325E-05 -5.725710E-03 -5.595748E-06 -5.225326E-03 -5.682741E-06 -8.374162E-03 -1.358989E-05 -8.070266E-03 -8.525794E-06 -5.663014E-03 -8.326352E-06 -1.077577E-02 -1.774824E-05 -6.823384E-03 -7.461723E-06 -1.309151E-02 -2.293933E-05 -9.734117E-03 -1.567869E-05 -1.064840E-02 -1.998801E-05 -6.598548E-03 -1.247960E-05 -8.533419E-03 -1.698271E-05 -1.187770E-02 -2.246194E-05 -3.905374E-03 -2.559130E-06 -2.608870E-03 -1.558560E-06 -6.052893E-03 -5.374399E-06 -5.291540E-03 -8.103686E-06 -7.976421E-03 -1.021030E-05 -9.757093E-03 -1.668583E-05 -7.385489E-03 -1.285403E-05 -7.929263E-03 -7.987788E-06 -9.704986E-03 -2.962975E-05 -7.525077E-03 -1.306302E-05 -6.991034E-03 -1.064873E-05 -5.005358E-03 -9.835012E-06 -8.092808E-03 -1.147394E-05 -4.474087E-03 -3.834905E-06 -6.834524E-03 -6.982199E-06 -4.812916E-03 -4.467796E-06 -5.990512E-03 -7.842268E-06 -4.574709E-03 -3.970763E-06 -4.788106E-03 -3.924811E-06 -8.916249E-03 -1.850608E-05 -5.259665E-03 -8.293438E-06 -9.696546E-03 -1.517672E-05 -4.590212E-03 -5.096431E-06 -7.314462E-03 -1.714769E-05 -3.860185E-03 -3.127895E-06 -1.784310E-03 -9.235975E-07 -5.547235E-03 -5.112055E-06 -5.865507E-03 -6.708947E-06 -4.328438E-03 -4.229047E-06 -5.092655E-03 -5.828910E-06 -6.709671E-03 -7.080990E-06 -4.327802E-03 -3.188523E-06 -4.937391E-03 -4.569445E-06 -8.293491E-03 -1.319561E-05 -3.930138E-03 -6.730814E-06 -4.416256E-03 -4.105889E-06 -3.467315E-03 -2.354469E-06 -5.332491E-03 -9.029639E-06 -2.694692E-03 -1.279641E-06 -5.342987E-03 -6.713119E-06 -7.519588E-03 -1.092346E-05 -5.285743E-03 -5.723628E-06 -6.665656E-03 -8.544653E-06 -3.846760E-03 -2.666108E-06 -6.284377E-03 -9.724369E-06 -6.196868E-03 -8.329996E-06 -5.286331E-03 -6.920429E-06 -7.052727E-03 -1.143953E-05 -5.029353E-03 -3.735294E-06 -2.407489E-03 -2.444788E-06 -4.133935E-04 -9.497986E-08 -6.027018E-03 -1.025712E-05 -3.598018E-03 -3.018229E-06 -4.613658E-03 -4.076030E-06 -3.342670E-03 -3.029962E-06 -3.733008E-03 -2.515848E-06 -5.141865E-03 -9.007182E-06 -7.728541E-03 -1.349554E-05 -1.579734E-03 -1.531714E-06 -3.519217E-03 -3.673203E-06 -5.032814E-03 -4.394432E-06 -1.399643E-03 -6.119406E-07 -3.930826E-03 -4.507517E-06 -4.767309E-03 -5.014044E-06 diff --git a/tests/regression_tests/unstructured_mesh/test.py b/tests/regression_tests/unstructured_mesh/test.py index c921a784826..0082198ddec 100644 --- a/tests/regression_tests/unstructured_mesh/test.py +++ b/tests/regression_tests/unstructured_mesh/test.py @@ -1,6 +1,8 @@ +import filecmp import glob from itertools import product import os +import warnings import openmc import openmc.lib @@ -9,18 +11,52 @@ import pytest from tests.testing_harness import PyAPITestHarness -TETS_PER_VOXEL = 12 - class UnstructuredMeshTest(PyAPITestHarness): - def __init__(self, statepoint_name, model, inputs_true, holes): + ELEM_PER_VOXEL = 12 + + def __init__(self, + statepoint_name, + model, + inputs_true='inputs_true.dat', + holes=False, + scale_factor=10.0): super().__init__(statepoint_name, model, inputs_true) self.holes = holes # holes in the test mesh + self.scale_bounding_cell(scale_factor) + + def scale_bounding_cell(self, scale_factor): + geometry = self._model.geometry + for surface in geometry.get_all_surfaces().values(): + if surface.boundary_type != 'vacuum': + continue + for coeff in surface._coefficients: + surface._coefficients[coeff] *= scale_factor def _compare_results(self): with openmc.StatePoint(self._sp_name) as sp: + # check some properties of the unstructured mesh + umesh = None + for m in sp.meshes.values(): + if isinstance(m, openmc.UnstructuredMesh): + umesh = m + assert umesh is not None + + # check that the first element centroid is correct + # this will depend on whether the tet mesh or hex mesh + # file is being used in this test + if umesh.element_types[0] == umesh._LINEAR_TET: + exp_vertex = (-10.0, -10.0, -10.0) + exp_centroid = (-8.75, -9.75, -9.25) + else: + exp_vertex = (-10.0, -10.0, 10.0) + exp_centroid = (-9.0, -9.0, 9.0) + + np.testing.assert_array_equal(umesh.vertices[0], exp_vertex) + np.testing.assert_array_equal(umesh.centroid(0), exp_centroid) + # loop over the tallies and get data for tally in sp.tallies.values(): # find the regular and unstructured meshes @@ -28,32 +64,39 @@ def _compare_results(self): flt = tally.find_filter(openmc.MeshFilter) if isinstance(flt.mesh, openmc.RegularMesh): - reg_mesh_data, reg_mesh_std_dev = self.get_mesh_tally_data(tally) + reg_mesh_data = self.get_mesh_tally_data(tally) if self.holes: reg_mesh_data = np.delete(reg_mesh_data, self.holes) - reg_mesh_std_dev = np.delete(reg_mesh_std_dev, self.holes) else: umesh_tally = tally - unstructured_data, unstructured_std_dev = self.get_mesh_tally_data(tally, True) + unstructured_data = self.get_mesh_tally_data(tally, True) - # we expect these results to be the same to within at least ten - # decimal places - decimals = 10 if umesh_tally.estimator == 'collision' else 8 - np.testing.assert_array_almost_equal(unstructured_data, - reg_mesh_data, - decimals) + # we expect these results to be the same to within at least ten + # decimal places + decimals = 10 if umesh_tally.estimator == 'collision' else 8 + np.testing.assert_array_almost_equal(np.sort(unstructured_data), + np.sort(reg_mesh_data), + decimals) - @staticmethod - def get_mesh_tally_data(tally, structured=False): + def get_mesh_tally_data(self, tally, structured=False): data = tally.get_reshaped_data(value='mean') - std_dev = tally.get_reshaped_data(value='std_dev') if structured: - data.shape = (data.size // TETS_PER_VOXEL, TETS_PER_VOXEL) - std_dev.shape = (std_dev.size // TETS_PER_VOXEL, TETS_PER_VOXEL) + data = data.reshape((-1, self.ELEM_PER_VOXEL)) else: data.shape = (data.size, 1) - std_dev.shape = (std_dev.size, 1) - return np.sum(data, axis=1), np.sum(std_dev, axis=1) + return np.sum(data, axis=1) + + def update_results(self): + """Update results_true.dat and inputs_true.dat""" + try: + self._build_inputs() + inputs = self._get_inputs() + self._write_inputs(inputs) + self._overwrite_inputs() + self._run_openmc() + self._test_output_created() + finally: + self._cleanup() def _cleanup(self): super()._cleanup() @@ -64,35 +107,11 @@ def _cleanup(self): os.remove(f) -param_values = (['libmesh', 'moab'], # mesh libraries - ['collision', 'tracklength'], # estimators - [True, False], # geometry outside of the mesh - [(333, 90, 77), None]) # location of holes in the mesh -test_cases = [] -for i, (lib, estimator, ext_geom, holes) in enumerate(product(*param_values)): - test_cases.append({'library' : lib, - 'estimator' : estimator, - 'external_geom' : ext_geom, - 'holes' : holes, - 'inputs_true' : 'inputs_true{}.dat'.format(i)}) - - -@pytest.mark.parametrize("test_opts", test_cases) -def test_unstructured_mesh(test_opts): - +@pytest.fixture +def model(): openmc.reset_auto_ids() - # skip the test if the library is not enabled - if test_opts['library'] == 'moab' and not openmc.lib._dagmc_enabled(): - pytest.skip("DAGMC (and MOAB) mesh not enbaled in this build.") - - if test_opts['library'] == 'libmesh' and not openmc.lib._libmesh_enabled(): - pytest.skip("LibMesh is not enabled in this build.") - - # skip the tracklength test for libmesh - if test_opts['library'] == 'libmesh' and \ - test_opts['estimator'] == 'tracklength': - pytest.skip("Tracklength tallies are not supported using libmesh.") + model = openmc.Model() ### Materials ### materials = openmc.Materials() @@ -113,7 +132,7 @@ def test_unstructured_mesh(test_opts): water_mat.set_density("atom/b-cm", 0.07416) materials.append(water_mat) - materials.export_to_xml() + model.materials = materials ### Geometry ### fuel_min_x = openmc.XPlane(-5.0, name="minimum x") @@ -149,29 +168,26 @@ def test_unstructured_mesh(test_opts): +clad_min_z & -clad_max_z) clad_cell.fill = zirc_mat - if test_opts['external_geom']: - bounds = (15, 15, 15) - else: - bounds = (10, 10, 10) - - water_min_x = openmc.XPlane(x0=-bounds[0], + # set bounding cell dimension to one + # this will be updated later according to the test case parameters + water_min_x = openmc.XPlane(x0=-1.0, name="minimum x", boundary_type='vacuum') - water_max_x = openmc.XPlane(x0=bounds[0], + water_max_x = openmc.XPlane(x0=1.0, name="maximum x", boundary_type='vacuum') - water_min_y = openmc.YPlane(y0=-bounds[1], + water_min_y = openmc.YPlane(y0=-1.0, name="minimum y", boundary_type='vacuum') - water_max_y = openmc.YPlane(y0=bounds[1], + water_max_y = openmc.YPlane(y0=1.0, name="maximum y", boundary_type='vacuum') - water_min_z = openmc.ZPlane(z0=-bounds[2], + water_min_z = openmc.ZPlane(z0=-1.0, name="minimum z", boundary_type='vacuum') - water_max_z = openmc.ZPlane(z0=bounds[2], + water_max_z = openmc.ZPlane(z0=1.0, name="maximum z", boundary_type='vacuum') @@ -185,9 +201,9 @@ def test_unstructured_mesh(test_opts): water_cell.fill = water_mat # create a containing universe - geometry = openmc.Geometry([fuel_cell, clad_cell, water_cell]) + model.geometry = openmc.Geometry([fuel_cell, clad_cell, water_cell]) - ### Tallies ### + ### Reference Tally ### # create meshes and mesh filters regular_mesh = openmc.RegularMesh() @@ -196,29 +212,11 @@ def test_unstructured_mesh(test_opts): regular_mesh.upper_right = (10.0, 10.0, 10.0) regular_mesh_filter = openmc.MeshFilter(mesh=regular_mesh) - - if test_opts['holes']: - mesh_filename = "test_mesh_tets_w_holes.e" - else: - mesh_filename = "test_mesh_tets.e" - - uscd_mesh = openmc.UnstructuredMesh(mesh_filename, test_opts['library']) - uscd_filter = openmc.MeshFilter(mesh=uscd_mesh) - - # create tallies - tallies = openmc.Tallies() - regular_mesh_tally = openmc.Tally(name="regular mesh tally") regular_mesh_tally.filters = [regular_mesh_filter] regular_mesh_tally.scores = ['flux'] - regular_mesh_tally.estimator = test_opts['estimator'] - tallies.append(regular_mesh_tally) - uscd_tally = openmc.Tally(name="unstructured mesh tally") - uscd_tally.filters = [uscd_filter] - uscd_tally.scores = ['flux'] - uscd_tally.estimator = test_opts['estimator'] - tallies.append(uscd_tally) + model.tallies = openmc.Tallies([regular_mesh_tally]) ### Settings ### settings = openmc.Settings() @@ -228,21 +226,101 @@ def test_unstructured_mesh(test_opts): # source setup r = openmc.stats.Uniform(a=0.0, b=0.0) - theta = openmc.stats.Discrete(x=[0.0], p=[1.0]) + cos_theta = openmc.stats.Discrete(x=[1.0], p=[1.0]) phi = openmc.stats.Discrete(x=[0.0], p=[1.0]) - space = openmc.stats.SphericalIndependent(r, theta, phi) + space = openmc.stats.SphericalIndependent(r, cos_theta, phi) energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) - source = openmc.Source(space=space, energy=energy) + source = openmc.IndependentSource(space=space, energy=energy) settings.source = source - model = openmc.model.Model(geometry=geometry, - materials=materials, - tallies=tallies, - settings=settings) + model.settings = settings + + return model + + +param_values = (['libmesh', 'moab'], # mesh libraries + ['collision', 'tracklength'], # estimators + [True, False], # geometry outside of the mesh + [(333, 90, 77), None]) # location of holes in the mesh +test_cases = [] +for i, (lib, estimator, ext_geom, holes) in enumerate(product(*param_values)): + test_cases.append({'library' : lib, + 'estimator' : estimator, + 'external_geom' : ext_geom, + 'holes' : holes, + 'inputs_true' : 'inputs_true{}.dat'.format(i)}) + + +@pytest.mark.parametrize("test_opts", test_cases) +def test_unstructured_mesh_tets(model, test_opts): + # skip the test if the library is not enabled + if test_opts['library'] == 'moab' and not openmc.lib._dagmc_enabled(): + pytest.skip("DAGMC (and MOAB) mesh not enbaled in this build.") + + if test_opts['library'] == 'libmesh' and not openmc.lib._libmesh_enabled(): + pytest.skip("LibMesh is not enabled in this build.") + + # skip the tracklength test for libmesh + if test_opts['library'] == 'libmesh' and \ + test_opts['estimator'] == 'tracklength': + pytest.skip("Tracklength tallies are not supported using libmesh.") + + if test_opts['holes']: + mesh_filename = "test_mesh_tets_w_holes.e" + else: + mesh_filename = "test_mesh_tets.e" + + # add reference mesh tally + regular_mesh_tally = model.tallies[0] + regular_mesh_tally.estimator = test_opts['estimator'] + + # add analagous unstructured mesh tally + uscd_mesh = openmc.UnstructuredMesh(mesh_filename, test_opts['library']) + if test_opts['library'] == 'moab': + uscd_mesh.options = 'MAX_DEPTH=15;PLANE_SET=2' + uscd_filter = openmc.MeshFilter(mesh=uscd_mesh) + + # create tallies + uscd_tally = openmc.Tally(name="unstructured mesh tally") + uscd_tally.filters = [uscd_filter] + uscd_tally.scores = ['flux'] + uscd_tally.estimator = test_opts['estimator'] + model.tallies.append(uscd_tally) + + # modify model geometry according to test opts + if test_opts['external_geom']: + scale_factor = 15.0 + else: + scale_factor = 10.0 harness = UnstructuredMeshTest('statepoint.10.h5', model, test_opts['inputs_true'], - test_opts['holes']) + test_opts['holes'], + scale_factor) + harness.main() + + +@pytest.mark.skipif(not openmc.lib._libmesh_enabled(), + reason='LibMesh is not enabled in this build.') +def test_unstructured_mesh_hexes(model): + regular_mesh_tally = model.tallies[0] + regular_mesh_tally.estimator = 'collision' + + # add analagous unstructured mesh tally + uscd_mesh = openmc.UnstructuredMesh('test_mesh_hexes.e', 'libmesh') + uscd_filter = openmc.MeshFilter(mesh=uscd_mesh) + + # create tallies + uscd_tally = openmc.Tally(name="unstructured mesh tally") + uscd_tally.filters = [uscd_filter] + uscd_tally.scores = ['flux'] + uscd_tally.estimator = 'collision' + model.tallies.append(uscd_tally) + + harness = UnstructuredMeshTest('statepoint.10.h5', + model) + harness.ELEM_PER_VOXEL = 1 + harness.main() diff --git a/tests/regression_tests/unstructured_mesh/test_mesh_hexes.e b/tests/regression_tests/unstructured_mesh/test_mesh_hexes.e new file mode 120000 index 00000000000..421bf6a89ad --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/test_mesh_hexes.e @@ -0,0 +1 @@ +test_mesh_hexes.exo \ No newline at end of file diff --git a/tests/regression_tests/unstructured_mesh/test_mesh_hexes.exo b/tests/regression_tests/unstructured_mesh/test_mesh_hexes.exo new file mode 100644 index 00000000000..03682c27564 Binary files /dev/null and b/tests/regression_tests/unstructured_mesh/test_mesh_hexes.exo differ diff --git a/tests/regression_tests/void/inputs_true.dat b/tests/regression_tests/void/inputs_true.dat index 64495209751..7fee0779e06 100644 --- a/tests/regression_tests/void/inputs_true.dat +++ b/tests/regression_tests/void/inputs_true.dat @@ -1,132 +1,131 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fixed source - 1000 - 3 - - - 0.0 0.0 0.0 - - - - - - - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 - - - 1 - total - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 1000 + 3 + + + 0.0 0.0 0.0 + + + + + + 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 + + + 1 + total + + + diff --git a/tests/regression_tests/void/test.py b/tests/regression_tests/void/test.py index af1e3887b82..76c15eb39f6 100644 --- a/tests/regression_tests/void/test.py +++ b/tests/regression_tests/void/test.py @@ -23,7 +23,7 @@ def model(): model.settings.run_mode = 'fixed source' model.settings.batches = 3 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) cell_filter = openmc.CellFilter(cells) tally = openmc.Tally() diff --git a/tests/regression_tests/volume_calc/inputs_true.dat b/tests/regression_tests/volume_calc/inputs_true.dat index aaf6d8b005f..e3a8162e3b8 100644 --- a/tests/regression_tests/volume_calc/inputs_true.dat +++ b/tests/regression_tests/volume_calc/inputs_true.dat @@ -1,75 +1,75 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - volume - - cell - 1 2 3 - 100000 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - material - 1 2 - 100000 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - universe - 0 - 100000 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - cell - 1 2 3 - 100 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - - material - 1 2 - 100 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - - cell - 1 2 3 - 100 - -1.0 -1.0 -6.0 - 1.0 1.0 6.0 - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + volume + + cell + 1 2 3 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + material + 1 2 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + universe + 0 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + material + 1 2 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + diff --git a/tests/regression_tests/volume_calc/inputs_true_mg.dat b/tests/regression_tests/volume_calc/inputs_true_mg.dat new file mode 100644 index 00000000000..2ace5cd3c92 --- /dev/null +++ b/tests/regression_tests/volume_calc/inputs_true_mg.dat @@ -0,0 +1,76 @@ + + + + mg_lib.h5 + + + + + + + + + + + + + + + + + + + + + + + + volume + multi-group + + cell + 1 2 3 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + material + 1 2 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + universe + 0 + 100000 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + material + 1 2 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index 1f1a2c7c951..c94d16c7975 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -1,6 +1,8 @@ import os import glob -import sys + +import numpy as np +import pytest import openmc @@ -9,20 +11,23 @@ class VolumeTest(PyAPITestHarness): - def __init__(self, *args, **kwargs): + def __init__(self, is_ce, *args, **kwargs): super().__init__(*args, **kwargs) self.exp_std_dev = 1e-01 self.exp_rel_err = 1e-01 self.exp_variance = 5e-02 + self.is_ce = is_ce + if not is_ce: + self.inputs_true = 'inputs_true_mg.dat' - def _build_inputs(self): # Define materials water = openmc.Material(1) water.add_nuclide('H1', 2.0) water.add_nuclide('O16', 1.0) water.add_nuclide('B10', 0.0001) - water.add_s_alpha_beta('c_H_in_H2O') + if self.is_ce: + water.add_s_alpha_beta('c_H_in_H2O') water.set_density('g/cc', 1.0) fuel = openmc.Material(2) @@ -31,7 +36,9 @@ def _build_inputs(self): fuel.set_density('g/cc', 4.5) materials = openmc.Materials((water, fuel)) - materials.export_to_xml() + if not self.is_ce: + materials.cross_sections = 'mg_lib.h5' + self._model.materials = materials cyl = openmc.ZCylinder(surface_id=1, r=1.0, boundary_type='vacuum') top_sphere = openmc.Sphere(surface_id=2, z0=5., r=1., boundary_type='vacuum') @@ -45,8 +52,7 @@ def _build_inputs(self): bottom_hemisphere = openmc.Cell(3, fill=water, region=-bottom_sphere & -top_plane) root = openmc.Universe(0, cells=(inside_cyl, top_hemisphere, bottom_hemisphere)) - geometry = openmc.Geometry(root) - geometry.export_to_xml() + self._model.geometry = openmc.Geometry(root) # Set up stochastic volume calculation ll, ur = root.bounding_box @@ -68,8 +74,51 @@ def _build_inputs(self): # Define settings settings = openmc.Settings() settings.run_mode = 'volume' + if not self.is_ce: + settings.energy_mode = 'multi-group' settings.volume_calculations = vol_calcs - settings.export_to_xml() + self._model.settings = settings + + # Create the MGXS file if necessary + if not self.is_ce: + groups = openmc.mgxs.EnergyGroups(group_edges=[0., 20.e6]) + mg_xs_file = openmc.MGXSLibrary(groups) + + nu = [2.] + fiss = [1.] + capture = [1.] + absorption_fissile = np.add(fiss, capture) + absorption_other = capture + scatter = np.array([[[1.]]]) + total_fissile = np.add(absorption_fissile, + np.sum(scatter[:, :, 0], axis=1)) + total_other = np.add(absorption_other, + np.sum(scatter[:, :, 0], axis=1)) + chi = [1.] + + for iso in ['H1', 'O16', 'B10', 'Mo99', 'U235']: + mat = openmc.XSdata(iso, groups) + mat.order = 0 + mat.atomic_weight_ratio = \ + openmc.data.atomic_mass(iso) / openmc.data.NEUTRON_MASS + mat.set_scatter_matrix(scatter) + if iso == 'U235': + mat.set_nu_fission(np.multiply(nu, fiss)) + mat.set_absorption(absorption_fissile) + mat.set_total(total_fissile) + mat.set_chi(chi) + else: + mat.set_absorption(absorption_other) + mat.set_total(total_other) + mg_xs_file.add_xsdata(mat) + mg_xs_file.export_to_hdf5('mg_lib.h5') + + def _cleanup(self): + super()._cleanup() + output = ['mg_lib.h5'] + for f in output: + if os.path.exists(f): + os.remove(f) def _get_results(self): outstr = '' @@ -116,6 +165,8 @@ def _get_results(self): def _test_output_created(self): pass -def test_volume_calc(): - harness = VolumeTest('') + +@pytest.mark.parametrize('is_ce', [True, False]) +def test_volume_calc(is_ce): + harness = VolumeTest(is_ce, '', model=openmc.Model()) harness.main() diff --git a/tests/regression_tests/weightwindows/__init__.py b/tests/regression_tests/weightwindows/__init__.py new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/regression_tests/weightwindows/__init__.py @@ -0,0 +1 @@ + diff --git a/tests/regression_tests/weightwindows/generators/__init__.py b/tests/regression_tests/weightwindows/generators/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/weightwindows/generators/test.py b/tests/regression_tests/weightwindows/generators/test.py new file mode 100644 index 00000000000..1d516db8dde --- /dev/null +++ b/tests/regression_tests/weightwindows/generators/test.py @@ -0,0 +1,61 @@ +import os + +import numpy as np +import openmc +import pytest + + +def test_ww_generator(run_in_tmpdir): + # create a simple spherical shield model + model = openmc.Model() + + water = openmc.Material() + water.set_density('g/cc', 1.0) + water.add_nuclide('H1', 0.66) + water.add_nuclide('O16', 0.34) + + s = openmc.Sphere(r=50, boundary_type='vacuum') + c = openmc.Cell(fill=water, region=-s) + + model.geometry = openmc.Geometry([c]) + + model.settings.particles = 500 + model.settings.batches = 5 + model.settings.run_mode = 'fixed source' + model.settings.max_splits = 100 + + mesh = openmc.RegularMesh.from_domain(model.geometry.root_universe) + energy_bounds = np.linspace(0.0, 1e6, 70) + particle = 'neutron' + + # include another tally to make sure user-specified tallies and those automaticaly + # created by weight window generators can coexist + tally = openmc.Tally() + ef = openmc.EnergyFilter(energy_bounds) + tally.filters = [ef] + tally.scores = ['flux'] + model.tallies = [tally] + + wwg = openmc.WeightWindowGenerator(mesh, energy_bounds, particle) + wwg.update_parameters = {'ratio': 5.0, 'threshold': 0.8, 'value': 'mean'} + + model.settings.weight_window_generators = wwg + model.run() + + # we test the effectiveness of the update method elsewhere, so + # just test that the generation happens successfully here + assert os.path.exists('weight_windows.h5') + + wws_mean = openmc.hdf5_to_wws() + assert len(wws_mean) == 1 + + # check that generation using the relative error works too + wwg.update_parameters['value'] = 'rel_err' + model.run() + + wws_rel_err = openmc.hdf5_to_wws() + assert len(wws_rel_err) == 1 + + # we should not get the same set of weight windows when switching to use of + # rel. err. + assert (wws_mean[0].lower_ww_bounds != wws_rel_err[0].lower_ww_bounds).any() diff --git a/tests/regression_tests/weightwindows/inputs_true.dat b/tests/regression_tests/weightwindows/inputs_true.dat new file mode 100644 index 00000000000..c40f4b7615e --- /dev/null +++ b/tests/regression_tests/weightwindows/inputs_true.dat @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 200 + 2 + + + 0.001 0.001 0.001 + + + 14000000.0 1.0 + + + true + + 2 + neutron + 0.0 0.5 20000000.0 + -1.0 0.007673145137236567 6.542700644645627e-07 0.0017541380096893788 0.0007245451610090619 7.476545089278482e-06 2.253382683081525e-06 2.1040609012865134e-05 0.08285899874014539 -1.0 1.0262431550731535e-13 3.3164825349503764e-16 0.0064803314120165335 3.5981031766416143e-06 -1.0 1.6205064883026195e-11 1.7770136411255912e-05 0.0001670700632870335 4.323138781337963e-05 -1.0 -1.0 6.922231352729155e-05 0.06550426960512012 -1.0 2.5639656866250453e-06 1.4508262073256659e-13 -1.0 -1.0 0.0009127050763987511 3.8523247550378815e-12 -1.0 0.0008175033526488423 -1.0 0.015148978428271613 2.5157355790201773e-07 2.1612150425221703e-06 1.3181562352445092e-10 2.9282097947816224e-05 2.762955748645507e-05 2.936268747135548e-14 1.6859219614058024e-19 3.937160538176268e-07 2.6011787393916806e-06 0.001570829313580841 -1.0 1.7041669224797384e-09 1.6421491993751715e-11 0.4899999304038166 6.948292975998466e-07 -1.0 -1.0 0.08657573566388353 0.006639379668946672 1.681305446488884e-11 2.2487617828938326e-05 4.109066205029878e-05 0.08288806458368345 -1.0 0.007385384405891666 -1.0 -1.0 1.008394964750947e-06 6.655926357459275e-08 0.0016279794552427574 1.4825219199133353e-12 -1.0 1.93847081892941e-05 1.284759166582202e-05 5.1161740516205715e-05 2.5447281241730366e-07 3.853097455417877e-06 -1.0 8.887234042637684e-05 0.01621821782442112 -1.0 1.8747824667478637e-14 5.97653814110781e-06 -1.0 -1.0 1.2296747260635405e-06 -1.0 -1.0 7.754700849337902e-06 7.091263906557291e-05 3.2799045883372075e-06 0.00020573181450240786 5.6949597066784976e-05 1.271128669411295e-07 0.0010019432401508087 -1.0 -1.0 6.848642863465585e-07 5.783974359937857e-06 2.380955631371226e-06 4.756872959630257e-05 2.1360401784344975e-18 0.00046029617115127556 1.0092905083158804e-11 0.08095280568305474 3.89841667138598e-08 4.354946981329799e-05 -1.0 0.5 0.0015447823995470042 -1.0 -1.0 0.001959411999677113 0.48573842213878143 -1.0 7.962899789920809e-06 5.619835883512353e-14 0.0835648710074336 2.7207433165796702e-11 0.00027464244062887683 4.076762579823379e-17 2.124999182004655e-05 8.037131813528501e-07 8.846493399850663e-06 1.080711295768551e-05 -1.0 -1.0 0.0010737081832502356 2.679340942769232e-06 2.1648918040467363e-05 0.0002668579837809081 1.3455341306162382e-05 2.5629068330446215e-05 1.3228013765525015e-05 -1.0 -1.0 7.002861620919232e-08 1.5172912057312398e-14 -1.0 7.989579285134734e-06 2.639268952045579e-10 -1.0 0.013330619853379314 0.00021534568699157805 2.4469456008493614e-09 8.211982683649991e-09 1.951356547084204e-15 0.00016419031150495913 5.985108617124989e-06 1.28584557092134e-05 1.5476769237571295e-14 5.5379154134462336e-08 0.0016637126543321873 2.499931357628383e-07 8.020767115181574e-07 2.7697233171399416e-13 -1.0 0.007197662162700777 -1.0 0.0833931797381589 2.8226276944532696e-05 3.353295403842037e-05 5.504813693036933e-12 0.007136750029575816 0.08636569925236791 -1.0 -1.0 6.315154082213375e-07 0.4877856021170283 -1.0 3.7051518220083886e-06 -1.0 0.0017950613169359904 7.84289689494925e-06 9.041149893307806e-07 -1.0 8.48176145671274e-10 9.03108551826469e-05 3.634644995026692e-05 2.0295213621716706e-09 1.0305672698745657e-11 1.5550455959178486e-06 0.01664109232689093 8.533030345699353e-17 0.0009252532821720597 -1.0 7.695031155172816e-14 0.0007151459162818186 -1.0 -1.0 5.182269672663266e-10 3.0160758454323657e-07 -1.0 0.06539005235506369 3.452537179033895e-05 -1.0 -1.0 3.855884234344845e-06 0.00017699858357744463 2.594951085377588e-06 1.1333627604823673e-09 -1.0 2.4306375693722205e-06 0.0063790654507599135 2.2060992580622125e-11 -1.0 -1.0 0.0848872967381878 3.932389299316285e-06 1.2911827198500372e-08 1.957092814065688e-05 0.0007213722022489493 0.0018327593437608 1.6699254277734109e-06 0.007188410694198128 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 + -10.0 0.07673145137236567 6.5427006446456266e-06 0.017541380096893787 0.0072454516100906195 7.476545089278483e-05 2.253382683081525e-05 0.00021040609012865135 0.828589987401454 -10.0 1.0262431550731535e-12 3.3164825349503764e-15 0.06480331412016534 3.5981031766416144e-05 -10.0 1.6205064883026195e-10 0.0001777013641125591 0.001670700632870335 0.0004323138781337963 -10.0 -10.0 0.0006922231352729155 0.6550426960512012 -10.0 2.5639656866250452e-05 1.4508262073256658e-12 -10.0 -10.0 0.009127050763987512 3.852324755037882e-11 -10.0 0.008175033526488424 -10.0 0.15148978428271614 2.515735579020177e-06 2.1612150425221703e-05 1.3181562352445092e-09 0.00029282097947816227 0.0002762955748645507 2.9362687471355483e-13 1.6859219614058023e-18 3.937160538176268e-06 2.6011787393916804e-05 0.015708293135808408 -10.0 1.7041669224797384e-08 1.6421491993751715e-10 4.899999304038166 6.948292975998466e-06 -10.0 -10.0 0.8657573566388354 0.06639379668946672 1.681305446488884e-10 0.00022487617828938325 0.0004109066205029878 0.8288806458368345 -10.0 0.07385384405891665 -10.0 -10.0 1.0083949647509469e-05 6.655926357459275e-07 0.016279794552427576 1.4825219199133352e-11 -10.0 0.000193847081892941 0.0001284759166582202 0.0005116174051620571 2.5447281241730365e-06 3.853097455417877e-05 -10.0 0.0008887234042637684 0.16218217824421122 -10.0 1.8747824667478637e-13 5.97653814110781e-05 -10.0 -10.0 1.2296747260635405e-05 -10.0 -10.0 7.754700849337902e-05 0.0007091263906557291 3.2799045883372076e-05 0.0020573181450240785 0.0005694959706678497 1.271128669411295e-06 0.010019432401508087 -10.0 -10.0 6.848642863465585e-06 5.7839743599378564e-05 2.380955631371226e-05 0.0004756872959630257 2.1360401784344976e-17 0.004602961711512756 1.0092905083158804e-10 0.8095280568305474 3.89841667138598e-07 0.00043549469813297995 -10.0 5.0 0.015447823995470043 -10.0 -10.0 0.01959411999677113 4.8573842213878144 -10.0 7.96289978992081e-05 5.619835883512353e-13 0.8356487100743359 2.7207433165796704e-10 0.002746424406288768 4.076762579823379e-16 0.00021249991820046548 8.037131813528501e-06 8.846493399850663e-05 0.0001080711295768551 -10.0 -10.0 0.010737081832502356 2.679340942769232e-05 0.00021648918040467362 0.0026685798378090807 0.00013455341306162382 0.00025629068330446217 0.00013228013765525016 -10.0 -10.0 7.002861620919232e-07 1.51729120573124e-13 -10.0 7.989579285134734e-05 2.639268952045579e-09 -10.0 0.13330619853379314 0.0021534568699157807 2.4469456008493615e-08 8.211982683649991e-08 1.951356547084204e-14 0.0016419031150495913 5.985108617124989e-05 0.000128584557092134 1.5476769237571296e-13 5.537915413446234e-07 0.016637126543321872 2.499931357628383e-06 8.020767115181574e-06 2.7697233171399415e-12 -10.0 0.07197662162700777 -10.0 0.8339317973815891 0.000282262769445327 0.00033532954038420373 5.504813693036933e-11 0.07136750029575815 0.8636569925236791 -10.0 -10.0 6.3151540822133754e-06 4.877856021170283 -10.0 3.7051518220083885e-05 -10.0 0.017950613169359905 7.84289689494925e-05 9.041149893307805e-06 -10.0 8.48176145671274e-09 0.000903108551826469 0.0003634644995026692 2.0295213621716707e-08 1.0305672698745658e-10 1.5550455959178486e-05 0.1664109232689093 8.533030345699353e-16 0.009252532821720597 -10.0 7.695031155172816e-13 0.007151459162818186 -10.0 -10.0 5.182269672663266e-09 3.0160758454323656e-06 -10.0 0.6539005235506369 0.0003452537179033895 -10.0 -10.0 3.855884234344845e-05 0.0017699858357744464 2.594951085377588e-05 1.1333627604823672e-08 -10.0 2.4306375693722206e-05 0.06379065450759913 2.2060992580622125e-10 -10.0 -10.0 0.848872967381878 3.9323892993162844e-05 1.2911827198500372e-07 0.0001957092814065688 0.0072137220224894934 0.018327593437608 1.669925427773411e-05 0.07188410694198127 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 + 3 + 1.5 + 10 + 1e-38 + + + 5 6 7 + -240 -240 -240 + 240 240 240 + + + 2 + neutron + 0.0 0.5 20000000.0 + -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 -1.0 0.06827568359008944 0.00017329528628152923 0.018541112907970003 0.011113024641218336 8.76041935303527e-05 8.168081568291806e-05 0.00046693784586018913 0.4952432605379829 2.2512327083641865e-10 4.6258592060517866e-07 2.7044817176109556e-05 0.054902816619122045 0.00014126153603265097 8.304845400451923e-08 2.2950716170641463e-05 0.0001335621430311088 0.003432919201293737 0.0005197081842709918 5.726152701849347e-16 -1.0 0.0013332554437480327 0.4346984808472855 7.691527781829036e-17 0.00011042047857307253 3.0571050855707084e-06 -1.0 4.986698316296507e-06 0.011128424196387618 1.3106335518133802e-05 5.447493368067179e-10 0.011440381012864086 4.670673837764874e-08 0.12364069326350118 0.00012558879474108074 3.136829920007009e-05 2.34750482787598e-05 0.001537590300149361 0.0017693279949094218 6.717625881826167e-05 4.587143797469485e-08 2.6211239246796104e-05 0.00030002326388383244 0.01729816946709781 4.5757238372058234e-11 6.92296299242814e-05 3.792209399652396e-06 -1.0 9.256616392487858e-05 8.541606727879512e-07 -1.0 0.49317081643076643 0.05500108683629957 1.298062961617927e-05 0.0006870228272606287 0.0008231482263927564 0.5 3.419181071650816e-06 0.06433819434431046 6.574706543646946e-16 4.0404626147344e-13 0.0003782322077390033 0.00012637534695610975 0.017602971074583987 1.0044390728858277e-05 -1.0 0.0008787411098754915 0.00023686818807101741 0.0009304497896205121 6.949587369646497e-05 0.00012918433677593975 2.0707648529746894e-06 0.0023295401596005313 0.11819165666519223 -1.0 2.1606550732170693e-05 0.00022057970761624768 -1.0 1.0325207105027347e-08 0.0002029396545382813 2.1234980618763222e-13 -1.0 0.00024175998138228048 0.001178616843705956 0.0001399807456616496 0.0038811025614225057 0.0011076796092102186 0.00010814452764860558 0.010955637485319249 -1.0 9.382800796426366e-17 5.098747893974248e-05 0.00027052054298385255 0.00021305826462238593 0.000808100901275472 4.233410073487772e-06 0.0051513292132259495 8.616027294555462e-07 0.4873897581604287 2.9093345975075226e-05 0.000469589568463265 -1.0 -1.0 0.017802624844035688 1.3116807133030035e-15 2.617878055106949e-16 0.01884234453311008 -1.0 2.027381220364608e-16 0.0004299195570308035 1.4628847959717225e-05 0.4899952354672477 2.774067049392004e-07 0.004441328419270369 4.279460329782799e-09 0.0012297303081805393 0.0002792896409558745 0.0006934466049804711 8.370896020975689e-05 3.8270536025799805e-15 -1.0 0.01208261392046878 0.0001497958445994315 0.0015016500045374082 0.005384625561469684 0.00025519632243117644 0.0011028020390507682 0.0002362355168421952 -1.0 -1.0 8.862760180332873e-05 1.3806577785135177e-06 -1.0 0.0001319677450153934 2.6866894852481906e-05 -1.0 0.11510120013926417 0.002672923773363389 1.2257360246712472e-05 8.544159282151438e-05 2.777791741571174e-05 0.0014957033281168012 0.0003257646134837451 0.0008919466185572302 1.2907171695294846e-13 4.6842350882367666e-05 0.01721806295736377 0.00025106741008066317 0.00022234471595443313 2.101790478097517e-09 5.752120832330886e-11 0.06428782790571179 3.2478301680021854e-08 0.4903495510314233 0.001146714816952061 0.0004777967757842694 1.0882011018684852e-06 0.05708498338352203 0.4981497862127628 -1.0 3.2790914744011534e-06 0.00010077009726691265 -1.0 2.210707325798542e-07 4.3166052799897375e-05 -1.0 0.01825795827020865 0.0003182108781955478 3.8561696337086434e-05 1.0995322456277382e-06 9.53380658669839e-06 0.001550036616828061 0.0012648333883989995 5.272021975060514e-06 1.9257248009114363e-05 0.00016757997590048827 0.11891251244906934 5.515522196186723e-06 0.01102706140784316 9.904481358675478e-13 3.520674728719278e-05 0.011294708566804167 7.239087311622819e-08 -1.0 3.5740607788414942e-06 0.00035983547999740665 1.0588257623722672e-07 0.42372713683725016 0.0011273340972061078 8.582011716859219e-15 1.1514579117272292e-10 0.00043130977711323417 0.0027847329307350423 0.00017287873387910357 6.401055165502384e-06 1.722191123879782e-08 0.00020848309220162036 0.05639071613735579 1.8064550990294753e-05 1.289814511028015e-06 1.078687446476881e-14 0.4897735047310072 0.0002981891705231209 0.00016079768514218546 9.332371598523186e-05 0.011724714376848187 0.019040707071165303 0.00014242053195529864 0.06684484191345574 -1.0 + -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 -10.0 0.6827568359008944 0.0017329528628152924 0.18541112907970003 0.11113024641218336 0.0008760419353035269 0.0008168081568291806 0.004669378458601891 4.952432605379829 2.2512327083641864e-09 4.625859206051786e-06 0.00027044817176109554 0.5490281661912204 0.0014126153603265096 8.304845400451923e-07 0.00022950716170641464 0.001335621430311088 0.03432919201293737 0.0051970818427099184 5.726152701849347e-15 -10.0 0.013332554437480326 4.346984808472855 7.6915277818290365e-16 0.0011042047857307254 3.0571050855707086e-05 -10.0 4.986698316296507e-05 0.11128424196387618 0.000131063355181338 5.447493368067179e-09 0.11440381012864086 4.670673837764874e-07 1.2364069326350118 0.0012558879474108074 0.0003136829920007009 0.000234750482787598 0.01537590300149361 0.01769327994909422 0.0006717625881826168 4.587143797469485e-07 0.000262112392467961 0.0030002326388383245 0.1729816946709781 4.5757238372058235e-10 0.0006922962992428139 3.792209399652396e-05 -10.0 0.0009256616392487858 8.541606727879512e-06 -10.0 4.931708164307665 0.5500108683629957 0.00012980629616179268 0.006870228272606287 0.008231482263927564 5.0 3.419181071650816e-05 0.6433819434431045 6.574706543646946e-15 4.0404626147344005e-12 0.003782322077390033 0.0012637534695610975 0.17602971074583987 0.00010044390728858278 -10.0 0.008787411098754914 0.002368681880710174 0.00930449789620512 0.0006949587369646498 0.0012918433677593976 2.0707648529746893e-05 0.023295401596005315 1.1819165666519222 -10.0 0.00021606550732170693 0.0022057970761624767 -10.0 1.0325207105027347e-07 0.0020293965453828133 2.123498061876322e-12 -10.0 0.0024175998138228046 0.01178616843705956 0.0013998074566164962 0.03881102561422506 0.011076796092102187 0.0010814452764860557 0.10955637485319249 -10.0 9.382800796426367e-16 0.0005098747893974248 0.0027052054298385255 0.0021305826462238594 0.00808100901275472 4.233410073487772e-05 0.0515132921322595 8.61602729455546e-06 4.873897581604287 0.0002909334597507523 0.0046958956846326495 -10.0 -10.0 0.1780262484403569 1.3116807133030034e-14 2.6178780551069492e-15 0.1884234453311008 -10.0 2.027381220364608e-15 0.004299195570308035 0.00014628847959717226 4.899952354672477 2.774067049392004e-06 0.04441328419270369 4.279460329782799e-08 0.012297303081805393 0.002792896409558745 0.006934466049804711 0.0008370896020975689 3.8270536025799805e-14 -10.0 0.1208261392046878 0.001497958445994315 0.015016500045374082 0.05384625561469684 0.0025519632243117644 0.011028020390507681 0.002362355168421952 -10.0 -10.0 0.0008862760180332873 1.3806577785135176e-05 -10.0 0.001319677450153934 0.00026866894852481903 -10.0 1.1510120013926417 0.026729237733633893 0.00012257360246712473 0.0008544159282151438 0.0002777791741571174 0.014957033281168012 0.0032576461348374514 0.008919466185572301 1.2907171695294846e-12 0.00046842350882367664 0.17218062957363772 0.0025106741008066318 0.0022234471595443312 2.101790478097517e-08 5.752120832330886e-10 0.6428782790571179 3.2478301680021856e-07 4.903495510314233 0.01146714816952061 0.004777967757842694 1.0882011018684853e-05 0.5708498338352204 4.981497862127628 -10.0 3.279091474401153e-05 0.0010077009726691265 -10.0 2.210707325798542e-06 0.00043166052799897375 -10.0 0.1825795827020865 0.0031821087819554777 0.00038561696337086434 1.0995322456277382e-05 9.53380658669839e-05 0.01550036616828061 0.012648333883989995 5.272021975060514e-05 0.00019257248009114364 0.0016757997590048828 1.1891251244906933 5.515522196186723e-05 0.1102706140784316 9.904481358675478e-12 0.0003520674728719278 0.11294708566804167 7.239087311622819e-07 -10.0 3.574060778841494e-05 0.0035983547999740664 1.0588257623722672e-06 4.237271368372502 0.011273340972061077 8.582011716859219e-14 1.151457911727229e-09 0.004313097771132342 0.027847329307350423 0.0017287873387910357 6.401055165502385e-05 1.722191123879782e-07 0.0020848309220162036 0.5639071613735579 0.00018064550990294753 1.289814511028015e-05 1.078687446476881e-13 4.897735047310072 0.002981891705231209 0.0016079768514218546 0.0009332371598523186 0.11724714376848187 0.19040707071165303 0.0014242053195529865 0.6684484191345574 -10.0 + 3 + 1.5 + 10 + 1e-38 + + 200 + + + + 5 10 15 + -240 -240 -240 + 240 240 240 + + + 1 + + + 0.0 0.5 20000000.0 + + + neutron photon + + + 1 2 3 + flux + + + diff --git a/tests/regression_tests/weightwindows/results_true.dat b/tests/regression_tests/weightwindows/results_true.dat new file mode 100644 index 00000000000..6c05af31aa3 --- /dev/null +++ b/tests/regression_tests/weightwindows/results_true.dat @@ -0,0 +1 @@ +ebc761815175b25fc95a226174928c226a3ab5dbf3b2a2abf09e079a0b87dee1dee74aa9b9eaec35acd58b8c481d264be7e9b3f052905bcc14ccd76f36b01549 \ No newline at end of file diff --git a/tests/regression_tests/weightwindows/test.py b/tests/regression_tests/weightwindows/test.py new file mode 100644 index 00000000000..9ed8559760f --- /dev/null +++ b/tests/regression_tests/weightwindows/test.py @@ -0,0 +1,174 @@ +from copy import deepcopy +import pytest +import numpy as np + +import openmc +from openmc.stats import Discrete, Point + +from tests.testing_harness import HashedPyAPITestHarness + + +@pytest.fixture +def model(): + model = openmc.Model() + + # materials (M4 steel alloy) + m4 = openmc.Material() + m4.set_density('g/cc', 2.3) + m4.add_nuclide('H1', 0.168018676) + m4.add_nuclide("H2", 1.93244e-05) + m4.add_nuclide("O16", 0.561814465) + m4.add_nuclide("O17", 0.00021401) + m4.add_nuclide("Na23", 0.021365) + m4.add_nuclide("Al27", 0.021343) + m4.add_nuclide("Si28", 0.187439342) + m4.add_nuclide("Si29", 0.009517714) + m4.add_nuclide("Si30", 0.006273944) + m4.add_nuclide("Ca40", 0.018026179) + m4.add_nuclide("Ca42", 0.00012031) + m4.add_nuclide("Ca43", 2.51033e-05) + m4.add_nuclide("Ca44", 0.000387892) + m4.add_nuclide("Ca46", 7.438e-07) + m4.add_nuclide("Ca48", 3.47727e-05) + m4.add_nuclide("Fe54", 0.000248179) + m4.add_nuclide("Fe56", 0.003895875) + m4.add_nuclide("Fe57", 8.99727e-05) + m4.add_nuclide("Fe58", 1.19737e-05) + + s0 = openmc.Sphere(r=240) + s1 = openmc.Sphere(r=250, boundary_type='vacuum') + + c0 = openmc.Cell(fill=m4, region=-s0) + c1 = openmc.Cell(region=+s0 & -s1) + + model.geometry = openmc.Geometry([c0, c1]) + + # settings + settings = model.settings + settings.run_mode = 'fixed source' + settings.particles = 200 + settings.batches = 2 + settings.max_splits = 200 + settings.photon_transport = True + space = Point((0.001, 0.001, 0.001)) + energy = Discrete([14E6], [1.0]) + + settings.source = openmc.IndependentSource(space=space, energy=energy) + + # tally + mesh = openmc.RegularMesh() + mesh.lower_left = (-240, -240, -240) + mesh.upper_right = (240, 240, 240) + mesh.dimension = (5, 10, 15) + + mesh_filter = openmc.MeshFilter(mesh) + + e_bnds = [0.0, 0.5, 2E7] + energy_filter = openmc.EnergyFilter(e_bnds) + + particle_filter = openmc.ParticleFilter(['neutron', 'photon']) + + tally = openmc.Tally() + tally.filters = [mesh_filter, energy_filter, particle_filter] + tally.scores = ['flux'] + + model.tallies.append(tally) + + # weight windows + + # load pre-generated weight windows + # (created using the same tally as above) + ww_n_lower_bnds = np.loadtxt('ww_n.txt') + ww_p_lower_bnds = np.loadtxt('ww_p.txt') + + # create a mesh matching the one used + # to generate the weight windows + ww_mesh = openmc.RegularMesh() + ww_mesh.lower_left = (-240, -240, -240) + ww_mesh.upper_right = (240, 240, 240) + ww_mesh.dimension = (5, 6, 7) + + ww_n = openmc.WeightWindows(ww_mesh, + ww_n_lower_bnds, + None, + 10.0, + e_bnds, + max_lower_bound_ratio=1.5) + + ww_p = openmc.WeightWindows(ww_mesh, + ww_p_lower_bnds, + None, + 10.0, + e_bnds, + max_lower_bound_ratio=1.5) + + model.settings.weight_windows = [ww_n, ww_p] + + return model + + +def test_weightwindows(model): + test = HashedPyAPITestHarness('statepoint.2.h5', model) + test.main() + + +def test_wwinp_cylindrical(): + + ww = openmc.wwinp_to_wws('ww_n_cyl.txt')[0] + + mesh = ww.mesh + + assert mesh.dimension == (8, 8, 7) + + # make sure that the mesh grids are correct + exp_r_grid = np.hstack((np.linspace(0.0, 3.02, 3, endpoint=False), + np.linspace(3.02, 6.0001, 6))).flatten() + + exp_phi_grid = np.hstack((np.linspace(0.0, 0.25, 2, endpoint=False), + np.linspace(0.25, 1.5707, 1, endpoint=False), + np.linspace(1.5707, 3.1415, 2, endpoint=False), + np.linspace(3.1415, 4.7124, 4))).flatten() + + exp_z_grid = np.hstack((np.linspace(0.0, 8.008, 4, endpoint=False), + np.linspace(8.008, 14.002, 4))).flatten() + + assert isinstance(mesh, openmc.CylindricalMesh) + + np.testing.assert_equal(mesh.r_grid, exp_r_grid) + np.testing.assert_equal(mesh.phi_grid, exp_phi_grid) + np.testing.assert_equal(mesh.z_grid, exp_z_grid) + np.testing.assert_equal(mesh.origin, (0, 0, -9.0001)) + assert ww.lower_ww_bounds.flat[0] == 0.0 + assert ww.lower_ww_bounds.flat[-1] == np.prod(mesh.dimension) - 1 + + +def test_wwinp_spherical(): + + ww = openmc.wwinp_to_wws('ww_n_sph.txt')[0] + + mesh = ww.mesh + + assert mesh.dimension == (8, 7, 8) + + # make sure that the mesh grids are correct + exp_r_grid = np.hstack((np.linspace(0.0, 3.02, 3, endpoint=False), + np.linspace(3.02, 6.0001, 6))).flatten() + + exp_theta_grid = np.hstack((np.linspace(0.0, 0.25, 2, endpoint=False), + np.linspace(0.25, 0.5, 1, endpoint=False), + np.linspace(0.5, 0.75, 2, endpoint=False), + np.linspace(0.75, 1.5707, 3))).flatten() + + exp_phi_grid = np.hstack((np.linspace(0.0, 0.25, 2, endpoint=False), + np.linspace(0.25, 0.5, 1, endpoint=False), + np.linspace(0.5, 1.5707, 2, endpoint=False), + np.linspace(1.5707, 3.1415, 4))).flatten() + + assert isinstance(mesh, openmc.SphericalMesh) + + np.testing.assert_equal(mesh.r_grid, exp_r_grid) + np.testing.assert_equal(mesh.theta_grid, exp_theta_grid) + np.testing.assert_equal(mesh.phi_grid, exp_phi_grid) + np.testing.assert_equal(mesh.origin, (0, 0, -9.0001)) + assert ww.lower_ww_bounds.flat[0] == 0.0 + assert ww.lower_ww_bounds.flat[-1] == np.prod(mesh.dimension) - 1 diff --git a/tests/regression_tests/weightwindows/ww_n.txt b/tests/regression_tests/weightwindows/ww_n.txt new file mode 100644 index 00000000000..dbb49537bde --- /dev/null +++ b/tests/regression_tests/weightwindows/ww_n.txt @@ -0,0 +1,420 @@ +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +7.695031155172815952e-14 +-1.000000000000000000e+00 +7.476545089278482294e-06 +-1.000000000000000000e+00 +2.161215042522170282e-06 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.136040178434497494e-18 +-1.000000000000000000e+00 +1.345534130616238158e-05 +-1.000000000000000000e+00 +3.353295403842037074e-05 +-1.000000000000000000e+00 +3.016075845432365699e-07 +-1.000000000000000000e+00 +1.026243155073153453e-13 +-1.000000000000000000e+00 +1.685921961405802360e-19 +-1.000000000000000000e+00 +3.853097455417877125e-06 +-1.000000000000000000e+00 +4.354946981329799215e-05 +-1.000000000000000000e+00 +7.002861620919231721e-08 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +1.620506488302619488e-11 +-1.000000000000000000e+00 +1.704166922479738429e-09 +-1.000000000000000000e+00 +1.874782466747863741e-14 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +5.619835883512352867e-14 +-1.000000000000000000e+00 +1.951356547084204088e-15 +-1.000000000000000000e+00 +8.481761456712739755e-10 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +1.450826207325665860e-13 +-1.000000000000000000e+00 +4.109066205029878035e-05 +-1.000000000000000000e+00 +2.057318145024078612e-04 +-1.000000000000000000e+00 +2.124999182004654892e-05 +-1.000000000000000000e+00 +5.537915413446233643e-08 +-1.000000000000000000e+00 +1.555045595917848555e-06 +-1.000000000000000000e+00 +7.213722022489493227e-04 +-1.000000000000000000e+00 +7.673145137236566868e-03 +-1.000000000000000000e+00 +8.175033526488423340e-04 +-1.000000000000000000e+00 +1.008394964750946906e-06 +-1.000000000000000000e+00 +6.848642863465584904e-07 +-1.000000000000000000e+00 +1.073708183250235556e-03 +-1.000000000000000000e+00 +7.197662162700776967e-03 +-1.000000000000000000e+00 +7.151459162818185784e-04 +-1.000000000000000000e+00 +2.253382683081525085e-06 +-1.000000000000000000e+00 +1.318156235244509166e-10 +-1.000000000000000000e+00 +1.938470818929409920e-05 +-1.000000000000000000e+00 +4.602961711512755646e-04 +-1.000000000000000000e+00 +2.562906833044621533e-05 +-1.000000000000000000e+00 +5.504813693036932910e-12 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +3.316482534950376351e-16 +-1.000000000000000000e+00 +3.937160538176268057e-07 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +1.517291205731239772e-14 +-1.000000000000000000e+00 +6.315154082213375425e-07 +-1.000000000000000000e+00 +3.855884234344844889e-06 +-1.000000000000000000e+00 +1.777013641125591191e-05 +-1.000000000000000000e+00 +1.642149199375171522e-11 +-1.000000000000000000e+00 +5.976538141107809983e-06 +-1.000000000000000000e+00 +1.959411999677113103e-03 +-1.000000000000000000e+00 +1.333061985337931354e-02 +-1.000000000000000000e+00 +1.795061316935990395e-03 +-1.000000000000000000e+00 +2.430637569372220458e-06 +-1.000000000000000000e+00 +6.922231352729155390e-05 +-1.000000000000000000e+00 +8.657573566388353237e-02 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +8.356487100743359431e-02 +-1.000000000000000000e+00 +1.641903115049591277e-04 +-1.000000000000000000e+00 +9.031085518264690009e-05 +-1.000000000000000000e+00 +8.488729673818780352e-02 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +8.288806458368344621e-02 +-1.000000000000000000e+00 +5.694959706678497628e-05 +-1.000000000000000000e+00 +8.037131813528500897e-07 +-1.000000000000000000e+00 +1.663712654332187308e-03 +-1.000000000000000000e+00 +1.664109232689093068e-02 +-1.000000000000000000e+00 +1.832759343760799985e-03 +-1.000000000000000000e+00 +6.542700644645626997e-07 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +6.655926357459274907e-08 +-1.000000000000000000e+00 +5.783974359937856763e-06 +-1.000000000000000000e+00 +2.679340942769232109e-06 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.104060901286513389e-05 +-1.000000000000000000e+00 +2.928209794781622450e-05 +-1.000000000000000000e+00 +1.284759166582201940e-05 +-1.000000000000000000e+00 +1.009290508315880392e-11 +-1.000000000000000000e+00 +1.322801376552501482e-05 +-1.000000000000000000e+00 +7.136750029575815620e-03 +-1.000000000000000000e+00 +6.539005235506369085e-02 +-1.000000000000000000e+00 +6.480331412016533503e-03 +-1.000000000000000000e+00 +2.601178739391680563e-06 +-1.000000000000000000e+00 +8.887234042637683843e-05 +-1.000000000000000000e+00 +5.000000000000000000e-01 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +4.877856021170283163e-01 +-1.000000000000000000e+00 +1.769985835774446302e-04 +-1.000000000000000000e+00 +1.670700632870335029e-04 +-1.000000000000000000e+00 +4.899999304038166192e-01 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +4.857384221387814338e-01 +-1.000000000000000000e+00 +2.153456869915780514e-04 +-1.000000000000000000e+00 +7.842896894949250204e-06 +-1.000000000000000000e+00 +6.379065450759913505e-03 +-1.000000000000000000e+00 +6.550426960512012453e-02 +-1.000000000000000000e+00 +6.639379668946672301e-03 +-1.000000000000000000e+00 +7.754700849337902260e-06 +-1.000000000000000000e+00 +2.720743316579670241e-11 +-1.000000000000000000e+00 +5.985108617124988932e-06 +-1.000000000000000000e+00 +3.634644995026691954e-05 +-1.000000000000000000e+00 +3.932389299316284718e-06 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +1.271128669411294917e-07 +-1.000000000000000000e+00 +8.846493399850662704e-06 +-1.000000000000000000e+00 +2.499931357628383163e-07 +-1.000000000000000000e+00 +8.533030345699353466e-17 +-1.000000000000000000e+00 +1.669925427773410862e-06 +-1.000000000000000000e+00 +1.754138009689378778e-03 +-1.000000000000000000e+00 +1.514897842827161306e-02 +-1.000000000000000000e+00 +1.627979455242757438e-03 +-1.000000000000000000e+00 +2.380955631371225994e-06 +-1.000000000000000000e+00 +2.164891804046736287e-05 +-1.000000000000000000e+00 +8.339317973815890683e-02 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +8.285899874014539257e-02 +-1.000000000000000000e+00 +2.762955748645507000e-05 +-1.000000000000000000e+00 +5.116174051620571477e-05 +-1.000000000000000000e+00 +8.095280568305474045e-02 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +8.636569925236790846e-02 +-1.000000000000000000e+00 +3.452537179033895228e-05 +-1.000000000000000000e+00 +3.598103176641614321e-06 +-1.000000000000000000e+00 +1.570829313580840913e-03 +-1.000000000000000000e+00 +1.621821782442112170e-02 +-1.000000000000000000e+00 +1.544782399547004175e-03 +-1.000000000000000000e+00 +7.989579285134733983e-06 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.594951085377587857e-06 +-1.000000000000000000e+00 +4.323138781337962887e-05 +-1.000000000000000000e+00 +6.948292975998465777e-07 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.446945600849361415e-09 +-1.000000000000000000e+00 +9.041149893307805599e-07 +-1.000000000000000000e+00 +2.206099258062212484e-11 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +1.681305446488883933e-11 +-1.000000000000000000e+00 +7.091263906557290927e-05 +-1.000000000000000000e+00 +2.746424406288768276e-04 +-1.000000000000000000e+00 +1.285845570921339974e-05 +-1.000000000000000000e+00 +2.029521362171670568e-09 +-1.000000000000000000e+00 +1.291182719850037242e-08 +-1.000000000000000000e+00 +9.127050763987511325e-04 +-1.000000000000000000e+00 +7.385384405891665810e-03 +-1.000000000000000000e+00 +1.001943240150808675e-03 +-1.000000000000000000e+00 +1.080711295768550941e-05 +-1.000000000000000000e+00 +8.020767115181573972e-07 +-1.000000000000000000e+00 +9.252532821720597109e-04 +-1.000000000000000000e+00 +7.188410694198127913e-03 +-1.000000000000000000e+00 +7.245451610090619275e-04 +-1.000000000000000000e+00 +2.515735579020177281e-07 +-1.000000000000000000e+00 +1.482521919913335348e-12 +-1.000000000000000000e+00 +4.756872959630257218e-05 +-1.000000000000000000e+00 +2.668579837809080925e-04 +-1.000000000000000000e+00 +2.822627694453269613e-05 +-1.000000000000000000e+00 +5.182269672663266089e-10 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.936268747135548187e-14 +-1.000000000000000000e+00 +2.544728124173036570e-07 +-1.000000000000000000e+00 +3.898416671385980035e-08 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.639268952045578987e-10 +-1.000000000000000000e+00 +3.705151822008388643e-06 +-1.000000000000000000e+00 +1.133362760482367266e-09 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +1.229674726063540458e-06 +-1.000000000000000000e+00 +7.962899789920809096e-06 +-1.000000000000000000e+00 +8.211982683649991481e-09 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.563965686625045276e-06 +-1.000000000000000000e+00 +2.248761782893832567e-05 +-1.000000000000000000e+00 +3.279904588337207471e-06 +-1.000000000000000000e+00 +4.076762579823379031e-17 +-1.000000000000000000e+00 +1.547676923757129466e-14 +-1.000000000000000000e+00 +1.030567269874565733e-11 +-1.000000000000000000e+00 +1.957092814065688094e-05 +-1.000000000000000000e+00 +3.852324755037881526e-12 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.769723317139941641e-13 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 diff --git a/tests/regression_tests/weightwindows/ww_n_cyl.txt b/tests/regression_tests/weightwindows/ww_n_cyl.txt new file mode 100644 index 00000000000..89232628fa1 --- /dev/null +++ b/tests/regression_tests/weightwindows/ww_n_cyl.txt @@ -0,0 +1,88 @@ +1 1 1 16 +1 +8.0000 7.0000 8.0000 0.0000 0.0000 -9.0001 +2.0000 2.0000 4.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 2.0000 +0.0000 3.0000 3.0200 1.0000 5.0000 6.0001 +1.0000 +0.0000 4.0000 8.0080 1.0000 3.0000 14.002 +1.0000 +0.0000 2.0000 0.25000 1.0000 1.0000 1.57070 +1.0000 2.0000 3.1415 1.0000 3.0000 4.7124 +1.0000 +100.00 +0.000000 1.000000 2.000000 3.000000 4.000000 5.000000 +6.000000 7.000000 8.000000 9.000000 10.000000 11.000000 +12.000000 13.000000 14.000000 15.000000 16.000000 17.000000 +18.000000 19.000000 20.000000 21.000000 22.000000 23.000000 +24.000000 25.000000 26.000000 27.000000 28.000000 29.000000 +30.000000 31.000000 32.000000 33.000000 34.000000 35.000000 +36.000000 37.000000 38.000000 39.000000 40.000000 41.000000 +42.000000 43.000000 44.000000 45.000000 46.000000 47.000000 +48.000000 49.000000 50.000000 51.000000 52.000000 53.000000 +54.000000 55.000000 56.000000 57.000000 58.000000 59.000000 +60.000000 61.000000 62.000000 63.000000 64.000000 65.000000 +66.000000 67.000000 68.000000 69.000000 70.000000 71.000000 +72.000000 73.000000 74.000000 75.000000 76.000000 77.000000 +78.000000 79.000000 80.000000 81.000000 82.000000 83.000000 +84.000000 85.000000 86.000000 87.000000 88.000000 89.000000 +90.000000 91.000000 92.000000 93.000000 94.000000 95.000000 +96.000000 97.000000 98.000000 99.000000 100.000000 101.000000 +102.000000 103.000000 104.000000 105.000000 106.000000 107.000000 +108.000000 109.000000 110.000000 111.000000 112.000000 113.000000 +114.000000 115.000000 116.000000 117.000000 118.000000 119.000000 +120.000000 121.000000 122.000000 123.000000 124.000000 125.000000 +126.000000 127.000000 128.000000 129.000000 130.000000 131.000000 +132.000000 133.000000 134.000000 135.000000 136.000000 137.000000 +138.000000 139.000000 140.000000 141.000000 142.000000 143.000000 +144.000000 145.000000 146.000000 147.000000 148.000000 149.000000 +150.000000 151.000000 152.000000 153.000000 154.000000 155.000000 +156.000000 157.000000 158.000000 159.000000 160.000000 161.000000 +162.000000 163.000000 164.000000 165.000000 166.000000 167.000000 +168.000000 169.000000 170.000000 171.000000 172.000000 173.000000 +174.000000 175.000000 176.000000 177.000000 178.000000 179.000000 +180.000000 181.000000 182.000000 183.000000 184.000000 185.000000 +186.000000 187.000000 188.000000 189.000000 190.000000 191.000000 +192.000000 193.000000 194.000000 195.000000 196.000000 197.000000 +198.000000 199.000000 200.000000 201.000000 202.000000 203.000000 +204.000000 205.000000 206.000000 207.000000 208.000000 209.000000 +210.000000 211.000000 212.000000 213.000000 214.000000 215.000000 +216.000000 217.000000 218.000000 219.000000 220.000000 221.000000 +222.000000 223.000000 224.000000 225.000000 226.000000 227.000000 +228.000000 229.000000 230.000000 231.000000 232.000000 233.000000 +234.000000 235.000000 236.000000 237.000000 238.000000 239.000000 +240.000000 241.000000 242.000000 243.000000 244.000000 245.000000 +246.000000 247.000000 248.000000 249.000000 250.000000 251.000000 +252.000000 253.000000 254.000000 255.000000 256.000000 257.000000 +258.000000 259.000000 260.000000 261.000000 262.000000 263.000000 +264.000000 265.000000 266.000000 267.000000 268.000000 269.000000 +270.000000 271.000000 272.000000 273.000000 274.000000 275.000000 +276.000000 277.000000 278.000000 279.000000 280.000000 281.000000 +282.000000 283.000000 284.000000 285.000000 286.000000 287.000000 +288.000000 289.000000 290.000000 291.000000 292.000000 293.000000 +294.000000 295.000000 296.000000 297.000000 298.000000 299.000000 +300.000000 301.000000 302.000000 303.000000 304.000000 305.000000 +306.000000 307.000000 308.000000 309.000000 310.000000 311.000000 +312.000000 313.000000 314.000000 315.000000 316.000000 317.000000 +318.000000 319.000000 320.000000 321.000000 322.000000 323.000000 +324.000000 325.000000 326.000000 327.000000 328.000000 329.000000 +330.000000 331.000000 332.000000 333.000000 334.000000 335.000000 +336.000000 337.000000 338.000000 339.000000 340.000000 341.000000 +342.000000 343.000000 344.000000 345.000000 346.000000 347.000000 +348.000000 349.000000 350.000000 351.000000 352.000000 353.000000 +354.000000 355.000000 356.000000 357.000000 358.000000 359.000000 +360.000000 361.000000 362.000000 363.000000 364.000000 365.000000 +366.000000 367.000000 368.000000 369.000000 370.000000 371.000000 +372.000000 373.000000 374.000000 375.000000 376.000000 377.000000 +378.000000 379.000000 380.000000 381.000000 382.000000 383.000000 +384.000000 385.000000 386.000000 387.000000 388.000000 389.000000 +390.000000 391.000000 392.000000 393.000000 394.000000 395.000000 +396.000000 397.000000 398.000000 399.000000 400.000000 401.000000 +402.000000 403.000000 404.000000 405.000000 406.000000 407.000000 +408.000000 409.000000 410.000000 411.000000 412.000000 413.000000 +414.000000 415.000000 416.000000 417.000000 418.000000 419.000000 +420.000000 421.000000 422.000000 423.000000 424.000000 425.000000 +426.000000 427.000000 428.000000 429.000000 430.000000 431.000000 +432.000000 433.000000 434.000000 435.000000 436.000000 437.000000 +438.000000 439.000000 440.000000 441.000000 442.000000 443.000000 +444.000000 445.000000 446.000000 447.000000 diff --git a/tests/regression_tests/weightwindows/ww_n_sph.txt b/tests/regression_tests/weightwindows/ww_n_sph.txt new file mode 100644 index 00000000000..3f9b8dab6d2 --- /dev/null +++ b/tests/regression_tests/weightwindows/ww_n_sph.txt @@ -0,0 +1,89 @@ +1 1 1 16 +1 +8.0000 7.0000 8.0000 0.0000 0.0000 -9.0001 +2.0000 4.0000 4.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 3.0000 +0.0000 3.0000 3.0200 1.0000 5.0000 6.0001 +1.0000 +0.0000 2.0000 0.25000 1.0000 1.0000 0.50000 +1.0000 2.0000 0.75000 1.0000 2.0000 1.5707 +1.0000 +0.0000 2.0000 0.25000 1.0000 1.0000 0.50000 +1.0000 2.0000 1.5707 1.0000 3.0000 3.1415 +1.0000 +100.00 +0.000000 1.000000 2.000000 3.000000 4.000000 5.000000 +6.000000 7.000000 8.000000 9.000000 10.000000 11.000000 +12.000000 13.000000 14.000000 15.000000 16.000000 17.000000 +18.000000 19.000000 20.000000 21.000000 22.000000 23.000000 +24.000000 25.000000 26.000000 27.000000 28.000000 29.000000 +30.000000 31.000000 32.000000 33.000000 34.000000 35.000000 +36.000000 37.000000 38.000000 39.000000 40.000000 41.000000 +42.000000 43.000000 44.000000 45.000000 46.000000 47.000000 +48.000000 49.000000 50.000000 51.000000 52.000000 53.000000 +54.000000 55.000000 56.000000 57.000000 58.000000 59.000000 +60.000000 61.000000 62.000000 63.000000 64.000000 65.000000 +66.000000 67.000000 68.000000 69.000000 70.000000 71.000000 +72.000000 73.000000 74.000000 75.000000 76.000000 77.000000 +78.000000 79.000000 80.000000 81.000000 82.000000 83.000000 +84.000000 85.000000 86.000000 87.000000 88.000000 89.000000 +90.000000 91.000000 92.000000 93.000000 94.000000 95.000000 +96.000000 97.000000 98.000000 99.000000 100.000000 101.000000 +102.000000 103.000000 104.000000 105.000000 106.000000 107.000000 +108.000000 109.000000 110.000000 111.000000 112.000000 113.000000 +114.000000 115.000000 116.000000 117.000000 118.000000 119.000000 +120.000000 121.000000 122.000000 123.000000 124.000000 125.000000 +126.000000 127.000000 128.000000 129.000000 130.000000 131.000000 +132.000000 133.000000 134.000000 135.000000 136.000000 137.000000 +138.000000 139.000000 140.000000 141.000000 142.000000 143.000000 +144.000000 145.000000 146.000000 147.000000 148.000000 149.000000 +150.000000 151.000000 152.000000 153.000000 154.000000 155.000000 +156.000000 157.000000 158.000000 159.000000 160.000000 161.000000 +162.000000 163.000000 164.000000 165.000000 166.000000 167.000000 +168.000000 169.000000 170.000000 171.000000 172.000000 173.000000 +174.000000 175.000000 176.000000 177.000000 178.000000 179.000000 +180.000000 181.000000 182.000000 183.000000 184.000000 185.000000 +186.000000 187.000000 188.000000 189.000000 190.000000 191.000000 +192.000000 193.000000 194.000000 195.000000 196.000000 197.000000 +198.000000 199.000000 200.000000 201.000000 202.000000 203.000000 +204.000000 205.000000 206.000000 207.000000 208.000000 209.000000 +210.000000 211.000000 212.000000 213.000000 214.000000 215.000000 +216.000000 217.000000 218.000000 219.000000 220.000000 221.000000 +222.000000 223.000000 224.000000 225.000000 226.000000 227.000000 +228.000000 229.000000 230.000000 231.000000 232.000000 233.000000 +234.000000 235.000000 236.000000 237.000000 238.000000 239.000000 +240.000000 241.000000 242.000000 243.000000 244.000000 245.000000 +246.000000 247.000000 248.000000 249.000000 250.000000 251.000000 +252.000000 253.000000 254.000000 255.000000 256.000000 257.000000 +258.000000 259.000000 260.000000 261.000000 262.000000 263.000000 +264.000000 265.000000 266.000000 267.000000 268.000000 269.000000 +270.000000 271.000000 272.000000 273.000000 274.000000 275.000000 +276.000000 277.000000 278.000000 279.000000 280.000000 281.000000 +282.000000 283.000000 284.000000 285.000000 286.000000 287.000000 +288.000000 289.000000 290.000000 291.000000 292.000000 293.000000 +294.000000 295.000000 296.000000 297.000000 298.000000 299.000000 +300.000000 301.000000 302.000000 303.000000 304.000000 305.000000 +306.000000 307.000000 308.000000 309.000000 310.000000 311.000000 +312.000000 313.000000 314.000000 315.000000 316.000000 317.000000 +318.000000 319.000000 320.000000 321.000000 322.000000 323.000000 +324.000000 325.000000 326.000000 327.000000 328.000000 329.000000 +330.000000 331.000000 332.000000 333.000000 334.000000 335.000000 +336.000000 337.000000 338.000000 339.000000 340.000000 341.000000 +342.000000 343.000000 344.000000 345.000000 346.000000 347.000000 +348.000000 349.000000 350.000000 351.000000 352.000000 353.000000 +354.000000 355.000000 356.000000 357.000000 358.000000 359.000000 +360.000000 361.000000 362.000000 363.000000 364.000000 365.000000 +366.000000 367.000000 368.000000 369.000000 370.000000 371.000000 +372.000000 373.000000 374.000000 375.000000 376.000000 377.000000 +378.000000 379.000000 380.000000 381.000000 382.000000 383.000000 +384.000000 385.000000 386.000000 387.000000 388.000000 389.000000 +390.000000 391.000000 392.000000 393.000000 394.000000 395.000000 +396.000000 397.000000 398.000000 399.000000 400.000000 401.000000 +402.000000 403.000000 404.000000 405.000000 406.000000 407.000000 +408.000000 409.000000 410.000000 411.000000 412.000000 413.000000 +414.000000 415.000000 416.000000 417.000000 418.000000 419.000000 +420.000000 421.000000 422.000000 423.000000 424.000000 425.000000 +426.000000 427.000000 428.000000 429.000000 430.000000 431.000000 +432.000000 433.000000 434.000000 435.000000 436.000000 437.000000 +438.000000 439.000000 440.000000 441.000000 442.000000 443.000000 +444.000000 445.000000 446.000000 447.000000 diff --git a/tests/regression_tests/weightwindows/ww_p.txt b/tests/regression_tests/weightwindows/ww_p.txt new file mode 100644 index 00000000000..09ff01ebd10 --- /dev/null +++ b/tests/regression_tests/weightwindows/ww_p.txt @@ -0,0 +1,420 @@ +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +5.447493368067179064e-10 +-1.000000000000000000e+00 +4.040462614734400249e-13 +-1.000000000000000000e+00 +9.382800796426366364e-17 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +5.752120832330885919e-11 +-1.000000000000000000e+00 +3.520674728719278012e-05 +-1.000000000000000000e+00 +8.760419353035269667e-05 +-1.000000000000000000e+00 +3.136829920007008993e-05 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +4.233410073487771971e-06 +-1.000000000000000000e+00 +2.551963224311764450e-04 +-1.000000000000000000e+00 +4.777967757842694024e-04 +-1.000000000000000000e+00 +3.598354799974066488e-04 +-1.000000000000000000e+00 +4.625859206051786618e-07 +-1.000000000000000000e+00 +4.587143797469485258e-08 +-1.000000000000000000e+00 +1.291843367759397518e-04 +-1.000000000000000000e+00 +4.695895684632649786e-04 +-1.000000000000000000e+00 +8.862760180332873163e-05 +-1.000000000000000000e+00 +3.279091474401153391e-06 +-1.000000000000000000e+00 +1.151457911727229161e-10 +-1.000000000000000000e+00 +2.295071617064146262e-05 +-1.000000000000000000e+00 +6.922962992428139458e-05 +-1.000000000000000000e+00 +2.160655073217069276e-05 +-1.000000000000000000e+00 +2.617878055106949035e-16 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +1.722191123879781983e-08 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.123498061876322157e-13 +-1.000000000000000000e+00 +1.462884795971722476e-05 +-1.000000000000000000e+00 +2.777791741571173956e-05 +-1.000000000000000000e+00 +9.533806586698390583e-06 +-1.000000000000000000e+00 +1.078687446476880940e-14 +-1.000000000000000000e+00 +3.057105085570708401e-06 +-1.000000000000000000e+00 +8.231482263927564300e-04 +-1.000000000000000000e+00 +3.881102561422505696e-03 +-1.000000000000000000e+00 +1.229730308180539307e-03 +-1.000000000000000000e+00 +4.684235088236766580e-05 +-1.000000000000000000e+00 +1.675799759004882713e-04 +-1.000000000000000000e+00 +1.172471437684818700e-02 +-1.000000000000000000e+00 +6.827568359008943932e-02 +-1.000000000000000000e+00 +1.144038101286408600e-02 +-1.000000000000000000e+00 +3.782322077390032930e-04 +-1.000000000000000000e+00 +5.098747893974247782e-05 +-1.000000000000000000e+00 +1.208261392046878005e-02 +-1.000000000000000000e+00 +6.428782790571178907e-02 +-1.000000000000000000e+00 +1.129470856680416663e-02 +-1.000000000000000000e+00 +8.168081568291806404e-05 +-1.000000000000000000e+00 +2.347504827875979927e-05 +-1.000000000000000000e+00 +8.787411098754914583e-04 +-1.000000000000000000e+00 +5.151329213225949548e-03 +-1.000000000000000000e+00 +1.102802039050768210e-03 +-1.000000000000000000e+00 +1.088201101868485208e-06 +-1.000000000000000000e+00 +1.058825762372267240e-07 +-1.000000000000000000e+00 +2.704481717610955638e-05 +-1.000000000000000000e+00 +2.621123924679610439e-05 +-1.000000000000000000e+00 +2.070764852974689408e-06 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +1.380657778513517658e-06 +-1.000000000000000000e+00 +1.007700972669126494e-04 +-1.000000000000000000e+00 +4.313097771132341687e-04 +-1.000000000000000000e+00 +1.335621430311087867e-04 +-1.000000000000000000e+00 +3.792209399652395984e-06 +-1.000000000000000000e+00 +2.205797076162476780e-04 +-1.000000000000000000e+00 +1.884234453311008084e-02 +-1.000000000000000000e+00 +1.151012001392641704e-01 +-1.000000000000000000e+00 +1.825795827020864834e-02 +-1.000000000000000000e+00 +2.084830922016203648e-04 +-1.000000000000000000e+00 +1.333255443748032664e-03 +-1.000000000000000000e+00 +4.931708164307664344e-01 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +4.899952354672477139e-01 +-1.000000000000000000e+00 +1.495703328116801227e-03 +-1.000000000000000000e+00 +1.550036616828060930e-03 +-1.000000000000000000e+00 +4.897735047310072254e-01 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +5.000000000000000000e-01 +-1.000000000000000000e+00 +1.107679609210218599e-03 +-1.000000000000000000e+00 +2.792896409558744781e-04 +-1.000000000000000000e+00 +1.721806295736377085e-02 +-1.000000000000000000e+00 +1.189125124490693353e-01 +-1.000000000000000000e+00 +1.904070707116530328e-02 +-1.000000000000000000e+00 +1.732952862815292309e-04 +-1.000000000000000000e+00 +4.670673837764873805e-08 +-1.000000000000000000e+00 +1.263753469561097525e-04 +-1.000000000000000000e+00 +2.705205429838525473e-04 +-1.000000000000000000e+00 +1.497958445994315019e-04 +-1.000000000000000000e+00 +3.247830168002185438e-08 +-1.000000000000000000e+00 +7.239087311622818554e-08 +-1.000000000000000000e+00 +4.669378458601891341e-04 +-1.000000000000000000e+00 +1.537590300149361015e-03 +-1.000000000000000000e+00 +2.368681880710174145e-04 +-1.000000000000000000e+00 +8.616027294555461632e-07 +-1.000000000000000000e+00 +2.362355168421952122e-04 +-1.000000000000000000e+00 +5.708498338352203244e-02 +-1.000000000000000000e+00 +4.237271368372501623e-01 +-1.000000000000000000e+00 +5.490281661912204542e-02 +-1.000000000000000000e+00 +3.000232638838324392e-04 +-1.000000000000000000e+00 +2.329540159600531311e-03 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.784732930735042255e-03 +-1.000000000000000000e+00 +3.432919201293736875e-03 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +2.672923773363389179e-03 +-1.000000000000000000e+00 +3.182108781955477806e-04 +-1.000000000000000000e+00 +5.639071613735578692e-02 +-1.000000000000000000e+00 +4.346984808472855177e-01 +-1.000000000000000000e+00 +5.500108683629956891e-02 +-1.000000000000000000e+00 +2.417599813822804812e-04 +-1.000000000000000000e+00 +2.774067049392004042e-07 +-1.000000000000000000e+00 +3.257646134837451210e-04 +-1.000000000000000000e+00 +1.264833388398999524e-03 +-1.000000000000000000e+00 +2.981891705231208794e-04 +-1.000000000000000000e+00 +4.986698316296506713e-06 +-1.000000000000000000e+00 +3.419181071650815928e-06 +-1.000000000000000000e+00 +1.081445276486055809e-04 +-1.000000000000000000e+00 +6.934466049804711161e-04 +-1.000000000000000000e+00 +2.510674100806631662e-04 +-1.000000000000000000e+00 +5.515522196186722918e-06 +-1.000000000000000000e+00 +1.424205319552986396e-04 +-1.000000000000000000e+00 +1.854111290797000322e-02 +-1.000000000000000000e+00 +1.236406932635011752e-01 +-1.000000000000000000e+00 +1.760297107458398680e-02 +-1.000000000000000000e+00 +2.130582646223859260e-04 +-1.000000000000000000e+00 +1.501650004537408200e-03 +-1.000000000000000000e+00 +4.903495510314233030e-01 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +4.952432605379828989e-01 +-1.000000000000000000e+00 +1.769327994909421784e-03 +-1.000000000000000000e+00 +9.304497896205120647e-04 +-1.000000000000000000e+00 +4.873897581604286766e-01 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +4.981497862127627907e-01 +-1.000000000000000000e+00 +1.127334097206107765e-03 +-1.000000000000000000e+00 +1.412615360326509664e-04 +-1.000000000000000000e+00 +1.729816946709781048e-02 +-1.000000000000000000e+00 +1.181916566651922268e-01 +-1.000000000000000000e+00 +1.780262484403568810e-02 +-1.000000000000000000e+00 +1.319677450153934042e-04 +-1.000000000000000000e+00 +2.210707325798542070e-07 +-1.000000000000000000e+00 +1.728787338791035720e-04 +-1.000000000000000000e+00 +5.197081842709918220e-04 +-1.000000000000000000e+00 +9.256616392487857544e-05 +-1.000000000000000000e+00 +1.032520710502734699e-08 +-1.000000000000000000e+00 +2.027381220364608057e-16 +-1.000000000000000000e+00 +1.225736024671247218e-05 +-1.000000000000000000e+00 +3.856169633708643398e-05 +-1.000000000000000000e+00 +1.806455099029475317e-05 +-1.000000000000000000e+00 +7.691527781829036254e-17 +-1.000000000000000000e+00 +1.298062961617926916e-05 +-1.000000000000000000e+00 +1.178616843705955963e-03 +-1.000000000000000000e+00 +4.441328419270368887e-03 +-1.000000000000000000e+00 +8.919466185572301909e-04 +-1.000000000000000000e+00 +5.272021975060514019e-06 +-1.000000000000000000e+00 +1.607976851421854571e-04 +-1.000000000000000000e+00 +1.112842419638761758e-02 +-1.000000000000000000e+00 +6.433819434431045647e-02 +-1.000000000000000000e+00 +1.095563748531924904e-02 +-1.000000000000000000e+00 +8.370896020975688591e-05 +-1.000000000000000000e+00 +2.223447159544331337e-04 +-1.000000000000000000e+00 +1.102706140784315975e-02 +-1.000000000000000000e+00 +6.684484191345574366e-02 +-1.000000000000000000e+00 +1.111302464121833623e-02 +-1.000000000000000000e+00 +1.255887947410807431e-04 +-1.000000000000000000e+00 +1.004439072885827748e-05 +-1.000000000000000000e+00 +8.081009012754719698e-04 +-1.000000000000000000e+00 +5.384625561469683769e-03 +-1.000000000000000000e+00 +1.146714816952060971e-03 +-1.000000000000000000e+00 +3.574060778841494232e-06 +-1.000000000000000000e+00 +2.251232708364186507e-10 +-1.000000000000000000e+00 +6.717625881826167172e-05 +-1.000000000000000000e+00 +6.949587369646497293e-05 +-1.000000000000000000e+00 +2.909334597507522605e-05 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +8.582011716859218622e-15 +-1.000000000000000000e+00 +8.304845400451923449e-08 +-1.000000000000000000e+00 +4.575723837205823402e-11 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +1.311680713303003522e-15 +-1.000000000000000000e+00 +2.686689485248190559e-05 +-1.000000000000000000e+00 +4.316605279989737501e-05 +-1.000000000000000000e+00 +6.401055165502384025e-06 +-1.000000000000000000e+00 +5.726152701849347207e-16 +-1.000000000000000000e+00 +8.541606727879512040e-07 +-1.000000000000000000e+00 +2.029396545382813118e-04 +-1.000000000000000000e+00 +4.299195570308034968e-04 +-1.000000000000000000e+00 +8.544159282151438236e-05 +-1.000000000000000000e+00 +1.099532245627738225e-06 +-1.000000000000000000e+00 +1.289814511028014912e-06 +-1.000000000000000000e+00 +1.104204785730725317e-04 +-1.000000000000000000e+00 +6.870228272606287295e-04 +-1.000000000000000000e+00 +1.399807456616496116e-04 +-1.000000000000000000e+00 +4.279460329782799377e-09 +-1.000000000000000000e+00 +1.290717169529484602e-13 +-1.000000000000000000e+00 +1.925724800911436302e-05 +-1.000000000000000000e+00 +9.332371598523186474e-05 +-1.000000000000000000e+00 +1.310633551813380206e-05 +-1.000000000000000000e+00 +6.574706543646946099e-16 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +-1.000000000000000000e+00 +3.827053602579980514e-15 +-1.000000000000000000e+00 +2.101790478097516960e-09 +-1.000000000000000000e+00 +9.904481358675477728e-13 +-1.000000000000000000e+00 +-1.000000000000000000e+00 diff --git a/tests/regression_tests/white_plane/results_true.dat b/tests/regression_tests/white_plane/results_true.dat index dea36920590..6f1d064eb36 100644 --- a/tests/regression_tests/white_plane/results_true.dat +++ b/tests/regression_tests/white_plane/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.279902E+00 3.262078E-03 +2.279719E+00 5.380792E-03 diff --git a/tests/test_matplotlib_import.py b/tests/test_matplotlib_import.py new file mode 100644 index 00000000000..d319976c453 --- /dev/null +++ b/tests/test_matplotlib_import.py @@ -0,0 +1,6 @@ +import sys +import openmc + +def test_matplotlib_presence(): + """Checks that matplotlib remains a deferred import""" + assert 'matplotlib' not in sys.modules diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 48f121d4598..81527452b84 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -1,11 +1,11 @@ from difflib import unified_diff +from subprocess import check_call import filecmp import glob +import h5py import hashlib -from optparse import OptionParser import os import shutil -import sys import numpy as np import openmc @@ -94,7 +94,7 @@ def _get_results(self, hash_output=False): # Write out k-combined. outstr += 'k-combined:\n' form = '{0:12.6E} {1:12.6E}\n' - outstr += form.format(sp.k_combined.n, sp.k_combined.s) + outstr += form.format(sp.keff.n, sp.keff.s) # Write out tally data. for i, tally_ind in enumerate(sp.tallies): @@ -115,6 +115,10 @@ def _get_results(self, hash_output=False): return outstr + @property + def statepoint_name(self): + return self._sp_name + def _write_results(self, results_string): """Write the results to an ASCII file.""" with open('results_test.dat', 'w') as fh: @@ -177,7 +181,7 @@ def _create_cmfd_result_str(self, cmfd_run): outstr += '\ncmfd openmc source comparison\n' outstr += '\n'.join(['{:.6E}'.format(x) for x in cmfd_run.src_cmp]) outstr += '\ncmfd source\n' - cmfdsrc = np.reshape(cmfd_run.cmfd_src, np.product(cmfd_run.indices), + cmfdsrc = np.reshape(cmfd_run.cmfd_src, np.prod(cmfd_run.indices), order='F') outstr += '\n'.join(['{:.6E}'.format(x) for x in cmfdsrc]) outstr += '\n' @@ -274,6 +278,13 @@ def _get_results(self): return outstr + def _cleanup(self): + """Delete particle restart files.""" + super()._cleanup() + output = glob.glob('particle*.h5') + for f in output: + os.remove(f) + class PyAPITestHarness(TestHarness): def __init__(self, statepoint_name, model=None, inputs_true=None): @@ -327,12 +338,11 @@ def update_results(self): def _build_inputs(self): """Write input XML files.""" - self._model.export_to_xml() + self._model.export_to_model_xml() def _get_inputs(self): """Return a hash digest of the input XML files.""" - xmls = ['geometry.xml', 'materials.xml', 'settings.xml', - 'tallies.xml', 'plots.xml'] + xmls = ['model.xml', 'plots.xml'] return ''.join([open(fname).read() for fname in xmls if os.path.exists(fname)]) @@ -362,7 +372,7 @@ def _cleanup(self): """Delete XMLs, statepoints, tally, and test files.""" super()._cleanup() output = ['materials.xml', 'geometry.xml', 'settings.xml', - 'tallies.xml', 'plots.xml', 'inputs_test.dat'] + 'tallies.xml', 'plots.xml', 'inputs_test.dat', 'model.xml'] for f in output: if os.path.exists(f): os.remove(f) @@ -372,3 +382,112 @@ class HashedPyAPITestHarness(PyAPITestHarness): def _get_results(self): """Digest info in the statepoint and return as a string.""" return super()._get_results(True) + + +class TolerantPyAPITestHarness(PyAPITestHarness): + """Specialized harness for running tests that involve significant levels + of floating point non-associativity when using shared memory parallelism + due to single precision usage (e.g., as in the random ray solver). + + """ + def _are_files_equal(self, actual_path, expected_path, tolerance): + def isfloat(value): + try: + float(value) + return True + except ValueError: + return False + + def tokenize(line): + return line.strip().split() + + def compare_tokens(token1, token2): + if isfloat(token1) and isfloat(token2): + float1, float2 = float(token1), float(token2) + return abs(float1 - float2) <= tolerance * max(abs(float1), abs(float2)) + else: + return token1 == token2 + + expected = open(expected_path).readlines() + actual = open(actual_path).readlines() + + if len(expected) != len(actual): + return False + + for line1, line2 in zip(expected, actual): + tokens1 = tokenize(line1) + tokens2 = tokenize(line2) + + if len(tokens1) != len(tokens2): + return False + + for token1, token2 in zip(tokens1, tokens2): + if not compare_tokens(token1, token2): + return False + + return True + + def _compare_results(self): + """Make sure the current results agree with the reference.""" + compare = self._are_files_equal('results_test.dat', 'results_true.dat', 1e-6) + if not compare: + expected = open('results_true.dat').readlines() + actual = open('results_test.dat').readlines() + diff = unified_diff(expected, actual, 'results_true.dat', + 'results_test.dat') + print('Result differences:') + print(''.join(colorize(diff))) + os.rename('results_test.dat', 'results_error.dat') + assert compare, 'Results do not agree' + + +class PlotTestHarness(TestHarness): + """Specialized TestHarness for running OpenMC plotting tests.""" + def __init__(self, plot_names, voxel_convert_checks=[]): + super().__init__(None) + self._plot_names = plot_names + self._voxel_convert_checks = voxel_convert_checks + + def _run_openmc(self): + openmc.plot_geometry(openmc_exec=config['exe']) + + # Check that voxel h5 can be converted to vtk + for voxel_h5_filename in self._voxel_convert_checks: + check_call(['../../../scripts/openmc-voxel-to-vtk'] + + glob.glob(voxel_h5_filename)) + + def _test_output_created(self): + """Make sure *.png has been created.""" + for fname in self._plot_names: + assert os.path.exists(fname), 'Plot output file does not exist.' + + def _cleanup(self): + super()._cleanup() + for fname in self._plot_names: + if os.path.exists(fname): + os.remove(fname) + + def _get_results(self): + """Return a string hash of the plot files.""" + outstr = bytes() + + for fname in self._plot_names: + if fname.endswith('.png'): + # Add PNG output to results + with open(fname, 'rb') as fh: + outstr += fh.read() + elif fname.endswith('.h5'): + # Add voxel data to results + with h5py.File(fname, 'r') as fh: + outstr += fh.attrs['filetype'] + outstr += fh.attrs['num_voxels'].tobytes() + outstr += fh.attrs['lower_left'].tobytes() + outstr += fh.attrs['voxel_width'].tobytes() + outstr += fh['data'][()].tobytes() + + # Hash the information and return. + sha512 = hashlib.sha512() + sha512.update(outstr) + outstr = sha512.hexdigest() + + return outstr diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 51d1b19a335..6041d898201 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -48,7 +48,7 @@ def sphere_model(): model.settings.particles = 100 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) return model diff --git a/tests/unit_tests/dagmc/broken_model.h5m b/tests/unit_tests/dagmc/broken_model.h5m new file mode 100644 index 00000000000..4bc6c7d4252 Binary files /dev/null and b/tests/unit_tests/dagmc/broken_model.h5m differ diff --git a/tests/unit_tests/dagmc/test.py b/tests/unit_tests/dagmc/test.py index e5d7725551e..e84b5317ede 100644 --- a/tests/unit_tests/dagmc/test.py +++ b/tests/unit_tests/dagmc/test.py @@ -1,6 +1,7 @@ import shutil import numpy as np +from pathlib import Path import pytest import openmc @@ -26,10 +27,21 @@ def dagmc_model(request): model.settings.verbosity = 1 source_box = openmc.stats.Box([ -4, -4, -4 ], [ 4, 4, 4 ]) - source = openmc.Source(space=source_box) + source = openmc.IndependentSource(space=source_box) model.settings.source = source - model.settings.dagmc = True + # geometry + dagmc_file = Path(request.fspath).parent / 'dagmc.h5m' + dagmc_universe = openmc.DAGMCUniverse(dagmc_file) + model.geometry = openmc.Geometry(dagmc_universe) + + # check number of surfaces and volumes for this pincell model there should + # be 5 volumes: two fuel regions, water, graveyard, implicit complement (the + # implicit complement cell is created automatically at runtime) + # and 21 surfaces: 3 cylinders (9 surfaces) and a bounding cubic shell + # (12 surfaces) + assert dagmc_universe.n_cells == 5 + assert dagmc_universe.n_surfaces == 21 # tally tally = openmc.Tally() diff --git a/tests/unit_tests/dagmc/test_bounds.py b/tests/unit_tests/dagmc/test_bounds.py new file mode 100644 index 00000000000..35e1dd3403f --- /dev/null +++ b/tests/unit_tests/dagmc/test_bounds.py @@ -0,0 +1,97 @@ +import openmc +import pytest +from pathlib import Path + + +def test_bounding_box(request): + """Checks that the DAGMCUniverse.bounding_box returns the correct values""" + + u = openmc.DAGMCUniverse(Path(request.fspath).parent / "dagmc.h5m") + + ll, ur = u.bounding_box + assert ll == pytest.approx((-25.0, -25.0, -25)) + assert ur == pytest.approx((25.0, 25.0, 25)) + + +def test_bounding_region(request): + """Checks that the DAGMCUniverse.bounding_region() returns a region with + correct surfaces and boundary types""" + + u = openmc.DAGMCUniverse(Path(request.fspath).parent / "dagmc.h5m") + + region = u.bounding_region() # should default to bounded_type='box' + assert isinstance(region, openmc.Region) + assert len(region) == 6 + assert region[0].surface.type == "x-plane" + assert region[0].surface.x0 == -25. + assert region[1].surface.type == "x-plane" + assert region[1].surface.x0 == 25. + assert region[2].surface.type == "y-plane" + assert region[2].surface.y0 == -25. + assert region[3].surface.type == "y-plane" + assert region[3].surface.y0 == 25. + assert region[4].surface.type == "z-plane" + assert region[4].surface.z0 == -25. + assert region[5].surface.type == "z-plane" + assert region[5].surface.z0 == 25. + assert region[0].surface.boundary_type == "vacuum" + assert region[1].surface.boundary_type == "vacuum" + assert region[2].surface.boundary_type == "vacuum" + assert region[3].surface.boundary_type == "vacuum" + assert region[4].surface.boundary_type == "vacuum" + assert region[5].surface.boundary_type == "vacuum" + region = u.bounding_region(padding_distance=5) + assert region[0].surface.x0 == -30. + assert region[1].surface.x0 == 30. + assert region[2].surface.y0 == -30. + assert region[3].surface.y0 == 30. + assert region[4].surface.z0 == -30. + assert region[5].surface.z0 == 30. + + region = u.bounding_region(bounded_type="sphere", boundary_type="reflective") + assert isinstance(region, openmc.Region) + assert isinstance(region, openmc.Halfspace) + assert region.surface.type == "sphere" + assert region.surface.boundary_type == "reflective" + larger_region = u.bounding_region(bounded_type="sphere", padding_distance=10) + assert larger_region.surface.r > region.surface.r + + +def test_bounded_universe(request): + """Checks that the DAGMCUniverse.bounded_universe() returns a + openmc.Universe with correct surface ids and cell ids""" + + u = openmc.DAGMCUniverse(Path(request.fspath).parent / "dagmc.h5m") + + # bounded with defaults + bu = u.bounded_universe() + + cells = list(bu.get_all_cells().items()) + assert isinstance(bu, openmc.Universe) + assert len(cells) == 1 + assert cells[0][0] == 10000 # default bounding_cell_id is 10000 + assert cells[0][1].id == 10000 # default bounding_cell_id is 10000 + surfaces = list(cells[0][1].region.get_surfaces().items()) + assert len(surfaces) == 6 + assert surfaces[0][1].id == 10000 + + # bounded with non defaults + bu = u.bounded_universe(bounding_cell_id=42, bounded_type="sphere", starting_id=43) + + cells = list(bu.get_all_cells().items()) + assert isinstance(bu, openmc.Universe) + assert len(cells) == 1 + assert cells[0][0] == 42 # default bounding_cell_id is 10000 + assert cells[0][1].id == 42 # default bounding_cell_id is 10000 + surfaces = list(cells[0][1].region.get_surfaces().items()) + assert surfaces[0][1].type == "sphere" + assert surfaces[0][1].id == 43 + + +def test_material_names(request): + """Checks that the DAGMCUniverse.material_names() returns a list of the + name present in the dagmc.h5m file in the expected order""" + + u = openmc.DAGMCUniverse(Path(request.fspath).parent / "dagmc.h5m") + + assert u.material_names == ['41', 'Graveyard', 'no-void fuel'] diff --git a/tests/unit_tests/dagmc/test_h5m_subdir.py b/tests/unit_tests/dagmc/test_h5m_subdir.py new file mode 100644 index 00000000000..dd9c6b043b6 --- /dev/null +++ b/tests/unit_tests/dagmc/test_h5m_subdir.py @@ -0,0 +1,40 @@ +import shutil +from pathlib import Path + +import openmc +import openmc.lib +import pytest + +pytestmark = pytest.mark.skipif( + not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled." +) + + +@pytest.mark.parametrize("absolute", [True, False]) +def test_model_h5m_in_subdirectory(run_in_tmpdir, request, absolute): + # Create new subdirectory and copy h5m file there + h5m = Path(request.fspath).parent / "dagmc.h5m" + subdir = Path("h5m") + subdir.mkdir() + shutil.copy(h5m, subdir) + + # Create simple model with h5m file in subdirectory + if absolute: + dag_univ = openmc.DAGMCUniverse((subdir / "dagmc.h5m").absolute()) + else: + dag_univ = openmc.DAGMCUniverse(subdir / "dagmc.h5m") + model = openmc.Model() + model.geometry = openmc.Geometry(dag_univ.bounded_universe()) + mat1 = openmc.Material(name="41") + mat1.add_nuclide("H1", 1.0) + mat2 = openmc.Material(name="no-void fuel") + mat2.add_nuclide("U235", 1.0) + model.materials = [mat1, mat2] + model.settings.batches = 10 + model.settings.inactive = 5 + model.settings.particles = 1000 + + # Make sure model can load + model.export_to_model_xml() + openmc.lib.init(["model.xml"]) + openmc.lib.finalize() diff --git a/tests/unit_tests/dagmc/test_lost_particles.py b/tests/unit_tests/dagmc/test_lost_particles.py new file mode 100644 index 00000000000..502bd795e85 --- /dev/null +++ b/tests/unit_tests/dagmc/test_lost_particles.py @@ -0,0 +1,81 @@ +import numpy as np +from pathlib import Path + +import openmc +import openmc.lib + +import pytest + +pytestmark = pytest.mark.skipif( + not openmc.lib._dagmc_enabled(), + reason="DAGMC CAD geometry is not enabled.") + + +@pytest.fixture +def broken_dagmc_model(request): + openmc.reset_auto_ids() + model = openmc.Model() + + ### MATERIALS ### + fuel = openmc.Material(name='no-void fuel') + fuel.set_density('g/cc', 10.29769) + fuel.add_nuclide('U233', 1.0) + + cladding = openmc.Material(name='clad') + cladding.set_density('g/cc', 6.55) + cladding.add_nuclide('Zr90', 1.0) + + h1 = openmc.Material(name='water') + h1.set_density('g/cc', 0.75) + h1.add_nuclide('H1', 1.0) + + model.materials = openmc.Materials([fuel, cladding, h1]) + + ### GEOMETRY ### + # create the DAGMC universe using a model that has many triangles + # removed + dagmc_file = Path(request.fspath).parent / "broken_model.h5m" + pincell_univ = openmc.DAGMCUniverse(filename=dagmc_file, auto_geom_ids=True) + + # create a 2 x 2 lattice using the DAGMC pincell + pitch = np.asarray((24.0, 24.0)) + lattice = openmc.RectLattice() + lattice.pitch = pitch + lattice.universes = [[pincell_univ] * 2] * 2 + lattice.lower_left = -pitch + + # clip the DAGMC geometry at +/- 10 cm w/ CSG planes + rpp = openmc.model.RectangularParallelepiped( + -pitch[0], pitch[0], -pitch[1], pitch[1], -10.0, 10.0, boundary_type='reflective') + bounding_cell = openmc.Cell(fill=lattice, region=-rpp) + + model.geometry = openmc.Geometry(root=[bounding_cell]) + + # settings + model.settings.particles = 100 + model.settings.batches = 10 + model.settings.inactive = 2 + model.settings.output = {'summary': False} + + model.export_to_xml() + + return model + + +def test_lost_particles(run_in_tmpdir, broken_dagmc_model): + broken_dagmc_model.export_to_xml() + # ensure that particles will be lost when cell intersections can't be found + # due to the removed triangles in this model + with pytest.raises(RuntimeError, match='Maximum number of lost particles has been reached.'): + openmc.run() + + # run this again, but with the dagmc universe as the root unvierse + for univ in broken_dagmc_model.geometry.get_all_universes().values(): + if isinstance(univ, openmc.DAGMCUniverse): + broken_dagmc_model.geometry.root_unvierse = univ + break + + broken_dagmc_model.export_to_xml() + with pytest.raises(RuntimeError, match='Maximum number of lost particles has been reached.'): + openmc.run() + diff --git a/tests/unit_tests/mesh_to_vtk/__init__.py b/tests/unit_tests/mesh_to_vtk/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk b/tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk new file mode 100644 index 00000000000..801a02b3ea4 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk @@ -0,0 +1,41 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 5 4 4 +POINTS 80 double +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -10 +9.375 11.082531755 -10 8.75 12.165063509 -10 8.125 13.247595264 -10 +7.5 14.330127019 -10 10 10 -10 9.375 8.9174682453 -10 +8.75 7.8349364905 -10 8.125 6.7524047358 -10 7.5 5.6698729811 -10 +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -9.3333333333 9.375 11.082531755 -9.3333333333 +8.75 12.165063509 -9.3333333333 8.125 13.247595264 -9.3333333333 7.5 14.330127019 -9.3333333333 +10 10 -9.3333333333 9.375 8.9174682453 -9.3333333333 8.75 7.8349364905 -9.3333333333 +8.125 6.7524047358 -9.3333333333 7.5 5.6698729811 -9.3333333333 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8.6666666667 9.375 11.082531755 -8.6666666667 8.75 12.165063509 -8.6666666667 +8.125 13.247595264 -8.6666666667 7.5 14.330127019 -8.6666666667 10 10 -8.6666666667 +9.375 8.9174682453 -8.6666666667 8.75 7.8349364905 -8.6666666667 8.125 6.7524047358 -8.6666666667 +7.5 5.6698729811 -8.6666666667 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 10 10 -8 +9.375 11.082531755 -8 8.75 12.165063509 -8 8.125 13.247595264 -8 +7.5 14.330127019 -8 10 10 -8 9.375 8.9174682453 -8 +8.75 7.8349364905 -8 8.125 6.7524047358 -8 7.5 5.6698729811 -8 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 +CELL_DATA 36 +FIELD FieldData 1 +ascending_data 1 36 double +0 100 200 300 400 500 600 700 800 +900 1000 1100 1200 1300 1400 1500 1600 1700 +1800 1900 2000 2100 2200 2300 2400 2500 2600 +2700 2800 2900 3000 3100 3200 3300 3400 3500 + diff --git a/tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk b/tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk new file mode 100644 index 00000000000..332d37db076 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk @@ -0,0 +1,329 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 323 double +-4.0450849719 -2.9389262615 0 -4.0450849719 -2.9389262615 0.66666666667 -4.0450849719 -2.9389262615 1.3333333333 +-4.0450849719 -2.9389262615 2 -4.0450849719 2.9389262615 0 -4.0450849719 2.9389262615 0.66666666667 +-4.0450849719 2.9389262615 1.3333333333 -4.0450849719 2.9389262615 2 -3.0338137289 -2.2041946961 0 +-3.0338137289 -2.2041946961 0.66666666667 -3.0338137289 -2.2041946961 1.3333333333 -3.0338137289 -2.2041946961 2 +-3.0338137289 2.2041946961 0 -3.0338137289 2.2041946961 0.66666666667 -3.0338137289 2.2041946961 1.3333333333 +-3.0338137289 2.2041946961 2 -2.0225424859 -1.4694631307 0 -2.0225424859 -1.4694631307 0.66666666667 +-2.0225424859 -1.4694631307 1.3333333333 -2.0225424859 -1.4694631307 2 -2.0225424859 1.4694631307 0 +-2.0225424859 1.4694631307 0.66666666667 -2.0225424859 1.4694631307 1.3333333333 -2.0225424859 1.4694631307 2 +-1.011271243 -0.73473156537 0 -1.011271243 -0.73473156537 0.66666666667 -1.011271243 -0.73473156537 1.3333333333 +-1.011271243 -0.73473156537 2 -1.011271243 0.73473156537 0 -1.011271243 0.73473156537 0.66666666667 +-1.011271243 0.73473156537 1.3333333333 -1.011271243 0.73473156537 2 0 0 0 +0 0 0.66666666667 0 0 1.3333333333 0 0 2 +0.38627124297 -1.1888206454 0 0.38627124297 -1.1888206454 0.66666666667 0.38627124297 -1.1888206454 1.3333333333 +0.38627124297 -1.1888206454 2 0.38627124297 1.1888206454 0 0.38627124297 1.1888206454 0.66666666667 +0.38627124297 1.1888206454 1.3333333333 0.38627124297 1.1888206454 2 0.77254248594 -2.3776412907 0 +0.77254248594 -2.3776412907 0.66666666667 0.77254248594 -2.3776412907 1.3333333333 0.77254248594 -2.3776412907 2 +0.77254248594 2.3776412907 0 0.77254248594 2.3776412907 0.66666666667 0.77254248594 2.3776412907 1.3333333333 +0.77254248594 2.3776412907 2 1.1588137289 -3.5664619361 0 1.1588137289 -3.5664619361 0.66666666667 +1.1588137289 -3.5664619361 1.3333333333 1.1588137289 -3.5664619361 2 1.1588137289 3.5664619361 0 +1.1588137289 3.5664619361 0.66666666667 1.1588137289 3.5664619361 1.3333333333 1.1588137289 3.5664619361 2 +1.25 -3.0616169979e-16 0 1.25 -3.0616169979e-16 0.66666666667 1.25 -3.0616169979e-16 1.3333333333 +1.25 -3.0616169979e-16 2 1.25 0 0 1.25 0 0.66666666667 +1.25 0 1.3333333333 1.25 0 2 1.5450849719 -4.7552825815 0 +1.5450849719 -4.7552825815 0.66666666667 1.5450849719 -4.7552825815 1.3333333333 1.5450849719 -4.7552825815 2 +1.5450849719 4.7552825815 0 1.5450849719 4.7552825815 0.66666666667 1.5450849719 4.7552825815 1.3333333333 +1.5450849719 4.7552825815 2 2.5 -6.1232339957e-16 0 2.5 -6.1232339957e-16 0.66666666667 +2.5 -6.1232339957e-16 1.3333333333 2.5 -6.1232339957e-16 2 2.5 0 0 +2.5 0 0.66666666667 2.5 0 1.3333333333 2.5 0 2 +3.75 -9.1848509936e-16 0 3.75 -9.1848509936e-16 0.66666666667 3.75 -9.1848509936e-16 1.3333333333 +3.75 -9.1848509936e-16 2 3.75 0 0 3.75 0 0.66666666667 +3.75 0 1.3333333333 3.75 0 2 5 -1.2246467991e-15 0 +5 -1.2246467991e-15 0.66666666667 5 -1.2246467991e-15 1.3333333333 5 -1.2246467991e-15 2 +5 0 0 5 0 0.66666666667 5 0 1.3333333333 +5 0 2 0.625 0 0 1.875 0 0 +3.125 0 0 4.375 0 0 0.19313562148 0.59441032268 0 +0.57940686445 1.7832309681 0 0.96567810742 2.9720516134 0 1.3519493504 4.1608722588 0 +-0.50563562148 0.36736578268 0 -1.5169068645 1.102097348 0 -2.5281781074 1.8368289134 0 +-3.5394493504 2.5715604788 0 -0.50563562148 -0.36736578268 0 -1.5169068645 -1.102097348 0 +-2.5281781074 -1.8368289134 0 -3.5394493504 -2.5715604788 0 0.19313562148 -0.59441032268 0 +0.57940686445 -1.7832309681 0 0.96567810742 -2.9720516134 0 1.3519493504 -4.1608722588 0 +0.625 0 0.66666666667 1.875 0 0.66666666667 3.125 0 0.66666666667 +4.375 0 0.66666666667 0.19313562148 0.59441032268 0.66666666667 0.57940686445 1.7832309681 0.66666666667 +0.96567810742 2.9720516134 0.66666666667 1.3519493504 4.1608722588 0.66666666667 -0.50563562148 0.36736578268 0.66666666667 +-1.5169068645 1.102097348 0.66666666667 -2.5281781074 1.8368289134 0.66666666667 -3.5394493504 2.5715604788 0.66666666667 +-0.50563562148 -0.36736578268 0.66666666667 -1.5169068645 -1.102097348 0.66666666667 -2.5281781074 -1.8368289134 0.66666666667 +-3.5394493504 -2.5715604788 0.66666666667 0.19313562148 -0.59441032268 0.66666666667 0.57940686445 -1.7832309681 0.66666666667 +0.96567810742 -2.9720516134 0.66666666667 1.3519493504 -4.1608722588 0.66666666667 0.625 0 1.3333333333 +1.875 0 1.3333333333 3.125 0 1.3333333333 4.375 0 1.3333333333 +0.19313562148 0.59441032268 1.3333333333 0.57940686445 1.7832309681 1.3333333333 0.96567810742 2.9720516134 1.3333333333 +1.3519493504 4.1608722588 1.3333333333 -0.50563562148 0.36736578268 1.3333333333 -1.5169068645 1.102097348 1.3333333333 +-2.5281781074 1.8368289134 1.3333333333 -3.5394493504 2.5715604788 1.3333333333 -0.50563562148 -0.36736578268 1.3333333333 +-1.5169068645 -1.102097348 1.3333333333 -2.5281781074 -1.8368289134 1.3333333333 -3.5394493504 -2.5715604788 1.3333333333 +0.19313562148 -0.59441032268 1.3333333333 0.57940686445 -1.7832309681 1.3333333333 0.96567810742 -2.9720516134 1.3333333333 +1.3519493504 -4.1608722588 1.3333333333 0.625 0 2 1.875 0 2 +3.125 0 2 4.375 0 2 0.19313562148 0.59441032268 2 +0.57940686445 1.7832309681 2 0.96567810742 2.9720516134 2 1.3519493504 4.1608722588 2 +-0.50563562148 0.36736578268 2 -1.5169068645 1.102097348 2 -2.5281781074 1.8368289134 2 +-3.5394493504 2.5715604788 2 -0.50563562148 -0.36736578268 2 -1.5169068645 -1.102097348 2 +-2.5281781074 -1.8368289134 2 -3.5394493504 -2.5715604788 2 0.19313562148 -0.59441032268 2 +0.57940686445 -1.7832309681 2 0.96567810742 -2.9720516134 2 1.3519493504 -4.1608722588 2 +1.011271243 0.73473156537 0 2.0225424859 1.4694631307 0 3.0338137289 2.2041946961 0 +4.0450849719 2.9389262615 0 -0.38627124297 1.1888206454 0 -0.77254248594 2.3776412907 0 +-1.1588137289 3.5664619361 0 -1.5450849719 4.7552825815 0 -1.25 1.5308084989e-16 0 +-2.5 3.0616169979e-16 0 -3.75 4.5924254968e-16 0 -5 6.1232339957e-16 0 +-0.38627124297 -1.1888206454 0 -0.77254248594 -2.3776412907 0 -1.1588137289 -3.5664619361 0 +-1.5450849719 -4.7552825815 0 1.011271243 -0.73473156537 0 2.0225424859 -1.4694631307 0 +3.0338137289 -2.2041946961 0 4.0450849719 -2.9389262615 0 1.011271243 0.73473156537 0.66666666667 +2.0225424859 1.4694631307 0.66666666667 3.0338137289 2.2041946961 0.66666666667 4.0450849719 2.9389262615 0.66666666667 +-0.38627124297 1.1888206454 0.66666666667 -0.77254248594 2.3776412907 0.66666666667 -1.1588137289 3.5664619361 0.66666666667 +-1.5450849719 4.7552825815 0.66666666667 -1.25 1.5308084989e-16 0.66666666667 -2.5 3.0616169979e-16 0.66666666667 +-3.75 4.5924254968e-16 0.66666666667 -5 6.1232339957e-16 0.66666666667 -0.38627124297 -1.1888206454 0.66666666667 +-0.77254248594 -2.3776412907 0.66666666667 -1.1588137289 -3.5664619361 0.66666666667 -1.5450849719 -4.7552825815 0.66666666667 +1.011271243 -0.73473156537 0.66666666667 2.0225424859 -1.4694631307 0.66666666667 3.0338137289 -2.2041946961 0.66666666667 +4.0450849719 -2.9389262615 0.66666666667 1.011271243 0.73473156537 1.3333333333 2.0225424859 1.4694631307 1.3333333333 +3.0338137289 2.2041946961 1.3333333333 4.0450849719 2.9389262615 1.3333333333 -0.38627124297 1.1888206454 1.3333333333 +-0.77254248594 2.3776412907 1.3333333333 -1.1588137289 3.5664619361 1.3333333333 -1.5450849719 4.7552825815 1.3333333333 +-1.25 1.5308084989e-16 1.3333333333 -2.5 3.0616169979e-16 1.3333333333 -3.75 4.5924254968e-16 1.3333333333 +-5 6.1232339957e-16 1.3333333333 -0.38627124297 -1.1888206454 1.3333333333 -0.77254248594 -2.3776412907 1.3333333333 +-1.1588137289 -3.5664619361 1.3333333333 -1.5450849719 -4.7552825815 1.3333333333 1.011271243 -0.73473156537 1.3333333333 +2.0225424859 -1.4694631307 1.3333333333 3.0338137289 -2.2041946961 1.3333333333 4.0450849719 -2.9389262615 1.3333333333 +1.011271243 0.73473156537 2 2.0225424859 1.4694631307 2 3.0338137289 2.2041946961 2 +4.0450849719 2.9389262615 2 -0.38627124297 1.1888206454 2 -0.77254248594 2.3776412907 2 +-1.1588137289 3.5664619361 2 -1.5450849719 4.7552825815 2 -1.25 1.5308084989e-16 2 +-2.5 3.0616169979e-16 2 -3.75 4.5924254968e-16 2 -5 6.1232339957e-16 2 +-0.38627124297 -1.1888206454 2 -0.77254248594 -2.3776412907 2 -1.1588137289 -3.5664619361 2 +-1.5450849719 -4.7552825815 2 1.011271243 -0.73473156537 2 2.0225424859 -1.4694631307 2 +3.0338137289 -2.2041946961 2 4.0450849719 -2.9389262615 2 0 0 0.33333333333 +1.25 0 0.33333333333 2.5 0 0.33333333333 3.75 0 0.33333333333 +5 0 0.33333333333 0.38627124297 1.1888206454 0.33333333333 0.77254248594 2.3776412907 0.33333333333 +1.1588137289 3.5664619361 0.33333333333 1.5450849719 4.7552825815 0.33333333333 -1.011271243 0.73473156537 0.33333333333 +-2.0225424859 1.4694631307 0.33333333333 -3.0338137289 2.2041946961 0.33333333333 -4.0450849719 2.9389262615 0.33333333333 +-1.011271243 -0.73473156537 0.33333333333 -2.0225424859 -1.4694631307 0.33333333333 -3.0338137289 -2.2041946961 0.33333333333 +-4.0450849719 -2.9389262615 0.33333333333 0.38627124297 -1.1888206454 0.33333333333 0.77254248594 -2.3776412907 0.33333333333 +1.1588137289 -3.5664619361 0.33333333333 1.5450849719 -4.7552825815 0.33333333333 0 0 1 +1.25 0 1 2.5 0 1 3.75 0 1 +5 0 1 0.38627124297 1.1888206454 1 0.77254248594 2.3776412907 1 +1.1588137289 3.5664619361 1 1.5450849719 4.7552825815 1 -1.011271243 0.73473156537 1 +-2.0225424859 1.4694631307 1 -3.0338137289 2.2041946961 1 -4.0450849719 2.9389262615 1 +-1.011271243 -0.73473156537 1 -2.0225424859 -1.4694631307 1 -3.0338137289 -2.2041946961 1 +-4.0450849719 -2.9389262615 1 0.38627124297 -1.1888206454 1 0.77254248594 -2.3776412907 1 +1.1588137289 -3.5664619361 1 1.5450849719 -4.7552825815 1 0 0 1.6666666667 +1.25 0 1.6666666667 2.5 0 1.6666666667 3.75 0 1.6666666667 +5 0 1.6666666667 0.38627124297 1.1888206454 1.6666666667 0.77254248594 2.3776412907 1.6666666667 +1.1588137289 3.5664619361 1.6666666667 1.5450849719 4.7552825815 1.6666666667 -1.011271243 0.73473156537 1.6666666667 +-2.0225424859 1.4694631307 1.6666666667 -3.0338137289 2.2041946961 1.6666666667 -4.0450849719 2.9389262615 1.6666666667 +-1.011271243 -0.73473156537 1.6666666667 -2.0225424859 -1.4694631307 1.6666666667 -3.0338137289 -2.2041946961 1.6666666667 +-4.0450849719 -2.9389262615 1.6666666667 0.38627124297 -1.1888206454 1.6666666667 0.77254248594 -2.3776412907 1.6666666667 +1.1588137289 -3.5664619361 1.6666666667 1.5450849719 -4.7552825815 1.6666666667 +CELLS 61 1200 +OFFSETS vtktypeint64 +0 20 40 60 80 100 120 140 160 +180 200 220 240 260 280 300 320 340 +360 380 400 420 440 460 480 500 520 +540 560 580 600 620 640 660 680 700 +720 740 760 780 800 820 840 860 880 +900 920 940 960 980 1000 1020 1040 1060 +1080 1100 1120 1140 1160 1180 1200 +CONNECTIVITY vtktypeint64 +32 60 40 32 33 61 41 33 100 +180 104 32 120 200 124 33 260 261 +265 260 60 76 48 40 61 77 49 +41 101 181 105 180 121 201 125 200 +261 262 266 265 76 84 56 48 77 +85 57 49 102 182 106 181 122 202 +126 201 262 263 267 266 84 92 72 +56 85 93 73 57 103 183 107 182 +123 203 127 202 263 264 268 267 32 +40 28 32 33 41 29 33 104 184 +108 32 124 204 128 33 260 265 269 +260 40 48 20 28 41 49 21 29 +105 185 109 184 125 205 129 204 265 +266 270 269 48 56 12 20 49 57 +13 21 106 186 110 185 126 206 130 +205 266 267 271 270 56 72 4 12 +57 73 5 13 107 187 111 186 127 +207 131 206 267 268 272 271 32 28 +24 32 33 29 25 33 108 188 112 +32 128 208 132 33 260 269 273 260 +28 20 16 24 29 21 17 25 109 +189 113 188 129 209 133 208 269 270 +274 273 20 12 8 16 21 13 9 +17 110 190 114 189 130 210 134 209 +270 271 275 274 12 4 0 8 13 +5 1 9 111 191 115 190 131 211 +135 210 271 272 276 275 32 24 36 +32 33 25 37 33 112 192 116 32 +132 212 136 33 260 273 277 260 24 +16 44 36 25 17 45 37 113 193 +117 192 133 213 137 212 273 274 278 +277 16 8 52 44 17 9 53 45 +114 194 118 193 134 214 138 213 274 +275 279 278 8 0 68 52 9 1 +69 53 115 195 119 194 135 215 139 +214 275 276 280 279 32 36 60 32 +33 37 61 33 116 196 100 32 136 +216 120 33 260 277 261 260 36 44 +76 60 37 45 77 61 117 197 101 +196 137 217 121 216 277 278 262 261 +44 52 84 76 45 53 85 77 118 +198 102 197 138 218 122 217 278 279 +263 262 52 68 92 84 53 69 93 +85 119 199 103 198 139 219 123 218 +279 280 264 263 33 61 41 33 34 +62 42 34 120 200 124 33 140 220 +144 34 281 282 286 281 61 77 49 +41 62 78 50 42 121 201 125 200 +141 221 145 220 282 283 287 286 77 +85 57 49 78 86 58 50 122 202 +126 201 142 222 146 221 283 284 288 +287 85 93 73 57 86 94 74 58 +123 203 127 202 143 223 147 222 284 +285 289 288 33 41 29 33 34 42 +30 34 124 204 128 33 144 224 148 +34 281 286 290 281 41 49 21 29 +42 50 22 30 125 205 129 204 145 +225 149 224 286 287 291 290 49 57 +13 21 50 58 14 22 126 206 130 +205 146 226 150 225 287 288 292 291 +57 73 5 13 58 74 6 14 127 +207 131 206 147 227 151 226 288 289 +293 292 33 29 25 33 34 30 26 +34 128 208 132 33 148 228 152 34 +281 290 294 281 29 21 17 25 30 +22 18 26 129 209 133 208 149 229 +153 228 290 291 295 294 21 13 9 +17 22 14 10 18 130 210 134 209 +150 230 154 229 291 292 296 295 13 +5 1 9 14 6 2 10 131 211 +135 210 151 231 155 230 292 293 297 +296 33 25 37 33 34 26 38 34 +132 212 136 33 152 232 156 34 281 +294 298 281 25 17 45 37 26 18 +46 38 133 213 137 212 153 233 157 +232 294 295 299 298 17 9 53 45 +18 10 54 46 134 214 138 213 154 +234 158 233 295 296 300 299 9 1 +69 53 10 2 70 54 135 215 139 +214 155 235 159 234 296 297 301 300 +33 37 61 33 34 38 62 34 136 +216 120 33 156 236 140 34 281 298 +282 281 37 45 77 61 38 46 78 +62 137 217 121 216 157 237 141 236 +298 299 283 282 45 53 85 77 46 +54 86 78 138 218 122 217 158 238 +142 237 299 300 284 283 53 69 93 +85 54 70 94 86 139 219 123 218 +159 239 143 238 300 301 285 284 34 +62 42 34 35 63 43 35 140 220 +144 34 160 240 164 35 302 303 307 +302 62 78 50 42 63 79 51 43 +141 221 145 220 161 241 165 240 303 +304 308 307 78 86 58 50 79 87 +59 51 142 222 146 221 162 242 166 +241 304 305 309 308 86 94 74 58 +87 95 75 59 143 223 147 222 163 +243 167 242 305 306 310 309 34 42 +30 34 35 43 31 35 144 224 148 +34 164 244 168 35 302 307 311 302 +42 50 22 30 43 51 23 31 145 +225 149 224 165 245 169 244 307 308 +312 311 50 58 14 22 51 59 15 +23 146 226 150 225 166 246 170 245 +308 309 313 312 58 74 6 14 59 +75 7 15 147 227 151 226 167 247 +171 246 309 310 314 313 34 30 26 +34 35 31 27 35 148 228 152 34 +168 248 172 35 302 311 315 302 30 +22 18 26 31 23 19 27 149 229 +153 228 169 249 173 248 311 312 316 +315 22 14 10 18 23 15 11 19 +150 230 154 229 170 250 174 249 312 +313 317 316 14 6 2 10 15 7 +3 11 151 231 155 230 171 251 175 +250 313 314 318 317 34 26 38 34 +35 27 39 35 152 232 156 34 172 +252 176 35 302 315 319 302 26 18 +46 38 27 19 47 39 153 233 157 +232 173 253 177 252 315 316 320 319 +18 10 54 46 19 11 55 47 154 +234 158 233 174 254 178 253 316 317 +321 320 10 2 70 54 11 3 71 +55 155 235 159 234 175 255 179 254 +317 318 322 321 34 38 62 34 35 +39 63 35 156 236 140 34 176 256 +160 35 302 319 303 302 38 46 78 +62 39 47 79 63 157 237 141 236 +177 257 161 256 319 320 304 303 46 +54 86 78 47 55 87 79 158 238 +142 237 178 258 162 257 320 321 305 +304 54 70 94 86 55 71 95 87 +159 239 143 238 179 259 163 258 321 +322 306 305 +CELL_TYPES 60 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 + +CELL_DATA 60 +FIELD FieldData 1 +ascending_data 1 60 double +0 100 200 300 400 500 600 700 800 +900 1000 1100 1200 1300 1400 1500 1600 1700 +1800 1900 2000 2100 2200 2300 2400 2500 2600 +2700 2800 2900 3000 3100 3200 3300 3400 3500 +3600 3700 3800 3900 4000 4100 4200 4300 4400 +4500 4600 4700 4800 4900 5000 5100 5200 5300 +5400 5500 5600 5700 5800 5900 diff --git a/tests/unit_tests/mesh_to_vtk/cyl-data.vtk b/tests/unit_tests/mesh_to_vtk/cyl-data.vtk new file mode 100644 index 00000000000..801a02b3ea4 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cyl-data.vtk @@ -0,0 +1,41 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 5 4 4 +POINTS 80 double +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -10 +9.375 11.082531755 -10 8.75 12.165063509 -10 8.125 13.247595264 -10 +7.5 14.330127019 -10 10 10 -10 9.375 8.9174682453 -10 +8.75 7.8349364905 -10 8.125 6.7524047358 -10 7.5 5.6698729811 -10 +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -9.3333333333 9.375 11.082531755 -9.3333333333 +8.75 12.165063509 -9.3333333333 8.125 13.247595264 -9.3333333333 7.5 14.330127019 -9.3333333333 +10 10 -9.3333333333 9.375 8.9174682453 -9.3333333333 8.75 7.8349364905 -9.3333333333 +8.125 6.7524047358 -9.3333333333 7.5 5.6698729811 -9.3333333333 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8.6666666667 9.375 11.082531755 -8.6666666667 8.75 12.165063509 -8.6666666667 +8.125 13.247595264 -8.6666666667 7.5 14.330127019 -8.6666666667 10 10 -8.6666666667 +9.375 8.9174682453 -8.6666666667 8.75 7.8349364905 -8.6666666667 8.125 6.7524047358 -8.6666666667 +7.5 5.6698729811 -8.6666666667 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 10 10 -8 +9.375 11.082531755 -8 8.75 12.165063509 -8 8.125 13.247595264 -8 +7.5 14.330127019 -8 10 10 -8 9.375 8.9174682453 -8 +8.75 7.8349364905 -8 8.125 6.7524047358 -8 7.5 5.6698729811 -8 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 +CELL_DATA 36 +FIELD FieldData 1 +ascending_data 1 36 double +0 100 200 300 400 500 600 700 800 +900 1000 1100 1200 1300 1400 1500 1600 1700 +1800 1900 2000 2100 2200 2300 2400 2500 2600 +2700 2800 2900 3000 3100 3200 3300 3400 3500 + diff --git a/tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk b/tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk new file mode 100644 index 00000000000..24bdd7f14ed --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk @@ -0,0 +1,198 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 195 double +7.5 5.6698729811 -10 7.5 5.6698729811 -9.3333333333 7.5 5.6698729811 -8.6666666667 +7.5 5.6698729811 -8 7.5 14.330127019 -10 7.5 14.330127019 -9.3333333333 +7.5 14.330127019 -8.6666666667 7.5 14.330127019 -8 8.125 6.7524047358 -10 +8.125 6.7524047358 -9.3333333333 8.125 6.7524047358 -8.6666666667 8.125 6.7524047358 -8 +8.125 13.247595264 -10 8.125 13.247595264 -9.3333333333 8.125 13.247595264 -8.6666666667 +8.125 13.247595264 -8 8.75 7.8349364905 -10 8.75 7.8349364905 -9.3333333333 +8.75 7.8349364905 -8.6666666667 8.75 7.8349364905 -8 8.75 12.165063509 -10 +8.75 12.165063509 -9.3333333333 8.75 12.165063509 -8.6666666667 8.75 12.165063509 -8 +9.375 8.9174682453 -10 9.375 8.9174682453 -9.3333333333 9.375 8.9174682453 -8.6666666667 +9.375 8.9174682453 -8 9.375 11.082531755 -10 9.375 11.082531755 -9.3333333333 +9.375 11.082531755 -8.6666666667 9.375 11.082531755 -8 10 10 -10 +10 10 -9.3333333333 10 10 -8.6666666667 10 10 -8 +11.25 10 -10 11.25 10 -9.3333333333 11.25 10 -8.6666666667 +11.25 10 -8 12.5 10 -10 12.5 10 -9.3333333333 +12.5 10 -8.6666666667 12.5 10 -8 13.75 10 -10 +13.75 10 -9.3333333333 13.75 10 -8.6666666667 13.75 10 -8 +13.75 10 -10 13.75 10 -9.3333333333 13.75 10 -8.6666666667 +13.75 10 -8 15 10 -10 15 10 -9.3333333333 +15 10 -8.6666666667 15 10 -8 15 10 -10 +15 10 -9.3333333333 15 10 -8.6666666667 15 10 -8 +10.625 10 -10 11.875 10 -10 13.125 10 -10 +14.375 10 -10 9.6875 10.541265877 -10 9.0625 11.623797632 -10 +8.4375 12.706329387 -10 7.8125 13.788861142 -10 9.6875 9.4587341226 -10 +9.0625 8.3762023679 -10 8.4375 7.2936706132 -10 7.8125 6.2111388584 -10 +10.625 10 -9.3333333333 11.875 10 -9.3333333333 13.125 10 -9.3333333333 +14.375 10 -9.3333333333 9.6875 10.541265877 -9.3333333333 9.0625 11.623797632 -9.3333333333 +8.4375 12.706329387 -9.3333333333 7.8125 13.788861142 -9.3333333333 9.6875 9.4587341226 -9.3333333333 +9.0625 8.3762023679 -9.3333333333 8.4375 7.2936706132 -9.3333333333 7.8125 6.2111388584 -9.3333333333 +10.625 10 -8.6666666667 11.875 10 -8.6666666667 13.125 10 -8.6666666667 +14.375 10 -8.6666666667 9.6875 10.541265877 -8.6666666667 9.0625 11.623797632 -8.6666666667 +8.4375 12.706329387 -8.6666666667 7.8125 13.788861142 -8.6666666667 9.6875 9.4587341226 -8.6666666667 +9.0625 8.3762023679 -8.6666666667 8.4375 7.2936706132 -8.6666666667 7.8125 6.2111388584 -8.6666666667 +10.625 10 -8 11.875 10 -8 13.125 10 -8 +14.375 10 -8 9.6875 10.541265877 -8 9.0625 11.623797632 -8 +8.4375 12.706329387 -8 7.8125 13.788861142 -8 9.6875 9.4587341226 -8 +9.0625 8.3762023679 -8 8.4375 7.2936706132 -8 7.8125 6.2111388584 -8 +10.625 11.082531755 -10 11.25 12.165063509 -10 11.875 13.247595264 -10 +12.5 14.330127019 -10 8.75 10 -10 7.5 10 -10 +6.25 10 -10 5 10 -10 10.625 8.9174682453 -10 +11.25 7.8349364905 -10 11.875 6.7524047358 -10 12.5 5.6698729811 -10 +10.625 11.082531755 -9.3333333333 11.25 12.165063509 -9.3333333333 11.875 13.247595264 -9.3333333333 +12.5 14.330127019 -9.3333333333 8.75 10 -9.3333333333 7.5 10 -9.3333333333 +6.25 10 -9.3333333333 5 10 -9.3333333333 10.625 8.9174682453 -9.3333333333 +11.25 7.8349364905 -9.3333333333 11.875 6.7524047358 -9.3333333333 12.5 5.6698729811 -9.3333333333 +10.625 11.082531755 -8.6666666667 11.25 12.165063509 -8.6666666667 11.875 13.247595264 -8.6666666667 +12.5 14.330127019 -8.6666666667 8.75 10 -8.6666666667 7.5 10 -8.6666666667 +6.25 10 -8.6666666667 5 10 -8.6666666667 10.625 8.9174682453 -8.6666666667 +11.25 7.8349364905 -8.6666666667 11.875 6.7524047358 -8.6666666667 12.5 5.6698729811 -8.6666666667 +10.625 11.082531755 -8 11.25 12.165063509 -8 11.875 13.247595264 -8 +12.5 14.330127019 -8 8.75 10 -8 7.5 10 -8 +6.25 10 -8 5 10 -8 10.625 8.9174682453 -8 +11.25 7.8349364905 -8 11.875 6.7524047358 -8 12.5 5.6698729811 -8 +10 10 -9.6666666667 11.25 10 -9.6666666667 12.5 10 -9.6666666667 +13.75 10 -9.6666666667 15 10 -9.6666666667 9.375 11.082531755 -9.6666666667 +8.75 12.165063509 -9.6666666667 8.125 13.247595264 -9.6666666667 7.5 14.330127019 -9.6666666667 +9.375 8.9174682453 -9.6666666667 8.75 7.8349364905 -9.6666666667 8.125 6.7524047358 -9.6666666667 +7.5 5.6698729811 -9.6666666667 10 10 -9 11.25 10 -9 +12.5 10 -9 13.75 10 -9 15 10 -9 +9.375 11.082531755 -9 8.75 12.165063509 -9 8.125 13.247595264 -9 +7.5 14.330127019 -9 9.375 8.9174682453 -9 8.75 7.8349364905 -9 +8.125 6.7524047358 -9 7.5 5.6698729811 -9 10 10 -8.3333333333 +11.25 10 -8.3333333333 12.5 10 -8.3333333333 13.75 10 -8.3333333333 +15 10 -8.3333333333 9.375 11.082531755 -8.3333333333 8.75 12.165063509 -8.3333333333 +8.125 13.247595264 -8.3333333333 7.5 14.330127019 -8.3333333333 9.375 8.9174682453 -8.3333333333 +8.75 7.8349364905 -8.3333333333 8.125 6.7524047358 -8.3333333333 7.5 5.6698729811 -8.3333333333 + +CELLS 37 720 +OFFSETS vtktypeint64 +0 20 40 60 80 100 120 140 160 +180 200 220 240 260 280 300 320 340 +360 380 400 420 440 460 480 500 520 +540 560 580 600 620 640 660 680 700 +720 +CONNECTIVITY vtktypeint64 +32 36 28 32 33 37 29 33 60 +108 64 32 72 120 76 33 156 157 +161 156 36 40 20 28 37 41 21 +29 61 109 65 108 73 121 77 120 +157 158 162 161 40 44 12 20 41 +45 13 21 62 110 66 109 74 122 +78 121 158 159 163 162 44 52 4 +12 45 53 5 13 63 111 67 110 +75 123 79 122 159 160 164 163 32 +28 24 32 33 29 25 33 64 112 +68 32 76 124 80 33 156 161 165 +156 28 20 16 24 29 21 17 25 +65 113 69 112 77 125 81 124 161 +162 166 165 20 12 8 16 21 13 +9 17 66 114 70 113 78 126 82 +125 162 163 167 166 12 4 0 8 +13 5 1 9 67 115 71 114 79 +127 83 126 163 164 168 167 32 24 +36 32 33 25 37 33 68 116 60 +32 80 128 72 33 156 165 157 156 +24 16 40 36 25 17 41 37 69 +117 61 116 81 129 73 128 165 166 +158 157 16 8 44 40 17 9 45 +41 70 118 62 117 82 130 74 129 +166 167 159 158 8 0 52 44 9 +1 53 45 71 119 63 118 83 131 +75 130 167 168 160 159 33 37 29 +33 34 38 30 34 72 120 76 33 +84 132 88 34 169 170 174 169 37 +41 21 29 38 42 22 30 73 121 +77 120 85 133 89 132 170 171 175 +174 41 45 13 21 42 46 14 22 +74 122 78 121 86 134 90 133 171 +172 176 175 45 53 5 13 46 54 +6 14 75 123 79 122 87 135 91 +134 172 173 177 176 33 29 25 33 +34 30 26 34 76 124 80 33 88 +136 92 34 169 174 178 169 29 21 +17 25 30 22 18 26 77 125 81 +124 89 137 93 136 174 175 179 178 +21 13 9 17 22 14 10 18 78 +126 82 125 90 138 94 137 175 176 +180 179 13 5 1 9 14 6 2 +10 79 127 83 126 91 139 95 138 +176 177 181 180 33 25 37 33 34 +26 38 34 80 128 72 33 92 140 +84 34 169 178 170 169 25 17 41 +37 26 18 42 38 81 129 73 128 +93 141 85 140 178 179 171 170 17 +9 45 41 18 10 46 42 82 130 +74 129 94 142 86 141 179 180 172 +171 9 1 53 45 10 2 54 46 +83 131 75 130 95 143 87 142 180 +181 173 172 34 38 30 34 35 39 +31 35 84 132 88 34 96 144 100 +35 182 183 187 182 38 42 22 30 +39 43 23 31 85 133 89 132 97 +145 101 144 183 184 188 187 42 46 +14 22 43 47 15 23 86 134 90 +133 98 146 102 145 184 185 189 188 +46 54 6 14 47 55 7 15 87 +135 91 134 99 147 103 146 185 186 +190 189 34 30 26 34 35 31 27 +35 88 136 92 34 100 148 104 35 +182 187 191 182 30 22 18 26 31 +23 19 27 89 137 93 136 101 149 +105 148 187 188 192 191 22 14 10 +18 23 15 11 19 90 138 94 137 +102 150 106 149 188 189 193 192 14 +6 2 10 15 7 3 11 91 139 +95 138 103 151 107 150 189 190 194 +193 34 26 38 34 35 27 39 35 +92 140 84 34 104 152 96 35 182 +191 183 182 26 18 42 38 27 19 +43 39 93 141 85 140 105 153 97 +152 191 192 184 183 18 10 46 42 +19 11 47 43 94 142 86 141 106 +154 98 153 192 193 185 184 10 2 +54 46 11 3 55 47 95 143 87 +142 107 155 99 154 193 194 186 185 + +CELL_TYPES 36 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 + diff --git a/tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk b/tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk new file mode 100644 index 00000000000..33d1ce497a1 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk @@ -0,0 +1,33 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 5 4 4 +POINTS 80 double +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -10 +9.375 11.082531755 -10 8.75 12.165063509 -10 8.125 13.247595264 -10 +7.5 14.330127019 -10 10 10 -10 9.375 8.9174682453 -10 +8.75 7.8349364905 -10 8.125 6.7524047358 -10 7.5 5.6698729811 -10 +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -9.3333333333 9.375 11.082531755 -9.3333333333 +8.75 12.165063509 -9.3333333333 8.125 13.247595264 -9.3333333333 7.5 14.330127019 -9.3333333333 +10 10 -9.3333333333 9.375 8.9174682453 -9.3333333333 8.75 7.8349364905 -9.3333333333 +8.125 6.7524047358 -9.3333333333 7.5 5.6698729811 -9.3333333333 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8.6666666667 9.375 11.082531755 -8.6666666667 8.75 12.165063509 -8.6666666667 +8.125 13.247595264 -8.6666666667 7.5 14.330127019 -8.6666666667 10 10 -8.6666666667 +9.375 8.9174682453 -8.6666666667 8.75 7.8349364905 -8.6666666667 8.125 6.7524047358 -8.6666666667 +7.5 5.6698729811 -8.6666666667 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 10 10 -8 +9.375 11.082531755 -8 8.75 12.165063509 -8 8.125 13.247595264 -8 +7.5 14.330127019 -8 10 10 -8 9.375 8.9174682453 -8 +8.75 7.8349364905 -8 8.125 6.7524047358 -8 7.5 5.6698729811 -8 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 diff --git a/tests/unit_tests/mesh_to_vtk/hexes.exo b/tests/unit_tests/mesh_to_vtk/hexes.exo new file mode 100644 index 00000000000..c16138e900e Binary files /dev/null and b/tests/unit_tests/mesh_to_vtk/hexes.exo differ diff --git a/tests/unit_tests/mesh_to_vtk/libmesh_hexes_ref.vtk b/tests/unit_tests/mesh_to_vtk/libmesh_hexes_ref.vtk new file mode 100644 index 00000000000..041d7065dda --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/libmesh_hexes_ref.vtk @@ -0,0 +1,76 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 54 double +-1 -1 2.5 -1 -1 1.5 -1 0 1.5 +-1 0 2.5 0 -1 2.5 0 -1 1.5 +0 0 1.5 0 0 2.5 -1 -1 0.5 +-1 0 0.5 0 -1 0.5 0 0 0.5 +-1 -1 -0.5 -1 0 -0.5 0 -1 -0.5 +0 0 -0.5 -1 -1 -1.5 -1 0 -1.5 +0 -1 -1.5 0 0 -1.5 -1 -1 -2.5 +-1 0 -2.5 0 -1 -2.5 0 0 -2.5 +-1 1 1.5 -1 1 2.5 0 1 1.5 +0 1 2.5 -1 1 0.5 0 1 0.5 +-1 1 -0.5 0 1 -0.5 -1 1 -1.5 +0 1 -1.5 -1 1 -2.5 0 1 -2.5 +1 -1 2.5 1 -1 1.5 1 0 1.5 +1 0 2.5 1 -1 0.5 1 0 0.5 +1 -1 -0.5 1 0 -0.5 1 -1 -1.5 +1 0 -1.5 1 -1 -2.5 1 0 -2.5 +1 1 1.5 1 1 2.5 1 1 0.5 +1 1 -0.5 1 1 -1.5 1 1 -2.5 + +CELLS 21 160 +OFFSETS vtktypeint64 +0 8 16 24 32 40 48 56 64 +72 80 88 96 104 112 120 128 136 +144 152 160 +CONNECTIVITY vtktypeint64 +0 1 2 3 4 5 6 7 1 +8 9 2 5 10 11 6 8 12 +13 9 10 14 15 11 12 16 17 +13 14 18 19 15 16 20 21 17 +18 22 23 19 3 2 24 25 7 +6 26 27 2 9 28 24 6 11 +29 26 9 13 30 28 11 15 31 +29 13 17 32 30 15 19 33 31 +17 21 34 32 19 23 35 33 4 +5 6 7 36 37 38 39 5 10 +11 6 37 40 41 38 10 14 15 +11 40 42 43 41 14 18 19 15 +42 44 45 43 18 22 23 19 44 +46 47 45 7 6 26 27 39 38 +48 49 6 11 29 26 38 41 50 +48 11 15 31 29 41 43 51 50 +15 19 33 31 43 45 52 51 19 +23 35 33 45 47 53 52 +CELL_TYPES 20 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 + +CELL_DATA 20 +FIELD FieldData 1 +ids 1 20 double +0 1 2 3 4 5 6 7 8 +9 10 11 12 13 14 15 16 17 +18 19 diff --git a/tests/unit_tests/mesh_to_vtk/libmesh_tets_ref.vtk b/tests/unit_tests/mesh_to_vtk/libmesh_tets_ref.vtk new file mode 100644 index 00000000000..90f2261212c --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/libmesh_tets_ref.vtk @@ -0,0 +1,292 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 58 double +-0.02593964576 -1 -1.1195739536 -0.40239958217 -0.40962166746 -1.9256035383 -1 0.02593964576 -1.1195739536 +-0.2248833639 0.23189144433 -1.2841109811 0.02593964576 1 -1.1195739536 1 -0.02593964576 -1.1195739536 +-0.042928712675 0.066425810853 -0.54270728017 -1 1 -1.5 -1 1 -0.5 +-0.49265312381 0.49332495053 -1.9656359509 -0.02608137991 -1 1.121521147 0.30281888252 -0.30293622513 1.8067963894 +1 -0.02608137991 1.121521147 -0.23236342389 0.26314805583 1.2867556783 0.074337770194 0.074337770194 2.5 +-0.40005770996 -0.36909660956 1.8768871762 -0.4896743493 0.49451064621 1.952829049 -1 1 1.5 +0.02608137991 1 1.121521147 -1 1 0.5 -0.038567136385 0.14628887118 0.55111724874 +-1 0.02608137991 1.121521147 0 -1 -2.5 0.37543954218 -0.36967061971 -1.8691105401 +1 -1 -2.5 0.074337770194 -0.074337770194 -2.5 1 0 -2.5 +0.4135797166 0.38351746262 -1.9274856063 1 -1 -1.5 -1 0 -2.5 +-1 -1 -1.5 -1 -1 -2.5 -1 0 2.5 +-1 1 2.5 0 1 2.5 0.46519182209 0.49356920409 1.95286052 +0 -1 2.5 -1 -1 1.5 -1 -1 2.5 +1 -1 2.5 1 -1 1.5 1 0 2.5 +1 1 2.5 1 1 1.5 0 1 -2.5 +-1 1 -2.5 1 -1 -0.5 1 1 -0.5 +0.038669824604 1 0.0046021677516 -1 -1 0.5 -0.038669824604 -1 0.0046021677516 +1 1 0.5 -1 0.038669824604 0.0046021677516 1 -0.038669824604 0.0046021677516 +1 1 -2.5 1 1 -1.5 1 -1 0.5 +-1 -1 -0.5 +CELLS 155 616 +OFFSETS vtktypeint64 +0 4 8 12 16 20 24 28 32 +36 40 44 48 52 56 60 64 68 +72 76 80 84 88 92 96 100 104 +108 112 116 120 124 128 132 136 140 +144 148 152 156 160 164 168 172 176 +180 184 188 192 196 200 204 208 212 +216 220 224 228 232 236 240 244 248 +252 256 260 264 268 272 276 280 284 +288 292 296 300 304 308 312 316 320 +324 328 332 336 340 344 348 352 356 +360 364 368 372 376 380 384 388 392 +396 400 404 408 412 416 420 424 428 +432 436 440 444 448 452 456 460 464 +468 472 476 480 484 488 492 496 500 +504 508 512 516 520 524 528 532 536 +540 544 548 552 556 560 564 568 572 +576 580 584 588 592 596 600 604 608 +612 616 +CONNECTIVITY vtktypeint64 +0 1 2 3 4 3 5 6 7 +4 8 3 7 3 2 9 8 3 +4 6 10 11 12 13 14 13 15 +16 17 13 18 16 19 18 13 20 +10 13 21 15 22 1 0 23 22 +24 25 23 25 1 3 9 26 23 +5 27 24 28 26 23 0 1 3 +23 29 30 31 1 22 31 30 1 +2 3 1 9 29 2 1 9 22 +0 28 23 32 15 21 16 14 13 +11 15 33 17 34 16 33 34 32 +16 34 16 18 35 10 11 13 15 +18 13 12 35 36 11 10 15 36 +37 38 15 32 38 37 15 32 21 +17 16 36 10 37 15 36 39 40 +11 41 40 39 11 41 12 11 35 +17 21 13 16 10 13 12 20 12 +13 11 35 14 13 16 35 34 17 +18 16 42 34 43 35 41 12 40 +11 14 41 11 35 42 41 14 35 +0 3 5 23 0 5 3 6 44 +4 9 27 29 2 30 1 44 45 +29 9 29 45 7 9 0 46 5 +6 47 48 4 6 0 3 2 6 +4 5 3 27 49 10 50 20 8 +2 3 6 51 18 48 20 49 50 +52 20 19 13 21 20 51 53 12 +20 19 48 18 20 25 3 1 23 +7 4 3 9 25 3 23 27 44 +4 7 9 25 23 26 27 54 55 +44 27 54 26 55 27 18 12 13 +20 14 16 34 35 19 21 52 20 +30 2 0 1 22 25 29 1 5 +23 3 27 25 26 44 27 22 29 +31 1 54 44 26 27 25 44 9 +27 22 28 24 23 26 5 55 27 +25 24 26 23 22 25 1 23 25 +44 29 9 25 29 1 9 48 6 +53 20 8 4 48 6 10 40 56 +12 10 40 12 11 17 19 18 13 +30 57 0 2 25 9 3 27 7 +8 2 3 26 28 5 23 29 7 +2 9 28 0 5 23 37 10 49 +21 49 50 57 52 56 12 53 20 +10 12 56 20 43 18 12 35 32 +37 21 15 14 11 13 35 19 52 +8 48 19 52 48 20 41 39 36 +11 50 6 52 20 46 53 5 6 +4 3 9 27 44 7 45 9 55 +47 4 5 28 0 46 5 8 52 +2 6 57 2 52 6 50 56 53 +20 10 56 50 20 57 50 0 6 +37 10 21 15 33 32 17 16 34 +18 43 35 57 52 50 6 51 48 +47 53 18 16 13 35 50 56 46 +53 14 36 32 15 14 11 36 15 +17 21 19 13 10 21 13 20 51 +12 18 20 50 53 46 6 14 15 +32 16 42 43 41 35 14 41 36 +11 49 52 21 20 36 40 10 11 +47 53 48 6 49 21 10 20 21 +15 13 16 51 48 53 20 55 5 +4 27 44 55 4 27 47 4 5 +6 8 48 52 6 47 5 53 6 +50 53 6 20 57 0 2 6 50 +46 0 6 52 6 48 20 42 14 +34 35 43 18 51 12 41 43 12 +35 22 30 0 1 14 32 34 16 +36 38 32 15 +CELL_TYPES 154 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 + +CELL_DATA 154 +FIELD FieldData 1 +ids 1 154 double +0 1 2 3 4 5 6 7 8 +9 10 11 12 13 14 15 16 17 +18 19 20 21 22 23 24 25 26 +27 28 29 30 31 32 33 34 35 +36 37 38 39 40 41 42 43 44 +45 46 47 48 49 50 51 52 53 +54 55 56 57 58 59 60 61 62 +63 64 65 66 67 68 69 70 71 +72 73 74 75 76 77 78 79 80 +81 82 83 84 85 86 87 88 89 +90 91 92 93 94 95 96 97 98 +99 100 101 102 103 104 105 106 107 +108 109 110 111 112 113 114 115 116 +117 118 119 120 121 122 123 124 125 +126 127 128 129 130 131 132 133 134 +135 136 137 138 139 140 141 142 143 +144 145 146 147 148 149 150 151 152 +153 diff --git a/tests/unit_tests/mesh_to_vtk/moab_tets_ref.vtk b/tests/unit_tests/mesh_to_vtk/moab_tets_ref.vtk new file mode 120000 index 00000000000..91e356480f4 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/moab_tets_ref.vtk @@ -0,0 +1 @@ +libmesh_tets_ref.vtk \ No newline at end of file diff --git a/tests/unit_tests/mesh_to_vtk/rectilinear.vtk b/tests/unit_tests/mesh_to_vtk/rectilinear.vtk new file mode 100644 index 00000000000..71826392e82 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/rectilinear.vtk @@ -0,0 +1,340 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 5 10 20 +POINTS 1000 double +0 5 1 2.5 5 1 5 5 1 +7.5 5 1 10 5 1 0 5.8326451979 1 +2.5 5.8326451979 1 5 5.8326451979 1 7.5 5.8326451979 1 +10 5.8326451979 1 0 6.8039500009 1 2.5 6.8039500009 1 +5 6.8039500009 1 7.5 6.8039500009 1 10 6.8039500009 1 +0 7.9370052598 1 2.5 7.9370052598 1 5 7.9370052598 1 +7.5 7.9370052598 1 10 7.9370052598 1 0 9.2587471229 1 +2.5 9.2587471229 1 5 9.2587471229 1 7.5 9.2587471229 1 +10 9.2587471229 1 0 10.800597389 1 2.5 10.800597389 1 +5 10.800597389 1 7.5 10.800597389 1 10 10.800597389 1 +0 12.599210499 1 2.5 12.599210499 1 5 12.599210499 1 +7.5 12.599210499 1 10 12.599210499 1 0 14.697344923 1 +2.5 14.697344923 1 5 14.697344923 1 7.5 14.697344923 1 +10 14.697344923 1 0 17.144879657 1 2.5 17.144879657 1 +5 17.144879657 1 7.5 17.144879657 1 10 17.144879657 1 +0 20 1 2.5 20 1 5 20 1 +7.5 20 1 10 20 1 0 5 6.2105263158 +2.5 5 6.2105263158 5 5 6.2105263158 7.5 5 6.2105263158 +10 5 6.2105263158 0 5.8326451979 6.2105263158 2.5 5.8326451979 6.2105263158 +5 5.8326451979 6.2105263158 7.5 5.8326451979 6.2105263158 10 5.8326451979 6.2105263158 +0 6.8039500009 6.2105263158 2.5 6.8039500009 6.2105263158 5 6.8039500009 6.2105263158 +7.5 6.8039500009 6.2105263158 10 6.8039500009 6.2105263158 0 7.9370052598 6.2105263158 +2.5 7.9370052598 6.2105263158 5 7.9370052598 6.2105263158 7.5 7.9370052598 6.2105263158 +10 7.9370052598 6.2105263158 0 9.2587471229 6.2105263158 2.5 9.2587471229 6.2105263158 +5 9.2587471229 6.2105263158 7.5 9.2587471229 6.2105263158 10 9.2587471229 6.2105263158 +0 10.800597389 6.2105263158 2.5 10.800597389 6.2105263158 5 10.800597389 6.2105263158 +7.5 10.800597389 6.2105263158 10 10.800597389 6.2105263158 0 12.599210499 6.2105263158 +2.5 12.599210499 6.2105263158 5 12.599210499 6.2105263158 7.5 12.599210499 6.2105263158 +10 12.599210499 6.2105263158 0 14.697344923 6.2105263158 2.5 14.697344923 6.2105263158 +5 14.697344923 6.2105263158 7.5 14.697344923 6.2105263158 10 14.697344923 6.2105263158 +0 17.144879657 6.2105263158 2.5 17.144879657 6.2105263158 5 17.144879657 6.2105263158 +7.5 17.144879657 6.2105263158 10 17.144879657 6.2105263158 0 20 6.2105263158 +2.5 20 6.2105263158 5 20 6.2105263158 7.5 20 6.2105263158 +10 20 6.2105263158 0 5 11.421052632 2.5 5 11.421052632 +5 5 11.421052632 7.5 5 11.421052632 10 5 11.421052632 +0 5.8326451979 11.421052632 2.5 5.8326451979 11.421052632 5 5.8326451979 11.421052632 +7.5 5.8326451979 11.421052632 10 5.8326451979 11.421052632 0 6.8039500009 11.421052632 +2.5 6.8039500009 11.421052632 5 6.8039500009 11.421052632 7.5 6.8039500009 11.421052632 +10 6.8039500009 11.421052632 0 7.9370052598 11.421052632 2.5 7.9370052598 11.421052632 +5 7.9370052598 11.421052632 7.5 7.9370052598 11.421052632 10 7.9370052598 11.421052632 +0 9.2587471229 11.421052632 2.5 9.2587471229 11.421052632 5 9.2587471229 11.421052632 +7.5 9.2587471229 11.421052632 10 9.2587471229 11.421052632 0 10.800597389 11.421052632 +2.5 10.800597389 11.421052632 5 10.800597389 11.421052632 7.5 10.800597389 11.421052632 +10 10.800597389 11.421052632 0 12.599210499 11.421052632 2.5 12.599210499 11.421052632 +5 12.599210499 11.421052632 7.5 12.599210499 11.421052632 10 12.599210499 11.421052632 +0 14.697344923 11.421052632 2.5 14.697344923 11.421052632 5 14.697344923 11.421052632 +7.5 14.697344923 11.421052632 10 14.697344923 11.421052632 0 17.144879657 11.421052632 +2.5 17.144879657 11.421052632 5 17.144879657 11.421052632 7.5 17.144879657 11.421052632 +10 17.144879657 11.421052632 0 20 11.421052632 2.5 20 11.421052632 +5 20 11.421052632 7.5 20 11.421052632 10 20 11.421052632 +0 5 16.631578947 2.5 5 16.631578947 5 5 16.631578947 +7.5 5 16.631578947 10 5 16.631578947 0 5.8326451979 16.631578947 +2.5 5.8326451979 16.631578947 5 5.8326451979 16.631578947 7.5 5.8326451979 16.631578947 +10 5.8326451979 16.631578947 0 6.8039500009 16.631578947 2.5 6.8039500009 16.631578947 +5 6.8039500009 16.631578947 7.5 6.8039500009 16.631578947 10 6.8039500009 16.631578947 +0 7.9370052598 16.631578947 2.5 7.9370052598 16.631578947 5 7.9370052598 16.631578947 +7.5 7.9370052598 16.631578947 10 7.9370052598 16.631578947 0 9.2587471229 16.631578947 +2.5 9.2587471229 16.631578947 5 9.2587471229 16.631578947 7.5 9.2587471229 16.631578947 +10 9.2587471229 16.631578947 0 10.800597389 16.631578947 2.5 10.800597389 16.631578947 +5 10.800597389 16.631578947 7.5 10.800597389 16.631578947 10 10.800597389 16.631578947 +0 12.599210499 16.631578947 2.5 12.599210499 16.631578947 5 12.599210499 16.631578947 +7.5 12.599210499 16.631578947 10 12.599210499 16.631578947 0 14.697344923 16.631578947 +2.5 14.697344923 16.631578947 5 14.697344923 16.631578947 7.5 14.697344923 16.631578947 +10 14.697344923 16.631578947 0 17.144879657 16.631578947 2.5 17.144879657 16.631578947 +5 17.144879657 16.631578947 7.5 17.144879657 16.631578947 10 17.144879657 16.631578947 +0 20 16.631578947 2.5 20 16.631578947 5 20 16.631578947 +7.5 20 16.631578947 10 20 16.631578947 0 5 21.842105263 +2.5 5 21.842105263 5 5 21.842105263 7.5 5 21.842105263 +10 5 21.842105263 0 5.8326451979 21.842105263 2.5 5.8326451979 21.842105263 +5 5.8326451979 21.842105263 7.5 5.8326451979 21.842105263 10 5.8326451979 21.842105263 +0 6.8039500009 21.842105263 2.5 6.8039500009 21.842105263 5 6.8039500009 21.842105263 +7.5 6.8039500009 21.842105263 10 6.8039500009 21.842105263 0 7.9370052598 21.842105263 +2.5 7.9370052598 21.842105263 5 7.9370052598 21.842105263 7.5 7.9370052598 21.842105263 +10 7.9370052598 21.842105263 0 9.2587471229 21.842105263 2.5 9.2587471229 21.842105263 +5 9.2587471229 21.842105263 7.5 9.2587471229 21.842105263 10 9.2587471229 21.842105263 +0 10.800597389 21.842105263 2.5 10.800597389 21.842105263 5 10.800597389 21.842105263 +7.5 10.800597389 21.842105263 10 10.800597389 21.842105263 0 12.599210499 21.842105263 +2.5 12.599210499 21.842105263 5 12.599210499 21.842105263 7.5 12.599210499 21.842105263 +10 12.599210499 21.842105263 0 14.697344923 21.842105263 2.5 14.697344923 21.842105263 +5 14.697344923 21.842105263 7.5 14.697344923 21.842105263 10 14.697344923 21.842105263 +0 17.144879657 21.842105263 2.5 17.144879657 21.842105263 5 17.144879657 21.842105263 +7.5 17.144879657 21.842105263 10 17.144879657 21.842105263 0 20 21.842105263 +2.5 20 21.842105263 5 20 21.842105263 7.5 20 21.842105263 +10 20 21.842105263 0 5 27.052631579 2.5 5 27.052631579 +5 5 27.052631579 7.5 5 27.052631579 10 5 27.052631579 +0 5.8326451979 27.052631579 2.5 5.8326451979 27.052631579 5 5.8326451979 27.052631579 +7.5 5.8326451979 27.052631579 10 5.8326451979 27.052631579 0 6.8039500009 27.052631579 +2.5 6.8039500009 27.052631579 5 6.8039500009 27.052631579 7.5 6.8039500009 27.052631579 +10 6.8039500009 27.052631579 0 7.9370052598 27.052631579 2.5 7.9370052598 27.052631579 +5 7.9370052598 27.052631579 7.5 7.9370052598 27.052631579 10 7.9370052598 27.052631579 +0 9.2587471229 27.052631579 2.5 9.2587471229 27.052631579 5 9.2587471229 27.052631579 +7.5 9.2587471229 27.052631579 10 9.2587471229 27.052631579 0 10.800597389 27.052631579 +2.5 10.800597389 27.052631579 5 10.800597389 27.052631579 7.5 10.800597389 27.052631579 +10 10.800597389 27.052631579 0 12.599210499 27.052631579 2.5 12.599210499 27.052631579 +5 12.599210499 27.052631579 7.5 12.599210499 27.052631579 10 12.599210499 27.052631579 +0 14.697344923 27.052631579 2.5 14.697344923 27.052631579 5 14.697344923 27.052631579 +7.5 14.697344923 27.052631579 10 14.697344923 27.052631579 0 17.144879657 27.052631579 +2.5 17.144879657 27.052631579 5 17.144879657 27.052631579 7.5 17.144879657 27.052631579 +10 17.144879657 27.052631579 0 20 27.052631579 2.5 20 27.052631579 +5 20 27.052631579 7.5 20 27.052631579 10 20 27.052631579 +0 5 32.263157895 2.5 5 32.263157895 5 5 32.263157895 +7.5 5 32.263157895 10 5 32.263157895 0 5.8326451979 32.263157895 +2.5 5.8326451979 32.263157895 5 5.8326451979 32.263157895 7.5 5.8326451979 32.263157895 +10 5.8326451979 32.263157895 0 6.8039500009 32.263157895 2.5 6.8039500009 32.263157895 +5 6.8039500009 32.263157895 7.5 6.8039500009 32.263157895 10 6.8039500009 32.263157895 +0 7.9370052598 32.263157895 2.5 7.9370052598 32.263157895 5 7.9370052598 32.263157895 +7.5 7.9370052598 32.263157895 10 7.9370052598 32.263157895 0 9.2587471229 32.263157895 +2.5 9.2587471229 32.263157895 5 9.2587471229 32.263157895 7.5 9.2587471229 32.263157895 +10 9.2587471229 32.263157895 0 10.800597389 32.263157895 2.5 10.800597389 32.263157895 +5 10.800597389 32.263157895 7.5 10.800597389 32.263157895 10 10.800597389 32.263157895 +0 12.599210499 32.263157895 2.5 12.599210499 32.263157895 5 12.599210499 32.263157895 +7.5 12.599210499 32.263157895 10 12.599210499 32.263157895 0 14.697344923 32.263157895 +2.5 14.697344923 32.263157895 5 14.697344923 32.263157895 7.5 14.697344923 32.263157895 +10 14.697344923 32.263157895 0 17.144879657 32.263157895 2.5 17.144879657 32.263157895 +5 17.144879657 32.263157895 7.5 17.144879657 32.263157895 10 17.144879657 32.263157895 +0 20 32.263157895 2.5 20 32.263157895 5 20 32.263157895 +7.5 20 32.263157895 10 20 32.263157895 0 5 37.473684211 +2.5 5 37.473684211 5 5 37.473684211 7.5 5 37.473684211 +10 5 37.473684211 0 5.8326451979 37.473684211 2.5 5.8326451979 37.473684211 +5 5.8326451979 37.473684211 7.5 5.8326451979 37.473684211 10 5.8326451979 37.473684211 +0 6.8039500009 37.473684211 2.5 6.8039500009 37.473684211 5 6.8039500009 37.473684211 +7.5 6.8039500009 37.473684211 10 6.8039500009 37.473684211 0 7.9370052598 37.473684211 +2.5 7.9370052598 37.473684211 5 7.9370052598 37.473684211 7.5 7.9370052598 37.473684211 +10 7.9370052598 37.473684211 0 9.2587471229 37.473684211 2.5 9.2587471229 37.473684211 +5 9.2587471229 37.473684211 7.5 9.2587471229 37.473684211 10 9.2587471229 37.473684211 +0 10.800597389 37.473684211 2.5 10.800597389 37.473684211 5 10.800597389 37.473684211 +7.5 10.800597389 37.473684211 10 10.800597389 37.473684211 0 12.599210499 37.473684211 +2.5 12.599210499 37.473684211 5 12.599210499 37.473684211 7.5 12.599210499 37.473684211 +10 12.599210499 37.473684211 0 14.697344923 37.473684211 2.5 14.697344923 37.473684211 +5 14.697344923 37.473684211 7.5 14.697344923 37.473684211 10 14.697344923 37.473684211 +0 17.144879657 37.473684211 2.5 17.144879657 37.473684211 5 17.144879657 37.473684211 +7.5 17.144879657 37.473684211 10 17.144879657 37.473684211 0 20 37.473684211 +2.5 20 37.473684211 5 20 37.473684211 7.5 20 37.473684211 +10 20 37.473684211 0 5 42.684210526 2.5 5 42.684210526 +5 5 42.684210526 7.5 5 42.684210526 10 5 42.684210526 +0 5.8326451979 42.684210526 2.5 5.8326451979 42.684210526 5 5.8326451979 42.684210526 +7.5 5.8326451979 42.684210526 10 5.8326451979 42.684210526 0 6.8039500009 42.684210526 +2.5 6.8039500009 42.684210526 5 6.8039500009 42.684210526 7.5 6.8039500009 42.684210526 +10 6.8039500009 42.684210526 0 7.9370052598 42.684210526 2.5 7.9370052598 42.684210526 +5 7.9370052598 42.684210526 7.5 7.9370052598 42.684210526 10 7.9370052598 42.684210526 +0 9.2587471229 42.684210526 2.5 9.2587471229 42.684210526 5 9.2587471229 42.684210526 +7.5 9.2587471229 42.684210526 10 9.2587471229 42.684210526 0 10.800597389 42.684210526 +2.5 10.800597389 42.684210526 5 10.800597389 42.684210526 7.5 10.800597389 42.684210526 +10 10.800597389 42.684210526 0 12.599210499 42.684210526 2.5 12.599210499 42.684210526 +5 12.599210499 42.684210526 7.5 12.599210499 42.684210526 10 12.599210499 42.684210526 +0 14.697344923 42.684210526 2.5 14.697344923 42.684210526 5 14.697344923 42.684210526 +7.5 14.697344923 42.684210526 10 14.697344923 42.684210526 0 17.144879657 42.684210526 +2.5 17.144879657 42.684210526 5 17.144879657 42.684210526 7.5 17.144879657 42.684210526 +10 17.144879657 42.684210526 0 20 42.684210526 2.5 20 42.684210526 +5 20 42.684210526 7.5 20 42.684210526 10 20 42.684210526 +0 5 47.894736842 2.5 5 47.894736842 5 5 47.894736842 +7.5 5 47.894736842 10 5 47.894736842 0 5.8326451979 47.894736842 +2.5 5.8326451979 47.894736842 5 5.8326451979 47.894736842 7.5 5.8326451979 47.894736842 +10 5.8326451979 47.894736842 0 6.8039500009 47.894736842 2.5 6.8039500009 47.894736842 +5 6.8039500009 47.894736842 7.5 6.8039500009 47.894736842 10 6.8039500009 47.894736842 +0 7.9370052598 47.894736842 2.5 7.9370052598 47.894736842 5 7.9370052598 47.894736842 +7.5 7.9370052598 47.894736842 10 7.9370052598 47.894736842 0 9.2587471229 47.894736842 +2.5 9.2587471229 47.894736842 5 9.2587471229 47.894736842 7.5 9.2587471229 47.894736842 +10 9.2587471229 47.894736842 0 10.800597389 47.894736842 2.5 10.800597389 47.894736842 +5 10.800597389 47.894736842 7.5 10.800597389 47.894736842 10 10.800597389 47.894736842 +0 12.599210499 47.894736842 2.5 12.599210499 47.894736842 5 12.599210499 47.894736842 +7.5 12.599210499 47.894736842 10 12.599210499 47.894736842 0 14.697344923 47.894736842 +2.5 14.697344923 47.894736842 5 14.697344923 47.894736842 7.5 14.697344923 47.894736842 +10 14.697344923 47.894736842 0 17.144879657 47.894736842 2.5 17.144879657 47.894736842 +5 17.144879657 47.894736842 7.5 17.144879657 47.894736842 10 17.144879657 47.894736842 +0 20 47.894736842 2.5 20 47.894736842 5 20 47.894736842 +7.5 20 47.894736842 10 20 47.894736842 0 5 53.105263158 +2.5 5 53.105263158 5 5 53.105263158 7.5 5 53.105263158 +10 5 53.105263158 0 5.8326451979 53.105263158 2.5 5.8326451979 53.105263158 +5 5.8326451979 53.105263158 7.5 5.8326451979 53.105263158 10 5.8326451979 53.105263158 +0 6.8039500009 53.105263158 2.5 6.8039500009 53.105263158 5 6.8039500009 53.105263158 +7.5 6.8039500009 53.105263158 10 6.8039500009 53.105263158 0 7.9370052598 53.105263158 +2.5 7.9370052598 53.105263158 5 7.9370052598 53.105263158 7.5 7.9370052598 53.105263158 +10 7.9370052598 53.105263158 0 9.2587471229 53.105263158 2.5 9.2587471229 53.105263158 +5 9.2587471229 53.105263158 7.5 9.2587471229 53.105263158 10 9.2587471229 53.105263158 +0 10.800597389 53.105263158 2.5 10.800597389 53.105263158 5 10.800597389 53.105263158 +7.5 10.800597389 53.105263158 10 10.800597389 53.105263158 0 12.599210499 53.105263158 +2.5 12.599210499 53.105263158 5 12.599210499 53.105263158 7.5 12.599210499 53.105263158 +10 12.599210499 53.105263158 0 14.697344923 53.105263158 2.5 14.697344923 53.105263158 +5 14.697344923 53.105263158 7.5 14.697344923 53.105263158 10 14.697344923 53.105263158 +0 17.144879657 53.105263158 2.5 17.144879657 53.105263158 5 17.144879657 53.105263158 +7.5 17.144879657 53.105263158 10 17.144879657 53.105263158 0 20 53.105263158 +2.5 20 53.105263158 5 20 53.105263158 7.5 20 53.105263158 +10 20 53.105263158 0 5 58.315789474 2.5 5 58.315789474 +5 5 58.315789474 7.5 5 58.315789474 10 5 58.315789474 +0 5.8326451979 58.315789474 2.5 5.8326451979 58.315789474 5 5.8326451979 58.315789474 +7.5 5.8326451979 58.315789474 10 5.8326451979 58.315789474 0 6.8039500009 58.315789474 +2.5 6.8039500009 58.315789474 5 6.8039500009 58.315789474 7.5 6.8039500009 58.315789474 +10 6.8039500009 58.315789474 0 7.9370052598 58.315789474 2.5 7.9370052598 58.315789474 +5 7.9370052598 58.315789474 7.5 7.9370052598 58.315789474 10 7.9370052598 58.315789474 +0 9.2587471229 58.315789474 2.5 9.2587471229 58.315789474 5 9.2587471229 58.315789474 +7.5 9.2587471229 58.315789474 10 9.2587471229 58.315789474 0 10.800597389 58.315789474 +2.5 10.800597389 58.315789474 5 10.800597389 58.315789474 7.5 10.800597389 58.315789474 +10 10.800597389 58.315789474 0 12.599210499 58.315789474 2.5 12.599210499 58.315789474 +5 12.599210499 58.315789474 7.5 12.599210499 58.315789474 10 12.599210499 58.315789474 +0 14.697344923 58.315789474 2.5 14.697344923 58.315789474 5 14.697344923 58.315789474 +7.5 14.697344923 58.315789474 10 14.697344923 58.315789474 0 17.144879657 58.315789474 +2.5 17.144879657 58.315789474 5 17.144879657 58.315789474 7.5 17.144879657 58.315789474 +10 17.144879657 58.315789474 0 20 58.315789474 2.5 20 58.315789474 +5 20 58.315789474 7.5 20 58.315789474 10 20 58.315789474 +0 5 63.526315789 2.5 5 63.526315789 5 5 63.526315789 +7.5 5 63.526315789 10 5 63.526315789 0 5.8326451979 63.526315789 +2.5 5.8326451979 63.526315789 5 5.8326451979 63.526315789 7.5 5.8326451979 63.526315789 +10 5.8326451979 63.526315789 0 6.8039500009 63.526315789 2.5 6.8039500009 63.526315789 +5 6.8039500009 63.526315789 7.5 6.8039500009 63.526315789 10 6.8039500009 63.526315789 +0 7.9370052598 63.526315789 2.5 7.9370052598 63.526315789 5 7.9370052598 63.526315789 +7.5 7.9370052598 63.526315789 10 7.9370052598 63.526315789 0 9.2587471229 63.526315789 +2.5 9.2587471229 63.526315789 5 9.2587471229 63.526315789 7.5 9.2587471229 63.526315789 +10 9.2587471229 63.526315789 0 10.800597389 63.526315789 2.5 10.800597389 63.526315789 +5 10.800597389 63.526315789 7.5 10.800597389 63.526315789 10 10.800597389 63.526315789 +0 12.599210499 63.526315789 2.5 12.599210499 63.526315789 5 12.599210499 63.526315789 +7.5 12.599210499 63.526315789 10 12.599210499 63.526315789 0 14.697344923 63.526315789 +2.5 14.697344923 63.526315789 5 14.697344923 63.526315789 7.5 14.697344923 63.526315789 +10 14.697344923 63.526315789 0 17.144879657 63.526315789 2.5 17.144879657 63.526315789 +5 17.144879657 63.526315789 7.5 17.144879657 63.526315789 10 17.144879657 63.526315789 +0 20 63.526315789 2.5 20 63.526315789 5 20 63.526315789 +7.5 20 63.526315789 10 20 63.526315789 0 5 68.736842105 +2.5 5 68.736842105 5 5 68.736842105 7.5 5 68.736842105 +10 5 68.736842105 0 5.8326451979 68.736842105 2.5 5.8326451979 68.736842105 +5 5.8326451979 68.736842105 7.5 5.8326451979 68.736842105 10 5.8326451979 68.736842105 +0 6.8039500009 68.736842105 2.5 6.8039500009 68.736842105 5 6.8039500009 68.736842105 +7.5 6.8039500009 68.736842105 10 6.8039500009 68.736842105 0 7.9370052598 68.736842105 +2.5 7.9370052598 68.736842105 5 7.9370052598 68.736842105 7.5 7.9370052598 68.736842105 +10 7.9370052598 68.736842105 0 9.2587471229 68.736842105 2.5 9.2587471229 68.736842105 +5 9.2587471229 68.736842105 7.5 9.2587471229 68.736842105 10 9.2587471229 68.736842105 +0 10.800597389 68.736842105 2.5 10.800597389 68.736842105 5 10.800597389 68.736842105 +7.5 10.800597389 68.736842105 10 10.800597389 68.736842105 0 12.599210499 68.736842105 +2.5 12.599210499 68.736842105 5 12.599210499 68.736842105 7.5 12.599210499 68.736842105 +10 12.599210499 68.736842105 0 14.697344923 68.736842105 2.5 14.697344923 68.736842105 +5 14.697344923 68.736842105 7.5 14.697344923 68.736842105 10 14.697344923 68.736842105 +0 17.144879657 68.736842105 2.5 17.144879657 68.736842105 5 17.144879657 68.736842105 +7.5 17.144879657 68.736842105 10 17.144879657 68.736842105 0 20 68.736842105 +2.5 20 68.736842105 5 20 68.736842105 7.5 20 68.736842105 +10 20 68.736842105 0 5 73.947368421 2.5 5 73.947368421 +5 5 73.947368421 7.5 5 73.947368421 10 5 73.947368421 +0 5.8326451979 73.947368421 2.5 5.8326451979 73.947368421 5 5.8326451979 73.947368421 +7.5 5.8326451979 73.947368421 10 5.8326451979 73.947368421 0 6.8039500009 73.947368421 +2.5 6.8039500009 73.947368421 5 6.8039500009 73.947368421 7.5 6.8039500009 73.947368421 +10 6.8039500009 73.947368421 0 7.9370052598 73.947368421 2.5 7.9370052598 73.947368421 +5 7.9370052598 73.947368421 7.5 7.9370052598 73.947368421 10 7.9370052598 73.947368421 +0 9.2587471229 73.947368421 2.5 9.2587471229 73.947368421 5 9.2587471229 73.947368421 +7.5 9.2587471229 73.947368421 10 9.2587471229 73.947368421 0 10.800597389 73.947368421 +2.5 10.800597389 73.947368421 5 10.800597389 73.947368421 7.5 10.800597389 73.947368421 +10 10.800597389 73.947368421 0 12.599210499 73.947368421 2.5 12.599210499 73.947368421 +5 12.599210499 73.947368421 7.5 12.599210499 73.947368421 10 12.599210499 73.947368421 +0 14.697344923 73.947368421 2.5 14.697344923 73.947368421 5 14.697344923 73.947368421 +7.5 14.697344923 73.947368421 10 14.697344923 73.947368421 0 17.144879657 73.947368421 +2.5 17.144879657 73.947368421 5 17.144879657 73.947368421 7.5 17.144879657 73.947368421 +10 17.144879657 73.947368421 0 20 73.947368421 2.5 20 73.947368421 +5 20 73.947368421 7.5 20 73.947368421 10 20 73.947368421 +0 5 79.157894737 2.5 5 79.157894737 5 5 79.157894737 +7.5 5 79.157894737 10 5 79.157894737 0 5.8326451979 79.157894737 +2.5 5.8326451979 79.157894737 5 5.8326451979 79.157894737 7.5 5.8326451979 79.157894737 +10 5.8326451979 79.157894737 0 6.8039500009 79.157894737 2.5 6.8039500009 79.157894737 +5 6.8039500009 79.157894737 7.5 6.8039500009 79.157894737 10 6.8039500009 79.157894737 +0 7.9370052598 79.157894737 2.5 7.9370052598 79.157894737 5 7.9370052598 79.157894737 +7.5 7.9370052598 79.157894737 10 7.9370052598 79.157894737 0 9.2587471229 79.157894737 +2.5 9.2587471229 79.157894737 5 9.2587471229 79.157894737 7.5 9.2587471229 79.157894737 +10 9.2587471229 79.157894737 0 10.800597389 79.157894737 2.5 10.800597389 79.157894737 +5 10.800597389 79.157894737 7.5 10.800597389 79.157894737 10 10.800597389 79.157894737 +0 12.599210499 79.157894737 2.5 12.599210499 79.157894737 5 12.599210499 79.157894737 +7.5 12.599210499 79.157894737 10 12.599210499 79.157894737 0 14.697344923 79.157894737 +2.5 14.697344923 79.157894737 5 14.697344923 79.157894737 7.5 14.697344923 79.157894737 +10 14.697344923 79.157894737 0 17.144879657 79.157894737 2.5 17.144879657 79.157894737 +5 17.144879657 79.157894737 7.5 17.144879657 79.157894737 10 17.144879657 79.157894737 +0 20 79.157894737 2.5 20 79.157894737 5 20 79.157894737 +7.5 20 79.157894737 10 20 79.157894737 0 5 84.368421053 +2.5 5 84.368421053 5 5 84.368421053 7.5 5 84.368421053 +10 5 84.368421053 0 5.8326451979 84.368421053 2.5 5.8326451979 84.368421053 +5 5.8326451979 84.368421053 7.5 5.8326451979 84.368421053 10 5.8326451979 84.368421053 +0 6.8039500009 84.368421053 2.5 6.8039500009 84.368421053 5 6.8039500009 84.368421053 +7.5 6.8039500009 84.368421053 10 6.8039500009 84.368421053 0 7.9370052598 84.368421053 +2.5 7.9370052598 84.368421053 5 7.9370052598 84.368421053 7.5 7.9370052598 84.368421053 +10 7.9370052598 84.368421053 0 9.2587471229 84.368421053 2.5 9.2587471229 84.368421053 +5 9.2587471229 84.368421053 7.5 9.2587471229 84.368421053 10 9.2587471229 84.368421053 +0 10.800597389 84.368421053 2.5 10.800597389 84.368421053 5 10.800597389 84.368421053 +7.5 10.800597389 84.368421053 10 10.800597389 84.368421053 0 12.599210499 84.368421053 +2.5 12.599210499 84.368421053 5 12.599210499 84.368421053 7.5 12.599210499 84.368421053 +10 12.599210499 84.368421053 0 14.697344923 84.368421053 2.5 14.697344923 84.368421053 +5 14.697344923 84.368421053 7.5 14.697344923 84.368421053 10 14.697344923 84.368421053 +0 17.144879657 84.368421053 2.5 17.144879657 84.368421053 5 17.144879657 84.368421053 +7.5 17.144879657 84.368421053 10 17.144879657 84.368421053 0 20 84.368421053 +2.5 20 84.368421053 5 20 84.368421053 7.5 20 84.368421053 +10 20 84.368421053 0 5 89.578947368 2.5 5 89.578947368 +5 5 89.578947368 7.5 5 89.578947368 10 5 89.578947368 +0 5.8326451979 89.578947368 2.5 5.8326451979 89.578947368 5 5.8326451979 89.578947368 +7.5 5.8326451979 89.578947368 10 5.8326451979 89.578947368 0 6.8039500009 89.578947368 +2.5 6.8039500009 89.578947368 5 6.8039500009 89.578947368 7.5 6.8039500009 89.578947368 +10 6.8039500009 89.578947368 0 7.9370052598 89.578947368 2.5 7.9370052598 89.578947368 +5 7.9370052598 89.578947368 7.5 7.9370052598 89.578947368 10 7.9370052598 89.578947368 +0 9.2587471229 89.578947368 2.5 9.2587471229 89.578947368 5 9.2587471229 89.578947368 +7.5 9.2587471229 89.578947368 10 9.2587471229 89.578947368 0 10.800597389 89.578947368 +2.5 10.800597389 89.578947368 5 10.800597389 89.578947368 7.5 10.800597389 89.578947368 +10 10.800597389 89.578947368 0 12.599210499 89.578947368 2.5 12.599210499 89.578947368 +5 12.599210499 89.578947368 7.5 12.599210499 89.578947368 10 12.599210499 89.578947368 +0 14.697344923 89.578947368 2.5 14.697344923 89.578947368 5 14.697344923 89.578947368 +7.5 14.697344923 89.578947368 10 14.697344923 89.578947368 0 17.144879657 89.578947368 +2.5 17.144879657 89.578947368 5 17.144879657 89.578947368 7.5 17.144879657 89.578947368 +10 17.144879657 89.578947368 0 20 89.578947368 2.5 20 89.578947368 +5 20 89.578947368 7.5 20 89.578947368 10 20 89.578947368 +0 5 94.789473684 2.5 5 94.789473684 5 5 94.789473684 +7.5 5 94.789473684 10 5 94.789473684 0 5.8326451979 94.789473684 +2.5 5.8326451979 94.789473684 5 5.8326451979 94.789473684 7.5 5.8326451979 94.789473684 +10 5.8326451979 94.789473684 0 6.8039500009 94.789473684 2.5 6.8039500009 94.789473684 +5 6.8039500009 94.789473684 7.5 6.8039500009 94.789473684 10 6.8039500009 94.789473684 +0 7.9370052598 94.789473684 2.5 7.9370052598 94.789473684 5 7.9370052598 94.789473684 +7.5 7.9370052598 94.789473684 10 7.9370052598 94.789473684 0 9.2587471229 94.789473684 +2.5 9.2587471229 94.789473684 5 9.2587471229 94.789473684 7.5 9.2587471229 94.789473684 +10 9.2587471229 94.789473684 0 10.800597389 94.789473684 2.5 10.800597389 94.789473684 +5 10.800597389 94.789473684 7.5 10.800597389 94.789473684 10 10.800597389 94.789473684 +0 12.599210499 94.789473684 2.5 12.599210499 94.789473684 5 12.599210499 94.789473684 +7.5 12.599210499 94.789473684 10 12.599210499 94.789473684 0 14.697344923 94.789473684 +2.5 14.697344923 94.789473684 5 14.697344923 94.789473684 7.5 14.697344923 94.789473684 +10 14.697344923 94.789473684 0 17.144879657 94.789473684 2.5 17.144879657 94.789473684 +5 17.144879657 94.789473684 7.5 17.144879657 94.789473684 10 17.144879657 94.789473684 +0 20 94.789473684 2.5 20 94.789473684 5 20 94.789473684 +7.5 20 94.789473684 10 20 94.789473684 0 5 100 +2.5 5 100 5 5 100 7.5 5 100 +10 5 100 0 5.8326451979 100 2.5 5.8326451979 100 +5 5.8326451979 100 7.5 5.8326451979 100 10 5.8326451979 100 +0 6.8039500009 100 2.5 6.8039500009 100 5 6.8039500009 100 +7.5 6.8039500009 100 10 6.8039500009 100 0 7.9370052598 100 +2.5 7.9370052598 100 5 7.9370052598 100 7.5 7.9370052598 100 +10 7.9370052598 100 0 9.2587471229 100 2.5 9.2587471229 100 +5 9.2587471229 100 7.5 9.2587471229 100 10 9.2587471229 100 +0 10.800597389 100 2.5 10.800597389 100 5 10.800597389 100 +7.5 10.800597389 100 10 10.800597389 100 0 12.599210499 100 +2.5 12.599210499 100 5 12.599210499 100 7.5 12.599210499 100 +10 12.599210499 100 0 14.697344923 100 2.5 14.697344923 100 +5 14.697344923 100 7.5 14.697344923 100 10 14.697344923 100 +0 17.144879657 100 2.5 17.144879657 100 5 17.144879657 100 +7.5 17.144879657 100 10 17.144879657 100 0 20 100 +2.5 20 100 5 20 100 7.5 20 100 +10 20 100 diff --git a/tests/unit_tests/mesh_to_vtk/regular.vtk b/tests/unit_tests/mesh_to_vtk/regular.vtk new file mode 100644 index 00000000000..8f8aca5a620 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/regular.vtk @@ -0,0 +1,2394 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 11 21 31 +POINTS 7161 double +0 0 0 2 0 0 4 0 0 +6 0 0 8 0 0 10 0 0 +12 0 0 14 0 0 16 0 0 +18 0 0 20 0 0 0 2.5 0 +2 2.5 0 4 2.5 0 6 2.5 0 +8 2.5 0 10 2.5 0 12 2.5 0 +14 2.5 0 16 2.5 0 18 2.5 0 +20 2.5 0 0 5 0 2 5 0 +4 5 0 6 5 0 8 5 0 +10 5 0 12 5 0 14 5 0 +16 5 0 18 5 0 20 5 0 +0 7.5 0 2 7.5 0 4 7.5 0 +6 7.5 0 8 7.5 0 10 7.5 0 +12 7.5 0 14 7.5 0 16 7.5 0 +18 7.5 0 20 7.5 0 0 10 0 +2 10 0 4 10 0 6 10 0 +8 10 0 10 10 0 12 10 0 +14 10 0 16 10 0 18 10 0 +20 10 0 0 12.5 0 2 12.5 0 +4 12.5 0 6 12.5 0 8 12.5 0 +10 12.5 0 12 12.5 0 14 12.5 0 +16 12.5 0 18 12.5 0 20 12.5 0 +0 15 0 2 15 0 4 15 0 +6 15 0 8 15 0 10 15 0 +12 15 0 14 15 0 16 15 0 +18 15 0 20 15 0 0 17.5 0 +2 17.5 0 4 17.5 0 6 17.5 0 +8 17.5 0 10 17.5 0 12 17.5 0 +14 17.5 0 16 17.5 0 18 17.5 0 +20 17.5 0 0 20 0 2 20 0 +4 20 0 6 20 0 8 20 0 +10 20 0 12 20 0 14 20 0 +16 20 0 18 20 0 20 20 0 +0 22.5 0 2 22.5 0 4 22.5 0 +6 22.5 0 8 22.5 0 10 22.5 0 +12 22.5 0 14 22.5 0 16 22.5 0 +18 22.5 0 20 22.5 0 0 25 0 +2 25 0 4 25 0 6 25 0 +8 25 0 10 25 0 12 25 0 +14 25 0 16 25 0 18 25 0 +20 25 0 0 27.5 0 2 27.5 0 +4 27.5 0 6 27.5 0 8 27.5 0 +10 27.5 0 12 27.5 0 14 27.5 0 +16 27.5 0 18 27.5 0 20 27.5 0 +0 30 0 2 30 0 4 30 0 +6 30 0 8 30 0 10 30 0 +12 30 0 14 30 0 16 30 0 +18 30 0 20 30 0 0 32.5 0 +2 32.5 0 4 32.5 0 6 32.5 0 +8 32.5 0 10 32.5 0 12 32.5 0 +14 32.5 0 16 32.5 0 18 32.5 0 +20 32.5 0 0 35 0 2 35 0 +4 35 0 6 35 0 8 35 0 +10 35 0 12 35 0 14 35 0 +16 35 0 18 35 0 20 35 0 +0 37.5 0 2 37.5 0 4 37.5 0 +6 37.5 0 8 37.5 0 10 37.5 0 +12 37.5 0 14 37.5 0 16 37.5 0 +18 37.5 0 20 37.5 0 0 40 0 +2 40 0 4 40 0 6 40 0 +8 40 0 10 40 0 12 40 0 +14 40 0 16 40 0 18 40 0 +20 40 0 0 42.5 0 2 42.5 0 +4 42.5 0 6 42.5 0 8 42.5 0 +10 42.5 0 12 42.5 0 14 42.5 0 +16 42.5 0 18 42.5 0 20 42.5 0 +0 45 0 2 45 0 4 45 0 +6 45 0 8 45 0 10 45 0 +12 45 0 14 45 0 16 45 0 +18 45 0 20 45 0 0 47.5 0 +2 47.5 0 4 47.5 0 6 47.5 0 +8 47.5 0 10 47.5 0 12 47.5 0 +14 47.5 0 16 47.5 0 18 47.5 0 +20 47.5 0 0 50 0 2 50 0 +4 50 0 6 50 0 8 50 0 +10 50 0 12 50 0 14 50 0 +16 50 0 18 50 0 20 50 0 +0 0 1.6666666667 2 0 1.6666666667 4 0 1.6666666667 +6 0 1.6666666667 8 0 1.6666666667 10 0 1.6666666667 +12 0 1.6666666667 14 0 1.6666666667 16 0 1.6666666667 +18 0 1.6666666667 20 0 1.6666666667 0 2.5 1.6666666667 +2 2.5 1.6666666667 4 2.5 1.6666666667 6 2.5 1.6666666667 +8 2.5 1.6666666667 10 2.5 1.6666666667 12 2.5 1.6666666667 +14 2.5 1.6666666667 16 2.5 1.6666666667 18 2.5 1.6666666667 +20 2.5 1.6666666667 0 5 1.6666666667 2 5 1.6666666667 +4 5 1.6666666667 6 5 1.6666666667 8 5 1.6666666667 +10 5 1.6666666667 12 5 1.6666666667 14 5 1.6666666667 +16 5 1.6666666667 18 5 1.6666666667 20 5 1.6666666667 +0 7.5 1.6666666667 2 7.5 1.6666666667 4 7.5 1.6666666667 +6 7.5 1.6666666667 8 7.5 1.6666666667 10 7.5 1.6666666667 +12 7.5 1.6666666667 14 7.5 1.6666666667 16 7.5 1.6666666667 +18 7.5 1.6666666667 20 7.5 1.6666666667 0 10 1.6666666667 +2 10 1.6666666667 4 10 1.6666666667 6 10 1.6666666667 +8 10 1.6666666667 10 10 1.6666666667 12 10 1.6666666667 +14 10 1.6666666667 16 10 1.6666666667 18 10 1.6666666667 +20 10 1.6666666667 0 12.5 1.6666666667 2 12.5 1.6666666667 +4 12.5 1.6666666667 6 12.5 1.6666666667 8 12.5 1.6666666667 +10 12.5 1.6666666667 12 12.5 1.6666666667 14 12.5 1.6666666667 +16 12.5 1.6666666667 18 12.5 1.6666666667 20 12.5 1.6666666667 +0 15 1.6666666667 2 15 1.6666666667 4 15 1.6666666667 +6 15 1.6666666667 8 15 1.6666666667 10 15 1.6666666667 +12 15 1.6666666667 14 15 1.6666666667 16 15 1.6666666667 +18 15 1.6666666667 20 15 1.6666666667 0 17.5 1.6666666667 +2 17.5 1.6666666667 4 17.5 1.6666666667 6 17.5 1.6666666667 +8 17.5 1.6666666667 10 17.5 1.6666666667 12 17.5 1.6666666667 +14 17.5 1.6666666667 16 17.5 1.6666666667 18 17.5 1.6666666667 +20 17.5 1.6666666667 0 20 1.6666666667 2 20 1.6666666667 +4 20 1.6666666667 6 20 1.6666666667 8 20 1.6666666667 +10 20 1.6666666667 12 20 1.6666666667 14 20 1.6666666667 +16 20 1.6666666667 18 20 1.6666666667 20 20 1.6666666667 +0 22.5 1.6666666667 2 22.5 1.6666666667 4 22.5 1.6666666667 +6 22.5 1.6666666667 8 22.5 1.6666666667 10 22.5 1.6666666667 +12 22.5 1.6666666667 14 22.5 1.6666666667 16 22.5 1.6666666667 +18 22.5 1.6666666667 20 22.5 1.6666666667 0 25 1.6666666667 +2 25 1.6666666667 4 25 1.6666666667 6 25 1.6666666667 +8 25 1.6666666667 10 25 1.6666666667 12 25 1.6666666667 +14 25 1.6666666667 16 25 1.6666666667 18 25 1.6666666667 +20 25 1.6666666667 0 27.5 1.6666666667 2 27.5 1.6666666667 +4 27.5 1.6666666667 6 27.5 1.6666666667 8 27.5 1.6666666667 +10 27.5 1.6666666667 12 27.5 1.6666666667 14 27.5 1.6666666667 +16 27.5 1.6666666667 18 27.5 1.6666666667 20 27.5 1.6666666667 +0 30 1.6666666667 2 30 1.6666666667 4 30 1.6666666667 +6 30 1.6666666667 8 30 1.6666666667 10 30 1.6666666667 +12 30 1.6666666667 14 30 1.6666666667 16 30 1.6666666667 +18 30 1.6666666667 20 30 1.6666666667 0 32.5 1.6666666667 +2 32.5 1.6666666667 4 32.5 1.6666666667 6 32.5 1.6666666667 +8 32.5 1.6666666667 10 32.5 1.6666666667 12 32.5 1.6666666667 +14 32.5 1.6666666667 16 32.5 1.6666666667 18 32.5 1.6666666667 +20 32.5 1.6666666667 0 35 1.6666666667 2 35 1.6666666667 +4 35 1.6666666667 6 35 1.6666666667 8 35 1.6666666667 +10 35 1.6666666667 12 35 1.6666666667 14 35 1.6666666667 +16 35 1.6666666667 18 35 1.6666666667 20 35 1.6666666667 +0 37.5 1.6666666667 2 37.5 1.6666666667 4 37.5 1.6666666667 +6 37.5 1.6666666667 8 37.5 1.6666666667 10 37.5 1.6666666667 +12 37.5 1.6666666667 14 37.5 1.6666666667 16 37.5 1.6666666667 +18 37.5 1.6666666667 20 37.5 1.6666666667 0 40 1.6666666667 +2 40 1.6666666667 4 40 1.6666666667 6 40 1.6666666667 +8 40 1.6666666667 10 40 1.6666666667 12 40 1.6666666667 +14 40 1.6666666667 16 40 1.6666666667 18 40 1.6666666667 +20 40 1.6666666667 0 42.5 1.6666666667 2 42.5 1.6666666667 +4 42.5 1.6666666667 6 42.5 1.6666666667 8 42.5 1.6666666667 +10 42.5 1.6666666667 12 42.5 1.6666666667 14 42.5 1.6666666667 +16 42.5 1.6666666667 18 42.5 1.6666666667 20 42.5 1.6666666667 +0 45 1.6666666667 2 45 1.6666666667 4 45 1.6666666667 +6 45 1.6666666667 8 45 1.6666666667 10 45 1.6666666667 +12 45 1.6666666667 14 45 1.6666666667 16 45 1.6666666667 +18 45 1.6666666667 20 45 1.6666666667 0 47.5 1.6666666667 +2 47.5 1.6666666667 4 47.5 1.6666666667 6 47.5 1.6666666667 +8 47.5 1.6666666667 10 47.5 1.6666666667 12 47.5 1.6666666667 +14 47.5 1.6666666667 16 47.5 1.6666666667 18 47.5 1.6666666667 +20 47.5 1.6666666667 0 50 1.6666666667 2 50 1.6666666667 +4 50 1.6666666667 6 50 1.6666666667 8 50 1.6666666667 +10 50 1.6666666667 12 50 1.6666666667 14 50 1.6666666667 +16 50 1.6666666667 18 50 1.6666666667 20 50 1.6666666667 +0 0 3.3333333333 2 0 3.3333333333 4 0 3.3333333333 +6 0 3.3333333333 8 0 3.3333333333 10 0 3.3333333333 +12 0 3.3333333333 14 0 3.3333333333 16 0 3.3333333333 +18 0 3.3333333333 20 0 3.3333333333 0 2.5 3.3333333333 +2 2.5 3.3333333333 4 2.5 3.3333333333 6 2.5 3.3333333333 +8 2.5 3.3333333333 10 2.5 3.3333333333 12 2.5 3.3333333333 +14 2.5 3.3333333333 16 2.5 3.3333333333 18 2.5 3.3333333333 +20 2.5 3.3333333333 0 5 3.3333333333 2 5 3.3333333333 +4 5 3.3333333333 6 5 3.3333333333 8 5 3.3333333333 +10 5 3.3333333333 12 5 3.3333333333 14 5 3.3333333333 +16 5 3.3333333333 18 5 3.3333333333 20 5 3.3333333333 +0 7.5 3.3333333333 2 7.5 3.3333333333 4 7.5 3.3333333333 +6 7.5 3.3333333333 8 7.5 3.3333333333 10 7.5 3.3333333333 +12 7.5 3.3333333333 14 7.5 3.3333333333 16 7.5 3.3333333333 +18 7.5 3.3333333333 20 7.5 3.3333333333 0 10 3.3333333333 +2 10 3.3333333333 4 10 3.3333333333 6 10 3.3333333333 +8 10 3.3333333333 10 10 3.3333333333 12 10 3.3333333333 +14 10 3.3333333333 16 10 3.3333333333 18 10 3.3333333333 +20 10 3.3333333333 0 12.5 3.3333333333 2 12.5 3.3333333333 +4 12.5 3.3333333333 6 12.5 3.3333333333 8 12.5 3.3333333333 +10 12.5 3.3333333333 12 12.5 3.3333333333 14 12.5 3.3333333333 +16 12.5 3.3333333333 18 12.5 3.3333333333 20 12.5 3.3333333333 +0 15 3.3333333333 2 15 3.3333333333 4 15 3.3333333333 +6 15 3.3333333333 8 15 3.3333333333 10 15 3.3333333333 +12 15 3.3333333333 14 15 3.3333333333 16 15 3.3333333333 +18 15 3.3333333333 20 15 3.3333333333 0 17.5 3.3333333333 +2 17.5 3.3333333333 4 17.5 3.3333333333 6 17.5 3.3333333333 +8 17.5 3.3333333333 10 17.5 3.3333333333 12 17.5 3.3333333333 +14 17.5 3.3333333333 16 17.5 3.3333333333 18 17.5 3.3333333333 +20 17.5 3.3333333333 0 20 3.3333333333 2 20 3.3333333333 +4 20 3.3333333333 6 20 3.3333333333 8 20 3.3333333333 +10 20 3.3333333333 12 20 3.3333333333 14 20 3.3333333333 +16 20 3.3333333333 18 20 3.3333333333 20 20 3.3333333333 +0 22.5 3.3333333333 2 22.5 3.3333333333 4 22.5 3.3333333333 +6 22.5 3.3333333333 8 22.5 3.3333333333 10 22.5 3.3333333333 +12 22.5 3.3333333333 14 22.5 3.3333333333 16 22.5 3.3333333333 +18 22.5 3.3333333333 20 22.5 3.3333333333 0 25 3.3333333333 +2 25 3.3333333333 4 25 3.3333333333 6 25 3.3333333333 +8 25 3.3333333333 10 25 3.3333333333 12 25 3.3333333333 +14 25 3.3333333333 16 25 3.3333333333 18 25 3.3333333333 +20 25 3.3333333333 0 27.5 3.3333333333 2 27.5 3.3333333333 +4 27.5 3.3333333333 6 27.5 3.3333333333 8 27.5 3.3333333333 +10 27.5 3.3333333333 12 27.5 3.3333333333 14 27.5 3.3333333333 +16 27.5 3.3333333333 18 27.5 3.3333333333 20 27.5 3.3333333333 +0 30 3.3333333333 2 30 3.3333333333 4 30 3.3333333333 +6 30 3.3333333333 8 30 3.3333333333 10 30 3.3333333333 +12 30 3.3333333333 14 30 3.3333333333 16 30 3.3333333333 +18 30 3.3333333333 20 30 3.3333333333 0 32.5 3.3333333333 +2 32.5 3.3333333333 4 32.5 3.3333333333 6 32.5 3.3333333333 +8 32.5 3.3333333333 10 32.5 3.3333333333 12 32.5 3.3333333333 +14 32.5 3.3333333333 16 32.5 3.3333333333 18 32.5 3.3333333333 +20 32.5 3.3333333333 0 35 3.3333333333 2 35 3.3333333333 +4 35 3.3333333333 6 35 3.3333333333 8 35 3.3333333333 +10 35 3.3333333333 12 35 3.3333333333 14 35 3.3333333333 +16 35 3.3333333333 18 35 3.3333333333 20 35 3.3333333333 +0 37.5 3.3333333333 2 37.5 3.3333333333 4 37.5 3.3333333333 +6 37.5 3.3333333333 8 37.5 3.3333333333 10 37.5 3.3333333333 +12 37.5 3.3333333333 14 37.5 3.3333333333 16 37.5 3.3333333333 +18 37.5 3.3333333333 20 37.5 3.3333333333 0 40 3.3333333333 +2 40 3.3333333333 4 40 3.3333333333 6 40 3.3333333333 +8 40 3.3333333333 10 40 3.3333333333 12 40 3.3333333333 +14 40 3.3333333333 16 40 3.3333333333 18 40 3.3333333333 +20 40 3.3333333333 0 42.5 3.3333333333 2 42.5 3.3333333333 +4 42.5 3.3333333333 6 42.5 3.3333333333 8 42.5 3.3333333333 +10 42.5 3.3333333333 12 42.5 3.3333333333 14 42.5 3.3333333333 +16 42.5 3.3333333333 18 42.5 3.3333333333 20 42.5 3.3333333333 +0 45 3.3333333333 2 45 3.3333333333 4 45 3.3333333333 +6 45 3.3333333333 8 45 3.3333333333 10 45 3.3333333333 +12 45 3.3333333333 14 45 3.3333333333 16 45 3.3333333333 +18 45 3.3333333333 20 45 3.3333333333 0 47.5 3.3333333333 +2 47.5 3.3333333333 4 47.5 3.3333333333 6 47.5 3.3333333333 +8 47.5 3.3333333333 10 47.5 3.3333333333 12 47.5 3.3333333333 +14 47.5 3.3333333333 16 47.5 3.3333333333 18 47.5 3.3333333333 +20 47.5 3.3333333333 0 50 3.3333333333 2 50 3.3333333333 +4 50 3.3333333333 6 50 3.3333333333 8 50 3.3333333333 +10 50 3.3333333333 12 50 3.3333333333 14 50 3.3333333333 +16 50 3.3333333333 18 50 3.3333333333 20 50 3.3333333333 +0 0 5 2 0 5 4 0 5 +6 0 5 8 0 5 10 0 5 +12 0 5 14 0 5 16 0 5 +18 0 5 20 0 5 0 2.5 5 +2 2.5 5 4 2.5 5 6 2.5 5 +8 2.5 5 10 2.5 5 12 2.5 5 +14 2.5 5 16 2.5 5 18 2.5 5 +20 2.5 5 0 5 5 2 5 5 +4 5 5 6 5 5 8 5 5 +10 5 5 12 5 5 14 5 5 +16 5 5 18 5 5 20 5 5 +0 7.5 5 2 7.5 5 4 7.5 5 +6 7.5 5 8 7.5 5 10 7.5 5 +12 7.5 5 14 7.5 5 16 7.5 5 +18 7.5 5 20 7.5 5 0 10 5 +2 10 5 4 10 5 6 10 5 +8 10 5 10 10 5 12 10 5 +14 10 5 16 10 5 18 10 5 +20 10 5 0 12.5 5 2 12.5 5 +4 12.5 5 6 12.5 5 8 12.5 5 +10 12.5 5 12 12.5 5 14 12.5 5 +16 12.5 5 18 12.5 5 20 12.5 5 +0 15 5 2 15 5 4 15 5 +6 15 5 8 15 5 10 15 5 +12 15 5 14 15 5 16 15 5 +18 15 5 20 15 5 0 17.5 5 +2 17.5 5 4 17.5 5 6 17.5 5 +8 17.5 5 10 17.5 5 12 17.5 5 +14 17.5 5 16 17.5 5 18 17.5 5 +20 17.5 5 0 20 5 2 20 5 +4 20 5 6 20 5 8 20 5 +10 20 5 12 20 5 14 20 5 +16 20 5 18 20 5 20 20 5 +0 22.5 5 2 22.5 5 4 22.5 5 +6 22.5 5 8 22.5 5 10 22.5 5 +12 22.5 5 14 22.5 5 16 22.5 5 +18 22.5 5 20 22.5 5 0 25 5 +2 25 5 4 25 5 6 25 5 +8 25 5 10 25 5 12 25 5 +14 25 5 16 25 5 18 25 5 +20 25 5 0 27.5 5 2 27.5 5 +4 27.5 5 6 27.5 5 8 27.5 5 +10 27.5 5 12 27.5 5 14 27.5 5 +16 27.5 5 18 27.5 5 20 27.5 5 +0 30 5 2 30 5 4 30 5 +6 30 5 8 30 5 10 30 5 +12 30 5 14 30 5 16 30 5 +18 30 5 20 30 5 0 32.5 5 +2 32.5 5 4 32.5 5 6 32.5 5 +8 32.5 5 10 32.5 5 12 32.5 5 +14 32.5 5 16 32.5 5 18 32.5 5 +20 32.5 5 0 35 5 2 35 5 +4 35 5 6 35 5 8 35 5 +10 35 5 12 35 5 14 35 5 +16 35 5 18 35 5 20 35 5 +0 37.5 5 2 37.5 5 4 37.5 5 +6 37.5 5 8 37.5 5 10 37.5 5 +12 37.5 5 14 37.5 5 16 37.5 5 +18 37.5 5 20 37.5 5 0 40 5 +2 40 5 4 40 5 6 40 5 +8 40 5 10 40 5 12 40 5 +14 40 5 16 40 5 18 40 5 +20 40 5 0 42.5 5 2 42.5 5 +4 42.5 5 6 42.5 5 8 42.5 5 +10 42.5 5 12 42.5 5 14 42.5 5 +16 42.5 5 18 42.5 5 20 42.5 5 +0 45 5 2 45 5 4 45 5 +6 45 5 8 45 5 10 45 5 +12 45 5 14 45 5 16 45 5 +18 45 5 20 45 5 0 47.5 5 +2 47.5 5 4 47.5 5 6 47.5 5 +8 47.5 5 10 47.5 5 12 47.5 5 +14 47.5 5 16 47.5 5 18 47.5 5 +20 47.5 5 0 50 5 2 50 5 +4 50 5 6 50 5 8 50 5 +10 50 5 12 50 5 14 50 5 +16 50 5 18 50 5 20 50 5 +0 0 6.6666666667 2 0 6.6666666667 4 0 6.6666666667 +6 0 6.6666666667 8 0 6.6666666667 10 0 6.6666666667 +12 0 6.6666666667 14 0 6.6666666667 16 0 6.6666666667 +18 0 6.6666666667 20 0 6.6666666667 0 2.5 6.6666666667 +2 2.5 6.6666666667 4 2.5 6.6666666667 6 2.5 6.6666666667 +8 2.5 6.6666666667 10 2.5 6.6666666667 12 2.5 6.6666666667 +14 2.5 6.6666666667 16 2.5 6.6666666667 18 2.5 6.6666666667 +20 2.5 6.6666666667 0 5 6.6666666667 2 5 6.6666666667 +4 5 6.6666666667 6 5 6.6666666667 8 5 6.6666666667 +10 5 6.6666666667 12 5 6.6666666667 14 5 6.6666666667 +16 5 6.6666666667 18 5 6.6666666667 20 5 6.6666666667 +0 7.5 6.6666666667 2 7.5 6.6666666667 4 7.5 6.6666666667 +6 7.5 6.6666666667 8 7.5 6.6666666667 10 7.5 6.6666666667 +12 7.5 6.6666666667 14 7.5 6.6666666667 16 7.5 6.6666666667 +18 7.5 6.6666666667 20 7.5 6.6666666667 0 10 6.6666666667 +2 10 6.6666666667 4 10 6.6666666667 6 10 6.6666666667 +8 10 6.6666666667 10 10 6.6666666667 12 10 6.6666666667 +14 10 6.6666666667 16 10 6.6666666667 18 10 6.6666666667 +20 10 6.6666666667 0 12.5 6.6666666667 2 12.5 6.6666666667 +4 12.5 6.6666666667 6 12.5 6.6666666667 8 12.5 6.6666666667 +10 12.5 6.6666666667 12 12.5 6.6666666667 14 12.5 6.6666666667 +16 12.5 6.6666666667 18 12.5 6.6666666667 20 12.5 6.6666666667 +0 15 6.6666666667 2 15 6.6666666667 4 15 6.6666666667 +6 15 6.6666666667 8 15 6.6666666667 10 15 6.6666666667 +12 15 6.6666666667 14 15 6.6666666667 16 15 6.6666666667 +18 15 6.6666666667 20 15 6.6666666667 0 17.5 6.6666666667 +2 17.5 6.6666666667 4 17.5 6.6666666667 6 17.5 6.6666666667 +8 17.5 6.6666666667 10 17.5 6.6666666667 12 17.5 6.6666666667 +14 17.5 6.6666666667 16 17.5 6.6666666667 18 17.5 6.6666666667 +20 17.5 6.6666666667 0 20 6.6666666667 2 20 6.6666666667 +4 20 6.6666666667 6 20 6.6666666667 8 20 6.6666666667 +10 20 6.6666666667 12 20 6.6666666667 14 20 6.6666666667 +16 20 6.6666666667 18 20 6.6666666667 20 20 6.6666666667 +0 22.5 6.6666666667 2 22.5 6.6666666667 4 22.5 6.6666666667 +6 22.5 6.6666666667 8 22.5 6.6666666667 10 22.5 6.6666666667 +12 22.5 6.6666666667 14 22.5 6.6666666667 16 22.5 6.6666666667 +18 22.5 6.6666666667 20 22.5 6.6666666667 0 25 6.6666666667 +2 25 6.6666666667 4 25 6.6666666667 6 25 6.6666666667 +8 25 6.6666666667 10 25 6.6666666667 12 25 6.6666666667 +14 25 6.6666666667 16 25 6.6666666667 18 25 6.6666666667 +20 25 6.6666666667 0 27.5 6.6666666667 2 27.5 6.6666666667 +4 27.5 6.6666666667 6 27.5 6.6666666667 8 27.5 6.6666666667 +10 27.5 6.6666666667 12 27.5 6.6666666667 14 27.5 6.6666666667 +16 27.5 6.6666666667 18 27.5 6.6666666667 20 27.5 6.6666666667 +0 30 6.6666666667 2 30 6.6666666667 4 30 6.6666666667 +6 30 6.6666666667 8 30 6.6666666667 10 30 6.6666666667 +12 30 6.6666666667 14 30 6.6666666667 16 30 6.6666666667 +18 30 6.6666666667 20 30 6.6666666667 0 32.5 6.6666666667 +2 32.5 6.6666666667 4 32.5 6.6666666667 6 32.5 6.6666666667 +8 32.5 6.6666666667 10 32.5 6.6666666667 12 32.5 6.6666666667 +14 32.5 6.6666666667 16 32.5 6.6666666667 18 32.5 6.6666666667 +20 32.5 6.6666666667 0 35 6.6666666667 2 35 6.6666666667 +4 35 6.6666666667 6 35 6.6666666667 8 35 6.6666666667 +10 35 6.6666666667 12 35 6.6666666667 14 35 6.6666666667 +16 35 6.6666666667 18 35 6.6666666667 20 35 6.6666666667 +0 37.5 6.6666666667 2 37.5 6.6666666667 4 37.5 6.6666666667 +6 37.5 6.6666666667 8 37.5 6.6666666667 10 37.5 6.6666666667 +12 37.5 6.6666666667 14 37.5 6.6666666667 16 37.5 6.6666666667 +18 37.5 6.6666666667 20 37.5 6.6666666667 0 40 6.6666666667 +2 40 6.6666666667 4 40 6.6666666667 6 40 6.6666666667 +8 40 6.6666666667 10 40 6.6666666667 12 40 6.6666666667 +14 40 6.6666666667 16 40 6.6666666667 18 40 6.6666666667 +20 40 6.6666666667 0 42.5 6.6666666667 2 42.5 6.6666666667 +4 42.5 6.6666666667 6 42.5 6.6666666667 8 42.5 6.6666666667 +10 42.5 6.6666666667 12 42.5 6.6666666667 14 42.5 6.6666666667 +16 42.5 6.6666666667 18 42.5 6.6666666667 20 42.5 6.6666666667 +0 45 6.6666666667 2 45 6.6666666667 4 45 6.6666666667 +6 45 6.6666666667 8 45 6.6666666667 10 45 6.6666666667 +12 45 6.6666666667 14 45 6.6666666667 16 45 6.6666666667 +18 45 6.6666666667 20 45 6.6666666667 0 47.5 6.6666666667 +2 47.5 6.6666666667 4 47.5 6.6666666667 6 47.5 6.6666666667 +8 47.5 6.6666666667 10 47.5 6.6666666667 12 47.5 6.6666666667 +14 47.5 6.6666666667 16 47.5 6.6666666667 18 47.5 6.6666666667 +20 47.5 6.6666666667 0 50 6.6666666667 2 50 6.6666666667 +4 50 6.6666666667 6 50 6.6666666667 8 50 6.6666666667 +10 50 6.6666666667 12 50 6.6666666667 14 50 6.6666666667 +16 50 6.6666666667 18 50 6.6666666667 20 50 6.6666666667 +0 0 8.3333333333 2 0 8.3333333333 4 0 8.3333333333 +6 0 8.3333333333 8 0 8.3333333333 10 0 8.3333333333 +12 0 8.3333333333 14 0 8.3333333333 16 0 8.3333333333 +18 0 8.3333333333 20 0 8.3333333333 0 2.5 8.3333333333 +2 2.5 8.3333333333 4 2.5 8.3333333333 6 2.5 8.3333333333 +8 2.5 8.3333333333 10 2.5 8.3333333333 12 2.5 8.3333333333 +14 2.5 8.3333333333 16 2.5 8.3333333333 18 2.5 8.3333333333 +20 2.5 8.3333333333 0 5 8.3333333333 2 5 8.3333333333 +4 5 8.3333333333 6 5 8.3333333333 8 5 8.3333333333 +10 5 8.3333333333 12 5 8.3333333333 14 5 8.3333333333 +16 5 8.3333333333 18 5 8.3333333333 20 5 8.3333333333 +0 7.5 8.3333333333 2 7.5 8.3333333333 4 7.5 8.3333333333 +6 7.5 8.3333333333 8 7.5 8.3333333333 10 7.5 8.3333333333 +12 7.5 8.3333333333 14 7.5 8.3333333333 16 7.5 8.3333333333 +18 7.5 8.3333333333 20 7.5 8.3333333333 0 10 8.3333333333 +2 10 8.3333333333 4 10 8.3333333333 6 10 8.3333333333 +8 10 8.3333333333 10 10 8.3333333333 12 10 8.3333333333 +14 10 8.3333333333 16 10 8.3333333333 18 10 8.3333333333 +20 10 8.3333333333 0 12.5 8.3333333333 2 12.5 8.3333333333 +4 12.5 8.3333333333 6 12.5 8.3333333333 8 12.5 8.3333333333 +10 12.5 8.3333333333 12 12.5 8.3333333333 14 12.5 8.3333333333 +16 12.5 8.3333333333 18 12.5 8.3333333333 20 12.5 8.3333333333 +0 15 8.3333333333 2 15 8.3333333333 4 15 8.3333333333 +6 15 8.3333333333 8 15 8.3333333333 10 15 8.3333333333 +12 15 8.3333333333 14 15 8.3333333333 16 15 8.3333333333 +18 15 8.3333333333 20 15 8.3333333333 0 17.5 8.3333333333 +2 17.5 8.3333333333 4 17.5 8.3333333333 6 17.5 8.3333333333 +8 17.5 8.3333333333 10 17.5 8.3333333333 12 17.5 8.3333333333 +14 17.5 8.3333333333 16 17.5 8.3333333333 18 17.5 8.3333333333 +20 17.5 8.3333333333 0 20 8.3333333333 2 20 8.3333333333 +4 20 8.3333333333 6 20 8.3333333333 8 20 8.3333333333 +10 20 8.3333333333 12 20 8.3333333333 14 20 8.3333333333 +16 20 8.3333333333 18 20 8.3333333333 20 20 8.3333333333 +0 22.5 8.3333333333 2 22.5 8.3333333333 4 22.5 8.3333333333 +6 22.5 8.3333333333 8 22.5 8.3333333333 10 22.5 8.3333333333 +12 22.5 8.3333333333 14 22.5 8.3333333333 16 22.5 8.3333333333 +18 22.5 8.3333333333 20 22.5 8.3333333333 0 25 8.3333333333 +2 25 8.3333333333 4 25 8.3333333333 6 25 8.3333333333 +8 25 8.3333333333 10 25 8.3333333333 12 25 8.3333333333 +14 25 8.3333333333 16 25 8.3333333333 18 25 8.3333333333 +20 25 8.3333333333 0 27.5 8.3333333333 2 27.5 8.3333333333 +4 27.5 8.3333333333 6 27.5 8.3333333333 8 27.5 8.3333333333 +10 27.5 8.3333333333 12 27.5 8.3333333333 14 27.5 8.3333333333 +16 27.5 8.3333333333 18 27.5 8.3333333333 20 27.5 8.3333333333 +0 30 8.3333333333 2 30 8.3333333333 4 30 8.3333333333 +6 30 8.3333333333 8 30 8.3333333333 10 30 8.3333333333 +12 30 8.3333333333 14 30 8.3333333333 16 30 8.3333333333 +18 30 8.3333333333 20 30 8.3333333333 0 32.5 8.3333333333 +2 32.5 8.3333333333 4 32.5 8.3333333333 6 32.5 8.3333333333 +8 32.5 8.3333333333 10 32.5 8.3333333333 12 32.5 8.3333333333 +14 32.5 8.3333333333 16 32.5 8.3333333333 18 32.5 8.3333333333 +20 32.5 8.3333333333 0 35 8.3333333333 2 35 8.3333333333 +4 35 8.3333333333 6 35 8.3333333333 8 35 8.3333333333 +10 35 8.3333333333 12 35 8.3333333333 14 35 8.3333333333 +16 35 8.3333333333 18 35 8.3333333333 20 35 8.3333333333 +0 37.5 8.3333333333 2 37.5 8.3333333333 4 37.5 8.3333333333 +6 37.5 8.3333333333 8 37.5 8.3333333333 10 37.5 8.3333333333 +12 37.5 8.3333333333 14 37.5 8.3333333333 16 37.5 8.3333333333 +18 37.5 8.3333333333 20 37.5 8.3333333333 0 40 8.3333333333 +2 40 8.3333333333 4 40 8.3333333333 6 40 8.3333333333 +8 40 8.3333333333 10 40 8.3333333333 12 40 8.3333333333 +14 40 8.3333333333 16 40 8.3333333333 18 40 8.3333333333 +20 40 8.3333333333 0 42.5 8.3333333333 2 42.5 8.3333333333 +4 42.5 8.3333333333 6 42.5 8.3333333333 8 42.5 8.3333333333 +10 42.5 8.3333333333 12 42.5 8.3333333333 14 42.5 8.3333333333 +16 42.5 8.3333333333 18 42.5 8.3333333333 20 42.5 8.3333333333 +0 45 8.3333333333 2 45 8.3333333333 4 45 8.3333333333 +6 45 8.3333333333 8 45 8.3333333333 10 45 8.3333333333 +12 45 8.3333333333 14 45 8.3333333333 16 45 8.3333333333 +18 45 8.3333333333 20 45 8.3333333333 0 47.5 8.3333333333 +2 47.5 8.3333333333 4 47.5 8.3333333333 6 47.5 8.3333333333 +8 47.5 8.3333333333 10 47.5 8.3333333333 12 47.5 8.3333333333 +14 47.5 8.3333333333 16 47.5 8.3333333333 18 47.5 8.3333333333 +20 47.5 8.3333333333 0 50 8.3333333333 2 50 8.3333333333 +4 50 8.3333333333 6 50 8.3333333333 8 50 8.3333333333 +10 50 8.3333333333 12 50 8.3333333333 14 50 8.3333333333 +16 50 8.3333333333 18 50 8.3333333333 20 50 8.3333333333 +0 0 10 2 0 10 4 0 10 +6 0 10 8 0 10 10 0 10 +12 0 10 14 0 10 16 0 10 +18 0 10 20 0 10 0 2.5 10 +2 2.5 10 4 2.5 10 6 2.5 10 +8 2.5 10 10 2.5 10 12 2.5 10 +14 2.5 10 16 2.5 10 18 2.5 10 +20 2.5 10 0 5 10 2 5 10 +4 5 10 6 5 10 8 5 10 +10 5 10 12 5 10 14 5 10 +16 5 10 18 5 10 20 5 10 +0 7.5 10 2 7.5 10 4 7.5 10 +6 7.5 10 8 7.5 10 10 7.5 10 +12 7.5 10 14 7.5 10 16 7.5 10 +18 7.5 10 20 7.5 10 0 10 10 +2 10 10 4 10 10 6 10 10 +8 10 10 10 10 10 12 10 10 +14 10 10 16 10 10 18 10 10 +20 10 10 0 12.5 10 2 12.5 10 +4 12.5 10 6 12.5 10 8 12.5 10 +10 12.5 10 12 12.5 10 14 12.5 10 +16 12.5 10 18 12.5 10 20 12.5 10 +0 15 10 2 15 10 4 15 10 +6 15 10 8 15 10 10 15 10 +12 15 10 14 15 10 16 15 10 +18 15 10 20 15 10 0 17.5 10 +2 17.5 10 4 17.5 10 6 17.5 10 +8 17.5 10 10 17.5 10 12 17.5 10 +14 17.5 10 16 17.5 10 18 17.5 10 +20 17.5 10 0 20 10 2 20 10 +4 20 10 6 20 10 8 20 10 +10 20 10 12 20 10 14 20 10 +16 20 10 18 20 10 20 20 10 +0 22.5 10 2 22.5 10 4 22.5 10 +6 22.5 10 8 22.5 10 10 22.5 10 +12 22.5 10 14 22.5 10 16 22.5 10 +18 22.5 10 20 22.5 10 0 25 10 +2 25 10 4 25 10 6 25 10 +8 25 10 10 25 10 12 25 10 +14 25 10 16 25 10 18 25 10 +20 25 10 0 27.5 10 2 27.5 10 +4 27.5 10 6 27.5 10 8 27.5 10 +10 27.5 10 12 27.5 10 14 27.5 10 +16 27.5 10 18 27.5 10 20 27.5 10 +0 30 10 2 30 10 4 30 10 +6 30 10 8 30 10 10 30 10 +12 30 10 14 30 10 16 30 10 +18 30 10 20 30 10 0 32.5 10 +2 32.5 10 4 32.5 10 6 32.5 10 +8 32.5 10 10 32.5 10 12 32.5 10 +14 32.5 10 16 32.5 10 18 32.5 10 +20 32.5 10 0 35 10 2 35 10 +4 35 10 6 35 10 8 35 10 +10 35 10 12 35 10 14 35 10 +16 35 10 18 35 10 20 35 10 +0 37.5 10 2 37.5 10 4 37.5 10 +6 37.5 10 8 37.5 10 10 37.5 10 +12 37.5 10 14 37.5 10 16 37.5 10 +18 37.5 10 20 37.5 10 0 40 10 +2 40 10 4 40 10 6 40 10 +8 40 10 10 40 10 12 40 10 +14 40 10 16 40 10 18 40 10 +20 40 10 0 42.5 10 2 42.5 10 +4 42.5 10 6 42.5 10 8 42.5 10 +10 42.5 10 12 42.5 10 14 42.5 10 +16 42.5 10 18 42.5 10 20 42.5 10 +0 45 10 2 45 10 4 45 10 +6 45 10 8 45 10 10 45 10 +12 45 10 14 45 10 16 45 10 +18 45 10 20 45 10 0 47.5 10 +2 47.5 10 4 47.5 10 6 47.5 10 +8 47.5 10 10 47.5 10 12 47.5 10 +14 47.5 10 16 47.5 10 18 47.5 10 +20 47.5 10 0 50 10 2 50 10 +4 50 10 6 50 10 8 50 10 +10 50 10 12 50 10 14 50 10 +16 50 10 18 50 10 20 50 10 +0 0 11.666666667 2 0 11.666666667 4 0 11.666666667 +6 0 11.666666667 8 0 11.666666667 10 0 11.666666667 +12 0 11.666666667 14 0 11.666666667 16 0 11.666666667 +18 0 11.666666667 20 0 11.666666667 0 2.5 11.666666667 +2 2.5 11.666666667 4 2.5 11.666666667 6 2.5 11.666666667 +8 2.5 11.666666667 10 2.5 11.666666667 12 2.5 11.666666667 +14 2.5 11.666666667 16 2.5 11.666666667 18 2.5 11.666666667 +20 2.5 11.666666667 0 5 11.666666667 2 5 11.666666667 +4 5 11.666666667 6 5 11.666666667 8 5 11.666666667 +10 5 11.666666667 12 5 11.666666667 14 5 11.666666667 +16 5 11.666666667 18 5 11.666666667 20 5 11.666666667 +0 7.5 11.666666667 2 7.5 11.666666667 4 7.5 11.666666667 +6 7.5 11.666666667 8 7.5 11.666666667 10 7.5 11.666666667 +12 7.5 11.666666667 14 7.5 11.666666667 16 7.5 11.666666667 +18 7.5 11.666666667 20 7.5 11.666666667 0 10 11.666666667 +2 10 11.666666667 4 10 11.666666667 6 10 11.666666667 +8 10 11.666666667 10 10 11.666666667 12 10 11.666666667 +14 10 11.666666667 16 10 11.666666667 18 10 11.666666667 +20 10 11.666666667 0 12.5 11.666666667 2 12.5 11.666666667 +4 12.5 11.666666667 6 12.5 11.666666667 8 12.5 11.666666667 +10 12.5 11.666666667 12 12.5 11.666666667 14 12.5 11.666666667 +16 12.5 11.666666667 18 12.5 11.666666667 20 12.5 11.666666667 +0 15 11.666666667 2 15 11.666666667 4 15 11.666666667 +6 15 11.666666667 8 15 11.666666667 10 15 11.666666667 +12 15 11.666666667 14 15 11.666666667 16 15 11.666666667 +18 15 11.666666667 20 15 11.666666667 0 17.5 11.666666667 +2 17.5 11.666666667 4 17.5 11.666666667 6 17.5 11.666666667 +8 17.5 11.666666667 10 17.5 11.666666667 12 17.5 11.666666667 +14 17.5 11.666666667 16 17.5 11.666666667 18 17.5 11.666666667 +20 17.5 11.666666667 0 20 11.666666667 2 20 11.666666667 +4 20 11.666666667 6 20 11.666666667 8 20 11.666666667 +10 20 11.666666667 12 20 11.666666667 14 20 11.666666667 +16 20 11.666666667 18 20 11.666666667 20 20 11.666666667 +0 22.5 11.666666667 2 22.5 11.666666667 4 22.5 11.666666667 +6 22.5 11.666666667 8 22.5 11.666666667 10 22.5 11.666666667 +12 22.5 11.666666667 14 22.5 11.666666667 16 22.5 11.666666667 +18 22.5 11.666666667 20 22.5 11.666666667 0 25 11.666666667 +2 25 11.666666667 4 25 11.666666667 6 25 11.666666667 +8 25 11.666666667 10 25 11.666666667 12 25 11.666666667 +14 25 11.666666667 16 25 11.666666667 18 25 11.666666667 +20 25 11.666666667 0 27.5 11.666666667 2 27.5 11.666666667 +4 27.5 11.666666667 6 27.5 11.666666667 8 27.5 11.666666667 +10 27.5 11.666666667 12 27.5 11.666666667 14 27.5 11.666666667 +16 27.5 11.666666667 18 27.5 11.666666667 20 27.5 11.666666667 +0 30 11.666666667 2 30 11.666666667 4 30 11.666666667 +6 30 11.666666667 8 30 11.666666667 10 30 11.666666667 +12 30 11.666666667 14 30 11.666666667 16 30 11.666666667 +18 30 11.666666667 20 30 11.666666667 0 32.5 11.666666667 +2 32.5 11.666666667 4 32.5 11.666666667 6 32.5 11.666666667 +8 32.5 11.666666667 10 32.5 11.666666667 12 32.5 11.666666667 +14 32.5 11.666666667 16 32.5 11.666666667 18 32.5 11.666666667 +20 32.5 11.666666667 0 35 11.666666667 2 35 11.666666667 +4 35 11.666666667 6 35 11.666666667 8 35 11.666666667 +10 35 11.666666667 12 35 11.666666667 14 35 11.666666667 +16 35 11.666666667 18 35 11.666666667 20 35 11.666666667 +0 37.5 11.666666667 2 37.5 11.666666667 4 37.5 11.666666667 +6 37.5 11.666666667 8 37.5 11.666666667 10 37.5 11.666666667 +12 37.5 11.666666667 14 37.5 11.666666667 16 37.5 11.666666667 +18 37.5 11.666666667 20 37.5 11.666666667 0 40 11.666666667 +2 40 11.666666667 4 40 11.666666667 6 40 11.666666667 +8 40 11.666666667 10 40 11.666666667 12 40 11.666666667 +14 40 11.666666667 16 40 11.666666667 18 40 11.666666667 +20 40 11.666666667 0 42.5 11.666666667 2 42.5 11.666666667 +4 42.5 11.666666667 6 42.5 11.666666667 8 42.5 11.666666667 +10 42.5 11.666666667 12 42.5 11.666666667 14 42.5 11.666666667 +16 42.5 11.666666667 18 42.5 11.666666667 20 42.5 11.666666667 +0 45 11.666666667 2 45 11.666666667 4 45 11.666666667 +6 45 11.666666667 8 45 11.666666667 10 45 11.666666667 +12 45 11.666666667 14 45 11.666666667 16 45 11.666666667 +18 45 11.666666667 20 45 11.666666667 0 47.5 11.666666667 +2 47.5 11.666666667 4 47.5 11.666666667 6 47.5 11.666666667 +8 47.5 11.666666667 10 47.5 11.666666667 12 47.5 11.666666667 +14 47.5 11.666666667 16 47.5 11.666666667 18 47.5 11.666666667 +20 47.5 11.666666667 0 50 11.666666667 2 50 11.666666667 +4 50 11.666666667 6 50 11.666666667 8 50 11.666666667 +10 50 11.666666667 12 50 11.666666667 14 50 11.666666667 +16 50 11.666666667 18 50 11.666666667 20 50 11.666666667 +0 0 13.333333333 2 0 13.333333333 4 0 13.333333333 +6 0 13.333333333 8 0 13.333333333 10 0 13.333333333 +12 0 13.333333333 14 0 13.333333333 16 0 13.333333333 +18 0 13.333333333 20 0 13.333333333 0 2.5 13.333333333 +2 2.5 13.333333333 4 2.5 13.333333333 6 2.5 13.333333333 +8 2.5 13.333333333 10 2.5 13.333333333 12 2.5 13.333333333 +14 2.5 13.333333333 16 2.5 13.333333333 18 2.5 13.333333333 +20 2.5 13.333333333 0 5 13.333333333 2 5 13.333333333 +4 5 13.333333333 6 5 13.333333333 8 5 13.333333333 +10 5 13.333333333 12 5 13.333333333 14 5 13.333333333 +16 5 13.333333333 18 5 13.333333333 20 5 13.333333333 +0 7.5 13.333333333 2 7.5 13.333333333 4 7.5 13.333333333 +6 7.5 13.333333333 8 7.5 13.333333333 10 7.5 13.333333333 +12 7.5 13.333333333 14 7.5 13.333333333 16 7.5 13.333333333 +18 7.5 13.333333333 20 7.5 13.333333333 0 10 13.333333333 +2 10 13.333333333 4 10 13.333333333 6 10 13.333333333 +8 10 13.333333333 10 10 13.333333333 12 10 13.333333333 +14 10 13.333333333 16 10 13.333333333 18 10 13.333333333 +20 10 13.333333333 0 12.5 13.333333333 2 12.5 13.333333333 +4 12.5 13.333333333 6 12.5 13.333333333 8 12.5 13.333333333 +10 12.5 13.333333333 12 12.5 13.333333333 14 12.5 13.333333333 +16 12.5 13.333333333 18 12.5 13.333333333 20 12.5 13.333333333 +0 15 13.333333333 2 15 13.333333333 4 15 13.333333333 +6 15 13.333333333 8 15 13.333333333 10 15 13.333333333 +12 15 13.333333333 14 15 13.333333333 16 15 13.333333333 +18 15 13.333333333 20 15 13.333333333 0 17.5 13.333333333 +2 17.5 13.333333333 4 17.5 13.333333333 6 17.5 13.333333333 +8 17.5 13.333333333 10 17.5 13.333333333 12 17.5 13.333333333 +14 17.5 13.333333333 16 17.5 13.333333333 18 17.5 13.333333333 +20 17.5 13.333333333 0 20 13.333333333 2 20 13.333333333 +4 20 13.333333333 6 20 13.333333333 8 20 13.333333333 +10 20 13.333333333 12 20 13.333333333 14 20 13.333333333 +16 20 13.333333333 18 20 13.333333333 20 20 13.333333333 +0 22.5 13.333333333 2 22.5 13.333333333 4 22.5 13.333333333 +6 22.5 13.333333333 8 22.5 13.333333333 10 22.5 13.333333333 +12 22.5 13.333333333 14 22.5 13.333333333 16 22.5 13.333333333 +18 22.5 13.333333333 20 22.5 13.333333333 0 25 13.333333333 +2 25 13.333333333 4 25 13.333333333 6 25 13.333333333 +8 25 13.333333333 10 25 13.333333333 12 25 13.333333333 +14 25 13.333333333 16 25 13.333333333 18 25 13.333333333 +20 25 13.333333333 0 27.5 13.333333333 2 27.5 13.333333333 +4 27.5 13.333333333 6 27.5 13.333333333 8 27.5 13.333333333 +10 27.5 13.333333333 12 27.5 13.333333333 14 27.5 13.333333333 +16 27.5 13.333333333 18 27.5 13.333333333 20 27.5 13.333333333 +0 30 13.333333333 2 30 13.333333333 4 30 13.333333333 +6 30 13.333333333 8 30 13.333333333 10 30 13.333333333 +12 30 13.333333333 14 30 13.333333333 16 30 13.333333333 +18 30 13.333333333 20 30 13.333333333 0 32.5 13.333333333 +2 32.5 13.333333333 4 32.5 13.333333333 6 32.5 13.333333333 +8 32.5 13.333333333 10 32.5 13.333333333 12 32.5 13.333333333 +14 32.5 13.333333333 16 32.5 13.333333333 18 32.5 13.333333333 +20 32.5 13.333333333 0 35 13.333333333 2 35 13.333333333 +4 35 13.333333333 6 35 13.333333333 8 35 13.333333333 +10 35 13.333333333 12 35 13.333333333 14 35 13.333333333 +16 35 13.333333333 18 35 13.333333333 20 35 13.333333333 +0 37.5 13.333333333 2 37.5 13.333333333 4 37.5 13.333333333 +6 37.5 13.333333333 8 37.5 13.333333333 10 37.5 13.333333333 +12 37.5 13.333333333 14 37.5 13.333333333 16 37.5 13.333333333 +18 37.5 13.333333333 20 37.5 13.333333333 0 40 13.333333333 +2 40 13.333333333 4 40 13.333333333 6 40 13.333333333 +8 40 13.333333333 10 40 13.333333333 12 40 13.333333333 +14 40 13.333333333 16 40 13.333333333 18 40 13.333333333 +20 40 13.333333333 0 42.5 13.333333333 2 42.5 13.333333333 +4 42.5 13.333333333 6 42.5 13.333333333 8 42.5 13.333333333 +10 42.5 13.333333333 12 42.5 13.333333333 14 42.5 13.333333333 +16 42.5 13.333333333 18 42.5 13.333333333 20 42.5 13.333333333 +0 45 13.333333333 2 45 13.333333333 4 45 13.333333333 +6 45 13.333333333 8 45 13.333333333 10 45 13.333333333 +12 45 13.333333333 14 45 13.333333333 16 45 13.333333333 +18 45 13.333333333 20 45 13.333333333 0 47.5 13.333333333 +2 47.5 13.333333333 4 47.5 13.333333333 6 47.5 13.333333333 +8 47.5 13.333333333 10 47.5 13.333333333 12 47.5 13.333333333 +14 47.5 13.333333333 16 47.5 13.333333333 18 47.5 13.333333333 +20 47.5 13.333333333 0 50 13.333333333 2 50 13.333333333 +4 50 13.333333333 6 50 13.333333333 8 50 13.333333333 +10 50 13.333333333 12 50 13.333333333 14 50 13.333333333 +16 50 13.333333333 18 50 13.333333333 20 50 13.333333333 +0 0 15 2 0 15 4 0 15 +6 0 15 8 0 15 10 0 15 +12 0 15 14 0 15 16 0 15 +18 0 15 20 0 15 0 2.5 15 +2 2.5 15 4 2.5 15 6 2.5 15 +8 2.5 15 10 2.5 15 12 2.5 15 +14 2.5 15 16 2.5 15 18 2.5 15 +20 2.5 15 0 5 15 2 5 15 +4 5 15 6 5 15 8 5 15 +10 5 15 12 5 15 14 5 15 +16 5 15 18 5 15 20 5 15 +0 7.5 15 2 7.5 15 4 7.5 15 +6 7.5 15 8 7.5 15 10 7.5 15 +12 7.5 15 14 7.5 15 16 7.5 15 +18 7.5 15 20 7.5 15 0 10 15 +2 10 15 4 10 15 6 10 15 +8 10 15 10 10 15 12 10 15 +14 10 15 16 10 15 18 10 15 +20 10 15 0 12.5 15 2 12.5 15 +4 12.5 15 6 12.5 15 8 12.5 15 +10 12.5 15 12 12.5 15 14 12.5 15 +16 12.5 15 18 12.5 15 20 12.5 15 +0 15 15 2 15 15 4 15 15 +6 15 15 8 15 15 10 15 15 +12 15 15 14 15 15 16 15 15 +18 15 15 20 15 15 0 17.5 15 +2 17.5 15 4 17.5 15 6 17.5 15 +8 17.5 15 10 17.5 15 12 17.5 15 +14 17.5 15 16 17.5 15 18 17.5 15 +20 17.5 15 0 20 15 2 20 15 +4 20 15 6 20 15 8 20 15 +10 20 15 12 20 15 14 20 15 +16 20 15 18 20 15 20 20 15 +0 22.5 15 2 22.5 15 4 22.5 15 +6 22.5 15 8 22.5 15 10 22.5 15 +12 22.5 15 14 22.5 15 16 22.5 15 +18 22.5 15 20 22.5 15 0 25 15 +2 25 15 4 25 15 6 25 15 +8 25 15 10 25 15 12 25 15 +14 25 15 16 25 15 18 25 15 +20 25 15 0 27.5 15 2 27.5 15 +4 27.5 15 6 27.5 15 8 27.5 15 +10 27.5 15 12 27.5 15 14 27.5 15 +16 27.5 15 18 27.5 15 20 27.5 15 +0 30 15 2 30 15 4 30 15 +6 30 15 8 30 15 10 30 15 +12 30 15 14 30 15 16 30 15 +18 30 15 20 30 15 0 32.5 15 +2 32.5 15 4 32.5 15 6 32.5 15 +8 32.5 15 10 32.5 15 12 32.5 15 +14 32.5 15 16 32.5 15 18 32.5 15 +20 32.5 15 0 35 15 2 35 15 +4 35 15 6 35 15 8 35 15 +10 35 15 12 35 15 14 35 15 +16 35 15 18 35 15 20 35 15 +0 37.5 15 2 37.5 15 4 37.5 15 +6 37.5 15 8 37.5 15 10 37.5 15 +12 37.5 15 14 37.5 15 16 37.5 15 +18 37.5 15 20 37.5 15 0 40 15 +2 40 15 4 40 15 6 40 15 +8 40 15 10 40 15 12 40 15 +14 40 15 16 40 15 18 40 15 +20 40 15 0 42.5 15 2 42.5 15 +4 42.5 15 6 42.5 15 8 42.5 15 +10 42.5 15 12 42.5 15 14 42.5 15 +16 42.5 15 18 42.5 15 20 42.5 15 +0 45 15 2 45 15 4 45 15 +6 45 15 8 45 15 10 45 15 +12 45 15 14 45 15 16 45 15 +18 45 15 20 45 15 0 47.5 15 +2 47.5 15 4 47.5 15 6 47.5 15 +8 47.5 15 10 47.5 15 12 47.5 15 +14 47.5 15 16 47.5 15 18 47.5 15 +20 47.5 15 0 50 15 2 50 15 +4 50 15 6 50 15 8 50 15 +10 50 15 12 50 15 14 50 15 +16 50 15 18 50 15 20 50 15 +0 0 16.666666667 2 0 16.666666667 4 0 16.666666667 +6 0 16.666666667 8 0 16.666666667 10 0 16.666666667 +12 0 16.666666667 14 0 16.666666667 16 0 16.666666667 +18 0 16.666666667 20 0 16.666666667 0 2.5 16.666666667 +2 2.5 16.666666667 4 2.5 16.666666667 6 2.5 16.666666667 +8 2.5 16.666666667 10 2.5 16.666666667 12 2.5 16.666666667 +14 2.5 16.666666667 16 2.5 16.666666667 18 2.5 16.666666667 +20 2.5 16.666666667 0 5 16.666666667 2 5 16.666666667 +4 5 16.666666667 6 5 16.666666667 8 5 16.666666667 +10 5 16.666666667 12 5 16.666666667 14 5 16.666666667 +16 5 16.666666667 18 5 16.666666667 20 5 16.666666667 +0 7.5 16.666666667 2 7.5 16.666666667 4 7.5 16.666666667 +6 7.5 16.666666667 8 7.5 16.666666667 10 7.5 16.666666667 +12 7.5 16.666666667 14 7.5 16.666666667 16 7.5 16.666666667 +18 7.5 16.666666667 20 7.5 16.666666667 0 10 16.666666667 +2 10 16.666666667 4 10 16.666666667 6 10 16.666666667 +8 10 16.666666667 10 10 16.666666667 12 10 16.666666667 +14 10 16.666666667 16 10 16.666666667 18 10 16.666666667 +20 10 16.666666667 0 12.5 16.666666667 2 12.5 16.666666667 +4 12.5 16.666666667 6 12.5 16.666666667 8 12.5 16.666666667 +10 12.5 16.666666667 12 12.5 16.666666667 14 12.5 16.666666667 +16 12.5 16.666666667 18 12.5 16.666666667 20 12.5 16.666666667 +0 15 16.666666667 2 15 16.666666667 4 15 16.666666667 +6 15 16.666666667 8 15 16.666666667 10 15 16.666666667 +12 15 16.666666667 14 15 16.666666667 16 15 16.666666667 +18 15 16.666666667 20 15 16.666666667 0 17.5 16.666666667 +2 17.5 16.666666667 4 17.5 16.666666667 6 17.5 16.666666667 +8 17.5 16.666666667 10 17.5 16.666666667 12 17.5 16.666666667 +14 17.5 16.666666667 16 17.5 16.666666667 18 17.5 16.666666667 +20 17.5 16.666666667 0 20 16.666666667 2 20 16.666666667 +4 20 16.666666667 6 20 16.666666667 8 20 16.666666667 +10 20 16.666666667 12 20 16.666666667 14 20 16.666666667 +16 20 16.666666667 18 20 16.666666667 20 20 16.666666667 +0 22.5 16.666666667 2 22.5 16.666666667 4 22.5 16.666666667 +6 22.5 16.666666667 8 22.5 16.666666667 10 22.5 16.666666667 +12 22.5 16.666666667 14 22.5 16.666666667 16 22.5 16.666666667 +18 22.5 16.666666667 20 22.5 16.666666667 0 25 16.666666667 +2 25 16.666666667 4 25 16.666666667 6 25 16.666666667 +8 25 16.666666667 10 25 16.666666667 12 25 16.666666667 +14 25 16.666666667 16 25 16.666666667 18 25 16.666666667 +20 25 16.666666667 0 27.5 16.666666667 2 27.5 16.666666667 +4 27.5 16.666666667 6 27.5 16.666666667 8 27.5 16.666666667 +10 27.5 16.666666667 12 27.5 16.666666667 14 27.5 16.666666667 +16 27.5 16.666666667 18 27.5 16.666666667 20 27.5 16.666666667 +0 30 16.666666667 2 30 16.666666667 4 30 16.666666667 +6 30 16.666666667 8 30 16.666666667 10 30 16.666666667 +12 30 16.666666667 14 30 16.666666667 16 30 16.666666667 +18 30 16.666666667 20 30 16.666666667 0 32.5 16.666666667 +2 32.5 16.666666667 4 32.5 16.666666667 6 32.5 16.666666667 +8 32.5 16.666666667 10 32.5 16.666666667 12 32.5 16.666666667 +14 32.5 16.666666667 16 32.5 16.666666667 18 32.5 16.666666667 +20 32.5 16.666666667 0 35 16.666666667 2 35 16.666666667 +4 35 16.666666667 6 35 16.666666667 8 35 16.666666667 +10 35 16.666666667 12 35 16.666666667 14 35 16.666666667 +16 35 16.666666667 18 35 16.666666667 20 35 16.666666667 +0 37.5 16.666666667 2 37.5 16.666666667 4 37.5 16.666666667 +6 37.5 16.666666667 8 37.5 16.666666667 10 37.5 16.666666667 +12 37.5 16.666666667 14 37.5 16.666666667 16 37.5 16.666666667 +18 37.5 16.666666667 20 37.5 16.666666667 0 40 16.666666667 +2 40 16.666666667 4 40 16.666666667 6 40 16.666666667 +8 40 16.666666667 10 40 16.666666667 12 40 16.666666667 +14 40 16.666666667 16 40 16.666666667 18 40 16.666666667 +20 40 16.666666667 0 42.5 16.666666667 2 42.5 16.666666667 +4 42.5 16.666666667 6 42.5 16.666666667 8 42.5 16.666666667 +10 42.5 16.666666667 12 42.5 16.666666667 14 42.5 16.666666667 +16 42.5 16.666666667 18 42.5 16.666666667 20 42.5 16.666666667 +0 45 16.666666667 2 45 16.666666667 4 45 16.666666667 +6 45 16.666666667 8 45 16.666666667 10 45 16.666666667 +12 45 16.666666667 14 45 16.666666667 16 45 16.666666667 +18 45 16.666666667 20 45 16.666666667 0 47.5 16.666666667 +2 47.5 16.666666667 4 47.5 16.666666667 6 47.5 16.666666667 +8 47.5 16.666666667 10 47.5 16.666666667 12 47.5 16.666666667 +14 47.5 16.666666667 16 47.5 16.666666667 18 47.5 16.666666667 +20 47.5 16.666666667 0 50 16.666666667 2 50 16.666666667 +4 50 16.666666667 6 50 16.666666667 8 50 16.666666667 +10 50 16.666666667 12 50 16.666666667 14 50 16.666666667 +16 50 16.666666667 18 50 16.666666667 20 50 16.666666667 +0 0 18.333333333 2 0 18.333333333 4 0 18.333333333 +6 0 18.333333333 8 0 18.333333333 10 0 18.333333333 +12 0 18.333333333 14 0 18.333333333 16 0 18.333333333 +18 0 18.333333333 20 0 18.333333333 0 2.5 18.333333333 +2 2.5 18.333333333 4 2.5 18.333333333 6 2.5 18.333333333 +8 2.5 18.333333333 10 2.5 18.333333333 12 2.5 18.333333333 +14 2.5 18.333333333 16 2.5 18.333333333 18 2.5 18.333333333 +20 2.5 18.333333333 0 5 18.333333333 2 5 18.333333333 +4 5 18.333333333 6 5 18.333333333 8 5 18.333333333 +10 5 18.333333333 12 5 18.333333333 14 5 18.333333333 +16 5 18.333333333 18 5 18.333333333 20 5 18.333333333 +0 7.5 18.333333333 2 7.5 18.333333333 4 7.5 18.333333333 +6 7.5 18.333333333 8 7.5 18.333333333 10 7.5 18.333333333 +12 7.5 18.333333333 14 7.5 18.333333333 16 7.5 18.333333333 +18 7.5 18.333333333 20 7.5 18.333333333 0 10 18.333333333 +2 10 18.333333333 4 10 18.333333333 6 10 18.333333333 +8 10 18.333333333 10 10 18.333333333 12 10 18.333333333 +14 10 18.333333333 16 10 18.333333333 18 10 18.333333333 +20 10 18.333333333 0 12.5 18.333333333 2 12.5 18.333333333 +4 12.5 18.333333333 6 12.5 18.333333333 8 12.5 18.333333333 +10 12.5 18.333333333 12 12.5 18.333333333 14 12.5 18.333333333 +16 12.5 18.333333333 18 12.5 18.333333333 20 12.5 18.333333333 +0 15 18.333333333 2 15 18.333333333 4 15 18.333333333 +6 15 18.333333333 8 15 18.333333333 10 15 18.333333333 +12 15 18.333333333 14 15 18.333333333 16 15 18.333333333 +18 15 18.333333333 20 15 18.333333333 0 17.5 18.333333333 +2 17.5 18.333333333 4 17.5 18.333333333 6 17.5 18.333333333 +8 17.5 18.333333333 10 17.5 18.333333333 12 17.5 18.333333333 +14 17.5 18.333333333 16 17.5 18.333333333 18 17.5 18.333333333 +20 17.5 18.333333333 0 20 18.333333333 2 20 18.333333333 +4 20 18.333333333 6 20 18.333333333 8 20 18.333333333 +10 20 18.333333333 12 20 18.333333333 14 20 18.333333333 +16 20 18.333333333 18 20 18.333333333 20 20 18.333333333 +0 22.5 18.333333333 2 22.5 18.333333333 4 22.5 18.333333333 +6 22.5 18.333333333 8 22.5 18.333333333 10 22.5 18.333333333 +12 22.5 18.333333333 14 22.5 18.333333333 16 22.5 18.333333333 +18 22.5 18.333333333 20 22.5 18.333333333 0 25 18.333333333 +2 25 18.333333333 4 25 18.333333333 6 25 18.333333333 +8 25 18.333333333 10 25 18.333333333 12 25 18.333333333 +14 25 18.333333333 16 25 18.333333333 18 25 18.333333333 +20 25 18.333333333 0 27.5 18.333333333 2 27.5 18.333333333 +4 27.5 18.333333333 6 27.5 18.333333333 8 27.5 18.333333333 +10 27.5 18.333333333 12 27.5 18.333333333 14 27.5 18.333333333 +16 27.5 18.333333333 18 27.5 18.333333333 20 27.5 18.333333333 +0 30 18.333333333 2 30 18.333333333 4 30 18.333333333 +6 30 18.333333333 8 30 18.333333333 10 30 18.333333333 +12 30 18.333333333 14 30 18.333333333 16 30 18.333333333 +18 30 18.333333333 20 30 18.333333333 0 32.5 18.333333333 +2 32.5 18.333333333 4 32.5 18.333333333 6 32.5 18.333333333 +8 32.5 18.333333333 10 32.5 18.333333333 12 32.5 18.333333333 +14 32.5 18.333333333 16 32.5 18.333333333 18 32.5 18.333333333 +20 32.5 18.333333333 0 35 18.333333333 2 35 18.333333333 +4 35 18.333333333 6 35 18.333333333 8 35 18.333333333 +10 35 18.333333333 12 35 18.333333333 14 35 18.333333333 +16 35 18.333333333 18 35 18.333333333 20 35 18.333333333 +0 37.5 18.333333333 2 37.5 18.333333333 4 37.5 18.333333333 +6 37.5 18.333333333 8 37.5 18.333333333 10 37.5 18.333333333 +12 37.5 18.333333333 14 37.5 18.333333333 16 37.5 18.333333333 +18 37.5 18.333333333 20 37.5 18.333333333 0 40 18.333333333 +2 40 18.333333333 4 40 18.333333333 6 40 18.333333333 +8 40 18.333333333 10 40 18.333333333 12 40 18.333333333 +14 40 18.333333333 16 40 18.333333333 18 40 18.333333333 +20 40 18.333333333 0 42.5 18.333333333 2 42.5 18.333333333 +4 42.5 18.333333333 6 42.5 18.333333333 8 42.5 18.333333333 +10 42.5 18.333333333 12 42.5 18.333333333 14 42.5 18.333333333 +16 42.5 18.333333333 18 42.5 18.333333333 20 42.5 18.333333333 +0 45 18.333333333 2 45 18.333333333 4 45 18.333333333 +6 45 18.333333333 8 45 18.333333333 10 45 18.333333333 +12 45 18.333333333 14 45 18.333333333 16 45 18.333333333 +18 45 18.333333333 20 45 18.333333333 0 47.5 18.333333333 +2 47.5 18.333333333 4 47.5 18.333333333 6 47.5 18.333333333 +8 47.5 18.333333333 10 47.5 18.333333333 12 47.5 18.333333333 +14 47.5 18.333333333 16 47.5 18.333333333 18 47.5 18.333333333 +20 47.5 18.333333333 0 50 18.333333333 2 50 18.333333333 +4 50 18.333333333 6 50 18.333333333 8 50 18.333333333 +10 50 18.333333333 12 50 18.333333333 14 50 18.333333333 +16 50 18.333333333 18 50 18.333333333 20 50 18.333333333 +0 0 20 2 0 20 4 0 20 +6 0 20 8 0 20 10 0 20 +12 0 20 14 0 20 16 0 20 +18 0 20 20 0 20 0 2.5 20 +2 2.5 20 4 2.5 20 6 2.5 20 +8 2.5 20 10 2.5 20 12 2.5 20 +14 2.5 20 16 2.5 20 18 2.5 20 +20 2.5 20 0 5 20 2 5 20 +4 5 20 6 5 20 8 5 20 +10 5 20 12 5 20 14 5 20 +16 5 20 18 5 20 20 5 20 +0 7.5 20 2 7.5 20 4 7.5 20 +6 7.5 20 8 7.5 20 10 7.5 20 +12 7.5 20 14 7.5 20 16 7.5 20 +18 7.5 20 20 7.5 20 0 10 20 +2 10 20 4 10 20 6 10 20 +8 10 20 10 10 20 12 10 20 +14 10 20 16 10 20 18 10 20 +20 10 20 0 12.5 20 2 12.5 20 +4 12.5 20 6 12.5 20 8 12.5 20 +10 12.5 20 12 12.5 20 14 12.5 20 +16 12.5 20 18 12.5 20 20 12.5 20 +0 15 20 2 15 20 4 15 20 +6 15 20 8 15 20 10 15 20 +12 15 20 14 15 20 16 15 20 +18 15 20 20 15 20 0 17.5 20 +2 17.5 20 4 17.5 20 6 17.5 20 +8 17.5 20 10 17.5 20 12 17.5 20 +14 17.5 20 16 17.5 20 18 17.5 20 +20 17.5 20 0 20 20 2 20 20 +4 20 20 6 20 20 8 20 20 +10 20 20 12 20 20 14 20 20 +16 20 20 18 20 20 20 20 20 +0 22.5 20 2 22.5 20 4 22.5 20 +6 22.5 20 8 22.5 20 10 22.5 20 +12 22.5 20 14 22.5 20 16 22.5 20 +18 22.5 20 20 22.5 20 0 25 20 +2 25 20 4 25 20 6 25 20 +8 25 20 10 25 20 12 25 20 +14 25 20 16 25 20 18 25 20 +20 25 20 0 27.5 20 2 27.5 20 +4 27.5 20 6 27.5 20 8 27.5 20 +10 27.5 20 12 27.5 20 14 27.5 20 +16 27.5 20 18 27.5 20 20 27.5 20 +0 30 20 2 30 20 4 30 20 +6 30 20 8 30 20 10 30 20 +12 30 20 14 30 20 16 30 20 +18 30 20 20 30 20 0 32.5 20 +2 32.5 20 4 32.5 20 6 32.5 20 +8 32.5 20 10 32.5 20 12 32.5 20 +14 32.5 20 16 32.5 20 18 32.5 20 +20 32.5 20 0 35 20 2 35 20 +4 35 20 6 35 20 8 35 20 +10 35 20 12 35 20 14 35 20 +16 35 20 18 35 20 20 35 20 +0 37.5 20 2 37.5 20 4 37.5 20 +6 37.5 20 8 37.5 20 10 37.5 20 +12 37.5 20 14 37.5 20 16 37.5 20 +18 37.5 20 20 37.5 20 0 40 20 +2 40 20 4 40 20 6 40 20 +8 40 20 10 40 20 12 40 20 +14 40 20 16 40 20 18 40 20 +20 40 20 0 42.5 20 2 42.5 20 +4 42.5 20 6 42.5 20 8 42.5 20 +10 42.5 20 12 42.5 20 14 42.5 20 +16 42.5 20 18 42.5 20 20 42.5 20 +0 45 20 2 45 20 4 45 20 +6 45 20 8 45 20 10 45 20 +12 45 20 14 45 20 16 45 20 +18 45 20 20 45 20 0 47.5 20 +2 47.5 20 4 47.5 20 6 47.5 20 +8 47.5 20 10 47.5 20 12 47.5 20 +14 47.5 20 16 47.5 20 18 47.5 20 +20 47.5 20 0 50 20 2 50 20 +4 50 20 6 50 20 8 50 20 +10 50 20 12 50 20 14 50 20 +16 50 20 18 50 20 20 50 20 +0 0 21.666666667 2 0 21.666666667 4 0 21.666666667 +6 0 21.666666667 8 0 21.666666667 10 0 21.666666667 +12 0 21.666666667 14 0 21.666666667 16 0 21.666666667 +18 0 21.666666667 20 0 21.666666667 0 2.5 21.666666667 +2 2.5 21.666666667 4 2.5 21.666666667 6 2.5 21.666666667 +8 2.5 21.666666667 10 2.5 21.666666667 12 2.5 21.666666667 +14 2.5 21.666666667 16 2.5 21.666666667 18 2.5 21.666666667 +20 2.5 21.666666667 0 5 21.666666667 2 5 21.666666667 +4 5 21.666666667 6 5 21.666666667 8 5 21.666666667 +10 5 21.666666667 12 5 21.666666667 14 5 21.666666667 +16 5 21.666666667 18 5 21.666666667 20 5 21.666666667 +0 7.5 21.666666667 2 7.5 21.666666667 4 7.5 21.666666667 +6 7.5 21.666666667 8 7.5 21.666666667 10 7.5 21.666666667 +12 7.5 21.666666667 14 7.5 21.666666667 16 7.5 21.666666667 +18 7.5 21.666666667 20 7.5 21.666666667 0 10 21.666666667 +2 10 21.666666667 4 10 21.666666667 6 10 21.666666667 +8 10 21.666666667 10 10 21.666666667 12 10 21.666666667 +14 10 21.666666667 16 10 21.666666667 18 10 21.666666667 +20 10 21.666666667 0 12.5 21.666666667 2 12.5 21.666666667 +4 12.5 21.666666667 6 12.5 21.666666667 8 12.5 21.666666667 +10 12.5 21.666666667 12 12.5 21.666666667 14 12.5 21.666666667 +16 12.5 21.666666667 18 12.5 21.666666667 20 12.5 21.666666667 +0 15 21.666666667 2 15 21.666666667 4 15 21.666666667 +6 15 21.666666667 8 15 21.666666667 10 15 21.666666667 +12 15 21.666666667 14 15 21.666666667 16 15 21.666666667 +18 15 21.666666667 20 15 21.666666667 0 17.5 21.666666667 +2 17.5 21.666666667 4 17.5 21.666666667 6 17.5 21.666666667 +8 17.5 21.666666667 10 17.5 21.666666667 12 17.5 21.666666667 +14 17.5 21.666666667 16 17.5 21.666666667 18 17.5 21.666666667 +20 17.5 21.666666667 0 20 21.666666667 2 20 21.666666667 +4 20 21.666666667 6 20 21.666666667 8 20 21.666666667 +10 20 21.666666667 12 20 21.666666667 14 20 21.666666667 +16 20 21.666666667 18 20 21.666666667 20 20 21.666666667 +0 22.5 21.666666667 2 22.5 21.666666667 4 22.5 21.666666667 +6 22.5 21.666666667 8 22.5 21.666666667 10 22.5 21.666666667 +12 22.5 21.666666667 14 22.5 21.666666667 16 22.5 21.666666667 +18 22.5 21.666666667 20 22.5 21.666666667 0 25 21.666666667 +2 25 21.666666667 4 25 21.666666667 6 25 21.666666667 +8 25 21.666666667 10 25 21.666666667 12 25 21.666666667 +14 25 21.666666667 16 25 21.666666667 18 25 21.666666667 +20 25 21.666666667 0 27.5 21.666666667 2 27.5 21.666666667 +4 27.5 21.666666667 6 27.5 21.666666667 8 27.5 21.666666667 +10 27.5 21.666666667 12 27.5 21.666666667 14 27.5 21.666666667 +16 27.5 21.666666667 18 27.5 21.666666667 20 27.5 21.666666667 +0 30 21.666666667 2 30 21.666666667 4 30 21.666666667 +6 30 21.666666667 8 30 21.666666667 10 30 21.666666667 +12 30 21.666666667 14 30 21.666666667 16 30 21.666666667 +18 30 21.666666667 20 30 21.666666667 0 32.5 21.666666667 +2 32.5 21.666666667 4 32.5 21.666666667 6 32.5 21.666666667 +8 32.5 21.666666667 10 32.5 21.666666667 12 32.5 21.666666667 +14 32.5 21.666666667 16 32.5 21.666666667 18 32.5 21.666666667 +20 32.5 21.666666667 0 35 21.666666667 2 35 21.666666667 +4 35 21.666666667 6 35 21.666666667 8 35 21.666666667 +10 35 21.666666667 12 35 21.666666667 14 35 21.666666667 +16 35 21.666666667 18 35 21.666666667 20 35 21.666666667 +0 37.5 21.666666667 2 37.5 21.666666667 4 37.5 21.666666667 +6 37.5 21.666666667 8 37.5 21.666666667 10 37.5 21.666666667 +12 37.5 21.666666667 14 37.5 21.666666667 16 37.5 21.666666667 +18 37.5 21.666666667 20 37.5 21.666666667 0 40 21.666666667 +2 40 21.666666667 4 40 21.666666667 6 40 21.666666667 +8 40 21.666666667 10 40 21.666666667 12 40 21.666666667 +14 40 21.666666667 16 40 21.666666667 18 40 21.666666667 +20 40 21.666666667 0 42.5 21.666666667 2 42.5 21.666666667 +4 42.5 21.666666667 6 42.5 21.666666667 8 42.5 21.666666667 +10 42.5 21.666666667 12 42.5 21.666666667 14 42.5 21.666666667 +16 42.5 21.666666667 18 42.5 21.666666667 20 42.5 21.666666667 +0 45 21.666666667 2 45 21.666666667 4 45 21.666666667 +6 45 21.666666667 8 45 21.666666667 10 45 21.666666667 +12 45 21.666666667 14 45 21.666666667 16 45 21.666666667 +18 45 21.666666667 20 45 21.666666667 0 47.5 21.666666667 +2 47.5 21.666666667 4 47.5 21.666666667 6 47.5 21.666666667 +8 47.5 21.666666667 10 47.5 21.666666667 12 47.5 21.666666667 +14 47.5 21.666666667 16 47.5 21.666666667 18 47.5 21.666666667 +20 47.5 21.666666667 0 50 21.666666667 2 50 21.666666667 +4 50 21.666666667 6 50 21.666666667 8 50 21.666666667 +10 50 21.666666667 12 50 21.666666667 14 50 21.666666667 +16 50 21.666666667 18 50 21.666666667 20 50 21.666666667 +0 0 23.333333333 2 0 23.333333333 4 0 23.333333333 +6 0 23.333333333 8 0 23.333333333 10 0 23.333333333 +12 0 23.333333333 14 0 23.333333333 16 0 23.333333333 +18 0 23.333333333 20 0 23.333333333 0 2.5 23.333333333 +2 2.5 23.333333333 4 2.5 23.333333333 6 2.5 23.333333333 +8 2.5 23.333333333 10 2.5 23.333333333 12 2.5 23.333333333 +14 2.5 23.333333333 16 2.5 23.333333333 18 2.5 23.333333333 +20 2.5 23.333333333 0 5 23.333333333 2 5 23.333333333 +4 5 23.333333333 6 5 23.333333333 8 5 23.333333333 +10 5 23.333333333 12 5 23.333333333 14 5 23.333333333 +16 5 23.333333333 18 5 23.333333333 20 5 23.333333333 +0 7.5 23.333333333 2 7.5 23.333333333 4 7.5 23.333333333 +6 7.5 23.333333333 8 7.5 23.333333333 10 7.5 23.333333333 +12 7.5 23.333333333 14 7.5 23.333333333 16 7.5 23.333333333 +18 7.5 23.333333333 20 7.5 23.333333333 0 10 23.333333333 +2 10 23.333333333 4 10 23.333333333 6 10 23.333333333 +8 10 23.333333333 10 10 23.333333333 12 10 23.333333333 +14 10 23.333333333 16 10 23.333333333 18 10 23.333333333 +20 10 23.333333333 0 12.5 23.333333333 2 12.5 23.333333333 +4 12.5 23.333333333 6 12.5 23.333333333 8 12.5 23.333333333 +10 12.5 23.333333333 12 12.5 23.333333333 14 12.5 23.333333333 +16 12.5 23.333333333 18 12.5 23.333333333 20 12.5 23.333333333 +0 15 23.333333333 2 15 23.333333333 4 15 23.333333333 +6 15 23.333333333 8 15 23.333333333 10 15 23.333333333 +12 15 23.333333333 14 15 23.333333333 16 15 23.333333333 +18 15 23.333333333 20 15 23.333333333 0 17.5 23.333333333 +2 17.5 23.333333333 4 17.5 23.333333333 6 17.5 23.333333333 +8 17.5 23.333333333 10 17.5 23.333333333 12 17.5 23.333333333 +14 17.5 23.333333333 16 17.5 23.333333333 18 17.5 23.333333333 +20 17.5 23.333333333 0 20 23.333333333 2 20 23.333333333 +4 20 23.333333333 6 20 23.333333333 8 20 23.333333333 +10 20 23.333333333 12 20 23.333333333 14 20 23.333333333 +16 20 23.333333333 18 20 23.333333333 20 20 23.333333333 +0 22.5 23.333333333 2 22.5 23.333333333 4 22.5 23.333333333 +6 22.5 23.333333333 8 22.5 23.333333333 10 22.5 23.333333333 +12 22.5 23.333333333 14 22.5 23.333333333 16 22.5 23.333333333 +18 22.5 23.333333333 20 22.5 23.333333333 0 25 23.333333333 +2 25 23.333333333 4 25 23.333333333 6 25 23.333333333 +8 25 23.333333333 10 25 23.333333333 12 25 23.333333333 +14 25 23.333333333 16 25 23.333333333 18 25 23.333333333 +20 25 23.333333333 0 27.5 23.333333333 2 27.5 23.333333333 +4 27.5 23.333333333 6 27.5 23.333333333 8 27.5 23.333333333 +10 27.5 23.333333333 12 27.5 23.333333333 14 27.5 23.333333333 +16 27.5 23.333333333 18 27.5 23.333333333 20 27.5 23.333333333 +0 30 23.333333333 2 30 23.333333333 4 30 23.333333333 +6 30 23.333333333 8 30 23.333333333 10 30 23.333333333 +12 30 23.333333333 14 30 23.333333333 16 30 23.333333333 +18 30 23.333333333 20 30 23.333333333 0 32.5 23.333333333 +2 32.5 23.333333333 4 32.5 23.333333333 6 32.5 23.333333333 +8 32.5 23.333333333 10 32.5 23.333333333 12 32.5 23.333333333 +14 32.5 23.333333333 16 32.5 23.333333333 18 32.5 23.333333333 +20 32.5 23.333333333 0 35 23.333333333 2 35 23.333333333 +4 35 23.333333333 6 35 23.333333333 8 35 23.333333333 +10 35 23.333333333 12 35 23.333333333 14 35 23.333333333 +16 35 23.333333333 18 35 23.333333333 20 35 23.333333333 +0 37.5 23.333333333 2 37.5 23.333333333 4 37.5 23.333333333 +6 37.5 23.333333333 8 37.5 23.333333333 10 37.5 23.333333333 +12 37.5 23.333333333 14 37.5 23.333333333 16 37.5 23.333333333 +18 37.5 23.333333333 20 37.5 23.333333333 0 40 23.333333333 +2 40 23.333333333 4 40 23.333333333 6 40 23.333333333 +8 40 23.333333333 10 40 23.333333333 12 40 23.333333333 +14 40 23.333333333 16 40 23.333333333 18 40 23.333333333 +20 40 23.333333333 0 42.5 23.333333333 2 42.5 23.333333333 +4 42.5 23.333333333 6 42.5 23.333333333 8 42.5 23.333333333 +10 42.5 23.333333333 12 42.5 23.333333333 14 42.5 23.333333333 +16 42.5 23.333333333 18 42.5 23.333333333 20 42.5 23.333333333 +0 45 23.333333333 2 45 23.333333333 4 45 23.333333333 +6 45 23.333333333 8 45 23.333333333 10 45 23.333333333 +12 45 23.333333333 14 45 23.333333333 16 45 23.333333333 +18 45 23.333333333 20 45 23.333333333 0 47.5 23.333333333 +2 47.5 23.333333333 4 47.5 23.333333333 6 47.5 23.333333333 +8 47.5 23.333333333 10 47.5 23.333333333 12 47.5 23.333333333 +14 47.5 23.333333333 16 47.5 23.333333333 18 47.5 23.333333333 +20 47.5 23.333333333 0 50 23.333333333 2 50 23.333333333 +4 50 23.333333333 6 50 23.333333333 8 50 23.333333333 +10 50 23.333333333 12 50 23.333333333 14 50 23.333333333 +16 50 23.333333333 18 50 23.333333333 20 50 23.333333333 +0 0 25 2 0 25 4 0 25 +6 0 25 8 0 25 10 0 25 +12 0 25 14 0 25 16 0 25 +18 0 25 20 0 25 0 2.5 25 +2 2.5 25 4 2.5 25 6 2.5 25 +8 2.5 25 10 2.5 25 12 2.5 25 +14 2.5 25 16 2.5 25 18 2.5 25 +20 2.5 25 0 5 25 2 5 25 +4 5 25 6 5 25 8 5 25 +10 5 25 12 5 25 14 5 25 +16 5 25 18 5 25 20 5 25 +0 7.5 25 2 7.5 25 4 7.5 25 +6 7.5 25 8 7.5 25 10 7.5 25 +12 7.5 25 14 7.5 25 16 7.5 25 +18 7.5 25 20 7.5 25 0 10 25 +2 10 25 4 10 25 6 10 25 +8 10 25 10 10 25 12 10 25 +14 10 25 16 10 25 18 10 25 +20 10 25 0 12.5 25 2 12.5 25 +4 12.5 25 6 12.5 25 8 12.5 25 +10 12.5 25 12 12.5 25 14 12.5 25 +16 12.5 25 18 12.5 25 20 12.5 25 +0 15 25 2 15 25 4 15 25 +6 15 25 8 15 25 10 15 25 +12 15 25 14 15 25 16 15 25 +18 15 25 20 15 25 0 17.5 25 +2 17.5 25 4 17.5 25 6 17.5 25 +8 17.5 25 10 17.5 25 12 17.5 25 +14 17.5 25 16 17.5 25 18 17.5 25 +20 17.5 25 0 20 25 2 20 25 +4 20 25 6 20 25 8 20 25 +10 20 25 12 20 25 14 20 25 +16 20 25 18 20 25 20 20 25 +0 22.5 25 2 22.5 25 4 22.5 25 +6 22.5 25 8 22.5 25 10 22.5 25 +12 22.5 25 14 22.5 25 16 22.5 25 +18 22.5 25 20 22.5 25 0 25 25 +2 25 25 4 25 25 6 25 25 +8 25 25 10 25 25 12 25 25 +14 25 25 16 25 25 18 25 25 +20 25 25 0 27.5 25 2 27.5 25 +4 27.5 25 6 27.5 25 8 27.5 25 +10 27.5 25 12 27.5 25 14 27.5 25 +16 27.5 25 18 27.5 25 20 27.5 25 +0 30 25 2 30 25 4 30 25 +6 30 25 8 30 25 10 30 25 +12 30 25 14 30 25 16 30 25 +18 30 25 20 30 25 0 32.5 25 +2 32.5 25 4 32.5 25 6 32.5 25 +8 32.5 25 10 32.5 25 12 32.5 25 +14 32.5 25 16 32.5 25 18 32.5 25 +20 32.5 25 0 35 25 2 35 25 +4 35 25 6 35 25 8 35 25 +10 35 25 12 35 25 14 35 25 +16 35 25 18 35 25 20 35 25 +0 37.5 25 2 37.5 25 4 37.5 25 +6 37.5 25 8 37.5 25 10 37.5 25 +12 37.5 25 14 37.5 25 16 37.5 25 +18 37.5 25 20 37.5 25 0 40 25 +2 40 25 4 40 25 6 40 25 +8 40 25 10 40 25 12 40 25 +14 40 25 16 40 25 18 40 25 +20 40 25 0 42.5 25 2 42.5 25 +4 42.5 25 6 42.5 25 8 42.5 25 +10 42.5 25 12 42.5 25 14 42.5 25 +16 42.5 25 18 42.5 25 20 42.5 25 +0 45 25 2 45 25 4 45 25 +6 45 25 8 45 25 10 45 25 +12 45 25 14 45 25 16 45 25 +18 45 25 20 45 25 0 47.5 25 +2 47.5 25 4 47.5 25 6 47.5 25 +8 47.5 25 10 47.5 25 12 47.5 25 +14 47.5 25 16 47.5 25 18 47.5 25 +20 47.5 25 0 50 25 2 50 25 +4 50 25 6 50 25 8 50 25 +10 50 25 12 50 25 14 50 25 +16 50 25 18 50 25 20 50 25 +0 0 26.666666667 2 0 26.666666667 4 0 26.666666667 +6 0 26.666666667 8 0 26.666666667 10 0 26.666666667 +12 0 26.666666667 14 0 26.666666667 16 0 26.666666667 +18 0 26.666666667 20 0 26.666666667 0 2.5 26.666666667 +2 2.5 26.666666667 4 2.5 26.666666667 6 2.5 26.666666667 +8 2.5 26.666666667 10 2.5 26.666666667 12 2.5 26.666666667 +14 2.5 26.666666667 16 2.5 26.666666667 18 2.5 26.666666667 +20 2.5 26.666666667 0 5 26.666666667 2 5 26.666666667 +4 5 26.666666667 6 5 26.666666667 8 5 26.666666667 +10 5 26.666666667 12 5 26.666666667 14 5 26.666666667 +16 5 26.666666667 18 5 26.666666667 20 5 26.666666667 +0 7.5 26.666666667 2 7.5 26.666666667 4 7.5 26.666666667 +6 7.5 26.666666667 8 7.5 26.666666667 10 7.5 26.666666667 +12 7.5 26.666666667 14 7.5 26.666666667 16 7.5 26.666666667 +18 7.5 26.666666667 20 7.5 26.666666667 0 10 26.666666667 +2 10 26.666666667 4 10 26.666666667 6 10 26.666666667 +8 10 26.666666667 10 10 26.666666667 12 10 26.666666667 +14 10 26.666666667 16 10 26.666666667 18 10 26.666666667 +20 10 26.666666667 0 12.5 26.666666667 2 12.5 26.666666667 +4 12.5 26.666666667 6 12.5 26.666666667 8 12.5 26.666666667 +10 12.5 26.666666667 12 12.5 26.666666667 14 12.5 26.666666667 +16 12.5 26.666666667 18 12.5 26.666666667 20 12.5 26.666666667 +0 15 26.666666667 2 15 26.666666667 4 15 26.666666667 +6 15 26.666666667 8 15 26.666666667 10 15 26.666666667 +12 15 26.666666667 14 15 26.666666667 16 15 26.666666667 +18 15 26.666666667 20 15 26.666666667 0 17.5 26.666666667 +2 17.5 26.666666667 4 17.5 26.666666667 6 17.5 26.666666667 +8 17.5 26.666666667 10 17.5 26.666666667 12 17.5 26.666666667 +14 17.5 26.666666667 16 17.5 26.666666667 18 17.5 26.666666667 +20 17.5 26.666666667 0 20 26.666666667 2 20 26.666666667 +4 20 26.666666667 6 20 26.666666667 8 20 26.666666667 +10 20 26.666666667 12 20 26.666666667 14 20 26.666666667 +16 20 26.666666667 18 20 26.666666667 20 20 26.666666667 +0 22.5 26.666666667 2 22.5 26.666666667 4 22.5 26.666666667 +6 22.5 26.666666667 8 22.5 26.666666667 10 22.5 26.666666667 +12 22.5 26.666666667 14 22.5 26.666666667 16 22.5 26.666666667 +18 22.5 26.666666667 20 22.5 26.666666667 0 25 26.666666667 +2 25 26.666666667 4 25 26.666666667 6 25 26.666666667 +8 25 26.666666667 10 25 26.666666667 12 25 26.666666667 +14 25 26.666666667 16 25 26.666666667 18 25 26.666666667 +20 25 26.666666667 0 27.5 26.666666667 2 27.5 26.666666667 +4 27.5 26.666666667 6 27.5 26.666666667 8 27.5 26.666666667 +10 27.5 26.666666667 12 27.5 26.666666667 14 27.5 26.666666667 +16 27.5 26.666666667 18 27.5 26.666666667 20 27.5 26.666666667 +0 30 26.666666667 2 30 26.666666667 4 30 26.666666667 +6 30 26.666666667 8 30 26.666666667 10 30 26.666666667 +12 30 26.666666667 14 30 26.666666667 16 30 26.666666667 +18 30 26.666666667 20 30 26.666666667 0 32.5 26.666666667 +2 32.5 26.666666667 4 32.5 26.666666667 6 32.5 26.666666667 +8 32.5 26.666666667 10 32.5 26.666666667 12 32.5 26.666666667 +14 32.5 26.666666667 16 32.5 26.666666667 18 32.5 26.666666667 +20 32.5 26.666666667 0 35 26.666666667 2 35 26.666666667 +4 35 26.666666667 6 35 26.666666667 8 35 26.666666667 +10 35 26.666666667 12 35 26.666666667 14 35 26.666666667 +16 35 26.666666667 18 35 26.666666667 20 35 26.666666667 +0 37.5 26.666666667 2 37.5 26.666666667 4 37.5 26.666666667 +6 37.5 26.666666667 8 37.5 26.666666667 10 37.5 26.666666667 +12 37.5 26.666666667 14 37.5 26.666666667 16 37.5 26.666666667 +18 37.5 26.666666667 20 37.5 26.666666667 0 40 26.666666667 +2 40 26.666666667 4 40 26.666666667 6 40 26.666666667 +8 40 26.666666667 10 40 26.666666667 12 40 26.666666667 +14 40 26.666666667 16 40 26.666666667 18 40 26.666666667 +20 40 26.666666667 0 42.5 26.666666667 2 42.5 26.666666667 +4 42.5 26.666666667 6 42.5 26.666666667 8 42.5 26.666666667 +10 42.5 26.666666667 12 42.5 26.666666667 14 42.5 26.666666667 +16 42.5 26.666666667 18 42.5 26.666666667 20 42.5 26.666666667 +0 45 26.666666667 2 45 26.666666667 4 45 26.666666667 +6 45 26.666666667 8 45 26.666666667 10 45 26.666666667 +12 45 26.666666667 14 45 26.666666667 16 45 26.666666667 +18 45 26.666666667 20 45 26.666666667 0 47.5 26.666666667 +2 47.5 26.666666667 4 47.5 26.666666667 6 47.5 26.666666667 +8 47.5 26.666666667 10 47.5 26.666666667 12 47.5 26.666666667 +14 47.5 26.666666667 16 47.5 26.666666667 18 47.5 26.666666667 +20 47.5 26.666666667 0 50 26.666666667 2 50 26.666666667 +4 50 26.666666667 6 50 26.666666667 8 50 26.666666667 +10 50 26.666666667 12 50 26.666666667 14 50 26.666666667 +16 50 26.666666667 18 50 26.666666667 20 50 26.666666667 +0 0 28.333333333 2 0 28.333333333 4 0 28.333333333 +6 0 28.333333333 8 0 28.333333333 10 0 28.333333333 +12 0 28.333333333 14 0 28.333333333 16 0 28.333333333 +18 0 28.333333333 20 0 28.333333333 0 2.5 28.333333333 +2 2.5 28.333333333 4 2.5 28.333333333 6 2.5 28.333333333 +8 2.5 28.333333333 10 2.5 28.333333333 12 2.5 28.333333333 +14 2.5 28.333333333 16 2.5 28.333333333 18 2.5 28.333333333 +20 2.5 28.333333333 0 5 28.333333333 2 5 28.333333333 +4 5 28.333333333 6 5 28.333333333 8 5 28.333333333 +10 5 28.333333333 12 5 28.333333333 14 5 28.333333333 +16 5 28.333333333 18 5 28.333333333 20 5 28.333333333 +0 7.5 28.333333333 2 7.5 28.333333333 4 7.5 28.333333333 +6 7.5 28.333333333 8 7.5 28.333333333 10 7.5 28.333333333 +12 7.5 28.333333333 14 7.5 28.333333333 16 7.5 28.333333333 +18 7.5 28.333333333 20 7.5 28.333333333 0 10 28.333333333 +2 10 28.333333333 4 10 28.333333333 6 10 28.333333333 +8 10 28.333333333 10 10 28.333333333 12 10 28.333333333 +14 10 28.333333333 16 10 28.333333333 18 10 28.333333333 +20 10 28.333333333 0 12.5 28.333333333 2 12.5 28.333333333 +4 12.5 28.333333333 6 12.5 28.333333333 8 12.5 28.333333333 +10 12.5 28.333333333 12 12.5 28.333333333 14 12.5 28.333333333 +16 12.5 28.333333333 18 12.5 28.333333333 20 12.5 28.333333333 +0 15 28.333333333 2 15 28.333333333 4 15 28.333333333 +6 15 28.333333333 8 15 28.333333333 10 15 28.333333333 +12 15 28.333333333 14 15 28.333333333 16 15 28.333333333 +18 15 28.333333333 20 15 28.333333333 0 17.5 28.333333333 +2 17.5 28.333333333 4 17.5 28.333333333 6 17.5 28.333333333 +8 17.5 28.333333333 10 17.5 28.333333333 12 17.5 28.333333333 +14 17.5 28.333333333 16 17.5 28.333333333 18 17.5 28.333333333 +20 17.5 28.333333333 0 20 28.333333333 2 20 28.333333333 +4 20 28.333333333 6 20 28.333333333 8 20 28.333333333 +10 20 28.333333333 12 20 28.333333333 14 20 28.333333333 +16 20 28.333333333 18 20 28.333333333 20 20 28.333333333 +0 22.5 28.333333333 2 22.5 28.333333333 4 22.5 28.333333333 +6 22.5 28.333333333 8 22.5 28.333333333 10 22.5 28.333333333 +12 22.5 28.333333333 14 22.5 28.333333333 16 22.5 28.333333333 +18 22.5 28.333333333 20 22.5 28.333333333 0 25 28.333333333 +2 25 28.333333333 4 25 28.333333333 6 25 28.333333333 +8 25 28.333333333 10 25 28.333333333 12 25 28.333333333 +14 25 28.333333333 16 25 28.333333333 18 25 28.333333333 +20 25 28.333333333 0 27.5 28.333333333 2 27.5 28.333333333 +4 27.5 28.333333333 6 27.5 28.333333333 8 27.5 28.333333333 +10 27.5 28.333333333 12 27.5 28.333333333 14 27.5 28.333333333 +16 27.5 28.333333333 18 27.5 28.333333333 20 27.5 28.333333333 +0 30 28.333333333 2 30 28.333333333 4 30 28.333333333 +6 30 28.333333333 8 30 28.333333333 10 30 28.333333333 +12 30 28.333333333 14 30 28.333333333 16 30 28.333333333 +18 30 28.333333333 20 30 28.333333333 0 32.5 28.333333333 +2 32.5 28.333333333 4 32.5 28.333333333 6 32.5 28.333333333 +8 32.5 28.333333333 10 32.5 28.333333333 12 32.5 28.333333333 +14 32.5 28.333333333 16 32.5 28.333333333 18 32.5 28.333333333 +20 32.5 28.333333333 0 35 28.333333333 2 35 28.333333333 +4 35 28.333333333 6 35 28.333333333 8 35 28.333333333 +10 35 28.333333333 12 35 28.333333333 14 35 28.333333333 +16 35 28.333333333 18 35 28.333333333 20 35 28.333333333 +0 37.5 28.333333333 2 37.5 28.333333333 4 37.5 28.333333333 +6 37.5 28.333333333 8 37.5 28.333333333 10 37.5 28.333333333 +12 37.5 28.333333333 14 37.5 28.333333333 16 37.5 28.333333333 +18 37.5 28.333333333 20 37.5 28.333333333 0 40 28.333333333 +2 40 28.333333333 4 40 28.333333333 6 40 28.333333333 +8 40 28.333333333 10 40 28.333333333 12 40 28.333333333 +14 40 28.333333333 16 40 28.333333333 18 40 28.333333333 +20 40 28.333333333 0 42.5 28.333333333 2 42.5 28.333333333 +4 42.5 28.333333333 6 42.5 28.333333333 8 42.5 28.333333333 +10 42.5 28.333333333 12 42.5 28.333333333 14 42.5 28.333333333 +16 42.5 28.333333333 18 42.5 28.333333333 20 42.5 28.333333333 +0 45 28.333333333 2 45 28.333333333 4 45 28.333333333 +6 45 28.333333333 8 45 28.333333333 10 45 28.333333333 +12 45 28.333333333 14 45 28.333333333 16 45 28.333333333 +18 45 28.333333333 20 45 28.333333333 0 47.5 28.333333333 +2 47.5 28.333333333 4 47.5 28.333333333 6 47.5 28.333333333 +8 47.5 28.333333333 10 47.5 28.333333333 12 47.5 28.333333333 +14 47.5 28.333333333 16 47.5 28.333333333 18 47.5 28.333333333 +20 47.5 28.333333333 0 50 28.333333333 2 50 28.333333333 +4 50 28.333333333 6 50 28.333333333 8 50 28.333333333 +10 50 28.333333333 12 50 28.333333333 14 50 28.333333333 +16 50 28.333333333 18 50 28.333333333 20 50 28.333333333 +0 0 30 2 0 30 4 0 30 +6 0 30 8 0 30 10 0 30 +12 0 30 14 0 30 16 0 30 +18 0 30 20 0 30 0 2.5 30 +2 2.5 30 4 2.5 30 6 2.5 30 +8 2.5 30 10 2.5 30 12 2.5 30 +14 2.5 30 16 2.5 30 18 2.5 30 +20 2.5 30 0 5 30 2 5 30 +4 5 30 6 5 30 8 5 30 +10 5 30 12 5 30 14 5 30 +16 5 30 18 5 30 20 5 30 +0 7.5 30 2 7.5 30 4 7.5 30 +6 7.5 30 8 7.5 30 10 7.5 30 +12 7.5 30 14 7.5 30 16 7.5 30 +18 7.5 30 20 7.5 30 0 10 30 +2 10 30 4 10 30 6 10 30 +8 10 30 10 10 30 12 10 30 +14 10 30 16 10 30 18 10 30 +20 10 30 0 12.5 30 2 12.5 30 +4 12.5 30 6 12.5 30 8 12.5 30 +10 12.5 30 12 12.5 30 14 12.5 30 +16 12.5 30 18 12.5 30 20 12.5 30 +0 15 30 2 15 30 4 15 30 +6 15 30 8 15 30 10 15 30 +12 15 30 14 15 30 16 15 30 +18 15 30 20 15 30 0 17.5 30 +2 17.5 30 4 17.5 30 6 17.5 30 +8 17.5 30 10 17.5 30 12 17.5 30 +14 17.5 30 16 17.5 30 18 17.5 30 +20 17.5 30 0 20 30 2 20 30 +4 20 30 6 20 30 8 20 30 +10 20 30 12 20 30 14 20 30 +16 20 30 18 20 30 20 20 30 +0 22.5 30 2 22.5 30 4 22.5 30 +6 22.5 30 8 22.5 30 10 22.5 30 +12 22.5 30 14 22.5 30 16 22.5 30 +18 22.5 30 20 22.5 30 0 25 30 +2 25 30 4 25 30 6 25 30 +8 25 30 10 25 30 12 25 30 +14 25 30 16 25 30 18 25 30 +20 25 30 0 27.5 30 2 27.5 30 +4 27.5 30 6 27.5 30 8 27.5 30 +10 27.5 30 12 27.5 30 14 27.5 30 +16 27.5 30 18 27.5 30 20 27.5 30 +0 30 30 2 30 30 4 30 30 +6 30 30 8 30 30 10 30 30 +12 30 30 14 30 30 16 30 30 +18 30 30 20 30 30 0 32.5 30 +2 32.5 30 4 32.5 30 6 32.5 30 +8 32.5 30 10 32.5 30 12 32.5 30 +14 32.5 30 16 32.5 30 18 32.5 30 +20 32.5 30 0 35 30 2 35 30 +4 35 30 6 35 30 8 35 30 +10 35 30 12 35 30 14 35 30 +16 35 30 18 35 30 20 35 30 +0 37.5 30 2 37.5 30 4 37.5 30 +6 37.5 30 8 37.5 30 10 37.5 30 +12 37.5 30 14 37.5 30 16 37.5 30 +18 37.5 30 20 37.5 30 0 40 30 +2 40 30 4 40 30 6 40 30 +8 40 30 10 40 30 12 40 30 +14 40 30 16 40 30 18 40 30 +20 40 30 0 42.5 30 2 42.5 30 +4 42.5 30 6 42.5 30 8 42.5 30 +10 42.5 30 12 42.5 30 14 42.5 30 +16 42.5 30 18 42.5 30 20 42.5 30 +0 45 30 2 45 30 4 45 30 +6 45 30 8 45 30 10 45 30 +12 45 30 14 45 30 16 45 30 +18 45 30 20 45 30 0 47.5 30 +2 47.5 30 4 47.5 30 6 47.5 30 +8 47.5 30 10 47.5 30 12 47.5 30 +14 47.5 30 16 47.5 30 18 47.5 30 +20 47.5 30 0 50 30 2 50 30 +4 50 30 6 50 30 8 50 30 +10 50 30 12 50 30 14 50 30 +16 50 30 18 50 30 20 50 30 +0 0 31.666666667 2 0 31.666666667 4 0 31.666666667 +6 0 31.666666667 8 0 31.666666667 10 0 31.666666667 +12 0 31.666666667 14 0 31.666666667 16 0 31.666666667 +18 0 31.666666667 20 0 31.666666667 0 2.5 31.666666667 +2 2.5 31.666666667 4 2.5 31.666666667 6 2.5 31.666666667 +8 2.5 31.666666667 10 2.5 31.666666667 12 2.5 31.666666667 +14 2.5 31.666666667 16 2.5 31.666666667 18 2.5 31.666666667 +20 2.5 31.666666667 0 5 31.666666667 2 5 31.666666667 +4 5 31.666666667 6 5 31.666666667 8 5 31.666666667 +10 5 31.666666667 12 5 31.666666667 14 5 31.666666667 +16 5 31.666666667 18 5 31.666666667 20 5 31.666666667 +0 7.5 31.666666667 2 7.5 31.666666667 4 7.5 31.666666667 +6 7.5 31.666666667 8 7.5 31.666666667 10 7.5 31.666666667 +12 7.5 31.666666667 14 7.5 31.666666667 16 7.5 31.666666667 +18 7.5 31.666666667 20 7.5 31.666666667 0 10 31.666666667 +2 10 31.666666667 4 10 31.666666667 6 10 31.666666667 +8 10 31.666666667 10 10 31.666666667 12 10 31.666666667 +14 10 31.666666667 16 10 31.666666667 18 10 31.666666667 +20 10 31.666666667 0 12.5 31.666666667 2 12.5 31.666666667 +4 12.5 31.666666667 6 12.5 31.666666667 8 12.5 31.666666667 +10 12.5 31.666666667 12 12.5 31.666666667 14 12.5 31.666666667 +16 12.5 31.666666667 18 12.5 31.666666667 20 12.5 31.666666667 +0 15 31.666666667 2 15 31.666666667 4 15 31.666666667 +6 15 31.666666667 8 15 31.666666667 10 15 31.666666667 +12 15 31.666666667 14 15 31.666666667 16 15 31.666666667 +18 15 31.666666667 20 15 31.666666667 0 17.5 31.666666667 +2 17.5 31.666666667 4 17.5 31.666666667 6 17.5 31.666666667 +8 17.5 31.666666667 10 17.5 31.666666667 12 17.5 31.666666667 +14 17.5 31.666666667 16 17.5 31.666666667 18 17.5 31.666666667 +20 17.5 31.666666667 0 20 31.666666667 2 20 31.666666667 +4 20 31.666666667 6 20 31.666666667 8 20 31.666666667 +10 20 31.666666667 12 20 31.666666667 14 20 31.666666667 +16 20 31.666666667 18 20 31.666666667 20 20 31.666666667 +0 22.5 31.666666667 2 22.5 31.666666667 4 22.5 31.666666667 +6 22.5 31.666666667 8 22.5 31.666666667 10 22.5 31.666666667 +12 22.5 31.666666667 14 22.5 31.666666667 16 22.5 31.666666667 +18 22.5 31.666666667 20 22.5 31.666666667 0 25 31.666666667 +2 25 31.666666667 4 25 31.666666667 6 25 31.666666667 +8 25 31.666666667 10 25 31.666666667 12 25 31.666666667 +14 25 31.666666667 16 25 31.666666667 18 25 31.666666667 +20 25 31.666666667 0 27.5 31.666666667 2 27.5 31.666666667 +4 27.5 31.666666667 6 27.5 31.666666667 8 27.5 31.666666667 +10 27.5 31.666666667 12 27.5 31.666666667 14 27.5 31.666666667 +16 27.5 31.666666667 18 27.5 31.666666667 20 27.5 31.666666667 +0 30 31.666666667 2 30 31.666666667 4 30 31.666666667 +6 30 31.666666667 8 30 31.666666667 10 30 31.666666667 +12 30 31.666666667 14 30 31.666666667 16 30 31.666666667 +18 30 31.666666667 20 30 31.666666667 0 32.5 31.666666667 +2 32.5 31.666666667 4 32.5 31.666666667 6 32.5 31.666666667 +8 32.5 31.666666667 10 32.5 31.666666667 12 32.5 31.666666667 +14 32.5 31.666666667 16 32.5 31.666666667 18 32.5 31.666666667 +20 32.5 31.666666667 0 35 31.666666667 2 35 31.666666667 +4 35 31.666666667 6 35 31.666666667 8 35 31.666666667 +10 35 31.666666667 12 35 31.666666667 14 35 31.666666667 +16 35 31.666666667 18 35 31.666666667 20 35 31.666666667 +0 37.5 31.666666667 2 37.5 31.666666667 4 37.5 31.666666667 +6 37.5 31.666666667 8 37.5 31.666666667 10 37.5 31.666666667 +12 37.5 31.666666667 14 37.5 31.666666667 16 37.5 31.666666667 +18 37.5 31.666666667 20 37.5 31.666666667 0 40 31.666666667 +2 40 31.666666667 4 40 31.666666667 6 40 31.666666667 +8 40 31.666666667 10 40 31.666666667 12 40 31.666666667 +14 40 31.666666667 16 40 31.666666667 18 40 31.666666667 +20 40 31.666666667 0 42.5 31.666666667 2 42.5 31.666666667 +4 42.5 31.666666667 6 42.5 31.666666667 8 42.5 31.666666667 +10 42.5 31.666666667 12 42.5 31.666666667 14 42.5 31.666666667 +16 42.5 31.666666667 18 42.5 31.666666667 20 42.5 31.666666667 +0 45 31.666666667 2 45 31.666666667 4 45 31.666666667 +6 45 31.666666667 8 45 31.666666667 10 45 31.666666667 +12 45 31.666666667 14 45 31.666666667 16 45 31.666666667 +18 45 31.666666667 20 45 31.666666667 0 47.5 31.666666667 +2 47.5 31.666666667 4 47.5 31.666666667 6 47.5 31.666666667 +8 47.5 31.666666667 10 47.5 31.666666667 12 47.5 31.666666667 +14 47.5 31.666666667 16 47.5 31.666666667 18 47.5 31.666666667 +20 47.5 31.666666667 0 50 31.666666667 2 50 31.666666667 +4 50 31.666666667 6 50 31.666666667 8 50 31.666666667 +10 50 31.666666667 12 50 31.666666667 14 50 31.666666667 +16 50 31.666666667 18 50 31.666666667 20 50 31.666666667 +0 0 33.333333333 2 0 33.333333333 4 0 33.333333333 +6 0 33.333333333 8 0 33.333333333 10 0 33.333333333 +12 0 33.333333333 14 0 33.333333333 16 0 33.333333333 +18 0 33.333333333 20 0 33.333333333 0 2.5 33.333333333 +2 2.5 33.333333333 4 2.5 33.333333333 6 2.5 33.333333333 +8 2.5 33.333333333 10 2.5 33.333333333 12 2.5 33.333333333 +14 2.5 33.333333333 16 2.5 33.333333333 18 2.5 33.333333333 +20 2.5 33.333333333 0 5 33.333333333 2 5 33.333333333 +4 5 33.333333333 6 5 33.333333333 8 5 33.333333333 +10 5 33.333333333 12 5 33.333333333 14 5 33.333333333 +16 5 33.333333333 18 5 33.333333333 20 5 33.333333333 +0 7.5 33.333333333 2 7.5 33.333333333 4 7.5 33.333333333 +6 7.5 33.333333333 8 7.5 33.333333333 10 7.5 33.333333333 +12 7.5 33.333333333 14 7.5 33.333333333 16 7.5 33.333333333 +18 7.5 33.333333333 20 7.5 33.333333333 0 10 33.333333333 +2 10 33.333333333 4 10 33.333333333 6 10 33.333333333 +8 10 33.333333333 10 10 33.333333333 12 10 33.333333333 +14 10 33.333333333 16 10 33.333333333 18 10 33.333333333 +20 10 33.333333333 0 12.5 33.333333333 2 12.5 33.333333333 +4 12.5 33.333333333 6 12.5 33.333333333 8 12.5 33.333333333 +10 12.5 33.333333333 12 12.5 33.333333333 14 12.5 33.333333333 +16 12.5 33.333333333 18 12.5 33.333333333 20 12.5 33.333333333 +0 15 33.333333333 2 15 33.333333333 4 15 33.333333333 +6 15 33.333333333 8 15 33.333333333 10 15 33.333333333 +12 15 33.333333333 14 15 33.333333333 16 15 33.333333333 +18 15 33.333333333 20 15 33.333333333 0 17.5 33.333333333 +2 17.5 33.333333333 4 17.5 33.333333333 6 17.5 33.333333333 +8 17.5 33.333333333 10 17.5 33.333333333 12 17.5 33.333333333 +14 17.5 33.333333333 16 17.5 33.333333333 18 17.5 33.333333333 +20 17.5 33.333333333 0 20 33.333333333 2 20 33.333333333 +4 20 33.333333333 6 20 33.333333333 8 20 33.333333333 +10 20 33.333333333 12 20 33.333333333 14 20 33.333333333 +16 20 33.333333333 18 20 33.333333333 20 20 33.333333333 +0 22.5 33.333333333 2 22.5 33.333333333 4 22.5 33.333333333 +6 22.5 33.333333333 8 22.5 33.333333333 10 22.5 33.333333333 +12 22.5 33.333333333 14 22.5 33.333333333 16 22.5 33.333333333 +18 22.5 33.333333333 20 22.5 33.333333333 0 25 33.333333333 +2 25 33.333333333 4 25 33.333333333 6 25 33.333333333 +8 25 33.333333333 10 25 33.333333333 12 25 33.333333333 +14 25 33.333333333 16 25 33.333333333 18 25 33.333333333 +20 25 33.333333333 0 27.5 33.333333333 2 27.5 33.333333333 +4 27.5 33.333333333 6 27.5 33.333333333 8 27.5 33.333333333 +10 27.5 33.333333333 12 27.5 33.333333333 14 27.5 33.333333333 +16 27.5 33.333333333 18 27.5 33.333333333 20 27.5 33.333333333 +0 30 33.333333333 2 30 33.333333333 4 30 33.333333333 +6 30 33.333333333 8 30 33.333333333 10 30 33.333333333 +12 30 33.333333333 14 30 33.333333333 16 30 33.333333333 +18 30 33.333333333 20 30 33.333333333 0 32.5 33.333333333 +2 32.5 33.333333333 4 32.5 33.333333333 6 32.5 33.333333333 +8 32.5 33.333333333 10 32.5 33.333333333 12 32.5 33.333333333 +14 32.5 33.333333333 16 32.5 33.333333333 18 32.5 33.333333333 +20 32.5 33.333333333 0 35 33.333333333 2 35 33.333333333 +4 35 33.333333333 6 35 33.333333333 8 35 33.333333333 +10 35 33.333333333 12 35 33.333333333 14 35 33.333333333 +16 35 33.333333333 18 35 33.333333333 20 35 33.333333333 +0 37.5 33.333333333 2 37.5 33.333333333 4 37.5 33.333333333 +6 37.5 33.333333333 8 37.5 33.333333333 10 37.5 33.333333333 +12 37.5 33.333333333 14 37.5 33.333333333 16 37.5 33.333333333 +18 37.5 33.333333333 20 37.5 33.333333333 0 40 33.333333333 +2 40 33.333333333 4 40 33.333333333 6 40 33.333333333 +8 40 33.333333333 10 40 33.333333333 12 40 33.333333333 +14 40 33.333333333 16 40 33.333333333 18 40 33.333333333 +20 40 33.333333333 0 42.5 33.333333333 2 42.5 33.333333333 +4 42.5 33.333333333 6 42.5 33.333333333 8 42.5 33.333333333 +10 42.5 33.333333333 12 42.5 33.333333333 14 42.5 33.333333333 +16 42.5 33.333333333 18 42.5 33.333333333 20 42.5 33.333333333 +0 45 33.333333333 2 45 33.333333333 4 45 33.333333333 +6 45 33.333333333 8 45 33.333333333 10 45 33.333333333 +12 45 33.333333333 14 45 33.333333333 16 45 33.333333333 +18 45 33.333333333 20 45 33.333333333 0 47.5 33.333333333 +2 47.5 33.333333333 4 47.5 33.333333333 6 47.5 33.333333333 +8 47.5 33.333333333 10 47.5 33.333333333 12 47.5 33.333333333 +14 47.5 33.333333333 16 47.5 33.333333333 18 47.5 33.333333333 +20 47.5 33.333333333 0 50 33.333333333 2 50 33.333333333 +4 50 33.333333333 6 50 33.333333333 8 50 33.333333333 +10 50 33.333333333 12 50 33.333333333 14 50 33.333333333 +16 50 33.333333333 18 50 33.333333333 20 50 33.333333333 +0 0 35 2 0 35 4 0 35 +6 0 35 8 0 35 10 0 35 +12 0 35 14 0 35 16 0 35 +18 0 35 20 0 35 0 2.5 35 +2 2.5 35 4 2.5 35 6 2.5 35 +8 2.5 35 10 2.5 35 12 2.5 35 +14 2.5 35 16 2.5 35 18 2.5 35 +20 2.5 35 0 5 35 2 5 35 +4 5 35 6 5 35 8 5 35 +10 5 35 12 5 35 14 5 35 +16 5 35 18 5 35 20 5 35 +0 7.5 35 2 7.5 35 4 7.5 35 +6 7.5 35 8 7.5 35 10 7.5 35 +12 7.5 35 14 7.5 35 16 7.5 35 +18 7.5 35 20 7.5 35 0 10 35 +2 10 35 4 10 35 6 10 35 +8 10 35 10 10 35 12 10 35 +14 10 35 16 10 35 18 10 35 +20 10 35 0 12.5 35 2 12.5 35 +4 12.5 35 6 12.5 35 8 12.5 35 +10 12.5 35 12 12.5 35 14 12.5 35 +16 12.5 35 18 12.5 35 20 12.5 35 +0 15 35 2 15 35 4 15 35 +6 15 35 8 15 35 10 15 35 +12 15 35 14 15 35 16 15 35 +18 15 35 20 15 35 0 17.5 35 +2 17.5 35 4 17.5 35 6 17.5 35 +8 17.5 35 10 17.5 35 12 17.5 35 +14 17.5 35 16 17.5 35 18 17.5 35 +20 17.5 35 0 20 35 2 20 35 +4 20 35 6 20 35 8 20 35 +10 20 35 12 20 35 14 20 35 +16 20 35 18 20 35 20 20 35 +0 22.5 35 2 22.5 35 4 22.5 35 +6 22.5 35 8 22.5 35 10 22.5 35 +12 22.5 35 14 22.5 35 16 22.5 35 +18 22.5 35 20 22.5 35 0 25 35 +2 25 35 4 25 35 6 25 35 +8 25 35 10 25 35 12 25 35 +14 25 35 16 25 35 18 25 35 +20 25 35 0 27.5 35 2 27.5 35 +4 27.5 35 6 27.5 35 8 27.5 35 +10 27.5 35 12 27.5 35 14 27.5 35 +16 27.5 35 18 27.5 35 20 27.5 35 +0 30 35 2 30 35 4 30 35 +6 30 35 8 30 35 10 30 35 +12 30 35 14 30 35 16 30 35 +18 30 35 20 30 35 0 32.5 35 +2 32.5 35 4 32.5 35 6 32.5 35 +8 32.5 35 10 32.5 35 12 32.5 35 +14 32.5 35 16 32.5 35 18 32.5 35 +20 32.5 35 0 35 35 2 35 35 +4 35 35 6 35 35 8 35 35 +10 35 35 12 35 35 14 35 35 +16 35 35 18 35 35 20 35 35 +0 37.5 35 2 37.5 35 4 37.5 35 +6 37.5 35 8 37.5 35 10 37.5 35 +12 37.5 35 14 37.5 35 16 37.5 35 +18 37.5 35 20 37.5 35 0 40 35 +2 40 35 4 40 35 6 40 35 +8 40 35 10 40 35 12 40 35 +14 40 35 16 40 35 18 40 35 +20 40 35 0 42.5 35 2 42.5 35 +4 42.5 35 6 42.5 35 8 42.5 35 +10 42.5 35 12 42.5 35 14 42.5 35 +16 42.5 35 18 42.5 35 20 42.5 35 +0 45 35 2 45 35 4 45 35 +6 45 35 8 45 35 10 45 35 +12 45 35 14 45 35 16 45 35 +18 45 35 20 45 35 0 47.5 35 +2 47.5 35 4 47.5 35 6 47.5 35 +8 47.5 35 10 47.5 35 12 47.5 35 +14 47.5 35 16 47.5 35 18 47.5 35 +20 47.5 35 0 50 35 2 50 35 +4 50 35 6 50 35 8 50 35 +10 50 35 12 50 35 14 50 35 +16 50 35 18 50 35 20 50 35 +0 0 36.666666667 2 0 36.666666667 4 0 36.666666667 +6 0 36.666666667 8 0 36.666666667 10 0 36.666666667 +12 0 36.666666667 14 0 36.666666667 16 0 36.666666667 +18 0 36.666666667 20 0 36.666666667 0 2.5 36.666666667 +2 2.5 36.666666667 4 2.5 36.666666667 6 2.5 36.666666667 +8 2.5 36.666666667 10 2.5 36.666666667 12 2.5 36.666666667 +14 2.5 36.666666667 16 2.5 36.666666667 18 2.5 36.666666667 +20 2.5 36.666666667 0 5 36.666666667 2 5 36.666666667 +4 5 36.666666667 6 5 36.666666667 8 5 36.666666667 +10 5 36.666666667 12 5 36.666666667 14 5 36.666666667 +16 5 36.666666667 18 5 36.666666667 20 5 36.666666667 +0 7.5 36.666666667 2 7.5 36.666666667 4 7.5 36.666666667 +6 7.5 36.666666667 8 7.5 36.666666667 10 7.5 36.666666667 +12 7.5 36.666666667 14 7.5 36.666666667 16 7.5 36.666666667 +18 7.5 36.666666667 20 7.5 36.666666667 0 10 36.666666667 +2 10 36.666666667 4 10 36.666666667 6 10 36.666666667 +8 10 36.666666667 10 10 36.666666667 12 10 36.666666667 +14 10 36.666666667 16 10 36.666666667 18 10 36.666666667 +20 10 36.666666667 0 12.5 36.666666667 2 12.5 36.666666667 +4 12.5 36.666666667 6 12.5 36.666666667 8 12.5 36.666666667 +10 12.5 36.666666667 12 12.5 36.666666667 14 12.5 36.666666667 +16 12.5 36.666666667 18 12.5 36.666666667 20 12.5 36.666666667 +0 15 36.666666667 2 15 36.666666667 4 15 36.666666667 +6 15 36.666666667 8 15 36.666666667 10 15 36.666666667 +12 15 36.666666667 14 15 36.666666667 16 15 36.666666667 +18 15 36.666666667 20 15 36.666666667 0 17.5 36.666666667 +2 17.5 36.666666667 4 17.5 36.666666667 6 17.5 36.666666667 +8 17.5 36.666666667 10 17.5 36.666666667 12 17.5 36.666666667 +14 17.5 36.666666667 16 17.5 36.666666667 18 17.5 36.666666667 +20 17.5 36.666666667 0 20 36.666666667 2 20 36.666666667 +4 20 36.666666667 6 20 36.666666667 8 20 36.666666667 +10 20 36.666666667 12 20 36.666666667 14 20 36.666666667 +16 20 36.666666667 18 20 36.666666667 20 20 36.666666667 +0 22.5 36.666666667 2 22.5 36.666666667 4 22.5 36.666666667 +6 22.5 36.666666667 8 22.5 36.666666667 10 22.5 36.666666667 +12 22.5 36.666666667 14 22.5 36.666666667 16 22.5 36.666666667 +18 22.5 36.666666667 20 22.5 36.666666667 0 25 36.666666667 +2 25 36.666666667 4 25 36.666666667 6 25 36.666666667 +8 25 36.666666667 10 25 36.666666667 12 25 36.666666667 +14 25 36.666666667 16 25 36.666666667 18 25 36.666666667 +20 25 36.666666667 0 27.5 36.666666667 2 27.5 36.666666667 +4 27.5 36.666666667 6 27.5 36.666666667 8 27.5 36.666666667 +10 27.5 36.666666667 12 27.5 36.666666667 14 27.5 36.666666667 +16 27.5 36.666666667 18 27.5 36.666666667 20 27.5 36.666666667 +0 30 36.666666667 2 30 36.666666667 4 30 36.666666667 +6 30 36.666666667 8 30 36.666666667 10 30 36.666666667 +12 30 36.666666667 14 30 36.666666667 16 30 36.666666667 +18 30 36.666666667 20 30 36.666666667 0 32.5 36.666666667 +2 32.5 36.666666667 4 32.5 36.666666667 6 32.5 36.666666667 +8 32.5 36.666666667 10 32.5 36.666666667 12 32.5 36.666666667 +14 32.5 36.666666667 16 32.5 36.666666667 18 32.5 36.666666667 +20 32.5 36.666666667 0 35 36.666666667 2 35 36.666666667 +4 35 36.666666667 6 35 36.666666667 8 35 36.666666667 +10 35 36.666666667 12 35 36.666666667 14 35 36.666666667 +16 35 36.666666667 18 35 36.666666667 20 35 36.666666667 +0 37.5 36.666666667 2 37.5 36.666666667 4 37.5 36.666666667 +6 37.5 36.666666667 8 37.5 36.666666667 10 37.5 36.666666667 +12 37.5 36.666666667 14 37.5 36.666666667 16 37.5 36.666666667 +18 37.5 36.666666667 20 37.5 36.666666667 0 40 36.666666667 +2 40 36.666666667 4 40 36.666666667 6 40 36.666666667 +8 40 36.666666667 10 40 36.666666667 12 40 36.666666667 +14 40 36.666666667 16 40 36.666666667 18 40 36.666666667 +20 40 36.666666667 0 42.5 36.666666667 2 42.5 36.666666667 +4 42.5 36.666666667 6 42.5 36.666666667 8 42.5 36.666666667 +10 42.5 36.666666667 12 42.5 36.666666667 14 42.5 36.666666667 +16 42.5 36.666666667 18 42.5 36.666666667 20 42.5 36.666666667 +0 45 36.666666667 2 45 36.666666667 4 45 36.666666667 +6 45 36.666666667 8 45 36.666666667 10 45 36.666666667 +12 45 36.666666667 14 45 36.666666667 16 45 36.666666667 +18 45 36.666666667 20 45 36.666666667 0 47.5 36.666666667 +2 47.5 36.666666667 4 47.5 36.666666667 6 47.5 36.666666667 +8 47.5 36.666666667 10 47.5 36.666666667 12 47.5 36.666666667 +14 47.5 36.666666667 16 47.5 36.666666667 18 47.5 36.666666667 +20 47.5 36.666666667 0 50 36.666666667 2 50 36.666666667 +4 50 36.666666667 6 50 36.666666667 8 50 36.666666667 +10 50 36.666666667 12 50 36.666666667 14 50 36.666666667 +16 50 36.666666667 18 50 36.666666667 20 50 36.666666667 +0 0 38.333333333 2 0 38.333333333 4 0 38.333333333 +6 0 38.333333333 8 0 38.333333333 10 0 38.333333333 +12 0 38.333333333 14 0 38.333333333 16 0 38.333333333 +18 0 38.333333333 20 0 38.333333333 0 2.5 38.333333333 +2 2.5 38.333333333 4 2.5 38.333333333 6 2.5 38.333333333 +8 2.5 38.333333333 10 2.5 38.333333333 12 2.5 38.333333333 +14 2.5 38.333333333 16 2.5 38.333333333 18 2.5 38.333333333 +20 2.5 38.333333333 0 5 38.333333333 2 5 38.333333333 +4 5 38.333333333 6 5 38.333333333 8 5 38.333333333 +10 5 38.333333333 12 5 38.333333333 14 5 38.333333333 +16 5 38.333333333 18 5 38.333333333 20 5 38.333333333 +0 7.5 38.333333333 2 7.5 38.333333333 4 7.5 38.333333333 +6 7.5 38.333333333 8 7.5 38.333333333 10 7.5 38.333333333 +12 7.5 38.333333333 14 7.5 38.333333333 16 7.5 38.333333333 +18 7.5 38.333333333 20 7.5 38.333333333 0 10 38.333333333 +2 10 38.333333333 4 10 38.333333333 6 10 38.333333333 +8 10 38.333333333 10 10 38.333333333 12 10 38.333333333 +14 10 38.333333333 16 10 38.333333333 18 10 38.333333333 +20 10 38.333333333 0 12.5 38.333333333 2 12.5 38.333333333 +4 12.5 38.333333333 6 12.5 38.333333333 8 12.5 38.333333333 +10 12.5 38.333333333 12 12.5 38.333333333 14 12.5 38.333333333 +16 12.5 38.333333333 18 12.5 38.333333333 20 12.5 38.333333333 +0 15 38.333333333 2 15 38.333333333 4 15 38.333333333 +6 15 38.333333333 8 15 38.333333333 10 15 38.333333333 +12 15 38.333333333 14 15 38.333333333 16 15 38.333333333 +18 15 38.333333333 20 15 38.333333333 0 17.5 38.333333333 +2 17.5 38.333333333 4 17.5 38.333333333 6 17.5 38.333333333 +8 17.5 38.333333333 10 17.5 38.333333333 12 17.5 38.333333333 +14 17.5 38.333333333 16 17.5 38.333333333 18 17.5 38.333333333 +20 17.5 38.333333333 0 20 38.333333333 2 20 38.333333333 +4 20 38.333333333 6 20 38.333333333 8 20 38.333333333 +10 20 38.333333333 12 20 38.333333333 14 20 38.333333333 +16 20 38.333333333 18 20 38.333333333 20 20 38.333333333 +0 22.5 38.333333333 2 22.5 38.333333333 4 22.5 38.333333333 +6 22.5 38.333333333 8 22.5 38.333333333 10 22.5 38.333333333 +12 22.5 38.333333333 14 22.5 38.333333333 16 22.5 38.333333333 +18 22.5 38.333333333 20 22.5 38.333333333 0 25 38.333333333 +2 25 38.333333333 4 25 38.333333333 6 25 38.333333333 +8 25 38.333333333 10 25 38.333333333 12 25 38.333333333 +14 25 38.333333333 16 25 38.333333333 18 25 38.333333333 +20 25 38.333333333 0 27.5 38.333333333 2 27.5 38.333333333 +4 27.5 38.333333333 6 27.5 38.333333333 8 27.5 38.333333333 +10 27.5 38.333333333 12 27.5 38.333333333 14 27.5 38.333333333 +16 27.5 38.333333333 18 27.5 38.333333333 20 27.5 38.333333333 +0 30 38.333333333 2 30 38.333333333 4 30 38.333333333 +6 30 38.333333333 8 30 38.333333333 10 30 38.333333333 +12 30 38.333333333 14 30 38.333333333 16 30 38.333333333 +18 30 38.333333333 20 30 38.333333333 0 32.5 38.333333333 +2 32.5 38.333333333 4 32.5 38.333333333 6 32.5 38.333333333 +8 32.5 38.333333333 10 32.5 38.333333333 12 32.5 38.333333333 +14 32.5 38.333333333 16 32.5 38.333333333 18 32.5 38.333333333 +20 32.5 38.333333333 0 35 38.333333333 2 35 38.333333333 +4 35 38.333333333 6 35 38.333333333 8 35 38.333333333 +10 35 38.333333333 12 35 38.333333333 14 35 38.333333333 +16 35 38.333333333 18 35 38.333333333 20 35 38.333333333 +0 37.5 38.333333333 2 37.5 38.333333333 4 37.5 38.333333333 +6 37.5 38.333333333 8 37.5 38.333333333 10 37.5 38.333333333 +12 37.5 38.333333333 14 37.5 38.333333333 16 37.5 38.333333333 +18 37.5 38.333333333 20 37.5 38.333333333 0 40 38.333333333 +2 40 38.333333333 4 40 38.333333333 6 40 38.333333333 +8 40 38.333333333 10 40 38.333333333 12 40 38.333333333 +14 40 38.333333333 16 40 38.333333333 18 40 38.333333333 +20 40 38.333333333 0 42.5 38.333333333 2 42.5 38.333333333 +4 42.5 38.333333333 6 42.5 38.333333333 8 42.5 38.333333333 +10 42.5 38.333333333 12 42.5 38.333333333 14 42.5 38.333333333 +16 42.5 38.333333333 18 42.5 38.333333333 20 42.5 38.333333333 +0 45 38.333333333 2 45 38.333333333 4 45 38.333333333 +6 45 38.333333333 8 45 38.333333333 10 45 38.333333333 +12 45 38.333333333 14 45 38.333333333 16 45 38.333333333 +18 45 38.333333333 20 45 38.333333333 0 47.5 38.333333333 +2 47.5 38.333333333 4 47.5 38.333333333 6 47.5 38.333333333 +8 47.5 38.333333333 10 47.5 38.333333333 12 47.5 38.333333333 +14 47.5 38.333333333 16 47.5 38.333333333 18 47.5 38.333333333 +20 47.5 38.333333333 0 50 38.333333333 2 50 38.333333333 +4 50 38.333333333 6 50 38.333333333 8 50 38.333333333 +10 50 38.333333333 12 50 38.333333333 14 50 38.333333333 +16 50 38.333333333 18 50 38.333333333 20 50 38.333333333 +0 0 40 2 0 40 4 0 40 +6 0 40 8 0 40 10 0 40 +12 0 40 14 0 40 16 0 40 +18 0 40 20 0 40 0 2.5 40 +2 2.5 40 4 2.5 40 6 2.5 40 +8 2.5 40 10 2.5 40 12 2.5 40 +14 2.5 40 16 2.5 40 18 2.5 40 +20 2.5 40 0 5 40 2 5 40 +4 5 40 6 5 40 8 5 40 +10 5 40 12 5 40 14 5 40 +16 5 40 18 5 40 20 5 40 +0 7.5 40 2 7.5 40 4 7.5 40 +6 7.5 40 8 7.5 40 10 7.5 40 +12 7.5 40 14 7.5 40 16 7.5 40 +18 7.5 40 20 7.5 40 0 10 40 +2 10 40 4 10 40 6 10 40 +8 10 40 10 10 40 12 10 40 +14 10 40 16 10 40 18 10 40 +20 10 40 0 12.5 40 2 12.5 40 +4 12.5 40 6 12.5 40 8 12.5 40 +10 12.5 40 12 12.5 40 14 12.5 40 +16 12.5 40 18 12.5 40 20 12.5 40 +0 15 40 2 15 40 4 15 40 +6 15 40 8 15 40 10 15 40 +12 15 40 14 15 40 16 15 40 +18 15 40 20 15 40 0 17.5 40 +2 17.5 40 4 17.5 40 6 17.5 40 +8 17.5 40 10 17.5 40 12 17.5 40 +14 17.5 40 16 17.5 40 18 17.5 40 +20 17.5 40 0 20 40 2 20 40 +4 20 40 6 20 40 8 20 40 +10 20 40 12 20 40 14 20 40 +16 20 40 18 20 40 20 20 40 +0 22.5 40 2 22.5 40 4 22.5 40 +6 22.5 40 8 22.5 40 10 22.5 40 +12 22.5 40 14 22.5 40 16 22.5 40 +18 22.5 40 20 22.5 40 0 25 40 +2 25 40 4 25 40 6 25 40 +8 25 40 10 25 40 12 25 40 +14 25 40 16 25 40 18 25 40 +20 25 40 0 27.5 40 2 27.5 40 +4 27.5 40 6 27.5 40 8 27.5 40 +10 27.5 40 12 27.5 40 14 27.5 40 +16 27.5 40 18 27.5 40 20 27.5 40 +0 30 40 2 30 40 4 30 40 +6 30 40 8 30 40 10 30 40 +12 30 40 14 30 40 16 30 40 +18 30 40 20 30 40 0 32.5 40 +2 32.5 40 4 32.5 40 6 32.5 40 +8 32.5 40 10 32.5 40 12 32.5 40 +14 32.5 40 16 32.5 40 18 32.5 40 +20 32.5 40 0 35 40 2 35 40 +4 35 40 6 35 40 8 35 40 +10 35 40 12 35 40 14 35 40 +16 35 40 18 35 40 20 35 40 +0 37.5 40 2 37.5 40 4 37.5 40 +6 37.5 40 8 37.5 40 10 37.5 40 +12 37.5 40 14 37.5 40 16 37.5 40 +18 37.5 40 20 37.5 40 0 40 40 +2 40 40 4 40 40 6 40 40 +8 40 40 10 40 40 12 40 40 +14 40 40 16 40 40 18 40 40 +20 40 40 0 42.5 40 2 42.5 40 +4 42.5 40 6 42.5 40 8 42.5 40 +10 42.5 40 12 42.5 40 14 42.5 40 +16 42.5 40 18 42.5 40 20 42.5 40 +0 45 40 2 45 40 4 45 40 +6 45 40 8 45 40 10 45 40 +12 45 40 14 45 40 16 45 40 +18 45 40 20 45 40 0 47.5 40 +2 47.5 40 4 47.5 40 6 47.5 40 +8 47.5 40 10 47.5 40 12 47.5 40 +14 47.5 40 16 47.5 40 18 47.5 40 +20 47.5 40 0 50 40 2 50 40 +4 50 40 6 50 40 8 50 40 +10 50 40 12 50 40 14 50 40 +16 50 40 18 50 40 20 50 40 +0 0 41.666666667 2 0 41.666666667 4 0 41.666666667 +6 0 41.666666667 8 0 41.666666667 10 0 41.666666667 +12 0 41.666666667 14 0 41.666666667 16 0 41.666666667 +18 0 41.666666667 20 0 41.666666667 0 2.5 41.666666667 +2 2.5 41.666666667 4 2.5 41.666666667 6 2.5 41.666666667 +8 2.5 41.666666667 10 2.5 41.666666667 12 2.5 41.666666667 +14 2.5 41.666666667 16 2.5 41.666666667 18 2.5 41.666666667 +20 2.5 41.666666667 0 5 41.666666667 2 5 41.666666667 +4 5 41.666666667 6 5 41.666666667 8 5 41.666666667 +10 5 41.666666667 12 5 41.666666667 14 5 41.666666667 +16 5 41.666666667 18 5 41.666666667 20 5 41.666666667 +0 7.5 41.666666667 2 7.5 41.666666667 4 7.5 41.666666667 +6 7.5 41.666666667 8 7.5 41.666666667 10 7.5 41.666666667 +12 7.5 41.666666667 14 7.5 41.666666667 16 7.5 41.666666667 +18 7.5 41.666666667 20 7.5 41.666666667 0 10 41.666666667 +2 10 41.666666667 4 10 41.666666667 6 10 41.666666667 +8 10 41.666666667 10 10 41.666666667 12 10 41.666666667 +14 10 41.666666667 16 10 41.666666667 18 10 41.666666667 +20 10 41.666666667 0 12.5 41.666666667 2 12.5 41.666666667 +4 12.5 41.666666667 6 12.5 41.666666667 8 12.5 41.666666667 +10 12.5 41.666666667 12 12.5 41.666666667 14 12.5 41.666666667 +16 12.5 41.666666667 18 12.5 41.666666667 20 12.5 41.666666667 +0 15 41.666666667 2 15 41.666666667 4 15 41.666666667 +6 15 41.666666667 8 15 41.666666667 10 15 41.666666667 +12 15 41.666666667 14 15 41.666666667 16 15 41.666666667 +18 15 41.666666667 20 15 41.666666667 0 17.5 41.666666667 +2 17.5 41.666666667 4 17.5 41.666666667 6 17.5 41.666666667 +8 17.5 41.666666667 10 17.5 41.666666667 12 17.5 41.666666667 +14 17.5 41.666666667 16 17.5 41.666666667 18 17.5 41.666666667 +20 17.5 41.666666667 0 20 41.666666667 2 20 41.666666667 +4 20 41.666666667 6 20 41.666666667 8 20 41.666666667 +10 20 41.666666667 12 20 41.666666667 14 20 41.666666667 +16 20 41.666666667 18 20 41.666666667 20 20 41.666666667 +0 22.5 41.666666667 2 22.5 41.666666667 4 22.5 41.666666667 +6 22.5 41.666666667 8 22.5 41.666666667 10 22.5 41.666666667 +12 22.5 41.666666667 14 22.5 41.666666667 16 22.5 41.666666667 +18 22.5 41.666666667 20 22.5 41.666666667 0 25 41.666666667 +2 25 41.666666667 4 25 41.666666667 6 25 41.666666667 +8 25 41.666666667 10 25 41.666666667 12 25 41.666666667 +14 25 41.666666667 16 25 41.666666667 18 25 41.666666667 +20 25 41.666666667 0 27.5 41.666666667 2 27.5 41.666666667 +4 27.5 41.666666667 6 27.5 41.666666667 8 27.5 41.666666667 +10 27.5 41.666666667 12 27.5 41.666666667 14 27.5 41.666666667 +16 27.5 41.666666667 18 27.5 41.666666667 20 27.5 41.666666667 +0 30 41.666666667 2 30 41.666666667 4 30 41.666666667 +6 30 41.666666667 8 30 41.666666667 10 30 41.666666667 +12 30 41.666666667 14 30 41.666666667 16 30 41.666666667 +18 30 41.666666667 20 30 41.666666667 0 32.5 41.666666667 +2 32.5 41.666666667 4 32.5 41.666666667 6 32.5 41.666666667 +8 32.5 41.666666667 10 32.5 41.666666667 12 32.5 41.666666667 +14 32.5 41.666666667 16 32.5 41.666666667 18 32.5 41.666666667 +20 32.5 41.666666667 0 35 41.666666667 2 35 41.666666667 +4 35 41.666666667 6 35 41.666666667 8 35 41.666666667 +10 35 41.666666667 12 35 41.666666667 14 35 41.666666667 +16 35 41.666666667 18 35 41.666666667 20 35 41.666666667 +0 37.5 41.666666667 2 37.5 41.666666667 4 37.5 41.666666667 +6 37.5 41.666666667 8 37.5 41.666666667 10 37.5 41.666666667 +12 37.5 41.666666667 14 37.5 41.666666667 16 37.5 41.666666667 +18 37.5 41.666666667 20 37.5 41.666666667 0 40 41.666666667 +2 40 41.666666667 4 40 41.666666667 6 40 41.666666667 +8 40 41.666666667 10 40 41.666666667 12 40 41.666666667 +14 40 41.666666667 16 40 41.666666667 18 40 41.666666667 +20 40 41.666666667 0 42.5 41.666666667 2 42.5 41.666666667 +4 42.5 41.666666667 6 42.5 41.666666667 8 42.5 41.666666667 +10 42.5 41.666666667 12 42.5 41.666666667 14 42.5 41.666666667 +16 42.5 41.666666667 18 42.5 41.666666667 20 42.5 41.666666667 +0 45 41.666666667 2 45 41.666666667 4 45 41.666666667 +6 45 41.666666667 8 45 41.666666667 10 45 41.666666667 +12 45 41.666666667 14 45 41.666666667 16 45 41.666666667 +18 45 41.666666667 20 45 41.666666667 0 47.5 41.666666667 +2 47.5 41.666666667 4 47.5 41.666666667 6 47.5 41.666666667 +8 47.5 41.666666667 10 47.5 41.666666667 12 47.5 41.666666667 +14 47.5 41.666666667 16 47.5 41.666666667 18 47.5 41.666666667 +20 47.5 41.666666667 0 50 41.666666667 2 50 41.666666667 +4 50 41.666666667 6 50 41.666666667 8 50 41.666666667 +10 50 41.666666667 12 50 41.666666667 14 50 41.666666667 +16 50 41.666666667 18 50 41.666666667 20 50 41.666666667 +0 0 43.333333333 2 0 43.333333333 4 0 43.333333333 +6 0 43.333333333 8 0 43.333333333 10 0 43.333333333 +12 0 43.333333333 14 0 43.333333333 16 0 43.333333333 +18 0 43.333333333 20 0 43.333333333 0 2.5 43.333333333 +2 2.5 43.333333333 4 2.5 43.333333333 6 2.5 43.333333333 +8 2.5 43.333333333 10 2.5 43.333333333 12 2.5 43.333333333 +14 2.5 43.333333333 16 2.5 43.333333333 18 2.5 43.333333333 +20 2.5 43.333333333 0 5 43.333333333 2 5 43.333333333 +4 5 43.333333333 6 5 43.333333333 8 5 43.333333333 +10 5 43.333333333 12 5 43.333333333 14 5 43.333333333 +16 5 43.333333333 18 5 43.333333333 20 5 43.333333333 +0 7.5 43.333333333 2 7.5 43.333333333 4 7.5 43.333333333 +6 7.5 43.333333333 8 7.5 43.333333333 10 7.5 43.333333333 +12 7.5 43.333333333 14 7.5 43.333333333 16 7.5 43.333333333 +18 7.5 43.333333333 20 7.5 43.333333333 0 10 43.333333333 +2 10 43.333333333 4 10 43.333333333 6 10 43.333333333 +8 10 43.333333333 10 10 43.333333333 12 10 43.333333333 +14 10 43.333333333 16 10 43.333333333 18 10 43.333333333 +20 10 43.333333333 0 12.5 43.333333333 2 12.5 43.333333333 +4 12.5 43.333333333 6 12.5 43.333333333 8 12.5 43.333333333 +10 12.5 43.333333333 12 12.5 43.333333333 14 12.5 43.333333333 +16 12.5 43.333333333 18 12.5 43.333333333 20 12.5 43.333333333 +0 15 43.333333333 2 15 43.333333333 4 15 43.333333333 +6 15 43.333333333 8 15 43.333333333 10 15 43.333333333 +12 15 43.333333333 14 15 43.333333333 16 15 43.333333333 +18 15 43.333333333 20 15 43.333333333 0 17.5 43.333333333 +2 17.5 43.333333333 4 17.5 43.333333333 6 17.5 43.333333333 +8 17.5 43.333333333 10 17.5 43.333333333 12 17.5 43.333333333 +14 17.5 43.333333333 16 17.5 43.333333333 18 17.5 43.333333333 +20 17.5 43.333333333 0 20 43.333333333 2 20 43.333333333 +4 20 43.333333333 6 20 43.333333333 8 20 43.333333333 +10 20 43.333333333 12 20 43.333333333 14 20 43.333333333 +16 20 43.333333333 18 20 43.333333333 20 20 43.333333333 +0 22.5 43.333333333 2 22.5 43.333333333 4 22.5 43.333333333 +6 22.5 43.333333333 8 22.5 43.333333333 10 22.5 43.333333333 +12 22.5 43.333333333 14 22.5 43.333333333 16 22.5 43.333333333 +18 22.5 43.333333333 20 22.5 43.333333333 0 25 43.333333333 +2 25 43.333333333 4 25 43.333333333 6 25 43.333333333 +8 25 43.333333333 10 25 43.333333333 12 25 43.333333333 +14 25 43.333333333 16 25 43.333333333 18 25 43.333333333 +20 25 43.333333333 0 27.5 43.333333333 2 27.5 43.333333333 +4 27.5 43.333333333 6 27.5 43.333333333 8 27.5 43.333333333 +10 27.5 43.333333333 12 27.5 43.333333333 14 27.5 43.333333333 +16 27.5 43.333333333 18 27.5 43.333333333 20 27.5 43.333333333 +0 30 43.333333333 2 30 43.333333333 4 30 43.333333333 +6 30 43.333333333 8 30 43.333333333 10 30 43.333333333 +12 30 43.333333333 14 30 43.333333333 16 30 43.333333333 +18 30 43.333333333 20 30 43.333333333 0 32.5 43.333333333 +2 32.5 43.333333333 4 32.5 43.333333333 6 32.5 43.333333333 +8 32.5 43.333333333 10 32.5 43.333333333 12 32.5 43.333333333 +14 32.5 43.333333333 16 32.5 43.333333333 18 32.5 43.333333333 +20 32.5 43.333333333 0 35 43.333333333 2 35 43.333333333 +4 35 43.333333333 6 35 43.333333333 8 35 43.333333333 +10 35 43.333333333 12 35 43.333333333 14 35 43.333333333 +16 35 43.333333333 18 35 43.333333333 20 35 43.333333333 +0 37.5 43.333333333 2 37.5 43.333333333 4 37.5 43.333333333 +6 37.5 43.333333333 8 37.5 43.333333333 10 37.5 43.333333333 +12 37.5 43.333333333 14 37.5 43.333333333 16 37.5 43.333333333 +18 37.5 43.333333333 20 37.5 43.333333333 0 40 43.333333333 +2 40 43.333333333 4 40 43.333333333 6 40 43.333333333 +8 40 43.333333333 10 40 43.333333333 12 40 43.333333333 +14 40 43.333333333 16 40 43.333333333 18 40 43.333333333 +20 40 43.333333333 0 42.5 43.333333333 2 42.5 43.333333333 +4 42.5 43.333333333 6 42.5 43.333333333 8 42.5 43.333333333 +10 42.5 43.333333333 12 42.5 43.333333333 14 42.5 43.333333333 +16 42.5 43.333333333 18 42.5 43.333333333 20 42.5 43.333333333 +0 45 43.333333333 2 45 43.333333333 4 45 43.333333333 +6 45 43.333333333 8 45 43.333333333 10 45 43.333333333 +12 45 43.333333333 14 45 43.333333333 16 45 43.333333333 +18 45 43.333333333 20 45 43.333333333 0 47.5 43.333333333 +2 47.5 43.333333333 4 47.5 43.333333333 6 47.5 43.333333333 +8 47.5 43.333333333 10 47.5 43.333333333 12 47.5 43.333333333 +14 47.5 43.333333333 16 47.5 43.333333333 18 47.5 43.333333333 +20 47.5 43.333333333 0 50 43.333333333 2 50 43.333333333 +4 50 43.333333333 6 50 43.333333333 8 50 43.333333333 +10 50 43.333333333 12 50 43.333333333 14 50 43.333333333 +16 50 43.333333333 18 50 43.333333333 20 50 43.333333333 +0 0 45 2 0 45 4 0 45 +6 0 45 8 0 45 10 0 45 +12 0 45 14 0 45 16 0 45 +18 0 45 20 0 45 0 2.5 45 +2 2.5 45 4 2.5 45 6 2.5 45 +8 2.5 45 10 2.5 45 12 2.5 45 +14 2.5 45 16 2.5 45 18 2.5 45 +20 2.5 45 0 5 45 2 5 45 +4 5 45 6 5 45 8 5 45 +10 5 45 12 5 45 14 5 45 +16 5 45 18 5 45 20 5 45 +0 7.5 45 2 7.5 45 4 7.5 45 +6 7.5 45 8 7.5 45 10 7.5 45 +12 7.5 45 14 7.5 45 16 7.5 45 +18 7.5 45 20 7.5 45 0 10 45 +2 10 45 4 10 45 6 10 45 +8 10 45 10 10 45 12 10 45 +14 10 45 16 10 45 18 10 45 +20 10 45 0 12.5 45 2 12.5 45 +4 12.5 45 6 12.5 45 8 12.5 45 +10 12.5 45 12 12.5 45 14 12.5 45 +16 12.5 45 18 12.5 45 20 12.5 45 +0 15 45 2 15 45 4 15 45 +6 15 45 8 15 45 10 15 45 +12 15 45 14 15 45 16 15 45 +18 15 45 20 15 45 0 17.5 45 +2 17.5 45 4 17.5 45 6 17.5 45 +8 17.5 45 10 17.5 45 12 17.5 45 +14 17.5 45 16 17.5 45 18 17.5 45 +20 17.5 45 0 20 45 2 20 45 +4 20 45 6 20 45 8 20 45 +10 20 45 12 20 45 14 20 45 +16 20 45 18 20 45 20 20 45 +0 22.5 45 2 22.5 45 4 22.5 45 +6 22.5 45 8 22.5 45 10 22.5 45 +12 22.5 45 14 22.5 45 16 22.5 45 +18 22.5 45 20 22.5 45 0 25 45 +2 25 45 4 25 45 6 25 45 +8 25 45 10 25 45 12 25 45 +14 25 45 16 25 45 18 25 45 +20 25 45 0 27.5 45 2 27.5 45 +4 27.5 45 6 27.5 45 8 27.5 45 +10 27.5 45 12 27.5 45 14 27.5 45 +16 27.5 45 18 27.5 45 20 27.5 45 +0 30 45 2 30 45 4 30 45 +6 30 45 8 30 45 10 30 45 +12 30 45 14 30 45 16 30 45 +18 30 45 20 30 45 0 32.5 45 +2 32.5 45 4 32.5 45 6 32.5 45 +8 32.5 45 10 32.5 45 12 32.5 45 +14 32.5 45 16 32.5 45 18 32.5 45 +20 32.5 45 0 35 45 2 35 45 +4 35 45 6 35 45 8 35 45 +10 35 45 12 35 45 14 35 45 +16 35 45 18 35 45 20 35 45 +0 37.5 45 2 37.5 45 4 37.5 45 +6 37.5 45 8 37.5 45 10 37.5 45 +12 37.5 45 14 37.5 45 16 37.5 45 +18 37.5 45 20 37.5 45 0 40 45 +2 40 45 4 40 45 6 40 45 +8 40 45 10 40 45 12 40 45 +14 40 45 16 40 45 18 40 45 +20 40 45 0 42.5 45 2 42.5 45 +4 42.5 45 6 42.5 45 8 42.5 45 +10 42.5 45 12 42.5 45 14 42.5 45 +16 42.5 45 18 42.5 45 20 42.5 45 +0 45 45 2 45 45 4 45 45 +6 45 45 8 45 45 10 45 45 +12 45 45 14 45 45 16 45 45 +18 45 45 20 45 45 0 47.5 45 +2 47.5 45 4 47.5 45 6 47.5 45 +8 47.5 45 10 47.5 45 12 47.5 45 +14 47.5 45 16 47.5 45 18 47.5 45 +20 47.5 45 0 50 45 2 50 45 +4 50 45 6 50 45 8 50 45 +10 50 45 12 50 45 14 50 45 +16 50 45 18 50 45 20 50 45 +0 0 46.666666667 2 0 46.666666667 4 0 46.666666667 +6 0 46.666666667 8 0 46.666666667 10 0 46.666666667 +12 0 46.666666667 14 0 46.666666667 16 0 46.666666667 +18 0 46.666666667 20 0 46.666666667 0 2.5 46.666666667 +2 2.5 46.666666667 4 2.5 46.666666667 6 2.5 46.666666667 +8 2.5 46.666666667 10 2.5 46.666666667 12 2.5 46.666666667 +14 2.5 46.666666667 16 2.5 46.666666667 18 2.5 46.666666667 +20 2.5 46.666666667 0 5 46.666666667 2 5 46.666666667 +4 5 46.666666667 6 5 46.666666667 8 5 46.666666667 +10 5 46.666666667 12 5 46.666666667 14 5 46.666666667 +16 5 46.666666667 18 5 46.666666667 20 5 46.666666667 +0 7.5 46.666666667 2 7.5 46.666666667 4 7.5 46.666666667 +6 7.5 46.666666667 8 7.5 46.666666667 10 7.5 46.666666667 +12 7.5 46.666666667 14 7.5 46.666666667 16 7.5 46.666666667 +18 7.5 46.666666667 20 7.5 46.666666667 0 10 46.666666667 +2 10 46.666666667 4 10 46.666666667 6 10 46.666666667 +8 10 46.666666667 10 10 46.666666667 12 10 46.666666667 +14 10 46.666666667 16 10 46.666666667 18 10 46.666666667 +20 10 46.666666667 0 12.5 46.666666667 2 12.5 46.666666667 +4 12.5 46.666666667 6 12.5 46.666666667 8 12.5 46.666666667 +10 12.5 46.666666667 12 12.5 46.666666667 14 12.5 46.666666667 +16 12.5 46.666666667 18 12.5 46.666666667 20 12.5 46.666666667 +0 15 46.666666667 2 15 46.666666667 4 15 46.666666667 +6 15 46.666666667 8 15 46.666666667 10 15 46.666666667 +12 15 46.666666667 14 15 46.666666667 16 15 46.666666667 +18 15 46.666666667 20 15 46.666666667 0 17.5 46.666666667 +2 17.5 46.666666667 4 17.5 46.666666667 6 17.5 46.666666667 +8 17.5 46.666666667 10 17.5 46.666666667 12 17.5 46.666666667 +14 17.5 46.666666667 16 17.5 46.666666667 18 17.5 46.666666667 +20 17.5 46.666666667 0 20 46.666666667 2 20 46.666666667 +4 20 46.666666667 6 20 46.666666667 8 20 46.666666667 +10 20 46.666666667 12 20 46.666666667 14 20 46.666666667 +16 20 46.666666667 18 20 46.666666667 20 20 46.666666667 +0 22.5 46.666666667 2 22.5 46.666666667 4 22.5 46.666666667 +6 22.5 46.666666667 8 22.5 46.666666667 10 22.5 46.666666667 +12 22.5 46.666666667 14 22.5 46.666666667 16 22.5 46.666666667 +18 22.5 46.666666667 20 22.5 46.666666667 0 25 46.666666667 +2 25 46.666666667 4 25 46.666666667 6 25 46.666666667 +8 25 46.666666667 10 25 46.666666667 12 25 46.666666667 +14 25 46.666666667 16 25 46.666666667 18 25 46.666666667 +20 25 46.666666667 0 27.5 46.666666667 2 27.5 46.666666667 +4 27.5 46.666666667 6 27.5 46.666666667 8 27.5 46.666666667 +10 27.5 46.666666667 12 27.5 46.666666667 14 27.5 46.666666667 +16 27.5 46.666666667 18 27.5 46.666666667 20 27.5 46.666666667 +0 30 46.666666667 2 30 46.666666667 4 30 46.666666667 +6 30 46.666666667 8 30 46.666666667 10 30 46.666666667 +12 30 46.666666667 14 30 46.666666667 16 30 46.666666667 +18 30 46.666666667 20 30 46.666666667 0 32.5 46.666666667 +2 32.5 46.666666667 4 32.5 46.666666667 6 32.5 46.666666667 +8 32.5 46.666666667 10 32.5 46.666666667 12 32.5 46.666666667 +14 32.5 46.666666667 16 32.5 46.666666667 18 32.5 46.666666667 +20 32.5 46.666666667 0 35 46.666666667 2 35 46.666666667 +4 35 46.666666667 6 35 46.666666667 8 35 46.666666667 +10 35 46.666666667 12 35 46.666666667 14 35 46.666666667 +16 35 46.666666667 18 35 46.666666667 20 35 46.666666667 +0 37.5 46.666666667 2 37.5 46.666666667 4 37.5 46.666666667 +6 37.5 46.666666667 8 37.5 46.666666667 10 37.5 46.666666667 +12 37.5 46.666666667 14 37.5 46.666666667 16 37.5 46.666666667 +18 37.5 46.666666667 20 37.5 46.666666667 0 40 46.666666667 +2 40 46.666666667 4 40 46.666666667 6 40 46.666666667 +8 40 46.666666667 10 40 46.666666667 12 40 46.666666667 +14 40 46.666666667 16 40 46.666666667 18 40 46.666666667 +20 40 46.666666667 0 42.5 46.666666667 2 42.5 46.666666667 +4 42.5 46.666666667 6 42.5 46.666666667 8 42.5 46.666666667 +10 42.5 46.666666667 12 42.5 46.666666667 14 42.5 46.666666667 +16 42.5 46.666666667 18 42.5 46.666666667 20 42.5 46.666666667 +0 45 46.666666667 2 45 46.666666667 4 45 46.666666667 +6 45 46.666666667 8 45 46.666666667 10 45 46.666666667 +12 45 46.666666667 14 45 46.666666667 16 45 46.666666667 +18 45 46.666666667 20 45 46.666666667 0 47.5 46.666666667 +2 47.5 46.666666667 4 47.5 46.666666667 6 47.5 46.666666667 +8 47.5 46.666666667 10 47.5 46.666666667 12 47.5 46.666666667 +14 47.5 46.666666667 16 47.5 46.666666667 18 47.5 46.666666667 +20 47.5 46.666666667 0 50 46.666666667 2 50 46.666666667 +4 50 46.666666667 6 50 46.666666667 8 50 46.666666667 +10 50 46.666666667 12 50 46.666666667 14 50 46.666666667 +16 50 46.666666667 18 50 46.666666667 20 50 46.666666667 +0 0 48.333333333 2 0 48.333333333 4 0 48.333333333 +6 0 48.333333333 8 0 48.333333333 10 0 48.333333333 +12 0 48.333333333 14 0 48.333333333 16 0 48.333333333 +18 0 48.333333333 20 0 48.333333333 0 2.5 48.333333333 +2 2.5 48.333333333 4 2.5 48.333333333 6 2.5 48.333333333 +8 2.5 48.333333333 10 2.5 48.333333333 12 2.5 48.333333333 +14 2.5 48.333333333 16 2.5 48.333333333 18 2.5 48.333333333 +20 2.5 48.333333333 0 5 48.333333333 2 5 48.333333333 +4 5 48.333333333 6 5 48.333333333 8 5 48.333333333 +10 5 48.333333333 12 5 48.333333333 14 5 48.333333333 +16 5 48.333333333 18 5 48.333333333 20 5 48.333333333 +0 7.5 48.333333333 2 7.5 48.333333333 4 7.5 48.333333333 +6 7.5 48.333333333 8 7.5 48.333333333 10 7.5 48.333333333 +12 7.5 48.333333333 14 7.5 48.333333333 16 7.5 48.333333333 +18 7.5 48.333333333 20 7.5 48.333333333 0 10 48.333333333 +2 10 48.333333333 4 10 48.333333333 6 10 48.333333333 +8 10 48.333333333 10 10 48.333333333 12 10 48.333333333 +14 10 48.333333333 16 10 48.333333333 18 10 48.333333333 +20 10 48.333333333 0 12.5 48.333333333 2 12.5 48.333333333 +4 12.5 48.333333333 6 12.5 48.333333333 8 12.5 48.333333333 +10 12.5 48.333333333 12 12.5 48.333333333 14 12.5 48.333333333 +16 12.5 48.333333333 18 12.5 48.333333333 20 12.5 48.333333333 +0 15 48.333333333 2 15 48.333333333 4 15 48.333333333 +6 15 48.333333333 8 15 48.333333333 10 15 48.333333333 +12 15 48.333333333 14 15 48.333333333 16 15 48.333333333 +18 15 48.333333333 20 15 48.333333333 0 17.5 48.333333333 +2 17.5 48.333333333 4 17.5 48.333333333 6 17.5 48.333333333 +8 17.5 48.333333333 10 17.5 48.333333333 12 17.5 48.333333333 +14 17.5 48.333333333 16 17.5 48.333333333 18 17.5 48.333333333 +20 17.5 48.333333333 0 20 48.333333333 2 20 48.333333333 +4 20 48.333333333 6 20 48.333333333 8 20 48.333333333 +10 20 48.333333333 12 20 48.333333333 14 20 48.333333333 +16 20 48.333333333 18 20 48.333333333 20 20 48.333333333 +0 22.5 48.333333333 2 22.5 48.333333333 4 22.5 48.333333333 +6 22.5 48.333333333 8 22.5 48.333333333 10 22.5 48.333333333 +12 22.5 48.333333333 14 22.5 48.333333333 16 22.5 48.333333333 +18 22.5 48.333333333 20 22.5 48.333333333 0 25 48.333333333 +2 25 48.333333333 4 25 48.333333333 6 25 48.333333333 +8 25 48.333333333 10 25 48.333333333 12 25 48.333333333 +14 25 48.333333333 16 25 48.333333333 18 25 48.333333333 +20 25 48.333333333 0 27.5 48.333333333 2 27.5 48.333333333 +4 27.5 48.333333333 6 27.5 48.333333333 8 27.5 48.333333333 +10 27.5 48.333333333 12 27.5 48.333333333 14 27.5 48.333333333 +16 27.5 48.333333333 18 27.5 48.333333333 20 27.5 48.333333333 +0 30 48.333333333 2 30 48.333333333 4 30 48.333333333 +6 30 48.333333333 8 30 48.333333333 10 30 48.333333333 +12 30 48.333333333 14 30 48.333333333 16 30 48.333333333 +18 30 48.333333333 20 30 48.333333333 0 32.5 48.333333333 +2 32.5 48.333333333 4 32.5 48.333333333 6 32.5 48.333333333 +8 32.5 48.333333333 10 32.5 48.333333333 12 32.5 48.333333333 +14 32.5 48.333333333 16 32.5 48.333333333 18 32.5 48.333333333 +20 32.5 48.333333333 0 35 48.333333333 2 35 48.333333333 +4 35 48.333333333 6 35 48.333333333 8 35 48.333333333 +10 35 48.333333333 12 35 48.333333333 14 35 48.333333333 +16 35 48.333333333 18 35 48.333333333 20 35 48.333333333 +0 37.5 48.333333333 2 37.5 48.333333333 4 37.5 48.333333333 +6 37.5 48.333333333 8 37.5 48.333333333 10 37.5 48.333333333 +12 37.5 48.333333333 14 37.5 48.333333333 16 37.5 48.333333333 +18 37.5 48.333333333 20 37.5 48.333333333 0 40 48.333333333 +2 40 48.333333333 4 40 48.333333333 6 40 48.333333333 +8 40 48.333333333 10 40 48.333333333 12 40 48.333333333 +14 40 48.333333333 16 40 48.333333333 18 40 48.333333333 +20 40 48.333333333 0 42.5 48.333333333 2 42.5 48.333333333 +4 42.5 48.333333333 6 42.5 48.333333333 8 42.5 48.333333333 +10 42.5 48.333333333 12 42.5 48.333333333 14 42.5 48.333333333 +16 42.5 48.333333333 18 42.5 48.333333333 20 42.5 48.333333333 +0 45 48.333333333 2 45 48.333333333 4 45 48.333333333 +6 45 48.333333333 8 45 48.333333333 10 45 48.333333333 +12 45 48.333333333 14 45 48.333333333 16 45 48.333333333 +18 45 48.333333333 20 45 48.333333333 0 47.5 48.333333333 +2 47.5 48.333333333 4 47.5 48.333333333 6 47.5 48.333333333 +8 47.5 48.333333333 10 47.5 48.333333333 12 47.5 48.333333333 +14 47.5 48.333333333 16 47.5 48.333333333 18 47.5 48.333333333 +20 47.5 48.333333333 0 50 48.333333333 2 50 48.333333333 +4 50 48.333333333 6 50 48.333333333 8 50 48.333333333 +10 50 48.333333333 12 50 48.333333333 14 50 48.333333333 +16 50 48.333333333 18 50 48.333333333 20 50 48.333333333 +0 0 50 2 0 50 4 0 50 +6 0 50 8 0 50 10 0 50 +12 0 50 14 0 50 16 0 50 +18 0 50 20 0 50 0 2.5 50 +2 2.5 50 4 2.5 50 6 2.5 50 +8 2.5 50 10 2.5 50 12 2.5 50 +14 2.5 50 16 2.5 50 18 2.5 50 +20 2.5 50 0 5 50 2 5 50 +4 5 50 6 5 50 8 5 50 +10 5 50 12 5 50 14 5 50 +16 5 50 18 5 50 20 5 50 +0 7.5 50 2 7.5 50 4 7.5 50 +6 7.5 50 8 7.5 50 10 7.5 50 +12 7.5 50 14 7.5 50 16 7.5 50 +18 7.5 50 20 7.5 50 0 10 50 +2 10 50 4 10 50 6 10 50 +8 10 50 10 10 50 12 10 50 +14 10 50 16 10 50 18 10 50 +20 10 50 0 12.5 50 2 12.5 50 +4 12.5 50 6 12.5 50 8 12.5 50 +10 12.5 50 12 12.5 50 14 12.5 50 +16 12.5 50 18 12.5 50 20 12.5 50 +0 15 50 2 15 50 4 15 50 +6 15 50 8 15 50 10 15 50 +12 15 50 14 15 50 16 15 50 +18 15 50 20 15 50 0 17.5 50 +2 17.5 50 4 17.5 50 6 17.5 50 +8 17.5 50 10 17.5 50 12 17.5 50 +14 17.5 50 16 17.5 50 18 17.5 50 +20 17.5 50 0 20 50 2 20 50 +4 20 50 6 20 50 8 20 50 +10 20 50 12 20 50 14 20 50 +16 20 50 18 20 50 20 20 50 +0 22.5 50 2 22.5 50 4 22.5 50 +6 22.5 50 8 22.5 50 10 22.5 50 +12 22.5 50 14 22.5 50 16 22.5 50 +18 22.5 50 20 22.5 50 0 25 50 +2 25 50 4 25 50 6 25 50 +8 25 50 10 25 50 12 25 50 +14 25 50 16 25 50 18 25 50 +20 25 50 0 27.5 50 2 27.5 50 +4 27.5 50 6 27.5 50 8 27.5 50 +10 27.5 50 12 27.5 50 14 27.5 50 +16 27.5 50 18 27.5 50 20 27.5 50 +0 30 50 2 30 50 4 30 50 +6 30 50 8 30 50 10 30 50 +12 30 50 14 30 50 16 30 50 +18 30 50 20 30 50 0 32.5 50 +2 32.5 50 4 32.5 50 6 32.5 50 +8 32.5 50 10 32.5 50 12 32.5 50 +14 32.5 50 16 32.5 50 18 32.5 50 +20 32.5 50 0 35 50 2 35 50 +4 35 50 6 35 50 8 35 50 +10 35 50 12 35 50 14 35 50 +16 35 50 18 35 50 20 35 50 +0 37.5 50 2 37.5 50 4 37.5 50 +6 37.5 50 8 37.5 50 10 37.5 50 +12 37.5 50 14 37.5 50 16 37.5 50 +18 37.5 50 20 37.5 50 0 40 50 +2 40 50 4 40 50 6 40 50 +8 40 50 10 40 50 12 40 50 +14 40 50 16 40 50 18 40 50 +20 40 50 0 42.5 50 2 42.5 50 +4 42.5 50 6 42.5 50 8 42.5 50 +10 42.5 50 12 42.5 50 14 42.5 50 +16 42.5 50 18 42.5 50 20 42.5 50 +0 45 50 2 45 50 4 45 50 +6 45 50 8 45 50 10 45 50 +12 45 50 14 45 50 16 45 50 +18 45 50 20 45 50 0 47.5 50 +2 47.5 50 4 47.5 50 6 47.5 50 +8 47.5 50 10 47.5 50 12 47.5 50 +14 47.5 50 16 47.5 50 18 47.5 50 +20 47.5 50 0 50 50 2 50 50 +4 50 50 6 50 50 8 50 50 +10 50 50 12 50 50 14 50 50 +16 50 50 18 50 50 20 50 50 + diff --git a/tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk b/tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk new file mode 100644 index 00000000000..2308432eec4 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk @@ -0,0 +1,210 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 175 double +5.4951556605 7.8305813044 -10 5.4951556605 12.169418696 -10 6.0986903619 8.1212282982 -7.5 +6.0986903619 11.878771702 -7.5 7.7475778302 8.9152906522 -10 7.7475778302 8.9152906522 -5.6698729811 +7.7475778302 11.084709348 -10 7.7475778302 11.084709348 -5.6698729811 8.0493451809 9.0606141491 -8.75 +8.0493451809 10.939385851 -8.75 8.8737889151 9.4576453261 -7.8349364905 8.8737889151 10.542354674 -7.8349364905 +8.8873953302 5.1253604391 -10 8.8873953302 14.874639561 -10 9.0364560916 5.778438306 -7.5 +9.0364560916 14.221561694 -7.5 9.4436976651 7.5626802195 -10 9.4436976651 7.5626802195 -5.6698729811 +9.4436976651 12.43731978 -10 9.4436976651 12.43731978 -5.6698729811 9.5182280458 7.889219153 -8.75 +9.5182280458 12.110780847 -8.75 9.7218488326 8.7813401098 -7.8349364905 9.7218488326 11.21865989 -7.8349364905 +10 10 -10 10 10 -7.5 10 10 -5 +10.779362252 9.0227106469 -7.8349364905 10.779362252 10.977289353 -7.8349364905 11.25 10 -7.8349364905 +11.349895019 8.3072851868 -8.75 11.349895019 11.692714813 -8.75 11.558724505 8.0454212938 -10 +11.558724505 8.0454212938 -5.6698729811 11.558724505 11.954578706 -10 11.558724505 11.954578706 -5.6698729811 +12.165063509 10 -8.75 12.5 10 -10 12.5 10 -5.6698729811 +12.699790037 6.6145703735 -7.5 12.699790037 13.385429626 -7.5 13.117449009 6.0908425877 -10 +13.117449009 13.909157412 -10 14.330127019 10 -7.5 14.330127019 10 -7.5 +15 10 -10 15 10 -10 10 10 -8.75 +10 10 -6.25 10.625 10 -8.9174682453 11.875 10 -6.7524047358 +11.082531755 10 -9.375 13.247595264 10 -8.125 11.25 10 -10 +13.75 10 -10 10.389681126 10.488644677 -8.9174682453 11.169043378 11.46593403 -6.7524047358 +10.674947509 10.846357407 -9.375 12.024842528 12.53907222 -8.125 10.779362252 10.977289353 -10 +12.338086757 12.931868059 -10 9.8609244163 10.609329945 -8.9174682453 9.5827732488 11.827989835 -6.7524047358 +9.7591140229 11.055390424 -9.375 9.2773420687 13.166171271 -8.125 9.7218488326 11.21865989 -10 +9.1655464977 13.655979671 -10 9.4368944576 10.271177337 -8.9174682453 8.3106833727 10.813532011 -6.7524047358 +9.0246725905 10.469692925 -9.375 7.0740177714 11.409078776 -8.125 8.8737889151 10.542354674 -10 +6.6213667454 11.627064022 -10 9.4368944576 9.7288226631 -8.9174682453 8.3106833727 9.1864679892 -6.7524047358 +9.0246725905 9.5303070745 -9.375 7.0740177714 8.5909212236 -8.125 8.8737889151 9.4576453261 -10 +6.6213667454 8.3729359783 -10 9.8609244163 9.3906700549 -8.9174682453 9.5827732488 8.1720101647 -6.7524047358 +9.7591140229 8.9446095765 -9.375 9.2773420687 6.8338287295 -8.125 9.7218488326 8.7813401098 -10 +9.1655464977 6.3440203293 -10 10.389681126 9.5113553235 -8.9174682453 11.169043378 8.5340659704 -6.7524047358 +10.674947509 9.1536425934 -9.375 12.024842528 7.4609277801 -8.125 10.779362252 9.0227106469 -10 +12.338086757 7.0681319407 -10 10.647047613 10 -7.5851854343 11.294095226 10 -5.1703708686 +11.767766953 10 -8.232233047 13.535533906 10 -6.4644660941 12.414814566 10 -9.3529523872 +14.829629131 10 -8.7059047745 10.403427588 10.505882194 -7.5851854343 10.806855176 11.011764389 -5.1703708686 +11.102184667 11.382095857 -8.232233047 12.204369334 12.764191715 -6.4644660941 11.505612255 11.887978052 -9.3529523872 +13.01122451 13.775956104 -8.7059047745 9.8560183609 10.630824778 -7.5851854343 9.7120367218 11.261649556 -5.1703708686 +9.6066348466 11.723445345 -8.232233047 9.2132696932 13.446890689 -6.4644660941 9.4626532075 12.354270123 -9.3529523872 +8.925306415 14.708540246 -8.7059047745 9.4170302449 10.280743438 -7.5851854343 8.8340604897 10.561486875 -5.1703708686 +8.4072970097 10.767005335 -8.232233047 6.8145940193 11.534010671 -6.4644660941 7.8243272545 11.047748773 -9.3529523872 +5.6486545091 12.095497546 -8.7059047745 9.4170302449 9.7192565624 -7.5851854343 8.8340604897 9.4385131248 -5.1703708686 +8.4072970097 9.2329946646 -8.232233047 6.8145940193 8.4659893291 -6.4644660941 7.8243272545 8.9522512269 -9.3529523872 +5.6486545091 7.9045024539 -8.7059047745 9.8560183609 9.3691752218 -7.5851854343 9.7120367218 8.7383504436 -5.1703708686 +9.6066348466 8.2765546553 -8.232233047 9.2132696932 6.5531093106 -6.4644660941 9.4626532075 7.6457298771 -9.3529523872 +8.925306415 5.2914597543 -8.7059047745 10.403427588 9.4941178057 -7.5851854343 10.806855176 8.9882356114 -5.1703708686 +11.102184667 8.6179041425 -8.232233047 12.204369334 7.235808285 -6.4644660941 11.505612255 8.1120219482 -9.3529523872 +13.01122451 6.2240438964 -8.7059047745 11.126211085 10.542354674 -7.8349364905 12.25242217 11.084709348 -5.6698729811 +11.950654819 10.939385851 -8.75 13.901309638 11.878771702 -7.5 12.25242217 11.084709348 -10 +14.50484434 12.169418696 -10 10.278151167 11.21865989 -7.8349364905 10.556302335 12.43731978 -5.6698729811 +10.481771954 12.110780847 -8.75 10.963543908 14.221561694 -7.5 10.556302335 12.43731978 -10 +11.11260467 14.874639561 -10 9.2206377477 10.977289353 -7.8349364905 8.4412754954 11.954578706 -5.6698729811 +8.6501049815 11.692714813 -8.75 7.3002099629 13.385429626 -7.5 8.4412754954 11.954578706 -10 +6.8825509907 13.909157412 -10 8.75 10 -7.8349364905 7.5 10 -5.6698729811 +7.8349364905 10 -8.75 5.6698729811 10 -7.5 7.5 10 -10 +5 10 -10 9.2206377477 9.0227106469 -7.8349364905 8.4412754954 8.0454212938 -5.6698729811 +8.6501049815 8.3072851868 -8.75 7.3002099629 6.6145703735 -7.5 8.4412754954 8.0454212938 -10 +6.8825509907 6.0908425877 -10 10.278151167 8.7813401098 -7.8349364905 10.556302335 7.5626802195 -5.6698729811 +10.481771954 7.889219153 -8.75 10.963543908 5.778438306 -7.5 10.556302335 7.5626802195 -10 +11.11260467 5.1253604391 -10 11.126211085 9.4576453261 -7.8349364905 12.25242217 8.9152906522 -5.6698729811 +11.950654819 9.0606141491 -8.75 13.901309638 8.1212282982 -7.5 12.25242217 8.9152906522 -10 +14.50484434 7.8305813044 -10 +CELLS 43 840 +OFFSETS vtktypeint64 +0 20 40 60 80 100 120 140 160 +180 200 220 240 260 280 300 320 340 +360 380 400 420 440 460 480 500 520 +540 560 580 600 620 640 660 680 700 +720 740 760 780 800 820 840 +CONNECTIVITY vtktypeint64 +24 25 29 24 24 25 28 24 47 +91 49 24 47 97 55 24 24 25 +133 24 25 26 38 29 25 26 35 +28 48 92 50 91 48 98 56 97 +25 26 134 133 24 29 36 24 24 +28 31 24 49 93 51 24 55 99 +57 24 24 133 135 24 29 38 43 +36 28 35 40 31 50 94 52 93 +56 100 58 99 133 134 136 135 24 +36 37 24 24 31 34 24 51 95 +53 24 57 101 59 24 24 135 137 +24 36 43 45 37 31 40 42 34 +52 96 54 95 58 102 60 101 135 +136 138 137 24 25 28 24 24 25 +23 24 47 97 55 24 47 103 61 +24 24 25 139 24 25 26 35 28 +25 26 19 23 48 98 56 97 48 +104 62 103 25 26 140 139 24 28 +31 24 24 23 21 24 55 99 57 +24 61 105 63 24 24 139 141 24 +28 35 40 31 23 19 15 21 56 +100 58 99 62 106 64 105 139 140 +142 141 24 31 34 24 24 21 18 +24 57 101 59 24 63 107 65 24 +24 141 143 24 31 40 42 34 21 +15 13 18 58 102 60 101 64 108 +66 107 141 142 144 143 24 25 23 +24 24 25 11 24 47 103 61 24 +47 109 67 24 24 25 145 24 25 +26 19 23 25 26 7 11 48 104 +62 103 48 110 68 109 25 26 146 +145 24 23 21 24 24 11 9 24 +61 105 63 24 67 111 69 24 24 +145 147 24 23 19 15 21 11 7 +3 9 62 106 64 105 68 112 70 +111 145 146 148 147 24 21 18 24 +24 9 6 24 63 107 65 24 69 +113 71 24 24 147 149 24 21 15 +13 18 9 3 1 6 64 108 66 +107 70 114 72 113 147 148 150 149 +24 25 11 24 24 25 10 24 47 +109 67 24 47 115 73 24 24 25 +151 24 25 26 7 11 25 26 5 +10 48 110 68 109 48 116 74 115 +25 26 152 151 24 11 9 24 24 +10 8 24 67 111 69 24 73 117 +75 24 24 151 153 24 11 7 3 +9 10 5 2 8 68 112 70 111 +74 118 76 117 151 152 154 153 24 +9 6 24 24 8 4 24 69 113 +71 24 75 119 77 24 24 153 155 +24 9 3 1 6 8 2 0 4 +70 114 72 113 76 120 78 119 153 +154 156 155 24 25 10 24 24 25 +22 24 47 115 73 24 47 121 79 +24 24 25 157 24 25 26 5 10 +25 26 17 22 48 116 74 115 48 +122 80 121 25 26 158 157 24 10 +8 24 24 22 20 24 73 117 75 +24 79 123 81 24 24 157 159 24 +10 5 2 8 22 17 14 20 74 +118 76 117 80 124 82 123 157 158 +160 159 24 8 4 24 24 20 16 +24 75 119 77 24 81 125 83 24 +24 159 161 24 8 2 0 4 20 +14 12 16 76 120 78 119 82 126 +84 125 159 160 162 161 24 25 22 +24 24 25 27 24 47 121 79 24 +47 127 85 24 24 25 163 24 25 +26 17 22 25 26 33 27 48 122 +80 121 48 128 86 127 25 26 164 +163 24 22 20 24 24 27 30 24 +79 123 81 24 85 129 87 24 24 +163 165 24 22 17 14 20 27 33 +39 30 80 124 82 123 86 130 88 +129 163 164 166 165 24 20 16 24 +24 30 32 24 81 125 83 24 87 +131 89 24 24 165 167 24 20 14 +12 16 30 39 41 32 82 126 84 +125 88 132 90 131 165 166 168 167 +24 25 27 24 24 25 29 24 47 +127 85 24 47 91 49 24 24 25 +169 24 25 26 33 27 25 26 38 +29 48 128 86 127 48 92 50 91 +25 26 170 169 24 27 30 24 24 +29 36 24 85 129 87 24 49 93 +51 24 24 169 171 24 27 33 39 +30 29 38 43 36 86 130 88 129 +50 94 52 93 169 170 172 171 24 +30 32 24 24 36 37 24 87 131 +89 24 51 95 53 24 24 171 173 +24 30 39 41 32 36 43 45 37 +88 132 90 131 52 96 54 95 171 +172 174 173 +CELL_TYPES 42 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 + diff --git a/tests/unit_tests/mesh_to_vtk/spherical-linear.vtk b/tests/unit_tests/mesh_to_vtk/spherical-linear.vtk new file mode 100644 index 00000000000..3dff18a0839 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/spherical-linear.vtk @@ -0,0 +1,39 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 3 4 8 +POINTS 96 double +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 11.25 10 -7.8349364905 12.5 10 -5.6698729811 +10 10 -10 12.165063509 10 -8.75 14.330127019 10 -7.5 +10 10 -10 12.5 10 -10 15 10 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 10.779362252 10.977289353 -7.8349364905 11.558724505 11.954578706 -5.6698729811 +10 10 -10 11.349895019 11.692714813 -8.75 12.699790037 13.385429626 -7.5 +10 10 -10 11.558724505 11.954578706 -10 13.117449009 13.909157412 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 9.7218488326 11.21865989 -7.8349364905 9.4436976651 12.43731978 -5.6698729811 +10 10 -10 9.5182280458 12.110780847 -8.75 9.0364560916 14.221561694 -7.5 +10 10 -10 9.4436976651 12.43731978 -10 8.8873953302 14.874639561 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 8.8737889151 10.542354674 -7.8349364905 7.7475778302 11.084709348 -5.6698729811 +10 10 -10 8.0493451809 10.939385851 -8.75 6.0986903619 11.878771702 -7.5 +10 10 -10 7.7475778302 11.084709348 -10 5.4951556605 12.169418696 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 8.8737889151 9.4576453261 -7.8349364905 7.7475778302 8.9152906522 -5.6698729811 +10 10 -10 8.0493451809 9.0606141491 -8.75 6.0986903619 8.1212282982 -7.5 +10 10 -10 7.7475778302 8.9152906522 -10 5.4951556605 7.8305813044 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 9.7218488326 8.7813401098 -7.8349364905 9.4436976651 7.5626802195 -5.6698729811 +10 10 -10 9.5182280458 7.889219153 -8.75 9.0364560916 5.778438306 -7.5 +10 10 -10 9.4436976651 7.5626802195 -10 8.8873953302 5.1253604391 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 10.779362252 9.0227106469 -7.8349364905 11.558724505 8.0454212938 -5.6698729811 +10 10 -10 11.349895019 8.3072851868 -8.75 12.699790037 6.6145703735 -7.5 +10 10 -10 11.558724505 8.0454212938 -10 13.117449009 6.0908425877 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 11.25 10 -7.8349364905 12.5 10 -5.6698729811 +10 10 -10 12.165063509 10 -8.75 14.330127019 10 -7.5 +10 10 -10 12.5 10 -10 15 10 -10 + diff --git a/tests/unit_tests/mesh_to_vtk/test.py b/tests/unit_tests/mesh_to_vtk/test.py new file mode 100644 index 00000000000..3ee6c0298ce --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/test.py @@ -0,0 +1,101 @@ +import difflib +import filecmp +import numpy as np +from pathlib import Path + +import openmc +import pytest + +from tests.regression_tests import config + +pytest.importorskip('vtk') + +def full_path(f): + return Path(__file__).parent.absolute() / f + +def diff_file(file1, file2): + with open(file1) as fh: + f1_text = fh.readlines() + with open(file2) as fh: + f2_text = fh.readlines() + diff_lines = difflib.unified_diff(f1_text, f2_text) + return ''.join(diff_lines) + +# test meshes +reg_mesh = openmc.RegularMesh() +reg_mesh.lower_left = (0, 0, 0) +reg_mesh.upper_right = (20, 50, 50) +reg_mesh.dimension = (10, 20, 30) + +rect_mesh = openmc.RectilinearMesh() +rect_mesh.x_grid = np.linspace(0, 10, 5) +rect_mesh.y_grid = np.geomspace(5., 20., 10) +rect_mesh.z_grid = np.linspace(1, 100, 20) + +cyl_mesh = openmc.CylindricalMesh( + origin=(10, 10, -10), + r_grid=np.linspace(0, 5, 5), + phi_grid=np.linspace(0, 2 * np.pi, 4), + z_grid=np.linspace(0, 2, 4), +) + +sphere_mesh = openmc.SphericalMesh( + origin=(10, 10, -10), + r_grid=np.linspace(0, 5, 3), + theta_grid=np.linspace(0, 0.5 * np.pi, 4), + phi_grid=np.linspace(0, 2*np.pi, 8), +) + + +def mesh_data(mesh_dims): + data = 100 * np.arange(np.prod(mesh_dims), dtype=float) + return data.reshape(*mesh_dims) + +test_data = ((reg_mesh, False, 'regular'), + (rect_mesh, False, 'rectilinear'), + (cyl_mesh, False, 'cylindrical-linear'), + (cyl_mesh, True, 'cylindrical-curvilinear'), + (sphere_mesh, False, 'spherical-linear'), + (sphere_mesh, True, 'spherical-curvilinear')) + +@pytest.mark.parametrize('mesh_params', + test_data, + ids=lambda params: params[2]) +def test_mesh_write_vtk(mesh_params, run_in_tmpdir): + mesh, curvilinear, filename = mesh_params + + test_data = full_path(filename + ".vtk") + kwargs = {} + if curvilinear: + kwargs['curvilinear'] = curvilinear + + # set output filename based on test configuration + filename = test_data if config['update'] else filename + "-actual.vtk" + + # write the mesh file and compare to the expected version + mesh.write_data_to_vtk(filename, **kwargs) + + try: + assert filecmp.cmp(test_data, filename) + except AssertionError as e: + diff = diff_file(test_data, filename) + raise AssertionError(diff) from e + +# check data writing +def test_mesh_write_vtk_data(run_in_tmpdir): + + data = {'ascending_data': mesh_data(cyl_mesh.dimension)} + filename_expected = full_path('cyl-data.vtk') + filename_actual = full_path('cyl-data-actual.vtk') + # update the test file if requested + filename = filename_expected if config['update'] else filename_actual + cyl_mesh.write_data_to_vtk(filename, datasets=data, volume_normalization=False) + + try: + assert filecmp.cmp(filename, filename_expected) + except AssertionError as e: + diff = diff_file(filename_expected, filename) + raise AssertionError(diff) from e + + + diff --git a/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py b/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py new file mode 100644 index 00000000000..baa54498438 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py @@ -0,0 +1,320 @@ +from itertools import product + +import numpy as np +from pathlib import Path +import pytest + +vtk = pytest.importorskip("vtk") +from vtk.util import numpy_support as nps + +import openmc + +@pytest.fixture +def model(): + openmc.reset_auto_ids() + + surf1 = openmc.Sphere(r=10, boundary_type='vacuum') + surf2 = openmc.XPlane(x0=-0.001, boundary_type='vacuum') + + cell = openmc.Cell(region=-surf1 & -surf2) + + geometry = openmc.Geometry([cell]) + + settings = openmc.Settings() + settings.batches = 2 + settings.particles = 100 + settings.run_mode = 'fixed source' + + source = openmc.IndependentSource() + source.angle = openmc.stats.Isotropic() + source.energy = openmc.stats.Discrete([1.0e6], [1.0]) + source.space = openmc.stats.Point((-0.01, -0.01, -0.01)) + + settings.source = source + + model = openmc.Model(geometry=geometry, settings=settings) + + return model + + +regular_mesh = openmc.RegularMesh() +regular_mesh.lower_left = (-10, -10, -10) +regular_mesh.upper_right = (10, 10, 10) +regular_mesh.dimension = [30, 20, 10] + +rectilinear_mesh = openmc.RectilinearMesh() +rectilinear_mesh.x_grid = np.linspace(-10, 10, 6) +rectilinear_mesh.y_grid = np.logspace(0, 1, 7) +rectilinear_mesh.y_grid = \ + np.concatenate((-rectilinear_mesh.y_grid[::-1], rectilinear_mesh.y_grid)) +rectilinear_mesh.z_grid = np.linspace(-10, 10, 11) + +cylinder_mesh = openmc.CylindricalMesh( + r_grid=np.linspace(0, 10, 23), + z_grid=np.linspace(0, 1, 15) +) +cylinder_mesh.phi_grid = np.linspace(0, np.pi, 21) + +spherical_mesh = openmc.SphericalMesh( + r_grid=np.linspace(1, 10, 30), + phi_grid=np.linspace(0, 0.8*np.pi, 25), + theta_grid=np.linspace(0, np.pi / 2, 15), +) + +MESHES = [cylinder_mesh, regular_mesh, rectilinear_mesh, spherical_mesh] + +x_plane = openmc.XPlane(x0=-0.001, boundary_type='vacuum') +y_plane = openmc.YPlane(y0=-0.001, boundary_type='vacuum') +z_plane = openmc.ZPlane(z0=-0.001, boundary_type='vacuum') + +SURFS = [x_plane, y_plane, z_plane] + + +def ids(mesh): + if isinstance(mesh, openmc.CylindricalMesh): + return 'cylindrical_mesh' + elif isinstance(mesh, openmc.RegularMesh): + return 'regular_mesh' + elif isinstance(mesh, openmc.RectilinearMesh): + return 'rectilinear_mesh' + elif isinstance(mesh, openmc.SphericalMesh): + return 'spherical_mesh' + + +@pytest.mark.parametrize("mesh", MESHES, ids=ids) +def test_write_data_to_vtk(mesh, tmpdir): + # BUILD + filename = Path(tmpdir) / "out.vtk" + + # use mesh element volumes as data to check volume-normalization ordering + # kji (i changing fastest) orering is expected for input data + # by using the volumes transposed as the data here, we can ensure the + # normalization is happening correctly + data = mesh.volumes.T + + # RUN + mesh.write_data_to_vtk(filename=filename, datasets={"label1": data, "label2": data}) + + # TEST + assert filename.is_file() + + # read file + reader = vtk.vtkStructuredGridReader() + reader.SetFileName(str(filename)) + reader.Update() + + # check name of datasets + vtk_grid = reader.GetOutput() + array1 = vtk_grid.GetCellData().GetArray(0) + array2 = vtk_grid.GetCellData().GetArray(1) + + assert array1.GetName() == "label1" + assert array2.GetName() == "label2" + + # check size of datasets + data1 = nps.vtk_to_numpy(array1) + data2 = nps.vtk_to_numpy(array2) + assert data1.size == data.size + assert data2.size == data.size + + assert all(data1 == data2) + assert all(data1 == 1.0) + + +@pytest.mark.parametrize("mesh", MESHES, ids=ids) +def test_write_data_to_vtk_size_mismatch(mesh): + """Checks that an error is raised when the size of the dataset + doesn't match the mesh number of cells + + Parameters + ---------- + mesh : openmc.StructuredMesh + The mesh to test + """ + right_size = mesh.num_mesh_cells + data = np.random.random(right_size + 1) + + # Error message has \ in to escape characters that are otherwise recognized + # by regex. These are needed to make the test string match the error message + # string when using the match argument as that uses regular expression + expected_error_msg = ( + fr"The size of the dataset 'label' \({len(data)}\) should be equal to " + fr"the number of mesh cells \({mesh.num_mesh_cells}\)" + ) + with pytest.raises(ValueError, match=expected_error_msg): + mesh.write_data_to_vtk(filename="out.vtk", datasets={"label": data}) + +def test_write_data_to_vtk_round_trip(run_in_tmpdir): + cmesh = openmc.CylindricalMesh( + r_grid=(0.0, 1.0, 2.0), + z_grid=(0.0, 2.0, 4.0, 5.0), + phi_grid=(0.0, 3.0, 6.0), + ) + + smesh = openmc.SphericalMesh( + r_grid=(0.0, 1.0, 2.0), + theta_grid=(0.0, 2.0, 4.0, 5.0), + phi_grid=(0.0, 3.0, 6.0), + ) + rmesh = openmc.RegularMesh() + rmesh.lower_left = (0.0, 0.0, 0.0) + rmesh.upper_right = (1.0, 3.0, 5.0) + rmesh.dimension = (2, 1, 6) + + for mesh in [smesh, cmesh, rmesh]: + + filename = "mesh.vtk" + data = np.array([1.0] * 12) # there are 12 voxels in each mesh + mesh.write_data_to_vtk( + filename=filename, + datasets={"normalized": data}, + volume_normalization=True + ) + + reader = vtk.vtkStructuredGridReader() + reader.SetFileName(filename) + reader.ReadAllFieldsOn() + reader.Update() + + cell_data = reader.GetOutput().GetCellData() + uniform_array = cell_data.GetArray("normalized") + num_tuples = uniform_array.GetNumberOfTuples() + vtk_values = [uniform_array.GetValue(i) for i in range(num_tuples)] + + # checks that the vtk cell values are equal to the data / mesh volumes + assert np.allclose(vtk_values, data / mesh.volumes.T.flatten()) + + mesh.write_data_to_vtk( + filename=filename, + datasets={"not_normalized": data}, + volume_normalization=False, + ) + + reader = vtk.vtkStructuredGridReader() + reader.SetFileName(filename) + reader.ReadAllFieldsOn() + reader.Update() + + cell_data = reader.GetOutput().GetCellData() + uniform_array = cell_data.GetArray("not_normalized") + num_tuples = uniform_array.GetNumberOfTuples() + vtk_values = [uniform_array.GetValue(i) for i in range(num_tuples)] + + # checks that the vtk cell values are equal to the data + assert np.array_equal(vtk_values, data) + +def mesh_surf_id(param): + if isinstance(param, openmc.MeshBase): + return ids(param) + elif isinstance(param, openmc.XPlane): + return 'XPlane' + elif isinstance(param, openmc.YPlane): + return 'YPlane' + elif isinstance(param, openmc.ZPlane): + return 'ZPlane' + + +@pytest.mark.parametrize("mesh,surface", product(MESHES, SURFS), ids=mesh_surf_id) +def test_vtk_write_ordering(run_in_tmpdir, model, mesh, surface): + + tally = openmc.Tally() + tally.scores = ['flux'] + # use the mesh on the specified tally + mesh_filter = openmc.MeshFilter(mesh) + tally.filters = [mesh_filter] + + model.tallies = openmc.Tallies([tally]) + + # run the problem + sp_filename = model.run() + + with openmc.StatePoint(sp_filename) as sp: + mean = sp.tallies[tally.id].mean + + # write the data to a VTK file + vtk_filename = 'test.vtk' + mesh.write_data_to_vtk(vtk_filename, datasets={'mean': mean}) + + # read file + reader = vtk.vtkStructuredGridReader() + reader.SetFileName(str(vtk_filename)) + reader.Update() + + # check name of datasets + vtk_grid = reader.GetOutput() + array = vtk_grid.GetCellData().GetArray(0) + vtk_data = nps.vtk_to_numpy(array) + + # convenience function for determining if a mesh + # element has vertices in the geometry. This + # particular geometry allows us to assume that tally results + # in the element should be zero if none of its vertices lie in the geometry + def in_geom(cell): + point_ids = cell.GetPointIds() + + for i in range(point_ids.GetNumberOfIds()): + p = vtk_grid.GetPoint(point_ids.GetId(i)) + if model.geometry.find(p): + return True + + return False + + # reshape mean according to mesh dimensions + mean = mean.reshape(mesh.dimension[::-1]).T + centroid = [0.0, 0.0, 0.0] + + # check that tally and vtk array results are zero where expected + for ijk in mesh.indices: + ijk = tuple(n - 1 for n in ijk) + # get the cell from the stuctured mesh object + cell = vtk_grid.GetCell(*ijk) + if not in_geom(cell): + cell.GetCentroid(centroid) + err_msg = f'IJK: {ijk} should be zero but is not. Centroid: {centroid}' + assert mean[ijk] == 0.0, err_msg + + # need to get flat index with axes reversed due to ordering passed into the VTK file + flat_idx = np.ravel_multi_index(tuple(ijk[::-1]), mesh.dimension[::-1]) + assert vtk_data[flat_idx] == 0.0, err_msg + + +def test_sphere_mesh_coordinates(run_in_tmpdir): + mesh = openmc.SphericalMesh( + r_grid=np.linspace(0.1, 10, 30), + phi_grid=np.linspace(0, 1.5*np.pi, 25), + theta_grid=np.linspace(0, np.pi / 2, 15), + ) + # write the data to a VTK file (no data) + vtk_filename = 'test.vtk' + mesh.write_data_to_vtk(vtk_filename, {}) + + # read file + reader = vtk.vtkStructuredGridReader() + reader.SetFileName(str(vtk_filename)) + reader.Update() + + vtk_grid = reader.GetOutput() + + # create a region that matches the spherical mesh description + x = openmc.XPlane() + z = openmc.ZPlane() + y = openmc.YPlane() + s = openmc.Sphere(r=10.0) + + region = +z & +y & -s | -x & -y & +z & -s + + # the VTK interface will update this list when GetCentroid is called + centroid = np.zeros(3) + + # ensure all centroids of the sphere mesh are inside the cell region + for i in range(vtk_grid.GetNumberOfCells()): + # get the cell from the stuctured mesh object + cell = vtk_grid.GetCell(i) + cell.GetCentroid(centroid) + + # if the coordinate conversion is happening correctly, + # every one of the cell centroids should be in the CSG region + assert centroid in region, \ + f'Cell centroid {centroid} not in equivalent ' \ + f'CSG region for spherical mesh {mesh}' + diff --git a/tests/unit_tests/mesh_to_vtk/tets.exo b/tests/unit_tests/mesh_to_vtk/tets.exo new file mode 100644 index 00000000000..add4f7cfacd Binary files /dev/null and b/tests/unit_tests/mesh_to_vtk/tets.exo differ diff --git a/tests/unit_tests/mesh_to_vtk/umesh.vtk b/tests/unit_tests/mesh_to_vtk/umesh.vtk new file mode 100644 index 00000000000..90f2261212c --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/umesh.vtk @@ -0,0 +1,292 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 58 double +-0.02593964576 -1 -1.1195739536 -0.40239958217 -0.40962166746 -1.9256035383 -1 0.02593964576 -1.1195739536 +-0.2248833639 0.23189144433 -1.2841109811 0.02593964576 1 -1.1195739536 1 -0.02593964576 -1.1195739536 +-0.042928712675 0.066425810853 -0.54270728017 -1 1 -1.5 -1 1 -0.5 +-0.49265312381 0.49332495053 -1.9656359509 -0.02608137991 -1 1.121521147 0.30281888252 -0.30293622513 1.8067963894 +1 -0.02608137991 1.121521147 -0.23236342389 0.26314805583 1.2867556783 0.074337770194 0.074337770194 2.5 +-0.40005770996 -0.36909660956 1.8768871762 -0.4896743493 0.49451064621 1.952829049 -1 1 1.5 +0.02608137991 1 1.121521147 -1 1 0.5 -0.038567136385 0.14628887118 0.55111724874 +-1 0.02608137991 1.121521147 0 -1 -2.5 0.37543954218 -0.36967061971 -1.8691105401 +1 -1 -2.5 0.074337770194 -0.074337770194 -2.5 1 0 -2.5 +0.4135797166 0.38351746262 -1.9274856063 1 -1 -1.5 -1 0 -2.5 +-1 -1 -1.5 -1 -1 -2.5 -1 0 2.5 +-1 1 2.5 0 1 2.5 0.46519182209 0.49356920409 1.95286052 +0 -1 2.5 -1 -1 1.5 -1 -1 2.5 +1 -1 2.5 1 -1 1.5 1 0 2.5 +1 1 2.5 1 1 1.5 0 1 -2.5 +-1 1 -2.5 1 -1 -0.5 1 1 -0.5 +0.038669824604 1 0.0046021677516 -1 -1 0.5 -0.038669824604 -1 0.0046021677516 +1 1 0.5 -1 0.038669824604 0.0046021677516 1 -0.038669824604 0.0046021677516 +1 1 -2.5 1 1 -1.5 1 -1 0.5 +-1 -1 -0.5 +CELLS 155 616 +OFFSETS vtktypeint64 +0 4 8 12 16 20 24 28 32 +36 40 44 48 52 56 60 64 68 +72 76 80 84 88 92 96 100 104 +108 112 116 120 124 128 132 136 140 +144 148 152 156 160 164 168 172 176 +180 184 188 192 196 200 204 208 212 +216 220 224 228 232 236 240 244 248 +252 256 260 264 268 272 276 280 284 +288 292 296 300 304 308 312 316 320 +324 328 332 336 340 344 348 352 356 +360 364 368 372 376 380 384 388 392 +396 400 404 408 412 416 420 424 428 +432 436 440 444 448 452 456 460 464 +468 472 476 480 484 488 492 496 500 +504 508 512 516 520 524 528 532 536 +540 544 548 552 556 560 564 568 572 +576 580 584 588 592 596 600 604 608 +612 616 +CONNECTIVITY vtktypeint64 +0 1 2 3 4 3 5 6 7 +4 8 3 7 3 2 9 8 3 +4 6 10 11 12 13 14 13 15 +16 17 13 18 16 19 18 13 20 +10 13 21 15 22 1 0 23 22 +24 25 23 25 1 3 9 26 23 +5 27 24 28 26 23 0 1 3 +23 29 30 31 1 22 31 30 1 +2 3 1 9 29 2 1 9 22 +0 28 23 32 15 21 16 14 13 +11 15 33 17 34 16 33 34 32 +16 34 16 18 35 10 11 13 15 +18 13 12 35 36 11 10 15 36 +37 38 15 32 38 37 15 32 21 +17 16 36 10 37 15 36 39 40 +11 41 40 39 11 41 12 11 35 +17 21 13 16 10 13 12 20 12 +13 11 35 14 13 16 35 34 17 +18 16 42 34 43 35 41 12 40 +11 14 41 11 35 42 41 14 35 +0 3 5 23 0 5 3 6 44 +4 9 27 29 2 30 1 44 45 +29 9 29 45 7 9 0 46 5 +6 47 48 4 6 0 3 2 6 +4 5 3 27 49 10 50 20 8 +2 3 6 51 18 48 20 49 50 +52 20 19 13 21 20 51 53 12 +20 19 48 18 20 25 3 1 23 +7 4 3 9 25 3 23 27 44 +4 7 9 25 23 26 27 54 55 +44 27 54 26 55 27 18 12 13 +20 14 16 34 35 19 21 52 20 +30 2 0 1 22 25 29 1 5 +23 3 27 25 26 44 27 22 29 +31 1 54 44 26 27 25 44 9 +27 22 28 24 23 26 5 55 27 +25 24 26 23 22 25 1 23 25 +44 29 9 25 29 1 9 48 6 +53 20 8 4 48 6 10 40 56 +12 10 40 12 11 17 19 18 13 +30 57 0 2 25 9 3 27 7 +8 2 3 26 28 5 23 29 7 +2 9 28 0 5 23 37 10 49 +21 49 50 57 52 56 12 53 20 +10 12 56 20 43 18 12 35 32 +37 21 15 14 11 13 35 19 52 +8 48 19 52 48 20 41 39 36 +11 50 6 52 20 46 53 5 6 +4 3 9 27 44 7 45 9 55 +47 4 5 28 0 46 5 8 52 +2 6 57 2 52 6 50 56 53 +20 10 56 50 20 57 50 0 6 +37 10 21 15 33 32 17 16 34 +18 43 35 57 52 50 6 51 48 +47 53 18 16 13 35 50 56 46 +53 14 36 32 15 14 11 36 15 +17 21 19 13 10 21 13 20 51 +12 18 20 50 53 46 6 14 15 +32 16 42 43 41 35 14 41 36 +11 49 52 21 20 36 40 10 11 +47 53 48 6 49 21 10 20 21 +15 13 16 51 48 53 20 55 5 +4 27 44 55 4 27 47 4 5 +6 8 48 52 6 47 5 53 6 +50 53 6 20 57 0 2 6 50 +46 0 6 52 6 48 20 42 14 +34 35 43 18 51 12 41 43 12 +35 22 30 0 1 14 32 34 16 +36 38 32 15 +CELL_TYPES 154 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 +10 + +CELL_DATA 154 +FIELD FieldData 1 +ids 1 154 double +0 1 2 3 4 5 6 7 8 +9 10 11 12 13 14 15 16 17 +18 19 20 21 22 23 24 25 26 +27 28 29 30 31 32 33 34 35 +36 37 38 39 40 41 42 43 44 +45 46 47 48 49 50 51 52 53 +54 55 56 57 58 59 60 61 62 +63 64 65 66 67 68 69 70 71 +72 73 74 75 76 77 78 79 80 +81 82 83 84 85 86 87 88 89 +90 91 92 93 94 95 96 97 98 +99 100 101 102 103 104 105 106 107 +108 109 110 111 112 113 114 115 116 +117 118 119 120 121 122 123 124 125 +126 127 128 129 130 131 132 133 134 +135 136 137 138 139 140 141 142 143 +144 145 146 147 148 149 150 151 152 +153 diff --git a/tests/unit_tests/test_bounding_box.py b/tests/unit_tests/test_bounding_box.py new file mode 100644 index 00000000000..57c880092e3 --- /dev/null +++ b/tests/unit_tests/test_bounding_box.py @@ -0,0 +1,190 @@ +import numpy as np +import openmc +import pytest + + +test_bb_1 = openmc.BoundingBox((-10.0, -20.0, -30.0), (1.0, 2.0, 3.0)) +test_bb_2 = openmc.BoundingBox((1.0, 2.0, 3.0), (11.0, 22.0, 33.0)) +test_bb_3 = openmc.BoundingBox((-10.0, -20.0, -30.0), (-1.0, -2.0, -3.0)) + + +@pytest.mark.parametrize( + "bb, expected", + [ + (test_bb_1, 7986), # 11 * 22 * 33 + (test_bb_2, 6000), # 10 * 20 * 30 + (test_bb_3, 4374), # 9 * 18 * 27 + ], +) +def test_bounding_box_volume(bb, expected): + assert bb.volume == expected + + +@pytest.mark.parametrize( + "bb, expected", + [ + (test_bb_1, np.array([-10.0, -20.0, -30.0])), + (test_bb_2, np.array([1.0, 2.0, 3.0])), + (test_bb_3, np.array([-10.0, -20.0, -30.0])), + ], +) +def test_bounding_lower_left(bb, expected): + assert np.array_equiv(expected, bb.lower_left) + + +@pytest.mark.parametrize( + "bb, expected", + [ + (test_bb_1, np.array([1.0, 2.0, 3.0])), + (test_bb_2, np.array([11.0, 22.0, 33.0])), + (test_bb_3, np.array([-1.0, -2.0, -3.0])), + ], +) +def test_bounding_upper_right(bb, expected): + assert np.array_equiv(expected, bb.upper_right) + + +@pytest.mark.parametrize( + "bb, expected", + [ + (test_bb_1, np.array([-4.5, -9.0, -13.5])), + (test_bb_2, np.array([6.0, 12.0, 18.0])), + (test_bb_3, np.array([-5.5, -11.0, -16.5])), + ], +) +def test_bounding_box_center(bb, expected): + assert np.array_equiv(expected, bb.center) + + +def test_bounding_box_input_checking(): + # checks that only passing lower_left is not accepted + with pytest.raises(TypeError): + openmc.BoundingBox((-10, -20, -3)) + # checks that a tuple with three entry is not accepted + with pytest.raises(TypeError): + openmc.BoundingBox((-1, -2, -3), (-1, -2, -3), (-1, -2, -3)) + # checks that a numpy array with two entries is not accepted + with pytest.raises(ValueError): + openmc.BoundingBox(np.array([-10, -30]), np.array([1, 2, 3])) + # checks that a numpy array with two entries is not accepted + with pytest.raises(ValueError): + openmc.BoundingBox(np.array([-10, -20, -30]), np.array([1, 3])) + # checks that a numpy array with four entries is not accepted + with pytest.raises(ValueError): + openmc.BoundingBox(np.array([-10, -20, -3, -4]), np.array([1, 2, 3])) + # checks that a numpy array with four entries is not accepted + with pytest.raises(ValueError): + openmc.BoundingBox(np.array([-10, -20, -4]), np.array([1, 2, 3, 4])) + + +def test_bounding_box_extents(): + assert test_bb_1.extent["xy"] == (-10.0, 1.0, -20.0, 2.0) + assert test_bb_1.extent["xz"] == (-10.0, 1.0, -30.0, 3.0) + assert test_bb_1.extent["yz"] == (-20.0, 2.0, -30.0, 3.0) + + +def test_bounding_box_methods(): + test_bb = openmc.BoundingBox.infinite() + + # check assignment operator + test_bb[0] = [-10, -11, -12] + test_bb[1] = [13, 14, 15] + + assert all(test_bb[0] == [-10, -11, -12]) + assert all(test_bb[1] == [13, 14, 15]) + + # check length and iteration + assert len(test_bb) == 2 + ll, ur = test_bb + assert all(ll == [-10, -11, -12]) + assert all(ur == [13, 14, 15]) + + # test expand/reduce methods + other_bb = openmc.BoundingBox([-5, -5, -50], [5, 50, 5]) + + reduced_bb = test_bb & other_bb + + # inplace was False by default. BoundingBox.reduce should return a new object + assert test_bb is not reduced_bb + + # the original bounding box should be unchanged + assert all(test_bb[0] == [-10, -11, -12]) + assert all(test_bb[1] == [13, 14, 15]) + + assert all(reduced_bb[0] == [-5, -5, -12]) + assert all(reduced_bb[1] == [5, 14, 5]) + + test_bb &= other_bb + + assert all(test_bb[0] == [-5, -5, -12]) + assert all(test_bb[1] == [5, 14, 5]) + + other_bb = openmc.BoundingBox([-50, -50, -1], [50, 1, 50]) + + expanded_bb = test_bb | other_bb + + # inplace was False by default. BoundingBox.expand should return a new object + assert test_bb is not expanded_bb + + # the original bounding box should be unchanged + assert all(test_bb[0] == [-5, -5, -12]) + assert all(test_bb[1] == [5, 14, 5]) + + assert all(expanded_bb[0] == [-50, -50, -12]) + assert all(expanded_bb[1] == [50, 14, 50]) + + test_bb |= other_bb + + assert all(test_bb[0] == [-50, -50, -12]) + assert all(test_bb[1] == [50, 14, 50]) + + extended_bbox = test_bb.expand(0.1) + + assert extended_bbox is not test_bb + + # the original bounding box should not be changed with inplace as False + assert all(test_bb[0] == [-50, -50, -12]) + assert all(test_bb[1] == [50, 14, 50]) + + assert all(extended_bbox[0] == [-50.1, -50.1, -12.1]) + assert all(extended_bbox[1] == [50.1, 14.1, 50.1]) + + extended_bbox = test_bb.expand(0.1, True) + + # inplace was set to True. BoundingBox.reduce should return the same object + assert extended_bbox is test_bb + + assert all(test_bb[0] == [-50.1, -50.1, -12.1]) + assert all(test_bb[1] == [50.1, 14.1, 50.1]) + + +@pytest.mark.parametrize( + "bb, other, expected", + [ + (test_bb_1, (0, 0, 0), True), + (test_bb_2, (3, 3, 3), False), + # completely disjoint + (test_bb_1, test_bb_2, False), + # contained but touching border + (test_bb_1, test_bb_3, False), + # Fully contained + (test_bb_1, openmc.BoundingBox((-9, -19, -29), (0, 0, 0)), True), + # intersecting boxes + (test_bb_1, openmc.BoundingBox((-9, -19, -29), (1, 2, 5)), False), + ], +) +def test_bounding_box_contains(bb, other, expected): + assert (other in bb) == expected + + +@pytest.mark.parametrize( + "invalid, ex", + [ + ((1, 0), ValueError), + ((1, 2, 3, 4), ValueError), + ("foo", TypeError), + ], +) +def test_bounding_box_contains_checking(invalid, ex): + with pytest.raises(ex): + invalid in test_bb_1 diff --git a/tests/unit_tests/test_cell.py b/tests/unit_tests/test_cell.py index 9234e7e4b53..95c8249bb33 100644 --- a/tests/unit_tests/test_cell.py +++ b/tests/unit_tests/test_cell.py @@ -1,11 +1,9 @@ -import xml.etree. ElementTree as ET - +import lxml.etree as ET import numpy as np from uncertainties import ufloat import openmc import pytest - from tests.unit_tests import assert_unbounded from openmc.data import atomic_mass, AVOGADRO @@ -57,25 +55,51 @@ def test_clone(): m = openmc.Material() cyl = openmc.ZCylinder() c = openmc.Cell(fill=m, region=-cyl) - c.temperature = 650. + # Check cloning with all optional params as the defaults c2 = c.clone() assert c2.id != c.id assert c2.fill != c.fill assert c2.region != c.region - assert c2.temperature == c.temperature c3 = c.clone(clone_materials=False) assert c3.id != c.id assert c3.fill == c.fill assert c3.region != c.region - assert c3.temperature == c.temperature c4 = c.clone(clone_regions=False) assert c4.id != c.id assert c4.fill != c.fill assert c4.region == c.region - assert c4.temperature == c.temperature + + # Add optional properties to the original cell to ensure they're cloned successfully + c.temperature = 650. + c.translation = (1., 2., 3.) + c.rotation = (4., 5., 6.) + c.volume = 100 + + c5 = c.clone(clone_materials=False, clone_regions=False) + assert c5.id != c.id + assert c5.fill == c.fill + assert c5.region == c.region + assert c5.temperature == c.temperature + assert c5.volume == c.volume + assert all(c5.translation == c.translation) + assert all(c5.rotation == c.rotation) + + # Mutate the original to ensure the changes are not seen in the clones + c.fill = openmc.Material() + c.region = +openmc.ZCylinder() + c.translation = (-1., -2., -3.) + c.rotation = (-4., -5., -6.) + c.temperature = 1 + c.volume = 1 + assert c5.fill != c.fill + assert c5.region != c.region + assert c5.temperature != c.temperature + assert c5.volume != c.volume + assert all(c5.translation != c.translation) + assert all(c5.rotation != c.rotation) def test_temperature(cell_with_lattice): @@ -92,6 +116,9 @@ def test_temperature(cell_with_lattice): assert c2.temperature == 400.0 with pytest.raises(ValueError): c.temperature = -100. + c.temperature = None + assert c1.temperature == None + assert c2.temperature == None # distributed temperature cells, _, _, _ = cell_with_lattice @@ -294,6 +321,43 @@ def test_to_xml_element(cell_with_lattice): c = cells[0] c.temperature = 900.0 + c.volume = 1.0 elem = c.create_xml_subelement(root) assert elem.get('region') == str(c.region) assert elem.get('temperature') == str(c.temperature) + assert elem.get('volume') == str(c.volume) + + +@pytest.mark.parametrize("rotation", [ + (90, 45, 0), + [[1.0, 0.0, 0.0], [0.0, 0.0, 1.0], [0.0, -1.0, 0.0]] +]) +def test_rotation_from_xml(rotation): + # Make sure rotation attribute (matrix) round trips through XML correctly + s = openmc.ZCylinder(r=10.0) + cell = openmc.Cell(region=-s) + cell.rotation = rotation + root = ET.Element('geometry') + elem = cell.create_xml_subelement(root) + new_cell = openmc.Cell.from_xml_element( + elem, {s.id: s}, {'void': None}, openmc.Universe + ) + np.testing.assert_allclose(new_cell.rotation, cell.rotation) + + +def test_plot(run_in_tmpdir): + zcyl = openmc.ZCylinder() + c = openmc.Cell(region=-zcyl) + + # create a universe before the plot + u_before = openmc.Universe() + + # create a plot of the cell + c.plot() + + # create a universe after the plot + u_after = openmc.Universe() + + # ensure that calling the plot method doesn't + # affect the universe ID space + assert u_before.id + 1 == u_after.id diff --git a/tests/unit_tests/test_cell_instance.py b/tests/unit_tests/test_cell_instance.py new file mode 100644 index 00000000000..25c20cfef22 --- /dev/null +++ b/tests/unit_tests/test_cell_instance.py @@ -0,0 +1,92 @@ +import numpy as np +import pytest + +import openmc +import openmc.lib + +from tests import cdtemp + + +@pytest.fixture(scope='module', autouse=True) +def double_lattice_model(): + openmc.reset_auto_ids() + model = openmc.Model() + + # Create a single material + m = openmc.Material() + m.add_nuclide('U235', 1.0) + m.set_density('g/cm3', 10.0) + model.materials.append(m) + + # Create a universe with a single infinite cell + c = openmc.Cell(fill=m) + u = openmc.Universe(cells=[c]) + + # Create a 2x2 lattice filled with above universe + lattice = openmc.RectLattice() + lattice.lower_left = (0.0, 0.0) + lattice.pitch = (1.0, 1.0) + lattice.universes = np.full((2, 2), u) + + # Create two cells each filled with the same lattice, one from x=0..2 and + # y=0..2 and the other from x=2..4 and y=0..2 + x0 = openmc.XPlane(0.0, boundary_type='vacuum') + x2 = openmc.XPlane(2.0) + x4 = openmc.XPlane(4.0, boundary_type='vacuum') + y0 = openmc.YPlane(0.0, boundary_type='vacuum') + y2 = openmc.YPlane(2.0, boundary_type='vacuum') + cell_with_lattice1 = openmc.Cell(fill=lattice, region=+x0 & -x2 & +y0 & -y2) + cell_with_lattice2 = openmc.Cell(fill=lattice, region=+x2 & -x4 & +y0 & -y2) + cell_with_lattice2.translation = (2., 0., 0.) + model.geometry = openmc.Geometry([cell_with_lattice1, cell_with_lattice2]) + + tally = openmc.Tally() + tally.filters = [openmc.DistribcellFilter(c)] + tally.scores = ['flux'] + model.tallies = [tally] + + # Add box source that covers the model space well + bbox = model.geometry.bounding_box + bbox[0][2] = -0.5 + bbox[1][2] = 0.5 + space = openmc.stats.Box(*bbox) + model.settings.source = openmc.IndependentSource(space=space) + + # Add necessary settings and export + model.settings.batches = 10 + model.settings.inactive = 0 + model.settings.particles = 100 + + with cdtemp(): + model.export_to_xml() + openmc.lib.init() + yield + openmc.lib.finalize() + + +# This shows the expected cell instance numbers for each lattice position: +# ┌─┬─┬─┬─┐ +# │2│3│6│7│ +# ├─┼─┼─┼─┤ +# │0│1│4│5│ +# └─┴─┴─┴─┘ +expected_results = [ + ((0.5, 0.5, 0.0), 0), + ((1.5, 0.5, 0.0), 1), + ((0.5, 1.5, 0.0), 2), + ((1.5, 1.5, 0.0), 3), + ((2.5, 0.5, 0.0), 4), + ((3.5, 0.5, 0.0), 5), + ((2.5, 1.5, 0.0), 6), + ((3.5, 1.5, 0.0), 7), +] +@pytest.mark.parametrize("r,expected_cell_instance", expected_results) +def test_cell_instance_multilattice(r, expected_cell_instance): + _, cell_instance = openmc.lib.find_cell(r) + assert cell_instance == expected_cell_instance + + +def test_cell_instance_multilattice_results(): + openmc.lib.run() + tally_results = openmc.lib.tallies[1].mean + assert (tally_results != 0.0).all() diff --git a/tests/unit_tests/test_complex_cell_bb.py b/tests/unit_tests/test_complex_cell_bb.py index ad6491cca92..8a94d9ddcfd 100644 --- a/tests/unit_tests/test_complex_cell_bb.py +++ b/tests/unit_tests/test_complex_cell_bb.py @@ -66,7 +66,7 @@ def complex_cell(run_in_tmpdir, mpi_intracomm): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-10., -10., -1.], [10., 10., 1.])) model.settings.verbosity = 1 diff --git a/tests/unit_tests/test_config.py b/tests/unit_tests/test_config.py new file mode 100644 index 00000000000..1d3c0f173b0 --- /dev/null +++ b/tests/unit_tests/test_config.py @@ -0,0 +1,43 @@ +from collections.abc import Mapping +import os + +import openmc +import pytest + + +@pytest.fixture(autouse=True, scope='module') +def reset_config(): + config = dict(openmc.config) + try: + yield + finally: + openmc.config.clear() + openmc.config.update(config) + + +def test_config_basics(): + assert isinstance(openmc.config, Mapping) + for key, value in openmc.config.items(): + assert isinstance(key, str) + assert isinstance(value, os.PathLike) + + # Set and delete + openmc.config['cross_sections'] = '/path/to/cross_sections.xml' + del openmc.config['cross_sections'] + assert 'cross_sections' not in openmc.config + assert 'OPENMC_CROSS_SECTIONS' not in os.environ + + # Can't use any key + with pytest.raises(KeyError): + openmc.config['🐖'] = '/like/to/eat/bacon' + + +def test_config_set_envvar(): + openmc.config['cross_sections'] = '/path/to/cross_sections.xml' + assert os.environ['OPENMC_CROSS_SECTIONS'] == '/path/to/cross_sections.xml' + + openmc.config['mg_cross_sections'] = '/path/to/mg_cross_sections.h5' + assert os.environ['OPENMC_MG_CROSS_SECTIONS'] == '/path/to/mg_cross_sections.h5' + + openmc.config['chain_file'] = '/path/to/chain_file.xml' + assert os.environ['OPENMC_CHAIN_FILE'] == '/path/to/chain_file.xml' diff --git a/tests/unit_tests/test_cylindrical_mesh.py b/tests/unit_tests/test_cylindrical_mesh.py new file mode 100644 index 00000000000..b408bc0e917 --- /dev/null +++ b/tests/unit_tests/test_cylindrical_mesh.py @@ -0,0 +1,197 @@ +from itertools import product, permutations + +import openmc +import numpy as np + +import pytest + +geom_size = 5 + +@pytest.fixture() +def model(): + openmc.reset_auto_ids() + + water = openmc.Material(name='water') + water.add_element('H', 2.0) + water.add_element('O', 1.0) + water.set_density('g/cc', 1.0) + + rpp = openmc.model.RectangularParallelepiped(*([-geom_size, geom_size] * 3), + boundary_type='vacuum') + + cell = openmc.Cell(region=-rpp, fill=water) + + geom = openmc.Geometry([cell]) + + source = openmc.IndependentSource() + source.space = openmc.stats.Point() + source.energy = openmc.stats.Discrete([10000], [1.0]) + + settings = openmc.Settings() + settings.particles = 2000 + settings.batches = 10 + settings.run_mode = 'fixed source' + + # build + mesh = openmc.CylindricalMesh( + phi_grid=np.linspace(0, 2*np.pi, 21), + z_grid=np.linspace(-geom_size, geom_size, 11), + r_grid=np.linspace(0, geom_size, geom_size) + ) + tally = openmc.Tally() + + mesh_filter = openmc.MeshFilter(mesh) + tally.filters.append(mesh_filter) + + tally.scores.append("flux") + + tallies = openmc.Tallies([tally]) + + return openmc.Model(geometry=geom, settings=settings, tallies=tallies) + +def test_origin_read_write_to_xml(run_in_tmpdir, model): + """Tests that the origin attribute can be written and read back to XML + """ + mesh = model.tallies[0].filters[0].mesh + mesh.origin = [0.1, 0.2, 0.3] + model.tallies.export_to_xml() + + # read back + new_tallies = openmc.Tallies.from_xml() + new_tally = new_tallies[0] + new_mesh = new_tally.filters[0].mesh + np.testing.assert_equal(new_mesh.origin, mesh.origin) + +estimators = ('tracklength', 'collision') +origins = set(permutations((-geom_size, 0, 0))) +origins |= set(permutations((geom_size, 0, 0))) + +test_cases = product(estimators, origins) + +def label(p): + if isinstance(p, tuple): + return f'origin:{p}' + if isinstance(p, str): + return f'estimator:{p}' + +@pytest.mark.parametrize('estimator,origin', test_cases, ids=label) +def test_offset_mesh(run_in_tmpdir, model, estimator, origin): + """Tests that the mesh has been moved based on tally results + """ + mesh = model.tallies[0].filters[0].mesh + model.tallies[0].estimator = estimator + # move the center of the cylinder mesh upwards + mesh.origin = origin + + sp_filename = model.run() + + with openmc.StatePoint(sp_filename) as sp: + tally = sp.tallies[1] + + # we've translated half of the cylinder mesh above the model, + # so ensure that half of the bins are populated + assert np.count_nonzero(tally.mean) == tally.mean.size / 2 + + # check that the half of the mesh that is outside of the geometry + # contains the zero values + mean = tally.get_reshaped_data('mean', expand_dims=True) + centroids = mesh.centroids + for ijk in mesh.indices: + i, j, k = np.array(ijk) - 1 + if model.geometry.find(centroids[i, j, k]): + mean[i, j, k] == 0.0 + else: + mean[i, j, k] != 0.0 + +@pytest.fixture() +def void_coincident_geom_model(): + """A model with many geometric boundaries coincident with mesh boundaries + across many scales + """ + openmc.reset_auto_ids() + model = openmc.model.Model() + + model.materials = openmc.Materials() + radii = [0.1,1, 5, 50, 100, 150, 250] + cylinders = [openmc.ZCylinder(r=ri) for ri in radii] + cylinders[-1].boundary_type = 'vacuum' + + regions = openmc.model.subdivide(cylinders)[:-1] + cells = [openmc.Cell(region=r, fill=None) for r in regions] + geom = openmc.Geometry(cells) + + model.geometry = geom + + settings = openmc.Settings(run_mode='fixed source') + settings.batches = 2 + settings.particles = 1000 + model.settings = settings + + mesh = openmc.CylindricalMesh( + r_grid=np.linspace(0, 250, 501), + z_grid=[-250, 250], + phi_grid=np.linspace(0, 2*np.pi, 2), + ) + mesh_filter = openmc.MeshFilter(mesh) + + tally = openmc.Tally() + tally.scores = ['flux'] + tally.filters = [mesh_filter] + + model.tallies = openmc.Tallies([tally]) + + return model + + +# convenience function for checking tally results +# in the following tests +def _check_void_cylindrical_tally(statepoint_filename): + with openmc.StatePoint(statepoint_filename) as sp: + flux_tally = sp.tallies[1] + mesh = flux_tally.find_filter(openmc.MeshFilter).mesh + neutron_flux = flux_tally.get_reshaped_data().squeeze() + # we expect the tally results to be the same as the mesh grid width + # for these cases + d_r = mesh.r_grid[1] - mesh.r_grid[0] + assert neutron_flux == pytest.approx(d_r) + +def test_void_geom_pnt_src(run_in_tmpdir, void_coincident_geom_model): + src = openmc.IndependentSource() + src.space = openmc.stats.Point() + src.angle = openmc.stats.PolarAzimuthal(mu=openmc.stats.Discrete([0.0], [1.0])) + src.energy = openmc.stats.Discrete([14.06e6], [1]) + void_coincident_geom_model.settings.source = src + + sp_filename = void_coincident_geom_model.run() + _check_void_cylindrical_tally(sp_filename) + + +def test_void_geom_boundary_src(run_in_tmpdir, void_coincident_geom_model): + # update source to a number of points on the outside of the cylinder + # with directions pointing toward the origin + bbox = void_coincident_geom_model.geometry.bounding_box + + # can't source particle directly on the geometry boundary + outer_r = bbox[1][0] - 1e-08 + + n_sources = 100 + radial_vals = np.linspace(0.0, 2.0*np.pi, n_sources) + + sources = [] + + energy = openmc.stats.Discrete([14.06e6], [1]) + for val in radial_vals: + src = openmc.IndependentSource() + src.energy = energy + + pnt = np.array([np.cos(val), np.sin(val), 0.0]) + u = -pnt + src.space = openmc.stats.Point(outer_r*pnt) + src.angle = openmc.stats.Monodirectional(u) + src.strength = 0.5/n_sources + sources.append(src) + + void_coincident_geom_model.settings.source = sources + sp_filename = void_coincident_geom_model.run() + + _check_void_cylindrical_tally(sp_filename) \ No newline at end of file diff --git a/tests/unit_tests/test_data_decay.py b/tests/unit_tests/test_data_decay.py index cb4560d5151..8900e7eace5 100644 --- a/tests/unit_tests/test_data_decay.py +++ b/tests/unit_tests/test_data_decay.py @@ -1,13 +1,14 @@ #!/usr/bin/env python -from collections.abc import Mapping import os from math import log +from pathlib import Path import numpy as np import pytest from uncertainties import ufloat import openmc.data +from openmc.exceptions import DataError def ufloat_close(a, b): @@ -23,6 +24,14 @@ def nb90(): return openmc.data.Decay.from_endf(filename) +@pytest.fixture(scope='module') +def ba137m(): + """Ba137_m1 decay data.""" + endf_data = os.environ['OPENMC_ENDF_DATA'] + filename = os.path.join(endf_data, 'decay', 'dec-056_Ba_137m1.endf') + return openmc.data.Decay.from_endf(filename) + + @pytest.fixture(scope='module') def u235_yields(): """U235 fission product yield data.""" @@ -31,11 +40,24 @@ def u235_yields(): return openmc.data.FissionProductYields.from_endf(filename) +def test_get_decay_modes(): + assert openmc.data.get_decay_modes(1.0) == ['beta-'] + assert openmc.data.get_decay_modes(6.0) == ['sf'] + assert openmc.data.get_decay_modes(10.0) == ['unknown'] + + assert openmc.data.get_decay_modes(1.5) == ['beta-', 'n'] + assert openmc.data.get_decay_modes(1.4) == ['beta-', 'alpha'] + assert openmc.data.get_decay_modes(1.55) == ['beta-', 'n', 'n'] + assert openmc.data.get_decay_modes(1.555) == ['beta-', 'n', 'n', 'n'] + assert openmc.data.get_decay_modes(2.4) == ['ec/beta+', 'alpha'] + + def test_nb90_halflife(nb90): ufloat_close(nb90.half_life, ufloat(52560.0, 180.0)) ufloat_close(nb90.decay_constant, log(2.)/nb90.half_life) ufloat_close(nb90.decay_energy, ufloat(2265527.5, 25159.400474401213)) + def test_nb90_nuclide(nb90): assert nb90.nuclide['atomic_number'] == 41 assert nb90.nuclide['mass_number'] == 90 @@ -79,3 +101,51 @@ def test_fpy(u235_yields): assert len(u235_yields.independent) == 3 thermal = u235_yields.independent[0] ufloat_close(thermal['I135'], ufloat(0.0292737, 0.000819663)) + + +def test_sources(ba137m, nb90): + # Running .sources twice should give same objects + sources = ba137m.sources + sources2 = ba137m.sources + for key in sources: + assert sources[key] is sources2[key] + + # Each source should be a univariate distribution + for dist in sources.values(): + assert isinstance(dist, openmc.stats.Univariate) + + # Check for presence of 662 keV gamma ray in decay of Ba137m + gamma_source = ba137m.sources['photon'] + assert isinstance(gamma_source, openmc.stats.Discrete) + b = np.isclose(gamma_source.x, 661657.) + assert np.count_nonzero(b) == 1 + + # Check value of decay/s/atom + idx = np.flatnonzero(b)[0] + assert gamma_source.p[idx] == pytest.approx(0.004069614) + + # Nb90 decays by β+ and should emit positrons, electrons, and photons + sources = nb90.sources + assert len(set(sources.keys()) ^ {'positron', 'electron', 'photon'}) == 0 + + +def test_decay_photon_energy(): + # If chain file is not set, we should get a data error + if 'chain_file' in openmc.config: + del openmc.config['chain_file'] + with pytest.raises(DataError): + openmc.data.decay_photon_energy('I135') + + # Set chain file to simple chain + openmc.config['chain_file'] = Path(__file__).parents[1] / "chain_simple.xml" + + # Check strength of I135 source and presence of specific spectral line + src = openmc.data.decay_photon_energy('I135') + assert isinstance(src, openmc.stats.Discrete) + assert src.integral() == pytest.approx(3.920996223799345e-05) + assert 1260409. in src.x + + # Check Xe135 source, which should be tabular + src = openmc.data.decay_photon_energy('Xe135') + assert isinstance(src, openmc.stats.Tabular) + assert src.integral() == pytest.approx(2.076506258964966e-05) diff --git a/tests/unit_tests/test_data_kalbach_mann.py b/tests/unit_tests/test_data_kalbach_mann.py new file mode 100644 index 00000000000..3b837af7da9 --- /dev/null +++ b/tests/unit_tests/test_data_kalbach_mann.py @@ -0,0 +1,176 @@ +"""Test of the Kalbach-Mann slope calculation when data are +retrieved from ENDF files.""" + +import os +from pathlib import Path +import pytest + +import numpy as np + +from openmc.data import IncidentNeutron +from openmc.data.kalbach_mann import _separation_energy, _AtomicRepresentation +from openmc.data import kalbach_slope +from openmc.data import KalbachMann + +from . import needs_njoy + + +@pytest.fixture(scope='module') +def neutron(): + """Neutron AtomicRepresentation.""" + return _AtomicRepresentation(z=0, a=1) + + +@pytest.fixture(scope='module') +def triton(): + """Triton AtomicRepresentation.""" + return _AtomicRepresentation(z=1, a=3) + + +@pytest.fixture(scope='module') +def b10(): + """B10 AtomicRepresentation.""" + return _AtomicRepresentation(z=5, a=10) + + +@pytest.fixture(scope='module') +def c12(): + """C12 AtomicRepresentation.""" + return _AtomicRepresentation(z=6, a=12) + + +@pytest.fixture(scope='module') +def c13(): + """C13 AtomicRepresentation.""" + return _AtomicRepresentation(z=6, a=13) + + +@pytest.fixture(scope='module') +def na23(): + """Na23 AtomicRepresentation.""" + return _AtomicRepresentation(z=11, a=23) + + +def test_atomic_representation(neutron, triton, b10, c12, c13, na23): + """Test the _AtomicRepresentation class.""" + # Test instantiation from_za + assert b10 == _AtomicRepresentation.from_za(5010) + + # Test addition + assert c13 + b10 == na23 + + # Test substraction + assert c13 - c12 == neutron + assert c13 - b10 == triton + + # Test properties when no information for Kalbach-Mann are given + assert c13.a == 13 + assert c13.z == 6 + assert c13.n == 7 + assert c13.za == 6013 + + # Test properties when information for Kalbach-Mann are given + assert triton.a == 3 + assert triton.z == 1 + assert triton.n == 2 + assert triton.za == 1003 + + # Test instantiation errors + with pytest.raises(ValueError): + _AtomicRepresentation(z=5, a=1) + with pytest.raises(ValueError): + _AtomicRepresentation(z=-1, a=1) + with pytest.raises(ValueError): + _AtomicRepresentation(z=5, a=0) + with pytest.raises(ValueError): + _AtomicRepresentation(z=5, a=-2) + with pytest.raises(ValueError): + neutron - triton + + +def test_separation_energy(triton, b10, c13): + """Comparison to hand-calculations on a simple example.""" + assert _separation_energy( + compound=c13, + nucleus=b10, + particle=triton + ) == pytest.approx(18.6880713) + + +def test_kalbach_slope(): + """Comparison to hand-calculations for n + c12 -> c13 -> triton + b10.""" + energy_projectile = 10.2 # [eV] + energy_emitted = 5.4 # [eV] + + # Check that NotImplementedError is raised if the projectile is not + # a neutron + with pytest.raises(NotImplementedError): + kalbach_slope( + energy_projectile=energy_projectile, + energy_emitted=energy_emitted, + za_projectile=1000, + za_emitted=1, + za_target=6012 + ) + + assert kalbach_slope( + energy_projectile=energy_projectile, + energy_emitted=energy_emitted, + za_projectile=1, + za_emitted=1003, + za_target=6012 + ) == pytest.approx(0.8409921475) + + +@pytest.mark.parametrize( + "hdf5_filename, endf_filename", [ + ('O16.h5', 'n-008_O_016.endf'), + ('Ca46.h5', 'n-020_Ca_046.endf'), + ('Hg204.h5', 'n-080_Hg_204.endf') + ] +) +def test_comparison_slope_hdf5(hdf5_filename, endf_filename): + """Test the calculation of the Kalbach-Mann slope done by OpenMC + by comparing it to HDF5 data. The test is based on the first product + of MT=5 (neutron). The isotopes tested have been selected because the + corresponding products in ENDF/B-VII.1 are described using MF=6, LAW=1, + LANG=2 (i.e., Kalbach-Mann systematics) and the slope is not given + explicitly. + + If an error occurs during the "validity check", this means that + the nuclear data evaluation has evolved and the distribution might + no longer be described using Kalbach-Mann systematics. Another + isotope needs to be identified and tested. + + Warning: This test is valid as long as ENDF files are not directly + used to generate the HDF5 files used in the tests. + + """ + # HDF5 data + hdf5_directory = Path(os.environ['OPENMC_CROSS_SECTIONS']).parent + hdf5_data = IncidentNeutron.from_hdf5(hdf5_directory / hdf5_filename) + hdf5_product = hdf5_data[5].products[0] + hdf5_distribution = hdf5_product.distribution[0] + + # ENDF data + endf_directory = Path(os.environ['OPENMC_ENDF_DATA']) + endf_path = endf_directory / 'neutrons' / endf_filename + endf_data = IncidentNeutron.from_endf(endf_path) + endf_product = endf_data[5].products[0] + endf_distribution = endf_product.distribution[0] + + # Validity check + assert isinstance(endf_distribution, KalbachMann) + assert isinstance(hdf5_distribution, KalbachMann) + assert endf_product.particle == hdf5_product.particle + assert len(endf_distribution.slope) == len(hdf5_distribution.slope) + + # Results check + for i, hdf5_slope in enumerate(hdf5_distribution.slope): + assert endf_distribution._calculated_slope[i] + + np.testing.assert_array_almost_equal( + endf_distribution.slope[i].y, + hdf5_slope.y, + decimal=5 + ) diff --git a/tests/unit_tests/test_data_misc.py b/tests/unit_tests/test_data_misc.py index 6a81fb1e086..226d848a502 100644 --- a/tests/unit_tests/test_data_misc.py +++ b/tests/unit_tests/test_data_misc.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -from collections.abc import Mapping +from math import log import os from pathlib import Path @@ -11,7 +11,7 @@ def test_data_library(tmpdir): lib = openmc.data.DataLibrary.from_xml() - for f in lib.libraries: + for f in lib: assert sorted(f.keys()) == ['materials', 'path', 'type'] f = lib.get_by_material('U235') @@ -22,6 +22,9 @@ def test_data_library(tmpdir): assert f['type'] == 'thermal' assert 'c_H_in_H2O' in f['materials'] + lib.remove_by_material('Pu239') + assert lib.get_by_material('Pu239') is None + filename = str(tmpdir.join('test.xml')) lib.export_to_xml(filename) assert os.path.exists(filename) @@ -29,9 +32,9 @@ def test_data_library(tmpdir): new_lib = openmc.data.DataLibrary() directory = os.path.dirname(os.environ['OPENMC_CROSS_SECTIONS']) new_lib.register_file(os.path.join(directory, 'H1.h5')) - assert new_lib.libraries[-1]['type'] == 'neutron' + assert new_lib[-1]['type'] == 'neutron' new_lib.register_file(os.path.join(directory, 'c_Zr_in_ZrH.h5')) - assert new_lib.libraries[-1]['type'] == 'thermal' + assert new_lib[-1]['type'] == 'thermal' def test_depletion_chain_data_library(run_in_tmpdir): @@ -76,15 +79,17 @@ def test_thin(): def test_atomic_mass(): - assert openmc.data.atomic_mass('H1') == 1.00782503224 - assert openmc.data.atomic_mass('U235') == 235.04392819 + assert openmc.data.atomic_mass('H1') == 1.007825031898 + assert openmc.data.atomic_mass('U235') == 235.043928117 + assert openmc.data.atomic_mass('Li6') == 6.01512288742 + assert openmc.data.atomic_mass('Pb220') == 220.025905 with pytest.raises(KeyError): openmc.data.atomic_mass('U100') def test_atomic_weight(): - assert openmc.data.atomic_weight('C') == 12.011115164864455 - assert openmc.data.atomic_weight('carbon') == 12.011115164864455 + assert openmc.data.atomic_weight('C') == 12.011115164865895 + assert openmc.data.atomic_weight('carbon') == 12.011115164865895 with pytest.raises(ValueError): openmc.data.atomic_weight('Qt') @@ -99,12 +104,12 @@ def test_water_density(): assert dens(500.0, 3.0) == pytest.approx(1e-3/0.120241800e-2, 1e-6) -def test_gnd_name(): - assert openmc.data.gnd_name(1, 1) == 'H1' - assert openmc.data.gnd_name(40, 90) == ('Zr90') - assert openmc.data.gnd_name(95, 242, 0) == ('Am242') - assert openmc.data.gnd_name(95, 242, 1) == ('Am242_m1') - assert openmc.data.gnd_name(95, 242, 10) == ('Am242_m10') +def test_gnds_name(): + assert openmc.data.gnds_name(1, 1) == 'H1' + assert openmc.data.gnds_name(40, 90) == ('Zr90') + assert openmc.data.gnds_name(95, 242, 0) == ('Am242') + assert openmc.data.gnds_name(95, 242, 1) == ('Am242_m1') + assert openmc.data.gnds_name(95, 242, 10) == ('Am242_m10') def test_isotopes(): @@ -126,3 +131,14 @@ def test_zam(): assert openmc.data.zam('Am242_m10') == (95, 242, 10) with pytest.raises(ValueError): openmc.data.zam('garbage') + + +def test_half_life(): + assert openmc.data.half_life('H2') is None + assert openmc.data.half_life('U235') == pytest.approx(2.22102e16) + assert openmc.data.half_life('Am242') == pytest.approx(57672.0) + assert openmc.data.half_life('Am242_m1') == pytest.approx(4449622000.0) + assert openmc.data.decay_constant('H2') == 0.0 + assert openmc.data.decay_constant('U235') == pytest.approx(log(2.0)/2.22102e16) + assert openmc.data.decay_constant('Am242') == pytest.approx(log(2.0)/57672.0) + assert openmc.data.decay_constant('Am242_m1') == pytest.approx(log(2.0)/4449622000.0) diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 0b33f05fc96..c0d6a1f1547 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -531,3 +531,12 @@ def test_ace_table_types(): assert TT.from_suffix('20t') == TT.THERMAL_SCATTERING with pytest.raises(ValueError): TT.from_suffix('z') + + +@needs_njoy +def test_high_temperature(): + endf_data = os.environ['OPENMC_ENDF_DATA'] + endf_file = os.path.join(endf_data, 'neutrons', 'n-001_H_001.endf') + + # Ensure that from_njoy works when given a high temperature + openmc.data.IncidentNeutron.from_njoy(endf_file, temperatures=[123_456.0]) diff --git a/tests/unit_tests/test_data_thermal.py b/tests/unit_tests/test_data_thermal.py index dc4d24628b1..9f5a8cb4046 100644 --- a/tests/unit_tests/test_data_thermal.py +++ b/tests/unit_tests/test_data_thermal.py @@ -262,3 +262,108 @@ def test_get_thermal_name(): # Names that don't remotely match anything assert f('boogie_monster') == 'c_boogie_monster' + + +@pytest.fixture +def fake_mixed_elastic(): + fake_tsl = openmc.data.ThermalScattering("c_D_in_7LiD", 1.9968, 4.9, [0.0253]) + fake_tsl.nuclides = ['H2'] + + # Create elastic reaction + bragg_edges = [0.00370672, 0.00494229, 0.00988458, 0.01359131, 0.01482688, + 0.01976918, 0.02347589, 0.02471147, 0.02965376, 0.03336048, + 0.03953834, 0.04324506, 0.04448063, 0.04942292, 0.05312964, + 0.05436522, 0.05930751, 0.06301423, 0.0642498 , 0.06919209, + 0.07289881, 0.07907667, 0.08278339, 0.08401896, 0.08896126, + 0.09266798, 0.09390355, 0.09884584, 0.1025526 , 0.1037882 , + 0.1087305 , 0.1124372 , 0.1186151 , 0.1223218 , 0.1235574 , + 0.1284997 , 0.1322064 , 0.133442 , 0.142091 , 0.1433266 , + 0.1482688 , 0.1519756 , 0.1581534 , 0.1618601 , 0.1630957 , + 0.168038 , 0.1717447 , 0.1729803 , 0.1779226 , 0.1816293 , + 0.1828649 , 0.1878072 , 0.1915139 , 0.1976918 , 0.2026341 , + 0.2075763 , 0.2125186 , 0.2174609 , 0.2224032 , 0.2273455 , + 0.2421724 , 0.2471147 , 0.252057 , 0.2569993 , 0.2619415 , + 0.2668838 , 0.2767684 , 0.2817107 , 0.2915953 , 0.3064222 , + 0.3261913 , 0.366965] + factors = [0.00375735, 0.01386287, 0.02595574, 0.02992438, 0.03549502, + 0.03855745, 0.04058831, 0.04986305, 0.05703106, 0.05855471, + 0.06078031, 0.06212291, 0.06656602, 0.06930339, 0.0697072 , + 0.07201456, 0.07263853, 0.07313129, 0.07465531, 0.07714482, + 0.07759976, 0.077809 , 0.07790282, 0.07927957, 0.08013058, + 0.08026637, 0.08073475, 0.08112202, 0.08123039, 0.08187171, + 0.08213756, 0.08218236, 0.08236572, 0.08240729, 0.08259795, + 0.08297893, 0.08300455, 0.08314566, 0.08315611, 0.08337715, + 0.08350026, 0.08350663, 0.08352815, 0.08353776, 0.0836098 , + 0.08367017, 0.08367361, 0.0837242 , 0.08375069, 0.08375227, + 0.08377006, 0.08381488, 0.08381644, 0.08382698, 0.08386266, + 0.08387756, 0.08388445, 0.08388974, 0.08390341, 0.08391088, + 0.08391695, 0.08392361, 0.08392684, 0.08392818, 0.08393161, + 0.08393546, 0.08393685, 0.08393801, 0.08393976, 0.08394167, + 0.08394288, 0.08394398] + coherent_xs = openmc.data.CoherentElastic(bragg_edges, factors) + incoherent_xs = openmc.data.Tabulated1D([0.00370672, 0.00370672], [0.00370672, 0.00370672]) + elastic_xs = {'294K': openmc.data.Sum((coherent_xs, incoherent_xs))} + coherent_dist = openmc.data.CoherentElasticAE(coherent_xs) + incoherent_dist = openmc.data.IncoherentElasticAEDiscrete([ + [-0.6, -0.18, 0.18, 0.6], [-0.6, -0.18, 0.18, 0.6] + ]) + elastic_dist = {'294K': openmc.data.MixedElasticAE(coherent_dist, incoherent_dist)} + fake_tsl.elastic = openmc.data.ThermalScatteringReaction(elastic_xs, elastic_dist) + + # Create inelastic reaction + inelastic_xs = {'294K': openmc.data.Tabulated1D([1.0e-5, 4.9], [13.4, 3.35])} + breakpoints = [3] + interpolation = [2] + energy = [1.0e-5, 4.3e-2, 4.9] + energy_out = [ + openmc.data.Tabular([0.0002, 0.067, 0.146, 0.366], [0.25, 0.25, 0.25, 0.25]), + openmc.data.Tabular([0.0001, 0.009, 0.137, 0.277], [0.25, 0.25, 0.25, 0.25]), + openmc.data.Tabular([0.0579, 4.555, 4.803, 4.874], [0.25, 0.25, 0.25, 0.25]), + ] + for eout in energy_out: + eout.normalize() + eout.c = eout.cdf() + discrete = openmc.stats.Discrete([-0.9, -0.6, -0.3, -0.1, 0.1, 0.3, 0.6, 0.9], [1/8]*8) + discrete.c = discrete.cdf()[1:] + mu = [[discrete]*4]*3 + inelastic_dist = {'294K': openmc.data.IncoherentInelasticAE( + breakpoints, interpolation, energy, energy_out, mu)} + inelastic = openmc.data.ThermalScatteringReaction(inelastic_xs, inelastic_dist) + fake_tsl.inelastic = inelastic + + return fake_tsl + + +def test_mixed_elastic(fake_mixed_elastic, run_in_tmpdir): + # Write data to HDF5 and then read back + original = fake_mixed_elastic + original.export_to_hdf5('c_D_in_7LiD.h5') + copy = openmc.data.ThermalScattering.from_hdf5('c_D_in_7LiD.h5') + + # Make sure data did not change as a result of HDF5 writing/reading + assert original == copy + + # Create modified cross_sections.xml file that includes the above data + xs = openmc.data.DataLibrary.from_xml() + xs.register_file('c_D_in_7LiD.h5') + xs.export_to_xml('cross_sections_mixed.xml') + + # Create a minimal model that includes the new data and run it + mat = openmc.Material() + mat.add_nuclide('H2', 1.0) + mat.add_nuclide('Li7', 1.0) + mat.set_density('g/cm3', 1.0) + mat.add_s_alpha_beta('c_D_in_7LiD') + sph = openmc.Sphere(r=10.0, boundary_type="vacuum") + cell = openmc.Cell(fill=mat, region=-sph) + model = openmc.Model() + model.geometry = openmc.Geometry([cell]) + model.materials = openmc.Materials([mat]) + model.materials.cross_sections = "cross_sections_mixed.xml" + model.settings.particles = 1000 + model.settings.batches = 10 + model.settings.run_mode = 'fixed source' + model.settings.source = openmc.IndependentSource( + energy=openmc.stats.Discrete([3.0], [1.0]) # 3 eV source + ) + model.run() diff --git a/tests/unit_tests/test_deplete_activation.py b/tests/unit_tests/test_deplete_activation.py index 6ccee250475..6afea8c9f9f 100644 --- a/tests/unit_tests/test_deplete_activation.py +++ b/tests/unit_tests/test_deplete_activation.py @@ -11,7 +11,7 @@ @pytest.fixture def model(): """Sphere of single nuclide""" - model = openmc.model.Model() + model = openmc.Model() w = openmc.Material(name='tungsten') w.add_nuclide('W186', 1.0) @@ -27,13 +27,13 @@ def model(): model.settings.batches = 10 model.settings.particles = 1000 - model.settings.source = openmc.Source( + model.settings.source = openmc.IndependentSource( space=openmc.stats.Point(), energy=openmc.stats.Discrete([1.0e6], [1.0]) ) model.settings.run_mode = 'fixed source' - rx_tally = openmc.Tally() + rx_tally = openmc.Tally(name='activation tally') rx_tally.scores = ['(n,gamma)'] model.tallies.append(rx_tally) @@ -47,13 +47,13 @@ def model(): ("direct", {}, 1e-5), ("flux", {'energies': ENERGIES}, 0.01), ("flux", {'energies': ENERGIES, 'reactions': ['(n,gamma)']}, 1e-5), - ("flux", {'energies': ENERGIES, 'reactions': ['(n,gamma)'], 'nuclides': ['W186']}, 1e-5), + ("flux", {'energies': ENERGIES, 'reactions': ['(n,gamma)'], 'nuclides': ['W186', 'H3']}, 1e-2), ]) def test_activation(run_in_tmpdir, model, reaction_rate_mode, reaction_rate_opts, tolerance): # Determine (n.gamma) reaction rate using initial run sp = model.run() with openmc.StatePoint(sp) as sp: - tally = sp.tallies[1] + tally = sp.get_tally(name='activation tally') capture_rate = tally.mean.flat[0] # Create one-nuclide depletion chain @@ -64,8 +64,8 @@ def test_activation(run_in_tmpdir, model, reaction_rate_mode, reaction_rate_opts chain.export_to_xml('test_chain.xml') # Create transport operator - op = openmc.deplete.Operator( - model.geometry, model.settings, 'test_chain.xml', + op = openmc.deplete.CoupledOperator( + model, 'test_chain.xml', normalization_mode="source-rate", reaction_rate_mode=reaction_rate_mode, reaction_rate_opts=reaction_rate_opts, @@ -92,7 +92,7 @@ def test_activation(run_in_tmpdir, model, reaction_rate_mode, reaction_rate_opts w = model.geometry.get_materials_by_name('tungsten')[0] atom_densities = w.get_nuclide_atom_densities() - atom_per_cc = 1e24 * atom_densities['W186'][1] # Density in atom/cm^3 + atom_per_cc = 1e24 * atom_densities['W186'] # Density in atom/cm^3 n0 = atom_per_cc * w.volume # Absolute number of atoms # Pick a random irradiation time and then determine necessary source rate to @@ -107,8 +107,8 @@ def test_activation(run_in_tmpdir, model, reaction_rate_mode, reaction_rate_opts integrator.integrate() # Get resulting number of atoms - results = openmc.deplete.ResultsList.from_hdf5('depletion_results.h5') - _, atoms = results.get_atoms(str(w.id), "W186") + results = openmc.deplete.Results('depletion_results.h5') + _, atoms = results.get_atoms(w, "W186") assert atoms[0] == pytest.approx(n0) assert atoms[1] / atoms[0] == pytest.approx(0.5, rel=tolerance) @@ -142,9 +142,10 @@ def test_decay(run_in_tmpdir): chain.add_nuclide(sr89) chain.export_to_xml('test_chain.xml') + model = openmc.Model(geometry=geometry, settings=settings) # Create transport operator - op = openmc.deplete.Operator( - geometry, settings, 'test_chain.xml', normalization_mode="source-rate" + op = openmc.deplete.CoupledOperator( + model, 'test_chain.xml', normalization_mode="source-rate" ) # Deplete with two decay steps @@ -154,9 +155,36 @@ def test_decay(run_in_tmpdir): integrator.integrate() # Get resulting number of atoms - results = openmc.deplete.ResultsList.from_hdf5('depletion_results.h5') - _, atoms = results.get_atoms(str(mat.id), "Sr89") + results = openmc.deplete.Results('depletion_results.h5') + _, atoms = results.get_atoms(mat, "Sr89") # Ensure density goes down by a factor of 2 after each half-life assert atoms[1] / atoms[0] == pytest.approx(0.5) assert atoms[2] / atoms[1] == pytest.approx(0.25) + + +def test_flux_rr_missing_nuclide(run_in_tmpdir, model): + # Create two-nuclide depletion chain -- since W184 is not in the model, this + # test ensures that FluxCollapseHelper loads missing nuclides appropriately + chain = openmc.deplete.Chain() + w184 = openmc.deplete.Nuclide('W184') + w184.add_reaction('(n,gamma)', None, 0.0, 1.0) + chain.add_nuclide(w184) + w186 = openmc.deplete.Nuclide('W186') + w186.add_reaction('(n,gamma)', None, 0.0, 1.0) + chain.add_nuclide(w186) + chain.export_to_xml('test_chain.xml') + + # Create transport operator + op = openmc.deplete.CoupledOperator( + model, 'test_chain.xml', + normalization_mode="source-rate", + reaction_rate_mode="flux", + reaction_rate_opts={'energies': [0.0, 20.0e6]}, + ) + + # Deplete with two decay steps + integrator = openmc.deplete.PredictorIntegrator( + op, [100.0], source_rates=[10.0] + ) + integrator.integrate() diff --git a/tests/unit_tests/test_deplete_chain.py b/tests/unit_tests/test_deplete_chain.py index fa90b35f2e5..9753a53f738 100644 --- a/tests/unit_tests/test_deplete_chain.py +++ b/tests/unit_tests/test_deplete_chain.py @@ -5,9 +5,12 @@ from math import log import os from pathlib import Path +import warnings import numpy as np -from openmc.deplete import comm, Chain, reaction_rates, nuclide, cram, pool +from openmc.mpi import comm +from openmc.deplete import Chain, reaction_rates, nuclide, cram, pool +from openmc.stats import Discrete import pytest from tests import cdtemp @@ -288,7 +291,7 @@ def test_get_set_chain_br(simple_chain): def test_capture_branch_infer_ground(): - """Ensure the ground state is infered if not given""" + """Ensure the ground state is inferred if not given""" # Make up a metastable capture transition: infer_br = {"Xe135": {"Xe136_m1": 0.5}} set_br = {"Xe135": {"Xe136": 0.5, "Xe136_m1": 0.5}} @@ -436,9 +439,9 @@ def test_validate(simple_chain): simple_chain["C"].yield_data = {0.0253: {"A": 1.4, "B": 0.6}} assert simple_chain.validate(strict=True, tolerance=0.0) - with pytest.warns(None) as record: + with warnings.catch_warnings(): + warnings.simplefilter("error") assert simple_chain.validate(strict=False, quiet=False, tolerance=0.0) - assert len(record) == 0 # Mess up "earlier" nuclide's reactions decay_mode = simple_chain["A"].decay_modes.pop() @@ -475,6 +478,15 @@ def gnd_simple_chain(): return Chain.from_xml(chainfile) +def test_chain_sources(gnd_simple_chain): + i135 = gnd_simple_chain['I135'] + assert isinstance(i135.sources, dict) + assert list(i135.sources.keys()) == ['photon'] + photon_src = i135.sources['photon'] + assert isinstance(photon_src, Discrete) + assert photon_src.integral() == pytest.approx(3.920996223799345e-05) + + def test_reduce(gnd_simple_chain, endf_chain): ref_U5 = gnd_simple_chain["U235"] ref_iodine = gnd_simple_chain["I135"] @@ -489,6 +501,7 @@ def test_reduce(gnd_simple_chain, endf_chain): assert u5_round0.n_decay_modes == ref_U5.n_decay_modes assert u5_round0.half_life == ref_U5.half_life assert u5_round0.decay_energy == ref_U5.decay_energy + assert u5_round0.sources == ref_U5.sources for newmode, refmode in zip(u5_round0.decay_modes, ref_U5.decay_modes): assert newmode.target is None assert newmode.type == refmode.type @@ -511,6 +524,7 @@ def test_reduce(gnd_simple_chain, endf_chain): assert bareI5.n_decay_modes == ref_iodine.n_decay_modes assert bareI5.half_life == ref_iodine.half_life assert bareI5.decay_energy == ref_iodine.decay_energy + assert bareI5.sources == ref_iodine.sources for newmode, refmode in zip(bareI5.decay_modes, ref_iodine.decay_modes): assert newmode.target is None assert newmode.type == refmode.type diff --git a/tests/unit_tests/test_deplete_coupled_operator.py b/tests/unit_tests/test_deplete_coupled_operator.py new file mode 100644 index 00000000000..fe79d621b12 --- /dev/null +++ b/tests/unit_tests/test_deplete_coupled_operator.py @@ -0,0 +1,120 @@ +"""Basic unit tests for openmc.deplete.CoupledOperator instantiation + +""" + +from pathlib import Path + +import pytest +from openmc.deplete import CoupledOperator +import openmc +import numpy as np + +CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" + + +@pytest.fixture(scope="module") +def model(): + fuel = openmc.Material(name="uo2") + fuel.add_element("U", 1, percent_type="ao", enrichment=4.25) + fuel.add_element("O", 2) + fuel.set_density("g/cc", 10.4) + + clad = openmc.Material(name="clad") + clad.add_element("Zr", 1) + clad.set_density("g/cc", 6) + + water = openmc.Material(name="water") + water.add_element("O", 1) + water.add_element("H", 2) + water.set_density("g/cc", 1.0) + water.add_s_alpha_beta("c_H_in_H2O") + + radii = [0.42, 0.45] + fuel.volume = np.pi * radii[0] ** 2 + clad.volume = np.pi * (radii[1]**2 - radii[0]**2) + water.volume = 1.24**2 - (np.pi * radii[1]**2) + + materials = openmc.Materials([fuel, clad, water]) + + pin_surfaces = [openmc.ZCylinder(r=r) for r in radii] + pin_univ = openmc.model.pin(pin_surfaces, materials) + bound_box = openmc.model.RectangularPrism( + 1.24, 1.24, boundary_type="reflective") + root_cell = openmc.Cell(fill=pin_univ, region=-bound_box) + geometry = openmc.Geometry([root_cell]) + + settings = openmc.Settings() + settings.particles = 1000 + settings.inactive = 10 + settings.batches = 50 + + return openmc.Model(geometry, materials, settings) + + +@pytest.fixture() +def model_with_volumes(): + mat1 = openmc.Material() + mat1.add_element("Ag", 1, percent_type="ao") + mat1.set_density("g/cm3", 10.49) + mat1.depletable = True + mat1.volume = 102 + + mat2 = openmc.Material() + mat2.add_element("Ag", 1, percent_type="ao") + mat2.set_density("g/cm3", 10.49) + + sph1 = openmc.Sphere(r=1.0) + sph2 = openmc.Sphere(r=2.0, x0=3) + sph3 = openmc.Sphere(r=5.0, boundary_type="vacuum") + + cell1 = openmc.Cell(region=-sph1, fill=mat1) + cell1.volume = 4.19 + cell2 = openmc.Cell(region=-sph2, fill=mat1) + cell2.volume = 33.51 + cell3 = openmc.Cell(region=-sph3 & +sph1 & +sph2, fill=mat2) + cell3.volume = 485.9 + + geometry = openmc.Geometry([cell1, cell2, cell3]) + + return openmc.Model(geometry) + + +def test_operator_init(model): + """The test uses a temporary dummy chain. This file will be removed + at the end of the test, and only contains a depletion_chain node.""" + + CoupledOperator(model, CHAIN_PATH) + + +def test_diff_volume_method_match_cell(model_with_volumes): + """Tests the volumes assigned to the materials match the cell volumes""" + + operator = openmc.deplete.CoupledOperator( + model=model_with_volumes, + diff_burnable_mats=True, + diff_volume_method='match cell', + chain_file=CHAIN_PATH + ) + + all_cells = list(operator.model.geometry.get_all_cells().values()) + assert all_cells[0].fill.volume == 4.19 + assert all_cells[1].fill.volume == 33.51 + # mat2 is not depletable + assert all_cells[2].fill.volume is None + + +def test_diff_volume_method_divide_equally(model_with_volumes): + """Tests the volumes assigned to the materials are divided equally""" + + operator = openmc.deplete.CoupledOperator( + model=model_with_volumes, + diff_burnable_mats=True, + diff_volume_method='divide equally', + chain_file=CHAIN_PATH + ) + + all_cells = list(operator.model.geometry.get_all_cells().values()) + assert all_cells[0].fill[0].volume == 51 + assert all_cells[1].fill[0].volume == 51 + # mat2 is not depletable + assert all_cells[2].fill.volume is None diff --git a/tests/unit_tests/test_deplete_decay.py b/tests/unit_tests/test_deplete_decay.py new file mode 100644 index 00000000000..aca812560c7 --- /dev/null +++ b/tests/unit_tests/test_deplete_decay.py @@ -0,0 +1,83 @@ +from pathlib import Path + +import openmc.deplete +import numpy as np +import pytest + + +def test_deplete_decay_products(run_in_tmpdir): + # Create chain file with H1, He4, and Li5 + with open('test_chain.xml', 'w') as chain_file: + chain_file.write(""" + + + + + + + + + """) + + # Create MicroXS object with no cross sections + micro_xs = openmc.deplete.MicroXS(np.empty((0, 0)), [], []) + + # Create depletion operator with no reactions + op = openmc.deplete.IndependentOperator.from_nuclides( + volume=1.0, + nuclides={'Li5': 1.0}, + flux=0.0, + micro_xs=micro_xs, + chain_file='test_chain.xml', + normalization_mode='source-rate' + ) + + # Create time-integrator and integrate + integrator = openmc.deplete.PredictorIntegrator( + op, timesteps=[1.0], source_rates=[0.0], timestep_units='d' + ) + integrator.integrate(final_step=False) + + # Get concentration of H1 and He4 + results = openmc.deplete.Results('depletion_results.h5') + _, h1 = results.get_atoms("1", "H1") + _, he4 = results.get_atoms("1", "He4") + + # Since we started with 1e24 atoms of Li5, we should have 1e24 atoms of both + # H1 and He4 + assert h1[1] == pytest.approx(1e24) + assert he4[1] == pytest.approx(1e24) + + +def test_deplete_decay_step_fissionable(run_in_tmpdir): + """Ensures that power is not computed in zero power cases with + fissionable material present. This tests decay calculations without + power, although this specific example does not exhibit any decay. + + Proves github issue #2963 is fixed + """ + + # Set up a pure decay operator + micro_xs = openmc.deplete.MicroXS(np.empty((0, 0)), [], []) + mat = openmc.Material() + mat.name = 'I do not decay.' + mat.add_nuclide('U238', 1.0, 'ao') + mat.volume = 10.0 + mat.set_density('g/cc', 1.0) + original_atoms = mat.get_nuclide_atoms()['U238'] + + mats = openmc.Materials([mat]) + op = openmc.deplete.IndependentOperator( + mats, [1.0], [micro_xs], Path(__file__).parents[1] / "chain_simple.xml") + + # Create time integrator and integrate + integrator = openmc.deplete.PredictorIntegrator( + op, [1.0], power=[0.0], timestep_units='s' + ) + integrator.integrate() + + # Get concentration of U238. It should be unchanged since this chain has no U238 decay. + results = openmc.deplete.Results('depletion_results.h5') + _, u238 = results.get_atoms("1", "U238") + + assert u238[1] == pytest.approx(original_atoms) diff --git a/tests/unit_tests/test_deplete_fission_yields.py b/tests/unit_tests/test_deplete_fission_yields.py index 8839b42b3df..1937e61e333 100644 --- a/tests/unit_tests/test_deplete_fission_yields.py +++ b/tests/unit_tests/test_deplete_fission_yields.py @@ -27,8 +27,8 @@ def materials(tmpdir_factory): mfuel.add_nuclide(nuclide, 1.0) openmc.Materials([mfuel]).export_to_xml() # Geometry - box = openmc.rectangular_prism(1.0, 1.0, boundary_type="reflective") - cell = openmc.Cell(fill=mfuel, region=box) + box = openmc.model.RectangularPrism(1.0, 1.0, boundary_type="reflective") + cell = openmc.Cell(fill=mfuel, region=-box) root = openmc.Universe(cells=[cell]) openmc.Geometry(root).export_to_xml() # settings @@ -43,12 +43,11 @@ def materials(tmpdir_factory): with lib.run_in_memory(): yield [lib.Material(), lib.Material()] finally: - # Convert to strings as os.remove in py 3.5 doesn't support Paths for file_path in ("settings.xml", "geometry.xml", "materials.xml", "summary.h5"): - os.remove(str(tmpdir / file_path)) + os.remove(tmpdir / file_path) orig.chdir() - os.rmdir(str(tmpdir)) + os.rmdir(tmpdir) def proxy_tally_data(tally, fill=None): diff --git a/tests/unit_tests/test_deplete_independent_operator.py b/tests/unit_tests/test_deplete_independent_operator.py new file mode 100644 index 00000000000..9129cf0642f --- /dev/null +++ b/tests/unit_tests/test_deplete_independent_operator.py @@ -0,0 +1,54 @@ +"""Basic unit tests for openmc.deplete.IndependentOperator instantiation + +""" + +from pathlib import Path + +import pytest + +from openmc import Material, Materials +from openmc.deplete import IndependentOperator, MicroXS + +CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" +ONE_GROUP_XS = Path(__file__).parents[1] / "micro_xs_simple.csv" + + +def test_operator_init(): + """The test uses a temporary dummy chain. This file will be removed + at the end of the test, and only contains a depletion_chain node.""" + volume = 1 + nuclides = {'U234': 8.922411359424315e+18, + 'U235': 9.98240191860822e+20, + 'U238': 2.2192386373095893e+22, + 'U236': 4.5724195495061115e+18, + 'O16': 4.639065406771322e+22, + 'O17': 1.7588724018066158e+19} + flux = 1.0 + micro_xs = MicroXS.from_csv(ONE_GROUP_XS) + IndependentOperator.from_nuclides( + volume, nuclides, flux, micro_xs, CHAIN_PATH, nuc_units='atom/cm3') + + fuel = Material(name="uo2") + fuel.add_element("U", 1, percent_type="ao", enrichment=4.25) + fuel.add_element("O", 2) + fuel.set_density("g/cc", 10.4) + fuel.depletable = True + fuel.volume = 1 + materials = Materials([fuel]) + fluxes = [1.0] + micros = [micro_xs] + IndependentOperator(materials, fluxes, micros, CHAIN_PATH) + + +def test_error_handling(): + micro_xs = MicroXS.from_csv(ONE_GROUP_XS) + fuel = Material(name="oxygen") + fuel.add_element("O", 2) + fuel.set_density("g/cc", 1) + fuel.depletable = True + fuel.volume = 1 + materials = Materials([fuel]) + fluxes = [1.0, 2.0] + micros = [micro_xs] + with pytest.raises(ValueError, match=r"The length of fluxes \(2\)"): + IndependentOperator(materials, fluxes, micros, CHAIN_PATH) diff --git a/tests/unit_tests/test_deplete_integrator.py b/tests/unit_tests/test_deplete_integrator.py index 3195c597685..b1d2cb950eb 100644 --- a/tests/unit_tests/test_deplete_integrator.py +++ b/tests/unit_tests/test_deplete_integrator.py @@ -14,11 +14,11 @@ from uncertainties import ufloat import pytest +from openmc.mpi import comm from openmc.deplete import ( - ReactionRates, Results, ResultsList, comm, OperatorResult, - PredictorIntegrator, CECMIntegrator, CF4Integrator, CELIIntegrator, - EPCRK4Integrator, LEQIIntegrator, SICELIIntegrator, SILEQIIntegrator, - cram) + ReactionRates, StepResult, Results, OperatorResult, PredictorIntegrator, + CECMIntegrator, CF4Integrator, CELIIntegrator, EPCRK4Integrator, + LEQIIntegrator, SICELIIntegrator, SILEQIIntegrator, cram) from tests import dummy_operator @@ -40,7 +40,7 @@ def test_results_save(run_in_tmpdir): stages = 3 - np.random.seed(comm.rank) + rng = np.random.RandomState(comm.rank) # Mock geometry op = MagicMock() @@ -68,26 +68,26 @@ def test_results_save(run_in_tmpdir): x2 = [] for i in range(stages): - x1.append([np.random.rand(2), np.random.rand(2)]) - x2.append([np.random.rand(2), np.random.rand(2)]) + x1.append([rng.random(2), rng.random(2)]) + x2.append([rng.random(2), rng.random(2)]) # Construct r r1 = ReactionRates(burn_list, ["na", "nb"], ["ra", "rb"]) - r1[:] = np.random.rand(2, 2, 2) + r1[:] = rng.random((2, 2, 2)) rate1 = [] rate2 = [] for i in range(stages): rate1.append(copy.deepcopy(r1)) - r1[:] = np.random.rand(2, 2, 2) + r1[:] = rng.random((2, 2, 2)) rate2.append(copy.deepcopy(r1)) - r1[:] = np.random.rand(2, 2, 2) + r1[:] = rng.random((2, 2, 2)) # Create global terms # Col 0: eig, Col 1: uncertainty - eigvl1 = np.random.rand(stages, 2) - eigvl2 = np.random.rand(stages, 2) + eigvl1 = rng.random((stages, 2)) + eigvl2 = rng.random((stages, 2)) eigvl1 = comm.bcast(eigvl1, root=0) eigvl2 = comm.bcast(eigvl2, root=0) @@ -99,11 +99,17 @@ def test_results_save(run_in_tmpdir): for k, rates in zip(eigvl1, rate1)] op_result2 = [OperatorResult(ufloat(*k), rates) for k, rates in zip(eigvl2, rate2)] - Results.save(op, x1, op_result1, t1, 0, 0) - Results.save(op, x2, op_result2, t2, 0, 1) + + # saves within a subdirectory + StepResult.save(op, x1, op_result1, t1, 0, 0, path='out/put/depletion.h5') + res = Results('out/put/depletion.h5') + + # saves with default filename + StepResult.save(op, x1, op_result1, t1, 0, 0) + StepResult.save(op, x2, op_result2, t2, 0, 1) # Load the files - res = ResultsList.from_hdf5("depletion_results.h5") + res = Results("depletion_results.h5") for i in range(stages): for mat_i, mat in enumerate(burn_list): @@ -176,8 +182,7 @@ def test_integrator(run_in_tmpdir, scheme): # get expected results - res = ResultsList.from_hdf5( - operator.output_dir / "depletion_results.h5") + res = Results(operator.output_dir / "depletion_results.h5") t1, y1 = res.get_atoms("1", "1") t2, y2 = res.get_atoms("1", "2") diff --git a/tests/unit_tests/test_deplete_microxs.py b/tests/unit_tests/test_deplete_microxs.py new file mode 100644 index 00000000000..ad54026f014 --- /dev/null +++ b/tests/unit_tests/test_deplete_microxs.py @@ -0,0 +1,111 @@ +"""Basic unit tests for openmc.deplete.IndependentOperator instantiation + +Modifies and resets environment variable OPENMC_CROSS_SECTIONS +to a custom file with new depletion_chain node +""" + +from os import remove +from pathlib import Path + +import pytest +from openmc.deplete import MicroXS +import numpy as np + +ONE_GROUP_XS = Path(__file__).parents[1] / "micro_xs_simple.csv" + + +def test_from_array(): + nuclides = [ + 'U234', + 'U235', + 'U238', + 'U236', + 'O16', + 'O17', + 'I135', + 'Xe135', + 'Xe136', + 'Cs135', + 'Gd157', + 'Gd156'] + reactions = ['fission', '(n,gamma)'] + # These values are placeholders and are not at all + # physically meaningful. + data = np.array([[0.1, 0.], + [0.1, 0.], + [0.9, 0.], + [0.4, 0.], + [0., 0.], + [0., 0.], + [0., 0.1], + [0., 0.9], + [0., 0.], + [0., 0.], + [0., 0.1], + [0., 0.1]]) + data.shape = (12, 2, 1) + + MicroXS(data, nuclides, reactions) + with pytest.raises(ValueError, match=r'Nuclides list of length \d* and ' + r'reactions array of length \d* do not ' + r'match dimensions of data array of shape \(\d*\, \d*\)'): + MicroXS(data[:, 0], nuclides, reactions) + + +def test_csv(): + ref_xs = MicroXS.from_csv(ONE_GROUP_XS) + ref_xs.to_csv('temp_xs.csv') + temp_xs = MicroXS.from_csv('temp_xs.csv') + assert np.all(ref_xs.data == temp_xs.data) + remove('temp_xs.csv') + + +def test_from_multigroup_flux(): + energies = [0., 6.25e-1, 5.53e3, 8.21e5, 2.e7] + flux = [1.1e-7, 1.2e-6, 1.3e-5, 1.4e-4] + chain_file = Path(__file__).parents[1] / 'chain_simple.xml' + kwargs = {'multigroup_flux': flux, 'chain_file': chain_file} + + # test with energy group structure from string + microxs = MicroXS.from_multigroup_flux(energies='CASMO-4', **kwargs) + assert isinstance(microxs, MicroXS) + + # test with energy group structure as floats + microxs = MicroXS.from_multigroup_flux(energies=energies, **kwargs) + assert isinstance(microxs, MicroXS) + + # test with nuclides provided + microxs = MicroXS.from_multigroup_flux( + energies=energies, nuclides=['Gd157', 'H1'], **kwargs + ) + assert isinstance(microxs, MicroXS) + assert microxs.nuclides == ['Gd157', 'H1'] + + # test with reactions provided + microxs = MicroXS.from_multigroup_flux( + energies=energies, reactions=['fission', '(n,2n)'], **kwargs + ) + assert isinstance(microxs, MicroXS) + assert microxs.reactions == ['fission', '(n,2n)'] + + +def test_multigroup_flux_same(): + chain_file = Path(__file__).parents[1] / 'chain_simple.xml' + + # Generate micro XS based on 4-group flux + energies = [0., 6.25e-1, 5.53e3, 8.21e5, 2.e7] + flux_per_ev = [0.3, 0.3, 1.0, 1.0] + flux = flux_per_ev * np.diff(energies) + microxs_4g = MicroXS.from_multigroup_flux( + energies=energies, multigroup_flux=flux, chain_file=chain_file) + + # Generate micro XS based on 2-group flux, where the boundaries line up with + # the 4 group flux and have the same flux per eV across the full energy + # range + energies = [0., 5.53e3, 2.0e7] + flux_per_ev = [0.3, 1.0] + flux = flux_per_ev * np.diff(energies) + microxs_2g = MicroXS.from_multigroup_flux( + energies=energies, multigroup_flux=flux, chain_file=chain_file) + + assert microxs_4g.data == pytest.approx(microxs_2g.data) diff --git a/tests/unit_tests/test_deplete_nuclide.py b/tests/unit_tests/test_deplete_nuclide.py index 705beb32a2d..f2bb7d1b65e 100644 --- a/tests/unit_tests/test_deplete_nuclide.py +++ b/tests/unit_tests/test_deplete_nuclide.py @@ -1,7 +1,9 @@ """Tests for the openmc.deplete.Nuclide class.""" -import xml.etree.ElementTree as ET +import copy +import warnings +import lxml.etree as ET import numpy as np import pytest from openmc.deplete import nuclide @@ -276,9 +278,9 @@ def test_validate(): } # nuclide is good and should have no warnings raise - with pytest.warns(None) as record: + with warnings.catch_warnings(): + warnings.simplefilter("error") assert nuc.validate(strict=True, quiet=False, tolerance=0.0) - assert len(record) == 0 # invalidate decay modes decay = nuc.decay_modes.pop() @@ -335,3 +337,14 @@ def test_validate(): assert "decay mode" in record[0].message.args[0] assert "0 reaction" in record[1].message.args[0] assert "1.0" in record[2].message.args[0] + + +def test_deepcopy(): + """Test deepcopying a FissionYield object""" + nuc = nuclide.FissionYield(products=("I129", "Sm149", "Xe135"), yields=np.array((0.001, 0.0003, 0.002))) + copied_nuc = copy.deepcopy(nuc) + # Check the deepcopy equals the original + assert copied_nuc == nuc + # Mutate the original and verify the copy remains intact + nuc *= 2 + assert copied_nuc != nuc diff --git a/tests/unit_tests/test_deplete_operator.py b/tests/unit_tests/test_deplete_operator.py index 3574d293dc7..6ea89fc4a5b 100644 --- a/tests/unit_tests/test_deplete_operator.py +++ b/tests/unit_tests/test_deplete_operator.py @@ -1,39 +1,15 @@ """Basic unit tests for openmc.deplete.Operator instantiation -Modifies and resets environment variable OPENMC_CROSS_SECTIONS -to a custom file with new depletion_chain node """ -from os import environ -from unittest import mock from pathlib import Path -import pytest from openmc.deplete.abc import TransportOperator from openmc.deplete.chain import Chain -BARE_XS_FILE = "bare_cross_sections.xml" CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" -@pytest.fixture() -def bare_xs(run_in_tmpdir): - """Create a very basic cross_sections file, return simple Chain. - - """ - - bare_xs_contents = """ - - - -""".format(CHAIN_PATH) - - with open(BARE_XS_FILE, "w") as out: - out.write(bare_xs_contents) - - yield - - class BareDepleteOperator(TransportOperator): """Very basic class for testing the initialization.""" @@ -54,14 +30,10 @@ def write_bos_data(): pass -@mock.patch.dict(environ, {"OPENMC_CROSS_SECTIONS": BARE_XS_FILE}) -def test_operator_init(bare_xs): - """The test will set and unset environment variable OPENMC_CROSS_SECTIONS - to point towards a temporary dummy file. This file will be removed - at the end of the test, and only contains a - depletion_chain node.""" - # force operator to read from OPENMC_CROSS_SECTIONS - bare_op = BareDepleteOperator(chain_file=None) +def test_operator_init(): + """The test uses a temporary dummy chain. This file will be removed + at the end of the test, and only contains a depletion_chain node.""" + bare_op = BareDepleteOperator(CHAIN_PATH) act_chain = bare_op.chain ref_chain = Chain.from_xml(CHAIN_PATH) assert len(act_chain) == len(ref_chain) @@ -79,8 +51,7 @@ def test_operator_init(bare_xs): def test_operator_fiss_q(): """Make sure fission q values can be set""" new_q = {"U235": 2.0E8, "U238": 2.0E8, "U234": 5.0E7} - chain_file = Path(__file__).parents[1] / "chain_simple.xml" - operator = BareDepleteOperator(chain_file=chain_file, fission_q=new_q) + operator = BareDepleteOperator(chain_file=CHAIN_PATH, fission_q=new_q) mod_chain = operator.chain for name, q in new_q.items(): chain_nuc = mod_chain[name] diff --git a/tests/unit_tests/test_deplete_restart.py b/tests/unit_tests/test_deplete_restart.py index 82ef05ac7b2..e8bfc062a08 100644 --- a/tests/unit_tests/test_deplete_restart.py +++ b/tests/unit_tests/test_deplete_restart.py @@ -24,8 +24,7 @@ def test_restart_predictor_cecm(run_in_tmpdir): openmc.deplete.PredictorIntegrator(op, dt, power).integrate() # Load the files - prev_res = openmc.deplete.ResultsList.from_hdf5( - op.output_dir / "depletion_results.h5") + prev_res = openmc.deplete.Results(op.output_dir / "depletion_results.h5") # Re-create depletion operator and load previous results op = dummy_operator.DummyOperator(prev_res) @@ -51,8 +50,7 @@ def test_restart_cecm_predictor(run_in_tmpdir): cecm.integrate() # Load the files - prev_res = openmc.deplete.ResultsList.from_hdf5( - op.output_dir / "depletion_results.h5") + prev_res = openmc.deplete.Results(op.output_dir / "depletion_results.h5") # Re-create depletion operator and load previous results op = dummy_operator.DummyOperator(prev_res) @@ -75,7 +73,7 @@ def test_restart(run_in_tmpdir, scheme): bundle.solver(operator, [0.75], 1.0).integrate() # restart - prev_res = openmc.deplete.ResultsList.from_hdf5( + prev_res = openmc.deplete.Results( operator.output_dir / "depletion_results.h5") operator = dummy_operator.DummyOperator(prev_res) @@ -84,7 +82,7 @@ def test_restart(run_in_tmpdir, scheme): # compare results - results = openmc.deplete.ResultsList.from_hdf5( + results = openmc.deplete.Results( operator.output_dir / "depletion_results.h5") _t, y1 = results.get_atoms("1", "1") diff --git a/tests/unit_tests/test_deplete_resultslist.py b/tests/unit_tests/test_deplete_resultslist.py index 5d8fb11e45d..b22a786509e 100644 --- a/tests/unit_tests/test_deplete_resultslist.py +++ b/tests/unit_tests/test_deplete_resultslist.py @@ -1,4 +1,4 @@ -"""Tests the ResultsList class""" +"""Tests the Results class""" from pathlib import Path from math import inf @@ -11,9 +11,30 @@ @pytest.fixture def res(): """Load the reference results""" - filename = (Path(__file__).parents[1] / 'regression_tests' / 'deplete' + filename = (Path(__file__).parents[1] / 'regression_tests' / 'deplete_with_transport' / 'test_reference.h5') - return openmc.deplete.ResultsList.from_hdf5(filename) + return openmc.deplete.Results(filename) + +def test_get_activity(res): + """Tests evaluating activity""" + t, a = res.get_activity("1") + + t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) + a_ref = np.array( + [1.25167956e+06, 3.71938527e+11, 4.43264300e+11, 3.55547176e+11]) + + np.testing.assert_allclose(t, t_ref) + np.testing.assert_allclose(a, a_ref) + + # Check by_nuclide + a_xe135_ref = np.array( + [2.106574218e+05, 1.227519888e+11, 1.177491828e+11, 1.031986176e+11]) + t_nuc, a_nuc = res.get_activity("1", by_nuclide=True) + + a_xe135 = np.array([a_nuc_i["Xe135"] for a_nuc_i in a_nuc]) + + np.testing.assert_allclose(t_nuc, t_ref) + np.testing.assert_allclose(a_xe135, a_xe135_ref) def test_get_atoms(res): @@ -22,7 +43,7 @@ def test_get_atoms(res): t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) n_ref = np.array( - [6.67473282e+08, 3.72442707e+14, 3.61129692e+14, 4.01920099e+14]) + [6.67473282e+08, 3.88942731e+14, 3.73091215e+14, 3.26987387e+14]) np.testing.assert_allclose(t, t_ref) np.testing.assert_allclose(n, n_ref) @@ -43,39 +64,97 @@ def test_get_atoms(res): assert t_hour == pytest.approx(t_ref / (60 * 60)) +def test_get_decay_heat(res): + """Tests evaluating decay heat.""" + # Set chain file for testing + openmc.config['chain_file'] = Path(__file__).parents[1] / 'chain_simple.xml' + + t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) + dh_ref = np.array( + [1.27933813e-09, 5.85347232e-03, 7.38773010e-03, 5.79954067e-03]) + + t, dh = res.get_decay_heat("1") + + np.testing.assert_allclose(t, t_ref) + np.testing.assert_allclose(dh, dh_ref) + + # Check by nuclide + dh_xe135_ref = np.array( + [1.27933813e-09, 7.45481920e-04, 7.15099509e-04, 6.26732849e-04]) + t_nuc, dh_nuc = res.get_decay_heat("1", by_nuclide=True) + + dh_nuc_xe135 = np.array([dh_nuc_i["Xe135"] for dh_nuc_i in dh_nuc]) + + np.testing.assert_allclose(t_nuc, t_ref) + np.testing.assert_allclose(dh_nuc_xe135, dh_xe135_ref) + + +def test_get_mass(res): + """Tests evaluating single nuclide concentration.""" + t, n = res.get_mass("1", "Xe135") + + t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) + n_ref = np.array( + [6.67473282e+08, 3.88942731e+14, 3.73091215e+14, 3.26987387e+14]) + + # Get g + n_ref *= openmc.data.atomic_mass('Xe135') / openmc.data.AVOGADRO + + np.testing.assert_allclose(t, t_ref) + np.testing.assert_allclose(n, n_ref) + + # Check alternate units + volume = res[0].volume["1"] + t_days, n_cm3 = res.get_mass("1", "Xe135", mass_units="g/cm3", time_units="d") + + assert t_days == pytest.approx(t_ref / (60 * 60 * 24)) + assert n_cm3 == pytest.approx(n_ref / volume) + + t_min, n_bcm = res.get_mass("1", "Xe135", mass_units="kg", time_units="min") + assert n_bcm == pytest.approx(n_ref / 1e3) + assert t_min == pytest.approx(t_ref / 60) + + t_hour, _n = res.get_mass("1", "Xe135", time_units="h") + assert t_hour == pytest.approx(t_ref / (60 * 60)) + + def test_get_reaction_rate(res): """Tests evaluating reaction rate.""" t, r = res.get_reaction_rate("1", "Xe135", "(n,gamma)") t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0] - n_ref = [6.67473282e+08, 3.72442707e+14, 3.61129692e+14, 4.01920099e+14] - xs_ref = [5.10301159e-05, 3.19379638e-05, 4.50543806e-05, 4.71004301e-05] + n_ref = [6.67473282e+08, 3.88942731e+14, 3.73091215e+14, 3.26987387e+14] + xs_ref = [2.53336104e-05, 4.21747011e-05, 3.48616127e-05, 3.61775563e-05] np.testing.assert_allclose(t, t_ref) np.testing.assert_allclose(r, np.array(n_ref) * xs_ref) -def test_get_eigenvalue(res): - """Tests evaluating eigenvalue.""" - t, k = res.get_eigenvalue() +def test_get_keff(res): + """Tests evaluating keff.""" + t, k = res.get_keff() + t_min, k = res.get_keff(time_units='min') t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0] - k_ref = [1.21409662, 1.16518654, 1.25357797, 1.22611968] - u_ref = [0.0278795195, 0.0233141097, 0.0167899218, 0.0246734716] + k_ref = [1.1596402556, 1.1914183335, 1.2292570871, 1.1797030302] + u_ref = [0.0270680649, 0.0219163444, 0.024268508 , 0.0221401194] np.testing.assert_allclose(t, t_ref) + np.testing.assert_allclose(t_min * 60, t_ref) np.testing.assert_allclose(k[:, 0], k_ref) np.testing.assert_allclose(k[:, 1], u_ref) -@pytest.mark.parametrize("unit", ("s", "d", "min", "h")) +@pytest.mark.parametrize("unit", ("s", "d", "min", "h", "a")) def test_get_steps(unit): - # Make a ResultsList full of near-empty Result instances + # Make a Results full of near-empty Result instances # Just fill out a time schedule - results = openmc.deplete.ResultsList() + results = openmc.deplete.Results(filename=None) # Time in units of unit times = np.linspace(0, 100, num=5) - if unit == "d": + if unit == "a": + conversion_to_seconds = 60 * 60 * 24 * 365.25 + elif unit == "d": conversion_to_seconds = 60 * 60 * 24 elif unit == "h": conversion_to_seconds = 60 * 60 @@ -85,7 +164,7 @@ def test_get_steps(unit): conversion_to_seconds = 1 for ix in range(times.size): - res = openmc.deplete.Results() + res = openmc.deplete.StepResult() res.time = times[ix:ix + 1] * conversion_to_seconds results.append(res) @@ -129,3 +208,17 @@ def test_get_steps(unit): actual = results.get_step_where( times[-1] * 100, time_units=unit, atol=inf, rtol=inf) assert actual == times.size - 1 + + +def test_stepresult_get_material(res): + # Get material at first timestep + step_result = res[0] + mat1 = step_result.get_material("1") + assert mat1.id == 1 + assert mat1.volume == step_result.volume["1"] + + # Spot check number densities + densities = mat1.get_nuclide_atom_densities() + assert densities['Xe135'] == pytest.approx(1e-14) + assert densities['I135'] == pytest.approx(1e-21) + assert densities['U234'] == pytest.approx(1.00506e-05) diff --git a/tests/unit_tests/test_deplete_transfer_rates.py b/tests/unit_tests/test_deplete_transfer_rates.py new file mode 100644 index 00000000000..847606be435 --- /dev/null +++ b/tests/unit_tests/test_deplete_transfer_rates.py @@ -0,0 +1,188 @@ +""" Tests for TransferRates class """ + +from pathlib import Path +from math import exp + +import pytest +import numpy as np + +import openmc +from openmc.deplete import CoupledOperator +from openmc.deplete.transfer_rates import TransferRates +from openmc.deplete.abc import (_SECONDS_PER_MINUTE, _SECONDS_PER_HOUR, + _SECONDS_PER_DAY, _SECONDS_PER_JULIAN_YEAR) + +CHAIN_PATH = Path(__file__).parents[1] / "chain_simple.xml" + +@pytest.fixture +def model(): + f = openmc.Material(name="f") + f.add_element("U", 1, percent_type="ao", enrichment=4.25) + f.add_element("O", 2) + f.set_density("g/cc", 10.4) + + w = openmc.Material(name="w") + w.add_element("O", 1) + w.add_element("H", 2) + w.set_density("g/cc", 1.0) + w.depletable = True + + # material just to test multiple destination material + h = openmc.Material(name="h") + h.add_element("He", 1) + h.set_density("g/cc", 1.78e-4) + h.depletable = True + + radii = [0.42, 0.45] + f.volume = np.pi * radii[0] ** 2 + w.volume = np.pi * (radii[1]**2 - radii[0]**2) + h.volume = 1 + materials = openmc.Materials([f, w, h]) + + surf_f = openmc.Sphere(r=radii[0]) + surf_w = openmc.Sphere(r=radii[1], boundary_type='vacuum') + surf_h = openmc.Sphere(x0=10, r=1, boundary_type='vacuum') + cell_f = openmc.Cell(fill=f, region=-surf_f) + cell_w = openmc.Cell(fill=w, region=+surf_f & -surf_w) + cell_h = openmc.Cell(fill=h, region=-surf_h) + geometry = openmc.Geometry([cell_f, cell_w, cell_h]) + + settings = openmc.Settings() + settings.particles = 1000 + settings.inactive = 10 + settings.batches = 50 + + return openmc.Model(geometry, materials, settings) + +@pytest.mark.parametrize("case_name, transfer_rates", [ + ('elements', {'U': 0.01, 'Xe': 0.1}), + ('nuclides', {'I135': 0.01, 'Gd156': 0.1, 'Gd157': 0.01}), + ('nuclides_elements', {'I135': 0.01, 'Gd156': 0.1, 'Gd157': 0.01, 'U': 0.01, + 'Xe': 0.1}), + ('elements_nuclides', {'U': 0.01, 'Xe': 0.1, 'I135': 0.01, 'Gd156': 0.1, + 'Gd157': 0.01}), + ('multiple_transfer', {'U': 0.01, 'Xe': 0.1, 'I135': 0.01, 'Gd156': 0.1, + 'Gd157': 0.01}), + ('rates_invalid_1', {'Gd': 0.01, 'Gd157': 0.01, 'Gd156': 0.01}), + ('rates_invalid_2', {'Gd156': 0.01, 'Gd157': 0.01, 'Gd': 0.01}), + ('rates_invalid_3', {'Gb156': 0.01}), + ('rates_invalid_4', {'Gb': 0.01}) + ]) +def test_get_set(model, case_name, transfer_rates): + """Tests the get/set methods""" + + op = CoupledOperator(model, CHAIN_PATH) + transfer = TransferRates(op, model) + + # Test by Openmc material, material name and material id + material, dest_material, dest_material2 = [m for m in model.materials + if m.depletable] + for material_input in [material, material.name, material.id]: + for dest_material_input in [dest_material, dest_material.name, + dest_material.id]: + if case_name == 'rates_invalid_1': + with pytest.raises(ValueError, match='Cannot add transfer ' + 'rate for nuclide Gd157 to material 1 ' + 'where element Gd already has a ' + 'transfer rate.'): + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, + [component], + transfer_rate) + elif case_name == 'rates_invalid_2': + with pytest.raises(ValueError, match='Cannot add transfer ' + f'rate for element Gd to material 1 with ' + r'transfer rate\(s\) for nuclide\(s\) ' + 'Gd156, Gd157.'): + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, + [component], + transfer_rate) + elif case_name == 'rates_invalid_3': + with pytest.raises(ValueError, match='Gb156 is not a valid ' + 'nuclide or element.'): + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, + [component], + transfer_rate) + elif case_name == 'rates_invalid_4': + with pytest.raises(ValueError, match='Gb is not a valid ' + 'nuclide or element.'): + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, + [component], + transfer_rate) + else: + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, [component], + transfer_rate, + destination_material=\ + dest_material_input) + assert transfer.get_transfer_rate( + material_input, component)[0] == transfer_rate + assert transfer.get_destination_material( + material_input, component)[0] == str(dest_material.id) + assert transfer.get_components(material_input) == \ + transfer_rates.keys() + + if case_name == 'multiple_transfer': + for dest2_material_input in [dest_material2, dest_material2.name, + dest_material2.id]: + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, [component], + transfer_rate, + destination_material=\ + dest2_material_input) + for id, dest_mat in zip([0,1],[dest_material,dest_material2]): + assert transfer.get_transfer_rate( + material_input, component)[id] == transfer_rate + assert transfer.get_destination_material( + material_input, component)[id] == str(dest_mat.id) + +@pytest.mark.parametrize("transfer_rate_units, unit_conv", [ + ('1/s', 1), + ('1/sec', 1), + ('1/min', _SECONDS_PER_MINUTE), + ('1/minute', _SECONDS_PER_MINUTE), + ('1/h', _SECONDS_PER_HOUR), + ('1/hr', _SECONDS_PER_HOUR), + ('1/hour', _SECONDS_PER_HOUR), + ('1/d', _SECONDS_PER_DAY), + ('1/day', _SECONDS_PER_DAY), + ('1/a', _SECONDS_PER_JULIAN_YEAR), + ('1/year', _SECONDS_PER_JULIAN_YEAR), + ]) +def test_units(transfer_rate_units, unit_conv, model): + """ Units testing""" + # create transfer rate Xe + components = ['Xe', 'U235'] + transfer_rate = 1e-5 + op = CoupledOperator(model, CHAIN_PATH) + transfer = TransferRates(op, model) + + for component in components: + transfer.set_transfer_rate('f', [component], transfer_rate * unit_conv, + transfer_rate_units=transfer_rate_units) + assert transfer.get_transfer_rate('f', component)[0] == transfer_rate + + +def test_transfer(run_in_tmpdir, model): + """Tests transfer depletion class without neither reaction rates nor decay + but only transfer rates""" + + # create transfer rate for U + element = ['U'] + transfer_rate = 1e-5 + op = CoupledOperator(model, CHAIN_PATH) + integrator = openmc.deplete.PredictorIntegrator( + op, [1,1], 0.0, timestep_units = 'd') + integrator.add_transfer_rate('f', element, transfer_rate) + integrator.integrate() + + # Get number of U238 atoms from results + results = openmc.deplete.Results('depletion_results.h5') + _, atoms = results.get_atoms(model.materials[0], "U238") + + # Ensure number of atoms equal transfer decay + assert atoms[1] == pytest.approx(atoms[0]*exp(-transfer_rate*3600*24)) + assert atoms[2] == pytest.approx(atoms[1]*exp(-transfer_rate*3600*24)) diff --git a/tests/unit_tests/test_element.py b/tests/unit_tests/test_element.py index bacb988b9a9..d3555701e2c 100644 --- a/tests/unit_tests/test_element.py +++ b/tests/unit_tests/test_element.py @@ -1,5 +1,5 @@ import openmc -from pytest import approx, raises +from pytest import approx, raises, warns from openmc.data import NATURAL_ABUNDANCE, atomic_mass @@ -37,6 +37,13 @@ def test_expand_enrichment(): assert isotope[1] == approx(ref[isotope[0]]) +def test_expand_no_isotopes(): + """Test that correct warning is raised for elements with no isotopes""" + with warns(UserWarning, match='No naturally occurring'): + element = openmc.Element('Tc') + element.expand(100.0, 'ao') + + def test_expand_exceptions(): """ Test that correct exceptions are raised for invalid input """ diff --git a/tests/unit_tests/test_element_wo.py b/tests/unit_tests/test_element_wo.py index 2431f9e0e7e..52fc80a378c 100644 --- a/tests/unit_tests/test_element_wo.py +++ b/tests/unit_tests/test_element_wo.py @@ -1,8 +1,5 @@ #!/usr/bin/env python -import os -import sys - import pytest from openmc import Material diff --git a/tests/unit_tests/test_endf.py b/tests/unit_tests/test_endf.py index 9e69708673e..1d4982054c8 100644 --- a/tests/unit_tests/test_endf.py +++ b/tests/unit_tests/test_endf.py @@ -23,6 +23,7 @@ def test_float_endf(): assert endf.float_endf('-1.+2') == approx(-100.0) assert endf.float_endf(' ') == 0.0 assert endf.float_endf('9.876540000000000') == approx(9.87654) + assert endf.float_endf('-2.225002+6') == approx(-2.225002e+6) def test_int_endf(): diff --git a/tests/unit_tests/test_energy_cutoff.py b/tests/unit_tests/test_energy_cutoff.py new file mode 100644 index 00000000000..45333f2e1dc --- /dev/null +++ b/tests/unit_tests/test_energy_cutoff.py @@ -0,0 +1,63 @@ +from random import uniform + +import pytest +import openmc + + +def inf_medium_model(cutoff_energy, source_energy): + """Infinite medium problem with a monoenergetic photon source""" + model = openmc.Model() + + m = openmc.Material() + m.add_nuclide('Zr90', 1.0) + m.set_density('g/cm3', 1.0) + + sph = openmc.Sphere(r=100.0, boundary_type='reflective') + cell = openmc.Cell(fill=m, region=-sph) + model.geometry = openmc.Geometry([cell]) + + model.settings.run_mode = 'fixed source' + model.settings.source = openmc.IndependentSource( + particle='photon', + energy=openmc.stats.Discrete([source_energy], [1.0]), + ) + model.settings.particles = 100 + model.settings.batches = 10 + model.settings.cutoff = {'energy_photon': cutoff_energy} + + tally_flux = openmc.Tally(name='flux') + tally_flux.filters = [ + openmc.EnergyFilter([0.0, cutoff_energy, source_energy]), + openmc.ParticleFilter(['photon']) + ] + tally_flux.scores = ['flux'] + tally_heating = openmc.Tally(name='heating') + tally_heating.scores = ['heating'] + model.tallies = openmc.Tallies([tally_flux, tally_heating]) + + return model + + +def test_energy_cutoff(run_in_tmpdir): + # Pick a random cutoff energy between 1 and 5 keV + cutoff_energy = uniform(1e3, 5e3) + + # Pick a random source energy some factor higher than cutoff energy + source_energy = uniform(10, 20) * cutoff_energy + + # Create model and run simulation + model = inf_medium_model(cutoff_energy, source_energy) + statepoint_path = model.run() + + # Get resulting flux and heating values + with openmc.StatePoint(statepoint_path) as sp: + flux = sp.get_tally(name='flux').mean.ravel() + heating = sp.get_tally(name='heating').mean.ravel() + + # There should be no flux below the cutoff energy (first bin in the tally) + assert flux[0] == 0.0 + assert flux[1] > 0.0 + + # Despite killing particles below the cutoff, the total heating should be + # equal to the source energy + assert heating[0] == pytest.approx(source_energy) diff --git a/tests/unit_tests/test_filter_mesh.py b/tests/unit_tests/test_filter_mesh.py new file mode 100644 index 00000000000..a8bd4996dd7 --- /dev/null +++ b/tests/unit_tests/test_filter_mesh.py @@ -0,0 +1,261 @@ +import math + +import numpy as np +import pytest +from uncertainties import unumpy + +import openmc + + +def test_spherical_mesh_estimators(run_in_tmpdir): + """Test that collision/tracklength estimators agree for SphericalMesh""" + + mat = openmc.Material() + mat.add_nuclide('U235', 1.0) + mat.set_density('g/cm3', 10.0) + + sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') + cell = openmc.Cell(fill=mat, region=-sphere) + model = openmc.Model() + model.geometry = openmc.Geometry([cell]) + model.settings.particles = 1_000 + model.settings.inactive = 10 + model.settings.batches = 20 + + sph_mesh = openmc.SphericalMesh( + r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3) + ) + tally1 = openmc.Tally() + tally1.filters = [openmc.MeshFilter(sph_mesh)] + tally1.scores = ['flux'] + tally1.estimator = 'collision' + + sph_mesh = openmc.SphericalMesh( + r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3) + ) + tally2 = openmc.Tally() + tally2.filters = [openmc.MeshFilter(sph_mesh)] + tally2.scores = ['flux'] + tally2.estimator = 'tracklength' + + model.tallies = openmc.Tallies([tally1, tally2]) + + # Run OpenMC + sp_filename = model.run() + + # Get radial flux distribution + with openmc.StatePoint(sp_filename) as sp: + flux_collision = sp.tallies[tally1.id].mean.ravel() + flux_collision_unc = sp.tallies[tally1.id].std_dev.ravel() + flux_tracklength = sp.tallies[tally2.id].mean.ravel() + flux_tracklength_unc = sp.tallies[tally2.id].std_dev.ravel() + + # Construct arrays with uncertainties + collision = unumpy.uarray(flux_collision, flux_collision_unc) + tracklength = unumpy.uarray(flux_tracklength, flux_tracklength_unc) + delta = collision - tracklength + + # Check that difference is within uncertainty + diff = unumpy.nominal_values(delta) + std_dev = unumpy.std_devs(delta) + assert np.all(diff < 3*std_dev) + + +def test_cylindrical_mesh_estimators(run_in_tmpdir): + """Test that collision/tracklength estimators agree for CylindricalMesh""" + + mat = openmc.Material() + mat.add_nuclide('U235', 1.0) + mat.set_density('g/cm3', 10.0) + + cyl = openmc.model.RightCircularCylinder((0., 0., -5.), 10., 10.0, + boundary_type='vacuum') + cell = openmc.Cell(fill=mat, region=-cyl) + model = openmc.Model() + model.geometry = openmc.Geometry([cell]) + model.settings.particles = 1_000 + model.settings.inactive = 10 + model.settings.batches = 20 + + cyl_mesh = openmc.CylindricalMesh( + r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3), + z_grid=[-5., 5.] + ) + tally1 = openmc.Tally() + tally1.filters = [openmc.MeshFilter(cyl_mesh)] + tally1.scores = ['flux'] + tally1.estimator = 'collision' + + cyl_mesh = openmc.CylindricalMesh( + r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3), + z_grid=[-5., 5.] + ) + tally2 = openmc.Tally() + tally2.filters = [openmc.MeshFilter(cyl_mesh)] + tally2.scores = ['flux'] + tally2.estimator = 'tracklength' + + model.tallies = openmc.Tallies([tally1, tally2]) + + # Run OpenMC + sp_filename = model.run() + + # Get radial flux distribution + with openmc.StatePoint(sp_filename) as sp: + flux_collision = sp.tallies[tally1.id].mean.ravel() + flux_collision_unc = sp.tallies[tally1.id].std_dev.ravel() + flux_tracklength = sp.tallies[tally2.id].mean.ravel() + flux_tracklength_unc = sp.tallies[tally2.id].std_dev.ravel() + + # Construct arrays with uncertainties + collision = unumpy.uarray(flux_collision, flux_collision_unc) + tracklength = unumpy.uarray(flux_tracklength, flux_tracklength_unc) + delta = collision - tracklength + + # Check that difference is within uncertainty + diff = unumpy.nominal_values(delta) + std_dev = unumpy.std_devs(delta) + assert np.all(diff < 3*std_dev) + + +@pytest.mark.parametrize("scale", [0.1, 1.0, 1e2, 1e4, 1e5]) +def test_cylindrical_mesh_coincident(scale, run_in_tmpdir): + """Test for cylindrical mesh boundary being coincident with a cell boundary""" + + fuel = openmc.Material() + fuel.add_nuclide('U235', 1.) + fuel.set_density('g/cm3', 4.5) + + zcyl = openmc.ZCylinder(r=1.25*scale) + box = openmc.model.RectangularPrism(4*scale, 4*scale, boundary_type='reflective') + cell1 = openmc.Cell(fill=fuel, region=-zcyl) + cell2 = openmc.Cell(fill=None, region=+zcyl & -box) + model = openmc.Model() + model.geometry = openmc.Geometry([cell1, cell2]) + + model.settings.particles = 100 + model.settings.batches = 10 + model.settings.inactive = 0 + + cyl_mesh = openmc.CylindricalMesh( + r_grid=[0., 1.25*scale], + phi_grid=[0., 2*math.pi], + z_grid=[-1e10, 1e10] + ) + cyl_mesh_filter = openmc.MeshFilter(cyl_mesh) + cell_filter = openmc.CellFilter([cell1]) + + tally1 = openmc.Tally() + tally1.filters = [cyl_mesh_filter] + tally1.scores = ['flux'] + tally2 = openmc.Tally() + tally2.filters = [cell_filter] + tally2.scores = ['flux'] + model.tallies = openmc.Tallies([tally1, tally2]) + + # Run OpenMC + sp_filename = model.run() + + # Get flux for each of the two tallies + with openmc.StatePoint(sp_filename) as sp: + t1 = sp.tallies[tally1.id] + t2 = sp.tallies[tally2.id] + mean1 = t1.mean.ravel()[0] + mean2 = t2.mean.ravel()[0] + + # The two tallies should be exactly the same + assert mean1 == pytest.approx(mean2) + + +@pytest.mark.parametrize("scale", [0.1, 1.0, 1e2, 1e4, 1e5]) +def test_spherical_mesh_coincident(scale, run_in_tmpdir): + """Test for spherical mesh boundary being coincident with a cell boundary""" + + fuel = openmc.Material() + fuel.add_nuclide('U235', 1.) + fuel.set_density('g/cm3', 4.5) + + sph = openmc.Sphere(r=1.25*scale) + rcc = openmc.model.RectangularParallelepiped( + -2*scale, 2*scale, -2*scale, 2*scale, -2*scale, 2*scale, + boundary_type='reflective') + cell1 = openmc.Cell(fill=fuel, region=-sph) + cell2 = openmc.Cell(fill=None, region=+sph & -rcc) + model = openmc.Model() + model.geometry = openmc.Geometry([cell1, cell2]) + + model.settings.particles = 100 + model.settings.batches = 10 + model.settings.inactive = 0 + + sph_mesh = openmc.SphericalMesh( + r_grid=[0., 1.25*scale], + phi_grid=[0., 2*math.pi], + theta_grid=[0., math.pi], + ) + + sph_mesh_filter = openmc.MeshFilter(sph_mesh) + cell_filter = openmc.CellFilter([cell1]) + + tally1 = openmc.Tally() + tally1.filters = [sph_mesh_filter] + tally1.scores = ['flux'] + tally2 = openmc.Tally() + tally2.filters = [cell_filter] + tally2.scores = ['flux'] + model.tallies = openmc.Tallies([tally1, tally2]) + + # Run OpenMC + sp_filename = model.run() + + # Get flux for each of the two tallies + with openmc.StatePoint(sp_filename) as sp: + t1 = sp.tallies[tally1.id] + t2 = sp.tallies[tally2.id] + mean1 = t1.mean.ravel()[0] + mean2 = t2.mean.ravel()[0] + + # The two tallies should be exactly the same + assert mean1 == pytest.approx(mean2) + + +def test_get_reshaped_data(run_in_tmpdir): + """Test that expanding MeshFilter dimensions works as expected""" + + mat = openmc.Material() + mat.add_nuclide('U235', 1.0) + mat.set_density('g/cm3', 10.0) + + sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') + cell = openmc.Cell(fill=mat, region=-sphere) + model = openmc.Model() + model.geometry = openmc.Geometry([cell]) + model.settings.particles = 1_000 + model.settings.inactive = 10 + model.settings.batches = 20 + + sph_mesh = openmc.SphericalMesh( + r_grid=np.linspace(0.0, 5.0**3, 20)**(1/3), + theta_grid=np.linspace(0, math.pi, 4), + phi_grid=np.linspace(0, 2*math.pi, 3) + ) + tally1 = openmc.Tally() + efilter = openmc.EnergyFilter([0, 1e5, 1e8]) + meshfilter = openmc.MeshFilter(sph_mesh) + assert meshfilter.shape == (19, 3, 2) + tally1.filters = [efilter, meshfilter] + tally1.scores = ['flux'] + + model.tallies = openmc.Tallies([tally1]) + + # Run OpenMC + sp_filename = model.run() + + # Get flux tally as reshaped data + with openmc.StatePoint(sp_filename) as sp: + t1 = sp.tallies[tally1.id] + data1 = t1.get_reshaped_data() + data2 = t1.get_reshaped_data(expand_dims=True) + + assert data1.shape == (2, 19*3*2, 1, 1) + assert data2.shape == (2, 19, 3, 2, 1, 1) diff --git a/tests/unit_tests/test_filter_meshborn.py b/tests/unit_tests/test_filter_meshborn.py new file mode 100644 index 00000000000..62fa1174e75 --- /dev/null +++ b/tests/unit_tests/test_filter_meshborn.py @@ -0,0 +1,116 @@ +"""Test the meshborn filter using a fixed source calculation on a H1 sphere. + +""" + +import numpy as np +from uncertainties import unumpy +import openmc +import pytest + + +@pytest.fixture +def model(): + """Sphere of H1 with one hemisphere containing the source (x>0) and one + hemisphere with no source (x<0). + + """ + openmc.reset_auto_ids() + model = openmc.Model() + + # Materials + h1 = openmc.Material() + h1.add_nuclide("H1", 1.0) + h1.set_density("g/cm3", 1.0) + model.materials = openmc.Materials([h1]) + + # Core geometry + r = 10.0 + sphere = openmc.Sphere(r=r, boundary_type="reflective") + core = openmc.Cell(fill=h1, region=-sphere) + model.geometry = openmc.Geometry([core]) + + # Settings + model.settings.run_mode = 'fixed source' + model.settings.particles = 2000 + model.settings.batches = 8 + + distribution = openmc.stats.Box((0., -r, -r), (r, r, r)) + model.settings.source = openmc.IndependentSource(space=distribution) + + # ============================================================================= + # Tallies + # ============================================================================= + + mesh = openmc.RegularMesh() + mesh.dimension = (2, 2, 1) + mesh.lower_left = (-r, -r, -r) + mesh.upper_right = (r, r, r) + + f = openmc.MeshBornFilter(mesh) + t_1 = openmc.Tally(name="scatter-collision") + t_1.filters = [f] + t_1.scores = ["scatter"] + t_1.estimator = "collision" + + t_2 = openmc.Tally(name="scatter-tracklength") + t_2.filters = [f] + t_2.scores = ["scatter"] + t_2.estimator = "tracklength" + + model.tallies = [t_1, t_2] + + return model + + +def test_estimator_consistency(model, run_in_tmpdir): + """Test that resuts obtained from a tracklength estimator are + consistent with results obtained from a collision estimator. + + """ + # Run OpenMC + sp_filename = model.run() + + # Get radial flux distribution + with openmc.StatePoint(sp_filename) as sp: + scatter_collision = sp.get_tally(name="scatter-collision").mean.ravel() + scatter_collision_std_dev = sp.get_tally(name="scatter-collision").std_dev.ravel() + scatter_tracklength = sp.get_tally(name="scatter-tracklength").mean.ravel() + scatter_tracklength_std_dev = sp.get_tally(name="scatter-tracklength").std_dev.ravel() + + collision = unumpy.uarray(scatter_collision, scatter_collision_std_dev) + tracklength = unumpy.uarray(scatter_tracklength, scatter_tracklength_std_dev) + delta = abs(collision - tracklength) + + diff = unumpy.nominal_values(delta) + std_dev = unumpy.std_devs(delta) + assert np.all(diff <= 3 * std_dev) + + +def test_xml_serialization(): + """Test xml serialization of the meshborn filter.""" + openmc.reset_auto_ids() + + mesh = openmc.RegularMesh() + mesh.dimension = (1, 1, 1) + mesh.lower_left = (0.0, 0.0, 0.0) + mesh.upper_right = (1.0, 1.0, 1.0) + + filter = openmc.MeshBornFilter(mesh) + filter.translation = (2.0, 2.0, 2.0) + assert filter.mesh.id == 1 + assert filter.mesh.dimension == (1, 1, 1) + assert filter.mesh.lower_left == (0.0, 0.0, 0.0) + assert filter.mesh.upper_right == (1.0, 1.0, 1.0) + + repr(filter) + + elem = filter.to_xml_element() + assert elem.tag == 'filter' + assert elem.attrib['type'] == 'meshborn' + assert elem[0].text == "1" + assert elem.get("translation") == "2.0 2.0 2.0" + + meshes = {1: mesh} + new_filter = openmc.Filter.from_xml_element(elem, meshes=meshes) + assert new_filter.bins == filter.bins + np.testing.assert_equal(new_filter.translation, [2.0, 2.0, 2.0]) diff --git a/tests/unit_tests/test_filters.py b/tests/unit_tests/test_filters.py index ea94a600e3f..55bb62075bd 100644 --- a/tests/unit_tests/test_filters.py +++ b/tests/unit_tests/test_filters.py @@ -1,7 +1,6 @@ -from math import sqrt, pi - +import numpy as np import openmc -from pytest import fixture, approx +from pytest import fixture, approx, raises @fixture(scope='module') @@ -11,14 +10,14 @@ def box_model(): m.add_nuclide('U235', 1.0) m.set_density('g/cm3', 1.0) - box = openmc.model.rectangular_prism(10., 10., boundary_type='vacuum') - c = openmc.Cell(fill=m, region=box) + box = openmc.model.RectangularPrism(10., 10., boundary_type='vacuum') + c = openmc.Cell(fill=m, region=-box) model.geometry.root_universe = openmc.Universe(cells=[c]) model.settings.particles = 100 model.settings.batches = 10 model.settings.inactive = 0 - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) return model @@ -38,6 +37,11 @@ def test_cell_instance(): assert all(x == c1.id for x in bins[:6:2]) assert all(x == c2.id for x in bins[6::2]) + # from_xml_element() + new_f = openmc.Filter.from_xml_element(elem) + assert new_f.id == f.id + assert np.all(new_f.bins == f.bins) + # get_pandas_dataframe() df = f.get_pandas_dataframe(f.num_bins, 1) cells = df['cellinstance', 'cell'] @@ -61,6 +65,11 @@ def test_collision(): assert elem.tag == 'filter' assert elem.attrib['type'] == 'collision' + # from_xml_element() + new_f = openmc.Filter.from_xml_element(elem) + assert new_f.id == f.id + assert np.all(new_f.bins == f.bins) + def test_legendre(): n = 5 @@ -79,6 +88,11 @@ def test_legendre(): assert elem.attrib['type'] == 'legendre' assert elem.find('order').text == str(n) + # from_xml_element() + new_f = openmc.Filter.from_xml_element(elem) + assert new_f.id == f.id + assert new_f.bins, f.bins + def test_spatial_legendre(): n = 5 @@ -102,6 +116,12 @@ def test_spatial_legendre(): assert elem.find('order').text == str(n) assert elem.find('axis').text == str(axis) + # from_xml_element() + new_f = openmc.Filter.from_xml_element(elem) + assert new_f.id == f.id + assert new_f.order == f.order + assert new_f.axis == f.axis + def test_spherical_harmonics(): n = 3 @@ -122,6 +142,12 @@ def test_spherical_harmonics(): assert elem.attrib['cosine'] == f.cosine assert elem.find('order').text == str(n) + # from_xml_element() + new_f = openmc.Filter.from_xml_element(elem) + assert new_f.id == f.id + assert new_f.order == f.order + assert new_f.cosine == f.cosine + def test_zernike(): n = 4 @@ -140,6 +166,12 @@ def test_zernike(): assert elem.attrib['type'] == 'zernike' assert elem.find('order').text == str(n) + # from_xml_element() + new_f = openmc.Filter.from_xml_element(elem) + for attr in ('id', 'order', 'x', 'y', 'r'): + assert getattr(new_f, attr) == getattr(f, attr) + + def test_zernike_radial(): n = 4 f = openmc.ZernikeRadialFilter(n, 0., 0., 1.) @@ -157,6 +189,11 @@ def test_zernike_radial(): assert elem.attrib['type'] == 'zernikeradial' assert elem.find('order').text == str(n) + # from_xml_element() + new_f = openmc.Filter.from_xml_element(elem) + for attr in ('id', 'order', 'x', 'y', 'r'): + assert getattr(new_f, attr) == getattr(f, attr) + def test_first_moment(run_in_tmpdir, box_model): plain_tally = openmc.Tally() @@ -203,3 +240,57 @@ def test_first_moment(run_in_tmpdir, box_model): assert first_score(sph_scat_tally) == scatter assert first_score(sph_flux_tally) == approx(flux) assert first_score(zernike_tally) == approx(scatter) + + +def test_energy(): + f = openmc.EnergyFilter.from_group_structure('CCFE-709') + assert f.bins.shape == (709, 2) + assert len(f.values) == 710 + + +def test_energyfilter_error_handling(): + with raises(ValueError): + openmc.EnergyFilter([1e6]) + + +def test_lethargy_bin_width(): + f = openmc.EnergyFilter.from_group_structure('VITAMIN-J-175') + assert len(f.lethargy_bin_width) == 175 + energy_bins = openmc.mgxs.GROUP_STRUCTURES['VITAMIN-J-175'] + assert f.lethargy_bin_width[0] == np.log10(energy_bins[1]/energy_bins[0]) + assert f.lethargy_bin_width[-1] == np.log10(energy_bins[-1]/energy_bins[-2]) + + +def test_energyfunc(): + f = openmc.EnergyFunctionFilter( + [0.0, 10.0, 2.0e3, 1.0e6, 20.0e6], + [1.0, 0.9, 0.8, 0.7, 0.6], + 'histogram' + ) + + # Make sure XML roundtrip works + elem = f.to_xml_element() + new_f = openmc.EnergyFunctionFilter.from_xml_element(elem) + np.testing.assert_allclose(f.energy, new_f.energy) + np.testing.assert_allclose(f.y, new_f.y) + assert f.interpolation == new_f.interpolation + + +def test_tabular_from_energyfilter(): + efilter = openmc.EnergyFilter([0.0, 10.0, 20.0, 25.0]) + tab = efilter.get_tabular(values=[5, 10, 10]) + + assert tab.x.tolist() == [0.0, 10.0, 20.0, 25.0] + + # combination of different values passed into get_tabular and different + # width energy bins results in a doubling value for each p value + assert tab.p.tolist() == [0.02, 0.04, 0.08, 0.0] + + # distribution should integrate to unity + assert tab.integral() == approx(1.0) + + # 'histogram' is the default + assert tab.interpolation == 'histogram' + + tab = efilter.get_tabular(values=np.array([10, 10, 5]), interpolation='linear-linear') + assert tab.interpolation == 'linear-linear' diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index 64a97e0a16d..6cc577c820c 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -1,4 +1,5 @@ -import xml.etree.ElementTree as ET +import lxml.etree as ET +from pathlib import Path import numpy as np import openmc @@ -19,7 +20,7 @@ def test_volume(run_in_tmpdir, uo2): model.settings.particles = 100 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) ll, ur = model.geometry.bounding_box assert ll == pytest.approx((-outer.r, -outer.r, -outer.r)) @@ -159,12 +160,13 @@ def test_get_by_name(): m2 = openmc.Material(name='Zirconium') m2.add_element('Zr', 1.0) - c1 = openmc.Cell(fill=m1, name='cell1') + s1 = openmc.Sphere(name='surface1') + c1 = openmc.Cell(fill=m1, region=-s1, name='cell1') u1 = openmc.Universe(name='Zircaloy universe', cells=[c1]) - cyl = openmc.ZCylinder() - c2 = openmc.Cell(fill=u1, region=-cyl, name='cell2') - c3 = openmc.Cell(fill=m2, region=+cyl, name='Cell3') + s2 = openmc.ZCylinder(name='surface2') + c2 = openmc.Cell(fill=u1, region=-s2, name='cell2') + c3 = openmc.Cell(fill=m2, region=+s2, name='Cell3') root = openmc.Universe(name='root Universe', cells=[c2, c3]) geom = openmc.Geometry(root) @@ -177,6 +179,13 @@ def test_get_by_name(): mats = geom.get_materials_by_name('zirconium', True, True) assert not mats + surfaces = set(geom.get_surfaces_by_name('surface')) + assert not surfaces ^ {s1, s2} + surfaces = set(geom.get_surfaces_by_name('Surface2', False, True)) + assert not surfaces ^ {s2} + surfaces = geom.get_surfaces_by_name('Surface2', True, True) + assert not surfaces + cells = set(geom.get_cells_by_name('cell')) assert not cells ^ {c1, c2, c3} cells = set(geom.get_cells_by_name('cell', True)) @@ -204,27 +213,27 @@ def test_get_by_name(): def test_hex_prism(): - hex_prism = openmc.model.hexagonal_prism(edge_length=5.0, - origin=(0.0, 0.0), - orientation='y') + hex_prism = openmc.model.HexagonalPrism(edge_length=5.0, + origin=(0.0, 0.0), + orientation='y') # clear checks - assert (0.0, 0.0, 0.0) in hex_prism - assert (10.0, 10.0, 10.0) not in hex_prism + assert (0.0, 0.0, 0.0) in -hex_prism + assert (10.0, 10.0, 10.0) not in -hex_prism # edge checks - assert (0.0, 5.01, 0.0) not in hex_prism - assert (0.0, 4.99, 0.0) in hex_prism + assert (0.0, 5.01, 0.0) not in -hex_prism + assert (0.0, 4.99, 0.0) in -hex_prism - rounded_hex_prism = openmc.model.hexagonal_prism(edge_length=5.0, - origin=(0.0, 0.0), - orientation='y', - corner_radius=1.0) + rounded_hex_prism = openmc.model.HexagonalPrism(edge_length=5.0, + origin=(0.0, 0.0), + orientation='y', + corner_radius=1.0) # clear checks - assert (0.0, 0.0, 0.0) in rounded_hex_prism - assert (10.0, 10.0, 10.0) not in rounded_hex_prism + assert (0.0, 0.0, 0.0) in -rounded_hex_prism + assert (10.0, 10.0, 10.0) not in -rounded_hex_prism # edge checks - assert (0.0, 5.01, 0.0) not in rounded_hex_prism - assert (0.0, 4.99, 0.0) not in rounded_hex_prism + assert (0.0, 5.01, 0.0) not in -rounded_hex_prism + assert (0.0, 4.99, 0.0) not in -rounded_hex_prism def test_get_lattice_by_name(cell_with_lattice): @@ -274,7 +283,22 @@ def test_from_xml(run_in_tmpdir, mixed_lattice_model): # Export model mixed_lattice_model.export_to_xml() - # Import geometry + mats_from_xml = openmc.Materials.from_xml('materials.xml') + # checking string a Path are both acceptable + for path in ['geometry.xml', Path('geometry.xml')]: + for materials in [mats_from_xml, 'materials.xml']: + # Import geometry from file + geom = openmc.Geometry.from_xml(path=path, materials=materials) + assert isinstance(geom, openmc.Geometry) + ll, ur = geom.bounding_box + assert ll == pytest.approx((-6.0, -6.0, -np.inf)) + assert ur == pytest.approx((6.0, 6.0, np.inf)) + + with pytest.raises(TypeError) as excinfo: + geom = openmc.Geometry.from_xml(path='geometry.xml', materials=None) + assert 'Unable to set "materials" to "None"' in str(excinfo.value) + + # checking that the default args also work geom = openmc.Geometry.from_xml() assert isinstance(geom, openmc.Geometry) ll, ur = geom.bounding_box @@ -338,13 +362,44 @@ def get_cyl_cell(r1, r2, z1, z2, fill): clad = get_cyl_cell(r1, r2, z1, z2, m2) water = get_cyl_cell(r2, r3, z1, z2, m3) root = openmc.Universe(cells=[fuel, clad, water]) - geom = openmc.Geometry(root) - + geom = openmc.Geometry(root=root, merge_surfaces=True, surface_precision=11) + assert geom.merge_surfaces is True + geom.merge_surfaces = False + assert geom.merge_surfaces is False + assert geom.surface_precision == 11 + geom.surface_precision = 10 + assert geom.surface_precision == 10 + model = openmc.model.Model(geometry=geom, + materials=openmc.Materials([m1, m2, m3])) + # There should be 6 redundant surfaces in this geometry - n_redundant_surfs = len(geom.get_redundant_surfaces().keys()) + n_redundant_surfs = len(geom.remove_redundant_surfaces().keys()) assert n_redundant_surfs == 6 - # Remove redundant surfaces - geom.remove_redundant_surfaces() # There should be 0 remaining redundant surfaces - n_redundant_surfs = len(geom.get_redundant_surfaces().keys()) + n_redundant_surfs = len(geom.remove_redundant_surfaces().keys()) assert n_redundant_surfs == 0 + +def test_get_all_nuclides(): + m1 = openmc.Material() + m1.add_nuclide('Fe56', 1) + m1.add_nuclide('Be9', 1) + m2 = openmc.Material() + m2.add_nuclide('Be9', 1) + s = openmc.Sphere() + c1 = openmc.Cell(fill=m1, region=-s) + c2 = openmc.Cell(fill=m2, region=+s) + geom = openmc.Geometry([c1, c2]) + assert geom.get_all_nuclides() == ['Be9', 'Fe56'] + + +def test_redundant_surfaces(): + # Make sure boundary condition is accounted for + s1 = openmc.Sphere(r=5.0) + s2 = openmc.Sphere(r=5.0, boundary_type="vacuum") + c1 = openmc.Cell(region=-s1) + c2 = openmc.Cell(region=+s1) + u_lower = openmc.Universe(cells=[c1, c2]) + c3 = openmc.Cell(fill=u_lower, region=-s2) + geom = openmc.Geometry([c3]) + redundant_surfs = geom.remove_redundant_surfaces() + assert len(redundant_surfs) == 0 diff --git a/tests/unit_tests/test_heating_by_nuclide.py b/tests/unit_tests/test_heating_by_nuclide.py new file mode 100644 index 00000000000..b34d7dd9431 --- /dev/null +++ b/tests/unit_tests/test_heating_by_nuclide.py @@ -0,0 +1,57 @@ +import openmc +import pytest + +from tests.testing_harness import config + + +@pytest.fixture +def model(): + # Create simple sphere model + model = openmc.Model() + mat = openmc.Material() + mat.add_nuclide('U235', 1.0) + mat.add_nuclide('H1', 1.0) + mat.set_density('g/cm3', 5.0) + sph = openmc.Sphere(r=10.0, boundary_type='vacuum') + cell = openmc.Cell(fill=mat, region=-sph) + model.geometry = openmc.Geometry([cell]) + model.settings.particles = 1000 + model.settings.inactive = 0 + model.settings.batches = 5 + model.settings.photon_transport = True + + # Add two tallies, one with heating by nuclide and one with total heating + particle_filter = openmc.ParticleFilter(['neutron', 'photon']) + heating_by_nuclide = openmc.Tally() + heating_by_nuclide.filters = [particle_filter] + heating_by_nuclide.nuclides = ['U235', 'H1'] + heating_by_nuclide.scores = ['heating'] + + heating_total = openmc.Tally() + heating_total.filters = [particle_filter] + heating_total.scores = ['heating'] + model.tallies.extend([heating_by_nuclide, heating_total]) + + return model + + +def test_heating_by_nuclide(model, run_in_tmpdir): + # If running in MPI mode, setup proper keyword arguments for run() + kwargs = {'openmc_exec': config['exe']} + if config['mpi']: + kwargs['mpi_args'] = [config['mpiexec'], '-n', config['mpi_np']] + sp_path = model.run(**kwargs) + + # Get tallies from resulting statepoint + with openmc.StatePoint(sp_path) as sp: + heating_by_nuclide = sp.tallies[model.tallies[0].id] + heating_total = sp.tallies[model.tallies[1].id] + + for particle in heating_by_nuclide.filters[0].bins: + # Get slice of each tally corresponding to a single particle + kwargs = {'filters': [openmc.ParticleFilter], 'filter_bins': [(particle,)]} + particle_slice_by_nuclide = heating_by_nuclide.get_values(**kwargs) + particle_slice_total = heating_total.get_values(**kwargs) + + # Summing over nuclides should equal total + assert particle_slice_by_nuclide.sum() == pytest.approx(particle_slice_total.sum()) diff --git a/tests/unit_tests/test_lattice.py b/tests/unit_tests/test_lattice.py index 31433af7dc3..6fa32760e65 100644 --- a/tests/unit_tests/test_lattice.py +++ b/tests/unit_tests/test_lattice.py @@ -1,6 +1,6 @@ from math import sqrt -import xml.etree.ElementTree as ET +import lxml.etree as ET import openmc import pytest @@ -157,11 +157,11 @@ def hlat3(pincell1, pincell2, uo2, water, zr): def test_get_nuclides(rlat2, rlat3, hlat2, hlat3): for lat in (rlat2, hlat2): - nucs = rlat2.get_nuclides() + nucs = lat.get_nuclides() assert sorted(nucs) == ['H1', 'O16', 'U235', 'Zr90', 'Zr91', 'Zr92', 'Zr94', 'Zr96'] for lat in (rlat3, hlat3): - nucs = rlat3.get_nuclides() + nucs = lat.get_nuclides() assert sorted(nucs) == ['H1', 'H2', 'O16', 'U235', 'Zr90', 'Zr91', 'Zr92', 'Zr94', 'Zr96'] @@ -360,4 +360,20 @@ def test_show_indices(): lines = openmc.HexLattice.show_indices(i).split('\n') assert len(lines) == 4*i - 3 lines_x = openmc.HexLattice.show_indices(i, 'x').split('\n') - assert len(lines) == 4*i - 3 + assert len(lines_x) == 4*i - 3 + + +def test_unset_universes(): + elem = ET.Element("dummy") + + lattice = openmc.RectLattice() + lattice.lower_left = (-1., -1.) + lattice.pitch = (1., 1.) + with pytest.raises(ValueError): + lattice.create_xml_subelement(elem) + + hex_lattice = openmc.HexLattice() + hex_lattice.center = (0., 0.) + hex_lattice.pitch = (1.,) + with pytest.raises(ValueError): + hex_lattice.create_xml_subelement(elem) diff --git a/tests/unit_tests/test_lattice_discretization.py b/tests/unit_tests/test_lattice_discretization.py index b2766572d78..c7779ea8bf5 100644 --- a/tests/unit_tests/test_lattice_discretization.py +++ b/tests/unit_tests/test_lattice_discretization.py @@ -1,8 +1,3 @@ -from math import sqrt -import xml.etree.ElementTree as ET - -import openmc -import pytest from tests.unit_tests.test_lattice import zr, pincell1, pincell2, rlat2 @@ -39,8 +34,8 @@ def test_discretization_clone_only_some_materials(rlat2): fuel1 = next(iter(rlat_clone.get_universe((0, 0)).cells.values())).fill rlat_clone.discretize(materials_to_clone=[fuel1]) - assert next(reversed(rlat_clone.get_universe((0, 0)).cells.values())).fill\ - == next(reversed(rlat_clone.get_universe((1, 0)).cells.values())).fill + assert next(reversed(list(rlat_clone.get_universe((0, 0)).cells.values()))).fill\ + == next(reversed(list(rlat_clone.get_universe((1, 0)).cells.values()))).fill assert next(iter(rlat_clone.get_universe((0, 0)).cells.values())).fill\ != next(iter(rlat_clone.get_universe((1, 0)).cells.values())).fill diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 87d4843c77f..009a9096831 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -1,4 +1,5 @@ from collections.abc import Mapping +from math import pi import os import numpy as np @@ -66,8 +67,10 @@ def uo2_trigger_model(): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( - [-0.5, -0.5, -1], [0.5, 0.5, 1], only_fissionable=True)) + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Box([-0.5, -0.5, -1], [0.5, 0.5, 1]), + constraints={'fissionable': True}, + ) model.settings.verbosity = 1 model.settings.keff_trigger = {'type': 'std_dev', 'threshold': 0.001} model.settings.trigger_active = True @@ -98,6 +101,21 @@ def lib_run(lib_simulation_init): openmc.lib.run() +@pytest.fixture(scope='module') +def pincell_model_w_univ(): + """Set up a model to test with and delete files when done""" + openmc.reset_auto_ids() + pincell = openmc.examples.pwr_pin_cell() + clad_univ = openmc.Universe(cells=[openmc.Cell(fill=pincell.materials[1])]) + pincell.geometry.root_universe.cells[2].fill = clad_univ + pincell.settings.verbosity = 1 + + # Write XML files in tmpdir + with cdtemp(): + pincell.export_to_xml() + yield + + def test_cell_mapping(lib_init): cells = openmc.lib.cells assert isinstance(cells, Mapping) @@ -111,10 +129,12 @@ def test_cell(lib_init): cell = openmc.lib.cells[1] assert isinstance(cell.fill, openmc.lib.Material) cell.fill = openmc.lib.materials[1] - assert str(cell) == 'Cell[0]' + assert str(cell) == '' assert cell.name == "Fuel" cell.name = "Not fuel" assert cell.name == "Not fuel" + assert cell.num_instances == 1 + def test_cell_temperature(lib_init): cell = openmc.lib.cells[1] @@ -124,6 +144,21 @@ def test_cell_temperature(lib_init): assert cell.get_temperature() == pytest.approx(200.0) +def test_properties_temperature(lib_init): + # Cell temperature should be 200 from above test + cell = openmc.lib.cells[1] + assert cell.get_temperature() == pytest.approx(200.0) + + # Export properties and change temperature + openmc.lib.export_properties('properties.h5') + cell.set_temperature(300.0) + assert cell.get_temperature() == pytest.approx(300.0) + + # Import properties and check that temperature is restored + openmc.lib.import_properties('properties.h5') + assert cell.get_temperature() == pytest.approx(200.0) + + def test_new_cell(lib_init): with pytest.raises(exc.AllocationError): openmc.lib.Cell(1) @@ -132,6 +167,13 @@ def test_new_cell(lib_init): assert len(openmc.lib.cells) == 5 +def test_properties_fail_cell(lib_init): + # The number of cells was changed in the previous test, so the properties + # file is no longer valid + with pytest.raises(exc.GeometryError, match="Number of cells"): + openmc.lib.import_properties("properties.h5") + + def test_material_mapping(lib_init): mats = openmc.lib.materials assert isinstance(mats, Mapping) @@ -162,11 +204,34 @@ def test_material(lib_init): assert sum(m.densities) == pytest.approx(rho) m.set_density(0.1, 'g/cm3') - assert m.density == pytest.approx(0.1) + assert m.get_density('g/cm3') == pytest.approx(0.1) assert m.name == "Hot borated water" m.name = "Not hot borated water" assert m.name == "Not hot borated water" + assert m.depletable == False + m.depletable = True + assert m.depletable == True + + +def test_properties_density(lib_init): + m = openmc.lib.materials[1] + orig_density = m.get_density('atom/b-cm') + orig_density_gpcc = m.get_density('g/cm3') + + # Export properties and change density + openmc.lib.export_properties('properties.h5') + m.set_density(orig_density_gpcc*2, 'g/cm3') + assert m.get_density() == pytest.approx(orig_density*2) + + # Import properties and check that density was restored + openmc.lib.import_properties('properties.h5') + assert m.get_density() == pytest.approx(orig_density) + + with pytest.raises(ValueError): + m.get_density('🥏') + + def test_material_add_nuclide(lib_init): m = openmc.lib.materials[3] m.add_nuclide('Xe135', 1e-12) @@ -182,6 +247,13 @@ def test_new_material(lib_init): assert len(openmc.lib.materials) == 5 +def test_properties_fail_material(lib_init): + # The number of materials was changed in the previous test, so the properties + # file is no longer valid + with pytest.raises(exc.GeometryError, match="Number of materials"): + openmc.lib.import_properties("properties.h5") + + def test_nuclide_mapping(lib_init): nucs = openmc.lib.nuclides assert isinstance(nucs, Mapping) @@ -197,6 +269,7 @@ def test_settings(lib_init): assert settings.generations_per_batch == 1 assert settings.particles == 100 assert settings.seed == 1 + assert settings.event_based is False settings.seed = 11 @@ -217,6 +290,11 @@ def test_energy_function_filter(lib_init): assert len(efunc.y) == 2 assert (efunc.y == [0.0, 2.0]).all() + # Default should be lin-lin + assert efunc.interpolation == 'linear-linear' + efunc.interpolation = 'histogram' + assert efunc.interpolation == 'histogram' + def test_tally(lib_init): t = openmc.lib.tallies[1] @@ -274,6 +352,20 @@ def test_new_tally(lib_init): assert len(openmc.lib.tallies) == 5 +def test_delete_tally(lib_init): + # delete tally 10 which was added in the above test + # check length is one less than before + del openmc.lib.tallies[10] + assert len(openmc.lib.tallies) == 4 + + +def test_invalid_tally_id(lib_init): + # attempt to access a tally that is guaranteed not to have a valid index + max_id = max(openmc.lib.tallies.keys()) + with pytest.raises(KeyError): + openmc.lib.tallies[max_id+1] + + def test_tally_activate(lib_simulation_init): t = openmc.lib.tallies[1] assert not t.active @@ -281,6 +373,19 @@ def test_tally_activate(lib_simulation_init): assert t.active +def test_tally_multiply_density(lib_simulation_init): + # multiply_density is True by default + t = openmc.lib.tallies[1] + assert t.multiply_density + + # Make sure setting multiply_density works + t.multiply_density = False + assert not t.multiply_density + + # Reset to True + t.multiply_density = True + + def test_tally_writable(lib_simulation_init): t = openmc.lib.tallies[1] assert t.writable @@ -463,6 +568,8 @@ def test_regular_mesh(lib_init): assert mesh.upper_right == pytest.approx(ur) assert mesh.width == pytest.approx(width) + np.testing.assert_allclose(mesh.volumes, 1.0) + meshes = openmc.lib.meshes assert isinstance(meshes, Mapping) assert len(meshes) == 1 @@ -482,6 +589,50 @@ def test_regular_mesh(lib_init): msf.translation = translation assert msf.translation == translation + # Test material volumes + mesh = openmc.lib.RegularMesh() + mesh.dimension = (2, 2, 1) + mesh.set_parameters(lower_left=(-0.63, -0.63, -0.5), + upper_right=(0.63, 0.63, 0.5)) + vols = mesh.material_volumes() + assert len(vols) == 4 + for elem_vols in vols: + assert sum(f[1] for f in elem_vols) == pytest.approx(1.26 * 1.26 / 4) + + # If the mesh extends beyond the boundaries of the model, the volumes should + # still be reported correctly + mesh.dimension = (1, 1, 1) + mesh.set_parameters(lower_left=(-1.0, -1.0, -0.5), + upper_right=(1.0, 1.0, 0.5)) + vols = mesh.material_volumes(100_000) + for elem_vols in vols: + assert sum(f[1] for f in elem_vols) == pytest.approx(1.26 * 1.26, 1e-2) + + +def test_regular_mesh_get_plot_bins(lib_init): + mesh: openmc.lib.RegularMesh = openmc.lib.meshes[2] + mesh.dimension = (2, 2, 1) + mesh.set_parameters(lower_left=(-1.0, -1.0, -0.5), + upper_right=(1.0, 1.0, 0.5)) + + # Get bins for a plot view covering only a single mesh bin + mesh_bins = mesh.get_plot_bins((-0.5, -0.5, 0.), (0.1, 0.1), 'xy', (20, 20)) + assert (mesh_bins == 0).all() + mesh_bins = mesh.get_plot_bins((0.5, 0.5, 0.), (0.1, 0.1), 'xy', (20, 20)) + assert (mesh_bins == 3).all() + + # Get bins for a plot view covering all mesh bins. Note that the y direction + # (first dimension) is flipped for plotting purposes + mesh_bins = mesh.get_plot_bins((0., 0., 0.), (2., 2.), 'xy', (20, 20)) + assert (mesh_bins[:10, :10] == 2).all() + assert (mesh_bins[:10, 10:] == 3).all() + assert (mesh_bins[10:, :10] == 0).all() + assert (mesh_bins[10:, 10:] == 1).all() + + # Get bins for a plot view outside of the mesh + mesh_bins = mesh.get_plot_bins((100., 100., 0.), (2., 2.), 'xy', (20, 20)) + assert (mesh_bins == -1).all() + def test_rectilinear_mesh(lib_init): mesh = openmc.lib.RectilinearMesh() @@ -497,12 +648,14 @@ def test_rectilinear_mesh(lib_init): for k, diff_z in enumerate(np.diff(z_grid)): assert np.all(mesh.width[i, j, k, :] == (10, 10, 10)) + np.testing.assert_allclose(mesh.volumes, 1000.0) + with pytest.raises(exc.AllocationError): mesh2 = openmc.lib.RectilinearMesh(mesh.id) meshes = openmc.lib.meshes assert isinstance(meshes, Mapping) - assert len(meshes) == 2 + assert len(meshes) == 3 mesh = meshes[mesh.id] assert isinstance(mesh, openmc.lib.RectilinearMesh) @@ -513,6 +666,124 @@ def test_rectilinear_mesh(lib_init): msf = openmc.lib.MeshSurfaceFilter(mesh) assert msf.mesh == mesh + # Test material volumes + mesh = openmc.lib.RectilinearMesh() + w = 1.26 + mesh.set_grid([-w/2, -w/4, w/2], [-w/2, -w/4, w/2], [-0.5, 0.5]) + + vols = mesh.material_volumes() + assert len(vols) == 4 + assert sum(f[1] for f in vols[0]) == pytest.approx(w/4 * w/4) + assert sum(f[1] for f in vols[1]) == pytest.approx(w/4 * 3*w/4) + assert sum(f[1] for f in vols[2]) == pytest.approx(3*w/4 * w/4) + assert sum(f[1] for f in vols[3]) == pytest.approx(3*w/4 * 3*w/4) + + +def test_cylindrical_mesh(lib_init): + deg2rad = lambda deg: deg*pi/180 + mesh = openmc.lib.CylindricalMesh() + r_grid = [0., 5., 10.] + phi_grid = np.radians([0., 10., 20.]) + z_grid = [10., 20., 30.] + mesh.set_grid(r_grid, phi_grid, z_grid) + assert np.all(mesh.lower_left == (0., 0., 10.)) + assert np.all(mesh.upper_right == (10., deg2rad(20.), 30.)) + assert np.all(mesh.dimension == (2, 2, 2)) + for i, _ in enumerate(np.diff(r_grid)): + for j, _ in enumerate(np.diff(phi_grid)): + for k, _ in enumerate(np.diff(z_grid)): + assert np.allclose(mesh.width[i, j, k, :], (5, deg2rad(10), 10)) + + np.testing.assert_allclose(mesh.volumes[::2], 10/360 * pi * 5**2 * 10) + np.testing.assert_allclose(mesh.volumes[1::2], 10/360 * pi * (10**2 - 5**2) * 10) + + with pytest.raises(exc.AllocationError): + mesh2 = openmc.lib.CylindricalMesh(mesh.id) + + meshes = openmc.lib.meshes + assert isinstance(meshes, Mapping) + assert len(meshes) == 5 + + mesh = meshes[mesh.id] + assert isinstance(mesh, openmc.lib.CylindricalMesh) + + mf = openmc.lib.MeshFilter(mesh) + assert mf.mesh == mesh + + msf = openmc.lib.MeshSurfaceFilter(mesh) + assert msf.mesh == mesh + + # Test material volumes + mesh = openmc.lib.CylindricalMesh() + r_grid = (0., 0.25, 0.5) + phi_grid = np.linspace(0., 2.0*pi, 4) + z_grid = (-0.5, 0.5) + mesh.set_grid(r_grid, phi_grid, z_grid) + + vols = mesh.material_volumes() + assert len(vols) == 6 + for i in range(0, 6, 2): + assert sum(f[1] for f in vols[i]) == pytest.approx(pi * 0.25**2 / 3) + for i in range(1, 6, 2): + assert sum(f[1] for f in vols[i]) == pytest.approx(pi * (0.5**2 - 0.25**2) / 3) + + +def test_spherical_mesh(lib_init): + deg2rad = lambda deg: deg*np.pi/180 + mesh = openmc.lib.SphericalMesh() + r_grid = [0., 5., 10.] + theta_grid = np.radians([0., 10., 20.]) + phi_grid = np.radians([10., 20., 30.]) + mesh.set_grid(r_grid, theta_grid, phi_grid) + assert np.all(mesh.lower_left == (0., 0., deg2rad(10.))) + assert np.all(mesh.upper_right == (10., deg2rad(20.), deg2rad(30.))) + assert np.all(mesh.dimension == (2, 2, 2)) + for i, _ in enumerate(np.diff(r_grid)): + for j, _ in enumerate(np.diff(theta_grid)): + for k, _ in enumerate(np.diff(phi_grid)): + assert np.allclose(mesh.width[i, j, k, :], (5, deg2rad(10), deg2rad(10))) + + dtheta = lambda d1, d2: np.cos(deg2rad(d1)) - np.cos(deg2rad(d2)) + f = 1/3 * deg2rad(10.) + np.testing.assert_allclose(mesh.volumes[::4], f * 5**3 * dtheta(0., 10.)) + np.testing.assert_allclose(mesh.volumes[1::4], f * (10**3 - 5**3) * dtheta(0., 10.)) + np.testing.assert_allclose(mesh.volumes[2::4], f * 5**3 * dtheta(10., 20.)) + np.testing.assert_allclose(mesh.volumes[3::4], f * (10**3 - 5**3) * dtheta(10., 20.)) + + with pytest.raises(exc.AllocationError): + mesh2 = openmc.lib.SphericalMesh(mesh.id) + + meshes = openmc.lib.meshes + assert isinstance(meshes, Mapping) + assert len(meshes) == 7 + + mesh = meshes[mesh.id] + assert isinstance(mesh, openmc.lib.SphericalMesh) + + mf = openmc.lib.MeshFilter(mesh) + assert mf.mesh == mesh + + msf = openmc.lib.MeshSurfaceFilter(mesh) + assert msf.mesh == mesh + + # Test material volumes + mesh = openmc.lib.SphericalMesh() + r_grid = (0., 0.25, 0.5) + theta_grid = np.linspace(0., pi, 3) + phi_grid = np.linspace(0., 2.0*pi, 4) + mesh.set_grid(r_grid, theta_grid, phi_grid) + + vols = mesh.material_volumes() + assert len(vols) == 12 + d_theta = theta_grid[1] - theta_grid[0] + d_phi = phi_grid[1] - phi_grid[0] + for i in range(0, 12, 2): + assert sum(f[1] for f in vols[i]) == pytest.approx( + 0.25**3 / 3 * d_theta * d_phi * 2/pi) + for i in range(1, 12, 2): + assert sum(f[1] for f in vols[i]) == pytest.approx( + (0.5**3 - 0.25**3) / 3 * d_theta * d_phi * 2/pi) + def test_restart(lib_init, mpi_intracomm): # Finalize and re-init to make internal state consistent with XML. @@ -558,9 +829,9 @@ def test_load_nuclide(lib_init): def test_id_map(lib_init): - expected_ids = np.array([[(3, 3), (2, 2), (3, 3)], - [(2, 2), (1, 1), (2, 2)], - [(3, 3), (2, 2), (3, 3)]], dtype='int32') + expected_ids = np.array([[(3, 0, 3), (2, 0, 2), (3, 0, 3)], + [(2, 0, 2), (1, 0, 1), (2, 0, 2)], + [(3, 0, 3), (2, 0, 2), (3, 0, 3)]], dtype='int32') # create a plot object s = openmc.lib.plot._PlotBase() @@ -575,6 +846,7 @@ def test_id_map(lib_init): ids = openmc.lib.plot.id_map(s) assert np.array_equal(expected_ids, ids) + def test_property_map(lib_init): expected_properties = np.array( [[(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)], @@ -641,3 +913,83 @@ def test_trigger_set_n_batches(uo2_trigger_model, mpi_intracomm): # Ensure statepoint was created only at batch 20 when calling set_batches assert not os.path.exists('statepoint.12.h5') assert os.path.exists('statepoint.20.h5') + + +def test_cell_translation(pincell_model_w_univ, mpi_intracomm): + openmc.lib.finalize() + openmc.lib.init(intracomm=mpi_intracomm) + # Cell 1 is filled with a material so it has a translation, but we can't + # set it. + cell = openmc.lib.cells[1] + assert cell.translation == pytest.approx([0., 0., 0.]) + with pytest.raises(exc.GeometryError, match='not filled with'): + cell.translation = (1., 0., -1.) + + # Cell 2 was given a universe, so we can assign it a translation vector + cell = openmc.lib.cells[2] + assert cell.translation == pytest.approx([0., 0., 0.]) + # This time we *can* set it + cell.translation = (1., 0., -1.) + assert cell.translation == pytest.approx([1., 0., -1.]) + openmc.lib.finalize() + + +def test_cell_rotation(pincell_model_w_univ, mpi_intracomm): + openmc.lib.finalize() + openmc.lib.init(intracomm=mpi_intracomm) + # Cell 1 is filled with a material so we cannot rotate it, but we can get + # its rotation matrix (which will be the identity matrix) + cell = openmc.lib.cells[1] + assert cell.rotation == pytest.approx([0., 0., 0.]) + with pytest.raises(exc.GeometryError, match='not filled with'): + cell.rotation = (180., 0., 0.) + + # Now repeat with Cell 2 and we will be allowed to do it + cell = openmc.lib.cells[2] + assert cell.rotation == pytest.approx([0., 0., 0.]) + cell.rotation = (180., 0., 0.) + assert cell.rotation == pytest.approx([180., 0., 0.]) + openmc.lib.finalize() + + +def test_sample_external_source(run_in_tmpdir, mpi_intracomm): + # Define a simple model and export + mat = openmc.Material() + mat.add_nuclide('U235', 1.0e-2) + sph = openmc.Sphere(r=100.0, boundary_type='vacuum') + cell = openmc.Cell(fill=mat, region=-sph) + model = openmc.Model() + model.geometry = openmc.Geometry([cell]) + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Box([-5., -5., -5.], [5., 5., 5.]), + angle=openmc.stats.Monodirectional((0., 0., 1.)), + energy=openmc.stats.Discrete([1.0e5], [1.0]) + ) + model.settings.particles = 1000 + model.settings.batches = 10 + model.export_to_xml() + + # Sample some particles and make sure they match specified source + openmc.lib.init() + particles = openmc.lib.sample_external_source(10, prn_seed=3) + assert len(particles) == 10 + for p in particles: + assert -5. < p.r[0] < 5. + assert -5. < p.r[1] < 5. + assert -5. < p.r[2] < 5. + assert p.u[0] == 0.0 + assert p.u[1] == 0.0 + assert p.u[2] == 1.0 + assert p.E == 1.0e5 + + # Using the same seed should produce the same particles + other_particles = openmc.lib.sample_external_source(10, prn_seed=3) + assert len(other_particles) == 10 + for p1, p2 in zip(particles, other_particles): + assert p1.r == p2.r + assert p1.u == p2.u + assert p1.E == p2.E + assert p1.time == p2.time + assert p1.wgt == p2.wgt + + openmc.lib.finalize() diff --git a/tests/unit_tests/test_lost_particles.py b/tests/unit_tests/test_lost_particles.py new file mode 100644 index 00000000000..478ddbaf0f7 --- /dev/null +++ b/tests/unit_tests/test_lost_particles.py @@ -0,0 +1,49 @@ +from pathlib import Path + +import openmc +import pytest + +from tests.testing_harness import config + + +@pytest.fixture +def model(): + mat = openmc.Material() + mat.add_nuclide('N14', 1.0) + mat.set_density('g/cm3', 1e-5) + + s1 = openmc.Sphere(r=80.0) + s2 = openmc.Sphere(r=90.0) + s3 = openmc.Sphere(r=100.0, boundary_type='vacuum') + cell1 = openmc.Cell(fill=mat, region=-s1) + cell2 = openmc.Cell(fill=mat, region=+s2 & -s3) + model = openmc.Model() + model.geometry = openmc.Geometry([cell1, cell2]) + + model.settings.run_mode = 'fixed source' + model.settings.batches = 10 + model.settings.inactive = 5 + model.settings.particles = 50 + model.settings.max_lost_particles = 1000 + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) + + return model + + +def test_max_write_lost_particles(model: openmc.Model, run_in_tmpdir): + # Set maximum number of lost particle restart files + model.settings.max_write_lost_particles = 5 + + # Run OpenMC to generate lost particle files. Use one thread so that we know + # exactly how much will be produced. If running in MPI mode, setup proper + # keyword arguments for run() + kwargs = {'openmc_exec': config['exe']} + if config['mpi']: + kwargs['mpi_args'] = [config['mpiexec'], '-n', config['mpi_np']] + model.run(threads=1, **kwargs) + + # Make sure number of lost particle files is as expected + lost_particle_files = list(Path.cwd().glob('particle*.h5')) + n_procs = int(config['mpi_np']) if config['mpi'] else 1 + assert len(lost_particle_files) == model.settings.max_write_lost_particles * n_procs + diff --git a/tests/unit_tests/test_material.py b/tests/unit_tests/test_material.py index 02e53a28dba..44c0730fbd2 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -1,8 +1,10 @@ from collections import defaultdict +from pathlib import Path import pytest import openmc +from openmc.data import decay_photon_energy import openmc.examples import openmc.model import openmc.stats @@ -25,6 +27,65 @@ def test_add_nuclide(): with pytest.raises(ValueError): m.add_nuclide('H1', 1.0, 'oa') +def test_add_components(): + """Test adding multipe elements or nuclides at once""" + m = openmc.Material() + components = {'H1': 2.0, + 'O16': 1.0, + 'Zr': 1.0, + 'O': 1.0, + 'Ag110_m1': 1.0, + 'U': {'percent': 1.0, + 'enrichment': 4.5}, + 'Li': {'percent': 1.0, + 'enrichment': 60.0, + 'enrichment_target': 'Li7'}, + 'H': {'percent': 1.0, + 'enrichment': 50.0, + 'enrichment_target': 'H2', + 'enrichment_type': 'wo'}} + m.add_components(components) + with pytest.raises(ValueError): + m.add_components({'U': {'percent': 1.0, + 'enrichment': 100.0}}) + with pytest.raises(ValueError): + m.add_components({'Pu': {'percent': 1.0, + 'enrichment': 3.0}}) + with pytest.raises(ValueError): + m.add_components({'U': {'percent': 1.0, + 'enrichment': 70.0, + 'enrichment_target':'U235'}}) + with pytest.raises(ValueError): + m.add_components({'He': {'percent': 1.0, + 'enrichment': 17.0, + 'enrichment_target': 'He6'}}) + with pytest.raises(ValueError): + m.add_components({'li': 1.0}) # should fail as 1st char is lowercase + with pytest.raises(ValueError): + m.add_components({'LI': 1.0}) # should fail as 2nd char is uppercase + with pytest.raises(ValueError): + m.add_components({'Xx': 1.0}) # should fail as Xx is not an element + with pytest.raises(ValueError): + m.add_components({'n': 1.0}) # check to avoid n for neutron being accepted + with pytest.raises(TypeError): + m.add_components({'H1': '1.0'}) + with pytest.raises(TypeError): + m.add_components({1.0: 'H1'}, percent_type = 'wo') + with pytest.raises(ValueError): + m.add_components({'H1': 1.0}, percent_type = 'oa') + +def test_nuclides_to_ignore(run_in_tmpdir): + """Test nuclides_to_ignore when exporting a material to XML""" + m = openmc.Material() + m.add_nuclide('U235', 1.0) + m.add_nuclide('H1', 1.0) + m.add_nuclide('O16', 1.0) + + mats = openmc.Materials([m]) + mats.export_to_xml(nuclides_to_ignore=['H1']) + + test_mats = openmc.Materials.from_xml() + assert 'H1' not in test_mats[0].get_nuclides() def test_remove_nuclide(): """Test removing nuclides.""" @@ -38,7 +99,18 @@ def test_remove_nuclide(): assert m.nuclides[1].percent == 2.0 -def test_elements(): +def test_remove_elements(): + """Test removing elements.""" + m = openmc.Material() + for elem, percent in [('Li', 1.0), ('Be', 1.0)]: + m.add_element(elem, percent) + m.remove_element('Li') + assert len(m.nuclides) == 1 + assert m.nuclides[0].name == 'Be9' + assert m.nuclides[0].percent == 1.0 + + +def test_add_element(): """Test adding elements.""" m = openmc.Material() m.add_element('Zr', 1.0) @@ -63,7 +135,6 @@ def test_elements(): with pytest.raises(ValueError): m.add_element('n', 1.0) # check to avoid n for neutron being accepted - def test_elements_by_name(): """Test adding elements by name""" m = openmc.Material() @@ -89,7 +160,7 @@ def test_add_elements_by_formula(): m.add_elements_from_formula('Li4SiO4') # checking the ratio of elements is 4:1:4 for Li:Si:O elem = defaultdict(float) - for nuclide, adens in m.get_nuclide_atom_densities().values(): + for nuclide, adens in m.get_nuclide_atom_densities().items(): if nuclide.startswith("Li"): elem["Li"] += adens if nuclide.startswith("Si"): @@ -106,7 +177,7 @@ def test_add_elements_by_formula(): 'O16': 0.443386, 'O17': 0.000168} nuc_dens = m.get_nuclide_atom_densities() for nuclide in ref_dens: - assert nuc_dens[nuclide][1] == pytest.approx(ref_dens[nuclide], 1e-2) + assert nuc_dens[nuclide] == pytest.approx(ref_dens[nuclide], 1e-2) # testing the correct nuclides are added to the Material when enriched m = openmc.Material() @@ -118,7 +189,7 @@ def test_add_elements_by_formula(): 'O16': 0.443386, 'O17': 0.000168} nuc_dens = m.get_nuclide_atom_densities() for nuclide in ref_dens: - assert nuc_dens[nuclide][1] == pytest.approx(ref_dens[nuclide], 1e-2) + assert nuc_dens[nuclide] == pytest.approx(ref_dens[nuclide], 1e-2) # testing the use of brackets m = openmc.Material() @@ -126,7 +197,7 @@ def test_add_elements_by_formula(): # checking the ratio of elements is 2:2:6 for Mg:N:O elem = defaultdict(float) - for nuclide, adens in m.get_nuclide_atom_densities().values(): + for nuclide, adens in m.get_nuclide_atom_densities().items(): if nuclide.startswith("Mg"): elem["Mg"] += adens if nuclide.startswith("N"): @@ -144,7 +215,7 @@ def test_add_elements_by_formula(): 'O16': 0.599772, 'O17': 0.000227} nuc_dens = m.get_nuclide_atom_densities() for nuclide in ref_dens: - assert nuc_dens[nuclide][1] == pytest.approx(ref_dens[nuclide], 1e-2) + assert nuc_dens[nuclide] == pytest.approx(ref_dens[nuclide], 1e-2) # testing non integer multiplier results in a value error m = openmc.Material() @@ -243,6 +314,23 @@ def test_isotropic(): assert m2.isotropic == ['H1'] +def test_get_nuclides(): + mat = openmc.Material() + + mat.add_nuclide('Li6', 1.0) + assert mat.get_nuclides() == ['Li6'] + assert mat.get_nuclides(element='Li') == ['Li6'] + assert mat.get_nuclides(element='Be') == [] + + mat.add_element('Li', 1.0) + assert mat.get_nuclides() == ['Li6', 'Li7'] + assert mat.get_nuclides(element='Be') == [] + + mat.add_element('Be', 1.0) + assert mat.get_nuclides() == ['Li6', 'Li7', 'Be9'] + assert mat.get_nuclides(element='Be') == ['Be9'] + + def test_get_elements(): # test that zero elements exist on creation m = openmc.Material() @@ -278,12 +366,33 @@ def test_get_nuclide_densities(uo2): def test_get_nuclide_atom_densities(uo2): - nucs = uo2.get_nuclide_atom_densities() - for nuc, density in nucs.values(): + for nuc, density in uo2.get_nuclide_atom_densities().items(): assert nuc in ('U235', 'O16') assert density > 0 +def test_get_nuclide_atom_densities_specific(uo2): + one_nuc = uo2.get_nuclide_atom_densities(nuclide='O16') + assert list(one_nuc.keys()) == ['O16'] + assert list(one_nuc.values())[0] > 0 + + all_nuc = uo2.get_nuclide_atom_densities() + assert all_nuc['O16'] == one_nuc['O16'] + + +def test_get_nuclide_atoms(): + mat = openmc.Material() + mat.add_nuclide('Li6', 1.0) + mat.set_density('atom/cm3', 3.26e20) + mat.volume = 100.0 + + atoms = mat.get_nuclide_atoms() + assert atoms['Li6'] == pytest.approx(mat.density * mat.volume) + + atoms = mat.get_nuclide_atoms(volume=10.0) + assert atoms['Li6'] == pytest.approx(mat.density * 10.0) + + def test_mass(): m = openmc.Material() m.add_nuclide('Zr90', 1.0, 'wo') @@ -300,6 +409,9 @@ def test_mass(): assert m.get_mass() == pytest.approx(20.0) assert m.fissionable_mass == pytest.approx(10.0) + # Test with volume specified as argument + assert m.get_mass('Zr90', volume=1.0) == pytest.approx(1.0) + def test_materials(run_in_tmpdir): m1 = openmc.Material() @@ -330,7 +442,7 @@ def test_borated_water(): 'O16':2.4672e-02} nuc_dens = m.get_nuclide_atom_densities() for nuclide in ref_dens: - assert nuc_dens[nuclide][1] == pytest.approx(ref_dens[nuclide], 1e-2) + assert nuc_dens[nuclide] == pytest.approx(ref_dens[nuclide], 1e-2) assert m.id == 50 # Test the Celsius conversion. @@ -404,3 +516,148 @@ def test_mix_materials(): assert m3.density == pytest.approx(dens3) assert m4.density == pytest.approx(dens4) assert m5.density == pytest.approx(dens5) + + +def test_get_activity(): + """Tests the activity of stable, metastable and active materials""" + + # Creates a material with stable isotopes to check the activity is 0 + m1 = openmc.Material() + m1.add_element("Fe", 0.7) + m1.add_element("Li", 0.3) + m1.set_density('g/cm3', 1.5) + # activity in Bq/cc and Bq/g should not require volume setting + assert m1.get_activity(units='Bq/cm3') == 0 + assert m1.get_activity(units='Bq/g') == 0 + m1.volume = 1 + assert m1.get_activity(units='Bq') == 0 + + # Checks that 1g of tritium has the correct activity scaling + m2 = openmc.Material() + m2.add_nuclide("H3", 1) + m2.set_density('g/cm3', 1) + m2.volume = 1 + assert pytest.approx(m2.get_activity(units='Bq')) == 3.559778e14 + m2.set_density('g/cm3', 2) + assert pytest.approx(m2.get_activity(units='Bq')) == 3.559778e14*2 + m2.volume = 3 + assert pytest.approx(m2.get_activity(units='Bq')) == 3.559778e14*2*3 + + # Checks that 1 mol of a metastable nuclides has the correct activity + m3 = openmc.Material() + m3.add_nuclide("Tc99_m1", 1) + m3.set_density('g/cm3', 1) + m3.volume = 98.9 + assert pytest.approx(m3.get_activity(units='Bq'), rel=0.001) == 1.93e19 + + # Checks that specific and volumetric activity of tritium are correct + m4 = openmc.Material() + m4.add_nuclide("H3", 1) + m4.set_density('g/cm3', 1.5) + assert pytest.approx(m4.get_activity(units='Bq/g')) == 355978108155965.94 # [Bq/g] + assert pytest.approx(m4.get_activity(units='Bq/g', by_nuclide=True)["H3"]) == 355978108155965.94 # [Bq/g] + assert pytest.approx(m4.get_activity(units='Bq/cm3')) == 355978108155965.94*3/2 # [Bq/cc] + assert pytest.approx(m4.get_activity(units='Bq/cm3', by_nuclide=True)["H3"]) == 355978108155965.94*3/2 # [Bq/cc] + # volume is required to calculate total activity + m4.volume = 10. + assert pytest.approx(m4.get_activity(units='Bq')) == 355978108155965.94*3/2*10 # [Bq] + + # Test with volume specified as argument + assert pytest.approx(m4.get_activity(units='Bq', volume=1.0)) == 355978108155965.94*3/2 + + +def test_get_decay_heat(): + # Set chain file for testing + openmc.config['chain_file'] = Path(__file__).parents[1] / 'chain_simple.xml' + + """Tests the decay heat of stable, metastable and active materials""" + m1 = openmc.Material() + m1.add_nuclide("U235", 0.2) + m1.add_nuclide("U238", 0.8) + m1.set_density('g/cm3', 10.5) + # decay heat in W/cc and W/g should not require volume setting + assert m1.get_decay_heat(units='W/cm3') == 0 + assert m1.get_decay_heat(units='W/g') == 0 + m1.volume = 1 + assert m1.get_decay_heat(units='W') == 0 + + # Checks that 1g of tritium has the correct decay heat scaling + m2 = openmc.Material() + m2.add_nuclide("I135", 1) + m2.set_density('g/cm3', 1) + m2.volume = 1 + assert pytest.approx(m2.get_decay_heat(units='W')) == 40175.15720273193 + m2.set_density('g/cm3', 2) + assert pytest.approx(m2.get_decay_heat(units='W')) == 40175.15720273193*2 + m2.volume = 3 + assert pytest.approx(m2.get_decay_heat(units='W')) == 40175.15720273193*2*3 + + # Checks that 1 mol of a metastable nuclides has the correct decay heat + m3 = openmc.Material() + m3.add_nuclide("Xe135", 1) + m3.set_density('g/cm3', 1) + m3.volume = 98.9 + assert pytest.approx(m3.get_decay_heat(units='W'), rel=0.001) == 846181.2921143445 + + # Checks that specific and volumetric decay heat of tritium are correct + m4 = openmc.Material() + m4.add_nuclide("I135", 1) + m4.set_density('g/cm3', 1.5) + assert pytest.approx(m4.get_decay_heat(units='W/g')) == 40175.15720273193 # [W/g] + assert pytest.approx(m4.get_decay_heat(units='W/g', by_nuclide=True)["I135"]) == 40175.15720273193 # [W/g] + assert pytest.approx(m4.get_decay_heat(units='W/cm3')) == 40175.15720273193*3/2 # [W/cc] + assert pytest.approx(m4.get_decay_heat(units='W/cm3', by_nuclide=True)["I135"]) == 40175.15720273193*3/2 #[W/cc] + # volume is required to calculate total decay heat + m4.volume = 10. + assert pytest.approx(m4.get_decay_heat(units='W')) == 40175.15720273193*3/2*10 # [W] + + # Test with volume specified as argument + assert pytest.approx(m4.get_decay_heat(units='W', volume=1.0)) == 40175.15720273193*3/2 + + +def test_decay_photon_energy(): + # Set chain file for testing + openmc.config['chain_file'] = Path(__file__).parents[1] / 'chain_simple.xml' + + # Material representing single atom of I135 and Cs135 + m = openmc.Material() + m.add_nuclide('I135', 1.0e-24) + m.add_nuclide('Cs135', 1.0e-24) + m.volume = 1.0 + + # Get decay photon source and make sure it's the right type + src = m.get_decay_photon_energy() + assert isinstance(src, openmc.stats.Discrete) + + # Make sure units/volume work as expected + src_v2 = m.get_decay_photon_energy(volume=2.0) + assert src.p * 2.0 == pytest.approx(src_v2.p) + src_per_cm3 = m.get_decay_photon_energy(units='Bq/cm3', volume=100.0) + assert (src.p == src_per_cm3.p).all() + + # If we add Xe135 (which has a tabular distribution), the photon source + # should be a mixture distribution + m.add_nuclide('Xe135', 1.0e-24) + src = m.get_decay_photon_energy() + assert isinstance(src, openmc.stats.Mixture) + + # With a single atom of each, the intensity of the photon source should be + # equal to the sum of the intensities for each nuclide + def intensity(src): + return src.integral() if src is not None else 0.0 + + assert src.integral() == pytest.approx(sum( + intensity(decay_photon_energy(nuc)) for nuc in m.get_nuclides() + ), rel=1e-3) + + # When the clipping threshold is zero, the intensities should match exactly + src = m.get_decay_photon_energy(0.0) + assert src.integral() == pytest.approx(sum( + intensity(decay_photon_energy(nuc)) for nuc in m.get_nuclides() + )) + + # A material with no unstable nuclides should have no decay photon source + stable = openmc.Material() + stable.add_nuclide('Gd156', 1.0) + stable.volume = 1.0 + assert stable.get_decay_photon_energy() is None diff --git a/tests/unit_tests/test_mesh.py b/tests/unit_tests/test_mesh.py new file mode 100644 index 00000000000..c4993065069 --- /dev/null +++ b/tests/unit_tests/test_mesh.py @@ -0,0 +1,367 @@ +from math import pi + +import numpy as np +import pytest +import openmc + + +@pytest.mark.parametrize("val_left,val_right", [(0, 0), (-1., -1.), (2.0, 2)]) +def test_raises_error_when_flat(val_left, val_right): + """Checks that an error is raised when a mesh is flat""" + mesh = openmc.RegularMesh() + + # Same X + with pytest.raises(ValueError): + mesh.lower_left = [val_left, -25, -25] + mesh.upper_right = [val_right, 25, 25] + + with pytest.raises(ValueError): + mesh.upper_right = [val_right, 25, 25] + mesh.lower_left = [val_left, -25, -25] + + # Same Y + with pytest.raises(ValueError): + mesh.lower_left = [-25, val_left, -25] + mesh.upper_right = [25, val_right, 25] + + with pytest.raises(ValueError): + mesh.upper_right = [25, val_right, 25] + mesh.lower_left = [-25, val_left, -25] + + # Same Z + with pytest.raises(ValueError): + mesh.lower_left = [-25, -25, val_left] + mesh.upper_right = [25, 25, val_right] + + with pytest.raises(ValueError): + mesh.upper_right = [25, 25, val_right] + mesh.lower_left = [-25, -25, val_left] + + +def test_regular_mesh_bounding_box(): + mesh = openmc.RegularMesh() + mesh.lower_left = [-2, -3, -5] + mesh.upper_right = [2, 3, 5] + bb = mesh.bounding_box + assert isinstance(bb, openmc.BoundingBox) + np.testing.assert_array_equal(bb.lower_left, (-2, -3 ,-5)) + np.testing.assert_array_equal(bb.upper_right, (2, 3, 5)) + + +def test_rectilinear_mesh_bounding_box(): + mesh = openmc.RectilinearMesh() + mesh.x_grid = [0., 1., 5., 10.] + mesh.y_grid = [-10., -5., 0.] + mesh.z_grid = [-100., 0., 100.] + bb = mesh.bounding_box + assert isinstance(bb, openmc.BoundingBox) + np.testing.assert_array_equal(bb.lower_left, (0., -10. ,-100.)) + np.testing.assert_array_equal(bb.upper_right, (10., 0., 100.)) + + +def test_cylindrical_mesh_bounding_box(): + # test with mesh at origin (0, 0, 0) + mesh = openmc.CylindricalMesh( + r_grid=[0.1, 0.2, 0.5, 1.], + z_grid=[0.1, 0.2, 0.4, 0.6, 1.], + origin=(0, 0, 0) + ) + np.testing.assert_array_equal(mesh.upper_right, (1, 1, 1)) + np.testing.assert_array_equal(mesh.lower_left, (-1, -1, 0.1)) + bb = mesh.bounding_box + assert isinstance(bb, openmc.BoundingBox) + np.testing.assert_array_equal(bb.lower_left, (-1, -1, 0.1)) + np.testing.assert_array_equal(bb.upper_right, (1, 1, 1)) + + # test with mesh at origin (3, 5, 7) + mesh.origin = (3, 5, 7) + np.testing.assert_array_equal(mesh.upper_right, (4, 6, 8)) + np.testing.assert_array_equal(mesh.lower_left, (2, 4, 7.1)) + bb = mesh.bounding_box + assert isinstance(bb, openmc.BoundingBox) + np.testing.assert_array_equal(bb.lower_left, (2, 4, 7.1)) + np.testing.assert_array_equal(bb.upper_right, (4, 6, 8)) + + # changing z grid to contain negative numbers + mesh.z_grid = [-10, 0, 10] + np.testing.assert_array_equal(mesh.lower_left, (2, 4, -3)) + np.testing.assert_array_equal(mesh.upper_right, (4, 6, 17)) + + +def test_spherical_mesh_bounding_box(): + # test with mesh at origin (0, 0, 0) + mesh = openmc.SphericalMesh([0.1, 0.2, 0.5, 1.], origin=(0., 0., 0.)) + np.testing.assert_array_equal(mesh.upper_right, (1, 1, 1)) + np.testing.assert_array_equal(mesh.lower_left, (-1, -1, -1)) + bb = mesh.bounding_box + assert isinstance(bb, openmc.BoundingBox) + np.testing.assert_array_equal(bb.lower_left, (-1, -1, -1)) + np.testing.assert_array_equal(bb.upper_right, (1, 1, 1)) + + # test with mesh at origin (3, 5, 7) + mesh.origin = (3, 5, 7) + np.testing.assert_array_equal(mesh.upper_right, (4, 6, 8)) + np.testing.assert_array_equal(mesh.lower_left, (2, 4, 6)) + bb = mesh.bounding_box + assert isinstance(bb, openmc.BoundingBox) + np.testing.assert_array_equal(bb.lower_left, (2, 4, 6)) + np.testing.assert_array_equal(bb.upper_right, (4, 6, 8)) + + +def test_SphericalMesh_initiation(): + # test defaults + mesh = openmc.SphericalMesh(r_grid=(0, 10)) + assert (mesh.origin == np.array([0, 0, 0])).all() + assert (mesh.r_grid == np.array([0, 10])).all() + assert (mesh.theta_grid == np.array([0, pi])).all() + assert (mesh.phi_grid == np.array([0, 2*pi])).all() + + # test setting on creation + mesh = openmc.SphericalMesh( + origin=(1, 2, 3), + r_grid=(0, 2), + theta_grid=(1, 3), + phi_grid=(2, 4) + ) + assert (mesh.origin == np.array([1, 2, 3])).all() + assert (mesh.r_grid == np.array([0., 2.])).all() + assert (mesh.theta_grid == np.array([1, 3])).all() + assert (mesh.phi_grid == np.array([2, 4])).all() + + # test attribute changing + mesh.r_grid = (0, 11) + assert (mesh.r_grid == np.array([0., 11.])).all() + + # waffles and pancakes are unfortunately not valid radii + with pytest.raises(TypeError): + openmc.SphericalMesh(('🧇', '🥞')) + + +def test_CylindricalMesh_initiation(): + # test defaults + mesh = openmc.CylindricalMesh(r_grid=(0, 10), z_grid=(0, 10)) + assert (mesh.origin == np.array([0, 0, 0])).all() + assert (mesh.r_grid == np.array([0, 10])).all() + assert (mesh.phi_grid == np.array([0, 2*pi])).all() + assert (mesh.z_grid == np.array([0, 10])).all() + + # test setting on creation + mesh = openmc.CylindricalMesh( + origin=(1, 2, 3), + r_grid=(0, 2), + z_grid=(1, 3), + phi_grid=(2, 4) + ) + assert (mesh.origin == np.array([1, 2, 3])).all() + assert (mesh.r_grid == np.array([0., 2.])).all() + assert (mesh.z_grid == np.array([1, 3])).all() + assert (mesh.phi_grid == np.array([2, 4])).all() + + # test attribute changing + mesh.r_grid = (0., 10.) + assert (mesh.r_grid == np.array([0, 10.])).all() + mesh.z_grid = (0., 4.) + assert (mesh.z_grid == np.array([0, 4.])).all() + + # waffles and pancakes are unfortunately not valid radii + with pytest.raises(TypeError): + openmc.SphericalMesh(('🧇', '🥞')) + + +def test_centroids(): + # regular mesh + mesh = openmc.RegularMesh() + mesh.lower_left = (1., 2., 3.) + mesh.upper_right = (11., 12., 13.) + mesh.dimension = (1, 1, 1) + np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [6., 7., 8.]) + + # rectilinear mesh + mesh = openmc.RectilinearMesh() + mesh.x_grid = [1., 11.] + mesh.y_grid = [2., 12.] + mesh.z_grid = [3., 13.] + np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [6., 7., 8.]) + + # cylindrical mesh + mesh = openmc.CylindricalMesh(r_grid=(0, 10), z_grid=(0, 10), phi_grid=(0, np.pi)) + np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [0.0, 5.0, 5.0]) + # ensure that setting an origin is handled correctly + mesh.origin = (5.0, 0, -10) + np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [5.0, 5.0, -5.0]) + + # spherical mesh, single element xyz-positive octant + mesh = openmc.SphericalMesh(r_grid=[0, 10], theta_grid=[0, 0.5*np.pi], phi_grid=[0, np.pi]) + x = 5.*np.cos(0.5*np.pi)*np.sin(0.25*np.pi) + y = 5.*np.sin(0.5*np.pi)*np.sin(0.25*np.pi) + z = 5.*np.sin(0.25*np.pi) + np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [x, y, z]) + + mesh.origin = (-5.0, -5.0, 5.0) + np.testing.assert_array_almost_equal(mesh.centroids[0, 0, 0], [x-5.0, y-5.0, z+5.0]) + + +@pytest.mark.parametrize('mesh_type', ('regular', 'rectilinear', 'cylindrical', 'spherical')) +def test_mesh_vertices(mesh_type): + + ijk = (2, 3, 2) + + # create a new mesh object + if mesh_type == 'regular': + mesh = openmc.RegularMesh() + ll = np.asarray([0.]*3) + width = np.asarray([0.5]*3) + mesh.lower_left = ll + mesh.width = width + mesh.dimension = (5, 7, 9) + + # spot check that an element has the correct vertex coordinates asociated with it + # (using zero-indexing here) + exp_i_j_k = ll + np.asarray(ijk, dtype=float) * width + np.testing.assert_equal(mesh.vertices[ijk], exp_i_j_k) + + # shift the mesh using the llc + shift = np.asarray((3.0, 6.0, 10.0)) + mesh.lower_left += shift + np.testing.assert_equal(mesh.vertices[ijk], exp_i_j_k+shift) + elif mesh_type == 'rectilinear': + mesh = openmc.RectilinearMesh() + w = np.asarray([0.5] * 3) + ll = np.asarray([0.]*3) + dims = (5, 7, 9) + mesh.x_grid = np.linspace(ll[0], w[0]*dims[0], dims[0]) + mesh.y_grid = np.linspace(ll[1], w[1]*dims[1], dims[1]) + mesh.z_grid = np.linspace(ll[2], w[2]*dims[2], dims[2]) + exp_vert = np.asarray((mesh.x_grid[2], mesh.y_grid[3], mesh.z_grid[2])) + np.testing.assert_equal(mesh.vertices[ijk], exp_vert) + elif mesh_type == 'cylindrical': + r_grid = np.linspace(0, 5, 10) + z_grid = np.linspace(-10, 10, 20) + phi_grid = np.linspace(0, 2*np.pi, 8) + mesh = openmc.CylindricalMesh(r_grid=r_grid, z_grid=z_grid, phi_grid=phi_grid) + exp_vert = np.asarray((mesh.r_grid[2], mesh.phi_grid[3], mesh.z_grid[2])) + np.testing.assert_equal(mesh.vertices_cylindrical[ijk], exp_vert) + elif mesh_type == 'spherical': + r_grid = np.linspace(0, 13, 14) + theta_grid = np.linspace(0, np.pi, 11) + phi_grid = np.linspace(0, 2*np.pi, 7) + mesh = openmc.SphericalMesh(r_grid=r_grid, theta_grid=theta_grid, phi_grid=phi_grid) + exp_vert = np.asarray((mesh.r_grid[2], mesh.theta_grid[3], mesh.phi_grid[2])) + np.testing.assert_equal(mesh.vertices_spherical[ijk], exp_vert) + + +def test_CylindricalMesh_get_indices_at_coords(): + # default origin (0, 0, 0) and default phi grid (0, 2*pi) + mesh = openmc.CylindricalMesh(r_grid=(0, 5, 10), z_grid=(0, 5, 10)) + assert mesh.get_indices_at_coords([1, 0, 1]) == (0, 0, 0) + assert mesh.get_indices_at_coords([6, 0, 1]) == (1, 0, 0) + assert mesh.get_indices_at_coords([9, 0, 1]) == (1, 0, 0) + assert mesh.get_indices_at_coords([0, 6, 0]) == (1, 0, 0) + assert mesh.get_indices_at_coords([0, 9, 6]) == (1, 0, 1) + assert mesh.get_indices_at_coords([-2, -2, 9]) == (0, 0, 1) + + with pytest.raises(ValueError): + assert mesh.get_indices_at_coords([8, 8, 1]) # resulting r value to large + with pytest.raises(ValueError): + assert mesh.get_indices_at_coords([-8, -8, 1]) # resulting r value to large + with pytest.raises(ValueError): + assert mesh.get_indices_at_coords([1, 0, -1]) # z value below range + with pytest.raises(ValueError): + assert mesh.get_indices_at_coords([1, 0, 11]) # z value above range + + assert mesh.get_indices_at_coords([1, 1, 1]) == (0, 0, 0) + + # negative range on z grid + mesh = openmc.CylindricalMesh( + r_grid=(0, 5, 10), + phi_grid=(0, 0.5 * pi, pi, 1.5 * pi, 1.9 * pi), + z_grid=(-5, 0, 5, 10), + ) + assert mesh.get_indices_at_coords([1, 1, 1]) == (0, 0, 1) # first angle quadrant + assert mesh.get_indices_at_coords([2, 2, 6]) == (0, 0, 2) # first angle quadrant + assert mesh.get_indices_at_coords([-2, 0.1, -1]) == (0, 1, 0) # second angle quadrant + assert mesh.get_indices_at_coords([-2, -0.1, -1]) == (0, 2, 0) # third angle quadrant + assert mesh.get_indices_at_coords([2, -0.9, -1]) == (0, 3, 0) # forth angle quadrant + + with pytest.raises(ValueError): + assert mesh.get_indices_at_coords([2, -0.1, 1]) # outside of phi range + + # origin of mesh not default + mesh = openmc.CylindricalMesh( + r_grid=(0, 5, 10), + phi_grid=(0, 0.5 * pi, pi, 1.5 * pi, 1.9 * pi), + z_grid=(-5, 0, 5, 10), + origin=(100, 200, 300), + ) + assert mesh.get_indices_at_coords([101, 201, 301]) == (0, 0, 1) # first angle quadrant + assert mesh.get_indices_at_coords([102, 202, 306]) == (0, 0, 2) # first angle quadrant + assert mesh.get_indices_at_coords([98, 200.1, 299]) == (0, 1, 0) # second angle quadrant + assert mesh.get_indices_at_coords([98, 199.9, 299]) == (0, 2, 0) # third angle quadrant + assert mesh.get_indices_at_coords([102, 199.1, 299]) == (0, 3, 0) # forth angle quadrant + + +def test_umesh_roundtrip(run_in_tmpdir, request): + umesh = openmc.UnstructuredMesh(request.path.parent / 'test_mesh_tets.e', 'moab') + umesh.output = True + + # create a tally using this mesh + mf = openmc.MeshFilter(umesh) + tally = openmc.Tally() + tally.filters = [mf] + tally.scores = ['flux'] + + tallies = openmc.Tallies([tally]) + tallies.export_to_xml() + + xml_tallies = openmc.Tallies.from_xml() + xml_tally = xml_tallies[0] + xml_mesh = xml_tally.filters[0].mesh + + assert umesh.id == xml_mesh.id + + +def test_mesh_get_homogenized_materials(): + """Test the get_homogenized_materials method""" + # Simple model with 1 cm of Fe56 next to 1 cm of H1 + fe = openmc.Material() + fe.add_nuclide('Fe56', 1.0) + fe.set_density('g/cm3', 5.0) + h = openmc.Material() + h.add_nuclide('H1', 1.0) + h.set_density('g/cm3', 1.0) + + x0 = openmc.XPlane(-1.0, boundary_type='vacuum') + x1 = openmc.XPlane(0.0) + x2 = openmc.XPlane(1.0) + x3 = openmc.XPlane(2.0, boundary_type='vacuum') + cell1 = openmc.Cell(fill=fe, region=+x0 & -x1) + cell2 = openmc.Cell(fill=h, region=+x1 & -x2) + cell_empty = openmc.Cell(region=+x2 & -x3) + model = openmc.Model(geometry=openmc.Geometry([cell1, cell2, cell_empty])) + model.settings.particles = 1000 + model.settings.batches = 10 + + mesh = openmc.RegularMesh() + mesh.lower_left = (-1., -1., -1.) + mesh.upper_right = (1., 1., 1.) + mesh.dimension = (3, 1, 1) + m1, m2, m3 = mesh.get_homogenized_materials(model, n_samples=1_000_000) + + # Left mesh element should be only Fe56 + assert m1.get_mass_density('Fe56') == pytest.approx(5.0) + + # Middle mesh element should be 50% Fe56 and 50% H1 + assert m2.get_mass_density('Fe56') == pytest.approx(2.5, rel=1e-2) + assert m2.get_mass_density('H1') == pytest.approx(0.5, rel=1e-2) + + # Right mesh element should be only H1 + assert m3.get_mass_density('H1') == pytest.approx(1.0) + + mesh_void = openmc.RegularMesh() + mesh_void.lower_left = (0.5, 0.5, -1.) + mesh_void.upper_right = (1.5, 1.5, 1.) + mesh_void.dimension = (1, 1, 1) + m4, = mesh_void.get_homogenized_materials(model, n_samples=1_000_000) + + # Mesh element that overlaps void should have half density + assert m4.get_mass_density('H1') == pytest.approx(0.5, rel=1e-2) diff --git a/tests/unit_tests/test_mesh_from_domain.py b/tests/unit_tests/test_mesh_from_domain.py new file mode 100644 index 00000000000..0cbe413e86a --- /dev/null +++ b/tests/unit_tests/test_mesh_from_domain.py @@ -0,0 +1,121 @@ +import numpy as np +import openmc +import pytest + + +def test_reg_mesh_from_cell(): + """Tests a RegularMesh can be made from a Cell and the specified dimensions + are propagated through. Cell is not centralized""" + surface = openmc.Sphere(r=10, x0=2, y0=3, z0=5) + cell = openmc.Cell(region=-surface) + + mesh = openmc.RegularMesh.from_domain(domain=cell, dimension=[7, 11, 13]) + assert isinstance(mesh, openmc.RegularMesh) + assert np.array_equal(mesh.dimension, (7, 11, 13)) + assert np.array_equal(mesh.lower_left, cell.bounding_box[0]) + assert np.array_equal(mesh.upper_right, cell.bounding_box[1]) + + +def test_cylindrical_mesh_from_cell(): + """Tests a CylindricalMesh can be made from a Cell and the specified + dimensions are propagated through.""" + # Cell is not centralized on Z axis + cy_surface = openmc.ZCylinder(r=50) + z_surface_1 = openmc.ZPlane(z0=40) + z_surface_2 = openmc.ZPlane(z0=10) + cell = openmc.Cell(region=-cy_surface & -z_surface_1 & +z_surface_2) + mesh = openmc.CylindricalMesh.from_domain(domain=cell, dimension=[2, 4, 3]) + + assert isinstance(mesh, openmc.CylindricalMesh) + assert np.array_equal(mesh.dimension, (2, 4, 3)) + assert np.array_equal(mesh.r_grid, [0., 25., 50.]) + assert np.array_equal(mesh.phi_grid, [0., 0.5*np.pi, np.pi, 1.5*np.pi, 2.*np.pi]) + assert np.array_equal(mesh.z_grid, [0., 10., 20., 30.]) + assert np.array_equal(mesh.origin, [0., 0., 10.]) + + # Cell is not centralized on Z or X axis + cy_surface = openmc.ZCylinder(r=50, x0=100) + cell = openmc.Cell(region=-cy_surface & -z_surface_1 & +z_surface_2) + mesh = openmc.CylindricalMesh.from_domain(domain=cell, dimension=[1, 1, 1]) + + assert isinstance(mesh, openmc.CylindricalMesh) + assert np.array_equal(mesh.dimension, (1, 1, 1)) + assert np.array_equal(mesh.r_grid, [0., 150.]) + assert np.array_equal(mesh.origin, [100., 0., 10.]) + + # Cell is not centralized on Z, X or Y axis + cy_surface = openmc.ZCylinder(r=50, x0=100, y0=170) + cell = openmc.Cell(region=-cy_surface & -z_surface_1 & +z_surface_2) + mesh = openmc.CylindricalMesh.from_domain(domain=cell, dimension=[1, 1, 1]) + + assert isinstance(mesh, openmc.CylindricalMesh) + assert np.array_equal(mesh.r_grid, [0., 220.]) + assert np.array_equal(mesh.origin, [100., 170., 10.]) + + +def test_reg_mesh_from_region(): + """Tests a RegularMesh can be made from a Region and the default dimensions + are propagated through. Region is not centralized""" + surface = openmc.Sphere(r=1, x0=-5, y0=-3, z0=-2) + region = -surface + + mesh = openmc.RegularMesh.from_domain(domain=region) + assert isinstance(mesh, openmc.RegularMesh) + assert np.array_equal(mesh.dimension, (10, 10, 10)) # default values + assert np.array_equal(mesh.lower_left, region.bounding_box[0]) + assert np.array_equal(mesh.upper_right, region.bounding_box[1]) + + +def test_cylindrical_mesh_from_region(): + """Tests a CylindricalMesh can be made from a Region and the specified + dimensions and phi_grid_bounds are propagated through. Cell is centralized""" + cy_surface = openmc.ZCylinder(r=6) + z_surface_1 = openmc.ZPlane(z0=30) + z_surface_2 = openmc.ZPlane(z0=-30) + cell = openmc.Cell(region=-cy_surface & -z_surface_1 & +z_surface_2) + mesh = openmc.CylindricalMesh.from_domain( + domain=cell, + dimension=(6, 2, 3), + phi_grid_bounds=(0., np.pi) + ) + + assert isinstance(mesh, openmc.CylindricalMesh) + assert np.array_equal(mesh.dimension, (6, 2, 3)) + assert np.array_equal(mesh.r_grid, [0., 1., 2., 3., 4., 5., 6.]) + assert np.array_equal(mesh.phi_grid, [0., 0.5*np.pi, np.pi]) + assert np.array_equal(mesh.z_grid, [0.0, 20., 40., 60]) + assert np.array_equal(mesh.origin, (0.0, 0.0, -30.)) + + +def test_reg_mesh_from_universe(): + """Tests a RegularMesh can be made from a Universe and the default + dimensions are propagated through. Universe is centralized""" + surface = openmc.Sphere(r=42) + cell = openmc.Cell(region=-surface) + universe = openmc.Universe(cells=[cell]) + + mesh = openmc.RegularMesh.from_domain(universe) + assert isinstance(mesh, openmc.RegularMesh) + assert np.array_equal(mesh.dimension, (10, 10, 10)) # default values + assert np.array_equal(mesh.lower_left, universe.bounding_box[0]) + assert np.array_equal(mesh.upper_right, universe.bounding_box[1]) + + +def test_reg_mesh_from_geometry(): + """Tests a RegularMesh can be made from a Geometry and the default + dimensions are propagated through. Geometry is centralized""" + surface = openmc.Sphere(r=42) + cell = openmc.Cell(region=-surface) + universe = openmc.Universe(cells=[cell]) + geometry = openmc.Geometry(universe) + + mesh = openmc.RegularMesh.from_domain(geometry) + assert isinstance(mesh, openmc.RegularMesh) + assert np.array_equal(mesh.dimension, (10, 10, 10)) # default values + assert np.array_equal(mesh.lower_left, geometry.bounding_box[0]) + assert np.array_equal(mesh.upper_right, geometry.bounding_box[1]) + + +def test_error_from_unsupported_object(): + with pytest.raises(TypeError): + openmc.RegularMesh.from_domain("vacuum energy") diff --git a/tests/unit_tests/test_mesh_tets.e b/tests/unit_tests/test_mesh_tets.e new file mode 120000 index 00000000000..8a6287b4de2 --- /dev/null +++ b/tests/unit_tests/test_mesh_tets.e @@ -0,0 +1 @@ +../regression_tests/unstructured_mesh/test_mesh_tets.e \ No newline at end of file diff --git a/tests/unit_tests/test_model.py b/tests/unit_tests/test_model.py new file mode 100644 index 00000000000..404235bef1f --- /dev/null +++ b/tests/unit_tests/test_model.py @@ -0,0 +1,593 @@ +from math import pi +from pathlib import Path +import os + +import numpy as np +import pytest + +import openmc +import openmc.lib + + +@pytest.fixture(scope='function') +def pin_model_attributes(): + uo2 = openmc.Material(material_id=1, name='UO2') + uo2.set_density('g/cm3', 10.29769) + uo2.add_element('U', 1., enrichment=2.4) + uo2.add_element('O', 2.) + uo2.depletable = True + + zirc = openmc.Material(material_id=2, name='Zirc') + zirc.set_density('g/cm3', 6.55) + zirc.add_element('Zr', 1.) + zirc.depletable = False + + borated_water = openmc.Material(material_id=3, name='Borated water') + borated_water.set_density('g/cm3', 0.740582) + borated_water.add_element('B', 4.0e-5) + borated_water.add_element('H', 5.0e-2) + borated_water.add_element('O', 2.4e-2) + borated_water.add_s_alpha_beta('c_H_in_H2O') + borated_water.depletable = False + + mats = openmc.Materials([uo2, zirc, borated_water]) + + pitch = 1.25984 + fuel_or = openmc.ZCylinder(r=0.39218, name='Fuel OR') + clad_or = openmc.ZCylinder(r=0.45720, name='Clad OR') + box = openmc.model.RectangularPrism(pitch, pitch, + boundary_type='reflective') + + # Define cells + fuel_inf_cell = openmc.Cell(cell_id=1, name='inf fuel', fill=uo2) + fuel_inf_univ = openmc.Universe(universe_id=1, cells=[fuel_inf_cell]) + fuel = openmc.Cell(cell_id=2, name='fuel', + fill=fuel_inf_univ, region=-fuel_or) + clad = openmc.Cell(cell_id=3, fill=zirc, region=+fuel_or & -clad_or) + water = openmc.Cell(cell_id=4, fill=borated_water, region=+clad_or & -box) + + # Define overall geometry + geom = openmc.Geometry([fuel, clad, water]) + uo2.volume = pi * fuel_or.r**2 + + settings = openmc.Settings() + settings.batches = 100 + settings.inactive = 10 + settings.particles = 1000 + + # Create a uniform spatial source distribution over fissionable zones + bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) + settings.source = openmc.IndependentSource( + space=uniform_dist, constraints={'fissionable': True}) + + entropy_mesh = openmc.RegularMesh() + entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50] + entropy_mesh.upper_right = [0.39218, 0.39218, 1.e50] + entropy_mesh.dimension = [10, 10, 1] + settings.entropy_mesh = entropy_mesh + + tals = openmc.Tallies() + tal = openmc.Tally(tally_id=1, name='test') + tal.filters = [openmc.MaterialFilter(bins=[uo2])] + tal.scores = ['flux', 'fission'] + tals.append(tal) + + plot1 = openmc.Plot(plot_id=1) + plot1.origin = (0., 0., 0.) + plot1.width = (pitch, pitch) + plot1.pixels = (300, 300) + plot1.color_by = 'material' + plot1.filename = 'test' + plot2 = openmc.Plot(plot_id=2) + plot2.origin = (0., 0., 0.) + plot2.width = (pitch, pitch) + plot2.pixels = (300, 300) + plot2.color_by = 'cell' + plots = openmc.Plots((plot1, plot2)) + + chain = './test_chain.xml' + + chain_file_xml = """ + + + + + + 2.53000e-02 + + Xe136 + 1.0 + + + + +""" + operator_kwargs = {'chain_file': chain} + + return (mats, geom, settings, tals, plots, operator_kwargs, chain_file_xml) + + +def test_init(run_in_tmpdir, pin_model_attributes, mpi_intracomm): + mats, geom, settings, tals, plots, _, _ = \ + pin_model_attributes + + openmc.reset_auto_ids() + # Check blank initialization of a model + test_model = openmc.Model() + assert test_model.geometry.root_universe is None + assert len(test_model.materials) == 0 + ref_settings = openmc.Settings() + assert sorted(test_model.settings.__dict__.keys()) == \ + sorted(ref_settings.__dict__.keys()) + for ref_k, ref_v in ref_settings.__dict__.items(): + assert test_model.settings.__dict__[ref_k] == ref_v + assert len(test_model.tallies) == 0 + assert len(test_model.plots) == 0 + assert test_model._materials_by_id == {} + assert test_model._materials_by_name == {} + assert test_model._cells_by_id == {} + assert test_model._cells_by_name == {} + assert test_model.is_initialized is False + + # Now check proper init of an actual model. Assume no interference between + # parameters and so we can apply them all at once instead of testing one + # parameter initialization at a time + test_model = openmc.Model(geom, mats, settings, tals, plots) + assert test_model.geometry is geom + assert test_model.materials is mats + assert test_model.settings is settings + assert test_model.tallies is tals + assert test_model.plots is plots + assert test_model._materials_by_id == {1: mats[0], 2: mats[1], 3: mats[2]} + assert test_model._materials_by_name == { + 'UO2': {mats[0]}, 'Zirc': {mats[1]}, 'Borated water': {mats[2]}} + # The last cell is the one that contains the infinite fuel + assert test_model._cells_by_id == \ + {2: geom.root_universe.cells[2], 3: geom.root_universe.cells[3], + 4: geom.root_universe.cells[4], + 1: geom.root_universe.cells[2].fill.cells[1]} + # No cell name for 2 and 3, so we expect a blank name to be assigned to + # cell 3 due to overwriting + assert test_model._cells_by_name == { + 'fuel': {geom.root_universe.cells[2]}, + '': {geom.root_universe.cells[3], geom.root_universe.cells[4]}, + 'inf fuel': {geom.root_universe.cells[2].fill.cells[1]}} + assert test_model.is_initialized is False + + # Finally test the parameter type checking by passing bad types and + # obtaining the right exception types + def_params = [geom, mats, settings, tals, plots] + for i in range(len(def_params)): + args = def_params.copy() + # Try an integer, as that is a bad type for all arguments + args[i] = i + with pytest.raises(TypeError): + test_model = openmc.Model(*args) + + +def test_from_xml(run_in_tmpdir, pin_model_attributes): + mats, geom, settings, tals, plots, _, _ = pin_model_attributes + + # This test will write the individual files to xml and then init that way + # and run the same sort of test as in test_init + mats.export_to_xml() + geom.export_to_xml() + settings.export_to_xml() + tals.export_to_xml() + plots.export_to_xml() + + # This from_xml method cannot load chain and fission_q + test_model = openmc.Model.from_xml() + assert test_model.geometry.root_universe.cells.keys() == \ + geom.root_universe.cells.keys() + assert [c.fill.name for c in + test_model.geometry.root_universe.cells.values()] == \ + [c.fill.name for c in geom.root_universe.cells.values()] + assert [mat.name for mat in test_model.materials] == \ + [mat.name for mat in mats] + # We will assume the attributes of settings that are custom objects are + # OK if the others are so we dotn need to implement explicit comparisons + no_test = ['_source', '_entropy_mesh'] + assert sorted(k for k in test_model.settings.__dict__.keys() + if k not in no_test) == \ + sorted(k for k in settings.__dict__.keys() if k not in no_test) + keys = sorted(k for k in settings.__dict__.keys() if k not in no_test) + for ref_k in keys: + assert test_model.settings.__dict__[ref_k] == settings.__dict__[ref_k] + assert len(test_model.tallies) == 1 + assert len(test_model.plots) == 2 + assert test_model._materials_by_id == \ + {1: test_model.materials[0], 2: test_model.materials[1], + 3: test_model.materials[2]} + assert test_model._materials_by_name == { + 'UO2': {test_model.materials[0]}, 'Zirc': {test_model.materials[1]}, + 'Borated water': {test_model.materials[2]}} + assert test_model._cells_by_id == { + 2: test_model.geometry.root_universe.cells[2], + 3: test_model.geometry.root_universe.cells[3], + 4: test_model.geometry.root_universe.cells[4], + 1: test_model.geometry.root_universe.cells[2].fill.cells[1]} + # No cell name for 2 and 3, so we expect a blank name to be assigned to + # cell 3 due to overwriting + assert test_model._cells_by_name == { + 'fuel': {test_model.geometry.root_universe.cells[2]}, + '': {test_model.geometry.root_universe.cells[3], + test_model.geometry.root_universe.cells[4]}, + 'inf fuel': {test_model.geometry.root_universe.cells[2].fill.cells[1]}} + assert test_model.is_initialized is False + + +def test_init_finalize_lib(run_in_tmpdir, pin_model_attributes, mpi_intracomm): + # We are going to init and then make sure data is loaded + mats, geom, settings, tals, plots, _, _ = pin_model_attributes + test_model = openmc.Model(geom, mats, settings, tals, plots) + test_model.init_lib(output=False, intracomm=mpi_intracomm) + + # First check that the API is advertised as initialized + assert openmc.lib.is_initialized is True + assert test_model.is_initialized is True + # Now make sure it actually is initialized by making a call to the lib + c_mat = openmc.lib.find_material((0.6, 0., 0.)) + # This should be Borated water + assert c_mat.name == 'Borated water' + assert c_mat.id == 3 + + # Ok, now lets test that we can clear the data and check that it is cleared + test_model.finalize_lib() + + # First check that the API is advertised as initialized + assert openmc.lib.is_initialized is False + assert test_model.is_initialized is False + # Note we cant actually test that a sys call fails because we should get a + # seg fault + + +def test_import_properties(run_in_tmpdir, mpi_intracomm): + """Test importing properties on the Model class """ + + # Create PWR pin cell model and write XML files + openmc.reset_auto_ids() + model = openmc.examples.pwr_pin_cell() + model.init_lib(output=False, intracomm=mpi_intracomm) + + # Change fuel temperature and density and export properties + cell = openmc.lib.cells[1] + cell.set_temperature(600.0) + cell.fill.set_density(5.0, 'g/cm3') + openmc.lib.export_properties(output=False) + + # Import properties to existing model + model.import_properties("properties.h5") + + # Check to see that values are assigned to the C and python representations + # First python + cell = model.geometry.get_all_cells()[1] + assert cell.temperature == [600.0] + assert cell.fill.get_mass_density() == pytest.approx(5.0) + # Now C + assert openmc.lib.cells[1].get_temperature() == 600. + assert openmc.lib.materials[1].get_density('g/cm3') == pytest.approx(5.0) + + # Clear the C API + openmc.lib.finalize() + + # Verify the attributes survived by exporting to XML and re-creating + model.export_to_xml("with_properties") + + # Load model with properties and confirm temperature/density changed + model_with_properties = openmc.Model.from_xml( + 'with_properties/geometry.xml', + 'with_properties/materials.xml', + 'with_properties/settings.xml' + ) + cell = model_with_properties.geometry.get_all_cells()[1] + assert cell.temperature == [600.0] + assert cell.fill.get_mass_density() == pytest.approx(5.0) + + +def test_run(run_in_tmpdir, pin_model_attributes, mpi_intracomm): + mats, geom, settings, tals, plots, _, _ = pin_model_attributes + test_model = openmc.Model(geom, mats, settings, tals, plots) + + # This case will run by getting the k-eff and tallies for command-line and + # C API execution modes and ensuring they give the same result. + sp_path = test_model.run(output=False) + with openmc.StatePoint(sp_path) as sp: + cli_keff = sp.keff + cli_flux = sp.get_tally(id=1).get_values(scores=['flux'])[0, 0, 0] + cli_fiss = sp.get_tally(id=1).get_values(scores=['fission'])[0, 0, 0] + + test_model.init_lib(output=False, intracomm=mpi_intracomm) + sp_path = test_model.run(output=False) + with openmc.StatePoint(sp_path) as sp: + lib_keff = sp.keff + lib_flux = sp.get_tally(id=1).get_values(scores=['flux'])[0, 0, 0] + lib_fiss = sp.get_tally(id=1).get_values(scores=['fission'])[0, 0, 0] + + # and lets compare results + assert lib_keff.n == pytest.approx(cli_keff.n, abs=1e-13) + assert lib_flux == pytest.approx(cli_flux, abs=1e-13) + assert lib_fiss == pytest.approx(cli_fiss, abs=1e-13) + + # Now we should make sure that the flags for items which should be handled + # by init are properly set + with pytest.raises(ValueError): + test_model.run(threads=1) + with pytest.raises(ValueError): + test_model.run(geometry_debug=True) + with pytest.raises(ValueError): + test_model.run(restart_file='1.h5') + with pytest.raises(ValueError): + test_model.run(tracks=True) + + test_model.finalize_lib() + + +def test_plots(run_in_tmpdir, pin_model_attributes, mpi_intracomm): + mats, geom, settings, tals, plots, _, _ = pin_model_attributes + test_model = openmc.Model(geom, mats, settings, tals, plots) + + # This test cannot check the correctness of the plot, but it can + # check that a plot was made and that the expected png files are there + + # We will run the test twice, the first time without C API, the second with + for i in range(2): + if i == 1: + test_model.init_lib(output=False, intracomm=mpi_intracomm) + test_model.plot_geometry(output=False) + + # Now look for the files + for fname in ('test.png', 'plot_2.png'): + test_file = Path(fname) + assert test_file.exists() + test_file.unlink() + + test_model.finalize_lib() + + +def test_py_lib_attributes(run_in_tmpdir, pin_model_attributes, mpi_intracomm): + mats, geom, settings, tals, plots, _, _ = pin_model_attributes + test_model = openmc.Model(geom, mats, settings, tals, plots) + + test_model.init_lib(output=False, intracomm=mpi_intracomm) + + # Now we can call rotate_cells, translate_cells, update_densities, + # and update_cell_temperatures and make sure the changes have taken hold. + # For each we will first try bad inputs to make sure we get the right + # errors and then we do a good one which calls the material by name and + # then id to make sure it worked + + # The rotate_cells and translate_cells will work on the cell named fill, as + # it is filled with a universe and thus the operation will be valid + + # First rotate_cells + with pytest.raises(TypeError): + # Make sure it tells us we have a bad names_or_ids type + test_model.rotate_cells(None, (0, 0, 90)) + with pytest.raises(TypeError): + test_model.rotate_cells([None], (0, 0, 90)) + with pytest.raises(openmc.exceptions.InvalidIDError): + # Make sure it tells us we had a bad id + test_model.rotate_cells([7200], (0, 0, 90)) + with pytest.raises(openmc.exceptions.InvalidIDError): + # Make sure it tells us we had a bad id + test_model.rotate_cells(['bad_name'], (0, 0, 90)) + # Now a good one + assert np.all(openmc.lib.cells[2].rotation == (0., 0., 0.)) + test_model.rotate_cells([2], (0, 0, 90)) + assert np.all(openmc.lib.cells[2].rotation == (0., 0., 90.)) + + # And same thing by name + test_model.rotate_cells(['fuel'], (0, 0, 180)) + + # Now translate_cells. We dont need to re-check the TypeErrors/bad ids, + # because the other functions use the same hidden method as rotate_cells + assert np.all(openmc.lib.cells[2].translation == (0., 0., 0.)) + test_model.translate_cells([2], (0, 0, 10)) + assert np.all(openmc.lib.cells[2].translation == (0., 0., 10.)) + + # Now lets do the density updates. + # Check initial conditions + assert openmc.lib.materials[1].get_density('atom/b-cm') == \ + pytest.approx(0.06891296988603757, abs=1e-13) + mat_a_dens = np.sum( + list(test_model.materials[0].get_nuclide_atom_densities().values())) + assert mat_a_dens == pytest.approx(0.06891296988603757, abs=1e-8) + # Change the density + test_model.update_densities(['UO2'], 2.) + assert openmc.lib.materials[1].get_density('atom/b-cm') == \ + pytest.approx(2., abs=1e-13) + mat_a_dens = np.sum( + list(test_model.materials[0].get_nuclide_atom_densities().values())) + assert mat_a_dens == pytest.approx(2., abs=1e-8) + + # Now lets do the cell temperature updates. + # Check initial conditions + assert test_model._cells_by_id == \ + {2: geom.root_universe.cells[2], 3: geom.root_universe.cells[3], + 4: geom.root_universe.cells[4], + 1: geom.root_universe.cells[2].fill.cells[1]} + assert openmc.lib.cells[3].get_temperature() == \ + pytest.approx(293.6, abs=1e-13) + assert test_model.geometry.root_universe.cells[3].temperature is None + # Change the temperature + test_model.update_cell_temperatures([3], 600.) + assert openmc.lib.cells[3].get_temperature() == \ + pytest.approx(600., abs=1e-13) + assert test_model.geometry.root_universe.cells[3].temperature == \ + pytest.approx(600., abs=1e-13) + + # And finally material volume + assert openmc.lib.materials[1].volume == \ + pytest.approx(0.4831931368640985, abs=1e-13) + # The temperature on the material will be None because its just the default + assert test_model.materials[0].volume == \ + pytest.approx(0.4831931368640985, abs=1e-13) + # Change the temperature + test_model.update_material_volumes(['UO2'], 2.) + assert openmc.lib.materials[1].volume == pytest.approx(2., abs=1e-13) + assert test_model.materials[0].volume == pytest.approx(2., abs=1e-13) + + test_model.finalize_lib() + + +def test_deplete(run_in_tmpdir, pin_model_attributes, mpi_intracomm): + mats, geom, settings, tals, plots, op_kwargs, chain_file_xml = \ + pin_model_attributes + with open('test_chain.xml', 'w') as f: + f.write(chain_file_xml) + test_model = openmc.Model(geom, mats, settings, tals, plots) + + initial_mat = mats[0].clone() + initial_u = initial_mat.get_nuclide_atom_densities()['U235'] + + # Note that the chain file includes only U-235 fission to a stable Xe136 w/ + # a yield of 100%. Thus all the U235 we lose becomes Xe136 + + # In this test we first run without pre-initializing the shared library + # data and then compare. Then we repeat with the C API already initialized + # and make sure we get the same answer + test_model.deplete([1e6], 'predictor', final_step=False, + operator_kwargs=op_kwargs, + power=1., output=False) + # Get the new Xe136 and U235 atom densities + after_xe = mats[0].get_nuclide_atom_densities()['Xe136'] + after_u = mats[0].get_nuclide_atom_densities()['U235'] + assert after_xe + after_u == pytest.approx(initial_u, abs=1e-15) + assert test_model.is_initialized is False + + # check the tally output + def check_tally_output(): + with openmc.StatePoint('openmc_simulation_n0.h5') as sp: + flux = sp.get_tally(id=1).get_values(scores=['flux'])[0, 0, 0] + fission = sp.get_tally(id=1).get_values( + scores=['fission'])[0, 0, 0] + + # we're mainly just checking that the result was produced, + # so a rough numerical comparison doesn't hurt to have. + assert flux == pytest.approx(13.1, abs=0.2) + assert fission == pytest.approx(0.47, abs=0.2) + + check_tally_output() + + # Reset the initial material densities + mats[0].nuclides.clear() + densities = initial_mat.get_nuclide_atom_densities() + tot_density = 0. + for nuc, density in densities.items(): + mats[0].add_nuclide(nuc, density) + tot_density += density + mats[0].set_density('atom/b-cm', tot_density) + + # Now we can re-run with the pre-initialized API + test_model.init_lib(output=False, intracomm=mpi_intracomm) + test_model.deplete([1e6], 'predictor', final_step=False, + operator_kwargs=op_kwargs, + power=1., output=False) + # Get the new Xe136 and U235 atom densities + after_lib_xe = mats[0].get_nuclide_atom_densities()['Xe136'] + after_lib_u = mats[0].get_nuclide_atom_densities()['U235'] + assert after_lib_xe + after_lib_u == pytest.approx(initial_u, abs=1e-15) + assert test_model.is_initialized is True + + # And end by comparing to the previous case + assert after_xe == pytest.approx(after_lib_xe, abs=1e-15) + assert after_u == pytest.approx(after_lib_u, abs=1e-15) + + check_tally_output() + + test_model.finalize_lib() + + +def test_calc_volumes(run_in_tmpdir, pin_model_attributes, mpi_intracomm): + mats, geom, settings, tals, plots, _, _ = pin_model_attributes + + test_model = openmc.Model(geom, mats, settings, tals, plots) + + # With no vol calcs, it should fail + with pytest.raises(ValueError): + test_model.calculate_volumes(output=False) + + # Add a cell and mat volume calc + material_vol_calc = openmc.VolumeCalculation( + [mats[2]], samples=1000, lower_left=(-.63, -.63, -100.), + upper_right=(.63, .63, 100.)) + cell_vol_calc = openmc.VolumeCalculation( + [geom.root_universe.cells[3]], samples=1000, + lower_left=(-.63, -.63, -100.), upper_right=(.63, .63, 100.)) + test_model.settings.volume_calculations = \ + [material_vol_calc, cell_vol_calc] + + # Now lets compute the volumes and check to see if it was applied + # First lets do without using the C-API + # Make sure the volumes are unassigned first + assert mats[2].volume is None + assert geom.root_universe.cells[3].volume is None + test_model.calculate_volumes(output=False, apply_volumes=True) + + # Now let's test that we have volumes assigned; we arent checking the + # value, just that the value was changed + assert mats[2].volume > 0. + assert geom.root_universe.cells[3].volume > 0. + + # Now reset the values + mats[2].volume = None + geom.root_universe.cells[3].volume = None + + # And do again with an initialized library + for file in ['volume_1.h5', 'volume_2.h5']: + file = Path(file) + file.unlink() + test_model.init_lib(output=False, intracomm=mpi_intracomm) + test_model.calculate_volumes(output=False, apply_volumes=True) + assert mats[2].volume > 0. + assert geom.root_universe.cells[3].volume > 0. + assert openmc.lib.materials[3].volume == mats[2].volume + + test_model.finalize_lib() + + +def test_model_xml(run_in_tmpdir): + + # load a model from examples + pwr_model = openmc.examples.pwr_core() + + # export to separate XMLs manually + pwr_model.settings.export_to_xml('settings_ref.xml') + pwr_model.materials.export_to_xml('materials_ref.xml') + pwr_model.geometry.export_to_xml('geometry_ref.xml') + + # now write and read a model.xml file + pwr_model.export_to_model_xml() + new_model = openmc.Model.from_model_xml() + + # make sure we can also export this again to separate + # XML files + new_model.export_to_xml() + + +def test_single_xml_exec(run_in_tmpdir): + + pincell_model = openmc.examples.pwr_pin_cell() + + pincell_model.export_to_model_xml('pwr_pincell.xml') + + openmc.run(path_input='pwr_pincell.xml') + + with pytest.raises(RuntimeError, match='ex-em-ell.xml'): + openmc.run(path_input='ex-em-ell.xml') + + # test that a file in a different directory can be used + os.mkdir('inputs') + pincell_model.export_to_model_xml('./inputs/pincell.xml') + openmc.run(path_input='./inputs/pincell.xml') + + with pytest.raises(RuntimeError, match='input_dir'): + openmc.run(path_input='input_dir/pincell.xml') + + # Make sure path can be specified with run + pincell_model.run(path='my_model.xml') + + os.mkdir('subdir') + pincell_model.run(path='subdir') diff --git a/tests/unit_tests/test_no_visible_boundary.py b/tests/unit_tests/test_no_visible_boundary.py new file mode 100644 index 00000000000..7c53e4e3fa3 --- /dev/null +++ b/tests/unit_tests/test_no_visible_boundary.py @@ -0,0 +1,30 @@ +import openmc + + +def test_no_visible_boundary(run_in_tmpdir): + copper = openmc.Material() + copper.add_nuclide('Cu63', 1.0) + copper.set_density('g/cm3', 0.3) + air = openmc.Material() + air.add_nuclide('N14', 1.0) + air.set_density('g/cm3', 0.0012) + + # Create a simple model of a neutron source directly impinging on a thin + # disc of copper. Neutrons leaving the back of the disc see no surfaces in + # front of them. + disc = openmc.model.RightCircularCylinder((0., 0., 1.), 0.1, 1.2) + box = openmc.model.RectangularPrism(width=10, height=10, boundary_type='vacuum') + c1 = openmc.Cell(fill=copper, region=-disc) + c2 = openmc.Cell(fill=air, region=+disc & -box) + model = openmc.Model() + model.geometry = openmc.Geometry([c1, c2]) + model.settings.run_mode = 'fixed source' + model.settings.particles = 1000 + model.settings.batches = 5 + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Point(), + angle=openmc.stats.Monodirectional((0., 0., 1.)) + ) + + # Run model to ensure it doesn't segfault + model.run() diff --git a/tests/unit_tests/test_plots.py b/tests/unit_tests/test_plots.py index f2d3e101481..922e4d9dc95 100644 --- a/tests/unit_tests/test_plots.py +++ b/tests/unit_tests/test_plots.py @@ -1,3 +1,5 @@ +from pathlib import Path + import openmc import openmc.examples import pytest @@ -12,8 +14,8 @@ def myplot(): plot.filename = 'myplot' plot.type = 'slice' plot.basis = 'yz' - plot.background = (0, 0, 0) plot.background = 'black' + plot.background = (0, 0, 0) plot.color_by = 'material' m1, m2 = openmc.Material(), openmc.Material() @@ -21,8 +23,8 @@ def myplot(): plot.colors = {m1: 'green', m2: 'blue'} plot.mask_components = [openmc.Material()] - plot.mask_background = (255, 255, 255) plot.mask_background = 'white' + plot.mask_background = (255, 255, 255) plot.overlap_color = (255, 211, 0) plot.overlap_color = 'yellow' @@ -38,15 +40,84 @@ def myplot(): return plot +@pytest.fixture(scope='module') +def myprojectionplot(): + plot = openmc.ProjectionPlot(name='myprojectionplot') + plot.look_at = (0.0, 0.0, 0.0) + plot.camera_position = (4.0, 3.0, 0.0) + plot.pixels = (500, 500) + plot.filename = 'myprojectionplot' + plot.background = (0, 0, 0) + plot.background = 'black' + + plot.color_by = 'material' + m1, m2 = openmc.Material(), openmc.Material() + plot.colors = {m1: (0, 255, 0), m2: (0, 0, 255)} + plot.colors = {m1: 'green', m2: 'blue'} + plot.xs = {m1: 1.0, m2: 0.01} + + plot.mask_components = [openmc.Material()] + plot.mask_background = (255, 255, 255) + plot.mask_background = 'white' + + plot.overlap_color = (255, 211, 0) + plot.overlap_color = 'yellow' + + plot.wireframe_thickness = 2 + + plot.level = 1 + return plot + + +def test_voxel_plot(run_in_tmpdir): + # attempt to preload VTK and skip this test if unavailable + vtk = pytest.importorskip('vtk') + surf1 = openmc.Sphere(r=500, boundary_type='vacuum') + cell1 = openmc.Cell(region=-surf1) + geometry = openmc.Geometry([cell1]) + geometry.export_to_xml() + materials = openmc.Materials() + materials.export_to_xml() + vox_plot = openmc.Plot() + vox_plot.type = 'voxel' + vox_plot.id = 12 + vox_plot.width = (1500., 1500., 1500.) + vox_plot.pixels = (200, 200, 200) + vox_plot.color_by = 'cell' + vox_plot.to_vtk('test_voxel_plot.vti') + + assert Path('plot_12.h5').is_file() + assert Path('test_voxel_plot.vti').is_file() + + vox_plot.filename = 'h5_voxel_plot' + vox_plot.to_vtk('another_test_voxel_plot.vti') + + assert Path('h5_voxel_plot.h5').is_file() + assert Path('another_test_voxel_plot.vti').is_file() + + slice_plot = openmc.Plot() + with pytest.raises(ValueError): + slice_plot.to_vtk('shimmy.vti') + + def test_attributes(myplot): assert myplot.name == 'myplot' +def test_attributes_proj(myprojectionplot): + assert myprojectionplot.name == 'myprojectionplot' + + def test_repr(myplot): r = repr(myplot) assert isinstance(r, str) +def test_repr_proj(myprojectionplot): + r = repr(myprojectionplot) + assert isinstance(r, str) + + def test_from_geometry(): width = 25. s = openmc.Sphere(r=width/2, boundary_type='vacuum') @@ -58,6 +129,7 @@ def test_from_geometry(): plot = openmc.Plot.from_geometry(geom, basis) assert plot.origin == pytest.approx((0., 0., 0.)) assert plot.width == pytest.approx((width, width)) + assert plot.basis == basis def test_highlight_domains(): @@ -70,7 +142,7 @@ def test_highlight_domains(): plots.highlight_domains(model.geometry, mats) -def test_to_xml_element(myplot): +def test_xml_element(myplot): elem = myplot.to_xml_element() assert 'id' in elem.attrib assert 'color_by' in elem.attrib @@ -80,15 +152,72 @@ def test_to_xml_element(myplot): assert elem.find('pixels') is not None assert elem.find('background').text == '0 0 0' + newplot = openmc.Plot.from_xml_element(elem) + attributes = ('id', 'color_by', 'filename', 'type', 'basis', 'level', + 'meshlines', 'show_overlaps', 'origin', 'width', 'pixels', + 'background', 'mask_background') + for attr in attributes: + assert getattr(newplot, attr) == getattr(myplot, attr), attr + + +def test_to_xml_element_proj(myprojectionplot): + elem = myprojectionplot.to_xml_element() + assert 'id' in elem.attrib + assert 'color_by' in elem.attrib + assert 'type' in elem.attrib + assert elem.find('camera_position') is not None + assert elem.find('wireframe_thickness') is not None + assert elem.find('look_at') is not None + assert elem.find('pixels') is not None + assert elem.find('background').text == '0 0 0' + def test_plots(run_in_tmpdir): p1 = openmc.Plot(name='plot1') + p1.origin = (5., 5., 5.) + p1.colors = {10: (255, 100, 0)} + p1.mask_components = [2, 4, 6] p2 = openmc.Plot(name='plot2') + p2.origin = (-3., -3., -3.) plots = openmc.Plots([p1, p2]) assert len(plots) == 2 - p3 = openmc.Plot(name='plot3') - plots.append(p3) + p3 = openmc.ProjectionPlot(name='plot3') + plots = openmc.Plots([p1, p2, p3]) assert len(plots) == 3 + p4 = openmc.Plot(name='plot4') + plots.append(p4) + assert len(plots) == 4 + plots.export_to_xml() + + # from_xml + new_plots = openmc.Plots.from_xml() + assert len(new_plots) + assert new_plots[0].origin == p1.origin + assert new_plots[0].colors == p1.colors + assert new_plots[0].mask_components == p1.mask_components + assert new_plots[1].origin == p2.origin + + +def test_voxel_plot_roundtrip(): + # Define a voxel plot and create XML element + plot = openmc.Plot(name='my voxel plot') + plot.type = 'voxel' + plot.filename = 'voxel1' + plot.pixels = (50, 50, 50) + plot.origin = (0., 0., 0.) + plot.width = (75., 75., 75.) + plot.color_by = 'material' + elem = plot.to_xml_element() + + # Read back from XML and make sure it hasn't changed + new_plot = plot.from_xml_element(elem) + assert new_plot.name == plot.name + assert new_plot.filename == plot.filename + assert new_plot.type == plot.type + assert new_plot.pixels == plot.pixels + assert new_plot.origin == plot.origin + assert new_plot.width == plot.width + assert new_plot.color_by == plot.color_by diff --git a/tests/unit_tests/test_plotter.py b/tests/unit_tests/test_plotter.py new file mode 100644 index 00000000000..2c195c5e120 --- /dev/null +++ b/tests/unit_tests/test_plotter.py @@ -0,0 +1,183 @@ +import numpy as np +import openmc +import pytest + + +@pytest.fixture(scope='module') +def test_mat(): + mat_1 = openmc.Material() + mat_1.add_element("H", 4.0, "ao") + mat_1.add_element("O", 4.0, "ao") + mat_1.add_element("C", 4.0, "ao") + return mat_1 + + +def test_calculate_cexs_elem_mat_sab(test_mat): + """Checks that sab cross sections are included in the + _calculate_cexs_elem_mat method and have the correct shape""" + + test_mat.add_s_alpha_beta("c_C6H6") + test_mat.set_density("g/cm3", 0.865) + + energy_grid, data = openmc.plotter._calculate_cexs_elem_mat( + test_mat, + ["inelastic"], + sab_name="c_C6H6", + ) + + assert isinstance(energy_grid, np.ndarray) + assert isinstance(data, np.ndarray) + assert len(energy_grid) > 1 + assert len(data) == 1 + assert len(data[0]) == len(energy_grid) + + +@pytest.mark.parametrize("this", ["Li", "Li6"]) +def test_calculate_cexs_with_nuclide_and_element(this): + # single type (reaction) + energy_grid, data = openmc.plotter.calculate_cexs( + this=this, types=[205] + ) + + assert isinstance(energy_grid, np.ndarray) + assert isinstance(data, np.ndarray) + assert len(energy_grid) > 1 + assert len(data) == 1 + assert len(data[0]) == len(energy_grid) + + # two types (reactions) + energy_grid, data = openmc.plotter.calculate_cexs( + this=this, types=[2, "elastic"] + ) + + assert isinstance(energy_grid, np.ndarray) + assert isinstance(data, np.ndarray) + assert len(energy_grid) > 1 + assert len(data) == 2 + assert len(data[0]) == len(energy_grid) + assert len(data[0]) == len(energy_grid) + # reactions are both the same MT number 2 is elastic + assert np.array_equal(data[0], data[1]) + + +def test_calculate_cexs_with_materials(test_mat): + energy_grid, data = openmc.plotter.calculate_cexs( + this=test_mat, types=[205] + ) + + assert isinstance(energy_grid, np.ndarray) + assert isinstance(data, np.ndarray) + assert len(energy_grid) > 1 + assert len(data) == 1 + assert len(data[0]) == len(energy_grid) + + +@pytest.mark.parametrize("this", ["Be", "Be9"]) +def test_plot_xs(this): + from matplotlib.figure import Figure + assert isinstance(openmc.plot_xs({this: ['total', 'elastic']}), Figure) + + +def test_plot_xs_mat(test_mat): + from matplotlib.figure import Figure + assert isinstance(openmc.plot_xs({test_mat: ['total']}), Figure) + + +@pytest.mark.parametrize("units", ["eV", "keV", "MeV"]) +def test_plot_xs_energy_axis(units): + plot = openmc.plot_xs({'Be9': ['(n,2n)']}, energy_axis_units=units) + axis_text = plot.get_axes()[0].get_xaxis().get_label().get_text() + assert axis_text == f'Energy [{units}]' + + +def test_plot_axes_labels(): + # just nuclides + axis_label = openmc.plotter._get_yaxis_label( + reactions={ + 'Li6': [205], + 'Li7': [205], + }, divisor_types=False + ) + assert axis_label == 'Microscopic Cross Section [b]' + + # just elements + axis_label = openmc.plotter._get_yaxis_label( + reactions={ + 'Li': [205], + 'Be': [16], + }, divisor_types=False + ) + assert axis_label == 'Microscopic Cross Section [b]' + + # mixed nuclide and element + axis_label = openmc.plotter._get_yaxis_label( + reactions={ + 'Li': [205], + 'Li7': [205], + }, divisor_types=False + ) + assert axis_label == 'Microscopic Cross Section [b]' + + axis_label = openmc.plotter._get_yaxis_label( + reactions={ + "Li": ["heating", "heating-local"], + "Li7": ["heating"], + "Be": ["damage-energy"], + }, + divisor_types=False, + ) + assert axis_label == "Heating Cross Section [eV-barn]" + + with pytest.raises(TypeError): + axis_label = openmc.plotter.plot_xs( + reactions={"Li": ["heating", "heating-local"], "Be9": ["(n,2n)"]} + ) + + # just materials + mat1 = openmc.Material() + mat1.add_nuclide('Fe56', 1) + mat1.set_density('g/cm3', 1) + mat2 = openmc.Material() + mat2.add_element('Fe', 1) + mat2.add_nuclide('Fe55', 1) + mat2.set_density('g/cm3', 1) + axis_label = openmc.plotter._get_yaxis_label( + reactions={ + mat1: [205], + mat2: [16], + }, divisor_types=False + ) + assert axis_label == 'Macroscopic Cross Section [1/cm]' + + # mixed materials and nuclides + with pytest.raises(TypeError): + openmc.plotter._get_yaxis_label( + reactions={'Li6': [205], mat2: [16]}, + divisor_types=False + ) + + # mixed materials and elements + with pytest.raises(TypeError): + openmc.plotter._get_yaxis_label( + reactions={'Li': [205], mat2: [16]}, + divisor_types=False + ) + + +def test_get_title(): + title = openmc.plotter._get_title(reactions={'Li': [205]}) + assert title == 'Cross Section Plot For Li' + title = openmc.plotter._get_title(reactions={'Li6': [205]}) + assert title == 'Cross Section Plot For Li6' + title = openmc.plotter._get_title(reactions={ + 'Li6': [205], + 'Li7': [205] + }) + assert title == 'Cross Section Plot' + + mat1 = openmc.Material() + mat1.add_nuclide('Fe56', 1) + mat1.set_density('g/cm3', 1) + mat1.name = 'my_mat' + title = openmc.plotter._get_title(reactions={mat1: [205]}) + assert title == 'Cross Section Plot For my_mat' diff --git a/tests/unit_tests/test_region.py b/tests/unit_tests/test_region.py index 8b2e06ad1be..8c9e0afe4d9 100644 --- a/tests/unit_tests/test_region.py +++ b/tests/unit_tests/test_region.py @@ -200,3 +200,54 @@ def test_from_expression(reset): assert isinstance(r, openmc.Intersection) assert isinstance(r[1], openmc.Union) assert r[1][:] == [-s2, +s3] + + # Make sure ")(" is handled correctly + r = openmc.Region.from_expression('(-1|2)(2|-3)', surfs) + assert str(r) == '((-1 | 2) (2 | -3))' + + # Opening parenthesis immediately after halfspace + r = openmc.Region.from_expression('1(2|-3)', surfs) + assert str(r) == '(1 (2 | -3))' + r = openmc.Region.from_expression('-1|(1 2(-3))', surfs) + assert str(r) == '(-1 | (1 2 -3))' + +def test_translate_inplace(): + sph = openmc.Sphere() + x = openmc.XPlane() + region = -sph & +x + + # Translating a region should produce new surfaces + region2 = region.translate((0.5, -6.7, 3.9), inplace=False) + assert str(region) != str(region2) + + # Translating a region in-place should *not* produce new surfaces + region3 = region.translate((0.5, -6.7, 3.9), inplace=True) + assert str(region) == str(region3) + + +def test_invalid_operands(): + s = openmc.Sphere() + z = 3 + + # Intersection with invalid operand + with pytest.raises(ValueError, match='must be of type Region'): + -s & +z + + # Union with invalid operand + with pytest.raises(ValueError, match='must be of type Region'): + -s | +z + + # Complement with invalid operand + with pytest.raises(ValueError, match='must be of type Region'): + openmc.Complement(z) + + +def test_plot(): + # Create region and plot + region = -openmc.Sphere() & +openmc.XPlane() + c_before = openmc.Cell() + region.plot() + + # Ensure that calling plot doesn't affect cell ID space + c_after = openmc.Cell() + assert c_after.id - 1 == c_before.id diff --git a/tests/unit_tests/test_settings.py b/tests/unit_tests/test_settings.py index 7a3357d4392..650bfd18680 100644 --- a/tests/unit_tests/test_settings.py +++ b/tests/unit_tests/test_settings.py @@ -3,9 +3,7 @@ def test_export_to_xml(run_in_tmpdir): - s = openmc.Settings() - s.run_mode = 'fixed source' - s.batches = 1000 + s = openmc.Settings(run_mode='fixed source', batches=1000, seed=17) s.generations_per_batch = 10 s.inactive = 100 s.particles = 1000000 @@ -14,21 +12,24 @@ def test_export_to_xml(run_in_tmpdir): s.keff_trigger = {'type': 'std_dev', 'threshold': 0.001} s.energy_mode = 'continuous-energy' s.max_order = 5 - s.source = openmc.Source(space=openmc.stats.Point()) + s.max_tracks = 1234 + s.source = openmc.IndependentSource(space=openmc.stats.Point()) s.output = {'summary': True, 'tallies': False, 'path': 'here'} s.verbosity = 7 s.sourcepoint = {'batches': [50, 150, 500, 1000], 'separate': True, - 'write': True, 'overwrite': True} + 'write': True, 'overwrite': True, 'mcpl': True} s.statepoint = {'batches': [50, 150, 500, 1000]} s.surf_source_read = {'path': 'surface_source_1.h5'} s.surf_source_write = {'surface_ids': [2], 'max_particles': 200} s.confidence_intervals = True s.ptables = True - s.seed = 17 + s.plot_seed = 100 s.survival_biasing = True s.cutoff = {'weight': 0.25, 'weight_avg': 0.5, 'energy_neutron': 1.0e-5, 'energy_photon': 1000.0, 'energy_electron': 1.0e-5, - 'energy_positron': 1.0e-5} + 'energy_positron': 1.0e-5, 'time_neutron': 1.0e-5, + 'time_photon': 1.0e-5, 'time_electron': 1.0e-5, + 'time_positron': 1.0e-5} mesh = openmc.RegularMesh() mesh.lower_left = (-10., -10., -10.) mesh.upper_right = (10., 10., 10.) @@ -42,7 +43,7 @@ def test_export_to_xml(run_in_tmpdir): s.temperature = {'default': 293.6, 'method': 'interpolation', 'multipole': True, 'range': (200., 1000.)} s.trace = (10, 1, 20) - s.track = [1, 1, 1, 2, 1, 1] + s.track = [(1, 1, 1), (2, 1, 1)] s.ufs_mesh = mesh s.resonance_scattering = {'enable': True, 'method': 'rvs', 'energy_min': 1.0, 'energy_max': 1000.0, @@ -51,10 +52,21 @@ def test_export_to_xml(run_in_tmpdir): domains=[openmc.Cell()], samples=1000, lower_left=(-10., -10., -10.), upper_right = (10., 10., 10.)) s.create_fission_neutrons = True + s.create_delayed_neutrons = False s.log_grid_bins = 2000 s.photon_transport = False s.electron_treatment = 'led' - s.dagmc = False + s.write_initial_source = True + s.weight_window_checkpoints = {'surface': True, 'collision': False} + s.random_ray = { + 'distance_inactive': 10.0, + 'distance_active': 100.0, + 'ray_source': openmc.IndependentSource( + space=openmc.stats.Box((-1., -1., -1.), (1., 1., 1.)) + ) + } + + s.max_particle_events = 100 # Make sure exporting XML works s.export_to_xml() @@ -71,26 +83,30 @@ def test_export_to_xml(run_in_tmpdir): assert s.keff_trigger == {'type': 'std_dev', 'threshold': 0.001} assert s.energy_mode == 'continuous-energy' assert s.max_order == 5 - assert isinstance(s.source[0], openmc.Source) + assert s.max_tracks == 1234 + assert isinstance(s.source[0], openmc.IndependentSource) assert isinstance(s.source[0].space, openmc.stats.Point) assert s.output == {'summary': True, 'tallies': False, 'path': 'here'} assert s.verbosity == 7 assert s.sourcepoint == {'batches': [50, 150, 500, 1000], 'separate': True, - 'write': True, 'overwrite': True} + 'write': True, 'overwrite': True, 'mcpl': True} assert s.statepoint == {'batches': [50, 150, 500, 1000]} assert s.surf_source_read == {'path': 'surface_source_1.h5'} assert s.surf_source_write == {'surface_ids': [2], 'max_particles': 200} assert s.confidence_intervals assert s.ptables + assert s.plot_seed == 100 assert s.seed == 17 assert s.survival_biasing assert s.cutoff == {'weight': 0.25, 'weight_avg': 0.5, 'energy_neutron': 1.0e-5, 'energy_photon': 1000.0, - 'energy_electron': 1.0e-5, 'energy_positron': 1.0e-5} + 'energy_electron': 1.0e-5, 'energy_positron': 1.0e-5, + 'time_neutron': 1.0e-5, 'time_photon': 1.0e-5, + 'time_electron': 1.0e-5, 'time_positron': 1.0e-5} assert isinstance(s.entropy_mesh, openmc.RegularMesh) assert s.entropy_mesh.lower_left == [-10., -10., -10.] assert s.entropy_mesh.upper_right == [10., 10., 10.] - assert s.entropy_mesh.dimension == [5, 5, 5] + assert s.entropy_mesh.dimension == (5, 5, 5) assert s.trigger_active assert s.trigger_max_batches == 10000 assert s.trigger_batch_interval == 50 @@ -99,16 +115,30 @@ def test_export_to_xml(run_in_tmpdir): assert s.temperature == {'default': 293.6, 'method': 'interpolation', 'multipole': True, 'range': [200., 1000.]} assert s.trace == [10, 1, 20] - assert s.track == [1, 1, 1, 2, 1, 1] + assert s.track == [(1, 1, 1), (2, 1, 1)] assert isinstance(s.ufs_mesh, openmc.RegularMesh) assert s.ufs_mesh.lower_left == [-10., -10., -10.] assert s.ufs_mesh.upper_right == [10., 10., 10.] - assert s.ufs_mesh.dimension == [5, 5, 5] + assert s.ufs_mesh.dimension == (5, 5, 5) assert s.resonance_scattering == {'enable': True, 'method': 'rvs', 'energy_min': 1.0, 'energy_max': 1000.0, 'nuclides': ['U235', 'U238', 'Pu239']} assert s.create_fission_neutrons + assert not s.create_delayed_neutrons assert s.log_grid_bins == 2000 assert not s.photon_transport assert s.electron_treatment == 'led' - assert not s.dagmc + assert s.write_initial_source == True + assert len(s.volume_calculations) == 1 + vol = s.volume_calculations[0] + assert vol.domain_type == 'cell' + assert len(vol.ids) == 1 + assert vol.samples == 1000 + assert vol.lower_left == (-10., -10., -10.) + assert vol.upper_right == (10., 10., 10.) + assert s.weight_window_checkpoints == {'surface': True, 'collision': False} + assert s.max_particle_events == 100 + assert s.random_ray['distance_inactive'] == 10.0 + assert s.random_ray['distance_active'] == 100.0 + assert s.random_ray['ray_source'].space.lower_left == [-1., -1., -1.] + assert s.random_ray['ray_source'].space.upper_right == [1., 1., 1.] diff --git a/tests/unit_tests/test_source.py b/tests/unit_tests/test_source.py index d4d17a3dab6..9a19f6f24dd 100644 --- a/tests/unit_tests/test_source.py +++ b/tests/unit_tests/test_source.py @@ -1,5 +1,13 @@ +from math import pi + import openmc +import openmc.lib import openmc.stats +import numpy as np +import pytest +from pytest import approx + +from tests.regression_tests import config def test_source(): @@ -7,7 +15,7 @@ def test_source(): energy = openmc.stats.Discrete([1.0e6], [1.0]) angle = openmc.stats.Isotropic() - src = openmc.Source(space=space, angle=angle, energy=energy) + src = openmc.IndependentSource(space=space, angle=angle, energy=energy) assert src.space == space assert src.angle == angle assert src.energy == energy @@ -18,7 +26,7 @@ def test_source(): assert elem.find('angle') is not None assert elem.find('energy') is not None - src = openmc.Source.from_xml_element(elem) + src = openmc.IndependentSource.from_xml_element(elem) assert isinstance(src.angle, openmc.stats.Isotropic) assert src.space.xyz == [0.0, 0.0, 0.0] assert src.energy.x == [1.0e6] @@ -26,19 +34,213 @@ def test_source(): assert src.strength == 1.0 +def test_spherical_uniform(): + r_outer = 2.0 + r_inner = 1.0 + thetas = (0.0, pi/2) + phis = (0.0, pi) + origin = (0.0, 1.0, 2.0) + + sph_indep_function = openmc.stats.spherical_uniform(r_outer, + r_inner, + thetas, + phis, + origin) + + assert isinstance(sph_indep_function, openmc.stats.SphericalIndependent) + + def test_source_file(): filename = 'source.h5' - src = openmc.Source(filename=filename) - assert src.file == filename + src = openmc.FileSource(path=filename) + assert src.path == filename elem = src.to_xml_element() assert 'strength' in elem.attrib assert 'file' in elem.attrib + def test_source_dlopen(): library = './libsource.so' - src = openmc.Source(library=library) + src = openmc.CompiledSource(library=library) assert src.library == library elem = src.to_xml_element() assert 'library' in elem.attrib + + +def test_source_xml_roundtrip(): + # Create a source and write to an XML element + space = openmc.stats.Box([-5., -5., -5.], [5., 5., 5.]) + energy = openmc.stats.Discrete([1.0e6, 2.0e6, 5.0e6], [0.3, 0.5, 0.2]) + angle = openmc.stats.PolarAzimuthal( + mu=openmc.stats.Uniform(0., 1.), + phi=openmc.stats.Uniform(0., 2*pi), + reference_uvw=(0., 1., 0.) + ) + src = openmc.IndependentSource( + space=space, angle=angle, energy=energy, + particle='photon', strength=100.0 + ) + elem = src.to_xml_element() + + # Read from XML element and make sure data is preserved + new_src = openmc.IndependentSource.from_xml_element(elem) + assert isinstance(new_src.space, openmc.stats.Box) + np.testing.assert_allclose(new_src.space.lower_left, src.space.lower_left) + np.testing.assert_allclose(new_src.space.upper_right, src.space.upper_right) + assert isinstance(new_src.energy, openmc.stats.Discrete) + np.testing.assert_allclose(new_src.energy.x, src.energy.x) + np.testing.assert_allclose(new_src.energy.p, src.energy.p) + assert isinstance(new_src.angle, openmc.stats.PolarAzimuthal) + assert new_src.angle.mu.a == src.angle.mu.a + assert new_src.angle.mu.b == src.angle.mu.b + assert new_src.angle.phi.a == src.angle.phi.a + assert new_src.angle.phi.b == src.angle.phi.b + np.testing.assert_allclose(new_src.angle.reference_uvw, src.angle.reference_uvw) + assert new_src.particle == src.particle + assert new_src.strength == approx(src.strength) + + +@pytest.fixture +def sphere_box_model(): + # Model with two spheres inside a box + mat = openmc.Material() + mat.add_nuclide('H1', 1.0) + sph1 = openmc.Sphere(x0=3, r=1.0) + sph2 = openmc.Sphere(x0=-3, r=1.0) + cube = openmc.model.RectangularParallelepiped( + -5., 5., -5., 5., -5., 5., boundary_type='reflective' + ) + cell1 = openmc.Cell(fill=mat, region=-sph1) + cell2 = openmc.Cell(fill=mat, region=-sph2) + non_source_region = +sph1 & +sph2 & -cube + cell3 = openmc.Cell(region=non_source_region) + model = openmc.Model() + model.geometry = openmc.Geometry([cell1, cell2, cell3]) + model.settings.particles = 100 + model.settings.batches = 10 + model.settings.run_mode = 'fixed source' + + return model, cell1, cell2, cell3 + + +def test_constraints_independent(sphere_box_model, run_in_tmpdir): + model, cell1, cell2, cell3 = sphere_box_model + + # Set up a box source with rejection on the spherical cell + space = openmc.stats.Box((-4., -1., -1.), (4., 1., 1.)) + model.settings.source = openmc.IndependentSource( + space=space, constraints={'domains': [cell1, cell2]} + ) + + # Load up model via openmc.lib and sample source + model.export_to_model_xml() + openmc.lib.init() + particles = openmc.lib.sample_external_source(1000) + + # Make sure that all sampled sources are within one of the spheres + for p in particles: + assert p.r in (cell1.region | cell2.region) + assert p.r not in cell3.region + + openmc.lib.finalize() + + +def test_constraints_mesh(sphere_box_model, run_in_tmpdir): + model, cell1, cell2, cell3 = sphere_box_model + + bbox = cell3.bounding_box + mesh = openmc.RegularMesh() + mesh.lower_left = bbox.lower_left + mesh.upper_right = bbox.upper_right + mesh.dimension = (2, 1, 1) + + left_source = openmc.IndependentSource() + right_source = openmc.IndependentSource() + model.settings.source = openmc.MeshSource( + mesh, [left_source, right_source], constraints={'domains': [cell1, cell2]} + ) + + # Load up model via openmc.lib and sample source + model.export_to_model_xml() + openmc.lib.init() + particles = openmc.lib.sample_external_source(1000) + + # Make sure that all sampled sources are within one of the spheres + for p in particles: + assert p.r in (cell1.region | cell2.region) + assert p.r not in cell3.region + + openmc.lib.finalize() + + +def test_constraints_file(sphere_box_model, run_in_tmpdir): + model = sphere_box_model[0] + + # Create source file with randomly sampled source sites + rng = np.random.default_rng() + energy = rng.uniform(0., 1e6, 10_000) + time = rng.uniform(0., 1., 10_000) + particles = [openmc.SourceParticle(E=e, time=t) for e, t in zip(energy, time)] + openmc.write_source_file(particles, 'uniform_source.h5') + + # Use source file + model.settings.source = openmc.FileSource( + 'uniform_source.h5', + constraints={ + 'time_bounds': [0.25, 0.75], + 'energy_bounds': [500.e3, 1.0e6], + } + ) + + # Load up model via openmc.lib and sample source + model.export_to_model_xml() + openmc.lib.init() + particles = openmc.lib.sample_external_source(1000) + + # Make sure that all sampled sources are within energy/time bounds + for p in particles: + assert 0.25 <= p.time <= 0.75 + assert 500.e3 <= p.E <= 1.0e6 + + openmc.lib.finalize() + + +@pytest.mark.skipif(config['mpi'], reason='Not compatible with MPI') +def test_rejection_limit(sphere_box_model, run_in_tmpdir): + model, cell1 = sphere_box_model[:2] + + # Define a point source that will get rejected 100% of the time + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Point((-3., 0., 0.)), + constraints={'domains': [cell1]} + ) + + # Confirm that OpenMC doesn't run in an infinite loop. Note that this may + # work when running with MPI since it won't necessarily capture the error + # message correctly + with pytest.raises(RuntimeError, match="rejected"): + model.run(openmc_exec=config['exe']) + + +def test_exceptions(): + + with pytest.raises(AttributeError, match=r'Please use the FileSource class'): + s = openmc.IndependentSource() + s.file = 'my_file' + + with pytest.raises(AttributeError, match=r'Please use the CompiledSource class'): + s = openmc.IndependentSource() + s.library = 'my_library' + + with pytest.raises(AttributeError, match=r'Please use the CompiledSource class'): + s = openmc.IndependentSource() + s.parameters = 'my_params' + + with pytest.warns(FutureWarning, match=r'in favor of \'IndependentSource\''): + s = openmc.Source() + + with pytest.raises(AttributeError, match=r'has no attribute \'frisbee\''): + s = openmc.IndependentSource() + s.frisbee diff --git a/tests/unit_tests/test_source_file.py b/tests/unit_tests/test_source_file.py index 8166f571265..1b5549b008e 100644 --- a/tests/unit_tests/test_source_file.py +++ b/tests/unit_tests/test_source_file.py @@ -1,5 +1,4 @@ from random import random -import subprocess import h5py import numpy as np @@ -46,6 +45,30 @@ def test_source_file(run_in_tmpdir): assert np.all(arr['particle'] == 0) + # Ensure sites read in are consistent + sites = openmc.read_source_file('test_source.h5') + + assert filetype == b'source' + xs = np.array([site.r[0] for site in sites]) + ys = np.array([site.r[1] for site in sites]) + zs = np.array([site.r[2] for site in sites]) + assert np.all((xs > 0.0) & (xs < 1.0)) + assert np.all(ys == np.arange(1000)) + assert np.all(zs == 0.0) + u = np.array([s.u for s in sites]) + assert np.all(u[..., 0] == 0.0) + assert np.all(u[..., 1] == 0.0) + assert np.all(u[..., 2] == 1.0) + E = np.array([s.E for s in sites]) + assert np.all(E == n - np.arange(n)) + wgt = np.array([s.wgt for s in sites]) + assert np.all(wgt == 1.0) + dgs = np.array([s.delayed_group for s in sites]) + assert np.all(dgs == 0) + p_types = np.array([s.particle for s in sites]) + assert np.all(p_types == 0) + + def test_wrong_source_attributes(run_in_tmpdir): # Create a source file with animal attributes source_dtype = np.dtype([ @@ -55,7 +78,7 @@ def test_wrong_source_attributes(run_in_tmpdir): ]) arr = np.array([(1.0, 2.0, 3), (4.0, 5.0, 6), (7.0, 8.0, 9)], dtype=source_dtype) with h5py.File('animal_source.h5', 'w') as fh: - fh.attrs['filetype'] = np.string_("source") + fh.attrs['filetype'] = np.bytes_("source") fh.create_dataset('source_bank', data=arr) # Create a simple model that uses this lovely animal source @@ -68,7 +91,7 @@ def test_wrong_source_attributes(run_in_tmpdir): settings = openmc.Settings() settings.particles = 100 settings.batches = 10 - settings.source = openmc.Source(filename='animal_source.h5') + settings.source = openmc.FileSource(path='animal_source.h5') settings.export_to_xml() # When we run the model, it should error out with a message that includes @@ -76,3 +99,25 @@ def test_wrong_source_attributes(run_in_tmpdir): with pytest.raises(RuntimeError) as excinfo: openmc.run() assert 'platypus, axolotl, narwhal' in str(excinfo.value) + + +def test_source_file_transport(run_in_tmpdir): + # Create a source file with a single particle + particle = openmc.SourceParticle() + openmc.write_source_file([particle], 'source.h5') + + # Created simple model to use source file + model = openmc.Model() + al = openmc.Material() + al.add_element('Al', 1.0) + al.set_density('g/cm3', 2.7) + sph = openmc.Sphere(r=10.0, boundary_type='vacuum') + cell = openmc.Cell(fill=al, region=-sph) + model.geometry = openmc.Geometry([cell]) + model.settings.source = openmc.FileSource(path='source.h5') + model.settings.particles = 10 + model.settings.batches = 3 + model.settings.run_mode = 'fixed source' + + # Try running OpenMC + model.run() diff --git a/tests/unit_tests/test_source_mesh.py b/tests/unit_tests/test_source_mesh.py new file mode 100644 index 00000000000..43bb1678c40 --- /dev/null +++ b/tests/unit_tests/test_source_mesh.py @@ -0,0 +1,398 @@ +from itertools import product +from pathlib import Path + +import pytest +import numpy as np +import openmc +import openmc.lib + +from tests import cdtemp + + +################### +# MeshSpatial Tests +################### +TETS_PER_VOXEL = 12 + +# This test uses a geometry file with cells that match a regular mesh. Each cell +# in the geometry corresponds to 12 tetrahedra in the unstructured mesh file. +@pytest.fixture +def model(): + openmc.reset_auto_ids() + + ### Materials ### + materials = openmc.Materials() + + water_mat = openmc.Material(name="water") + water_mat.add_nuclide("H1", 2.0) + water_mat.add_nuclide("O16", 1.0) + water_mat.set_density("atom/b-cm", 0.07416) + materials.append(water_mat) + + ### Geometry ### + # This test uses a geometry file that resembles a regular mesh. + # 12 tets are used to match each voxel in the geometry. + + # create a regular mesh that matches the superimposed mesh + regular_mesh = openmc.RegularMesh(mesh_id=10) + regular_mesh.lower_left = (-10, -10, -10) + regular_mesh.dimension = (10, 10, 10) + regular_mesh.width = (2, 2, 2) + + root_cell, _ = regular_mesh.build_cells(bc=['vacuum']*6) + + geometry = openmc.Geometry(root=[root_cell]) + + ### Settings ### + settings = openmc.Settings() + settings.run_mode = 'fixed source' + settings.particles = 100 + settings.batches = 2 + + return openmc.Model(geometry=geometry, + materials=materials, + settings=settings) + +### Setup test cases ### +param_values = (['libmesh', 'moab'], # mesh libraries + ['uniform', 'manual']) # Element weighting schemes + +test_cases = [] +for i, (lib, schemes) in enumerate(product(*param_values)): + test_cases.append({'library' : lib, + 'source_strengths' : schemes}) + +def ids(params): + """Test naming function for clarity""" + return f"{params['library']}-{params['source_strengths']}" + +@pytest.mark.parametrize("test_cases", test_cases, ids=ids) +def test_unstructured_mesh_sampling(model, request, test_cases): + # skip the test if the library is not enabled + if test_cases['library'] == 'moab' and not openmc.lib._dagmc_enabled(): + pytest.skip("DAGMC (and MOAB) mesh not enabled in this build.") + + if test_cases['library'] == 'libmesh' and not openmc.lib._libmesh_enabled(): + pytest.skip("LibMesh is not enabled in this build.") + + # setup mesh source ### + mesh_filename = Path(request.fspath).parent / "test_mesh_tets.e" + uscd_mesh = openmc.UnstructuredMesh(mesh_filename, test_cases['library']) + + # subtract one to account for root cell produced by RegularMesh.build_cells + n_cells = len(model.geometry.get_all_cells()) - 1 + + # set source weights according to test case + if test_cases['source_strengths'] == 'uniform': + vol_norm = True + strengths = None + elif test_cases['source_strengths'] == 'manual': + vol_norm = False + # assign random weights + strengths = np.random.rand(n_cells*TETS_PER_VOXEL) + + # create the spatial distribution based on the mesh + space = openmc.stats.MeshSpatial(uscd_mesh, strengths, vol_norm) + + energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) + source = openmc.IndependentSource(space=space, energy=energy) + model.settings.source = source + + with cdtemp([mesh_filename]): + model.export_to_xml() + + n_measurements = 100 + n_samples = 1000 + + cell_counts = np.zeros((n_cells, n_measurements)) + + # This model contains 1000 geometry cells. Each cell is a hex + # corresponding to 12 of the tets. This test runs 1000 samples. This + # results in the following average for each cell + openmc.lib.init([]) + + # perform many sets of samples and track counts for each cell + for m in range(n_measurements): + sites = openmc.lib.sample_external_source(n_samples) + cells = [openmc.lib.find_cell(s.r) for s in sites] + + for c in cells: + # subtract one from index to account for root cell + cell_counts[c[0]._index - 1, m] += 1 + + # make sure particle transport is successful + openmc.lib.run() + openmc.lib.finalize() + + # normalize cell counts to get sampling frequency per particle + cell_counts /= n_samples + + # get the mean and std. dev. of the cell counts + mean = cell_counts.mean(axis=1) + std_dev = cell_counts.std(axis=1) + + if test_cases['source_strengths'] == 'uniform': + exp_vals = np.ones(n_cells) / n_cells + else: + # sum up the source strengths for each tet, these are the expected true mean + # of the sampling frequency for that cell + exp_vals = strengths.reshape(-1, 12).sum(axis=1) / sum(strengths) + + diff = np.abs(mean - exp_vals) + assert((diff < 2*std_dev).sum() / diff.size >= 0.95) + assert((diff < 6*std_dev).sum() / diff.size >= 0.997) + + +def test_strengths_size_failure(request, model): + # setup mesh source ### + mesh_filename = Path(request.fspath).parent / "test_mesh_tets.e" + uscd_mesh = openmc.UnstructuredMesh(mesh_filename, 'libmesh') + + # intentionally incorrectly sized to trigger an error + n_cells = len(model.geometry.get_all_cells()) + strengths = np.random.rand(n_cells*TETS_PER_VOXEL) + + # create the spatial distribution based on the mesh + space = openmc.stats.MeshSpatial(uscd_mesh, strengths) + + energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) + source = openmc.IndependentSource(space=space, energy=energy) + model.settings.source = source + + # skip the test if unstructured mesh is not available + if not openmc.lib._libmesh_enabled(): + if openmc.lib._dagmc_enabled(): + source.space.mesh.library = 'moab' + else: + pytest.skip("Unstructured mesh support unavailable.") + + # make sure that an incorrrectly sized strengths array causes a failure + source.space.strengths = source.space.strengths[:-1] + + mesh_filename = Path(request.fspath).parent / source.space.mesh.filename + + with pytest.raises(RuntimeError, match=r'strengths array'), cdtemp([mesh_filename]): + model.export_to_xml() + openmc.run() + + +def test_roundtrip(run_in_tmpdir, model, request): + if not openmc.lib._libmesh_enabled() and not openmc.lib._dagmc_enabled(): + pytest.skip("Unstructured mesh is not enabled in this build.") + + mesh_filename = Path(request.fspath).parent / 'test_mesh_tets.e' + ucd_mesh = openmc.UnstructuredMesh(mesh_filename, library='libmesh') + + if not openmc.lib._libmesh_enabled(): + ucd_mesh.library = 'moab' + + n_cells = len(model.geometry.get_all_cells()) + + space_out = openmc.MeshSpatial(ucd_mesh) + space_out.strengths = np.random.rand(n_cells*TETS_PER_VOXEL) + model.settings.source = openmc.IndependentSource(space=space_out) + + # write out the model + model.export_to_xml() + + model_in = openmc.Model.from_xml() + + space_in = model_in.settings.source[0].space + + np.testing.assert_equal(space_out.strengths, space_in.strengths) + + assert space_in.mesh.id == space_out.mesh.id + assert space_in.volume_normalized == space_out.volume_normalized + + +################### +# MeshSource tests +################### +@pytest.fixture +def void_model(): + """ + A void model containing a single box + """ + model = openmc.Model() + + box = openmc.model.RectangularParallelepiped(*[-10, 10]*3, boundary_type='vacuum') + model.geometry = openmc.Geometry([openmc.Cell(region=-box)]) + + model.settings.particles = 100 + model.settings.batches = 10 + model.settings.run_mode = 'fixed source' + + return model + + +@pytest.mark.parametrize('mesh_type', ('rectangular', 'cylindrical')) +def test_mesh_source_independent(run_in_tmpdir, void_model, mesh_type): + """ + A void model containing a single box + """ + model = void_model + + # define a 2 x 2 x 2 mesh + if mesh_type == 'rectangular': + mesh = openmc.RegularMesh.from_domain(model.geometry, (2, 2, 2)) + elif mesh_type == 'cylindrical': + mesh = openmc.CylindricalMesh.from_domain(model.geometry, (1, 4, 2)) + + energy = openmc.stats.Discrete([1.e6], [1.0]) + + # create sources with only one non-zero strength for the source in the mesh + # voxel occupying the lowest octant. Direct source particles straight out of + # the problem from there. This demonstrates that + # 1) particles are only being sourced within the intented mesh voxel based + # on source strength + # 2) particles are respecting the angle distributions assigned to each voxel + sources = np.empty(mesh.dimension, dtype=openmc.SourceBase) + centroids = mesh.centroids + x, y, z = np.swapaxes(mesh.centroids, -1, 0) + for i, j, k in mesh.indices: + # mesh.indices is currently one-indexed, adjust for Python arrays + ijk = (i-1, j-1, k-1) + + # get the centroid of the ijk mesh element and use it to set the + # direction of the source directly out of the problem + centroid = centroids[ijk] + vec = np.sign(centroid, dtype=float) + vec /= np.linalg.norm(vec) + angle = openmc.stats.Monodirectional(vec) + sources[ijk] = openmc.IndependentSource(energy=energy, angle=angle, strength=0.0) + + # create and apply the mesh source + mesh_source = openmc.MeshSource(mesh, sources) + model.settings.source = mesh_source + + # tally the flux on the mesh + mesh_filter = openmc.MeshFilter(mesh) + tally = openmc.Tally() + tally.filters = [mesh_filter] + tally.scores = ['flux'] + + model.tallies = openmc.Tallies([tally]) + + # for each element, set a single-non zero source with particles + # traveling out of the mesh (and geometry) w/o crossing any other + # mesh elements + for flat_index, (i, j, k) in enumerate(mesh.indices): + ijk = (i-1, j-1, k-1) + # zero-out all source strengths and set the strength + # on the element of interest + mesh_source.strength = 0.0 + mesh_source.sources[flat_index].strength = 1.0 + + sp_file = model.run() + + with openmc.StatePoint(sp_file) as sp: + tally_out = sp.get_tally(id=tally.id) + mean = tally_out.get_reshaped_data(expand_dims=True) + + # remove nuclides and scores axes + mean = mean[..., 0, 0] + # the mesh elment with a non-zero source strength should have a value + assert mean[ijk] != 0 + # all other values should be zero + mean[ijk] = 0 + assert np.all(mean == 0), f'Failed on index {ijk} with centroid {mesh.centroids[ijk]}' + + # test roundtrip + xml_model = openmc.Model.from_model_xml() + xml_source = xml_model.settings.source[0] + assert isinstance(xml_source, openmc.MeshSource) + assert xml_source.strength == 1.0 + assert isinstance(xml_source.mesh, type(mesh_source.mesh)) + assert xml_source.mesh.dimension == mesh_source.mesh.dimension + assert xml_source.mesh.id == mesh_source.mesh.id + assert len(xml_source.sources) == len(mesh_source.sources) + + # check strength adjustment methods + assert mesh_source.strength == 1.0 + mesh_source.strength = 100.0 + assert mesh_source.strength == 100.0 + + mesh_source.normalize_source_strengths() + assert mesh_source.strength == 1.0 + + +@pytest.mark.parametrize("library", ('moab', 'libmesh')) +def test_umesh_source_independent(run_in_tmpdir, request, void_model, library): + import openmc.lib + # skip the test if the library is not enabled + if library == 'moab' and not openmc.lib._dagmc_enabled(): + pytest.skip("DAGMC (and MOAB) mesh not enabled in this build.") + + if library == 'libmesh' and not openmc.lib._libmesh_enabled(): + pytest.skip("LibMesh is not enabled in this build.") + + model = void_model + + mesh_filename = Path(request.fspath).parent / "test_mesh_tets.e" + uscd_mesh = openmc.UnstructuredMesh(mesh_filename, library) + ind_source = openmc.IndependentSource() + n_elements = 12_000 + model.settings.source = openmc.MeshSource(uscd_mesh, n_elements*[ind_source]) + model.export_to_model_xml() + try: + openmc.lib.init() + openmc.lib.simulation_init() + sites = openmc.lib.sample_external_source(10) + openmc.lib.statepoint_write('statepoint.h5') + finally: + openmc.lib.finalize() + + with openmc.StatePoint('statepoint.h5') as sp: + uscd_mesh = sp.meshes[uscd_mesh.id] + + # ensure at least that all sites are inside the mesh + bounding_box = uscd_mesh.bounding_box + for site in sites: + assert site.r in bounding_box + + +def test_mesh_source_file(run_in_tmpdir): + # Creating a source file with a single particle + source_particle = openmc.SourceParticle(time=10.0) + openmc.write_source_file([source_particle], 'source.h5') + file_source = openmc.FileSource('source.h5') + + model = openmc.Model() + + rect_prism = openmc.model.RectangularParallelepiped( + -5.0, 5.0, -5.0, 5.0, -5.0, 5.0, boundary_type='vacuum') + + mat = openmc.Material() + mat.add_nuclide('H1', 1.0) + + model.geometry = openmc.Geometry([openmc.Cell(fill=mat, region=-rect_prism)]) + model.settings.particles = 1000 + model.settings.batches = 10 + model.settings.run_mode = 'fixed source' + + mesh = openmc.RegularMesh() + mesh.lower_left = (-1, -2, -3) + mesh.upper_right = (2, 3, 4) + mesh.dimension = (1, 1, 1) + + model.settings.source = openmc.MeshSource(mesh, [file_source]) + + model.export_to_model_xml() + + openmc.lib.init() + openmc.lib.simulation_init() + sites = openmc.lib.sample_external_source(10) + openmc.lib.simulation_finalize() + openmc.lib.finalize() + + # The mesh bounds do not contain the point of the lone source site in the + # file source, so it should not appear in the set of source sites produced + # from the mesh source. Additionally, the source should be located within + # the mesh + bbox = mesh.bounding_box + for site in sites: + assert site.r != (0, 0, 0) + assert site.E == source_particle.E + assert site.u == source_particle.u + assert site.time == source_particle.time + assert site.r in bbox diff --git a/tests/unit_tests/test_spherical_mesh.py b/tests/unit_tests/test_spherical_mesh.py new file mode 100644 index 00000000000..0b579be35f7 --- /dev/null +++ b/tests/unit_tests/test_spherical_mesh.py @@ -0,0 +1,208 @@ +from itertools import product, permutations + +import openmc +import numpy as np + +import pytest + +geom_size = 5 + +@pytest.fixture() +def model(): + openmc.reset_auto_ids() + + water = openmc.Material(name='water') + water.add_element('H', 2.0) + water.add_element('O', 1.0) + water.set_density('g/cc', 1.0) + + rpp = openmc.model.RectangularParallelepiped(*([-geom_size, geom_size] * 3), + boundary_type='vacuum') + + cell = openmc.Cell(region=-rpp, fill=water) + + geom = openmc.Geometry([cell]) + + source = openmc.IndependentSource() + source.space = openmc.stats.Point() + source.energy = openmc.stats.Discrete([10000], [1.0]) + + settings = openmc.Settings() + settings.particles = 2000 + settings.batches = 10 + settings.run_mode = 'fixed source' + + # build + mesh = openmc.SphericalMesh( + phi_grid=np.linspace(0, 2*np.pi, 13), + theta_grid=np.linspace(0, np.pi, 7), + r_grid=np.linspace(0, geom_size, geom_size), + ) + tally = openmc.Tally() + + mesh_filter = openmc.MeshFilter(mesh) + tally.filters.append(mesh_filter) + + tally.scores.append("flux") + + tallies = openmc.Tallies([tally]) + + return openmc.Model(geometry=geom, settings=settings, tallies=tallies) + +def test_origin_read_write_to_xml(run_in_tmpdir, model): + """Tests that the origin attribute can be written and read back to XML + """ + mesh = model.tallies[0].filters[0].mesh + mesh.origin = [0.1, 0.2, 0.3] + model.tallies.export_to_xml() + + # read back + new_tallies = openmc.Tallies.from_xml() + new_tally = new_tallies[0] + new_mesh = new_tally.filters[0].mesh + np.testing.assert_equal(new_mesh.origin, mesh.origin) + +estimators = ('tracklength', 'collision') +# TODO: determine why this is needed for spherical mesh +# but not cylindrical mesh +offset = geom_size + 0.001 + +origins = set(permutations((-offset, 0, 0))) +origins |= set(permutations((offset, 0, 0))) + +test_cases = product(estimators, origins) + +def label(p): + if isinstance(p, tuple): + return f'origin:{p}' + if isinstance(p, str): + return f'estimator:{p}' + +@pytest.mark.parametrize('estimator,origin', test_cases, ids=label) +def test_offset_mesh(run_in_tmpdir, model, estimator, origin): + """Tests that the mesh has been moved based on tally results + """ + mesh = model.tallies[0].filters[0].mesh + model.tallies[0].estimator = estimator + # move the center of the spherical mesh + mesh.origin = origin + + sp_filename = model.run() + + with openmc.StatePoint(sp_filename) as sp: + tally = sp.tallies[1] + + # we've translated half of the spherical mesh above the model, + # so ensure that half of the bins are populated + assert np.count_nonzero(tally.mean) == tally.mean.size / 2 + + # check that the half of the mesh that is outside of the geometry + # contains the zero values + mean = tally.get_reshaped_data('mean', expand_dims=True) + centroids = mesh.centroids + for ijk in mesh.indices: + i, j, k = np.array(ijk) - 1 + if model.geometry.find(centroids[i, j, k]): + mean[i, j, k] == 0.0 + else: + mean[i, j, k] != 0.0 + +# Some void geometry tests to check our radial intersection methods on +# spherical and cylindrical meshes + +@pytest.fixture() +def void_coincident_geom_model(): + """A model with many geometric boundaries coincident with mesh boundaries + across many scales + """ + openmc.reset_auto_ids() + + model = openmc.Model() + + model.materials = openmc.Materials() + radii = [0.1, 1, 5, 50, 100, 150, 250] + spheres = [openmc.Sphere(r=ri) for ri in radii] + spheres[-1].boundary_type = 'vacuum' + + regions = openmc.model.subdivide(spheres)[:-1] + cells = [openmc.Cell(region=r, fill=None) for r in regions] + geom = openmc.Geometry(cells) + + model.geometry = geom + + settings = openmc.Settings(run_mode='fixed source') + settings.batches = 2 + settings.particles = 5000 + model.settings = settings + + mesh = openmc.SphericalMesh(r_grid=np.linspace(0, 250, 501)) + mesh_filter = openmc.MeshFilter(mesh) + + tally = openmc.Tally() + tally.scores = ['flux'] + tally.filters = [mesh_filter] + + model.tallies = openmc.Tallies([tally]) + + return model + + +# convenience function for checking tally results +# in the following tests +def _check_void_spherical_tally(statepoint_filename): + with openmc.StatePoint(statepoint_filename) as sp: + flux_tally = sp.tallies[1] + mesh = flux_tally.find_filter(openmc.MeshFilter).mesh + neutron_flux = flux_tally.get_reshaped_data().squeeze() + # the flux values for each bin should equal the width + # width of the mesh bins + d_r = mesh.r_grid[1] - mesh.r_grid[0] + assert neutron_flux == pytest.approx(d_r) + + +def test_void_geom_pnt_src(run_in_tmpdir, void_coincident_geom_model): + # add isotropic point source + src = openmc.IndependentSource() + src.space = openmc.stats.Point() + src.energy = openmc.stats.Discrete([14.06e6], [1]) + void_coincident_geom_model.settings.source = src + + # run model and check tally results + sp_filename = void_coincident_geom_model.run() + _check_void_spherical_tally(sp_filename) + + +def test_void_geom_boundary_src(run_in_tmpdir, void_coincident_geom_model): + # update source to a number of points on the outside of the sphere + # with directions pointing toward the origin + n_sources = 20 + phi_vals = np.linspace(0, np.pi, n_sources) + theta_vals = np.linspace(0, 2.0*np.pi, n_sources) + + bbox = void_coincident_geom_model.geometry.bounding_box + # can't source particles directly on the geometry boundary + outer_r = bbox[1][0] - 1e-08 + + sources = [] + + energy = openmc.stats.Discrete([14.06e6], [1]) + + for phi, theta in zip(phi_vals, theta_vals): + + src = openmc.IndependentSource() + src.energy = energy + + pnt = np.array([np.sin(phi)*np.cos(theta), np.sin(phi)*np.sin(theta), np.cos(phi)]) + u = -pnt + src.space = openmc.stats.Point(outer_r*pnt) + src.angle = openmc.stats.Monodirectional(u) + # set source strengths so that we can still expect + # a tally value of 0.5 + src.strength = 0.5/n_sources + + sources.append(src) + + void_coincident_geom_model.settings.source = sources + + sp_filename = void_coincident_geom_model.run() + _check_void_spherical_tally(sp_filename) diff --git a/tests/unit_tests/test_stats.py b/tests/unit_tests/test_stats.py index e1595847829..761f26ab3df 100644 --- a/tests/unit_tests/test_stats.py +++ b/tests/unit_tests/test_stats.py @@ -4,6 +4,16 @@ import pytest import openmc import openmc.stats +from scipy.integrate import trapezoid + + +def assert_sample_mean(samples, expected_mean): + # Calculate sample standard deviation + std_dev = samples.std() / np.sqrt(samples.size - 1) + + # Means should agree within 4 sigma 99.993% of the time. Note that this is + # expected to fail about 1 out of 16,000 times + assert np.abs(expected_mean - samples.mean()) < 4*std_dev def test_discrete(): @@ -13,8 +23,8 @@ def test_discrete(): elem = d.to_xml_element('distribution') d = openmc.stats.Discrete.from_xml_element(elem) - assert d.x == x - assert d.p == p + np.testing.assert_array_equal(d.x, x) + np.testing.assert_array_equal(d.p, p) assert len(d) == len(x) d = openmc.stats.Univariate.from_xml_element(elem) @@ -26,6 +36,66 @@ def test_discrete(): assert d2.p == [1.0] assert len(d2) == 1 + vals = np.array([1.0, 2.0, 3.0]) + probs = np.array([0.1, 0.7, 0.2]) + + exp_mean = (vals * probs).sum() + + d3 = openmc.stats.Discrete(vals, probs) + + # sample discrete distribution and check that the mean of the samples is + # within 4 std. dev. of the expected mean + n_samples = 1_000_000 + samples = d3.sample(n_samples) + assert_sample_mean(samples, exp_mean) + + +def test_merge_discrete(): + x1 = [0.0, 1.0, 10.0] + p1 = [0.3, 0.2, 0.5] + d1 = openmc.stats.Discrete(x1, p1) + + x2 = [0.5, 1.0, 5.0] + p2 = [0.4, 0.5, 0.1] + d2 = openmc.stats.Discrete(x2, p2) + + # Merged distribution should have x values sorted and probabilities + # appropriately combined. Duplicate x values should appear once. + merged = openmc.stats.Discrete.merge([d1, d2], [0.6, 0.4]) + assert merged.x == pytest.approx([0.0, 0.5, 1.0, 5.0, 10.0]) + assert merged.p == pytest.approx( + [0.6*0.3, 0.4*0.4, 0.6*0.2 + 0.4*0.5, 0.4*0.1, 0.6*0.5]) + assert merged.integral() == pytest.approx(1.0) + + # Probabilities add up but are not normalized + d1 = openmc.stats.Discrete([3.0], [1.0]) + triple = openmc.stats.Discrete.merge([d1, d1, d1], [1.0, 2.0, 3.0]) + assert triple.x == pytest.approx([3.0]) + assert triple.p == pytest.approx([6.0]) + assert triple.integral() == pytest.approx(6.0) + + +def test_clip_discrete(): + # Create discrete distribution with two points that are not important, one + # because the x value is very small, and one because the p value is very + # small + d = openmc.stats.Discrete([1e-8, 1.0, 2.0, 1000.0], [3.0, 2.0, 5.0, 1e-12]) + + # Clipping the distribution should result in two points + d_clip = d.clip(1e-6) + assert d_clip.x.size == 2 + assert d_clip.p.size == 2 + + # Make sure inplace returns same object + d_same = d.clip(1e-6, inplace=True) + assert d_same is d + + with pytest.raises(ValueError): + d.clip(-1.) + + with pytest.raises(ValueError): + d.clip(5) + def test_uniform(): a, b = 10.0, 20.0 @@ -38,10 +108,38 @@ def test_uniform(): assert len(d) == 2 t = d.to_tabular() - assert t.x == [a, b] - assert t.p == [1/(b-a), 1/(b-a)] + np.testing.assert_array_equal(t.x, [a, b]) + np.testing.assert_array_equal(t.p, [1/(b-a), 1/(b-a)]) assert t.interpolation == 'histogram' + # Sample distribution and check that the mean of the samples is within 4 + # std. dev. of the expected mean + exp_mean = 0.5 * (a + b) + n_samples = 1_000_000 + samples = d.sample(n_samples) + assert_sample_mean(samples, exp_mean) + + +def test_powerlaw(): + a, b, n = 10.0, 100.0, 2.0 + d = openmc.stats.PowerLaw(a, b, n) + elem = d.to_xml_element('distribution') + + d = openmc.stats.PowerLaw.from_xml_element(elem) + assert d.a == a + assert d.b == b + assert d.n == n + assert len(d) == 3 + + # Determine mean of distribution + exp_mean = (n+1)*(b**(n+2) - a**(n+2))/((n+2)*(b**(n+1) - a**(n+1))) + + # sample power law distribution and check that the mean of the samples is + # within 4 std. dev. of the expected mean + n_samples = 1_000_000 + samples = d.sample(n_samples) + assert_sample_mean(samples, exp_mean) + def test_maxwell(): theta = 1.2895e6 @@ -52,6 +150,19 @@ def test_maxwell(): assert d.theta == theta assert len(d) == 1 + exp_mean = 3/2 * theta + + # sample maxwell distribution and check that the mean of the samples is + # within 4 std. dev. of the expected mean + n_samples = 1_000_000 + samples = d.sample(n_samples) + assert_sample_mean(samples, exp_mean) + + # A second sample starting from a different seed + samples_2 = d.sample(n_samples) + assert_sample_mean(samples_2, exp_mean) + assert samples_2.mean() != samples.mean() + def test_watt(): a, b = 0.965e6, 2.29e-6 @@ -63,19 +174,49 @@ def test_watt(): assert d.b == b assert len(d) == 2 + # mean value form adapted from + # "Prompt-fission-neutron average energy for 238U(n, f ) from + # threshold to 200 MeV" Ethvignot et. al. + # https://doi.org/10.1016/j.physletb.2003.09.048 + exp_mean = 3/2 * a + a**2 * b / 4 + + # sample Watt distribution and check that the mean of the samples is within + # 4 std. dev. of the expected mean + n_samples = 1_000_000 + samples = d.sample(n_samples) + assert_sample_mean(samples, exp_mean) + def test_tabular(): - x = [0.0, 5.0, 7.0] - p = [0.1, 0.2, 0.05] + x = np.array([0.0, 5.0, 7.0]) + p = np.array([10.0, 20.0, 5.0]) d = openmc.stats.Tabular(x, p, 'linear-linear') elem = d.to_xml_element('distribution') d = openmc.stats.Tabular.from_xml_element(elem) - assert d.x == x - assert d.p == p + assert all(d.x == x) + assert all(d.p == p) assert d.interpolation == 'linear-linear' assert len(d) == len(x) + # test linear-linear sampling + d = openmc.stats.Tabular(x, p) + n_samples = 100_000 + samples = d.sample(n_samples) + assert_sample_mean(samples, d.mean()) + + # test linear-linear normalization + d.normalize() + assert d.integral() == pytest.approx(1.0) + + # test histogram sampling + d = openmc.stats.Tabular(x, p, interpolation='histogram') + samples = d.sample(n_samples) + assert_sample_mean(samples, d.mean()) + + d.normalize() + assert d.integral() == pytest.approx(1.0) + def test_legendre(): # Pu239 elastic scattering at 100 keV @@ -86,7 +227,7 @@ def test_legendre(): # Integrating distribution should yield one mu = np.linspace(-1., 1., 1000) - assert np.trapz(d(mu), mu) == pytest.approx(1.0, rel=1e-4) + assert trapezoid(d(mu), mu) == pytest.approx(1.0, rel=1e-4) with pytest.raises(NotImplementedError): d.to_xml_element('distribution') @@ -101,8 +242,35 @@ def test_mixture(): assert mix.distribution == [d1, d2] assert len(mix) == 4 - with pytest.raises(NotImplementedError): - mix.to_xml_element('distribution') + # Sample and make sure sample mean is close to expected mean + n_samples = 1_000_000 + samples = mix.sample(n_samples) + assert_sample_mean(samples, (2.5 + 5.0)/2) + + elem = mix.to_xml_element('distribution') + + d = openmc.stats.Mixture.from_xml_element(elem) + assert d.probability == p + assert d.distribution == [d1, d2] + assert len(d) == 4 + + +def test_mixture_clip(): + # Create mixture distribution containing a discrete distribution with two + # points that are not important, one because the x value is very small, and + # one because the p value is very small + d1 = openmc.stats.Discrete([1e-8, 1.0, 2.0, 1000.0], [3.0, 2.0, 5.0, 1e-12]) + d2 = openmc.stats.Uniform(0, 5) + mix = openmc.stats.Mixture([0.5, 0.5], [d1, d2]) + + # Clipping should reduce the contained discrete distribution to 2 points + mix_clip = mix.clip(1e-6) + assert mix_clip.distribution[0].x.size == 2 + assert mix_clip.distribution[0].p.size == 2 + + # Make sure inplace returns same object + mix_same = mix.clip(1e-6, inplace=True) + assert mix_same is mix def test_polar_azimuthal(): @@ -214,6 +382,7 @@ def test_point(): d = openmc.stats.Point.from_xml_element(elem) assert d.xyz == pytest.approx(p) + def test_normal(): mean = 10.0 std_dev = 2.0 @@ -227,17 +396,71 @@ def test_normal(): assert d.std_dev == pytest.approx(std_dev) assert len(d) == 2 + # sample normal distribution + n_samples = 100_000 + samples = d.sample(n_samples) + assert_sample_mean(samples, mean) + + def test_muir(): mean = 10.0 mass = 5.0 temp = 20000. - d = openmc.stats.Muir(mean,mass,temp) + d = openmc.stats.muir(mean, mass, temp) + assert isinstance(d, openmc.stats.Normal) elem = d.to_xml_element('energy') - assert elem.attrib['type'] == 'muir' + assert elem.attrib['type'] == 'normal' - d = openmc.stats.Muir.from_xml_element(elem) - assert d.e0 == pytest.approx(mean) - assert d.m_rat == pytest.approx(mass) - assert d.kt == pytest.approx(temp) - assert len(d) == 3 + d = openmc.stats.Univariate.from_xml_element(elem) + assert isinstance(d, openmc.stats.Normal) + + # sample muir distribution + n_samples = 100_000 + samples = d.sample(n_samples) + assert_sample_mean(samples, mean) + + +def test_combine_distributions(): + # Combine two discrete (same data as in test_merge_discrete) + x1 = [0.0, 1.0, 10.0] + p1 = [0.3, 0.2, 0.5] + d1 = openmc.stats.Discrete(x1, p1) + x2 = [0.5, 1.0, 5.0] + p2 = [0.4, 0.5, 0.1] + d2 = openmc.stats.Discrete(x2, p2) + + # Merged distribution should have x values sorted and probabilities + # appropriately combined. Duplicate x values should appear once. + merged = openmc.stats.combine_distributions([d1, d2], [0.6, 0.4]) + assert isinstance(merged, openmc.stats.Discrete) + assert merged.x == pytest.approx([0.0, 0.5, 1.0, 5.0, 10.0]) + assert merged.p == pytest.approx( + [0.6*0.3, 0.4*0.4, 0.6*0.2 + 0.4*0.5, 0.4*0.1, 0.6*0.5]) + + # Probabilities add up but are not normalized + d1 = openmc.stats.Discrete([3.0], [1.0]) + triple = openmc.stats.combine_distributions([d1, d1, d1], [1.0, 2.0, 3.0]) + assert triple.x == pytest.approx([3.0]) + assert triple.p == pytest.approx([6.0]) + + # Combine discrete and tabular + t1 = openmc.stats.Tabular(x2, p2) + mixed = openmc.stats.combine_distributions([d1, t1], [0.5, 0.5]) + assert isinstance(mixed, openmc.stats.Mixture) + assert len(mixed.distribution) == 2 + assert len(mixed.probability) == 2 + + # Combine 1 discrete and 2 tabular -- the tabular distributions should + # combine to produce a uniform distribution with mean 0.5. The combined + # distribution should have a mean of 0.25. + t1 = openmc.stats.Tabular([0., 1.], [2.0, 0.0]) + t2 = openmc.stats.Tabular([0., 1.], [0.0, 2.0]) + d1 = openmc.stats.Discrete([0.0], [1.0]) + combined = openmc.stats.combine_distributions([t1, t2, d1], [0.25, 0.25, 0.5]) + assert combined.integral() == pytest.approx(1.0) + + # Sample the combined distribution and make sure the sample mean is within + # uncertainty of the expected value + samples = combined.sample(10_000) + assert_sample_mean(samples, 0.25) diff --git a/tests/unit_tests/test_surface.py b/tests/unit_tests/test_surface.py index e7d37c4e91d..12cd8c9d20d 100644 --- a/tests/unit_tests/test_surface.py +++ b/tests/unit_tests/test_surface.py @@ -605,3 +605,151 @@ def test_cylinder_from_points_axis(): assert (d, e, f) == pytest.approx((0., 0., 0.)) assert (g, h, j) == pytest.approx((-4., 0., -10.)) assert k == pytest.approx(13.) + + +def torus_common(center, R, r1, r2, cls): + x, y, z = center + s = cls(x0=x, y0=y, z0=z, a=R, b=r1, c=r2) + assert s.x0 == x + assert s.y0 == y + assert s.z0 == z + assert s.a == R + assert s.b == r1 + assert s.c == r2 + + # evaluate method + assert s.evaluate((x, y, z)) > 0.0 + + # translate method + trans = np.array([1.0, 1.5, -2.0]) + st = s.translate(trans) + assert st.x0 == s.x0 + trans[0] + assert st.y0 == s.y0 + trans[1] + assert st.z0 == s.z0 + trans[2] + assert st.a == s.a + assert st.b == s.b + assert st.c == s.c + + # trivial rotations + for rotation in [(0., 0., 0.), (180., 0., 0.), (0., 180., 0.), (0., 0., 180.)]: + sr = s.rotate(rotation) + assert type(sr) == type(s) + assert (sr.a, sr.b, sr.c) == (s.a, s.b, s.c) + + # can't do generic rotate at present + with pytest.raises(NotImplementedError): + s.rotate((0., 45., 0.)) + + # Check bounding box + ll, ur = (+s).bounding_box + assert np.all(np.isinf(ll)) + assert np.all(np.isinf(ur)) + + ll, ur = (-s).bounding_box + llt, urt = (-st).bounding_box + np.testing.assert_allclose(ll + trans, llt) + np.testing.assert_allclose(ur + trans, urt) + + # Make sure repr works + repr(s) + + return s + + +def test_xtorus(): + x, y, z = 2, -4, 5 + R, r1, r2 = 3, 1.5, 1 + s = torus_common((x, y, z), R, r1, r2, openmc.XTorus) + + # evaluate method (points inside torus) + assert s.evaluate((x, y + R, z)) < 0.0 + assert s.evaluate((x, y - R, z)) < 0.0 + assert s.evaluate((x, y, z + R)) < 0.0 + assert s.evaluate((x, y, z - R)) < 0.0 + + # evaluate method (points on torus) + assert s.evaluate((x, y + R + r2, z)) == pytest.approx(0.0) + assert s.evaluate((x, y - R - r2, z)) == pytest.approx(0.0) + assert s.evaluate((x, y, z + R - r2)) == pytest.approx(0.0) + assert s.evaluate((x, y, z - R + r2)) == pytest.approx(0.0) + assert s.evaluate((x + r1, y + R, z)) == pytest.approx(0.0) + + # evaluate method (points outside torus) + assert s.evaluate((x, y + R, z + R)) > 0.0 + assert s.evaluate((x, y - R, z + R)) > 0.0 + assert s.evaluate((x, y + R + r2 + 0.01, z)) > 0.0 + assert s.evaluate((x, y, z + R + r2 + 0.01)) > 0.0 + assert s.evaluate((x + r1 + 0.01, y, z + R)) > 0.0 + assert s.evaluate((x + r1 + 0.01, y + R, z)) > 0.0 + + # rotation + sr = s.rotate((0., 0., 90.)) + assert isinstance(sr, openmc.YTorus) + sr = s.rotate((0., 90., 0.)) + assert isinstance(sr, openmc.ZTorus) + + +def test_ytorus(): + x, y, z = 2, -4, 5 + R, r1, r2 = 3, 1.5, 1 + s = torus_common((x, y, z), R, r1, r2, openmc.YTorus) + + # evaluate method (points inside torus) + assert s.evaluate((x + R, y, z)) < 0.0 + assert s.evaluate((x - R, y, z)) < 0.0 + assert s.evaluate((x, y, z + R)) < 0.0 + assert s.evaluate((x, y, z - R)) < 0.0 + + # evaluate method (points on torus) + assert s.evaluate((x + R + r2, y, z)) == pytest.approx(0.0) + assert s.evaluate((x - R - r2, y, z)) == pytest.approx(0.0) + assert s.evaluate((x, y, z + R - r2)) == pytest.approx(0.0) + assert s.evaluate((x, y, z - R + r2)) == pytest.approx(0.0) + assert s.evaluate((x + R, y + r1, z)) == pytest.approx(0.0) + + # evaluate method (points outside torus) + assert s.evaluate((x + R, y, z + R)) > 0.0 + assert s.evaluate((x - R, y, z + R)) > 0.0 + assert s.evaluate((x + R + r2 + 0.01, y, z)) > 0.0 + assert s.evaluate((x, y, z + R + r2 + 0.01)) > 0.0 + assert s.evaluate((x, y + r1 + 0.01, z + R)) > 0.0 + assert s.evaluate((x + R, y + r1 + 0.01, z)) > 0.0 + + # rotation + sr = s.rotate((90., 0., 0.)) + assert isinstance(sr, openmc.ZTorus) + sr = s.rotate((0., 0., 90.)) + assert isinstance(sr, openmc.XTorus) + + +def test_ztorus(): + x, y, z = 2, -4, 5 + R, r1, r2 = 3, 1.5, 1 + s = torus_common((x, y, z), R, r1, r2, openmc.ZTorus) + + # evaluate method (points inside torus) + assert s.evaluate((x, y + R, z)) < 0.0 + assert s.evaluate((x, y - R, z)) < 0.0 + assert s.evaluate((x + R, y, z)) < 0.0 + assert s.evaluate((x - R, y, z)) < 0.0 + + # evaluate method (points on torus) + assert s.evaluate((x, y + R + r2, z)) == pytest.approx(0.0) + assert s.evaluate((x, y - R - r2, z)) == pytest.approx(0.0) + assert s.evaluate((x + R - r2, y, z)) == pytest.approx(0.0) + assert s.evaluate((x - R + r2, y, z)) == pytest.approx(0.0) + assert s.evaluate((x, y + R, z + r1)) == pytest.approx(0.0) + + # evaluate method (points outside torus) + assert s.evaluate((x + R, y + R, z)) > 0.0 + assert s.evaluate((x + R, y - R, z)) > 0.0 + assert s.evaluate((x, y + R + r2 + 0.01, z)) > 0.0 + assert s.evaluate((x + R + r2 + 0.01, y, z)) > 0.0 + assert s.evaluate((x + R, y, z + r1 + 0.01)) > 0.0 + assert s.evaluate((x, y + R, z + r1 + 0.01)) > 0.0 + + # rotation + sr = s.rotate((90., 0., 0.)) + assert isinstance(sr, openmc.YTorus) + sr = s.rotate((0., 90., 0.)) + assert isinstance(sr, openmc.XTorus) diff --git a/tests/unit_tests/test_surface_composite.py b/tests/unit_tests/test_surface_composite.py index a1a218311db..19221212e06 100644 --- a/tests/unit_tests/test_surface_composite.py +++ b/tests/unit_tests/test_surface_composite.py @@ -12,7 +12,8 @@ def test_rectangular_parallelepiped(): ymax = ymin + uniform(0., 5.) zmin = uniform(-5., 5.) zmax = zmin + uniform(0., 5.) - s = openmc.model.RectangularParallelepiped(xmin, xmax, ymin, ymax, zmin, zmax) + s = openmc.model.RectangularParallelepiped( + xmin, xmax, ymin, ymax, zmin, zmax) assert isinstance(s.xmin, openmc.XPlane) assert isinstance(s.xmax, openmc.XPlane) assert isinstance(s.ymin, openmc.YPlane) @@ -64,30 +65,84 @@ def test_right_circular_cylinder(axis, indices): x, y, z = 1.0, -2.5, 3.0 h, r = 5.0, 3.0 s = openmc.model.RightCircularCylinder((x, y, z), h, r, axis=axis.lower()) - assert isinstance(s.cyl, getattr(openmc, axis + "Cylinder")) - assert isinstance(s.top, getattr(openmc, axis + "Plane")) - assert isinstance(s.bottom, getattr(openmc, axis + "Plane")) + s_r = openmc.model.RightCircularCylinder((x, y, z), h, r, axis=axis.lower(), + upper_fillet_radius=1.6, + lower_fillet_radius=1.6) + for s in (s, s_r): + assert isinstance(s.cyl, getattr(openmc, axis + "Cylinder")) + assert isinstance(s.top, getattr(openmc, axis + "Plane")) + assert isinstance(s.bottom, getattr(openmc, axis + "Plane")) + + # Make sure boundary condition propagates + s.boundary_type = 'reflective' + assert s.boundary_type == 'reflective' + assert s.cyl.boundary_type == 'reflective' + assert s.bottom.boundary_type == 'reflective' + assert s.top.boundary_type == 'reflective' + + # Check bounding box + ll, ur = (+s).bounding_box + assert np.all(np.isinf(ll)) + assert np.all(np.isinf(ur)) + ll, ur = (-s).bounding_box + assert ll == pytest.approx((x, y, z) + np.roll([0, -r, -r], indices[0])) + assert ur == pytest.approx((x, y, z) + np.roll([h, r, r], indices[0])) + + # __contains__ on associated half-spaces + point_pos = (x, y, z) + np.roll([h/2, r+1, r+1], indices[0]) + assert point_pos in +s + assert point_pos not in -s + point_neg = (x, y, z) + np.roll([h/2, 0, 0], indices[0]) + assert point_neg in -s + assert point_neg not in +s + + # translate method + t = uniform(-5.0, 5.0) + s_t = s.translate((t, t, t)) + ll_t, ur_t = (-s_t).bounding_box + assert ur_t == pytest.approx(ur + t) + assert ll_t == pytest.approx(ll + t) + + # Make sure repr works + repr(s) + + +@pytest.mark.parametrize( + "axis, point_pos, point_neg, ll_true", [ + ("X", (8., 0., 0.), (12., 0., 0.), (10., -np.inf, -np.inf)), + ("Y", (10., -2., 0.), (10., 2., 0.), (-np.inf, 0., -np.inf)), + ("Z", (10., 0., -3.), (10., 0., 3.), (-np.inf, -np.inf, 0.)) + ] +) +def test_cone_one_sided(axis, point_pos, point_neg, ll_true): + cone_oneside = getattr(openmc.model, axis + "ConeOneSided") + cone_twoside = getattr(openmc, axis + "Cone") + plane = getattr(openmc, axis + "Plane") + + x, y, z = 10., 0., 0. + r2 = 4. + s = cone_oneside(x, y, z, r2, True) + assert isinstance(s.cone, cone_twoside) + assert isinstance(s.plane, plane) + assert s.up # Make sure boundary condition propagates s.boundary_type = 'reflective' assert s.boundary_type == 'reflective' - assert s.cyl.boundary_type == 'reflective' - assert s.bottom.boundary_type == 'reflective' - assert s.top.boundary_type == 'reflective' + assert s.cone.boundary_type == 'reflective' + assert s.plane.boundary_type == 'transmission' # Check bounding box ll, ur = (+s).bounding_box assert np.all(np.isinf(ll)) assert np.all(np.isinf(ur)) ll, ur = (-s).bounding_box - assert ll == pytest.approx((x, y, z) + np.roll([0, -r, -r], indices[0])) - assert ur == pytest.approx((x, y, z) + np.roll([h, r, r], indices[0])) + assert np.all(np.isinf(ur)) + assert ll == pytest.approx(ll_true) # __contains__ on associated half-spaces - point_pos = (x, y, z) + np.roll([h/2, r+1, r+1], indices[0]) assert point_pos in +s assert point_pos not in -s - point_neg = (x, y, z) + np.roll([h/2, 0, 0], indices[0]) assert point_neg in -s assert point_neg not in +s @@ -103,39 +158,319 @@ def test_right_circular_cylinder(axis, indices): @pytest.mark.parametrize( - "axis, point_pos, point_neg, ll_true", [ - ("X", (8., 0., 0.), (12., 0., 0.), (10., -np.inf, -np.inf)), - ("Y", (10., -2., 0.), (10., 2., 0.), (-np.inf, 0., -np.inf)), - ("Z", (10., 0., -3.), (10., 0., 3.), (-np.inf, -np.inf, 0.)) + "axis, indices", [ + ("X", [0, 1, 2]), + ("Y", [1, 2, 0]), + ("Z", [2, 0, 1]), ] ) -def test_cone_one_sided(axis, point_pos, point_neg, ll_true): - cone_oneside = getattr(openmc.model, axis + "ConeOneSided") - cone_twoside = getattr(openmc, axis + "Cone") - plane = getattr(openmc, axis + "Plane") +def test_cylinder_sector(axis, indices): + r1, r2 = 0.5, 1.5 + d = (r2 - r1) / 2 + phi1 = -60. + phi2 = 60 + s = openmc.model.CylinderSector(r1, r2, phi1, phi2, + axis=axis.lower()) + assert isinstance(s.outer_cyl, getattr(openmc, axis + "Cylinder")) + assert isinstance(s.inner_cyl, getattr(openmc, axis + "Cylinder")) + assert isinstance(s.plane1, openmc.Plane) + assert isinstance(s.plane2, openmc.Plane) - x, y, z = 10., 0., 0. - r2 = 4. - s = cone_oneside(x, y, z, r2, True) - assert isinstance(s.cone, cone_twoside) - assert isinstance(s.plane, plane) - assert s.up + # Make sure boundary condition propagates + s.boundary_type = 'reflective' + assert s.boundary_type == 'reflective' + assert s.outer_cyl.boundary_type == 'reflective' + assert s.inner_cyl.boundary_type == 'reflective' + assert s.plane1.boundary_type == 'reflective' + assert s.plane2.boundary_type == 'reflective' + + # Check bounding box + ll, ur = (+s).bounding_box + assert np.all(np.isinf(ll)) + assert np.all(np.isinf(ur)) + ll, ur = (-s).bounding_box + assert ll == pytest.approx(np.roll([-np.inf, -r2, -r2], indices[0])) + assert ur == pytest.approx(np.roll([np.inf, r2, r2], indices[0])) + + # __contains__ on associated half-spaces + point_pos = np.roll([0, r2 + 1, 0], indices[0]) + assert point_pos in +s + assert point_pos not in -s + point_neg = np.roll([0, r1 + d, r1 + d], indices[0]) + assert point_neg in -s + assert point_neg not in +s + + # translate method + t = uniform(-5.0, 5.0) + s_t = s.translate((t, t, t)) + ll_t, ur_t = (-s_t).bounding_box + assert ur_t == pytest.approx(ur + t) + assert ll_t == pytest.approx(ll + t) + + # Check invalid r1, r2 combinations + with pytest.raises(ValueError): + openmc.model.CylinderSector(r2, r1, phi1, phi2) + + # Check invalid angles + with pytest.raises(ValueError): + openmc.model.CylinderSector(r1, r2, phi2, phi1) + + # Make sure repr works + repr(s) + + +def test_cylinder_sector_from_theta_alpha(): + r1, r2 = 0.5, 1.5 + d = (r2 - r1) / 2 + theta = 120. + alpha = -60. + theta1 = alpha + theta2 = alpha + theta + s = openmc.model.CylinderSector(r1, r2, theta1, theta2) + s_alt = openmc.model.CylinderSector.from_theta_alpha(r1, + r2, + theta, + alpha) + + # Check that the angles are correct + assert s.plane1.coefficients == s_alt.plane1.coefficients + assert s.plane2.coefficients == s_alt.plane2.coefficients + assert s.inner_cyl.coefficients == s_alt.inner_cyl.coefficients + assert s.outer_cyl.coefficients == s_alt.outer_cyl.coefficients + + # Check invalid sector width + with pytest.raises(ValueError): + openmc.model.CylinderSector.from_theta_alpha(r1, r2, 360, alpha) + with pytest.raises(ValueError): + openmc.model.CylinderSector.from_theta_alpha(r1, r2, -1, alpha) + + +@pytest.mark.parametrize( + "axis, plane_tb, plane_lr, axis_idx", [ + ("x", "Z", "Y", 0), + ("y", "X", "Z", 1), + ("z", "Y", "X", 2), + ] +) +def test_isogonal_octagon(axis, plane_tb, plane_lr, axis_idx): + center = np.array([0., 0.]) + point_pos = np.array([0.8, 0.8]) + point_neg = np.array([0.7, 0.7]) + r1 = 1. + r2 = 1. + plane_top_bottom = getattr(openmc, plane_tb + "Plane") + plane_left_right = getattr(openmc, plane_lr + "Plane") + s = openmc.model.IsogonalOctagon(center, r1, r2, axis=axis) + assert isinstance(s.top, plane_top_bottom) + assert isinstance(s.bottom, plane_top_bottom) + assert isinstance(s.right, plane_left_right) + assert isinstance(s.left, plane_left_right) + assert isinstance(s.upper_right, openmc.Plane) + assert isinstance(s.lower_right, openmc.Plane) + assert isinstance(s.upper_left, openmc.Plane) + assert isinstance(s.lower_left, openmc.Plane) # Make sure boundary condition propagates s.boundary_type = 'reflective' assert s.boundary_type == 'reflective' - assert s.cone.boundary_type == 'reflective' - assert s.plane.boundary_type == 'transmission' + assert s.top.boundary_type == 'reflective' + assert s.bottom.boundary_type == 'reflective' + assert s.right.boundary_type == 'reflective' + assert s.left.boundary_type == 'reflective' + assert s.upper_right.boundary_type == 'reflective' + assert s.lower_right.boundary_type == 'reflective' + assert s.lower_left.boundary_type == 'reflective' + assert s.upper_left.boundary_type == 'reflective' # Check bounding box + center = np.insert(center, axis_idx, np.inf) + xmax, ymax, zmax = center + r1 + coord_min = center - r1 + coord_min[axis_idx] *= -1 + xmin, ymin, zmin = coord_min ll, ur = (+s).bounding_box assert np.all(np.isinf(ll)) assert np.all(np.isinf(ur)) ll, ur = (-s).bounding_box + assert ur == pytest.approx((xmax, ymax, zmax)) + assert ll == pytest.approx((xmin, ymin, zmin)) + + # __contains__ on associated half-spaces + point_pos = np.insert(point_pos, axis_idx, 0) + point_neg = np.insert(point_neg, axis_idx, 0) + assert point_pos in +s + assert point_pos not in -s + assert point_neg in -s + assert point_neg not in +s + + # translate method + t = uniform(-5.0, 5.0) + s_t = s.translate((t, t, t)) + ll_t, ur_t = (-s_t).bounding_box + assert ur_t == pytest.approx(ur + t) + assert ll_t == pytest.approx(ll + t) + + # Check invalid r1, r2 combinations + with pytest.raises(ValueError): + openmc.model.IsogonalOctagon(center, r1=1.0, r2=10.) + with pytest.raises(ValueError): + openmc.model.IsogonalOctagon(center, r1=10., r2=1.) + + # Make sure repr works + repr(s) + + +def test_polygon(): + # define a 5 pointed star centered on 1, 1 + star = np.array([[1. , 2. ], + [0.70610737, 1.4045085 ], + [0.04894348, 1.30901699], + [0.52447174, 0.8454915 ], + [0.41221475, 0.19098301], + [1. , 0.5 ], + [1.58778525, 0.19098301], + [1.47552826, 0.8454915 ], + [1.95105652, 1.30901699], + [1.29389263, 1.4045085 ], + [1. , 2. ]]) + points_in = [(1, 1, 0), (0, 1, 1), (1, 0, 1), (.707, .707, 1)] + for i, basis in enumerate(('xy', 'yz', 'xz', 'rz')): + star_poly = openmc.model.Polygon(star, basis=basis) + assert points_in[i] in -star_poly + assert any([points_in[i] in reg for reg in star_poly.regions]) + assert points_in[i] not in +star_poly + assert (0, 0, 0) not in -star_poly + if basis != 'rz': + offset_star = star_poly.offset(.6) + assert (0, 0, 0) in -offset_star + assert any([(0, 0, 0) in reg for reg in offset_star.regions]) + + # check invalid Polygon input points + # duplicate points not just at start and end + rz_points = np.array([[6.88, 3.02], + [6.88, 2.72], + [6.88, 3.02], + [7.63, 0.0], + [5.75, 0.0], + [5.75, 1.22], + [7.63, 0.0], + [6.30, 1.22], + [6.30, 3.02], + [6.88, 3.02]]) + with pytest.raises(ValueError): + openmc.model.Polygon(rz_points) + + # segment traces back on previous segment + rz_points = np.array([[6.88, 3.02], + [6.88, 2.72], + [6.88, 2.32], + [6.88, 2.52], + [7.63, 0.0], + [5.75, 0.0], + [6.75, 0.0], + [5.75, 1.22], + [6.30, 1.22], + [6.30, 3.02], + [6.88, 3.02]]) + with pytest.raises(ValueError): + openmc.model.Polygon(rz_points) + + # segments intersect (line-line) + rz_points = np.array([[6.88, 3.02], + [5.88, 2.32], + [7.63, 0.0], + [5.75, 0.0], + [5.75, 1.22], + [6.30, 1.22], + [6.30, 3.02], + [6.88, 3.02]]) + with pytest.raises(ValueError): + openmc.model.Polygon(rz_points) + + # segments intersect (line-point) + rz_points = np.array([[6.88, 3.02], + [6.3, 2.32], + [7.63, 0.0], + [5.75, 0.0], + [5.75, 1.22], + [6.30, 1.22], + [6.30, 3.02], + [6.88, 3.02]]) + with pytest.raises(ValueError): + openmc.model.Polygon(rz_points) + + # Test "M" shaped polygon + points = np.array([[8.5151581, -17.988337], + [10.381711000000001, -17.988337], + [12.744357, -24.288728000000003], + [15.119406000000001, -17.988337], + [16.985959, -17.988337], + [16.985959, -27.246687], + [15.764328, -27.246687], + [15.764328, -19.116951], + [13.376877, -25.466951], + [12.118039, -25.466951], + [9.7305877, -19.116951], + [9.7305877, -27.246687], + [8.5151581, -27.246687]]) + + # Test points inside and outside by using offset method + m_polygon = openmc.model.Polygon(points, basis='xz') + inner_pts = m_polygon.offset(-0.1).points + assert all([(pt[0], 0, pt[1]) in -m_polygon for pt in inner_pts]) + outer_pts = m_polygon.offset(0.1).points + assert all([(pt[0], 0, pt[1]) in +m_polygon for pt in outer_pts]) + + # Offset of -0.2 will cause self-intersection + with pytest.raises(ValueError): + m_polygon.offset(-0.2) + + +@pytest.mark.parametrize("axis", ["x", "y", "z"]) +def test_cruciform_prism(axis): + center = x0, y0 = (3., 4.) + distances = [2., 3., 5.] + s = openmc.model.CruciformPrism(distances, center, axis=axis) + + if axis == 'x': + i1, i2 = 1, 2 + elif axis == 'y': + i1, i2 = 0, 2 + elif axis == 'z': + i1, i2 = 0, 1 + plane_cls = (openmc.XPlane, openmc.YPlane, openmc.ZPlane) + + # Check type of surfaces + for i in range(3): + assert isinstance(getattr(s, f'hmin{i}'), plane_cls[i1]) + assert isinstance(getattr(s, f'hmax{i}'), plane_cls[i1]) + assert isinstance(getattr(s, f'vmin{i}'), plane_cls[i2]) + assert isinstance(getattr(s, f'vmax{i}'), plane_cls[i2]) + + # Make sure boundary condition propagates + s.boundary_type = 'reflective' + for i in range(3): + assert getattr(s, f'hmin{i}').boundary_type == 'reflective' + assert getattr(s, f'hmax{i}').boundary_type == 'reflective' + assert getattr(s, f'vmin{i}').boundary_type == 'reflective' + assert getattr(s, f'vmax{i}').boundary_type == 'reflective' + + # Check bounding box + ll, ur = (+s).bounding_box + assert np.all(np.isinf(ll)) assert np.all(np.isinf(ur)) - assert ll == pytest.approx(ll_true) + ll, ur = (-s).bounding_box + assert ur[i1] == pytest.approx(x0 + distances[-1]) + assert ur[i2] == pytest.approx(y0 + distances[-1]) + assert ll[i1] == pytest.approx(x0 - distances[-1]) + assert ll[i2] == pytest.approx(y0 - distances[-1]) # __contains__ on associated half-spaces + point_pos, point_neg = np.zeros(3), np.zeros(3) + point_pos[i1] = x0 + 3.1 + point_pos[i2] = y0 + 2.05 + point_neg[i1] = x0 + 3.5 + point_neg[i2] = y0 + 1.99 assert point_pos in +s assert point_pos not in -s assert point_neg in -s @@ -150,3 +485,9 @@ def test_cone_one_sided(axis, point_pos, point_neg, ll_true): # Make sure repr works repr(s) + + # Check that non-monotonic distances fail + with pytest.raises(ValueError): + openmc.model.CruciformPrism([1.0, 0.5, 2.0, 3.0]) + with pytest.raises(ValueError): + openmc.model.CruciformPrism([3.0, 2.0, 0.5, 1.0]) diff --git a/tests/unit_tests/test_tallies.py b/tests/unit_tests/test_tallies.py new file mode 100644 index 00000000000..54444331257 --- /dev/null +++ b/tests/unit_tests/test_tallies.py @@ -0,0 +1,44 @@ +import numpy as np + +import openmc + + +def test_xml_roundtrip(run_in_tmpdir): + # Create a tally with all possible gizmos + mesh = openmc.RegularMesh() + mesh.lower_left = (-10., -10., -10.) + mesh.upper_right = (10., 10., 10.,) + mesh.dimension = (5, 5, 5) + mesh_filter = openmc.MeshFilter(mesh) + meshborn_filter = openmc.MeshBornFilter(mesh) + tally = openmc.Tally() + tally.filters = [mesh_filter, meshborn_filter] + tally.nuclides = ['U235', 'I135', 'Li6'] + tally.scores = ['total', 'fission', 'heating'] + tally.derivative = openmc.TallyDerivative( + variable='nuclide_density', material=1, nuclide='Li6' + ) + tally.triggers = [openmc.Trigger('rel_err', 0.025)] + tally.triggers[0].scores = ['total', 'fission'] + tallies = openmc.Tallies([tally]) + + # Roundtrip through XML and make sure we get what we started with + tallies.export_to_xml() + new_tallies = openmc.Tallies.from_xml() + assert len(new_tallies) == 1 + new_tally = new_tallies[0] + assert new_tally.id == tally.id + assert len(new_tally.filters) == 2 + assert isinstance(new_tally.filters[0], openmc.MeshFilter) + assert np.allclose(new_tally.filters[0].mesh.lower_left, mesh.lower_left) + assert isinstance(new_tally.filters[1], openmc.MeshBornFilter) + assert np.allclose(new_tally.filters[1].mesh.lower_left, mesh.lower_left) + assert new_tally.nuclides == tally.nuclides + assert new_tally.scores == tally.scores + assert new_tally.derivative.variable == tally.derivative.variable + assert new_tally.derivative.material == tally.derivative.material + assert new_tally.derivative.nuclide == tally.derivative.nuclide + assert len(new_tally.triggers) == 1 + assert new_tally.triggers[0].trigger_type == tally.triggers[0].trigger_type + assert new_tally.triggers[0].threshold == tally.triggers[0].threshold + assert new_tally.triggers[0].scores == tally.triggers[0].scores \ No newline at end of file diff --git a/tests/unit_tests/test_tally_multiply_density.py b/tests/unit_tests/test_tally_multiply_density.py new file mode 100644 index 00000000000..66ef41e0dac --- /dev/null +++ b/tests/unit_tests/test_tally_multiply_density.py @@ -0,0 +1,50 @@ +import numpy as np +import openmc +import pytest + + +def test_micro_macro_compare(): + # Create simple sphere model with H1 and H2 + mat = openmc.Material() + mat.add_components({'H1': 1.0, 'H2': 1.0}) + mat.set_density('g/cm3', 1.0) + sph = openmc.Sphere(r=10.0, boundary_type='vacuum') + cell = openmc.Cell(fill=mat, region=-sph) + model = openmc.Model() + model.geometry = openmc.Geometry([cell]) + model.settings.run_mode = 'fixed source' + model.settings.particles = 1000 + model.settings.batches = 10 + + # Set up two reaction rate tallies, one that multplies by density and the + # other that doesn't + tally_macro = openmc.Tally() + tally_macro.nuclides = ['H1', 'H2', 'H3'] + tally_macro.scores = ['total', 'elastic'] + tally_micro = openmc.Tally() + tally_micro.nuclides = ['H1', 'H2', 'H3'] + tally_micro.scores = ['total', 'elastic'] + tally_micro.multiply_density = False + model.tallies = [tally_macro, tally_micro] + + sp_filename = model.run() + with openmc.StatePoint(sp_filename) as sp: + tally_macro = sp.tallies[tally_macro.id] + tally_micro = sp.tallies[tally_micro.id] + + # Make sure multply_density attribute from statepoint is set correctly + assert tally_macro.multiply_density + assert not tally_micro.multiply_density + + # Dividing macro by density should give micro + density = mat.get_nuclide_atom_densities() + for nuc in ('H1', 'H2'): + micro_derived = tally_macro.get_values(nuclides=[nuc]) / density[nuc] + micro = tally_micro.get_values(nuclides=[nuc]) + assert micro_derived == pytest.approx(micro) + + # For macro tally, H3 scores should be zero + assert np.all(tally_macro.get_values(nuclides=['H3']) == 0.0) + + # For micro tally, H3 scores should be positive + assert np.all(tally_micro.get_values(nuclides=['H3']) > 0.0) diff --git a/tests/unit_tests/test_temp_interp.py b/tests/unit_tests/test_temp_interp.py new file mode 100644 index 00000000000..4c2882347b3 --- /dev/null +++ b/tests/unit_tests/test_temp_interp.py @@ -0,0 +1,275 @@ +from math import isnan +import os +from pathlib import Path + +import numpy as np +import openmc.data +from openmc.data import K_BOLTZMANN +from openmc.stats import Uniform +import pytest + + +def make_fake_cross_section(): + """Create fake U235 nuclide with a fake thermal scattering library attached + + This nuclide is designed to have k_inf=1 at 300 K, k_inf=2 at 600 K, and + k_inf=1 at 900 K. The absorption cross section is also constant with + temperature so as to make the true k-effective go linear with temperature. + """ + + def isotropic_angle(E_min, E_max): + return openmc.data.AngleDistribution( + [E_min, E_max], + [Uniform(-1., 1.), Uniform(-1., 1.)] + ) + + def cross_section(value): + return openmc.data.Tabulated1D( + energy, + value*np.ones_like(energy) + ) + + temperatures = (300, 600, 900) + + u235_fake = openmc.data.IncidentNeutron( + 'U235', 92, 235, 0, 233.0248, [T*K_BOLTZMANN for T in temperatures] + ) + + # Create energy grids + E_min, E_max = 1e-5, 20.0e6 + energy = np.logspace(np.log10(E_min), np.log10(E_max)) + for T in temperatures: + u235_fake.energy['{}K'.format(T)] = energy + + # Create elastic scattering + elastic = openmc.data.Reaction(2) + for T in temperatures: + elastic.xs['{}K'.format(T)] = cross_section(1.0) + elastic_dist = openmc.data.UncorrelatedAngleEnergy(isotropic_angle(E_min, E_max)) + product = openmc.data.Product() + product.distribution.append(elastic_dist) + elastic.products.append(product) + u235_fake.reactions[2] = elastic + + # Create fission + fission = openmc.data.Reaction(18) + fission.center_of_mass = False + fission.Q_value = 193.0e6 + fission_xs = (2., 4., 2.) + for T, xs in zip(temperatures, fission_xs): + fission.xs['{}K'.format(T)] = cross_section(xs) + a = openmc.data.Tabulated1D([E_min, E_max], [0.988e6, 0.988e6]) + b = openmc.data.Tabulated1D([E_min, E_max], [2.249e-6, 2.249e-6]) + fission_dist = openmc.data.UncorrelatedAngleEnergy( + isotropic_angle(E_min, E_max), + openmc.data.WattEnergy(a, b, -E_max) + ) + product = openmc.data.Product() + product.distribution.append(fission_dist) + product.yield_ = openmc.data.Polynomial((2.0,)) + fission.products.append(product) + u235_fake.reactions[18] = fission + + # Create capture + capture = openmc.data.Reaction(102) + capture.q_value = 6.5e6 + capture_xs = (2., 0., 2.) + for T, xs in zip(temperatures, capture_xs): + capture.xs['{}K'.format(T)] = cross_section(xs) + u235_fake.reactions[102] = capture + + # Export HDF5 file + u235_fake.export_to_hdf5('U235_fake.h5', 'w') + + # Create a fake thermal scattering library attached to the fake U235 data + c_U_fake = openmc.data.ThermalScattering("c_U_fake", 1.9968, 4.9, [0.0253]) + c_U_fake.nuclides = ['U235'] + + # Create elastic reaction + bragg_edges = [0.00370672, 0.00494229] + factors = [0.00375735, 0.01386287] + coherent_xs = openmc.data.CoherentElastic(bragg_edges, factors) + incoherent_xs_294 = openmc.data.Tabulated1D([0.00370672, 0.00370672], [0.00370672, 0.00370672]) + elastic_xs_base = openmc.data.Sum((coherent_xs, incoherent_xs_294)) + elastic_xs = {'294K': elastic_xs_base, '600K': elastic_xs_base} + coherent_dist = openmc.data.CoherentElasticAE(coherent_xs) + incoherent_dist_294 = openmc.data.IncoherentElasticAEDiscrete([ + [-0.6, -0.18, 0.18, 0.6], [-0.6, -0.18, 0.18, 0.6] + ]) + incoherent_dist_600 = openmc.data.IncoherentElasticAEDiscrete([ + [-0.1, -0.2, 0.2, 0.1], [-0.1, -0.2, 0.2, 0.1] + ]) + elastic_dist = { + '294K': openmc.data.MixedElasticAE(coherent_dist, incoherent_dist_294), + '600K': openmc.data.MixedElasticAE(coherent_dist, incoherent_dist_600) + } + c_U_fake.elastic = openmc.data.ThermalScatteringReaction(elastic_xs, elastic_dist) + + # Create inelastic reaction + inelastic_xs = { + '294K': openmc.data.Tabulated1D([1.0e-5, 4.9], [13.4, 3.35]), + '600K': openmc.data.Tabulated1D([1.0e-2, 10], [1.4, 5]) + } + breakpoints = [3] + interpolation = [2] + energy = [1.0e-5, 4.3e-2, 4.9] + energy_out = [ + openmc.data.Tabular([0.0002, 0.067, 0.146, 0.366], [0.25, 0.25, 0.25, 0.25]), + openmc.data.Tabular([0.0001, 0.009, 0.137, 0.277], [0.25, 0.25, 0.25, 0.25]), + openmc.data.Tabular([0.0579, 4.555, 4.803, 4.874], [0.25, 0.25, 0.25, 0.25]), + ] + for eout in energy_out: + eout.normalize() + eout.c = eout.cdf() + discrete = openmc.stats.Discrete([-0.9, -0.6, -0.3, -0.1, 0.1, 0.3, 0.6, 0.9], [1/8]*8) + discrete.c = discrete.cdf()[1:] + mu = [[discrete]*4]*3 + dist = openmc.data.IncoherentInelasticAE( + breakpoints, interpolation, energy, energy_out, mu) + inelastic_dist = {'294K': dist, '600K': dist} + inelastic = openmc.data.ThermalScatteringReaction(inelastic_xs, inelastic_dist) + c_U_fake.inelastic = inelastic + + # Export HDF5 file + c_U_fake.export_to_hdf5("c_U_fake.h5") + + # Create a data library of the fake nuclide and its thermal scattering data + lib = openmc.data.DataLibrary() + lib.register_file('U235_fake.h5') + lib.register_file("c_U_fake.h5") + lib.export_to_xml('cross_sections_fake.xml') + + +@pytest.fixture(scope='module') +def model(tmp_path_factory): + tmp_path = tmp_path_factory.mktemp("temp_interp") + orig = Path.cwd() + os.chdir(tmp_path) + + make_fake_cross_section() + + model = openmc.model.Model() + mat = openmc.Material() + mat.add_nuclide('U235', 1.0) + model.materials.append(mat) + model.materials.cross_sections = str(Path('cross_sections_fake.xml').resolve()) + + sph = openmc.Sphere(r=100.0, boundary_type='reflective') + cell = openmc.Cell(fill=mat, region=-sph) + model.geometry = openmc.Geometry([cell]) + + model.settings.particles = 1000 + model.settings.inactive = 0 + model.settings.batches = 10 + + tally = openmc.Tally() + tally.scores = ['absorption', 'fission', 'scatter', 'nu-fission'] + model.tallies = [tally] + + try: + yield model + finally: + os.chdir(orig) + + +@pytest.mark.parametrize( + ["method", "temperature", "fission_expected", "tolerance"], + [ + ("nearest", 300.0, 0.5, 10), + ("nearest", 600.0, 1.0, 10), + ("nearest", 900.0, 0.5, 10), + ("interpolation", 360.0, 0.6, 10), + ("interpolation", 450.0, 0.75, 10), + ("interpolation", 540.0, 0.9, 10), + ("interpolation", 660.0, 0.9, 10), + ("interpolation", 750.0, 0.75, 10), + ("interpolation", 840.0, 0.6, 10), + ("interpolation", 295.0, 0.5, 10), + ("interpolation", 990.0, 0.5, 100), + ] +) +def test_interpolation(model, method, temperature, fission_expected, tolerance): + model.settings.temperature = {'method': method, 'default': temperature, "tolerance": tolerance} + sp_filename = model.run() + with openmc.StatePoint(sp_filename) as sp: + t = sp.tallies[model.tallies[0].id] + absorption_mean, fission_mean, scatter_mean, nu_fission_mean = t.mean.ravel() + absorption_unc, fission_unc, scatter_unc, nu_fission_unc = t.std_dev.ravel() + + nu = 2.0 + assert abs(absorption_mean - 1) < 3*absorption_unc + assert abs(fission_mean - fission_expected) < 3*fission_unc + assert abs(scatter_mean - 1/4) < 3*scatter_unc + assert abs(nu_fission_mean - nu*fission_expected) < 3*nu_fission_unc + + # Check that k-effective value matches expected + k = sp.keff + if isnan(k.s): + assert k.n == pytest.approx(nu*fission_expected) + else: + assert abs(k.n - nu*fission_expected) <= 3*k.s + + +def test_temperature_interpolation_tolerance(model): + """Test applying global and cell temperatures with thermal scattering libraries + """ + model.materials[0].add_s_alpha_beta("c_U_fake") + + # Default k-effective, using the thermal scattering data's minimum available temperature + model.settings.temperature = {'method': "nearest", 'default': 294, "tolerance": 50} + sp_filename = model.run() + with openmc.StatePoint(sp_filename) as sp: + default_k = sp.keff.n + + # Get k-effective with temperature below the minimum but in interpolation mode + model.settings.temperature = {'method': "interpolation", 'default': 255, "tolerance": 50} + sp_filename = model.run() + with openmc.StatePoint(sp_filename) as sp: + interpolated_k = sp.keff.n + + # Get the k-effective with the temperature applied to the cell, instead of globally + model.settings.temperature = {'method': "interpolation", 'default': 500, "tolerance": 50} + for cell in model.geometry.get_all_cells().values(): + cell.temperature = 275 + sp_filename = model.run() + with openmc.StatePoint(sp_filename) as sp: + cell_k = sp.keff.n + + # All calculated k-effectives should be equal + assert default_k == pytest.approx(interpolated_k) + assert interpolated_k == pytest.approx(cell_k) + + +def test_temperature_slightly_above(run_in_tmpdir): + """In this test, we have two materials at temperatures close to actual data + temperatures. However, one is slightly above the highest temperature which + invokes separate logic. The k-effective value should be somewhere between + k=2 (if the temperature were only 600 K) and k=1 (if the temperature were + only 900 K).""" + + make_fake_cross_section() + + model = openmc.Model() + mat1 = openmc.Material() + mat1.add_nuclide('U235', 1.0) + mat1.temperature = 900.1 + mat2 = openmc.Material() + mat2.add_nuclide('U235', 1.0) + mat2.temperature = 600.0 + model.materials.extend([mat1, mat2]) + model.materials.cross_sections = str(Path('cross_sections_fake.xml').resolve()) + + sph1 = openmc.Sphere(r=1.0) + sph2 = openmc.Sphere(r=4.0, boundary_type='reflective') + cell1 = openmc.Cell(fill=mat1, region=-sph1) + cell2 = openmc.Cell(fill=mat2, region=+sph1 & -sph2) + model.geometry = openmc.Geometry([cell1, cell2]) + + model.settings.particles = 1000 + model.settings.inactive = 0 + model.settings.batches = 10 + model.settings.temperature = {'method': 'interpolation'} + + sp_filename = model.run() + with openmc.StatePoint(sp_filename) as sp: + assert 1.1 < sp.keff.n < 1.9 diff --git a/tests/unit_tests/test_time_filter.py b/tests/unit_tests/test_time_filter.py new file mode 100644 index 00000000000..b57c80a9758 --- /dev/null +++ b/tests/unit_tests/test_time_filter.py @@ -0,0 +1,187 @@ +from math import sqrt +from random import uniform + +import numpy as np +import openmc +import pytest + + +def test_time_filter_basics(): + f = openmc.TimeFilter([1.0, 2.0, 5.0, 9.0]) + np.testing.assert_allclose(f.bins[0], [1.0, 2.0]) + np.testing.assert_allclose(f.bins[1], [2.0, 5.0]) + np.testing.assert_allclose(f.bins[-1], [5.0, 9.0]) + assert len(f.bins) == 3 + + # Make sure __repr__ works + repr(f) + + # to_xml_element() + elem = f.to_xml_element() + assert elem.tag == 'filter' + assert elem.attrib['type'] == 'time' + + +def time(particle, distance, E): + """Return the time it takes a particle at a given energy to travel a certain + distance""" + if particle == 'neutron': + mass = 939.56542052e6 # eV/c² + elif particle == 'photon': + mass = 0.0 + + # Calculate speed via v = c * sqrt(1 - γ^-2) + inv_gamma = mass / (E + mass) + velocity = 2.99792458e10 * sqrt(1 - inv_gamma * inv_gamma) # cm/s + return distance / velocity + + +@pytest.fixture(params=['neutron', 'photon']) +def model(request): + # Select random sphere radius, source position, and source energy + r = uniform(0., 2.) + x = uniform(2., 10.) + E = uniform(0., 20.0e6) + + # Create model + model = openmc.Model() + mat = openmc.Material() + mat.add_nuclide('Zr90', 1.0) + mat.set_density('g/cm3', 1.0) + model.materials.append(mat) + inner_sphere = openmc.Sphere(r=r) + outer_sphere = openmc.Sphere(r=10.0, boundary_type='vacuum') + center_cell = openmc.Cell(fill=mat, region=-inner_sphere) + outer_void = openmc.Cell(region=+inner_sphere & -outer_sphere) + model.geometry = openmc.Geometry([center_cell, outer_void]) + model.settings = openmc.Settings() + model.settings.run_mode = 'fixed source' + model.settings.particles = 1000 + model.settings.batches = 20 + particle = request.param + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Point((x, 0., 0.)), + angle=openmc.stats.Monodirectional([-1., 0., 0.]), + energy=openmc.stats.Discrete([E], [1.0]), + particle=particle + ) + + # Calculate time it will take neutrons to reach sphere + t0 = time(particle, x - r, E) + + # Create tally with time filter + tally = openmc.Tally() + tally.filters = [openmc.TimeFilter([0.0, t0, 2*t0])] + tally.scores = ['total'] + model.tallies.append(tally) + return model + + +@pytest.fixture(params=['neutron', 'photon']) +def model_surf(request): + # Select random distance and source energy + x = uniform(50., 100.) + E = uniform(0., 20.0e6) + + # Create model + model = openmc.Model() + mat = openmc.Material() + mat.add_nuclide('Zr90', 1.0) + mat.set_density('g/cm3', 1.0) + model.materials.append(mat) + left = openmc.XPlane(-1., boundary_type='vacuum') + black_surface = openmc.XPlane(x, boundary_type='vacuum') + right = openmc.XPlane(x + 1) + void_cell = openmc.Cell(region=+left & -black_surface) + black_cell = openmc.Cell(region=+black_surface & -right) + model.geometry = openmc.Geometry([void_cell, black_cell]) + model.settings = openmc.Settings() + model.settings.run_mode = 'fixed source' + model.settings.particles = 1000 + model.settings.batches = 20 + particle = request.param + model.settings.source = openmc.IndependentSource( + space=openmc.stats.Point((0., 0., 0.)), + angle=openmc.stats.Monodirectional([1., 0., 0.]), + energy=openmc.stats.Discrete([E], [1.0]), + particle=particle + ) + + # Calculate time it will take neutrons to reach purely-absorbing surface + t0 = time(particle, x, E) + + # Create tally with surface and time filters + tally = openmc.Tally() + tally.filters = [ + openmc.SurfaceFilter([black_surface]), + openmc.TimeFilter([0.0, t0*0.999, t0*1.001, 100.0]) + ] + tally.scores = ['current'] + model.tallies.append(tally) + return model + + +def test_time_filter_volume(model, run_in_tmpdir): + sp_filename = model.run() + with openmc.StatePoint(sp_filename) as sp: + t = sp.tallies[model.tallies[0].id] + values = t.mean.ravel() + + # Before t0, the reaction rate should be zero + assert values[0] == pytest.approx(0.0) + + # After t0, the reaction rate should be positive + assert values[1] > 0.0 + + +def test_time_filter_surface(model_surf, run_in_tmpdir): + sp_filename = model_surf.run() + with openmc.StatePoint(sp_filename) as sp: + t = sp.tallies[model_surf.tallies[0].id] + values = t.mean.ravel() + print(values) + + # Before t0-ε, the current should be zero + assert values[0] == 0.0 + + # Between t0-ε and t0+ε, the current should be one + assert values[1] == 1.0 + + # After t0+ε, the current should be zero + assert values[2] == 0.0 + + +def test_small_time_interval(run_in_tmpdir): + # Create a model with a photon source at 1.0e8 seconds. Based on the speed + # of the photon, the time intervals are on the order of 1e-9 seconds, which + # are effectively 0 when compared to the starting time of the photon. + mat = openmc.Material() + mat.add_element('N', 1.0) + mat.set_density('g/cm3', 0.001) + sph = openmc.Sphere(r=5.0, boundary_type='vacuum') + cell = openmc.Cell(fill=mat, region=-sph) + model = openmc.Model() + model.geometry = openmc.Geometry([cell]) + model.settings.particles = 100 + model.settings.batches = 10 + model.settings.run_mode = 'fixed source' + model.settings.source = openmc.IndependentSource( + time=openmc.stats.Discrete([1.0e8], [1.0]), + particle='photon' + ) + + # Add tallies with and without a time filter that should match all particles + time_filter = openmc.TimeFilter([0.0, 1.0e100]) + tally_with_filter = openmc.Tally() + tally_with_filter.filters = [time_filter] + tally_with_filter.scores = ['flux'] + tally_without_filter = openmc.Tally() + tally_without_filter.scores = ['flux'] + model.tallies.extend([tally_with_filter, tally_without_filter]) + + # Run the model and make sure the two tallies match + sp_filename = model.run() + with openmc.StatePoint(sp_filename) as sp: + flux_with = sp.tallies[tally_with_filter.id].mean.ravel()[0] + flux_without = sp.tallies[tally_without_filter.id].mean.ravel()[0] + assert flux_with == pytest.approx(flux_without) diff --git a/tests/unit_tests/test_torus.py b/tests/unit_tests/test_torus.py new file mode 100644 index 00000000000..8c413ffe06d --- /dev/null +++ b/tests/unit_tests/test_torus.py @@ -0,0 +1,47 @@ +from itertools import combinations +from random import uniform +import openmc +import pytest + + +def get_torus_keff(cls, R, r, center=(0, 0, 0)): + model = openmc.Model() + mat = openmc.Material() + mat.add_nuclide('U235', 1.0) + mat.set_density('g/cm3', 10.0) + + x, y, z = center + torus = cls(x0=x, y0=y, z0=z, a=R, b=r, c=r) + sphere = openmc.Sphere(x0=x, y0=y, z0=z, r=R + r + 1, boundary_type="vacuum") + torus_cell = openmc.Cell(fill=mat, region=-torus) + outer_cell = openmc.Cell(region=+torus & -sphere) + model.geometry = openmc.Geometry([torus_cell, outer_cell]) + + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point(center)) + model.settings.batches = 10 + model.settings.inactive = 5 + model.settings.particles = 1000 + + sp_path = model.run() + with openmc.StatePoint(sp_path) as sp: + return sp.keff + + +@pytest.mark.parametrize("R,r", [(2.1, 2.0), (3.0, 1.0)]) +def test_torus_keff(R, r, run_in_tmpdir): + random_point = lambda: (uniform(-5, 5), uniform(-5, 5), uniform(-5, 5)) + keffs = [ + get_torus_keff(openmc.XTorus, R, r), + get_torus_keff(openmc.XTorus, R, r, random_point()), + get_torus_keff(openmc.YTorus, R, r), + get_torus_keff(openmc.YTorus, R, r, random_point()), + get_torus_keff(openmc.ZTorus, R, r), + get_torus_keff(openmc.ZTorus, R, r, random_point()) + ] + + # For each combination of keff values, their difference should be within + # uncertainty (3 std dev) + for k1, k2 in combinations(keffs, 2): + print(k1, k2) + diff = k1 - k2 + assert abs(diff.n) < 3*diff.s diff --git a/tests/unit_tests/test_tracks.py b/tests/unit_tests/test_tracks.py new file mode 100644 index 00000000000..3951a72c63c --- /dev/null +++ b/tests/unit_tests/test_tracks.py @@ -0,0 +1,192 @@ +from pathlib import Path + +import h5py +import numpy as np +import openmc +import pytest + +from tests.testing_harness import config + + +@pytest.fixture +def sphere_model(): + openmc.reset_auto_ids() + mat = openmc.Material() + mat.add_nuclide('Zr90', 1.0) + mat.set_density('g/cm3', 1.0) + + model = openmc.Model() + sph = openmc.Sphere(r=25.0, boundary_type='vacuum') + cell = openmc.Cell(fill=mat, region=-sph) + model.geometry = openmc.Geometry([cell]) + + model.settings.run_mode = 'fixed source' + model.settings.batches = 2 + model.settings.particles = 50 + + return model + + +def generate_track_file(model, **kwargs): + # If running in MPI mode, setup proper keyword arguments for run() + kwargs.setdefault('openmc_exec', config['exe']) + if config['mpi']: + kwargs['mpi_args'] = [config['mpiexec'], '-n', config['mpi_np']] + model.run(**kwargs) + + if config['mpi'] and int(config['mpi_np']) > 1: + # With MPI, we need to combine track files + track_files = Path.cwd().glob('tracks_p*.h5') + openmc.Tracks.combine(track_files, 'tracks.h5') + else: + track_file = Path('tracks.h5') + assert track_file.is_file() + + +@pytest.mark.parametrize("particle", ["neutron", "photon"]) +def test_tracks(sphere_model, particle, run_in_tmpdir): + # Set track identifiers + sphere_model.settings.track = [(1, 1, 1), (1, 1, 10), (2, 1, 15)] + + # Set source particle + sphere_model.settings.source = openmc.IndependentSource(particle=particle) + + # Run OpenMC to generate tracks.h5 file + generate_track_file(sphere_model) + + # Open track file and make sure we have correct number of tracks + tracks = openmc.Tracks('tracks.h5') + assert len(tracks) == len(sphere_model.settings.track) + + for track, identifier in zip(tracks, sphere_model.settings.track): + # Check attributes on Track object + assert isinstance(track, openmc.Track) + assert track.identifier == identifier + assert isinstance(track.particle_tracks, list) + if particle == 'neutron': + assert len(track.particle_tracks) == 1 + + # Check attributes on ParticleTrack object + particle_track = track.particle_tracks[0] + assert isinstance(particle_track, openmc.ParticleTrack) + + assert particle_track.particle.name.lower() == particle + assert isinstance(particle_track.states, np.ndarray) + + # Sanity checks on actual data + for state in particle_track.states: + assert np.linalg.norm([*state['r']]) <= 25.0001 + assert np.linalg.norm([*state['u']]) == pytest.approx(1.0) + assert 0.0 <= state['E'] <= 20.0e6 + assert state['time'] >= 0.0 + assert 0.0 <= state['wgt'] <= 1.0 + assert state['cell_id'] == 1 + assert state['material_id'] == 1 + + # Checks on 'sources' property + sources = track.sources + assert len(sources) == len(track.particle_tracks) + x = sources[0] + state = particle_track.states[0] + assert x.r == (*state['r'],) + assert x.u == (*state['u'],) + assert x.E == state['E'] + assert x.time == state['time'] + assert x.wgt == state['wgt'] + assert x.particle == particle_track.particle + + +def test_max_tracks(sphere_model, run_in_tmpdir): + # Set maximum number of tracks per process to write + sphere_model.settings.max_tracks = expected_num_tracks = 10 + if config['mpi']: + expected_num_tracks *= int(config['mpi_np']) + + # Run OpenMC to generate tracks.h5 file + generate_track_file(sphere_model, tracks=True) + + # Open track file and make sure we have correct number of tracks + tracks = openmc.Tracks('tracks.h5') + assert len(tracks) == expected_num_tracks + + +def test_filter(sphere_model, run_in_tmpdir): + # Set maximum number of tracks per process to write + sphere_model.settings.max_tracks = 25 + sphere_model.settings.photon_transport = True + + # Run OpenMC to generate tracks.h5 file + generate_track_file(sphere_model, tracks=True) + + tracks = openmc.Tracks('tracks.h5') + for track in tracks: + # Test filtering by particle + matches = track.filter(particle='photon') + for x in matches: + assert x.particle == openmc.ParticleType.PHOTON + + # Test general state filter + matches = track.filter(state_filter=lambda s: s['cell_id'] == 1) + assert isinstance(matches, openmc.Track) + assert matches.particle_tracks == track.particle_tracks + matches = track.filter(state_filter=lambda s: s['cell_id'] == 2) + assert matches.particle_tracks == [] + matches = track.filter(state_filter=lambda s: s['E'] < 0.0) + assert matches.particle_tracks == [] + + # Test filter method on Tracks + matches = tracks.filter(particle='neutron') + assert isinstance(matches, openmc.Tracks) + assert matches == tracks + matches = tracks.filter(state_filter=lambda s: s['E'] > 0.0) + assert matches == tracks + matches = tracks.filter(particle='bunnytron') + assert matches == [] + + +def test_write_to_vtk(sphere_model): + vtk = pytest.importorskip('vtk') + # Set maximum number of tracks per process to write + sphere_model.settings.max_tracks = 25 + sphere_model.settings.photon_transport = True + + # Run OpenMC to generate tracks.h5 file + generate_track_file(sphere_model, tracks=True) + + tracks = openmc.Tracks('tracks.h5') + polydata = tracks.write_to_vtk('tracks.vtp') + + assert isinstance(polydata, vtk.vtkPolyData) + assert Path('tracks.vtp').is_file() + + +def test_restart_track(run_in_tmpdir, sphere_model): + # cut the sphere model in half with an improper boundary condition + plane = openmc.XPlane(x0=-1.0) + for cell in sphere_model.geometry.get_all_cells().values(): + cell.region &= +plane + + # generate lost particle files + with pytest.raises(RuntimeError, match='Maximum number of lost particles has been reached.'): + sphere_model.run(output=False) + + lost_particle_files = list(Path.cwd().glob('particle_*.h5')) + assert len(lost_particle_files) > 0 + particle_file = lost_particle_files[0] + # restart the lost particle with tracks enabled + sphere_model.run(tracks=True, restart_file=particle_file) + tracks_file = Path('tracks.h5') + assert tracks_file.is_file() + + # check that the last track of the file matches the lost particle file + tracks = openmc.Tracks(tracks_file) + initial_state = tracks[0].particle_tracks[0].states[0] + restart_r = np.array(initial_state['r']) + restart_u = np.array(initial_state['u']) + + with h5py.File(particle_file, 'r') as lost_particle_file: + lost_r = np.array(lost_particle_file['xyz'][()]) + lost_u = np.array(lost_particle_file['uvw'][()]) + + pytest.approx(restart_r, lost_r) + pytest.approx(restart_u, lost_u) diff --git a/tests/unit_tests/test_transfer_volumes.py b/tests/unit_tests/test_transfer_volumes.py index 2e735c911e3..b768bc88a2a 100644 --- a/tests/unit_tests/test_transfer_volumes.py +++ b/tests/unit_tests/test_transfer_volumes.py @@ -1,11 +1,8 @@ -"""Regression tests for openmc.deplete.Results.transfer_volumes method. - - -""" +"""Regression tests for openmc.deplete.Results.transfer_volumes method.""" from pytest import approx import openmc -from openmc.deplete import PredictorIntegrator, ResultsList +from openmc.deplete import PredictorIntegrator, Results from tests import dummy_operator @@ -22,7 +19,7 @@ def test_transfer_volumes(run_in_tmpdir): PredictorIntegrator(op, dt, power).integrate() # Load the files - res = openmc.deplete.ResultsList.from_hdf5(op.output_dir / "depletion_results.h5") + res = openmc.deplete.Results(op.output_dir / "depletion_results.h5") # Create a dictionary of volumes to transfer res[0].volume['1'] = 1.5 @@ -40,7 +37,7 @@ def test_transfer_volumes(run_in_tmpdir): geometry = openmc.Geometry(root) # Transfer volumes - res[0].transfer_volumes(geometry) + res[0].transfer_volumes(openmc.Model(geometry)) assert mat1.volume == 1.5 assert mat2.volume is None diff --git a/tests/unit_tests/test_triggers.py b/tests/unit_tests/test_triggers.py new file mode 100644 index 00000000000..6b9e54eeb72 --- /dev/null +++ b/tests/unit_tests/test_triggers.py @@ -0,0 +1,115 @@ + +import openmc + +def test_tally_trigger(run_in_tmpdir): + pincell = openmc.examples.pwr_pin_cell() + + # create a tally filter on the materials + mat_filter = openmc.MaterialFilter(pincell.materials) + + # create a tally with triggers applied + tally = openmc.Tally() + tally.filters = [mat_filter] + tally.scores = ['scatter'] + + trigger = openmc.Trigger('rel_err', 0.05) + trigger.scores = ['scatter'] + + tally.triggers = [trigger] + + pincell.tallies = [tally] + + pincell.settings.trigger_active = True + pincell.settings.trigger_max_batches = 100 + pincell.settings.trigger_batch_interval = 5 + + sp_file = pincell.run() + with openmc.StatePoint(sp_file) as sp: + expected_realizations = sp.n_realizations + + # adding other scores to the tally should not change the + # number of batches required to satisfy the trigger + tally.scores = ['total', 'absorption', 'scatter'] + + sp_file = pincell.run() + + with openmc.StatePoint(sp_file) as sp: + realizations = sp.n_realizations + + assert realizations == expected_realizations + + +def test_tally_trigger_null_score(run_in_tmpdir): + pincell = openmc.examples.pwr_pin_cell() + + # create a tally filter on the materials + mat_filter = openmc.MaterialFilter(pincell.materials) + + # apply a tally with a score that be tallied in this model + tally = openmc.Tally() + tally.filters = [mat_filter] + tally.scores = ['pair-production'] + + trigger = openmc.Trigger('rel_err', 0.05) + trigger.scores = ['pair-production'] + + tally.triggers = [trigger] + + pincell.tallies = [tally] + + pincell.settings.trigger_active = True + pincell.settings.trigger_max_batches = 50 + pincell.settings.trigger_batch_interval = 5 + + sp_file = pincell.run() + + with openmc.StatePoint(sp_file) as sp: + # verify that the tally mean is zero + tally_out = sp.get_tally(id=tally.id) + assert all(tally_out.mean == 0.0) + + # we expect that this simulation will run + # up to the max allowed batches + total_batches = sp.n_realizations + sp.n_inactive + assert total_batches == pincell.settings.trigger_max_batches + + +def test_tally_trigger_zero_ignored(run_in_tmpdir): + pincell = openmc.examples.pwr_pin_cell() + + # create an energy filter below and around the O-16(n,p) threshold (1.02e7 eV) + e_filter = openmc.EnergyFilter([0.0, 1e7, 2e7]) + + # create a tally with triggers applied + tally = openmc.Tally() + tally.filters = [e_filter] + tally.scores = ['(n,p)'] + tally.nuclides = ["O16"] + + # 100% relative error: should be immediately satisfied in nonzero bin + trigger = openmc.Trigger('rel_err', 1.0) + trigger.scores = ['(n,p)'] + trigger.ignore_zeros = True + + tally.triggers = [trigger] + + pincell.tallies = [tally] + + pincell.settings.particles = 1000 # we need a few more particles for this + pincell.settings.trigger_active = True + pincell.settings.trigger_max_batches = 50 + pincell.settings.trigger_batch_interval = 20 + + sp_file = pincell.run() + + with openmc.StatePoint(sp_file) as sp: + # verify that the first bin is zero and the second is nonzero + tally_out = sp.get_tally(id=tally.id) + below, above = tally_out.mean.squeeze() + assert below == 0.0, "Tally events observed below expected threshold" + assert above > 0, "No tally events observed. Test with more particles." + + # we expect that the trigger fires before max batches are hit + total_batches = sp.n_realizations + sp.n_inactive + assert total_batches < pincell.settings.trigger_max_batches + diff --git a/tests/unit_tests/test_universe.py b/tests/unit_tests/test_universe.py index ab3fd6e33a3..46d4ec3f734 100644 --- a/tests/unit_tests/test_universe.py +++ b/tests/unit_tests/test_universe.py @@ -1,5 +1,4 @@ -import xml.etree.ElementTree as ET - +import lxml.etree as ET import numpy as np import openmc import pytest @@ -49,16 +48,55 @@ def test_bounding_box(): def test_plot(run_in_tmpdir, sphere_model): + + # model with -inf and inf in the bounding box + pincell = openmc.examples.pwr_pin_cell() + materials = pincell.materials + + mat_colors = { + materials[0]: (200, 1, 1), + materials[1]: "gray", + materials[2]: "limegreen" + } + + for basis in ('xy', 'yz', 'xz'): + plot = pincell.geometry.root_universe.plot( + colors=mat_colors, + color_by="material", + legend=True, + pixels=(10, 10), + basis=basis, + outline=True, + axis_units='m' + ) + assert plot.xaxis.get_label().get_text() == f'{basis[0]} [m]' + assert plot.yaxis.get_label().get_text() == f'{basis[1]} [m]' + + # model with no inf values in bounding box m = sphere_model.materials[0] univ = sphere_model.geometry.root_universe colors = {m: 'limegreen'} + for basis in ('xy', 'yz', 'xz'): - univ.plot( - basis=basis, - pixels=(10, 10), - color_by='material', + plot = univ.plot( colors=colors, + color_by="cell", + legend=False, + pixels=100, + basis=basis, + outline=False + ) + assert plot.xaxis.get_label().get_text() == f'{basis[0]} [cm]' + assert plot.yaxis.get_label().get_text() == f'{basis[1]} [cm]' + + msg = "Must pass 'colors' dictionary if you are adding a legend via legend=True." + # This plot call should fail as legend is True but colors is None + with pytest.raises(ValueError, match=msg): + univ.plot( + color_by="cell", + legend=True, + pixels=100, ) @@ -93,10 +131,12 @@ def test_get_all_universes(): u2 = openmc.Universe(cells=[c2]) c3 = openmc.Cell(fill=u1) c4 = openmc.Cell(fill=u2) - u3 = openmc.Universe(cells=[c3, c4]) + u3 = openmc.DAGMCUniverse(filename="") + c5 = openmc.Cell(fill=u3) + u4 = openmc.Universe(cells=[c3, c4, c5]) - univs = set(u3.get_all_universes().values()) - assert not (univs ^ {u1, u2}) + univs = set(u4.get_all_universes().values()) + assert not (univs ^ {u1, u2, u3}) def test_clone(): @@ -107,11 +147,13 @@ def test_clone(): c2.fill = openmc.Material() c3 = openmc.Cell() u1 = openmc.Universe(name='cool', cells=(c1, c2, c3)) + u1.volume = 1. u2 = u1.clone() assert u2.name == u1.name assert u2.cells != u1.cells assert u2.get_all_materials() != u1.get_all_materials() + assert u2.volume == u1.volume u2 = u1.clone(clone_materials=False) assert u2.get_all_materials() == u1.get_all_materials() @@ -120,6 +162,33 @@ def test_clone(): assert next(iter(u3.cells.values())).region ==\ next(iter(u1.cells.values())).region + # Change attributes, make sure clone stays intact + u1.volume = 2. + u1.name = "different name" + assert u3.volume != u1.volume + assert u3.name != u1.name + + # Test cloning a DAGMC universe + dagmc_u = openmc.DAGMCUniverse(filename="", name="DAGMC universe") + dagmc_u.volume = 1. + dagmc_u.auto_geom_ids = True + dagmc_u.auto_mat_ids = True + dagmc_u1 = dagmc_u.clone() + assert dagmc_u1.name == dagmc_u.name + assert dagmc_u1.volume == dagmc_u.volume + assert dagmc_u1.auto_geom_ids == dagmc_u.auto_geom_ids + assert dagmc_u1.auto_mat_ids == dagmc_u.auto_mat_ids + + # Change attributes, check the clone remained intact + dagmc_u.name = "another name" + dagmc_u.auto_geom_ids = False + dagmc_u.auto_mat_ids = False + dagmc_u.volume = 2. + assert dagmc_u1.name != dagmc_u.name + assert dagmc_u1.volume != dagmc_u.volume + assert dagmc_u1.auto_geom_ids != dagmc_u.auto_geom_ids + assert dagmc_u1.auto_mat_ids != dagmc_u.auto_mat_ids + def test_create_xml(cell_with_lattice): cells = [openmc.Cell() for i in range(5)] @@ -132,3 +201,14 @@ def test_create_xml(cell_with_lattice): assert all(c.get('universe') == str(u.id) for c in cell_elems) assert not (set(c.get('id') for c in cell_elems) ^ set(str(c.id) for c in cells)) + + +def test_get_nuclide_densities(): + surf = openmc.Sphere() + material = openmc.Material() + material.add_elements_from_formula("H2O") + material.set_density("g/cm3", 1) + cell = openmc.Cell(region=-surf, fill=material) + universe = openmc.Universe(cells=[cell]) + with pytest.raises(RuntimeError): + universe.get_nuclide_densities() diff --git a/tests/unit_tests/test_urr_capture.py b/tests/unit_tests/test_urr_capture.py index 745d62cef0f..34b518e9de8 100644 --- a/tests/unit_tests/test_urr_capture.py +++ b/tests/unit_tests/test_urr_capture.py @@ -19,7 +19,7 @@ def th232_model(): model.settings.batches = 10 model.settings.run_mode = 'fixed source' energies = openmc.stats.Uniform(e_min, e_max) - model.settings.source = openmc.Source(energy=energies) + model.settings.source = openmc.IndependentSource(energy=energies) tally = openmc.Tally(name='rates') tally.filters = [openmc.EnergyFilter([e_min, e_max])] diff --git a/tests/unit_tests/test_volume.py b/tests/unit_tests/test_volume.py new file mode 100644 index 00000000000..0993cb66aab --- /dev/null +++ b/tests/unit_tests/test_volume.py @@ -0,0 +1,45 @@ +import numpy as np +import pytest + +import openmc + + +def test_infinity_handling(): + surf1 = openmc.Sphere(boundary_type="vacuum") + cell1 = openmc.Cell(region=-surf1) + + lower_left = (-2, -np.inf, -2) + upper_right = (np.inf, 2, 2) + + with pytest.raises(ValueError, match="must be finite"): + openmc.VolumeCalculation([cell1], 100, lower_left, upper_right) + + +@pytest.mark.parametrize('cls', [openmc.Cell, openmc.Material, openmc.Universe]) +def test_invalid_id(run_in_tmpdir, cls): + m = openmc.Material() + m.add_nuclide('U235', 0.02) + sph = openmc.Sphere(boundary_type='vacuum') + cell = openmc.Cell(fill=m, region=-sph) + model = openmc.Model(geometry=openmc.Geometry([cell])) + + # Apply volume calculation with unused domains + model.settings.volume_calculations = openmc.VolumeCalculation( + [cls()], 10000, *model.geometry.bounding_box) + + with pytest.raises(RuntimeError): + model.calculate_volumes() + + +def test_no_bcs(run_in_tmpdir): + """Ensure that a model without boundary conditions can be used in a volume calculation""" + model = openmc.examples.pwr_pin_cell() + for surface in model.geometry.get_all_surfaces().values(): + surface.boundary_type = 'transmission' + + bbox = openmc.BoundingBox([-1.]*3, [1.]*3) + cells = list(model.geometry.get_all_cells().values()) + vc = openmc.VolumeCalculation(cells, samples=10, lower_left=bbox[0], upper_right=bbox[1]) + + model.settings.volume_calculations = [vc] + model.calculate_volumes() diff --git a/tests/unit_tests/weightwindows/__init__.py b/tests/unit_tests/weightwindows/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit_tests/weightwindows/test.py b/tests/unit_tests/weightwindows/test.py new file mode 100644 index 00000000000..8af843cbdc0 --- /dev/null +++ b/tests/unit_tests/weightwindows/test.py @@ -0,0 +1,299 @@ +import os +from pathlib import Path + +import numpy as np +import pytest +from uncertainties import ufloat + +import openmc +import openmc.lib +from openmc.stats import Discrete, Point + +from tests import cdtemp + + +@pytest.fixture +def wws(): + + # weight windows + ww_files = ('ww_n.txt', 'ww_p.txt') + cwd = Path(__file__).parent.absolute() + ww_n_file, ww_p_file = [cwd / Path(f) for f in ww_files] + + # load pre-generated weight windows + # (created using the same tally as above) + ww_n_lower_bnds = np.loadtxt(ww_n_file) + ww_p_lower_bnds = np.loadtxt(ww_p_file) + + # create a mesh matching the one used + # to generate the weight windows + ww_mesh = openmc.RegularMesh() + ww_mesh.lower_left = (-240, -240, -240) + ww_mesh.upper_right = (240, 240, 240) + ww_mesh.dimension = (5, 6, 7) + + # energy bounds matching those of the + # generated weight windows + e_bnds = [0.0, 0.5, 2E7] + + ww_n = openmc.WeightWindows(ww_mesh, + ww_n_lower_bnds, + None, + 10.0, + e_bnds, + survival_ratio=1.01) + + ww_p = openmc.WeightWindows(ww_mesh, + ww_p_lower_bnds, + None, + 10.0, + e_bnds, + survival_ratio=1.01) + + return [ww_n, ww_p] + + +@pytest.fixture +def model(): + openmc.reset_auto_ids() + model = openmc.Model() + + # materials (M4 steel alloy) + m4 = openmc.Material() + m4.set_density('g/cc', 2.3) + m4.add_nuclide('H1', 0.168018676) + m4.add_nuclide("H2", 1.93244e-05) + m4.add_nuclide("O16", 0.561814465) + m4.add_nuclide("O17", 0.00021401) + m4.add_nuclide("Na23", 0.021365) + m4.add_nuclide("Al27", 0.021343) + m4.add_nuclide("Si28", 0.187439342) + m4.add_nuclide("Si29", 0.009517714) + m4.add_nuclide("Si30", 0.006273944) + m4.add_nuclide("Ca40", 0.018026179) + m4.add_nuclide("Ca42", 0.00012031) + m4.add_nuclide("Ca43", 2.51033e-05) + m4.add_nuclide("Ca44", 0.000387892) + m4.add_nuclide("Ca46", 7.438e-07) + m4.add_nuclide("Ca48", 3.47727e-05) + m4.add_nuclide("Fe54", 0.000248179) + m4.add_nuclide("Fe56", 0.003895875) + m4.add_nuclide("Fe57", 8.99727e-05) + m4.add_nuclide("Fe58", 1.19737e-05) + + s0 = openmc.Sphere(r=240) + s1 = openmc.Sphere(r=250, boundary_type='vacuum') + + c0 = openmc.Cell(fill=m4, region=-s0) + c1 = openmc.Cell(region=+s0 & -s1) + + model.geometry = openmc.Geometry([c0, c1]) + + # settings + settings = model.settings + settings.run_mode = 'fixed source' + settings.particles = 500 + settings.batches = 2 + settings.max_splits = 100 + settings.photon_transport = True + space = Point((0.001, 0.001, 0.001)) + energy = Discrete([14E6], [1.0]) + + settings.source = openmc.IndependentSource(space=space, energy=energy) + + # tally + mesh = openmc.RegularMesh() + mesh.lower_left = (-240, -240, -240) + mesh.upper_right = (240, 240, 240) + mesh.dimension = (3, 5, 7) + + mesh_filter = openmc.MeshFilter(mesh) + + e_bnds = [0.0, 0.5, 2E7] + energy_filter = openmc.EnergyFilter(e_bnds) + + particle_filter = openmc.ParticleFilter(['neutron', 'photon']) + + tally = openmc.Tally() + tally.filters = [mesh_filter, energy_filter, particle_filter] + tally.scores = ['flux'] + + model.tallies.append(tally) + + return model + + +def test_weightwindows(model, wws): + + ww_files = ('ww_n.txt', 'ww_p.txt') + cwd = Path(__file__).parent.absolute() + filepaths = [cwd / Path(f) for f in ww_files] + + with cdtemp(filepaths): + # run once with variance reduction off + model.settings.weight_windows_on = False + analog_sp = model.run() + os.rename(analog_sp, 'statepoint.analog.h5') + + model.settings.weight_windows = wws + + # check that string form of the class can be created + for ww in model.settings.weight_windows: + str(ww) + + # run again with variance reduction on + model.settings.weight_windows_on = True + ww_sp = model.run() + os.rename(ww_sp, 'statepoint.ww.h5') + + # load both statepoints and examine results + asp = openmc.StatePoint('statepoint.analog.h5') + wsp = openmc.StatePoint('statepoint.ww.h5') + + analog_tally = asp.tallies[1] + ww_tally = wsp.tallies[1] + + def compare_results(particle, analog_tally, ww_tally): + # get values from each of the tallies + an_mean = analog_tally.get_values(filters=[openmc.ParticleFilter], + filter_bins=[(particle,)]) + ww_mean = ww_tally.get_values(filters=[openmc.ParticleFilter], + filter_bins=[(particle,)]) + + # expect that more bins were scored with weight windows than + # the analog run + assert np.count_nonzero(an_mean) < np.count_nonzero(ww_mean) + + an_rel_err = analog_tally.get_values(filters=[openmc.ParticleFilter], + filter_bins=[(particle,)], + value='rel_err') + ww_rel_err = ww_tally.get_values(filters=[openmc.ParticleFilter], + filter_bins=[(particle,)], + value='rel_err') + + an_rel_err[an_mean == 0.0] = 1.0 + ww_rel_err[ww_mean == 0.0] = 1.0 + + an_avg_rel_err = np.mean(an_rel_err) + ww_avg_rel_err = np.mean(ww_rel_err) + + # expect that the average relative error in the tally + # decreases + assert an_avg_rel_err > ww_avg_rel_err + + # ensure that the value of the mesh bin containing the + # source is statistically similar in both runs + an_std_dev = analog_tally.get_values(filters=[openmc.ParticleFilter], + filter_bins=[(particle,)], + value='std_dev') + ww_std_dev = ww_tally.get_values(filters=[openmc.ParticleFilter], + filter_bins=[(particle,)], + value='std_dev') + + # index of the mesh bin containing the source for the higher + # energy group + source_bin_idx = (an_mean.shape[0]//2, 0, 0) + + an_source_bin = ufloat(an_mean[source_bin_idx], + an_std_dev[source_bin_idx]) + ww_source_bin = ufloat(ww_mean[source_bin_idx], + ww_std_dev[source_bin_idx]) + + diff = an_source_bin - ww_source_bin + + # check that values are within two combined standard deviations + assert abs(diff.nominal_value) / diff.std_dev < 2.0 + + compare_results('neutron', analog_tally, ww_tally) + compare_results('photon', analog_tally, ww_tally) + + +def test_lower_ww_bounds_shape(): + """checks that lower_ww_bounds is reshaped to the mesh dimension when set""" + ww_mesh = openmc.RegularMesh() + ww_mesh.lower_left = (-10, -10, -10) + ww_mesh.upper_right = (10, 10, 10) + ww_mesh.dimension = (2, 3, 4) + + ww = openmc.WeightWindows( + mesh=ww_mesh, + lower_ww_bounds=[1]*24, + upper_bound_ratio=5, + energy_bounds=(1, 1e40) + ) + assert ww.lower_ww_bounds.shape == (2, 3, 4, 1) + + +def test_roundtrip(run_in_tmpdir, model, wws): + model.settings.weight_windows = wws + + # write the model with weight windows to XML + model.export_to_xml() + + # ensure that they can be read successfully from XML and that they match the input values + model_read = openmc.Model.from_xml() + + zipped_wws = zip(model.settings.weight_windows, + model_read.settings.weight_windows) + + # ensure the lower bounds read in from the XML match those of the + for ww_out, ww_in in zipped_wws: + assert(ww_out == ww_in) + + +def test_ww_attrs_python(model): + mesh = openmc.RegularMesh.from_domain(model.geometry) + lower_bounds = np.ones(mesh.dimension) + + # ensure that creation of weight window objects with default arg values + # is successful + wws = openmc.WeightWindows(mesh, lower_bounds, upper_bound_ratio=10.0) + + assert wws.energy_bounds == None + + wwg = openmc.WeightWindowGenerator(mesh) + + assert wwg.energy_bounds == None + +def test_ww_attrs_capi(run_in_tmpdir, model): + model.export_to_xml() + + openmc.lib.init() + + tally = openmc.lib.tallies[model.tallies[0].id] + + wws = openmc.lib.WeightWindows.from_tally(tally) + + # this is the first weight window object created + assert wws.id == 1 + + with pytest.raises(ValueError): + tally.find_filter(openmc.lib.AzimuthalFilter) + + mesh_filter = tally.find_filter(openmc.lib.MeshFilter) + mesh = mesh_filter.mesh + + assert wws.mesh.id == mesh.id + + assert wws.particle == openmc.ParticleType.NEUTRON + + wws.particle = 1 + assert wws.particle == openmc.ParticleType.PHOTON + wws.particle = 'photon' + assert wws.particle == openmc.ParticleType.PHOTON + + with pytest.raises(ValueError): + wws.particle = '🌠' + + energy_filter = tally.find_filter(openmc.lib.EnergyFilter) + np.testing.assert_allclose(np.unique(energy_filter.bins), wws.energy_bounds) + + # at this point the weight window bounds are uninitialized + assert all(wws.bounds[0] == -1) + assert all(wws.bounds[1] == -1) + + wws = openmc.lib.WeightWindows.from_tally(tally, particle='photon') + assert wws.id == 2 + assert wws.particle == openmc.ParticleType.PHOTON + + openmc.lib.finalize() \ No newline at end of file diff --git a/tests/unit_tests/weightwindows/test_ww_gen.py b/tests/unit_tests/weightwindows/test_ww_gen.py new file mode 100644 index 00000000000..072e332cb75 --- /dev/null +++ b/tests/unit_tests/weightwindows/test_ww_gen.py @@ -0,0 +1,334 @@ +from itertools import permutations +from pathlib import Path + +import numpy as np +import openmc +import openmc.lib +import pytest + + +@pytest.fixture +def model(): + openmc.reset_auto_ids() + + # create a simple spherical shell shielding model + + ### Materials ### + water = openmc.Material() + water.set_density('g/cc', 1.0) + water.add_nuclide("H1", 2) + water.add_nuclide("O16", 1) + + steel = openmc.Material() + steel.set_density('g/cc', 8.0) + steel.add_nuclide("Fe56", 1.0) + + air = openmc.Material() + air.set_density('g/cc', 0.001205) + air.add_nuclide("N14", 0.781557629247) + air.add_nuclide("O16", 0.210668126508) + + boron = openmc.Material() + boron.set_density('g/cc', 2.52) + boron.add_nuclide("B10", 0.15856) + boron.add_nuclide("B11", 0.64144) + boron.add_nuclide("C0", 0.2) + + ### Geometry ### + radii = [5.0, 10.0, 30.0, 31.0, 50.0] + + surfs = [openmc.Sphere(r=r) for r in radii] + + surfs[-1].boundary_type = 'vacuum' + + regions = openmc.model.subdivide(surfs) + + mats = [air, water, steel, boron, air] + + cells = [openmc.Cell(fill=m, region=r) for r, m in zip(regions, mats)] + + geometry = openmc.Geometry(cells) + + ### Settings ### + + settings = openmc.Settings( + run_mode='fixed source', + particles=100, + batches=10, + max_splits=10, + survival_biasing=False + ) + + # 10 keV neutron point source at the origin + space = openmc.stats.Point() + energy = openmc.stats.Discrete(x=[1e4], p=[1.0]) + settings.source = openmc.IndependentSource(space=space, energy=energy) + + return openmc.Model(geometry=geometry, settings=settings) + + +# create a tally used for weight window generation +mesh = openmc.RegularMesh() +mesh.lower_left = [-50.0] * 3 +mesh.upper_right = [50.0] * 3 +# use un-equal mesh widths in each dimension to more robustly check +# use of tally data +mesh.dimension = (19, 20, 21) + +mf = openmc.MeshFilter(mesh) + +ef = openmc.EnergyFilter([0.0, 1e7]) + +pf = openmc.ParticleFilter(['neutron', 'photon']) + +filters = [mf, ef, pf] + +test_cases = list(permutations(filters)) +test_cases += list(permutations(filters[:-1])) +test_cases += list(permutations(filters[::2])) + + +def labels(params): + out = [] + for p in params: + if isinstance(p, openmc.ParticleFilter): + out.append('particle') + elif isinstance(p, openmc.MeshFilter): + out.append('mesh') + elif isinstance(p, openmc.EnergyFilter): + out.append('energy') + return "filters:" + '-'.join(out) + + +@pytest.mark.parametrize("filters", test_cases, ids=labels) +def test_ww_gen(filters, model): + + tally = openmc.Tally() + tally.filters = list(filters) + tally.scores = ['flux'] + model.tallies = openmc.Tallies([tally]) + + model.export_to_model_xml() + + ref_lower = None + ref_upper = None + # test weight window generation capability + with openmc.lib.run_in_memory(): + + # retrieve the tally we created above in memory + lib_tally = openmc.lib.tallies[tally.id] + + # create a new weight windows object + ww = openmc.lib.WeightWindows.from_tally(lib_tally) + + # run particle transport + openmc.lib.run() + + # capture analog data + analog_mean = np.copy(lib_tally.mean) + + # update the weight window values using tally results + ww.update_magic(lib_tally) + + assert any(ww.bounds[0] != -1) + assert any(ww.bounds[1] != -1) + + # make sure that the weight window update doesn't change tally values + np.testing.assert_equal(lib_tally.mean, analog_mean) + + # check against weight windows from the previous iteration + # the order of filters should not change the weight window values + if ref_lower is None: + ref_lower = ww.bounds[0].copy() + else: + np.testing.assert_equal(ref_lower, ww.bounds[0]) + + if ref_upper is None: + ref_upper = ww.bounds[1].copy() + else: + np.testing.assert_equal(ref_upper, ww.bounds[1]) + + # turn on weight windows for the subsequent run + openmc.lib.settings.weight_windows_on = True + + openmc.lib.hard_reset() + + openmc.lib.run() + + ww_mean = np.copy(lib_tally.mean) + + # we expect that the application of weight windows will populate more tally + # bins than the analog run for the meshes in this test model + assert any(ww_mean != analog_mean) + assert np.count_nonzero(ww_mean) > np.count_nonzero(analog_mean) + + +def test_ww_import_export(run_in_tmpdir, model): + # create a tally for weight windows + mesh = openmc.RegularMesh() + mesh.lower_left = [-50.0] * 3 + mesh.upper_right = [50.0] * 3 + # use un-equal mesh widths in each dimension to more robustly check + # use of tally data + mesh.dimension = (3, 4, 5) + + mf = openmc.MeshFilter(mesh) + + e_groups = np.logspace(0, 7, 8) + ef = openmc.EnergyFilter(e_groups) + + pf = openmc.ParticleFilter(['neutron', 'photon']) + + tally = openmc.Tally() + tally.filters = [mf, ef, pf] + tally.scores = ['flux'] + + model.tallies = openmc.Tallies([tally]) + + # first, generate some weight windows + model.export_to_model_xml() + + openmc.lib.init() + + tally = openmc.lib.tallies[tally.id] + + ww = openmc.lib.WeightWindows.from_tally(tally) + + openmc.lib.run() + + mean_before = np.array(tally.mean) + + ww.update_magic(tally) + + mean_after = np.array(tally.mean) + + assert (mean_before == mean_after).all() + + lb_before, up_before = ww.bounds + + # set some additional weight windows properties after transport + ww.survival_ratio = 0.7 + assert ww.survival_ratio == 0.7 + + ww.weight_cutoff = 1e-10 + assert ww.weight_cutoff == 1e-10 + + ww.max_lower_bound_ratio = 200.0 + assert ww.max_lower_bound_ratio == 200.0 + + ww.max_split = 26000 + assert ww.max_split == 26000 + + openmc.lib.export_weight_windows() + + assert Path('weight_windows.h5').exists() + + openmc.lib.import_weight_windows('weight_windows.h5') + + imported_ww = openmc.lib.weight_windows[2] + + lb_after, up_after = imported_ww.bounds + + assert np.allclose(lb_before, lb_after) + assert np.allclose(up_before, up_after) + + assert ww.survival_ratio == imported_ww.survival_ratio + assert ww.max_lower_bound_ratio == imported_ww.max_lower_bound_ratio + assert ww.weight_cutoff == imported_ww.weight_cutoff + assert ww.max_split == imported_ww.max_split + + openmc.lib.finalize() + + +def test_ww_gen_roundtrip(run_in_tmpdir, model): + + mesh = openmc.RegularMesh.from_domain(model.geometry.root_universe) + energy_bounds = np.linspace(0.0, 1e8, 11) + particle_type = 'neutron' + + wwg = openmc.WeightWindowGenerator(mesh, energy_bounds, particle_type) + wwg.update_parameters = {'ratio' : 5.0, + 'threshold': 0.8, + 'value' : 'mean'} + + model.settings.weight_window_generators = wwg + model.export_to_xml() + + model_in = openmc.Model.from_xml() + + assert len(model_in.settings.weight_window_generators) == 1 + + wwg_in = model.settings.weight_window_generators[0] + + # rountrip tests + model_in = openmc.Model.from_xml() + assert len(model_in.settings.weight_window_generators) == 1 + wwg_in = model_in.settings.weight_window_generators[0] + assert wwg_in.max_realizations == 1 + assert wwg_in.on_the_fly == True + assert wwg_in.update_interval == 1 + assert wwg_in.update_parameters == wwg.update_parameters + + with pytest.raises(ValueError): + wwg.method = '🦍🐒' + + with pytest.raises(TypeError): + wwg.update_parameters = {'ratio' : 'one-to-one'} + + with pytest.raises(ValueError): + wwg.max_realizations = -1 + + +def test_python_hdf5_roundtrip(run_in_tmpdir, model): + + # add a tally to the model + mesh = openmc.RegularMesh.from_domain(model.geometry) + + # some arbitrary energy groups + e_groups = np.logspace(0, 6, 4) + energy_filter = openmc.EnergyFilter(e_groups) + + bounds = np.arange(energy_filter.num_bins * np.prod(mesh.dimension)) + + wws = openmc.WeightWindows(mesh, bounds, bounds, energy_bounds=e_groups) + + model.settings.weight_windows = [wws] + + model.export_to_xml() + + # initialize and export wws to HDF5 + openmc.lib.init() + + openmc.lib.export_weight_windows() + + openmc.lib.finalize() + + wws_hdf5 = openmc.hdf5_to_wws()[0] + + # ensure + assert all(wws.energy_bounds == wws_hdf5.energy_bounds) + assert wws.id == wws_hdf5.id + assert wws.mesh.id == wws_hdf5.mesh.id + np.testing.assert_array_equal(wws.lower_ww_bounds, wws_hdf5.lower_ww_bounds) + np.testing.assert_array_equal(wws.upper_ww_bounds, wws_hdf5.upper_ww_bounds) + + +def test_ww_bounds_set_in_memory(run_in_tmpdir, model): + tally = openmc.Tally() + tally.filters = filters + tally.scores = ['flux'] + model.tallies = [tally] + + bounds = np.arange(ef.num_bins * np.prod(mf.mesh.dimension)) + + model.export_to_xml() + + openmc.lib.init() + + lib_tally = openmc.lib.tallies[tally.id] + + wws = openmc.lib.WeightWindows.from_tally(lib_tally) + + wws.bounds = (bounds, bounds) + + openmc.lib.finalize() diff --git a/tests/unit_tests/weightwindows/test_wwinp_reader.py b/tests/unit_tests/weightwindows/test_wwinp_reader.py new file mode 100644 index 00000000000..434a36753ab --- /dev/null +++ b/tests/unit_tests/weightwindows/test_wwinp_reader.py @@ -0,0 +1,143 @@ +from pathlib import Path + +import numpy as np +import openmc +import pytest + +# check that we can successfully read wwinp files with the following contents: +# +# - neutrons on a rectilinear mesh +# - neutrons and photons on a rectilinear mesh + +# check that the following raises the correct exceptions (for now): +# +# - wwinp file with multiple time steps +# - wwinp file with cylindrical or spherical mesh + + +# expected retults - neutron data only +n_mesh = openmc.RectilinearMesh() +n_mesh.x_grid = np.array([-100.0, + -99.0, + -97.0, + -79.3636, + -61.7273, + -44.0909, + -26.4546, + -8.81818, + 8.81818, + 26.4546, + 44.0909, + 61.7273, + 79.3636, + 97.0, + 99.0, + 100]) +n_mesh.y_grid = np.array([-100.0, + -50.0, + -13.3333, + 23.3333, + 60.0, + 70.0, + 80.0, + 90.0, + 100.0]) +n_mesh.z_grid = np.array([-100.0, + -66.6667, + -33.3333, + 0.0, + 33.3333, + 66.6667, + 100.0]) +n_e_bounds = (np.array([0.0, + 100000.0, + 146780.0]),) +n_particles = ('neutron',) + +# expected results - neutron and photon data +np_mesh = openmc.RectilinearMesh() +np_mesh.x_grid = np.array([-100.0, 100.0]) +# y grid and z grid are the same as the previous mesh +np_mesh.y_grid = n_mesh.y_grid +np_mesh.z_grid = n_mesh.z_grid + +np_e_bounds = (np.array([0.0, 100000.0, 146780.0, 215440.0]), + np.array([0.0, 1.0E8])) +np_particles = ('neutron', 'photon') + +# expected results - photon data only +p_mesh = openmc.RectilinearMesh() +# adopts z grid from previous meshes as its x grid +p_mesh.x_grid = np_mesh.z_grid +# uses the same y grid +p_mesh.y_grid = np_mesh.y_grid +p_mesh.z_grid = np.array([-50.0, 50.0]) + +p_e_bounds = (np.array([0.0, 100000.0, 146780.0, 215440.0, 316230.0]),) +p_particles = ('photon',) + +expected_results = [('wwinp_n', n_mesh, n_particles, n_e_bounds), + ('wwinp_np', np_mesh, np_particles, np_e_bounds), + ('wwinp_p', p_mesh, p_particles, p_e_bounds)] + + +# function for printing readable test labels +def id_fn(params): + suffix = params[0].split('_')[-1] + if suffix == 'n': + return 'neutron-only' + elif suffix == 'np': + return 'neutron-photon' + elif suffix == 'p': + return 'photon-only' + + +@pytest.mark.parametrize('wwinp_data', expected_results, ids=id_fn) +def test_wwinp_reader(wwinp_data, request): + wwinp_file, mesh, particle_types, energy_bounds = wwinp_data + + wws = openmc.wwinp_to_wws(request.node.path.parent / wwinp_file) + + for i, ww in enumerate(wws): + e_bounds = energy_bounds[i] + particle_type = particle_types[i] + + assert ww.particle_type == particle_type + + # check the mesh grid + # there will be some very small changes due to the number of digits + # provided in the wwinp format and the use of np.linspace to compute + # boundaries of the fine mesh intervals + np.testing.assert_allclose(mesh.x_grid, ww.mesh.x_grid, rtol=1e-6) + np.testing.assert_allclose(mesh.y_grid, ww.mesh.y_grid, rtol=1e-6) + np.testing.assert_allclose(mesh.z_grid, ww.mesh.z_grid, rtol=1e-6) + + # check the energy bounds + np.testing.assert_array_equal(e_bounds, ww.energy_bounds) + + # check the expected weight window values mocked in the file -- + # a reversed array of the flat index into the numpy array + n_wws = np.prod((*mesh.dimension, e_bounds.size - 1)) + exp_ww_lb = np.linspace(1, n_wws, n_wws)[::-1] + np.testing.assert_array_equal(exp_ww_lb, ww.lower_ww_bounds.flatten()) + + +# check expected failures +def fail_id_fn(params): + suffix = params[0].split('_')[-1] + if suffix == 't': + return 'time-steps-failure' + elif suffix == 'cyl': + return 'cyl-mesh-failure' + + +expected_failure_data = (('wwinp_t', ValueError), + ('wwinp_cyl', NotImplementedError)) + + +@pytest.mark.parametrize('wwinp_data', expected_failure_data, ids=fail_id_fn) +def test_wwinp_reader_failures(wwinp_data, request): + filename, expected_failure = wwinp_data + + with pytest.raises(expected_failure): + _ = openmc.wwinp_to_wws(request.node.path.parent / filename) diff --git a/tests/unit_tests/weightwindows/ww_n.txt b/tests/unit_tests/weightwindows/ww_n.txt new file mode 120000 index 00000000000..3bd70d2c930 --- /dev/null +++ b/tests/unit_tests/weightwindows/ww_n.txt @@ -0,0 +1 @@ +../../regression_tests/weightwindows/ww_n.txt \ No newline at end of file diff --git a/tests/unit_tests/weightwindows/ww_p.txt b/tests/unit_tests/weightwindows/ww_p.txt new file mode 120000 index 00000000000..8a94de7097b --- /dev/null +++ b/tests/unit_tests/weightwindows/ww_p.txt @@ -0,0 +1 @@ +../../regression_tests/weightwindows/ww_p.txt \ No newline at end of file diff --git a/tests/unit_tests/weightwindows/wwinp_cyl b/tests/unit_tests/weightwindows/wwinp_cyl new file mode 100644 index 00000000000..aac9d46f255 --- /dev/null +++ b/tests/unit_tests/weightwindows/wwinp_cyl @@ -0,0 +1,48 @@ + 1 1 2 16 + 0 4 + 6.0 8.0 1.0 -1.00000E+02 -1.00000E+02 -5.00000E+01 + 6.0 8.0 1.0 -1.00000E+02 -1.00000E+02 5.00000E+01 + -1.00000E+02 1.00000E+02 -5.00000E+01 2.0 + -1.00000E+02 1.00000E+00 -6.66667E+01 1.00000E+00 1.00000E+00 -3.33333E+01 + 1.00000E+00 1.00000E+00 0.00000E+00 1.00000E+00 1.00000E+00 3.33333E+01 + 1.00000E+00 1.00000E+00 6.66667E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + -1.00000E+02 1.00000E+00 -5.00000E+01 1.00000E+00 1.00000E+00 -1.33333E+01 + 1.00000E+00 1.00000E+00 2.33333E+01 1.00000E+00 1.00000E+00 6.00000E+01 + 1.00000E+00 1.00000E+00 7.00000E+01 1.00000E+00 1.00000E+00 8.00000E+01 + 1.00000E+00 1.00000E+00 9.00000E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + 0.00000E+01 1.00000E+00 3.14159E+00 1.00000E+00 + 1.00000E-01 1.46780E-01 2.15440E-01 3.16230E-01 + 1.92000E+02 1.60000E+02 1.28000E+02 9.60000E+01 6.40000E+01 3.20000E+01 + 1.88000E+02 1.56000E+02 1.24000E+02 9.20000E+01 6.00000E+01 2.80000E+01 + 1.84000E+02 1.52000E+02 1.20000E+02 8.80000E+01 5.60000E+01 2.40000E+01 + 1.80000E+02 1.48000E+02 1.16000E+02 8.40000E+01 5.20000E+01 2.00000E+01 + 1.76000E+02 1.44000E+02 1.12000E+02 8.00000E+01 4.80000E+01 1.60000E+01 + 1.72000E+02 1.40000E+02 1.08000E+02 7.60000E+01 4.40000E+01 1.20000E+01 + 1.68000E+02 1.36000E+02 1.04000E+02 7.20000E+01 4.00000E+01 8.00000E+00 + 1.64000E+02 1.32000E+02 1.00000E+02 6.80000E+01 3.60000E+01 4.00000E+00 + 1.91000E+02 1.59000E+02 1.27000E+02 9.50000E+01 6.30000E+01 3.10000E+01 + 1.87000E+02 1.55000E+02 1.23000E+02 9.10000E+01 5.90000E+01 2.70000E+01 + 1.83000E+02 1.51000E+02 1.19000E+02 8.70000E+01 5.50000E+01 2.30000E+01 + 1.79000E+02 1.47000E+02 1.15000E+02 8.30000E+01 5.10000E+01 1.90000E+01 + 1.75000E+02 1.43000E+02 1.11000E+02 7.90000E+01 4.70000E+01 1.50000E+01 + 1.71000E+02 1.39000E+02 1.07000E+02 7.50000E+01 4.30000E+01 1.10000E+01 + 1.67000E+02 1.35000E+02 1.03000E+02 7.10000E+01 3.90000E+01 7.00000E+00 + 1.63000E+02 1.31000E+02 9.90000E+01 6.70000E+01 3.50000E+01 3.00000E+00 + 1.90000E+02 1.58000E+02 1.26000E+02 9.40000E+01 6.20000E+01 3.00000E+01 + 1.86000E+02 1.54000E+02 1.22000E+02 9.00000E+01 5.80000E+01 2.60000E+01 + 1.82000E+02 1.50000E+02 1.18000E+02 8.60000E+01 5.40000E+01 2.20000E+01 + 1.78000E+02 1.46000E+02 1.14000E+02 8.20000E+01 5.00000E+01 1.80000E+01 + 1.74000E+02 1.42000E+02 1.10000E+02 7.80000E+01 4.60000E+01 1.40000E+01 + 1.70000E+02 1.38000E+02 1.06000E+02 7.40000E+01 4.20000E+01 1.00000E+01 + 1.66000E+02 1.34000E+02 1.02000E+02 7.00000E+01 3.80000E+01 6.00000E+00 + 1.62000E+02 1.30000E+02 9.80000E+01 6.60000E+01 3.40000E+01 2.00000E+00 + 1.89000E+02 1.57000E+02 1.25000E+02 9.30000E+01 6.10000E+01 2.90000E+01 + 1.85000E+02 1.53000E+02 1.21000E+02 8.90000E+01 5.70000E+01 2.50000E+01 + 1.81000E+02 1.49000E+02 1.17000E+02 8.50000E+01 5.30000E+01 2.10000E+01 + 1.77000E+02 1.45000E+02 1.13000E+02 8.10000E+01 4.90000E+01 1.70000E+01 + 1.73000E+02 1.41000E+02 1.09000E+02 7.70000E+01 4.50000E+01 1.30000E+01 + 1.69000E+02 1.37000E+02 1.05000E+02 7.30000E+01 4.10000E+01 9.00000E+00 + 1.65000E+02 1.33000E+02 1.01000E+02 6.90000E+01 3.70000E+01 5.00000E+00 + 1.61000E+02 1.29000E+02 9.70000E+01 6.50000E+01 3.30000E+01 1.00000E+00 diff --git a/tests/unit_tests/weightwindows/wwinp_n b/tests/unit_tests/weightwindows/wwinp_n new file mode 100644 index 00000000000..73a4fc496b4 --- /dev/null +++ b/tests/unit_tests/weightwindows/wwinp_n @@ -0,0 +1,263 @@ + 1 1 1 10 + 2 + 15.0 8.0 6.0 -1.00000E+02 -1.00000E+02 -1.00000E+02 + 15.0 8.0 6.0 1.0 + -1.00000E+02 1.00000E+00 -9.90000E+01 1.00000E+00 1.00000E+00 -9.70000E+01 + 1.00000E+00 1.00000E+00 -7.93636E+01 1.00000E+00 1.00000E+00 -6.17273E+01 + 1.00000E+00 1.00000E+00 -4.40909E+01 1.00000E+00 1.00000E+00 -2.64546E+01 + 1.00000E+00 1.00000E+00 -8.81818E+00 1.00000E+00 1.00000E+00 8.81818E+00 + 1.00000E+00 1.00000E+00 2.64546E+01 1.00000E+00 1.00000E+00 4.40909E+01 + 1.00000E+00 1.00000E+00 6.17273E+01 1.00000E+00 1.00000E+00 7.93636E+01 + 1.00000E+00 1.00000E+00 9.70000E+01 1.00000E+00 1.00000E+00 9.90000E+01 + 1.00000E+00 1.00000E+00 1.00000E+02 1.00000E+00 + -1.00000E+02 1.00000E+00 -5.00000E+01 1.00000E+00 1.00000E+00 -1.33333E+01 + 1.00000E+00 1.00000E+00 2.33333E+01 1.00000E+00 1.00000E+00 6.00000E+01 + 1.00000E+00 1.00000E+00 7.00000E+01 1.00000E+00 1.00000E+00 8.00000E+01 + 1.00000E+00 1.00000E+00 9.00000E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + -1.00000E+02 1.00000E+00 -6.66667E+01 1.00000E+00 1.00000E+00 -3.33333E+01 + 1.00000E+00 1.00000E+00 0.00000E+00 1.00000E+00 1.00000E+00 3.33333E+01 + 1.00000E+00 1.00000E+00 6.66667E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + 1.00000E-01 1.46780E-01 + 1.44000E+03 1.34400E+03 1.24800E+03 1.15200E+03 1.05600E+03 9.60000E+02 + 8.64000E+02 7.68000E+02 6.72000E+02 5.76000E+02 4.80000E+02 3.84000E+02 + 2.88000E+02 1.92000E+02 9.60000E+01 1.42800E+03 1.33200E+03 1.23600E+03 + 1.14000E+03 1.04400E+03 9.48000E+02 8.52000E+02 7.56000E+02 6.60000E+02 + 5.64000E+02 4.68000E+02 3.72000E+02 2.76000E+02 1.80000E+02 8.40000E+01 + 1.41600E+03 1.32000E+03 1.22400E+03 1.12800E+03 1.03200E+03 9.36000E+02 + 8.40000E+02 7.44000E+02 6.48000E+02 5.52000E+02 4.56000E+02 3.60000E+02 + 2.64000E+02 1.68000E+02 7.20000E+01 1.40400E+03 1.30800E+03 1.21200E+03 + 1.11600E+03 1.02000E+03 9.24000E+02 8.28000E+02 7.32000E+02 6.36000E+02 + 5.40000E+02 4.44000E+02 3.48000E+02 2.52000E+02 1.56000E+02 6.00000E+01 + 1.39200E+03 1.29600E+03 1.20000E+03 1.10400E+03 1.00800E+03 9.12000E+02 + 8.16000E+02 7.20000E+02 6.24000E+02 5.28000E+02 4.32000E+02 3.36000E+02 + 2.40000E+02 1.44000E+02 4.80000E+01 1.38000E+03 1.28400E+03 1.18800E+03 + 1.09200E+03 9.96000E+02 9.00000E+02 8.04000E+02 7.08000E+02 6.12000E+02 + 5.16000E+02 4.20000E+02 3.24000E+02 2.28000E+02 1.32000E+02 3.60000E+01 + 1.36800E+03 1.27200E+03 1.17600E+03 1.08000E+03 9.84000E+02 8.88000E+02 + 7.92000E+02 6.96000E+02 6.00000E+02 5.04000E+02 4.08000E+02 3.12000E+02 + 2.16000E+02 1.20000E+02 2.40000E+01 1.35600E+03 1.26000E+03 1.16400E+03 + 1.06800E+03 9.72000E+02 8.76000E+02 7.80000E+02 6.84000E+02 5.88000E+02 + 4.92000E+02 3.96000E+02 3.00000E+02 2.04000E+02 1.08000E+02 1.20000E+01 + 1.43800E+03 1.34200E+03 1.24600E+03 1.15000E+03 1.05400E+03 9.58000E+02 + 8.62000E+02 7.66000E+02 6.70000E+02 5.74000E+02 4.78000E+02 3.82000E+02 + 2.86000E+02 1.90000E+02 9.40000E+01 1.42600E+03 1.33000E+03 1.23400E+03 + 1.13800E+03 1.04200E+03 9.46000E+02 8.50000E+02 7.54000E+02 6.58000E+02 + 5.62000E+02 4.66000E+02 3.70000E+02 2.74000E+02 1.78000E+02 8.20000E+01 + 1.41400E+03 1.31800E+03 1.22200E+03 1.12600E+03 1.03000E+03 9.34000E+02 + 8.38000E+02 7.42000E+02 6.46000E+02 5.50000E+02 4.54000E+02 3.58000E+02 + 2.62000E+02 1.66000E+02 7.00000E+01 1.40200E+03 1.30600E+03 1.21000E+03 + 1.11400E+03 1.01800E+03 9.22000E+02 8.26000E+02 7.30000E+02 6.34000E+02 + 5.38000E+02 4.42000E+02 3.46000E+02 2.50000E+02 1.54000E+02 5.80000E+01 + 1.39000E+03 1.29400E+03 1.19800E+03 1.10200E+03 1.00600E+03 9.10000E+02 + 8.14000E+02 7.18000E+02 6.22000E+02 5.26000E+02 4.30000E+02 3.34000E+02 + 2.38000E+02 1.42000E+02 4.60000E+01 1.37800E+03 1.28200E+03 1.18600E+03 + 1.09000E+03 9.94000E+02 8.98000E+02 8.02000E+02 7.06000E+02 6.10000E+02 + 5.14000E+02 4.18000E+02 3.22000E+02 2.26000E+02 1.30000E+02 3.40000E+01 + 1.36600E+03 1.27000E+03 1.17400E+03 1.07800E+03 9.82000E+02 8.86000E+02 + 7.90000E+02 6.94000E+02 5.98000E+02 5.02000E+02 4.06000E+02 3.10000E+02 + 2.14000E+02 1.18000E+02 2.20000E+01 1.35400E+03 1.25800E+03 1.16200E+03 + 1.06600E+03 9.70000E+02 8.74000E+02 7.78000E+02 6.82000E+02 5.86000E+02 + 4.90000E+02 3.94000E+02 2.98000E+02 2.02000E+02 1.06000E+02 1.00000E+01 + 1.43600E+03 1.34000E+03 1.24400E+03 1.14800E+03 1.05200E+03 9.56000E+02 + 8.60000E+02 7.64000E+02 6.68000E+02 5.72000E+02 4.76000E+02 3.80000E+02 + 2.84000E+02 1.88000E+02 9.20000E+01 1.42400E+03 1.32800E+03 1.23200E+03 + 1.13600E+03 1.04000E+03 9.44000E+02 8.48000E+02 7.52000E+02 6.56000E+02 + 5.60000E+02 4.64000E+02 3.68000E+02 2.72000E+02 1.76000E+02 8.00000E+01 + 1.41200E+03 1.31600E+03 1.22000E+03 1.12400E+03 1.02800E+03 9.32000E+02 + 8.36000E+02 7.40000E+02 6.44000E+02 5.48000E+02 4.52000E+02 3.56000E+02 + 2.60000E+02 1.64000E+02 6.80000E+01 1.40000E+03 1.30400E+03 1.20800E+03 + 1.11200E+03 1.01600E+03 9.20000E+02 8.24000E+02 7.28000E+02 6.32000E+02 + 5.36000E+02 4.40000E+02 3.44000E+02 2.48000E+02 1.52000E+02 5.60000E+01 + 1.38800E+03 1.29200E+03 1.19600E+03 1.10000E+03 1.00400E+03 9.08000E+02 + 8.12000E+02 7.16000E+02 6.20000E+02 5.24000E+02 4.28000E+02 3.32000E+02 + 2.36000E+02 1.40000E+02 4.40000E+01 1.37600E+03 1.28000E+03 1.18400E+03 + 1.08800E+03 9.92000E+02 8.96000E+02 8.00000E+02 7.04000E+02 6.08000E+02 + 5.12000E+02 4.16000E+02 3.20000E+02 2.24000E+02 1.28000E+02 3.20000E+01 + 1.36400E+03 1.26800E+03 1.17200E+03 1.07600E+03 9.80000E+02 8.84000E+02 + 7.88000E+02 6.92000E+02 5.96000E+02 5.00000E+02 4.04000E+02 3.08000E+02 + 2.12000E+02 1.16000E+02 2.00000E+01 1.35200E+03 1.25600E+03 1.16000E+03 + 1.06400E+03 9.68000E+02 8.72000E+02 7.76000E+02 6.80000E+02 5.84000E+02 + 4.88000E+02 3.92000E+02 2.96000E+02 2.00000E+02 1.04000E+02 8.00000E+00 + 1.43400E+03 1.33800E+03 1.24200E+03 1.14600E+03 1.05000E+03 9.54000E+02 + 8.58000E+02 7.62000E+02 6.66000E+02 5.70000E+02 4.74000E+02 3.78000E+02 + 2.82000E+02 1.86000E+02 9.00000E+01 1.42200E+03 1.32600E+03 1.23000E+03 + 1.13400E+03 1.03800E+03 9.42000E+02 8.46000E+02 7.50000E+02 6.54000E+02 + 5.58000E+02 4.62000E+02 3.66000E+02 2.70000E+02 1.74000E+02 7.80000E+01 + 1.41000E+03 1.31400E+03 1.21800E+03 1.12200E+03 1.02600E+03 9.30000E+02 + 8.34000E+02 7.38000E+02 6.42000E+02 5.46000E+02 4.50000E+02 3.54000E+02 + 2.58000E+02 1.62000E+02 6.60000E+01 1.39800E+03 1.30200E+03 1.20600E+03 + 1.11000E+03 1.01400E+03 9.18000E+02 8.22000E+02 7.26000E+02 6.30000E+02 + 5.34000E+02 4.38000E+02 3.42000E+02 2.46000E+02 1.50000E+02 5.40000E+01 + 1.38600E+03 1.29000E+03 1.19400E+03 1.09800E+03 1.00200E+03 9.06000E+02 + 8.10000E+02 7.14000E+02 6.18000E+02 5.22000E+02 4.26000E+02 3.30000E+02 + 2.34000E+02 1.38000E+02 4.20000E+01 1.37400E+03 1.27800E+03 1.18200E+03 + 1.08600E+03 9.90000E+02 8.94000E+02 7.98000E+02 7.02000E+02 6.06000E+02 + 5.10000E+02 4.14000E+02 3.18000E+02 2.22000E+02 1.26000E+02 3.00000E+01 + 1.36200E+03 1.26600E+03 1.17000E+03 1.07400E+03 9.78000E+02 8.82000E+02 + 7.86000E+02 6.90000E+02 5.94000E+02 4.98000E+02 4.02000E+02 3.06000E+02 + 2.10000E+02 1.14000E+02 1.80000E+01 1.35000E+03 1.25400E+03 1.15800E+03 + 1.06200E+03 9.66000E+02 8.70000E+02 7.74000E+02 6.78000E+02 5.82000E+02 + 4.86000E+02 3.90000E+02 2.94000E+02 1.98000E+02 1.02000E+02 6.00000E+00 + 1.43200E+03 1.33600E+03 1.24000E+03 1.14400E+03 1.04800E+03 9.52000E+02 + 8.56000E+02 7.60000E+02 6.64000E+02 5.68000E+02 4.72000E+02 3.76000E+02 + 2.80000E+02 1.84000E+02 8.80000E+01 1.42000E+03 1.32400E+03 1.22800E+03 + 1.13200E+03 1.03600E+03 9.40000E+02 8.44000E+02 7.48000E+02 6.52000E+02 + 5.56000E+02 4.60000E+02 3.64000E+02 2.68000E+02 1.72000E+02 7.60000E+01 + 1.40800E+03 1.31200E+03 1.21600E+03 1.12000E+03 1.02400E+03 9.28000E+02 + 8.32000E+02 7.36000E+02 6.40000E+02 5.44000E+02 4.48000E+02 3.52000E+02 + 2.56000E+02 1.60000E+02 6.40000E+01 1.39600E+03 1.30000E+03 1.20400E+03 + 1.10800E+03 1.01200E+03 9.16000E+02 8.20000E+02 7.24000E+02 6.28000E+02 + 5.32000E+02 4.36000E+02 3.40000E+02 2.44000E+02 1.48000E+02 5.20000E+01 + 1.38400E+03 1.28800E+03 1.19200E+03 1.09600E+03 1.00000E+03 9.04000E+02 + 8.08000E+02 7.12000E+02 6.16000E+02 5.20000E+02 4.24000E+02 3.28000E+02 + 2.32000E+02 1.36000E+02 4.00000E+01 1.37200E+03 1.27600E+03 1.18000E+03 + 1.08400E+03 9.88000E+02 8.92000E+02 7.96000E+02 7.00000E+02 6.04000E+02 + 5.08000E+02 4.12000E+02 3.16000E+02 2.20000E+02 1.24000E+02 2.80000E+01 + 1.36000E+03 1.26400E+03 1.16800E+03 1.07200E+03 9.76000E+02 8.80000E+02 + 7.84000E+02 6.88000E+02 5.92000E+02 4.96000E+02 4.00000E+02 3.04000E+02 + 2.08000E+02 1.12000E+02 1.60000E+01 1.34800E+03 1.25200E+03 1.15600E+03 + 1.06000E+03 9.64000E+02 8.68000E+02 7.72000E+02 6.76000E+02 5.80000E+02 + 4.84000E+02 3.88000E+02 2.92000E+02 1.96000E+02 1.00000E+02 4.00000E+00 + 1.43000E+03 1.33400E+03 1.23800E+03 1.14200E+03 1.04600E+03 9.50000E+02 + 8.54000E+02 7.58000E+02 6.62000E+02 5.66000E+02 4.70000E+02 3.74000E+02 + 2.78000E+02 1.82000E+02 8.60000E+01 1.41800E+03 1.32200E+03 1.22600E+03 + 1.13000E+03 1.03400E+03 9.38000E+02 8.42000E+02 7.46000E+02 6.50000E+02 + 5.54000E+02 4.58000E+02 3.62000E+02 2.66000E+02 1.70000E+02 7.40000E+01 + 1.40600E+03 1.31000E+03 1.21400E+03 1.11800E+03 1.02200E+03 9.26000E+02 + 8.30000E+02 7.34000E+02 6.38000E+02 5.42000E+02 4.46000E+02 3.50000E+02 + 2.54000E+02 1.58000E+02 6.20000E+01 1.39400E+03 1.29800E+03 1.20200E+03 + 1.10600E+03 1.01000E+03 9.14000E+02 8.18000E+02 7.22000E+02 6.26000E+02 + 5.30000E+02 4.34000E+02 3.38000E+02 2.42000E+02 1.46000E+02 5.00000E+01 + 1.38200E+03 1.28600E+03 1.19000E+03 1.09400E+03 9.98000E+02 9.02000E+02 + 8.06000E+02 7.10000E+02 6.14000E+02 5.18000E+02 4.22000E+02 3.26000E+02 + 2.30000E+02 1.34000E+02 3.80000E+01 1.37000E+03 1.27400E+03 1.17800E+03 + 1.08200E+03 9.86000E+02 8.90000E+02 7.94000E+02 6.98000E+02 6.02000E+02 + 5.06000E+02 4.10000E+02 3.14000E+02 2.18000E+02 1.22000E+02 2.60000E+01 + 1.35800E+03 1.26200E+03 1.16600E+03 1.07000E+03 9.74000E+02 8.78000E+02 + 7.82000E+02 6.86000E+02 5.90000E+02 4.94000E+02 3.98000E+02 3.02000E+02 + 2.06000E+02 1.10000E+02 1.40000E+01 1.34600E+03 1.25000E+03 1.15400E+03 + 1.05800E+03 9.62000E+02 8.66000E+02 7.70000E+02 6.74000E+02 5.78000E+02 + 4.82000E+02 3.86000E+02 2.90000E+02 1.94000E+02 9.80000E+01 2.00000E+00 + 1.43900E+03 1.34300E+03 1.24700E+03 1.15100E+03 1.05500E+03 9.59000E+02 + 8.63000E+02 7.67000E+02 6.71000E+02 5.75000E+02 4.79000E+02 3.83000E+02 + 2.87000E+02 1.91000E+02 9.50000E+01 1.42700E+03 1.33100E+03 1.23500E+03 + 1.13900E+03 1.04300E+03 9.47000E+02 8.51000E+02 7.55000E+02 6.59000E+02 + 5.63000E+02 4.67000E+02 3.71000E+02 2.75000E+02 1.79000E+02 8.30000E+01 + 1.41500E+03 1.31900E+03 1.22300E+03 1.12700E+03 1.03100E+03 9.35000E+02 + 8.39000E+02 7.43000E+02 6.47000E+02 5.51000E+02 4.55000E+02 3.59000E+02 + 2.63000E+02 1.67000E+02 7.10000E+01 1.40300E+03 1.30700E+03 1.21100E+03 + 1.11500E+03 1.01900E+03 9.23000E+02 8.27000E+02 7.31000E+02 6.35000E+02 + 5.39000E+02 4.43000E+02 3.47000E+02 2.51000E+02 1.55000E+02 5.90000E+01 + 1.39100E+03 1.29500E+03 1.19900E+03 1.10300E+03 1.00700E+03 9.11000E+02 + 8.15000E+02 7.19000E+02 6.23000E+02 5.27000E+02 4.31000E+02 3.35000E+02 + 2.39000E+02 1.43000E+02 4.70000E+01 1.37900E+03 1.28300E+03 1.18700E+03 + 1.09100E+03 9.95000E+02 8.99000E+02 8.03000E+02 7.07000E+02 6.11000E+02 + 5.15000E+02 4.19000E+02 3.23000E+02 2.27000E+02 1.31000E+02 3.50000E+01 + 1.36700E+03 1.27100E+03 1.17500E+03 1.07900E+03 9.83000E+02 8.87000E+02 + 7.91000E+02 6.95000E+02 5.99000E+02 5.03000E+02 4.07000E+02 3.11000E+02 + 2.15000E+02 1.19000E+02 2.30000E+01 1.35500E+03 1.25900E+03 1.16300E+03 + 1.06700E+03 9.71000E+02 8.75000E+02 7.79000E+02 6.83000E+02 5.87000E+02 + 4.91000E+02 3.95000E+02 2.99000E+02 2.03000E+02 1.07000E+02 1.10000E+01 + 1.43700E+03 1.34100E+03 1.24500E+03 1.14900E+03 1.05300E+03 9.57000E+02 + 8.61000E+02 7.65000E+02 6.69000E+02 5.73000E+02 4.77000E+02 3.81000E+02 + 2.85000E+02 1.89000E+02 9.30000E+01 1.42500E+03 1.32900E+03 1.23300E+03 + 1.13700E+03 1.04100E+03 9.45000E+02 8.49000E+02 7.53000E+02 6.57000E+02 + 5.61000E+02 4.65000E+02 3.69000E+02 2.73000E+02 1.77000E+02 8.10000E+01 + 1.41300E+03 1.31700E+03 1.22100E+03 1.12500E+03 1.02900E+03 9.33000E+02 + 8.37000E+02 7.41000E+02 6.45000E+02 5.49000E+02 4.53000E+02 3.57000E+02 + 2.61000E+02 1.65000E+02 6.90000E+01 1.40100E+03 1.30500E+03 1.20900E+03 + 1.11300E+03 1.01700E+03 9.21000E+02 8.25000E+02 7.29000E+02 6.33000E+02 + 5.37000E+02 4.41000E+02 3.45000E+02 2.49000E+02 1.53000E+02 5.70000E+01 + 1.38900E+03 1.29300E+03 1.19700E+03 1.10100E+03 1.00500E+03 9.09000E+02 + 8.13000E+02 7.17000E+02 6.21000E+02 5.25000E+02 4.29000E+02 3.33000E+02 + 2.37000E+02 1.41000E+02 4.50000E+01 1.37700E+03 1.28100E+03 1.18500E+03 + 1.08900E+03 9.93000E+02 8.97000E+02 8.01000E+02 7.05000E+02 6.09000E+02 + 5.13000E+02 4.17000E+02 3.21000E+02 2.25000E+02 1.29000E+02 3.30000E+01 + 1.36500E+03 1.26900E+03 1.17300E+03 1.07700E+03 9.81000E+02 8.85000E+02 + 7.89000E+02 6.93000E+02 5.97000E+02 5.01000E+02 4.05000E+02 3.09000E+02 + 2.13000E+02 1.17000E+02 2.10000E+01 1.35300E+03 1.25700E+03 1.16100E+03 + 1.06500E+03 9.69000E+02 8.73000E+02 7.77000E+02 6.81000E+02 5.85000E+02 + 4.89000E+02 3.93000E+02 2.97000E+02 2.01000E+02 1.05000E+02 9.00000E+00 + 1.43500E+03 1.33900E+03 1.24300E+03 1.14700E+03 1.05100E+03 9.55000E+02 + 8.59000E+02 7.63000E+02 6.67000E+02 5.71000E+02 4.75000E+02 3.79000E+02 + 2.83000E+02 1.87000E+02 9.10000E+01 1.42300E+03 1.32700E+03 1.23100E+03 + 1.13500E+03 1.03900E+03 9.43000E+02 8.47000E+02 7.51000E+02 6.55000E+02 + 5.59000E+02 4.63000E+02 3.67000E+02 2.71000E+02 1.75000E+02 7.90000E+01 + 1.41100E+03 1.31500E+03 1.21900E+03 1.12300E+03 1.02700E+03 9.31000E+02 + 8.35000E+02 7.39000E+02 6.43000E+02 5.47000E+02 4.51000E+02 3.55000E+02 + 2.59000E+02 1.63000E+02 6.70000E+01 1.39900E+03 1.30300E+03 1.20700E+03 + 1.11100E+03 1.01500E+03 9.19000E+02 8.23000E+02 7.27000E+02 6.31000E+02 + 5.35000E+02 4.39000E+02 3.43000E+02 2.47000E+02 1.51000E+02 5.50000E+01 + 1.38700E+03 1.29100E+03 1.19500E+03 1.09900E+03 1.00300E+03 9.07000E+02 + 8.11000E+02 7.15000E+02 6.19000E+02 5.23000E+02 4.27000E+02 3.31000E+02 + 2.35000E+02 1.39000E+02 4.30000E+01 1.37500E+03 1.27900E+03 1.18300E+03 + 1.08700E+03 9.91000E+02 8.95000E+02 7.99000E+02 7.03000E+02 6.07000E+02 + 5.11000E+02 4.15000E+02 3.19000E+02 2.23000E+02 1.27000E+02 3.10000E+01 + 1.36300E+03 1.26700E+03 1.17100E+03 1.07500E+03 9.79000E+02 8.83000E+02 + 7.87000E+02 6.91000E+02 5.95000E+02 4.99000E+02 4.03000E+02 3.07000E+02 + 2.11000E+02 1.15000E+02 1.90000E+01 1.35100E+03 1.25500E+03 1.15900E+03 + 1.06300E+03 9.67000E+02 8.71000E+02 7.75000E+02 6.79000E+02 5.83000E+02 + 4.87000E+02 3.91000E+02 2.95000E+02 1.99000E+02 1.03000E+02 7.00000E+00 + 1.43300E+03 1.33700E+03 1.24100E+03 1.14500E+03 1.04900E+03 9.53000E+02 + 8.57000E+02 7.61000E+02 6.65000E+02 5.69000E+02 4.73000E+02 3.77000E+02 + 2.81000E+02 1.85000E+02 8.90000E+01 1.42100E+03 1.32500E+03 1.22900E+03 + 1.13300E+03 1.03700E+03 9.41000E+02 8.45000E+02 7.49000E+02 6.53000E+02 + 5.57000E+02 4.61000E+02 3.65000E+02 2.69000E+02 1.73000E+02 7.70000E+01 + 1.40900E+03 1.31300E+03 1.21700E+03 1.12100E+03 1.02500E+03 9.29000E+02 + 8.33000E+02 7.37000E+02 6.41000E+02 5.45000E+02 4.49000E+02 3.53000E+02 + 2.57000E+02 1.61000E+02 6.50000E+01 1.39700E+03 1.30100E+03 1.20500E+03 + 1.10900E+03 1.01300E+03 9.17000E+02 8.21000E+02 7.25000E+02 6.29000E+02 + 5.33000E+02 4.37000E+02 3.41000E+02 2.45000E+02 1.49000E+02 5.30000E+01 + 1.38500E+03 1.28900E+03 1.19300E+03 1.09700E+03 1.00100E+03 9.05000E+02 + 8.09000E+02 7.13000E+02 6.17000E+02 5.21000E+02 4.25000E+02 3.29000E+02 + 2.33000E+02 1.37000E+02 4.10000E+01 1.37300E+03 1.27700E+03 1.18100E+03 + 1.08500E+03 9.89000E+02 8.93000E+02 7.97000E+02 7.01000E+02 6.05000E+02 + 5.09000E+02 4.13000E+02 3.17000E+02 2.21000E+02 1.25000E+02 2.90000E+01 + 1.36100E+03 1.26500E+03 1.16900E+03 1.07300E+03 9.77000E+02 8.81000E+02 + 7.85000E+02 6.89000E+02 5.93000E+02 4.97000E+02 4.01000E+02 3.05000E+02 + 2.09000E+02 1.13000E+02 1.70000E+01 1.34900E+03 1.25300E+03 1.15700E+03 + 1.06100E+03 9.65000E+02 8.69000E+02 7.73000E+02 6.77000E+02 5.81000E+02 + 4.85000E+02 3.89000E+02 2.93000E+02 1.97000E+02 1.01000E+02 5.00000E+00 + 1.43100E+03 1.33500E+03 1.23900E+03 1.14300E+03 1.04700E+03 9.51000E+02 + 8.55000E+02 7.59000E+02 6.63000E+02 5.67000E+02 4.71000E+02 3.75000E+02 + 2.79000E+02 1.83000E+02 8.70000E+01 1.41900E+03 1.32300E+03 1.22700E+03 + 1.13100E+03 1.03500E+03 9.39000E+02 8.43000E+02 7.47000E+02 6.51000E+02 + 5.55000E+02 4.59000E+02 3.63000E+02 2.67000E+02 1.71000E+02 7.50000E+01 + 1.40700E+03 1.31100E+03 1.21500E+03 1.11900E+03 1.02300E+03 9.27000E+02 + 8.31000E+02 7.35000E+02 6.39000E+02 5.43000E+02 4.47000E+02 3.51000E+02 + 2.55000E+02 1.59000E+02 6.30000E+01 1.39500E+03 1.29900E+03 1.20300E+03 + 1.10700E+03 1.01100E+03 9.15000E+02 8.19000E+02 7.23000E+02 6.27000E+02 + 5.31000E+02 4.35000E+02 3.39000E+02 2.43000E+02 1.47000E+02 5.10000E+01 + 1.38300E+03 1.28700E+03 1.19100E+03 1.09500E+03 9.99000E+02 9.03000E+02 + 8.07000E+02 7.11000E+02 6.15000E+02 5.19000E+02 4.23000E+02 3.27000E+02 + 2.31000E+02 1.35000E+02 3.90000E+01 1.37100E+03 1.27500E+03 1.17900E+03 + 1.08300E+03 9.87000E+02 8.91000E+02 7.95000E+02 6.99000E+02 6.03000E+02 + 5.07000E+02 4.11000E+02 3.15000E+02 2.19000E+02 1.23000E+02 2.70000E+01 + 1.35900E+03 1.26300E+03 1.16700E+03 1.07100E+03 9.75000E+02 8.79000E+02 + 7.83000E+02 6.87000E+02 5.91000E+02 4.95000E+02 3.99000E+02 3.03000E+02 + 2.07000E+02 1.11000E+02 1.50000E+01 1.34700E+03 1.25100E+03 1.15500E+03 + 1.05900E+03 9.63000E+02 8.67000E+02 7.71000E+02 6.75000E+02 5.79000E+02 + 4.83000E+02 3.87000E+02 2.91000E+02 1.95000E+02 9.90000E+01 3.00000E+00 + 1.42900E+03 1.33300E+03 1.23700E+03 1.14100E+03 1.04500E+03 9.49000E+02 + 8.53000E+02 7.57000E+02 6.61000E+02 5.65000E+02 4.69000E+02 3.73000E+02 + 2.77000E+02 1.81000E+02 8.50000E+01 1.41700E+03 1.32100E+03 1.22500E+03 + 1.12900E+03 1.03300E+03 9.37000E+02 8.41000E+02 7.45000E+02 6.49000E+02 + 5.53000E+02 4.57000E+02 3.61000E+02 2.65000E+02 1.69000E+02 7.30000E+01 + 1.40500E+03 1.30900E+03 1.21300E+03 1.11700E+03 1.02100E+03 9.25000E+02 + 8.29000E+02 7.33000E+02 6.37000E+02 5.41000E+02 4.45000E+02 3.49000E+02 + 2.53000E+02 1.57000E+02 6.10000E+01 1.39300E+03 1.29700E+03 1.20100E+03 + 1.10500E+03 1.00900E+03 9.13000E+02 8.17000E+02 7.21000E+02 6.25000E+02 + 5.29000E+02 4.33000E+02 3.37000E+02 2.41000E+02 1.45000E+02 4.90000E+01 + 1.38100E+03 1.28500E+03 1.18900E+03 1.09300E+03 9.97000E+02 9.01000E+02 + 8.05000E+02 7.09000E+02 6.13000E+02 5.17000E+02 4.21000E+02 3.25000E+02 + 2.29000E+02 1.33000E+02 3.70000E+01 1.36900E+03 1.27300E+03 1.17700E+03 + 1.08100E+03 9.85000E+02 8.89000E+02 7.93000E+02 6.97000E+02 6.01000E+02 + 5.05000E+02 4.09000E+02 3.13000E+02 2.17000E+02 1.21000E+02 2.50000E+01 + 1.35700E+03 1.26100E+03 1.16500E+03 1.06900E+03 9.73000E+02 8.77000E+02 + 7.81000E+02 6.85000E+02 5.89000E+02 4.93000E+02 3.97000E+02 3.01000E+02 + 2.05000E+02 1.09000E+02 1.30000E+01 1.34500E+03 1.24900E+03 1.15300E+03 + 1.05700E+03 9.61000E+02 8.65000E+02 7.69000E+02 6.73000E+02 5.77000E+02 + 4.81000E+02 3.85000E+02 2.89000E+02 1.93000E+02 9.70000E+01 1.00000E+00 + diff --git a/tests/unit_tests/weightwindows/wwinp_np b/tests/unit_tests/weightwindows/wwinp_np new file mode 100644 index 00000000000..ed2073cf92a --- /dev/null +++ b/tests/unit_tests/weightwindows/wwinp_np @@ -0,0 +1,49 @@ + 1 1 2 10 + 3 1 + 1.0 8.0 6.0 -1.00000E+02 -1.00000E+02 -1.00000E+02 + 1.0 8.0 6.0 1.0 + -1.00000E+02 1.00000E+00 1.00000E+02 1.00000E+00 + -1.00000E+02 1.00000E+00 -5.00000E+01 1.00000E+00 1.00000E+00 -1.33333E+01 + 1.00000E+00 1.00000E+00 2.33333E+01 1.00000E+00 1.00000E+00 6.00000E+01 + 1.00000E+00 1.00000E+00 7.00000E+01 1.00000E+00 1.00000E+00 8.00000E+01 + 1.00000E+00 1.00000E+00 9.00000E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + -1.00000E+02 1.00000E+00 -6.66667E+01 1.00000E+00 1.00000E+00 -3.33333E+01 + 1.00000E+00 1.00000E+00 0.00000E+00 1.00000E+00 1.00000E+00 3.33333E+01 + 1.00000E+00 1.00000E+00 6.66667E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + 1.00000E-01 1.46780E-01 2.15440E-01 + 1.44000E+02 1.26000E+02 1.08000E+02 9.00000E+01 7.20000E+01 5.40000E+01 + 3.60000E+01 1.80000E+01 1.41000E+02 1.23000E+02 1.05000E+02 8.70000E+01 + 6.90000E+01 5.10000E+01 3.30000E+01 1.50000E+01 1.38000E+02 1.20000E+02 + 1.02000E+02 8.40000E+01 6.60000E+01 4.80000E+01 3.00000E+01 1.20000E+01 + 1.35000E+02 1.17000E+02 9.90000E+01 8.10000E+01 6.30000E+01 4.50000E+01 + 2.70000E+01 9.00000E+00 1.32000E+02 1.14000E+02 9.60000E+01 7.80000E+01 + 6.00000E+01 4.20000E+01 2.40000E+01 6.00000E+00 1.29000E+02 1.11000E+02 + 9.30000E+01 7.50000E+01 5.70000E+01 3.90000E+01 2.10000E+01 3.00000E+00 + 1.43000E+02 1.25000E+02 1.07000E+02 8.90000E+01 7.10000E+01 5.30000E+01 + 3.50000E+01 1.70000E+01 1.40000E+02 1.22000E+02 1.04000E+02 8.60000E+01 + 6.80000E+01 5.00000E+01 3.20000E+01 1.40000E+01 1.37000E+02 1.19000E+02 + 1.01000E+02 8.30000E+01 6.50000E+01 4.70000E+01 2.90000E+01 1.10000E+01 + 1.34000E+02 1.16000E+02 9.80000E+01 8.00000E+01 6.20000E+01 4.40000E+01 + 2.60000E+01 8.00000E+00 1.31000E+02 1.13000E+02 9.50000E+01 7.70000E+01 + 5.90000E+01 4.10000E+01 2.30000E+01 5.00000E+00 1.28000E+02 1.10000E+02 + 9.20000E+01 7.40000E+01 5.60000E+01 3.80000E+01 2.00000E+01 2.00000E+00 + 1.42000E+02 1.24000E+02 1.06000E+02 8.80000E+01 7.00000E+01 5.20000E+01 + 3.40000E+01 1.60000E+01 1.39000E+02 1.21000E+02 1.03000E+02 8.50000E+01 + 6.70000E+01 4.90000E+01 3.10000E+01 1.30000E+01 1.36000E+02 1.18000E+02 + 1.00000E+02 8.20000E+01 6.40000E+01 4.60000E+01 2.80000E+01 1.00000E+01 + 1.33000E+02 1.15000E+02 9.70000E+01 7.90000E+01 6.10000E+01 4.30000E+01 + 2.50000E+01 7.00000E+00 1.30000E+02 1.12000E+02 9.40000E+01 7.60000E+01 + 5.80000E+01 4.00000E+01 2.20000E+01 4.00000E+00 1.27000E+02 1.09000E+02 + 9.10000E+01 7.30000E+01 5.50000E+01 3.70000E+01 1.90000E+01 1.00000E+00 + 1.00000E+02 + 4.80000E+01 4.20000E+01 3.60000E+01 3.00000E+01 2.40000E+01 1.80000E+01 + 1.20000E+01 6.00000E+00 4.70000E+01 4.10000E+01 3.50000E+01 2.90000E+01 + 2.30000E+01 1.70000E+01 1.10000E+01 5.00000E+00 4.60000E+01 4.00000E+01 + 3.40000E+01 2.80000E+01 2.20000E+01 1.60000E+01 1.00000E+01 4.00000E+00 + 4.50000E+01 3.90000E+01 3.30000E+01 2.70000E+01 2.10000E+01 1.50000E+01 + 9.00000E+00 3.00000E+00 4.40000E+01 3.80000E+01 3.20000E+01 2.60000E+01 + 2.00000E+01 1.40000E+01 8.00000E+00 2.00000E+00 4.30000E+01 3.70000E+01 + 3.10000E+01 2.50000E+01 1.90000E+01 1.30000E+01 7.00000E+00 1.00000E+00 + diff --git a/tests/unit_tests/weightwindows/wwinp_p b/tests/unit_tests/weightwindows/wwinp_p new file mode 100644 index 00000000000..a9f9f98dff9 --- /dev/null +++ b/tests/unit_tests/weightwindows/wwinp_p @@ -0,0 +1,48 @@ + 1 1 2 10 + 0 4 + 6.0 8.0 1.0 -1.00000E+02 -1.00000E+02 -5.00000E+01 + 6.0 8.0 1.0 1.0 + -1.00000E+02 1.00000E+00 -6.66667E+01 1.00000E+00 1.00000E+00 -3.33333E+01 + 1.00000E+00 1.00000E+00 0.00000E+00 1.00000E+00 1.00000E+00 3.33333E+01 + 1.00000E+00 1.00000E+00 6.66667E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + -1.00000E+02 1.00000E+00 -5.00000E+01 1.00000E+00 1.00000E+00 -1.33333E+01 + 1.00000E+00 1.00000E+00 2.33333E+01 1.00000E+00 1.00000E+00 6.00000E+01 + 1.00000E+00 1.00000E+00 7.00000E+01 1.00000E+00 1.00000E+00 8.00000E+01 + 1.00000E+00 1.00000E+00 9.00000E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + -5.00000E+01 1.00000E+00 5.00000E+01 1.00000E+00 + 1.00000E-01 1.46780E-01 2.15440E-01 3.16230E-01 + 1.92000E+02 1.60000E+02 1.28000E+02 9.60000E+01 6.40000E+01 3.20000E+01 + 1.88000E+02 1.56000E+02 1.24000E+02 9.20000E+01 6.00000E+01 2.80000E+01 + 1.84000E+02 1.52000E+02 1.20000E+02 8.80000E+01 5.60000E+01 2.40000E+01 + 1.80000E+02 1.48000E+02 1.16000E+02 8.40000E+01 5.20000E+01 2.00000E+01 + 1.76000E+02 1.44000E+02 1.12000E+02 8.00000E+01 4.80000E+01 1.60000E+01 + 1.72000E+02 1.40000E+02 1.08000E+02 7.60000E+01 4.40000E+01 1.20000E+01 + 1.68000E+02 1.36000E+02 1.04000E+02 7.20000E+01 4.00000E+01 8.00000E+00 + 1.64000E+02 1.32000E+02 1.00000E+02 6.80000E+01 3.60000E+01 4.00000E+00 + 1.91000E+02 1.59000E+02 1.27000E+02 9.50000E+01 6.30000E+01 3.10000E+01 + 1.87000E+02 1.55000E+02 1.23000E+02 9.10000E+01 5.90000E+01 2.70000E+01 + 1.83000E+02 1.51000E+02 1.19000E+02 8.70000E+01 5.50000E+01 2.30000E+01 + 1.79000E+02 1.47000E+02 1.15000E+02 8.30000E+01 5.10000E+01 1.90000E+01 + 1.75000E+02 1.43000E+02 1.11000E+02 7.90000E+01 4.70000E+01 1.50000E+01 + 1.71000E+02 1.39000E+02 1.07000E+02 7.50000E+01 4.30000E+01 1.10000E+01 + 1.67000E+02 1.35000E+02 1.03000E+02 7.10000E+01 3.90000E+01 7.00000E+00 + 1.63000E+02 1.31000E+02 9.90000E+01 6.70000E+01 3.50000E+01 3.00000E+00 + 1.90000E+02 1.58000E+02 1.26000E+02 9.40000E+01 6.20000E+01 3.00000E+01 + 1.86000E+02 1.54000E+02 1.22000E+02 9.00000E+01 5.80000E+01 2.60000E+01 + 1.82000E+02 1.50000E+02 1.18000E+02 8.60000E+01 5.40000E+01 2.20000E+01 + 1.78000E+02 1.46000E+02 1.14000E+02 8.20000E+01 5.00000E+01 1.80000E+01 + 1.74000E+02 1.42000E+02 1.10000E+02 7.80000E+01 4.60000E+01 1.40000E+01 + 1.70000E+02 1.38000E+02 1.06000E+02 7.40000E+01 4.20000E+01 1.00000E+01 + 1.66000E+02 1.34000E+02 1.02000E+02 7.00000E+01 3.80000E+01 6.00000E+00 + 1.62000E+02 1.30000E+02 9.80000E+01 6.60000E+01 3.40000E+01 2.00000E+00 + 1.89000E+02 1.57000E+02 1.25000E+02 9.30000E+01 6.10000E+01 2.90000E+01 + 1.85000E+02 1.53000E+02 1.21000E+02 8.90000E+01 5.70000E+01 2.50000E+01 + 1.81000E+02 1.49000E+02 1.17000E+02 8.50000E+01 5.30000E+01 2.10000E+01 + 1.77000E+02 1.45000E+02 1.13000E+02 8.10000E+01 4.90000E+01 1.70000E+01 + 1.73000E+02 1.41000E+02 1.09000E+02 7.70000E+01 4.50000E+01 1.30000E+01 + 1.69000E+02 1.37000E+02 1.05000E+02 7.30000E+01 4.10000E+01 9.00000E+00 + 1.65000E+02 1.33000E+02 1.01000E+02 6.90000E+01 3.70000E+01 5.00000E+00 + 1.61000E+02 1.29000E+02 9.70000E+01 6.50000E+01 3.30000E+01 1.00000E+00 + diff --git a/tests/unit_tests/weightwindows/wwinp_t b/tests/unit_tests/weightwindows/wwinp_t new file mode 100644 index 00000000000..a12668aa4d9 --- /dev/null +++ b/tests/unit_tests/weightwindows/wwinp_t @@ -0,0 +1,49 @@ + 1 2 2 10 + 1 1 + 0 4 + 6.0 8.0 1.0 -1.00000E+02 -1.00000E+02 -5.00000E+01 + 6.0 8.0 1.0 1.0 + -1.00000E+02 1.00000E+00 -6.66667E+01 1.00000E+00 1.00000E+00 -3.33333E+01 + 1.00000E+00 1.00000E+00 0.00000E+00 1.00000E+00 1.00000E+00 3.33333E+01 + 1.00000E+00 1.00000E+00 6.66667E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + -1.00000E+02 1.00000E+00 -5.00000E+01 1.00000E+00 1.00000E+00 -1.33333E+01 + 1.00000E+00 1.00000E+00 2.33333E+01 1.00000E+00 1.00000E+00 6.00000E+01 + 1.00000E+00 1.00000E+00 7.00000E+01 1.00000E+00 1.00000E+00 8.00000E+01 + 1.00000E+00 1.00000E+00 9.00000E+01 1.00000E+00 1.00000E+00 1.00000E+02 + 1.00000E+00 + 1.00000E+02 + -5.00000E+01 1.00000E+00 5.00000E+01 1.00000E+00 + 1.00000E-01 1.46780E-01 2.15440E-01 3.16230E-01 + 1.92000E+02 1.60000E+02 1.28000E+02 9.60000E+01 6.40000E+01 3.20000E+01 + 1.88000E+02 1.56000E+02 1.24000E+02 9.20000E+01 6.00000E+01 2.80000E+01 + 1.84000E+02 1.52000E+02 1.20000E+02 8.80000E+01 5.60000E+01 2.40000E+01 + 1.80000E+02 1.48000E+02 1.16000E+02 8.40000E+01 5.20000E+01 2.00000E+01 + 1.76000E+02 1.44000E+02 1.12000E+02 8.00000E+01 4.80000E+01 1.60000E+01 + 1.72000E+02 1.40000E+02 1.08000E+02 7.60000E+01 4.40000E+01 1.20000E+01 + 1.68000E+02 1.36000E+02 1.04000E+02 7.20000E+01 4.00000E+01 8.00000E+00 + 1.64000E+02 1.32000E+02 1.00000E+02 6.80000E+01 3.60000E+01 4.00000E+00 + 1.91000E+02 1.59000E+02 1.27000E+02 9.50000E+01 6.30000E+01 3.10000E+01 + 1.87000E+02 1.55000E+02 1.23000E+02 9.10000E+01 5.90000E+01 2.70000E+01 + 1.83000E+02 1.51000E+02 1.19000E+02 8.70000E+01 5.50000E+01 2.30000E+01 + 1.79000E+02 1.47000E+02 1.15000E+02 8.30000E+01 5.10000E+01 1.90000E+01 + 1.75000E+02 1.43000E+02 1.11000E+02 7.90000E+01 4.70000E+01 1.50000E+01 + 1.71000E+02 1.39000E+02 1.07000E+02 7.50000E+01 4.30000E+01 1.10000E+01 + 1.67000E+02 1.35000E+02 1.03000E+02 7.10000E+01 3.90000E+01 7.00000E+00 + 1.63000E+02 1.31000E+02 9.90000E+01 6.70000E+01 3.50000E+01 3.00000E+00 + 1.90000E+02 1.58000E+02 1.26000E+02 9.40000E+01 6.20000E+01 3.00000E+01 + 1.86000E+02 1.54000E+02 1.22000E+02 9.00000E+01 5.80000E+01 2.60000E+01 + 1.82000E+02 1.50000E+02 1.18000E+02 8.60000E+01 5.40000E+01 2.20000E+01 + 1.78000E+02 1.46000E+02 1.14000E+02 8.20000E+01 5.00000E+01 1.80000E+01 + 1.74000E+02 1.42000E+02 1.10000E+02 7.80000E+01 4.60000E+01 1.40000E+01 + 1.70000E+02 1.38000E+02 1.06000E+02 7.40000E+01 4.20000E+01 1.00000E+01 + 1.66000E+02 1.34000E+02 1.02000E+02 7.00000E+01 3.80000E+01 6.00000E+00 + 1.62000E+02 1.30000E+02 9.80000E+01 6.60000E+01 3.40000E+01 2.00000E+00 + 1.89000E+02 1.57000E+02 1.25000E+02 9.30000E+01 6.10000E+01 2.90000E+01 + 1.85000E+02 1.53000E+02 1.21000E+02 8.90000E+01 5.70000E+01 2.50000E+01 + 1.81000E+02 1.49000E+02 1.17000E+02 8.50000E+01 5.30000E+01 2.10000E+01 + 1.77000E+02 1.45000E+02 1.13000E+02 8.10000E+01 4.90000E+01 1.70000E+01 + 1.73000E+02 1.41000E+02 1.09000E+02 7.70000E+01 4.50000E+01 1.30000E+01 + 1.69000E+02 1.37000E+02 1.05000E+02 7.30000E+01 4.10000E+01 9.00000E+00 + 1.65000E+02 1.33000E+02 1.01000E+02 6.90000E+01 3.70000E+01 5.00000E+00 + 1.61000E+02 1.29000E+02 9.70000E+01 6.50000E+01 3.30000E+01 1.00000E+00 diff --git a/tools/ci/gha-install-libmesh.sh b/tools/ci/gha-install-libmesh.sh index 132963820d9..cb808ae5b3b 100755 --- a/tools/ci/gha-install-libmesh.sh +++ b/tools/ci/gha-install-libmesh.sh @@ -5,7 +5,7 @@ set -ex # libMESH install pushd $HOME mkdir LIBMESH && cd LIBMESH -git clone https://github.com/libmesh/libmesh -b v1.6.0 --recurse-submodules +git clone https://github.com/libmesh/libmesh -b v1.7.1 --recurse-submodules mkdir build && cd build export METHODS="opt" diff --git a/tools/ci/gha-install-mcpl.sh b/tools/ci/gha-install-mcpl.sh new file mode 100755 index 00000000000..9b8609398a0 --- /dev/null +++ b/tools/ci/gha-install-mcpl.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -ex +cd $HOME +git clone https://github.com/mctools/mcpl +cd mcpl +mkdir build && cd build +cmake .. && make 2>/dev/null && sudo make install diff --git a/tools/ci/gha-install-ncrystal.sh b/tools/ci/gha-install-ncrystal.sh new file mode 100755 index 00000000000..16f77e13e2b --- /dev/null +++ b/tools/ci/gha-install-ncrystal.sh @@ -0,0 +1,46 @@ +#!/bin/bash +set -ex +cd $HOME + +#Use the NCrystal develop branch (in the near future we can move this to master): +git clone https://github.com/mctools/ncrystal --branch develop --single-branch --depth 1 ncrystal_src + +SRC_DIR="$PWD/ncrystal_src" +BLD_DIR="$PWD/ncrystal_bld" +INST_DIR="$PWD/ncrystal_inst" +PYTHON=$(which python3) + +CPU_COUNT=1 + +mkdir "$BLD_DIR" +cd ncrystal_bld + +cmake \ + "${SRC_DIR}" \ + -DBUILD_SHARED_LIBS=ON \ + -DNCRYSTAL_NOTOUCH_CMAKE_BUILD_TYPE=ON \ + -DNCRYSTAL_MODIFY_RPATH=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DNCRYSTAL_ENABLE_EXAMPLES=OFF \ + -DNCRYSTAL_ENABLE_SETUPSH=OFF \ + -DNCRYSTAL_ENABLE_DATA=EMBED \ + -DCMAKE_INSTALL_PREFIX="${INST_DIR}" \ + -DPython3_EXECUTABLE="$PYTHON" + +make -j${CPU_COUNT:-1} +make install + +#Note: There is no "make test" or "make ctest" functionality for NCrystal +# yet. If it appears in the future, we should add it here. + +# Output the configuration to the log + +"${INST_DIR}/bin/ncrystal-config" --setup + +# Change environmental variables + +eval $( "${INST_DIR}/bin/ncrystal-config" --setup ) + +# Check installation worked + +nctool --test diff --git a/tools/ci/gha-install-vectfit.sh b/tools/ci/gha-install-vectfit.sh index 343942e03d4..bd38e1ea8cd 100755 --- a/tools/ci/gha-install-vectfit.sh +++ b/tools/ci/gha-install-vectfit.sh @@ -4,10 +4,10 @@ set -ex PYBIND_BRANCH='master' PYBIND_REPO='https://github.com/pybind/pybind11' -XTL_BRANCH='0.6.9' +XTL_BRANCH='0.6.13' XTL_REPO='https://github.com/xtensor-stack/xtl' -XTENSOR_BRANCH='0.21.2' +XTENSOR_BRANCH='0.21.3' XTENSOR_REPO='https://github.com/xtensor-stack/xtensor' XTENSOR_PYTHON_BRANCH='0.24.1' @@ -16,8 +16,6 @@ XTENSOR_PYTHON_REPO='https://github.com/xtensor-stack/xtensor-python' XTENSOR_BLAS_BRANCH='0.17.1' XTENSOR_BLAS_REPO='https://github.com/xtensor-stack/xtensor-blas' -sudo apt-get install -y libblas-dev liblapack-dev - cd $HOME git clone -b $PYBIND_BRANCH $PYBIND_REPO cd pybind11 && mkdir build && cd build && cmake .. && sudo make install @@ -39,7 +37,10 @@ cd $HOME git clone -b $XTENSOR_BLAS_BRANCH $XTENSOR_BLAS_REPO cd xtensor-blas && mkdir build && cd build && cmake .. && sudo make install +# Install wheel (remove when vectfit supports installation with build isolation) +pip install wheel + # Install vectfit cd $HOME git clone https://github.com/liangjg/vectfit.git -pip install ./vectfit +pip install --no-build-isolation ./vectfit diff --git a/tools/ci/gha-install.py b/tools/ci/gha-install.py index 9c163c1dcbb..f4b2fbb3187 100644 --- a/tools/ci/gha-install.py +++ b/tools/ci/gha-install.py @@ -19,22 +19,22 @@ def is_exe(fpath): return None -def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False): +def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False, ncrystal=False): # Create build directory and change to it shutil.rmtree('build', ignore_errors=True) os.mkdir('build') os.chdir('build') - # Build in debug mode by default - cmake_cmd = ['cmake', '-Ddebug=on'] + # Build in debug mode by default with support for MCPL + cmake_cmd = ['cmake', '-DCMAKE_BUILD_TYPE=Debug', '-DOPENMC_USE_MCPL=on'] # Turn off OpenMP if specified if not omp: - cmake_cmd.append('-Dopenmp=off') + cmake_cmd.append('-DOPENMC_USE_OPENMP=off') # Use MPI wrappers when building in parallel if mpi: - os.environ['CXX'] = 'mpicxx' + cmake_cmd.append('-DOPENMC_USE_MPI=on') # Tell CMake to prefer parallel HDF5 if specified if phdf5: @@ -46,16 +46,21 @@ def install(omp=False, mpi=False, phdf5=False, dagmc=False, libmesh=False): cmake_cmd.append('-DHDF5_PREFER_PARALLEL=OFF') if dagmc: - cmake_cmd.append('-Ddagmc=ON') + cmake_cmd.append('-DOPENMC_USE_DAGMC=ON') cmake_cmd.append('-DCMAKE_PREFIX_PATH=~/DAGMC') if libmesh: - cmake_cmd.append('-Dlibmesh=ON') + cmake_cmd.append('-DOPENMC_USE_LIBMESH=ON') libmesh_path = os.environ.get('HOME') + '/LIBMESH' cmake_cmd.append('-DCMAKE_PREFIX_PATH=' + libmesh_path) + if ncrystal: + cmake_cmd.append('-DOPENMC_USE_NCRYSTAL=ON') + ncrystal_cmake_path = os.environ.get('HOME') + '/ncrystal_inst/lib/cmake' + cmake_cmd.append(f'-DCMAKE_PREFIX_PATH={ncrystal_cmake_path}') + # Build in coverage mode for coverage testing - cmake_cmd.append('-Dcoverage=on') + cmake_cmd.append('-DOPENMC_ENABLE_COVERAGE=on') # Build and install cmake_cmd.append('..') @@ -70,10 +75,11 @@ def main(): mpi = (os.environ.get('MPI') == 'y') phdf5 = (os.environ.get('PHDF5') == 'y') dagmc = (os.environ.get('DAGMC') == 'y') + ncrystal = (os.environ.get('NCRYSTAL') == 'y') libmesh = (os.environ.get('LIBMESH') == 'y') # Build and install - install(omp, mpi, phdf5, dagmc, libmesh) + install(omp, mpi, phdf5, dagmc, libmesh, ncrystal) if __name__ == '__main__': main() diff --git a/tools/ci/gha-install.sh b/tools/ci/gha-install.sh index 8c4762e3e40..2cef974d346 100755 --- a/tools/ci/gha-install.sh +++ b/tools/ci/gha-install.sh @@ -1,7 +1,7 @@ #!/bin/bash set -ex -# Upgrade pip, pytest, numpy before doing anything else +# Upgrade pip, pytest, numpy before doing anything else. pip install --upgrade pip pip install --upgrade pytest pip install --upgrade numpy @@ -14,6 +14,11 @@ if [[ $DAGMC = 'y' ]]; then ./tools/ci/gha-install-dagmc.sh fi +# Install NCrystal if needed +if [[ $NCRYSTAL = 'y' ]]; then + ./tools/ci/gha-install-ncrystal.sh +fi + # Install vectfit for WMP generation if needed if [[ $VECTFIT = 'y' ]]; then ./tools/ci/gha-install-vectfit.sh @@ -24,6 +29,9 @@ if [[ $LIBMESH = 'y' ]]; then ./tools/ci/gha-install-libmesh.sh fi +# Install MCPL +./tools/ci/gha-install-mcpl.sh + # For MPI configurations, make sure mpi4py and h5py are built against the # correct version of MPI if [[ $MPI == 'y' ]]; then @@ -32,7 +40,8 @@ if [[ $MPI == 'y' ]]; then export CC=mpicc export HDF5_MPI=ON export HDF5_DIR=/usr/lib/x86_64-linux-gnu/hdf5/mpich - pip install --no-binary=h5py h5py + pip install wheel "cython<3.0" + pip install --no-binary=h5py --no-build-isolation h5py fi # Build and install OpenMC executable diff --git a/tools/ci/gha-script.sh b/tools/ci/gha-script.sh index c791167e99d..9de84f3e553 100755 --- a/tools/ci/gha-script.sh +++ b/tools/ci/gha-script.sh @@ -8,11 +8,18 @@ args=" " if [[ $MPI == 'y' ]]; then args="${args} --mpi " fi - + # Check for event-based if [[ $EVENT == 'y' ]]; then args="${args} --event " fi +# Check NCrystal installation +if [[ $NCRYSTAL = 'y' ]]; then + # Change environmental variables + eval $( "${HOME}/ncrystal_inst/bin/ncrystal-config" --setup ) + nctool --test +fi + # Run regression and unit tests pytest --cov=openmc -v $args tests diff --git a/tools/dev/COPYRIGHT.celeritas b/tools/dev/COPYRIGHT.celeritas new file mode 100644 index 00000000000..39fad59ed14 --- /dev/null +++ b/tools/dev/COPYRIGHT.celeritas @@ -0,0 +1,14 @@ +Note: this copyright applies to the following files: + - install-commit-hooks.sh + - post-commit.git-clang-format +which originated from https://github.com/celeritas-project/celeritas + +Intellectual Property Notice +---------------------------- + +Celeritas is licensed under the Apache License, Version 2.0 (LICENSE-APACHE +or http://www.apache.org/licenses/LICENSE-2.0) or the MIT license, +(LICENSE-MIT or http://opensource.org/licenses/MIT), at your option. + +Copyrights and patents in the Celeritas project are retained by contributors. +No copyright assignment is required to contribute to Celeritas. diff --git a/tools/dev/install-commit-hooks.sh b/tools/dev/install-commit-hooks.sh new file mode 100755 index 00000000000..06f610da5a1 --- /dev/null +++ b/tools/dev/install-commit-hooks.sh @@ -0,0 +1,32 @@ +#!/bin/sh -e + +if ! hash git-clang-format ; then + printf "\e[31mgit-clang-format is not installed.\e[0m +Install clang-format and update your paths. +" + exit 1 +fi + +GIT_WORK_TREE="$(git rev-parse --show-toplevel)" +POSTCOMMIT=${GIT_WORK_TREE}/.git/hooks/post-commit + +# Ensure a post-commit hook exists (Git LFS might have created one). +if [ ! -f "${POSTCOMMIT}" ]; then + printf "\e[33mCreating post-commit hook at ${POSTCOMMIT}.\e[0m\n" + echo "#!/bin/sh" > "${POSTCOMMIT}" + chmod a+x "${POSTCOMMIT}" +fi + +printf "\e[2;37mSetting clang format options in git config\e[0m\n" +git config clangFormat.extension "cc,hh,h,cpp,hpp" +git config clangFormat.style "file" + +if ! grep 'git-clang-format' ${POSTCOMMIT} >/dev/null ; then + printf "\e[33mAppending git-clang-format call to ${POSTCOMMIT}\e[0m\n" + cat >> "${POSTCOMMIT}" << 'EOF' +GCF="$(git rev-parse --show-toplevel)/tools/dev/post-commit.git-clang-format" +test -x "${GCF}" && "${GCF}" "$@" +EOF +fi + +printf "\e[0;32mPre-commit hook successfully installed for ${GIT_WORK_TREE}\e[0m\n" diff --git a/tools/dev/post-commit.git-clang-format b/tools/dev/post-commit.git-clang-format new file mode 100755 index 00000000000..01e67f3597e --- /dev/null +++ b/tools/dev/post-commit.git-clang-format @@ -0,0 +1,38 @@ +#!/bin/sh -e + +if [ -n "${SKIP_GCF}" ]; then + # Running inside of another git-clang-format hook + exit 0 +fi + +if ! command -v git-clang-format >/dev/null 2>&1 ; then + printf "\e[1;33mgit-clang-format is not installed!\e[0m + Install clang to enable auto-formatting. +" >&2 + exit 0 +fi + +if ! git diff-files --quiet ; then + printf "\e[1;33mWill not git-clang-format: repository is dirty\e[0m. \e[33m \ +Stage (with 'git add') or stash (with 'git stash') all files before committing \ +to apply formatting.\e[0m +" >&2 + exit 0 +fi + +printf "\e[2;37;40mRunning git-clang-format...\e[0m" >&2 +CLANG_FORMAT_RESULT="$(git-clang-format HEAD^)" + +if git diff-files --quiet ; then + printf "\r\e[2;32mAll code changes were properly formatted\e[0m\n" >&2 +else + BAD_COMMIT=$(git rev-parse --short HEAD) + printf "\r\e[0;33mCode formatting changes were required:\e[0m\n" >&2 + printf "${CLANG_FORMAT_RESULT}\n" >&2 + git add -u :/ + SKIP_GCF=1 git commit --amend -C HEAD >/dev/null + GOOD_COMMIT=$(git rev-parse --short HEAD) + printf "\e[2;37mTo view formatting changes: + git diff ${BAD_COMMIT} ${GOOD_COMMIT}\e[0m +" >&2 +fi diff --git a/vendor/Catch2 b/vendor/Catch2 new file mode 160000 index 00000000000..5a40b2275ca --- /dev/null +++ b/vendor/Catch2 @@ -0,0 +1 @@ +Subproject commit 5a40b2275caa05cf809bf04df848764a9d7df2e2 diff --git a/vendor/fmt b/vendor/fmt index 65ac626c585..d141cdbeb0f 160000 --- a/vendor/fmt +++ b/vendor/fmt @@ -1 +1 @@ -Subproject commit 65ac626c5856f5aad1f1542e79407a6714357043 +Subproject commit d141cdbeb0fb422a3fb7173b285fd38e0d1772dc diff --git a/vendor/xtensor b/vendor/xtensor index 31acec1e90b..3634f2ded19 160000 --- a/vendor/xtensor +++ b/vendor/xtensor @@ -1 +1 @@ -Subproject commit 31acec1e90bbea6d4bc17af0710a123bd5da6689 +Subproject commit 3634f2ded19e0cf38208c8b86cea9e1d7c8e397d diff --git a/vendor/xtl b/vendor/xtl index c19750fb148..a7c1c5444df 160000 --- a/vendor/xtl +++ b/vendor/xtl @@ -1 +1 @@ -Subproject commit c19750fb1488369dc41f6069bc2b8446fc093e75 +Subproject commit a7c1c5444dfc57f76620391af4c94785ff82c8d6