def _calc_value(self, conditions, indx=None): to_mask = np.where((int_rounded(conditions.az) > self.az_min) & (int_rounded(conditions.az) < self.az_max))[0] result = self.result.copy() result[to_mask] = self.out_of_bounds_val return result
def __init__(self, nside=None, min_alt=20., max_alt=82., shadow_minutes=40., penalty=np.nan, site='LSST'): super(Zenith_shadow_mask_basis_function, self).__init__(nside=nside) self.update_on_newobs = False self.penalty = penalty self.min_alt = np.radians(min_alt) self.max_alt = np.radians(max_alt) self.ra, self.dec = _hpid2RaDec(nside, np.arange(hp.nside2npix(nside))) self.shadow_minutes = np.radians(shadow_minutes / 60. * 360. / 24.) # Compute the declination band where things could drift into zenith self.decband = np.zeros(self.dec.size, dtype=float) self.zenith_radius = np.radians(90. - max_alt) / 2. site = Site(name=site) self.lat_rad = site.latitude_rad self.lon_rad = site.longitude_rad self.decband[np.where( (int_rounded(self.dec) < int_rounded(self.lat_rad + self.zenith_radius)) & (int_rounded(self.dec) > int_rounded(self.lat_rad - self.zenith_radius)))] = 1 self.result = np.empty(hp.nside2npix(self.nside), dtype=float) self.result.fill(self.penalty)
def _calc_value(self, conditions, indx=None): result = self.result.copy() alt_limit = np.where( (int_rounded(conditions.alt) > int_rounded(self.min_alt)) & (int_rounded(conditions.alt) < int_rounded(self.max_alt)))[0] result[alt_limit] = 1 return result
def __init__(self, nside=None, out_of_bounds_val=np.nan, az_min=0., az_max=180.): super(Mask_azimuth_basis_function, self).__init__(nside=nside) self.az_min = int_rounded(np.radians(az_min)) self.az_max = int_rounded(np.radians(az_max)) self.out_of_bounds_val = out_of_bounds_val self.result = np.ones(hp.nside2npix(self.nside))
def _check_queue_mjd_only(self, mjd): """ Check if there are things in the queue that can be executed using only MJD and not full conditions. This is primarly used by sim_runner to reduce calls calculating updated conditions when they are not needed. """ result = False if len(self.queue) > 0: if (int_rounded(mjd) < int_rounded(self.queue[0]['flush_by_mjd']) ) | (self.queue[0]['flush_by_mjd'] == 0): result = True return result
def __init__(self, filtername='r', nside=None, FWHMeff_limit=100.): if nside is None: nside = utils.set_default_nside() self.filtername = filtername self.FWHMeff_limit = int_rounded(FWHMeff_limit) # Starting at limiting mag of zero should be fine. self.feature = np.zeros(hp.nside2npix(nside), dtype=float)
def _calc_value(self, conditions, indx=None): result = self.result.copy() angular_distance = _angularSeparation(conditions.az, conditions.alt, conditions.moonAz, conditions.moonAlt) result[int_rounded(angular_distance) < self.moon_distance] = np.nan return result
def calc_reward_function(self, conditions): """ """ # Set the number of observations we are going to try and take self._set_block_size(conditions) # Computing reward like usual with basis functions and weights if self._check_feasibility(conditions): self.reward = 0 indx = np.arange(hp.nside2npix(self.nside)) for bf, weight in zip(self.basis_functions, self.basis_weights): basis_value = bf(conditions, indx=indx) self.reward += basis_value * weight # might be faster to pull this out into the feasabiliity check? if self.smoothing_kernel is not None: self.smooth_reward() # Apply max altitude cut too_high = np.where( int_rounded(conditions.alt) > int_rounded(self.alt_max)) self.reward[too_high] = np.nan # Select healpixels within some radius of the max # This is probably faster with a kd-tree. max_hp = np.where(self.reward == np.nanmax(self.reward))[0] if np.size(max_hp) > 0: peak_reward = np.min(max_hp) else: # Everything is masked, so get out return -np.inf # Apply radius selection dists = _angularSeparation(self.ra[peak_reward], self.dec[peak_reward], self.ra, self.dec) out_hp = np.where( int_rounded(dists) > int_rounded(self.search_radius)) self.reward[out_hp] = np.nan # Apply az cut az_centered = conditions.az - conditions.az[peak_reward] az_centered[np.where(az_centered < 0)] += 2. * np.pi az_out = np.where( (int_rounded(az_centered) > int_rounded(self.az_range / 2.)) & (int_rounded(az_centered) < int_rounded(2. * np.pi - self.az_range / 2.))) self.reward[az_out] = np.nan else: self.reward = -np.inf self.reward_checked = True return self.reward
def add_observation(self, observation, indx=None): if observation['filter'] == self.filtername: if int_rounded(observation['FWHMeff']) <= self.FWHMeff_limit: m5 = m5_flat_sed(observation['filter'], observation['skybrightness'], observation['FWHMeff'], observation['exptime'], observation['airmass']) self.feature[indx] = 1.25 * np.log10( 10.**(0.8 * self.feature[indx]) + 10.**(0.8 * m5))
def _calc_value(self, conditions, indx=None): result = self.result.copy() alt_limit = np.where( (int_rounded(conditions.alt) > int_rounded(self.min_alt)) & (int_rounded(conditions.alt) < int_rounded(self.max_alt)))[0] result[alt_limit] = 1 to_mask = np.where((int_rounded(conditions.HA) > int_rounded( 2. * np.pi - self.shadow_minutes - self.zenith_radius)) & (self.decband == 1)) result[to_mask] = np.nan return result
def __call__(self, observation_list, conditions): obs_array = np.concatenate(observation_list) alt, az = _approx_RaDec2AltAz(obs_array['RA'], obs_array['dec'], conditions.site.latitude_rad, conditions.site.longitude_rad, conditions.mjd) alt_diff = np.abs(alt - conditions.telAlt) in_band = np.where(int_rounded(alt_diff) <= self.alt_band)[0] if in_band.size == 0: in_band = np.arange(alt.size) # Find the closest in angular distance of the points that are in band ang_dist = _angularSeparation(az[in_band], alt[in_band], conditions.telAz, conditions.telAlt) good = np.min(np.where(ang_dist == ang_dist.min())[0]) indx = in_band[good] result = observation_list[indx:] + observation_list[:indx] return result
def request_observation(self, mjd=None): """ Ask the scheduler what it wants to observe next Paramters --------- mjd : float (None) The Modified Julian Date. If None, it uses the MJD from the conditions from the last conditions update. Returns ------- observation object (ra,dec,filter,rotangle) Returns None if the queue fails to fill """ if mjd is None: mjd = self.conditions.mjd if len(self.queue) == 0: self._fill_queue() if len(self.queue) == 0: return None else: # If the queue has gone stale, flush and refill. Zero means no flush_by was set. if (int_rounded(mjd) > int_rounded(self.queue[0]['flush_by_mjd']) ) & (self.queue[0]['flush_by_mjd'] != 0): self.flushed += len(self.queue) self.flush_queue() self._fill_queue() if len(self.queue) == 0: return None observation = self.queue.pop(0) # If we are limiting the camera rotator if self.rotator_limits is not None: alt, az = _approx_RaDec2AltAz( observation['RA'], observation['dec'], self.conditions.site.latitude_rad, self.conditions.site.longitude_rad, mjd) obs_pa = approx_altaz2pa(alt, az, self.conditions.site.latitude_rad) rotTelPos_expected = (obs_pa - observation['rotSkyPos']) % (2. * np.pi) if (int_rounded(rotTelPos_expected) > int_rounded( self.rotator_limits[0])) & ( int_rounded(rotTelPos_expected) < int_rounded( self.rotator_limits[1])): diff = np.abs(self.rotator_limits - rotTelPos_expected) limit_indx = np.min(np.where(diff == np.min(diff))[0]) observation['rotSkyPos'] = ( obs_pa - self.rotator_limits[limit_indx]) % (2. * np.pi) return observation
def __init__(self, alt_band=10.): super(Close_alt_detailer, self).__init__() self.alt_band = int_rounded(np.radians(alt_band))
def __init__(self, nside=None, moon_distance=30.): super(Moon_avoidance_basis_function, self).__init__(nside=nside) self.update_on_newobs = False self.moon_distance = int_rounded(np.radians(moon_distance)) self.result = np.ones(hp.nside2npix(self.nside), dtype=float)
def check_feasibility(self, conditions): available_time = getattr(conditions, 'sun_n' + self.alt_limit + '_rising') - conditions.mjd result = int_rounded(available_time) < self.time_remaining return result
def __init__(self, time_remaining=30., alt_limit=18): super(End_of_evening_basis_function, self).__init__() self.time_remaining = int_rounded(time_remaining/60./24.) self.alt_limit = str(alt_limit)
def __init__(self, illum_limit=10.): self.illum_limit_IR = int_rounded(illum_limit)
def check_feasibility(self, conditions): result = True target_HA = (conditions.lmst - self.ra_hours) % 24 ratio = self.survey_features['N_survey'].feature / self.survey_features['Ntot'].feature available_time = getattr(conditions, 'sun_' + self.sun_alt_limit + '_rising') - conditions.mjd # If it's more that self.time_jump to hour angle zero # See if there will be enough time to twilight in the future if (int_rounded(target_HA) > int_rounded(12)) & (int_rounded(target_HA) < int_rounded(24.-self.time_jump)): if int_rounded(available_time) > int_rounded(self.time_needed + self.time_jump): result = False # If we paused for better conditions, but the moon will rise, turn things back on. if int_rounded(conditions.moonAlt) < int_rounded(0): if int_rounded(conditions.moonrise) > int_rounded(conditions.mjd): if int_rounded(conditions.moonrise - conditions.mjd) > int_rounded(self.time_jump): result = True # If the moon is up and will set soon, pause if int_rounded(conditions.moonAlt) > int_rounded(0): time_after_moonset = getattr(conditions, 'sun_' + self.sun_alt_limit + '_rising') - conditions.moonset if int_rounded(conditions.moonset) > int_rounded(self.time_jump): if int_rounded(time_after_moonset) > int_rounded(self.time_needed): result = False # If the survey has fallen far behind, be agressive and observe anytime it's up. if int_rounded(ratio) < int_rounded(self.aggressive_fraction): result = True return result
def __call__(self, conditions): if int_rounded(conditions.moonPhase) > self.illum_limit_IR: result = ['g', 'r', 'i', 'z', 'y'] else: result = ['u', 'g', 'r', 'i', 'y'] return result