Skip to content
36 changes: 35 additions & 1 deletion documentation/source/physics-models/plasma_scrape_off_layer.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,45 @@ The $R^2$ value for this fit is 0.55

--------

### Eich 2011 JET Model | `calculate_eich2011_jet_sol_power_decay_length()`

The power decay length in metres is given by[^eich_2011]:

$$
\lambda_q = 0.7(\pm0.26) \times 10^{-3} B_{\text{T,0}}^{-0.84(\pm0.26)} q_{\text{cyl}}^{1.23(\pm0.26)} P_{\text{sep}}^{0.14(\pm0.14)}
$$

Here $B_{\text{T,0}}$ is the on axis toroidal magnetic field, $q_{\text{cyl}}$ is the cylindrical safety factor and $P_{\text{sep}}$ is the plasma separatrix power in $\text{MW}$.

This can be found in Table 2 from Eich et.al [^eich_2011]

The scaling is done for type-I ELMy H-mode plasmas

----------

### Eich 2011 JET+ASDEX Model | `calculate_eich2011_jet_asdex_sol_power_decay_length()`

The power decay length in metres is given by[^eich_2011]:

$$
\lambda_q = 0.73(\pm0.38) \times 10^{-3} B_{\text{T,0}}^{-0.78(\pm0.25)} q_{\text{cyl}}^{1.2(\pm0.27)} P_{\text{sep}}^{0.1(\pm0.11)}R_0^{0.02(\pm0.2)}
$$

Here $B_{\text{T,0}}$ is the on axis toroidal magnetic field, $q_{\text{cyl}}$ is the cylindrical safety factor, $P_{\text{sep}}$ is the plasma separatrix power in $\text{MW}$ and $R_0$ is the plasma major radius.

This can be found in Table 2 from Eich et.al [^eich_2011]

The scaling is done for type-I ELMy H-mode plasmas

------------------

[^eich_2013]: T. Eich et al., “Scaling of the tokamak near the scrape-off layer H-mode power width and implications for ITER,” Nuclear Fusion, vol. 53, no. 9 p. 093031, Aug. 2013, doi: 10.1088/0029-5515/53/9/093031.

[^mast_2014]: A. J. Thornton and A. Kirk, “Scaling of the scrape-off layer width during inter-ELM H modes on MAST as measured by infrared thermography,”
Plasma Physics and Controlled Fusion, vol. 56, no. 5, p. 055008, Apr. 2014, doi: 10.1088/0741-3335/56/5/055008.

[^stangeby_boundary]: P. C. Stangeby, “The Plasma Boundary of Magnetic Fusion Devices,” Jan. 2000, doi: 10.1201/9780367801489.

[^henderson_step]: S. S. Henderson et al., “An overview of the STEP divertor design and the simple models driving the plasma exhaust scenario,” Nuclear Fusion, vol. 65, no. 1, pp. 016033–016033, Nov. 2024, doi: 10.1088/1741-4326/ad93e7.
[^henderson_step]: S. S. Henderson et al., “An overview of the STEP divertor design and the simple models driving the plasma exhaust scenario,” Nuclear Fusion, vol. 65, no. 1, pp. 016033–016033, Nov. 2024, doi: 10.1088/1741-4326/ad93e7.

[^eich_2011]: T. Eich, B. Sieglin, A. Scarabosio, W. Fundamenski, Robert James Goldston, and A. Herrmann, “Inter-ELM Power Decay Length for JET and ASDEX Upgrade: Measurement and Comparison with Heuristic Drift-Based Model,” Physical Review Letters, vol. 107, no. 21, Nov. 2011, doi: https://doi.org/10.1103/PhysRevLett.107.215001.
16 changes: 12 additions & 4 deletions process/core/io/plot/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from process.data_structure.physics_variables import (
ConfinementTimeModel,
DivertorNumberModels,
OutbordSOLPowerDecayLengthModel,
)
from process.data_structure.superconducting_tf_coil_variables import TFWPIntegerTurnType
from process.models.build import Build
Expand Down Expand Up @@ -9034,12 +9035,19 @@ def plot_sol_power_decay_length_comparison(axis: plt.Axes, mfile: MFile, scan: i
len_plasma_sol_mast14_power_decay_2_mm = (
mfile.get("len_plasma_sol_mast14_power_decay_2", scan=scan) * 1e3
)

len_plasma_sol_eich11_jet_power_decay_mm = (
mfile.get("len_plasma_sol_eich11_jet_power_decay", scan=scan) * 1e3
)
len_plasma_sol_eich11_jet_asdex_power_decay_mm = (
mfile.get("len_plasma_sol_eich11_jet_asdex_power_decay", scan=scan) * 1e3
)
# Data for the box plot
data = {
"Eich 2013": len_plasma_sol_eich13_power_decay_mm,
"MAST 2014 (1)": len_plasma_sol_mast14_power_decay_1_mm,
"MAST 2014 (2)": len_plasma_sol_mast14_power_decay_2_mm,
f"{OutbordSOLPowerDecayLengthModel.EICH_2013.description}": len_plasma_sol_eich13_power_decay_mm,
f"{OutbordSOLPowerDecayLengthModel.MAST_2014_1.description}": len_plasma_sol_mast14_power_decay_1_mm,
f"{OutbordSOLPowerDecayLengthModel.MAST_2014_2.description}": len_plasma_sol_mast14_power_decay_2_mm,
f"{OutbordSOLPowerDecayLengthModel.EICH_2011_JET.description}": len_plasma_sol_eich11_jet_power_decay_mm,
f"{OutbordSOLPowerDecayLengthModel.EICH_2011_JET_ASDEX.description}": len_plasma_sol_eich11_jet_asdex_power_decay_mm,
}
# Create the violin plot
axis.violinplot(data.values(), showextrema=False)
Expand Down
8 changes: 8 additions & 0 deletions process/data_structure/physics_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class OutbordSOLPowerDecayLengthModel(IntEnum):
EICH_2013 = (1, "Eich 2013")
MAST_2014_1 = (2, "MAST 2014-1")
MAST_2014_2 = (3, "MAST 2014-2")
EICH_2011_JET = (4, "Eich 2011 JET")
EICH_2011_JET_ASDEX = (5, "Eich 2011 JET + ASDEX Upgrade")

def __new__(cls, value: int, description: str):
"""Create a new instance of OutbordSOLPowerDecayLengthModel.
Expand Down Expand Up @@ -1739,6 +1741,12 @@ class PhysicsData:
len_plasma_sol_mast14_power_decay_2: float = 0.0
"""MAST 2014 power decay length in the scrape-off layer scaling 2 (λ_q) [m]"""

len_plasma_sol_eich11_jet_power_decay: float = 0.0
"""Eich 2011 JET power decay length in the scrape-off layer scaling (λ_q) [m]"""

len_plasma_sol_eich11_jet_asdex_power_decay: float = 0.0
"""Eich 2011 JET + ASDEX power decay length in the scrape-off layer scaling (λ_q) [m]"""

a_plasma_outboard_sol_eich13_parallel: float = 0.0
"""Plasma outboard midplane (upstream) Eich 2013 SOL parallel area (Aₗₗ,ᵤ) [m]"""

Expand Down
137 changes: 137 additions & 0 deletions process/models/physics/scrape_off_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@ def run(self):
)
)

self.data.physics.len_plasma_sol_eich11_jet_power_decay = (
self.calculate_eich2011_jet_sol_power_decay_length(
b_plasma_toroidal_on_axis=self.data.physics.b_plasma_toroidal_on_axis,
q_cyl=self.data.physics.qstar,
p_plasma_separatrix_mw=self.data.physics.p_plasma_separatrix_mw,
)
)

self.data.physics.len_plasma_sol_eich11_jet_asdex_power_decay = (
self.calculate_eich2011_jet_asdex_sol_power_decay_length(
b_plasma_toroidal_on_axis=self.data.physics.b_plasma_toroidal_on_axis,
q_cyl=self.data.physics.qstar,
p_plasma_separatrix_mw=self.data.physics.p_plasma_separatrix_mw,
rmajor=self.data.physics.rmajor,
)
)

# Set to user input if OutbordSOLPowerDecayLengthModel = 1/USER_INUT

if (
Expand Down Expand Up @@ -70,6 +87,24 @@ def run(self):
self.data.physics.len_sol_outboard_power_decay = (
self.data.physics.len_plasma_sol_mast14_power_decay_2
)
elif (
OutbordSOLPowerDecayLengthModel(
self.data.physics.i_len_sol_outboard_power_decay
)
== OutbordSOLPowerDecayLengthModel.EICH_2011_JET
):
self.data.physics.len_sol_outboard_power_decay = (
self.data.physics.len_plasma_sol_eich11_jet_power_decay
)
elif (
OutbordSOLPowerDecayLengthModel(
self.data.physics.i_len_sol_outboard_power_decay
)
== OutbordSOLPowerDecayLengthModel.EICH_2011_JET_ASDEX
):
self.data.physics.len_sol_outboard_power_decay = (
self.data.physics.len_plasma_sol_eich11_jet_asdex_power_decay
)

self.data.physics.len_sol_inboard_power_decay = (
self.data.physics.f_len_sol_power_decay_inboard_outboard
Expand Down Expand Up @@ -154,6 +189,18 @@ def output(self) -> None:
"(len_plasma_sol_mast14_power_decay_2)",
self.data.physics.len_plasma_sol_mast14_power_decay_2,
)
po.ovarre(
self.outfile,
"Eich 2011 JET SOL power decay length (λ_q) [m]",
"(len_plasma_sol_eich11_jet_power_decay)",
self.data.physics.len_plasma_sol_eich11_jet_power_decay,
)
po.ovarre(
self.outfile,
"Eich 2011 JET + ASDEX Upgrade SOL power decay length (λ_q) [m]",
"(len_plasma_sol_eich11_jet_asdex_power_decay)",
self.data.physics.len_plasma_sol_eich11_jet_asdex_power_decay,
)
po.oblnkl(self.outfile)
po.ocmmnt(self.outfile, "----------------------------")

Expand Down Expand Up @@ -301,6 +348,96 @@ def calculate_mast2014_sol_power_decay_length_2(
"""
return 4.57e-3 * p_plasma_separatrix_mw**0.22 * cur_plasma_ma**-0.64

@staticmethod
def calculate_eich2011_jet_sol_power_decay_length(
b_plasma_toroidal_on_axis: float,
q_cyl: float,
p_plasma_separatrix_mw: float,
) -> float:
"""Calculate the Eich 2011 JET SOL power decay length (λ_q).
Comment thread
chris-ashe marked this conversation as resolved.

Parameters
----------
b_plasma_toroidal_on_axis : float
Toroidal magnetic field at the plasma axis (Bᴛ(R₀)) [T]
q_cyl : float
Cylindrical safety factor (q_cyl) [-]
p_plasma_separatrix_mw : float
Power crossing the separatrix (Pₛₑₚ) [MW]

Returns
-------
float
Eich 2011 JET SOL power decay length (λ_q) [m]

Notes
-----
- The fit values can be found in Table 2 of [1].
- The scaling is done for type-I ELMy H-mode plasmas

References
----------
[1] T. Eich, B. Sieglin, A. Scarabosio, W. Fundamenski, Robert James Goldston,
and A. Herrmann, “Inter-ELM Power Decay Length for JET and ASDEX Upgrade:
Measurement and Comparison with Heuristic Drift-Based Model,”
Physical Review Letters, vol. 107, no. 21, Nov. 2011,
doi: https://doi.org/10.1103/PhysRevLett.107.215001.

"""
return (
0.7e-3
* b_plasma_toroidal_on_axis**-0.84
* q_cyl**1.23
* p_plasma_separatrix_mw**0.14
)

@staticmethod
def calculate_eich2011_jet_asdex_sol_power_decay_length(
b_plasma_toroidal_on_axis: float,
q_cyl: float,
p_plasma_separatrix_mw: float,
rmajor: float,
) -> float:
"""Calculate the Eich 2011 JET + ASDEX Upgrade SOL power decay length (λ_q).

Parameters
----------
b_plasma_toroidal_on_axis : float
Toroidal magnetic field at the plasma axis (Bᴛ(R₀)) [T]
q_cyl : float
Cylindrical safety factor (q_cyl) [-]
p_plasma_separatrix_mw : float
Power crossing the separatrix (Pₛₑₚ) [MW]
rmajor : float
Major radius of the plasma (R₀) [m]

Returns
-------
float
Eich 2011 JET + ASDEX Upgrade SOL power decay length (λ_q) [m]

Notes
-----
- The fit values can be found in Table 2 of [1].
- The scaling is done for type-I ELMy H-mode plasmas

References
----------
[1] T. Eich, B. Sieglin, A. Scarabosio, W. Fundamenski, Robert James Goldston,
and A. Herrmann, “Inter-ELM Power Decay Length for JET and ASDEX Upgrade:
Measurement and Comparison with Heuristic Drift-Based Model,”
Physical Review Letters, vol. 107, no. 21, Nov. 2011,
doi: https://doi.org/10.1103/PhysRevLett.107.215001.

"""
return (
0.73e-3
* b_plasma_toroidal_on_axis**-0.78
* q_cyl**1.2
* p_plasma_separatrix_mw**0.1
* rmajor**0.02
)

@staticmethod
def calculate_upstream_sol_outboard_parallel_area(
rmajor: float,
Expand Down
77 changes: 77 additions & 0 deletions tests/unit/models/physics/test_scrape_off_layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,83 @@ def test_calculate_eich2013_sol_power_decay_length_exact():
assert pytest.approx(result) == 0.0015345296622855315


@pytest.mark.parametrize(
("b_plasma_toroidal_on_axis", "q_cyl", "p_plasma_separatrix_mw"),
[
(3.0, 2.0, 100.0),
(2.0, 1.0, 10.0),
(5.0, 4.0, 500.0),
(1.0, 3.0, 100.0),
],
)
def test_calculate_eich2011_jet_sol_power_decay_length(
b_plasma_toroidal_on_axis, q_cyl, p_plasma_separatrix_mw
):
"""Test Eich 2011 JET SOL power decay length with various parameters."""
result = ScrapeOffLayer.calculate_eich2011_jet_sol_power_decay_length(
b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis,
q_cyl=q_cyl,
p_plasma_separatrix_mw=p_plasma_separatrix_mw,
)
assert isinstance(result, float)
assert result > 0


def test_calculate_eich2011_jet_sol_power_decay_length_exact():
"""Test Eich 2011 JET SOL power decay length with exact value check."""
result = ScrapeOffLayer.calculate_eich2011_jet_sol_power_decay_length(
b_plasma_toroidal_on_axis=1.0,
q_cyl=1.0,
p_plasma_separatrix_mw=100.0,
)
assert isinstance(result, float)
assert pytest.approx(result) == 0.001333822502574273


@pytest.mark.parametrize(
(
"b_plasma_toroidal_on_axis",
"q_cyl",
"p_plasma_separatrix_mw",
"rmajor",
),
[
(3.0, 2.0, 100.0, 3.0),
(2.0, 1.0, 10.0, 3.0),
(5.0, 4.0, 500.0, 3.0),
(3.0, 2.0, 100.0, 10.0),
],
)
def test_calculate_eich2011_jet_asdex_sol_power_decay_length(
b_plasma_toroidal_on_axis, q_cyl, p_plasma_separatrix_mw, rmajor
):
"""Test Eich 2011 JET + ASDEX Upgrade SOL power decay length with
various parameters.
"""
result = ScrapeOffLayer.calculate_eich2011_jet_asdex_sol_power_decay_length(
b_plasma_toroidal_on_axis=b_plasma_toroidal_on_axis,
q_cyl=q_cyl,
p_plasma_separatrix_mw=p_plasma_separatrix_mw,
rmajor=rmajor,
)
assert isinstance(result, float)
assert result > 0


def test_calculate_eich2011_jet_asdex_sol_power_decay_length_exact():
"""Test Eich 2011 JET + ASDEX Upgrade SOL power decay length with exact value
check.
"""
result = ScrapeOffLayer.calculate_eich2011_jet_asdex_sol_power_decay_length(
b_plasma_toroidal_on_axis=1.0,
q_cyl=1.0,
p_plasma_separatrix_mw=100.0,
rmajor=1.0,
)
assert isinstance(result, float)
assert pytest.approx(result) == 0.0011569720304966129


@pytest.mark.parametrize(
("p_plasma_separatrix_mw", "b_plasma_surface_poloidal_average"),
[
Expand Down
Loading