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

1from __future__ import print_function, division 

2from copy import deepcopy 

3import os 

4import numpy as np 

5import numpy.ma as ma 

6import matplotlib.pyplot as plt 

7import lsst.sims.maf.metrics as metrics 

8import lsst.sims.maf.slicers as slicers 

9import lsst.sims.maf.stackers as stackers 

10import lsst.sims.maf.plots as plots 

11import lsst.sims.maf.metricBundles as mb 

12from .colMapDict import ColMapDict 

13from .common import summaryCompletenessAtTime, summaryCompletenessOverH, fractionPopulationAtThreshold 

14 

15__all__ = ['defaultHrange', 'defaultCharacterization','setupMoSlicer', 

16 'quickDiscoveryBatch', 'discoveryBatch', 

17 'runCompletenessSummary', 'plotCompleteness', 

18 'characterizationInnerBatch', 'characterizationOuterBatch', 

19 'runFractionSummary', 'plotFractions', 

20 'plotSingle', 'plotActivity', 

21 'readAndCombine', 'combineSubsets'] 

22 

23 

24def defaultHrange(metadata): 

25 "Provide useful default ranges for H, based on metadata of population type." 

26 defaultRanges = {'PHA': [16, 28, 0.2], 

27 'NEO': [16, 28, 0.2], 

28 'MBA': [16, 26, 0.2], 

29 'Trojan': [14, 22, 0.2], 

30 'TNO': [4, 12, 0.2], 

31 'SDO': [4, 12, 0.2]} 

32 defaultHmark = {'PHA': 22, 'NEO': 22, 'MBA': 20, 

33 'Trojan': 18, 'TNO': 8, 'SDO': 8} 

34 if metadata in defaultRanges: 

35 Hrange = defaultRanges[metadata] 

36 Hmark = defaultHmark[metadata] 

37 elif metadata.upper().startswith('GRANVIK'): 

38 Hrange = defaultRanges['NEO'] 

39 Hmark = defaultHmark['NEO'] 

40 elif metadata.upper().startswith('L7'): 

41 Hrange = defaultRanges('TNO') 

42 Hmark = defaultHmark['TNO'] 

43 else: 

44 print(f'## Could not find {metadata} in default keys ({defaultRanges.keys()}). \n' 

45 f'## Using expanded default range instead.') 

46 Hrange = [4, 28, 0.5] 

47 Hmark = 10 

48 return Hrange, Hmark 

49 

50 

51def defaultCharacterization(metadata): 

52 "Provide useful characterization bundle type, based on metadata of population type." 

53 defaultChar = {'PHA': 'inner', 'NEO': 'inner', 

54 'MBA': 'inner', 'Trojan': 'inner', 

55 'TNO': 'outer', 'SDO': 'outer'} 

56 if metadata in defaultChar: 

57 char = defaultChar[metadata] 

58 elif metadata.upper().startswith('GRANVIK'): 

59 char = 'inner' 

60 elif metadata.upper().startswith('L7'): 

61 char = 'outer' 

62 else: 

63 print(f'## Could not find {metadata} in default keys ({defaultChar.keys()}). \n' 

64 f'## Using Inner (Asteroid) characterization by default.') 

65 char = 'inner' 

66 return char 

67 

68 

69def setupMoSlicer(orbitFile, Hrange, obsFile=None): 

70 """ 

71 Set up the slicer and read orbitFile and obsFile from disk. 

72 

73 Parameters 

74 ---------- 

75 orbitFile : str 

76 The file containing the orbit information. 

77 Hrange : numpy.ndarray or None 

78 The Hrange parameter to pass to slicer.readOrbits 

79 obsFile : str, optional 

80 The file containing the observations of each object, optional. 

81 If not provided (default, None), then the slicer will not be able to 'slice', but can still plot. 

82 

83 Returns 

84 ------- 

85 ~lsst.sims.maf.slicer.MoObjSlicer 

86 """ 

87 # Read the orbit file and set the H values for the slicer. 

88 slicer = slicers.MoObjSlicer(Hrange=Hrange) 

89 slicer.setupSlicer(orbitFile=orbitFile, obsFile=obsFile) 

90 return slicer 

91 

92 

93def quickDiscoveryBatch(slicer, colmap=None, runName='opsim', detectionLosses='detection', metadata='', 

94 albedo=None, Hmark=None, npReduce=np.mean, constraint=None): 

95 if colmap is None: 

96 colmap = ColMapDict('opsimV4') 

97 bundleList = [] 

98 plotBundles = [] 

99 

100 basicPlotDict = {'albedo': albedo, 'Hmark': Hmark, 'npReduce': npReduce, 

101 'nxbins': 200, 'nybins': 200} 

102 plotFuncs = [plots.MetricVsH()] 

103 displayDict ={'group': 'Discovery'} 

104 

105 if detectionLosses not in ('detection', 'trailing'): 

106 raise ValueError('Please choose detection or trailing as options for detectionLosses.') 

107 if detectionLosses == 'trailing': 

108 magStacker = stackers.MoMagStacker(lossCol='dmagTrail') 

109 detectionLosses = ' trailing loss' 

110 else: 

111 magStacker = stackers.MoMagStacker(lossCol='dmagDetect') 

112 detectionLosses = ' detection loss' 

113 

114 # Set up a dictionary to pass to each metric for the column names. 

115 colkwargs = {'mjdCol': colmap['mjd'], 'seeingCol': colmap['seeingGeom'], 

116 'expTimeCol': colmap['exptime'], 'm5Col': colmap['fiveSigmaDepth'], 

117 'nightCol': colmap['night'], 'filterCol': colmap['filter']} 

118 

119 def _setup_child_metrics(parentMetric): 

120 childMetrics = {} 

121 childMetrics['Time'] = metrics.Discovery_TimeMetric(parentMetric, **colkwargs) 

122 childMetrics['N_Chances'] = metrics.Discovery_N_ChancesMetric(parentMetric, **colkwargs) 

123 # Could expand to add N_chances per year, but not really necessary. 

124 return childMetrics 

125 

126 def _configure_child_bundles(parentBundle): 

127 dispDict = {'group': 'Discovery', 'subgroup': 'Time', 

128 'caption': 'Time of discovery of objects', 'order': 0} 

129 parentBundle.childBundles['Time'].setDisplayDict(dispDict) 

130 dispDict = {'group': 'Discovery', 'subgroup': 'NChances', 

131 'caption': 'Number of chances for discovery of objects', 'order': 0} 

132 parentBundle.childBundles['N_Chances'].setDisplayDict(dispDict) 

133 return 

134 

135 # 3 pairs in 15 

136 md = metadata + ' 3 pairs in 15 nights' + detectionLosses 

137 # Set up plot dict. 

138 plotDict = {'title': '%s: %s' % (runName, md)} 

139 plotDict.update(basicPlotDict) 

140 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90./60./24., 

141 nNightsPerWindow=3, tWindow=15, **colkwargs) 

142 childMetrics = _setup_child_metrics(metric) 

143 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

144 stackerList=[magStacker], 

145 runName=runName, metadata=md, 

146 childMetrics=childMetrics, 

147 plotDict=plotDict, plotFuncs=plotFuncs, 

148 displayDict=displayDict) 

149 _configure_child_bundles(bundle) 

150 bundleList.append(bundle) 

151 

152 # 3 pairs in 30 

153 md = metadata + ' 3 pairs in 30 nights' + detectionLosses 

154 plotDict = {'title': '%s: %s' % (runName, md)} 

155 plotDict.update(basicPlotDict) 

156 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

157 nNightsPerWindow=3, tWindow=30, **colkwargs) 

158 childMetrics = _setup_child_metrics(metric) 

159 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

160 stackerList=[magStacker], 

161 runName=runName, metadata=md, 

162 childMetrics=childMetrics, 

163 plotDict=plotDict, plotFuncs=plotFuncs, 

164 displayDict=displayDict) 

165 _configure_child_bundles(bundle) 

166 bundleList.append(bundle) 

167 

168 # Set the runName for all bundles and return the bundleDict. 

169 for b in bundleList: 

170 b.setRunName(runName) 

171 return mb.makeBundlesDictFromList(bundleList), plotBundles 

172 

173 

174def discoveryBatch(slicer, colmap=None, runName='opsim', detectionLosses='detection', metadata='', 

175 albedo=None, Hmark=None, npReduce=np.mean, constraint=None): 

176 if colmap is None: 

177 colmap = ColMapDict('opsimV4') 

178 bundleList = [] 

179 plotBundles = [] 

180 

181 basicPlotDict = {'albedo': albedo, 'Hmark': Hmark, 'npReduce': npReduce, 

182 'nxbins': 200, 'nybins': 200} 

183 plotFuncs = [plots.MetricVsH()] 

184 displayDict ={'group': 'Discovery'} 

185 

186 if detectionLosses not in ('detection', 'trailing'): 

187 raise ValueError('Please choose detection or trailing as options for detectionLosses.') 

188 if detectionLosses == 'trailing': 

189 # These are the SNR-losses only. 

190 magStacker = stackers.MoMagStacker(lossCol='dmagTrail') 

191 detectionLosses = ' trailing loss' 

192 else: 

193 # This is SNR losses, plus additional loss due to detecting with stellar PSF. 

194 magStacker = stackers.MoMagStacker(lossCol='dmagDetect') 

195 detectionLosses = ' detection loss' 

196 

197 # Set up a dictionary to pass to each metric for the column names. 

198 colkwargs = {'mjdCol': colmap['mjd'], 'seeingCol': colmap['seeingGeom'], 

199 'expTimeCol': colmap['exptime'], 'm5Col': colmap['fiveSigmaDepth'], 

200 'nightCol': colmap['night'], 'filterCol': colmap['filter']} 

201 

202 def _setup_child_metrics(parentMetric): 

203 childMetrics = {} 

204 childMetrics['Time'] = metrics.Discovery_TimeMetric(parentMetric, **colkwargs) 

205 childMetrics['N_Chances'] = metrics.Discovery_N_ChancesMetric(parentMetric, **colkwargs) 

206 # Could expand to add N_chances per year, but not really necessary. 

207 return childMetrics 

208 

209 def _configure_child_bundles(parentBundle): 

210 dispDict = {'group': 'Discovery', 'subgroup': 'Time', 

211 'caption': 'Time of discovery of objects', 'order': 0} 

212 parentBundle.childBundles['Time'].setDisplayDict(dispDict) 

213 dispDict = {'group': 'Discovery', 'subgroup': 'NChances', 

214 'caption': 'Number of chances for discovery of objects', 'order': 0} 

215 parentBundle.childBundles['N_Chances'].setDisplayDict(dispDict) 

216 return 

217 

218 # 3 pairs in 15 and 3 pairs in 30 done in 'quickDiscoveryBatch' (with vis). 

219 

220 # 3 pairs in 12 

221 md = metadata + ' 3 pairs in 12 nights' + detectionLosses 

222 plotDict = {'title': '%s: %s' % (runName, md)} 

223 plotDict.update(basicPlotDict) 

224 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

225 nNightsPerWindow=3, tWindow=12, **colkwargs) 

226 childMetrics = _setup_child_metrics(metric) 

227 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

228 stackerList=[magStacker], 

229 runName=runName, metadata=md, 

230 childMetrics=childMetrics, 

231 plotDict=plotDict, plotFuncs=plotFuncs, 

232 displayDict=displayDict) 

233 _configure_child_bundles(bundle) 

234 bundleList.append(bundle) 

235 

236 # 3 pairs in 20 

237 md = metadata + ' 3 pairs in 20 nights' + detectionLosses 

238 plotDict = {'title': '%s: %s' % (runName, md)} 

239 plotDict.update(basicPlotDict) 

240 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

241 nNightsPerWindow=3, tWindow=20, **colkwargs) 

242 childMetrics = _setup_child_metrics(metric) 

243 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

244 stackerList=[magStacker], 

245 runName=runName, metadata=md, 

246 childMetrics=childMetrics, 

247 plotDict=plotDict, plotFuncs=plotFuncs, 

248 displayDict=displayDict) 

249 _configure_child_bundles(bundle) 

250 bundleList.append(bundle) 

251 

252 # 3 pairs in 25 

253 md = metadata + ' 3 pairs in 25 nights' + detectionLosses 

254 plotDict = {'title': '%s: %s' % (runName, md)} 

255 plotDict.update(basicPlotDict) 

256 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

257 nNightsPerWindow=3, tWindow=25, **colkwargs) 

258 childMetrics = _setup_child_metrics(metric) 

259 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

260 stackerList=[magStacker], 

261 runName=runName, metadata=md, 

262 childMetrics=childMetrics, 

263 plotDict=plotDict, plotFuncs=plotFuncs, 

264 displayDict=displayDict) 

265 _configure_child_bundles(bundle) 

266 bundleList.append(bundle) 

267 

268 # 4 pairs in 20 

269 md = metadata + ' 4 pairs in 20 nights' + detectionLosses 

270 plotDict = {'title': '%s: %s' % (runName, md)} 

271 plotDict.update(basicPlotDict) 

272 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

273 nNightsPerWindow=4, tWindow=20, **colkwargs) 

274 childMetrics = _setup_child_metrics(metric) 

275 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

276 stackerList=[magStacker], 

277 runName=runName, metadata=md, 

278 childMetrics=childMetrics, 

279 plotDict=plotDict, plotFuncs=plotFuncs, 

280 displayDict=displayDict) 

281 _configure_child_bundles(bundle) 

282 bundleList.append(bundle) 

283 

284 # 3 triplets in 30 

285 md = metadata + ' 3 triplets in 30 nights' + detectionLosses 

286 plotDict = {'title': '%s: %s' % (runName, md)} 

287 plotDict.update(basicPlotDict) 

288 metric = metrics.DiscoveryMetric(nObsPerNight=3, tMin=0, tMax=120. / 60. / 24., 

289 nNightsPerWindow=3, tWindow=30, **colkwargs) 

290 childMetrics = _setup_child_metrics(metric) 

291 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

292 stackerList=[magStacker], 

293 runName=runName, metadata=md, 

294 childMetrics=childMetrics, 

295 plotDict=plotDict, plotFuncs=plotFuncs, 

296 displayDict=displayDict) 

297 _configure_child_bundles(bundle) 

298 bundleList.append(bundle) 

299 

300 # 3 quads in 30 

301 md = metadata + ' 3 quads in 30 nights' + detectionLosses 

302 plotDict = {'title': '%s: %s' % (runName, md)} 

303 plotDict.update(basicPlotDict) 

304 metric = metrics.DiscoveryMetric(nObsPerNight=4, tMin=0, tMax=150. / 60. / 24., 

305 nNightsPerWindow=3, tWindow=30, **colkwargs) 

306 childMetrics = _setup_child_metrics(metric) 

307 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

308 stackerList=[magStacker], 

309 runName=runName, metadata=md, 

310 childMetrics=childMetrics, 

311 plotDict=plotDict, plotFuncs=plotFuncs, 

312 displayDict=displayDict) 

313 _configure_child_bundles(bundle) 

314 bundleList.append(bundle) 

315 

316 # Play with SNR. 

317 # First standard SNR / probabilistic visibility (SNR~5) 

318 # 3 pairs in 15 

319 md = metadata + ' 3 pairs in 15 nights SNR=5' + detectionLosses 

320 # Set up plot dict. 

321 plotDict = {'title': '%s: %s' % (runName, md)} 

322 plotDict.update(basicPlotDict) 

323 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90./60./24., 

324 nNightsPerWindow=3, tWindow=15, snrLimit=5, **colkwargs) 

325 childMetrics = _setup_child_metrics(metric) 

326 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

327 stackerList=[magStacker], 

328 runName=runName, metadata=md, 

329 childMetrics=childMetrics, 

330 plotDict=plotDict, plotFuncs=plotFuncs, 

331 displayDict=displayDict) 

332 _configure_child_bundles(bundle) 

333 bundleList.append(bundle) 

334 

335 

336 # 3 pairs in 15, SNR=4. 

337 md = metadata + ' 3 pairs in 15 nights SNR=4' + detectionLosses 

338 plotDict = {'title': '%s: %s' % (runName, md)} 

339 plotDict.update(basicPlotDict) 

340 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

341 nNightsPerWindow=3, tWindow=15, snrLimit=4, **colkwargs) 

342 childMetrics = _setup_child_metrics(metric) 

343 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

344 stackerList=[magStacker], 

345 runName=runName, metadata=md, 

346 childMetrics=childMetrics, 

347 plotDict=plotDict, plotFuncs=plotFuncs, 

348 displayDict=displayDict) 

349 _configure_child_bundles(bundle) 

350 bundleList.append(bundle) 

351 

352 # 3 pairs in 30, SNR=5 

353 md = metadata + ' 3 pairs in 30 nights SNR=5' + detectionLosses 

354 plotDict = {'title': '%s: %s' % (runName, md)} 

355 plotDict.update(basicPlotDict) 

356 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

357 nNightsPerWindow=3, tWindow=30, snrLimit=5, **colkwargs) 

358 childMetrics = _setup_child_metrics(metric) 

359 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

360 stackerList=[magStacker], 

361 runName=runName, metadata=md, 

362 childMetrics=childMetrics, 

363 plotDict=plotDict, plotFuncs=plotFuncs, 

364 displayDict=displayDict) 

365 _configure_child_bundles(bundle) 

366 bundleList.append(bundle) 

367 

368 

369 # 3 pairs in 30, SNR=4 

370 md = metadata + ' 3 pairs in 30 nights SNR=4' + detectionLosses 

371 plotDict = {'title': '%s: %s' % (runName, md)} 

372 plotDict.update(basicPlotDict) 

373 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

374 nNightsPerWindow=3, tWindow=30, snrLimit=4, **colkwargs) 

375 childMetrics = _setup_child_metrics(metric) 

376 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

377 stackerList=[magStacker], 

378 runName=runName, metadata=md, 

379 childMetrics=childMetrics, 

380 plotDict=plotDict, plotFuncs=plotFuncs, 

381 displayDict=displayDict) 

382 _configure_child_bundles(bundle) 

383 bundleList.append(bundle) 

384 

385 # Play with SNR. SNR=3 

386 # 3 pairs in 15, SNR=3 

387 md = metadata + ' 3 pairs in 15 nights SNR=3' + detectionLosses 

388 plotDict = {'title': '%s: %s' % (runName, md)} 

389 plotDict.update(basicPlotDict) 

390 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

391 nNightsPerWindow=3, tWindow=15, snrLimit=3, **colkwargs) 

392 childMetrics = _setup_child_metrics(metric) 

393 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

394 stackerList=[magStacker], 

395 runName=runName, metadata=md, 

396 childMetrics=childMetrics, 

397 plotDict=plotDict, plotFuncs=plotFuncs, 

398 displayDict=displayDict) 

399 _configure_child_bundles(bundle) 

400 bundleList.append(bundle) 

401 

402 # SNR = 0 

403 # 3 pairs in 15, SNR=0 

404 md = metadata + ' 3 pairs in 15 nights SNR=0' + detectionLosses 

405 plotDict = {'title': '%s: %s' % (runName, md)} 

406 plotDict.update(basicPlotDict) 

407 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

408 nNightsPerWindow=3, tWindow=15, snrLimit=0, **colkwargs) 

409 childMetrics = _setup_child_metrics(metric) 

410 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

411 stackerList=[magStacker], 

412 runName=runName, metadata=md, 

413 childMetrics=childMetrics, 

414 plotDict=plotDict, plotFuncs=plotFuncs, 

415 displayDict=displayDict) 

416 _configure_child_bundles(bundle) 

417 bundleList.append(bundle) 

418 

419 # Play with weird strategies. 

420 # Single detection. 

421 md = metadata + ' Single detection' + detectionLosses 

422 plotDict = {'title': '%s: %s' % (runName, md)} 

423 plotDict.update(basicPlotDict) 

424 metric = metrics.DiscoveryMetric(nObsPerNight=1, tMin=0, tMax=90. / 60. / 24., 

425 nNightsPerWindow=1, tWindow=5, **colkwargs) 

426 childMetrics = _setup_child_metrics(metric) 

427 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

428 stackerList=[magStacker], 

429 runName=runName, metadata=md, 

430 childMetrics=childMetrics, 

431 plotDict=plotDict, plotFuncs=plotFuncs, 

432 displayDict=displayDict) 

433 _configure_child_bundles(bundle) 

434 bundleList.append(bundle) 

435 

436 # Single pair of detections. 

437 md = metadata + ' Single pair' + detectionLosses 

438 plotDict = {'title': '%s: %s' % (runName, md)} 

439 plotDict.update(basicPlotDict) 

440 metric = metrics.DiscoveryMetric(nObsPerNight=2, tMin=0, tMax=90. / 60. / 24., 

441 nNightsPerWindow=1, tWindow=5, **colkwargs) 

442 childMetrics = _setup_child_metrics(metric) 

443 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

444 stackerList=[magStacker], 

445 runName=runName, metadata=md, 

446 childMetrics=childMetrics, 

447 plotDict=plotDict, plotFuncs=plotFuncs, 

448 displayDict=displayDict) 

449 _configure_child_bundles(bundle) 

450 bundleList.append(bundle) 

451 

452 # High velocity discovery. 

453 displayDict['subgroup'] = 'High Velocity' 

454 

455 # High velocity. 

456 md = metadata + ' High velocity pair' + detectionLosses 

457 plotDict = {'title': '%s: %s' % (runName, md)} 

458 plotDict.update(basicPlotDict) 

459 metric = metrics.HighVelocityNightsMetric(psfFactor=2., nObsPerNight=2, **colkwargs) 

460 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

461 stackerList=[magStacker], 

462 runName=runName, metadata=md, 

463 plotDict=plotDict, plotFuncs=plotFuncs, 

464 displayDict=displayDict) 

465 bundleList.append(bundle) 

466 

467 # "magic" detection - 6 in 60 days. 

468 md = metadata + ' 6 detections in 60 nights' + detectionLosses 

469 plotDict = {'title': '%s: %s' % (runName, md)} 

470 plotDict.update(basicPlotDict) 

471 metric = metrics.MagicDiscoveryMetric(nObs=6, tWindow=60, **colkwargs) 

472 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

473 stackerList=[magStacker], 

474 runName=runName, metadata=md, 

475 plotDict=plotDict, plotFuncs=plotFuncs, 

476 displayDict=displayDict) 

477 bundleList.append(bundle) 

478 

479 # Set the runName for all bundles and return the bundleDict. 

480 for b in bundleList: 

481 b.setRunName(runName) 

482 return mb.makeBundlesDictFromList(bundleList), plotBundles 

483 

484 

485def runCompletenessSummary(bdict, Hmark, times, outDir, resultsDb): 

486 """ 

487 Calculate completeness and create completeness bundles from all N_Chances and Time (child) metrics 

488 of the (discovery) bundles in bdict, and write completeness at Hmark to resultsDb, save bundle to disk. 

489 

490 This should be done after combining any sub-sets of the metric results. 

491 

492 Parameters 

493 ---------- 

494 bdict : dict of metricBundles 

495 Dict containing ~lsst.sims.maf.MoMetricBundles, 

496 including bundles we're expecting to contain completeness. 

497 Hmark : float 

498 Hmark value to add to completeness plotting dict. 

499 If not defined (None), then the Hmark from the plotdict from the metric will be used if available. 

500 If None and Hmark not in plotDict, then median of Hrange value will be used. 

501 times : np.ndarray 

502 The times at which to calculate completeness (over time). 

503 outDir : str 

504 Output directory to save completeness bundles to disk. 

505 resultsDb : ~lsst.sims.maf.db.ResultsDb 

506 Results database to save information about completeness bundle. 

507 

508 Returns 

509 ------- 

510 dict of metricBundles 

511 A dictionary of the new completeness bundles. Keys match original keys, 

512 with additions of "[Differential,Cumulative]Completeness@Time" 

513 and "[Differential,Cumulative]Completeness" to distinguish new entries. 

514 """ 

515 # Add completeness bundles and write completeness at Hmark to resultsDb. 

516 completeness = {} 

517 group = 'Discovery' 

518 subgroup = 'Completeness' 

519 

520 def _compbundles(b, bundle, Hmark, resultsDb): 

521 # Find Hmark if not set (this may be different for different bundles). 

522 if Hmark is None and 'Hmark' in bundle.plotDict: 

523 Hmark = bundle.plotDict['Hmark'] 

524 if Hmark is None: 

525 Hmark = np.median(bundle.slicer.slicePoints['H']) 

526 # Set up the summary metrics. 

527 summaryTimeMetrics = summaryCompletenessAtTime(times, Hval=Hmark, Hindex=0.33) 

528 summaryTimeMetrics2 = summaryCompletenessAtTime(times, Hval=Hmark - 2, Hindex=0.33) 

529 summaryHMetrics = summaryCompletenessOverH(requiredChances=1, Hindex=0.33) 

530 comp = {} 

531 # Bundle = single metric bundle. Add differential and cumulative completeness. 

532 if 'Time' in bundle.metric.name: 

533 for metric in summaryTimeMetrics: 

534 newkey = b + ' ' + metric.name 

535 comp[newkey] = mb.makeCompletenessBundle(bundle, metric, 

536 Hmark=None, resultsDb=resultsDb) 

537 comp[newkey].plotDict['times'] = times 

538 comp[newkey].plotDict['Hval'] = metric.Hval 

539 for metric in summaryTimeMetrics2: 

540 newkey = b + ' ' + metric.name 

541 comp[newkey] = mb.makeCompletenessBundle(bundle, metric, 

542 Hmark=None, resultsDb=resultsDb) 

543 comp[newkey].plotDict['times'] = times 

544 comp[newkey].plotDict['Hval'] = metric.Hval 

545 elif 'N_Chances' in bundle.metric.name: 

546 for metric in summaryHMetrics: 

547 newkey = b + ' ' + metric.name 

548 comp[newkey] = mb.makeCompletenessBundle(bundle, metric, 

549 Hmark=Hmark, resultsDb=resultsDb) 

550 return comp 

551 

552 # Generate the completeness bundles for the various discovery metrics. 

553 for b, bundle in bdict.items(): 

554 if 'Discovery' in bundle.metric.name: 

555 completeness.update(_compbundles(b, bundle, Hmark, resultsDb)) 

556 if isinstance(bundle.metric, metrics.HighVelocityNightsMetric): 

557 completeness.update(_compbundles(b, bundle, Hmark, resultsDb)) 

558 if isinstance(bundle.metric, metrics.MagicDiscoveryMetric): 

559 completeness.update(_compbundles(b, bundle, Hmark, resultsDb)) 

560 

561 # Write the completeness bundles to disk, so we can re-read them later. 

562 # (also set the display dict properties, for the resultsDb output). 

563 for b, bundle in completeness.items(): 

564 bundle.setDisplayDict({'group': group, 'subgroup': subgroup}) 

565 bundle.write(outDir=outDir, resultsDb=resultsDb) 

566 

567 return completeness 

568 

569 

570def plotCompleteness(bdictCompleteness, figroot=None, resultsDb=None, 

571 outDir='.', figformat='pdf'): 

572 """Plot a minor subset of the completeness results. 

573 """ 

574 # Separate some subsets to plot together. 

575 keys = ['3_pairs_in_30_nights_detection_loss', 

576 '3_pairs_in_15_nights_detection_loss'] 

577 plotTimes = {} 

578 plotComp = {} 

579 plotDiff = {} 

580 for k in bdictCompleteness: 

581 for key in keys: 

582 if key in k: 

583 if 'Discovery_Time' in k: 

584 if 'Cumulative' in k: 

585 plotTimes[k] = bdictCompleteness[k] 

586 elif 'Discovery_N_Chances' in k: 

587 if 'Differential' in k: 

588 plotDiff[k] = bdictCompleteness[k] 

589 elif 'Cumulative' in k: 

590 plotComp[k] = bdictCompleteness[k] 

591 

592 # Add plot dictionaries to code 30 nights red, 15 nights blue, differentials dotted. 

593 def _codePlot(key): 

594 plotDict = {} 

595 if 'Differential' in k: 

596 plotDict['linestyle'] = ':' 

597 else: 

598 plotDict['linestyle'] = '-' 

599 if '30_nights' in k: 

600 plotDict['color'] = 'r' 

601 if '15_nights' in k: 

602 plotDict['color'] = 'b' 

603 return plotDict 

604 # Apply color-coding. 

605 for k, b in plotTimes.items(): 

606 b.setPlotDict(_codePlot(k)) 

607 for k, b in plotDiff.items(): 

608 b.setPlotDict(_codePlot(k)) 

609 for k, b in plotComp.items(): 

610 b.setPlotDict(_codePlot(k)) 

611 

612 first = bdictCompleteness[list(bdictCompleteness.keys())[0]] 

613 if figroot is None: 

614 figroot = first.runName 

615 

616 # Plot completeness as a function of time. 

617 fig = plt.figure(figsize=(8, 6)) 

618 for k in plotTimes: 

619 plt.plot(plotTimes[k].plotDict['times'], plotTimes[k].metricValues[0, :], 

620 label=plotTimes[k].plotDict['label'] + ' @H=%.2f' % plotTimes[k].plotDict['Hval']) 

621 plt.legend() 

622 plt.xlabel('Time (MJD)') 

623 plt.ylabel('Completeness') 

624 plt.grid(True, alpha=0.3) 

625 # Make a PlotHandler to deal with savings/resultsDb, etc. 

626 ph = plots.PlotHandler(figformat=figformat, resultsDb=resultsDb, outDir=outDir) 

627 displayDict = {'group': 'Completeness', 'subgroup': 'Over Time', 

628 'caption': 'Completeness over time, for H values indicated in legend.'} 

629 ph.saveFig(fig.number, f'{figroot}_CompletenessOverTime', 'Combo', 'CompletenessOverTime', 'MoObjSlicer', 

630 figroot, None, None, displayDict=displayDict) 

631 

632 plt.savefig(os.path.join(outDir, f'{figroot}_CompletenessOverTime.{figformat}'), format=figformat) 

633 

634 # Plot cumulative completeness. 

635 ph = plots.PlotHandler(figformat=figformat, resultsDb=resultsDb, outDir=outDir) 

636 ph.setMetricBundles(plotComp) 

637 plotDict = {'ylabel': "Completeness", 'figsize': (8, 6), 'albedo': 0.14} 

638 ph.plot(plotFunc=plots.MetricVsH(), plotDicts=plotDict, 

639 outfileRoot=figroot + '_CumulativeCompleteness') 

640 

641 # Plot differential completeness. 

642 ph = plots.PlotHandler(figformat=figformat, resultsDb=resultsDb, outDir=outDir) 

643 ph.setMetricBundles(plotDiff) 

644 plotDict = {'ylabel': "Completeness", 'figsize': (8, 6)} 

645 ph.plot(plotFunc=plots.MetricVsH(), plotDicts=plotDict, 

646 outfileRoot=figroot + '_DifferentialCompleteness') 

647 

648 

649def characterizationInnerBatch(slicer, colmap=None, runName='opsim', metadata='', 

650 albedo=None, Hmark=None, constraint=None, npReduce=np.mean, 

651 windows=None, bins=None): 

652 """Characterization metrics for inner solar system objects. 

653 """ 

654 if colmap is None: 

655 colmap = ColMapDict('opsimV4') 

656 bundleList = [] 

657 plotBundles = [] 

658 

659 # Set up a dictionary to pass to each metric for the column names. 

660 colkwargs = {'mjdCol': colmap['mjd'], 'seeingCol': colmap['seeingGeom'], 

661 'expTimeCol': colmap['exptime'], 'm5Col': colmap['fiveSigmaDepth'], 

662 'nightCol': colmap['night'], 'filterCol': colmap['filter']} 

663 

664 basicPlotDict = {'albedo': albedo, 'Hmark': Hmark, 'npReduce': npReduce, 

665 'nxbins': 200, 'nybins': 200} 

666 plotFuncs = [plots.MetricVsH()] 

667 displayDict ={'group': 'Characterization'} 

668 

669 # Stackers 

670 magStacker = stackers.MoMagStacker(lossCol='dmagDetect') 

671 eclStacker = stackers.EclStacker() 

672 stackerList = [magStacker, eclStacker] 

673 

674 # Windows are the different 'length of activity' 

675 if windows is None: 

676 windows = np.arange(10, 200, 30.) 

677 # Bins are the different 'anomaly variations' of activity 

678 if bins is None: 

679 bins = np.arange(5, 185, 20.) 

680 

681 # Number of observations. 

682 md = metadata 

683 plotDict = {'ylabel': 'Number of observations (#)', 

684 'title': '%s: Number of observations %s' % (runName, md)} 

685 plotDict.update(basicPlotDict) 

686 metric = metrics.NObsMetric(**colkwargs) 

687 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

688 stackerList=stackerList, 

689 runName=runName, metadata=md, 

690 plotDict=plotDict, plotFuncs=plotFuncs, 

691 displayDict=displayDict) 

692 bundleList.append(bundle) 

693 

694 # Observational arc. 

695 md = metadata 

696 plotDict = {'ylabel': 'Observational Arc (days)', 

697 'title': '%s: Observational Arc Length %s' % (runName, md)} 

698 plotDict.update(basicPlotDict) 

699 metric = metrics.ObsArcMetric(**colkwargs) 

700 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

701 stackerList=stackerList, 

702 runName=runName, metadata=md, 

703 plotDict=plotDict, plotFuncs=plotFuncs, 

704 displayDict=displayDict) 

705 bundleList.append(bundle) 

706 

707 # Activity detection. 

708 for w in windows: 

709 md = metadata + ' activity lasting %.0f days' % w 

710 plotDict = {'title': '%s: Chances of detecting %s' % (runName, md), 

711 'ylabel': 'Probability of detection per %.0f day window' % w} 

712 metricName = 'Chances of detecting activity lasting %.0f days' % w 

713 metric = metrics.ActivityOverTimeMetric(w, metricName=metricName, **colkwargs) 

714 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

715 stackerList=stackerList, 

716 runName=runName, metadata=metadata, 

717 plotDict=plotDict, plotFuncs=plotFuncs, 

718 displayDict=displayDict) 

719 bundleList.append(bundle) 

720 

721 for b in bins: 

722 md = metadata + ' activity covering %.0f deg' % (b) 

723 plotDict = {'title': '%s: Chances of detecting %s' % (runName, md), 

724 'ylabel': 'Probability of detection per %.0f deg window' % b} 

725 metricName = 'Chances of detecting activity covering %.0f deg' % (b) 

726 metric = metrics.ActivityOverPeriodMetric(b, metricName=metricName, **colkwargs) 

727 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

728 stackerList=stackerList, 

729 runName=runName, metadata=metadata, 

730 plotDict=plotDict, plotFuncs=plotFuncs, 

731 displayDict=displayDict) 

732 bundleList.append(bundle) 

733 

734 # Lightcurve inversion. 

735 md = metadata 

736 plotDict = {'yMin': 0, 'yMax': 1, 'ylabel': 'Fraction of objects', 

737 'title': '%s: Fraction with potential lightcurve inversion %s' % (runName, md)} 

738 plotDict.update(basicPlotDict) 

739 metric = metrics.LightcurveInversion_AsteroidMetric(**colkwargs) 

740 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

741 stackerList=stackerList, 

742 runName=runName, metadata=md, 

743 plotDict=plotDict, plotFuncs=plotFuncs, 

744 displayDict=displayDict) 

745 bundleList.append(bundle) 

746 

747 # Color determination. 

748 md = metadata 

749 plotDict = {'yMin': 0, 'yMax': 1, 'ylabel': 'Fraction of objects', 

750 'title': '%s: Fraction of population with colors in X filters %s' % (runName, md)} 

751 plotDict.update(basicPlotDict) 

752 metric = metrics.Color_AsteroidMetric(**colkwargs) 

753 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

754 stackerList=stackerList, 

755 runName=runName, metadata=md, 

756 plotDict=plotDict, plotFuncs=plotFuncs, 

757 displayDict=displayDict) 

758 bundleList.append(bundle) 

759 

760 # Set the runName for all bundles and return the bundleDict. 

761 for b in bundleList: 

762 b.setRunName(runName) 

763 return mb.makeBundlesDictFromList(bundleList), plotBundles 

764 

765 

766def characterizationOuterBatch(slicer, colmap=None, runName='opsim', metadata='', 

767 albedo=None, Hmark=None, constraint=None, npReduce=np.mean, 

768 windows=None, bins=None): 

769 """Characterization metrics for outer solar system objects. 

770 """ 

771 if colmap is None: 

772 colmap = ColMapDict('opsimV4') 

773 bundleList = [] 

774 plotBundles = [] 

775 

776 # Set up a dictionary to pass to each metric for the column names. 

777 colkwargs = {'mjdCol': colmap['mjd'], 'seeingCol': colmap['seeingGeom'], 

778 'expTimeCol': colmap['exptime'], 'm5Col': colmap['fiveSigmaDepth'], 

779 'nightCol': colmap['night'], 'filterCol': colmap['filter']} 

780 

781 basicPlotDict = {'albedo': albedo, 'Hmark': Hmark, 'npReduce': npReduce, 

782 'nxbins': 200, 'nybins': 200} 

783 plotFuncs = [plots.MetricVsH()] 

784 displayDict ={'group': 'Characterization'} 

785 

786 # Stackers 

787 magStacker = stackers.MoMagStacker(lossCol='dmagDetect') 

788 eclStacker = stackers.EclStacker() 

789 stackerList = [magStacker, eclStacker] 

790 

791 # Windows are the different 'length of activity' 

792 if windows is None: 

793 windows = np.arange(10, 200, 30.) 

794 # Bins are the different 'anomaly variations' of activity 

795 if bins is None: 

796 bins = np.arange(5, 185, 20.) 

797 

798 # Number of observations. 

799 md = metadata 

800 plotDict = {'ylabel': 'Number of observations (#)', 

801 'title': '%s: Number of observations %s' % (runName, md)} 

802 plotDict.update(basicPlotDict) 

803 metric = metrics.NObsMetric(**colkwargs) 

804 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

805 stackerList=stackerList, 

806 runName=runName, metadata=md, 

807 plotDict=plotDict, plotFuncs=plotFuncs, 

808 displayDict=displayDict) 

809 bundleList.append(bundle) 

810 

811 # Observational arc. 

812 md = metadata 

813 plotDict = {'ylabel': 'Observational Arc (days)', 

814 'title': '%s: Observational Arc Length %s' % (runName, md)} 

815 plotDict.update(basicPlotDict) 

816 metric = metrics.ObsArcMetric(**colkwargs) 

817 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

818 stackerList=stackerList, 

819 runName=runName, metadata=md, 

820 plotDict=plotDict, plotFuncs=plotFuncs, 

821 displayDict=displayDict) 

822 bundleList.append(bundle) 

823 

824 # Activity detection. 

825 for w in windows: 

826 md = metadata + ' activity lasting %.0f days' % w 

827 plotDict = {'title': '%s: Chances of detecting %s' % (runName, md), 

828 'ylabel': 'Probability of detection per %.0f day window' % w} 

829 metricName = 'Chances of detecting activity lasting %.0f days' % w 

830 metric = metrics.ActivityOverTimeMetric(w, metricName=metricName, **colkwargs) 

831 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

832 stackerList=stackerList, 

833 runName=runName, metadata=metadata, 

834 plotDict=plotDict, plotFuncs=plotFuncs, 

835 displayDict=displayDict) 

836 bundleList.append(bundle) 

837 

838 for b in bins: 

839 md = metadata + ' activity covering %.0f deg' % (b) 

840 plotDict = {'title': '%s: Chances of detecting %s' % (runName, md), 

841 'ylabel': 'Probability of detection per %.2f deg window' % b} 

842 metricName = 'Chances of detecting activity covering %.0f deg' % (b) 

843 metric = metrics.ActivityOverPeriodMetric(b, metricName=metricName, **colkwargs) 

844 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

845 stackerList=stackerList, 

846 runName=runName, metadata=metadata, 

847 plotDict=plotDict, plotFuncs=plotFuncs, 

848 displayDict=displayDict) 

849 bundleList.append(bundle) 

850 

851 # Color determination. 

852 md = metadata 

853 plotDict = {'yMin': 0, 'yMax': 1, 'ylabel': 'Fraction of objects', 

854 'title': '%s: Fraction of population with colors in X filters %s' % (runName, md)} 

855 plotDict.update(basicPlotDict) 

856 metric = metrics.LightcurveColor_OuterMetric(**colkwargs) 

857 bundle = mb.MoMetricBundle(metric, slicer, constraint, 

858 stackerList=stackerList, 

859 runName=runName, metadata=md, 

860 plotDict=plotDict, plotFuncs=plotFuncs, 

861 displayDict=displayDict) 

862 bundleList.append(bundle) 

863 

864 # Set the runName for all bundles and return the bundleDict. 

865 for b in bundleList: 

866 b.setRunName(runName) 

867 return mb.makeBundlesDictFromList(bundleList), plotBundles 

868 

869 

870def runFractionSummary(bdict, Hmark, outDir, resultsDb): 

871 """ 

872 Calculate fractional completeness of the population for color and lightcurve metrics. 

873 

874 This should be done after combining any sub-sets of the metric results. 

875 

876 Parameters 

877 ---------- 

878 bdict : dict of metricBundles 

879 Dict containing ~lsst.sims.maf.MoMetricBundles, 

880 including bundles we're expecting to contain lightcurve/color evaluations. 

881 Hmark : float 

882 Hmark value to add to completeness plotting dict. 

883 If defined, this value is used. If None, but Hmark in plotDict for metric, then this value (-2) is 

884 used. If Hmark not in plotdict, then the median Hrange value - 2 is used. 

885 times : np.ndarray 

886 The times at which to calculate completeness (over time). 

887 outDir : str 

888 Output directory to save completeness bundles to disk. 

889 resultsDb : ~lsst.sims.maf.db.ResultsDb 

890 Results database to save information about completeness bundle. 

891 

892 Returns 

893 ------- 

894 dict of metricBundles 

895 Dictionary of the metric bundles for the fractional evaluation of the population. 

896 """ 

897 fractions = {} 

898 group = 'Characterization' 

899 subgroup = 'Fraction of Population with Color/Lightcurve' 

900 

901 # Look for metrics from asteroid or outer solar system color/lightcurve metrics. 

902 inversionSummary = fractionPopulationAtThreshold([1], ['Lightcurve Inversion']) 

903 asteroidColorSummary = fractionPopulationAtThreshold([4, 3, 2, 1], ['6 of ugrizy', '5 of grizy', 

904 '4 of grizy', 

905 '2 of g, r or i, z or y']) 

906 asteroidSummaryMetrics = {'LightcurveInversion_Asteroid': inversionSummary, 

907 'Color_Asteroid': asteroidColorSummary} 

908 

909 outerColorSummary = fractionPopulationAtThreshold([6, 5, 4, 3, 2, 1], ['6 filters', '5 filters', 

910 '4 filters', '3 filters', 

911 '2 filters', '1 filters']) 

912 outerSummaryMetrics = {'LightcurveColor_Outer': outerColorSummary} 

913 

914 for b, bundle in bdict.items(): 

915 # Find Hmark if not set (this may be different for different bundles). 

916 if Hmark is None and 'Hmark' in bundle.plotDict: 

917 Hmark = bundle.plotDict['Hmark'] - 2 

918 if Hmark is None: 

919 Hmark = np.median(bundle.slicer.slicePoints['H']) - 2 

920 for k in asteroidSummaryMetrics: 

921 if k in b: 

922 for summary_metric in asteroidSummaryMetrics[k]: 

923 newkey = b + ' ' + summary_metric.name 

924 fractions[newkey] = mb.makeCompletenessBundle(bundle, summary_metric, 

925 Hmark=Hmark, resultsDb=resultsDb) 

926 for k in outerSummaryMetrics: 

927 if k in b: 

928 for summary_metric in outerSummaryMetrics[k]: 

929 newkey = b + ' ' + summary_metric.name 

930 fractions[newkey] = mb.makeCompletenessBundle(bundle, summary_metric, 

931 Hmark=Hmark, resultsDb=resultsDb) 

932 # Write the fractional populations bundles to disk, so we can re-read them later. 

933 # (also set the display dict properties, for the resultsDb output). 

934 for b, bundle in fractions.items(): 

935 bundle.setDisplayDict({'group': group, 'subgroup': subgroup}) 

936 bundle.write(outDir=outDir, resultsDb=resultsDb) 

937 return fractions 

938 

939 

940def plotFractions(bdictFractions, figroot=None, resultsDb=None, 

941 outDir='.', figformat='pdf'): 

942 # Set colors for the fractions. 

943 for b in bdictFractions.values(): 

944 k = b.metric.name 

945 print(k) 

946 if '6' in k: 

947 b.plotDict['color'] = 'b' 

948 if '5' in k: 

949 b.plotDict['color'] = 'cyan' 

950 if '4' in k: 

951 b.plotDict['color'] = 'orange' 

952 if '2' in k: 

953 b.plotDict['color'] = 'r' 

954 if '1' in k: 

955 b.plotDict['color'] = 'magenta' 

956 if 'Lightcurve Inversion' in k: 

957 b.plotDict['color'] = 'k' 

958 b.plotDict['linestyle'] = ':' 

959 b.plotDict['linewidth'] = 3 

960 

961 if figroot is None: 

962 first = bdictFractions[list(bdictFractions.keys())[0]] 

963 figroot = first.runName 

964 

965 displayDict = {'group': 'Characterization', 'subgroup': 'Color/Inversion'} 

966 

967 ph = plots.PlotHandler(figformat=figformat, resultsDb=resultsDb, outDir=outDir) 

968 ph.setMetricBundles(bdictFractions) 

969 ph.jointMetricNames = 'Fraction of population for colors or lightcurve inversion' 

970 plotDict = {'ylabel': "Fraction of population", 'figsize': (8, 6)} 

971 ph.plot(plotFunc=plots.MetricVsH(), plotDicts=plotDict, displayDict=displayDict, 

972 outfileRoot=figroot + '_characterization') 

973 

974 

975def plotSingle(bundle, resultsDb=None, outDir='.', figformat='pdf'): 

976 """Plot 5%/25%/50%/75%/95% iles for a metric value. 

977 """ 

978 pDict = {'95%ile': {'color': 'k', 'linestyle': '--', 'label': '95th %ile', 

979 'npReduce': lambda x, axis: np.percentile(x, 95, axis=axis)}, 

980 '75%ile': {'color': 'magenta', 'linestyle': ':', 'label': '75th %ile', 

981 'npReduce': lambda x, axis: np.percentile(x, 75, axis=axis)}, 

982 'Median': {'color': 'b', 'linestyle': '-', 'label': 'Median', 

983 'npReduce': lambda x, axis: np.median(x, axis=axis)}, 

984 'Mean': {'color': 'g', 'linestyle': '--', 'label': 'Mean', 

985 'npReduce': np.mean}, 

986 '25%ile': {'color': 'magenta', 'linestyle': ':', 'label': '25th %ile', 

987 'npReduce': lambda x, axis: np.percentile(x, 25, axis=axis)}, 

988 '5%ile': {'color': 'k', 'linestyle': '--', 'label': '5th %ile', 

989 'npReduce': lambda x, axis: np.percentile(x, 5, axis=axis)}} 

990 displayDict = {'group': 'Characterization', 'subgroup': bundle.metric.name} 

991 ph = plots.PlotHandler(figformat=figformat, resultsDb=resultsDb, outDir=outDir) 

992 plotBundles = [] 

993 plotDicts = [] 

994 for r in pDict: 

995 plotBundles.append(bundle) 

996 plotDicts.append(pDict[r]) 

997 plotDicts[0].update({'figsize': (8, 6), 'legendloc': 'upper right', 'yMin': 0}) 

998 # Remove the Hmark line because these plots get complicated. 

999 for r in plotDicts: 

1000 del plotDicts[r]['Hmark'] 

1001 ph.setMetricBundles(plotBundles) 

1002 ph.plot(plotFunc=plots.MetricVsH(), plotDicts=plotDicts, displayDict=displayDict) 

1003 

1004 

1005def plotNotFound(nChances, Hmark): 

1006 pass 

1007 

1008 

1009def plotActivity(bdict, figroot=None, resultsDb=None, outDir='.', figformat='pdf'): 

1010 activity_deg = {} 

1011 activity_days = {} 

1012 for k in bdict: 

1013 if 'Chances_of_detecting_activity' in k: 

1014 if 'deg' in k: 

1015 activity_deg[k] = bdict[k] 

1016 if 'days' in k: 

1017 activity_days[k] = bdict[k] 

1018 

1019 if figroot is None: 

1020 first = bdict[list(bdict.keys())[0]] 

1021 figroot = first.runName 

1022 

1023 displayDict = {'group': 'Characterization', 'subgroup': 'Activity'} 

1024 

1025 # Plot (mean) likelihood of detection of activity over X days 

1026 ph = plots.PlotHandler(figformat=figformat, resultsDb=resultsDb, outDir=outDir) 

1027 ph.setMetricBundles(activity_days) 

1028 ph.jointMetricNames = 'Chances of detecting activity lasting X days' 

1029 plotDict = {'ylabel': "Mean likelihood of detection", 'figsize': (8, 6)} 

1030 ph.plot(plotFunc=plots.MetricVsH(), plotDicts=plotDict, displayDict=displayDict, 

1031 outfileRoot=figroot + '_activityDays') 

1032 # Plot (mean) likelihood of detection of activity over X amount of orbit 

1033 ph.setMetricBundles(activity_deg) 

1034 ph.jointMetricNames = 'Chances of detecting activity covering X deg' 

1035 plotDict = {'ylabel': "Mean likelihood of detection", 'figsize': (8, 6)} 

1036 ph.plot(plotFunc=plots.MetricVsH(), plotDicts=plotDict, displayDict=displayDict, 

1037 outfileRoot=figroot + '_activityDeg') 

1038 

1039 

1040def readAndCombine(orbitRoot, baseDir, splits, metricfile): 

1041 """Read and combine the metric results from split locations, returning a single bundle. 

1042 

1043 This will read the files from 

1044 baseDir/orbitRoot_[split]/metricfile 

1045 where split = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], etc. (the subsets the original orbit file was split into). 

1046 

1047 Parameters 

1048 ---------- 

1049 orbitRoot: str 

1050 The root of the orbit file - l7_5k, mbas_5k, etc. 

1051 baseDir: str 

1052 The root directory containing the subset directories. (e.g. '.' often) 

1053 splits: np.ndarray or list of ints 

1054 The integers describing the split directories (e.g. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

1055 metricfile: str 

1056 The metric filename. 

1057 

1058 Returns 

1059 ------- 

1060 ~lsst.sims.maf.bundle 

1061 A single metric bundle containing the combined data from each of the subsets. 

1062 

1063 Note that this won't work for particularly complex metric values, such as the parent Discovery metrics. 

1064 However, you can read and combine their child metrics, as for these we can propagate the data masks. 

1065 """ 

1066 subsets = {} 

1067 for i in splits: 

1068 subsets[i] = mb.createEmptyMoMetricBundle() 

1069 ddir = os.path.join(baseDir, f'{orbitRoot}_{i}') 

1070 subsets[i].read(os.path.join(ddir, metricfile)) 

1071 bundle = combineSubsets(subsets) 

1072 return bundle 

1073 

1074 

1075def combineSubsets(mbSubsets): 

1076 # Combine the data from the subset metric bundles. 

1077 # The first bundle will be used a template for the slicer. 

1078 if isinstance(mbSubsets, dict): 

1079 first = mbSubsets[list(mbSubsets.keys())[0]] 

1080 else: 

1081 first = mbSubsets[0] 

1082 subsetdict = {} 

1083 for i, b in enumerate(mbSubsets): 

1084 subsetdict[i] = b 

1085 mbSubsets = subsetdict 

1086 joint = mb.createEmptyMoMetricBundle() 

1087 # Check if they're the same slicer. 

1088 slicer = deepcopy(first.slicer) 

1089 for i in mbSubsets: 

1090 if np.any(slicer.slicePoints['H'] != mbSubsets[i].slicer.slicePoints['H']): 

1091 if np.any(slicer.slicePoints['orbits'] != mbSubsets[i].slicer.slicePoints['orbits']): 

1092 raise ValueError('Bundle %s has a different slicer than the first bundle' % (i)) 

1093 # Join metric values. 

1094 joint.slicer = slicer 

1095 joint.metric = first.metric 

1096 # Don't just use the slicer shape to define the metricValues, because of CompletenessBundles. 

1097 metricValues = np.zeros(first.metricValues.shape, float) 

1098 metricValuesMask = np.zeros(first.metricValues.shape, bool) 

1099 for i in mbSubsets: 

1100 metricValues += mbSubsets[i].metricValues.filled(0) 

1101 metricValuesMask = np.where(metricValuesMask & mbSubsets[i].metricValues.mask, True, False) 

1102 joint.metricValues = ma.MaskedArray(data=metricValues, mask=metricValuesMask, fill_value=0) 

1103 joint.metadata = first.metadata 

1104 joint.runName = first.runName 

1105 joint.fileRoot = first.fileRoot.replace('.npz', '') 

1106 joint.plotDict = first.plotDict 

1107 return joint