Coverage for python/gsfit/database_readers/freegsnke/setup_pressure_sensors.py: 32%

34 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 numpy as np 

5import numpy.typing as npt 

6from freegsnke.equilibrium_update import Equilibrium as FreeGsnkeEquilibrium 

7from gsfit_rs import Pressure 

8 

9if TYPE_CHECKING: 

10 from . import DatabaseReader 

11 

12 

13def setup_pressure_sensors( 

14 self: "DatabaseReader", 

15 pulseNo: int, 

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

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

18 freegsnke_eqs: list[FreeGsnkeEquilibrium], 

19) -> Pressure: 

20 """ 

21 This method initialises the Rust `Pressure` class using synthetic pressure sensors, 

22 generated from the FreeGSNKE "truth" equilibrium. 

23 

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

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

26 :param time: Measured time vector 

27 :param freegsnke_eqs: List of FreeGSNKE equilibrium objects, one for each time-slice 

28 

29 The pressure sensors are only added when `sensor_weights_pressure.json["include"]` is `True`. 

30 Synthetic sensors are placed along the outboard midplane (at the magnetic axis height), 

31 from `synthetic.r_start` to `synthetic.r_end` [metre], measured relative to the magnetic axis 

32 radius. The measured pressure at each sensor is read directly from the FreeGSNKE equilibrium's 

33 `pressure(psi_n)` profile, so it is a "perfect" synthetic measurement (no noise added). 

34 Sensors landing outside the last closed flux surface, where the pressure is (by definition) 

35 below `synthetic.minimum_pressure` [pascal], are discarded. 

36 

37 **This method is specific to FreeGSNKE.** 

38 

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

40 """ 

41 

42 # Initialise the Pressure Rust class 

43 pressure = Pressure() 

44 

45 pressure_settings = settings["sensor_weights_pressure.json"] 

46 

47 # Pressure sensors are opt-in 

48 if not pressure_settings.get("include", False): 

49 return pressure 

50 

51 synthetic_settings = pressure_settings["synthetic"] 

52 sensor_r_start: float = synthetic_settings["r_start"] 

53 sensor_r_end: float = synthetic_settings["r_end"] 

54 n_sensors: int = synthetic_settings["n_sensors"] 

55 minimum_pressure: float = synthetic_settings["minimum_pressure"] 

56 

57 sensor_name_prefix = pressure_settings["sensor_name_prefix"] 

58 fit_settings_comment = pressure_settings["fit_settings"]["comment"] 

59 fit_settings_weight = pressure_settings["fit_settings"]["weight"] 

60 

61 n_time: int = len(time) 

62 

63 # We assume the sensor geometry is not changing in time, so we use the first time-slice 

64 mag_r: float = freegsnke_eqs[0].Rmagnetic() 

65 mag_z: float = freegsnke_eqs[0].Zmagnetic() 

66 sensors_geometry_r: npt.NDArray[np.float64] = mag_r + np.linspace(sensor_r_start, sensor_r_end, n_sensors) 

67 sensors_geometry_z: npt.NDArray[np.float64] = np.full(n_sensors, mag_z) 

68 

69 # Get the "measured" pressure at each sensor, for each time-slice 

70 pressure_measured = np.full((n_time, n_sensors), np.nan) 

71 for i_time in range(n_time): 

72 psi_n_sensors = freegsnke_eqs[i_time].psiNRZ(sensors_geometry_r, sensors_geometry_z) 

73 pressure_measured[i_time, :] = freegsnke_eqs[i_time].pressure(psi_n_sensors) 

74 

75 for i_sensor in range(n_sensors): 

76 measured = pressure_measured[:, i_sensor].copy() 

77 

78 # Ignore (set to NaN) any non-physical / below-threshold measurements, e.g. sensors 

79 # which landed outside the last closed flux surface 

80 measured[measured <= minimum_pressure] = np.nan 

81 

82 # Only add the sensor if it has at least one valid measurement 

83 if np.any(~np.isnan(measured)): 

84 pressure.add_sensor( 

85 name=f"{sensor_name_prefix}{i_sensor + 1:02d}", 

86 geometry_r=sensors_geometry_r[i_sensor], 

87 geometry_z=sensors_geometry_z[i_sensor], 

88 fit_settings_comment=fit_settings_comment, 

89 fit_settings_expected_value=float(np.nanmax(measured)), 

90 fit_settings_include=True, 

91 fit_settings_weight=fit_settings_weight, 

92 time=time, 

93 measured=measured, 

94 ) 

95 

96 return pressure