8000 Set tf general methods 3 by chris-ashe · Pull Request #3699 · ukaea/PROCESS · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Set tf general methods 3 #3699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jul 1, 2025
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
2 changes: 1 addition & 1 deletion documentation/proc-pages/eng-models/tf-coil.md
Original file line number Diff line number Diff line change
Expand Up @@ -1232,7 +1232,7 @@ the following order:
5. `coilhap`: Define the vertical TF coil shape
6. `tf_res_heating`: Estimate the TF coil resistive heating (not used for SC magnets)
7. `tf_field_and_force`: Estimate the inboard/outboard vertical tensions
8. `tfcind`: Estimate the TF coil inductance
8. `tf_coil_self_inductance`: Estimate the TF coil inductance
9. `tf_coil_area_and_masses`: Estimate the mass of the different coil materials
10. `peak_tf_with_ripple`: Estimate the ripple peak field correction.
11. `stresscl`: Estimate the inboard mid-plane stress distributions.
Expand Down
26 changes: 11 additions & 15 deletions process/resistive_tf_coil.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,21 +98,17 @@ def run(self, output: bool):
self.res_tf_internal_geom()
self.tf_res_heating()

if physics_variables.itart == 0 and tfcoil_variables.i_tf_shape == 1:
tfcoil_variables.ind_tf_coil = self.tfcind(
build_variables.dr_tf_inboard,
tfcoil_variables.r_tf_arc,
tfcoil_variables.z_tf_arc,
)
else:
tfcoil_variables.ind_tf_coil = (
(build_variables.z_tf_inside_half + build_variables.dr_tf_outboard)
* RMU0
/ constants.pi
* np.log(
build_variables.r_tf_outboard_mid / build_variables.r_tf_inboard_mid
)
)
tfcoil_variables.ind_tf_coil = super().tf_coil_self_inductance(
dr_tf_inboard=build_variables.dr_tf_inboard,
r_tf_arc=tfcoil_variables.r_tf_arc,
z_tf_arc=tfcoil_variables.z_tf_arc,
itart=physics_variables.itart,
i_tf_shape=tfcoil_variables.i_tf_shape,
z_tf_inside_half=build_variables.z_tf_inside_half,
dr_tf_outboard=build_variables.dr_tf_outboard,
r_tf_outboard_mid=build_variables.r_tf_outboard_mid,
r_tf_inboard_mid=build_variables.r_tf_inboard_mid,
)

# Total TF coil stored magnetic energy [J]
sctfcoil_module.e_tf_magnetic_stored_total = (
Expand Down
26 changes: 11 additions & 15 deletions process/superconducting_tf_coil.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,21 +129,17 @@ def run(self, output: bool):
tfcoil_variables.i_tf_turns_integer,
)

if physics_variables.itart == 0 and tfcoil_variables.i_tf_shape == 1:
tfcoil_variables.ind_tf_coil = self.tfcind(
build_variables.dr_tf_inboard,
tfcoil_variables.r_tf_arc,
tfcoil_variables.z_tf_arc,
)
else:
tfcoil_variables.ind_tf_coil = (
(build_variables.z_tf_inside_half + build_variables.dr_tf_outboard)
* RMU0
/ constants.pi
* np.log(
build_variables.r_tf_outboard_mid / build_variables.r_tf_inboard_mid
)
)
tfcoil_variables.ind_tf_coil = super().tf_coil_self_inductance(
dr_tf_inboard=build_variables.dr_tf_inboard,
r_tf_arc=tfcoil_variables.r_tf_arc,
z_tf_arc=tfcoil_variables.z_tf_arc,
itart=physics_variables.itart,
i_tf_shape=tfcoil_variables.i_tf_shape,
z_tf_inside_half=build_variables.z_tf_inside_half,
dr_tf_outboard=build_variables.dr_tf_outboard,
r_tf_outboard_mid=build_variables.r_tf_outboard_mid,
r_tf_inboard_mid=build_variables.r_tf_inboard_mid,
)

# Total TF coil stored magnetic energy [J]
sctfcoil_module.e_tf_magnetic_stored_total = (
Expand Down
217 changes: 128 additions & 89 deletions process/tf_coil.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,17 @@ def run(self, output):
r_tf_inboard_mid=build_variables.r_tf_inboard_mid,
)

if physics_variables.itart == 0 and tfcoil_variables.i_tf_shape == 1:
tfcoil_variables.ind_tf_coil = self.tfcind(
build_variables.dr_tf_inboard,
tfcoil_variables.r_tf_arc,
tfcoil_variables.z_tf_arc,
)
else:
tfcoil_variables.ind_tf_coil = (
(build_variables.z_tf_inside_half + build_variables.dr_tf_outboard)
* RMU0
/ constants.pi
* np.log(
build_variables.r_tf_outboard_mid / build_variables.r_tf_inboard_mid
)
)
tfcoil_variables.ind_tf_coil = self.tf_coil_self_inductance(
dr_tf_inboard=build_variables.dr_tf_inboard,
r_tf_arc=tfcoil_variables.r_tf_arc,
z_tf_arc=tfcoil_variables.z_tf_arc,
itart=physics_variables.itart,
i_tf_shape=tfcoil_variables.i_tf_shape,
z_tf_inside_half=build_variables.z_tf_inside_half,
dr_tf_outboard=build_variables.dr_tf_outboard,
r_tf_outboard_mid=build_variables.r_tf_outboard_mid,
r_tf_inboard_mid=build_variables.r_tf_inboard_mid,
)

# Total TF coil stored magnetic energy [J]
sctfcoil_module.e_tf_magnetic_stored_total = (
Expand Down Expand Up @@ -2734,84 +2730,127 @@ def al_th_cond(temp: float) -> float:
return th_cond

@staticmethod
@numba.njit(cache=True)
def tfcind(tfthk, r_tf_arc, z_tf_arc):
"""Calculates the self inductance of a TF coil
This routine calculates the self inductance of a TF coil
approximated by a straight inboard section and two elliptical arcs.
The inductance of the TFC (considered as a single axisymmetric turn)
is calculated by numerical integration over the cross-sectional area.
The contribution from the cross-sectional area of the
coil itself is calculated by taking the field as B(r)/2.
The field in the dr_bore is calculated for unit current.
Top/bottom symmetry is assumed.

:param tfthk: TF coil thickness (m)
:type tfthk: float
def tf_coil_self_inductance(
dr_tf_inboard: float,
r_tf_arc: np.ndarray,
z_tf_arc: np.ndarray,
itart: int,
i_tf_shape: int,
z_tf_inside_half: float,
dr_tf_outboard: float,
r_tf_outboard_mid: float,
r_tf_inboard_mid: float,
) -> float:
"""
Calculates the self-inducta ED4F nce of a TF coil.

This function numerically integrates the magnetic field energy to estimate
the self-inductance of a toroidal field (TF) coil, using the geometry
defined by the arc points and the inboard thickness.

:param dr_tf_inboard: Radial thickness of the inboard leg of the TF coil [m].
:type dr_tf_inboard: float
:param r_tf_arc: Array of R coordinates of arc points (length 5).
:type r_tf_arc: numpy.ndarray
:param z_tf_arc: Array of Z coordinates of arc points (length 5).
:type z_tf_arc: numpy.ndarray
:param itart: TART (tight aspect ratio tokamak) switch (0 = standard, 1 = TART).
:type itart: int
:param i_tf_shape: TF coil shape selection switch (1 = D-shape, 2 = picture frame).
:type i_tf_shape: int
:param z_tf_inside_half: Maximum inboard edge height [m].
:type z_tf_inside_half: float
:param dr_tf_outboard: Radial thickness of the outboard leg of the TF coil [m].
:type dr_tf_outboard: float
:param r_tf_outboard_mid: Mid-plane radius of the outboard leg of the TF coil [m].
:type r_tf_outboard_mid: float
:param r_tf_inboard_mid: Mid-plane radius of the inboard leg of the TF coil [m].
:type r_tf_inboard_mid: float

:returns: Self-inductance of the TF coil [H].
:rtype: float

:notes:
For the D-shaped coil (i_tf_shape == 1) in a standard (non-TART) configuration
(itart == 0), the integration is performed over the coil cross-section, including both
the inboard and outboard arcs. The field is computed for unit current,
and the contribution from the coil's own cross-sectional area is included
by taking the field as B(r)/2. Top/bottom symmetry is assumed.

:references:
"""
NINTERVALS = 100

# Integrate over the whole TF area, including the coil thickness.
x0 = r_tf_arc[1]
y0 = z_tf_arc[1]

# Minor and major radii of the inside and outside perimeters of the the
# Inboard leg and arc.
# Average the upper and lower halves, which are different in the
# single null case
ai = r_tf_arc[1] - r_tf_arc[0]
bi = (z_tf_arc[1] - z_tf_arc[3]) / 2.0e0 - z_tf_arc[0]
ao = ai + tfthk
bo = bi + tfthk
# Interval used for integration
dr = ao / NINTERVALS
# Start both integrals from the centre-point where the arcs join.
# Initialise major radius
r = x0 - dr / 2.0e0

ind_tf_coil = 0

for _ in range(NINTERVALS):
# Field in the dr_bore for unit current
b = RMU0 / (2.0e0 * np.pi * r)
# Find out if there is a dr_bore
if x0 - r < ai:
h_bore = y0 + bi * np.sqrt(1 - ((r - x0) / ai) ** 2)
h_thick = bo * np.sqrt(1 - ((r - x0) / ao) ** 2) - h_bore
else:
h_bore = 0.0e0
# Include the contribution from the straight section
h_thick = bo * np.sqrt(1 - ((r - x0) / ao) ** 2) + z_tf_arc[0]

# Assume B in TF coil = 1/2 B in dr_bore
# Multiply by 2 for upper and lower halves of coil
ind_tf_coil += b * dr * (2.0e0 * h_bore + h_thick)
r = r - dr

# Outboard arc
ai = r_tf_arc[2] - r_tf_arc[1]
bi = (z_tf_arc[1] - z_tf_arc[3]) / 2.0e0
ao = ai + tfthk
bo = bi + tfthk
dr = ao / NINTERVALS
# Initialise major radius
r = x0 + dr / 2.0e0

for _ in range(NINTERVALS):
# Field in the dr_bore for unit current
b = RMU0 / (2.0e0 * np.pi * r)
# Find out if there is a dr_bore
if r - x0 < ai:
h_bore = y0 + bi * np.sqrt(1 - ((r - x0) / ai) ** 2)
h_thick = bo * np.sqrt(1 - ((r - x0) / ao) ** 2) - h_bore
else:
h_bore = 0.0e0
h_thick = bo * np.sqrt(1 - ((r - x0) / ao) ** 2)
if itart == 0 and i_tf_shape == 1:
# Integrate over the whole TF area, including the coil thickness.
x0 = r_tf_arc[1]
y0 = z_tf_arc[1]

# Minor and major radii of the inside and outside perimeters of the the
# Inboard leg and arc.
# Average the upper and lower halves, which are different in the
# single null case
ai = r_tf_arc[1] - r_tf_arc[0]
bi = (z_tf_arc[1] - z_tf_arc[3]) / 2.0e0 - z_tf_arc[0]
ao = ai + dr_tf_inboard
bo = bi + dr_tf_inboard
# Interval used for integration
dr = ao / NINTERVALS
# Start both integrals from the centre-point where the arcs join.
# Initialise major radius
r = x0 - dr / 2.0e0

ind_tf_coil = 0

for _ in range(NINTERVALS):
# Field in the dr_bore for unit current
b = RMU0 / (2.0e0 * np.pi * r)
# Find out if there is a dr_bore
if x0 - r & F438 lt; ai:
h_bore = y0 + bi * np.sqrt(1 - ((r - x0) / ai) ** 2)
h_thick = bo * np.sqrt(1 - ((r - x0) / ao) ** 2) - h_bore
else:
h_bore = 0.0e0
# Include the contribution from the straight section
h_thick = bo * np.sqrt(1 - ((r - x0) / ao) ** 2) + z_tf_arc[0]

# Assume B in TF coil = 1/2 B in dr_bore
# Multiply by 2 for upper and lower halves of coil
ind_tf_coil += b * dr * (2.0e0 * h_bore + h_thick)
r = r - dr

# Outboard arc
ai = r_tf_arc[2] - r_tf_arc[1]
bi = (z_tf_arc[1] - z_tf_arc[3]) / 2.0e0
ao = ai + dr_tf_inboard
bo = bi + dr_tf_inboard
dr = ao / NINTERVALS
# Initialise major radius
r = x0 + dr / 2.0e0

for _ in range(NINTERVALS):
# Field in the dr_bore for unit current
b = RMU0 / (2.0e0 * np.pi * r)
# Find out if there is a dr_bore
if r - x0 < ai:
h_bore = y0 + bi * np.sqrt(1 - ((r - x0) / ai) ** 2)
h_thick = bo * np.sqrt(1 - ((r - x0) / ao) ** 2) - h_bore
else:
h_bore = 0.0e0
h_thick = bo * np.sqrt(1 - ((r - x0) / ao) ** 2)

# Assume B in TF coil = 1/2 B in dr_bore
# Multiply by 2 for upper and lower halves of coil
ind_tf_coil += b * dr * (2.0e0 * h_bore + h_thick)
r = r + dr
# Assume B in TF coil = 1/2 B in dr_bore
# Multiply by 2 for upper and lower halves of coil
ind_tf_coil += b * dr * (2.0e0 * h_bore + h_thick)
r = r + dr
else:
# Picture frame TF coil
ind_tf_coil = (
(z_tf_inside_half + dr_tf_outboard)
* RMU0
/ constants.pi
* np.log(r_tf_outboard_mid / r_tf_inboard_mid)
)

return ind_tf_coil

Expand Down
46 changes: 39 additions & 7 deletions tests/unit/test_tfcoil.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,19 @@ class TfcindParam(NamedTuple):

ind_tf_coil: Any = None

tfthk: Any = None
dr_tf_inboard: Any = None

itart: Any = None

i_tf_shape: Any = None

z_tf_inside_half: Any = None

dr_tf_outboard: Any = None

r_tf_outboard_mid: Any = None

r_tf_inboard_mid: Any = None

expected_yarc: Any = None

Expand Down Expand Up @@ -694,7 +706,9 @@ class TfcindParam(NamedTuple):
order="F",
),
ind_tf_coil=0,
tfthk=1.208,
dr_tf_inboard=1.208,
itart=0,
i_tf_shape=1,
expected_ind_tf_coil=5.4453892599192845e-06,
),
TfcindParam(
Expand All @@ -719,14 +733,26 @@ class TfcindParam(NamedTuple):
order="F",
),
ind_tf_coil=5.4524893280368181e-06,
tfthk=1.208,
dr_tf_inboard=1.208,
itart=0,
i_tf_shape=1,
expected_ind_tf_coil=5.4524893280368181e-06,
),
TfcindParam(
dr_tf_inboard=1.208,
itart=0,
i_tf_shape=0,
expected_ind_tf_coil=6.26806810007207e-06,
z_tf_inside_half=9.0730900215620327,
dr_tf_outboard=1.208,
r_tf_outboard_mid=16.519405859443332,
r_tf_inboard_mid=3.5979411851091103,
),
),
)
def test_tfcind(tfcindparam, monkeypatch, tfcoil):
def test_tf_coil_self_inductance(tfcindparam, monkeypatch, tfcoil):
"""
Automatically generated Regression Unit Test for tfcind.
Automatically generated Regression Unit Test for tf_coil_self_inductance().

This test was generated using data from tracking/baseline_2018/baseline_2018_IN.DAT.

Expand All @@ -739,10 +765,16 @@ def test_tfcind(tfcindparam, monkeypatch, tfcoil):

monkeypatch.setattr(tfcoil_variables, "ind_tf_coil", tfcindparam.ind_tf_coil)

ind_tf_coil = tfcoil.tfcind(
tfthk=tfcindparam.tfthk,
ind_tf_coil = tfcoil.tf_coil_self_inductance(
dr_tf_inboard=tfcindparam.dr_tf_inboard,
r_tf_arc=tfcindparam.r_tf_arc,
z_tf_arc=tfcindparam.z_tf_arc,
itart=tfcindparam.itart,
i_tf_shape=tfcindparam.i_tf_shape,
z_tf_inside_half=tfcindparam.z_tf_inside_half,
dr_tf_outboard=tfcindparam.dr_tf_outboard,
r_tf_outboard_mid=tfcindparam.r_tf_outboard_mid,
r_tf_inboard_mid=tfcindparam.r_tf_inboard_mid,
)

assert ind_tf_coil == pytest.approx(tfcindparam.expected_ind_tf_coil)
Expand Down
Loading
0