Coverage for python/lsst/sims/featureScheduler/surveys/dd_surveys.py : 10%

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
6from lsst.sims.featureScheduler import features
7import logging
8import random
11__all__ = ['Deep_drilling_survey', 'generate_dd_surveys', 'dd_bfs', 'dd_u_bfs']
13log = logging.getLogger(__name__)
16class Deep_drilling_survey(BaseSurvey):
17 """A survey class for running deep drilling fields.
19 Parameters
20 ----------
21 basis_functions : list of lsst.sims.featureScheduler.basis_function objects
22 These should be feasibility basis functions.
23 RA : float
24 The RA of the field (degrees)
25 dec : float
26 The dec of the field to observe (degrees)
27 sequence : list of observation objects or str (rgizy)
28 The sequence of observations to take. Can be a string of list of obs objects.
29 nvis : list of ints
30 The number of visits in each filter. Should be same length as sequence.
31 survey_name : str (DD)
32 The name to give this survey so it can be tracked
33 reward_value : float (101.)
34 The reward value to report if it is able to start (unitless).
35 readtime : float (2.)
36 Readout time for computing approximate time of observing the sequence. (seconds)
37 filter_match_shuffle : bool (True)
38 If True, switch up the order filters are executed in (first sequence will be currently
39 loaded filter if possible)
40 flush_pad : float (30.)
41 How long to hold observations in the queue after they were expected to be completed (minutes).
42 """
44 def __init__(self, basis_functions, RA, dec, sequence='rgizy',
45 nvis=[20, 10, 20, 26, 20],
46 exptime=30., nexp=2, ignore_obs=None, survey_name='DD',
47 reward_value=None, readtime=2., filter_change_time=120.,
48 nside=None, filter_match_shuffle=True, flush_pad=30., seed=42, detailers=None):
49 super(Deep_drilling_survey, self).__init__(nside=nside, basis_functions=basis_functions,
50 detailers=detailers, ignore_obs=ignore_obs)
51 random.seed(a=seed)
53 self.ra = np.radians(RA)
54 self.ra_hours = RA/360.*24.
55 self.dec = np.radians(dec)
56 self.survey_name = survey_name
57 self.reward_value = reward_value
58 self.flush_pad = flush_pad/60./24. # To days
59 self.filter_sequence = []
60 if type(sequence) == str:
61 self.observations = []
62 for num, filtername in zip(nvis, sequence):
63 for j in range(num):
64 obs = empty_observation()
65 obs['filter'] = filtername
66 obs['exptime'] = exptime
67 obs['RA'] = self.ra
68 obs['dec'] = self.dec
69 obs['nexp'] = nexp
70 obs['note'] = survey_name
71 self.observations.append(obs)
72 self.filter_sequence.append(filtername)
73 else:
74 self.observations = sequence
75 self.filter_sequence = [obs['filter'] for obs in sequence]
77 # Make an estimate of how long a seqeunce will take. Assumes no major rotational or spatial
78 # dithering slowing things down.
79 self.approx_time = np.sum([o['exptime']+readtime*o['nexp'] for o in self.observations])/3600./24. \
80 + filter_change_time*len(sequence)/3600./24. # to days
81 self.filter_match_shuffle = filter_match_shuffle
82 self.filter_indices = {}
83 self.filter_sequence = np.array(self.filter_sequence)
84 for filtername in np.unique(self.filter_sequence):
85 self.filter_indices[filtername] = np.where(self.filter_sequence == filtername)[0]
87 if self.reward_value is None:
88 self.extra_features['Ntot'] = features.N_obs_survey()
89 self.extra_features['N_survey'] = features.N_obs_survey(note=self.survey_name)
91 def check_continue(self, observation, conditions):
92 # feasibility basis functions?
93 '''
94 This method enables external calls to check if a given observations that belongs to this survey is
95 feasible or not. This is called once a sequence has started to make sure it can continue.
97 XXX--TODO: Need to decide if we want to develope check_continue, or instead hold the
98 sequence in the survey, and be able to check it that way.
99 '''
101 result = True
103 return result
105 def calc_reward_function(self, conditions):
106 result = -np.inf
107 if self._check_feasibility(conditions):
108 if self.reward_value is not None:
109 result = self.reward_value
110 else:
111 # XXX This might backfire if we want to have DDFs with different fractions of the
112 # survey time. Then might need to define a goal fraction, and have the reward be the
113 # number of observations behind that target fraction.
114 result = self.extra_features['Ntot'].feature / (self.extra_features['N_survey'].feature+1)
115 return result
117 def generate_observations_rough(self, conditions):
118 result = []
119 if self._check_feasibility(conditions):
120 result = copy.deepcopy(self.observations)
122 if self.filter_match_shuffle:
123 filters_remaining = list(self.filter_indices.keys())
124 random.shuffle(filters_remaining)
125 # If we want to observe the currrent filter, put it first
126 if conditions.current_filter in filters_remaining:
127 filters_remaining.insert(0, filters_remaining.pop(filters_remaining.index(conditions.current_filter)))
128 final_result = []
129 for filtername in filters_remaining:
130 final_result.extend(result[np.min(self.filter_indices[filtername]):np.max(self.filter_indices[filtername])+1])
131 result = final_result
132 # Let's set the mjd to flush the queue by
133 for i, obs in enumerate(result):
134 result[i]['flush_by_mjd'] = conditions.mjd + self.approx_time + self.flush_pad
135 return result
138def dd_bfs(RA, dec, survey_name, ha_limits, frac_total=0.0185, aggressive_frac=0.011):
139 """
140 Convienence function to generate all the feasibility basis functions
141 """
142 sun_alt_limit = -18.
143 time_needed = 62.
144 fractions = [0.00, aggressive_frac, frac_total]
145 bfs = []
146 bfs.append(basis_functions.Filter_loaded_basis_function(filternames=['r', 'g', 'i', 'z', 'y']))
147 bfs.append(basis_functions.Not_twilight_basis_function(sun_alt_limit=sun_alt_limit))
148 bfs.append(basis_functions.Time_to_twilight_basis_function(time_needed=time_needed))
149 bfs.append(basis_functions.Hour_Angle_limit_basis_function(RA=RA, ha_limits=ha_limits))
150 bfs.append(basis_functions.Fraction_of_obs_basis_function(frac_total=frac_total, survey_name=survey_name))
151 bfs.append(basis_functions.Look_ahead_ddf_basis_function(frac_total, aggressive_frac,
152 sun_alt_limit=sun_alt_limit, time_needed=time_needed,
153 RA=RA, survey_name=survey_name,
154 ha_limits=ha_limits))
155 bfs.append(basis_functions.Soft_delay_basis_function(fractions=fractions, delays=[0., 0.5, 1.5],
156 survey_name=survey_name))
158 return bfs
161def dd_u_bfs(RA, dec, survey_name, ha_limits, frac_total=0.0019, aggressive_frac=0.0014):
162 """Convienence function to generate all the feasibility basis functions for u-band DDFs
163 """
164 bfs = []
165 sun_alt_limit = -18.
166 time_needed = 6.
167 fractions = [0.00, aggressive_frac, frac_total]
168 bfs.append(basis_functions.Filter_loaded_basis_function(filternames='u'))
169 bfs.append(basis_functions.Not_twilight_basis_function(sun_alt_limit=sun_alt_limit))
170 bfs.append(basis_functions.Time_to_twilight_basis_function(time_needed=time_needed))
171 bfs.append(basis_functions.Hour_Angle_limit_basis_function(RA=RA, ha_limits=ha_limits))
172 bfs.append(basis_functions.Moon_down_basis_function())
173 bfs.append(basis_functions.Fraction_of_obs_basis_function(frac_total=frac_total, survey_name=survey_name))
174 bfs.append(basis_functions.Look_ahead_ddf_basis_function(frac_total, aggressive_frac,
175 sun_alt_limit=sun_alt_limit, time_needed=time_needed,
176 RA=RA, survey_name=survey_name,
177 ha_limits=ha_limits))
178 bfs.append(basis_functions.Soft_delay_basis_function(fractions=fractions, delays=[0., 0.2, 0.5],
179 survey_name=survey_name))
181 return bfs
184def generate_dd_surveys(nside=None, nexp=2, detailers=None, reward_value=100):
185 """Utility to return a list of standard deep drilling field surveys.
187 XXX-Someone double check that I got the coordinates right!
189 """
191 surveys = []
193 # ELAIS S1
194 RA = 9.45
195 dec = -44.
196 survey_name = 'DD:ELAISS1'
197 ha_limits = ([0., 1.5], [22.5, 24.])
198 bfs = dd_bfs(RA, dec, survey_name, ha_limits)
199 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy',
200 nvis=[20, 10, 20, 26, 20],
201 survey_name=survey_name, reward_value=reward_value,
202 nside=nside, nexp=nexp, detailers=detailers))
204 survey_name = 'DD:u,ELAISS1'
205 bfs = dd_u_bfs(RA, dec, survey_name, ha_limits)
207 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u',
208 nvis=[8], survey_name=survey_name, reward_value=reward_value, nside=nside,
209 nexp=nexp, detailers=detailers))
211 # XMM-LSS
212 survey_name = 'DD:XMM-LSS'
213 RA = 35.708333
214 dec = -4-45/60.
215 ha_limits = ([0., 1.5], [22.5, 24.])
216 bfs = dd_bfs(RA, dec, survey_name, ha_limits)
218 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy',
219 nvis=[20, 10, 20, 26, 20], survey_name=survey_name, reward_value=reward_value,
220 nside=nside, nexp=nexp, detailers=detailers))
221 survey_name = 'DD:u,XMM-LSS'
222 bfs = dd_u_bfs(RA, dec, survey_name, ha_limits)
224 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u',
225 nvis=[8], survey_name=survey_name, reward_value=reward_value, nside=nside,
226 nexp=nexp, detailers=detailers))
228 # Extended Chandra Deep Field South
229 # XXX -- this one can pass too close to zenith
230 RA = 53.125
231 dec = -28.-6/60.
232 survey_name = 'DD:ECDFS'
233 ha_limits = [[0.5, 3.0], [20., 22.5]]
234 bfs = dd_bfs(RA, dec, survey_name, ha_limits)
235 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy',
236 nvis=[20, 10, 20, 26, 20],
237 survey_name=survey_name, reward_value=reward_value, nside=nside,
238 nexp=nexp, detailers=detailers))
240 survey_name = 'DD:u,ECDFS'
241 bfs = dd_u_bfs(RA, dec, survey_name, ha_limits)
242 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u',
243 nvis=[8], survey_name=survey_name, reward_value=reward_value, nside=nside,
244 nexp=nexp, detailers=detailers))
245 # COSMOS
246 RA = 150.1
247 dec = 2.+10./60.+55/3600.
248 survey_name = 'DD:COSMOS'
249 ha_limits = ([0., 1.5], [22.5, 24.])
250 bfs = dd_bfs(RA, dec, survey_name, ha_limits)
251 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy',
252 nvis=[20, 10, 20, 26, 20],
253 survey_name=survey_name, reward_value=reward_value, nside=nside,
254 nexp=nexp, detailers=detailers))
255 survey_name = 'DD:u,COSMOS'
256 bfs = dd_u_bfs(RA, dec, survey_name, ha_limits)
257 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u',
258 nvis=[8], survey_name=survey_name, reward_value=reward_value, nside=nside,
259 nexp=nexp, detailers=detailers))
261 # Extra DD Field, just to get to 5. Still not closed on this one
262 survey_name = 'DD:290'
263 RA = 349.386443
264 dec = -63.321004
265 ha_limits = ([0., 1.5], [22.5, 24.])
266 bfs = dd_bfs(RA, dec, survey_name, ha_limits)
267 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy',
268 nvis=[20, 10, 20, 26, 20],
269 survey_name=survey_name, reward_value=reward_value, nside=nside,
270 nexp=nexp, detailers=detailers))
272 survey_name = 'DD:u,290'
273 bfs = dd_u_bfs(RA, dec, survey_name, ha_limits)
274 surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u', nvis=[8],
275 survey_name=survey_name, reward_value=reward_value, nside=nside,
276 nexp=nexp, detailers=detailers))
278 return surveys