Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to package configuration #39

Merged
merged 14 commits into from
Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@ jobs:
- run:
name: install
command: |
python setup.py install
pip install --upgrade pip
pip install .[tests]
apt-get update -y && apt-get install -y curl

- run:
name: run tests
command: |
pytest tests/test_point_source.py -v --cov=openmc_plasma_source --cov-append --cov-report term --cov-report xml
pytest tests/test_ring_source.py -v --cov=openmc_plasma_source --cov-append --cov-report term --cov-report xml
pytest tests/test_tokamak_source.py -v --cov=openmc_plasma_source --cov-append --cov-report term --cov-report xml
pytest tests/test_plotting.py -v --cov=openmc_plasma_source --cov-append --cov-report term --cov-report xml
pytest tests -v --cov=openmc_plasma_source --cov-append --cov-report term --cov-report xml

- store_test_results:
path: test-reports
Expand Down
16 changes: 11 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,16 @@ jobs:
uses: actions/checkout@v2

- name: Install
run: python setup.py install
run: |
python3 -m pip install --upgrade pip
python3 -m pip install .[tests]

- name: Run tests
run: |
python3 -m pytest -v tests

- name: run example
- name: Run examples
run: |
python examples/point_source_example.py
python examples/ring_source_example.py
python examples/tokamak_source_example.py
python3 examples/point_source_example.py
python3 examples/ring_source_example.py
python3 examples/tokamak_source_example.py
22 changes: 9 additions & 13 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,29 +19,25 @@ jobs:

steps:
- uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Autobump version
run: |
# from refs/tags/v1.2.3 get 1.2.3
VERSION=$(echo $GITHUB_REF | sed 's#.*/v##')
PLACEHOLDER='version="develop"'
VERSION_FILE='setup.py'
# Grep checks that the placeholder is in the file. If grep doesn't find
# the placeholder then it exits with exit code 1 and github actions fails.
grep "$PLACEHOLDER" "$VERSION_FILE"
sed -i "s/$PLACEHOLDER/version=\"${VERSION}\"/g" "$VERSION_FILE"
shell: bash

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install build
pip install setuptools build wheel twine

- name: Build package
run: python -m build

- name: Check build
run: twine check dist/*

- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
_version.py

# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
File renamed without changes.
13 changes: 13 additions & 0 deletions openmc_plasma_source/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
try:
from importlib.metadata import version, PackageNotFoundError
except (ModuleNotFoundError, ImportError):
from importlib_metadata import version, PackageNotFoundError
try:
__version__ = version("openmc_plasma_source")
except PackageNotFoundError:
from setuptools_scm import get_version

__version__ = get_version(root="..", relative_to=__file__)

__all__ = ["__version__"]

from .tokamak_source import TokamakSource
from .ring_source import FusionRingSource
from .point_source import FusionPointSource
11 changes: 11 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[build-system]
requires = [
"setuptools >= 45",
"wheel",
"setuptools_scm[toml] >= 6.2",
"setuptools_scm_git_archive",
]
build-backend = "setuptools.build_meta"

[tool.setuptools_scm]
write_to = "openmc_plasma_source/_version.py"
2 changes: 0 additions & 2 deletions requirements.txt

This file was deleted.

36 changes: 36 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[metadata]
name = openmc_plasma_source
author = The openmc-plasma-source Development Team
author_email = [email protected]
description = Creates tokamak plasma sources for OpenMC
long_description = file: README.md
long_description_content_type = text/markdown
url = https://github.com/fusion-energy/openmc-plasma-source
license = MIT
license_file = LICENSE.txt
classifiers =
Natural Language :: English
Topic :: Scientific/Engineering
Programming Language :: Python :: 3
Programming Language :: Python :: 3.6
Programming Language :: Python :: 3.7
Programming Language :: Python :: 3.8
Programming Language :: Python :: 3.9
License :: OSI Approved :: MIT License
Operating System :: OS Independent
project_urls =
Source = https://github.com/fusion-energy/openmc-plasma-source
Tracker = https://github.com/fusion-energy/openmc-plasma-source/issues

[options]
packages = find:
python_requires= >=3.6
install_requires=
numpy >= 1.9
matplotlib >= 3.4.3
importlib-metadata; python_version < "3.8"

[options.extras_require]
tests =
pytest >= 5.4.3
hypothesis
32 changes: 2 additions & 30 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,4 @@
import setuptools

with open("README.md", "r") as fh:
long_description = fh.read()

setuptools.setup(
name="openmc_plasma_source",
version="develop",
author="The openmc-plasma-source Development Team",
author_email="[email protected]",
description="Creates tokamak plasma sources for OpenMC",
long_description=long_description,
long_description_content_type="text/markdown",
url="https://github.com/fusion-energy/openmc-plasma-source",
packages=setuptools.find_packages(),
classifiers=[
"Natural Language :: English",
"Topic :: Scientific/Engineering",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
tests_require=[
"pytest",
],
python_requires=">=3.6",
install_requires=["numpy>=1.9", "matplotlib >= 3.2.2"],
)
if __name__ == "__main__":
setuptools.setup()
170 changes: 107 additions & 63 deletions tests/test_tokamak_source.py
Original file line number Diff line number Diff line change
@@ -1,74 +1,118 @@
from openmc_plasma_source import TokamakSource

from openmc import Source
import numpy as np

import pytest
from hypothesis import given, settings, assume, strategies as st


@st.composite
def tokamak_source_strategy(draw, return_dict=False):
"""Defines a hypothesis strategy that automatically generates a TokamakSource.
When passed `return_dict=True`, only a dict of the args is passed.
Geometry attributes are varied, while plasma attributes are fixed.
"""
# Used to avoid generation of inappropriate float values
finites = {"allow_nan": False, "allow_infinity": False, "allow_subnormal": False}

# Specify the base strategies for each geometry input
minor_radius = draw(st.floats(min_value=0.0, max_value=100.0, **finites))
major_radius = draw(st.floats(min_value=0.0, max_value=100.0, **finites))
pedestal_radius = draw(st.floats(min_value=0.0, max_value=100.0, **finites))
elongation = draw(st.floats(min_value=1.0, max_value=10.0, **finites))
triangularity = draw(st.floats(min_value=-1.0, max_value=1.0, **finites))
shafranov_factor = draw(st.floats(min_value=0.0, max_value=1.0, **finites))

# Specify requirements that must be satisfied for a valid tokamak
assume(major_radius > minor_radius)
assume(minor_radius > pedestal_radius)
assume(minor_radius > shafranov_factor)

args_dict = {
"elongation": elongation,
"triangularity": triangularity,
"major_radius": major_radius,
"minor_radius": minor_radius,
"pedestal_radius": pedestal_radius,
"shafranov_factor": shafranov_factor,
"ion_density_centre": 1.09e20,
"ion_density_peaking_factor": 1,
"ion_density_pedestal": 1.09e20,
"ion_density_separatrix": 3e19,
"ion_temperature_centre": 45.9,
"ion_temperature_peaking_factor": 8.06,
"ion_temperature_pedestal": 6.09,
"ion_temperature_separatrix": 0.1,
"mode": "H",
"ion_temperature_beta": 6,
}

return args_dict if return_dict else TokamakSource(**args_dict)


def test_creation():
my_source = TokamakSource(
elongation=1.557,
ion_density_centre=1.09e20,
ion_density_peaking_factor=1,
ion_density_pedestal=1.09e20,
ion_density_separatrix=3e19,
ion_temperature_centre=45.9,
ion_temperature_peaking_factor=8.06,
ion_temperature_pedestal=6.09,
ion_temperature_separatrix=0.1,
major_radius=9.06,
minor_radius=2.92258,
pedestal_radius=0.8 * 2.92258,
mode="H",
shafranov_factor=0.44789,
triangularity=0.270,
ion_temperature_beta=6,
)
for source in my_source.make_openmc_sources():
@given(tokamak_source=tokamak_source_strategy())
@settings(max_examples=1, deadline=None)
def test_creation(tokamak_source):
"""Tests that the sources generated by TokamakSource are of type openmc.Source"""
for source in tokamak_source.sources:
assert isinstance(source, Source)


def test_strengths_are_normalised():
@given(tokamak_source=tokamak_source_strategy())
@settings(max_examples=100, deadline=None)
def test_strengths_are_normalised(tokamak_source):
"""Tests that the sum of the strengths attribute is equal to"""
my_source = TokamakSource(
elongation=1.557,
ion_density_centre=1.09e20,
ion_density_peaking_factor=1,
ion_density_pedestal=1.09e20,
ion_density_separatrix=3e19,
ion_temperature_centre=45.9,
ion_temperature_peaking_factor=8.06,
ion_temperature_pedestal=6.09,
ion_temperature_separatrix=0.1,
major_radius=9.06,
minor_radius=2.92258,
pedestal_radius=0.8 * 2.92258,
mode="H",
shafranov_factor=0.44789,
triangularity=0.270,
ion_temperature_beta=6,
)
assert pytest.approx(sum(my_source.strengths), 1)


def test_angles():
assert pytest.approx(sum(tokamak_source.strengths), 1)


@given(tokamak_source=tokamak_source_strategy())
@settings(max_examples=100, deadline=None)
def test_source_locations_are_within_correct_range(tokamak_source):
"""Tests that each source has RZ locations within the expected range.
As the function converting (a,alpha) coordinates to (R,Z) is not bijective, we
cannot convert back to validate each individual point. However, we can determine
whether the generated points are contained within the shell of the last closed
magnetic surface.
See "Tokamak D-T neutron source models for different plasma physics confinement
modes", C. Fausser et al., Fusion Engineering and Design, 2012 for more info.
"""
R_0 = tokamak_source.major_radius
A = tokamak_source.minor_radius
El = tokamak_source.elongation
delta = tokamak_source.triangularity

def get_R_on_LCMS(alpha):
"""Gets R on the last closed magnetic surface for a given alpha"""
return R_0 + A * np.cos(alpha + delta * np.sin(alpha))

approx_lt = lambda x, y: x < y or np.isclose(x, y)
approx_gt = lambda x, y: x > y or np.isclose(x, y)

for source in tokamak_source.sources:
R, Z = source.space.r.x[0], source.space.z.x[0]
# First test that the point is contained with a simple box with
# lower left (r_min,-z_max) and upper right (r_max,z_max)
assert approx_gt(R, R_0 - A)
assert approx_lt(R, R_0 + A)
assert approx_lt(abs(Z), A * El)
# For a given Z, we can determine the two values of alpha where
# where a = minor_radius, and from there determine the upper and
# lower bounds for R.
alpha_1 = np.arcsin(abs(Z) / (El * A))
alpha_2 = np.pi - alpha_1
R_max, R_min = get_R_on_LCMS(alpha_1), get_R_on_LCMS(alpha_2)
assert approx_lt(R_max, R_0 + A)
assert approx_gt(R_min, R_0 - A)
assert approx_lt(R, R_max)
assert approx_gt(R, R_min)


@given(tokamak_args_dict=tokamak_source_strategy(return_dict=True))
@settings(max_examples=1, deadline=None)
def test_angles(tokamak_args_dict):
"""Checks that custom angles can be set"""
my_source = TokamakSource(
elongation=1.557,
ion_density_centre=1.09e20,
ion_density_peaking_factor=1,
ion_density_pedestal=1.09e20,
ion_density_separatrix=3e19,
ion_temperature_centre=45.9,
ion_temperature_peaking_factor=8.06,
ion_temperature_pedestal=6.09,
ion_temperature_separatrix=0.1,
major_radius=9.06,
minor_radius=2.92258,
pedestal_radius=0.8 * 2.92258,
mode="H",
shafranov_factor=0.44789,
triangularity=0.270,
ion_temperature_beta=6,
angles=(0, 1),
)
tokamak_args_dict["angles"] = (0, 1)
tokamak_source = TokamakSource(**tokamak_args_dict)
assert tokamak_source.angles == (0, 1)
for source in tokamak_source.sources:
assert (source.space.phi.a, source.space.phi.b) == (0, 1)