9 """Create a circular pupil.
11 AUTHORS : Axel Pottier, Johan Mazoyer
12 7/9/22 Modified by J Mazoyer to remove the pixel crenellation with rebin and add a better center option
17 Size of the image (in pixels)
19 Size of the pupil radius (in pixels)
20 center_pos : string (optional, default 'b')
21 Option for the center pixel.
22 If 'p', center on the pixel dim_pp//2.
23 If 'b', center in between pixels dim_pp//2 -1 and dim_pp//2, for 'dim_pp' odd or even.
27 pupilnormal : 2D array
31 xx, yy = np.meshgrid(np.arange(dim_pp) - dim_pp // 2, np.arange(dim_pp) - dim_pp // 2)
33 if center_pos.lower() ==
'b':
35 elif center_pos.lower() ==
'p':
38 raise ValueError(
"center_pos must be 'p' (centered on pixel) or 'b' (centered in between 4 pixels)")
40 rr = np.hypot(yy + offset, xx + offset)
41 pupilnormal = np.zeros((dim_pp, dim_pp))
42 pupilnormal[rr <= prad] = 1.0
47 """Create a classical Lyot coronagraph of radius rad_LyotFP.
49 AUTHOR : Johan Mazoyer
53 ClassicalLyotFPM_allwl : list of 2D numpy arrays
54 The FP masks at all wavelengths.
57 rad_LyotFP_pix = rad_lyot_fpm * Lyot_fpm_sampling
58 ClassicalLyotFPM = 1. -
roundpupil(dim_fpm, rad_LyotFP_pix)
60 ClassicalLyotFPM_allwl = []
62 ClassicalLyotFPM_allwl.append(ClassicalLyotFPM)
64 return ClassicalLyotFPM_allwl
71 def make_VLT_pupil(pupdiam, centralobs = 0.14, spiders = 0.00625, spiders_bool = True, centralobs_bool = True):
74 based on make_VLT function from shesha/shesha/util/make_pupil.py
77 pupdiam (int) [pixel] : pupil diameter
79 centralobs (float, optional) [fraction of diameter] : central obtruction diameter, default = 0.14
81 spiders (float, optional) [fraction of diameter] : spider diameter, default = 0.00625
83 spiders_bool (bool, optional) : if False, return the VLT pupil without spiders; default = True
85 centralobs_bool (bool, optional) : if False, return the VLT pupil without central obstruction; default = True
88 VLT_pupil (2D array) : VLT transmission pupil of shape (pupdiam, pupdiam), filled with 0 and 1
90 range = (0.5 * (1) - 0.25 / pupdiam)
91 X = np.tile(np.linspace(-range, range, pupdiam, dtype=np.float32), (pupdiam, 1))
92 R = np.sqrt(X**2 + (X.T)**2)
95 VLT_pupil = ((R < 0.5) & (R > (centralobs / 2))).astype(np.float32)
96 elif centralobs_bool ==
False :
97 VLT_pupil = (R < 0.5).astype(np.float32)
100 angle = 50.5 * np.pi / 180.
102 if pupdiam % 2 == 0 :
105 (X - centralobs / 2 + spiders / np.sin(angle)) * np.tan(angle)) +
106 (X.T < (X - centralobs / 2) * np.tan(angle))) * (X > 0) * (X.T > 0)
107 elif pupdiam % 2 == 1 :
110 (X - centralobs / 2 + spiders / np.sin(angle)) * np.tan(angle)) +
111 (X.T < (X - centralobs / 2) * np.tan(angle))) * (X >= 0) * (X.T >= 0)
112 spiders_map += np.fliplr(spiders_map)
113 spiders_map += np.flipud(spiders_map)
114 VLT_pupil = VLT_pupil * spiders_map
120 Compute the transmission radial profile of the SPHERE APO1 apodizer.
121 x is the radial coordinate inside the pupil
122 x = 0 at the center of the pupil and x = 1 on the outer edge
123 This profile has been estimated with a five order polynomial fit.
124 Don't go inside the central obstruction, namely x < 0.14,
125 as the fit is no longer reliable.
130 distance to the pupil center, in fraction of the pupil radius
134 profile : float or array
135 corresponding transmission
137 a = 0.16544446129778326
138 b = 4.840243632913415
139 c = -12.02291052479871
140 d = 7.549499000031292
141 e = -1.031115714037546
142 f = 0.8227341447351052
143 profile = a * x**5 + b * x**4 + c * x**3 + d * x**2 + e * x + f
146 def make_sphere_apodizer(pupdiam, centralobs = 0.14, radial_profile = sphere_apodizer_radial_profile):
148 Return the SPHERE APLC apodizer APO1, based on its radial transmission profile
150 can be used with any profile, assuming that the radial coordinates is 0 at center
151 and 1 at the outer edge pixel
154 pupdiam (int) [pixel] : pupil diameter
156 centralobs (float, optional) [fraction of diameter] : central obtruction diameter
158 radialProfile (function, optional) : apodizer radial transmission; default is SPHERE APO1 apodizer
161 apodizer (2D array) : apodizer transmission pupil
164 pup =
make_VLT_pupil(pupdiam, centralobs = centralobs, spiders = 0, spiders_bool =
False, centralobs_bool =
True)
167 X = np.tile(np.linspace(-1, 1, pupdiam, dtype=np.float32), (pupdiam, 1))
168 R = np.sqrt(X**2 + (X.T)**2)
169 apodizer = pup*radial_profile(R)
175 add_centralobs = 7.3/100,
176 add_spiders = 3.12/100,
177 add_outer_edge_obs = 1.8/100):
179 Return the SPHERE Lyot stop
181 default values of additional central obstruction, spiders size and
182 outer edge obstruction have been estimated by eye on the real lyot stop
183 WARNING : this lyot stop does not feature the dead actuators patches
186 pupdiam (int) [pixel] : pupil diameter
188 centralobs (float, optional) [fraction of diameter] : central obstruction diameter
190 spiders (float, optional) [fraction of diameter] : spider diameter
192 add_centralobs (float, optional) [fraction of diameter] : additional diameter of central obstruction
194 add_spiders (float, optional) [fraction of diameter] : additional diameter of spiders obstruction
196 add_outer_edge_obs (float, optional) [fraction of diameter] : outer edge obstruction size
199 lyotStop (2D array) : Sphere lyot Stop transmission pupil of shape (pupdiam, pupdiam), filled with 0 and 1
201 lyotCentralObs = centralobs + add_centralobs
204 X = np.tile(np.linspace(-range, range, pupdiam, dtype=np.float32), (pupdiam, 1))
205 R = np.sqrt(X**2 + (X.T)**2)
206 lyotCentralMap = ((R < 0.5) & (R > (lyotCentralObs / 2))).astype(np.float32)
208 angle = 50.5 * np.pi / 180.
209 if pupdiam % 2 == 0 :
211 (X.T > (X - centralobs / 2 + (spiders + add_spiders / 2) / np.sin(angle)) * np.tan(angle)) +
212 (X.T < (X - centralobs / 2 - add_spiders / 2 / np.sin(angle)) * np.tan(angle))
213 ) * (X > 0) * (X.T > 0)
214 elif pupdiam % 2 == 1 :
216 (X.T > (X - centralobs / 2 + (spiders + add_spiders / 2) / np.sin(angle)) * np.tan(angle)) +
217 (X.T < (X - centralobs / 2 - add_spiders / 2 / np.sin(angle)) * np.tan(angle))
218 ) * (X >= 0) * (X.T >= 0)
219 lyotSpidersMap += np.fliplr(lyotSpidersMap)
220 lyotSpidersMap += np.flipud(lyotSpidersMap)
222 X = np.tile(np.linspace(-range, range, pupdiam, dtype=np.float32), (pupdiam, 1))
223 R = np.sqrt(X**2 + (X.T)**2)
224 lyotOuterEdge = (R < 0.5 - add_outer_edge_obs)
226 lyotStop = lyotCentralMap*lyotSpidersMap*lyotOuterEdge
234 def ring(center, radius_min, radius_max, shape):
235 """ Returns a ring mask
238 center: (float or (float, float)): center of the ring in pixel
240 radius_min: (float): internal radius in pixel
242 radius_max: (float): external radius in pixel
244 shape: (int or (int, int)): shape of the image in pixel
247 mask (boolean 2D array) : image of boolean, filled
248 with False outside the ring and True inside
250 if np.isscalar(shape):
251 shape = (shape, shape)
252 if np.isscalar(center):
253 center = (center, center)
254 mask = np.full(shape,
False)
255 xx, yy = np.meshgrid(np.arange(shape[0]) - center[0], np.arange(shape[1]) - center[1])
256 rr = np.hypot(xx, yy)
257 mask = np.logical_and((radius_min <= rr), (rr <= radius_max))
261 """ Computes average, standard deviation, minimum and maximum
262 over rings at several distances from the center of the image.
264 A ring includes the pixels between the following radiuses :
265 r_min + k * width - width / 2 and r_min + k * width + width / 2,
266 with k = 0, 1, 2... until r_min + k * width > r_max (excluded).
269 image: (2D array): the coronagraphic image
271 center: (float or (float, float)): center of the coronagraphic image in pixel
273 r_min: (float): radius of the first ring in pixel
275 r_max: (float): maximum radius in pixel
277 width: (float): width of one ring in pixel
280 distances: (1D array): distances in pixel
282 mean: (1D array): corresponding averages
284 std: (1D array): corresponding standard deviations
286 mini: (1D array): corresponding minimums
288 maxi: (1D array): corresponding maximums
291 distances = np.arange(r_min, r_max, width)
296 for radius
in distances:
297 mask =
ring(center, radius - width / 2, radius + width / 2, image.shape)
299 mean.append(np.mean(values))
300 std.append(np.std(values))
301 mini.append(np.min(values))
302 maxi.append(np.max(values))
303 mean = np.array(mean)
305 mini = np.array(mini)
306 maxi = np.array(maxi)
307 return distances, mean, std, mini, maxi
def compute_contrast(image, center, r_min, r_max, width)
Computes average, standard deviation, minimum and maximum over rings at several distances from the ce...
def sphere_apodizer_radial_profile(x)
Compute the transmission radial profile of the SPHERE APO1 apodizer.
def make_VLT_pupil(pupdiam, centralobs=0.14, spiders=0.00625, spiders_bool=True, centralobs_bool=True)
Return a VLT pupil based on make_VLT function from shesha/shesha/util/make_pupil.py.
def make_sphere_apodizer(pupdiam, centralobs=0.14, radial_profile=sphere_apodizer_radial_profile)
Return the SPHERE APLC apodizer APO1, based on its radial transmission profile.
def make_sphere_lyot_stop(pupdiam, centralobs=0.14, spiders=0.00625, add_centralobs=7.3/100, add_spiders=3.12/100, add_outer_edge_obs=1.8/100)
Return the SPHERE Lyot stop.
def classical_lyot_fpm(rad_lyot_fpm, dim_fpm, Lyot_fpm_sampling, wav_vec)
Create a classical Lyot coronagraph of radius rad_LyotFP.
def roundpupil(dim_pp, prad, center_pos='b')
Create a circular pupil.
def ring(center, radius_min, radius_max, shape)
Returns a ring mask.