Coverage for python/lsst/sims/featureScheduler/basis_functions/mask_basis_funcs.py : 24%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1import numpy as np
2import healpy as hp
3from lsst.sims.utils import _hpid2RaDec, Site, _angularSeparation, _xyz_from_ra_dec
4import matplotlib.pylab as plt
5from lsst.sims.featureScheduler.basis_functions import Base_basis_function
6from lsst.sims.featureScheduler.utils import hp_in_lsst_fov, int_rounded
9__all__ = ['Zenith_mask_basis_function', 'Zenith_shadow_mask_basis_function',
10 'Moon_avoidance_basis_function', 'Map_cloud_basis_function',
11 'Planet_mask_basis_function', 'Mask_azimuth_basis_function']
14class Zenith_mask_basis_function(Base_basis_function):
15 """Just remove the area near zenith.
17 Parameters
18 ----------
19 min_alt : float (20.)
20 The minimum possible altitude (degrees)
21 max_alt : float (82.)
22 The maximum allowed altitude (degrees)
23 """
24 def __init__(self, min_alt=20., max_alt=82.):
25 super(Zenith_mask_basis_function, self).__init__()
26 self.update_on_newobs = False
27 self.min_alt = np.radians(min_alt)
28 self.max_alt = np.radians(max_alt)
29 self.result = np.empty(hp.nside2npix(self.nside), dtype=float).fill(self.penalty)
31 def _calc_value(self, conditions, indx=None):
33 result = self.result.copy()
34 alt_limit = np.where((int_rounded(conditions.alt) > int_rounded(self.min_alt)) &
35 (int_rounded(conditions.alt) < int_rounded(self.max_alt)))[0]
36 result[alt_limit] = 1
37 return result
40class Planet_mask_basis_function(Base_basis_function):
41 """Mask the bright planets
43 Parameters
44 ----------
45 mask_radius : float (3.5)
46 The radius to mask around a planet (degrees).
47 planets : list of str (None)
48 A list of planet names to mask. Defaults to ['venus', 'mars', 'jupiter']. Not including
49 Saturn because it moves really slow and has average apparent mag of ~0.4, so fainter than Vega.
51 """
52 def __init__(self, mask_radius=3.5, planets=None, nside=None, scale=1e5):
53 super(Planet_mask_basis_function, self).__init__(nside=nside)
54 if planets is None:
55 planets = ['venus', 'mars', 'jupiter']
56 self.planets = planets
57 self.mask_radius = np.radians(mask_radius)
58 self.result = np.zeros(hp.nside2npix(nside))
59 # set up a kdtree. Could maybe use healpy.query_disc instead.
60 self.in_fov = hp_in_lsst_fov(nside=nside, fov_radius=mask_radius, scale=scale)
62 def _calc_value(self, conditions, indx=None):
63 result = self.result.copy()
64 for pn in self.planets:
65 indices = self.in_fov(conditions.planet_positions[pn+'_RA'], conditions.planet_positions[pn+'_dec'])
66 result[indices] = np.nan
68 return result
71class Zenith_shadow_mask_basis_function(Base_basis_function):
72 """Mask the zenith, and things that will soon pass near zenith. Useful for making sure
73 observations will not be too close to zenith when they need to be observed again (e.g. for a pair).
75 Parameters
76 ----------
77 min_alt : float (20.)
78 The minimum alititude to alow. Everything lower is masked. (degrees)
79 max_alt : float (82.)
80 The maximum altitude to alow. Everything higher is masked. (degrees)
81 shadow_minutes : float (40.)
82 Mask anything that will pass through the max alt in the next shadow_minutes time. (minutes)
83 """
84 def __init__(self, nside=None, min_alt=20., max_alt=82.,
85 shadow_minutes=40., penalty=np.nan, site='LSST'):
86 super(Zenith_shadow_mask_basis_function, self).__init__(nside=nside)
87 self.update_on_newobs = False
89 self.penalty = penalty
91 self.min_alt = np.radians(min_alt)
92 self.max_alt = np.radians(max_alt)
93 self.ra, self.dec = _hpid2RaDec(nside, np.arange(hp.nside2npix(nside)))
94 self.shadow_minutes = np.radians(shadow_minutes/60. * 360./24.)
95 # Compute the declination band where things could drift into zenith
96 self.decband = np.zeros(self.dec.size, dtype=float)
97 self.zenith_radius = np.radians(90.-max_alt)/2.
98 site = Site(name=site)
99 self.lat_rad = site.latitude_rad
100 self.lon_rad = site.longitude_rad
101 self.decband[np.where((int_rounded(self.dec) < int_rounded(self.lat_rad+self.zenith_radius)) &
102 (int_rounded(self.dec) > int_rounded(self.lat_rad-self.zenith_radius)))] = 1
104 self.result = np.empty(hp.nside2npix(self.nside), dtype=float)
105 self.result.fill(self.penalty)
107 def _calc_value(self, conditions, indx=None):
109 result = self.result.copy()
110 alt_limit = np.where((int_rounded(conditions.alt) > int_rounded(self.min_alt)) &
111 (int_rounded(conditions.alt) < int_rounded(self.max_alt)))[0]
112 result[alt_limit] = 1
113 to_mask = np.where((int_rounded(conditions.HA) > int_rounded(2.*np.pi-self.shadow_minutes-self.zenith_radius)) &
114 (self.decband == 1))
115 result[to_mask] = np.nan
116 return result
119class Moon_avoidance_basis_function(Base_basis_function):
120 """Avoid looking too close to the moon.
122 Parameters
123 ----------
124 moon_distance: float (30.)
125 Minimum allowed moon distance. (degrees)
127 XXX--TODO: This could be a more complicated function of filter and moon phase.
128 """
129 def __init__(self, nside=None, moon_distance=30.):
130 super(Moon_avoidance_basis_function, self).__init__(nside=nside)
131 self.update_on_newobs = False
133 self.moon_distance = int_rounded(np.radians(moon_distance))
134 self.result = np.ones(hp.nside2npix(self.nside), dtype=float)
136 def _calc_value(self, conditions, indx=None):
137 result = self.result.copy()
139 angular_distance = _angularSeparation(conditions.az, conditions.alt,
140 conditions.moonAz,
141 conditions.moonAlt)
143 result[int_rounded(angular_distance) < self.moon_distance] = np.nan
145 return result
148class Bulk_cloud_basis_function(Base_basis_function):
149 """Mark healpixels on a map if their cloud values are greater than
150 the same healpixels on a maximum cloud map.
152 Parameters
153 ----------
154 nside: int (default_nside)
155 The healpix resolution.
156 max_cloud_map : numpy array (None)
157 A healpix map showing the maximum allowed cloud values for all points on the sky
158 out_of_bounds_val : float (10.)
159 Point value to give regions where there are no observations requested
160 """
162 def __init__(self, nside=None, max_cloud_map=None, max_val=0.7,
163 out_of_bounds_val=np.nan):
164 super(Bulk_cloud_basis_function, self).__init__(nside=nside)
165 self.update_on_newobs = False
167 if max_cloud_map is None:
168 self.max_cloud_map = np.zeros(hp.nside2npix(nside), dtype=float) + max_val
169 else:
170 self.max_cloud_map = max_cloud_map
171 self.out_of_bounds_area = np.where(self.max_cloud_map > 1.)[0]
172 self.out_of_bounds_val = out_of_bounds_val
173 self.result = np.ones(hp.nside2npix(self.nside))
175 def _calc_value(self, conditions, indx=None):
176 """
177 Parameters
178 ----------
179 indx : list (None)
180 Index values to compute, if None, full map is computed
181 Returns
182 -------
183 Healpix map where pixels with a cloud value greater than the max_cloud_map
184 value are marked as unseen.
185 """
187 result = self.result.copy()
189 clouded = np.where(self.max_cloud_map <= conditions.bulk_cloud)
190 result[clouded] = self.out_of_bounds_val
192 return result
195class Map_cloud_basis_function(Base_basis_function):
196 """Mark healpixels on a map if their cloud values are greater than
197 the same healpixels on a maximum cloud map. Currently a placeholder for
198 when the telemetry stream can include a full sky cloud map.
200 Parameters
201 ----------
202 nside: int (default_nside)
203 The healpix resolution.
204 max_cloud_map : numpy array (None)
205 A healpix map showing the maximum allowed cloud values for all points on the sky
206 out_of_bounds_val : float (10.)
207 Point value to give regions where there are no observations requested
208 """
210 def __init__(self, nside=None, max_cloud_map=None, max_val=0.7,
211 out_of_bounds_val=np.nan):
212 super(Bulk_cloud_basis_function, self).__init__(nside=nside)
213 self.update_on_newobs = False
215 if max_cloud_map is None:
216 self.max_cloud_map = np.zeros(hp.nside2npix(nside), dtype=float) + max_val
217 else:
218 self.max_cloud_map = max_cloud_map
219 self.out_of_bounds_area = np.where(self.max_cloud_map > 1.)[0]
220 self.out_of_bounds_val = out_of_bounds_val
221 self.result = np.ones(hp.nside2npix(self.nside))
223 def _calc_value(self, conditions, indx=None):
224 """
225 Parameters
226 ----------
227 indx : list (None)
228 Index values to compute, if None, full map is computed
229 Returns
230 -------
231 Healpix map where pixels with a cloud value greater than the max_cloud_map
232 value are marked as unseen.
233 """
235 result = self.result.copy()
237 clouded = np.where(self.max_cloud_map <= conditions.bulk_cloud)
238 result[clouded] = self.out_of_bounds_val
240 return result
243class Mask_azimuth_basis_function(Base_basis_function):
244 """Mask pixels based on azimuth
245 """
246 def __init__(self, nside=None, out_of_bounds_val=np.nan, az_min=0., az_max=180.):
247 super(Mask_azimuth_basis_function, self).__init__(nside=nside)
248 self.az_min = int_rounded(np.radians(az_min))
249 self.az_max = int_rounded(np.radians(az_max))
250 self.out_of_bounds_val = out_of_bounds_val
251 self.result = np.ones(hp.nside2npix(self.nside))
253 def _calc_value(self, conditions, indx=None):
254 to_mask = np.where((int_rounded(conditions.az) > self.az_min) & (int_rounded(conditions.az) < self.az_max))[0]
255 result = self.result.copy()
256 result[to_mask] = self.out_of_bounds_val
258 return result