Coverage for python/gsfit/database_readers/st40_spider_mdsplus/setup_coils.py: 0%
133 statements
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-14 15:25 +0000
« prev ^ index » next coverage.py v7.16.2, created at 2026-10-14 15:25 +0000
1# mypy: ignore-errors
2# TODO: need to fix mypy errors
4import typing
5from typing import TYPE_CHECKING
7import mdsthin
8import numpy as np
9import numpy.typing as npt
10from gsfit_rs import Coils
11from st40_database import GetData
13if TYPE_CHECKING:
14 from . import DatabaseReader
16# # The PF coil's are defined in the `P2.3/coil.dat` file, in the `SPIDER` GitLab repository.
17# # On `smaug2`, this file is at `/home/alexei.dnestrovskij/ASTRA_TE_user/astra_user/exp/equ/P2.3/coil.dat`
18# spider_coil_description = dict(
19# DIVT=dict(rc=0.1930, zc=0.7907, wc=0.0566, hc=0.1351, ndi=20),
20# DIVB=dict(rc=0.1930, zc=-0.7907, wc=0.0566, hc=0.1351, ndi=20),
21# BVLT=dict(rc=1.3860, zc=0.422, wc=0.11, hc=0.1156, ndi=12),
22# BVLB=dict(rc=1.3860, zc=-0.422, wc=0.11, hc=0.1156, ndi=12),
23# BVUT=dict(rc=1.0470, zc=1.0390, wc=0.0552, hc=0.1382, ndi=20),
24# BVUB=dict(rc=1.0470, zc=-1.0390, wc=0.0552, hc=0.1382, ndi=20),
25# SOL=dict(rc=0.1295, zc=0.0000, wc=0.0161, hc=1.4711, ndi=64),
26# MCT=dict(rc=0.7500, zc=0.3550, wc=0.0407, hc=0.0467, ndi=12),
27# MCB=dict(rc=0.7500, zc=-0.3550, wc=0.0407, hc=0.0467, ndi=12),
28# PSHT1=dict(rc=0.8518, zc=0.669, wc=0.007, hc=0.0232, ndi=4),
29# PSHB1=dict(rc=0.8518, zc=-0.669, wc=0.007, hc=0.0232, ndi=4),
30# PSHT2=dict(rc=0.833, zc=0.7016, wc=0.007, hc=0.0232, ndi=4),
31# PSHB2=dict(rc=0.833, zc=-0.7016, wc=0.007, hc=0.0232, ndi=4),
32# )
35# spider_coil_description = dict(
36# DIVT=dict(rc=0.1930, zc=0.7907, wc=0.0566, hc=0.1351, ndi=20),
37# DIVB=dict(rc=0.1930, zc=-0.7907, wc=0.0566, hc=0.1351, ndi=20),
38# BVLT=dict(rc=1.3860, zc=0.422, wc=0.11, hc=0.1156, ndi=12),
39# BVLB=dict(rc=1.3860, zc=-0.422, wc=0.11, hc=0.1156, ndi=12),
40# BVUT=dict(rc=1.0470, zc=1.0390, wc=0.0552, hc=0.1382, ndi=20),
41# BVUB=dict(rc=1.0470, zc=-1.0390, wc=0.0552, hc=0.1382, ndi=20),
42# SOL=dict(rc=0.1295, zc=0.0000, wc=0.0161, hc=1.4711, ndi=64),
43# MCT=dict(rc=0.7500, zc=0.3550, wc=0.0407, hc=0.0467, ndi=12),
44# MCB=dict(rc=0.7500, zc=-0.3550, wc=0.0407, hc=0.0467, ndi=12),
45# PSHT1=dict(rc=0.8518, zc=0.669, wc=0.007, hc=0.0232, ndi=4),
46# PSHB1=dict(rc=0.8518, zc=-0.669, wc=0.007, hc=0.0232, ndi=4),
47# PSHT2=dict(rc=0.833, zc=0.7016, wc=0.007, hc=0.0232, ndi=4),
48# PSHB2=dict(rc=0.833, zc=-0.7016, wc=0.007, hc=0.0232, ndi=4)
49# )
52# Taken from `https://tokamak-devlin.tokamak.local/gitlab/physics/SPIDER/-/blob/main/EFIT/coil.dat?ref_type=heads`
53spider_coil_description = dict(
54 DIVT=dict(rc=0.1930, zc=0.7907, wc=0.0566, hc=0.1351, ndi=20),
55 DIVB=dict(rc=0.1930, zc=-0.7907, wc=0.0566, hc=0.1351, ndi=20),
56 BVLT=dict(rc=1.3860, zc=0.408, wc=0.11, hc=0.1156, ndi=12),
57 BVLB=dict(rc=1.3860, zc=-0.43, wc=0.11, hc=0.1156, ndi=12),
58 BVUT=dict(rc=1.0470, zc=1.0390, wc=0.0552, hc=0.1382, ndi=20),
59 BVUB=dict(rc=1.0470, zc=-1.0390, wc=0.0552, hc=0.1382, ndi=20),
60 SOL=dict(rc=0.1295, zc=0.0000, wc=0.0161, hc=1.4711, ndi=64),
61 MCT=dict(rc=0.7500, zc=0.3550, wc=0.0407, hc=0.0467, ndi=12),
62 MCB=dict(rc=0.7500, zc=-0.3550, wc=0.0407, hc=0.0467, ndi=12),
63 PSHT1=dict(rc=0.8518, zc=0.669, wc=0.007, hc=0.0232, ndi=4),
64 PSHB1=dict(rc=0.8518, zc=-0.669, wc=0.007, hc=0.0232, ndi=4),
65 PSHT2=dict(rc=0.833, zc=0.7016, wc=0.007, hc=0.0232, ndi=4),
66 PSHB2=dict(rc=0.833, zc=-0.7016, wc=0.007, hc=0.0232, ndi=4),
67)
69# 20
70# 0.1930 0.7907 0.0566 0.1351 0.0 90.0 0.0 28 1 DIVT 1
71# 20
72# 0.1930 -0.7907 0.0566 0.1351 0.0 90.0 0.0 28 1 DIVB 2
73# 12
74# 1.3860 0.422 0.11 0.1156 0.0 90.0 0.0 16 2 BVLT 3
75# 12
76# 1.3860 -0.422 0.11 0.1156 0.0 90.0 0.0 16 2 BVLB 4
77# 20
78# 1.0470 1.0390 0.0552 0.1382 0.0 90.0 0.0 24 3 BVUT 5
79# 20
80# 1.0470 -1.0390 0.0552 0.1382 0.0 90.0 0.0 24 4 BVUB 6
81# 64
82# 0.1295 0.0000 0.0161 1.4711 0.0 90.0 0.0 190 5 CS 7
83# 12
84# 0.7500 0.3550 0.0407 0.0467 0.0 90.0 0.0 11 6 MCT 8
85# 12
86# 0.7500 -0.3550 0.0407 0.0467 0.0 90.0 0.0 11 6 MCB 9
87# 4
88# 0.8518 0.669 0.007 0.0232 0.0 120.0 0.0 4 7 PSHT1 10
89# 4
90# 0.8518 -0.669 0.007 0.0232 0.0 60.0 0.0 4 7 PSHB1 11
91# 4
92# 0.833 0.7016 0.007 0.0232 0.0 120.0 0.0 4 7 PSHT2 12
93# 4
94# 0.833 -0.7016 0.007 0.0232 0.0 60.0 0.0 4 7 PSHB2 13
97def dividing_parallograms(coil_dictionary) -> tuple[int, int]:
98 """
99 The PF coils are described as parallograms, and discretized in `SPIDER/SRC/Trecur_2.f`, in the `equil_spider_tepm` GitLab repository.
101 ```
102 SW = SQRT( NDIVA*WSIZE/HSIZE )
103 SH = SQRT( NDIVA*HSIZE/WSIZE )
104 SW = SW + 0.5
105 SH = SH + 0.5
106 C
107 NDIVW = IDINT(SW)
108 NDIVH = IDINT(SH)
109 ```
110 """
111 ndi = coil_dictionary["ndi"]
112 wc = coil_dictionary["wc"]
113 hc = coil_dictionary["hc"]
115 sw = np.sqrt(ndi * wc / hc)
116 sh = np.sqrt(ndi * hc / wc)
117 sw = sw + 0.5
118 sh = sh + 0.5
119 ndivw = int(sw)
120 ndivh = int(sh)
121 return ndivw, ndivh
124def calculate_coil_filament_positions(coil_dictionary) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
125 """
126 Calculate the coil filament positions from the coil description dictionary.
128 :param coil_dictionary: Dictionary containing the coil description
129 :return: Tuple of numpy arrays containing the r and z positions of the coil filaments
131 ```
132 C**************************************************************
133 C SUBROUTINE FOR DIVIDING OF PARALLELOGRAM
134 C ( FOR PFC CROSS-SECTION )
135 C**************************************************************
136 C INPUT DATE:
137 C ----------
138 C RC,ZC - CILINDER COORDINATES OF CENTER OF PARALLELOGRAM
139 C WC - PROJECTION OF THE FIRST SIDE OF PARALLELOGRAM
140 C ON AXIS "R" (IN METER)
141 C HC - PROJECTION OF THE SECOND SIDE OF PARALLELOGRAM
142 C ON AXIS "Z" (IN METER)
143 C AWC - ANGLE BETWEEN THE FIRST SIDE OF PARAL. AND
144 C AXIS "R" (IN DEGREES, IT MUST NOT BE EQUAL 90 ,
145 C IT MUST BE : -90 < AWC < 90 )
146 C AHC - ANGLE BETWEEN THE SECOND SIDE OF PARAL. AND
147 C AXIS "R" (IN DEGREES, IT MUST NOT BE EQUAL 0 ,
148 C IT MUST BE : 0 < AHC < 180 )
149 C CURC - CURRENT OF PARALLELOGRAM (IN MA)
150 C NDIV - APPROXIMATE NUMBER OF CELLS OF DIVIDING:
151 C NDIV=0 - A SPECIAL CASE: AUTOMATICALLY NDIVRE=1,
152 C RS(1)=RC, ZS(1)=ZC, PS=CURC
153 C IF NDIV > 0 THEN WE HAVE THE MOST TOTAL ALGORITHM OF
154 C DIVIDING
155 C IF NDIV < 0 THEN NDIVW AND NDIVH ARE CUT OFF BY ABS(NDIV)
156 C
157 C OUTPUT DATE:
158 C ----------
159 C NDIVRE - REAL NUMBER OF CELLS OF DIVIDING ( = NDIVW*NDIVH )
160 C NDIVW - NUMBER OF DIVIDING OF THE FIRST SIDE OF PARAL.
161 C NDIVH - NUMBER OF DIVIDING OF THE SECOND SIDE OF PARAL.
162 C RS(L),ZS(L) - CILINDER COORDINATES OF CENTERS OF CELLS OF DIVIDING
163 C L = 1,2,...,NDIVRE ! (IN METER)
164 C PS - CURRENT OF EVERY CELL OF DIVIDING (IN MA)
165 C VERS - VERTICAL (OR LINEAR, OR RADIUS) SIZE OF CELL CROSS-S.
166 C HORS - HORIZONTAL SIZE OF CELL CROSS-SECTION
167 C
168 C**************************************************************
169 C
170 SUBROUTINE DIVPAR( RC, ZC, WC, HC, AWC, AHC, CURC, NDIV,
171 * NDIVRE, NDIVW, NDIVH, RS, ZS, PS,
172 * VERS, HORS )
173 C
174 C
175 include 'double.inc'
176 C
177 DIMENSION RS(1), ZS(1)
178 C
179 C**************************************************************
180 SIN(X) = DSIN(X)
181 COS(X) = DCOS(X)
182 ATAN(X) = DATAN(X)
183 SQRT(X) = DSQRT(X)
184 C**************************************************************
185 C
186 IF(NDIV.EQ.0) THEN
187 NDIVW = 1
188 NDIVH = 1
189 NDIVRE = 1
190 RS(1) = RC
191 ZS(1) = ZC
192 PS = CURC
193 VERS = HC
194 HORS = WC
195 RETURN
196 END IF
197 C***************************************
198 C
199 IF(AHC.LT.0) AHC = AHC + 180.
200 C
201 IF(NDIV.GE.0) THEN
202 NDIVA = NDIV
203 ELSE
204 NDIVA = -NDIV
205 END IF
206 C***************************************
207 C PARAMETERS OF PARALLELOGRAM
208 C
209 XX = 1.
210 PI = 4.*ATAN(XX)
211 C
212 AWCR = AWC * PI /180.
213 AHCR = AHC * PI /180.
214 C
215 R0 = RC - 0.5*( WC + HC * COS(AHCR)/SIN(AHCR) )
216 Z0 = ZC - 0.5*( HC + WC * SIN(AWCR)/COS(AWCR) )
217 C
218 WSIZE = WC / COS(AWCR)
219 HSIZE = HC / SIN(AHCR)
220 C
221 WR = WC
222 WZ = WC * SIN(AWCR) / COS(AWCR)
223 HR = HC * COS(AHCR) / SIN(AHCR)
224 HZ = HC
225 C***************************************
226 C CALCULATION NDIVW, NDIVH, NDIVRE, PS
227 C
228 SW = SQRT( NDIVA*WSIZE/HSIZE )
229 SH = SQRT( NDIVA*HSIZE/WSIZE )
230 SW = SW + 0.5
231 SH = SH + 0.5
232 C
233 NDIVW = IDINT(SW)
234 NDIVH = IDINT(SH)
235 C
236 IF(NDIVW.EQ.0) NDIVW = 1
237 IF(NDIVH.EQ.0) NDIVH = 1
238 C
239 IF((NDIV.LT.0).AND.(NDIVW.GT.NDIVA)) NDIVW = NDIVA
240 IF((NDIV.LT.0).AND.(NDIVH.GT.NDIVA)) NDIVH = NDIVA
241 C
242 NDIVRE = NDIVW * NDIVH
243 PS = CURC / NDIVRE
244 C***************************************
245 C CALCULATION RS(L), ZS(L) : L = 1,2,...,NDIVRE
246 C
247 WR = WR / NDIVW
248 WZ = WZ / NDIVW
249 HR = HR / NDIVH
250 HZ = HZ / NDIVH
251 C
252 HORS = WR
253 VERS = HZ
254 C
255 RS(1) = R0 + 0.5*(WR + HR)
256 ZS(1) = Z0 + 0.5*(WZ + HZ)
257 C
258 DO 1 I=1,NDIVW
259 DO 1 J=1,NDIVH
260 L = (I-1)*NDIVH + J
261 RS(L) = RS(1) + (I-1)*WR + (J-1)*HR
262 ZS(L) = ZS(1) + (I-1)*WZ + (J-1)*HZ
263 1 CONTINUE
264 C***************************************
265 C
266 RETURN
267 END
268 ```
269 """
271 # Extract required parameters
272 rc = float(coil_dictionary["rc"]) # center R
273 zc = float(coil_dictionary["zc"]) # center Z
274 wc = float(coil_dictionary["wc"]) # projection of first side on R
275 hc = float(coil_dictionary["hc"]) # projection of second side on Z
276 # Optional angles (degrees). Default to AWC=0, AHC=90 if not provided,
277 # matching the most common cases in the coil table.
278 awc = float(coil_dictionary.get("awc", 0.0))
279 ahc = float(coil_dictionary.get("ahc", 90.0))
280 # Approximate number of cells (NDIV/NDIVA)
281 ndia = int(coil_dictionary.get("ndi", 1))
283 # Handle the special case NDIV == 0
284 if ndia == 0:
285 rs = np.array([rc], dtype=np.float64)
286 zs = np.array([zc], dtype=np.float64)
287 return rs, zs
289 # Convert angles to radians, applying the Fortran adjustment for AHC < 0
290 if ahc < 0.0:
291 ahc = ahc + 180.0
293 pi = np.pi
294 awcr = awc * pi / 180.0
295 ahcr = ahc * pi / 180.0
297 # Guard against invalid angles (avoid division by zero)
298 # In Fortran code: it assumes -90 < AWC < 90 and 0 < AHC < 180
299 # If cos(awcr) or sin(ahcr) are too close to zero, nudge slightly.
300 eps = 1e-12
301 c_aw = np.cos(awcr)
302 s_aw = np.sin(awcr)
303 s_ah = np.sin(ahcr)
304 c_ah = np.cos(ahcr)
305 if abs(c_aw) < eps:
306 c_aw = eps if c_aw >= 0 else -eps
307 if abs(s_ah) < eps:
308 s_ah = eps if s_ah >= 0 else -eps
310 # Fortran mapping
311 r0 = rc - 0.5 * (wc + hc * c_ah / s_ah)
312 z0 = zc - 0.5 * (hc + wc * s_aw / c_aw)
314 wsize = wc / c_aw
315 hsize = hc / s_ah
317 wr = wc
318 wz = wc * s_aw / c_aw
319 hr = hc * c_ah / s_ah
320 hz = hc
322 # Calculate NDIVW, NDIVH per Fortran's DIVPAR (NDIV >= 0 path)
323 sw = np.sqrt(ndia * wsize / hsize) + 0.5
324 sh = np.sqrt(ndia * hsize / wsize) + 0.5
325 ndivw = int(sw)
326 ndivh = int(sh)
327 if ndivw == 0:
328 ndivw = 1
329 if ndivh == 0:
330 ndivh = 1
332 # Real number of divided cells
333 ndivre = ndivw * ndivh
335 # Cell sizes
336 wr_cell = wr / ndivw
337 wz_cell = wz / ndivw
338 hr_cell = hr / ndivh
339 hz_cell = hz / ndivh
341 # First cell center
342 r1 = r0 + 0.5 * (wr_cell + hr_cell)
343 z1 = z0 + 0.5 * (wz_cell + hz_cell)
345 # Generate centers for all cells (Fortran order L = (I-1)*NDIVH + J)
346 rs = np.empty(ndivre, dtype=np.float64)
347 zs = np.empty(ndivre, dtype=np.float64)
348 idx = 0
349 for i in range(1, ndivw + 1):
350 for j in range(1, ndivh + 1):
351 r = r1 + (i - 1) * wr_cell + (j - 1) * hr_cell
352 z = z1 + (i - 1) * wz_cell + (j - 1) * hz_cell
353 rs[idx] = r
354 zs[idx] = z
355 idx += 1
357 return rs, zs
360def setup_coils(
361 self: "DatabaseReader",
362 settings: dict[str, typing.Any],
363 pulseNo: int,
364) -> Coils:
365 """
366 This method initialises the Rust `Coils` class.
368 :param pulseNo: Pulse number, used to read from the database
369 :param settings: Dictionary containing the JSON settings read from the `settings` directory
371 **This method is specific to ST40's SPIDER stored on MDSplus.**
373 See `python/gsfit/database_readers/interface.py` for more details on how a new database_reader should be implemented.
374 """
376 # Initialise the Coils Rust class
377 coils = Coils()
379 # Extract the spider_run_name from settings
380 spider_run_name = settings["GSFIT_code_settings.json"]["database_reader"]["st40_spider_mdsplus"]["workflow"]["spider"]["run_name"]
382 # Connect to MDSplus
383 conn = mdsthin.Connection("smaug")
384 conn.openTree("SPIDER", pulseNo)
386 # SPIDER time
387 time = conn.get(f"\\SPIDER::TOP.{spider_run_name}:TIME").data().astype(np.float64)
389 # PF coil currents
390 # ["IPL", "MC", "PSH", "DIV", "BVL", "BVUT", "BVUB", "CS"]
391 # [0, 1, 2, 3, 4, 5, 6, 7]
392 currents = conn.get(f"\\SPIDER::TOP.{spider_run_name}.COILS.PSU2PF:I").data().astype(np.float64) * 1.0e6
394 # Add BVLB PF coil
395 coil_name = "BVLB"
396 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
397 # Read in BVL PSU current, and normalise by the number of filaments
398 currents_local = currents[:, 4] * 4.0 * 4.0 / len(coil_r)
399 coils.add_pf_coil(
400 coil_name,
401 coil_r,
402 coil_z,
403 d_r=0.0 * coil_r,
404 d_z=0.0 * coil_z,
405 time=time,
406 measured=currents_local,
407 )
408 # Add BVLT PF coil
409 coil_name = "BVLT"
410 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
411 coils.add_pf_coil(
412 coil_name,
413 coil_r,
414 coil_z,
415 d_r=0.0 * coil_r,
416 d_z=0.0 * coil_z,
417 time=time,
418 measured=currents_local,
419 )
421 # Read in BVUB PSU current, and normalise by the number of filaments
422 coil_name = "BVUB"
423 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
424 currents_local = currents[:, 6] * 4.0 * 6.0 / len(coil_r)
425 coils.add_pf_coil(
426 coil_name,
427 coil_r,
428 coil_z,
429 d_r=0.0 * coil_r,
430 d_z=0.0 * coil_z,
431 time=time,
432 measured=currents_local,
433 )
435 # Read in BVUT PSU current, and normalise by the number of filaments
436 coil_name = "BVUT"
437 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
438 currents_local = currents[:, 5] * 4.0 * 6.0 / len(coil_r)
439 coils.add_pf_coil(
440 coil_name,
441 coil_r,
442 coil_z,
443 d_r=0.0 * coil_r,
444 d_z=0.0 * coil_z,
445 time=time,
446 measured=currents_local,
447 )
449 # Read in SOL PSU current, and normalise by the number of filaments
450 coil_name = "SOL"
451 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
452 currents_local = currents[:, 7] * 2.0 * 95.0 / len(coil_r)
453 coils.add_pf_coil(
454 coil_name,
455 coil_r,
456 coil_z,
457 d_r=0.0 * coil_r,
458 d_z=0.0 * coil_z,
459 time=time,
460 measured=currents_local,
461 )
463 # Add DIVT PF coil, and normalise by the number of filaments
464 coil_name = "DIVT"
465 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
466 currents_local = currents[:, 3] * 4.0 * 7.0 / len(coil_r)
467 coils.add_pf_coil(
468 coil_name,
469 coil_r,
470 coil_z,
471 d_r=0.0 * coil_r,
472 d_z=0.0 * coil_z,
473 time=time,
474 measured=currents_local,
475 )
476 # Add DIVB PF coil
477 coil_name = "DIVB"
478 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
479 coils.add_pf_coil(
480 coil_name,
481 coil_r,
482 coil_z,
483 d_r=0.0 * coil_r,
484 d_z=0.0 * coil_z,
485 time=time,
486 measured=currents_local,
487 )
489 # Add MCT PF coil, and normalise by the number of filaments
490 coil_name = "MCT"
491 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
492 currents_local = currents[:, 1] * 11.0 / len(coil_r)
493 coils.add_pf_coil(
494 coil_name,
495 coil_r,
496 coil_z,
497 d_r=0.0 * coil_r,
498 d_z=0.0 * coil_z,
499 time=time,
500 measured=currents_local,
501 )
502 # Add MCB PF coil
503 coil_name = "MCB"
504 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
505 coils.add_pf_coil(
506 coil_name,
507 coil_r,
508 coil_z,
509 d_r=0.0 * coil_r,
510 d_z=0.0 * coil_z,
511 time=time,
512 measured=currents_local,
513 )
515 # Add PSHT PF coil
516 coil_name = "PSHT1"
517 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
518 currents_local = currents[:, 2] * 4.0 / len(coil_r)
519 coils.add_pf_coil(
520 coil_name,
521 coil_r,
522 coil_z,
523 d_r=0.0 * coil_r,
524 d_z=0.0 * coil_z,
525 time=time,
526 measured=currents_local,
527 )
528 # Add PSHB PF coil
529 coil_name = "PSHB1"
530 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
531 coils.add_pf_coil(
532 coil_name,
533 coil_r,
534 coil_z,
535 d_r=0.0 * coil_r,
536 d_z=0.0 * coil_z,
537 time=time,
538 measured=currents_local,
539 )
540 # Add PSHT2 PF coil
541 coil_name = "PSHT2"
542 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
543 coils.add_pf_coil(
544 coil_name,
545 coil_r,
546 coil_z,
547 d_r=0.0 * coil_r,
548 d_z=0.0 * coil_z,
549 time=time,
550 measured=currents_local,
551 )
552 # Add PSHB2 PF coil
553 coil_name = "PSHB2"
554 coil_r, coil_z = calculate_coil_filament_positions(spider_coil_description[coil_name])
555 coils.add_pf_coil(
556 coil_name,
557 coil_r,
558 coil_z,
559 d_r=0.0 * coil_r,
560 d_z=0.0 * coil_z,
561 time=time,
562 measured=currents_local,
563 )
565 return coils