Skip to content

Add PlasmaDensityLimit class and integrate into physics and stellarat…#4093

Open
chris-ashe wants to merge 16 commits intomainfrom
create_density_limit_class
Open

Add PlasmaDensityLimit class and integrate into physics and stellarat…#4093
chris-ashe wants to merge 16 commits intomainfrom
create_density_limit_class

Conversation

@chris-ashe
Copy link
Collaborator

…or models

Description

Checklist

I confirm that I have completed the following checks:

  • My changes follow the PROCESS style guide
  • I have justified any large differences in the regression tests caused by this pull request in the comments.
  • I have added new tests where appropriate for the changes I have made.
  • If I have had to change any existing unit or integration tests, I have justified this change in the pull request comments.
  • If I have made documentation changes, I have checked they render correctly.
  • I have added documentation for my change, if appropriate.

@chris-ashe chris-ashe added Physics Relating to the physics models Refactor labels Feb 12, 2026
@codecov-commenter
Copy link

codecov-commenter commented Feb 12, 2026

Codecov Report

❌ Patch coverage is 64.70588% with 36 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.94%. Comparing base (bb358d5) to head (c8dcd34).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
process/models/physics/density_limit.py 65.62% 33 Missing ⚠️
process/models/physics/physics.py 50.00% 2 Missing ⚠️
process/main.py 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4093      +/-   ##
==========================================
+ Coverage   46.86%   46.94%   +0.07%     
==========================================
  Files         136      137       +1     
  Lines       29228    29319      +91     
==========================================
+ Hits        13698    13764      +66     
- Misses      15530    15555      +25     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@chris-ashe chris-ashe force-pushed the create_density_limit_class branch from e2784ec to aa1518c Compare February 12, 2026 13:44
@chris-ashe chris-ashe marked this pull request as ready for review February 12, 2026 14:11
@chris-ashe chris-ashe requested a review from a team as a code owner February 12, 2026 14:11
Copy link
Collaborator

@timothy-nunn timothy-nunn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix conflicts before a review can be provided

@chris-ashe chris-ashe force-pushed the create_density_limit_class branch from d46b934 to f9d01b2 Compare February 21, 2026 14:06
@chris-ashe chris-ashe force-pushed the create_density_limit_class branch from 98854e8 to a4f2d2d Compare February 21, 2026 14:24
@timothy-nunn timothy-nunn self-assigned this Feb 25, 2026
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several density limit models are available in PROCESS. These are
calculated in routine calculate_density_limit(), which is called by physics.

Needs to be updated to reflect the new class

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot see this

Comment on lines 10197 to 10350
def calculate_density_limit(
self,
b_plasma_toroidal_on_axis: float,
i_density_limit: int,
p_plasma_separatrix_mw: float,
p_hcd_injected_total_mw: float,
plasma_current: float,
prn1: float,
qcyl: float,
q95: float,
rmajor: float,
rminor: float,
a_plasma_surface: float,
zeff: float,
) -> tuple[np.ndarray, float]:
"""
Calculate the density limit using various models.

Args:
b_plasma_toroidal_on_axis (float): Toroidal field on axis (T).
i_density_limit (int): Switch denoting which formula to enforce.
p_plasma_separatrix_mw (float): Power flowing to the edge plasma via charged particles (MW).
p_hcd_injected_total_mw (float): Power injected into the plasma (MW).
plasma_current (float): Plasma current (A).
prn1 (float): Edge density / average plasma density.
qcyl (float): Equivalent cylindrical safety factor (qstar).
q95 (float): Safety factor at 95% surface.
rmajor (float): Plasma major radius (m).
rminor (float): Plasma minor radius (m).
a_plasma_surface (float): Plasma surface area (m^2).
zeff (float): Plasma effective charge.

Returns:
Tuple[np.ndarray, float]: A tuple containing:
- nd_plasma_electron_max_array (np.ndarray): Average plasma density limit using seven different models (m^-3).
- nd_plasma_electrons_max (float): Enforced average plasma density limit (m^-3).

Raises:
ValueError: If i_density_limit is not between 1 and 7.

Notes:
This routine calculates several different formulae for the density limit and enforces the one chosen by the user.
For i_density_limit = 1-5, 8, we scale the sepatrix density limit output by the ratio of the separatrix to volume averaged density

References:
- AEA FUS 172: Physics Assessment for the European Reactor Study

- N.A. Uckan and ITER Physics Group, 'ITER Physics Design Guidelines: 1989

- M. Bernert et al., “The H-mode density limit in the full tungsten ASDEX Upgrade tokamak,”
vol. 57, no. 1, pp. 014038-014038, Nov. 2014, doi: https://doi.org/10.1088/0741-3335/57/1/014038. ‌
"""

if i_density_limit < 1 or i_density_limit > 7:
raise ProcessValueError(
"Illegal value for i_density_limit", i_density_limit=i_density_limit
)

nd_plasma_electron_max_array = np.empty((8,))

# Power per unit area crossing the plasma edge
# (excludes radiation and neutrons)

p_perp = p_plasma_separatrix_mw / a_plasma_surface

# Old ASDEX density limit formula
# This applies to the density at the plasma edge, so must be scaled
# to give the density limit applying to the average plasma density.

nd_plasma_electron_max_array[0] = self.calculate_asdex_density_limit(
p_perp=p_perp,
b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis,
q95=q95,
rmajor=rmajor,
prn1=prn1,
)

# Borrass density limit model for ITER (I)
# This applies to the density at the plasma edge, so must be scaled
# to give the density limit applying to the average plasma density.
# Borrass et al, ITER-TN-PH-9-6 (1989)

nd_plasma_electron_max_array[1] = self.calculate_borrass_iter_i_density_limit(
p_perp=p_perp,
b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis,
q95=q95,
rmajor=rmajor,
prn1=prn1,
)

# Borrass density limit model for ITER (II)
# This applies to the density at the plasma edge, so must be scaled
# to give the density limit applying to the average plasma density.
# This formula is (almost) identical to that in the original routine
# denlim (now deleted).

nd_plasma_electron_max_array[2] = self.calculate_borrass_iter_ii_density_limit(
p_perp=p_perp,
b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis,
q95=q95,
rmajor=rmajor,
prn1=prn1,
)

# JET edge radiation density limit model
# This applies to the density at the plasma edge, so must be scaled
# to give the density limit applying to the average plasma density.
# qcyl=qstar here, but literature is not clear.

nd_plasma_electron_max_array[3] = (
self.calculate_jet_edge_radiation_density_limit(
zeff=zeff,
p_hcd_injected_total_mw=p_hcd_injected_total_mw,
prn1=prn1,
qcyl=qcyl,
)
)

# JET simplified density limit model
# This applies to the density at the plasma edge, so must be scaled
# to give the density limit applying to the average plasma density.

nd_plasma_electron_max_array[4] = self.calculate_jet_simple_density_limit(
b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis,
p_plasma_separatrix_mw=p_plasma_separatrix_mw,
rmajor=rmajor,
prn1=prn1,
)

# Hugill-Murakami M.q limit
# qcyl=qstar here, which is okay according to the literature

nd_plasma_electron_max_array[5] = self.calculate_hugill_murakami_density_limit(
b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis, rmajor=rmajor, qcyl=qcyl
)

# Greenwald limit

nd_plasma_electron_max_array[6] = self.calculate_greenwald_density_limit(
c_plasma=plasma_current, rminor=rminor
)

nd_plasma_electron_max_array[7] = self.calculate_asdex_new_density_limit(
p_hcd_injected_total_mw=p_hcd_injected_total_mw,
c_plasma=plasma_current,
q95=q95,
prn1=prn1,
)

# Enforce the chosen density limit

return nd_plasma_electron_max_array, nd_plasma_electron_max_array[
i_density_limit - 1
]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this ever called by the code?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its ran from self.density_limit.run() on line 2462


nd_plasma_electron_max_array, nd_plasma_electrons_max = (
physics.calculate_density_limit(
PlasmaDensityLimit().calculate_density_limit(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PlasmaDensityLimit().calculate_density_limit(
physics.density_limit.calculate_density_limit(

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation style for this file is out of date, please use the numpy style

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to numpy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Physics Relating to the physics models Refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants