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 cumulative_azimuth_rad : float
98 The cummulative telescope azimuth (radians). For tracking cable wrap
99 cloud_map : np.array
100 A healpix map with the cloud coverage. XXX-expand, is this bool map? Transparency map?
101 airmass : np.array
102 A healpix map with the airmass value of each healpixel. (unitless)
103 sunset : float
104 The MJD of sunset that starts the current night. Note MJDs of sunset, moonset, twilight times, etc
105 are from interpolations. This means the sun may actually be slightly above/below the horizon
106 at the given sunset time.
107 sun_n12_setting : float
108 The MJD of when the sun is at -12 degees altitude and setting during the
109 current night. From interpolation.
110 sun_n18_setting : float
111 The MJD when the sun is at -18 degrees altitude and setting during the current night.
112 From interpolation.
113 sun_n18_rising : float
114 The MJD when the sun is at -18 degrees altitude and rising during the current night.
115 From interpolation.
116 sun_n12_rising : float
117 The MJD when the sun is at -12 degrees altitude and rising during the current night.
118 From interpolation.
119 sunrise : float
120 The MJD of sunrise during the current night. From interpolation
121 moonrise : float
122 The MJD of moonrise during the current night. From interpolation.
123 moonset : float
124 The MJD of moonset during the current night. From interpolation.
125 targets_of_opportunity : list of lsst.sims.featureScheduler.targetoO object(s)
126 targetoO objects.
127 planet_positions : dict
128 Dictionary of planet name and coordinate e.g., 'venus_RA', 'mars_dec'
129 scheduled_observations : np.array
130 A list of MJD times when there are scheduled observations. Defaults to empty array.
132 Attributes (calculated on demand and cached)
133 ------------------------------------------
134 alt : np.array
135 Altitude of each healpixel (radians). Recaclulated if mjd is updated. Uses fast
136 approximate equation for converting RA,Dec to alt,az.
137 az : np.array
138 Azimuth of each healpixel (radians). Recaclulated if mjd is updated. Uses fast
139 approximate equation for converting RA,Dec to alt,az.
140 pa : np.array
141 The parallactic angle of each healpixel (radians). Recaclulated if mjd is updated.
142 Based on the fast approximate alt,az values.
143 lmst : float
144 The local mean sidearal time (hours). Updates is mjd is changed.
145 M5Depth : dict of np.array
146 the 5-sigma limiting depth healpix maps, keyed by filtername (mags). Will be recalculated
147 if the skybrightness, seeing, or airmass are updated.
148 HA : np.array
149 Healpix map of the hour angle of each healpixel (radians). Runs from 0 to 2pi.
150 az_to_sun : np.array
151 Healpix map of the azimuthal distance to the sun for each healpixel (radians)
153 Attributes (set by the scheduler)
154 -------------------------------
155 queue : list of observation objects
156 The current queue of observations core_scheduler is waiting to execute.
158 """
159 if nside is None:
160 nside = set_default_nside()
161 self.nside = nside
162 self.site = Site(site)
163 self.exptime = exptime
164 self.mjd_start = mjd_start
165 hpids = np.arange(hp.nside2npix(nside))
166 self.season_offset = season_offset
167 self.sun_RA_start = sun_RA_start
168 # Generate an empty map so we can copy when we need a new map
169 self.zeros_map = np.zeros(hp.nside2npix(nside), dtype=float)
170 self.nan_map = np.zeros(hp.nside2npix(nside), dtype=float)
171 self.nan_map.fill(np.nan)
172 # The RA, Dec grid we are using
173 self.ra, self.dec = _hpid2RaDec(nside, hpids)
175 # Modified Julian Date (day)
176 self._mjd = None
177 # Altitude and azimuth. Dict with degrees and radians
178 self._alt = None
179 self._az = None
180 self._pa = None
181 # The cloud level. Fraction, but could upgrade to transparency map
182 self.clouds = None
183 self._slewtime = None
184 self.current_filter = None
185 self.mounted_filters = None
186 self.night = None
187 self._lmst = None
188 # Should be a dict with filtername keys
189 self._skybrightness = {}
190 self._FWHMeff = {}
191 self._M5Depth = None
192 self._airmass = None
194 # Upcomming scheduled observations
195 self.scheduled_observations = np.array([], dtype=float)
197 # Attribute to hold the current observing queue
198 self.queue = None
200 # Moon
201 self.moonAlt = None
202 self.moonAz = None
203 self.moonRA = None
204 self.moonDec = None
205 self.moonPhase = None
207 # Sun
208 self.sunAlt = None
209 self.sunAz = None
210 self.sunRA = None
211 self.sunDec = None
213 # Almanac information
214 self.sunset = None
215 self.sun_n12_setting = None
216 self.sun_n18_setting = None
217 self.sun_n18_rising = None
218 self.sun_n12_rising = None
219 self.sunrise = None
220 self.moonrise = None
221 self.moonset = None
223 self.planet_positions = None
225 # Current telescope pointing
226 self.telRA = None
227 self.telDec = None
228 self.telAlt = None
229 self.telAz = None
231 # Full sky cloud map
232 self._cloud_map = None
233 self._HA = None
235 # XXX--document
236 self.bulk_cloud = None
238 self.rotTelPos = None
240 self.targets_of_opportunity = None
242 self._season = None
244 self.season_modulo = None
245 self.season_max_season = None
246 self.season_length = 365.25
247 self.season_floor = True
249 @property
250 def lmst(self):
251 return self._lmst
253 @lmst.setter
254 def lmst(self, value):
255 self._lmst = value
256 self._HA = None
258 @property
259 def HA(self):
260 if self._HA is None:
261 self.calc_HA()
262 return self._HA
264 def calc_HA(self):
265 self._HA = np.radians(self._lmst*360./24.) - self.ra
266 self._HA[np.where(self._HA < 0)] += 2.*np.pi
268 @property
269 def cloud_map(self):
270 return self._cloud_map
272 @cloud_map.setter
273 def cloud_map(self, value):
274 self._cloud_map = match_hp_resolution(value, nside_out=self.nside)
276 @property
277 def slewtime(self):
278 return self._slewtime
280 @slewtime.setter
281 def slewtime(self, value):
282 # Using 0 for start of night
283 if np.size(value) == 1:
284 self._slewtime = value
285 else:
286 self._slewtime = match_hp_resolution(value, nside_out=self.nside)
288 @property
289 def airmass(self):
290 return self._airmass
292 @airmass.setter
293 def airmass(self, value):
294 self._airmass = match_hp_resolution(value, nside_out=self.nside)
295 self._M5Depth = None
297 @property
298 def pa(self):
299 if self._pa is None:
300 self.calc_pa()
301 return self._pa
303 def calc_pa(self):
304 self._pa = _approx_altaz2pa(self.alt, self.az, self.site.latitude_rad)
306 @property
307 def alt(self):
308 if self._alt is None:
309 self.calc_altAz()
310 return self._alt
312 @property
313 def az(self):
314 if self._az is None:
315 self.calc_altAz()
316 return self._az
318 def calc_altAz(self):
319 self._alt, self._az = _approx_RaDec2AltAz(self.ra, self.dec,
320 self.site.latitude_rad,
321 self.site.longitude_rad, self._mjd)
323 @property
324 def mjd(self):
325 return self._mjd
327 @mjd.setter
328 def mjd(self, value):
329 self._mjd = value
330 # Set things that need to be recalculated to None
331 self._az = None
332 self._alt = None
333 self._pa = None
334 self._HA = None
335 self._lmst = None
336 self._az_to_sun = None
337 self._season = None
339 @property
340 def skybrightness(self):
341 return self._skybrightness
343 @skybrightness.setter
344 def skybrightness(self, indict):
345 for key in indict:
347 self._skybrightness[key] = match_hp_resolution(indict[key], nside_out=self.nside)
348 # If sky brightness changes, need to recalc M5 depth.
349 self._M5Depth = None
351 @property
352 def FWHMeff(self):
353 return self._FWHMeff
355 @FWHMeff.setter
356 def FWHMeff(self, indict):
357 for key in indict:
358 self._FWHMeff[key] = match_hp_resolution(indict[key], nside_out=self.nside)
359 self._M5Depth = None
361 @property
362 def M5Depth(self):
363 if self._M5Depth is None:
364 self.calc_M5Depth()
365 return self._M5Depth
367 def calc_M5Depth(self):
368 self._M5Depth = {}
369 for filtername in self._skybrightness:
370 good = ~np.isnan(self._skybrightness[filtername])
371 self._M5Depth[filtername] = self.nan_map.copy()
372 self._M5Depth[filtername][good] = m5_flat_sed(filtername,
373 self._skybrightness[filtername][good],
374 self._FWHMeff[filtername][good],
375 self.exptime,
376 self._airmass[good])
378 def calc_az_to_sun(self):
379 diff = np.abs(self.ra - self.sunRA)
380 self._az_to_sun = diff
381 self._az_to_sun[np.where(diff > np.pi)] = 2.*np.pi-diff[np.where(diff > np.pi)]
383 @property
384 def az_to_sun(self):
385 if self._az_to_sun is None:
386 self.calc_az_to_sun()
387 return self._az_to_sun
389 # XXX, there's probably an elegant decorator that could do this caching automatically
390 def season(self, modulo=None, max_season=None, season_length=365.25, floor=True):
391 if self.season_offset is not None:
392 kwargs_match = (modulo == self.season_modulo) & (max_season == self.season_max_season) & (season_length == self.season_length) & (floor == self.season_floor)
393 if ~kwargs_match:
394 self.season_modulo = modulo
395 self.season_max_season = max_season
396 self.season_length = season_length
397 self.season_floor = floor
398 if (self._season is None) | (~kwargs_match):
399 self._season = season_calc(self.night, offset=self.season_offset,
400 modulo=modulo, max_season=max_season,
401 season_length=season_length, floor=floor)
402 else:
403 self._season = None
405 return self._season