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