From b961d1ac7b721337832aa6f959eeab939120c88e Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 10:30:15 +0000 Subject: [PATCH 01/12] Add ConfinementTimeModel and integrate PlasmaConfinementTime into Physics class --- process/main.py | 3 + process/models/physics/confinement_time.py | 69 ++++++++++++++++++++++ process/models/physics/physics.py | 9 ++- tests/unit/test_physics.py | 2 + tests/unit/test_stellarator.py | 2 + 5 files changed, 83 insertions(+), 2 deletions(-) diff --git a/process/main.py b/process/main.py index a2b243d10..337adc55d 100644 --- a/process/main.py +++ b/process/main.py @@ -85,6 +85,7 @@ from process.models.ife import IFE from process.models.pfcoil import PFCoil from process.models.physics.bootstrap_current import PlasmaBootstrapCurrent +from process.models.physics.confinement_time import PlasmaConfinementTime from process.models.physics.current_drive import ( CurrentDrive, ElectronBernstein, @@ -706,6 +707,7 @@ def __init__(self): self.plasma_bootstrap_current = PlasmaBootstrapCurrent( plasma_profile=self.plasma_profile ) + self.plasma_confinement = PlasmaConfinementTime() self.physics = Physics( plasma_profile=self.plasma_profile, current_drive=self.current_drive, @@ -714,6 +716,7 @@ def __init__(self): plasma_density_limit=self.plasma_density_limit, plasma_exhaust=self.plasma_exhaust, plasma_bootstrap_current=self.plasma_bootstrap_current, + plasma_confinement=self.plasma_confinement, ) self.physics_detailed = DetailedPhysics( plasma_profile=self.plasma_profile, diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index eeda7ec7e..6f22904b4 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -1,5 +1,74 @@ +import logging +from enum import IntEnum + import numpy as np +from process.core import constants + +logger = logging.getLogger(__name__) + + +class ConfinementTimeModel(IntEnum): + """Confinement time (τ_E) model types""" + + USER_INPUT = 0 + NEO_ALCATOR = 1 + MIRNOV = 2 + MEREZHKIN_MUHKOVATOV = 3 + SHIMOMURA = 4 + KAYE_GOLDSTON = 5 + ITER_89P = 6 + ITER_89_0 = 7 + REBUT_LALLIA = 8 + GOLDSTON = 9 + T_10 = 10 + JAERI = 11 + KAYE_BIG = 12 + ITER_H90_P = 13 + RIEDEL_L = 14 + CHRISTIANSEN = 15 + LACKNER_GOTTARDI = 16 + NEO_KAYE = 17 + RIEDEL_H = 18 + ITER_H90_P_AMENDED = 19 + SUDO_ET_AL = 20 + GYRO_REDUCED_BOHM = 21 + LACKNER_GOTTARDI_STELLARATOR = 22 + ITER_93H = 23 + ITER_H97P = 24 + ITER_H97P_ELMY = 25 + ITER_96P = 26 + VALOVIC_ELMY = 27 + KAYE = 28 + ITER_PB98PY = 29 + ITER_IPB98Y = 30 + ITER_IPB98Y1 = 31 + ITER_IPB98Y2 = 32 + ITER_IPB98Y3 = 33 + ITER_IPB98Y4 = 34 + ISS95_STELLARATOR = 35 + ISS04_STELLARATOR = 36 + DS03 = 37 + MURARI = 38 + PETTY08 = 39 + LANG_HIGH_DENSITY = 40 + HUBBARD_NOMINAL = 41 + HUBBARD_LOWER = 42 + HUBBARD_UPPER = 43 + MENARD_NSTX = 44 + MENARD_NSTX_PETTY08_HYBRID = 45 + NSTX_GYRO_BOHM = 46 + ITPA20 = 47 + ITPA20_IL = 48 + + +class PlasmaConfinementTime: + """Class to calculate plasma confinement time using various empirical scaling laws""" + + def __init__(self): + self.outfile = constants.NOUT + self.mfile = constants.MFILE + def neo_alcator_confinement_time( dene20: float, rminor: float, rmajor: float, qstar: float diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 84c686704..794e540d1 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -27,6 +27,9 @@ times_variables, ) from process.models.physics.bootstrap_current import PlasmaBootstrapCurrent +from process.models.physics.confinement_time import PlasmaConfinementTime +from process.models.physics.density_limit import PlasmaDensityLimit +from process.models.physics.exhaust import PlasmaExhaust logger = logging.getLogger(__name__) @@ -638,8 +641,9 @@ def __init__( current_drive, plasma_beta, plasma_inductance, - plasma_density_limit, - plasma_exhaust, + plasma_density_limit: PlasmaDensityLimit, + plasma_exhaust: PlasmaExhaust, + plasma_confinement: PlasmaConfinementTime, plasma_bootstrap_current: PlasmaBootstrapCurrent, ): self.outfile = constants.NOUT @@ -651,6 +655,7 @@ def __init__( self.density_limit = plasma_density_limit self.exhaust = plasma_exhaust self.plasma_bootstrap_current = plasma_bootstrap_current + self.confinement = plasma_confinement def physics(self): """Routine to calculate tokamak plasma physics information diff --git a/tests/unit/test_physics.py b/tests/unit/test_physics.py index 52f5799ef..c727c3b42 100644 --- a/tests/unit/test_physics.py +++ b/tests/unit/test_physics.py @@ -12,6 +12,7 @@ physics_variables, ) from process.models.physics.bootstrap_current import PlasmaBootstrapCurrent +from process.models.physics.confinement_time import PlasmaConfinementTime from process.models.physics.current_drive import ( CurrentDrive, ElectronBernstein, @@ -62,6 +63,7 @@ def physics(): PlasmaDensityLimit(), PlasmaExhaust(), PlasmaBootstrapCurrent(plasma_profile=PlasmaProfile()), + PlasmaConfinementTime(), ) diff --git a/tests/unit/test_stellarator.py b/tests/unit/test_stellarator.py index 6bec26a1f..ff2fe1537 100644 --- a/tests/unit/test_stellarator.py +++ b/tests/unit/test_stellarator.py @@ -22,6 +22,7 @@ from process.models.costs.costs import Costs from process.models.fw import FirstWall from process.models.physics.bootstrap_current import PlasmaBootstrapCurrent +from process.models.physics.confinement_time import PlasmaConfinementTime from process.models.physics.current_drive import ( CurrentDrive, ElectronBernstein, @@ -92,6 +93,7 @@ def stellarator(): PlasmaDensityLimit(), PlasmaExhaust(), PlasmaBootstrapCurrent(plasma_profile=PlasmaProfile()), + PlasmaConfinementTime(), ), Neoclassics(), plasma_beta=PlasmaBeta(), From 6d307c64f94ed720f941224eabec33ed0434b5af Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 10:48:27 +0000 Subject: [PATCH 02/12] Refactor confinement time tests to use PlasmaConfinementTime class - Updated test_confinement_time.py to replace direct function calls from the confinement_time module with method calls from the PlasmaConfinementTime class. - Adjusted the parameterized tests to reflect the new method structure. - Modified test_physics.py to call the confinement time calculation method from the confinement attribute of the physics object. --- process/models/physics/confinement_time.py | 5925 ++++++++++++-------- process/models/physics/physics.py | 955 +--- tests/unit/test_confinement_time.py | 154 +- tests/unit/test_physics.py | 2 +- 4 files changed, 3547 insertions(+), 3489 deletions(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 6f22904b4..1c6551c05 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -4,6 +4,10 @@ import numpy as np from process.core import constants +from process.core.exceptions import ProcessValueError +from process.data_structure import ( + physics_variables, +) logger = logging.getLogger(__name__) @@ -69,2496 +73,3447 @@ def __init__(self): self.outfile = constants.NOUT self.mfile = constants.MFILE + def calculate_confinement_time( + self, + m_fuel_amu: float, + p_alpha_total_mw: float, + aspect: float, + b_plasma_toroidal_on_axis: float, + nd_plasma_ions_total_vol_avg: float, + nd_plasma_electrons_vol_avg: float, + nd_plasma_electron_line: float, + eps: float, + hfact: float, + i_confinement_time: int, + i_plasma_ignited: int, + kappa: float, + kappa95: float, + p_non_alpha_charged_mw: float, + p_hcd_injected_total_mw: float, + plasma_current: float, + pden_plasma_core_rad_mw: float, + rmajor: float, + rminor: float, + temp_plasma_electron_density_weighted_kev: float, + temp_plasma_ion_density_weighted_kev: float, + q95: float, + qstar: float, + vol_plasma: float, + zeff: float, + ) -> tuple[float, float, float, float, float, float, float]: + """Calculate the confinement times and the transport power loss terms. + + Parameters + ---------- + m_fuel_amu : + Average mass of fuel (amu) + p_alpha_total_mw : + Alpha particle power (MW) + aspect : + Aspect ratio + b_plasma_toroidal_on_axis : + Toroidal field on axis (T) + nd_plasma_ions_total_vol_avg : + Total ion density (/m3) + nd_plasma_electrons_vol_avg : + Volume averaged electron density (/m3) + nd_plasma_electron_line : + Line-averaged electron density (/m3) + eps : + Inverse aspect ratio + hfact : + H factor on energy confinement scalings + i_confinement_time : + Switch for energy confinement scaling to use + i_plasma_ignited : + Switch for ignited calculation + kappa : + Plasma elongation + kappa95 : + Plasma elongation at 95% surface + p_non_alpha_charged_mw : + Non-alpha charged particle fusion power (MW) + p_hcd_injected_total_mw : + Auxiliary power to ions and electrons (MW) + plasma_current : + Plasma current (A) + pden_plasma_core_rad_mw : + Total core radiation power (MW/m3) + q95 : + Edge safety factor (tokamaks), or rotational transform iotabar (stellarators) + qstar : + Equivalent cylindrical edge safety factor + rmajor : + Plasma major radius (m) + rminor : + Plasma minor radius (m) + temp_plasma_electron_density_weighted_kev : + Density weighted average electron temperature (keV) + temp_plasma_ion_density_weighted_kev : + Density weighted average ion temperature (keV) + vol_plasma : + Plasma volume (m3) + a_plasma_poloidal : + Plasma cross-sectional area (m2) + zeff : + Plasma effective charge + + Returns + ------- + type + Tuple containing: + - pden_electron_transport_loss_mw (float): Electron transport power (MW/m3) + - pden_ion_transport_loss_mw (float): Ion transport power (MW/m3) + - t_electron_energy_confinement (float): Electron energy confinement time (s) + - t_ion_energy_confinement (float): Ion energy confinement time (s) + - t_energy_confinement (float): Global energy confinement time (s) + - p_plasma_loss_mw (float): Heating power (MW) assumed in calculation + + """ + + # ======================================================================== + + # Calculate heating power (MW) + p_plasma_loss_mw = ( + physics_variables.f_p_alpha_plasma_deposited * p_alpha_total_mw + + p_non_alpha_charged_mw + + physics_variables.p_plasma_ohmic_mw + ) + + # If the device is not ignited, add the injected auxiliary power + if i_plasma_ignited == 0: + p_plasma_loss_mw = p_plasma_loss_mw + p_hcd_injected_total_mw + + # Include the radiation as a loss term if requested + if physics_variables.i_rad_loss == 0: + p_plasma_loss_mw = ( + p_plasma_loss_mw - physics_variables.pden_plasma_rad_mw * vol_plasma + ) + elif physics_variables.i_rad_loss == 1: + p_plasma_loss_mw = ( + p_plasma_loss_mw - pden_plasma_core_rad_mw * vol_plasma + ) # shouldn't this be vol_core instead of vol_plasma? + # else do not adjust p_plasma_loss_mw for radiation + + # Ensure heating power is positive (shouldn't be necessary) + p_plasma_loss_mw = max(p_plasma_loss_mw, 1.0e-3) + + # ======================================================================== + + # Line averaged electron density in scaled units + dnla20 = nd_plasma_electron_line * 1.0e-20 + dnla19 = nd_plasma_electron_line * 1.0e-19 + + # Volume averaged electron density in units of 10**20 m**-3 + n20 = nd_plasma_electrons_vol_avg / 1.0e20 -def neo_alcator_confinement_time( - dene20: float, rminor: float, rmajor: float, qstar: float -) -> float: - """Calculate the Nec-Alcator(NA) OH scaling confinement time - - Parameters - ---------- - dene20 : - Volume averaged electron density in units of 10**20 m**-3 - rminor : - Plasma minor radius [m] - rmajor : - Plasma major radius [m] - qstar : - Equivalent cylindrical edge safety factor - - Returns - ------- - : - float: Neo-Alcator confinement time [s] - - - References: - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - return 0.07e0 * dene20 * rminor * rmajor * rmajor * qstar - - -def mirnov_confinement_time(rminor: float, kappa95: float, pcur: float) -> float: - """Calculate the Mirnov scaling (H-mode) confinement time - - Parameters - ---------- - rminor : - Plasma minor radius [m] - kappa95 : - Plasma elongation at 95% flux surface - pcur : - Plasma current [MA] - - Returns - ------- - : - float: Mirnov scaling confinement time [s] - - References: - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - return 0.2e0 * rminor * np.sqrt(kappa95) * pcur - - -def merezhkin_muhkovatov_confinement_time( - rmajor: float, - rminor: float, - kappa95: float, - qstar: float, - dnla20: float, - afuel: float, - ten: float, -) -> float: - """Calculate the Merezhkin-Mukhovatov (MM) OH/L-mode scaling confinement time - - Parameters - ---------- - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa95 : - Plasma elongation at 95% flux surface - qstar : - Equivalent cylindrical edge safety factor - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - afuel : - Fuel atomic mass number - ten : - Electron temperature [keV] - - Returns - ------- - : - float: Merezhkin-Mukhovatov confinement time [s] - - - References: - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - return ( - 3.5e-3 - * rmajor**2.75e0 - * rminor**0.25e0 - * kappa95**0.125e0 - * qstar - * dnla20 - * np.sqrt(afuel) - / np.sqrt(ten / 10.0e0) - ) - - -def shimomura_confinement_time( - rmajor: float, - rminor: float, - b_plasma_toroidal_on_axis: float, - kappa95: float, - afuel: float, -) -> float: - """Calculate the Shimomura (S) optimized H-mode scaling confinement time - - Parameters - ---------- - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - kappa95 : - Plasma elongation at 95% flux surface - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: Shimomura confinement time [s] - - References: - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - return ( - 0.045e0 - * rmajor - * rminor - * b_plasma_toroidal_on_axis - * np.sqrt(kappa95) - * np.sqrt(afuel) - ) - - -def kaye_goldston_confinement_time( - kappa95: float, - pcur: float, - n20: float, - rmajor: float, - afuel: float, - b_plasma_toroidal_on_axis: float, - rminor: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Kaye-Goldston (KG) L-mode scaling confinement time - - Parameters - ---------- - kappa95 : - Plasma elongation at 95% flux surface - pcur : - Plasma current [MA] - n20 : - Line averaged electron density in units of 10**20 m**-3 - rmajor : - Plasma major radius [m] - afuel : - Fuel atomic mass number - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - rminor : - Plasma minor radius [m] - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Kaye-Goldston confinement time [s] - - Notes: - - An isotope correction factor (M_i/1.5)^0.5 is added to the original scaling to reflect the fact - that the empirical fits to the data were from experiments with H and D mixture, M_i = 1.5 - - References: - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - return ( - 0.055e0 - * kappa95**0.28e0 - * pcur**1.24e0 - * n20**0.26e0 - * rmajor**1.65e0 - * np.sqrt(afuel / 1.5e0) - / (b_plasma_toroidal_on_axis**0.09e0 * rminor**0.49e0 * p_plasma_loss_mw**0.58e0) - ) - - -def iter_89p_confinement_time( - pcur: float, - rmajor: float, - rminor: float, - kappa: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - afuel: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the ITER Power scaling - ITER 89-P (L-mode) confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa : - Plasma elongation - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - afuel : - Fuel atomic mass number - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: ITER 89-P confinement time [s] - - - References: - - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 - - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - return ( - 0.048e0 - * pcur**0.85e0 - * rmajor**1.2e0 - * rminor**0.3e0 - * np.sqrt(kappa) - * dnla20**0.1e0 - * b_plasma_toroidal_on_axis**0.2e0 - * np.sqrt(afuel) - / np.sqrt(p_plasma_loss_mw) - ) - - -def iter_89_0_confinement_time( - pcur: float, - rmajor: float, - rminor: float, - kappa: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - afuel: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the ITER Offset linear scaling - ITER 89-O (L-mode) confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa : - Plasma elongation - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - afuel : - Fuel atomic mass number - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: ITER 89-O confinement time [s] - - References: - - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 - """ - term1 = ( - 0.04e0 - * pcur**0.5e0 - * rmajor**0.3e0 - * rminor**0.8e0 - * kappa**0.6e0 - * afuel**0.5e0 - ) - term2 = ( - 0.064e0 - * pcur**0.8e0 - * rmajor**1.6e0 - * rminor**0.6e0 - * kappa**0.5e0 - * dnla20**0.6e0 - * b_plasma_toroidal_on_axis**0.35e0 - * afuel**0.2e0 - / p_plasma_loss_mw - ) - return term1 + term2 - - -def rebut_lallia_confinement_time( - rminor: float, - rmajor: float, - kappa: float, - afuel: float, - pcur: float, - zeff: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Rebut-Lallia offset linear scaling (L-mode) confinement time - - Parameters - ---------- - rminor : - Plasma minor radius [m] - rmajor : - Plasma major radius [m] - kappa : - Plasma elongation at 95% flux surface - afuel : - Fuel atomic mass number - pcur : - Plasma current [MA] - zeff : - Effective charge - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Rebut-Lallia confinement time [s] - - - References: - - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 - """ - rll = (rminor**2 * rmajor * kappa) ** (1.0e0 / 3.0e0) - term1 = 1.2e-2 * pcur * rll**1.5e0 / np.sqrt(zeff) - term2 = ( - 0.146e0 - * dnla20**0.75e0 - * np.sqrt(pcur) - * np.sqrt(b_plasma_toroidal_on_axis) - * rll**2.75e0 - * zeff**0.25e0 - / p_plasma_loss_mw - ) - return 1.65e0 * np.sqrt(afuel / 2.0e0) * (term1 + term2) - - -def goldston_confinement_time( - pcur: float, - rmajor: float, - rminor: float, - kappa95: float, - afuel: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Goldston scaling (L-mode) confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa95 : - Plasma elongation at 95% flux surface - afuel : - Fuel atomic mass number - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Goldston confinement time [s] - - References: - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - return ( - 0.037e0 - * pcur - * rmajor**1.75e0 - * rminor ** (-0.37e0) - * np.sqrt(kappa95) - * np.sqrt(afuel / 1.5e0) - / np.sqrt(p_plasma_loss_mw) - ) - - -def t10_confinement_time( - dnla20: float, - rmajor: float, - qstar: float, - b_plasma_toroidal_on_axis: float, - rminor: float, - kappa95: float, - p_plasma_loss_mw: float, - zeff: float, - pcur: float, -) -> float: - """Calculate the T-10 scaling confinement time - - Parameters - ---------- - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - rmajor : - Plasma major radius [m] - qstar : - Equivalent cylindrical edge safety factor - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - rminor : - Plasma minor radius [m] - kappa95 : - Plasma elongation at 95% flux surface - p_plasma_loss_mw : - Net Heating power [MW] - zeff : - Effective charge - pcur : - Plasma current [MA] - - Returns - ------- - : - float: T-10 confinement time [s] - - References: - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - denfac = dnla20 * rmajor * qstar / (1.3e0 * b_plasma_toroidal_on_axis) - denfac = min(1.0e0, denfac) - return ( - 0.095e0 - * rmajor - * rminor - * b_plasma_toroidal_on_axis - * np.sqrt(kappa95) - * denfac - / p_plasma_loss_mw**0.4e0 - * (zeff**2 * pcur**4 / (rmajor * rminor * qstar**3 * kappa95**1.5e0)) ** 0.08e0 - ) - - -def jaeri_confinement_time( - kappa95: float, - rminor: float, - afuel: float, - n20: float, - pcur: float, - b_plasma_toroidal_on_axis: float, - rmajor: float, - qstar: float, - zeff: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the JAERI / Odajima-Shimomura L-mode scaling confinement time - - Parameters - ---------- - kappa95 : - Plasma elongation at 95% flux surface - rminor : - Plasma minor radius [m] - afuel : - Fuel atomic mass number - n20 : - Line averaged electron density in units of 10**20 m**-3 - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - rmajor : - Plasma major radius [m] - qstar : - Equivalent cylindrical edge safety factor - zeff : - Effective charge - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: JAERI confinement time [s] - - References: - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - gjaeri = ( - zeff**0.4e0 - * ((15.0e0 - zeff) / 20.0e0) ** 0.6e0 - * (3.0e0 * qstar * (qstar + 5.0e0) / ((qstar + 2.0e0) * (qstar + 7.0e0))) - ** 0.6e0 - ) - return ( - 0.085e0 * kappa95 * rminor**2 * np.sqrt(afuel) - + 0.069e0 - * n20**0.6e0 - * pcur - * b_plasma_toroidal_on_axis**0.2e0 - * rminor**0.4e0 - * rmajor**1.6e0 - * np.sqrt(afuel) - * gjaeri - * kappa95**0.2e0 - / p_plasma_loss_mw - ) - - -def kaye_big_confinement_time( - rmajor: float, - rminor: float, - b_plasma_toroidal_on_axis: float, - kappa95: float, - pcur: float, - n20: float, - afuel: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Kaye-Big scaling confinement time - - Parameters - ---------- - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - kappa95 : - Plasma elongation at 95% flux surface - pcur : - Plasma current [MA] - n20 : - Line averaged electron density in units of 10**20 m**-3 - afuel : - Fuel atomic mass number - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Kaye-Big confinement time [s] - - - References: - - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, - "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. - """ - return ( - 0.105e0 - * np.sqrt(rmajor) - * rminor**0.8e0 - * b_plasma_toroidal_on_axis**0.3e0 - * kappa95**0.25e0 - * pcur**0.85e0 - * n20**0.1e0 - * np.sqrt(afuel) - / np.sqrt(p_plasma_loss_mw) - ) - - -def iter_h90_p_confinement_time( - pcur: float, - rmajor: float, - rminor: float, - kappa: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - afuel: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the ITER H-mode scaling - ITER H90-P confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa : - Plasma elongation - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - afuel : - Fuel atomic mass number - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: ITER H90-P confinement time [s] - - - References: - - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 - """ - return ( - 0.064e0 - * pcur**0.87e0 - * rmajor**1.82e0 - * rminor ** (-0.12e0) - * kappa**0.35e0 - * dnla20**0.09e0 - * b_plasma_toroidal_on_axis**0.15e0 - * np.sqrt(afuel) - / np.sqrt(p_plasma_loss_mw) - ) - - -def riedel_l_confinement_time( - pcur: float, - rmajor: float, - rminor: float, - kappa95: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Riedel scaling (L-mode) confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa95 : - Plasma elongation at 95% flux surface - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Riedel confinement time [s] - - References: - - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 - """ - return ( - 0.044e0 - * pcur**0.93e0 - * rmajor**1.37e0 - * rminor ** (-0.049e0) - * kappa95**0.588e0 - * dnla20**0.078e0 - * b_plasma_toroidal_on_axis**0.152e0 - / p_plasma_loss_mw**0.537e0 - ) - - -def christiansen_confinement_time( - pcur: float, - rmajor: float, - rminor: float, - kappa95: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, - afuel: float, -) -> float: - """Calculate the Christiansen et al scaling (L-mode) confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa95 : - Plasma elongation at 95% flux surface - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: Christiansen confinement time [s] - - References: - - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 - """ - return ( - 0.24e0 - * pcur**0.79e0 - * rmajor**0.56e0 - * rminor**1.46e0 - * kappa95**0.73e0 - * dnla20**0.41e0 - * b_plasma_toroidal_on_axis**0.29e0 - / (p_plasma_loss_mw**0.79e0 * afuel**0.02e0) - ) - - -def lackner_gottardi_confinement_time( - pcur: float, - rmajor: float, - rminor: float, - kappa95: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Lackner-Gottardi scaling (L-mode) confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa95 : - Plasma elongation at 95% flux surface - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Lackner-Gottardi confinement time [s] - - References: - - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 - """ - qhat = ( - (1.0e0 + kappa95**2) - * rminor**2 - * b_plasma_toroidal_on_axis - / (0.4e0 * pcur * rmajor) - ) - return ( - 0.12e0 - * pcur**0.8e0 - * rmajor**1.8e0 - * rminor**0.4e0 - * kappa95 - * (1.0e0 + kappa95) ** (-0.8e0) - * dnla20**0.6e0 - * qhat**0.4e0 - / p_plasma_loss_mw**0.6e0 - ) - - -def neo_kaye_confinement_time( - pcur: float, - rmajor: float, - rminor: float, - kappa95: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Neo-Kaye scaling (L-mode) confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa95 : - Plasma elongation at 95% flux surface - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Neo-Kaye confinement time [s] - - - References: - - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 - """ - return ( - 0.063e0 - * pcur**1.12e0 - * rmajor**1.3e0 - * rminor ** (-0.04e0) - * kappa95**0.28e0 - * dnla20**0.14e0 - * b_plasma_toroidal_on_axis**0.04e0 - / p_plasma_loss_mw**0.59e0 - ) - - -def riedel_h_confinement_time( - pcur: float, - rmajor: float, - rminor: float, - kappa95: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - afuel: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Riedel scaling (H-mode) confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa95 : - Plasma elongation at 95% flux surface - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - afuel : - Fuel atomic mass number - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Riedel H-mode confinement time [s] - - References: - - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 - """ - return ( - 0.1e0 - * np.sqrt(afuel) - * pcur**0.884e0 - * rmajor**1.24e0 - * rminor ** (-0.23e0) - * kappa95**0.317e0 - * b_plasma_toroidal_on_axis**0.207e0 - * dnla20**0.105e0 - / p_plasma_loss_mw**0.486e0 - ) - - -def iter_h90_p_amended_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - afuel: float, - rmajor: float, - p_plasma_loss_mw: float, - kappa: float, -) -> float: - """Calculate the amended ITER H90-P confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - afuel : - Fuel atomic mass number - rmajor : - Plasma major radius [m] - p_plasma_loss_mw : - Net Heating power [MW] - kappa : - Plasma elongation - - Returns - ------- - : - float: Amended ITER H90-P confinement time [s] - - References: - - J. P. Christiansen et al., “Global energy confinement H-mode database for ITER,” - Nuclear Fusion, vol. 32, no. 2, pp. 291-338, Feb. 1992, - doi: https://doi.org/10.1088/0029-5515/32/2/i11. - """ - return ( - 0.082e0 - * pcur**1.02e0 - * b_plasma_toroidal_on_axis**0.15e0 - * np.sqrt(afuel) - * rmajor**1.60e0 - / (p_plasma_loss_mw**0.47e0 * kappa**0.19e0) - ) - - -def sudo_et_al_confinement_time( - rmajor: float, - rminor: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Sudo et al. scaling confinement time - - Parameters - ---------- - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Sudo et al. confinement time [s] - - References: - - S. Sudo et al., “Scalings of energy confinement and density limit in stellarator/heliotron devices,” - Nuclear Fusion, vol. 30, no. 1, pp. 11-21, Jan. 1990, - doi: https://doi.org/10.1088/0029-5515/30/1/002. - """ - - return ( - 0.17e0 - * rmajor**0.75e0 - * rminor**2 - * dnla20**0.69e0 - * b_plasma_toroidal_on_axis**0.84e0 - * p_plasma_loss_mw ** (-0.58e0) - ) - - -def gyro_reduced_bohm_confinement_time( - b_plasma_toroidal_on_axis: float, - dnla20: float, - p_plasma_loss_mw: float, - rminor: float, - rmajor: float, -) -> float: - """Calculate the Gyro-reduced Bohm scaling confinement time - - Parameters - ---------- - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rminor : - Plasma minor radius [m] - rmajor : - Plasma major radius [m] - - Returns - ------- - : - float: Gyro-reduced Bohm confinement time [s] - - References: - - Goldston, R. J., H. Biglari, and G. W. Hammett. "E x B/B 2 vs. μ B/B as the Cause of Transport in Tokamaks." - Bull. Am. Phys. Soc 34 (1989): 1964. - """ - return ( - 0.25e0 - * b_plasma_toroidal_on_axis**0.8e0 - * dnla20**0.6e0 - * p_plasma_loss_mw ** (-0.6e0) - * rminor**2.4e0 - * rmajor**0.6e0 - ) - - -def lackner_gottardi_stellarator_confinement_time( - rmajor: float, - rminor: float, - dnla20: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, - q: float, -) -> float: - """Calculate the Lackner-Gottardi stellarator scaling confinement time - - Parameters - ---------- - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - q : - Edge safety factor - - Returns - ------- - : - float: Lackner-Gottardi stellarator confinement time [s] - - References: - - K. Lackner and N. A. O. Gottardi, “Tokamak confinement in relation to plateau scaling,” - Nuclear Fusion, vol. 30, no. 4, pp. 767-770, Apr. 1990, - doi: https://doi.org/10.1088/0029-5515/30/4/018. - """ - return ( - 0.17e0 - * rmajor - * rminor**2 - * dnla20**0.6e0 - * b_plasma_toroidal_on_axis**0.8e0 - * p_plasma_loss_mw ** (-0.6e0) - * q**0.4e0 - ) - - -def iter_93h_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, - afuel: float, - rmajor: float, - dnla20: float, - aspect: float, - kappa: float, -) -> float: - """Calculate the ITER-93H scaling ELM-free confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - afuel : - Fuel atomic mass number - rmajor : - Plasma major radius [m] - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - aspect : - Aspect ratio - kappa : - Plasma elongation - - Returns - ------- - : - float: ITER-93H confinement time [s] - - References: - - K. Thomsen et al., “ITER H mode confinement database update,” - vol. 34, no. 1, pp. 131-167, Jan. 1994, doi: https://doi.org/10.1088/0029-5515/34/1/i10. - """ - return ( - 0.036e0 - * pcur**1.06e0 - * b_plasma_toroidal_on_axis**0.32e0 - * p_plasma_loss_mw ** (-0.67e0) - * afuel**0.41e0 - * rmajor**1.79e0 - * dnla20**0.17e0 - * aspect**0.11e0 - * kappa**0.66e0 - ) - - -def iter_h97p_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, - dnla19: float, - rmajor: float, - aspect: float, - kappa: float, - afuel: float, -) -> float: - """Calculate the ELM-free ITER H-mode scaling - ITER H97-P confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - rmajor : - Plasma major radius [m] - aspect : - Aspect ratio - kappa : - Plasma elongation - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: ITER H97-P confinement time [s] - - References: - - I. C. Database and M. W. G. (presented Cordey), “Energy confinement scaling and the extrapolation to ITER,” - Plasma Physics and Controlled Fusion, vol. 39, no. 12B, pp. B115-B127, Dec. 1997, - doi: https://doi.org/10.1088/0741-3335/39/12b/009. - """ - return ( - 0.031e0 - * pcur**0.95e0 - * b_plasma_toroidal_on_axis**0.25e0 - * p_plasma_loss_mw ** (-0.67e0) - * dnla19**0.35e0 - * rmajor**1.92e0 - * aspect ** (-0.08e0) - * kappa**0.63e0 - * afuel**0.42e0 - ) - - -def iter_h97p_elmy_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, - dnla19: float, - rmajor: float, - aspect: float, - kappa: float, - afuel: float, -) -> float: - """Calculate the ELMy ITER H-mode scaling - ITER H97-P(y) confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - rmajor : - Plasma major radius [m] - aspect : - Aspect ratio - kappa : - Plasma elongation - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: ITER H97-P(y) confinement time [s] - - References: - - I. C. Database and M. W. G. (presented Cordey), “Energy confinement scaling and the extrapolation to ITER,” - Plasma Physics and Controlled Fusion, vol. 39, no. 12B, pp. B115-B127, Dec. 1997, - doi: https://doi.org/10.1088/0741-3335/39/12b/009. - - - International Atomic Energy Agency, Vienna (Austria), "Technical basis for the ITER final design report, cost review and safety analysis (FDR)", - no.16. Dec. 1998. - """ - return ( - 0.029e0 - * pcur**0.90e0 - * b_plasma_toroidal_on_axis**0.20e0 - * p_plasma_loss_mw ** (-0.66e0) - * dnla19**0.40e0 - * rmajor**2.03e0 - * aspect ** (-0.19e0) - * kappa**0.92e0 - * afuel**0.2e0 - ) - - -def iter_96p_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - kappa95: float, - rmajor: float, - aspect: float, - dnla19: float, - afuel: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the ITER-96P (= ITER-97L) L-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - kappa95 : - Plasma elongation at 95% flux surface - rmajor : - Plasma major radius [m] - aspect : - Aspect ratio - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - afuel : - Fuel atomic mass number - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: ITER-96P confinement time [s] - - Notes: - - The thermal energy confinement time is given below - - References: - - S. B. Kaye et al., “ITER L mode confinement database,” - Nuclear Fusion, vol. 37, no. 9, pp. 1303-1328, Sep. 1997, - doi: https://doi.org/10.1088/0029-5515/37/9/i10. - """ - return ( - 0.023e0 - * pcur**0.96e0 - * b_plasma_toroidal_on_axis**0.03e0 - * kappa95**0.64e0 - * rmajor**1.83e0 - * aspect**0.06e0 - * dnla19**0.40e0 - * afuel**0.20e0 - * p_plasma_loss_mw ** (-0.73e0) - ) - - -def valovic_elmy_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - afuel: float, - rmajor: float, - rminor: float, - kappa: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Valovic modified ELMy-H mode scaling confinement time - - Parameters - ---------- - hfact : - H-factor - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - afuel : - Fuel atomic mass number - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - kappa : - Plasma elongation - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Valovic modified ELMy-H mode confinement time [s] - """ - return ( - 0.067e0 - * pcur**0.9e0 - * b_plasma_toroidal_on_axis**0.17e0 - * dnla19**0.45e0 - * afuel**0.05e0 - * rmajor**1.316e0 - * rminor**0.79e0 - * kappa**0.56e0 - * p_plasma_loss_mw ** (-0.68e0) - ) - - -def kaye_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - kappa: float, - rmajor: float, - aspect: float, - dnla19: float, - afuel: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Kaye PPPL Workshop April 1998 L-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - kappa : - Plasma elongation - rmajor : - Plasma major radius [m] - aspect : - Aspect ratio - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - afuel : - Fuel atomic mass number - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Kaye PPPL Workshop confinement time [s] - - References: - - Kaye PPPL Workshop April 1998 - """ - return ( - 0.021e0 - * pcur**0.81e0 - * b_plasma_toroidal_on_axis**0.14e0 - * kappa**0.7e0 - * rmajor**2.01e0 - * aspect ** (-0.18e0) - * dnla19**0.47e0 - * afuel**0.25e0 - * p_plasma_loss_mw ** (-0.73e0) - ) - - -def iter_pb98py_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa: float, - aspect: float, - afuel: float, -) -> float: - """Calculate the ITERH-PB98P(y) ELMy H-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa : - Plasma separatrix elongation - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: ITERH-PB98P(y) ELMy H-mode confinement time [s] - """ - return ( - 0.0615e0 - * pcur**0.9e0 - * b_plasma_toroidal_on_axis**0.1e0 - * dnla19**0.4e0 - * p_plasma_loss_mw ** (-0.66e0) - * rmajor**2 - * kappa**0.75e0 - * aspect ** (-0.66e0) - * afuel**0.2e0 - ) - - -def iter_ipb98y_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa: float, - aspect: float, - afuel: float, -) -> float: - """Calculate the IPB98(y) ELMy H-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa : - IPB sprcific plasma separatrix elongation - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: IPB98(y) ELMy H-mode confinement time [s] - - Notes: - - Unlike the other IPB98 scaling laws, the IPB98(y) scaling law uses the true separatrix elongation. - - See correction paper below for more information - - References: - - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” - Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. - - - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” - Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. - """ - return ( - 0.0365e0 - * pcur**0.97e0 - * b_plasma_toroidal_on_axis**0.08e0 - * dnla19**0.41e0 - * p_plasma_loss_mw ** (-0.63e0) - * rmajor**1.93e0 - * kappa**0.67e0 - * aspect ** (-0.23e0) - * afuel**0.2e0 - ) - - -def iter_ipb98y1_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa_ipb: float, - aspect: float, - afuel: float, -) -> float: - """Calculate the IPB98(y,1) ELMy H-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa_ipb : - IPB specific plasma separatrix elongation - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: IPB98(y,1) ELMy H-mode confinement time [s] - - Notes: - - See correction paper below for more information about the re-definition of the elongation used. - - References: - - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” - Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. - - - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” - Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. - """ - return ( - 0.0503e0 - * pcur**0.91e0 - * b_plasma_toroidal_on_axis**0.15e0 - * dnla19**0.44e0 - * p_plasma_loss_mw ** (-0.65e0) - * rmajor**2.05e0 - * kappa_ipb**0.72e0 - * aspect ** (-0.57e0) - * afuel**0.13e0 - ) - - -def iter_ipb98y2_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa_ipb: float, - aspect: float, - afuel: float, -) -> float: - """Calculate the IPB98(y,2) ELMy H-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa_ipb : - IPB specific plasma separatrix elongation - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: IPB98(y,2) ELMy H-mode confinement time [s] - - Notes: - - See correction paper below for more information about the re-definition of the elongation used. - - References: - - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” - Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. - - - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” - Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. - """ - return ( - 0.0562e0 - * pcur**0.93e0 - * b_plasma_toroidal_on_axis**0.15e0 - * dnla19**0.41e0 - * p_plasma_loss_mw ** (-0.69e0) - * rmajor**1.97e0 - * kappa_ipb**0.78e0 - * aspect ** (-0.58e0) - * afuel**0.19e0 - ) - - -def iter_ipb98y3_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa_ipb: float, - aspect: float, - afuel: float, -) -> float: - """Calculate the IPB98(y,3) ELMy H-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa_ipb : - IPB specific plasma separatrix elongation - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: IPB98(y,3) ELMy H-mode confinement time [s] - - Notes: - - See correction paper below for more information about the re-definition of the elongation used. - - References: - - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” - Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. - - - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” - Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. - """ - return ( - 0.0564e0 - * pcur**0.88e0 - * b_plasma_toroidal_on_axis**0.07e0 - * dnla19**0.40e0 - * p_plasma_loss_mw ** (-0.69e0) - * rmajor**2.15e0 - * kappa_ipb**0.78e0 - * aspect ** (-0.64e0) - * afuel**0.20e0 - ) - - -def iter_ipb98y4_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa_ipb: float, - aspect: float, - afuel: float, -) -> float: - """Calculate the IPB98(y,4) ELMy H-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa_ipb : - IPB specific plasma separatrix elongation - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: IPB98(y,4) ELMy H-mode confinement time [s] - - Notes: - - See correction paper below for more information about the re-definition of the elongation used. - - References: - - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” - Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. - - - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” - Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. - """ - return ( - 0.0587e0 - * pcur**0.85e0 - * b_plasma_toroidal_on_axis**0.29e0 - * dnla19**0.39e0 - * p_plasma_loss_mw ** (-0.70e0) - * rmajor**2.08e0 - * kappa_ipb**0.76e0 - * aspect ** (-0.69e0) - * afuel**0.17e0 - ) - - -def iss95_stellarator_confinement_time( - rminor: float, - rmajor: float, - dnla19: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, - iotabar: float, -) -> float: - """Calculate the ISS95 stellarator scaling confinement time - - Parameters - ---------- - rminor : - Plasma minor radius [m] - rmajor : - Plasma major radius [m] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - iotabar : - Rotational transform - - Returns - ------- - : - float: ISS95 stellarator confinement time [s] - - References: - - U. Stroth et al., “Energy confinement scaling from the international stellarator database,” - vol. 36, no. 8, pp. 1063-1077, Aug. 1996, doi: https://doi.org/10.1088/0029-5515/36/8/i11. - """ - return ( - 0.079e0 - * rminor**2.21e0 - * rmajor**0.65e0 - * dnla19**0.51e0 - * b_plasma_toroidal_on_axis**0.83e0 - * p_plasma_loss_mw ** (-0.59e0) - * iotabar**0.4e0 - ) - - -def iss04_stellarator_confinement_time( - rminor: float, - rmajor: float, - dnla19: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, - iotabar: float, -) -> float: - """Calculate the ISS04 stellarator scaling confinement time - - Parameters - ---------- - rminor : - Plasma minor radius [m] - rmajor : - Plasma major radius [m] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - iotabar : - Rotational transform - - Returns - ------- - : - float: ISS04 stellarator confinement time [s] - - References: - - H. Yamada et al., “Characterization of energy confinement in net-current free plasmas using the extended International Stellarator Database,” - vol. 45, no. 12, pp. 1684-1693, Nov. 2005, doi: https://doi.org/10.1088/0029-5515/45/12/024. - """ - return ( - 0.134e0 - * rminor**2.28e0 - * rmajor**0.64e0 - * dnla19**0.54e0 - * b_plasma_toroidal_on_axis**0.84e0 - * p_plasma_loss_mw ** (-0.61e0) - * iotabar**0.41e0 - ) - - -def ds03_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa95: float, - aspect: float, - afuel: float, -) -> float: - """Calculate the DS03 beta-independent H-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa95 : - Plasma elongation at 95% flux surface - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: DS03 beta-independent H-mode confinement time [s] - - References: - - T. C. Luce, C. C. Petty, and J. G. Cordey, “Application of dimensionless parameter scaling techniques to the design and interpretation of magnetic fusion experiments,” - Plasma Physics and Controlled Fusion, vol. 50, no. 4, p. 043001, Mar. 2008, - doi: https://doi.org/10.1088/0741-3335/50/4/043001. - """ - return ( - 0.028e0 - * pcur**0.83e0 - * b_plasma_toroidal_on_axis**0.07e0 - * dnla19**0.49e0 - * p_plasma_loss_mw ** (-0.55e0) - * rmajor**2.11e0 - * kappa95**0.75e0 - * aspect ** (-0.3e0) - * afuel**0.14e0 - ) - - -def murari_confinement_time( - pcur: float, - rmajor: float, - kappa_ipb: float, - dnla19: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Murari H-mode energy confinement scaling time - - Parameters - ---------- - pcur : - Plasma current [MA] - rmajor : - Plasma major radius [m] - kappa_ipb : - IPB specific plasma separatrix elongation - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Murari confinement time [s] - - Notes: - - This scaling uses the IPB defintiion of elongation, see reference for more information. - - References: - - A. Murari, E. Peluso, Michela Gelfusa, I. Lupelli, and P. Gaudio, “A new approach to the formulation and validation of scaling expressions for plasma confinement in tokamaks,” - Nuclear Fusion, vol. 55, no. 7, pp. 073009-073009, Jun. 2015, doi: https://doi.org/10.1088/0029-5515/55/7/073009. - - - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” - Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. - """ - return ( - 0.0367 - * pcur**1.006 - * rmajor**1.731 - * kappa_ipb**1.450 - * p_plasma_loss_mw ** (-0.735) - * ( - dnla19**0.448 - / (1.0 + np.exp(-9.403 * (dnla19 / b_plasma_toroidal_on_axis) ** -1.365)) + # Plasma current in MA + pcur = plasma_current / 1.0e6 + + # Separatrix kappa defined with plasma volume for IPB scalings + # Updated version of kappa used by the IPB98 scalings correction in: + + # None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, + # “Corrections to a sequence of papers in Nuclear Fusion,” Nuclear Fusion, + # vol. 48, no. 9, pp. 099801099801, Aug. 2008, + # doi: https://doi.org/10.1088/0029-5515/48/9/099801. + + physics_variables.kappa_ipb = (vol_plasma / (2.0 * np.pi * rmajor)) / ( + np.pi * rminor**2 ) - ) - - -def petty08_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa_ipb: float, - aspect: float, -) -> float: - """Calculate the beta independent dimensionless Petty08 confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa_ipb : - IPB specific plasma separatrix elongation - aspect : - Aspect ratio - - Returns - ------- - : - float: Petty08 confinement time [s] - - Notes: - - This scaling uses the IPB defintiion of elongation, see reference for more information. - - References: - - C. C. Petty, “Sizing up plasmas using dimensionless parameters,” - Physics of Plasmas, vol. 15, no. 8, Aug. 2008, doi: https://doi.org/10.1063/1.2961043. - - - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” - Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. - """ - return ( - 0.052e0 - * pcur**0.75e0 - * b_plasma_toroidal_on_axis**0.3e0 - * dnla19**0.32e0 - * p_plasma_loss_mw ** (-0.47e0) - * rmajor**2.09e0 - * kappa_ipb**0.88e0 - * aspect ** (-0.84e0) - ) - - -def lang_high_density_confinement_time( - plasma_current: float, - b_plasma_toroidal_on_axis: float, - nd_plasma_electron_line: float, - p_plasma_loss_mw: float, - rmajor: float, - rminor: float, - q: float, - qstar: float, - aspect: float, - afuel: float, - kappa_ipb: float, -) -> float: - """Calculate the high density relevant confinement time - - Parameters - ---------- - plasma_current : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - nd_plasma_electron_line : - Line averaged electron density [m**-3] - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - rminor : - Plasma minor radius [m] - q : - Safety factor - qstar : - Equivalent cylindrical edge safety factor - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - kappa_ipb : - Plasma elongation at 95% flux surface - - Returns - ------- - : - float: High density relevant confinement time [s] - - References: - - P. T. Lang, C. Angioni, R. M. M. Dermott, R. Fischer, and H. Zohm, “Pellet Induced High Density Phases during ELM Suppression in ASDEX Upgrade,” - 24th IAEA Conference Fusion Energy, 2012, Oct. 2012, - Available: https://www.researchgate.net/publication/274456104_Pellet_Induced_High_Density_Phases_during_ELM_Suppression_in_ASDEX_Upgrade - """ - qratio = q / qstar - n_gw = 1.0e14 * plasma_current / (np.pi * rminor * rminor) - nratio = nd_plasma_electron_line / n_gw - return ( - 6.94e-7 - * plasma_current**1.3678e0 - * b_plasma_toroidal_on_axis**0.12e0 - * nd_plasma_electron_line**0.032236e0 - * (p_plasma_loss_mw * 1.0e6) ** (-0.74e0) - * rmajor**1.2345e0 - * kappa_ipb**0.37e0 - * aspect**2.48205e0 - * afuel**0.2e0 - * qratio**0.77e0 - * aspect ** (-0.9e0 * np.log(aspect)) - * nratio ** (-0.22e0 * np.log(nratio)) - ) - - -def hubbard_nominal_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla20: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Hubbard 2017 I-mode confinement time scaling - nominal - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Hubbard confinement time [s] - - References: - - A. E. Hubbard et al., “Physics and performance of the I-mode regime over an expanded operating space on Alcator C-Mod,” - Nuclear Fusion, vol. 57, no. 12, p. 126039, Oct. 2017, doi: https://doi.org/10.1088/1741-4326/aa8570. - """ - return ( - 0.014e0 - * pcur**0.68e0 - * b_plasma_toroidal_on_axis**0.77e0 - * dnla20**0.02e0 - * p_plasma_loss_mw ** (-0.29e0) - ) - - -def hubbard_lower_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla20: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Hubbard 2017 I-mode confinement time scaling - lower - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Hubbard confinement time [s] - - References: - - A. E. Hubbard et al., “Physics and performance of the I-mode regime over an expanded operating space on Alcator C-Mod,” - Nuclear Fusion, vol. 57, no. 12, p. 126039, Oct. 2017, doi: https://doi.org/10.1088/1741-4326/aa8570. - """ - return ( - 0.014e0 - * pcur**0.60e0 - * b_plasma_toroidal_on_axis**0.70e0 - * dnla20 ** (-0.03e0) - * p_plasma_loss_mw ** (-0.33e0) - ) - - -def hubbard_upper_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla20: float, - p_plasma_loss_mw: float, -) -> float: - """Calculate the Hubbard 2017 I-mode confinement time scaling - upper - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - - Returns - ------- - : - float: Hubbard confinement time [s] - - References: - - A. E. Hubbard et al., “Physics and performance of the I-mode regime over an expanded operating space on Alcator C-Mod,” - Nuclear Fusion, vol. 57, no. 12, p. 126039, Oct. 2017, doi: https://doi.org/10.1088/1741-4326/aa8570. - """ - return ( - 0.014e0 - * pcur**0.76e0 - * b_plasma_toroidal_on_axis**0.84e0 - * dnla20**0.07 - * p_plasma_loss_mw ** (-0.25e0) - ) - - -def menard_nstx_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa_ipb: float, - aspect: float, - afuel: float, -) -> float: - """Calculate the Menard NSTX ELMy H-mode scaling confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa_ipb : - IPB specific plasma separatrix elongation - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: Menard NSTX ELMy H-mode confinement time [s] - - Notes: - - "The leading NSTX confinement scaling coefficient is chosen such that the ITER and ST energy confinement times are - identical for a reference NSTX scenario" - - Assumes IPB98(y,2) exponents are applicable where the ST exponents are not yet determined, i.e. - the species mass, major radius, inverse aspect ratio and elongation. Hence here we use the IPB98(y,2) definition - of elongation. - - References: - - J. E. Menard, “Compact steady-state tokamak performance dependence on magnet and core physics limits,” - Philosophical Transactions of the Royal Society A, vol. 377, no. 2141, pp. 20170440-20170440, Feb. 2019, - doi: https://doi.org/10.1098/rsta.2017.0440. - """ - return ( - 0.095e0 - * pcur**0.57e0 - * b_plasma_toroidal_on_axis**1.08e0 - * dnla19**0.44e0 - * p_plasma_loss_mw ** (-0.73e0) - * rmajor**1.97e0 - * kappa_ipb**0.78e0 - * aspect ** (-0.58e0) - * afuel**0.19e0 - ) - - -def menard_nstx_petty08_hybrid_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - kappa_ipb: float, - aspect: float, - afuel: float, -) -> float: - """Calculate the Menard NSTX-Petty hybrid confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Line averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - kappa_ipb : - IPB specific plasma separatrix elongation - aspect : - Aspect ratio - afuel : - Fuel atomic mass number - - Returns - ------- - : - float: Menard NSTX-Petty hybrid confinement time [s] - - Notes: - - Assuming a linear interpolation in (1/aspect) between the two scalings - - References: - - J. E. Menard, “Compact steady-state tokamak performance dependence on magnet and core physics limits,” - Philosophical Transactions of the Royal Society A, vol. 377, no. 2141, pp. 20170440-20170440, Feb. 2019, - doi: https://doi.org/10.1098/rsta.2017.0440. - """ - # Equivalent to A > 2.5, use Petty scaling - if (1.0e0 / aspect) <= 0.4e0: - return petty08_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - kappa_ipb, - aspect, + + # Electron energy confinement times + + # ======================================================================== + + # User defined confinement time + if i_confinement_time == 0: # t_electron_energy_confinement is an input + t_electron_confinement = physics_variables.tauee_in + + # ======================================================================== + + # Nec-Alcator(NA) OH scaling + if i_confinement_time == 1: + t_electron_confinement = self.neo_alcator_confinement_time( + n20, rminor, rmajor, qstar + ) + + # ======================================================================== + + # "Mirnov"-like scaling (H-mode) + elif i_confinement_time == 2: # Mirnov scaling (H-mode) + t_electron_confinement = self.mirnov_confinement_time(rminor, kappa95, pcur) + + # ======================================================================== + + # Merezhkin-Mukhovatov (MM) OH/L-mode scaling + elif i_confinement_time == 3: + t_electron_confinement = self.merezhkin_muhkovatov_confinement_time( + rmajor, + rminor, + kappa95, + qstar, + dnla20, + m_fuel_amu, + temp_plasma_electron_density_weighted_kev, + ) + + # ======================================================================== + + # Shimomura (S) optimized H-mode scaling + elif i_confinement_time == 4: + t_electron_confinement = self.shimomura_confinement_time( + rmajor, rminor, b_plasma_toroidal_on_axis, kappa95, m_fuel_amu + ) + + # ======================================================================== + + # Kaye-Goldston scaling (L-mode) + elif i_confinement_time == 5: + t_electron_confinement = self.kaye_goldston_confinement_time( + pcur, + rmajor, + rminor, + kappa, + dnla20, + b_plasma_toroidal_on_axis, + m_fuel_amu, + p_plasma_loss_mw, + ) + + # ======================================================================== + + # ITER Power scaling - ITER 89-P (L-mode) + elif i_confinement_time == 6: + t_electron_confinement = self.iter_89p_confinement_time( + pcur, + rmajor, + rminor, + kappa, + dnla20, + b_plasma_toroidal_on_axis, + m_fuel_amu, + p_plasma_loss_mw, + ) + + # ======================================================================== + + # ITER Offset linear scaling - ITER 89-O (L-mode) + elif i_confinement_time == 7: + t_electron_confinement = self.iter_89_0_confinement_time( + pcur, + rmajor, + rminor, + kappa, + dnla20, + b_plasma_toroidal_on_axis, + m_fuel_amu, + p_plasma_loss_mw, + ) + # ======================================================================== + + # Rebut-Lallia offset linear scaling (L-mode) + elif i_confinement_time == 8: + t_electron_confinement = self.rebut_lallia_confinement_time( + rminor, + rmajor, + kappa, + m_fuel_amu, + pcur, + zeff, + dnla20, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + ) + + # ======================================================================== + + # Goldston scaling (L-mode) + elif i_confinement_time == 9: # Goldston scaling (L-mode) + t_electron_confinement = self.goldston_confinement_time( + pcur, rmajor, rminor, kappa95, m_fuel_amu, p_plasma_loss_mw + ) + + # ======================================================================== + + # T-10 scaling (L-mode) + elif i_confinement_time == 10: + t_electron_confinement = self.t10_confinement_time( + dnla20, + rmajor, + qstar, + b_plasma_toroidal_on_axis, + rminor, + kappa95, + p_plasma_loss_mw, + zeff, + pcur, + ) + + # ======================================================================== + + # JAERI / Odajima-Shimomura L-mode scaling + elif i_confinement_time == 11: # JAERI scaling + t_electron_confinement = self.jaeri_confinement_time( + kappa95, + rminor, + m_fuel_amu, + n20, + pcur, + b_plasma_toroidal_on_axis, + rmajor, + qstar, + zeff, + p_plasma_loss_mw, + ) + + # ======================================================================== + + # Kaye "big" L-mode scaling (based only on big tokamak data) + elif i_confinement_time == 12: + t_electron_confinement = self.kaye_big_confinement_time( + rmajor, + rminor, + b_plasma_toroidal_on_axis, + kappa95, + pcur, + n20, + m_fuel_amu, + p_plasma_loss_mw, + ) + + # ======================================================================== + + # ITER H90-P H-mode scaling + elif i_confinement_time == 13: + t_electron_confinement = self.iter_h90_p_confinement_time( + pcur, + rmajor, + rminor, + kappa, + dnla20, + b_plasma_toroidal_on_axis, + m_fuel_amu, + p_plasma_loss_mw, + ) + + # ======================================================================== + + # Minimum of ITER 89-P and ITER 89-O + elif i_confinement_time == 14: + t_electron_confinement = min( + self.iter_89p_confinement_time( + pcur, + rmajor, + rminor, + kappa, + dnla20, + b_plasma_toroidal_on_axis, + m_fuel_amu, + p_plasma_loss_mw, + ), + self.iter_89_0_confinement_time( + pcur, + rmajor, + rminor, + kappa, + dnla20, + b_plasma_toroidal_on_axis, + m_fuel_amu, + p_plasma_loss_mw, + ), + ) + + # ======================================================================== + + # Riedel scaling (L-mode) + elif i_confinement_time == 15: + t_electron_confinement = self.riedel_l_confinement_time( + pcur, + rmajor, + rminor, + kappa95, + dnla20, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + ) + + # ======================================================================== + + # Christiansen et al scaling (L-mode) + elif i_confinement_time == 16: + t_electron_confinement = self.christiansen_confinement_time( + pcur, + rmajor, + rminor, + kappa95, + dnla20, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + m_fuel_amu, + ) + + # ======================================================================== + + # Lackner-Gottardi scaling (L-mode) + elif i_confinement_time == 17: + t_electron_confinement = self.lackner_gottardi_confinement_time( + pcur, + rmajor, + rminor, + kappa95, + dnla20, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + ) + + # ======================================================================== + + # Neo-Kaye scaling (L-mode) + elif i_confinement_time == 18: + t_electron_confinement = self.neo_kaye_confinement_time( + pcur, + rmajor, + rminor, + kappa95, + dnla20, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + ) + + # ======== ================================================================ + + # Riedel scaling (H-mode) + elif i_confinement_time == 19: + t_electron_confinement = self.riedel_h_confinement_time( + pcur, + rmajor, + rminor, + kappa95, + dnla20, + b_plasma_toroidal_on_axis, + m_fuel_amu, + p_plasma_loss_mw, + ) + + # ======================================================================== + + # Amended version of ITER H90-P law + elif i_confinement_time == 20: + t_electron_confinement = self.iter_h90_p_amended_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + m_fuel_amu, + rmajor, + p_plasma_loss_mw, + kappa, + ) + + # ========================================================================== + + # Sudo et al. scaling (stellarators/heliotron) + elif i_confinement_time == 21: + t_electron_confinement = self.sudo_et_al_confinement_time( + rmajor, + rminor, + dnla20, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + ) + + # ========================================================================== + + # Gyro-reduced Bohm scaling + elif i_confinement_time == 22: + t_electron_confinement = self.gyro_reduced_bohm_confinement_time( + b_plasma_toroidal_on_axis, + dnla20, + p_plasma_loss_mw, + rminor, + rmajor, + ) + + # ========================================================================== + + # Lackner-Gottardi stellarator scaling + elif i_confinement_time == 23: + t_electron_confinement = self.lackner_gottardi_stellarator_confinement_time( + rmajor, + rminor, + dnla20, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + q95, + ) + + # ========================================================================== + + # ITER_93 ELM-free H-mode scaling + elif i_confinement_time == 24: + t_electron_confinement = self.iter_93h_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + m_fuel_amu, + rmajor, + dnla20, + aspect, + kappa, + ) + + # ========================================================================== + # Scaling removed + elif i_confinement_time == 25: + raise ProcessValueError("Scaling removed") + # ========================================================================== + + # ELM-free: ITERH-97P + elif i_confinement_time == 26: + t_electron_confinement = self.iter_h97p_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + dnla19, + rmajor, + aspect, + kappa, + m_fuel_amu, + ) + + # ========================================================================== + + # ELMy: ITERH-97P(y) + elif i_confinement_time == 27: + t_electron_confinement = self.iter_h97p_elmy_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + dnla19, + rmajor, + aspect, + kappa, + m_fuel_amu, + ) + + # ========================================================================== + + # ITER-96P (= ITER-97L) L-mode scaling + elif i_confinement_time == 28: + t_electron_confinement = self.iter_96p_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + kappa95, + rmajor, + aspect, + dnla19, + m_fuel_amu, + p_plasma_loss_mw, + ) + + # ========================================================================== + + # Valovic modified ELMy-H mode scaling + # WARNING: No reference found for this scaling. This may not be its real name + elif i_confinement_time == 29: + t_electron_confinement = self.valovic_elmy_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + m_fuel_amu, + rmajor, + rminor, + kappa, + p_plasma_loss_mw, + ) + + # ========================================================================== + + # Kaye PPPL Workshop April 1998 L-mode scaling + # WARNING: No reference found for this scaling. This may not be its real name + elif i_confinement_time == 30: + t_electron_confinement = self.kaye_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + kappa, + rmajor, + aspect, + dnla19, + m_fuel_amu, + p_plasma_loss_mw, + ) + + # ========================================================================== + + # ITERH-PB98P(y), ELMy H-mode scaling + # WARNING: No reference found for this scaling. This may not be its real name + elif i_confinement_time == 31: + t_electron_confinement = self.iter_pb98py_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + physics_variables.kappa_ipb, + aspect, + m_fuel_amu, + ) + + # ========================================================================== + + # IPB98(y), ELMy H-mode scaling + elif i_confinement_time == 32: + t_electron_confinement = self.iter_ipb98y_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + kappa, + aspect, + m_fuel_amu, + ) + + # ========================================================================== + + # IPB98(y,1), ELMy H-mode scaling + elif i_confinement_time == 33: + t_electron_confinement = self.iter_ipb98y1_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + physics_variables.kappa_ipb, + aspect, + m_fuel_amu, + ) + + # ========================================================================== + + # IPB98(y,2), ELMy H-mode scaling + elif i_confinement_time == 34: + t_electron_confinement = self.iter_ipb98y2_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + physics_variables.kappa_ipb, + aspect, + m_fuel_amu, + ) + + # ========================================================================== + + # IPB98(y,3), ELMy H-mode scaling + elif i_confinement_time == 35: + t_electron_confinement = self.iter_ipb98y3_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + physics_variables.kappa_ipb, + aspect, + m_fuel_amu, + ) + + # ========================================================================== + + # IPB98(y,4), ELMy H-mode scaling + elif i_confinement_time == 36: + t_electron_confinement = self.iter_ipb98y4_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + physics_variables.kappa_ipb, + aspect, + m_fuel_amu, + ) + + # ========================================================================== + + # ISS95 stellarator scaling + elif i_confinement_time == 37: + # dummy argument q95 is actual argument iotabar for stellarators + iotabar = q95 + t_electron_confinement = self.iss95_stellarator_confinement_time( + rminor, + rmajor, + dnla19, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + iotabar, + ) + + # ========================================================================== + + # ISS04 stellarator scaling + elif i_confinement_time == 38: + # dummy argument q95 is actual argument iotabar for stellarators + iotabar = q95 + t_electron_confinement = self.iss04_stellarator_confinement_time( + rminor, + rmajor, + dnla19, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + iotabar, + ) + + # ========================================================================== + + # DS03 beta-independent H-mode scaling + elif i_confinement_time == 39: + t_electron_confinement = self.ds03_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + kappa95, + aspect, + m_fuel_amu, + ) + + # ========================================================================== + + # Murari "Non-power law" scaling + elif i_confinement_time == 40: + t_electron_confinement = self.murari_confinement_time( + pcur, + rmajor, + physics_variables.kappa_ipb, + dnla19, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + ) + + # ========================================================================== + + # Petty08, beta independent dimensionless scaling + elif i_confinement_time == 41: + t_electron_confinement = self.petty08_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + physics_variables.kappa_ipb, + aspect, + ) + + # ========================================================================== + + # Lang high density relevant confinement scaling + elif i_confinement_time == 42: + t_electron_confinement = self.lang_high_density_confinement_time( + plasma_current, + b_plasma_toroidal_on_axis, + nd_plasma_electron_line, + p_plasma_loss_mw, + rmajor, + rminor, + q95, + qstar, + aspect, + m_fuel_amu, + physics_variables.kappa_ipb, + ) + + # ========================================================================== + + # Hubbard 2017 I-mode confinement time scaling - nominal + elif i_confinement_time == 43: + t_electron_confinement = self.hubbard_nominal_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla20, + p_plasma_loss_mw, + ) + + # ========================================================================== + + # Hubbard 2017 I-mode confinement time scaling - lower + elif i_confinement_time == 44: + t_electron_confinement = self.hubbard_lower_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla20, + p_plasma_loss_mw, + ) + + # ========================================================================== + + # Hubbard 2017 I-mode confinement time scaling - upper + elif i_confinement_time == 45: + t_electron_confinement = self.hubbard_upper_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla20, + p_plasma_loss_mw, + ) + + # ========================================================================== + + # Menard NSTX, ELMy H-mode scaling + elif i_confinement_time == 46: + t_electron_confinement = self.menard_nstx_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + physics_variables.kappa_ipb, + aspect, + m_fuel_amu, + ) + + # ========================================================================== + + # Menard NSTX-Petty08 Hybrid + elif i_confinement_time == 47: + t_electron_confinement = self.menard_nstx_petty08_hybrid_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + physics_variables.kappa_ipb, + aspect, + m_fuel_amu, + ) + + # ========================================================================== + + # NSTX gyro-Bohm (Buxton) + elif i_confinement_time == 48: + t_electron_confinement = self.nstx_gyro_bohm_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + rmajor, + dnla20, + ) + + # ========================================================================== + + # ITPA20 H-mode scaling + elif i_confinement_time == 49: + t_electron_confinement = self.itpa20_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + physics_variables.triang, + physics_variables.kappa_ipb, + eps, + physics_variables.m_ions_total_amu, + ) + + # ========================================================================== + + # ITPA20-IL confinement time scaling + elif i_confinement_time == 50: + t_electron_confinement = self.itpa20_il_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + p_plasma_loss_mw, + dnla19, + physics_variables.m_ions_total_amu, + rmajor, + physics_variables.triang, + physics_variables.kappa_ipb, + ) + + # ========================================================================== + + else: + raise ProcessValueError( + "Illegal value for i_confinement_time", + i_confinement_time=i_confinement_time, + ) + + # Apply H-factor correction to chosen scaling + t_electron_energy_confinement = hfact * t_electron_confinement + + # Ion energy confinement time + t_ion_energy_confinement = t_electron_energy_confinement + + # Calculate H* non-radiation corrected H factor + # Note: we will assume the IPB-98y2 scaling. + if physics_variables.i_rad_loss == 1: + physics_variables.hstar = ( + hfact + * ( + p_plasma_loss_mw + / ( + p_plasma_loss_mw + + physics_variables.pden_plasma_sync_mw * vol_plasma + + physics_variables.p_plasma_inner_rad_mw + ) + ) + ** 0.31 + ) + elif physics_variables.i_rad_loss == 0: + physics_variables.hstar = ( + hfact + * ( + p_plasma_loss_mw + / ( + p_plasma_loss_mw + + physics_variables.pden_plasma_rad_mw * vol_plasma + ) + ) + ** 0.31 + ) + elif physics_variables.i_rad_loss == 2: + physics_variables.hstar = hfact + + # Calculation of the transport power loss terms + # Transport losses in Watts/m3 are 3/2 * n.e.T / tau , with T in eV + # (here, temp_plasma_ion_density_weighted_kev and temp_plasma_electron_density_weighted_kev are in keV, and pden_electron_transport_loss_mw and pden_ion_transport_loss_mw are in MW/m3) + + # The transport losses is just the electron and ion thermal energies divided by the confinement time. + pden_ion_transport_loss_mw = ( + (3 / 2) + * (constants.ELECTRON_CHARGE / 1e3) + * nd_plasma_ions_total_vol_avg + * temp_plasma_ion_density_weighted_kev + / t_ion_energy_confinement + ) + pden_electron_transport_loss_mw = ( + (3 / 2) + * (constants.ELECTRON_CHARGE / 1e3) + * nd_plasma_electrons_vol_avg + * temp_plasma_electron_density_weighted_kev + / t_electron_energy_confinement ) - # Equivalent to A < 1.7, use NSTX scaling - if (1.0e0 / aspect) >= 0.6e0: - return menard_nstx_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - kappa_ipb, - aspect, - afuel, + ratio = (nd_plasma_ions_total_vol_avg / nd_plasma_electrons_vol_avg) * ( + temp_plasma_ion_density_weighted_kev + / temp_plasma_electron_density_weighted_kev ) - return (((1.0e0 / aspect) - 0.4e0) / (0.6e0 - 0.4e0)) * ( - menard_nstx_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - kappa_ipb, - aspect, - afuel, + + # Global energy confinement time + + t_energy_confinement = (ratio + 1.0e0) / ( + ratio / t_ion_energy_confinement + 1.0e0 / t_electron_energy_confinement ) - ) + ((0.6e0 - (1.0e0 / aspect)) / (0.6e0 - 0.4e0)) * ( - petty08_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, + + # For comparison directly calculate the confinement time from the stored energy calculated + # from the total plasma beta and the loss power used above. + physics_variables.t_energy_confinement_beta = ( + physics_variables.e_plasma_beta / 1e6 + ) / p_plasma_loss_mw + + return ( + pden_electron_transport_loss_mw, + pden_ion_transport_loss_mw, + t_electron_energy_confinement, + t_ion_energy_confinement, + t_energy_confinement, p_plasma_loss_mw, - rmajor, - kappa_ipb, - aspect, ) - ) - - -def nstx_gyro_bohm_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, - rmajor: float, - dnla20: float, -) -> float: - """Calculate the NSTX gyro-Bohm confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Net Heating power [MW] - rmajor : - Plasma major radius [m] - dnla20 : - Line averaged electron density in units of 10**20 m**-3 - - Returns - ------- - : - float: NSTX gyro-Bohm confinement time [s] - - References: - - P. F. Buxton, L. Connor, A. E. Costley, Mikhail Gryaznevich, and S. McNamara, - “On the energy confinement time in spherical tokamaks: implications for the design of pilot plants and fusion reactors,” - vol. 61, no. 3, pp. 035006-035006, Jan. 2019, doi: https://doi.org/10.1088/1361-6587/aaf7e5. - """ - return ( - 0.21e0 - * pcur**0.54e0 - * b_plasma_toroidal_on_axis**0.91e0 - * p_plasma_loss_mw ** (-0.38e0) - * rmajor**2.14e0 - * dnla20 ** (-0.05e0) - ) - - -def itpa20_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - dnla19: float, - p_plasma_loss_mw: float, - rmajor: float, - triang: float, - kappa_ipb: float, - eps: float, - aion: float, -) -> float: - """Calculate the ITPA20 Issue #3164 confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - dnla19 : - Central line-averaged electron density in units of 10**19 m**-3 - p_plasma_loss_mw : - Thermal power lost due to transport through the LCFS [MW] - rmajor : - Plasma major radius [m] - triang : - Triangularity - kappa_ipb : - IPB specific plasma separatrix elongation - eps : - Inverse aspect ratio - aion : - Average mass of all ions (amu) - - Returns - ------- - : - float: ITPA20 confinement time [s] - - Notes: - - Mass term is the effective mass of the plasma, so we assume the total ion mass here - - This scaling uses the IPB defintiion of elongation, see reference for more information. - - References: - - G. Verdoolaege et al., “The updated ITPA global H-mode confinement database: description and analysis,” - Nuclear Fusion, vol. 61, no. 7, pp. 076006-076006, Jan. 2021, doi: https://doi.org/10.1088/1741-4326/abdb91. - """ - return ( - 0.053 - * pcur**0.98 - * b_plasma_toroidal_on_axis**0.22 - * dnla19**0.24 - * p_plasma_loss_mw ** (-0.669) - * rmajor**1.71 - * (1 + triang) ** 0.36 - * kappa_ipb**0.8 - * eps**0.35 - * aion**0.2 - ) - - -def itpa20_il_confinement_time( - pcur: float, - b_plasma_toroidal_on_axis: float, - p_plasma_loss_mw: float, - dnla19: float, - aion: float, - rmajor: float, - triang: float, - kappa_ipb: float, -) -> float: - """Calculate the ITPA20-IL Issue #1852 confinement time - - Parameters - ---------- - pcur : - Plasma current [MA] - b_plasma_toroidal_on_axis : - Toroidal magnetic field [T] - p_plasma_loss_mw : - Thermal power lost due to transport through the LCFS [MW] - dnla19 : - Central line-averaged electron density in units of 10**19 m**-3 - aion : - Average mass of all ions (amu) - rmajor : - Plasma major radius [m] - triang : - Triangularity - kappa_ipb : - IPB specific plasma separatrix elongation - - Returns - ------- - : - float: ITPA20-IL confinement time [s] - - Notes: - - Mass term is the effective mass of the plasma, so we assume the total ion mass here - - This scaling uses the IPB defintiion of elongation, see reference for more information. - - References: - - T. Luda et al., “Validation of a full-plasma integrated modeling approach on ASDEX Upgrade,” - Nuclear Fusion, vol. 61, no. 12, pp. 126048-126048, Nov. 2021, doi: https://doi.org/10.1088/1741-4326/ac3293. - """ - - return ( - 0.067 - * pcur**1.29 - * b_plasma_toroidal_on_axis**-0.13 - * p_plasma_loss_mw ** (-0.644) - * dnla19**0.15 - * aion**0.3 - * rmajor**1.19 - * (1 + triang) ** 0.56 - * kappa_ipb**0.67 - ) + + @staticmethod + def neo_alcator_confinement_time( + dene20: float, rminor: float, rmajor: float, qstar: float + ) -> float: + """Calculate the Nec-Alcator(NA) OH scaling confinement time + + Parameters + ---------- + dene20 : + Volume averaged electron density in units of 10**20 m**-3 + rminor : + Plasma minor radius [m] + rmajor : + Plasma major radius [m] + qstar : + Equivalent cylindrical edge safety factor + + Returns + ------- + : + float: Neo-Alcator confinement time [s] + + + References: + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + return 0.07e0 * dene20 * rminor * rmajor * rmajor * qstar + + @staticmethod + def mirnov_confinement_time(rminor: float, kappa95: float, pcur: float) -> float: + """Calculate the Mirnov scaling (H-mode) confinement time + + Parameters + ---------- + rminor : + Plasma minor radius [m] + kappa95 : + Plasma elongation at 95% flux surface + pcur : + Plasma current [MA] + + Returns + ------- + : + float: Mirnov scaling confinement time [s] + + References: + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + return 0.2e0 * rminor * np.sqrt(kappa95) * pcur + + @staticmethod + def merezhkin_muhkovatov_confinement_time( + rmajor: float, + rminor: float, + kappa95: float, + qstar: float, + dnla20: float, + afuel: float, + ten: float, + ) -> float: + """Calculate the Merezhkin-Mukhovatov (MM) OH/L-mode scaling confinement time + + Parameters + ---------- + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa95 : + Plasma elongation at 95% flux surface + qstar : + Equivalent cylindrical edge safety factor + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + afuel : + Fuel atomic mass number + ten : + Electron temperature [keV] + + Returns + ------- + : + float: Merezhkin-Mukhovatov confinement time [s] + + + References: + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + return ( + 3.5e-3 + * rmajor**2.75e0 + * rminor**0.25e0 + * kappa95**0.125e0 + * qstar + * dnla20 + * np.sqrt(afuel) + / np.sqrt(ten / 10.0e0) + ) + + @staticmethod + def shimomura_confinement_time( + rmajor: float, + rminor: float, + b_plasma_toroidal_on_axis: float, + kappa95: float, + afuel: float, + ) -> float: + """Calculate the Shimomura (S) optimized H-mode scaling confinement time + + Parameters + ---------- + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + kappa95 : + Plasma elongation at 95% flux surface + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: Shimomura confinement time [s] + + References: + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + return ( + 0.045e0 + * rmajor + * rminor + * b_plasma_toroidal_on_axis + * np.sqrt(kappa95) + * np.sqrt(afuel) + ) + + @staticmethod + def kaye_goldston_confinement_time( + kappa95: float, + pcur: float, + n20: float, + rmajor: float, + afuel: float, + b_plasma_toroidal_on_axis: float, + rminor: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Kaye-Goldston (KG) L-mode scaling confinement time + + Parameters + ---------- + kappa95 : + Plasma elongation at 95% flux surface + pcur : + Plasma current [MA] + n20 : + Line averaged electron density in units of 10**20 m**-3 + rmajor : + Plasma major radius [m] + afuel : + Fuel atomic mass number + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + rminor : + Plasma minor radius [m] + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Kaye-Goldston confinement time [s] + + Notes: + - An isotope correction factor (M_i/1.5)^0.5 is added to the original scaling to reflect the fact + that the empirical fits to the data were from experiments with H and D mixture, M_i = 1.5 + + References: + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + return ( + 0.055e0 + * kappa95**0.28e0 + * pcur**1.24e0 + * n20**0.26e0 + * rmajor**1.65e0 + * np.sqrt(afuel / 1.5e0) + / ( + b_plasma_toroidal_on_axis**0.09e0 + * rminor**0.49e0 + * p_plasma_loss_mw**0.58e0 + ) + ) + + @staticmethod + def iter_89p_confinement_time( + pcur: float, + rmajor: float, + rminor: float, + kappa: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + afuel: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the ITER Power scaling - ITER 89-P (L-mode) confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa : + Plasma elongation + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + afuel : + Fuel atomic mass number + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: ITER 89-P confinement time [s] + + + References: + - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 + + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + return ( + 0.048e0 + * pcur**0.85e0 + * rmajor**1.2e0 + * rminor**0.3e0 + * np.sqrt(kappa) + * dnla20**0.1e0 + * b_plasma_toroidal_on_axis**0.2e0 + * np.sqrt(afuel) + / np.sqrt(p_plasma_loss_mw) + ) + + @staticmethod + def iter_89_0_confinement_time( + pcur: float, + rmajor: float, + rminor: float, + kappa: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + afuel: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the ITER Offset linear scaling - ITER 89-O (L-mode) confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa : + Plasma elongation + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + afuel : + Fuel atomic mass number + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: ITER 89-O confinement time [s] + + References: + - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 + """ + term1 = ( + 0.04e0 + * pcur**0.5e0 + * rmajor**0.3e0 + * rminor**0.8e0 + * kappa**0.6e0 + * afuel**0.5e0 + ) + term2 = ( + 0.064e0 + * pcur**0.8e0 + * rmajor**1.6e0 + * rminor**0.6e0 + * kappa**0.5e0 + * dnla20**0.6e0 + * b_plasma_toroidal_on_axis**0.35e0 + * afuel**0.2e0 + / p_plasma_loss_mw + ) + return term1 + term2 + + @staticmethod + def rebut_lallia_confinement_time( + rminor: float, + rmajor: float, + kappa: float, + afuel: float, + pcur: float, + zeff: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Rebut-Lallia offset linear scaling (L-mode) confinement time + + Parameters + ---------- + rminor : + Plasma minor radius [m] + rmajor : + Plasma major radius [m] + kappa : + Plasma elongation at 95% flux surface + afuel : + Fuel atomic mass number + pcur : + Plasma current [MA] + zeff : + Effective charge + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Rebut-Lallia confinement time [s] + + + References: + - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 + """ + rll = (rminor**2 * rmajor * kappa) ** (1.0e0 / 3.0e0) + term1 = 1.2e-2 * pcur * rll**1.5e0 / np.sqrt(zeff) + term2 = ( + 0.146e0 + * dnla20**0.75e0 + * np.sqrt(pcur) + * np.sqrt(b_plasma_toroidal_on_axis) + * rll**2.75e0 + * zeff**0.25e0 + / p_plasma_loss_mw + ) + return 1.65e0 * np.sqrt(afuel / 2.0e0) * (term1 + term2) + + @staticmethod + def goldston_confinement_time( + pcur: float, + rmajor: float, + rminor: float, + kappa95: float, + afuel: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Goldston scaling (L-mode) confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa95 : + Plasma elongation at 95% flux surface + afuel : + Fuel atomic mass number + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Goldston confinement time [s] + + References: + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + return ( + 0.037e0 + * pcur + * rmajor**1.75e0 + * rminor ** (-0.37e0) + * np.sqrt(kappa95) + * np.sqrt(afuel / 1.5e0) + / np.sqrt(p_plasma_loss_mw) + ) + + @staticmethod + def t10_confinement_time( + dnla20: float, + rmajor: float, + qstar: float, + b_plasma_toroidal_on_axis: float, + rminor: float, + kappa95: float, + p_plasma_loss_mw: float, + zeff: float, + pcur: float, + ) -> float: + """Calculate the T-10 scaling confinement time + + Parameters + ---------- + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + rmajor : + Plasma major radius [m] + qstar : + Equivalent cylindrical edge safety factor + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + rminor : + Plasma minor radius [m] + kappa95 : + Plasma elongation at 95% flux surface + p_plasma_loss_mw : + Net Heating power [MW] + zeff : + Effective charge + pcur : + Plasma current [MA] + + Returns + ------- + : + float: T-10 confinement time [s] + + References: + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + denfac = dnla20 * rmajor * qstar / (1.3e0 * b_plasma_toroidal_on_axis) + denfac = min(1.0e0, denfac) + return ( + 0.095e0 + * rmajor + * rminor + * b_plasma_toroidal_on_axis + * np.sqrt(kappa95) + * denfac + / p_plasma_loss_mw**0.4e0 + * (zeff**2 * pcur**4 / (rmajor * rminor * qstar**3 * kappa95**1.5e0)) + ** 0.08e0 + ) + + @staticmethod + def jaeri_confinement_time( + kappa95: float, + rminor: float, + afuel: float, + n20: float, + pcur: float, + b_plasma_toroidal_on_axis: float, + rmajor: float, + qstar: float, + zeff: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the JAERI / Odajima-Shimomura L-mode scaling confinement time + + Parameters + ---------- + kappa95 : + Plasma elongation at 95% flux surface + rminor : + Plasma minor radius [m] + afuel : + Fuel atomic mass number + n20 : + Line averaged electron density in units of 10**20 m**-3 + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + rmajor : + Plasma major radius [m] + qstar : + Equivalent cylindrical edge safety factor + zeff : + Effective charge + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: JAERI confinement time [s] + + References: + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + gjaeri = ( + zeff**0.4e0 + * ((15.0e0 - zeff) / 20.0e0) ** 0.6e0 + * (3.0e0 * qstar * (qstar + 5.0e0) / ((qstar + 2.0e0) * (qstar + 7.0e0))) + ** 0.6e0 + ) + return ( + 0.085e0 * kappa95 * rminor**2 * np.sqrt(afuel) + + 0.069e0 + * n20**0.6e0 + * pcur + * b_plasma_toroidal_on_axis**0.2e0 + * rminor**0.4e0 + * rmajor**1.6e0 + * np.sqrt(afuel) + * gjaeri + * kappa95**0.2e0 + / p_plasma_loss_mw + ) + + @staticmethod + def kaye_big_confinement_time( + rmajor: float, + rminor: float, + b_plasma_toroidal_on_axis: float, + kappa95: float, + pcur: float, + n20: float, + afuel: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Kaye-Big scaling confinement time + + Parameters + ---------- + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + kappa95 : + Plasma elongation at 95% flux surface + pcur : + Plasma current [MA] + n20 : + Line averaged electron density in units of 10**20 m**-3 + afuel : + Fuel atomic mass number + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Kaye-Big confinement time [s] + + + References: + - N. A. Uckan, International Atomic Energy Agency, Vienna (Austria)and ITER Physics Group, + "ITER physics design guidelines: 1989", no. No. 10. Feb. 1990. + """ + return ( + 0.105e0 + * np.sqrt(rmajor) + * rminor**0.8e0 + * b_plasma_toroidal_on_axis**0.3e0 + * kappa95**0.25e0 + * pcur**0.85e0 + * n20**0.1e0 + * np.sqrt(afuel) + / np.sqrt(p_plasma_loss_mw) + ) + + @staticmethod + def iter_h90_p_confinement_time( + pcur: float, + rmajor: float, + rminor: float, + kappa: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + afuel: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the ITER H-mode scaling - ITER H90-P confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa : + Plasma elongation + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + afuel : + Fuel atomic mass number + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: ITER H90-P confinement time [s] + + + References: + - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 + """ + return ( + 0.064e0 + * pcur**0.87e0 + * rmajor**1.82e0 + * rminor ** (-0.12e0) + * kappa**0.35e0 + * dnla20**0.09e0 + * b_plasma_toroidal_on_axis**0.15e0 + * np.sqrt(afuel) + / np.sqrt(p_plasma_loss_mw) + ) + + @staticmethod + def riedel_l_confinement_time( + pcur: float, + rmajor: float, + rminor: float, + kappa95: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Riedel scaling (L-mode) confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa95 : + Plasma elongation at 95% flux surface + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Riedel confinement time [s] + + References: + - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 + """ + return ( + 0.044e0 + * pcur**0.93e0 + * rmajor**1.37e0 + * rminor ** (-0.049e0) + * kappa95**0.588e0 + * dnla20**0.078e0 + * b_plasma_toroidal_on_axis**0.152e0 + / p_plasma_loss_mw**0.537e0 + ) + + @staticmethod + def christiansen_confinement_time( + pcur: float, + rmajor: float, + rminor: float, + kappa95: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + afuel: float, + ) -> float: + """Calculate the Christiansen et al scaling (L-mode) confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa95 : + Plasma elongation at 95% flux surface + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: Christiansen confinement time [s] + + References: + - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 + """ + return ( + 0.24e0 + * pcur**0.79e0 + * rmajor**0.56e0 + * rminor**1.46e0 + * kappa95**0.73e0 + * dnla20**0.41e0 + * b_plasma_toroidal_on_axis**0.29e0 + / (p_plasma_loss_mw**0.79e0 * afuel**0.02e0) + ) + + @staticmethod + def lackner_gottardi_confinement_time( + pcur: float, + rmajor: float, + rminor: float, + kappa95: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Lackner-Gottardi scaling (L-mode) confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa95 : + Plasma elongation at 95% flux surface + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Lackner-Gottardi confinement time [s] + + References: + - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 + """ + qhat = ( + (1.0e0 + kappa95**2) + * rminor**2 + * b_plasma_toroidal_on_axis + / (0.4e0 * pcur * rmajor) + ) + return ( + 0.12e0 + * pcur**0.8e0 + * rmajor**1.8e0 + * rminor**0.4e0 + * kappa95 + * (1.0e0 + kappa95) ** (-0.8e0) + * dnla20**0.6e0 + * qhat**0.4e0 + / p_plasma_loss_mw**0.6e0 + ) + + @staticmethod + def neo_kaye_confinement_time( + pcur: float, + rmajor: float, + rminor: float, + kappa95: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Neo-Kaye scaling (L-mode) confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa95 : + Plasma elongation at 95% flux surface + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Neo-Kaye confinement time [s] + + + References: + - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 + """ + return ( + 0.063e0 + * pcur**1.12e0 + * rmajor**1.3e0 + * rminor ** (-0.04e0) + * kappa95**0.28e0 + * dnla20**0.14e0 + * b_plasma_toroidal_on_axis**0.04e0 + / p_plasma_loss_mw**0.59e0 + ) + + @staticmethod + def riedel_h_confinement_time( + pcur: float, + rmajor: float, + rminor: float, + kappa95: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + afuel: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Riedel scaling (H-mode) confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa95 : + Plasma elongation at 95% flux surface + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + afuel : + Fuel atomic mass number + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Riedel H-mode confinement time [s] + + References: + - T.C.Hender et.al., 'Physics Assesment of the European Reactor Study', AEA FUS 172, 1992 + """ + return ( + 0.1e0 + * np.sqrt(afuel) + * pcur**0.884e0 + * rmajor**1.24e0 + * rminor ** (-0.23e0) + * kappa95**0.317e0 + * b_plasma_toroidal_on_axis**0.207e0 + * dnla20**0.105e0 + / p_plasma_loss_mw**0.486e0 + ) + + @staticmethod + def iter_h90_p_amended_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + afuel: float, + rmajor: float, + p_plasma_loss_mw: float, + kappa: float, + ) -> float: + """Calculate the amended ITER H90-P confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + afuel : + Fuel atomic mass number + rmajor : + Plasma major radius [m] + p_plasma_loss_mw : + Net Heating power [MW] + kappa : + Plasma elongation + + Returns + ------- + : + float: Amended ITER H90-P confinement time [s] + + References: + - J. P. Christiansen et al., “Global energy confinement H-mode database for ITER,” + Nuclear Fusion, vol. 32, no. 2, pp. 291-338, Feb. 1992, + doi: https://doi.org/10.1088/0029-5515/32/2/i11. + """ + return ( + 0.082e0 + * pcur**1.02e0 + * b_plasma_toroidal_on_axis**0.15e0 + * np.sqrt(afuel) + * rmajor**1.60e0 + / (p_plasma_loss_mw**0.47e0 * kappa**0.19e0) + ) + + @staticmethod + def sudo_et_al_confinement_time( + rmajor: float, + rminor: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Sudo et al. scaling confinement time + + Parameters + ---------- + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Sudo et al. confinement time [s] + + References: + - S. Sudo et al., “Scalings of energy confinement and density limit in stellarator/heliotron devices,” + Nuclear Fusion, vol. 30, no. 1, pp. 11-21, Jan. 1990, + doi: https://doi.org/10.1088/0029-5515/30/1/002. + """ + + return ( + 0.17e0 + * rmajor**0.75e0 + * rminor**2 + * dnla20**0.69e0 + * b_plasma_toroidal_on_axis**0.84e0 + * p_plasma_loss_mw ** (-0.58e0) + ) + + @staticmethod + def gyro_reduced_bohm_confinement_time( + b_plasma_toroidal_on_axis: float, + dnla20: float, + p_plasma_loss_mw: float, + rminor: float, + rmajor: float, + ) -> float: + """Calculate the Gyro-reduced Bohm scaling confinement time + + Parameters + ---------- + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rminor : + Plasma minor radius [m] + rmajor : + Plasma major radius [m] + + Returns + ------- + : + float: Gyro-reduced Bohm confinement time [s] + + References: + - Goldston, R. J., H. Biglari, and G. W. Hammett. "E x B/B 2 vs. μ B/B as the Cause of Transport in Tokamaks." + Bull. Am. Phys. Soc 34 (1989): 1964. + """ + return ( + 0.25e0 + * b_plasma_toroidal_on_axis**0.8e0 + * dnla20**0.6e0 + * p_plasma_loss_mw ** (-0.6e0) + * rminor**2.4e0 + * rmajor**0.6e0 + ) + + @staticmethod + def lackner_gottardi_stellarator_confinement_time( + rmajor: float, + rminor: float, + dnla20: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + q: float, + ) -> float: + """Calculate the Lackner-Gottardi stellarator scaling confinement time + + Parameters + ---------- + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + q : + Edge safety factor + + Returns + ------- + : + float: Lackner-Gottardi stellarator confinement time [s] + + References: + - K. Lackner and N. A. O. Gottardi, “Tokamak confinement in relation to plateau scaling,” + Nuclear Fusion, vol. 30, no. 4, pp. 767-770, Apr. 1990, + doi: https://doi.org/10.1088/0029-5515/30/4/018. + """ + return ( + 0.17e0 + * rmajor + * rminor**2 + * dnla20**0.6e0 + * b_plasma_toroidal_on_axis**0.8e0 + * p_plasma_loss_mw ** (-0.6e0) + * q**0.4e0 + ) + + @staticmethod + def iter_93h_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + afuel: float, + rmajor: float, + dnla20: float, + aspect: float, + kappa: float, + ) -> float: + """Calculate the ITER-93H scaling ELM-free confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + afuel : + Fuel atomic mass number + rmajor : + Plasma major radius [m] + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + aspect : + Aspect ratio + kappa : + Plasma elongation + + Returns + ------- + : + float: ITER-93H confinement time [s] + + References: + - K. Thomsen et al., “ITER H mode confinement database update,” + vol. 34, no. 1, pp. 131-167, Jan. 1994, doi: https://doi.org/10.1088/0029-5515/34/1/i10. + """ + return ( + 0.036e0 + * pcur**1.06e0 + * b_plasma_toroidal_on_axis**0.32e0 + * p_plasma_loss_mw ** (-0.67e0) + * afuel**0.41e0 + * rmajor**1.79e0 + * dnla20**0.17e0 + * aspect**0.11e0 + * kappa**0.66e0 + ) + + @staticmethod + def iter_h97p_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + dnla19: float, + rmajor: float, + aspect: float, + kappa: float, + afuel: float, + ) -> float: + """Calculate the ELM-free ITER H-mode scaling - ITER H97-P confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + rmajor : + Plasma major radius [m] + aspect : + Aspect ratio + kappa : + Plasma elongation + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: ITER H97-P confinement time [s] + + References: + - I. C. Database and M. W. G. (presented Cordey), “Energy confinement scaling and the extrapolation to ITER,” + Plasma Physics and Controlled Fusion, vol. 39, no. 12B, pp. B115-B127, Dec. 1997, + doi: https://doi.org/10.1088/0741-3335/39/12b/009. + """ + return ( + 0.031e0 + * pcur**0.95e0 + * b_plasma_toroidal_on_axis**0.25e0 + * p_plasma_loss_mw ** (-0.67e0) + * dnla19**0.35e0 + * rmajor**1.92e0 + * aspect ** (-0.08e0) + * kappa**0.63e0 + * afuel**0.42e0 + ) + + @staticmethod + def iter_h97p_elmy_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + dnla19: float, + rmajor: float, + aspect: float, + kappa: float, + afuel: float, + ) -> float: + """Calculate the ELMy ITER H-mode scaling - ITER H97-P(y) confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + rmajor : + Plasma major radius [m] + aspect : + Aspect ratio + kappa : + Plasma elongation + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: ITER H97-P(y) confinement time [s] + + References: + - I. C. Database and M. W. G. (presented Cordey), “Energy confinement scaling and the extrapolation to ITER,” + Plasma Physics and Controlled Fusion, vol. 39, no. 12B, pp. B115-B127, Dec. 1997, + doi: https://doi.org/10.1088/0741-3335/39/12b/009. + + - International Atomic Energy Agency, Vienna (Austria), "Technical basis for the ITER final design report, cost review and safety analysis (FDR)", + no.16. Dec. 1998. + """ + return ( + 0.029e0 + * pcur**0.90e0 + * b_plasma_toroidal_on_axis**0.20e0 + * p_plasma_loss_mw ** (-0.66e0) + * dnla19**0.40e0 + * rmajor**2.03e0 + * aspect ** (-0.19e0) + * kappa**0.92e0 + * afuel**0.2e0 + ) + + @staticmethod + def iter_96p_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + kappa95: float, + rmajor: float, + aspect: float, + dnla19: float, + afuel: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the ITER-96P (= ITER-97L) L-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + kappa95 : + Plasma elongation at 95% flux surface + rmajor : + Plasma major radius [m] + aspect : + Aspect ratio + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + afuel : + Fuel atomic mass number + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: ITER-96P confinement time [s] + + Notes: + - The thermal energy confinement time is given below + + References: + - S. B. Kaye et al., “ITER L mode confinement database,” + Nuclear Fusion, vol. 37, no. 9, pp. 1303-1328, Sep. 1997, + doi: https://doi.org/10.1088/0029-5515/37/9/i10. + """ + return ( + 0.023e0 + * pcur**0.96e0 + * b_plasma_toroidal_on_axis**0.03e0 + * kappa95**0.64e0 + * rmajor**1.83e0 + * aspect**0.06e0 + * dnla19**0.40e0 + * afuel**0.20e0 + * p_plasma_loss_mw ** (-0.73e0) + ) + + @staticmethod + def valovic_elmy_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + afuel: float, + rmajor: float, + rminor: float, + kappa: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Valovic modified ELMy-H mode scaling confinement time + + Parameters + ---------- + hfact : + H-factor + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + afuel : + Fuel atomic mass number + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + kappa : + Plasma elongation + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Valovic modified ELMy-H mode confinement time [s] + """ + return ( + 0.067e0 + * pcur**0.9e0 + * b_plasma_toroidal_on_axis**0.17e0 + * dnla19**0.45e0 + * afuel**0.05e0 + * rmajor**1.316e0 + * rminor**0.79e0 + * kappa**0.56e0 + * p_plasma_loss_mw ** (-0.68e0) + ) + + @staticmethod + def kaye_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + kappa: float, + rmajor: float, + aspect: float, + dnla19: float, + afuel: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Kaye PPPL Workshop April 1998 L-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + kappa : + Plasma elongation + rmajor : + Plasma major radius [m] + aspect : + Aspect ratio + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + afuel : + Fuel atomic mass number + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Kaye PPPL Workshop confinement time [s] + + References: + - Kaye PPPL Workshop April 1998 + """ + return ( + 0.021e0 + * pcur**0.81e0 + * b_plasma_toroidal_on_axis**0.14e0 + * kappa**0.7e0 + * rmajor**2.01e0 + * aspect ** (-0.18e0) + * dnla19**0.47e0 + * afuel**0.25e0 + * p_plasma_loss_mw ** (-0.73e0) + ) + + @staticmethod + def iter_pb98py_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa: float, + aspect: float, + afuel: float, + ) -> float: + """Calculate the ITERH-PB98P(y) ELMy H-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa : + Plasma separatrix elongation + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: ITERH-PB98P(y) ELMy H-mode confinement time [s] + """ + return ( + 0.0615e0 + * pcur**0.9e0 + * b_plasma_toroidal_on_axis**0.1e0 + * dnla19**0.4e0 + * p_plasma_loss_mw ** (-0.66e0) + * rmajor**2 + * kappa**0.75e0 + * aspect ** (-0.66e0) + * afuel**0.2e0 + ) + + @staticmethod + def iter_ipb98y_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa: float, + aspect: float, + afuel: float, + ) -> float: + """Calculate the IPB98(y) ELMy H-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa : + IPB sprcific plasma separatrix elongation + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: IPB98(y) ELMy H-mode confinement time [s] + + Notes: + - Unlike the other IPB98 scaling laws, the IPB98(y) scaling law uses the true separatrix elongation. + - See correction paper below for more information + + References: + - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” + Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. + + - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” + Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. + """ + return ( + 0.0365e0 + * pcur**0.97e0 + * b_plasma_toroidal_on_axis**0.08e0 + * dnla19**0.41e0 + * p_plasma_loss_mw ** (-0.63e0) + * rmajor**1.93e0 + * kappa**0.67e0 + * aspect ** (-0.23e0) + * afuel**0.2e0 + ) + + @staticmethod + def iter_ipb98y1_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa_ipb: float, + aspect: float, + afuel: float, + ) -> float: + """Calculate the IPB98(y,1) ELMy H-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa_ipb : + IPB specific plasma separatrix elongation + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: IPB98(y,1) ELMy H-mode confinement time [s] + + Notes: + - See correction paper below for more information about the re-definition of the elongation used. + + References: + - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” + Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. + + - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” + Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. + """ + return ( + 0.0503e0 + * pcur**0.91e0 + * b_plasma_toroidal_on_axis**0.15e0 + * dnla19**0.44e0 + * p_plasma_loss_mw ** (-0.65e0) + * rmajor**2.05e0 + * kappa_ipb**0.72e0 + * aspect ** (-0.57e0) + * afuel**0.13e0 + ) + + @staticmethod + def iter_ipb98y2_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa_ipb: float, + aspect: float, + afuel: float, + ) -> float: + """Calculate the IPB98(y,2) ELMy H-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa_ipb : + IPB specific plasma separatrix elongation + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: IPB98(y,2) ELMy H-mode confinement time [s] + + Notes: + - See correction paper below for more information about the re-definition of the elongation used. + + References: + - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” + Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. + + - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” + Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. + """ + return ( + 0.0562e0 + * pcur**0.93e0 + * b_plasma_toroidal_on_axis**0.15e0 + * dnla19**0.41e0 + * p_plasma_loss_mw ** (-0.69e0) + * rmajor**1.97e0 + * kappa_ipb**0.78e0 + * aspect ** (-0.58e0) + * afuel**0.19e0 + ) + + @staticmethod + def iter_ipb98y3_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa_ipb: float, + aspect: float, + afuel: float, + ) -> float: + """Calculate the IPB98(y,3) ELMy H-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa_ipb : + IPB specific plasma separatrix elongation + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: IPB98(y,3) ELMy H-mode confinement time [s] + + Notes: + - See correction paper below for more information about the re-definition of the elongation used. + + References: + - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” + Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. + + - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” + Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. + """ + return ( + 0.0564e0 + * pcur**0.88e0 + * b_plasma_toroidal_on_axis**0.07e0 + * dnla19**0.40e0 + * p_plasma_loss_mw ** (-0.69e0) + * rmajor**2.15e0 + * kappa_ipb**0.78e0 + * aspect ** (-0.64e0) + * afuel**0.20e0 + ) + + @staticmethod + def iter_ipb98y4_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa_ipb: float, + aspect: float, + afuel: float, + ) -> float: + """Calculate the IPB98(y,4) ELMy H-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa_ipb : + IPB specific plasma separatrix elongation + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: IPB98(y,4) ELMy H-mode confinement time [s] + + Notes: + - See correction paper below for more information about the re-definition of the elongation used. + + References: + - I. P. E. G. on C. Transport, I. P. E. G. on C. Database, and I. P. B. Editors, “Chapter 2: Plasma confinement and transport,” + Nuclear Fusion, vol. 39, no. 12, pp. 2175-2249, Dec. 1999, doi: https://doi.org/10.1088/0029-5515/39/12/302. + + - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” + Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. + """ + return ( + 0.0587e0 + * pcur**0.85e0 + * b_plasma_toroidal_on_axis**0.29e0 + * dnla19**0.39e0 + * p_plasma_loss_mw ** (-0.70e0) + * rmajor**2.08e0 + * kappa_ipb**0.76e0 + * aspect ** (-0.69e0) + * afuel**0.17e0 + ) + + @staticmethod + def iss95_stellarator_confinement_time( + rminor: float, + rmajor: float, + dnla19: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + iotabar: float, + ) -> float: + """Calculate the ISS95 stellarator scaling confinement time + + Parameters + ---------- + rminor : + Plasma minor radius [m] + rmajor : + Plasma major radius [m] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + iotabar : + Rotational transform + + Returns + ------- + : + float: ISS95 stellarator confinement time [s] + + References: + - U. Stroth et al., “Energy confinement scaling from the international stellarator database,” + vol. 36, no. 8, pp. 1063-1077, Aug. 1996, doi: https://doi.org/10.1088/0029-5515/36/8/i11. + """ + return ( + 0.079e0 + * rminor**2.21e0 + * rmajor**0.65e0 + * dnla19**0.51e0 + * b_plasma_toroidal_on_axis**0.83e0 + * p_plasma_loss_mw ** (-0.59e0) + * iotabar**0.4e0 + ) + + @staticmethod + def iss04_stellarator_confinement_time( + rminor: float, + rmajor: float, + dnla19: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + iotabar: float, + ) -> float: + """Calculate the ISS04 stellarator scaling confinement time + + Parameters + ---------- + rminor : + Plasma minor radius [m] + rmajor : + Plasma major radius [m] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + iotabar : + Rotational transform + + Returns + ------- + : + float: ISS04 stellarator confinement time [s] + + References: + - H. Yamada et al., “Characterization of energy confinement in net-current free plasmas using the extended International Stellarator Database,” + vol. 45, no. 12, pp. 1684-1693, Nov. 2005, doi: https://doi.org/10.1088/0029-5515/45/12/024. + """ + return ( + 0.134e0 + * rminor**2.28e0 + * rmajor**0.64e0 + * dnla19**0.54e0 + * b_plasma_toroidal_on_axis**0.84e0 + * p_plasma_loss_mw ** (-0.61e0) + * iotabar**0.41e0 + ) + + @staticmethod + def ds03_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa95: float, + aspect: float, + afuel: float, + ) -> float: + """Calculate the DS03 beta-independent H-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa95 : + Plasma elongation at 95% flux surface + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: DS03 beta-independent H-mode confinement time [s] + + References: + - T. C. Luce, C. C. Petty, and J. G. Cordey, “Application of dimensionless parameter scaling techniques to the design and interpretation of magnetic fusion experiments,” + Plasma Physics and Controlled Fusion, vol. 50, no. 4, p. 043001, Mar. 2008, + doi: https://doi.org/10.1088/0741-3335/50/4/043001. + """ + return ( + 0.028e0 + * pcur**0.83e0 + * b_plasma_toroidal_on_axis**0.07e0 + * dnla19**0.49e0 + * p_plasma_loss_mw ** (-0.55e0) + * rmajor**2.11e0 + * kappa95**0.75e0 + * aspect ** (-0.3e0) + * afuel**0.14e0 + ) + + @staticmethod + def murari_confinement_time( + pcur: float, + rmajor: float, + kappa_ipb: float, + dnla19: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Murari H-mode energy confinement scaling time + + Parameters + ---------- + pcur : + Plasma current [MA] + rmajor : + Plasma major radius [m] + kappa_ipb : + IPB specific plasma separatrix elongation + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Murari confinement time [s] + + Notes: + - This scaling uses the IPB defintiion of elongation, see reference for more information. + + References: + - A. Murari, E. Peluso, Michela Gelfusa, I. Lupelli, and P. Gaudio, “A new approach to the formulation and validation of scaling expressions for plasma confinement in tokamaks,” + Nuclear Fusion, vol. 55, no. 7, pp. 073009-073009, Jun. 2015, doi: https://doi.org/10.1088/0029-5515/55/7/073009. + + - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” + Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. + """ + return ( + 0.0367 + * pcur**1.006 + * rmajor**1.731 + * kappa_ipb**1.450 + * p_plasma_loss_mw ** (-0.735) + * ( + dnla19**0.448 + / (1.0 + np.exp(-9.403 * (dnla19 / b_plasma_toroidal_on_axis) ** -1.365)) + ) + ) + + @staticmethod + def petty08_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa_ipb: float, + aspect: float, + ) -> float: + """Calculate the beta independent dimensionless Petty08 confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa_ipb : + IPB specific plasma separatrix elongation + aspect : + Aspect ratio + + Returns + ------- + : + float: Petty08 confinement time [s] + + Notes: + - This scaling uses the IPB defintiion of elongation, see reference for more information. + + References: + - C. C. Petty, “Sizing up plasmas using dimensionless parameters,” + Physics of Plasmas, vol. 15, no. 8, Aug. 2008, doi: https://doi.org/10.1063/1.2961043. + + - None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, “Corrections to a sequence of papers in Nuclear Fusion,” + Nuclear Fusion, vol. 48, no. 9, pp. 099801-099801, Aug. 2008, doi: https://doi.org/10.1088/0029-5515/48/9/099801. + """ + return ( + 0.052e0 + * pcur**0.75e0 + * b_plasma_toroidal_on_axis**0.3e0 + * dnla19**0.32e0 + * p_plasma_loss_mw ** (-0.47e0) + * rmajor**2.09e0 + * kappa_ipb**0.88e0 + * aspect ** (-0.84e0) + ) + + @staticmethod + def lang_high_density_confinement_time( + plasma_current: float, + b_plasma_toroidal_on_axis: float, + nd_plasma_electron_line: float, + p_plasma_loss_mw: float, + rmajor: float, + rminor: float, + q: float, + qstar: float, + aspect: float, + afuel: float, + kappa_ipb: float, + ) -> float: + """Calculate the high density relevant confinement time + + Parameters + ---------- + plasma_current : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + nd_plasma_electron_line : + Line averaged electron density [m**-3] + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + rminor : + Plasma minor radius [m] + q : + Safety factor + qstar : + Equivalent cylindrical edge safety factor + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + kappa_ipb : + Plasma elongation at 95% flux surface + + Returns + ------- + : + float: High density relevant confinement time [s] + + References: + - P. T. Lang, C. Angioni, R. M. M. Dermott, R. Fischer, and H. Zohm, “Pellet Induced High Density Phases during ELM Suppression in ASDEX Upgrade,” + 24th IAEA Conference Fusion Energy, 2012, Oct. 2012, + Available: https://www.researchgate.net/publication/274456104_Pellet_Induced_High_Density_Phases_during_ELM_Suppression_in_ASDEX_Upgrade + """ + qratio = q / qstar + n_gw = 1.0e14 * plasma_current / (np.pi * rminor * rminor) + nratio = nd_plasma_electron_line / n_gw + return ( + 6.94e-7 + * plasma_current**1.3678e0 + * b_plasma_toroidal_on_axis**0.12e0 + * nd_plasma_electron_line**0.032236e0 + * (p_plasma_loss_mw * 1.0e6) ** (-0.74e0) + * rmajor**1.2345e0 + * kappa_ipb**0.37e0 + * aspect**2.48205e0 + * afuel**0.2e0 + * qratio**0.77e0 + * aspect ** (-0.9e0 * np.log(aspect)) + * nratio ** (-0.22e0 * np.log(nratio)) + ) + + @staticmethod + def hubbard_nominal_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla20: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Hubbard 2017 I-mode confinement time scaling - nominal + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Hubbard confinement time [s] + + References: + - A. E. Hubbard et al., “Physics and performance of the I-mode regime over an expanded operating space on Alcator C-Mod,” + Nuclear Fusion, vol. 57, no. 12, p. 126039, Oct. 2017, doi: https://doi.org/10.1088/1741-4326/aa8570. + """ + return ( + 0.014e0 + * pcur**0.68e0 + * b_plasma_toroidal_on_axis**0.77e0 + * dnla20**0.02e0 + * p_plasma_loss_mw ** (-0.29e0) + ) + + @staticmethod + def hubbard_lower_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla20: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Hubbard 2017 I-mode confinement time scaling - lower + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Hubbard confinement time [s] + + References: + - A. E. Hubbard et al., “Physics and performance of the I-mode regime over an expanded operating space on Alcator C-Mod,” + Nuclear Fusion, vol. 57, no. 12, p. 126039, Oct. 2017, doi: https://doi.org/10.1088/1741-4326/aa8570. + """ + return ( + 0.014e0 + * pcur**0.60e0 + * b_plasma_toroidal_on_axis**0.70e0 + * dnla20 ** (-0.03e0) + * p_plasma_loss_mw ** (-0.33e0) + ) + + @staticmethod + def hubbard_upper_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla20: float, + p_plasma_loss_mw: float, + ) -> float: + """Calculate the Hubbard 2017 I-mode confinement time scaling - upper + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + + Returns + ------- + : + float: Hubbard confinement time [s] + + References: + - A. E. Hubbard et al., “Physics and performance of the I-mode regime over an expanded operating space on Alcator C-Mod,” + Nuclear Fusion, vol. 57, no. 12, p. 126039, Oct. 2017, doi: https://doi.org/10.1088/1741-4326/aa8570. + """ + return ( + 0.014e0 + * pcur**0.76e0 + * b_plasma_toroidal_on_axis**0.84e0 + * dnla20**0.07 + * p_plasma_loss_mw ** (-0.25e0) + ) + + @staticmethod + def menard_nstx_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa_ipb: float, + aspect: float, + afuel: float, + ) -> float: + """Calculate the Menard NSTX ELMy H-mode scaling confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa_ipb : + IPB specific plasma separatrix elongation + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: Menard NSTX ELMy H-mode confinement time [s] + + Notes: + - "The leading NSTX confinement scaling coefficient is chosen such that the ITER and ST energy confinement times are + identical for a reference NSTX scenario" + - Assumes IPB98(y,2) exponents are applicable where the ST exponents are not yet determined, i.e. + the species mass, major radius, inverse aspect ratio and elongation. Hence here we use the IPB98(y,2) definition + of elongation. + + References: + - J. E. Menard, “Compact steady-state tokamak performance dependence on magnet and core physics limits,” + Philosophical Transactions of the Royal Society A, vol. 377, no. 2141, pp. 20170440-20170440, Feb. 2019, + doi: https://doi.org/10.1098/rsta.2017.0440. + """ + return ( + 0.095e0 + * pcur**0.57e0 + * b_plasma_toroidal_on_axis**1.08e0 + * dnla19**0.44e0 + * p_plasma_loss_mw ** (-0.73e0) + * rmajor**1.97e0 + * kappa_ipb**0.78e0 + * aspect ** (-0.58e0) + * afuel**0.19e0 + ) + + def menard_nstx_petty08_hybrid_confinement_time( + self, + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + kappa_ipb: float, + aspect: float, + afuel: float, + ) -> float: + """Calculate the Menard NSTX-Petty hybrid confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Line averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + kappa_ipb : + IPB specific plasma separatrix elongation + aspect : + Aspect ratio + afuel : + Fuel atomic mass number + + Returns + ------- + : + float: Menard NSTX-Petty hybrid confinement time [s] + + Notes: + - Assuming a linear interpolation in (1/aspect) between the two scalings + + References: + - J. E. Menard, “Compact steady-state tokamak performance dependence on magnet and core physics limits,” + Philosophical Transactions of the Royal Society A, vol. 377, no. 2141, pp. 20170440-20170440, Feb. 2019, + doi: https://doi.org/10.1098/rsta.2017.0440. + """ + # Equivalent to A > 2.5, use Petty scaling + if (1.0e0 / aspect) <= 0.4e0: + return self.petty08_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + kappa_ipb, + aspect, + ) + + # Equivalent to A < 1.7, use NSTX scaling + if (1.0e0 / aspect) >= 0.6e0: + return self.menard_nstx_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + kappa_ipb, + aspect, + afuel, + ) + return (((1.0e0 / aspect) - 0.4e0) / (0.6e0 - 0.4e0)) * ( + self.menard_nstx_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + kappa_ipb, + aspect, + afuel, + ) + ) + ((0.6e0 - (1.0e0 / aspect)) / (0.6e0 - 0.4e0)) * ( + self.petty08_confinement_time( + pcur, + b_plasma_toroidal_on_axis, + dnla19, + p_plasma_loss_mw, + rmajor, + kappa_ipb, + aspect, + ) + ) + + @staticmethod + def nstx_gyro_bohm_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + rmajor: float, + dnla20: float, + ) -> float: + """Calculate the NSTX gyro-Bohm confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Net Heating power [MW] + rmajor : + Plasma major radius [m] + dnla20 : + Line averaged electron density in units of 10**20 m**-3 + + Returns + ------- + : + float: NSTX gyro-Bohm confinement time [s] + + References: + - P. F. Buxton, L. Connor, A. E. Costley, Mikhail Gryaznevich, and S. McNamara, + “On the energy confinement time in spherical tokamaks: implications for the design of pilot plants and fusion reactors,” + vol. 61, no. 3, pp. 035006-035006, Jan. 2019, doi: https://doi.org/10.1088/1361-6587/aaf7e5. + """ + return ( + 0.21e0 + * pcur**0.54e0 + * b_plasma_toroidal_on_axis**0.91e0 + * p_plasma_loss_mw ** (-0.38e0) + * rmajor**2.14e0 + * dnla20 ** (-0.05e0) + ) + + @staticmethod + def itpa20_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + dnla19: float, + p_plasma_loss_mw: float, + rmajor: float, + triang: float, + kappa_ipb: float, + eps: float, + aion: float, + ) -> float: + """Calculate the ITPA20 Issue #3164 confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + dnla19 : + Central line-averaged electron density in units of 10**19 m**-3 + p_plasma_loss_mw : + Thermal power lost due to transport through the LCFS [MW] + rmajor : + Plasma major radius [m] + triang : + Triangularity + kappa_ipb : + IPB specific plasma separatrix elongation + eps : + Inverse aspect ratio + aion : + Average mass of all ions (amu) + + Returns + ------- + : + float: ITPA20 confinement time [s] + + Notes: + - Mass term is the effective mass of the plasma, so we assume the total ion mass here + - This scaling uses the IPB defintiion of elongation, see reference for more information. + + References: + - G. Verdoolaege et al., “The updated ITPA global H-mode confinement database: description and analysis,” + Nuclear Fusion, vol. 61, no. 7, pp. 076006-076006, Jan. 2021, doi: https://doi.org/10.1088/1741-4326/abdb91. + """ + return ( + 0.053 + * pcur**0.98 + * b_plasma_toroidal_on_axis**0.22 + * dnla19**0.24 + * p_plasma_loss_mw ** (-0.669) + * rmajor**1.71 + * (1 + triang) ** 0.36 + * kappa_ipb**0.8 + * eps**0.35 + * aion**0.2 + ) + + @staticmethod + def itpa20_il_confinement_time( + pcur: float, + b_plasma_toroidal_on_axis: float, + p_plasma_loss_mw: float, + dnla19: float, + aion: float, + rmajor: float, + triang: float, + kappa_ipb: float, + ) -> float: + """Calculate the ITPA20-IL Issue #1852 confinement time + + Parameters + ---------- + pcur : + Plasma current [MA] + b_plasma_toroidal_on_axis : + Toroidal magnetic field [T] + p_plasma_loss_mw : + Thermal power lost due to transport through the LCFS [MW] + dnla19 : + Central line-averaged electron density in units of 10**19 m**-3 + aion : + Average mass of all ions (amu) + rmajor : + Plasma major radius [m] + triang : + Triangularity + kappa_ipb : + IPB specific plasma separatrix elongation + + Returns + ------- + : + float: ITPA20-IL confinement time [s] + + Notes: + - Mass term is the effective mass of the plasma, so we assume the total ion mass here + - This scaling uses the IPB defintiion of elongation, see reference for more information. + + References: + - T. Luda et al., “Validation of a full-plasma integrated modeling approach on ASDEX Upgrade,” + Nuclear Fusion, vol. 61, no. 12, pp. 126048-126048, Nov. 2021, doi: https://doi.org/10.1088/1741-4326/ac3293. + """ + + return ( + 0.067 + * pcur**1.29 + * b_plasma_toroidal_on_axis**-0.13 + * p_plasma_loss_mw ** (-0.644) + * dnla19**0.15 + * aion**0.3 + * rmajor**1.19 + * (1 + triang) ** 0.56 + * kappa_ipb**0.67 + ) diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 794e540d1..c4b2c602a 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -6,7 +6,6 @@ import numpy as np from scipy.optimize import root_scalar -import process.models.physics.confinement_time as confinement import process.models.physics.fusion_reactions as reactions import process.models.physics.impurity_radiation as impurity_radiation import process.models.physics.l_h_transition as transition @@ -1277,7 +1276,7 @@ def physics(self): physics_variables.t_energy_confinement, physics_variables.t_ion_energy_confinement, physics_variables.p_plasma_loss_mw, - ) = self.calculate_confinement_time( + ) = self.confinement.calculate_confinement_time( physics_variables.m_fuel_amu, physics_variables.p_alpha_total_mw, physics_variables.aspect, @@ -4491,958 +4490,6 @@ def fhz(hfact: float) -> float: return root_scalar(fhz, bracket=(0.01, 150), xtol=0.001).root - @staticmethod - def calculate_confinement_time( - m_fuel_amu: float, - p_alpha_total_mw: float, - aspect: float, - b_plasma_toroidal_on_axis: float, - nd_plasma_ions_total_vol_avg: float, - nd_plasma_electrons_vol_avg: float, - nd_plasma_electron_line: float, - eps: float, - hfact: float, - i_confinement_time: int, - i_plasma_ignited: int, - kappa: float, - kappa95: float, - p_non_alpha_charged_mw: float, - p_hcd_injected_total_mw: float, - plasma_current: float, - pden_plasma_core_rad_mw: float, - rmajor: float, - rminor: float, - temp_plasma_electron_density_weighted_kev: float, - temp_plasma_ion_density_weighted_kev: float, - q95: float, - qstar: float, - vol_plasma: float, - zeff: float, - ) -> tuple[float, float, float, float, float, float, float]: - """Calculate the confinement times and the transport power loss terms. - - Parameters - ---------- - m_fuel_amu : - Average mass of fuel (amu) - p_alpha_total_mw : - Alpha particle power (MW) - aspect : - Aspect ratio - b_plasma_toroidal_on_axis : - Toroidal field on axis (T) - nd_plasma_ions_total_vol_avg : - Total ion density (/m3) - nd_plasma_electrons_vol_avg : - Volume averaged electron density (/m3) - nd_plasma_electron_line : - Line-averaged electron density (/m3) - eps : - Inverse aspect ratio - hfact : - H factor on energy confinement scalings - i_confinement_time : - Switch for energy confinement scaling to use - i_plasma_ignited : - Switch for ignited calculation - kappa : - Plasma elongation - kappa95 : - Plasma elongation at 95% surface - p_non_alpha_charged_mw : - Non-alpha charged particle fusion power (MW) - p_hcd_injected_total_mw : - Auxiliary power to ions and electrons (MW) - plasma_current : - Plasma current (A) - pden_plasma_core_rad_mw : - Total core radiation power (MW/m3) - q95 : - Edge safety factor (tokamaks), or rotational transform iotabar (stellarators) - qstar : - Equivalent cylindrical edge safety factor - rmajor : - Plasma major radius (m) - rminor : - Plasma minor radius (m) - temp_plasma_electron_density_weighted_kev : - Density weighted average electron temperature (keV) - temp_plasma_ion_density_weighted_kev : - Density weighted average ion temperature (keV) - vol_plasma : - Plasma volume (m3) - a_plasma_poloidal : - Plasma cross-sectional area (m2) - zeff : - Plasma effective charge - - Returns - ------- - type - Tuple containing: - - pden_electron_transport_loss_mw (float): Electron transport power (MW/m3) - - pden_ion_transport_loss_mw (float): Ion transport power (MW/m3) - - t_electron_energy_confinement (float): Electron energy confinement time (s) - - t_ion_energy_confinement (float): Ion energy confinement time (s) - - t_energy_confinement (float): Global energy confinement time (s) - - p_plasma_loss_mw (float): Heating power (MW) assumed in calculation - - """ - - # ======================================================================== - - # Calculate heating power (MW) - p_plasma_loss_mw = ( - physics_variables.f_p_alpha_plasma_deposited * p_alpha_total_mw - + p_non_alpha_charged_mw - + physics_variables.p_plasma_ohmic_mw - ) - - # If the device is not ignited, add the injected auxiliary power - if i_plasma_ignited == 0: - p_plasma_loss_mw = p_plasma_loss_mw + p_hcd_injected_total_mw - - # Include the radiation as a loss term if requested - if physics_variables.i_rad_loss == 0: - p_plasma_loss_mw = ( - p_plasma_loss_mw - physics_variables.pden_plasma_rad_mw * vol_plasma - ) - elif physics_variables.i_rad_loss == 1: - p_plasma_loss_mw = ( - p_plasma_loss_mw - pden_plasma_core_rad_mw * vol_plasma - ) # shouldn't this be vol_core instead of vol_plasma? - # else do not adjust p_plasma_loss_mw for radiation - - # Ensure heating power is positive (shouldn't be necessary) - p_plasma_loss_mw = max(p_plasma_loss_mw, 1.0e-3) - - # ======================================================================== - - # Line averaged electron density in scaled units - dnla20 = nd_plasma_electron_line * 1.0e-20 - dnla19 = nd_plasma_electron_line * 1.0e-19 - - # Volume averaged electron density in units of 10**20 m**-3 - n20 = nd_plasma_electrons_vol_avg / 1.0e20 - - # Plasma current in MA - pcur = plasma_current / 1.0e6 - - # Separatrix kappa defined with plasma volume for IPB scalings - # Updated version of kappa used by the IPB98 scalings correction in: - - # None Otto Kardaun, N. K. Thomsen, and None Alexander Chudnovskiy, - # “Corrections to a sequence of papers in Nuclear Fusion,” Nuclear Fusion, - # vol. 48, no. 9, pp. 099801099801, Aug. 2008, - # doi: https://doi.org/10.1088/0029-5515/48/9/099801. - - physics_variables.kappa_ipb = (vol_plasma / (2.0 * np.pi * rmajor)) / ( - np.pi * rminor**2 - ) - - # Electron energy confinement times - - # ======================================================================== - - # User defined confinement time - if i_confinement_time == 0: # t_electron_energy_confinement is an input - t_electron_confinement = physics_variables.tauee_in - - # ======================================================================== - - # Nec-Alcator(NA) OH scaling - if i_confinement_time == 1: - t_electron_confinement = confinement.neo_alcator_confinement_time( - n20, rminor, rmajor, qstar - ) - - # ======================================================================== - - # "Mirnov"-like scaling (H-mode) - elif i_confinement_time == 2: # Mirnov scaling (H-mode) - t_electron_confinement = confinement.mirnov_confinement_time( - rminor, kappa95, pcur - ) - - # ======================================================================== - - # Merezhkin-Mukhovatov (MM) OH/L-mode scaling - elif i_confinement_time == 3: - t_electron_confinement = confinement.merezhkin_muhkovatov_confinement_time( - rmajor, - rminor, - kappa95, - qstar, - dnla20, - m_fuel_amu, - temp_plasma_electron_density_weighted_kev, - ) - - # ======================================================================== - - # Shimomura (S) optimized H-mode scaling - elif i_confinement_time == 4: - t_electron_confinement = confinement.shimomura_confinement_time( - rmajor, rminor, b_plasma_toroidal_on_axis, kappa95, m_fuel_amu - ) - - # ======================================================================== - - # Kaye-Goldston scaling (L-mode) - elif i_confinement_time == 5: - t_electron_confinement = confinement.kaye_goldston_confinement_time( - pcur, - rmajor, - rminor, - kappa, - dnla20, - b_plasma_toroidal_on_axis, - m_fuel_amu, - p_plasma_loss_mw, - ) - - # ======================================================================== - - # ITER Power scaling - ITER 89-P (L-mode) - elif i_confinement_time == 6: - t_electron_confinement = confinement.iter_89p_confinement_time( - pcur, - rmajor, - rminor, - kappa, - dnla20, - b_plasma_toroidal_on_axis, - m_fuel_amu, - p_plasma_loss_mw, - ) - - # ======================================================================== - - # ITER Offset linear scaling - ITER 89-O (L-mode) - elif i_confinement_time == 7: - t_electron_confinement = confinement.iter_89_0_confinement_time( - pcur, - rmajor, - rminor, - kappa, - dnla20, - b_plasma_toroidal_on_axis, - m_fuel_amu, - p_plasma_loss_mw, - ) - # ======================================================================== - - # Rebut-Lallia offset linear scaling (L-mode) - elif i_confinement_time == 8: - t_electron_confinement = confinement.rebut_lallia_confinement_time( - rminor, - rmajor, - kappa, - m_fuel_amu, - pcur, - zeff, - dnla20, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - ) - - # ======================================================================== - - # Goldston scaling (L-mode) - elif i_confinement_time == 9: # Goldston scaling (L-mode) - t_electron_confinement = confinement.goldston_confinement_time( - pcur, rmajor, rminor, kappa95, m_fuel_amu, p_plasma_loss_mw - ) - - # ======================================================================== - - # T-10 scaling (L-mode) - elif i_confinement_time == 10: - t_electron_confinement = confinement.t10_confinement_time( - dnla20, - rmajor, - qstar, - b_plasma_toroidal_on_axis, - rminor, - kappa95, - p_plasma_loss_mw, - zeff, - pcur, - ) - - # ======================================================================== - - # JAERI / Odajima-Shimomura L-mode scaling - elif i_confinement_time == 11: # JAERI scaling - t_electron_confinement = confinement.jaeri_confinement_time( - kappa95, - rminor, - m_fuel_amu, - n20, - pcur, - b_plasma_toroidal_on_axis, - rmajor, - qstar, - zeff, - p_plasma_loss_mw, - ) - - # ======================================================================== - - # Kaye "big" L-mode scaling (based only on big tokamak data) - elif i_confinement_time == 12: - t_electron_confinement = confinement.kaye_big_confinement_time( - rmajor, - rminor, - b_plasma_toroidal_on_axis, - kappa95, - pcur, - n20, - m_fuel_amu, - p_plasma_loss_mw, - ) - - # ======================================================================== - - # ITER H90-P H-mode scaling - elif i_confinement_time == 13: - t_electron_confinement = confinement.iter_h90_p_confinement_time( - pcur, - rmajor, - rminor, - kappa, - dnla20, - b_plasma_toroidal_on_axis, - m_fuel_amu, - p_plasma_loss_mw, - ) - - # ======================================================================== - - # Minimum of ITER 89-P and ITER 89-O - elif i_confinement_time == 14: - t_electron_confinement = min( - confinement.iter_89p_confinement_time( - pcur, - rmajor, - rminor, - kappa, - dnla20, - b_plasma_toroidal_on_axis, - m_fuel_amu, - p_plasma_loss_mw, - ), - confinement.iter_89_0_confinement_time( - pcur, - rmajor, - rminor, - kappa, - dnla20, - b_plasma_toroidal_on_axis, - m_fuel_amu, - p_plasma_loss_mw, - ), - ) - - # ======================================================================== - - # Riedel scaling (L-mode) - elif i_confinement_time == 15: - t_electron_confinement = confinement.riedel_l_confinement_time( - pcur, - rmajor, - rminor, - kappa95, - dnla20, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - ) - - # ======================================================================== - - # Christiansen et al scaling (L-mode) - elif i_confinement_time == 16: - t_electron_confinement = confinement.christiansen_confinement_time( - pcur, - rmajor, - rminor, - kappa95, - dnla20, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - m_fuel_amu, - ) - - # ======================================================================== - - # Lackner-Gottardi scaling (L-mode) - elif i_confinement_time == 17: - t_electron_confinement = confinement.lackner_gottardi_confinement_time( - pcur, - rmajor, - rminor, - kappa95, - dnla20, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - ) - - # ======================================================================== - - # Neo-Kaye scaling (L-mode) - elif i_confinement_time == 18: - t_electron_confinement = confinement.neo_kaye_confinement_time( - pcur, - rmajor, - rminor, - kappa95, - dnla20, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - ) - - # ======== ================================================================ - - # Riedel scaling (H-mode) - elif i_confinement_time == 19: - t_electron_confinement = confinement.riedel_h_confinement_time( - pcur, - rmajor, - rminor, - kappa95, - dnla20, - b_plasma_toroidal_on_axis, - m_fuel_amu, - p_plasma_loss_mw, - ) - - # ======================================================================== - - # Amended version of ITER H90-P law - elif i_confinement_time == 20: - t_electron_confinement = confinement.iter_h90_p_amended_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - m_fuel_amu, - rmajor, - p_plasma_loss_mw, - kappa, - ) - - # ========================================================================== - - # Sudo et al. scaling (stellarators/heliotron) - elif i_confinement_time == 21: - t_electron_confinement = confinement.sudo_et_al_confinement_time( - rmajor, - rminor, - dnla20, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - ) - - # ========================================================================== - - # Gyro-reduced Bohm scaling - elif i_confinement_time == 22: - t_electron_confinement = confinement.gyro_reduced_bohm_confinement_time( - b_plasma_toroidal_on_axis, - dnla20, - p_plasma_loss_mw, - rminor, - rmajor, - ) - - # ========================================================================== - - # Lackner-Gottardi stellarator scaling - elif i_confinement_time == 23: - t_electron_confinement = ( - confinement.lackner_gottardi_stellarator_confinement_time( - rmajor, - rminor, - dnla20, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - q95, - ) - ) - - # ========================================================================== - - # ITER_93 ELM-free H-mode scaling - elif i_confinement_time == 24: - t_electron_confinement = confinement.iter_93h_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - m_fuel_amu, - rmajor, - dnla20, - aspect, - kappa, - ) - - # ========================================================================== - # Scaling removed - elif i_confinement_time == 25: - raise ProcessValueError("Scaling removed") - # ========================================================================== - - # ELM-free: ITERH-97P - elif i_confinement_time == 26: - t_electron_confinement = confinement.iter_h97p_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - dnla19, - rmajor, - aspect, - kappa, - m_fuel_amu, - ) - - # ========================================================================== - - # ELMy: ITERH-97P(y) - elif i_confinement_time == 27: - t_electron_confinement = confinement.iter_h97p_elmy_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - dnla19, - rmajor, - aspect, - kappa, - m_fuel_amu, - ) - - # ========================================================================== - - # ITER-96P (= ITER-97L) L-mode scaling - elif i_confinement_time == 28: - t_electron_confinement = confinement.iter_96p_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - kappa95, - rmajor, - aspect, - dnla19, - m_fuel_amu, - p_plasma_loss_mw, - ) - - # ========================================================================== - - # Valovic modified ELMy-H mode scaling - # WARNING: No reference found for this scaling. This may not be its real name - elif i_confinement_time == 29: - t_electron_confinement = confinement.valovic_elmy_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - m_fuel_amu, - rmajor, - rminor, - kappa, - p_plasma_loss_mw, - ) - - # ========================================================================== - - # Kaye PPPL Workshop April 1998 L-mode scaling - # WARNING: No reference found for this scaling. This may not be its real name - elif i_confinement_time == 30: - t_electron_confinement = confinement.kaye_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - kappa, - rmajor, - aspect, - dnla19, - m_fuel_amu, - p_plasma_loss_mw, - ) - - # ========================================================================== - - # ITERH-PB98P(y), ELMy H-mode scaling - # WARNING: No reference found for this scaling. This may not be its real name - elif i_confinement_time == 31: - t_electron_confinement = confinement.iter_pb98py_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - physics_variables.kappa_ipb, - aspect, - m_fuel_amu, - ) - - # ========================================================================== - - # IPB98(y), ELMy H-mode scaling - elif i_confinement_time == 32: - t_electron_confinement = confinement.iter_ipb98y_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - kappa, - aspect, - m_fuel_amu, - ) - - # ========================================================================== - - # IPB98(y,1), ELMy H-mode scaling - elif i_confinement_time == 33: - t_electron_confinement = confinement.iter_ipb98y1_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - physics_variables.kappa_ipb, - aspect, - m_fuel_amu, - ) - - # ========================================================================== - - # IPB98(y,2), ELMy H-mode scaling - elif i_confinement_time == 34: - t_electron_confinement = confinement.iter_ipb98y2_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - physics_variables.kappa_ipb, - aspect, - m_fuel_amu, - ) - - # ========================================================================== - - # IPB98(y,3), ELMy H-mode scaling - elif i_confinement_time == 35: - t_electron_confinement = confinement.iter_ipb98y3_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - physics_variables.kappa_ipb, - aspect, - m_fuel_amu, - ) - - # ========================================================================== - - # IPB98(y,4), ELMy H-mode scaling - elif i_confinement_time == 36: - t_electron_confinement = confinement.iter_ipb98y4_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - physics_variables.kappa_ipb, - aspect, - m_fuel_amu, - ) - - # ========================================================================== - - # ISS95 stellarator scaling - elif i_confinement_time == 37: - # dummy argument q95 is actual argument iotabar for stellarators - iotabar = q95 - t_electron_confinement = confinement.iss95_stellarator_confinement_time( - rminor, - rmajor, - dnla19, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - iotabar, - ) - - # ========================================================================== - - # ISS04 stellarator scaling - elif i_confinement_time == 38: - # dummy argument q95 is actual argument iotabar for stellarators - iotabar = q95 - t_electron_confinement = confinement.iss04_stellarator_confinement_time( - rminor, - rmajor, - dnla19, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - iotabar, - ) - - # ========================================================================== - - # DS03 beta-independent H-mode scaling - elif i_confinement_time == 39: - t_electron_confinement = confinement.ds03_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - kappa95, - aspect, - m_fuel_amu, - ) - - # ========================================================================== - - # Murari "Non-power law" scaling - elif i_confinement_time == 40: - t_electron_confinement = confinement.murari_confinement_time( - pcur, - rmajor, - physics_variables.kappa_ipb, - dnla19, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - ) - - # ========================================================================== - - # Petty08, beta independent dimensionless scaling - elif i_confinement_time == 41: - t_electron_confinement = confinement.petty08_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - physics_variables.kappa_ipb, - aspect, - ) - - # ========================================================================== - - # Lang high density relevant confinement scaling - elif i_confinement_time == 42: - t_electron_confinement = confinement.lang_high_density_confinement_time( - plasma_current, - b_plasma_toroidal_on_axis, - nd_plasma_electron_line, - p_plasma_loss_mw, - rmajor, - rminor, - q95, - qstar, - aspect, - m_fuel_amu, - physics_variables.kappa_ipb, - ) - - # ========================================================================== - - # Hubbard 2017 I-mode confinement time scaling - nominal - elif i_confinement_time == 43: - t_electron_confinement = confinement.hubbard_nominal_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla20, - p_plasma_loss_mw, - ) - - # ========================================================================== - - # Hubbard 2017 I-mode confinement time scaling - lower - elif i_confinement_time == 44: - t_electron_confinement = confinement.hubbard_lower_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla20, - p_plasma_loss_mw, - ) - - # ========================================================================== - - # Hubbard 2017 I-mode confinement time scaling - upper - elif i_confinement_time == 45: - t_electron_confinement = confinement.hubbard_upper_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla20, - p_plasma_loss_mw, - ) - - # ========================================================================== - - # Menard NSTX, ELMy H-mode scaling - elif i_confinement_time == 46: - t_electron_confinement = confinement.menard_nstx_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - physics_variables.kappa_ipb, - aspect, - m_fuel_amu, - ) - - # ========================================================================== - - # Menard NSTX-Petty08 Hybrid - elif i_confinement_time == 47: - t_electron_confinement = ( - confinement.menard_nstx_petty08_hybrid_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - physics_variables.kappa_ipb, - aspect, - m_fuel_amu, - ) - ) - - # ========================================================================== - - # NSTX gyro-Bohm (Buxton) - elif i_confinement_time == 48: - t_electron_confinement = confinement.nstx_gyro_bohm_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - rmajor, - dnla20, - ) - - # ========================================================================== - - # ITPA20 H-mode scaling - elif i_confinement_time == 49: - t_electron_confinement = confinement.itpa20_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - dnla19, - p_plasma_loss_mw, - rmajor, - physics_variables.triang, - physics_variables.kappa_ipb, - eps, - physics_variables.m_ions_total_amu, - ) - - # ========================================================================== - - # ITPA20-IL confinement time scaling - elif i_confinement_time == 50: - t_electron_confinement = confinement.itpa20_il_confinement_time( - pcur, - b_plasma_toroidal_on_axis, - p_plasma_loss_mw, - dnla19, - physics_variables.m_ions_total_amu, - rmajor, - physics_variables.triang, - physics_variables.kappa_ipb, - ) - - # ========================================================================== - - else: - raise ProcessValueError( - "Illegal value for i_confinement_time", - i_confinement_time=i_confinement_time, - ) - - # Apply H-factor correction to chosen scaling - t_electron_energy_confinement = hfact * t_electron_confinement - - # Ion energy confinement time - t_ion_energy_confinement = t_electron_energy_confinement - - # Calculate H* non-radiation corrected H factor - # Note: we will assume the IPB-98y2 scaling. - if physics_variables.i_rad_loss == 1: - physics_variables.hstar = ( - hfact - * ( - p_plasma_loss_mw - / ( - p_plasma_loss_mw - + physics_variables.pden_plasma_sync_mw * vol_plasma - + physics_variables.p_plasma_inner_rad_mw - ) - ) - ** 0.31 - ) - elif physics_variables.i_rad_loss == 0: - physics_variables.hstar = ( - hfact - * ( - p_plasma_loss_mw - / ( - p_plasma_loss_mw - + physics_variables.pden_plasma_rad_mw * vol_plasma - ) - ) - ** 0.31 - ) - elif physics_variables.i_rad_loss == 2: - physics_variables.hstar = hfact - - # Calculation of the transport power loss terms - # Transport losses in Watts/m3 are 3/2 * n.e.T / tau , with T in eV - # (here, temp_plasma_ion_density_weighted_kev and temp_plasma_electron_density_weighted_kev are in keV, and pden_electron_transport_loss_mw and pden_ion_transport_loss_mw are in MW/m3) - - # The transport losses is just the electron and ion thermal energies divided by the confinement time. - pden_ion_transport_loss_mw = ( - (3 / 2) - * (constants.ELECTRON_CHARGE / 1e3) - * nd_plasma_ions_total_vol_avg - * temp_plasma_ion_density_weighted_kev - / t_ion_energy_confinement - ) - pden_electron_transport_loss_mw = ( - (3 / 2) - * (constants.ELECTRON_CHARGE / 1e3) - * nd_plasma_electrons_vol_avg - * temp_plasma_electron_density_weighted_kev - / t_electron_energy_confinement - ) - - ratio = (nd_plasma_ions_total_vol_avg / nd_plasma_electrons_vol_avg) * ( - temp_plasma_ion_density_weighted_kev - / temp_plasma_electron_density_weighted_kev - ) - - # Global energy confinement time - - t_energy_confinement = (ratio + 1.0e0) / ( - ratio / t_ion_energy_confinement + 1.0e0 / t_electron_energy_confinement - ) - - # For comparison directly calculate the confinement time from the stored energy calculated - # from the total plasma beta and the loss power used above. - physics_variables.t_energy_confinement_beta = ( - physics_variables.e_plasma_beta / 1e6 - ) / p_plasma_loss_mw - - return ( - pden_electron_transport_loss_mw, - pden_ion_transport_loss_mw, - t_electron_energy_confinement, - t_ion_energy_confinement, - t_energy_confinement, - p_plasma_loss_mw, - ) - @staticmethod def calculate_plasma_masses( m_fuel_amu: float, diff --git a/tests/unit/test_confinement_time.py b/tests/unit/test_confinement_time.py index 5a36dbd59..05e252e47 100644 --- a/tests/unit/test_confinement_time.py +++ b/tests/unit/test_confinement_time.py @@ -1,188 +1,244 @@ import pytest -from process.models.physics import confinement_time as conf +from process.models.physics.confinement_time import PlasmaConfinementTime @pytest.mark.parametrize( "func, args, expected", [ - (conf.neo_alcator_confinement_time, (1.0, 1.0, 1.0, 1.0), 0.07), - (conf.mirnov_confinement_time, (1.0, 1.0, 1.0), 0.2), ( - conf.merezhkin_muhkovatov_confinement_time, + PlasmaConfinementTime().neo_alcator_confinement_time, + (1.0, 1.0, 1.0, 1.0), + 0.07, + ), + (PlasmaConfinementTime().mirnov_confinement_time, (1.0, 1.0, 1.0), 0.2), + ( + PlasmaConfinementTime().merezhkin_muhkovatov_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.011067971810589328, ), - (conf.shimomura_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0), 0.045), ( - conf.kaye_goldston_confinement_time, + PlasmaConfinementTime().shimomura_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0), + 0.045, + ), + ( + PlasmaConfinementTime().kaye_goldston_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.04490731195102493, ), ( - conf.iter_89p_confinement_time, + PlasmaConfinementTime().iter_89p_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.048, ), ( - conf.iter_89_0_confinement_time, + PlasmaConfinementTime().iter_89_0_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.104, ), ( - conf.rebut_lallia_confinement_time, + PlasmaConfinementTime().rebut_lallia_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.18434273785533292, ), ( - conf.goldston_confinement_time, + PlasmaConfinementTime().goldston_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.03021037349432586, ), ( - conf.t10_confinement_time, + PlasmaConfinementTime().t10_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.07307692307692307, ), ( - conf.jaeri_confinement_time, + PlasmaConfinementTime().jaeri_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.13187536611732242, ), ( - conf.kaye_big_confinement_time, + PlasmaConfinementTime().kaye_big_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.105, ), ( - conf.iter_h90_p_confinement_time, + PlasmaConfinementTime().iter_h90_p_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.064, ), - (conf.riedel_l_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.044), ( - conf.christiansen_confinement_time, + PlasmaConfinementTime().riedel_l_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), + 0.044, + ), + ( + PlasmaConfinementTime().christiansen_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.24, ), ( - conf.lackner_gottardi_confinement_time, + PlasmaConfinementTime().lackner_gottardi_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.13120344887319335, ), - (conf.neo_kaye_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.063), - (conf.riedel_h_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.1), ( - conf.iter_h90_p_amended_confinement_time, + PlasmaConfinementTime().neo_kaye_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), + 0.063, + ), + ( + PlasmaConfinementTime().riedel_h_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), + 0.1, + ), + ( + PlasmaConfinementTime().iter_h90_p_amended_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.082, ), - (conf.sudo_et_al_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0), 0.17), - (conf.gyro_reduced_bohm_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0), 0.25), ( - conf.lackner_gottardi_stellarator_confinement_time, + PlasmaConfinementTime().sudo_et_al_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0), + 0.17, + ), + ( + PlasmaConfinementTime().gyro_reduced_bohm_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0), + 0.25, + ), + ( + PlasmaConfinementTime().lackner_gottardi_stellarator_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.17, ), ( - conf.iter_93h_confinement_time, + PlasmaConfinementTime().iter_93h_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.036, ), ( - conf.iter_h97p_confinement_time, + PlasmaConfinementTime().iter_h97p_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.031, ), ( - conf.iter_h97p_elmy_confinement_time, + PlasmaConfinementTime().iter_h97p_elmy_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.029, ), ( - conf.iter_96p_confinement_time, + PlasmaConfinementTime().iter_96p_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.023, ), ( - conf.valovic_elmy_confinement_time, + PlasmaConfinementTime().valovic_elmy_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.067, ), - (conf.kaye_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.021), ( - conf.iter_pb98py_confinement_time, + PlasmaConfinementTime().kaye_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), + 0.021, + ), + ( + PlasmaConfinementTime().iter_pb98py_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.0615, ), ( - conf.iter_ipb98y_confinement_time, + PlasmaConfinementTime().iter_ipb98y_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.0365, ), ( - conf.iter_ipb98y1_confinement_time, + PlasmaConfinementTime().iter_ipb98y1_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.0503, ), ( - conf.iter_ipb98y2_confinement_time, + PlasmaConfinementTime().iter_ipb98y2_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.0562, ), ( - conf.iter_ipb98y3_confinement_time, + PlasmaConfinementTime().iter_ipb98y3_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.0564, ), ( - conf.iter_ipb98y4_confinement_time, + PlasmaConfinementTime().iter_ipb98y4_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.0587, ), ( - conf.iss95_stellarator_confinement_time, + PlasmaConfinementTime().iss95_stellarator_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.079, ), ( - conf.iss04_stellarator_confinement_time, + PlasmaConfinementTime().iss04_stellarator_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.134, ), - (conf.ds03_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.028), ( - conf.murari_confinement_time, + PlasmaConfinementTime().ds03_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), + 0.028, + ), + ( + PlasmaConfinementTime().murari_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.03669697337069055, ), - (conf.petty08_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.052), ( - conf.lang_high_density_confinement_time, + PlasmaConfinementTime().petty08_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), + 0.052, + ), + ( + PlasmaConfinementTime().lang_high_density_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 1.0970434976417428e-103, ), - (conf.hubbard_nominal_confinement_time, (1.0, 1.0, 1.0, 1.0), 0.014), - (conf.hubbard_lower_confinement_time, (1.0, 1.0, 1.0, 1.0), 0.014), - (conf.hubbard_upper_confinement_time, (1.0, 1.0, 1.0, 1.0), 0.014), ( - conf.menard_nstx_confinement_time, + PlasmaConfinementTime().hubbard_nominal_confinement_time, + (1.0, 1.0, 1.0, 1.0), + 0.014, + ), + ( + PlasmaConfinementTime().hubbard_lower_confinement_time, + (1.0, 1.0, 1.0, 1.0), + 0.014, + ), + ( + PlasmaConfinementTime().hubbard_upper_confinement_time, + (1.0, 1.0, 1.0, 1.0), + 0.014, + ), + ( + PlasmaConfinementTime().menard_nstx_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.095, ), ( - conf.menard_nstx_petty08_hybrid_confinement_time, + PlasmaConfinementTime().menard_nstx_petty08_hybrid_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.095, ), - (conf.nstx_gyro_bohm_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0), 0.21), ( - conf.itpa20_confinement_time, + PlasmaConfinementTime().nstx_gyro_bohm_confinement_time, + (1.0, 1.0, 1.0, 1.0, 1.0), + 0.21, + ), + ( + PlasmaConfinementTime().itpa20_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.06802157257083392, ), ( - conf.itpa20_il_confinement_time, + PlasmaConfinementTime().itpa20_il_confinement_time, (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0), 0.09877603755850378, ), diff --git a/tests/unit/test_physics.py b/tests/unit/test_physics.py index c727c3b42..dadffa7f5 100644 --- a/tests/unit/test_physics.py +++ b/tests/unit/test_physics.py @@ -3309,7 +3309,7 @@ def test_calculate_confinement_time(confinementtimeparam, monkeypatch, physics): t_ion_energy_confinement, t_energy_confinement, p_plasma_loss_mw, - ) = physics.calculate_confinement_time( + ) = physics.confinement.calculate_confinement_time( i_confinement_time=confinementtimeparam.i_confinement_time, i_plasma_ignited=confinementtimeparam.i_plasma_ignited, m_fuel_amu=confinementtimeparam.m_fuel_amu, From 8f19ff27935055098355014c957a66d0e4fcf20d Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 10:56:48 +0000 Subject: [PATCH 03/12] Add ConfinementRadiationLossModel and update radiation loss handling in PlasmaConfinementTime --- process/models/physics/confinement_time.py | 36 ++++++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 1c6551c05..f7b51bf3e 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -66,6 +66,14 @@ class ConfinementTimeModel(IntEnum): ITPA20_IL = 48 +class ConfinementRadiationLossModel(IntEnum): + """Confinement radiation loss model types""" + + FULL_RADIATION = 0 + CORE_ONLY = 1 + NO_RADIATION = 2 + + class PlasmaConfinementTime: """Class to calculate plasma confinement time using various empirical scaling laws""" @@ -184,16 +192,24 @@ def calculate_confinement_time( if i_plasma_ignited == 0: p_plasma_loss_mw = p_plasma_loss_mw + p_hcd_injected_total_mw - # Include the radiation as a loss term if requested - if physics_variables.i_rad_loss == 0: - p_plasma_loss_mw = ( - p_plasma_loss_mw - physics_variables.pden_plasma_rad_mw * vol_plasma - ) - elif physics_variables.i_rad_loss == 1: - p_plasma_loss_mw = ( - p_plasma_loss_mw - pden_plasma_core_rad_mw * vol_plasma - ) # shouldn't this be vol_core instead of vol_plasma? - # else do not adjust p_plasma_loss_mw for radiation + # Include the radiation as a loss term based on radiation model + try: + model = ConfinementRadiationLossModel(int(physics_variables.i_rad_loss)) + + if model == ConfinementRadiationLossModel.FULL_RADIATION: + p_plasma_loss_mw = ( + p_plasma_loss_mw - physics_variables.pden_plasma_rad_mw * vol_plasma + ) + elif model == ConfinementRadiationLossModel.CORE_ONLY: + p_plasma_loss_mw = ( + p_plasma_loss_mw - pden_plasma_core_rad_mw * vol_plasma + ) + # NO_RADIATION: do not adjust p_plasma_loss_mw for radiation + except ValueError: + raise ProcessValueError( + "Illegal value of i_rad_loss", + i_rad_loss=physics_variables.i_rad_loss, + ) from None # Ensure heating power is positive (shouldn't be necessary) p_plasma_loss_mw = max(p_plasma_loss_mw, 1.0e-3) From ef646dc425f0e89d82abef6626fba331ed97ec29 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 11:15:58 +0000 Subject: [PATCH 04/12] Reorder ConfinementTimeModel enum values and update PlasmaConfinementTime logic for model handling --- process/models/physics/confinement_time.py | 190 +++++++++++---------- 1 file changed, 102 insertions(+), 88 deletions(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index f7b51bf3e..1d7086b3a 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -29,41 +29,43 @@ class ConfinementTimeModel(IntEnum): JAERI = 11 KAYE_BIG = 12 ITER_H90_P = 13 - RIEDEL_L = 14 - CHRISTIANSEN = 15 - LACKNER_GOTTARDI = 16 - NEO_KAYE = 17 - RIEDEL_H = 18 - ITER_H90_P_AMENDED = 19 - SUDO_ET_AL = 20 - GYRO_REDUCED_BOHM = 21 - LACKNER_GOTTARDI_STELLARATOR = 22 - ITER_93H = 23 - ITER_H97P = 24 - ITER_H97P_ELMY = 25 - ITER_96P = 26 - VALOVIC_ELMY = 27 - KAYE = 28 - ITER_PB98PY = 29 - ITER_IPB98Y = 30 - ITER_IPB98Y1 = 31 - ITER_IPB98Y2 = 32 - ITER_IPB98Y3 = 33 - ITER_IPB98Y4 = 34 - ISS95_STELLARATOR = 35 - ISS04_STELLARATOR = 36 - DS03 = 37 - MURARI = 38 - PETTY08 = 39 - LANG_HIGH_DENSITY = 40 - HUBBARD_NOMINAL = 41 - HUBBARD_LOWER = 42 - HUBBARD_UPPER = 43 - MENARD_NSTX = 44 - MENARD_NSTX_PETTY08_HYBRID = 45 - NSTX_GYRO_BOHM = 46 - ITPA20 = 47 - ITPA20_IL = 48 + MINIMUM_OF_ITER_89P_AND_ITER_89_0 = 14 + RIEDEL_L = 15 + CHRISTIANSEN = 16 + LACKNER_GOTTARDI = 17 + NEO_KAYE = 18 + RIEDEL_H = 19 + ITER_H90_P_AMENDED = 20 + SUDO_ET_AL = 21 + GYRO_REDUCED_BOHM = 22 + LACKNER_GOTTARDI_STELLARATOR = 23 + ITER_93H = 24 + TITAN_REMOVED = 25 + ITER_H97P = 26 + ITER_H97P_ELMY = 27 + ITER_96P = 28 + VALOVIC_ELMY = 29 + KAYE = 30 + ITER_PB98P_Y = 31 + IPB98_Y = 32 + ITER_IPB98Y1 = 33 + ITER_IPB98Y2 = 34 + ITER_IPB98Y3 = 35 + ITER_IPB98Y4 = 36 + ISS95_STELLARATOR = 37 + ISS04_STELLARATOR = 38 + DS03 = 39 + MURARI = 40 + PETTY08 = 41 + LANG_HIGH_DENSITY = 42 + HUBBARD_NOMINAL = 43 + HUBBARD_LOWER = 44 + HUBBARD_UPPER = 45 + MENARD_NSTX = 46 + MENARD_NSTX_PETTY08_HYBRID = 47 + NSTX_GYRO_BOHM = 48 + ITPA20 = 49 + ITPA20_IL = 50 class ConfinementRadiationLossModel(IntEnum): @@ -240,16 +242,28 @@ def calculate_confinement_time( # Electron energy confinement times + try: + model = ConfinementTimeModel(i_confinement_time) + except ValueError: + raise ProcessValueError( + "Illegal value for i_confinement_time", + i_confinement_time=i_confinement_time, + ) from None + # ======================================================================== # User defined confinement time - if i_confinement_time == 0: # t_electron_energy_confinement is an input + if ( + model == ConfinementTimeModel.USER_INPUT + ): # t_electron_energy_confinement is an input t_electron_confinement = physics_variables.tauee_in # ======================================================================== # Nec-Alcator(NA) OH scaling - if i_confinement_time == 1: + if ( + model == ConfinementTimeModel.NEO_ALCATOR + ): # t_electron_energy_confinement is an input t_electron_confinement = self.neo_alcator_confinement_time( n20, rminor, rmajor, qstar ) @@ -257,13 +271,13 @@ def calculate_confinement_time( # ======================================================================== # "Mirnov"-like scaling (H-mode) - elif i_confinement_time == 2: # Mirnov scaling (H-mode) + elif model == ConfinementTimeModel.MIRNOV: # Mirnov scaling (H-mode) t_electron_confinement = self.mirnov_confinement_time(rminor, kappa95, pcur) # ======================================================================== # Merezhkin-Mukhovatov (MM) OH/L-mode scaling - elif i_confinement_time == 3: + elif model == ConfinementTimeModel.MEREZHKIN_MUHKOVATOV: t_electron_confinement = self.merezhkin_muhkovatov_confinement_time( rmajor, rminor, @@ -277,7 +291,7 @@ def calculate_confinement_time( # ======================================================================== # Shimomura (S) optimized H-mode scaling - elif i_confinement_time == 4: + elif model == ConfinementTimeModel.SHIMOMURA: t_electron_confinement = self.shimomura_confinement_time( rmajor, rminor, b_plasma_toroidal_on_axis, kappa95, m_fuel_amu ) @@ -285,7 +299,7 @@ def calculate_confinement_time( # ======================================================================== # Kaye-Goldston scaling (L-mode) - elif i_confinement_time == 5: + elif model == ConfinementTimeModel.KAYE_GOLDSTON: t_electron_confinement = self.kaye_goldston_confinement_time( pcur, rmajor, @@ -300,7 +314,7 @@ def calculate_confinement_time( # ======================================================================== # ITER Power scaling - ITER 89-P (L-mode) - elif i_confinement_time == 6: + elif model == ConfinementTimeModel.ITER_89P: t_electron_confinement = self.iter_89p_confinement_time( pcur, rmajor, @@ -315,7 +329,7 @@ def calculate_confinement_time( # ======================================================================== # ITER Offset linear scaling - ITER 89-O (L-mode) - elif i_confinement_time == 7: + elif model == ConfinementTimeModel.ITER_89_0: t_electron_confinement = self.iter_89_0_confinement_time( pcur, rmajor, @@ -329,7 +343,7 @@ def calculate_confinement_time( # ======================================================================== # Rebut-Lallia offset linear scaling (L-mode) - elif i_confinement_time == 8: + elif model == ConfinementTimeModel.REBUT_LALLIA: t_electron_confinement = self.rebut_lallia_confinement_time( rminor, rmajor, @@ -345,7 +359,7 @@ def calculate_confinement_time( # ======================================================================== # Goldston scaling (L-mode) - elif i_confinement_time == 9: # Goldston scaling (L-mode) + elif model == ConfinementTimeModel.GOLDSTON: # Goldston scaling (L-mode) t_electron_confinement = self.goldston_confinement_time( pcur, rmajor, rminor, kappa95, m_fuel_amu, p_plasma_loss_mw ) @@ -353,7 +367,7 @@ def calculate_confinement_time( # ======================================================================== # T-10 scaling (L-mode) - elif i_confinement_time == 10: + elif model == ConfinementTimeModel.T_10: t_electron_confinement = self.t10_confinement_time( dnla20, rmajor, @@ -369,7 +383,7 @@ def calculate_confinement_time( # ======================================================================== # JAERI / Odajima-Shimomura L-mode scaling - elif i_confinement_time == 11: # JAERI scaling + elif model == ConfinementTimeModel.JAERI: # JAERI scaling t_electron_confinement = self.jaeri_confinement_time( kappa95, rminor, @@ -386,7 +400,7 @@ def calculate_confinement_time( # ======================================================================== # Kaye "big" L-mode scaling (based only on big tokamak data) - elif i_confinement_time == 12: + elif model == ConfinementTimeModel.KAYE_BIG: t_electron_confinement = self.kaye_big_confinement_time( rmajor, rminor, @@ -401,7 +415,7 @@ def calculate_confinement_time( # ======================================================================== # ITER H90-P H-mode scaling - elif i_confinement_time == 13: + elif model == ConfinementTimeModel.ITER_H90_P: t_electron_confinement = self.iter_h90_p_confinement_time( pcur, rmajor, @@ -416,7 +430,7 @@ def calculate_confinement_time( # ======================================================================== # Minimum of ITER 89-P and ITER 89-O - elif i_confinement_time == 14: + elif model == ConfinementTimeModel.MINIMUM_OF_ITER_89P_AND_ITER_89_0: t_electron_confinement = min( self.iter_89p_confinement_time( pcur, @@ -443,7 +457,7 @@ def calculate_confinement_time( # ======================================================================== # Riedel scaling (L-mode) - elif i_confinement_time == 15: + elif model == ConfinementTimeModel.RIEDEL_L: t_electron_confinement = self.riedel_l_confinement_time( pcur, rmajor, @@ -457,7 +471,7 @@ def calculate_confinement_time( # ======================================================================== # Christiansen et al scaling (L-mode) - elif i_confinement_time == 16: + elif model == ConfinementTimeModel.CHRISTIANSEN: t_electron_confinement = self.christiansen_confinement_time( pcur, rmajor, @@ -472,7 +486,7 @@ def calculate_confinement_time( # ======================================================================== # Lackner-Gottardi scaling (L-mode) - elif i_confinement_time == 17: + elif model == ConfinementTimeModel.LACKNER_GOTTARDI: t_electron_confinement = self.lackner_gottardi_confinement_time( pcur, rmajor, @@ -486,7 +500,7 @@ def calculate_confinement_time( # ======================================================================== # Neo-Kaye scaling (L-mode) - elif i_confinement_time == 18: + elif model == ConfinementTimeModel.NEO_KAYE: t_electron_confinement = self.neo_kaye_confinement_time( pcur, rmajor, @@ -500,7 +514,7 @@ def calculate_confinement_time( # ======== ================================================================ # Riedel scaling (H-mode) - elif i_confinement_time == 19: + elif model == ConfinementTimeModel.RIEDEL_H: t_electron_confinement = self.riedel_h_confinement_time( pcur, rmajor, @@ -515,7 +529,7 @@ def calculate_confinement_time( # ======================================================================== # Amended version of ITER H90-P law - elif i_confinement_time == 20: + elif model == ConfinementTimeModel.ITER_H90_P_AMENDED: t_electron_confinement = self.iter_h90_p_amended_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -528,7 +542,7 @@ def calculate_confinement_time( # ========================================================================== # Sudo et al. scaling (stellarators/heliotron) - elif i_confinement_time == 21: + elif model == ConfinementTimeModel.SUDO_ET_AL: t_electron_confinement = self.sudo_et_al_confinement_time( rmajor, rminor, @@ -540,7 +554,7 @@ def calculate_confinement_time( # ========================================================================== # Gyro-reduced Bohm scaling - elif i_confinement_time == 22: + elif model == ConfinementTimeModel.GYRO_REDUCED_BOHM: t_electron_confinement = self.gyro_reduced_bohm_confinement_time( b_plasma_toroidal_on_axis, dnla20, @@ -552,7 +566,7 @@ def calculate_confinement_time( # ========================================================================== # Lackner-Gottardi stellarator scaling - elif i_confinement_time == 23: + elif model == ConfinementTimeModel.LACKNER_GOTTARDI_STELLARATOR: t_electron_confinement = self.lackner_gottardi_stellarator_confinement_time( rmajor, rminor, @@ -565,7 +579,7 @@ def calculate_confinement_time( # ========================================================================== # ITER_93 ELM-free H-mode scaling - elif i_confinement_time == 24: + elif model == ConfinementTimeModel.ITER_93H: t_electron_confinement = self.iter_93h_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -579,12 +593,12 @@ def calculate_confinement_time( # ========================================================================== # Scaling removed - elif i_confinement_time == 25: + elif model == ConfinementTimeModel.TITAN_REMOVED: raise ProcessValueError("Scaling removed") # ========================================================================== # ELM-free: ITERH-97P - elif i_confinement_time == 26: + elif model == ConfinementTimeModel.ITER_H97P: t_electron_confinement = self.iter_h97p_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -599,7 +613,7 @@ def calculate_confinement_time( # ========================================================================== # ELMy: ITERH-97P(y) - elif i_confinement_time == 27: + elif model == ConfinementTimeModel.ITER_H97P_ELMY: t_electron_confinement = self.iter_h97p_elmy_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -614,7 +628,7 @@ def calculate_confinement_time( # ========================================================================== # ITER-96P (= ITER-97L) L-mode scaling - elif i_confinement_time == 28: + elif model == ConfinementTimeModel.ITER_96P: t_electron_confinement = self.iter_96p_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -630,7 +644,7 @@ def calculate_confinement_time( # Valovic modified ELMy-H mode scaling # WARNING: No reference found for this scaling. This may not be its real name - elif i_confinement_time == 29: + elif model == ConfinementTimeModel.VALOVIC_ELMY: t_electron_confinement = self.valovic_elmy_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -646,7 +660,7 @@ def calculate_confinement_time( # Kaye PPPL Workshop April 1998 L-mode scaling # WARNING: No reference found for this scaling. This may not be its real name - elif i_confinement_time == 30: + elif model == ConfinementTimeModel.KAYE: t_electron_confinement = self.kaye_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -662,7 +676,7 @@ def calculate_confinement_time( # ITERH-PB98P(y), ELMy H-mode scaling # WARNING: No reference found for this scaling. This may not be its real name - elif i_confinement_time == 31: + elif model == ConfinementTimeModel.ITER_PB98P_Y: t_electron_confinement = self.iter_pb98py_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -677,7 +691,7 @@ def calculate_confinement_time( # ========================================================================== # IPB98(y), ELMy H-mode scaling - elif i_confinement_time == 32: + elif model == ConfinementTimeModel.IPB98_Y: t_electron_confinement = self.iter_ipb98y_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -692,7 +706,7 @@ def calculate_confinement_time( # ========================================================================== # IPB98(y,1), ELMy H-mode scaling - elif i_confinement_time == 33: + elif model == ConfinementTimeModel.ITER_IPB98Y1: t_electron_confinement = self.iter_ipb98y1_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -707,7 +721,7 @@ def calculate_confinement_time( # ========================================================================== # IPB98(y,2), ELMy H-mode scaling - elif i_confinement_time == 34: + elif model == ConfinementTimeModel.ITER_IPB98Y2: t_electron_confinement = self.iter_ipb98y2_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -722,7 +736,7 @@ def calculate_confinement_time( # ========================================================================== # IPB98(y,3), ELMy H-mode scaling - elif i_confinement_time == 35: + elif model == ConfinementTimeModel.ITER_IPB98Y3: t_electron_confinement = self.iter_ipb98y3_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -737,7 +751,7 @@ def calculate_confinement_time( # ========================================================================== # IPB98(y,4), ELMy H-mode scaling - elif i_confinement_time == 36: + elif model == ConfinementTimeModel.ITER_IPB98Y4: t_electron_confinement = self.iter_ipb98y4_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -752,7 +766,7 @@ def calculate_confinement_time( # ========================================================================== # ISS95 stellarator scaling - elif i_confinement_time == 37: + elif model == ConfinementTimeModel.ISS95_STELLARATOR: # dummy argument q95 is actual argument iotabar for stellarators iotabar = q95 t_electron_confinement = self.iss95_stellarator_confinement_time( @@ -767,7 +781,7 @@ def calculate_confinement_time( # ========================================================================== # ISS04 stellarator scaling - elif i_confinement_time == 38: + elif model == ConfinementTimeModel.ISS04_STELLARATOR: # dummy argument q95 is actual argument iotabar for stellarators iotabar = q95 t_electron_confinement = self.iss04_stellarator_confinement_time( @@ -782,7 +796,7 @@ def calculate_confinement_time( # ========================================================================== # DS03 beta-independent H-mode scaling - elif i_confinement_time == 39: + elif model == ConfinementTimeModel.DS03: t_electron_confinement = self.ds03_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -797,7 +811,7 @@ def calculate_confinement_time( # ========================================================================== # Murari "Non-power law" scaling - elif i_confinement_time == 40: + elif model == ConfinementTimeModel.MURARI: t_electron_confinement = self.murari_confinement_time( pcur, rmajor, @@ -810,7 +824,7 @@ def calculate_confinement_time( # ========================================================================== # Petty08, beta independent dimensionless scaling - elif i_confinement_time == 41: + elif model == ConfinementTimeModel.PETTY08: t_electron_confinement = self.petty08_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -824,7 +838,7 @@ def calculate_confinement_time( # ========================================================================== # Lang high density relevant confinement scaling - elif i_confinement_time == 42: + elif model == ConfinementTimeModel.LANG_HIGH_DENSITY: t_electron_confinement = self.lang_high_density_confinement_time( plasma_current, b_plasma_toroidal_on_axis, @@ -842,7 +856,7 @@ def calculate_confinement_time( # ========================================================================== # Hubbard 2017 I-mode confinement time scaling - nominal - elif i_confinement_time == 43: + elif model == ConfinementTimeModel.HUBBARD_NOMINAL: t_electron_confinement = self.hubbard_nominal_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -853,7 +867,7 @@ def calculate_confinement_time( # ========================================================================== # Hubbard 2017 I-mode confinement time scaling - lower - elif i_confinement_time == 44: + elif model == ConfinementTimeModel.HUBBARD_LOWER: t_electron_confinement = self.hubbard_lower_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -864,7 +878,7 @@ def calculate_confinement_time( # ========================================================================== # Hubbard 2017 I-mode confinement time scaling - upper - elif i_confinement_time == 45: + elif model == ConfinementTimeModel.HUBBARD_UPPER: t_electron_confinement = self.hubbard_upper_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -875,7 +889,7 @@ def calculate_confinement_time( # ========================================================================== # Menard NSTX, ELMy H-mode scaling - elif i_confinement_time == 46: + elif model == ConfinementTimeModel.MENARD_NSTX: t_electron_confinement = self.menard_nstx_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -890,7 +904,7 @@ def calculate_confinement_time( # ========================================================================== # Menard NSTX-Petty08 Hybrid - elif i_confinement_time == 47: + elif model == ConfinementTimeModel.MENARD_NSTX_PETTY08_HYBRID: t_electron_confinement = self.menard_nstx_petty08_hybrid_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -905,7 +919,7 @@ def calculate_confinement_time( # ========================================================================== # NSTX gyro-Bohm (Buxton) - elif i_confinement_time == 48: + elif model == ConfinementTimeModel.NSTX_GYRO_BOHM: t_electron_confinement = self.nstx_gyro_bohm_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -917,7 +931,7 @@ def calculate_confinement_time( # ========================================================================== # ITPA20 H-mode scaling - elif i_confinement_time == 49: + elif model == ConfinementTimeModel.ITPA20: t_electron_confinement = self.itpa20_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -933,7 +947,7 @@ def calculate_confinement_time( # ========================================================================== # ITPA20-IL confinement time scaling - elif i_confinement_time == 50: + elif model == ConfinementTimeModel.ITPA20_IL: t_electron_confinement = self.itpa20_il_confinement_time( pcur, b_plasma_toroidal_on_axis, @@ -949,8 +963,8 @@ def calculate_confinement_time( else: raise ProcessValueError( - "Illegal value for i_confinement_time", - i_confinement_time=i_confinement_time, + "Illegal value for model", + model=model.value, ) # Apply H-factor correction to chosen scaling From 396287bfc46d4a5843491defa762f78ff7cc23b0 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 11:33:21 +0000 Subject: [PATCH 05/12] Refactor confinement time calculations to use the confinement module in Physics and Stellarator classes --- process/core/io/plot_proc.py | 58 ++++++++++++----------- process/models/physics/physics.py | 4 +- process/models/stellarator/stellarator.py | 2 +- 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/process/core/io/plot_proc.py b/process/core/io/plot_proc.py index 17168438b..92387e1b9 100644 --- a/process/core/io/plot_proc.py +++ b/process/core/io/plot_proc.py @@ -31,7 +31,6 @@ import process.core.constants as constants import process.core.io.mfile as mf import process.data_structure.pfcoil_variables as pfcoil_variables -import process.models.physics.confinement_time as confine import process.models.tfcoil.superconducting as sctf from process.core.io.mfile import MFileErrorClass from process.core.solver.objectives import OBJECTIVE_NAMES @@ -60,6 +59,7 @@ vacuum_vessel_geometry_double_null, vacuum_vessel_geometry_single_null, ) +from process.models.physics.confinement_time import PlasmaConfinementTime from process.models.physics.current_drive import ElectronBernstein, ElectronCyclotron from process.models.physics.impurity_radiation import read_impurity_file from process.models.tfcoil.superconducting import SUPERCONDUCTING_TF_TYPES @@ -8547,7 +8547,7 @@ def plot_confinement_time_comparison( m_ions_total_amu = mfile.get("m_ions_total_amu", scan=scan) # Calculate confinement times using the scan data - iter_89p = confine.iter_89p_confinement_time( + iter_89p = PlasmaConfinementTime().iter_89p_confinement_time( pcur=c_plasma_ma, rmajor=rmajor, rminor=rminor, @@ -8557,7 +8557,7 @@ def plot_confinement_time_comparison( afuel=afuel, p_plasma_loss_mw=p_plasma_separatrix_mw, ) - iter_89_0 = confine.iter_89_0_confinement_time( + iter_89_0 = PlasmaConfinementTime().iter_89_0_confinement_time( pcur=c_plasma_ma, rmajor=rmajor, rminor=rminor, @@ -8567,7 +8567,7 @@ def plot_confinement_time_comparison( afuel=afuel, p_plasma_loss_mw=p_plasma_separatrix_mw, ) - iter_h90_p = confine.iter_h90_p_confinement_time( + iter_h90_p = PlasmaConfinementTime().iter_h90_p_confinement_time( pcur=c_plasma_ma, rmajor=rmajor, rminor=rminor, @@ -8577,7 +8577,7 @@ def plot_confinement_time_comparison( afuel=afuel, p_plasma_loss_mw=p_plasma_separatrix_mw, ) - iter_h90_p_amended = confine.iter_h90_p_amended_confinement_time( + iter_h90_p_amended = PlasmaConfinementTime().iter_h90_p_amended_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, afuel=afuel, @@ -8585,7 +8585,7 @@ def plot_confinement_time_comparison( p_plasma_loss_mw=p_plasma_separatrix_mw, kappa=kappa, ) - iter_93h = confine.iter_93h_confinement_time( + iter_93h = PlasmaConfinementTime().iter_93h_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, p_plasma_loss_mw=p_plasma_separatrix_mw, @@ -8595,7 +8595,7 @@ def plot_confinement_time_comparison( aspect=aspect, kappa=kappa, ) - iter_h97p = confine.iter_h97p_confinement_time( + iter_h97p = PlasmaConfinementTime().iter_h97p_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, p_plasma_loss_mw=p_plasma_separatrix_mw, @@ -8605,7 +8605,7 @@ def plot_confinement_time_comparison( kappa=kappa, afuel=afuel, ) - iter_h97p_elmy = confine.iter_h97p_elmy_confinement_time( + iter_h97p_elmy = PlasmaConfinementTime().iter_h97p_elmy_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, p_plasma_loss_mw=p_plasma_separatrix_mw, @@ -8615,7 +8615,7 @@ def plot_confinement_time_comparison( kappa=kappa, afuel=afuel, ) - iter_96p = confine.iter_96p_confinement_time( + iter_96p = PlasmaConfinementTime().iter_96p_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, kappa95=kappa95, @@ -8625,7 +8625,7 @@ def plot_confinement_time_comparison( afuel=afuel, p_plasma_loss_mw=p_plasma_separatrix_mw, ) - iter_pb98py = confine.iter_pb98py_confinement_time( + iter_pb98py = PlasmaConfinementTime().iter_pb98py_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, dnla19=dnla19, @@ -8635,7 +8635,7 @@ def plot_confinement_time_comparison( aspect=aspect, afuel=afuel, ) - iter_ipb98y = confine.iter_ipb98y_confinement_time( + iter_ipb98y = PlasmaConfinementTime().iter_ipb98y_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, dnla19=dnla19, @@ -8645,7 +8645,7 @@ def plot_confinement_time_comparison( aspect=aspect, afuel=afuel, ) - iter_ipb98y1 = confine.iter_ipb98y1_confinement_time( + iter_ipb98y1 = PlasmaConfinementTime().iter_ipb98y1_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, dnla19=dnla19, @@ -8655,7 +8655,7 @@ def plot_confinement_time_comparison( aspect=aspect, afuel=afuel, ) - iter_ipb98y2 = confine.iter_ipb98y2_confinement_time( + iter_ipb98y2 = PlasmaConfinementTime().iter_ipb98y2_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, dnla19=dnla19, @@ -8665,7 +8665,7 @@ def plot_confinement_time_comparison( aspect=aspect, afuel=afuel, ) - iter_ipb98y3 = confine.iter_ipb98y3_confinement_time( + iter_ipb98y3 = PlasmaConfinementTime().iter_ipb98y3_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, dnla19=dnla19, @@ -8675,7 +8675,7 @@ def plot_confinement_time_comparison( aspect=aspect, afuel=afuel, ) - iter_ipb98y4 = confine.iter_ipb98y4_confinement_time( + iter_ipb98y4 = PlasmaConfinementTime().iter_ipb98y4_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, dnla19=dnla19, @@ -8685,7 +8685,7 @@ def plot_confinement_time_comparison( aspect=aspect, afuel=afuel, ) - petty08 = confine.petty08_confinement_time( + petty08 = PlasmaConfinementTime().petty08_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, dnla19=dnla19, @@ -8694,7 +8694,7 @@ def plot_confinement_time_comparison( kappa_ipb=kappa_ipb, aspect=aspect, ) - menard_nstx = confine.menard_nstx_confinement_time( + menard_nstx = PlasmaConfinementTime().menard_nstx_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, dnla19=dnla19, @@ -8704,17 +8704,19 @@ def plot_confinement_time_comparison( aspect=aspect, afuel=afuel, ) - menard_nstx_petty08 = confine.menard_nstx_petty08_hybrid_confinement_time( - pcur=c_plasma_ma, - b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, - dnla19=dnla19, - p_plasma_loss_mw=p_plasma_separatrix_mw, - rmajor=rmajor, - kappa_ipb=kappa_ipb, - aspect=aspect, - afuel=afuel, + menard_nstx_petty08 = ( + PlasmaConfinementTime().menard_nstx_petty08_hybrid_confinement_time( + pcur=c_plasma_ma, + b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, + dnla19=dnla19, + p_plasma_loss_mw=p_plasma_separatrix_mw, + rmajor=rmajor, + kappa_ipb=kappa_ipb, + aspect=aspect, + afuel=afuel, + ) ) - itpa20 = confine.itpa20_confinement_time( + itpa20 = PlasmaConfinementTime().itpa20_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, dnla19=dnla19, @@ -8725,7 +8727,7 @@ def plot_confinement_time_comparison( eps=(1 / aspect), aion=m_ions_total_amu, ) - itpa20_ilc = confine.itpa20_il_confinement_time( + itpa20_ilc = PlasmaConfinementTime().itpa20_il_confinement_time( pcur=c_plasma_ma, b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, p_plasma_loss_mw=p_plasma_separatrix_mw, diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index c4b2c602a..95ce0c5b8 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -4350,7 +4350,7 @@ def output_confinement_comparison(self, istell: int): _, _, _, - ) = self.calculate_confinement_time( + ) = self.confinement.calculate_confinement_time( physics_variables.m_fuel_amu, physics_variables.p_alpha_total_mw, physics_variables.aspect, @@ -4435,7 +4435,7 @@ def fhz(hfact: float) -> float: _, _, _, - ) = self.calculate_confinement_time( + ) = self.confinement.calculate_confinement_time( physics_variables.m_fuel_amu, physics_variables.p_alpha_total_mw, physics_variables.aspect, diff --git a/process/models/stellarator/stellarator.py b/process/models/stellarator/stellarator.py index 4d04f6181..9a85f0e47 100644 --- a/process/models/stellarator/stellarator.py +++ b/process/models/stellarator/stellarator.py @@ -2294,7 +2294,7 @@ def st_phys(self, output): physics_variables.t_ion_energy_confinement, physics_variables.t_energy_confinement, physics_variables.p_plasma_loss_mw, - ) = self.physics.calculate_confinement_time( + ) = self.physics.confinement.calculate_confinement_time( physics_variables.m_fuel_amu, physics_variables.p_alpha_total_mw, physics_variables.aspect, From 611c549732092f62375dd800c06d9769b6165f18 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 14:09:35 +0000 Subject: [PATCH 06/12] Move the double and triple product into a new function in confinement class --- process/models/physics/confinement_time.py | 30 ++++++++++++++++++++++ process/models/physics/physics.py | 25 ++++++------------ tests/unit/test_physics.py | 14 ---------- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 1d7086b3a..aa3331141 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -1049,6 +1049,36 @@ def calculate_confinement_time( p_plasma_loss_mw, ) + def calculate_double_and_triple_product( + self, + nd_plasma_electrons_vol_avg: float, + temp_plasma_electrons_vol_avg_kev: float, + t_energy_confinement: float, + ) -> tuple[float, float]: + """Calculate the plasma double (nτ_E) and triple product (nTτ_E) + + Parameters + ---------- + nd_plasma_electrons_vol_avg : + Volume averaged electron density [m⁻³] + temp_plasma_electrons_vol_avg_kev : + Volume averaged electron temperature [keV] + t_energy_confinement : + Energy confinement time [s] + + Returns + ------- + : + Tuple[float, float]: (ntau, nTtau) where ntau is the plasma double product (n * τ_E) in units of m⁻³ * s, + and nTtau is the plasma triple product (n * T * τ_E) in units of keV * s * m⁻³ + + """ + + ntau = t_energy_confinement * nd_plasma_electrons_vol_avg + nTtau = ntau * temp_plasma_electrons_vol_avg_kev + + return ntau, nTtau + @staticmethod def neo_alcator_confinement_time( dene20: float, rminor: float, rmajor: float, qstar: float diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 95ce0c5b8..daed046c6 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -1345,8 +1345,6 @@ def physics(self): sbar = 1.0e0 ( physics_variables.burnup, - physics_variables.ntau, - physics_variables.nTtau, physics_variables.figmer, physics_variables.fusrat, physics_variables.molflow_plasma_fuelling_required, @@ -1355,8 +1353,6 @@ def physics(self): physics_variables.f_alpha_energy_confinement, ) = self.phyaux( physics_variables.aspect, - physics_variables.nd_plasma_electrons_vol_avg, - physics_variables.temp_plasma_electron_vol_avg_kev, physics_variables.nd_plasma_fuel_ions_vol_avg, physics_variables.fusden_total, physics_variables.fusden_alpha_total, @@ -1367,6 +1363,14 @@ def physics(self): physics_variables.vol_plasma, ) + physics_variables.ntau, physics_variables.nTtau = ( + self.confinement.calculate_double_and_triple_product( + nd_plasma_electrons_vol_avg=physics_variables.nd_plasma_electrons_vol_avg, + t_energy_confinement=physics_variables.t_energy_confinement, + temp_plasma_electrons_vol_avg_kev=physics_variables.temp_plasma_electron_vol_avg_kev, + ) + ) + # Total transport power from scaling law (MW) physics_variables.pscalingmw = ( physics_variables.p_electron_transport_loss_mw @@ -1834,8 +1838,6 @@ def plasma_composition(): @staticmethod def phyaux( aspect: float, - nd_plasma_electrons_vol_avg: float, - te: float, nd_plasma_fuel_ions_vol_avg: float, fusden_total: float, fusden_alpha_total: float, @@ -1851,10 +1853,6 @@ def phyaux( ---------- aspect : float Plasma aspect ratio. - nd_plasma_electrons_vol_avg : float - Electron density (/m3). - te : float - Volume avergaed electron temperature (keV). nd_plasma_fuel_ions_vol_avg : float Fuel ion density (/m3). fusden_total : float @@ -1877,8 +1875,6 @@ def phyaux( tuple A tuple containing: - burnup (float): Fractional plasma burnup. - - ntau (float): Plasma average n-tau (s/m3). - - nTtau (float): Plasma triple product nT-tau (s/m3). - figmer (float): Physics figure of merit. - fusrat (float): Number of fusion reactions per second. - molflow_plasma_fuelling_required (float): Fuelling rate for D-T (nucleus-pairs/sec). @@ -1890,9 +1886,6 @@ def phyaux( """ figmer = 1e-6 * plasma_current * aspect**sbar - ntau = t_energy_confinement * nd_plasma_electrons_vol_avg - nTtau = ntau * te - # Fusion reactions per second fusrat = fusden_total * vol_plasma @@ -1932,8 +1925,6 @@ def phyaux( return ( burnup, - ntau, - nTtau, figmer, fusrat, molflow_plasma_fuelling_required, diff --git a/tests/unit/test_physics.py b/tests/unit/test_physics.py index dadffa7f5..536b879c3 100644 --- a/tests/unit/test_physics.py +++ b/tests/unit/test_physics.py @@ -2206,8 +2206,6 @@ class PhyauxParam(NamedTuple): tauratio=1, burnup_in=0, aspect=3, - nd_plasma_electrons_vol_avg=7.5e19, - te=12.569, nd_plasma_fuel_ions_vol_avg=5.8589175702454272e19, nd_plasma_alphas_vol_avg=7.5e18, fusden_total=1.9852091609123786e17, @@ -2217,8 +2215,6 @@ class PhyauxParam(NamedTuple): t_energy_confinement=3.401323521525641, vol_plasma=1888.1711539956691, expected_burnup=0.20383432558954095, - expected_ntau=2.5509926411442307e20, - expected_nTtau=3.253e21, expected_figmer=55.195367036602576, expected_fusrat=3.7484146722826997e20, expected_molflow_plasma_fuelling_required=1.8389516394951276e21, @@ -2229,8 +2225,6 @@ class PhyauxParam(NamedTuple): tauratio=1, burnup_in=0, aspect=3, - nd_plasma_electrons_vol_avg=7.5e19, - te=12.569, nd_plasma_fuel_ions_vol_avg=5.8576156204039725e19, nd_plasma_alphas_vol_avg=7.5e18, fusden_total=1.9843269653375773e17, @@ -2240,8 +2234,6 @@ class PhyauxParam(NamedTuple): t_energy_confinement=3.402116961408892, vol_plasma=1888.1711539956691, expected_burnup=0.20387039462081086, - expected_ntau=2.5515877210566689e20, - expected_nTtau=3.253e21, expected_figmer=55.195367036602576, expected_fusrat=3.7467489360461772e20, expected_molflow_plasma_fuelling_required=1.8378092331723546e21, @@ -2269,8 +2261,6 @@ def test_phyaux(phyauxparam, monkeypatch, physics): ( burnup, - ntau, - _nTtau, figmer, fusrat, molflow_plasma_fuelling_required, @@ -2279,8 +2269,6 @@ def test_phyaux(phyauxparam, monkeypatch, physics): _, ) = physics.phyaux( aspect=phyauxparam.aspect, - nd_plasma_electrons_vol_avg=phyauxparam.nd_plasma_electrons_vol_avg, - te=phyauxparam.te, nd_plasma_fuel_ions_vol_avg=phyauxparam.nd_plasma_fuel_ions_vol_avg, nd_plasma_alphas_vol_avg=phyauxparam.nd_plasma_alphas_vol_avg, fusden_total=phyauxparam.fusden_total, @@ -2293,8 +2281,6 @@ def test_phyaux(phyauxparam, monkeypatch, physics): assert burnup == pytest.approx(phyauxparam.expected_burnup) - assert ntau == pytest.approx(phyauxparam.expected_ntau) - assert figmer == pytest.approx(phyauxparam.expected_figmer) assert fusrat == pytest.approx(phyauxparam.expected_fusrat) From a90a9c528c00b63102ca65f2aa19d5b5a8cc2144 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 14:51:07 +0000 Subject: [PATCH 07/12] Refactor confinement time handling to utilize ConfinementTimeModel and remove LABELS_CONFINEMENT_SCALINGS --- process/core/io/plot_proc.py | 45 ++++---- process/data_structure/physics_variables.py | 57 +---------- process/models/physics/confinement_time.py | 108 +++++++++++--------- process/models/physics/physics.py | 13 ++- 4 files changed, 90 insertions(+), 133 deletions(-) diff --git a/process/core/io/plot_proc.py b/process/core/io/plot_proc.py index 92387e1b9..27d2f8b45 100644 --- a/process/core/io/plot_proc.py +++ b/process/core/io/plot_proc.py @@ -34,7 +34,7 @@ import process.models.tfcoil.superconducting as sctf from process.core.io.mfile import MFileErrorClass from process.core.solver.objectives import OBJECTIVE_NAMES -from process.data_structure import impurity_radiation_module, physics_variables +from process.data_structure import impurity_radiation_module from process.models.build import Build from process.models.geometry.blanket import ( blanket_geometry_double_null, @@ -59,7 +59,10 @@ vacuum_vessel_geometry_double_null, vacuum_vessel_geometry_single_null, ) -from process.models.physics.confinement_time import PlasmaConfinementTime +from process.models.physics.confinement_time import ( + ConfinementTimeModel, + PlasmaConfinementTime, +) from process.models.physics.current_drive import ElectronBernstein, ElectronCyclotron from process.models.physics.impurity_radiation import read_impurity_file from process.models.tfcoil.superconducting import SUPERCONDUCTING_TF_TYPES @@ -8740,25 +8743,25 @@ def plot_confinement_time_comparison( # Data for the box plot data = { - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[6]}": iter_89p, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[7]}": iter_89_0, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[13]}": iter_h90_p, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[20]}": iter_h90_p_amended, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[24]}": iter_93h, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[26]}": iter_h97p, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[27]}": iter_h97p_elmy, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[28]}": iter_96p, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[31]}": iter_pb98py, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[32]}": iter_ipb98y, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[33]}": iter_ipb98y1, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[34]}": iter_ipb98y2, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[35]}": iter_ipb98y3, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[36]}": iter_ipb98y4, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[41]}": petty08, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[46]}": menard_nstx, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[47]}": menard_nstx_petty08, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[49]}": itpa20, - rf"{physics_variables.LABELS_CONFINEMENT_SCALINGS[50]}": itpa20_ilc, + rf"{ConfinementTimeModel.ITER_89P.full_name}": iter_89p, + rf"{ConfinementTimeModel.ITER_89_0.full_name}": iter_89_0, + rf"{ConfinementTimeModel.ITER_H90_P.full_name}": iter_h90_p, + rf"{ConfinementTimeModel.ITER_H90_P_AMENDED.full_name}": iter_h90_p_amended, + rf"{ConfinementTimeModel.ITER_93H.full_name}": iter_93h, + rf"{ConfinementTimeModel.ITER_H97P.full_name}": iter_h97p, + rf"{ConfinementTimeModel.ITER_H97P_ELMY.full_name}": iter_h97p_elmy, + rf"{ConfinementTimeModel.ITER_96P.full_name}": iter_96p, + rf"{ConfinementTimeModel.ITER_PB98P_Y.full_name}": iter_pb98py, + rf"{ConfinementTimeModel.IPB98_Y.full_name}": iter_ipb98y, + rf"{ConfinementTimeModel.ITER_IPB98Y1.full_name}": iter_ipb98y1, + rf"{ConfinementTimeModel.ITER_IPB98Y2.full_name}": iter_ipb98y2, + rf"{ConfinementTimeModel.ITER_IPB98Y3.full_name}": iter_ipb98y3, + rf"{ConfinementTimeModel.ITER_IPB98Y4.full_name}": iter_ipb98y4, + rf"{ConfinementTimeModel.PETTY08.full_name}": petty08, + rf"{ConfinementTimeModel.MENARD_NSTX.full_name}": menard_nstx, + rf"{ConfinementTimeModel.MENARD_NSTX_PETTY08_HYBRID.full_name}": menard_nstx_petty08, + rf"{ConfinementTimeModel.ITPA20.full_name}": itpa20, + rf"{ConfinementTimeModel.ITPA20_IL.full_name}": itpa20_ilc, } # Create the violin plot diff --git a/process/data_structure/physics_variables.py b/process/data_structure/physics_variables.py index 72e4fd564..5318ed6aa 100644 --- a/process/data_structure/physics_variables.py +++ b/process/data_structure/physics_variables.py @@ -89,61 +89,6 @@ N_CONFINEMENT_SCALINGS: int = 51 """number of energy confinement time scaling laws""" -LABELS_CONFINEMENT_SCALINGS: list[str] = [ - "User input electron confinement ", - "Neo-Alcator (Ohmic)", - "Mirnov (H)", - "Merezkhin-Muhkovatov (Ohmic)(L)", - "Shimomura (H)", - "Kaye-Goldston (L)", - "ITER 89-P (L)", - "ITER 89-O (L)", - "Rebut-Lallia (L)", - "Goldston (L)", - "T10 (L)", - "JAERI / Odajima-Shimomura (L)", - "Kaye-Big Complex (L)", - "ITER H90-P (H)", - "ITER 89-P & 89-O min (L)", - "Riedel (L)", - "Christiansen (L)", - "Lackner-Gottardi (L)", - "Neo-Kaye (L)", - "Riedel (H)", - "ITER H90-P amended (H)", - "LHD (Stell)", - "Gyro-reduced Bohm (Stell)", - "Lackner-Gottardi (Stell)", - "ITER-93H ELM-free (H)", - "TITAN RFP OBSOLETE ", - "ITER H-97P ELM-free (H)", - "ITER H-97P ELMy (H)", - "ITER-96P (ITER-97L) (L)", - "Valovic modified ELMy (H)", - "Kaye 98 modified (L)", - "ITERH-PB98P(y) (H)", - "IPB98(y) (H)", - "IPB98(y,1) (H)", - "IPB98(y,2) (H)", - "IPB98(y,3) (H)", - "IPB98(y,4) (H)", - "ISS95 (Stell)", - "ISS04 (Stell)", - "DS03 beta-independent (H)", - 'Murari "Non-power law" (H)', - "Petty 2008 (ST)(H)", - "Lang high density (H)", - "Hubbard 2017 - nominal (I)", - "Hubbard 2017 - lower (I)", - "Hubbard 2017 - upper (I)", - "Menard NSTX (ST)(H)", - "Menard NSTX-Petty08 hybrid (ST)(H)", - "Buxton NSTX gyro-Bohm (ST)(H)", - "ITPA20 (H)", - "ITPA20-IL (H)", -] -"""labels describing energy confinement scaling laws""" - m_beam_amu: float = None """beam ion mass (amu)""" @@ -721,7 +666,7 @@ i_confinement_time: int = None -"""switch for energy confinement time scaling law (see description in `LABELS_CONFINEMENT_SCALINGS`)""" +"""switch for energy confinement time scaling law""" i_plasma_wall_gap: int = None diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index aa3331141..1d7f356c0 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -15,57 +15,63 @@ class ConfinementTimeModel(IntEnum): """Confinement time (τ_E) model types""" - USER_INPUT = 0 - NEO_ALCATOR = 1 - MIRNOV = 2 - MEREZHKIN_MUHKOVATOV = 3 - SHIMOMURA = 4 - KAYE_GOLDSTON = 5 - ITER_89P = 6 - ITER_89_0 = 7 - REBUT_LALLIA = 8 - GOLDSTON = 9 - T_10 = 10 - JAERI = 11 - KAYE_BIG = 12 - ITER_H90_P = 13 - MINIMUM_OF_ITER_89P_AND_ITER_89_0 = 14 - RIEDEL_L = 15 - CHRISTIANSEN = 16 - LACKNER_GOTTARDI = 17 - NEO_KAYE = 18 - RIEDEL_H = 19 - ITER_H90_P_AMENDED = 20 - SUDO_ET_AL = 21 - GYRO_REDUCED_BOHM = 22 - LACKNER_GOTTARDI_STELLARATOR = 23 - ITER_93H = 24 - TITAN_REMOVED = 25 - ITER_H97P = 26 - ITER_H97P_ELMY = 27 - ITER_96P = 28 - VALOVIC_ELMY = 29 - KAYE = 30 - ITER_PB98P_Y = 31 - IPB98_Y = 32 - ITER_IPB98Y1 = 33 - ITER_IPB98Y2 = 34 - ITER_IPB98Y3 = 35 - ITER_IPB98Y4 = 36 - ISS95_STELLARATOR = 37 - ISS04_STELLARATOR = 38 - DS03 = 39 - MURARI = 40 - PETTY08 = 41 - LANG_HIGH_DENSITY = 42 - HUBBARD_NOMINAL = 43 - HUBBARD_LOWER = 44 - HUBBARD_UPPER = 45 - MENARD_NSTX = 46 - MENARD_NSTX_PETTY08_HYBRID = 47 - NSTX_GYRO_BOHM = 48 - ITPA20 = 49 - ITPA20_IL = 50 + USER_INPUT = (0, "User input electron confinement ") + NEO_ALCATOR = (1, "Neo-Alcator (Ohmic)") + MIRNOV = (2, "Mirnov (H)") + MEREZHKIN_MUHKOVATOV = (3, "Merezkhin-Muhkovatov (Ohmic)(L)") + SHIMOMURA = (4, "Shimomura (H)") + KAYE_GOLDSTON = (5, "Kaye-Goldston (L)") + ITER_89P = (6, "ITER 89-P (L)") + ITER_89_0 = (7, "ITER 89-O (L)") + REBUT_LALLIA = (8, "Rebut-Lallia (L)") + GOLDSTON = (9, "Goldston (L)") + T_10 = (10, "T10 (L)") + JAERI = (11, "JAERI / Odajima-Shimomura (L)") + KAYE_BIG = (12, "Kaye-Big Complex (L)") + ITER_H90_P = (13, "ITER H90-P (H)") + MINIMUM_OF_ITER_89P_AND_ITER_89_0 = (14, "ITER 89-P & 89-O min (L)") + RIEDEL_L = (15, "Riedel (L)") + CHRISTIANSEN = (16, "Christiansen (L)") + LACKNER_GOTTARDI = (17, "Lackner-Gottardi (L)") + NEO_KAYE = (18, "Neo-Kaye (L)") + RIEDEL_H = (19, "Riedel (H)") + ITER_H90_P_AMENDED = (20, "ITER H90-P amended (H)") + SUDO_ET_AL = (21, "LHD (Stell)") + GYRO_REDUCED_BOHM = (22, "Gyro-reduced Bohm (Stell)") + LACKNER_GOTTARDI_STELLARATOR = (23, "Lackner-Gottardi (Stell)") + ITER_93H = (24, "ITER-93H ELM-free (H)") + TITAN_REMOVED = (25, "TITAN RFP OBSOLETE ") + ITER_H97P = (26, "ITER H-97P ELM-free (H)") + ITER_H97P_ELMY = (27, "ITER H-97P ELMy (H)") + ITER_96P = (28, "ITER-96P (ITER-97L) (L)") + VALOVIC_ELMY = (29, "Valovic modified ELMy (H)") + KAYE = (30, "Kaye 98 modified (L)") + ITER_PB98P_Y = (31, "ITERH-PB98P(y) (H)") + IPB98_Y = (32, "IPB98(y) (H)") + ITER_IPB98Y1 = (33, "IPB98(y,1) (H)") + ITER_IPB98Y2 = (34, "IPB98(y,2) (H)") + ITER_IPB98Y3 = (35, "IPB98(y,3) (H)") + ITER_IPB98Y4 = (36, "IPB98(y,4) (H)") + ISS95_STELLARATOR = (37, "ISS95 (Stell)") + ISS04_STELLARATOR = (38, "ISS04 (Stell)") + DS03 = (39, "DS03 beta-independent (H)") + MURARI = (40, 'Murari "Non-power law" (H)') + PETTY08 = (41, "Petty 2008 (ST)(H)") + LANG_HIGH_DENSITY = (42, "Lang high density (H)") + HUBBARD_NOMINAL = (43, "Hubbard 2017 - nominal (I)") + HUBBARD_LOWER = (44, "Hubbard 2017 - lower (I)") + HUBBARD_UPPER = (45, "Hubbard 2017 - upper (I)") + MENARD_NSTX = (46, "Menard NSTX (ST)(H)") + MENARD_NSTX_PETTY08_HYBRID = (47, "Menard NSTX-Petty08 hybrid (ST)(H)") + NSTX_GYRO_BOHM = (48, "Buxton NSTX gyro-Bohm (ST)(H)") + ITPA20 = (49, "ITPA20 (H)") + ITPA20_IL = (50, "ITPA20-IL (H)") + + def __new__(cls, value, full_name): + obj = int.__new__(cls, value) + obj._value_ = value + obj.full_name = full_name + return obj class ConfinementRadiationLossModel(IntEnum): diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index daed046c6..55ba1703b 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -26,7 +26,10 @@ times_variables, ) from process.models.physics.bootstrap_current import PlasmaBootstrapCurrent -from process.models.physics.confinement_time import PlasmaConfinementTime +from process.models.physics.confinement_time import ( + ConfinementTimeModel, + PlasmaConfinementTime, +) from process.models.physics.density_limit import PlasmaDensityLimit from process.models.physics.exhaust import PlasmaExhaust @@ -4047,9 +4050,7 @@ def outplas(self): ) po.oblnkl(self.outfile) - tauelaw = physics_variables.LABELS_CONFINEMENT_SCALINGS[ - physics_variables.i_confinement_time - ] + tauelaw = ConfinementTimeModel(physics_variables.i_confinement_time).full_name po.ocmmnt( self.outfile, @@ -4379,9 +4380,11 @@ def output_confinement_comparison(self, istell: int): # just write a NaN--its not worth crashing PROCESS over. physics_variables.hfac[i_confinement_time - 1] = np.nan + scaling_name = ConfinementTimeModel(i_confinement_time).full_name + po.ocmmnt( self.outfile, - f"{'':>2}{physics_variables.LABELS_CONFINEMENT_SCALINGS[i_confinement_time]:<38}" + f"{'':>2}{scaling_name:<38}" f"{taueez:<28.3f}{physics_variables.hfac[i_confinement_time - 1]:.3f}", ) From 8999282973da8468a290456508a7a65d36831cc7 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 15:12:07 +0000 Subject: [PATCH 08/12] Post rebase conflict fix --- process/models/physics/physics.py | 2 +- process/models/stellarator/stellarator.py | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 55ba1703b..50e008b89 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -645,8 +645,8 @@ def __init__( plasma_inductance, plasma_density_limit: PlasmaDensityLimit, plasma_exhaust: PlasmaExhaust, - plasma_confinement: PlasmaConfinementTime, plasma_bootstrap_current: PlasmaBootstrapCurrent, + plasma_confinement: PlasmaConfinementTime, ): self.outfile = constants.NOUT self.mfile = constants.MFILE diff --git a/process/models/stellarator/stellarator.py b/process/models/stellarator/stellarator.py index 9a85f0e47..4e6ff43bc 100644 --- a/process/models/stellarator/stellarator.py +++ b/process/models/stellarator/stellarator.py @@ -2341,8 +2341,6 @@ def st_phys(self, output): sbar = 1.0e0 ( physics_variables.burnup, - physics_variables.ntau, - physics_variables.nTtau, physics_variables.figmer, _fusrat, physics_variables.molflow_plasma_fuelling_required, @@ -2351,8 +2349,6 @@ def st_phys(self, output): physics_variables.f_alpha_energy_confinement, ) = self.physics.phyaux( physics_variables.aspect, - physics_variables.nd_plasma_electrons_vol_avg, - physics_variables.temp_plasma_electron_vol_avg_kev, physics_variables.nd_plasma_fuel_ions_vol_avg, physics_variables.fusden_total, physics_variables.fusden_alpha_total, From b7f445278e607d5e3a0882eb8c2e221ce7a6a2be Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 15:26:40 +0000 Subject: [PATCH 09/12] Refactor confinement time handling by moving output_confinement_comparison and find_other_h_factors methods to PlasmaConfinementTime class --- process/models/physics/confinement_time.py | 202 ++++++++++++++++ process/models/physics/physics.py | 254 +++------------------ 2 files changed, 230 insertions(+), 226 deletions(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 1d7f356c0..7343ea89f 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -2,10 +2,13 @@ from enum import IntEnum import numpy as np +from scipy.optimize import root_scalar from process.core import constants +from process.core import process_output as po from process.core.exceptions import ProcessValueError from process.data_structure import ( + current_drive_variables, physics_variables, ) @@ -1085,6 +1088,205 @@ def calculate_double_and_triple_product( return ntau, nTtau + def find_other_h_factors(self, i_confinement_time: int) -> float: + """Function to find H-factor for the equivalent confinement time in other scalings. + + Parameters + ---------- + i_confinement_time : int + Index of the confinement time scaling to use. + + Returns + ------- + float + The calculated H-factor. + + """ + + def fhz(hfact: float) -> float: + """Function used to find power balance. + + Parameters + ---------- + hfact : float + H-factor to be used in the calculation. + hfact: float : + + + Returns + ------- + float + The difference between the calculated power and the required power for balance. + + """ + ( + ptrez, + ptriz, + _, + _, + _, + _, + ) = self.calculate_confinement_time( + m_fuel_amu=physics_variables.m_fuel_amu, + p_alpha_total_mw=physics_variables.p_alpha_total_mw, + aspect=physics_variables.aspect, + b_plasma_toroidal_on_axis=physics_variables.b_plasma_toroidal_on_axis, + nd_plasma_ions_total_vol_avg=physics_variables.nd_plasma_ions_total_vol_avg, + nd_plasma_electrons_vol_avg=physics_variables.nd_plasma_electrons_vol_avg, + nd_plasma_electron_line=physics_variables.nd_plasma_electron_line, + eps=physics_variables.eps, + hfact=hfact, + i_confinement_time=i_confinement_time, + i_plasma_ignited=physics_variables.i_plasma_ignited, + kappa=physics_variables.kappa, + kappa95=physics_variables.kappa95, + p_non_alpha_charged_mw=physics_variables.p_non_alpha_charged_mw, + p_hcd_injected_total_mw=current_drive_variables.p_hcd_injected_total_mw, + plasma_current=physics_variables.plasma_current, + pden_plasma_core_rad_mw=physics_variables.pden_plasma_core_rad_mw, + rmajor=physics_variables.rmajor, + rminor=physics_variables.rminor, + temp_plasma_electron_density_weighted_kev=physics_variables.temp_plasma_electron_density_weighted_kev, + temp_plasma_ion_density_weighted_kev=physics_variables.temp_plasma_ion_density_weighted_kev, + q95=physics_variables.q95, + qstar=physics_variables.qstar, + vol_plasma=physics_variables.vol_plasma, + zeff=physics_variables.n_charge_plasma_effective_vol_avg, + ) + + # At power balance, fhz is zero. + fhz_value = ( + ptrez + + ptriz + - physics_variables.f_p_alpha_plasma_deposited + * physics_variables.pden_alpha_total_mw + - physics_variables.pden_non_alpha_charged_mw + - physics_variables.pden_plasma_ohmic_mw + ) + + # Take into account whether injected power is included in tau_e calculation (i.e. whether device is ignited) + if physics_variables.i_plasma_ignited == 0: + fhz_value -= ( + current_drive_variables.p_hcd_injected_total_mw + / physics_variables.vol_plasma + ) + + # Include the radiation power if requested + if physics_variables.i_rad_loss == 0: + fhz_value += physics_variables.pden_plasma_rad_mw + elif physics_variables.i_rad_loss == 1: + fhz_value += physics_variables.pden_plasma_core_rad_mw + + return fhz_value + + return root_scalar(fhz, bracket=(0.01, 150), xtol=0.001).root + + def output_confinement_comparison(self, istell: int): + """Routine to calculate ignition margin for different confinement scalings and equivalent confinement times for H=1. + + This routine calculates the ignition margin at the final point with different scalings and outputs the results to a file. + + The output includes: + - Energy confinement times + - Required H-factors for power balance + + The routine iterates over a range of confinement times, skipping the first user input and a specific index (25). For each confinement time, it calculates various parameters related to confinement and ignition using the `calculate_confinement_time` method. It then calculates the H-factor for when the plasma is ignited using the `find_other_h_factors` method and writes the results to the output file. + + Output format: + - Header: "Energy confinement times, and required H-factors :" + - Columns: "Scaling law", "Confinement time [s]", "H-factor for power balance" + + Methods used: + - `calculate_confinement_time`: Calculates confinement-related parameters. + - `find_other_h_factors`: Calculates the H-factor for a given confinement time. + + Parameters + ---------- + istell : + Indicator for stellarator (0 for tokamak, >=1 for stellarator). + + """ + + po.oheadr(self.outfile, "Energy confinement times, and required H-factors :") + po.ocmmnt( + self.outfile, + f"{'':>2}{'Scaling law':<27}{'Electron confinement time [s]':<32}Equivalent H-factor for", + ) + po.ocmmnt( + self.outfile, + f"{'':>38}{'for H = 1':<23}same confinement time", + ) + po.oblnkl(self.outfile) + + # List of key values for stellarator scalings + stellarator_scalings = [21, 22, 23, 37, 38] + + # Plot all of the confinement scalings for comparison when H = 1 + # Start from range 1 as the first i_confinement_time is a user input + # If stellarator, use the stellarator scalings + for i_confinement_time in ( + range(1, physics_variables.N_CONFINEMENT_SCALINGS) + if istell == 0 + else stellarator_scalings + ): + if i_confinement_time == 25: + continue + ( + _, + _, + taueez, + _, + _, + _, + ) = self.calculate_confinement_time( + m_fuel_amu=physics_variables.m_fuel_amu, + p_alpha_total_mw=physics_variables.p_alpha_total_mw, + aspect=physics_variables.aspect, + b_plasma_toroidal_on_axis=physics_variables.b_plasma_toroidal_on_axis, + nd_plasma_ions_total_vol_avg=physics_variables.nd_plasma_ions_total_vol_avg, + nd_plasma_electrons_vol_avg=physics_variables.nd_plasma_electrons_vol_avg, + nd_plasma_electron_line=physics_variables.nd_plasma_electron_line, + eps=physics_variables.eps, + hfact=1.0, + i_confinement_time=i_confinement_time, + i_plasma_ignited=physics_variables.i_plasma_ignited, + kappa=physics_variables.kappa, + kappa95=physics_variables.kappa95, + p_non_alpha_charged_mw=physics_variables.p_non_alpha_charged_mw, + p_hcd_injected_total_mw=current_drive_variables.p_hcd_injected_total_mw, + plasma_current=physics_variables.plasma_current, + pden_plasma_core_rad_mw=physics_variables.pden_plasma_core_rad_mw, + rmajor=physics_variables.rmajor, + rminor=physics_variables.rminor, + temp_plasma_electron_density_weighted_kev=physics_variables.temp_plasma_electron_density_weighted_kev, + temp_plasma_ion_density_weighted_kev=physics_variables.temp_plasma_ion_density_weighted_kev, + q95=physics_variables.q95, + qstar=physics_variables.qstar, + vol_plasma=physics_variables.vol_plasma, + zeff=physics_variables.n_charge_plasma_effective_vol_avg, + ) + + try: + # Calculate the H-factor for the same confinement time in other scalings + physics_variables.hfac[i_confinement_time - 1] = ( + self.find_other_h_factors(i_confinement_time) + ) + except ValueError: + # This is only used for a table in the OUT.DAT so if it fails + # just write a NaN--its not worth crashing PROCESS over. + physics_variables.hfac[i_confinement_time - 1] = np.nan + + scaling_name = ConfinementTimeModel(i_confinement_time).full_name + + po.ocmmnt( + self.outfile, + f"{'':>2}{scaling_name:<38}" + f"{taueez:<28.3f}{physics_variables.hfac[i_confinement_time - 1]:.3f}", + ) + + po.oblnkl(self.outfile) + po.ostars(self.outfile, 110) + @staticmethod def neo_alcator_confinement_time( dene20: float, rminor: float, rmajor: float, qstar: float diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 50e008b89..6efa9c116 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -4,7 +4,6 @@ import numba as nb import numpy as np -from scipy.optimize import root_scalar import process.models.physics.fusion_reactions as reactions import process.models.physics.impurity_radiation as impurity_radiation @@ -1280,31 +1279,31 @@ def physics(self): physics_variables.t_ion_energy_confinement, physics_variables.p_plasma_loss_mw, ) = self.confinement.calculate_confinement_time( - physics_variables.m_fuel_amu, - physics_variables.p_alpha_total_mw, - physics_variables.aspect, - physics_variables.b_plasma_toroidal_on_axis, - physics_variables.nd_plasma_ions_total_vol_avg, - physics_variables.nd_plasma_electrons_vol_avg, - physics_variables.nd_plasma_electron_line, - physics_variables.eps, - physics_variables.hfact, - physics_variables.i_confinement_time, - physics_variables.i_plasma_ignited, - physics_variables.kappa, - physics_variables.kappa95, - physics_variables.p_non_alpha_charged_mw, - current_drive_variables.p_hcd_injected_total_mw, - physics_variables.plasma_current, - physics_variables.pden_plasma_core_rad_mw, - physics_variables.rmajor, - physics_variables.rminor, - physics_variables.temp_plasma_electron_density_weighted_kev, - physics_variables.temp_plasma_ion_density_weighted_kev, - physics_variables.q95, - physics_variables.qstar, - physics_variables.vol_plasma, - physics_variables.n_charge_plasma_effective_vol_avg, + m_fuel_amu=physics_variables.m_fuel_amu, + p_alpha_total_mw=physics_variables.p_alpha_total_mw, + aspect=physics_variables.aspect, + b_plasma_toroidal_on_axis=physics_variables.b_plasma_toroidal_on_axis, + nd_plasma_ions_total_vol_avg=physics_variables.nd_plasma_ions_total_vol_avg, + nd_plasma_electrons_vol_avg=physics_variables.nd_plasma_electrons_vol_avg, + nd_plasma_electron_line=physics_variables.nd_plasma_electron_line, + eps=physics_variables.eps, + hfact=physics_variables.hfact, + i_confinement_time=physics_variables.i_confinement_time, + i_plasma_ignited=physics_variables.i_plasma_ignited, + kappa=physics_variables.kappa, + kappa95=physics_variables.kappa95, + p_non_alpha_charged_mw=physics_variables.p_non_alpha_charged_mw, + p_hcd_injected_total_mw=current_drive_variables.p_hcd_injected_total_mw, + plasma_current=physics_variables.plasma_current, + pden_plasma_core_rad_mw=physics_variables.pden_plasma_core_rad_mw, + rmajor=physics_variables.rmajor, + rminor=physics_variables.rminor, + temp_plasma_electron_density_weighted_kev=physics_variables.temp_plasma_electron_density_weighted_kev, + temp_plasma_ion_density_weighted_kev=physics_variables.temp_plasma_ion_density_weighted_kev, + q95=physics_variables.q95, + qstar=physics_variables.qstar, + vol_plasma=physics_variables.vol_plasma, + zeff=physics_variables.n_charge_plasma_effective_vol_avg, ) # Total transport power from scaling law (MW) @@ -4183,7 +4182,9 @@ def outplas(self): ) # Plot table of al the H-factor scalings and coparison values - self.output_confinement_comparison(istell=stellarator_variables.istell) + self.confinement.output_confinement_comparison( + istell=stellarator_variables.istell + ) if stellarator_variables.istell == 0: # Issues 363 Output dimensionless plasma parameters MDK @@ -4285,205 +4286,6 @@ def outplas(self): reinke_variables.fzactual, ) - def output_confinement_comparison(self, istell: int): - """Routine to calculate ignition margin for different confinement scalings and equivalent confinement times for H=1. - - This routine calculates the ignition margin at the final point with different scalings and outputs the results to a file. - - The output includes: - - Energy confinement times - - Required H-factors for power balance - - The routine iterates over a range of confinement times, skipping the first user input and a specific index (25). For each confinement time, it calculates various parameters related to confinement and ignition using the `calculate_confinement_time` method. It then calculates the H-factor for when the plasma is ignited using the `find_other_h_factors` method and writes the results to the output file. - - Output format: - - Header: "Energy confinement times, and required H-factors :" - - Columns: "Scaling law", "Confinement time [s]", "H-factor for power balance" - - Methods used: - - `calculate_confinement_time`: Calculates confinement-related parameters. - - `find_other_h_factors`: Calculates the H-factor for a given confinement time. - - Parameters - ---------- - istell : - Indicator for stellarator (0 for tokamak, >=1 for stellarator). - - """ - - po.oheadr(self.outfile, "Energy confinement times, and required H-factors :") - po.ocmmnt( - self.outfile, - f"{'':>2}{'Scaling law':<27}{'Electron confinement time [s]':<32}Equivalent H-factor for", - ) - po.ocmmnt( - self.outfile, - f"{'':>38}{'for H = 1':<23}same confinement time", - ) - po.oblnkl(self.outfile) - - # List of key values for stellarator scalings - stellarator_scalings = [21, 22, 23, 37, 38] - - # Plot all of the confinement scalings for comparison when H = 1 - # Start from range 1 as the first i_confinement_time is a user input - # If stellarator, use the stellarator scalings - for i_confinement_time in ( - range(1, physics_variables.N_CONFINEMENT_SCALINGS) - if istell == 0 - else stellarator_scalings - ): - if i_confinement_time == 25: - continue - ( - _, - _, - taueez, - _, - _, - _, - ) = self.confinement.calculate_confinement_time( - physics_variables.m_fuel_amu, - physics_variables.p_alpha_total_mw, - physics_variables.aspect, - physics_variables.b_plasma_toroidal_on_axis, - physics_variables.nd_plasma_ions_total_vol_avg, - physics_variables.nd_plasma_electrons_vol_avg, - physics_variables.nd_plasma_electron_line, - physics_variables.eps, - 1.0, - i_confinement_time, - physics_variables.i_plasma_ignited, - physics_variables.kappa, - physics_variables.kappa95, - physics_variables.p_non_alpha_charged_mw, - current_drive_variables.p_hcd_injected_total_mw, - physics_variables.plasma_current, - physics_variables.pden_plasma_core_rad_mw, - physics_variables.rmajor, - physics_variables.rminor, - physics_variables.temp_plasma_electron_density_weighted_kev, - physics_variables.temp_plasma_ion_density_weighted_kev, - physics_variables.q95, - physics_variables.qstar, - physics_variables.vol_plasma, - physics_variables.n_charge_plasma_effective_vol_avg, - ) - - try: - # Calculate the H-factor for the same confinement time in other scalings - physics_variables.hfac[i_confinement_time - 1] = ( - self.find_other_h_factors(i_confinement_time) - ) - except ValueError: - # This is only used for a table in the OUT.DAT so if it fails - # just write a NaN--its not worth crashing PROCESS over. - physics_variables.hfac[i_confinement_time - 1] = np.nan - - scaling_name = ConfinementTimeModel(i_confinement_time).full_name - - po.ocmmnt( - self.outfile, - f"{'':>2}{scaling_name:<38}" - f"{taueez:<28.3f}{physics_variables.hfac[i_confinement_time - 1]:.3f}", - ) - - po.oblnkl(self.outfile) - po.ostars(self.outfile, 110) - - def find_other_h_factors(self, i_confinement_time: int) -> float: - """Function to find H-factor for the equivalent confinement time in other scalings. - - Parameters - ---------- - i_confinement_time : int - Index of the confinement time scaling to use. - - Returns - ------- - float - The calculated H-factor. - - """ - - def fhz(hfact: float) -> float: - """Function used to find power balance. - - Parameters - ---------- - hfact : float - H-factor to be used in the calculation. - hfact: float : - - - Returns - ------- - float - The difference between the calculated power and the required power for balance. - - """ - ( - ptrez, - ptriz, - _, - _, - _, - _, - ) = self.confinement.calculate_confinement_time( - physics_variables.m_fuel_amu, - physics_variables.p_alpha_total_mw, - physics_variables.aspect, - physics_variables.b_plasma_toroidal_on_axis, - physics_variables.nd_plasma_ions_total_vol_avg, - physics_variables.nd_plasma_electrons_vol_avg, - physics_variables.nd_plasma_electron_line, - physics_variables.eps, - hfact, - i_confinement_time, - physics_variables.i_plasma_ignited, - physics_variables.kappa, - physics_variables.kappa95, - physics_variables.p_non_alpha_charged_mw, - current_drive_variables.p_hcd_injected_total_mw, - physics_variables.plasma_current, - physics_variables.pden_plasma_core_rad_mw, - physics_variables.rmajor, - physics_variables.rminor, - physics_variables.temp_plasma_electron_density_weighted_kev, - physics_variables.temp_plasma_ion_density_weighted_kev, - physics_variables.q95, - physics_variables.qstar, - physics_variables.vol_plasma, - physics_variables.n_charge_plasma_effective_vol_avg, - ) - - # At power balance, fhz is zero. - fhz_value = ( - ptrez - + ptriz - - physics_variables.f_p_alpha_plasma_deposited - * physics_variables.pden_alpha_total_mw - - physics_variables.pden_non_alpha_charged_mw - - physics_variables.pden_plasma_ohmic_mw - ) - - # Take into account whether injected power is included in tau_e calculation (i.e. whether device is ignited) - if physics_variables.i_plasma_ignited == 0: - fhz_value -= ( - current_drive_variables.p_hcd_injected_total_mw - / physics_variables.vol_plasma - ) - - # Include the radiation power if requested - if physics_variables.i_rad_loss == 0: - fhz_value += physics_variables.pden_plasma_rad_mw - elif physics_variables.i_rad_loss == 1: - fhz_value += physics_variables.pden_plasma_core_rad_mw - - return fhz_value - - return root_scalar(fhz, bracket=(0.01, 150), xtol=0.001).root - @staticmethod def calculate_plasma_masses( m_fuel_amu: float, From 96e07b2ed6f3f255574719ec82d3f5cd0d7d6af5 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 15:35:05 +0000 Subject: [PATCH 10/12] Refactor confinement time output handling by moving logic to output_confinement_time_info method in PlasmaConfinementTime class --- process/models/physics/confinement_time.py | 147 +++++++++++++++++++++ process/models/physics/physics.py | 147 +-------------------- 2 files changed, 148 insertions(+), 146 deletions(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 7343ea89f..637cc55d3 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -4,6 +4,8 @@ import numpy as np from scipy.optimize import root_scalar +import process.data_structure.constraint_variables as constraint_variables +import process.data_structure.stellarator_variables as stellarator_variables from process.core import constants from process.core import process_output as po from process.core.exceptions import ProcessValueError @@ -1181,6 +1183,151 @@ def fhz(hfact: float) -> float: return root_scalar(fhz, bracket=(0.01, 150), xtol=0.001).root + def output_confinement_time_info(self): + po.oheadr(self.outfile, "Energy Confinement") + + if physics_variables.i_plasma_ignited == 1: + po.ocmmnt( + self.outfile, + "Device is assumed to be ignited for the calculation of confinement time", + ) + po.oblnkl(self.outfile) + + tauelaw = ConfinementTimeModel(physics_variables.i_confinement_time).full_name + + po.ocmmnt( + self.outfile, + f"Confinement scaling law: {tauelaw}", + ) + + po.ovarst( + self.outfile, + "Confinement scaling law", + "(tauelaw)", + f'"{tauelaw.strip().split(" ")[0]}"', + ) + + po.ovarrf( + self.outfile, "Confinement H factor", "(hfact)", physics_variables.hfact + ) + po.ovarrf( + self.outfile, + "Global thermal energy confinement time, from scaling (s)", + "(t_energy_confinement)", + physics_variables.t_energy_confinement, + "OP ", + ) + po.ovarrf( + self.outfile, + "Directly calculated total energy confinement time (s)", + "(t_energy_confinement_beta)", + physics_variables.t_energy_confinement_beta, + "OP ", + ) + po.ocmmnt( + self.outfile, + "(Total thermal energy derived from total plasma beta / loss power)", + ) + po.ovarrf( + self.outfile, + "Ion energy confinement time, from scaling (s)", + "(t_ion_energy_confinement)", + physics_variables.t_ion_energy_confinement, + "OP ", + ) + po.ovarrf( + self.outfile, + "Electron energy confinement time, from scaling (s)", + "(t_electron_energy_confinement)", + physics_variables.t_electron_energy_confinement, + "OP ", + ) + po.ovarre( + self.outfile, + "Fusion double product (s/m3)", + "(ntau)", + physics_variables.ntau, + "OP ", + ) + po.ovarre( + self.outfile, + "Lawson Triple product (keV s/m3)", + "(nTtau)", + physics_variables.nTtau, + "OP ", + ) + po.ovarre( + self.outfile, + "Transport loss power assumed in scaling law (MW)", + "(p_plasma_loss_mw)", + physics_variables.p_plasma_loss_mw, + "OP ", + ) + po.ovarin( + self.outfile, + "Switch for radiation loss term usage in power balance", + "(i_rad_loss)", + physics_variables.i_rad_loss, + ) + if physics_variables.i_rad_loss == 0: + po.ovarre( + self.outfile, + "Radiation power subtracted from plasma power balance (MW)", + "", + physics_variables.p_plasma_rad_mw, + "OP ", + ) + po.ocmmnt(self.outfile, " (Radiation correction is total radiation power)") + elif physics_variables.i_rad_loss == 1: + po.ovarre( + self.outfile, + "Radiation power subtracted from plasma power balance (MW)", + "", + physics_variables.p_plasma_inner_rad_mw, + "OP ", + ) + po.ocmmnt(self.outfile, " (Radiation correction is core radiation power)") + else: + po.ovarre( + self.outfile, + "Radiation power subtracted from plasma power balance (MW)", + "", + 0.0e0, + ) + po.ocmmnt(self.outfile, " (No radiation correction applied)") + po.ovarrf( + self.outfile, + "H* non-radiation corrected", + "(hstar)", + physics_variables.hstar, + "OP", + ) + po.ocmmnt(self.outfile, " (H* assumes IPB98(y,2), ELMy H-mode scaling)") + po.ovarrf( + self.outfile, + "Alpha particle confinement time (s)", + "(t_alpha_confinement)", + physics_variables.t_alpha_confinement, + "OP ", + ) + # Note alpha confinement time is no longer equal to fuel particle confinement time. + po.ovarrf( + self.outfile, + "Alpha particle/energy confinement time ratio", + "(f_alpha_energy_confinement)", + physics_variables.f_alpha_energy_confinement, + "OP ", + ) + po.ovarrf( + self.outfile, + "Lower limit on f_alpha_energy_confinement", + "(f_alpha_energy_confinement_min)", + constraint_variables.f_alpha_energy_confinement_min, + ) + + # Plot table of al the H-factor scalings and coparison values + self.output_confinement_comparison(istell=stellarator_variables.istell) + def output_confinement_comparison(self, istell: int): """Routine to calculate ignition margin for different confinement scalings and equivalent confinement times for H=1. diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 6efa9c116..4784ae9d7 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -26,7 +26,6 @@ ) from process.models.physics.bootstrap_current import PlasmaBootstrapCurrent from process.models.physics.confinement_time import ( - ConfinementTimeModel, PlasmaConfinementTime, ) from process.models.physics.density_limit import PlasmaDensityLimit @@ -4040,151 +4039,7 @@ def outplas(self): "OP ", ) - po.osubhd(self.outfile, "Confinement :") - - if physics_variables.i_plasma_ignited == 1: - po.ocmmnt( - self.outfile, - "Device is assumed to be ignited for the calculation of confinement time", - ) - po.oblnkl(self.outfile) - - tauelaw = ConfinementTimeModel(physics_variables.i_confinement_time).full_name - - po.ocmmnt( - self.outfile, - f"Confinement scaling law: {tauelaw}", - ) - - po.ovarst( - self.outfile, - "Confinement scaling law", - "(tauelaw)", - f'"{tauelaw.strip().split(" ")[0]}"', - ) - - po.ovarrf( - self.outfile, "Confinement H factor", "(hfact)", physics_variables.hfact - ) - po.ovarrf( - self.outfile, - "Global thermal energy confinement time, from scaling (s)", - "(t_energy_confinement)", - physics_variables.t_energy_confinement, - "OP ", - ) - po.ovarrf( - self.outfile, - "Directly calculated total energy confinement time (s)", - "(t_energy_confinement_beta)", - physics_variables.t_energy_confinement_beta, - "OP ", - ) - po.ocmmnt( - self.outfile, - "(Total thermal energy derived from total plasma beta / loss power)", - ) - po.ovarrf( - self.outfile, - "Ion energy confinement time, from scaling (s)", - "(t_ion_energy_confinement)", - physics_variables.t_ion_energy_confinement, - "OP ", - ) - po.ovarrf( - self.outfile, - "Electron energy confinement time, from scaling (s)", - "(t_electron_energy_confinement)", - physics_variables.t_electron_energy_confinement, - "OP ", - ) - po.ovarre( - self.outfile, - "Fusion double product (s/m3)", - "(ntau)", - physics_variables.ntau, - "OP ", - ) - po.ovarre( - self.outfile, - "Lawson Triple product (keV s/m3)", - "(nTtau)", - physics_variables.nTtau, - "OP ", - ) - po.ovarre( - self.outfile, - "Transport loss power assumed in scaling law (MW)", - "(p_plasma_loss_mw)", - physics_variables.p_plasma_loss_mw, - "OP ", - ) - po.ovarin( - self.outfile, - "Switch for radiation loss term usage in power balance", - "(i_rad_loss)", - physics_variables.i_rad_loss, - ) - if physics_variables.i_rad_loss == 0: - po.ovarre( - self.outfile, - "Radiation power subtracted from plasma power balance (MW)", - "", - physics_variables.p_plasma_rad_mw, - "OP ", - ) - po.ocmmnt(self.outfile, " (Radiation correction is total radiation power)") - elif physics_variables.i_rad_loss == 1: - po.ovarre( - self.outfile, - "Radiation power subtracted from plasma power balance (MW)", - "", - physics_variables.p_plasma_inner_rad_mw, - "OP ", - ) - po.ocmmnt(self.outfile, " (Radiation correction is core radiation power)") - else: - po.ovarre( - self.outfile, - "Radiation power subtracted from plasma power balance (MW)", - "", - 0.0e0, - ) - po.ocmmnt(self.outfile, " (No radiation correction applied)") - po.ovarrf( - self.outfile, - "H* non-radiation corrected", - "(hstar)", - physics_variables.hstar, - "OP", - ) - po.ocmmnt(self.outfile, " (H* assumes IPB98(y,2), ELMy H-mode scaling)") - po.ovarrf( - self.outfile, - "Alpha particle confinement time (s)", - "(t_alpha_confinement)", - physics_variables.t_alpha_confinement, - "OP ", - ) - # Note alpha confinement time is no longer equal to fuel particle confinement time. - po.ovarrf( - self.outfile, - "Alpha particle/energy confinement time ratio", - "(f_alpha_energy_confinement)", - physics_variables.f_alpha_energy_confinement, - "OP ", - ) - po.ovarrf( - self.outfile, - "Lower limit on f_alpha_energy_confinement", - "(f_alpha_energy_confinement_min)", - constraint_variables.f_alpha_energy_confinement_min, - ) - - # Plot table of al the H-factor scalings and coparison values - self.confinement.output_confinement_comparison( - istell=stellarator_variables.istell - ) + self.confinement.output_confinement_time_info() if stellarator_variables.istell == 0: # Issues 363 Output dimensionless plasma parameters MDK From b4c08c97310791c8a53f72e322c2de03132c8753 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 15:44:13 +0000 Subject: [PATCH 11/12] Enhance ConfinementRadiationLossModel with descriptions and update handling in PlasmaConfinementTime class --- process/models/physics/confinement_time.py | 31 +++++++++++++--------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 637cc55d3..06a6e941f 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -82,9 +82,15 @@ def __new__(cls, value, full_name): class ConfinementRadiationLossModel(IntEnum): """Confinement radiation loss model types""" - FULL_RADIATION = 0 - CORE_ONLY = 1 - NO_RADIATION = 2 + FULL_RADIATION = (0, "All radiation included in loss power term") + CORE_ONLY = (1, "Only core radiation included in loss power term") + NO_RADIATION = (2, "No radiation included in loss power term") + + def __new__(cls, value, description): + obj = int.__new__(cls, value) + obj._value_ = value + obj.description = description + return obj class PlasmaConfinementTime: @@ -1269,32 +1275,33 @@ def output_confinement_time_info(self): "(i_rad_loss)", physics_variables.i_rad_loss, ) - if physics_variables.i_rad_loss == 0: + model = ConfinementRadiationLossModel(physics_variables.i_rad_loss) + + if model == ConfinementRadiationLossModel.FULL_RADIATION: po.ovarre( self.outfile, - "Radiation power subtracted from plasma power balance (MW)", + "Radiation power subtracted from plasma heating power balance (MW)", "", physics_variables.p_plasma_rad_mw, "OP ", ) - po.ocmmnt(self.outfile, " (Radiation correction is total radiation power)") - elif physics_variables.i_rad_loss == 1: + elif model == ConfinementRadiationLossModel.CORE_ONLY: po.ovarre( self.outfile, - "Radiation power subtracted from plasma power balance (MW)", + "Radiation power subtracted from plasma heating power balance (MW)", "", physics_variables.p_plasma_inner_rad_mw, "OP ", ) - po.ocmmnt(self.outfile, " (Radiation correction is core radiation power)") - else: + else: # NO_RADIATION po.ovarre( self.outfile, - "Radiation power subtracted from plasma power balance (MW)", + "Radiation power subtracted from plasma heating power balance (MW)", "", 0.0e0, ) - po.ocmmnt(self.outfile, " (No radiation correction applied)") + + po.ocmmnt(self.outfile, f" (Radiation correction: {model.description})") po.ovarrf( self.outfile, "H* non-radiation corrected", From 07e7a7b04ffd88b7e954cea581960e07ad234b19 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 5 Mar 2026 16:07:30 +0000 Subject: [PATCH 12/12] :memo: Update plasma confinement documentation with model references and formatting improvements --- .../physics-models/plasma_confinement.md | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/documentation/source/physics-models/plasma_confinement.md b/documentation/source/physics-models/plasma_confinement.md index 7da7e17cf..9e190f6b6 100644 --- a/documentation/source/physics-models/plasma_confinement.md +++ b/documentation/source/physics-models/plasma_confinement.md @@ -1,4 +1,4 @@ -# Plasma confinement time +# Plasma confinement time | `PlasmaConfinementTime` ## Overview @@ -22,7 +22,7 @@ P_{\text{L}} = \frac{W}{\tau_{\text{E}}} $$ where $W$ is the total thermal energy of the plasma. We can look at it mainly as the difference in heating and loss powers in the plasma, as such we interpret it as power transported out from the -“core” by charged particles. This leads to the classic definition of loss power for the scaling: +"core" by charged particles. This leads to the classic definition of loss power for the scaling: $$ P_{\text{L}} = \underbrace{f_{\alpha}P_{\alpha} + P_{\text{c}} + P_{\text{OH}} + P_{\text{HCD}}}_{\text{Plasma heating}} @@ -49,7 +49,7 @@ The loss power $P_{\text{L}}$ [$\mathtt{p\_plasma\_loss\_mw}$] is calculated fro ------------- -### Effect of radiation on energy confinement +### Effect of radiation on energy confinement | `ConfinementRadiationLossModel` Published confinement scalings are all based on low radiation pulses. A power plant will certainly be a high radiation machine, both in the core, due to @@ -113,7 +113,7 @@ $$ ------------ -#### 1: Nec-Alcator scaling (Ohmic) +#### 1: Nec-Alcator scaling (Ohmic) | `neo_alcator_confinement_time()` Is selected with `i_confinement_time = 1`[^1] @@ -123,7 +123,7 @@ $$ ------------ -#### 2: Mirnov scaling (H-mode) +#### 2: Mirnov scaling (H-mode) | `mirnov_confinement_time()` Is selected with `i_confinement_time = 2`[^1] @@ -133,7 +133,7 @@ $$ ------------ -#### 3: Merezhkin-Mukhovatov scaling (Ohmic / L-mode) +#### 3: Merezhkin-Mukhovatov scaling (Ohmic / L-mode) | `merezhkin_muhkovatov_confinement_time()` Is selected with `i_confinement_time = 3`[^1] @@ -144,7 +144,7 @@ $$ --------------- -#### 4: Shimomura scaling (H-mode) +#### 4: Shimomura scaling (H-mode) | `shimomura_confinement_time()` Is selected with `i_confinement_time = 4`[^1] @@ -154,7 +154,7 @@ $$ ---------------- -#### 5: Kaye-Goldston scaling (L-mode) +#### 5: Kaye-Goldston scaling (L-mode) | `kaye_goldston_confinement_time()` Is selected with `i_confinement_time = 5`[^1] @@ -164,7 +164,7 @@ $$ ---------------- -#### 6: ITER 89-P scaling (L-mode) +#### 6: ITER 89-P scaling (L-mode) | `iter_89p_confinement_time()` Is selected with `i_confinement_time = 6`[^1] [^2] @@ -174,7 +174,7 @@ $$ ---------------- -#### 7: ITER 89-0 scaling (L-mode) +#### 7: ITER 89-0 scaling (L-mode) | `iter_89_0_confinement_time()` Is selected with `i_confinement_time = 7` [^2] @@ -187,7 +187,7 @@ $$ ---------------- -#### 8: Rebut-Lallia scaling (L-mode) +#### 8: Rebut-Lallia scaling (L-mode) | `rebut_lallia_confinement_time()` Is selected with `i_confinement_time = 8` [^2] @@ -202,7 +202,7 @@ where $\ell = \left(a^2R\kappa\right)^{\frac{1}{3}}$ ---------------- -#### 9: Goldston scaling (L-mode) +#### 9: Goldston scaling (L-mode) | `goldston_confinement_time()` Is selected with `i_confinement_time = 9` [^1] @@ -212,7 +212,7 @@ $$ ---------------- -#### 10: T-10 scaling (L-mode) +#### 10: T-10 scaling (L-mode) | `t10_confinement_time()` Is selected with `i_confinement_time = 10` [^1] @@ -225,7 +225,7 @@ where $\overline{n}_{20*} = 1.3\left(\frac{B_{\text{T}}}{Rq_{\text{cyl}}}\right) ---------------- -#### 11: JAERI / Odajima-Shimomura scaling (L-mode) +#### 11: JAERI / Odajima-Shimomura scaling (L-mode) | `jaeri_confinement_time()` Is selected with `i_confinement_time = 11` [^1] @@ -239,7 +239,7 @@ where $G\left(q_{\text{cyl}},Z_{\text{eff}}\right) = Z_{\text{eff}}^{0.4}\left[\ ---------------- -#### 12: Kaye "big" scaling (L-mode) +#### 12: Kaye "big" scaling (L-mode) | `kaye_big_confinement_time()` Is selected with `i_confinement_time = 12` [^1] @@ -249,7 +249,7 @@ $$ ------------------------- -#### 13: ITER H90-P scaling (H-mode) +#### 13: ITER H90-P scaling (H-mode) | `iter_h90_p_confinement_time()` Is selected with `i_confinement_time = 13` [^2] @@ -267,7 +267,7 @@ Will return the value of [ITER 89-P](#6-iter-89-p-l-mode-scaling) or [ITER 89-O] ------------------------- -#### 15: Riedel scaling (L-mode) +#### 15: Riedel scaling (L-mode) | `riedel_l_confinement_time()` Is selected with `i_confinement_time = 15` [^2] @@ -277,7 +277,7 @@ $$ ------------------------- -#### 16: Christiansen scaling (L-mode) +#### 16: Christiansen scaling (L-mode) | `christiansen_confinement_time()` Is selected with `i_confinement_time = 16` [^2] @@ -287,7 +287,7 @@ $$ ------------------------- -#### 17: Lackner-Gottardi scaling (L-mode) +#### 17: Lackner-Gottardi scaling (L-mode) | `lackner_gottardi_confinement_time()` Is selected with `i_confinement_time = 17` [^2] @@ -299,7 +299,7 @@ where $\hat{q} = \frac{(1+\kappa_{95}a^2B_{\text{T}})}{0.4 I_{\text{p}} R}$ ------------------------- -#### 18: Neo-Kaye scaling (L-mode) +#### 18: Neo-Kaye scaling (L-mode) | `neo_kaye_confinement_time()` Is selected with `i_confinement_time = 18` [^2] @@ -309,7 +309,7 @@ $$ ------------------------- -#### 19: Riedel scaling (H-mode) +#### 19: Riedel scaling (H-mode) | `riedel_h_confinement_time()` Is selected with `i_confinement_time = 19` [^2] @@ -319,7 +319,7 @@ $$ ------------------------- -#### 20: Amended ITER H90-P scaling (H-mode) +#### 20: Amended ITER H90-P scaling (H-mode) | `iter_h90_p_amended_confinement_time()` Is selected with `i_confinement_time = 20` [^3] @@ -329,7 +329,7 @@ $$ ------------------------- -#### 21: Sudo et al. scaling (Stellarator) +#### 21: Sudo et al. scaling (Stellarator) | `sudo_et_al_confinement_time()` Is selected with `i_confinement_time = 21` [^4] @@ -339,7 +339,7 @@ $$ ------------------------- -#### 22: Gyro reduced Bohm scaling (Stellarator) +#### 22: Gyro reduced Bohm scaling (Stellarator) | `gyro_reduced_bohm_confinement_time()` Is selected with `i_confinement_time = 22` [^5] @@ -349,7 +349,7 @@ $$ ------------------------- -#### 23: Lackner-Gottardi scaling (Stellarator) +#### 23: Lackner-Gottardi scaling (Stellarator) | `lackner_gottardi_stellarator_confinement_time()` Is selected with `i_confinement_time = 23` [^6] @@ -359,7 +359,7 @@ $$ ------------------------- -#### 24: ITER H93 ELM-free scaling (H-mode) +#### 24: ITER H93 ELM-free scaling (H-mode) | `iter_93h_confinement_time()` Is selected with `i_confinement_time = 24` [^7] @@ -378,7 +378,7 @@ Is selected with `i_confinement_time = 25` ------------------------- -#### 26: ITER H-97P ELM-free scaling (H-mode) +#### 26: ITER H-97P ELM-free scaling (H-mode) | `iter_h97p_confinement_time()` Is selected with `i_confinement_time = 26` [^8] @@ -388,7 +388,7 @@ $$ ------------------------- -#### 27: ITER H-97P ELMy scaling (H-mode) +#### 27: ITER H-97P ELMy scaling (H-mode) | `iter_h97p_elmy_confinement_time()` Is selected with `i_confinement_time = 27` [^8] [^9] @@ -398,7 +398,7 @@ $$ ------------------------- -#### 28: ITER-96P (ITER-97L) scaling (L-mode) +#### 28: ITER-96P (ITER-97L) scaling (L-mode) | `iter_96p_confinement_time()` Is selected with `i_confinement_time = 28` [^10] @@ -408,7 +408,7 @@ $$ ------------------------- -#### 29: Valovic modified ELMy scaling (H-mode) +#### 29: Valovic modified ELMy scaling (H-mode) | `valovic_elmy_confinement_time()` Is selected with `i_confinement_time = 29` @@ -421,7 +421,7 @@ $$ ------------------------- -#### 30: Kaye 98 modified scaling (L-mode) +#### 30: Kaye 98 modified scaling (L-mode) | `kaye_confinement_time()` Is selected with `i_confinement_time = 30` @@ -434,7 +434,7 @@ $$ ------------------------- -#### 31: ITERH-PB98P(y) scaling (H-mode) +#### 31: ITERH-PB98P(y) scaling (H-mode) | `iter_pb98py_confinement_time()` Is selected with `i_confinement_time = 31` @@ -447,7 +447,7 @@ $$ ------------------------- -#### 32: IPB98(y) ELMy scaling (H-mode) +#### 32: IPB98(y) ELMy scaling (H-mode) | `iter_ipb98y_confinement_time()` Is selected with `i_confinement_time = 32` [^11] [^12] @@ -457,7 +457,7 @@ $$ ------------------------- -#### 33: IPB98(y,1) ELMy scaling (H-mode) +#### 33: IPB98(y,1) ELMy scaling (H-mode) | `iter_ipb98y1_confinement_time()` Is selected with `i_confinement_time = 33` [^11] [^12] @@ -467,7 +467,7 @@ $$ ------------------------- -#### 34: IPB98(y,2) ELMy scaling (H-mode) +#### 34: IPB98(y,2) ELMy scaling (H-mode) | `iter_ipb98y2_confinement_time()` Is selected with `i_confinement_time = 34` [^11] [^12] @@ -477,7 +477,7 @@ $$ ------------------------- -#### 35: IPB98(y,3) ELMy scaling (H-mode) +#### 35: IPB98(y,3) ELMy scaling (H-mode) | `iter_ipb98y3_confinement_time()` Is selected with `i_confinement_time = 35` [^11] [^12] @@ -487,7 +487,7 @@ $$ ------------------------- -#### 36: IPB98(y,4) ELMy scaling (H-mode) +#### 36: IPB98(y,4) ELMy scaling (H-mode) | `iter_ipb98y4_confinement_time()` Is selected with `i_confinement_time = 36` [^11] [^12] @@ -498,7 +498,7 @@ $$ ------------------------- -#### 37: ISS95 scaling (Stellarator) +#### 37: ISS95 scaling (Stellarator) | `iss95_stellarator_confinement_time()` Is selected with `i_confinement_time = 37` [^13] @@ -509,7 +509,7 @@ $$ ------------------------- -#### 38: ISS04 scaling (Stellarator) +#### 38: ISS04 scaling (Stellarator) | `iss04_stellarator_confinement_time()` Is selected with `i_confinement_time = 38` [^14] @@ -519,7 +519,7 @@ $$ ------------------------- -#### 39: DS03 beta-independent scaling (H-mode) +#### 39: DS03 beta-independent scaling (H-mode) | `ds03_confinement_time()` Is selected with `i_confinement_time = 39` [^15] @@ -529,7 +529,7 @@ $$ ------------------------- -#### 40: Murari "Non-power law" scaling (H-mode) +#### 40: Murari "Non-power law" scaling (H-mode) | `murari_confinement_time()` Is selected with `i_confinement_time = 40` [^16] @@ -540,7 +540,7 @@ $$ ------------------------- -#### 41: Petty08 scaling (H-mode) +#### 41: Petty08 scaling (H-mode) | `petty08_confinement_time()` Is selected with `i_confinement_time = 41` [^17] @@ -550,7 +550,7 @@ $$ ------------------------- -#### 42: Lang high density scaling (H-mode) +#### 42: Lang high density scaling (H-mode) | `lang_high_density_confinement_time()` Is selected with `i_confinement_time = 42` [^18] @@ -561,7 +561,7 @@ $$ ------------------------- -#### 43: Hubbard nominal scaling (I-mode) +#### 43: Hubbard nominal scaling (I-mode) | `hubbard_nominal_confinement_time()` Is selected with `i_confinement_time = 43` [^19] @@ -571,7 +571,7 @@ $$ ------------------------- -#### 44: Hubbard lower scaling (I-mode) +#### 44: Hubbard lower scaling (I-mode) | `hubbard_lower_confinement_time()` Is selected with `i_confinement_time = 44` [^19] @@ -581,7 +581,7 @@ $$ ------------------------- -#### 45: Hubbard upper scaling (I-mode) +#### 45: Hubbard upper scaling (I-mode) | `hubbard_upper_confinement_time()` Is selected with `i_confinement_time = 45` [^19] @@ -592,7 +592,7 @@ $$ ------------------------- -#### 46: Menard NSTX scaling (H-mode) +#### 46: Menard NSTX scaling (H-mode) | `menard_nstx_confinement_time()` Is selected with `i_confinement_time = 46` [^20] @@ -602,11 +602,11 @@ $$ ------------------------- -#### 47: Menard NSTX-Petty08 hybrid scaling +#### 47: Menard NSTX-Petty08 hybrid scaling | `menard_nstx_petty08_hybrid_confinement_time()` Is selected with `i_confinement_time = 47` [^20] -- If $\epsilon \le 0.4 \ (A \ge 2.5)$ apply the [Petty08 scaling](#41-petty-h-mode-scaling) +- If $\epsilon \le 0.4 \ (A \ge 2.5)$ apply the [Petty08 scaling](#41-petty08-h-mode-scaling) - If $\epsilon \ge 0.6 \ (A \le 1.7)$ apply the [Menard NSTX scaling](#46-menard-nstx-h-mode-scaling) Otherwise: @@ -617,7 +617,7 @@ $$ ------------------------- -#### 48: Buxton NSTX Gyro-Bohm scaling (H-mode) +#### 48: Buxton NSTX Gyro-Bohm scaling (H-mode) | `nstx_gyro_bohm_confinement_time()` Is selected with `i_confinement_time = 48` [^21] @@ -627,7 +627,7 @@ $$ ------------------------- -#### 49: ITPA20 scaling (H-mode) +#### 49: ITPA20 scaling (H-mode) | `itpa20_confinement_time()` Is selected with `i_confinement_time = 49` [^22] @@ -637,7 +637,7 @@ $$ ------------------------- -#### 50: ITPA20-IL scaling (H-mode) +#### 50: ITPA20-IL scaling (H-mode) | `itpa20_il_confinement_time()` Is selected with `i_confinement_time = 50` [^23]