Skip to content
This repository was archived by the owner on May 19, 2025. It is now read-only.

Commit 162e7d1

Browse files
committed
Merge pull request #36 from lsst/feature/SIM-1318-update-opsimMovies
Feature/sim 1318 update opsim movies
2 parents ebd200a + 3ec8743 commit 162e7d1

File tree

4 files changed

+107
-95
lines changed

4 files changed

+107
-95
lines changed

examples/pythonScripts/opsimMovie.py

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# python $SIMS_MAF_DIR/examples/pythonScripts/opsimMovie.py ops2_1088_sqlite.db --sqlConstraint 'night=130' --outDir Output
1+
# python $SIMS_MAF_DIR/examples/pythonScripts/opsimMovie.py enigma_1189_sqlite.db --sqlConstraint 'night=130' --outDir Output
22
#
33
# --ips = number of images to stitch together per second of view (default is 10).
44
# --fps = frames per second for the output video .. default just matches ips. If specified as higher than ips,
@@ -22,7 +22,8 @@
2222
import lsst.sims.maf.slicers as slicers
2323
import lsst.sims.maf.metrics as metrics
2424
import lsst.sims.maf.stackers as stackers
25-
import lsst.sims.maf.sliceMetrics as sliceMetrics
25+
import lsst.sims.maf.metricBundles as metricBundles
26+
import lsst.sims.maf.plots as plots
2627
from lsst.sims.maf.utils import TelescopeInfo
2728

2829
import time
@@ -53,31 +54,29 @@ def getData(opsDb, sqlconstraint):
5354

5455
def setupMetrics(opsimName, metadata, plotlabel='', t0=0, tStep=40./24./60./60., years=0,
5556
onlyFilterColors=False, verbose=False):
56-
# Set up metrics. Will apply one to ms and one to ms_curr, but note that
57-
# because of the nature of this script, the metrics are applied to cumulative data (from all filters).
57+
# Set up metrics and plotDicts (they will be bundled with the appropriate opsim slicers below).
5858
t = time.time()
5959
nvisitsMax = 90*(years+1)
6060
colorMax = int(nvisitsMax/4)
6161
metricList = []
62+
plotDictList = []
6263
if not onlyFilterColors:
63-
metricList.append(metrics.CountMetric('expMJD', metricName='Nvisits',
64-
plotDict={'colorMin':0, 'colorMax':nvisitsMax,
65-
'xlabel':'Number of visits',
66-
'title':'Cumulative visits (all bands)'}))
64+
metricList.append(metrics.CountMetric('expMJD', metricName='Nvisits'))
65+
plotDictList.append({'colorMin':0, 'colorMax':nvisitsMax,
66+
'xlabel':'Number of visits', 'title':'Cumulative visits (all bands)',
67+
'label':plotlabel, 'metricIsColor':False})
6768
for f in (['u', 'g', 'r', 'i', 'z', 'y']):
68-
metricList.append(metrics.CountSubsetMetric('filter', subset=f, metricName='Nvisits_'+f,
69-
plotDict={'colorMin':0, 'colorMax':colorMax,
70-
'cbarFormat': '%d', 'xlabel':'Number of Visits',
71-
'title':'%s band' %(f)}))
72-
# Apply plotlabel only to nvisits plots (will place it on FilterColors by hand).
73-
for m in metricList:
74-
m.plotDict['label'] = plotlabel
75-
metricList.append(metrics.FilterColorsMetric(t0=t0, tStep=tStep,
76-
plotDict={'title':'Simulation %s: %s' %(opsimName, metadata)}))
69+
metricList.append(metrics.CountSubsetMetric('filter', subset=f, metricName='Nvisits_'+f))
70+
plotDictList.append({'colorMin':0, 'colorMax':colorMax, 'cbarFormat': '%d',
71+
'xlabel':'Number of Visits', 'title':'%s band' %(f),
72+
'label':plotlabel, 'metricIsColor':False})
73+
metricList.append(metrics.FilterColorsMetric(t0=t0, tStep=tStep))
74+
plotDictList.append({'title':'Simulation %s: %s' %(opsimName, metadata), 'bgcolor':None,
75+
'metricIsColor':True})
7776
dt, t = dtime(t)
7877
if verbose:
7978
print 'Set up metrics %f s' %(dt)
80-
return metricList
79+
return metricList, plotDictList
8180

8281
def setupMovieSlicer(simdata, bins, verbose=False):
8382
t = time.time()
@@ -88,15 +87,6 @@ def setupMovieSlicer(simdata, bins, verbose=False):
8887
print 'Set up movie slicers in %f s' %(dt)
8988
return movieslicer
9089

91-
def setupOpsimFieldSlicer(verbose=False):
92-
t = time.time()
93-
ops = slicers.OpsimFieldSlicer(plotFuncs='plotSkyMap')
94-
dt, t = dtime(t)
95-
if verbose:
96-
print 'Set up opsim field slicer in %s' %(dt)
97-
return ops
98-
99-
10090
def addHorizon(horizon_altitude=np.radians(20.), lat_telescope=TelescopeInfo('LSST').lat, raCen=0.):
10191
"""
10292
Adds a horizon at horizon_altitude, using the telescope latitude lat_telescope.
@@ -124,7 +114,7 @@ def addHorizon(horizon_altitude=np.radians(20.), lat_telescope=TelescopeInfo('LS
124114
lon = -(lon - np.pi) % (np.pi*2) - np.pi
125115
return lon, lat
126116

127-
def runSlices(opsimName, metadata, simdata, fields, bins, args, verbose=False):
117+
def runSlices(opsimName, metadata, simdata, fields, bins, args, opsDb, verbose=False):
128118
# Set up the movie slicer.
129119
movieslicer = setupMovieSlicer(simdata, bins)
130120
# Set up formatting for output suffix.
@@ -151,34 +141,49 @@ def runSlices(opsimName, metadata, simdata, fields, bins, args, verbose=False):
151141
days = times_from_start - years*365
152142
plotlabel = 'Year %d Day %.4f' %(years, days)
153143
# Set up metrics.
154-
metricList = setupMetrics(opsimName, metadata, plotlabel=plotlabel,
144+
metricList, plotDictList = setupMetrics(opsimName, metadata, plotlabel=plotlabel,
155145
t0=ms['slicePoint']['binRight'], tStep=tstep, years=years, verbose=verbose)
156146
# Identify the subset of simdata in the movieslicer 'data slice'
157147
simdatasubset = simdata[ms['idxs']]
158148
# Set up opsim slicer on subset of simdata provided by movieslicer
159-
ops = setupOpsimFieldSlicer()
160-
# Set up sliceMetric to handle healpix slicer + metrics calculation + plotting
161-
sm = sliceMetrics.RunSliceMetric(outDir = args.outDir, useResultsDb=False,
162-
figformat='png', dpi=72, thumbnail=False)
163-
sm.setMetricsSlicerStackers(metricList, ops)
164-
sm.runSlices(simdatasubset, simDataName=opsimName, fieldData=fields)
149+
opslicer = slicers.OpsimFieldSlicer()
150+
# Set up metricBundles to combine metrics, plotdicts and slicer.
151+
bundles = []
152+
sqlconstraint = ''
153+
for metric, plotDict in zip(metricList, plotDictList):
154+
bundles.append(metricBundles.MetricBundle(metric, opslicer, sqlconstraint=sqlconstraint,
155+
metadata=metadata, runName=opsimName,
156+
plotDict=plotDict))
157+
# Remove (default) stackers from bundles, because we've already run them above on the original data.
158+
for mb in bundles:
159+
mb.stackerList = []
160+
bundledict = metricBundles.makeBundlesDictFromList(bundles)
161+
# Set up metricBundleGroup to handle metrics calculation + plotting
162+
bg = metricBundles.MetricBundleGroup(bundledict, opsDb, outDir=args.outDir, resultsDb=None, saveEarly=False)
163+
# 'Hack' bundleGroup to just go ahead and run the metrics, without querying the database.
164+
simData = simdatasubset
165+
bg.fieldData = fields
166+
bg.setCurrent(sqlconstraint)
167+
bg.runCurrent(sqlconstraint = sqlconstraint, simData=simData)
165168
# Plot data each metric, for this slice of the movie, adding slicenumber as a suffix for output plots.
166169
# Plotting here, rather than automatically via sliceMetric method because we're going to rotate the sky,
167170
# and add extra legend info and figure text (for FilterColors metric).
171+
ph = plots.PlotHandler(outDir=args.outDir, figformat='png', dpi=72, thumbnail=False, savefig=False)
168172
obsnow = np.where(simdatasubset['expMJD'] == simdatasubset['expMJD'].max())[0]
169173
raCen = np.mean(simdatasubset[obsnow]['lst'])
170174
# Calculate horizon location.
171175
horizonlon, horizonlat = addHorizon(lat_telescope=lat_tele, raCen=raCen)
172-
# Create the plot for each metric.
173-
for mId in sm.metricValues:
174-
fignum = ops.plotSkyMap(sm.metricValues[mId], raCen=raCen, **sm.plotDicts[mId])
176+
# Create the plot for each metric and save it (after some additional manipulation).
177+
for mb in bundles:
178+
ph.setMetricBundles([mb])
179+
fignum = ph.plot(plotFunc=plots.BaseSkyMap(), plotDicts={'raCen':raCen})
175180
fig = plt.figure(fignum)
176181
ax = plt.gca()
177182
# Add horizon and zenith.
178183
plt.plot(horizonlon, horizonlat, 'k.', alpha=0.3, markersize=1.8)
179184
plt.plot(0, lat_tele, 'k+')
180185
# For the FilterColors metric, add some extra items.
181-
if sm.metricNames[mId] == 'FilterColors':
186+
if mb.metric.name == 'FilterColors':
182187
# Add the time stamp info (plotlabel) with a fancybox.
183188
plt.figtext(0.75, 0.9, '%s' %(plotlabel), bbox=dict(boxstyle='Round, pad=0.7', fc='w', ec='k', alpha=0.5))
184189
# Add a legend for the filters.
@@ -204,7 +209,7 @@ def runSlices(opsimName, metadata, simdata, fields, bins, args, verbose=False):
204209
plt.legend(handles=[horizon, zenith, galaxy, ecliptic, moon], loc=[0.1, -0.35], ncol=3, frameon=False,
205210
title = 'Aitoff plot showing HA/Dec of simulated survey pointings', numpoints=1, fontsize='small')
206211
# Save figure.
207-
plt.savefig(os.path.join(args.outDir, sm.metricNames[mId] + '_' + slicenumber + '_SkyMap.png'), format='png', dpi=72)
212+
plt.savefig(os.path.join(args.outDir, mb.metric.name + '_' + slicenumber + '_SkyMap.png'), format='png', dpi=72)
208213
plt.close('all')
209214
dt, t = dtime(t)
210215
if verbose:
@@ -217,7 +222,7 @@ def stitchMovie(metricList, args):
217222
for metric in metricList:
218223
# Identify filenames.
219224
outfileroot = metric.name
220-
plotfiles = fnmatch.filter(os.listdir(args.outDir), outfileroot + '*SkyMap.png')
225+
plotfiles = fnmatch.filter(os.listdir(args.outDir), outfileroot + '*_SkyMap.png')
221226
slicenum = plotfiles[0].replace(outfileroot, '').replace('_SkyMap.png', '').replace('_', '')
222227
sliceformat = '%s0%dd' %('%', len(slicenum))
223228
n_images = len(plotfiles)
@@ -236,7 +241,7 @@ def stitchMovie(metricList, args):
236241
else:
237242
args.fps = 30.0
238243
# Create the movie.
239-
movieslicer.plotMovie(outfileroot, sliceformat, plotType='SkyMap', figformat='png',
244+
movieslicer.makeMovie(outfileroot, sliceformat, plotType='SkyMap', figformat='png',
240245
outDir=args.outDir, ips=args.ips, fps=args.fps)
241246

242247
if __name__ == '__main__':
@@ -287,8 +292,8 @@ def stitchMovie(metricList, args):
287292
if not args.skipComp:
288293
verbose=False
289294
# Get db connection info, and connect to database.
290-
dbAddress = 'sqlite:///' + os.path.join(args.dbDir, args.opsimDb)
291-
oo = db.OpsimDatabase(dbAddress)
295+
dbfile = os.path.join(args.dbDir, args.opsimDb)
296+
oo = db.OpsimDatabase(dbfile)
292297
sqlconstraint = args.sqlConstraint
293298
# Fetch the data from opsim.
294299
simdata, fields = getData(oo, sqlconstraint)
@@ -310,10 +315,10 @@ def stitchMovie(metricList, args):
310315
bins[0] = simdata['expMJD'][0]
311316

312317
# Run the movie slicer (and at each step, setup opsim slicer and calculate metrics).
313-
runSlices(opsimName, metadata, simdata, fields, bins, args, verbose=verbose)
318+
runSlices(opsimName, metadata, simdata, fields, bins, args, oo, verbose=verbose)
314319

315320
# Need to set up the metrics to get their names, but don't need to have realistic arguments.
316-
metricList = setupMetrics(opsimName, metadata)
321+
metricList, plotDictList = setupMetrics(opsimName, metadata)
317322
stitchMovie(metricList, args)
318323
end_t, start_t = dtime(start_t)
319324
print 'Total time to create movie: ', end_t

python/lsst/sims/maf/metricBundles/metricBundleGroup.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ def _getDictSubset(self, origdict, subsetkeys):
9090
newdict = {key:origdict.get(key) for key in subsetkeys}
9191
return newdict
9292

93-
def _setCurrent(self, sqlconstraint):
93+
def setCurrent(self, sqlconstraint):
9494
"""
95-
Private utility to set the currentBundleDict (i.e. a set of metricBundles with the same SQL constraint).
95+
Utility to set the currentBundleDict (i.e. a set of metricBundles with the same SQL constraint).
9696
"""
9797
self.currentBundleDict = {}
9898
for k, b in self.bundleDict.iteritems():
@@ -158,15 +158,15 @@ def runAll(self, clearMemory=False, plotNow=False, plotKwargs=None):
158158
for sqlconstraint in self.sqlconstraints:
159159
# Set the 'currentBundleDict' which is a dictionary of the metricBundles which match this
160160
# sqlconstraint.
161-
self._setCurrent(sqlconstraint)
161+
self.setCurrent(sqlconstraint)
162162
self.runCurrent(sqlconstraint, clearMemory=clearMemory)
163163
if plotNow:
164164
if plotKwargs is None:
165165
self.plotCurrent()
166166
else:
167167
self.plotCurrent(**plotKwargs)
168168

169-
def runCurrent(self, sqlconstraint, clearMemory=False):
169+
def runCurrent(self, sqlconstraint, clearMemory=False, simData=None):
170170
"""
171171
Run all the metricBundles which match this sqlconstraint in the metricBundleGroup.
172172
Also runs 'reduceAll' and then 'summaryAll'.
@@ -176,17 +176,22 @@ def runCurrent(self, sqlconstraint, clearMemory=False):
176176
for b in self.currentBundleDict.itervalues():
177177
self.dbCols.extend(b.dbCols)
178178
self.dbCols = list(set(self.dbCols))
179-
self.simData = None
180179

181-
# Query and get the simdata.
182-
try:
183-
self.getData(sqlconstraint)
184-
except UserWarning:
185-
print 'No data matching sqlconstraint %s' %(sqlconstraint)
186-
return
187-
except ValueError:
188-
print 'One of the columns requested from the database was not available - skipping sqlconstraint %s' %(sqlconstraint)
189-
return
180+
# Can pass simData directly (if had other method for getting data)
181+
if simData is not None:
182+
self.simData = simData
183+
184+
else:
185+
self.simData = None
186+
# Query for the data.
187+
try:
188+
self.getData(sqlconstraint)
189+
except UserWarning:
190+
print 'No data matching sqlconstraint %s' %(sqlconstraint)
191+
return
192+
except ValueError:
193+
print 'One of the columns requested from the database was not available - skipping sqlconstraint %s' %(sqlconstraint)
194+
return
190195

191196
# Find compatible subsets of the MetricBundle dictionary, which can be run/metrics calculated/ together.
192197
self._findCompatibleLists()
@@ -361,7 +366,7 @@ def reduceAll(self, updateSummaries=True):
361366
This assumes that 'clearMemory' was false.
362367
"""
363368
for sqlconstraint in self.sqlconstraints:
364-
self._setCurrent(sqlconstraint)
369+
self.setCurrent(sqlconstraint)
365370
self.reduceCurrent(updateSummaries=updateSummaries)
366371

367372
def reduceCurrent(self, updateSummaries=True):
@@ -397,7 +402,7 @@ def summaryAll(self):
397402
This assumes that 'clearMemory' was false.
398403
"""
399404
for sqlconstraint in self.sqlconstraints:
400-
self._setCurrent(sqlconstraint)
405+
self.setCurrent(sqlconstraint)
401406
self.summaryCurrent()
402407

403408
def summaryCurrent(self):
@@ -416,7 +421,7 @@ def plotAll(self, savefig=True, outfileSuffix=None, figformat='pdf', dpi=600, th
416421
for sqlconstraint in self.sqlconstraints:
417422
if self.verbose:
418423
print 'Plotting figures with %s sqlconstraint now.' %(sqlconstraint)
419-
self._setCurrent(sqlconstraint)
424+
self.setCurrent(sqlconstraint)
420425
self.plotCurrent(savefig=savefig, outfileSuffix=outfileSuffix, figformat=figformat, dpi=dpi,
421426
thumbnail=thumbnail, closefigs=closefigs)
422427

@@ -440,7 +445,7 @@ def writeAll(self):
440445
Assumes 'clearMemory' was false.
441446
"""
442447
for sqlconstraint in self.sqlconstraints:
443-
self._setCurrent(sqlconstraint)
448+
self.setCurrent(sqlconstraint)
444449
self.writeCurrent()
445450

446451
def writeCurrent(self):

python/lsst/sims/maf/metrics/technicalMetrics.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ def __init__(self, rRGB='rRGB', gRGB='gRGB', bRGB='bRGB',
288288
if self.t0 is None:
289289
self.t0 = 52939
290290
self.tStep = tStep
291-
super(FilterColors, self).__init__(col=[rRGB, gRGB, bRGB, timeCol],
292-
metricName=metricName, **kwargs)
291+
super(FilterColorsMetric, self).__init__(col=[rRGB, gRGB, bRGB, timeCol],
292+
metricName=metricName, **kwargs)
293293
self.metricDtype = 'object'
294294
self.comment = 'Metric specifically to generate colors for the opsim movie'
295295

0 commit comments

Comments
 (0)