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

from __future__ import print_function 

# Collection of utilities for MAF that relate to Opsim specifically. 

 

import os 

import numpy as np 

from .outputUtils import printDict 

 

__all__ = ['writeConfigs', 'getFieldData', 'getSimData', 

'scaleBenchmarks', 'calcCoaddedDepth'] 

 

 

def writeConfigs(opsimDb, outDir): 

""" 

Convenience function to get the configuration information from the opsim database and write 

this information to text files 'configSummary.txt' and 'configDetails.txt'. 

 

Parameters 

---------- 

opsimDb : OpsimDatabase 

The opsim database from which to pull the opsim configuration information. 

Opsim SQLite databases save this configuration information in their config table. 

outputDir : str 

The path to the output directory, where to write the config*.txt files. 

""" 

configSummary, configDetails = opsimDb.fetchConfig() 

outfile = os.path.join(outDir, 'configSummary.txt') 

f = open(outfile, 'w') 

printDict(configSummary, 'Summary', f) 

f.close() 

outfile = os.path.join(outDir, 'configDetails.txt') 

f = open(outfile, 'w') 

printDict(configDetails, 'Details', f) 

f.close() 

 

 

def getFieldData(opsimDb, sqlconstraint): 

""" 

Find the fields (ra/dec/fieldID) relevant for a given sql constraint. 

If the opsimDb contains a Fields table, it uses 

:meth:`OpsimDatabase.fetchFieldsFromFieldTable()` 

to get the fields. If the opsimDb contains only a Summary, it uses 

:meth:`OpsimDatabase.fetchFieldsFromSummaryTable()`. 

 

Parameters 

---------- 

opsimDb : OpsimDatabase 

An opsim database to use to query for field information. 

sqlconstraint : str 

A SQL constraint to apply to the query (i.e. find all fields for DD proposal) 

 

Returns 

------- 

numpy.ndarray 

A numpy structured array containing the field information. This data will ALWAYS be in radians. 

""" 

# Get all fields used for all proposals. 

if 'proposalId' not in sqlconstraint: 

propids, propTags = opsimDb.fetchPropInfo() 

propids = list(propids.keys()) 

else: 

# Parse the propID out of the sqlconstraint. 

# example: sqlconstraint: filter = r and (propid = 219 or propid = 155) and propid!= 90 

sqlconstraint = sqlconstraint.replace('=', ' = ').replace('(', '').replace(')', '') 

sqlconstraint = sqlconstraint.replace("'", '').replace('"', '') 

# Allow for choosing all but a particular proposal. 

sqlconstraint = sqlconstraint.replace('! =', ' !=') 

sqlconstraint = sqlconstraint.replace(' ', ' ') 

sqllist = sqlconstraint.split(' ') 

propids = [] 

nonpropids = [] 

i = 0 

while i < len(sqllist): 

if sqllist[i].lower() == 'proposalid': 

i += 1 

if sqllist[i] == "=": 

i += 1 

propids.append(int(sqllist[i])) 

elif sqllist[i] == '!=': 

i += 1 

nonpropids.append(int(sqllist[i])) 

i += 1 

if len(propids) == 0: 

propids, propTags = opsimDb.fetchPropInfo() 

propids = list(propids.keys()) 

if len(nonpropids) > 0: 

for nonpropid in nonpropids: 

if nonpropid in propids: 

propids.remove(nonpropid) 

# And query the field Table. 

if 'Field' in opsimDb.tables: 

# The field table is always in degrees. 

fieldData = opsimDb.fetchFieldsFromFieldTable(propids, degreesToRadians=True) 

# Or give up and query the summary table. 

else: 

fieldData = opsimDb.fetchFieldsFromSummaryTable(sqlconstraint) 

return fieldData 

 

 

def getSimData(opsimDb, sqlconstraint, dbcols, stackers=None, groupBy='default', tableName=None): 

""" 

Query an opsim database for the needed data columns and run any required stackers. 

 

Parameters 

---------- 

opsimDb : OpsimDatabase 

sqlconstraint : str 

SQL constraint to apply to query for observations. 

dbcols : list of str 

Columns required from the database. 

stackers : list of Stackers 

Stackers to be used to generate additional columns. 

tableName : str 

Name of the table to query. 

distinctExpMJD : bool 

Only select observations with a distinct expMJD value. This is overriden if groupBy is not expMJD. 

groupBy : str 

Column name to group SQL results by. 

 

Returns 

------- 

numpy.ndarray 

A numpy structured array with columns resulting from dbcols + stackers, for observations matching 

the SQLconstraint. 

""" 

# Get data from database. 

simData = opsimDb.fetchMetricData(dbcols, sqlconstraint, groupBy=groupBy, tableName=tableName) 

if len(simData) == 0: 

raise UserWarning('No data found matching sqlconstraint %s' % (sqlconstraint)) 

# Now add the stacker columns. 

if stackers is not None: 

for s in stackers: 

simData = s.run(simData) 

return simData 

 

 

def scaleBenchmarks(runLength, benchmark='design'): 

""" 

Set the design and stretch values of the number of visits, area of the footprint, 

seeing values, FWHMeff values, skybrightness, and single visit depth (based on SRD values). 

Scales number of visits for the length of the run, relative to 10 years. 

 

Parameters 

---------- 

runLength : float 

The length (in years) of the run. 

benchmark : str 

design or stretch - which version of the SRD values to return. 

requested is another option, in which case the values of the number of visits requested 

by the OpSim run (recorded in the Config table) is returned. 

 

Returns 

------- 

dict of floats 

A dictionary containing the number of visits, area of footprint, seeing and FWHMeff values, 

skybrightness and single visit depth for either the design or stretch SRD values. 

""" 

# Set baseline (default) numbers for the baseline survey length (10 years). 

baseline = 10. 

 

design = {} 

stretch = {} 

 

design['nvisitsTotal'] = 825 

stretch['nvisitsTotal'] = 1000 

design['Area'] = 18000 

stretch['Area'] = 20000 

 

design['nvisits']={'u':56,'g':80, 'r':184, 'i':184, 'z':160, 'y':160} 

stretch['nvisits']={'u':70,'g':100, 'r':230, 'i':230, 'z':200, 'y':200} 

 

design['skybrightness'] = {'u':21.8, 'g':22., 'r':21.3, 'i':20.0, 'z':19.1, 'y':17.5} # mag/sq arcsec 

stretch['skybrightness'] = {'u':21.8, 'g':22., 'r':21.3, 'i':20.0, 'z':19.1, 'y':17.5} 

 

design['seeing'] = {'u':0.77, 'g':0.73, 'r':0.7, 'i':0.67, 'z':0.65, 'y':0.63} # arcsec - old seeing values 

stretch['seeing'] = {'u':0.77, 'g':0.73, 'r':0.7, 'i':0.67, 'z':0.65, 'y':0.63} 

 

design['FWHMeff'] = {'u':0.92, 'g':0.87, 'r':0.83, 'i':0.80, 'z':0.78, 'y':0.76} # arcsec - new FWHMeff values (scaled from old seeing) 

stretch['FWHMeff'] = {'u':0.92, 'g':0.87, 'r':0.83, 'i':0.80, 'z':0.78, 'y':0.76} 

 

design['singleVisitDepth'] = {'u':23.9,'g':25.0, 'r':24.7, 'i':24.0, 'z':23.3, 'y':22.1} 

stretch['singleVisitDepth'] = {'u':24.0,'g':25.1, 'r':24.8, 'i':24.1, 'z':23.4, 'y':22.2} 

 

# Scale the number of visits. 

if runLength != baseline: 

scalefactor = float(runLength) / float(baseline) 

# Calculate scaled value for design and stretch values of nvisits, per filter. 

for f in design['nvisits']: 

design['nvisits'][f] = int(np.floor(design['nvisits'][f] * scalefactor)) 

stretch['nvisits'][f] = int(np.floor(stretch['nvisits'][f] * scalefactor)) 

 

if benchmark == 'design': 

return design 

elif benchmark == 'stretch': 

return stretch 

else: 

raise ValueError("Benchmark value %s not understood: use 'design' or 'stretch'" % (benchmark)) 

 

 

def calcCoaddedDepth(nvisits, singleVisitDepth): 

""" 

Calculate the coadded depth expected for a given number of visits and single visit depth. 

 

Parameters 

---------- 

nvisits : dict of ints or floats 

Dictionary (per filter) of number of visits 

singleVisitDepth : dict of floats 

Dictionary (per filter) of the single visit depth 

 

Returns 

------- 

dict of floats 

Dictionary of coadded depths per filter. 

""" 

coaddedDepth = {} 

for f in nvisits: 

if f not in singleVisitDepth: 

raise ValueError('Filter keys in nvisits and singleVisitDepth must match') 

coaddedDepth[f] = float(1.25 * np.log10(nvisits[f] * 10**(0.8*singleVisitDepth[f]))) 

if not np.isfinite(coaddedDepth[f]): 

coaddedDepth[f] = singleVisitDepth[f] 

return coaddedDepth