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
3import healpy as hp
4from lsst.sims.featureScheduler.utils import set_default_nside, match_hp_resolution, approx_altaz2pa, 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)
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'
128 Attributes (calculated on demand and cached)
129 ------------------------------------------
130 alt : np.array
131 Altitude of each healpixel (radians). Recaclulated if mjd is updated. Uses fast
132 approximate equation for converting RA,Dec to alt,az.
133 az : np.array
134 Azimuth of each healpixel (radians). Recaclulated if mjd is updated. Uses fast
135 approximate equation for converting RA,Dec to alt,az.
136 pa : np.array
137 The parallactic angle of each healpixel (radians). Recaclulated if mjd is updated.
138 Based on the fast approximate alt,az values.
139 lmst : float
140 The local mean sidearal time (hours). Updates is mjd is changed.
141 M5Depth : dict of np.array
142 the 5-sigma limiting depth healpix maps, keyed by filtername (mags). Will be recalculated
143 if the skybrightness, seeing, or airmass are updated.
144 HA : np.array
145 Healpix map of the hour angle of each healpixel (radians).
146 az_to_sun : np.array
147 Healpix map of the azimuthal distance to the sun for each healpixel (radians)
149 Attributes (set by the scheduler)
150 -------------------------------
151 queue : list of observation objects
152 The current queue of observations core_scheduler is waiting to execute.
154 """
155 if nside is None:
156 nside = set_default_nside()
157 self.nside = nside
158 self.site = Site(site)
159 self.exptime = exptime
160 self.mjd_start = mjd_start
161 hpids = np.arange(hp.nside2npix(nside))
162 self.season_offset = season_offset
163 self.sun_RA_start = sun_RA_start
164 # Generate an empty map so we can copy when we need a new map
165 self.zeros_map = np.zeros(hp.nside2npix(nside), dtype=float)
166 self.nan_map = np.zeros(hp.nside2npix(nside), dtype=float)
167 self.nan_map.fill(np.nan)
168 # The RA, Dec grid we are using
169 self.ra, self.dec = _hpid2RaDec(nside, hpids)
171 # Modified Julian Date (day)
172 self._mjd = None
173 # Altitude and azimuth. Dict with degrees and radians
174 self._alt = None
175 self._az = None
176 self._pa = None
177 # The cloud level. Fraction, but could upgrade to transparency map
178 self.clouds = None
179 self._slewtime = None
180 self.current_filter = None
181 self.mounted_filters = None
182 self.night = None
183 self._lmst = None
184 # Should be a dict with filtername keys
185 self._skybrightness = {}
186 self._FWHMeff = {}
187 self._M5Depth = None
188 self._airmass = None
190 # Attribute to hold the current observing queue
191 self.queue = None
193 # Moon
194 self.moonAlt = None
195 self.moonAz = None
196 self.moonRA = None
197 self.moonDec = None
198 self.moonPhase = None
200 # Sun
201 self.sunAlt = None
202 self.sunAz = None
203 self.sunRA = None
204 self.sunDec = None
206 # Almanac information
207 self.sunset = None
208 self.sun_n12_setting = None
209 self.sun_n18_setting = None
210 self.sun_n18_rising = None
211 self.sun_n12_rising = None
212 self.sunrise = None
213 self.moonrise = None
214 self.moonset = None
216 self.planet_positions = None
218 # Current telescope pointing
219 self.telRA = None
220 self.telDec = None
221 self.telAlt = None
222 self.telAz = None
224 # Full sky cloud map
225 self._cloud_map = None
226 self._HA = None
228 # XXX--document
229 self.bulk_cloud = None
231 self.rotTelPos = None
233 self.targets_of_opportunity = None
235 self._season = None
237 self.season_modulo = None
238 self.season_max_season = None
239 self.season_length = 365.25
240 self.season_floor = True
242 @property
243 def lmst(self):
244 return self._lmst
246 @lmst.setter
247 def lmst(self, value):
248 self._lmst = value
249 self._HA = None
251 @property
252 def HA(self):
253 if self._HA is None:
254 self.calc_HA()
255 return self._HA
257 def calc_HA(self):
258 self._HA = np.radians(self._lmst*360./24.) - self.ra
259 self._HA[np.where(self._HA < 0)] += 2.*np.pi
261 @property
262 def cloud_map(self):
263 return self._cloud_map
265 @cloud_map.setter
266 def cloud_map(self, value):
267 self._cloud_map = match_hp_resolution(value, nside_out=self.nside)
269 @property
270 def slewtime(self):
271 return self._slewtime
273 @slewtime.setter
274 def slewtime(self, value):
275 # Using 0 for start of night
276 if np.size(value) == 1:
277 self._slewtime = value
278 else:
279 self._slewtime = match_hp_resolution(value, nside_out=self.nside)
281 @property
282 def airmass(self):
283 return self._airmass
285 @airmass.setter
286 def airmass(self, value):
287 self._airmass = match_hp_resolution(value, nside_out=self.nside)
288 self._M5Depth = None
290 @property
291 def pa(self):
292 if self._pa is None:
293 self.calc_pa()
294 return self._pa
296 def calc_pa(self):
297 self._pa = approx_altaz2pa(self.alt, self.az, self.site.latitude_rad)
299 @property
300 def alt(self):
301 if self._alt is None:
302 self.calc_altAz()
303 return self._alt
305 @property
306 def az(self):
307 if self._az is None:
308 self.calc_altAz()
309 return self._az
311 def calc_altAz(self):
312 self._alt, self._az = _approx_RaDec2AltAz(self.ra, self.dec,
313 self.site.latitude_rad,
314 self.site.longitude_rad, self._mjd)
316 @property
317 def mjd(self):
318 return self._mjd
320 @mjd.setter
321 def mjd(self, value):
322 self._mjd = value
323 # Set things that need to be recalculated to None
324 self._az = None
325 self._alt = None
326 self._pa = None
327 self._HA = None
328 self._lmst = None
329 self._az_to_sun = None
330 self._season = None
332 @property
333 def skybrightness(self):
334 return self._skybrightness
336 @skybrightness.setter
337 def skybrightness(self, indict):
338 for key in indict:
340 self._skybrightness[key] = match_hp_resolution(indict[key], nside_out=self.nside)
341 # If sky brightness changes, need to recalc M5 depth.
342 self._M5Depth = None
344 @property
345 def FWHMeff(self):
346 return self._FWHMeff
348 @FWHMeff.setter
349 def FWHMeff(self, indict):
350 for key in indict:
351 self._FWHMeff[key] = match_hp_resolution(indict[key], nside_out=self.nside)
352 self._M5Depth = None
354 @property
355 def M5Depth(self):
356 if self._M5Depth is None:
357 self.calc_M5Depth()
358 return self._M5Depth
360 def calc_M5Depth(self):
361 self._M5Depth = {}
362 for filtername in self._skybrightness:
363 good = ~np.isnan(self._skybrightness[filtername])
364 self._M5Depth[filtername] = self.nan_map.copy()
365 self._M5Depth[filtername][good] = m5_flat_sed(filtername,
366 self._skybrightness[filtername][good],
367 self._FWHMeff[filtername][good],
368 self.exptime,
369 self._airmass[good])
371 def calc_az_to_sun(self):
372 diff = np.abs(self.ra - self.sunRA)
373 self._az_to_sun = diff
374 self._az_to_sun[np.where(diff > np.pi)] = 2.*np.pi-diff[np.where(diff > np.pi)]
376 @property
377 def az_to_sun(self):
378 if self._az_to_sun is None:
379 self.calc_az_to_sun()
380 return self._az_to_sun
382 # XXX, there's probably an elegant decorator that could do this caching automatically
383 def season(self, modulo=None, max_season=None, season_length=365.25, floor=True):
384 if self.season_offset is not None:
385 kwargs_match = (modulo == self.season_modulo) & (max_season == self.season_max_season) & (season_length == self.season_length) & (floor == self.season_floor)
386 if ~kwargs_match:
387 self.season_modulo = modulo
388 self.season_max_season = max_season
389 self.season_length = season_length
390 self.season_floor = floor
391 if (self._season is None) | (~kwargs_match):
392 self._season = season_calc(self.night, offset=self.season_offset,
393 modulo=modulo, max_season=max_season,
394 season_length=season_length, floor=floor)
395 else:
396 self._season = None
398 return self._season