Skip to content

Commit 54612af

Browse files
Magnet solenoid tools (#2304)
* add solenoid tools file * first pass max field * first pass hoop stress * flake8 * max flux * rename * docstrings * axial stress start * replace estimate with calculation * remove temp scaffolding * flake8 * add test * flkae8 * add livingstone test
1 parent c89c15c commit 54612af

File tree

2 files changed

+230
-0
lines changed

2 files changed

+230
-0
lines changed

bluemira/magnets/solenoid_tools.py

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# bluemira is an integrated inter-disciplinary design tool for future fusion
2+
# reactors. It incorporates several modules, some of which rely on other
3+
# codes, to carry out a range of typical conceptual fusion reactor design
4+
# activities.
5+
#
6+
# Copyright (C) 2021-2023 M. Coleman, J. Cook, F. Franza, I.A. Maione, S. McIntosh,
7+
# J. Morris, D. Short
8+
#
9+
# bluemira is free software; you can redistribute it and/or
10+
# modify it under the terms of the GNU Lesser General Public
11+
# License as published by the Free Software Foundation; either
12+
# version 2.1 of the License, or (at your option) any later version.
13+
#
14+
# bluemira is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
# Lesser General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU Lesser General Public
20+
# License along with bluemira; if not, see <https://www.gnu.org/licenses/>.
21+
22+
"""
23+
Tools for simple solenoid calculations.
24+
"""
25+
26+
from typing import Tuple
27+
28+
import numpy as np
29+
30+
from bluemira.magnetostatics.semianalytic_2d import semianalytic_Bx, semianalytic_Bz
31+
32+
33+
def calculate_B_max(
34+
rho_j: float, r_inner: float, r_outer: float, height: float, z_0: float = 0.0
35+
) -> float:
36+
"""
37+
Calculate the maximum self-field in a solenoid. This is always located
38+
at (r_inner, z_0)
39+
40+
Parameters
41+
----------
42+
rho_j:
43+
Current density across the solenoid winding pack [A/m^2]
44+
r_inner:
45+
Solenoid inner radius [m]
46+
r_outer:
47+
Solenoid outer radius [m]
48+
height:
49+
Solenoid vertical extent [m]
50+
51+
Returns
52+
-------
53+
Maximum field in a solenoid [T]
54+
55+
Notes
56+
-----
57+
Cross-checked graphically with k data from Boom and Livingstone, "Superconducting
58+
solenoids", 1962, Fig. 6
59+
"""
60+
dxc = 0.5 * (r_outer - r_inner)
61+
xc = r_inner + dxc
62+
dzc = 0.5 * height
63+
x_bmax = r_inner
64+
current = rho_j * (height * (r_outer - r_inner))
65+
Bx_max = current * semianalytic_Bx(xc, z_0, x_bmax, z_0, dxc, dzc)
66+
Bz_max = current * semianalytic_Bz(xc, z_0, x_bmax, z_0, dxc, dzc)
67+
return np.hypot(Bx_max, Bz_max)
68+
69+
70+
def calculate_hoop_radial_stress(
71+
B_in: float,
72+
B_out: float,
73+
rho_j: float,
74+
r_inner: float,
75+
r_outer: float,
76+
r: float,
77+
poisson_ratio: float = 0.3,
78+
) -> Tuple[float]:
79+
"""
80+
Calculate the hoop and radial stress at a radial location in a solenoid
81+
82+
Parameters
83+
----------
84+
B_in:
85+
Field at the inside edge of the solenoid [T]
86+
B_out:
87+
Field at the outside edge of the solenoid [T]
88+
rho_j:
89+
Current density across the solenoid winding pack [A/m^2]
90+
r_inner:
91+
Solenoid inner radius [m]
92+
r_outer:
93+
Solenoid outer radius [m]
94+
r:
95+
Radius at which to calculate [m]
96+
poisson_ratio:
97+
Poisson ratio of the material
98+
99+
Returns
100+
-------
101+
hoop_stress:
102+
Hoop stress at the radial location [Pa]
103+
radial_stress:
104+
Radial stress at the radial location [Pa]
105+
106+
Notes
107+
-----
108+
Wilson, Superconducting Magnets, 1982, equations 4.10 and 4.11
109+
Must still factor in the fraction of load-bearing material
110+
"""
111+
alpha = r_outer / r_inner
112+
eps = r / r_inner
113+
nu = poisson_ratio
114+
alpha2 = alpha**2
115+
eps2 = eps**2
116+
ratio2 = alpha2 / eps2
117+
118+
K = (alpha * B_in - B_out) * rho_j * r_inner / (alpha - 1) # noqa: N806
119+
M = (B_in - B_out) * rho_j * r_inner / (alpha - 1) # noqa: N806
120+
a = K * (2 + nu) / (3 * (alpha + 1))
121+
c = M * (3 + nu) / 8
122+
123+
b = alpha2 + alpha + 1
124+
b1 = ratio2 - eps * (1 + 2 * nu) * (alpha + 1) / (2 + nu)
125+
b2 = -ratio2 - eps * (alpha + 1)
126+
127+
d = alpha2 + 1 + ratio2 - eps2 * (1 + 3 * nu) / (3 + nu)
128+
e = alpha2 + 1 - ratio2 - eps2
129+
130+
hoop_stress = a * (b + b1) - c * d
131+
radial_stress = a * (b + b2) - c * e
132+
133+
return hoop_stress, radial_stress
134+
135+
136+
def calculate_flux_max(B_max: float, r_inner: float, r_outer: float) -> float:
137+
"""
138+
Calculate the maximum flux achievable from a solenoid
139+
140+
Parameters
141+
----------
142+
B_max:
143+
Maximum field in the solenoid [T]
144+
r_inner:
145+
Solenoid inner radius [m]
146+
r_outer:
147+
Solenoid outer radius [m]
148+
149+
Returns
150+
-------
151+
Maximum flux achievable from a solenoid [V.s]
152+
"""
153+
return np.pi / 3 * B_max * (r_outer**2 + r_inner**2 + r_outer * r_inner)
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# bluemira is an integrated inter-disciplinary design tool for future fusion
2+
# reactors. It incorporates several modules, some of which rely on other
3+
# codes, to carry out a range of typical conceptual fusion reactor design
4+
# activities.
5+
#
6+
# Copyright (C) 2021-2023 M. Coleman, J. Cook, F. Franza, I.A. Maione, S. McIntosh,
7+
# J. Morris, D. Short
8+
#
9+
# bluemira is free software; you can redistribute it and/or
10+
# modify it under the terms of the GNU Lesser General Public
11+
# License as published by the Free Software Foundation; either
12+
# version 2.1 of the License, or (at your option) any later version.
13+
#
14+
# bluemira is distributed in the hope that it will be useful,
15+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17+
# Lesser General Public License for more details.
18+
#
19+
# You should have received a copy of the GNU Lesser General Public
20+
# License along with bluemira; if not, see <https://www.gnu.org/licenses/>.
21+
22+
23+
import numpy as np
24+
import pytest
25+
26+
from bluemira.base.constants import MU_0
27+
from bluemira.magnetostatics.semianalytic_2d import semianalytic_Bx, semianalytic_Bz
28+
from bluemira.magnets.solenoid_tools import calculate_B_max, calculate_hoop_radial_stress
29+
30+
31+
class TestHoopRadialStress:
32+
def test_radial_boundary_conditions(self):
33+
x, z = 4, 0
34+
dx, dz = 0.25, 0.8
35+
rho_j = 1e6
36+
nu = 0.3
37+
current = rho_j * (4 * dx * dz)
38+
Bx_in = current * semianalytic_Bx(x - dx, z, x, z, dx, dz)
39+
Bz_in = current * semianalytic_Bz(x - dx, z, x, z, dx, dz)
40+
B_in = np.hypot(Bx_in, Bz_in)
41+
Bx_out = current * semianalytic_Bx(x + dx, z, x, z, dx, dz)
42+
Bz_out = current * semianalytic_Bz(x + dx, z, x, z, dx, dz)
43+
B_out = np.hypot(Bx_out, Bz_out)
44+
sigma_theta_in, sigma_r_in = calculate_hoop_radial_stress(
45+
B_in, B_out, rho_j, x - dx, x + dx, x - dx, nu
46+
)
47+
np.testing.assert_almost_equal(sigma_r_in, 0.0)
48+
sigma_theta_out, sigma_r_out = calculate_hoop_radial_stress(
49+
B_in, B_out, rho_j, x - dx, x + dx, x + dx, nu
50+
)
51+
np.testing.assert_almost_equal(sigma_r_out, 0.0)
52+
assert sigma_theta_in > sigma_theta_out
53+
54+
55+
class TestCalculateBmax:
56+
@pytest.mark.parametrize(
57+
"alpha,beta,k_expected",
58+
[[1.375, 1.2, 1.12], [1.322, 1.5, 1.07], [1.287, 2.0, 1.03]],
59+
)
60+
def test_Bmax(self, alpha, beta, k_expected):
61+
"""
62+
Expected values from Boom and Livingstone, 1962, Example 4 table (unlabelled)
63+
"""
64+
r_inner = 3
65+
r_outer = alpha * r_inner
66+
dz = beta * r_inner
67+
rho_j = 1e6
68+
B_max = calculate_B_max(rho_j, r_inner, r_outer, 2 * dz, 0)
69+
B_0 = (
70+
rho_j
71+
* r_inner
72+
* MU_0
73+
* beta
74+
* np.log((alpha + np.hypot(alpha, beta)) / (1 + np.hypot(1, beta)))
75+
)
76+
k_calc = B_max / B_0
77+
np.testing.assert_almost_equal(k_calc, k_expected, decimal=2)

0 commit comments

Comments
 (0)