From 1757c18e896a639e55ce28e24dc0074a12e446bf Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 15:34:46 -0500 Subject: [PATCH 01/11] minor refac + proper type hinting + better docstrings --- src/openmc_plasma_source/ring_source.py | 53 +++++++++++-------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/src/openmc_plasma_source/ring_source.py b/src/openmc_plasma_source/ring_source.py index fe6f64f..892fdd7 100644 --- a/src/openmc_plasma_source/ring_source.py +++ b/src/openmc_plasma_source/ring_source.py @@ -1,16 +1,19 @@ import numpy as np import openmc +from openmc import IndependentSource from .fuel_types import get_neutron_energy_distribution +from typing import Tuple, List, Dict + def fusion_ring_source( radius: float, - angles: tuple[float, float] = (0, 2 * np.pi), + angles: Tuple[float, float] = (0, 2 * np.pi), z_placement: float = 0, temperature: float = 20000.0, - fuel: dict = {"D": 0.5, "T": 0.5}, -) -> list[openmc.IndependentSource]: + fuel: Dict = {"D": 0.5, "T": 0.5}, +) -> List[IndependentSource]: """Creates a list of openmc.IndependentSource objects in a ring shape. Useful for simulations where all the plasma parameters are not known and @@ -18,20 +21,21 @@ def fusion_ring_source( energy distribution according to the fuel composition. Args: - radius (float): the inner radius of the ring source, in metres - angles (iterable of floats): the start and stop angles of the ring in + radius: the inner radius of the ring source, in metres + angles: the start and stop angles of the ring in radians - z_placement (float): Location of the ring source (m). Defaults to 0. - temperature (float): Temperature of the source (eV). - fuel (dict): Isotopes as keys and atom fractions as values + z_placement: Location of the ring source (m). Defaults to 0. + temperature: Temperature of the source (eV). + fuel: Isotopes as keys and atom fractions as values + + Returns: + A list of one openmc.IndependentSource instance. """ - if isinstance(radius, (int, float)) and radius > 0: - pass - else: + if not isinstance(radius, (int, float)) or radius <= 0: raise ValueError("Radius must be a float strictly greater than 0.") - if ( + if not ( isinstance(angles, tuple) and len(angles) == 2 and all( @@ -39,27 +43,15 @@ def fusion_ring_source( for angle in angles ) ): - pass - else: raise ValueError("Angles must be a tuple of floats between zero and 2 * np.pi") - if isinstance(z_placement, (int, float)): - pass - else: + if not isinstance(z_placement, (int, float)): raise TypeError("Z placement must be a float.") - if isinstance(temperature, (int, float)) and temperature > 0: - pass - else: + if not (isinstance(temperature, (int, float)) and temperature > 0): raise ValueError("Temperature must be a float strictly greater than 0.") - sources = [] - - energy_distributions = get_neutron_energy_distribution( - ion_temperature=temperature, fuel=fuel - ) - - source = openmc.IndependentSource() + source = IndependentSource() source.space = openmc.stats.CylindricalIndependent( r=openmc.stats.Discrete([radius], [1]), @@ -68,8 +60,11 @@ def fusion_ring_source( origin=(0.0, 0.0, 0.0), ) + energy_distributions = get_neutron_energy_distribution( + ion_temperature=temperature, fuel=fuel + ) + source.energy = energy_distributions source.angle = openmc.stats.Isotropic() - sources.append(source) - return sources + return [source] From 2f15c4707671fc57297d0d3078355e9d8ed7da76 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 15:41:55 -0500 Subject: [PATCH 02/11] typing + explicit import for pylance --- src/openmc_plasma_source/fuel_types.py | 48 ++++++++++++++------------ 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/src/openmc_plasma_source/fuel_types.py b/src/openmc_plasma_source/fuel_types.py index 5e527a5..c021060 100644 --- a/src/openmc_plasma_source/fuel_types.py +++ b/src/openmc_plasma_source/fuel_types.py @@ -1,22 +1,25 @@ import NeSST as nst import numpy as np -import openmc +import openmc.stats + +from typing import Dict, List def neutron_energy_mean(ion_temperature: float, reaction: str) -> float: - """Calculates the mean energy of the neutron emitted during DD or DT + """ + Calculates the mean energy of the neutron emitted during DD or DT fusion accounting for temperature of the incident ions. Based on Ballabio fits, see Table III of L. Ballabio et al 1998 Nucl. Fusion 38 1723 Args: - ion_temperature (float): the temperature of the ions in eV - reaction (str): the two isotope that fuse, can be either 'DD' or 'DT' + ion_temperature: the temperature of the ions in eV. + reaction: the two isotope that fuse, can be either 'DD' or 'DT'. Raises: - ValueError: if the reaction is not 'DD' or 'DT' then a ValueError is raised + ValueError: if the reaction is not 'DD' or 'DT' then a ValueError is raised. Returns: - float: the mean neutron energy in eV + The mean neutron energy in eV. """ # values from Ballabio paper @@ -47,19 +50,20 @@ def neutron_energy_mean(ion_temperature: float, reaction: str) -> float: def neutron_energy_std_dev(ion_temperature: float, reaction: str) -> float: - """Calculates the standard deviation of the neutron energy emitted during DD + """ + Calculates the standard deviation of the neutron energy emitted during DD or DT fusion accounting for temperature of the incident ions. Based on Ballabio fits, see Table III of L. Ballabio et al 1998 Nucl. Fusion 38 1723 Args: - ion_temperature (float): the temperature of the ions in eV - reaction (str): the two isotope that fuse, can be either 'DD' or 'DT' + ion_temperature: the temperature of the ions in eV. + reaction: the two isotope that fuse, can be either 'DD' or 'DT'. Raises: - ValueError: if the reaction is not 'DD' or 'DT' then a ValueError is raised + ValueError: if the reaction is not 'DD' or 'DT' then a ValueError is raised. Returns: - float: the mean neutron energy in eV + The mean neutron energy in eV """ # values from Ballabio paper @@ -93,35 +97,33 @@ def neutron_energy_std_dev(ion_temperature: float, reaction: str) -> float: return std_dev -def get_reactions_from_fuel(fuel): - if ["D", "T"] == sorted(set(fuel.keys())): +def get_reactions_from_fuel(fuel: Dict[str, float]) -> List[str]: + unique_keys = sorted(set(fuel.keys())) + if ["D", "T"] == unique_keys: return ["DT", "DD", "TT"] - elif ["D"] == sorted(set(fuel.keys())): + elif ["D"] == unique_keys: return ["DD"] - elif ["T"] == sorted(set(fuel.keys())): + elif ["T"] == unique_keys: return ["TT"] else: - msg = 'reactions of fuel {fuel} could not be found. Supported fuel keys are "T" and "D"' + msg = f'reactions of fuel {fuel} could not be found. Supported fuel keys are "T" and "D"' raise ValueError(msg) def get_neutron_energy_distribution( ion_temperature: float, - fuel: dict, + fuel: Dict[str, float], ) -> openmc.stats.Discrete: """Finds the energy distribution and their relative strengths. Parameters ---------- - ion_temperature : float - temperature of plasma ions in eV - fuel : dict - isotopes as keys and atom fractions as values + ion_temperature : temperature of plasma ions in eV + fuel : isotopes as keys and atom fractions as values Returns ------- - openmc.stats.Discrete - energy distribution + energy distribution """ sum_fuel_isotopes = sum(fuel.values()) From 8b3484dd3fef1d148737bfa81a476a15451a248b Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 15:43:54 -0500 Subject: [PATCH 03/11] minor refac + typing --- src/openmc_plasma_source/point_source.py | 27 ++++++++++++------------ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/openmc_plasma_source/point_source.py b/src/openmc_plasma_source/point_source.py index 0ba064b..2bb9df2 100644 --- a/src/openmc_plasma_source/point_source.py +++ b/src/openmc_plasma_source/point_source.py @@ -1,34 +1,38 @@ from typing import Tuple import openmc +from openmc import IndependentSource from .fuel_types import get_neutron_energy_distribution +from typing import Dict, List + def fusion_point_source( coordinate: Tuple[float, float, float] = (0.0, 0.0, 0.0), temperature: float = 20000.0, - fuel: dict = {"D": 0.5, "T": 0.5}, -) -> list[openmc.IndependentSource]: + fuel: Dict[str, float] = {"D": 0.5, "T": 0.5}, +) -> List[IndependentSource]: """Creates a list of openmc.IndependentSource objects representing an ICF source. Resulting ICF (Inertial Confinement Fusion) source will have an energy distribution according to the fuel composition. Args: - coordinate (tuple[float,float,float]): Location of the point source. + coordinate: Location of the point source. Each component is measured in metres. - temperature (float): Temperature of the source (eV). - fuel (dict): Isotopes as keys and atom fractions as values + temperature: Temperature of the source (eV). + fuel: Isotopes as keys and atom fractions as values + + Returns: + A list of one openmc.IndependentSource instance. """ - if ( + if not ( isinstance(coordinate, tuple) and len(coordinate) == 3 and all(isinstance(x, (int, float)) for x in coordinate) ): - pass - else: raise ValueError("coordinate must be a tuple of three floats.") if not isinstance(temperature, (int, float)): @@ -36,16 +40,13 @@ def fusion_point_source( if temperature <= 0: raise ValueError("Temperature must be positive float.") - sources = [] + source = openmc.IndependentSource() energy_distribution = get_neutron_energy_distribution( ion_temperature=temperature, fuel=fuel ) - - source = openmc.IndependentSource() source.energy = energy_distribution source.space = openmc.stats.Point(coordinate) source.angle = openmc.stats.Isotropic() - sources.append(source) - return sources + return [source] From 51806e43a5fb616f101d91b1beb947d8a6b4699b Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 15:44:25 -0500 Subject: [PATCH 04/11] import stats explicitely --- src/openmc_plasma_source/point_source.py | 2 +- src/openmc_plasma_source/ring_source.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openmc_plasma_source/point_source.py b/src/openmc_plasma_source/point_source.py index 2bb9df2..e41ea11 100644 --- a/src/openmc_plasma_source/point_source.py +++ b/src/openmc_plasma_source/point_source.py @@ -1,6 +1,6 @@ from typing import Tuple -import openmc +import openmc.stats from openmc import IndependentSource from .fuel_types import get_neutron_energy_distribution diff --git a/src/openmc_plasma_source/ring_source.py b/src/openmc_plasma_source/ring_source.py index 892fdd7..bae5c7c 100644 --- a/src/openmc_plasma_source/ring_source.py +++ b/src/openmc_plasma_source/ring_source.py @@ -1,5 +1,5 @@ import numpy as np -import openmc +import openmc.stats from openmc import IndependentSource from .fuel_types import get_neutron_energy_distribution From 3429e2a95b4d5d78d9cf83e3a7cf78a9b6f3a7a8 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 15:48:57 -0500 Subject: [PATCH 05/11] fixed typo --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dfb7de8..8366f51 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: - name: Run tests shell: bash -l {0} run: | - pytest tests --cov opennmc_plasma_source --cov-report xml --cov-report term + pytest tests --cov openmc_plasma_source --cov-report xml --cov-report term - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 From a8036235834f602f34c30ab8812c3b0a22a3e674 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 15:49:56 -0500 Subject: [PATCH 06/11] typing and docstrings updates --- src/openmc_plasma_source/tokamak_source.py | 51 +++++++++++----------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/openmc_plasma_source/tokamak_source.py b/src/openmc_plasma_source/tokamak_source.py index c546787..c133b51 100644 --- a/src/openmc_plasma_source/tokamak_source.py +++ b/src/openmc_plasma_source/tokamak_source.py @@ -1,7 +1,8 @@ -from typing import Tuple +from typing import Tuple, Dict import numpy as np import openmc +from openmc import IndependentSource import openmc.checkvalue as cv from NeSST.spectral_model import reac_DD, reac_DT, reac_TT @@ -27,9 +28,9 @@ def tokamak_source( shafranov_factor: float, angles: Tuple[float, float] = (0, 2 * np.pi), sample_size: int = 1000, - fuel: dict = {"D": 0.5, "T": 0.5}, + fuel: Dict[str, float] = {"D": 0.5, "T": 0.5}, sample_seed: int = 122807528840384100672342137672332424406, -) -> list[openmc.IndependentSource]: +) -> list[IndependentSource]: """Creates a list of openmc.IndependentSource objects representing a tokamak plasma. Resulting sources will have an energy distribution according to the fuel @@ -45,37 +46,37 @@ def tokamak_source( my_settings.source = my_source Args: - major_radius (float): Plasma major radius (cm) - minor_radius (float): Plasma minor radius (cm) - elongation (float): Plasma elongation - triangularity (float): Plasma triangularity - mode (str): Confinement mode ("L", "H", "A") - ion_density_centre (float): Ion density at the plasma centre (m-3) - ion_density_peaking_factor (float): Ion density peaking factor + major_radius: Plasma major radius (cm) + minor_radius: Plasma minor radius (cm) + elongation: Plasma elongation + triangularity: Plasma triangularity + mode: Confinement mode ("L", "H", "A") + ion_density_centre: Ion density at the plasma centre (m-3) + ion_density_peaking_factor: Ion density peaking factor (referred in [1] as ion density exponent) - ion_density_pedestal (float): Ion density at pedestal (m-3) - ion_density_separatrix (float): Ion density at separatrix (m-3) - ion_temperature_centre (float): Ion temperature at the plasma + ion_density_pedestal: Ion density at pedestal (m-3) + ion_density_separatrix: Ion density at separatrix (m-3) + ion_temperature_centre: Ion temperature at the plasma centre (eV) - ion_temperature_peaking_factor (float): Ion temperature peaking + ion_temperature_peaking_factor: Ion temperature peaking factor (referred in [1] as ion temperature exponent alpha_T) - ion_temperature_beta (float): Ion temperature beta exponent + ion_temperature_beta: Ion temperature beta exponent (referred in [1] as ion temperature exponent beta_T) - ion_temperature_pedestal (float): Ion temperature at pedestal (eV) - ion_temperature_separatrix (float): Ion temperature at separatrix + ion_temperature_pedestal: Ion temperature at pedestal (eV) + ion_temperature_separatrix: Ion temperature at separatrix (eV) - pedestal_radius (float): Minor radius at pedestal (cm) - shafranov_factor (float): Shafranov factor (referred in [1] as esh) + pedestal_radius: Minor radius at pedestal (cm) + shafranov_factor: Shafranov factor (referred in [1] as esh) also known as outward radial displacement of magnetic surfaces (cm) - angles (iterable of floats): the start and stop angles of the ring in + angles: the start and stop angles of the ring in radians sample_seed int: the seed passed to numpy.random when sampling source location. Numpy recommend a large int value. Defaults to 122807528840384100672342137672332424406 - sample_size (int, optional): number of neutron sources. Defaults + sample_size: number of neutron sources. Defaults to 1000. - fuel (dict): Isotopes as keys and atom fractions as values + fuel: Isotopes as keys and atom fractions as values """ # Perform sanity checks for inputs not caught by properties @@ -102,7 +103,7 @@ def tokamak_source( cv.check_greater_than("ion_density_pedestal", ion_density_pedestal, 0) cv.check_greater_than("ion_density_separatrix", ion_density_separatrix, 0) - if ( + if not ( isinstance(angles, tuple) and len(angles) == 2 and all( @@ -110,8 +111,6 @@ def tokamak_source( for angle in angles ) ): - pass - else: raise ValueError("Angles must be a tuple of floats between zero and 2 * np.pi") # Create a list of sources @@ -372,7 +371,7 @@ def tokamak_make_openmc_sources( z_values = openmc.stats.Discrete([Z_val], [1]) angle = openmc.stats.Uniform(a=angles[0], b=angles[1]) - my_source = openmc.IndependentSource() + my_source = IndependentSource() my_source.energy = get_neutron_energy_distribution( ion_temperature=temperature, fuel=fuel, From 92a79e77670847dcbe2cfffa504d4ccae4e45a03 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 16:07:17 -0500 Subject: [PATCH 07/11] enhance typing and docstrings for tokamak source functions --- src/openmc_plasma_source/tokamak_source.py | 162 ++++++++++++--------- 1 file changed, 96 insertions(+), 66 deletions(-) diff --git a/src/openmc_plasma_source/tokamak_source.py b/src/openmc_plasma_source/tokamak_source.py index c133b51..e653421 100644 --- a/src/openmc_plasma_source/tokamak_source.py +++ b/src/openmc_plasma_source/tokamak_source.py @@ -1,6 +1,7 @@ -from typing import Tuple, Dict +from typing import Tuple, Dict, List import numpy as np +from numpy.typing import NDArray import openmc from openmc import IndependentSource import openmc.checkvalue as cv @@ -31,7 +32,8 @@ def tokamak_source( fuel: Dict[str, float] = {"D": 0.5, "T": 0.5}, sample_seed: int = 122807528840384100672342137672332424406, ) -> list[IndependentSource]: - """Creates a list of openmc.IndependentSource objects representing a tokamak plasma. + """ + Creates a list of openmc.IndependentSource objects representing a tokamak plasma. Resulting sources will have an energy distribution according to the fuel composition.This function greatly relies on models described in [1] @@ -164,8 +166,8 @@ def tokamak_source( fuel_densities[key] = densities * value reactions = get_reactions_from_fuel(fuel) - neutron_source_density = {} - total_source_density = 0 + neutron_source_density = {} # type: Dict[str, NDArray] + total_source_density = 0.0 for reaction in reactions: if reaction == "DD": @@ -184,7 +186,7 @@ def tokamak_source( total_source_density += sum(neutron_source_density[reaction]) - all_sources = [] + all_sources = [] # type: List[IndependentSource] for reaction in reactions: strengths = neutron_source_density[reaction] / total_source_density @@ -200,23 +202,32 @@ def tokamak_source( def tokamak_ion_density( - mode, - ion_density_centre, - ion_density_peaking_factor, - ion_density_pedestal, - major_radius, - pedestal_radius, - ion_density_separatrix, - r, -): - """Computes the ion density at a given position. The ion density is + mode: str, + ion_density_centre: float, + ion_density_peaking_factor: float, + ion_density_pedestal: float, + major_radius: float, + pedestal_radius: float, + ion_density_separatrix: float, + r: float | NDArray, +) -> NDArray: + """ + Computes the ion density at a given position. The ion density is only dependent on the minor radius. Args: - r (float, ndarray): the minor radius (cm) + mode: Confinement mode ("L", "H", "A") + ion_density_centre: Ion density at the plasma centre (m-3) + ion_density_peaking_factor: Ion density peaking factor + (referred in [1] as ion density exponent) + ion_density_pedestal: Ion density at pedestal (m-3) + major_radius: Plasma major radius (cm) + pedestal_radius: Minor radius at pedestal (cm) + ion_density_separatrix: Ion density at separatrix (m-3) + r: Minor radius (cm) Returns: - float, ndarray: ion density in m-3 + ion density in m-3 """ r = np.asarray(r) @@ -247,24 +258,36 @@ def tokamak_ion_density( def tokamak_ion_temperature( - r, - mode, - pedestal_radius, - ion_temperature_pedestal, - ion_temperature_centre, - ion_temperature_beta, - ion_temperature_peaking_factor, - ion_temperature_separatrix, - major_radius, -): - """Computes the ion temperature at a given position. The ion + r: float | NDArray, + mode: str, + pedestal_radius: float, + ion_temperature_pedestal: float, + ion_temperature_centre: float, + ion_temperature_beta: float, + ion_temperature_peaking_factor: float, + ion_temperature_separatrix: float, + major_radius: float, +) -> NDArray: + """ + Computes the ion temperature at a given position. The ion temperature is only dependent on the minor radius. Args: - r (float, ndarray): minor radius (cm) + r: Minor radius (cm) + mode: Confinement mode ("L", "H", "A") + pedestal_radius: Minor radius at pedestal (cm) + ion_temperature_pedestal: Ion temperature at pedestal (eV) + ion_temperature_centre: Ion temperature at the plasma + centre (eV) + ion_temperature_beta: Ion temperature beta exponent + ion_temperature_peaking_factor: Ion temperature peaking + factor + ion_temperature_separatrix: Ion temperature at separatrix (eV) + major_radius: Plasma major radius (cm) + Returns: - float, ndarray: ion temperature (eV) + ion temperature (eV) """ r = np.asarray(r) @@ -296,31 +319,34 @@ def tokamak_ion_temperature( def tokamak_convert_a_alpha_to_R_Z( - a, - alpha, - shafranov_factor, - minor_radius, - major_radius, - triangularity, - elongation, -): - """Converts (r, alpha) cylindrical coordinates to (R, Z) cartesian + a: float | NDArray, + alpha: float | NDArray, + shafranov_factor: float, + minor_radius: float, + major_radius: float, + triangularity: float, + elongation: float, +) -> Tuple[NDArray, NDArray]: + """ + Converts (r, alpha) cylindrical coordinates to (R, Z) cartesian coordinates. Args: - a (float, ndarray): minor radius (cm) - alpha (float, ndarray): angle (rad) - shafranov_factor: - minor_radius: - major_radius: + a: Minor radius (cm) + alpha: Poloidal angle (radians) + shafranov_factor: Shafranov factor + minor_radius: Plasma minor radius (cm) + major_radius: Plasma major radius (cm) + triangularity: Plasma triangularity + elongation: Plasma elongation Returns: - ((float, ndarray), (float, ndarray)): (R, Z) coordinates + (R, Z) coordinates """ a = np.asarray(a) alpha = np.asarray(alpha) if np.any(a < 0): - raise ValueError("Radius 'a' must not be negative") + raise ValueError("Radius 'a' must not be negative") shafranov_shift = shafranov_factor * (1.0 - (a / minor_radius) ** 2) R = ( @@ -333,28 +359,28 @@ def tokamak_convert_a_alpha_to_R_Z( def tokamak_make_openmc_sources( - strengths, - angles, - temperatures, - fuel, - RZ, -): - """Creates a list of OpenMC Sources() objects. The created sources are + strengths: List[float] | NDArray, + angles: Tuple[float, float], + temperatures: NDArray, + fuel: Dict[str, float], + RZ: Tuple[NDArray, NDArray], +) -> List[IndependentSource]: + """ + Creates a list of OpenMC IndependentSource() objects. The created sources are ring sources based on the .RZ coordinates between two angles. The energy of the sources are Muir energy spectra with ion temperatures based on .temperatures. The strength of the sources (their probability) is based on .strengths. Args: - strengths - angles ((float, float), optional): rotation of the ring source. - Defaults to (0, 2*np.pi). - temperatures - fuel - RZ + strengths: The strength of the sources + angles: The start and stop angles of the ring in radians + temperatures: The ion temperatures + fuel: Isotopes as keys and atom fractions as values + RZ: The (R, Z) coordinates of the sources Returns: - list: list of openmc.IndependentSource() + list of openmc.IndependentSource instances """ sources = [] @@ -390,16 +416,20 @@ def tokamak_make_openmc_sources( return sources -def tokamak_neutron_source_density(ion_density, ion_temperature, reaction): - """Computes the neutron source density given ion density and ion +def tokamak_neutron_source_density( + ion_density: float | NDArray, ion_temperature: float | NDArray, reaction: str +) -> NDArray: + """ + Computes the neutron source density given ion density and ion temperature. Args: - ion_density (float, ndarray): Ion density (m-3) - ion_temperature (float, ndarray): Ion temperature (eV) - reaction (str): The fusion reactions to consider e.g. 'DD' + ion_density: Ion density (m-3) + ion_temperature: Ion temperature (eV) + reaction: The fusion reactions to consider e.g. 'DD' + Returns: - float, ndarray: Neutron source density (neutron/s/m3) + Neutron source density (neutron/s/m3) """ ion_density = np.asarray(ion_density) From 9afcbe70c7df2085545ca22eb478d3ecc58aa006 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 16:17:24 -0500 Subject: [PATCH 08/11] added test for coverage --- tests/test_fuel_types.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/test_fuel_types.py b/tests/test_fuel_types.py index b0a2c8a..f5ca4bc 100644 --- a/tests/test_fuel_types.py +++ b/tests/test_fuel_types.py @@ -1,6 +1,9 @@ import pytest -from openmc_plasma_source import get_neutron_energy_distribution +from openmc_plasma_source import ( + get_neutron_energy_distribution, + get_reactions_from_fuel, +) @pytest.mark.parametrize( @@ -45,3 +48,22 @@ def test_fuel_with_incorrect_isotopese(temperature, fuel): # Should reject anything which is not 'D' or 'T'. with pytest.raises(ValueError): get_neutron_energy_distribution(temperature, fuel) + + +@pytest.mark.parametrize( + "fuel, expected_output", + [ + ({"D": 1.0}, ["DD"]), + ({"T": 1.0}, ["TT"]), + ({"T": 0.5, "D": 0.5}, ["DT", "DD", "TT"]), + ({"D": 0.2, "T": 0.8}, ["DT", "DD", "TT"]), + ({"coucou": 0.2}, None), + ], +) +def test_get_reactions_from_fuel(fuel, expected_output): + """Test the get_reactions_from_fuel function""" + if expected_output is None: + with pytest.raises(ValueError, match=f"{fuel}"): + get_reactions_from_fuel(fuel) + else: + assert get_reactions_from_fuel(fuel) == expected_output From 15e1a211cfddc77907cbf24109b3829b3aca3ab3 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 16:19:27 -0500 Subject: [PATCH 09/11] List instead of list --- src/openmc_plasma_source/tokamak_source.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openmc_plasma_source/tokamak_source.py b/src/openmc_plasma_source/tokamak_source.py index e653421..e9227d7 100644 --- a/src/openmc_plasma_source/tokamak_source.py +++ b/src/openmc_plasma_source/tokamak_source.py @@ -1,7 +1,7 @@ from typing import Tuple, Dict, List import numpy as np -from numpy.typing import NDArray +from numpy.typing import NDArray, List import openmc from openmc import IndependentSource import openmc.checkvalue as cv @@ -31,7 +31,7 @@ def tokamak_source( sample_size: int = 1000, fuel: Dict[str, float] = {"D": 0.5, "T": 0.5}, sample_seed: int = 122807528840384100672342137672332424406, -) -> list[IndependentSource]: +) -> List[IndependentSource]: """ Creates a list of openmc.IndependentSource objects representing a tokamak plasma. From c97a6967fd05d292d5dd45b4c71d2ecf5568fc74 Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 16:21:15 -0500 Subject: [PATCH 10/11] better compatibility with previous python --- src/openmc_plasma_source/tokamak_source.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/openmc_plasma_source/tokamak_source.py b/src/openmc_plasma_source/tokamak_source.py index e9227d7..b03e5bc 100644 --- a/src/openmc_plasma_source/tokamak_source.py +++ b/src/openmc_plasma_source/tokamak_source.py @@ -1,7 +1,7 @@ -from typing import Tuple, Dict, List +from typing import Tuple, Dict, List, Union import numpy as np -from numpy.typing import NDArray, List +from numpy.typing import NDArray import openmc from openmc import IndependentSource import openmc.checkvalue as cv @@ -209,7 +209,7 @@ def tokamak_ion_density( major_radius: float, pedestal_radius: float, ion_density_separatrix: float, - r: float | NDArray, + r: Union[float, NDArray], ) -> NDArray: """ Computes the ion density at a given position. The ion density is @@ -258,7 +258,7 @@ def tokamak_ion_density( def tokamak_ion_temperature( - r: float | NDArray, + r: Union[float, NDArray], mode: str, pedestal_radius: float, ion_temperature_pedestal: float, @@ -319,8 +319,8 @@ def tokamak_ion_temperature( def tokamak_convert_a_alpha_to_R_Z( - a: float | NDArray, - alpha: float | NDArray, + a: Union[float, NDArray], + alpha: Union[float, NDArray], shafranov_factor: float, minor_radius: float, major_radius: float, @@ -417,7 +417,9 @@ def tokamak_make_openmc_sources( def tokamak_neutron_source_density( - ion_density: float | NDArray, ion_temperature: float | NDArray, reaction: str + ion_density: Union[float, NDArray], + ion_temperature: Union[float, NDArray], + reaction: str, ) -> NDArray: """ Computes the neutron source density given ion density and ion From 32f5e9570c80b45e30886214cf539a15002c66bf Mon Sep 17 00:00:00 2001 From: RemDelaporteMathurin Date: Tue, 26 Nov 2024 16:22:03 -0500 Subject: [PATCH 11/11] better error message --- src/openmc_plasma_source/tokamak_source.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openmc_plasma_source/tokamak_source.py b/src/openmc_plasma_source/tokamak_source.py index b03e5bc..a439583 100644 --- a/src/openmc_plasma_source/tokamak_source.py +++ b/src/openmc_plasma_source/tokamak_source.py @@ -445,5 +445,5 @@ def tokamak_neutron_source_density( return ion_density * reac_DT(ion_temperature) # could use _DT_xs instead else: raise ValueError( - 'Reaction {reaction} not in available options ["DD", "DT", "TT"]' + f'Reaction {reaction} not in available options ["DD", "DT", "TT"]' )