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

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, smallest_signed_angle
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)
152 az_to_anitsun : np.array
153 Healpix map of the azimuthal distance to the anit-sun for each healpixel (radians)
155 Attributes (set by the scheduler)
156 -------------------------------
157 queue : list of observation objects
158 The current queue of observations core_scheduler is waiting to execute.
160 """
161 if nside is None:
162 nside = set_default_nside()
163 self.nside = nside
164 self.site = Site(site)
165 self.exptime = exptime
166 self.mjd_start = mjd_start
167 hpids = np.arange(hp.nside2npix(nside))
168 self.season_offset = season_offset
169 self.sun_RA_start = sun_RA_start
170 # Generate an empty map so we can copy when we need a new map
171 self.zeros_map = np.zeros(hp.nside2npix(nside), dtype=float)
172 self.nan_map = np.zeros(hp.nside2npix(nside), dtype=float)
173 self.nan_map.fill(np.nan)
174 # The RA, Dec grid we are using
175 self.ra, self.dec = _hpid2RaDec(nside, hpids)
177 # Modified Julian Date (day)
178 self._mjd = None
179 # Altitude and azimuth. Dict with degrees and radians
180 self._alt = None
181 self._az = None
182 self._pa = None
183 # The cloud level. Fraction, but could upgrade to transparency map
184 self.clouds = None
185 self._slewtime = None
186 self.current_filter = None
187 self.mounted_filters = None
188 self.night = None
189 self._lmst = None
190 # Should be a dict with filtername keys
191 self._skybrightness = {}
192 self._FWHMeff = {}
193 self._M5Depth = None
194 self._airmass = None
196 # Upcomming scheduled observations
197 self.scheduled_observations = np.array([], dtype=float)
199 # Attribute to hold the current observing queue
200 self.queue = None
202 # Moon
203 self.moonAlt = None
204 self.moonAz = None
205 self.moonRA = None
206 self.moonDec = None
207 self.moonPhase = None
209 # Sun
210 self.sunAlt = None
211 self.sunAz = None
212 self.sunRA = None
213 self.sunDec = None
215 # Almanac information
216 self.sunset = None
217 self.sun_n12_setting = None
218 self.sun_n18_setting = None
219 self.sun_n18_rising = None
220 self.sun_n12_rising = None
221 self.sunrise = None
222 self.moonrise = None
223 self.moonset = None
225 self.planet_positions = None
227 # Current telescope pointing
228 self.telRA = None
229 self.telDec = None
230 self.telAlt = None
231 self.telAz = None
233 # Full sky cloud map
234 self._cloud_map = None
235 self._HA = None
237 # XXX--document
238 self.bulk_cloud = None
240 self.rotTelPos = None
242 self.targets_of_opportunity = None
244 self._season = None
246 self.season_modulo = None
247 self.season_max_season = None
248 self.season_length = 365.25
249 self.season_floor = True
251 @property
252 def lmst(self):
253 return self._lmst
255 @lmst.setter
256 def lmst(self, value):
257 self._lmst = value
258 self._HA = None
260 @property
261 def HA(self):
262 if self._HA is None:
263 self.calc_HA()
264 return self._HA
266 def calc_HA(self):
267 self._HA = np.radians(self._lmst*360./24.) - self.ra
268 self._HA[np.where(self._HA < 0)] += 2.*np.pi
270 @property
271 def cloud_map(self):
272 return self._cloud_map
274 @cloud_map.setter
275 def cloud_map(self, value):
276 self._cloud_map = match_hp_resolution(value, nside_out=self.nside)
278 @property
279 def slewtime(self):
280 return self._slewtime
282 @slewtime.setter
283 def slewtime(self, value):
284 # Using 0 for start of night
285 if np.size(value) == 1:
286 self._slewtime = value
287 else:
288 self._slewtime = match_hp_resolution(value, nside_out=self.nside)
290 @property
291 def airmass(self):
292 return self._airmass
294 @airmass.setter
295 def airmass(self, value):
296 self._airmass = match_hp_resolution(value, nside_out=self.nside)
297 self._M5Depth = None
299 @property
300 def pa(self):
301 if self._pa is None:
302 self.calc_pa()
303 return self._pa
305 def calc_pa(self):
306 self._pa = _approx_altaz2pa(self.alt, self.az, self.site.latitude_rad)
308 @property
309 def alt(self):
310 if self._alt is None:
311 self.calc_altAz()
312 return self._alt
314 @property
315 def az(self):
316 if self._az is None:
317 self.calc_altAz()
318 return self._az
320 def calc_altAz(self):
321 self._alt, self._az = _approx_RaDec2AltAz(self.ra, self.dec,
322 self.site.latitude_rad,
323 self.site.longitude_rad, self._mjd)
325 @property
326 def mjd(self):
327 return self._mjd
329 @mjd.setter
330 def mjd(self, value):
331 self._mjd = value
332 # Set things that need to be recalculated to None
333 self._az = None
334 self._alt = None
335 self._pa = None
336 self._HA = None
337 self._lmst = None
338 self._az_to_sun = None
339 self._az_to_antisun = None
340 self._season = None
342 @property
343 def skybrightness(self):
344 return self._skybrightness
346 @skybrightness.setter
347 def skybrightness(self, indict):
348 for key in indict:
350 self._skybrightness[key] = match_hp_resolution(indict[key], nside_out=self.nside)
351 # If sky brightness changes, need to recalc M5 depth.
352 self._M5Depth = None
354 @property
355 def FWHMeff(self):
356 return self._FWHMeff
358 @FWHMeff.setter
359 def FWHMeff(self, indict):
360 for key in indict:
361 self._FWHMeff[key] = match_hp_resolution(indict[key], nside_out=self.nside)
362 self._M5Depth = None
364 @property
365 def M5Depth(self):
366 if self._M5Depth is None:
367 self.calc_M5Depth()
368 return self._M5Depth
370 def calc_M5Depth(self):
371 self._M5Depth = {}
372 for filtername in self._skybrightness:
373 good = ~np.isnan(self._skybrightness[filtername])
374 self._M5Depth[filtername] = self.nan_map.copy()
375 self._M5Depth[filtername][good] = m5_flat_sed(filtername,
376 self._skybrightness[filtername][good],
377 self._FWHMeff[filtername][good],
378 self.exptime,
379 self._airmass[good])
381 def calc_az_to_sun(self):
382 self._az_to_sun = smallest_signed_angle(self.ra, self.sunRA)
384 def calc_az_to_antisun(self):
385 self._az_to_antisun = smallest_signed_angle(self.ra+np.pi, self.sunRA)
387 @property
388 def az_to_sun(self):
389 if self._az_to_sun is None:
390 self.calc_az_to_sun()
391 return self._az_to_sun
393 @property
394 def az_to_antisun(self):
395 if self._az_to_antisun is None:
396 self.calc_az_to_antisun()
397 return self._az_to_antisun
399 # XXX, there's probably an elegant decorator that could do this caching automatically
400 def season(self, modulo=None, max_season=None, season_length=365.25, floor=True):
401 if self.season_offset is not None:
402 kwargs_match = (modulo == self.season_modulo) & (max_season == self.season_max_season) & (season_length == self.season_length) & (floor == self.season_floor)
403 if ~kwargs_match:
404 self.season_modulo = modulo
405 self.season_max_season = max_season
406 self.season_length = season_length
407 self.season_floor = floor
408 if (self._season is None) | (~kwargs_match):
409 self._season = season_calc(self.night, offset=self.season_offset,
410 modulo=modulo, max_season=max_season,
411 season_length=season_length, floor=floor)
412 else:
413 self._season = None
415 return self._season