Coverage for python/gsfit/database_readers/st40_spider_mdsplus/setup_plasma.py: 0%

44 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-14 15:25 +0000

1import typing 

2from typing import TYPE_CHECKING 

3 

4import gsfit_rs 

5import numpy as np 

6import numpy.typing as npt 

7from gsfit_rs import Plasma 

8 

9if TYPE_CHECKING: 

10 from . import DatabaseReader 

11 

12 

13def setup_plasma( 

14 self: "DatabaseReader", 

15 pulseNo: int, 

16 settings: dict[str, typing.Any], 

17 times_to_reconstruct: npt.NDArray[np.float64], 

18) -> Plasma: 

19 """ 

20 This method initialises the Rust `Plasma` class. 

21 

22 :param pulseNo: Pulse number, used to read from the database 

23 :param settings: Dictionary containing the JSON settings read from the `settings` directory 

24 :param times_to_reconstruct: Times the equilibrium will be solved at [second] 

25 

26 **This method is specific to ST40's experimental MDSplus database.** 

27 

28 See `python/gsfit/database_readers/interface.py` for more details on how a new database_reader should be implemented. 

29 """ 

30 

31 # Initial plasma conditions 

32 initial_guess_ip = settings["GSFIT_code_settings.json"]["initial_guess"]["ip"] 

33 initial_guess_cur_r = settings["GSFIT_code_settings.json"]["initial_guess"]["cur_r"] 

34 initial_guess_cur_z = settings["GSFIT_code_settings.json"]["initial_guess"]["cur_z"] 

35 initial_guess_minor_radius = settings["GSFIT_code_settings.json"]["initial_guess"]["minor_radius"] 

36 initial_guess_elongation = settings["GSFIT_code_settings.json"]["initial_guess"]["elongation"] 

37 

38 # Numerical settings the Grad-Shafranov solve is run with 

39 n_iter_max = settings["GSFIT_code_settings.json"]["numerics"]["n_iter_max"] 

40 n_iter_min = settings["GSFIT_code_settings.json"]["numerics"]["n_iter_min"] 

41 n_iter_no_vertical_feedback = settings["GSFIT_code_settings.json"]["numerics"]["n_iter_no_vertical_feedback"] 

42 grad_shafranov_deviation_tolerance = settings["GSFIT_code_settings.json"]["numerics"]["grad_shafranov_deviation_tolerance"] 

43 use_anderson_mixing = settings["GSFIT_code_settings.json"]["numerics"]["anderson_mixing"]["use"] 

44 anderson_mixing_from_previous_iter = settings["GSFIT_code_settings.json"]["numerics"]["anderson_mixing"]["mixing_from_previous_iter"] 

45 # The pressure at the plasma boundary. Integrating `p'` leaves the pressure defined up to a constant, which 

46 # GSFit historically fixed by demanding zero pressure at the boundary. Setting `free` makes it a degree of 

47 # freedom of the fit instead. `.get` is used so that older settings directories keep working 

48 pressure_edge_settings = settings["source_function_p_prime.json"].get( 

49 "pressure_edge", settings["GSFIT_code_settings.json"]["numerics"].get("pressure_edge", {}) 

50 ) 

51 pressure_edge_free = pressure_edge_settings.get("free", False) 

52 pressure_edge_regularisation_weight = pressure_edge_settings.get("regularisation_weight", 1.0e-4) 

53 

54 # Set the source functions types 

55 p_prime_source_function: gsfit_rs.EfitPolynomial 

56 ff_prime_source_function: gsfit_rs.EfitPolynomial 

57 

58 if settings["source_function_p_prime.json"]["method"] == "efit_polynomial": 

59 n_dof = settings["source_function_p_prime.json"]["efit_polynomial"]["n_dof"] 

60 regularisations = np.array(settings["source_function_p_prime.json"]["efit_polynomial"]["regularizations"]) 

61 # If `regularisations` is [[]] in the json file, will be interpreted by numpy as having size (1, 0). 

62 # Which would be interpreted as (n_regularisations, n_dof). So it would cause an error 

63 if regularisations.shape == (1, 0): 

64 regularisations = np.zeros((0, n_dof), dtype=np.float64) 

65 p_prime_source_function = gsfit_rs.EfitPolynomial(n_dof, regularisations) 

66 else: 

67 raise ValueError(f"Unknown method for p_prime source function: {settings['source_function_p_prime.json']['method']}") 

68 

69 if settings["source_function_ff_prime.json"]["method"] == "efit_polynomial": 

70 n_dof = settings["source_function_ff_prime.json"]["efit_polynomial"]["n_dof"] 

71 regularisations = np.array(settings["source_function_ff_prime.json"]["efit_polynomial"]["regularizations"]) 

72 # If `regularisations` is [[]] in the json file, will be interpreted by numpy as having size (1, 0). 

73 # Which would be interpreted as (n_regularisations, n_dof). So it would cause an error 

74 if regularisations.shape == (1, 0): 

75 regularisations = np.zeros((0, n_dof), dtype=np.float64) 

76 ff_prime_source_function = gsfit_rs.EfitPolynomial(n_dof, regularisations) 

77 

78 # Grid size and shape 

79 n_r = settings["GSFIT_code_settings.json"]["grid"]["n_r"] 

80 n_z = settings["GSFIT_code_settings.json"]["grid"]["n_z"] 

81 r_min = settings["GSFIT_code_settings.json"]["grid"]["r_min"] 

82 r_max = settings["GSFIT_code_settings.json"]["grid"]["r_max"] 

83 z_min = settings["GSFIT_code_settings.json"]["grid"]["z_min"] 

84 z_max = settings["GSFIT_code_settings.json"]["grid"]["z_max"] 

85 

86 # Normalised poloidal flux grid 

87 n_psi_n = settings["GSFIT_code_settings.json"]["n_psi_n"] 

88 psi_n = np.linspace(0.0, 1.0, n_psi_n).astype(np.float64) 

89 

90 # Initialise the Plasma Rust class 

91 plasma = Plasma( 

92 n_r, 

93 n_z, 

94 r_min, 

95 r_max, 

96 z_min, 

97 z_max, 

98 psi_n, # BUXTON: perhaps better to send in `n_psi_n` 

99 p_prime_source_function, 

100 ff_prime_source_function, 

101 initial_guess_ip, 

102 initial_guess_cur_r, 

103 initial_guess_cur_z, 

104 initial_guess_minor_radius, 

105 initial_guess_elongation, 

106 n_iter_max, 

107 n_iter_min, 

108 n_iter_no_vertical_feedback, 

109 grad_shafranov_deviation_tolerance, 

110 use_anderson_mixing, 

111 anderson_mixing_from_previous_iter, 

112 times_to_reconstruct, 

113 pressure_edge_free, 

114 pressure_edge_regularisation_weight, 

115 ) 

116 

117 return plasma 

118 

119 

120# import typing 

121# from typing import TYPE_CHECKING 

122 

123# import gsfit_rs 

124# import numpy as np 

125# import numpy.typing as npt 

126# from gsfit_rs import Plasma 

127# from st40_database import GetData # type: ignore[import-not-found] 

128 

129# if TYPE_CHECKING: 

130# from . import DatabaseReader 

131 

132 

133# def setup_plasma( 

134# self: "DatabaseReader", 

135# pulseNo: int, 

136# settings: dict[str, typing.Any], 

137# ) -> Plasma: 

138# """ 

139# This method initialises the Rust `Plasma` class. 

140 

141# :param pulseNo: Pulse number, used to read from the database 

142# :param settings: Dictionary containing the JSON settings read from the `settings` directory 

143 

144# **This method is specific to ST40's ASTRA stored on MDSplus.** 

145 

146# See `python/gsfit/database_readers/interface.py` for more details on how a new database_reader should be implemented. 

147# """ 

148 

149# # Initial plasma conditions 

150# initial_guess_ip = settings["GSFIT_code_settings.json"]["initial_guess"]["ip"] 

151# initial_guess_cur_r = settings["GSFIT_code_settings.json"]["initial_guess"]["cur_r"] 

152# initial_guess_cur_z = settings["GSFIT_code_settings.json"]["initial_guess"]["cur_z"] 

153 

154# # Set the source functions types 

155# p_prime_source_function: gsfit_rs.EfitPolynomial 

156# ff_prime_source_function: gsfit_rs.EfitPolynomial 

157 

158# if settings["source_function_p_prime.json"]["method"] == "efit_polynomial": 

159# n_dof = settings["source_function_p_prime.json"]["efit_polynomial"]["n_dof"] 

160# regularisations = np.array(settings["source_function_p_prime.json"]["efit_polynomial"]["regularizations"]) 

161# p_prime_source_function = gsfit_rs.EfitPolynomial(n_dof, regularisations) 

162# elif settings["source_function_p_prime.json"]["method"] == "efit_polynomial": 

163# n_dof = settings["source_function_p_prime.json"]["efit_polynomial"]["n_dof"] 

164# regularisations = np.array(settings["source_function_p_prime.json"]["efit_polynomial"]["regularizations"]) 

165# p_prime_source_function = gsfit_rs.EfitPolynomial(n_dof, regularisations) 

166# else: 

167# raise ValueError(f"Unknown method for p_prime source function: {settings['source_function_p_prime.json']['method']}") 

168 

169# if settings["source_function_ff_prime.json"]["method"] == "efit_polynomial": 

170# n_dof = settings["source_function_ff_prime.json"]["efit_polynomial"]["n_dof"] 

171# regularisations = np.array(settings["source_function_ff_prime.json"]["efit_polynomial"]["regularizations"]) 

172# ff_prime_source_function = gsfit_rs.EfitPolynomial(n_dof, regularisations) 

173# elif settings["source_function_ff_prime.json"]["method"] == "efit_polynomial": 

174# n_dof = settings["source_function_ff_prime.json"]["efit_polynomial"]["n_dof"] 

175# regularisations = np.array(settings["source_function_ff_prime.json"]["efit_polynomial"]["regularizations"]) 

176# ff_prime_source_function = gsfit_rs.EfitPolynomial(n_dof, regularisations) 

177 

178# # Grid size and shape 

179# n_r = settings["GSFIT_code_settings.json"]["grid"]["n_r"] 

180# n_z = settings["GSFIT_code_settings.json"]["grid"]["n_z"] 

181# r_min = settings["GSFIT_code_settings.json"]["grid"]["r_min"] 

182# r_max = settings["GSFIT_code_settings.json"]["grid"]["r_max"] 

183# z_min = settings["GSFIT_code_settings.json"]["grid"]["z_min"] 

184# z_max = settings["GSFIT_code_settings.json"]["grid"]["z_max"] 

185 

186# # Normalised poloidal flux grid 

187# n_psi_n = settings["GSFIT_code_settings.json"]["n_psi_n"] 

188# psi_n = np.linspace(0.0, 1.0, n_psi_n).astype(np.float64) 

189 

190# # Limiter 

191# elmag_run_name = settings["GSFIT_code_settings.json"]["database_reader"]["st40_astra_mdsplus"]["elmag_run_name"] 

192# elmag = GetData(12050, f"ELMAG#{elmag_run_name}", is_fail_quiet=False) 

193# limit_pts_r = typing.cast(npt.NDArray[np.float64], elmag.get("LIMITER.LIMIT_PTS.R")) 

194# limit_pts_z = typing.cast(npt.NDArray[np.float64], elmag.get("LIMITER.LIMIT_PTS.Z")) 

195 

196# # Vacuum vessel where the plasma is allowed to be 

197# vessel_r = limit_pts_r 

198# vessel_z = limit_pts_z 

199 

200# # Add lower MC tiles 

201# limit_pts_r = np.append(limit_pts_r, 0.7103) 

202# limit_pts_z = np.append(limit_pts_z, -0.3131) 

203# # Add upper MC tiles 

204# limit_pts_r = np.append(limit_pts_r, 0.7103) 

205# limit_pts_z = np.append(limit_pts_z, 0.3031) 

206 

207# # Initialise the Plasma Rust class 

208# plasma = Plasma( 

209# n_r, 

210# n_z, 

211# r_min, 

212# r_max, 

213# z_min, 

214# z_max, 

215# psi_n, # BUXTON: perhaps better to send in `n_psi_n` 

216# limit_pts_r, 

217# limit_pts_z, 

218# vessel_r, 

219# vessel_z, 

220# p_prime_source_function, 

221# ff_prime_source_function, 

222# initial_guess_ip, 

223# initial_guess_cur_r, 

224# initial_guess_cur_z, 

225# ) 

226 

227# return plasma