Coverage for rta_reconstruction/image_displacement.py: 28%
36 statements
« prev ^ index » next coverage.py v7.6.7, created at 2024-11-16 09:59 +0000
« prev ^ index » next coverage.py v7.6.7, created at 2024-11-16 09:59 +0000
1import astropy.units as u
2import numpy as np
4from rta_reconstruction.utils.coordinates import pol2cart, sky_to_camera
7def disp(cog_x, cog_y, src_x, src_y, hillas_psi):
8 """
9 Compute the disp parameters
11 Parameters
12 ----------
13 cog_x: `numpy.ndarray` or float
14 cog_y: `numpy.ndarray` or float
15 src_x: `numpy.ndarray` or float
16 src_y: `numpy.ndarray` or float
17 hillas_psi: `numpy.ndarray` or float
19 Returns
20 -------
21 (disp_dx, disp_dy, disp_norm, disp_angle, disp_sign):
22 disp_dx: 'astropy.units.m`
23 disp_dy: 'astropy.units.m`
24 disp_norm: 'astropy.units.m`
25 disp_angle: 'astropy.units.rad`
26 disp_sign: `numpy.ndarray`
27 """
28 disp_dx = src_x - cog_x
29 disp_dy = src_y - cog_y
31 disp_norm = disp_dx * np.cos(hillas_psi) + disp_dy * np.sin(hillas_psi)
32 disp_sign = np.sign(disp_norm)
33 disp_norm = np.abs(disp_norm)
35 # disp_sign : indicates in which direction, "positive" or "negative", we must move along the
36 # reconstructed image axis (with direction defined by the versor cos(hillas_psi), sin(hillas_psi))
37 # we must move from cog_x, cog_y to get closest to the true direction (src_x, src_y)
39 if hasattr(disp_dx, "__len__"):
40 disp_angle = np.arctan(disp_dy / disp_dx)
41 disp_angle[disp_dx == 0] = np.pi / 2.0 * np.sign(disp_dy[disp_dx == 0])
42 else:
43 if disp_dx == 0:
44 disp_angle = np.pi / 2.0 * np.sign(disp_dy)
45 else:
46 disp_angle = np.arctan(disp_dy / disp_dx)
48 return disp_dx, disp_dy, disp_norm, disp_angle, disp_sign
51def miss(disp_dx, disp_dy, hillas_psi):
52 """
53 Compute miss
55 Parameters
56 ----------
57 disp_dx: `numpy.ndarray` or float
58 disp_dy: `numpy.ndarray` or float
59 hillas_psi: `numpy.ndarray` or float
61 Returns
62 -------
64 """
65 return np.abs(np.sin(hillas_psi) * disp_dx - np.cos(hillas_psi) * disp_dy)
68def disp_vector_pol2cart(disp_norm, disp_angle, disp_sign):
69 """
70 Compute `disp_norm.dx` and `disp_norm.dy` vector from `disp_norm.norm`,
71 `disp_norm.angle` and `disp_norm.sign`
73 Parameters
74 ----------
75 disp_norm: float
76 disp_angle: float
77 disp_sign: float
79 Returns
80 -------
81 disp_dx, disp_dy
82 """
83 return np.transpose(pol2cart(disp_norm, disp_angle, disp_sign))
86def disp_to_pos(disp_dx, disp_dy, cog_x, cog_y):
87 """
88 Calculates source position in camera coordinates(x,y)
89 from the reconstructed disp.
91 Parameters
92 ----------
93 disp: DispContainer
94 cog_x: float
95 Coordinate x of the center of gravity of Hillas ellipse
96 cog_y: float
97 Coordinate y of the center of gravity of Hillas ellipse
99 Returns
100 -------
101 (source_pos_x, source_pos_y)
102 """
103 source_pos_x = cog_x + disp_dx
104 source_pos_y = cog_y + disp_dy
106 return source_pos_x, source_pos_y
109def update_disp_with_effective_focal_length(data, effective_focal_length=29.30565 * u.m):
110 """Update disp parameters using effective focal length
112 Parameters
113 ----------
114 data: Pandas DataFrame
115 config: dictionnary containing configuration
116 """
118 source_pos_in_camera = sky_to_camera(
119 u.Quantity(data["mc_alt"].values, u.rad, copy=False),
120 u.Quantity(data["mc_az"].values, u.rad, copy=False),
121 effective_focal_length,
122 u.Quantity(data["mc_alt_tel"].values, u.rad, copy=False),
123 u.Quantity(data["mc_az_tel"].values, u.rad, copy=False),
124 )
126 expected_src_pos_x_m = source_pos_in_camera.x.to_value(u.m)
127 expected_src_pos_y_m = source_pos_in_camera.y.to_value(u.m)
129 data["src_x"] = expected_src_pos_x_m
130 data["src_y"] = expected_src_pos_y_m
132 disp_dx, disp_dy, disp_norm, disp_angle, disp_sign = disp.disp(
133 data["x"].values, data["y"].values, expected_src_pos_x_m, expected_src_pos_y_m, data["psi"].values
134 )
136 data["disp_dx"] = disp_dx
137 data["disp_dy"] = disp_dy
138 data["disp_norm"] = disp_norm
139 data["disp_angle"] = disp_angle
140 data["disp_sign"] = disp_sign