├── .github
└── workflows
│ ├── anaconda-publish.yml
│ ├── black.yml
│ ├── conda-build-test.yml
│ ├── docker_ci_main.yml
│ └── python-publish.yml
├── .gitignore
├── CITATION.cff
├── LICENSE
├── README.md
├── conda
├── conda_build_config.yaml
└── meta.yaml
├── pyproject.toml
├── requirements.txt
├── src
└── openmc_data_downloader
│ ├── __init__.py
│ ├── cross_sections_directory.py
│ ├── fendl_3.1d_cross_sections.xml
│ ├── nndc_7.1_cross_sections.xml
│ ├── nndc_8.0_cross_sections.xml
│ ├── tendl_2019_cross_sections.xml
│ ├── terminal_cmd.py
│ └── utils.py
└── tests
├── test_command_line_usage.py
├── test_cross_sections_directory.py
├── test_functions.py
└── test_use_in_openmc.py
/.github/workflows/anaconda-publish.yml:
--------------------------------------------------------------------------------
1 | name: anaconda-publish
2 |
3 | on:
4 | workflow_dispatch:
5 | release:
6 | types: [published]
7 |
8 | jobs:
9 | build:
10 | runs-on: ubuntu-latest
11 | container: continuumio/miniconda3:4.10.3
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 |
16 | - name: Set up conda
17 | run: |
18 | apt-get --allow-releaseinfo-change update
19 | conda install -y anaconda-client conda-build
20 | conda config --set anaconda_upload no
21 | - name: Build and publish to conda
22 | env:
23 | ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_TOKEN }}
24 | run: |
25 | conda build conda -c conda-forge --config-file conda/conda_build_config.yaml
26 | conda convert /opt/conda/conda-bld/linux-64/*.tar.bz2 --platform osx-64 --platform win-64 -o /opt/conda/conda-bld/
27 | anaconda upload -f /opt/conda/conda-bld/*/*.tar.bz2
28 |
--------------------------------------------------------------------------------
/.github/workflows/black.yml:
--------------------------------------------------------------------------------
1 | name: black
2 |
3 | on:
4 | push:
5 | paths:
6 | - '**.py'
7 |
8 | defaults:
9 | run:
10 | shell: bash
11 |
12 | jobs:
13 | black:
14 | runs-on: ubuntu-latest
15 | steps:
16 | - uses: actions/checkout@v2
17 | with:
18 | ref: ${{ github.head_ref }}
19 | - name: Setup Python
20 | uses: actions/setup-python@v2
21 | with:
22 | python-version: 3.x
23 | - name: Install black
24 | run: |
25 | python -m pip install --upgrade pip
26 | pip install black
27 | - name: Run black
28 | run: |
29 | black .
30 | - uses: stefanzweifel/git-auto-commit-action@v4
31 | with:
32 | commit_message: "[skip ci] Apply formatting changes"
33 |
--------------------------------------------------------------------------------
/.github/workflows/conda-build-test.yml:
--------------------------------------------------------------------------------
1 | name: conda-build-test
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | branches:
7 | - develop
8 | - main
9 |
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | container: continuumio/miniconda3:4.10.3
14 |
15 | steps:
16 | - uses: actions/checkout@v2
17 |
18 | - name: Set up conda
19 | run: |
20 | apt-get --allow-releaseinfo-change update
21 | conda install -y anaconda-client conda-build
22 | conda config --set anaconda_upload no
23 | - name: Build and test
24 | env:
25 | GIT_DESCRIBE_TAG: 0.1
26 | run: |
27 | conda build conda -c conda-forge --config-file conda/conda_build_config.yaml
28 |
--------------------------------------------------------------------------------
/.github/workflows/docker_ci_main.yml:
--------------------------------------------------------------------------------
1 |
2 | name: CI tests
3 | on:
4 | pull_request:
5 | branches:
6 | - main
7 | - develop
8 | push:
9 | branches:
10 | - main
11 | - develop
12 | jobs:
13 | build:
14 | runs-on: ubuntu-latest
15 | container:
16 | image: openmc/openmc:develop
17 |
18 | steps:
19 | - name: checkout repository
20 | uses: actions/checkout@v2
21 |
22 | - name: Setup package
23 | run: |
24 | pip install .
25 |
26 | - name: test_command_line_usage.py
27 | run: |
28 | pytest tests/test_command_line_usage.py -v --cov=src --cov-report term --cov-report xml
29 |
30 | - name: test_functions.py
31 | run: |
32 | pytest tests/test_functions.py -v --cov=src --cov-report term --cov-report xml
33 |
34 | - name: test_use_in_openmc.py
35 | run: |
36 | pytest tests/test_use_in_openmc.py -v --cov=src --cov-report term --cov-report xml
37 |
38 | - name: upload test results
39 | run: |
40 | curl -s https://codecov.io/bash | bash
41 |
--------------------------------------------------------------------------------
/.github/workflows/python-publish.yml:
--------------------------------------------------------------------------------
1 | # This yml file will trigger a Github Actions event that builds and upload the
2 | # Python package to PiPy. This makes use of Twine and is triggered when a push
3 | # to the main branch occures. For more information see:
4 | # https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
5 | # and for details on the Autobump version section see:
6 | # https://github.com/grst/python-ci-versioneer
7 |
8 | name: Upload Python Package
9 |
10 | on:
11 | # allows us to run workflows manually
12 | workflow_dispatch:
13 | release:
14 | types: [created]
15 |
16 | jobs:
17 | deploy:
18 |
19 | runs-on: ubuntu-latest
20 |
21 | steps:
22 | - uses: actions/checkout@v2
23 | - name: Set up Python
24 | uses: actions/setup-python@v2
25 | with:
26 | python-version: '3.x'
27 |
28 | - name: Install dependencies
29 | run: |
30 | python -m pip install --upgrade pip
31 | pip install setuptools wheel build twine
32 |
33 | - name: Build and publish
34 | env:
35 | TWINE_USERNAME: __token__
36 | TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
37 | run: |
38 | python -m build
39 | twine check dist/*
40 | twine upload dist/*
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
131 | # OpenMC files
132 | materials.xml
133 | tallies.xml
134 | geometry.xml
135 | settings.xml
136 | *.h5
137 |
138 | **_version.py
--------------------------------------------------------------------------------
/CITATION.cff:
--------------------------------------------------------------------------------
1 | cff-version: 1.2.0
2 | message: "If you use this software, please cite it as below."
3 | authors:
4 | - family-names: "Shimwell"
5 | given-names: "Jonathan"
6 | orcid: "https://orcid.org/0000-0001-6909-0946"
7 | title: "openmc-data-downloader. A Python package for downloading h5 cross section files for use in OpenMC."
8 | version: 0.4.1
9 | date-released: 2021-11-11
10 | url: "https://github.com/openmc-data-storage/openmc_data_downloader"
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 openmc-data-storage
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | [](https://github.com/openmc-data-storage/openmc_data_downloader/actions/workflows/docker_ci_main.yml)
3 | [](https://github.com/openmc-data-storage/openmc_data_downloader/actions/workflows/python-publish.yml)
4 | [](https://pypi.org/project/openmc_data_downloader/)
5 | [](https://codecov.io/gh/openmc-data-storage/openmc_data_downloader)
6 |
7 | # OpenMC data downloader
8 |
9 | A Python package for downloading preprocessed cross section data in the h5 file
10 | format for use with OpenMC.
11 |
12 | This package allows you to download a fully reproducible composite nuclear data
13 | library with one command.
14 |
15 | There are several methods of obtaining complete data libraries for use with
16 | OpenMC, for example:
17 |
18 | - [OpenMC.org](https://openmc.org/) has entire libraries downloadable as compressed files
19 | - [OpenMC data repository scripts](https://github.com/openmc-dev/data/) has scripts for automatically downloading ACE and ENDF files and generating h5 files from these inputs.
20 |
21 | ## History
22 |
23 | The package was originally conceived by Jonathan Shimwell as a means of
24 | downloading a minimal selection of data for use on continuous integration
25 | platforms.
26 | The package can also used to produce traceable and reproducible
27 | nuclear data distributions.
28 |
29 | ## System Installation
30 |
31 | To install the openmc_data_downloader you need to have Python3 installed,
32 | OpenMC is also advisable if you want to run simulations using the h5 data files
33 | but not actually mandatory if you just want to download the cross sections.
34 |
35 | ```bash
36 | pip install openmc_data_downloader
37 | ```
38 |
39 | ## Features
40 |
41 | The OpenMC data downloader is able to download cross section files for isotopes
42 | from nuclear data libraries.The user specifies the nuclear data libraries in
43 | order of their preference. When an isotope is found in multiple libraries it
44 | will be downloaded from the highest preference library. This avoid duplication
45 | of isotopes and provides a reproducible nuclear data environment.
46 |
47 | The nuclear data h5 file are downloaded from the OpenMC-data-storage
48 | repository. Prior to being added to the repository they have been automatically
49 | processed using scripts from OpenMC data repository, these scripts convert ACE
50 | and ENDF file to h5 files.
51 |
52 | The resulting h5 files are then used in and automated test suite of simulations
53 | to help ensure they are suitable for their intended purpose.
54 |
55 | Isotopes for downloading can be found in a variety of ways as demonstrated below.
56 | When downloading a cross_section.xml file is automatically created and h5 files
57 | are named with their nuclear data library and the isotope. This helps avoid
58 | downloading files that already exist locally and the ```overwrite``` argument
59 | can be used to control if these files are downloaded again.
60 |
61 | ## Usage - command line usage
62 |
63 | ### Getting a description of the input options
64 |
65 | ```bash
66 | openmc_data_downloader --help
67 | ```
68 |
69 | ### Downloading a single isotope from the FENDL 3.1d nuclear library
70 |
71 | ```bash
72 | openmc_data_downloader -l FENDL-3.1d -i Li6
73 | ```
74 |
75 | ### Downloading a multiple isotopes from the TENDL 2019 nuclear library
76 |
77 | ```bash
78 | openmc_data_downloader -l TENDL-2019 -i Li6 Li7
79 | ```
80 |
81 | ### Downloading a single element from the TENDL 2019 nuclear library
82 |
83 | ```bash
84 | openmc_data_downloader -l TENDL-2019 -e Li
85 | ```
86 |
87 | ### Downloading a multiple element from the TENDL 2019 nuclear library
88 |
89 | ```bash
90 | openmc_data_downloader -l TENDL-2019 -e Li Si Na
91 | ```
92 |
93 | ### Downloading h5 files from the ENDF/B 7.1 NNDC library to a specific folder (destination)
94 |
95 | ```bash
96 | openmc_data_downloader -l ENDFB-7.1-NNDC -i Be9 -d my_h5_files
97 | ```
98 |
99 | ### Downloading a combination of isotopes and element from the TENDL 2019 nuclear library
100 |
101 | ```bash
102 | openmc_data_downloader -l TENDL-2019 -e Li Si Na -i Fe56 U235
103 | ```
104 | ### Downloading all the isotopes from the TENDL 2019 nuclear library
105 |
106 | ```bash
107 | openmc_data_downloader -l TENDL-2019 -i all
108 | ```
109 | ### Downloading all the stable isotopes from the TENDL 2019 nuclear library
110 |
111 | ```bash
112 | openmc_data_downloader -l TENDL-2019 -i stable
113 | ```
114 |
115 | ### Downloading all the isotopes in a materials.xml file from the TENDL 2019 nuclear library
116 |
117 | ```bash
118 | openmc_data_downloader -l TENDL-2019 -m materials.xml
119 | ```
120 |
121 | ### Downloading 3 isotopes from ENDF/B 7.1 NNDC (first choice) and TENDL 2019 (second choice) nuclear library
122 |
123 | ```bash
124 | openmc_data_downloader -l ENDFB-7.1-NNDC TENDL-2019 -i Li6 Li7 Be9
125 | ```
126 |
127 | ### Downloading the photon only cross section for an element ENDF/B 7.1 NNDC
128 |
129 | ```bash
130 | openmc_data_downloader -l ENDFB-7.1-NNDC -e Li -p photon
131 | ```
132 |
133 | ### Downloading the neutron and photon cross section for an element ENDF/B 7.1 NNDC
134 |
135 | ```bash
136 | openmc_data_downloader -l ENDFB-7.1-NNDC -e Li -p neutron photon
137 | ```
138 |
139 | ### Downloading the neutron cross section for elements and an SaB cross sections
140 |
141 | ```bash
142 | openmc_data_downloader -l ENDFB-7.1-NNDC -e Be O -s c_Be_in_BeO
143 | ```
144 |
145 | ## Usage - within a Python environment
146 |
147 | When using the Python API the ```just_in_time_library_generator()``` function
148 | provides similar capabilities to the ```openmc_data_downloader``` terminal
149 | command. With one key difference being that ```just_in_time_library_generator()```
150 | sets the ```OPENMC_CROSS_SECTIONS``` environmental variable to point to the
151 | newly created cross_sections.xml by default.
152 |
153 | ### Downloading the isotopes present in an OpenMC material
154 |
155 | ```python
156 | import openmc
157 | import openmc_data_downloader as odd
158 |
159 | mat1 = openmc.Material()
160 | mat1.add_element('Fe', 0.95)
161 | mat1.add_element('C', 0.05)
162 |
163 | mats = openmc.Materials([mat1])
164 |
165 | odd.download_cross_section_data(
166 | mats,
167 | libraries=["FENDL-3.1d"],
168 | set_OPENMC_CROSS_SECTIONS=True,
169 | particles=["neutron"],
170 | )
171 | ```
172 |
173 | ### Downloading the isotopes present in an OpenMC material from two libraries but with a preference for ENDF/B 7.1 NNDC library over TENDL 2019
174 |
175 | ```python
176 | import openmc
177 | import openmc_data_downloader as odd
178 |
179 | mat1 = openmc.Material()
180 | mat1.add_element('Fe', 0.95)
181 | mat1.add_element('C', 0.05)
182 |
183 | mats = openmc.Materials([mat1])
184 |
185 | odd.download_cross_section_data(
186 | mats,
187 | libraries=['ENDFB-7.1-NNDC', 'TENDL-2019'],
188 | set_OPENMC_CROSS_SECTIONS=True,
189 | particles=["neutron"],
190 | )
191 | ```
192 |
193 |
194 | ### Downloading neutron cross sections for a material with an SaB
195 |
196 | ```python
197 | import openmc
198 | import openmc_data_downloader as odd
199 |
200 | my_mat = openmc.Material()
201 | my_mat.add_element('Be', 0.5)
202 | my_mat.add_element('O', 0.5)
203 | my_mat.add_s_alpha_beta('Be_in_BeO')
204 |
205 | mats = openmc.Materials([my_mat])
206 |
207 | odd.download_cross_section_data(
208 | mats,
209 | libraries=['ENDFB-7.1-NNDC', 'TENDL-2019'],
210 | set_OPENMC_CROSS_SECTIONS=True,
211 | particles=["neutron"],
212 | )
213 | ```
214 |
215 | ### Downloading photon and neutron cross sections for isotopes and elements from the TENDL 2019 library
216 |
217 | ```python
218 | import openmc
219 | import openmc_data_downloader as odd
220 |
221 | mat1 = openmc.Material()
222 | mat1.add_element('Fe', 0.95)
223 | mat1.add_element('C', 0.05)
224 |
225 | mats = openmc.Materials([mat1])
226 |
227 | odd.download_cross_section_data(
228 | mats,
229 | libraries=['ENDFB-7.1-NNDC', 'TENDL-2019'],
230 | set_OPENMC_CROSS_SECTIONS=True,
231 | particles=["neutron", "photon"],
232 | )
233 | ```
234 |
--------------------------------------------------------------------------------
/conda/conda_build_config.yaml:
--------------------------------------------------------------------------------
1 | python:
2 | - 3.10
3 | - 3.9
4 | - 3.8
5 | - 3.7
6 |
--------------------------------------------------------------------------------
/conda/meta.yaml:
--------------------------------------------------------------------------------
1 | {% set name = "openmc_data_downloader" %}
2 |
3 | package:
4 | name: "{{ name|lower }}"
5 | # conda package version tag is obtained from the git release version tag
6 | version: {{ GIT_DESCRIBE_TAG }}
7 |
8 | source:
9 | path: ..
10 |
11 | build:
12 | number: 0
13 | script: python -m pip install --no-deps --ignore-installed .
14 |
15 | requirements:
16 | build:
17 | - python {{ python }}
18 | - setuptools>=65.4.0
19 | - setuptools_scm[toml]>=7.0.5
20 | run:
21 | - python
22 | - pandas
23 | - retry
24 | - openmc
25 |
26 | test:
27 | imports:
28 | - openmc_data_downloader
29 | requires:
30 | - pytest
31 | source_files:
32 | - tests/
33 | commands:
34 | - pytest tests/test_command_line_usage.py
35 | - pytest tests/test_functions.py
36 | # test_use_in_openmc.py skipped for now as test is failing for upstream bug
37 |
38 | about:
39 | home: "https://github.com/openmc-data-storage/openmc_data_downloader"
40 | license: MIT
41 | license_family: MIT
42 | license_file: LICENSE
43 | doc_url: https://github.com/openmc-data-storage/openmc_data_downloader
44 | dev_url: https://github.com/openmc-data-storage/openmc_data_downloader
45 | summary: openmc_data_downloader - A Python package for downloading h5 cross section files for use in OpenMC.
46 |
47 | extra:
48 | recipe-maintainers:
49 | - shimwell
50 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [build-system]
2 | requires = [
3 | "setuptools >= 65.5.0",
4 | "setuptools_scm[toml] >= 7.0.5",
5 | ]
6 | build-backend = "setuptools.build_meta"
7 |
8 |
9 | [project]
10 | name = "openmc_data_downloader"
11 | authors = [
12 | { name="Jonathan Shimwell", email="mail@jshimwell.com" },
13 | ]
14 | license = {file = "LICENSE"}
15 | description = "A tool for selectively downloading h5 files for specified isotopes / elements from your libraries of choice"
16 | readme = "README.md"
17 | requires-python = ">=3.8"
18 | keywords = ["openmc", "nuclear", "data", "download", "process", "cross", "section"]
19 | classifiers = [
20 | "Programming Language :: Python :: 3",
21 | "License :: OSI Approved :: MIT License",
22 | "Operating System :: OS Independent",
23 | ]
24 | dependencies = [
25 | "pandas",
26 | "retry"
27 | ]
28 | dynamic = ["version"]
29 |
30 | [tool.setuptools_scm]
31 | write_to = "src/_version.py"
32 |
33 |
34 | [project.optional-dependencies]
35 | tests = [
36 | "pytest"
37 | ]
38 |
39 | [project.urls]
40 | "Homepage" = "https://github.com/fusion-energy/openmc_data_downloader"
41 | "Bug Tracker" = "https://github.com/fusion-energy/openmc_data_downloader/issues"
42 |
43 | [tool.setuptools]
44 | package-dir = {"" = "src"}
45 |
46 | [project.scripts]
47 | openmc_data_downloader = "openmc_data_downloader.terminal_cmd:main"
48 |
49 | [tool.setuptools.package-data]
50 | openmc_data_downloader = ["*.xml"]
51 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 |
2 | pandas
3 | retry
4 | # openmc is optional, but not avaialbe via pip
5 |
--------------------------------------------------------------------------------
/src/openmc_data_downloader/__init__.py:
--------------------------------------------------------------------------------
1 | try:
2 | # this works for python 3.7 and lower
3 | from importlib.metadata import version, PackageNotFoundError
4 | except (ModuleNotFoundError, ImportError):
5 | # this works for python 3.8 and higher
6 | from importlib_metadata import version, PackageNotFoundError
7 | try:
8 | __version__ = version("openmc_data_downloader")
9 | except PackageNotFoundError:
10 | from setuptools_scm import get_version
11 |
12 | __version__ = get_version(root="..", relative_to=__file__)
13 |
14 | __all__ = ["__version__"]
15 |
16 | from .cross_sections_directory import *
17 | from .utils import *
18 |
--------------------------------------------------------------------------------
/src/openmc_data_downloader/cross_sections_directory.py:
--------------------------------------------------------------------------------
1 | import re
2 | import xml.etree.ElementTree as ET
3 | from pathlib import Path
4 |
5 | from numpy import nested_iters
6 |
7 | # from https://github.com/openmc-dev/openmc/blob/develop/openmc/data/data.py
8 | # remove when pip install openmc via PyPi is available
9 | NATURAL_ABUNDANCE = {
10 | "H": ["H1", "H2"],
11 | "He": ["He3", "He4"],
12 | "Li": ["Li6", "Li7"],
13 | "Be": ["Be9"],
14 | "B": ["B10", "B11"],
15 | "C": ["C12", "C13", "C0"], # C0 included for ENDF/B 7.1 NNDC
16 | "N": ["N14", "N15"],
17 | "O": ["O16", "O17", "O18"],
18 | "F": ["F19"],
19 | "Ne": ["Ne20", "Ne21", "Ne22"],
20 | "Na": ["Na23"],
21 | "Mg": ["Mg24", "Mg25", "Mg26"],
22 | "Al": ["Al27"],
23 | "Si": ["Si28", "Si29", "Si30"],
24 | "P": ["P31"],
25 | "S": ["S32", "S33", "S34", "S36"],
26 | "Cl": ["Cl35", "Cl37"],
27 | "Ar": ["Ar36", "Ar38", "Ar40"],
28 | "K": ["K39", "K40", "K41"],
29 | "Ca": ["Ca40", "Ca42", "Ca43", "Ca44", "Ca46", "Ca48"],
30 | "Sc": ["Sc45"],
31 | "Ti": ["Ti46", "Ti47", "Ti48", "Ti49", "Ti50"],
32 | "V": ["V50", "V51"],
33 | "Cr": ["Cr50", "Cr52", "Cr53", "Cr54"],
34 | "Mn": ["Mn55"],
35 | "Fe": ["Fe54", "Fe56", "Fe57", "Fe58"],
36 | "Co": ["Co59"],
37 | "Ni": ["Ni58", "Ni60", "Ni61", "Ni62", "Ni64"],
38 | "Cu": ["Cu63", "Cu65"],
39 | "Zn": ["Zn64", "Zn66", "Zn67", "Zn68", "Zn70"],
40 | "Ga": ["Ga69", "Ga71"],
41 | "Ge": ["Ge70", "Ge72", "Ge73", "Ge74", "Ge76"],
42 | "As": ["As75"],
43 | "Se": ["Se74", "Se76", "Se77", "Se78", "Se80", "Se82"],
44 | "Br": ["Br79", "Br81"],
45 | "Kr": ["Kr78", "Kr80", "Kr82", "Kr83", "Kr84", "Kr86"],
46 | "Rb": ["Rb85", "Rb87"],
47 | "Sr": ["Sr84", "Sr86", "Sr87", "Sr88"],
48 | "Y": ["Y89"],
49 | "Zr": ["Zr90", "Zr91", "Zr92", "Zr94", "Zr96"],
50 | "Nb": ["Nb93"],
51 | "Mo": ["Mo92", "Mo94", "Mo95", "Mo96", "Mo97", "Mo98", "Mo100"],
52 | "Ru": ["Ru96", "Ru98", "Ru99", "Ru100", "Ru101", "Ru102", "Ru104"],
53 | "Rh": ["Rh103"],
54 | "Pd": ["Pd102", "Pd104", "Pd105", "Pd106", "Pd108", "Pd110"],
55 | "Ag": ["Ag107", "Ag109"],
56 | "Cd": ["Cd106", "Cd108", "Cd110", "Cd111", "Cd112", "Cd113", "Cd114", "Cd116"],
57 | "In": ["In113", "In115"],
58 | "Sn": [
59 | "Sn112",
60 | "Sn114",
61 | "Sn115",
62 | "Sn116",
63 | "Sn117",
64 | "Sn118",
65 | "Sn119",
66 | "Sn120",
67 | "Sn122",
68 | "Sn124",
69 | ],
70 | "Sb": ["Sb121", "Sb123"],
71 | "Te": ["Te120", "Te122", "Te123", "Te124", "Te125", "Te126", "Te128", "Te130"],
72 | "I": ["I127"],
73 | "Xe": [
74 | "Xe124",
75 | "Xe126",
76 | "Xe128",
77 | "Xe129",
78 | "Xe130",
79 | "Xe131",
80 | "Xe132",
81 | "Xe134",
82 | "Xe136",
83 | ],
84 | "Cs": ["Cs133"],
85 | "Ba": ["Ba130", "Ba132", "Ba134", "Ba135", "Ba136", "Ba137", "Ba138"],
86 | "La": ["La138", "La139"],
87 | "Ce": ["Ce136", "Ce138", "Ce140", "Ce142"],
88 | "Pr": ["Pr141"],
89 | "Nd": ["Nd142", "Nd143", "Nd144", "Nd145", "Nd146", "Nd148", "Nd150"],
90 | "Sm": ["Sm144", "Sm147", "Sm148", "Sm149", "Sm150", "Sm152", "Sm154"],
91 | "Eu": ["Eu151", "Eu153"],
92 | "Gd": ["Gd152", "Gd154", "Gd155", "Gd156", "Gd157", "Gd158", "Gd160"],
93 | "Tb": ["Tb159"],
94 | "Dy": ["Dy156", "Dy158", "Dy160", "Dy161", "Dy162", "Dy163", "Dy164"],
95 | "Ho": ["Ho165"],
96 | "Er": ["Er162", "Er164", "Er166", "Er167", "Er168", "Er170"],
97 | "Tm": ["Tm169"],
98 | "Yb": ["Yb168", "Yb170", "Yb171", "Yb172", "Yb173", "Yb174", "Yb176"],
99 | "Lu": ["Lu175", "Lu176"],
100 | "Hf": ["Hf174", "Hf176", "Hf177", "Hf178", "Hf179", "Hf180"],
101 | "Ta": ["Ta180", "Ta181"],
102 | "W": ["W180", "W182", "W183", "W184", "W186"],
103 | "Re": ["Re185", "Re187"],
104 | "Os": ["Os184", "Os186", "Os187", "Os188", "Os189", "Os190", "Os192"],
105 | "Ir": ["Ir191", "Ir193"],
106 | "Pt": ["Pt190", "Pt192", "Pt194", "Pt195", "Pt196", "Pt198"],
107 | "Au": ["Au197"],
108 | "Hg": ["Hg196", "Hg198", "Hg199", "Hg200", "Hg201", "Hg202", "Hg204"],
109 | "Tl": ["Tl203", "Tl205"],
110 | "Pb": ["Pb204", "Pb206", "Pb207", "Pb208"],
111 | "Bi": ["Bi209"],
112 | "Th": ["Th230", "Th232"],
113 | "Pa": ["Pa231"],
114 | "U": ["U234", "U235", "U238"],
115 | "Ac": [], # no stable isotopes
116 | "Am": [], # no stable isotopes
117 | "At": [], # no stable isotopes
118 | "Bk": [], # no stable isotopes
119 | "Cf": [], # no stable isotopes
120 | "Cm": [], # no stable isotopes
121 | "Es": [], # no stable isotopes
122 | "Fm": [], # no stable isotopes
123 | "Fr": [], # no stable isotopes
124 | "Np": [], # no stable isotopes
125 | "Pm": [], # no stable isotopes
126 | "Po": [], # no stable isotopes
127 | "Pu": [], # no stable isotopes
128 | "Ra": [], # no stable isotopes
129 | "Rn": [], # no stable isotopes
130 | "Tc": [], # no stable isotopes
131 | }
132 |
133 |
134 | def zaid_to_isotope(zaid: str) -> str:
135 | """converts an isotope into a zaid e.g. 003006 -> Li6"""
136 | a = str(zaid)[-3:]
137 | z = str(zaid)[:-3]
138 | symbol = ATOMIC_SYMBOL[int(z)]
139 | return symbol + str(int(a))
140 |
141 |
142 | def get_isotopes_or_elements_from_xml(filename, particle_type):
143 | if particle_type == "sab":
144 | particle_type = "thermal"
145 | tree = ET.parse(Path(__file__).parent / filename)
146 | root = tree.getroot()
147 | neutron_isotopes = []
148 | for elem in root:
149 | if elem.attrib["type"] == particle_type:
150 | neutron_isotopes.append(elem.attrib["materials"])
151 | if len(neutron_isotopes) == 0:
152 | raise ValueError(f"no {particle_type} were found in {filename}")
153 | return neutron_isotopes
154 |
155 |
156 | def core_dict_entry(library, name, base_url):
157 | entry = {}
158 | entry["library"] = library
159 | entry["remote_file"] = name + ".h5"
160 | entry["url"] = base_url + entry["remote_file"]
161 | entry["local_file"] = entry["library"] + "_" + entry["remote_file"]
162 | return entry
163 |
164 |
165 | def populate_neutron_cross_section_list(isotopes, base_url, library):
166 | xs_info = []
167 | for isotope in isotopes:
168 | entry = core_dict_entry(library, isotope, base_url)
169 | entry["particle"] = "neutron"
170 | entry["isotope"] = isotope
171 | entry["element"] = re.split(r"(\d+)", entry["isotope"])[0]
172 | xs_info.append(entry)
173 | return xs_info
174 |
175 |
176 | def populate_sab_cross_section_list(sabs, base_url, library):
177 | xs_info = []
178 | for sab in sabs:
179 | entry = core_dict_entry(library, sab, base_url)
180 | entry["particle"] = "sab"
181 | entry["sab"] = sab
182 | xs_info.append(entry)
183 | return xs_info
184 |
185 |
186 | def populate_photon_cross_section_list(elements, base_url, library):
187 | xs_info = []
188 | for element in elements:
189 | entry = core_dict_entry(library, element, base_url)
190 | entry["particle"] = "photon"
191 | entry["element"] = element
192 | xs_info.append(entry)
193 | return xs_info
194 |
195 |
196 | def get_isotopes_or_elements_info_from_xml(particle_type, library):
197 | base_url = lib_to_base_url[(library, particle_type)]
198 | filename = lib_to_xml[library]
199 |
200 | isotopes_or_elements = get_isotopes_or_elements_from_xml(filename, particle_type)
201 |
202 | if particle_type == "photon":
203 | info = populate_photon_cross_section_list(
204 | isotopes_or_elements, base_url, library
205 | )
206 |
207 | elif particle_type == "neutron":
208 | info = populate_neutron_cross_section_list(
209 | isotopes_or_elements, base_url, library
210 | )
211 | elif particle_type == "sab":
212 | info = populate_sab_cross_section_list(isotopes_or_elements, base_url, library)
213 | else:
214 | raise ValueError(
215 | f'particle type {particle_type} not supported, acceptable particle types are "neutron" or "photon'
216 | )
217 | return info
218 |
219 |
220 | # {
221 | # 'filename':
222 | # 'particle_type':
223 | # 'base_url':,
224 | # 'library':
225 | # }
226 |
227 | lib_to_xml = {
228 | "FENDL-3.1d": "fendl_3.1d_cross_sections.xml",
229 | "ENDFB-8.0-NNDC": "nndc_8.0_cross_sections.xml",
230 | "ENDFB-7.1-NNDC": "nndc_7.1_cross_sections.xml",
231 | "TENDL-2019": "tendl_2019_cross_sections.xml",
232 | }
233 | lib_to_base_url = {
234 | (
235 | "FENDL-3.1d",
236 | "neutron",
237 | ): "https://github.com/openmc-data-storage/FENDL-3.1d/raw/main/h5_files/neutron/",
238 | (
239 | "FENDL-3.1d",
240 | "photon",
241 | ): "https://github.com/openmc-data-storage/FENDL-3.1d/raw/main/h5_files/photon/",
242 | (
243 | "ENDFB-8.0-NNDC",
244 | "neutron",
245 | ): "https://github.com/openmc-data-storage/ENDF-B-VIII.0-NNDC/raw/main/h5_files/neutron/",
246 | (
247 | "ENDFB-8.0-NNDC",
248 | "sab",
249 | ): "https://github.com/openmc-data-storage/ENDF-B-VIII.0-NNDC/raw/main/h5_files/neutron/",
250 | (
251 | "ENDFB-8.0-NNDC",
252 | "photon",
253 | ): "https://github.com/openmc-data-storage/ENDF-B-VIII.0-NNDC/raw/main/h5_files/photon/",
254 | (
255 | "ENDFB-7.1-NNDC",
256 | "neutron",
257 | ): "https://github.com/openmc-data-storage/ENDF-B-VII.1-NNDC/raw/main/h5_files/neutron/",
258 | (
259 | "ENDFB-7.1-NNDC",
260 | "sab",
261 | ): "https://github.com/openmc-data-storage/ENDF-B-VII.1-NNDC/raw/main/h5_files/neutron/",
262 | (
263 | "ENDFB-7.1-NNDC",
264 | "photon",
265 | ): "https://github.com/openmc-data-storage/ENDF-B-VII.1-NNDC/raw/main/h5_files/photon/",
266 | (
267 | "TENDL-2019",
268 | "neutron",
269 | ): "https://github.com/openmc-data-storage/TENDL-2019/raw/main/h5_files/",
270 | }
271 |
272 | neutron_xs_info = []
273 | neutron_xs_info += get_isotopes_or_elements_info_from_xml("neutron", "TENDL-2019")
274 | neutron_xs_info += get_isotopes_or_elements_info_from_xml("neutron", "ENDFB-7.1-NNDC")
275 | neutron_xs_info += get_isotopes_or_elements_info_from_xml("neutron", "FENDL-3.1d")
276 | neutron_xs_info += get_isotopes_or_elements_info_from_xml("neutron", "ENDFB-8.0-NNDC")
277 |
278 | photon_xs_info = []
279 | photon_xs_info += get_isotopes_or_elements_info_from_xml(
280 | "photon",
281 | "ENDFB-7.1-NNDC",
282 | )
283 | photon_xs_info += get_isotopes_or_elements_info_from_xml("photon", "FENDL-3.1d")
284 | photon_xs_info += get_isotopes_or_elements_info_from_xml("photon", "ENDFB-8.0-NNDC")
285 |
286 | sab_xs_info = []
287 | sab_xs_info += get_isotopes_or_elements_info_from_xml(
288 | "sab",
289 | "ENDFB-7.1-NNDC",
290 | )
291 | sab_xs_info += get_isotopes_or_elements_info_from_xml("sab", "ENDFB-8.0-NNDC")
292 |
293 | ATOMIC_SYMBOL = {
294 | 0: "n",
295 | 1: "H",
296 | 2: "He",
297 | 3: "Li",
298 | 4: "Be",
299 | 5: "B",
300 | 6: "C",
301 | 7: "N",
302 | 8: "O",
303 | 9: "F",
304 | 10: "Ne",
305 | 11: "Na",
306 | 12: "Mg",
307 | 13: "Al",
308 | 14: "Si",
309 | 15: "P",
310 | 16: "S",
311 | 17: "Cl",
312 | 18: "Ar",
313 | 19: "K",
314 | 20: "Ca",
315 | 21: "Sc",
316 | 22: "Ti",
317 | 23: "V",
318 | 24: "Cr",
319 | 25: "Mn",
320 | 26: "Fe",
321 | 27: "Co",
322 | 28: "Ni",
323 | 29: "Cu",
324 | 30: "Zn",
325 | 31: "Ga",
326 | 32: "Ge",
327 | 33: "As",
328 | 34: "Se",
329 | 35: "Br",
330 | 36: "Kr",
331 | 37: "Rb",
332 | 38: "Sr",
333 | 39: "Y",
334 | 40: "Zr",
335 | 41: "Nb",
336 | 42: "Mo",
337 | 43: "Tc",
338 | 44: "Ru",
339 | 45: "Rh",
340 | 46: "Pd",
341 | 47: "Ag",
342 | 48: "Cd",
343 | 49: "In",
344 | 50: "Sn",
345 | 51: "Sb",
346 | 52: "Te",
347 | 53: "I",
348 | 54: "Xe",
349 | 55: "Cs",
350 | 56: "Ba",
351 | 57: "La",
352 | 58: "Ce",
353 | 59: "Pr",
354 | 60: "Nd",
355 | 61: "Pm",
356 | 62: "Sm",
357 | 63: "Eu",
358 | 64: "Gd",
359 | 65: "Tb",
360 | 66: "Dy",
361 | 67: "Ho",
362 | 68: "Er",
363 | 69: "Tm",
364 | 70: "Yb",
365 | 71: "Lu",
366 | 72: "Hf",
367 | 73: "Ta",
368 | 74: "W",
369 | 75: "Re",
370 | 76: "Os",
371 | 77: "Ir",
372 | 78: "Pt",
373 | 79: "Au",
374 | 80: "Hg",
375 | 81: "Tl",
376 | 82: "Pb",
377 | 83: "Bi",
378 | 84: "Po",
379 | 85: "At",
380 | 86: "Rn",
381 | 87: "Fr",
382 | 88: "Ra",
383 | 89: "Ac",
384 | 90: "Th",
385 | 91: "Pa",
386 | 92: "U",
387 | 93: "Np",
388 | 94: "Pu",
389 | 95: "Am",
390 | 96: "Cm",
391 | 97: "Bk",
392 | 98: "Cf",
393 | 99: "Es",
394 | 100: "Fm",
395 | 101: "Md",
396 | 102: "No",
397 | 103: "Lr",
398 | 104: "Rf",
399 | 105: "Db",
400 | 106: "Sg",
401 | 107: "Bh",
402 | 108: "Hs",
403 | 109: "Mt",
404 | 110: "Ds",
405 | 111: "Rg",
406 | 112: "Cn",
407 | 113: "Nh",
408 | 114: "Fl",
409 | 115: "Mc",
410 | 116: "Lv",
411 | 117: "Ts",
412 | 118: "Og",
413 | }
414 |
415 |
416 | all_libs = []
417 | for entry in neutron_xs_info:
418 | all_libs.append(entry["library"])
419 |
420 | LIB_OPTIONS = list(set(all_libs))
421 | PARTICLE_OPTIONS = ["neutron", "photon", "sab"]
422 |
423 | nested_list = list(NATURAL_ABUNDANCE.values())
424 |
425 | # should this come from the isotopes available in the xml files
426 | STABLE_ISOTOPE_OPTIONS = [item for sublist in nested_list for item in sublist]
427 |
428 | ALL_ISOTOPE_OPTIONS = []
429 | for xml in [
430 | "tendl_2019_cross_sections.xml",
431 | "nndc_7.1_cross_sections.xml",
432 | "nndc_8.0_cross_sections.xml",
433 | "fendl_3.1d_cross_sections.xml",
434 | ]:
435 | isotopes = get_isotopes_or_elements_from_xml(xml, "neutron")
436 | ALL_ISOTOPE_OPTIONS = ALL_ISOTOPE_OPTIONS + isotopes
437 |
438 | SAB_OPTIONS = []
439 | for xml in [
440 | "nndc_7.1_cross_sections.xml",
441 | "nndc_8.0_cross_sections.xml",
442 | ]:
443 | sabs = get_isotopes_or_elements_from_xml(xml, "sab")
444 | SAB_OPTIONS = SAB_OPTIONS + sabs
445 |
446 | ALL_ISOTOPE_OPTIONS = sorted(list(set(ALL_ISOTOPE_OPTIONS)))
447 |
448 | ALL_ELEMENT_OPTIONS = sorted(
449 | list(set([re.split(r"(\d+)", i)[0] for i in ALL_ISOTOPE_OPTIONS]))
450 | )
451 | STABLE_ELEMENT_OPTIONS = sorted(
452 | list(set([re.split(r"(\d+)", i)[0] for i in STABLE_ISOTOPE_OPTIONS]))
453 | )
454 |
--------------------------------------------------------------------------------
/src/openmc_data_downloader/fendl_3.1d_cross_sections.xml:
--------------------------------------------------------------------------------
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 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
--------------------------------------------------------------------------------
/src/openmc_data_downloader/nndc_7.1_cross_sections.xml:
--------------------------------------------------------------------------------
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 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
--------------------------------------------------------------------------------
/src/openmc_data_downloader/tendl_2019_cross_sections.xml:
--------------------------------------------------------------------------------
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 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
--------------------------------------------------------------------------------
/src/openmc_data_downloader/terminal_cmd.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 |
3 | """
4 | A nuclear data downloading package that facilitates the reproduction of cross
5 | section collections. Use the command line tool or Python API to download the h5
6 | cross sections for just the isotopes / elements that you want. Specify the
7 | preferred nuclear data libraries to use. Automatically avoid duplication and
8 | generation of custom cross_section.xml files
9 | """
10 |
11 | import argparse
12 | from pathlib import Path
13 | import openmc_data_downloader
14 | from openmc_data_downloader.cross_sections_directory import (
15 | lib_to_xml,
16 | NATURAL_ABUNDANCE,
17 | SAB_OPTIONS,
18 | )
19 | import openmc
20 |
21 |
22 | def main():
23 | parser = argparse.ArgumentParser()
24 |
25 | parser.add_argument(
26 | "-l",
27 | "--libraries",
28 | choices=openmc_data_downloader.LIB_OPTIONS,
29 | nargs="*",
30 | help="The nuclear data libraries to search through when searching for \
31 | cross sections. Multiple libaries are acceptable and will be \
32 | preferentially utilized in the order provided",
33 | default=[],
34 | required=True,
35 | )
36 | parser.add_argument(
37 | "-i",
38 | "--isotopes",
39 | nargs="*",
40 | default=[],
41 | help="The isotope or isotopes to download, name of isotope e.g. 'Al27' or keyword 'all' or 'stable'",
42 | )
43 |
44 | parser.add_argument(
45 | "-s",
46 | "--sab",
47 | nargs="*",
48 | default=[],
49 | help="The SaB cross sections to download. Options include "
50 | + " ".join(SAB_OPTIONS),
51 | )
52 |
53 | parser.add_argument(
54 | "-e",
55 | "--elements",
56 | nargs="*",
57 | default=[],
58 | help="The element or elements to download, name of element e.g. 'Al' or keyword 'all' or 'stable'",
59 | )
60 | parser.add_argument(
61 | "-p",
62 | "--particles",
63 | nargs="*",
64 | default=["neutron"],
65 | choices=["neutron", "photon", "sab"],
66 | help="The particle to download",
67 | )
68 | parser.add_argument(
69 | "-m",
70 | "--materials_xml",
71 | nargs="*",
72 | default=[],
73 | help="The filename of the materials.xml file to \
74 | provide cross sections for",
75 | )
76 | parser.add_argument(
77 | "-d",
78 | "--destination",
79 | type=Path,
80 | default=None,
81 | help="Directory to create new library in",
82 | )
83 |
84 | parser.add_argument(
85 | "--overwrite", action="store_true", help="Exiting files will be overwritten"
86 | )
87 |
88 | parser.add_argument(
89 | "--no-overwrite",
90 | action="store_false",
91 | help="Exiting files will not be overwritten",
92 | )
93 |
94 | parser.set_defaults(overwrite=False)
95 | args = parser.parse_args()
96 |
97 | if args.elements == ["all"]:
98 | args.elements = openmc_data_downloader.ALL_ELEMENT_OPTIONS
99 | if args.elements == ["stable"]:
100 | args.elements = openmc_data_downloader.STABLE_ELEMENT_OPTIONS
101 |
102 | if args.isotopes == ["all"]:
103 | args.isotopes = openmc_data_downloader.ALL_ISOTOPE_OPTIONS
104 | if args.isotopes == ["stable"]:
105 | args.isotopes = openmc_data_downloader.STABLE_ISOTOPE_OPTIONS
106 |
107 | mat = openmc.Material()
108 | for isotope in args.isotopes:
109 | mat.add_nuclide(isotope, 1)
110 | for element in args.elements:
111 | # we get the nuclides for the element and add each nuclide
112 | # adding elements expands to nuclides using the cross_sections.xml
113 | # which can fail if the element is not present in the local cross_sections.xml
114 | nuclides = NATURAL_ABUNDANCE[element]
115 | for nuclide in nuclides:
116 | mat.add_nuclide(nuclide, 1)
117 | for sab in args.sab:
118 | mat.add_s_alpha_beta(sab)
119 |
120 | mats = openmc.Materials([mat])
121 |
122 | if args.materials_xml:
123 | for material_xml in args.materials_xml:
124 | mats_from_xml = openmc.Materials.from_xml(material_xml)
125 | mats = mats + mats_from_xml
126 |
127 | mats.download_cross_section_data(
128 | libraries=args.libraries,
129 | destination=args.destination,
130 | particles=args.particles,
131 | set_OPENMC_CROSS_SECTIONS=False,
132 | overwrite=args.overwrite,
133 | )
134 |
135 |
136 | if __name__ == "__main__":
137 | main()
138 |
--------------------------------------------------------------------------------
/src/openmc_data_downloader/utils.py:
--------------------------------------------------------------------------------
1 | import os
2 | import xml.etree.ElementTree as ET
3 | from pathlib import Path
4 | import typing
5 | from typing import List, Optional, Union
6 | from urllib.parse import urlparse
7 | from urllib.request import urlopen
8 | from urllib.error import HTTPError
9 | import pandas as pd
10 | from retry import retry
11 | import openmc
12 |
13 |
14 | from openmc_data_downloader import (
15 | ALL_ISOTOPE_OPTIONS,
16 | STABLE_ISOTOPE_OPTIONS,
17 | ALL_ELEMENT_OPTIONS,
18 | STABLE_ELEMENT_OPTIONS,
19 | LIB_OPTIONS,
20 | PARTICLE_OPTIONS,
21 | neutron_xs_info,
22 | photon_xs_info,
23 | sab_xs_info,
24 | SAB_OPTIONS,
25 | )
26 |
27 | _BLOCK_SIZE = 16384
28 |
29 |
30 | def set_environmental_variable(cross_section_xml_path: Union[Path, str]) -> None:
31 | if not isinstance(cross_section_xml_path, Path):
32 | cross_section_xml_path = Path(cross_section_xml_path)
33 |
34 | if cross_section_xml_path.is_file() is False:
35 | raise FileNotFoundError(
36 | f"{cross_section_xml_path} was not found, therefore not setting "
37 | "OPENMC_CROSS_SECTIONS environmental variable"
38 | )
39 |
40 | print(f"setting OPENMC_CROSS_SECTIONS to {str(cross_section_xml_path)}")
41 | os.environ["OPENMC_CROSS_SECTIONS"] = str(cross_section_xml_path)
42 | # openmc.config['cross_sections'] = cross_section_xml_path
43 |
44 |
45 | def expand_materials_to_isotopes(materials: openmc.Materials):
46 | if not isinstance(materials, openmc.Materials):
47 | raise ValueError("materials argument must be an openmc.Materials() object")
48 | if len(materials) == 0:
49 | raise ValueError(
50 | "There are no openmc.Material() entries within the openmc.Materials() object"
51 | )
52 |
53 | isotopes_from_materials = []
54 | for material in materials:
55 | for nuc in material.nuclides:
56 | isotopes_from_materials.append(nuc.name)
57 |
58 | return sorted(list(set(isotopes_from_materials)))
59 |
60 |
61 | def expand_materials_to_sabs(materials: openmc.Materials):
62 | if not isinstance(materials, openmc.Materials):
63 | raise ValueError("materials argument must be an openmc.Materials() object")
64 | if len(materials) == 0:
65 | raise ValueError(
66 | "There are no openmc.Material() entries within the openmc.Materials() object"
67 | )
68 |
69 | sabs_from_materials = []
70 | for material in materials:
71 | for sab in material._sab:
72 | sabs_from_materials.append(sab[0])
73 |
74 | return sorted(list(set(sabs_from_materials)))
75 |
76 |
77 | def expand_materials_to_elements(materials: openmc.Materials):
78 | if not isinstance(materials, openmc.Materials):
79 | raise ValueError("materials argument must be an openmc.Materials() object")
80 | if len(materials) == 0:
81 | raise ValueError(
82 | "There are no openmc.Material() entries within the openmc.Materials() object"
83 | )
84 |
85 | elements_from_materials = []
86 | for material in materials:
87 | elements = material.get_elements()
88 | elements_from_materials = elements_from_materials + elements
89 |
90 | return list(set(elements_from_materials))
91 |
92 |
93 | def download_cross_section_data(
94 | materials: openmc.Materials,
95 | libraries: typing.Iterable[str] = (
96 | "TENDL-2019",
97 | "ENDFB-7.1-NNDC",
98 | "ENDFB-8.0-NNDC",
99 | "FENDL-3.1d",
100 | ),
101 | destination: Union[str, Path] = None,
102 | particles: Optional[typing.Iterable[str]] = ("neutron", "photon"),
103 | set_OPENMC_CROSS_SECTIONS: bool = True,
104 | overwrite: bool = False,
105 | ) -> str:
106 | """Download cross section data for materials
107 |
108 | Args:
109 | materials: Materials for which to download cross section data
110 | libraries: list of libraries from which to download cross section data.
111 | destination: Specifies a folder location to save the downloaded files. By
112 | default, the files are saved in the current working directory.
113 | particles: list of particles for which to download cross section data ("neutron", "photon")
114 | set_OPENMC_CROSS_SECTIONS: Set the OPENMC_CROSS_SECTIONS environment variable
115 | overwrite: if set to True will overwrite any existing files
116 |
117 | Raises:
118 | ValueError: If the particle is not one of the following: "neutron", "photon"
119 |
120 | Returns:
121 | Path to the cross sections xml file
122 | """
123 |
124 | for entry in particles:
125 | if entry not in PARTICLE_OPTIONS:
126 | raise ValueError(
127 | f"The particle must be one of the following {PARTICLE_OPTIONS}. Not {entry}"
128 | )
129 |
130 | dataframe = pd.DataFrame()
131 |
132 | if "neutron" in particles:
133 | isotopes = expand_materials_to_isotopes(materials)
134 | # filters the large dataframe of all isotopes into just the ones you want
135 | dataframe_isotopes_xs = identify_isotopes_to_download(
136 | libraries=libraries,
137 | isotopes=isotopes,
138 | )
139 | dataframe = pd.concat([dataframe, dataframe_isotopes_xs])
140 |
141 | if "photon" in particles:
142 | elements = expand_materials_to_elements(materials)
143 | dataframe_elements_xs = identify_elements_to_download(
144 | libraries=libraries,
145 | elements=elements,
146 | )
147 | dataframe = pd.concat([dataframe, dataframe_elements_xs])
148 |
149 | sabs = expand_materials_to_sabs(materials)
150 | if len(sabs) > 0:
151 | dataframe_sabs_xs = identify_sabs_to_download(
152 | libraries=libraries,
153 | sabs=sabs,
154 | )
155 | dataframe = pd.concat([dataframe, dataframe_sabs_xs])
156 | print("dataframe_sabs_xs", dataframe_sabs_xs)
157 |
158 | print(dataframe)
159 |
160 | download_data_frame_of(
161 | dataframe=dataframe, destination=destination, overwrite=overwrite
162 | )
163 |
164 | cross_section_xml_path = create_cross_sections_xml(dataframe, destination)
165 |
166 | if set_OPENMC_CROSS_SECTIONS is True:
167 | materials.cross_sections = cross_section_xml_path
168 | # making the cross section xml requires openmc and returns None if
169 | # openmc is not found.
170 | if cross_section_xml_path is not None:
171 | set_environmental_variable(cross_section_xml_path)
172 | else:
173 | print(
174 | "Set your $OPENMC_CROSS_SECTIONS environmental variable to "
175 | f"{cross_section_xml_path} to use this custom library"
176 | )
177 |
178 | return cross_section_xml_path
179 |
180 |
181 | def download_single_file(
182 | url: str,
183 | output_filename: Union[str, Path] = None,
184 | destination: Union[str, Path] = None,
185 | overwrite: bool = True,
186 | ) -> Path:
187 | """Download file from a URL
188 |
189 | Arguments:
190 | url: URL from which to download
191 | destination: Specifies a folder location to save the downloaded file
192 |
193 | Returns
194 | Name of file written locally
195 | """
196 |
197 | if output_filename is not None:
198 | if not isinstance(output_filename, Path):
199 | output_filename = Path(output_filename)
200 |
201 | if destination is not None:
202 | if not isinstance(destination, Path):
203 | destination = Path(destination)
204 |
205 | if output_filename is None:
206 | local_path = Path(Path(urlparse(url).path).name)
207 | else:
208 | local_path = output_filename
209 |
210 | if destination is not None:
211 | Path(destination).mkdir(parents=True, exist_ok=True)
212 | local_path = destination / local_path
213 |
214 | if overwrite is False and local_path.is_file():
215 | print(f"Skipping {local_path}, already downloaded")
216 | return local_path
217 |
218 | local_path = download_url_in_chuncks(url, local_path)
219 |
220 | return local_path
221 |
222 |
223 | @retry(HTTPError, tries=3)
224 | def download_url_in_chuncks(url, local_path):
225 | with urlopen(url) as response:
226 | # Copy file to disk in chunks
227 | print("Downloading {}... ".format(local_path), end="")
228 |
229 | with open(local_path, "wb") as fh:
230 | while True:
231 | chunk = response.read(_BLOCK_SIZE)
232 | if not chunk:
233 | break
234 | fh.write(chunk)
235 | print("")
236 |
237 | return local_path
238 |
239 |
240 | def download_data_frame_of(
241 | dataframe: pd.DataFrame, destination: Union[str, Path], overwrite: bool = True
242 | ):
243 | local_files = []
244 | for index, row in dataframe.iterrows():
245 | local_file = download_single_file(
246 | url=row["url"],
247 | output_filename=row["local_file"],
248 | destination=destination,
249 | overwrite=overwrite,
250 | )
251 | local_files.append(local_file)
252 |
253 | return local_files
254 |
255 |
256 | def create_cross_sections_xml(
257 | dataframe: pd.DataFrame, destination: Union[str, Path]
258 | ) -> str:
259 | library = openmc.data.DataLibrary()
260 | for index, row in dataframe.iterrows():
261 | if destination is None:
262 | library.register_file(Path(row["local_file"]))
263 | else:
264 | library.register_file(Path(destination) / Path(row["local_file"]))
265 | if destination is None:
266 | library.export_to_xml("cross_sections.xml")
267 | cross_sections_xml_path = "cross_sections.xml"
268 | else:
269 | if not isinstance(destination, Path):
270 | destination = Path(destination)
271 | destination.mkdir(parents=True, exist_ok=True)
272 | library.export_to_xml(destination / "cross_sections.xml")
273 | cross_sections_xml_path = str(destination / "cross_sections.xml")
274 |
275 | absolute_path = str(Path(cross_sections_xml_path).absolute())
276 | print(f"written cross sections xml file to {absolute_path}")
277 |
278 | return absolute_path
279 |
280 |
281 | def identify_sabs_to_download(
282 | libraries: typing.Tuple[str],
283 | sabs: typing.Tuple[str],
284 | ):
285 | if sabs == []:
286 | return pd.DataFrame()
287 | elif sabs == "all" or sabs == ["all"]:
288 | sabs = SAB_OPTIONS
289 | elif sabs == "stable" or sabs == ["stable"]:
290 | sabs = SAB_OPTIONS # todo check they are all stable, perhaps not UO2
291 |
292 | if len(libraries) == 0:
293 | raise ValueError(
294 | "At least one library must be selected, options are", LIB_OPTIONS
295 | )
296 |
297 | for sab in sabs:
298 | if sab not in SAB_OPTIONS:
299 | raise ValueError(
300 | f"Sab passing in {sab} not found in available names {SAB_OPTIONS}"
301 | )
302 |
303 | priority_dict = {}
304 | for counter, entry in enumerate(libraries):
305 | if entry not in LIB_OPTIONS:
306 | raise ValueError(
307 | f"The library must be one of the following {LIB_OPTIONS}. Not {entry}."
308 | )
309 |
310 | priority_dict[entry] = counter + 1
311 |
312 | print("Searching libraries with the following priority", priority_dict)
313 |
314 | # Tried to removed this dict to dataframe conversion out of the function
315 | # and into the initialization of the package but this resulted in
316 | # a SettingwithCopyWarning which can be fixed and understood here
317 | # https://www.dataquest.io/blog/settingwithcopywarning/
318 | xs_info_df = pd.DataFrame.from_dict(sab_xs_info)
319 |
320 | is_library = xs_info_df["library"].isin(libraries)
321 | print("Sab found matching library requirements", is_library.values.sum())
322 |
323 | is_particle = xs_info_df["particle"].isin(["sab"])
324 | print("Sab found matching particle requirements", is_particle.values.sum())
325 |
326 | is_sab = xs_info_df["sab"].isin(sabs)
327 | print("Sab found matching isotope requirements", is_sab.values.sum())
328 |
329 | xs_info_df = xs_info_df[(is_sab) & (is_library) & (is_particle)]
330 |
331 | xs_info_df["priority"] = xs_info_df["library"].map(priority_dict)
332 |
333 | xs_info_df = xs_info_df.sort_values(by=["priority"])
334 |
335 | xs_info_df = xs_info_df.drop_duplicates(subset=["sab", "particle"], keep="first")
336 |
337 | # end url is unique so this avoids downloading duplicates of the same file
338 | xs_info_df = xs_info_df.drop_duplicates(subset=["url"], keep="first")
339 |
340 | print("Sabs found matching all requirements", len(xs_info_df))
341 |
342 | return xs_info_df
343 |
344 |
345 | def identify_isotopes_to_download(
346 | libraries: typing.Tuple[str],
347 | isotopes: typing.Tuple[str],
348 | ):
349 | if isotopes == []:
350 | return pd.DataFrame()
351 | elif isotopes == "all" or isotopes == ["all"]:
352 | isotopes = ALL_ISOTOPE_OPTIONS
353 | elif isotopes == "stable" or isotopes == ["stable"]:
354 | isotopes = STABLE_ISOTOPE_OPTIONS
355 |
356 | print("isotopes", isotopes)
357 |
358 | if len(libraries) == 0:
359 | raise ValueError(
360 | "At least one library must be selected, options are", LIB_OPTIONS
361 | )
362 |
363 | priority_dict = {}
364 | for counter, entry in enumerate(libraries):
365 | if entry not in LIB_OPTIONS:
366 | raise ValueError(
367 | f"The library must be one of the following {LIB_OPTIONS}. Not {entry}."
368 | )
369 |
370 | priority_dict[entry] = counter + 1
371 |
372 | print("Searching libraries with the following priority", priority_dict)
373 |
374 | # Tried to removed this dict to dataframe conversion out of the function
375 | # and into the initialization of the package but this resulted in
376 | # a SettingwithCopyWarning which can be fixed and understood here
377 | # https://www.dataquest.io/blog/settingwithcopywarning/
378 | xs_info_df = pd.DataFrame.from_dict(neutron_xs_info)
379 |
380 | is_library = xs_info_df["library"].isin(libraries)
381 | print("Isotopes found matching library requirements", is_library.values.sum())
382 |
383 | is_particle = xs_info_df["particle"].isin(["neutron"])
384 | print("Isotopes found matching particle requirements", is_particle.values.sum())
385 |
386 | is_isotope = xs_info_df["isotope"].isin(isotopes)
387 | print("Isotopes found matching isotope requirements", is_isotope.values.sum())
388 |
389 | xs_info_df = xs_info_df[(is_isotope) & (is_library) & (is_particle)]
390 |
391 | xs_info_df["priority"] = xs_info_df["library"].map(priority_dict)
392 |
393 | xs_info_df = xs_info_df.sort_values(by=["priority"])
394 |
395 | xs_info_df = xs_info_df.drop_duplicates(
396 | subset=["isotope", "particle"], keep="first"
397 | )
398 |
399 | # end url is unique so this avoids downloading duplicates of the same file
400 | xs_info_df = xs_info_df.drop_duplicates(subset=["url"], keep="first")
401 |
402 | print("Isotopes found matching all requirements", len(xs_info_df))
403 |
404 | return xs_info_df
405 |
406 |
407 | def identify_elements_to_download(
408 | libraries: typing.Tuple[str],
409 | elements: typing.Tuple[str],
410 | ):
411 | if elements == []:
412 | return pd.DataFrame()
413 | elif elements == "all" or elements == ["all"]:
414 | elements = ALL_ELEMENT_OPTIONS
415 | elif elements == "stable" or elements == ["stable"]:
416 | elements = STABLE_ELEMENT_OPTIONS
417 |
418 | print("elements", elements)
419 |
420 | if len(libraries) == 0:
421 | raise ValueError(
422 | "At least one library must be selected, options are", LIB_OPTIONS
423 | )
424 |
425 | priority_dict = {}
426 | for counter, entry in enumerate(libraries):
427 | if entry not in LIB_OPTIONS:
428 | raise ValueError("The library must be one of the following", LIB_OPTIONS)
429 |
430 | priority_dict[entry] = counter + 1
431 |
432 | print("Searching libraries with the following priority", priority_dict)
433 |
434 | # Tried to removed this dict to dataframe conversion out of the function
435 | # and into the initialization of the package but this resulted in
436 | # a SettingwithCopyWarning which can be fixed and understood here
437 | # https://www.dataquest.io/blog/settingwithcopywarning/
438 | xs_info_df = pd.DataFrame.from_dict(photon_xs_info)
439 |
440 | is_library = xs_info_df["library"].isin(libraries)
441 | print("Elements found matching library requirements", is_library.values.sum())
442 |
443 | is_particle = xs_info_df["particle"].isin(["photon"])
444 | print("Elements found matching particle requirements", is_particle.values.sum())
445 |
446 | is_element = xs_info_df["element"].isin(elements)
447 | print("Elements found matching element requirements", is_element.values.sum())
448 |
449 | xs_info_df = xs_info_df[(is_element) & (is_library) & (is_particle)]
450 |
451 | xs_info_df["priority"] = xs_info_df["library"].map(priority_dict)
452 |
453 | xs_info_df = xs_info_df.sort_values(by=["priority"])
454 |
455 | xs_info_df = xs_info_df.drop_duplicates(
456 | subset=["element", "particle"], keep="first"
457 | )
458 |
459 | # end url is unique so this avoids downloading duplicates of the same file
460 | xs_info_df = xs_info_df.drop_duplicates(subset=["url"], keep="first")
461 |
462 | print("Elements found matching all requirements", len(xs_info_df))
463 |
464 | return xs_info_df
465 |
466 |
467 | openmc.Materials.download_cross_section_data = download_cross_section_data
468 |
--------------------------------------------------------------------------------
/tests/test_command_line_usage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | __author__ = "Jonathan Shimwell"
4 |
5 |
6 | import os
7 | import time
8 | from pathlib import Path
9 |
10 | import openmc
11 | import openmc_data_downloader
12 |
13 |
14 | # def test_single_isotope_download_endf_71_wmp():
15 | # os.system("rm *.h5")
16 | # os.system("openmc_data_downloader -l ENDFB-7.1-WMP -i H1")
17 |
18 | # assert Path("ENDFB-7.1-WMP_H1.h5").is_file()
19 | # assert len(list(Path(".").glob("*.h5"))) == 1
20 |
21 |
22 | def test_single_isotope_download_tendl_2019():
23 | os.system("rm *.h5")
24 | os.system("openmc_data_downloader -l TENDL-2019 -i H1")
25 |
26 | assert Path("TENDL-2019_H1.h5").is_file()
27 | assert len(list(Path(".").glob("*.h5"))) == 1
28 |
29 |
30 | def test_multiple_isotope_download():
31 | os.system("rm *.h5")
32 | os.system("openmc_data_downloader -l TENDL-2019 -i H1 He4")
33 |
34 | assert Path("TENDL-2019_H1.h5").is_file()
35 | assert Path("TENDL-2019_He4.h5").is_file()
36 | assert len(list(Path(".").glob("*.h5"))) == 2
37 |
38 |
39 | def test_correct_files_from_command_line_usage_2():
40 | os.system("rm *.h5")
41 | os.system("openmc_data_downloader -l TENDL-2019 -e F")
42 |
43 | assert Path("TENDL-2019_F19.h5").is_file()
44 | assert len(list(Path(".").glob("*.h5"))) == 1
45 |
46 |
47 | def test_correct_files_from_command_line_usage_3():
48 | os.system("rm *.h5")
49 |
50 | os.system("openmc_data_downloader -l ENDFB-7.1-NNDC -e Co Y")
51 |
52 | assert Path("ENDFB-7.1-NNDC_Co59.h5").is_file()
53 | assert Path("ENDFB-7.1-NNDC_Y89.h5").is_file()
54 | assert len(list(Path(".").glob("*.h5"))) == 2
55 |
56 |
57 | def test_correct_files_from_command_line_usage_4():
58 | os.system("rm *.h5 materials.xml")
59 |
60 | my_mat = openmc.Material()
61 | my_mat.add_element("Nb", 0.5)
62 | my_mat.add_nuclide("Cs133", 0.5)
63 | os.system("rm materials.xml")
64 | openmc.Materials([my_mat]).export_to_xml()
65 |
66 | os.system("openmc_data_downloader -l TENDL-2019 -m materials.xml")
67 |
68 | assert Path("TENDL-2019_Nb93.h5").is_file()
69 | assert Path("TENDL-2019_Cs133.h5").is_file()
70 | assert len(list(Path(".").glob("*.h5"))) == 2
71 |
72 |
73 | def test_correct_files_from_command_line_usage_5():
74 | """Tests downloading with FENDL"""
75 | os.system("rm *.h5 materials.xml")
76 |
77 | my_mat = openmc.Material()
78 | my_mat.add_element("Nb", 0.5)
79 | os.system("rm materials.xml")
80 | openmc.Materials([my_mat]).export_to_xml()
81 |
82 | os.system("openmc_data_downloader -l FENDL-3.1d -m materials.xml -p neutron")
83 |
84 | assert Path("FENDL-3.1d_Nb93.h5").is_file()
85 | assert len(list(Path(".").glob("*.h5"))) == 1
86 |
87 |
88 | def test_correct_files_from_command_line_usage_6():
89 | """Tests downloading with FENDL as priority but without the element in
90 | FENDL"""
91 |
92 | os.system("rm *.h5")
93 |
94 | os.system("openmc_data_downloader -l FENDL-3.1d TENDL-2019 -e Pr")
95 |
96 | assert Path("TENDL-2019_Pr141.h5").is_file()
97 | assert len(list(Path(".").glob("*.h5"))) == 1
98 |
99 |
100 | def test_photon_download_of_isotope_nndc():
101 | """Tests downloading with NNDC photon data and checks it exists"""
102 |
103 | os.system("rm *.h5")
104 |
105 | os.system("openmc_data_downloader -l ENDFB-7.1-NNDC -i He4 -p photon")
106 |
107 | assert Path("ENDFB-7.1-NNDC_He.h5").is_file()
108 | assert len(list(Path(".").glob("*.h5"))) == 1
109 |
110 |
111 | def test_photon_download_of_isotope_fendl():
112 | """Tests downloading with FENDL photon data and checks it exists"""
113 |
114 | os.system("rm *.h5")
115 |
116 | os.system("openmc_data_downloader -l FENDL-3.1d -i He4 -p photon")
117 |
118 | assert Path("FENDL-3.1d_He.h5").is_file()
119 | assert len(list(Path(".").glob("*.h5"))) == 1
120 |
121 |
122 | def test_neutron_and_photon_download_of_isotope_fendl():
123 | """Tests downloading with FENDL photon data and checks it exists"""
124 |
125 | os.system("rm *.h5")
126 |
127 | os.system("openmc_data_downloader -l FENDL-3.1d -i He4 -p photon neutron")
128 |
129 | assert Path("FENDL-3.1d_He.h5").is_file()
130 | assert Path("FENDL-3.1d_He4.h5").is_file()
131 | assert len(list(Path(".").glob("*.h5"))) == 2
132 |
133 |
134 | def test_sab_download_with_endf():
135 | """Tests downloading with FENDL photon data and checks it exists"""
136 |
137 | os.system("rm *.h5")
138 |
139 | os.system(
140 | "openmc_data_downloader -l ENDFB-7.1-NNDC TENDL-2019 -e Be O -s c_Be_in_BeO"
141 | )
142 |
143 | assert Path("ENDFB-7.1-NNDC_Be9.h5").is_file()
144 | assert Path("ENDFB-7.1-NNDC_O16.h5").is_file()
145 | assert Path("ENDFB-7.1-NNDC_O17.h5").is_file()
146 | assert Path("TENDL-2019_O18.h5").is_file()
147 | assert Path("ENDFB-7.1-NNDC_c_Be_in_BeO.h5").is_file()
148 | assert Path("materials.xml").is_file()
149 | assert len(list(Path(".").glob("*.h5"))) == 5
150 |
151 |
152 | def test_download_single_file_with_overwrite_speed_up():
153 | """Checks that downloading with overwrite to False is quicker"""
154 |
155 | current_time = time.time()
156 | os.system("openmc_data_downloader -l ENDFB-7.1-NNDC TENDL-2019 -e Be --overwrite")
157 | time_after_download = time.time()
158 | time_to_download = time_after_download - current_time
159 |
160 | current_time = time.time()
161 | os.system(
162 | "openmc_data_downloader -l ENDFB-7.1-NNDC TENDL-2019 -e Be --no-overwrite",
163 | )
164 | time_after_download = time.time()
165 | time_to_not_download = time_after_download - current_time
166 |
167 | assert time_to_not_download < time_to_download
168 |
--------------------------------------------------------------------------------
/tests/test_cross_sections_directory.py:
--------------------------------------------------------------------------------
1 | from openmc_data_downloader import cross_sections_directory
2 |
3 |
4 | def test_neutron_isotopes():
5 | tendl_2019_xs_neutron_info = (
6 | cross_sections_directory.get_isotopes_or_elements_info_from_xml(
7 | "neutron",
8 | "TENDL-2019",
9 | )
10 | )
11 | assert len(tendl_2019_xs_neutron_info) == 630
12 |
13 | nndc_71_neutron_xs_info = (
14 | cross_sections_directory.get_isotopes_or_elements_info_from_xml(
15 | "neutron",
16 | "ENDFB-7.1-NNDC",
17 | )
18 | )
19 | assert len(nndc_71_neutron_xs_info) == 423
20 |
21 | nndc_80_neutron_xs_info = (
22 | cross_sections_directory.get_isotopes_or_elements_info_from_xml(
23 | "neutron",
24 | "ENDFB-8.0-NNDC",
25 | )
26 | )
27 | assert len(nndc_80_neutron_xs_info) == 556
28 |
29 | fendl_31d_neutron_xs_info = (
30 | cross_sections_directory.get_isotopes_or_elements_info_from_xml(
31 | "neutron",
32 | "FENDL-3.1d",
33 | )
34 | )
35 | assert len(fendl_31d_neutron_xs_info) == 180
36 |
37 |
38 | def test_photon_elements():
39 | nndc_71_photon_xs_info = (
40 | cross_sections_directory.get_isotopes_or_elements_info_from_xml(
41 | "photon",
42 | "ENDFB-7.1-NNDC",
43 | )
44 | )
45 | assert len(nndc_71_photon_xs_info) == 100
46 |
47 | fendl_31d_photon_xs_info = (
48 | cross_sections_directory.get_isotopes_or_elements_info_from_xml(
49 | "photon",
50 | "FENDL-3.1d",
51 | )
52 | )
53 | assert len(fendl_31d_photon_xs_info) == 59
54 |
55 | nndc_80_photon_xs_info = (
56 | cross_sections_directory.get_isotopes_or_elements_info_from_xml(
57 | "photon",
58 | "ENDFB-8.0-NNDC",
59 | )
60 | )
61 | assert len(nndc_80_photon_xs_info) == 100
62 |
63 |
64 | def test_sab():
65 | nndc_71_sab_xs_info = (
66 | cross_sections_directory.get_isotopes_or_elements_info_from_xml(
67 | "sab",
68 | "ENDFB-7.1-NNDC",
69 | )
70 | )
71 | assert len(nndc_71_sab_xs_info) == 20
72 |
73 | nndc_80_sab_xs_info = (
74 | cross_sections_directory.get_isotopes_or_elements_info_from_xml(
75 | "sab",
76 | "ENDFB-8.0-NNDC",
77 | )
78 | )
79 | assert len(nndc_80_sab_xs_info) == 34
80 |
--------------------------------------------------------------------------------
/tests/test_functions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | __author__ = "Jonathan Shimwell"
4 |
5 |
6 | import os
7 | import unittest
8 | import time
9 | import pytest
10 |
11 | import openmc
12 | import pandas as pd
13 | from openmc_data_downloader import (
14 | expand_materials_to_isotopes,
15 | identify_isotopes_to_download,
16 | identify_sabs_to_download,
17 | expand_materials_to_sabs,
18 | download_single_file,
19 | )
20 |
21 |
22 | def test_identify_isotopes_to_download_finds_tendl_neutron():
23 | filtered_df = identify_isotopes_to_download(
24 | libraries=["TENDL-2019"], isotopes=["Be9"]
25 | )
26 | answer_df = pd.DataFrame.from_dict(
27 | {
28 | "library": ["TENDL-2019"],
29 | "remote_file": ["Be9.h5"],
30 | "url": [
31 | "https://github.com/openmc-data-storage/TENDL-2019/raw/main/h5_files/Be9.h5"
32 | ],
33 | "local_file": ["TENDL-2019_Be9.h5"],
34 | "particle": ["neutron"],
35 | "isotope": ["Be9"],
36 | "element": ["Be"],
37 | "priority": [1],
38 | }
39 | )
40 | print(filtered_df)
41 | assert len(filtered_df.values) == 1
42 | assert list(filtered_df.keys()) == list(answer_df.keys())
43 | assert filtered_df.values[0].tolist() == answer_df.values[0].tolist()
44 |
45 | # can't get pandas dataframe comparison to work so resorted to the lists above
46 | # assert_frame_equal(answer_df, filtered_df)
47 |
48 |
49 | def test_identify_isotopes_to_download_finds_fendl_photon():
50 | filtered_df = identify_isotopes_to_download(
51 | libraries=["FENDL-3.1d"], isotopes=["Be9"]
52 | )
53 | answer_df = pd.DataFrame.from_dict(
54 | {
55 | "library": ["FENDL-3.1d"],
56 | "remote_file": ["Be9.h5"],
57 | "url": [
58 | "https://github.com/openmc-data-storage/FENDL-3.1d/raw/main/h5_files/neutron/Be9.h5"
59 | ],
60 | "local_file": ["FENDL-3.1d_Be9.h5"],
61 | "particle": ["neutron"],
62 | "isotope": ["Be9"],
63 | "element": ["Be"],
64 | "priority": [1],
65 | }
66 | )
67 |
68 | assert len(filtered_df.values) == 1
69 | assert list(filtered_df.keys()) == list(answer_df.keys())
70 | assert filtered_df.values[0].tolist() == answer_df.values[0].tolist()
71 |
72 |
73 | def test_identify_isotopes_to_download_finds_fendl_photon_neutron():
74 | filtered_df = identify_isotopes_to_download(
75 | libraries=["FENDL-3.1d"], isotopes=["Be9"]
76 | )
77 | answer_df = pd.DataFrame.from_dict(
78 | {
79 | "library": ["FENDL-3.1d"],
80 | "remote_file": ["Be9.h5"],
81 | "url": [
82 | "https://github.com/openmc-data-storage/FENDL-3.1d/raw/main/h5_files/neutron/Be9.h5",
83 | ],
84 | "local_file": ["FENDL-3.1d_Be9.h5"],
85 | "particle": ["neutron"],
86 | "isotope": ["Be9"],
87 | "element": ["Be"],
88 | "priority": [1],
89 | }
90 | )
91 |
92 | assert len(filtered_df.values) == 1
93 | assert list(filtered_df.keys()) == list(answer_df.keys())
94 | assert filtered_df.values[0].tolist() == answer_df.values[0].tolist()
95 |
96 |
97 | def test_identify_isotopes_to_download_finds_fendl_photon_neutron_multi_isotopes():
98 | filtered_df = identify_isotopes_to_download(
99 | libraries=["FENDL-3.1d"],
100 | isotopes=["Fe56", "Fe57"],
101 | )
102 | answer_df = pd.DataFrame.from_dict(
103 | {
104 | "library": ["FENDL-3.1d", "FENDL-3.1d"],
105 | "remote_file": ["Fe56.h5", "Fe57.h5"],
106 | "url": [
107 | "https://github.com/openmc-data-storage/FENDL-3.1d/raw/main/h5_files/neutron/Fe56.h5",
108 | "https://github.com/openmc-data-storage/FENDL-3.1d/raw/main/h5_files/neutron/Fe57.h5",
109 | ],
110 | "local_file": [
111 | "FENDL-3.1d_Fe56.h5",
112 | "FENDL-3.1d_Fe57.h5",
113 | ],
114 | "particle": ["neutron", "neutron"],
115 | "isotope": ["Fe56", "Fe57"],
116 | "element": ["Fe", "Fe"],
117 | "priority": [1, 1],
118 | }
119 | )
120 |
121 | assert len(filtered_df.values) == 2
122 | assert list(filtered_df.keys()) == list(answer_df.keys())
123 | assert filtered_df.values[0].tolist() == answer_df.values[0].tolist()
124 | assert filtered_df.values[1].tolist() == answer_df.values[1].tolist()
125 |
126 |
127 | def test_identify_isotopes_to_download_all():
128 | filtered_df = identify_isotopes_to_download(
129 | libraries=["FENDL-3.1d"], isotopes=["all"]
130 | )
131 |
132 | assert len(filtered_df.values) == 180
133 |
134 | filtered_df = identify_isotopes_to_download(
135 | libraries=["FENDL-3.1d"], isotopes="all"
136 | )
137 |
138 | assert len(filtered_df.values) == 180
139 |
140 |
141 | def test_expand_materials_from_object_list_with_single_mat():
142 | my_mat = openmc.Material()
143 | my_mat.add_nuclide("Pu239", 3.7047e-2)
144 | my_mat.add_nuclide("Pu240", 1.7512e-3)
145 | my_mat.add_nuclide("Pu241", 1.1674e-4)
146 |
147 | assert expand_materials_to_isotopes(openmc.Materials([my_mat])) == [
148 | "Pu239",
149 | "Pu240",
150 | "Pu241",
151 | ]
152 |
153 |
154 | def test_expand_materials_from_object_with_single_mat():
155 | my_mat = openmc.Material()
156 | my_mat.add_nuclide("Pu239", 3.7047e-2)
157 | my_mat.add_nuclide("Pu240", 1.7512e-3)
158 | my_mat.add_nuclide("Pu241", 1.1674e-4)
159 |
160 | assert expand_materials_to_isotopes(openmc.Materials([my_mat])) == [
161 | "Pu239",
162 | "Pu240",
163 | "Pu241",
164 | ]
165 |
166 |
167 | def test_expand_materials_from_object_list_with_multiple_mat():
168 | my_mat1 = openmc.Material()
169 | my_mat1.add_nuclide("Li6", 0.5)
170 | my_mat1.add_nuclide("Li7", 0.25)
171 |
172 | my_mat2 = openmc.Material()
173 | my_mat2.add_nuclide("Al27", 0.25)
174 |
175 | assert expand_materials_to_isotopes(openmc.Materials([my_mat1, my_mat2])) == [
176 | "Al27",
177 | "Li6",
178 | "Li7",
179 | ]
180 |
181 |
182 | def test_expand_materials_from_object_list_with_openmc_materials():
183 | my_mat1 = openmc.Material()
184 | my_mat1.add_nuclide("Li6", 0.5)
185 | my_mat1.add_nuclide("Li7", 0.25)
186 |
187 | my_mat2 = openmc.Material()
188 | my_mat2.add_nuclide("Al27", 0.25)
189 |
190 | mats = openmc.Materials([my_mat1, my_mat2])
191 |
192 | assert expand_materials_to_isotopes(mats) == ["Al27", "Li6", "Li7"]
193 |
194 |
195 | def test_expand_material_xmls_for_sabs_with_sab():
196 | my_mat = openmc.Material()
197 | my_mat.add_element("Be", 0.5)
198 | my_mat.add_s_alpha_beta("c_Be_in_BeO")
199 | my_mats = openmc.Materials([my_mat])
200 |
201 | assert expand_materials_to_sabs(my_mats) == ["c_Be_in_BeO"]
202 |
203 |
204 | def test_expand_material_xmls_for_sabs_with_two_sab():
205 | my_mat = openmc.Material()
206 | my_mat.add_element("Be", 0.5)
207 | my_mat.add_s_alpha_beta("c_Be_in_BeO")
208 | my_mat.add_s_alpha_beta("c_H_in_H2O")
209 | my_mats = openmc.Materials([my_mat])
210 |
211 | assert expand_materials_to_sabs(my_mats) == [
212 | "c_Be_in_BeO",
213 | "c_H_in_H2O",
214 | ]
215 |
216 |
217 | def test_expand_material_for_sabs_with_two_sab():
218 | my_mat = openmc.Material()
219 | my_mat.add_element("Be", 0.5)
220 | my_mat.add_s_alpha_beta("c_Be_in_BeO")
221 | my_mat.add_s_alpha_beta("c_H_in_H2O")
222 | my_mats = openmc.Materials([my_mat])
223 | assert expand_materials_to_sabs(my_mats) == ["c_Be_in_BeO", "c_H_in_H2O"]
224 |
225 |
226 | def test_expand_material_for_sabs_with_sab():
227 | my_mat = openmc.Material()
228 | my_mat.add_element("Be", 0.5)
229 | my_mat.add_s_alpha_beta("c_H_in_H2O")
230 | my_mats = openmc.Materials([my_mat])
231 |
232 | assert expand_materials_to_sabs(my_mats) == ["c_H_in_H2O"]
233 |
234 |
235 | def test_incorrect_material_enpty():
236 | with pytest.raises(ValueError):
237 | expand_materials_to_sabs("my_mat")
238 |
239 |
240 | def test_incorrect_sab_name():
241 | with pytest.raises(ValueError):
242 | identify_sabs_to_download(libraries=["ENDFB-7.1-NNDC"], sabs=["incorrect name"])
243 |
244 |
245 | def test_incorrect_libraries():
246 | with pytest.raises(ValueError):
247 | identify_sabs_to_download(libraries=[], sabs=["c_Fe56"])
248 |
249 |
250 | def test_incorrect_library_name_for_sab_identifying():
251 | with pytest.raises(ValueError):
252 | identify_sabs_to_download(libraries=["incorrect name"], sabs=["c_Fe56"])
253 |
254 |
255 | def test_library_values_single_entry_list():
256 | isotopes_df = identify_isotopes_to_download(
257 | libraries=["TENDL-2019"], isotopes=["Al27", "Li6"]
258 | )
259 |
260 | assert len(isotopes_df) == 2
261 |
262 |
263 | def test_emplty_isotopes():
264 | empty_df = identify_isotopes_to_download(libraries=["TENDL-2019"], isotopes=[])
265 | assert len(empty_df) == 0
266 | assert isinstance(empty_df, type(pd.DataFrame()))
267 |
268 |
269 | def test_incorrect_library_values_empty():
270 | with pytest.raises(ValueError):
271 | identify_isotopes_to_download(libraries=[], isotopes="Li6")
272 |
273 |
274 | def test_incorrect_library_values_wrong():
275 | with pytest.raises(ValueError):
276 | identify_isotopes_to_download(libraries=["coucou"], isotopes="Li6")
277 |
278 |
279 | def test_incorrect_expand_materials_to_isotopes_with_incorrect_args():
280 | """Checks than an error is raised when incorrect values of materials
281 | are passed"""
282 |
283 | with pytest.raises(ValueError):
284 | expand_materials_to_isotopes(1)
285 |
286 | with pytest.raises(ValueError):
287 | expand_materials_to_isotopes([1, 2, 3])
288 |
289 |
290 | def test_download_single_file_with_overwrite_speed_up():
291 | """Checks that downloading with overwrite to False is quicker"""
292 |
293 | current_time = time.time()
294 | download_single_file(
295 | url="https://github.com/openmc-data-storage/FENDL-3.1d/raw/main/h5_files/photon/Fe.h5",
296 | output_filename="Fe56_new_download.h5",
297 | overwrite=True,
298 | )
299 | time_after_download = time.time()
300 | time_to_download = time_after_download - current_time
301 |
302 | current_time = time.time()
303 | download_single_file(
304 | url="https://github.com/openmc-data-storage/FENDL-3.1d/raw/main/h5_files/photon/Fe.h5",
305 | output_filename="Fe56_new_download.h5",
306 | overwrite=False,
307 | )
308 | time_after_download = time.time()
309 | time_to_not_download = time_after_download - current_time
310 |
311 | assert time_to_not_download < time_to_download
312 |
--------------------------------------------------------------------------------
/tests/test_use_in_openmc.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import os
4 |
5 | from pathlib import Path
6 |
7 | import openmc
8 | import openmc_data_downloader
9 |
10 | import pytest
11 |
12 |
13 | @pytest.mark.parametrize("monkeypatch", [True, False])
14 | def test_materials_download(monkeypatch: bool):
15 | """openmc.Materials are a container for openmc.Material objects. This
16 | test checks that they are handeled correctly"""
17 |
18 | os.system("rm *.h5")
19 | os.system("rm my_custom_nuclear_data_with_materials/*.h5")
20 |
21 | # Define material
22 | my_mat_1 = openmc.Material()
23 | my_mat_1.add_nuclide("Pu239", 3.7047e-2)
24 |
25 | my_mat_2 = openmc.Material()
26 | my_mat_2.add_nuclide("Pu240", 1.7512e-3)
27 | my_mat_2.add_nuclide("As75", 1.3752e-3)
28 | mats = openmc.Materials([my_mat_1, my_mat_2])
29 |
30 | if monkeypatch:
31 | mats.download_cross_section_data(
32 | destination="my_custom_nuclear_data_with_materials",
33 | libraries=["ENDFB-8.0-NNDC"],
34 | set_OPENMC_CROSS_SECTIONS=True,
35 | particles=["neutron"],
36 | )
37 | else:
38 | openmc_data_downloader.download_cross_section_data(
39 | materials=mats,
40 | destination="my_custom_nuclear_data_with_materials",
41 | libraries=["ENDFB-8.0-NNDC"],
42 | set_OPENMC_CROSS_SECTIONS=True,
43 | particles=["neutron"],
44 | )
45 | mats.export_to_xml()
46 |
47 | # Create a sphere of my_mat
48 | surf_1 = openmc.Sphere(r=1)
49 | surf_2 = openmc.Sphere(r=2, boundary_type="vacuum")
50 | cell_1 = openmc.Cell(fill=my_mat_1, region=-surf_1)
51 | cell_2 = openmc.Cell(fill=my_mat_1, region=surf_1 and -surf_2)
52 | openmc.Geometry([cell_1, cell_2]).export_to_xml()
53 |
54 | # Define settings for the simulation
55 | settings = openmc.Settings()
56 | settings.particles = 5
57 | settings.batches = 3
58 | settings.inactive = 0
59 | center = (0.0, 0.0, 0.0)
60 | settings.source = openmc.Source(space=openmc.stats.Point(center))
61 | settings.export_to_xml()
62 |
63 | # this clears the enviromental varible just to be sure that current
64 | # system settings are not being used
65 | try:
66 | del os.environ["OPENMC_CROSS_SECTIONS"]
67 | except KeyError:
68 | # key not found on system
69 | pass
70 |
71 | os.system("echo $OPENMC_CROSS_SECTIONS")
72 | openmc.run()
73 |
74 | assert Path(
75 | "my_custom_nuclear_data_with_materials/ENDFB-8.0-NNDC_Pu239.h5"
76 | ).is_file()
77 | assert Path(
78 | "my_custom_nuclear_data_with_materials/ENDFB-8.0-NNDC_Pu240.h5"
79 | ).is_file()
80 | assert Path(
81 | "my_custom_nuclear_data_with_materials/ENDFB-8.0-NNDC_As75.h5"
82 | ).is_file()
83 |
84 | assert Path("summary.h5").is_file()
85 | assert Path("statepoint.3.h5").is_file()
86 |
87 | assert len(list(Path("my_custom_nuclear_data_with_materials").glob("*.h5"))) == 3
88 |
89 |
90 | def test_simulation_with_destination():
91 | os.system("rm *.h5")
92 | os.system("rm my_custom_nuclear_data_dir/*.h5")
93 |
94 | # Define material
95 | my_mat = openmc.openmc.Material()
96 | my_mat.add_nuclide("Pu239", 3.7047e-2)
97 | my_mat.add_nuclide("Pu240", 1.7512e-3)
98 | my_mat.add_nuclide("As75", 1.3752e-3)
99 | my_mats = openmc.openmc.Materials([my_mat])
100 | my_mats.download_cross_section_data(
101 | destination="my_custom_nuclear_data_dir",
102 | libraries=["TENDL-2019"],
103 | set_OPENMC_CROSS_SECTIONS=True,
104 | )
105 | my_mats.export_to_xml()
106 |
107 | # Create a sphere of my_mat
108 | surf = openmc.Sphere(r=6.3849, boundary_type="vacuum")
109 | main_cell = openmc.Cell(fill=my_mat, region=-surf)
110 | openmc.Geometry([main_cell]).export_to_xml()
111 |
112 | # Define settings for the simulation
113 | settings = openmc.Settings()
114 | settings.particles = 10
115 | settings.batches = 2
116 | settings.inactive = 0
117 | center = (0.0, 0.0, 0.0)
118 | settings.source = openmc.Source(space=openmc.stats.Point(center))
119 | settings.export_to_xml()
120 |
121 | # this clears the enviromental varible just to be sure that current
122 | # system settings are not being used
123 | try:
124 | del os.environ["OPENMC_CROSS_SECTIONS"]
125 | except KeyError:
126 | # key not found on system
127 | pass
128 |
129 | os.system("echo $OPENMC_CROSS_SECTIONS")
130 | openmc.run()
131 |
132 | assert Path("my_custom_nuclear_data_dir/TENDL-2019_Pu239.h5").is_file()
133 | assert Path("my_custom_nuclear_data_dir/TENDL-2019_Pu240.h5").is_file()
134 | assert Path("my_custom_nuclear_data_dir/TENDL-2019_As75.h5").is_file()
135 |
136 | assert Path("summary.h5").is_file()
137 | assert Path("statepoint.2.h5").is_file()
138 |
139 | assert len(list(Path("my_custom_nuclear_data_dir").glob("*.h5"))) == 3
140 |
141 |
142 | def test_photon_simulation_with_single_mat():
143 | os.system("rm *.h5")
144 |
145 | # this clears the enviromental varible just to be sure that current
146 | # system settings are not being used
147 | try:
148 | del os.environ["OPENMC_CROSS_SECTIONS"]
149 | except KeyError:
150 | # key not found on system
151 | pass
152 |
153 | # Define material
154 | my_mat = openmc.Material()
155 | my_mat.add_element("Fe", 1)
156 | my_mats = openmc.Materials([my_mat])
157 | my_mats.export_to_xml()
158 | my_mats.download_cross_section_data(
159 | libraries=["FENDL-3.1d"],
160 | # TODO find out why neutrons are needed here
161 | particles=["photon", "neutron"],
162 | set_OPENMC_CROSS_SECTIONS=True,
163 | )
164 |
165 | # Create a sphere of my_mat
166 | surf = openmc.Sphere(r=6.3849, boundary_type="vacuum")
167 | main_cell = openmc.Cell(fill=my_mat, region=-surf)
168 | openmc.Geometry([main_cell]).export_to_xml()
169 |
170 | # Define settings for the simulation
171 | settings = openmc.Settings()
172 | settings.particles = 10
173 | settings.batches = 2
174 | settings.inactive = 0
175 | settings.run_mode = "fixed source"
176 | settings.photon_transport = True
177 |
178 | source = openmc.Source()
179 | source.space = openmc.stats.Point((0, 0, 0))
180 | source.angle = openmc.stats.Isotropic()
181 | # This is a Co60 source, see the task on sources to understand it
182 | source.energy = openmc.stats.Discrete([1.1732e6], [1.0])
183 | source.particle = "photon"
184 |
185 | settings.source = source
186 | settings.export_to_xml()
187 |
188 | os.system("echo $OPENMC_CROSS_SECTIONS")
189 | openmc.run()
190 |
191 | assert Path("FENDL-3.1d_Fe.h5").is_file()
192 |
193 | assert Path("summary.h5").is_file()
194 | assert Path("statepoint.2.h5").is_file()
195 |
196 | # normally 3 if just photons used
197 | assert len(list(Path(".").glob("*.h5"))) == 7
198 |
199 |
200 | def test_photon_neutron_simulation_with_single_mat():
201 | os.system("rm *.h5")
202 |
203 | # this clears the enviromental varible just to be sure that current
204 | # system settings are not being used
205 | try:
206 | del os.environ["OPENMC_CROSS_SECTIONS"]
207 | except KeyError:
208 | # key not found on system
209 | pass
210 |
211 | # Define material
212 | my_mat = openmc.openmc.Material()
213 | my_mat.add_element("Fe", 1)
214 | my_mats = openmc.openmc.Materials([my_mat])
215 | my_mats.export_to_xml()
216 | my_mats.download_cross_section_data(
217 | libraries=["FENDL-3.1d"],
218 | particles=["neutron", "photon"],
219 | set_OPENMC_CROSS_SECTIONS=True,
220 | )
221 |
222 | # Create a sphere of my_mat
223 | surf = openmc.Sphere(r=6.3849, boundary_type="vacuum")
224 | main_cell = openmc.Cell(fill=my_mat, region=-surf)
225 | openmc.Geometry([main_cell]).export_to_xml()
226 |
227 | # Define settings for the simulation
228 | settings = openmc.Settings()
229 | settings.particles = 10
230 | settings.batches = 2
231 | settings.inactive = 0
232 | settings.photon_transport = True
233 | center = (0.0, 0.0, 0.0)
234 | settings.source = openmc.Source(space=openmc.stats.Point(center))
235 | settings.run_mode = "fixed source"
236 | settings.export_to_xml()
237 |
238 | os.system("echo $OPENMC_CROSS_SECTIONS")
239 | openmc.run()
240 |
241 | assert Path("FENDL-3.1d_Fe54.h5").is_file()
242 | assert Path("FENDL-3.1d_Fe56.h5").is_file()
243 | assert Path("FENDL-3.1d_Fe57.h5").is_file()
244 | assert Path("FENDL-3.1d_Fe58.h5").is_file()
245 | assert Path("FENDL-3.1d_Fe.h5").is_file()
246 |
247 | assert Path("summary.h5").is_file()
248 | assert Path("statepoint.2.h5").is_file()
249 | assert len(list(Path(".").glob("*.h5"))) == 7 # summary and statepoint
250 |
251 |
252 | def test_simulation_with_single_mat():
253 | os.system("rm *.h5")
254 |
255 | # this clears the enviromental varible just to be sure that current
256 | # system settings are not being used
257 | try:
258 | del os.environ["OPENMC_CROSS_SECTIONS"]
259 | except KeyError:
260 | # key not found on system
261 | pass
262 |
263 | # Define material
264 | my_mat = openmc.openmc.Material()
265 | my_mat.add_nuclide("Pu239", 3.7047e-2)
266 | my_mat.add_nuclide("Pu240", 1.7512e-3)
267 | my_mat.add_nuclide("As75", 1.3752e-3)
268 | my_mats = openmc.openmc.Materials([my_mat])
269 | my_mats.export_to_xml()
270 | my_mats.download_cross_section_data(
271 | libraries=["TENDL-2019"],
272 | particles=["neutron"],
273 | set_OPENMC_CROSS_SECTIONS=True,
274 | )
275 |
276 | # Create a sphere of my_mat
277 | surf = openmc.Sphere(r=6.3849, boundary_type="vacuum")
278 | main_cell = openmc.Cell(fill=my_mat, region=-surf)
279 | openmc.Geometry([main_cell]).export_to_xml()
280 |
281 | # Define settings for the simulation
282 | settings = openmc.Settings()
283 | settings.particles = 10
284 | settings.batches = 2
285 | settings.inactive = 0
286 | center = (0.0, 0.0, 0.0)
287 | settings.source = openmc.Source(space=openmc.stats.Point(center))
288 | settings.export_to_xml()
289 |
290 | os.system("echo $OPENMC_CROSS_SECTIONS")
291 | openmc.run()
292 |
293 | assert Path("TENDL-2019_Pu239.h5").is_file()
294 | assert Path("TENDL-2019_Pu240.h5").is_file()
295 | assert Path("TENDL-2019_As75.h5").is_file()
296 |
297 | assert Path("summary.h5").is_file()
298 | assert Path("statepoint.2.h5").is_file()
299 | assert len(list(Path(".").glob("*.h5"))) == 5 # summary and statepoint
300 |
301 |
302 | def test_simulation_with_sab():
303 | os.system("rm *.h5")
304 |
305 | # this clears the enviromental varible just to be sure that current
306 | # system settings are not being used
307 | try:
308 | del os.environ["OPENMC_CROSS_SECTIONS"]
309 | except KeyError:
310 | # key not found on system
311 | pass
312 |
313 | # Define material
314 | my_mat = openmc.Material()
315 | my_mat.add_element("Be", 0.5)
316 | my_mat.add_s_alpha_beta("c_Be_in_BeO")
317 | my_mats = openmc.openmc.Materials([my_mat])
318 | my_mats.export_to_xml()
319 | my_mats.download_cross_section_data(
320 | libraries=["ENDFB-7.1-NNDC"],
321 | particles=["neutron"],
322 | set_OPENMC_CROSS_SECTIONS=True,
323 | )
324 |
325 | # Create a sphere of my_mat
326 | surf = openmc.Sphere(r=6.3849, boundary_type="vacuum")
327 | main_cell = openmc.Cell(fill=my_mat, region=-surf)
328 | openmc.Geometry([main_cell]).export_to_xml()
329 |
330 | # Define settings for the simulation
331 | settings = openmc.Settings()
332 | settings.particles = 10
333 | settings.batches = 2
334 | settings.inactive = 0
335 | center = (0.0, 0.0, 0.0)
336 | settings.source = openmc.Source(space=openmc.stats.Point(center))
337 | settings.run_mode = "fixed source"
338 | settings.export_to_xml()
339 |
340 | os.system("echo $OPENMC_CROSS_SECTIONS")
341 | openmc.run()
342 |
343 | assert Path("ENDFB-7.1-NNDC_Be9.h5").is_file()
344 | assert Path("ENDFB-7.1-NNDC_c_Be_in_BeO.h5").is_file()
345 |
346 | assert Path("summary.h5").is_file()
347 | assert Path("statepoint.2.h5").is_file()
348 | assert len(list(Path(".").glob("*.h5"))) == 4 # summary and statepoint
349 |
350 |
351 | def test_simulation_with_single_mat_list():
352 | os.system("rm *.h5")
353 |
354 | # this clears the enviromental varible just to be sure that current
355 | # system settings are not being used
356 | try:
357 | del os.environ["OPENMC_CROSS_SECTIONS"]
358 | except KeyError:
359 | # key not found on system
360 | pass
361 |
362 | # Define material
363 | my_mat = openmc.openmc.Material()
364 | my_mat.add_nuclide("Pu239", 3.7047e-2)
365 | my_mat.add_nuclide("Pu240", 1.7512e-3)
366 | my_mat.add_nuclide("As75", 1.3752e-3)
367 | my_mats = openmc.openmc.Materials([my_mat])
368 | my_mats.export_to_xml()
369 | my_mats.download_cross_section_data(
370 | libraries=["TENDL-2019"],
371 | particles=["neutron"],
372 | set_OPENMC_CROSS_SECTIONS=True,
373 | )
374 |
375 | # Create a sphere of my_mat
376 | surf = openmc.Sphere(r=6.3849, boundary_type="vacuum")
377 | main_cell = openmc.Cell(fill=my_mat, region=-surf)
378 | openmc.Geometry([main_cell]).export_to_xml()
379 |
380 | # Define settings for the simulation
381 | settings = openmc.Settings()
382 | settings.particles = 10
383 | settings.batches = 2
384 | settings.inactive = 0
385 | center = (0.0, 0.0, 0.0)
386 | settings.source = openmc.Source(space=openmc.stats.Point(center))
387 | settings.export_to_xml()
388 |
389 | os.system("echo $OPENMC_CROSS_SECTIONS")
390 | openmc.run()
391 |
392 | assert Path("TENDL-2019_Pu239.h5").is_file()
393 | assert Path("TENDL-2019_Pu240.h5").is_file()
394 | assert Path("TENDL-2019_As75.h5").is_file()
395 |
396 | assert Path("summary.h5").is_file()
397 | assert Path("statepoint.2.h5").is_file()
398 |
399 | assert len(list(Path(".").glob("*.h5"))) == 5 # summary and statepoint
400 |
401 |
402 | def test_simulation_with_multi_mat_list():
403 | os.system("rm *.h5")
404 |
405 | # this clears the enviromental varible just to be sure that current
406 | # system settings are not being used
407 | try:
408 | del os.environ["OPENMC_CROSS_SECTIONS"]
409 | except KeyError:
410 | # key not found on system
411 | pass
412 |
413 | # Define material
414 | my_mat1 = openmc.openmc.Material()
415 | my_mat1.add_nuclide("Pu239", 3.7047e-2)
416 | my_mat1.add_nuclide("Pu240", 1.7512e-3)
417 |
418 | my_mat2 = openmc.openmc.Material()
419 | my_mat2.add_element("As", 1.3752e-3)
420 | my_mats = openmc.Materials([my_mat1, my_mat2])
421 | my_mats.export_to_xml()
422 |
423 | # Create a sphere of my_mat
424 | surf1 = openmc.Sphere(r=1)
425 | surf2 = openmc.Sphere(r=6, boundary_type="vacuum")
426 | main_cell = openmc.Cell(fill=my_mat1, region=-surf1)
427 | outer_cell = openmc.Cell(fill=my_mat2, region=+surf1 & -surf2)
428 | universe = openmc.Universe(cells=[main_cell, outer_cell])
429 | openmc.Geometry(universe).export_to_xml()
430 |
431 | # Define settings for the simulation
432 | settings = openmc.Settings()
433 | settings.particles = 10
434 | settings.batches = 2
435 | settings.inactive = 0
436 | center = (0.0, 0.0, 0.0)
437 | settings.source = openmc.Source(space=openmc.stats.Point(center))
438 | settings.export_to_xml()
439 |
440 | my_mats.download_cross_section_data(
441 | libraries=["TENDL-2019"],
442 | set_OPENMC_CROSS_SECTIONS=True,
443 | )
444 |
445 | os.system("echo $OPENMC_CROSS_SECTIONS")
446 | openmc.run()
447 |
448 | assert Path("TENDL-2019_Pu239.h5").is_file()
449 | assert Path("TENDL-2019_Pu240.h5").is_file()
450 | assert Path("TENDL-2019_As75.h5").is_file()
451 |
452 | assert Path("summary.h5").is_file()
453 | assert Path("statepoint.2.h5").is_file()
454 |
455 | assert len(list(Path(".").glob("*.h5"))) == 5 # summary and statepoint
456 |
--------------------------------------------------------------------------------