From d55eff32aae8d60d6fdd754e4364bf81c61fd4e1 Mon Sep 17 00:00:00 2001 From: chris-ashe Date: Mon, 29 Jun 2026 23:47:07 +0100 Subject: [PATCH 01/14] Create confinement time dataclass and update output parsing for relevant tests --- process/models/physics/confinement_time.py | 173 ++++++++++++++++----- tests/unit/models/physics/test_physics.py | 21 +-- 2 files changed, 145 insertions(+), 49 deletions(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 78d6eca7ad..ddcee04146 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -1,6 +1,7 @@ """Confinement time model calculations and definitions.""" import logging +from dataclasses import dataclass import numpy as np from scipy.optimize import root_scalar @@ -20,6 +21,128 @@ logger = logging.getLogger(__name__) +@dataclass(slots=True, frozen=True) +class ConfinementTimeData: + """Data structure for confinement time model calculations.""" + + pden_electron_transport_loss_mw: float + """Electron transport loss power density in MW.""" + pden_ion_transport_loss_mw: float + """Ion transport loss power density in MW.""" + t_electron_energy_confinement: float + """Electron energy confinement time in seconds.""" + t_ion_energy_confinement: float + """Ion energy confinement time in seconds.""" + t_plasma_energy_confinement: float + """Plasma energy confinement time in seconds.""" + p_plasma_loss_mw: float + """Total plasma loss power in MW.""" + + +class ConfinementTimeModel(IntEnum): + """Confinement time (τ_E) model types""" + + 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: int, full_name: str): + """Create a new instance of ConfinementTimeModel. + + Parameters + ---------- + value : int + The enum value + full_name : str + The full name of the confinement time model + + Returns + ------- + ConfinementTimeModel + A new enum instance with the given value and full name + """ + obj = int.__new__(cls, value) + obj._value_ = value + obj.full_name = full_name + return obj + + +class ConfinementRadiationLossModel(IntEnum): + """Confinement radiation loss model types""" + + 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: int, description: str): + """Create a new instance of ConfinementRadiationLossModel. + + Parameters + ---------- + value : int + The enum value + description : str + The description of the radiation loss model + + Returns + ------- + ConfinementRadiationLossModel + A new enum instance with the given value and description + """ + obj = int.__new__(cls, value) + obj._value_ = value + obj.description = description + return obj + + class PlasmaConfinementTime(Model): """Class to calculate plasma confinement time using various empirical scaling laws""" @@ -60,7 +183,7 @@ def calculate_confinement_time( zeff: float, eden_plasma_electrons_thermal_vol_avg: float, eden_plasma_ions_thermal_vol_avg: float, - ) -> tuple[float, float, float, float, float, float, float]: + ) -> ConfinementTimeData: """Calculate the confinement times and the transport power loss terms. Parameters @@ -118,14 +241,7 @@ def calculate_confinement_time( Returns ------- - type - Tuple containing: - - pden_electron_transport_loss_mw (float): Electron transport power (MW/m³) - - pden_ion_transport_loss_mw (float): Ion transport power (MW/m³) - - 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 + ConfinementTimeData Raises ------ @@ -982,13 +1098,13 @@ def calculate_confinement_time( self.data.physics.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, + return ConfinementTimeData( + pden_electron_transport_loss_mw=pden_electron_transport_loss_mw, + pden_ion_transport_loss_mw=pden_ion_transport_loss_mw, + t_electron_energy_confinement=t_electron_energy_confinement, + t_ion_energy_confinement=t_ion_energy_confinement, + t_plasma_energy_confinement=t_energy_confinement, + p_plasma_loss_mw=p_plasma_loss_mw, ) @staticmethod @@ -1054,14 +1170,7 @@ def fhz(hfact: float) -> float: balance. """ - ( - ptrez, - ptriz, - _, - _, - _, - _, - ) = self.calculate_confinement_time( + confinement_time_data: ConfinementTimeData = self.calculate_confinement_time( m_fuel_amu=self.data.physics.m_fuel_amu, p_alpha_total_mw=self.data.physics.p_alpha_total_mw, aspect=self.data.physics.aspect, @@ -1091,8 +1200,8 @@ def fhz(hfact: float) -> float: # At power balance, fhz is zero. fhz_value = ( - ptrez - + ptriz + confinement_time_data.pden_electron_transport_loss_mw + + confinement_time_data.pden_ion_transport_loss_mw - self.data.physics.f_p_alpha_plasma_deposited * self.data.physics.pden_alpha_total_mw - self.data.physics.pden_non_alpha_charged_mw @@ -1347,14 +1456,8 @@ def output_confinement_comparison(self, istell: int): ): if i_confinement_time == 25: continue - ( - _, - _, - taueez, - _, - _, - _, - ) = self.calculate_confinement_time( + + confinement_time_data: ConfinementTimeData = self.calculate_confinement_time( m_fuel_amu=self.data.physics.m_fuel_amu, p_alpha_total_mw=self.data.physics.p_alpha_total_mw, aspect=self.data.physics.aspect, @@ -1397,7 +1500,7 @@ def output_confinement_comparison(self, istell: int): po.ocmmnt( self.outfile, f"{'':>2}{scaling_name:<38}" - f"{taueez:<28.3f}{self.data.physics.hfac[i_confinement_time - 1]:.3f}", + f"{confinement_time_data.t_electron_energy_confinement:<28.3f}{self.data.physics.hfac[i_confinement_time - 1]:.3f}", ) po.oblnkl(self.outfile) diff --git a/tests/unit/models/physics/test_physics.py b/tests/unit/models/physics/test_physics.py index 9d9351e200..40635ef441 100644 --- a/tests/unit/models/physics/test_physics.py +++ b/tests/unit/models/physics/test_physics.py @@ -3119,14 +3119,7 @@ def test_calculate_confinement_time(confinementtimeparam, monkeypatch, physics): physics.data.physics, field, getattr(confinementtimeparam, field) ) - ( - 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, - ) = physics.confinement.calculate_confinement_time( + confinement_time_data = 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, @@ -3158,27 +3151,27 @@ def test_calculate_confinement_time(confinementtimeparam, monkeypatch, physics): confinementtimeparam.expected_kappa_ipb ) - assert p_plasma_loss_mw == pytest.approx( + assert confinement_time_data.p_plasma_loss_mw == pytest.approx( confinementtimeparam.expected_p_plasma_loss_mw ) - assert pden_electron_transport_loss_mw == pytest.approx( + assert confinement_time_data.pden_electron_transport_loss_mw == pytest.approx( confinementtimeparam.expected_pden_electron_transport_loss_mw ) - assert pden_ion_transport_loss_mw == pytest.approx( + assert confinement_time_data.pden_ion_transport_loss_mw == pytest.approx( confinementtimeparam.expected_pden_ion_transport_loss_mw ) - assert t_electron_energy_confinement == pytest.approx( + assert confinement_time_data.t_electron_energy_confinement == pytest.approx( confinementtimeparam.expected_tauee ) - assert t_energy_confinement == pytest.approx( + assert confinement_time_data.t_plasma_energy_confinement == pytest.approx( confinementtimeparam.expected_t_energy_confinement ) - assert t_ion_energy_confinement == pytest.approx( + assert confinement_time_data.t_ion_energy_confinement == pytest.approx( confinementtimeparam.expected_t_ion_energy_confinement ) From 06e861e8c544790d084681851a20f43ecb1c60d9 Mon Sep 17 00:00:00 2001 From: chris-ashe Date: Mon, 29 Jun 2026 23:53:21 +0100 Subject: [PATCH 02/14] :bug: Make confinement time comparison output the global plasma confinement time instead of just the electron --- process/models/physics/confinement_time.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index ddcee04146..98bfcb46f5 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -1500,7 +1500,7 @@ def output_confinement_comparison(self, istell: int): po.ocmmnt( self.outfile, f"{'':>2}{scaling_name:<38}" - f"{confinement_time_data.t_electron_energy_confinement:<28.3f}{self.data.physics.hfac[i_confinement_time - 1]:.3f}", + f"{confinement_time_data.t_plasma_energy_confinement:<28.3f}{self.data.physics.hfac[i_confinement_time - 1]:.3f}", ) po.oblnkl(self.outfile) From 0dc08b1c54acba138c8e017a41a8ffab831f322c Mon Sep 17 00:00:00 2001 From: chris-ashe Date: Mon, 29 Jun 2026 23:58:18 +0100 Subject: [PATCH 03/14] :bug: Apply new dataclass return in Physics run and fix positional return placement error between ion and energy confinement time --- process/models/physics/physics.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 17e9a0bec7..872880402b 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -28,6 +28,7 @@ from process.data_structure.physics_variables import PhysicsData from process.models.physics.bootstrap_current import PlasmaBootstrapCurrent from process.models.physics.confinement_time import ( + ConfinementTimeData, PlasmaConfinementTime, ) from process.models.physics.density_limit import PlasmaDensityLimit @@ -843,14 +844,7 @@ def run(self): # Calculate transport losses and energy confinement time using the # chosen scaling law - ( - self.data.physics.pden_electron_transport_loss_mw, - self.data.physics.pden_ion_transport_loss_mw, - self.data.physics.t_electron_energy_confinement, - self.data.physics.t_energy_confinement, - self.data.physics.t_ion_energy_confinement, - self.data.physics.p_plasma_loss_mw, - ) = self.confinement.calculate_confinement_time( + confinement_time_data: ConfinementTimeData = self.confinement.calculate_confinement_time( m_fuel_amu=self.data.physics.m_fuel_amu, p_alpha_total_mw=self.data.physics.p_alpha_total_mw, aspect=self.data.physics.aspect, @@ -877,6 +871,22 @@ def run(self): eden_plasma_electrons_thermal_vol_avg=self.data.physics.eden_plasma_electrons_thermal_vol_avg, eden_plasma_ions_thermal_vol_avg=self.data.physics.eden_plasma_ions_thermal_vol_avg, ) + self.data.physics.pden_electron_transport_loss_mw = ( + confinement_time_data.pden_electron_transport_loss_mw + ) + self.data.physics.pden_ion_transport_loss_mw = ( + confinement_time_data.pden_ion_transport_loss_mw + ) + self.data.physics.t_electron_energy_confinement = ( + confinement_time_data.t_electron_energy_confinement + ) + self.data.physics.t_energy_confinement = ( + confinement_time_data.t_energy_confinement + ) + self.data.physics.t_ion_energy_confinement = ( + confinement_time_data.t_ion_energy_confinement + ) + self.data.physics.p_plasma_loss_mw = confinement_time_data.p_plasma_loss_mw # Total transport power from scaling law (MW) self.data.physics.p_electron_transport_loss_mw = ( From cac2b53a81cbc30697f223d57e7427896226fe69 Mon Sep 17 00:00:00 2001 From: chris-ashe Date: Tue, 30 Jun 2026 00:05:44 +0100 Subject: [PATCH 04/14] Apply confinement dataclass output to stellerator file --- process/models/physics/physics.py | 2 +- process/models/stellarator/stellarator.py | 53 ++++++++++++++++++++--- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 872880402b..7d7927af63 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -881,7 +881,7 @@ def run(self): confinement_time_data.t_electron_energy_confinement ) self.data.physics.t_energy_confinement = ( - confinement_time_data.t_energy_confinement + confinement_time_data.t_plasma_energy_confinement ) self.data.physics.t_ion_energy_confinement = ( confinement_time_data.t_ion_energy_confinement diff --git a/process/models/stellarator/stellarator.py b/process/models/stellarator/stellarator.py index 0a0b17b309..88ae2320ad 100644 --- a/process/models/stellarator/stellarator.py +++ b/process/models/stellarator/stellarator.py @@ -2252,13 +2252,35 @@ def st_phys(self, output): ) ( - self.data.physics.pden_electron_transport_loss_mw, - self.data.physics.pden_ion_transport_loss_mw, - self.data.physics.t_electron_energy_confinement, - self.data.physics.t_ion_energy_confinement, - self.data.physics.t_energy_confinement, - self.data.physics.p_plasma_loss_mw, - ) = self.physics.confinement.calculate_confinement_time( + self.data.physics.eden_plasma_electrons_thermal_vol_avg, + self.data.physics.e_plasma_electrons_thermal, + ) = self.physics.calaculate_stored_thermal_energy( + vol_plasma=self.data.physics.vol_plasma, + nd_plasma_vol_avg=self.data.physics.nd_plasma_electrons_vol_avg, + temp_plasma_density_weighted_vol_avg_kev=self.data.physics.temp_plasma_electron_density_weighted_kev, + ) + + ( + self.data.physics.eden_plasma_ions_thermal_vol_avg, + self.data.physics.e_plasma_ions_thermal, + ) = self.physics.calaculate_stored_thermal_energy( + vol_plasma=self.data.physics.vol_plasma, + nd_plasma_vol_avg=self.data.physics.nd_plasma_ions_total_vol_avg, + temp_plasma_density_weighted_vol_avg_kev=self.data.physics.temp_plasma_ion_density_weighted_kev, + ) + + self.data.physics.eden_plasma_thermal_vol_avg = ( + self.data.physics.eden_plasma_electrons_thermal_vol_avg + + self.data.physics.eden_plasma_ions_thermal_vol_avg + ) + + self.data.physics.e_plasma_thermal_total = ( + self.data.physics.e_plasma_electrons_thermal + + self.data.physics.e_plasma_ions_thermal + ) + + + confinement_time_data = self.physics.confinement.calculate_confinement_time( self.data.physics.m_fuel_amu, self.data.physics.p_alpha_total_mw, self.data.physics.aspect, @@ -2286,6 +2308,23 @@ def st_phys(self, output): eden_plasma_ions_thermal_vol_avg=self.data.physics.eden_plasma_ions_thermal_vol_avg, ) + self.data.physics.pden_electron_transport_loss_mw = ( + confinement_time_data.pden_electron_transport_loss_mw + ) + self.data.physics.pden_ion_transport_loss_mw = ( + confinement_time_data.pden_ion_transport_loss_mw + ) + self.data.physics.t_electron_energy_confinement = ( + confinement_time_data.t_electron_energy_confinement + ) + self.data.physics.t_energy_confinement = ( + confinement_time_data.t_plasma_energy_confinement + ) + self.data.physics.t_ion_energy_confinement = ( + confinement_time_data.t_ion_energy_confinement + ) + self.data.physics.p_plasma_loss_mw = confinement_time_data.p_plasma_loss_mw + self.data.physics.ntau, self.data.physics.nTtau = ( self.physics.confinement.calculate_double_and_triple_product( nd_plasma_electrons_vol_avg=self.data.physics.nd_plasma_electrons_vol_avg, From b7a2e0878bdab2a290f142bf9c0719ed5de8cf50 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Tue, 30 Jun 2026 10:53:57 +0100 Subject: [PATCH 05/14] Post rebase fixes --- process/models/physics/confinement_time.py | 104 --------------------- 1 file changed, 104 deletions(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 98bfcb46f5..ae41b43746 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -39,110 +39,6 @@ class ConfinementTimeData: """Total plasma loss power in MW.""" -class ConfinementTimeModel(IntEnum): - """Confinement time (τ_E) model types""" - - 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: int, full_name: str): - """Create a new instance of ConfinementTimeModel. - - Parameters - ---------- - value : int - The enum value - full_name : str - The full name of the confinement time model - - Returns - ------- - ConfinementTimeModel - A new enum instance with the given value and full name - """ - obj = int.__new__(cls, value) - obj._value_ = value - obj.full_name = full_name - return obj - - -class ConfinementRadiationLossModel(IntEnum): - """Confinement radiation loss model types""" - - 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: int, description: str): - """Create a new instance of ConfinementRadiationLossModel. - - Parameters - ---------- - value : int - The enum value - description : str - The description of the radiation loss model - - Returns - ------- - ConfinementRadiationLossModel - A new enum instance with the given value and description - """ - obj = int.__new__(cls, value) - obj._value_ = value - obj.description = description - return obj - - class PlasmaConfinementTime(Model): """Class to calculate plasma confinement time using various empirical scaling laws""" From c8d3726dbb9d12acbadf7aac7b5c02917f2648d0 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Fri, 3 Jul 2026 10:38:21 +0100 Subject: [PATCH 06/14] Post rebase fixes --- process/models/stellarator/stellarator.py | 1 - 1 file changed, 1 deletion(-) diff --git a/process/models/stellarator/stellarator.py b/process/models/stellarator/stellarator.py index 88ae2320ad..c8b7da4f53 100644 --- a/process/models/stellarator/stellarator.py +++ b/process/models/stellarator/stellarator.py @@ -2279,7 +2279,6 @@ def st_phys(self, output): + self.data.physics.e_plasma_ions_thermal ) - confinement_time_data = self.physics.confinement.calculate_confinement_time( self.data.physics.m_fuel_amu, self.data.physics.p_alpha_total_mw, From 881e671a4420f64c69464d12059c80e1b3268335 Mon Sep 17 00:00:00 2001 From: Christopher Ashe <91618944+chris-ashe@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:30:24 +0100 Subject: [PATCH 07/14] Update process/models/physics/confinement_time.py Co-authored-by: clmould <86794332+clmould@users.noreply.github.com> --- process/models/physics/confinement_time.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index ae41b43746..2f382fc73d 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -1066,7 +1066,7 @@ def fhz(hfact: float) -> float: balance. """ - confinement_time_data: ConfinementTimeData = self.calculate_confinement_time( + confinement_time_data = self.calculate_confinement_time( m_fuel_amu=self.data.physics.m_fuel_amu, p_alpha_total_mw=self.data.physics.p_alpha_total_mw, aspect=self.data.physics.aspect, From 804fe5e27776bcf7971025e7f989cfdb92fe0510 Mon Sep 17 00:00:00 2001 From: Christopher Ashe <91618944+chris-ashe@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:30:32 +0100 Subject: [PATCH 08/14] Update process/models/physics/confinement_time.py Co-authored-by: clmould <86794332+clmould@users.noreply.github.com> --- process/models/physics/confinement_time.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 2f382fc73d..271e2785f8 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -1353,7 +1353,7 @@ def output_confinement_comparison(self, istell: int): if i_confinement_time == 25: continue - confinement_time_data: ConfinementTimeData = self.calculate_confinement_time( + confinement_time_data = self.calculate_confinement_time( m_fuel_amu=self.data.physics.m_fuel_amu, p_alpha_total_mw=self.data.physics.p_alpha_total_mw, aspect=self.data.physics.aspect, From d37aef468e6442b3b5c99287aedf9d637e5c2ef0 Mon Sep 17 00:00:00 2001 From: Christopher Ashe <91618944+chris-ashe@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:30:43 +0100 Subject: [PATCH 09/14] Update process/models/physics/confinement_time.py Co-authored-by: clmould <86794332+clmould@users.noreply.github.com> --- process/models/physics/confinement_time.py | 1 + 1 file changed, 1 insertion(+) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index 271e2785f8..f8fc058bc4 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -138,6 +138,7 @@ def calculate_confinement_time( Returns ------- ConfinementTimeData + Dataclass containing confinement time model calculation parameters Raises ------ From 25521df60d42d7ce084bb8348c841cd10288ea2f Mon Sep 17 00:00:00 2001 From: Christopher Ashe <91618944+chris-ashe@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:30:56 +0100 Subject: [PATCH 10/14] Update process/models/physics/confinement_time.py Co-authored-by: clmould <86794332+clmould@users.noreply.github.com> --- process/models/physics/confinement_time.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process/models/physics/confinement_time.py b/process/models/physics/confinement_time.py index f8fc058bc4..6e697c71c7 100644 --- a/process/models/physics/confinement_time.py +++ b/process/models/physics/confinement_time.py @@ -23,7 +23,7 @@ @dataclass(slots=True, frozen=True) class ConfinementTimeData: - """Data structure for confinement time model calculations.""" + """Dataclass to hold confinement time model calculation parameters.""" pden_electron_transport_loss_mw: float """Electron transport loss power density in MW.""" From c3a3a87183d2d5873d24be2731f9777a016835c5 Mon Sep 17 00:00:00 2001 From: Christopher Ashe <91618944+chris-ashe@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:31:04 +0100 Subject: [PATCH 11/14] Update process/models/physics/physics.py Co-authored-by: clmould <86794332+clmould@users.noreply.github.com> --- process/models/physics/physics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 7d7927af63..1d7e3e07b7 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -844,7 +844,7 @@ def run(self): # Calculate transport losses and energy confinement time using the # chosen scaling law - confinement_time_data: ConfinementTimeData = self.confinement.calculate_confinement_time( + confinement_time_data = self.confinement.calculate_confinement_time( m_fuel_amu=self.data.physics.m_fuel_amu, p_alpha_total_mw=self.data.physics.p_alpha_total_mw, aspect=self.data.physics.aspect, From b2c2472eb7a9de068e790e456030606c4ef61317 Mon Sep 17 00:00:00 2001 From: Christopher Ashe <91618944+chris-ashe@users.noreply.github.com> Date: Fri, 3 Jul 2026 13:32:15 +0100 Subject: [PATCH 12/14] Update process/models/stellarator/stellarator.py Co-authored-by: clmould <86794332+clmould@users.noreply.github.com> --- process/models/stellarator/stellarator.py | 26 ----------------------- 1 file changed, 26 deletions(-) diff --git a/process/models/stellarator/stellarator.py b/process/models/stellarator/stellarator.py index c8b7da4f53..22207a1330 100644 --- a/process/models/stellarator/stellarator.py +++ b/process/models/stellarator/stellarator.py @@ -2252,32 +2252,6 @@ def st_phys(self, output): ) ( - self.data.physics.eden_plasma_electrons_thermal_vol_avg, - self.data.physics.e_plasma_electrons_thermal, - ) = self.physics.calaculate_stored_thermal_energy( - vol_plasma=self.data.physics.vol_plasma, - nd_plasma_vol_avg=self.data.physics.nd_plasma_electrons_vol_avg, - temp_plasma_density_weighted_vol_avg_kev=self.data.physics.temp_plasma_electron_density_weighted_kev, - ) - - ( - self.data.physics.eden_plasma_ions_thermal_vol_avg, - self.data.physics.e_plasma_ions_thermal, - ) = self.physics.calaculate_stored_thermal_energy( - vol_plasma=self.data.physics.vol_plasma, - nd_plasma_vol_avg=self.data.physics.nd_plasma_ions_total_vol_avg, - temp_plasma_density_weighted_vol_avg_kev=self.data.physics.temp_plasma_ion_density_weighted_kev, - ) - - self.data.physics.eden_plasma_thermal_vol_avg = ( - self.data.physics.eden_plasma_electrons_thermal_vol_avg - + self.data.physics.eden_plasma_ions_thermal_vol_avg - ) - - self.data.physics.e_plasma_thermal_total = ( - self.data.physics.e_plasma_electrons_thermal - + self.data.physics.e_plasma_ions_thermal - ) confinement_time_data = self.physics.confinement.calculate_confinement_time( self.data.physics.m_fuel_amu, From 39ce639578ec47861d835388ee9c8a31b9a0c968 Mon Sep 17 00:00:00 2001 From: Christopher Ashe <91618944+chris-ashe@users.noreply.github.com> Date: Thu, 9 Jul 2026 09:02:11 +0100 Subject: [PATCH 13/14] Update process/models/stellarator/stellarator.py Co-authored-by: clmould <86794332+clmould@users.noreply.github.com> --- process/models/stellarator/stellarator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/process/models/stellarator/stellarator.py b/process/models/stellarator/stellarator.py index 22207a1330..2f31a9fd76 100644 --- a/process/models/stellarator/stellarator.py +++ b/process/models/stellarator/stellarator.py @@ -2251,7 +2251,7 @@ def st_phys(self, output): + self.data.physics.e_plasma_ions_thermal ) - ( + confinement_time_data = self.physics.confinement.calculate_confinement_time( self.data.physics.m_fuel_amu, From 691306fce6ad0c35bcbd23a93a292ae691534891 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Thu, 9 Jul 2026 09:21:47 +0100 Subject: [PATCH 14/14] Remove unused ConfinementTimeData import and clean up whitespace in stellarator.py --- process/models/physics/physics.py | 1 - process/models/stellarator/stellarator.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 1d7e3e07b7..3987ad7a08 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -28,7 +28,6 @@ from process.data_structure.physics_variables import PhysicsData from process.models.physics.bootstrap_current import PlasmaBootstrapCurrent from process.models.physics.confinement_time import ( - ConfinementTimeData, PlasmaConfinementTime, ) from process.models.physics.density_limit import PlasmaDensityLimit diff --git a/process/models/stellarator/stellarator.py b/process/models/stellarator/stellarator.py index 2f31a9fd76..a2f6129e6e 100644 --- a/process/models/stellarator/stellarator.py +++ b/process/models/stellarator/stellarator.py @@ -2251,8 +2251,6 @@ def st_phys(self, output): + self.data.physics.e_plasma_ions_thermal ) - - confinement_time_data = self.physics.confinement.calculate_confinement_time( self.data.physics.m_fuel_amu, self.data.physics.p_alpha_total_mw,