From 35fbda9eaa01080e51a2817a680b2ec7a0da85c3 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Jul 2026 09:12:26 +0100 Subject: [PATCH 1/8] Add volume-averaged plasma electron temperature ratio to PhysicsData --- process/data_structure/physics_variables.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/process/data_structure/physics_variables.py b/process/data_structure/physics_variables.py index 046015ac4a..0c46e9506d 100644 --- a/process/data_structure/physics_variables.py +++ b/process/data_structure/physics_variables.py @@ -1403,6 +1403,9 @@ class PhysicsData: temp_plasma_electron_on_axis_kev: float = 0.0 """Plasma central electron temperature (Tₑ₀) [keV]""" + f_temp_plasma_electron__on_axis_vol_avg: float = 0.0 + """Ratio of plasma central electron temperature to volume averaged (Tₑ₀/⟨Tₑ⟩)""" + temp_plasma_electron_density_weighted_kev: float = 0.0 """Density weighted average electron temperature (⟨Tₑ⟩_n) [keV]""" From 222e9268bb5955b5b11d3ac0ad7c511f773af1fa Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Jul 2026 09:13:37 +0100 Subject: [PATCH 2/8] Add volume-averaged central plasma thermal pressure ratio to PhysicsData --- process/data_structure/physics_variables.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/process/data_structure/physics_variables.py b/process/data_structure/physics_variables.py index 0c46e9506d..b6ef77955f 100644 --- a/process/data_structure/physics_variables.py +++ b/process/data_structure/physics_variables.py @@ -1040,6 +1040,9 @@ class PhysicsData: pres_plasma_thermal_on_axis: float = 0.0 """Plasma central thermal pressure (p₀) (no fast ions or beam pressure) [Pa]""" + f_pres_plasma_thermal_on_axis_vol_avg: float = 0.0 + """Ratio of central plasma thermal pressure to volume averaged (p₀/⟨p⟩)""" + pres_plasma_thermal_total_profile: list[float] = field(default_factory=list) """Profile of total pressure in plasma [Pa]""" From 188b923e81644855f166cbbee813617f7478cb36 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Jul 2026 09:39:18 +0100 Subject: [PATCH 3/8] Add central to volume averaged plasma thermal pressure ratio calculation --- process/core/io/plot/summary.py | 5 ++++- process/models/physics/physics.py | 7 +++++++ process/models/physics/plasma_profiles.py | 5 +++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 5c53ac2933..53d110a531 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -12281,7 +12281,10 @@ def plot_plasma_pressure_profiles(axis: plt.Axes, mfile: MFile, scan: int): axis.legend() textstr_pressure = "\n".join(( - rf"$p_0$: {mfile.get('pres_plasma_thermal_on_axis', scan=scan) / 1000:,.3f} kPa", + ( + rf"$p_0$: {mfile.get('pres_plasma_thermal_on_axis', scan=scan) / 1000:,.3f} kPa" + rf"$\hspace{{2}} \frac{{p_0}}{{\langle p_{{\text{{total}}}} \rangle_\text{{V}}}}$: {mfile.get('f_pres_plasma_thermal_on_axis_vol_avg', scan=scan):,.3f}" + ), rf"$\langle p_{{\text{{total}}}} \rangle_\text{{V}}$: {mfile.get('pres_plasma_thermal_vol_avg', scan=scan) / 1000:,.3f} kPa", )) diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 926e0eee8f..f183ca54fe 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -3226,6 +3226,13 @@ def output_temperature_density_profile_info(self) -> None: self.data.physics.pres_plasma_thermal_vol_avg, "OP ", ) + po.ovarre( + self.outfile, + "Central to volume averaged plasma thermal pressure ratio (p₀/⟨p⟩)", + "(f_pres_plasma_thermal_on_axis_vol_avg)", + self.data.physics.f_pres_plasma_thermal_on_axis_vol_avg, + "OP ", + ) # As array output is not currently supported, each element is output as a float # instance # Output plasma pressure profiles to mfile diff --git a/process/models/physics/plasma_profiles.py b/process/models/physics/plasma_profiles.py index c27ac81917..58cc77899b 100644 --- a/process/models/physics/plasma_profiles.py +++ b/process/models/physics/plasma_profiles.py @@ -312,6 +312,11 @@ def calculate_profile_factors(self): * self.data.physics.temp_plasma_ion_density_weighted_kev ) * constants.KILOELECTRON_VOLT + self.data.physics.f_pres_plasma_thermal_on_axis_vol_avg = ( + self.data.physics.pres_plasma_thermal_on_axis + / self.data.physics.pres_plasma_thermal_vol_avg + ) + # Central plasma current density (A/m²) # Assumes a parabolic profile for the current density self.data.physics.j_plasma_on_axis = ( From 2e539e4cf4ee96e83a9b199f2ffe96073bee3665 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Jul 2026 09:39:51 +0100 Subject: [PATCH 4/8] Fix units for total plasma thermal energy and its components from Watts to Joules --- process/models/physics/physics.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index f183ca54fe..d8dd81b9cd 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -3272,21 +3272,21 @@ def output_temperature_density_profile_info(self) -> None: po.ovarre( self.outfile, - "Total plasma thermal energy [W]", + "Total plasma thermal energy [J]", "(e_plasma_thermal_total)", self.data.physics.e_plasma_thermal_total, "OP ", ) po.ovarre( self.outfile, - "Plasma thermal energy in electrons [W]", + "Plasma thermal energy in electrons [J]", "(e_plasma_electrons_thermal)", self.data.physics.e_plasma_electrons_thermal, "OP ", ) po.ovarre( self.outfile, - "Plasma thermal energy in ions [W]", + "Plasma thermal energy in ions [J]", "(e_plasma_ions_thermal)", self.data.physics.e_plasma_ions_thermal, "OP ", From 832bd33ff67cf73180d1ab8146f47436685626a5 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Jul 2026 09:53:11 +0100 Subject: [PATCH 5/8] Add pressure peaking fraction value calculation and update PhysicsData --- process/core/io/plot/summary.py | 2 +- process/data_structure/physics_variables.py | 2 +- process/models/physics/physics.py | 7 +++++++ process/models/physics/plasma_profiles.py | 10 ++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 53d110a531..e4308a7321 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -4345,7 +4345,7 @@ def plot_t_profiles(prof, demo_ranges: bool, mfile: MFile, scan: int): ( rf"$\rho_{{\text{{ped,T}}}}$: {radius_plasma_pedestal_temp_norm:.3f}" r"$ \hspace{5} \frac{T_{e,0}}{\langle T_e \rangle}$: " - f"{te0 / te:.3f}" + f"{mfile.get('f_temp_plasma_electron_on_axis_vol_avg', scan=scan):.3f}" ), ( rf"$T_{{\text{{e,sep}}}}$: {temp_plasma_separatrix_kev:.3f} keV" diff --git a/process/data_structure/physics_variables.py b/process/data_structure/physics_variables.py index b6ef77955f..92a9128cba 100644 --- a/process/data_structure/physics_variables.py +++ b/process/data_structure/physics_variables.py @@ -1406,7 +1406,7 @@ class PhysicsData: temp_plasma_electron_on_axis_kev: float = 0.0 """Plasma central electron temperature (Tₑ₀) [keV]""" - f_temp_plasma_electron__on_axis_vol_avg: float = 0.0 + f_temp_plasma_electron_on_axis_vol_avg: float = 0.0 """Ratio of plasma central electron temperature to volume averaged (Tₑ₀/⟨Tₑ⟩)""" temp_plasma_electron_density_weighted_kev: float = 0.0 diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index d8dd81b9cd..68d8f63ca5 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -2968,6 +2968,13 @@ def output_temperature_density_profile_info(self) -> None: self.data.physics.temp_plasma_electron_on_axis_kev, "OP ", ) + po.ovarre( + self.outfile, + "Ratio of electron temperature on axis to volume averaged (Tₑ₀/⟨Tₑ⟩)", + "(f_temp_plasma_electron_on_axis_vol_avg)", + self.data.physics.f_temp_plasma_electron_on_axis_vol_avg, + "OP ", + ) po.ovarre( self.outfile, "Line averaged electron temperature (keV)", diff --git a/process/models/physics/plasma_profiles.py b/process/models/physics/plasma_profiles.py index 58cc77899b..16a961a98c 100644 --- a/process/models/physics/plasma_profiles.py +++ b/process/models/physics/plasma_profiles.py @@ -171,6 +171,11 @@ def parabolic_parameterisation(self): * (1.0 + self.data.physics.alphat) ) + self.data.physics.f_temp_plasma_electron_on_axis_vol_avg = ( + self.data.physics.temp_plasma_electron_on_axis_kev + / self.data.physics.temp_plasma_electron_vol_avg_kev + ) + self.data.physics.nd_plasma_electron_on_axis = ( self.data.physics.nd_plasma_electrons_vol_avg * (1.0 + self.data.physics.alphan) @@ -237,6 +242,11 @@ def pedestal_parameterisation(self): self.teprofile.profile_integ ) + self.data.physics.f_temp_plasma_electron_on_axis_vol_avg = ( + self.data.physics.temp_plasma_electron_on_axis_kev + / self.data.physics.temp_plasma_electron_vol_avg_kev + ) + # Scrape-off density / volume averaged density # (Input value is used if i_plasma_pedestal = 0) From 5ebf84895f29c1a4c79b20b638e525da82d9dcde Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Jul 2026 09:57:20 +0100 Subject: [PATCH 6/8] Add plasma pedestal and separatrix thermal pressure attributes to PhysicsData --- process/data_structure/physics_variables.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/process/data_structure/physics_variables.py b/process/data_structure/physics_variables.py index 92a9128cba..cb1250e7ce 100644 --- a/process/data_structure/physics_variables.py +++ b/process/data_structure/physics_variables.py @@ -1055,6 +1055,12 @@ class PhysicsData: pres_plasma_fuel_profile: list[float] = field(default_factory=list) """Profile of fuel pressure in plasma [Pa]""" + pres_plasma_pedestal_thermal: float = 0.0 + """Plasma pedestal thermal pressure (p_ped) (no fast ions or beam pressure) [Pa]""" + + pres_plasma_separatrix_thermal: float = 0.0 + """Plasma separatrix thermal pressure (pₛₑₚ) (no fast ions or beam pressure) [Pa]""" + j_plasma_on_axis: float = 0.0 """Central plasma current density (j₀) [A/m²]""" From d2cc28236af531d96d25e4f3e60b9c70d291b65f Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Jul 2026 10:23:42 +0100 Subject: [PATCH 7/8] Add pedestal and separatrix thermal pressure calculations to PlasmaProfile --- process/core/io/plot/summary.py | 21 +++++++++++++++++++++ process/models/physics/physics.py | 18 ++++++++++++++++++ process/models/physics/plasma_profiles.py | 16 ++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index e4308a7321..30ae00b08c 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -80,6 +80,7 @@ PlasmaShapeModelType, ) from process.models.pulse import PulseTimings +from process.models.physics.profiles import PlasmaProfileShapeType from process.models.superconductors import SuperconductorModel from process.models.tfcoil.base import ( TFCoilShapeModel, @@ -12299,6 +12300,26 @@ def plot_plasma_pressure_profiles(axis: plt.Axes, mfile: MFile, scan: int): bbox={"boxstyle": "round", "facecolor": "wheat", "alpha": 0.5}, ) + if ( + int(mfile.get("i_plasma_pedestal", scan=scan)) + == PlasmaProfileShapeType.PEDESTAL_PROFILE + ): + textstr_pressure_pedestal = "\n".join(( + rf"$p_{{\text{{ped}}}}$: {mfile.get('pres_plasma_pedestal_thermal', scan=scan) / 1000:,.3f} kPa", + rf"$p_{{\text{{sep}}}}$: {mfile.get('pres_plasma_separatrix_thermal', scan=scan) / 1000:,.3f} kPa", + )) + + axis.text( + 0.9, + 1.2, + textstr_pressure_pedestal, + transform=axis.transAxes, + fontsize=9, + verticalalignment="top", + horizontalalignment="center", + bbox={"boxstyle": "round", "facecolor": "wheat", "alpha": 0.5}, + ) + def plot_plasma_current_comparison(axis: plt.Axes, mfile: MFile, scan: int): """Function to plot a scatter box plot of different plasma current comparisons. diff --git a/process/models/physics/physics.py b/process/models/physics/physics.py index 68d8f63ca5..e95cd3f34c 100644 --- a/process/models/physics/physics.py +++ b/process/models/physics/physics.py @@ -3240,6 +3240,24 @@ def output_temperature_density_profile_info(self) -> None: self.data.physics.f_pres_plasma_thermal_on_axis_vol_avg, "OP ", ) + if ( + self.data.physics.i_plasma_pedestal + == PlasmaProfileShapeType.PEDESTAL_PROFILE + ): + po.oblnkl(self.outfile) + po.ovarre( + self.outfile, + "Plasma thermal pressure at pedestal (p_ped) [Pa]", + "(pres_plasma_pedestal_thermal)", + self.data.physics.pres_plasma_pedestal_thermal, + ) + po.ovarre( + self.outfile, + "Plasma thermal pressure at separatrix (pₛₑₚ) [Pa]", + "(pres_plasma_separatrix_thermal)", + self.data.physics.pres_plasma_separatrix_thermal, + ) + # As array output is not currently supported, each element is output as a float # instance # Output plasma pressure profiles to mfile diff --git a/process/models/physics/plasma_profiles.py b/process/models/physics/plasma_profiles.py index 16a961a98c..0c57e06b2a 100644 --- a/process/models/physics/plasma_profiles.py +++ b/process/models/physics/plasma_profiles.py @@ -294,6 +294,22 @@ def calculate_profile_factors(self): + self.data.physics.pres_plasma_ion_total_profile ) + # Calculate pedestal and separatrix pressures for pedestal profile case + if ( + PlasmaProfileShapeType(self.data.physics.i_plasma_pedestal) + == PlasmaProfileShapeType.PEDESTAL_PROFILE + ): + # Pedestal pressure is the profile value where gradient is maximum + rho = self.neprofile.profile_x + pres_profile = self.data.physics.pres_plasma_thermal_total_profile + dpres_drho = np.gradient(pres_profile, rho) + max_grad_idx = np.argmin(dpres_drho) + self.data.physics.pres_plasma_pedestal_thermal = pres_profile[max_grad_idx] + + self.data.physics.pres_plasma_separatrix_thermal = ( + self.data.physics.pres_plasma_thermal_total_profile[-1] + ) + # Fuel ion pressure profile (Pa) self.data.physics.pres_plasma_fuel_profile = ( self.data.physics.nd_plasma_fuel_ions_vol_avg From 7e42afe117fd6247322eca077a47821cfbe78ee5 Mon Sep 17 00:00:00 2001 From: mn3981 Date: Wed, 29 Jul 2026 11:23:29 +0100 Subject: [PATCH 8/8] Add calculation for plasma pedestal thermal pressure based on gradient analysis --- process/core/io/plot/summary.py | 2 +- process/models/physics/plasma_profiles.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/process/core/io/plot/summary.py b/process/core/io/plot/summary.py index 30ae00b08c..d24f417de7 100644 --- a/process/core/io/plot/summary.py +++ b/process/core/io/plot/summary.py @@ -79,8 +79,8 @@ PlasmaGeometryModelType, PlasmaShapeModelType, ) -from process.models.pulse import PulseTimings from process.models.physics.profiles import PlasmaProfileShapeType +from process.models.pulse import PulseTimings from process.models.superconductors import SuperconductorModel from process.models.tfcoil.base import ( TFCoilShapeModel, diff --git a/process/models/physics/plasma_profiles.py b/process/models/physics/plasma_profiles.py index 0c57e06b2a..d553319984 100644 --- a/process/models/physics/plasma_profiles.py +++ b/process/models/physics/plasma_profiles.py @@ -300,10 +300,21 @@ def calculate_profile_factors(self): == PlasmaProfileShapeType.PEDESTAL_PROFILE ): # Pedestal pressure is the profile value where gradient is maximum + # (i.e the smallest negative value) rho = self.neprofile.profile_x pres_profile = self.data.physics.pres_plasma_thermal_total_profile dpres_drho = np.gradient(pres_profile, rho) - max_grad_idx = np.argmin(dpres_drho) + # Find rho index closest to the normalized pedestal positions + pedestal_rho = np.min([ + self.data.physics.radius_plasma_pedestal_temp_norm, + self.data.physics.radius_plasma_pedestal_density_norm, + ]) + closest_idx = np.argmin(np.abs(rho - pedestal_rho)) + mask = np.zeros_like(rho, dtype=bool) + mask[closest_idx:] = True + dpres_drho_pedestal = dpres_drho[mask] + max_grad_idx_pedestal = np.argmax(dpres_drho_pedestal) + max_grad_idx = np.where(mask)[0][max_grad_idx_pedestal] self.data.physics.pres_plasma_pedestal_thermal = pres_profile[max_grad_idx] self.data.physics.pres_plasma_separatrix_thermal = (