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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

import numpy as np 

from lsst.sims.featureScheduler.surveys import BaseSurvey 

import copy 

import lsst.sims.featureScheduler.basis_functions as basis_functions 

from lsst.sims.featureScheduler.utils import empty_observation 

from lsst.sims.featureScheduler import features 

import logging 

import random 

 

 

__all__ = ['Deep_drilling_survey', 'generate_dd_surveys', 'dd_bfs', 'dd_u_bfs'] 

 

log = logging.getLogger(__name__) 

 

 

class Deep_drilling_survey(BaseSurvey): 

"""A survey class for running deep drilling fields. 

 

Parameters 

---------- 

basis_functions : list of lsst.sims.featureScheduler.basis_function objects 

These should be feasibility basis functions. 

RA : float 

The RA of the field (degrees) 

dec : float 

The dec of the field to observe (degrees) 

sequence : list of observation objects or str (rgizy) 

The sequence of observations to take. Can be a string of list of obs objects. 

nvis : list of ints 

The number of visits in each filter. Should be same length as sequence. 

survey_name : str (DD) 

The name to give this survey so it can be tracked 

reward_value : float (101.) 

The reward value to report if it is able to start (unitless). 

readtime : float (2.) 

Readout time for computing approximate time of observing the sequence. (seconds) 

filter_match_shuffle : bool (True) 

If True, switch up the order filters are executed in (first sequence will be currently 

loaded filter if possible) 

flush_pad : float (30.) 

How long to hold observations in the queue after they were expected to be completed (minutes). 

""" 

 

def __init__(self, basis_functions, RA, dec, sequence='rgizy', 

nvis=[20, 10, 20, 26, 20], 

exptime=30., nexp=2, ignore_obs=None, survey_name='DD', 

reward_value=None, readtime=2., filter_change_time=120., 

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

super(Deep_drilling_survey, self).__init__(nside=nside, basis_functions=basis_functions, 

detailers=detailers, ignore_obs=ignore_obs) 

random.seed(a=seed) 

 

self.ra = np.radians(RA) 

self.ra_hours = RA/360.*24. 

self.dec = np.radians(dec) 

self.survey_name = survey_name 

self.reward_value = reward_value 

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

self.filter_sequence = [] 

if type(sequence) == str: 

self.observations = [] 

for num, filtername in zip(nvis, sequence): 

for j in range(num): 

obs = empty_observation() 

obs['filter'] = filtername 

obs['exptime'] = exptime 

obs['RA'] = self.ra 

obs['dec'] = self.dec 

obs['nexp'] = nexp 

obs['note'] = survey_name 

self.observations.append(obs) 

self.filter_sequence.append(filtername) 

else: 

self.observations = sequence 

self.filter_sequence = [obs['filter'] for obs in sequence] 

 

# Make an estimate of how long a seqeunce will take. Assumes no major rotational or spatial 

# dithering slowing things down. 

self.approx_time = np.sum([o['exptime']+readtime*o['nexp'] for o in self.observations])/3600./24. \ 

+ filter_change_time*len(sequence)/3600./24. # to days 

self.filter_match_shuffle = filter_match_shuffle 

self.filter_indices = {} 

self.filter_sequence = np.array(self.filter_sequence) 

for filtername in np.unique(self.filter_sequence): 

self.filter_indices[filtername] = np.where(self.filter_sequence == filtername)[0] 

 

if self.reward_value is None: 

self.extra_features['Ntot'] = features.N_obs_survey() 

self.extra_features['N_survey'] = features.N_obs_survey(note=self.survey_name) 

 

def check_continue(self, observation, conditions): 

# feasibility basis functions? 

''' 

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

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

 

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

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

''' 

 

result = True 

 

return result 

 

def calc_reward_function(self, conditions): 

result = -np.inf 

if self._check_feasibility(conditions): 

if self.reward_value is not None: 

result = self.reward_value 

else: 

# XXX This might backfire if we want to have DDFs with different fractions of the 

# survey time. Then might need to define a goal fraction, and have the reward be the 

# number of observations behind that target fraction. 

result = self.extra_features['Ntot'].feature / (self.extra_features['N_survey'].feature+1) 

return result 

 

def generate_observations_rough(self, conditions): 

result = [] 

if self._check_feasibility(conditions): 

result = copy.deepcopy(self.observations) 

 

if self.filter_match_shuffle: 

filters_remaining = list(self.filter_indices.keys()) 

random.shuffle(filters_remaining) 

# If we want to observe the currrent filter, put it first 

if conditions.current_filter in filters_remaining: 

filters_remaining.insert(0, filters_remaining.pop(filters_remaining.index(conditions.current_filter))) 

final_result = [] 

for filtername in filters_remaining: 

final_result.extend(result[np.min(self.filter_indices[filtername]):np.max(self.filter_indices[filtername])+1]) 

result = final_result 

# Let's set the mjd to flush the queue by 

for i, obs in enumerate(result): 

result[i]['flush_by_mjd'] = conditions.mjd + self.approx_time + self.flush_pad 

return result 

 

 

def dd_bfs(RA, dec, survey_name, ha_limits, frac_total=0.0185, aggressive_frac=0.011): 

""" 

Convienence function to generate all the feasibility basis functions 

""" 

sun_alt_limit = -18. 

time_needed = 62. 

fractions = [0.00, aggressive_frac, frac_total] 

bfs = [] 

bfs.append(basis_functions.Filter_loaded_basis_function(filternames=['r', 'g', 'i', 'z', 'y'])) 

bfs.append(basis_functions.Not_twilight_basis_function(sun_alt_limit=sun_alt_limit)) 

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

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

bfs.append(basis_functions.Fraction_of_obs_basis_function(frac_total=frac_total, survey_name=survey_name)) 

bfs.append(basis_functions.Look_ahead_ddf_basis_function(frac_total, aggressive_frac, 

sun_alt_limit=sun_alt_limit, time_needed=time_needed, 

RA=RA, survey_name=survey_name, 

ha_limits=ha_limits)) 

bfs.append(basis_functions.Soft_delay_basis_function(fractions=fractions, delays=[0., 0.5, 1.5], 

survey_name=survey_name)) 

 

return bfs 

 

 

def dd_u_bfs(RA, dec, survey_name, ha_limits, frac_total=0.0019, aggressive_frac=0.0014): 

"""Convienence function to generate all the feasibility basis functions for u-band DDFs 

""" 

bfs = [] 

sun_alt_limit = -18. 

time_needed = 6. 

fractions = [0.00, aggressive_frac, frac_total] 

bfs.append(basis_functions.Filter_loaded_basis_function(filternames='u')) 

bfs.append(basis_functions.Not_twilight_basis_function(sun_alt_limit=sun_alt_limit)) 

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

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

bfs.append(basis_functions.Moon_down_basis_function()) 

bfs.append(basis_functions.Fraction_of_obs_basis_function(frac_total=frac_total, survey_name=survey_name)) 

bfs.append(basis_functions.Look_ahead_ddf_basis_function(frac_total, aggressive_frac, 

sun_alt_limit=sun_alt_limit, time_needed=time_needed, 

RA=RA, survey_name=survey_name, 

ha_limits=ha_limits)) 

bfs.append(basis_functions.Soft_delay_basis_function(fractions=fractions, delays=[0., 0.2, 0.5], 

survey_name=survey_name)) 

 

return bfs 

 

 

def generate_dd_surveys(nside=None, nexp=2, detailers=None, reward_value=100): 

"""Utility to return a list of standard deep drilling field surveys. 

 

XXX-Someone double check that I got the coordinates right! 

 

""" 

 

surveys = [] 

 

# ELAIS S1 

RA = 9.45 

dec = -44. 

survey_name = 'DD:ELAISS1' 

ha_limits = ([0., 1.5], [22.5, 24.]) 

bfs = dd_bfs(RA, dec, survey_name, ha_limits) 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy', 

nvis=[20, 10, 20, 26, 20], 

survey_name=survey_name, reward_value=reward_value, 

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

 

survey_name = 'DD:u,ELAISS1' 

bfs = dd_u_bfs(RA, dec, survey_name, ha_limits) 

 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u', 

nvis=[8], survey_name=survey_name, reward_value=reward_value, nside=nside, 

nexp=nexp, detailers=detailers)) 

 

# XMM-LSS 

survey_name = 'DD:XMM-LSS' 

RA = 35.708333 

dec = -4-45/60. 

ha_limits = ([0., 1.5], [22.5, 24.]) 

bfs = dd_bfs(RA, dec, survey_name, ha_limits) 

 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy', 

nvis=[20, 10, 20, 26, 20], survey_name=survey_name, reward_value=reward_value, 

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

survey_name = 'DD:u,XMM-LSS' 

bfs = dd_u_bfs(RA, dec, survey_name, ha_limits) 

 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u', 

nvis=[8], survey_name=survey_name, reward_value=reward_value, nside=nside, 

nexp=nexp, detailers=detailers)) 

 

# Extended Chandra Deep Field South 

# XXX -- this one can pass too close to zenith 

RA = 53.125 

dec = -28.-6/60. 

survey_name = 'DD:ECDFS' 

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

bfs = dd_bfs(RA, dec, survey_name, ha_limits) 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy', 

nvis=[20, 10, 20, 26, 20], 

survey_name=survey_name, reward_value=reward_value, nside=nside, 

nexp=nexp, detailers=detailers)) 

 

survey_name = 'DD:u,ECDFS' 

bfs = dd_u_bfs(RA, dec, survey_name, ha_limits) 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u', 

nvis=[8], survey_name=survey_name, reward_value=reward_value, nside=nside, 

nexp=nexp, detailers=detailers)) 

# COSMOS 

RA = 150.1 

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

survey_name = 'DD:COSMOS' 

ha_limits = ([0., 1.5], [22.5, 24.]) 

bfs = dd_bfs(RA, dec, survey_name, ha_limits) 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy', 

nvis=[20, 10, 20, 26, 20], 

survey_name=survey_name, reward_value=reward_value, nside=nside, 

nexp=nexp, detailers=detailers)) 

survey_name = 'DD:u,COSMOS' 

bfs = dd_u_bfs(RA, dec, survey_name, ha_limits) 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u', 

nvis=[8], survey_name=survey_name, reward_value=reward_value, nside=nside, 

nexp=nexp, detailers=detailers)) 

 

# Extra DD Field, just to get to 5. Still not closed on this one 

survey_name = 'DD:290' 

RA = 349.386443 

dec = -63.321004 

ha_limits = ([0., 1.5], [22.5, 24.]) 

bfs = dd_bfs(RA, dec, survey_name, ha_limits) 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='rgizy', 

nvis=[20, 10, 20, 26, 20], 

survey_name=survey_name, reward_value=reward_value, nside=nside, 

nexp=nexp, detailers=detailers)) 

 

survey_name = 'DD:u,290' 

bfs = dd_u_bfs(RA, dec, survey_name, ha_limits) 

surveys.append(Deep_drilling_survey(bfs, RA, dec, sequence='u', nvis=[8], 

survey_name=survey_name, reward_value=reward_value, nside=nside, 

nexp=nexp, detailers=detailers)) 

 

return surveys