Coverage for python/lsst/sims/featureScheduler/features/conditions.py : 17%

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
2from lsst.sims.utils import _approx_RaDec2AltAz, Site, _hpid2RaDec, m5_flat_sed, _approx_altaz2pa
3import healpy as hp
4from lsst.sims.featureScheduler.utils import set_default_nside, match_hp_resolution, season_calc
6__all__ = ['Conditions']
9class Conditions(object):
10 """
11 Class to hold telemetry information
13 If the incoming value is a healpix map, we use a setter to ensure the
14 resolution matches.
16 Unless otherwise noted, all values are assumed to be valid at the time
17 given by self.mjd
18 """
19 def __init__(self, nside=None, site='LSST', exptime=30., mjd_start=59853.5, season_offset=None,
20 sun_RA_start=None):
21 """
22 Parameters
23 ----------
24 nside : int
25 The healpixel nside to set the resolution of attributes.
26 site : str ('LSST')
27 A site name used to create a sims.utils.Site object. For looking up
28 observatory paramteres like latitude and longitude.
29 expTime : float (30)
30 The exposure time to assume when computing the 5-sigma limiting depth
31 mjd_start : float (59853.5)
32 The starting MJD of the survey.
33 season_offset : np.array
34 A HEALpix array that specifies the day offset when computing the season for each HEALpix.
35 sun_RA_start : float (None)
37 Attributes (Set on init)
38 -----------
39 nside : int
40 Healpix resolution. All maps are set to this reslution.
41 site : lsst.sims.Site object ('LSST')
42 Contains static site-specific data (lat, lon, altitude, etc). Defaults to 'LSST'.
43 ra : np.array
44 A healpix array with the RA of each healpixel center (radians). Automatically
45 generated.
46 dec : np.array
47 A healpix array with the Dec of each healpixel center (radians). Automatically generated.
49 Attributes (to be set by user/telemetry stream/scheduler)
50 -------------------------------------------
51 mjd : float
52 Modified Julian Date (days).
53 bulk_cloud : float
54 The fraction of sky covered by clouds. (In the future might update to transparency map)
55 cloud_map : np.array
56 XXX--to be done. HEALpix array with cloudy pixels set to NaN.
57 slewtime : np.array
58 Healpix showing the slewtime to each healpixel center (seconds)
59 current_filter : str
60 The name of the current filter. (expect one of u, g, r, i, z, y).
61 mounted_filters : list of str
62 The filters that are currently mounted and thu available (expect 5 of u, g, r, i, z, y)
63 night : int
64 The current night number (days). Probably starts at 1.
65 skybrightness : dict of np.array
66 Dictionary keyed by filtername. Values are healpix arrays with the sky brightness at each
67 healpix center (mag/acsec^2)
68 FWHMeff : dict of np.array
69 Dictionary keyed by filtername. Values are the effective seeing FWHM at each healpix
70 center (arcseconds)
71 moonAlt : float
72 The altitude of the Moon (radians)
73 moonAz : float
74 The Azimuth of the moon (radians)
75 moonRA : float
76 RA of the moon (radians)
77 moonDec : float
78 Declination of the moon (radians)
79 moonPhase : float
80 The Phase of the moon. (percent, 0=new moon, 100=full moon)
81 sunAlt : float
82 The altitude of the sun (radians).
83 sunAz : float
84 The Azimuth of the sun (radians).
85 sunRA : float
86 The RA of the sun (radians).
87 sunDec : float
88 The Dec of the sun (radians).
89 telRA : float
90 The current telescope RA pointing (radians).
91 telDec : float
92 The current telescope Declination (radians).
93 telAlt : float
94 The current telescope altitude (radians).
95 telAz : float
96 The current telescope azimuth (radians).
97 cloud_map : np.array
98 A healpix map with the cloud coverage. XXX-expand, is this bool map? Transparency map?
99 airmass : np.array
100 A healpix map with the airmass value of each healpixel. (unitless)
101 sunset : float
102 The MJD of sunset that starts the current night. Note MJDs of sunset, moonset, twilight times, etc
103 are from interpolations. This means the sun may actually be slightly above/below the horizon
104 at the given sunset time.
105 sun_n12_setting : float
106 The MJD of when the sun is at -12 degees altitude and setting during the
107 current night. From interpolation.
108 sun_n18_setting : float
109 The MJD when the sun is at -18 degrees altitude and setting during the current night.
110 From interpolation.
111 sun_n18_rising : float
112 The MJD when the sun is at -18 degrees altitude and rising during the current night.
113 From interpolation.
114 sun_n12_rising : float
115 The MJD when the sun is at -12 degrees altitude and rising during the current night.
116 From interpolation.
117 sunrise : float
118 The MJD of sunrise during the current night. From interpolation
119 moonrise : float
120 The MJD of moonrise during the current night. From interpolation.
121 moonset : float
122 The MJD of moonset during the current night. From interpolation.
123 targets_of_opportunity : list of lsst.sims.featureScheduler.targetoO object(s)
124 targetoO objects.
125 planet_positions : dict
126 Dictionary of planet name and coordinate e.g., 'venus_RA', 'mars_dec'
127 scheduled_observations : np.array
128 A list of MJD times when there are scheduled observations. Defaults to empty array.
130 Attributes (calculated on demand and cached)
131 ------------------------------------------
132 alt : np.array
133 Altitude of each healpixel (radians). Recaclulated if mjd is updated. Uses fast
134 approximate equation for converting RA,Dec to alt,az.
135 az : np.array
136 Azimuth of each healpixel (radians). Recaclulated if mjd is updated. Uses fast
137 approximate equation for converting RA,Dec to alt,az.
138 pa : np.array
139 The parallactic angle of each healpixel (radians). Recaclulated if mjd is updated.
140 Based on the fast approximate alt,az values.
141 lmst : float
142 The local mean sidearal time (hours). Updates is mjd is changed.
143 M5Depth : dict of np.array
144 the 5-sigma limiting depth healpix maps, keyed by filtername (mags). Will be recalculated
145 if the skybrightness, seeing, or airmass are updated.
146 HA : np.array
147 Healpix map of the hour angle of each healpixel (radians). Runs from 0 to 2pi.
148 az_to_sun : np.array
149 Healpix map of the azimuthal distance to the sun for each healpixel (radians)
151 Attributes (set by the scheduler)
152 -------------------------------
153 queue : list of observation objects
154 The current queue of observations core_scheduler is waiting to execute.
156 """
157 if nside is None:
158 nside = set_default_nside()
159 self.nside = nside
160 self.site = Site(site)
161 self.exptime = exptime
162 self.mjd_start = mjd_start
163 hpids = np.arange(hp.nside2npix(nside))
164 self.season_offset = season_offset
165 self.sun_RA_start = sun_RA_start
166 # Generate an empty map so we can copy when we need a new map
167 self.zeros_map = np.zeros(hp.nside2npix(nside), dtype=float)
168 self.nan_map = np.zeros(hp.nside2npix(nside), dtype=float)
169 self.nan_map.fill(np.nan)
170 # The RA, Dec grid we are using
171 self.ra, self.dec = _hpid2RaDec(nside, hpids)
173 # Modified Julian Date (day)
174 self._mjd = None
175 # Altitude and azimuth. Dict with degrees and radians
176 self._alt = None
177 self._az = None
178 self._pa = None
179 # The cloud level. Fraction, but could upgrade to transparency map
180 self.clouds = None
181 self._slewtime = None
182 self.current_filter = None
183 self.mounted_filters = None
184 self.night = None
185 self._lmst = None
186 # Should be a dict with filtername keys
187 self._skybrightness = {}
188 self._FWHMeff = {}
189 self._M5Depth = None
190 self._airmass = None
192 # Upcomming scheduled observations
193 self.scheduled_observations = np.array([], dtype=float)
195 # Attribute to hold the current observing queue
196 self.queue = None
198 # Moon
199 self.moonAlt = None
200 self.moonAz = None
201 self.moonRA = None
202 self.moonDec = None
203 self.moonPhase = None
205 # Sun
206 self.sunAlt = None
207 self.sunAz = None
208 self.sunRA = None
209 self.sunDec = None
211 # Almanac information
212 self.sunset = None
213 self.sun_n12_setting = None
214 self.sun_n18_setting = None
215 self.sun_n18_rising = None
216 self.sun_n12_rising = None
217 self.sunrise = None
218 self.moonrise = None
219 self.moonset = None
221 self.planet_positions = None
223 # Current telescope pointing
224 self.telRA = None
225 self.telDec = None
226 self.telAlt = None
227 self.telAz = None
229 # Full sky cloud map
230 self._cloud_map = None
231 self._HA = None
233 # XXX--document
234 self.bulk_cloud = None
236 self.rotTelPos = None
238 self.targets_of_opportunity = None
240 self._season = None
242 self.season_modulo = None
243 self.season_max_season = None
244 self.season_length = 365.25
245 self.season_floor = True
247 @property
248 def lmst(self):
249 return self._lmst
251 @lmst.setter
252 def lmst(self, value):
253 self._lmst = value
254 self._HA = None
256 @property
257 def HA(self):
258 if self._HA is None:
259 self.calc_HA()
260 return self._HA
262 def calc_HA(self):
263 self._HA = np.radians(self._lmst*360./24.) - self.ra
264 self._HA[np.where(self._HA < 0)] += 2.*np.pi
266 @property
267 def cloud_map(self):
268 return self._cloud_map
270 @cloud_map.setter
271 def cloud_map(self, value):
272 self._cloud_map = match_hp_resolution(value, nside_out=self.nside)
274 @property
275 def slewtime(self):
276 return self._slewtime
278 @slewtime.setter
279 def slewtime(self, value):
280 # Using 0 for start of night
281 if np.size(value) == 1:
282 self._slewtime = value
283 else:
284 self._slewtime = match_hp_resolution(value, nside_out=self.nside)
286 @property
287 def airmass(self):
288 return self._airmass
290 @airmass.setter
291 def airmass(self, value):
292 self._airmass = match_hp_resolution(value, nside_out=self.nside)
293 self._M5Depth = None
295 @property
296 def pa(self):
297 if self._pa is None:
298 self.calc_pa()
299 return self._pa
301 def calc_pa(self):
302 self._pa = _approx_altaz2pa(self.alt, self.az, self.site.latitude_rad)
304 @property
305 def alt(self):
306 if self._alt is None:
307 self.calc_altAz()
308 return self._alt
310 @property
311 def az(self):
312 if self._az is None:
313 self.calc_altAz()
314 return self._az
316 def calc_altAz(self):
317 self._alt, self._az = _approx_RaDec2AltAz(self.ra, self.dec,
318 self.site.latitude_rad,
319 self.site.longitude_rad, self._mjd)
321 @property
322 def mjd(self):
323 return self._mjd
325 @mjd.setter
326 def mjd(self, value):
327 self._mjd = value
328 # Set things that need to be recalculated to None
329 self._az = None
330 self._alt = None
331 self._pa = None
332 self._HA = None
333 self._lmst = None
334 self._az_to_sun = None
335 self._season = None
337 @property
338 def skybrightness(self):
339 return self._skybrightness
341 @skybrightness.setter
342 def skybrightness(self, indict):
343 for key in indict:
345 self._skybrightness[key] = match_hp_resolution(indict[key], nside_out=self.nside)
346 # If sky brightness changes, need to recalc M5 depth.
347 self._M5Depth = None
349 @property
350 def FWHMeff(self):
351 return self._FWHMeff
353 @FWHMeff.setter
354 def FWHMeff(self, indict):
355 for key in indict:
356 self._FWHMeff[key] = match_hp_resolution(indict[key], nside_out=self.nside)
357 self._M5Depth = None
359 @property
360 def M5Depth(self):
361 if self._M5Depth is None:
362 self.calc_M5Depth()
363 return self._M5Depth
365 def calc_M5Depth(self):
366 self._M5Depth = {}
367 for filtername in self._skybrightness:
368 good = ~np.isnan(self._skybrightness[filtername])
369 self._M5Depth[filtername] = self.nan_map.copy()
370 self._M5Depth[filtername][good] = m5_flat_sed(filtername,
371 self._skybrightness[filtername][good],
372 self._FWHMeff[filtername][good],
373 self.exptime,
374 self._airmass[good])
376 def calc_az_to_sun(self):
377 diff = np.abs(self.ra - self.sunRA)
378 self._az_to_sun = diff
379 self._az_to_sun[np.where(diff > np.pi)] = 2.*np.pi-diff[np.where(diff > np.pi)]
381 @property
382 def az_to_sun(self):
383 if self._az_to_sun is None:
384 self.calc_az_to_sun()
385 return self._az_to_sun
387 # XXX, there's probably an elegant decorator that could do this caching automatically
388 def season(self, modulo=None, max_season=None, season_length=365.25, floor=True):
389 if self.season_offset is not None:
390 kwargs_match = (modulo == self.season_modulo) & (max_season == self.season_max_season) & (season_length == self.season_length) & (floor == self.season_floor)
391 if ~kwargs_match:
392 self.season_modulo = modulo
393 self.season_max_season = max_season
394 self.season_length = season_length
395 self.season_floor = floor
396 if (self._season is None) | (~kwargs_match):
397 self._season = season_calc(self.night, offset=self.season_offset,
398 modulo=modulo, max_season=max_season,
399 season_length=season_length, floor=floor)
400 else:
401 self._season = None
403 return self._season