Skip to content
Merged
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
70 changes: 35 additions & 35 deletions process/models/physics/confinement_time.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -20,6 +21,24 @@
logger = logging.getLogger(__name__)


@dataclass(slots=True, frozen=True)
class ConfinementTimeData:
"""Dataclass to hold confinement time model calculation parameters."""

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 PlasmaConfinementTime(Model):
"""Class to calculate plasma confinement time using various empirical scaling laws"""

Expand Down Expand Up @@ -60,7 +79,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
Expand Down Expand Up @@ -118,14 +137,8 @@ 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
Comment thread
chris-ashe marked this conversation as resolved.
Dataclass containing confinement time model calculation parameters

Raises
------
Expand Down Expand Up @@ -982,13 +995,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
Expand Down Expand Up @@ -1054,14 +1067,7 @@ def fhz(hfact: float) -> float:
balance.

"""
(
ptrez,
ptriz,
_,
_,
_,
_,
) = 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,
Expand Down Expand Up @@ -1091,8 +1097,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
Expand Down Expand Up @@ -1347,14 +1353,8 @@ def output_confinement_comparison(self, istell: int):
):
if i_confinement_time == 25:
continue
(
_,
_,
taueez,
_,
_,
_,
) = 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,
Expand Down Expand Up @@ -1397,7 +1397,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_plasma_energy_confinement:<28.3f}{self.data.physics.hfac[i_confinement_time - 1]:.3f}",
)

po.oblnkl(self.outfile)
Expand Down
25 changes: 17 additions & 8 deletions process/models/physics/physics.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,14 +843,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 = 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,
Expand All @@ -877,6 +870,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_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

# Total transport power from scaling law (MW)
self.data.physics.p_electron_transport_loss_mw = (
Expand Down
26 changes: 18 additions & 8 deletions process/models/stellarator/stellarator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2251,14 +2251,7 @@ def st_phys(self, output):
+ self.data.physics.e_plasma_ions_thermal
)

(
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(
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,
Expand Down Expand Up @@ -2286,6 +2279,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,
Expand Down
21 changes: 7 additions & 14 deletions tests/unit/models/physics/test_physics.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
)

Expand Down
Loading