Coverage for python/lsst/sims/maf/utils/opsimUtils.py : 8%

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
1from __future__ import print_function
2# Collection of utilities for MAF that relate to Opsim specifically.
4import os
5import numpy as np
6from .outputUtils import printDict
8__all__ = ['writeConfigs', 'getFieldData', 'getSimData',
9 'scaleBenchmarks', 'calcCoaddedDepth']
12def writeConfigs(opsimDb, outDir):
13 """
14 Convenience function to get the configuration information from the opsim database and write
15 this information to text files 'configSummary.txt' and 'configDetails.txt'.
17 Parameters
18 ----------
19 opsimDb : OpsimDatabase
20 The opsim database from which to pull the opsim configuration information.
21 Opsim SQLite databases save this configuration information in their config table.
22 outputDir : str
23 The path to the output directory, where to write the config*.txt files.
24 """
25 configSummary, configDetails = opsimDb.fetchConfig()
26 outfile = os.path.join(outDir, 'configSummary.txt')
27 f = open(outfile, 'w')
28 printDict(configSummary, 'Summary', f)
29 f.close()
30 outfile = os.path.join(outDir, 'configDetails.txt')
31 f = open(outfile, 'w')
32 printDict(configDetails, 'Details', f)
33 f.close()
36def getFieldData(opsimDb, sqlconstraint):
37 """
38 Find the fields (ra/dec/fieldID) relevant for a given sql constraint.
39 If the opsimDb contains a Fields table, it uses
40 :meth:`OpsimDatabase.fetchFieldsFromFieldTable()`
41 to get the fields. If the opsimDb contains only a Summary, it uses
42 :meth:`OpsimDatabase.fetchFieldsFromSummaryTable()`.
44 Parameters
45 ----------
46 opsimDb : OpsimDatabase
47 An opsim database to use to query for field information.
48 sqlconstraint : str
49 A SQL constraint to apply to the query (i.e. find all fields for DD proposal)
51 Returns
52 -------
53 numpy.ndarray
54 A numpy structured array containing the field information. This data will ALWAYS be in radians.
55 """
56 # Get all fields used for all proposals.
57 if 'proposalId' not in sqlconstraint:
58 propids, propTags = opsimDb.fetchPropInfo()
59 propids = list(propids.keys())
60 else:
61 # Parse the propID out of the sqlconstraint.
62 # example: sqlconstraint: filter = r and (propid = 219 or propid = 155) and propid!= 90
63 sqlconstraint = sqlconstraint.replace('=', ' = ').replace('(', '').replace(')', '')
64 sqlconstraint = sqlconstraint.replace("'", '').replace('"', '')
65 # Allow for choosing all but a particular proposal.
66 sqlconstraint = sqlconstraint.replace('! =', ' !=')
67 sqlconstraint = sqlconstraint.replace(' ', ' ')
68 sqllist = sqlconstraint.split(' ')
69 propids = []
70 nonpropids = []
71 i = 0
72 while i < len(sqllist):
73 if sqllist[i].lower() == 'proposalid':
74 i += 1
75 if sqllist[i] == "=":
76 i += 1
77 propids.append(int(sqllist[i]))
78 elif sqllist[i] == '!=':
79 i += 1
80 nonpropids.append(int(sqllist[i]))
81 i += 1
82 if len(propids) == 0:
83 propids, propTags = opsimDb.fetchPropInfo()
84 propids = list(propids.keys())
85 if len(nonpropids) > 0:
86 for nonpropid in nonpropids:
87 if nonpropid in propids:
88 propids.remove(nonpropid)
89 # And query the field Table.
90 if 'Field' in opsimDb.tables:
91 # The field table is always in degrees.
92 fieldData = opsimDb.fetchFieldsFromFieldTable(propids, degreesToRadians=True)
93 # Or give up and query the summary table.
94 else:
95 fieldData = opsimDb.fetchFieldsFromSummaryTable(sqlconstraint)
96 return fieldData
99def getSimData(opsimDb, sqlconstraint, dbcols, stackers=None, groupBy='default', tableName=None):
100 """
101 Query an opsim database for the needed data columns and run any required stackers.
103 Parameters
104 ----------
105 opsimDb : OpsimDatabase
106 sqlconstraint : str
107 SQL constraint to apply to query for observations.
108 dbcols : list of str
109 Columns required from the database.
110 stackers : list of Stackers
111 Stackers to be used to generate additional columns.
112 tableName : str
113 Name of the table to query.
114 distinctExpMJD : bool
115 Only select observations with a distinct expMJD value. This is overriden if groupBy is not expMJD.
116 groupBy : str
117 Column name to group SQL results by.
119 Returns
120 -------
121 numpy.ndarray
122 A numpy structured array with columns resulting from dbcols + stackers, for observations matching
123 the SQLconstraint.
124 """
125 # Get data from database.
126 simData = opsimDb.fetchMetricData(dbcols, sqlconstraint, groupBy=groupBy, tableName=tableName)
127 if len(simData) == 0:
128 raise UserWarning('No data found matching sqlconstraint %s' % (sqlconstraint))
129 # Now add the stacker columns.
130 if stackers is not None:
131 for s in stackers:
132 simData = s.run(simData)
133 return simData
136def scaleBenchmarks(runLength, benchmark='design'):
137 """
138 Set the design and stretch values of the number of visits, area of the footprint,
139 seeing values, FWHMeff values, skybrightness, and single visit depth (based on SRD values).
140 Scales number of visits for the length of the run, relative to 10 years.
142 Parameters
143 ----------
144 runLength : float
145 The length (in years) of the run.
146 benchmark : str
147 design or stretch - which version of the SRD values to return.
148 requested is another option, in which case the values of the number of visits requested
149 by the OpSim run (recorded in the Config table) is returned.
151 Returns
152 -------
153 dict of floats
154 A dictionary containing the number of visits, area of footprint, seeing and FWHMeff values,
155 skybrightness and single visit depth for either the design or stretch SRD values.
156 """
157 # Set baseline (default) numbers for the baseline survey length (10 years).
158 baseline = 10.
160 design = {}
161 stretch = {}
163 design['nvisitsTotal'] = 825
164 stretch['nvisitsTotal'] = 1000
165 design['Area'] = 18000
166 stretch['Area'] = 20000
168 design['nvisits']={'u':56,'g':80, 'r':184, 'i':184, 'z':160, 'y':160}
169 stretch['nvisits']={'u':70,'g':100, 'r':230, 'i':230, 'z':200, 'y':200}
171 design['skybrightness'] = {'u':21.8, 'g':22., 'r':21.3, 'i':20.0, 'z':19.1, 'y':17.5} # mag/sq arcsec
172 stretch['skybrightness'] = {'u':21.8, 'g':22., 'r':21.3, 'i':20.0, 'z':19.1, 'y':17.5}
174 design['seeing'] = {'u':0.77, 'g':0.73, 'r':0.7, 'i':0.67, 'z':0.65, 'y':0.63} # arcsec - old seeing values
175 stretch['seeing'] = {'u':0.77, 'g':0.73, 'r':0.7, 'i':0.67, 'z':0.65, 'y':0.63}
177 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)
178 stretch['FWHMeff'] = {'u':0.92, 'g':0.87, 'r':0.83, 'i':0.80, 'z':0.78, 'y':0.76}
180 design['singleVisitDepth'] = {'u':23.9,'g':25.0, 'r':24.7, 'i':24.0, 'z':23.3, 'y':22.1}
181 stretch['singleVisitDepth'] = {'u':24.0,'g':25.1, 'r':24.8, 'i':24.1, 'z':23.4, 'y':22.2}
183 # Scale the number of visits.
184 if runLength != baseline:
185 scalefactor = float(runLength) / float(baseline)
186 # Calculate scaled value for design and stretch values of nvisits, per filter.
187 for f in design['nvisits']:
188 design['nvisits'][f] = int(np.floor(design['nvisits'][f] * scalefactor))
189 stretch['nvisits'][f] = int(np.floor(stretch['nvisits'][f] * scalefactor))
191 if benchmark == 'design':
192 return design
193 elif benchmark == 'stretch':
194 return stretch
195 else:
196 raise ValueError("Benchmark value %s not understood: use 'design' or 'stretch'" % (benchmark))
199def calcCoaddedDepth(nvisits, singleVisitDepth):
200 """
201 Calculate the coadded depth expected for a given number of visits and single visit depth.
203 Parameters
204 ----------
205 nvisits : dict of ints or floats
206 Dictionary (per filter) of number of visits
207 singleVisitDepth : dict of floats
208 Dictionary (per filter) of the single visit depth
210 Returns
211 -------
212 dict of floats
213 Dictionary of coadded depths per filter.
214 """
215 coaddedDepth = {}
216 for f in nvisits:
217 if f not in singleVisitDepth:
218 raise ValueError('Filter keys in nvisits and singleVisitDepth must match')
219 coaddedDepth[f] = float(1.25 * np.log10(nvisits[f] * 10**(0.8*singleVisitDepth[f])))
220 if not np.isfinite(coaddedDepth[f]):
221 coaddedDepth[f] = singleVisitDepth[f]
222 return coaddedDepth