"""Calculate the threshold values for the power crossing the separatrix."""
from ...algorithm_class import Algorithm
from ...named_options import ConfinementPowerScaling
from ...unit_handling import ureg, wraps_ufunc
[docs]
@Algorithm.register_algorithm(return_keys=["P_LH_thresh"])
@wraps_ufunc(
return_units=dict(P_LH_thresh=ureg.MW),
input_units=dict(
plasma_current=ureg.MA,
magnetic_field_on_axis=ureg.T,
minor_radius=ureg.m,
major_radius=ureg.m,
surface_area=ureg.m**2,
average_ion_mass=ureg.amu,
average_electron_density=ureg.n19,
confinement_power_scaling=None,
confinement_threshold_scalar=ureg.dimensionless,
),
)
def calc_LH_transition_threshold_power(
plasma_current: float,
magnetic_field_on_axis: float,
minor_radius: float,
major_radius: float,
surface_area: float,
average_ion_mass: float,
average_electron_density: float,
confinement_power_scaling: ConfinementPowerScaling = ConfinementPowerScaling.H_mode_Martin,
confinement_threshold_scalar: float = 1.0,
) -> float:
"""Calculate the threshold power (crossing the separatrix) to transition into H-mode.
From Martin NF 2008 Scaling, with mass correction :cite:`martin_power_2008`
Added in low density branch from Ryter 2014 :cite:`Ryter_2014`
Args:
plasma_current: [MA] :term:`glossary link<plasma_current>`
magnetic_field_on_axis: [T] :term:`glossary link<magnetic_field_on_axis>`
minor_radius: [m] :term:`glossary link<minor_radius>`
major_radius: [m] :term:`glossary link<major_radius>`
surface_area: [m^2] :term:`glossary link<surface_area>`
average_ion_mass: [amu] :term:`glossary link<average_ion_mass>`
average_electron_density: [1e19 m^-3] :term:`glossary link<average_electron_density>`
confinement_power_scaling: [~] :term:`glossary link<confinement_power_scaling>`
confinement_threshold_scalar: [~] :term:`glossary link<confinement_threshold_scalar>`
Returns:
:term:`P_LH_thresh` [MW]
"""
def _calc_Martin_LH_threshold(electron_density: float) -> float:
_DEUTERIUM_MASS_NUMBER = 2.0
return float(0.0488 * ((electron_density / 10.0) ** 0.717) * (magnetic_field_on_axis**0.803) * (surface_area**0.941)) * (
_DEUTERIUM_MASS_NUMBER / average_ion_mass
)
if confinement_power_scaling == ConfinementPowerScaling.H_mode_Martin:
# Ryter 2014, equation 3
neMin19 = (
0.7 * (plasma_current**0.34) * (magnetic_field_on_axis**0.62) * (minor_radius**-0.95) * ((major_radius / minor_radius) ** 0.4)
)
if average_electron_density < neMin19:
P_LH_thresh = _calc_Martin_LH_threshold(electron_density=neMin19)
return float(P_LH_thresh * (neMin19 / average_electron_density) ** 2.0) * confinement_threshold_scalar
else:
P_LH_thresh = _calc_Martin_LH_threshold(electron_density=average_electron_density)
return P_LH_thresh * confinement_threshold_scalar
else:
raise NotImplementedError(
f"No implementation for calc_LH_transition_threshold_power with confinement_power_scaling = {confinement_power_scaling} (type ({type(confinement_power_scaling)}))"
)
calc_ratio_P_LH = Algorithm.from_single_function(
func=lambda power_crossing_separatrix, P_LH_thresh: power_crossing_separatrix / P_LH_thresh,
return_keys=["ratio_of_P_SOL_to_P_LH"],
name="calc_ratio_P_LH",
)
[docs]
@Algorithm.register_algorithm(return_keys=["P_LI_thresh"])
@wraps_ufunc(
return_units=dict(P_LI_thresh=ureg.MW),
input_units=dict(
plasma_current=ureg.MA,
magnetic_field_on_axis=ureg.T,
surface_area=ureg.m**2,
average_electron_density=ureg.n19,
confinement_power_scaling=None,
confinement_threshold_scalar=ureg.dimensionless,
),
)
def calc_LI_transition_threshold_power(
plasma_current: float,
magnetic_field_on_axis: float,
surface_area: float,
average_electron_density: float,
confinement_power_scaling: ConfinementPowerScaling = ConfinementPowerScaling.I_mode_HubbardNF17,
confinement_threshold_scalar: float = 1.0,
) -> float:
"""Calculate the threshold power (crossing the separatrix) to transition into I-mode.
Note:
"AUG" option is inspired from :cite:`ryter_i-mode_2016` and :cite:`Happel_2017`
"HubbardNF17" uses scaling described in Fig 6 of :cite:`hubbard_threshold_2017`
"HubbardNF12" uses scaling described in Fig 5 of ref :cite:`hubbard_threshold_2012`
Args:
plasma_current: [MA] :term:`glossary link<plasma_current>`
magnetic_field_on_axis: [T] :term:`glossary link<magnetic_field_on_axis>`
surface_area: [m^2] :term:`glossary link<surface_area>`
average_electron_density: [1e19 m^-3] :term:`glossary link<average_electron_density>`
confinement_power_scaling: [~] :term:`glossary link<confinement_power_scaling>`
confinement_threshold_scalar: [~] :term:`glossary link<confinement_threshold_scalar>`
Returns:
:term:`P_LI_thresh` [MW]
"""
def _calc_AUG_LI_threshold(
average_electron_density: float, magnetic_field_on_axis: float, surface_area: float, confinement_threshold_scalar: float
) -> float:
return (
float(0.14 * (average_electron_density / 10) * (magnetic_field_on_axis / 2.4) ** 0.39 * surface_area)
* confinement_threshold_scalar
)
def _calc_HubbardNF17_LI_threshold(
average_electron_density: float, magnetic_field_on_axis: float, surface_area: float, confinement_threshold_scalar: float
) -> float:
return (
float(0.162 * (average_electron_density / 10) * (magnetic_field_on_axis**0.262) * surface_area) * confinement_threshold_scalar
)
def _calc_HubbardNF12_LI_threshold(
average_electron_density: float, plasma_current: float, confinement_threshold_scalar: float
) -> float:
return float(2.11 * plasma_current**0.94 * ((average_electron_density / 10.0) ** 0.65)) * confinement_threshold_scalar
if confinement_power_scaling == ConfinementPowerScaling.I_mode_AUG:
P_LI_thresh = _calc_AUG_LI_threshold(average_electron_density, magnetic_field_on_axis, surface_area, confinement_threshold_scalar)
elif confinement_power_scaling == ConfinementPowerScaling.I_mode_HubbardNF17:
P_LI_thresh = _calc_HubbardNF17_LI_threshold(
average_electron_density, magnetic_field_on_axis, surface_area, confinement_threshold_scalar
)
elif confinement_power_scaling == ConfinementPowerScaling.I_mode_HubbardNF12:
P_LI_thresh = _calc_HubbardNF12_LI_threshold(average_electron_density, plasma_current, confinement_threshold_scalar)
else:
raise NotImplementedError(
f"No implementation for calc_LI_transition_threshold_power with confinement_power_scaling = {confinement_power_scaling} (type ({type(confinement_power_scaling)}))"
)
return float(P_LI_thresh)
calc_ratio_P_LI = Algorithm.from_single_function(
func=lambda power_crossing_separatrix, P_LI_thresh: power_crossing_separatrix / P_LI_thresh,
return_keys=["ratio_of_P_SOL_to_P_LI"],
name="calc_ratio_P_LI",
)