Skip to content

Commit

Permalink
improved energy distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
shimwell committed Jan 20, 2024
1 parent 64e4aa1 commit 77af3f9
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 47 deletions.
111 changes: 83 additions & 28 deletions src/openmc_plasma_source/fuel_types.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,92 @@
"""fuel_types.py
import NeSST as nst
import numpy as np
import openmc

Defines dictionary for determining mean energy and mass of reactants
for a given fusion fuel type.
"""
def get_neutron_energy_distribution(
ion_temperature: float,
fuel: dict = {'D':0.5, 'T':0.5},
) -> openmc.stats.Discrete:
"""Finds the energy distribution
Parameters
----------
ion_temperature : float
temperature of plasma ions in eV
fuel : dict
isotopes as keys and atom fractions as values
class Fuel:
def __init__(self, mean_energy, mass_of_reactants):
self.mean_energy = mean_energy
self.mass_of_reactants = mass_of_reactants
Returns
-------
openmc.stats.Discrete
energy distribution
"""

@property
def mean_energy(self):
return self._mean_energy
ion_temperature = ion_temperature / 1e3 # convert eV to keV

@mean_energy.setter
def mean_energy(self, value):
if value <= 0:
raise (ValueError("mean_energy needs to be strictly positive"))
self._mean_energy = value
sum_fuel_isotopes = sum(fuel.values())
if sum_fuel_isotopes > 1.:
raise ValueError(f'isotope fractions within the fuel must sum to be below 1. Not {sum_fuel_isotopes}')

@property
def mass_of_reactants(self):
return self._mass_of_reactants
if sum_fuel_isotopes < 0.:
raise ValueError(f'isotope must sum to be above 0. Not {sum_fuel_isotopes}')

@mass_of_reactants.setter
def mass_of_reactants(self, value):
if value <= 0:
raise (ValueError("mass_of_reactants needs to be strictly positive"))
self._mass_of_reactants = value
for k, v in fuel.dict:
if k not in ['D', 'T']:
raise ValueError(f'Fuel dictionary keys must be either "D" or "T" not "{k}".')
if v < 0:
raise ValueError(f'Fuel dictionary values must be above 0 not "{k}".')
if v > 1:
raise ValueError(f'Fuel dictionary values must be below 1 not "{k}".')

#Set atomic fraction of D and T in scattering medium and source
if 'D' in fuel.keys():
nst.frac_D_default = fuel['D']
max_energy_mev=5
else:
nst.frac_D_default = 0

fuel_types = {
"DD": Fuel(mean_energy=2450000.0, mass_of_reactants=4),
"DT": Fuel(mean_energy=14080000.0, mass_of_reactants=5),
}
if 'T' in fuel.keys():
nst.frac_T_default = fuel['T']
max_energy_mev=12
else:
nst.frac_T_default = 0

if 'T' in fuel.keys() and 'D' in fuel.keys():
max_energy_mev=20

# 1.0 neutron yield, all reactions scaled by this value
num_of_vals = 500
# single grid for DT, DD and TT grid
E_pspec = np.linspace(0, max_energy_mev, num_of_vals) # accepts MeV units

dNdE_DT_DD_TT = np.zeros(num_of_vals)
if 'D' in fuel.keys() and 'T' in fuel.keys():
DTmean, DTvar = nst.DTprimspecmoments(ion_temperature)
DDmean, DDvar = nst.DDprimspecmoments(ion_temperature)

Y_DT = 1.0
Y_DD = nst.yield_from_dt_yield_ratio("dd", Y_DT, ion_temperature)
Y_TT = nst.yield_from_dt_yield_ratio("tt", Y_DT, ion_temperature)

dNdE_DT = Y_DT * nst.Qb(E_pspec, DTmean, DTvar) # Brysk shape i.e. Gaussian
dNdE_DD = Y_DD * nst.Qb(E_pspec, DDmean, DDvar) # Brysk shape i.e. Gaussian
dNdE_TT = Y_TT * nst.dNdE_TT(E_pspec, ion_temperature)
dNdE_DT_DD_TT= dNdE_DT + dNdE_DD + dNdE_TT

if 'D' in fuel.keys() and 'T' not in fuel.keys():
DTmean, DTvar = nst.DTprimspecmoments(ion_temperature)
DDmean, DDvar = nst.DDprimspecmoments(ion_temperature)

Y_DD = 1.0

dNdE_DD = Y_DD * nst.Qb(E_pspec, DDmean, DDvar) # Brysk shape i.e. Gaussian
dNdE_DT_DD_TT= dNdE_DD

if 'D' not in fuel.keys() and 'T' in fuel.keys():

Y_TT = 1.0

dNdE_TT = Y_TT * nst.dNdE_TT(E_pspec, ion_temperature)
dNdE_DT_DD_TT= dNdE_TT

return openmc.stats.Discrete(E_pspec * 1e6, dNdE_DT_DD_TT)
10 changes: 3 additions & 7 deletions src/openmc_plasma_source/point_source.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import openmc
from typing import Tuple

from .fuel_types import fuel_types
from .fuel_types import get_neutron_energy_distribution


class FusionPointSource(openmc.IndependentSource):
Expand All @@ -21,7 +21,7 @@ def __init__(
self,
coordinate: Tuple[float, float, float] = (0.0, 0.0, 0.0),
temperature: float = 20000.0,
fuel: str = "DT",
fuel: dict = {"D": 0.5, "T": 0.5},
):
# Set local attributes
self.coordinate = coordinate
Expand All @@ -35,11 +35,7 @@ def __init__(
# performed after the super init as these are Source attributes
self.space = openmc.stats.Point(self.coordinate)
self.angle = openmc.stats.Isotropic()
self.energy = openmc.stats.muir(
e0=self.fuel.mean_energy,
m_rat=self.fuel.mass_of_reactants,
kt=self.temperature,
)
self.energy = get_neutron_energy_distribution(ion_temperature=temperature, fuel=fuel)

@property
def coordinate(self):
Expand Down
13 changes: 4 additions & 9 deletions src/openmc_plasma_source/ring_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import numpy as np
from typing import Tuple

from .fuel_types import fuel_types
from .fuel_types import get_neutron_energy_distribution


class FusionRingSource(openmc.IndependentSource):
Expand All @@ -25,15 +25,14 @@ def __init__(
angles: Tuple[float, float] = (0, 2 * np.pi),
z_placement: float = 0,
temperature: float = 20000.0,
fuel: str = "DT",
fuel: dict = {"D": 0.5, "T": 0.5},
):
# Set local attributes
self.radius = radius
self.angles = angles
self.z_placement = z_placement
self.temperature = temperature
self.fuel_type = fuel
self.fuel = fuel_types[self.fuel_type]
self.fuel = fuel

# Call init for openmc.Source
super().__init__()
Expand All @@ -46,11 +45,7 @@ def __init__(
origin=(0.0, 0.0, 0.0),
)
self.angle = openmc.stats.Isotropic()
self.energy = openmc.stats.muir(
e0=self.fuel.mean_energy,
m_rat=self.fuel.mass_of_reactants,
kt=self.temperature,
)
self.energy = get_neutron_energy_distribution(ion_temperature=temperature, fuel=fuel)

@property
def radius(self):
Expand Down
8 changes: 5 additions & 3 deletions src/openmc_plasma_source/tokamak_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import numpy as np
from typing import Tuple

from .fuel_types import get_neutron_energy_distribution


class TokamakSource:
"""Plasma neutron source sampling.
Expand Down Expand Up @@ -68,6 +70,7 @@ def __init__(
shafranov_factor: float,
angles: Tuple[float, float] = (0, 2 * np.pi),
sample_size: int = 1000,
fuel: dict = {"D": 0.5, "T": 0.5},
) -> None:
# Assign attributes
self.major_radius = major_radius
Expand All @@ -88,6 +91,7 @@ def __init__(
self.shafranov_factor = shafranov_factor
self.angles = angles
self.sample_size = sample_size
self.fuel = fuel

# Perform sanity checks for inputs not caught by properties
if self.minor_radius >= self.major_radius:
Expand Down Expand Up @@ -385,9 +389,7 @@ def make_openmc_sources(self):
)

my_source.angle = openmc.stats.Isotropic()
my_source.energy = openmc.stats.muir(
e0=14080000.0, m_rat=5.0, kt=self.temperatures[i]
)
my_source.energy = get_neutron_energy_distribution(ion_temperature=self.temperature[i], fuel=self.fuel)

# the strength of the source (its probability) is given by
# self.strengths
Expand Down

0 comments on commit 77af3f9

Please sign in to comment.