Hide keyboard shortcuts

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.featureScheduler.surveys import BaseSurvey 

3import copy 

4import lsst.sims.featureScheduler.basis_functions as basis_functions 

5from lsst.sims.featureScheduler.utils import empty_observation 

6import healpy as hp 

7import random 

8 

9 

10__all__ = ['DESC_ddf', 'generate_desc_dd_surveys'] 

11 

12 

13class DESC_ddf(BaseSurvey): 

14 """DDF survey based on Scolnic et al Cadence White Paper. 

15 """ 

16 def __init__(self, basis_functions, RA, dec, sequences=None, 

17 exptime=30., nexp=1, ignore_obs=None, survey_name='DD_DESC', 

18 reward_value=101., readtime=2., filter_change_time=120., 

19 nside=None, flush_pad=30., seed=42, detailers=None): 

20 super(DESC_ddf, self).__init__(nside=nside, basis_functions=basis_functions, 

21 detailers=detailers, ignore_obs=ignore_obs) 

22 

23 self.ra = np.radians(RA) 

24 self.ra_hours = RA/360.*24. 

25 self.dec = np.radians(dec) 

26 self.survey_name = survey_name 

27 self.reward_value = reward_value 

28 self.flush_pad = flush_pad/60./24. # To days 

29 

30 self.simple_obs = empty_observation() 

31 self.simple_obs['RA'] = np.radians(RA) 

32 self.simple_obs['dec'] = np.radians(dec) 

33 self.simple_obs['exptime'] = exptime 

34 self.simple_obs['nexp'] = nexp 

35 self.simple_obs['note'] = survey_name 

36 

37 # Define the sequences we would like to do 

38 if sequences is None: 

39 self.sequences = [{'u': 2, 'g': 2, 'r': 4, 'i': 8}, {'z': 25, 'y': 4}, None] 

40 else: 

41 self.sequences = sequences 

42 

43 self.approx_times = [] 

44 for sequence in self.sequences: 

45 if sequence is None: 

46 self.approx_times.append(0) 

47 else: 

48 n_exp_in_seq = np.sum(list(sequence.values())) 

49 time_needed = filter_change_time*len(sequence.keys()) 

50 time_needed += exptime*n_exp_in_seq 

51 time_needed += readtime*n_exp_in_seq*nexp 

52 self.approx_times.append(time_needed/3600./24.) 

53 

54 # Track what we last tried to do 

55 # XXX-this should probably go into self.extra_features or something for consistency. 

56 self.sequence_index = 0 

57 self.last_night_observed = -100 

58 

59 def check_continue(self, observation, conditions): 

60 # feasibility basis functions? 

61 ''' 

62 This method enables external calls to check if a given observations that belongs to this survey is 

63 feasible or not. This is called once a sequence has started to make sure it can continue. 

64 

65 XXX--TODO: Need to decide if we want to develope check_continue, or instead hold the  

66 sequence in the survey, and be able to check it that way. 

67 ''' 

68 

69 result = True 

70 return result 

71 

72 def _check_feasibility(self, conditions): 

73 """ 

74 Check if the survey is feasable in the current conditions 

75 """ 

76 

77 # No more if we've already observed this night 

78 if self.last_night_observed == conditions.night: 

79 return False 

80 

81 # Advance the sequence index if we have skipped a day intentionally 

82 if (self.sequences[self.sequence_index] is None) & (conditions.night-self.last_night_observed > 1): 

83 self.sequence_index = (self.sequence_index + 1) % len(self.sequences) 

84 

85 # If we want to skip this day 

86 if self.sequences[self.sequence_index] is None: 

87 return False 

88 

89 # The usual basis function checks 

90 for bf in self.basis_functions: 

91 result = bf.check_feasibility(conditions) 

92 if not result: 

93 return result 

94 return result 

95 

96 def calc_reward_function(self, conditions): 

97 result = -np.inf 

98 if self._check_feasibility(conditions): 

99 result = self.reward_value 

100 return result 

101 

102 def generate_observations_rough(self, conditions): 

103 result = [] 

104 for key in self.sequences[self.sequence_index]: 

105 # Just skip adding the z-band ones if it's not loaded 

106 if key in conditions.mounted_filters: 

107 for i in np.arange(self.sequences[self.sequence_index][key]): 

108 temp_obs = self.simple_obs.copy() 

109 temp_obs['filter'] = key 

110 # XXX--need to set flush by mjd 

111 result.append(temp_obs) 

112 for i, obs in enumerate(result): 

113 result[i]['flush_by_mjd'] = conditions.mjd + self.approx_times[self.sequence_index] + self.flush_pad 

114 # Just assuming this sequence gets observed. 

115 self.last_night_observed = conditions.night 

116 self.sequence_index = (self.sequence_index + 1) % len(self.sequences) 

117 return result 

118 

119 

120def desc_dd_bfs(RA, dec, survey_name, ha_limits, frac_total=0.0185): 

121 """ 

122 Convienence function to generate all the feasibility basis functions 

123 """ 

124 bfs = [] 

125 bfs.append(basis_functions.Not_twilight_basis_function(sun_alt_limit=-18)) 

126 bfs.append(basis_functions.Time_to_twilight_basis_function(time_needed=30.)) 

127 bfs.append(basis_functions.Hour_Angle_limit_basis_function(RA=RA, ha_limits=ha_limits)) 

128 bfs.append(basis_functions.Rising_more_basis_function(RA=RA)) 

129 bfs.append(basis_functions.Clouded_out_basis_function()) 

130 

131 return bfs 

132 

133 

134def generate_desc_dd_surveys(nside=None, nexp=1, detailers=None): 

135 surveys = [] 

136 

137 # ELAIS S1 

138 RA = 9.45 

139 dec = -44. 

140 survey_name = 'DD:ELAISS1' 

141 ha_limits = ([0., 1.18], [21.82, 24.]) 

142 bfs = desc_dd_bfs(RA, dec, survey_name, ha_limits) 

143 surveys.append(DESC_ddf(bfs, RA, dec, survey_name=survey_name, reward_value=100, 

144 nside=nside, nexp=nexp, detailers=detailers)) 

145 

146 # XMM-LSS 

147 survey_name = 'DD:XMM-LSS' 

148 RA = 35.708333 

149 dec = -4-45/60. 

150 ha_limits = ([0., 1.3], [21.7, 24.]) 

151 bfs = desc_dd_bfs(RA, dec, survey_name, ha_limits) 

152 

153 surveys.append(DESC_ddf(bfs, RA, dec, survey_name=survey_name, reward_value=100, 

154 nside=nside, nexp=nexp, detailers=detailers)) 

155 # Extended Chandra Deep Field South 

156 RA = 53.125 

157 dec = -28.-6/60. 

158 survey_name = 'DD:ECDFS' 

159 ha_limits = [[0.5, 3.0], [20., 22.5]] 

160 bfs = desc_dd_bfs(RA, dec, survey_name, ha_limits) 

161 surveys.append(DESC_ddf(bfs, RA, dec, survey_name=survey_name, reward_value=100, nside=nside, 

162 nexp=nexp, detailers=detailers)) 

163 

164 # COSMOS 

165 RA = 150.1 

166 dec = 2.+10./60.+55/3600. 

167 survey_name = 'DD:COSMOS' 

168 ha_limits = ([0., 1.5], [21.5, 24.]) 

169 bfs = desc_dd_bfs(RA, dec, survey_name, ha_limits) 

170 # have a special sequence for COSMOS 

171 sequences = [{'g': 2, 'r': 4, 'i': 8}, {'z': 25, 'y': 4}] 

172 surveys.append(DESC_ddf(bfs, RA, dec, survey_name=survey_name, reward_value=100, nside=nside, 

173 nexp=nexp, detailers=detailers, sequences=sequences)) 

174 

175 # Just do the two Euclid fields independently for now 

176 survey_name = 'DD:EDFSa' 

177 RA = 58.97 

178 dec = -49.28 

179 ha_limits = ([0., 1.5], [23., 24.]) 

180 bfs = desc_dd_bfs(RA, dec, survey_name, ha_limits) 

181 surveys.append(DESC_ddf(bfs, RA, dec, survey_name=survey_name, reward_value=100, nside=nside, 

182 nexp=nexp, detailers=detailers)) 

183 

184 survey_name = 'DD:EDFSb' 

185 RA = 63.6 

186 dec = -47.60 

187 ha_limits = ([0., 1.5], [23., 24.]) 

188 bfs = desc_dd_bfs(RA, dec, survey_name, ha_limits) 

189 surveys.append(DESC_ddf(bfs, RA, dec, survey_name=survey_name, reward_value=100, nside=nside, 

190 nexp=nexp, detailers=detailers)) 

191 

192 return surveys 

193 

194 pass