Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 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,42 @@ 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]


----------

### 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]

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

[^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.
20 changes: 15 additions & 5 deletions process/core/io/plot/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@
from process.data_structure.impurity_radiation_variables import N_IMPURITIES
from process.data_structure.numerics import FiguresOfMerit, PROCESSRunMode
from process.data_structure.pfcoil_variables import NFIXMX
from process.data_structure.physics_variables import ConfinementTimeModel
from process.data_structure.physics_variables import (
ConfinementTimeModel,
OutbordSOLPowerDecayLengthModel,
)
from process.data_structure.superconducting_tf_coil_variables import TFWPIntegerTurnType
from process.models.build import Build
from process.models.engineering.materials import (
Expand Down Expand Up @@ -9029,12 +9032,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 @@ -1708,6 +1710,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
135 changes: 135 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.a_plasma_outboard_sol_parallel = self.calculate_upstream_sol_outboard_parallel_area( # noqa: E501
rmajor=self.data.physics.rmajor,
Expand Down Expand Up @@ -136,6 +171,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 @@ -283,6 +330,94 @@ 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).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe we could have another comment on the validity of this model - which plasmas does it apply to? Is it H-mode only?


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].

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].

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