rubin-sim 2.6.1.dev2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (387) hide show
  1. batch/compile_prenight_metadata_cache.sh +34 -0
  2. batch/run_auxtel_prenight_sims.sh +163 -0
  3. batch/run_prenight_sims.sh +239 -0
  4. docs/.gitignore +3 -0
  5. docs/Makefile +32 -0
  6. docs/api.rst +25 -0
  7. docs/conf.py +8 -0
  8. docs/data-api.rst +12 -0
  9. docs/data-download.rst +70 -0
  10. docs/developer.rst +14 -0
  11. docs/documenteer.toml +11 -0
  12. docs/index.rst +22 -0
  13. docs/installation.rst +76 -0
  14. docs/introduction.rst +37 -0
  15. docs/maf-api-batches.rst +12 -0
  16. docs/maf-api-db.rst +12 -0
  17. docs/maf-api-maf-contrib.rst +12 -0
  18. docs/maf-api-maps.rst +12 -0
  19. docs/maf-api-metricbundles.rst +12 -0
  20. docs/maf-api-metrics.rst +12 -0
  21. docs/maf-api-plots.rst +12 -0
  22. docs/maf-api-run-comparison.rst +12 -0
  23. docs/maf-api-slicers.rst +12 -0
  24. docs/maf-api-stackers.rst +12 -0
  25. docs/maf-api-utils.rst +12 -0
  26. docs/maf-api.rst +22 -0
  27. docs/maf.rst +60 -0
  28. docs/metric_list.py +49 -0
  29. docs/moving-objects-api.rst +12 -0
  30. docs/moving-objects.rst +22 -0
  31. docs/phot-utils-api.rst +12 -0
  32. docs/phot-utils.rst +11 -0
  33. docs/prenight.rst +117 -0
  34. docs/protoarchive.rst +276 -0
  35. docs/satellite-constellations-api.rst +12 -0
  36. docs/satellite-constellations.rst +13 -0
  37. docs/selfcal-api.rst +12 -0
  38. docs/selfcal.rst +15 -0
  39. docs/sim-archive-api.rst +12 -0
  40. docs/skybrightness-api.rst +12 -0
  41. docs/skybrightness.rst +23 -0
  42. docs/user-guide.rst +28 -0
  43. docs/vseqarchive-architecture.rst +438 -0
  44. docs/vseqarchive-setup.rst +238 -0
  45. docs/vseqarchive.rst +225 -0
  46. rubin_sim/__init__.py +7 -0
  47. rubin_sim/data/__init__.py +1 -0
  48. rubin_sim/data/rs_download_data.py +155 -0
  49. rubin_sim/maf/__init__.py +34 -0
  50. rubin_sim/maf/batches/__init__.py +18 -0
  51. rubin_sim/maf/batches/altaz_batch.py +161 -0
  52. rubin_sim/maf/batches/col_map_dict.py +274 -0
  53. rubin_sim/maf/batches/common.py +388 -0
  54. rubin_sim/maf/batches/ddf_batch.py +728 -0
  55. rubin_sim/maf/batches/filterchange_batch.py +182 -0
  56. rubin_sim/maf/batches/glance_batch.py +591 -0
  57. rubin_sim/maf/batches/hourglass_batch.py +79 -0
  58. rubin_sim/maf/batches/info_batch.py +114 -0
  59. rubin_sim/maf/batches/metadata_batch.py +558 -0
  60. rubin_sim/maf/batches/moving_objects_batch.py +1587 -0
  61. rubin_sim/maf/batches/openshutter_batch.py +100 -0
  62. rubin_sim/maf/batches/radar_limited.py +1100 -0
  63. rubin_sim/maf/batches/science_radar_batch.py +1910 -0
  64. rubin_sim/maf/batches/skycoverage.py +155 -0
  65. rubin_sim/maf/batches/slew_batch.py +146 -0
  66. rubin_sim/maf/batches/srd_batch.py +637 -0
  67. rubin_sim/maf/batches/time_batch.py +757 -0
  68. rubin_sim/maf/batches/time_sci_batch.py +105 -0
  69. rubin_sim/maf/batches/visitdepth_batch.py +485 -0
  70. rubin_sim/maf/db/__init__.py +2 -0
  71. rubin_sim/maf/db/add_run.py +34 -0
  72. rubin_sim/maf/db/results_db.py +1074 -0
  73. rubin_sim/maf/db/tracking_db.py +332 -0
  74. rubin_sim/maf/ddf_dir.py +53 -0
  75. rubin_sim/maf/generate_ss.py +218 -0
  76. rubin_sim/maf/glance_dir.py +58 -0
  77. rubin_sim/maf/maf_contrib/__init__.py +25 -0
  78. rubin_sim/maf/maf_contrib/calculate_lsst_field_visibility_astropy.py +170 -0
  79. rubin_sim/maf/maf_contrib/depth_limited_num_gal_metric.py +109 -0
  80. rubin_sim/maf/maf_contrib/example_new_metrics.py +40 -0
  81. rubin_sim/maf/maf_contrib/filter_pair_t_gaps_metric.py +208 -0
  82. rubin_sim/maf/maf_contrib/grb_transient_metric.py +249 -0
  83. rubin_sim/maf/maf_contrib/gw170817_det_metric.py +72 -0
  84. rubin_sim/maf/maf_contrib/intervals_between_obs_metric.py +68 -0
  85. rubin_sim/maf/maf_contrib/kne_metrics.py +473 -0
  86. rubin_sim/maf/maf_contrib/lss_metrics.py +45 -0
  87. rubin_sim/maf/maf_contrib/lss_obs_strategy/__init__.py +3 -0
  88. rubin_sim/maf/maf_contrib/lss_obs_strategy/constants_for_pipeline.py +73 -0
  89. rubin_sim/maf/maf_contrib/lss_obs_strategy/galaxy_counts_metric_extended.py +205 -0
  90. rubin_sim/maf/maf_contrib/lss_obs_strategy/galaxy_counts_with_pixel_calibration.py +171 -0
  91. rubin_sim/maf/maf_contrib/lv_dwarfs/__init__.py +1 -0
  92. rubin_sim/maf/maf_contrib/lv_dwarfs/lv_dwarfs_metrics.py +388 -0
  93. rubin_sim/maf/maf_contrib/microlensing_metric.py +593 -0
  94. rubin_sim/maf/maf_contrib/num_obs_in_survey_time_overlap_metric.py +43 -0
  95. rubin_sim/maf/maf_contrib/periodic_metric.py +51 -0
  96. rubin_sim/maf/maf_contrib/periodic_star_metric.py +186 -0
  97. rubin_sim/maf/maf_contrib/periodic_star_modulation_metric.py +236 -0
  98. rubin_sim/maf/maf_contrib/presto_color_kne_pop_metric.py +441 -0
  99. rubin_sim/maf/maf_contrib/selfcal_uniformity_metric.py +171 -0
  100. rubin_sim/maf/maf_contrib/star_count_mass_metric.py +64 -0
  101. rubin_sim/maf/maf_contrib/star_count_metric.py +56 -0
  102. rubin_sim/maf/maf_contrib/star_counts/__init__.py +8 -0
  103. rubin_sim/maf/maf_contrib/star_counts/abs_mag.py +324 -0
  104. rubin_sim/maf/maf_contrib/star_counts/coords.py +99 -0
  105. rubin_sim/maf/maf_contrib/star_counts/readme.txt +1 -0
  106. rubin_sim/maf/maf_contrib/star_counts/spec_type.py +91 -0
  107. rubin_sim/maf/maf_contrib/star_counts/starcount.py +30 -0
  108. rubin_sim/maf/maf_contrib/star_counts/starcount_bymass.py +93 -0
  109. rubin_sim/maf/maf_contrib/star_counts/stellardensity.py +59 -0
  110. rubin_sim/maf/maf_contrib/static_probes_fom_summary_metric.py +386 -0
  111. rubin_sim/maf/maf_contrib/tdes_pop_metric.py +362 -0
  112. rubin_sim/maf/maf_contrib/transient_ascii_sed_metric.py +652 -0
  113. rubin_sim/maf/maf_contrib/triplet_metric.py +156 -0
  114. rubin_sim/maf/maf_contrib/var_depth_metric.py +157 -0
  115. rubin_sim/maf/maf_contrib/xrb_metrics.py +523 -0
  116. rubin_sim/maf/maf_contrib/young_stellar_objects_metric.py +200 -0
  117. rubin_sim/maf/maf_night_report.py +200 -0
  118. rubin_sim/maf/make_fbs_tracking_db.py +90 -0
  119. rubin_sim/maf/maps/__init__.py +8 -0
  120. rubin_sim/maf/maps/base_map.py +72 -0
  121. rubin_sim/maf/maps/create_gaia_density_map.py +158 -0
  122. rubin_sim/maf/maps/dust_map.py +66 -0
  123. rubin_sim/maf/maps/dust_map_3d.py +190 -0
  124. rubin_sim/maf/maps/ebv_3d_hp.py +170 -0
  125. rubin_sim/maf/maps/ebv_hp.py +64 -0
  126. rubin_sim/maf/maps/gal_coords_map.py +22 -0
  127. rubin_sim/maf/maps/galactic_plane_priority_maps.py +210 -0
  128. rubin_sim/maf/maps/stellar_density_map.py +73 -0
  129. rubin_sim/maf/maps/trilegal_map.py +82 -0
  130. rubin_sim/maf/metadata_dir.py +90 -0
  131. rubin_sim/maf/metric_bundles/__init__.py +3 -0
  132. rubin_sim/maf/metric_bundles/metric_bundle.py +816 -0
  133. rubin_sim/maf/metric_bundles/metric_bundle_group.py +834 -0
  134. rubin_sim/maf/metric_bundles/mo_metric_bundle.py +646 -0
  135. rubin_sim/maf/metrics/__init__.py +52 -0
  136. rubin_sim/maf/metrics/agn_time_lag_metric.py +118 -0
  137. rubin_sim/maf/metrics/agnstructure.py +141 -0
  138. rubin_sim/maf/metrics/area_summary_metrics.py +120 -0
  139. rubin_sim/maf/metrics/base_metric.py +215 -0
  140. rubin_sim/maf/metrics/brown_dwarf_metric.py +162 -0
  141. rubin_sim/maf/metrics/cadence_metrics.py +400 -0
  142. rubin_sim/maf/metrics/calibration_metrics.py +618 -0
  143. rubin_sim/maf/metrics/chip_vendor_metric.py +43 -0
  144. rubin_sim/maf/metrics/color_slope_metrics.py +189 -0
  145. rubin_sim/maf/metrics/cosmology_summary_metrics.py +1212 -0
  146. rubin_sim/maf/metrics/coverage_metric.py +48 -0
  147. rubin_sim/maf/metrics/crowding_metric.py +255 -0
  148. rubin_sim/maf/metrics/cumulative_metric.py +46 -0
  149. rubin_sim/maf/metrics/dcr_metric.py +93 -0
  150. rubin_sim/maf/metrics/exgal_m5.py +57 -0
  151. rubin_sim/maf/metrics/fft_metric.py +27 -0
  152. rubin_sim/maf/metrics/galactic_plane_metrics.py +375 -0
  153. rubin_sim/maf/metrics/galplane_time_sampling_metrics.py +236 -0
  154. rubin_sim/maf/metrics/hourglass_metric.py +130 -0
  155. rubin_sim/maf/metrics/incremental_template_metric.py +255 -0
  156. rubin_sim/maf/metrics/kuiper_metrics.py +26 -0
  157. rubin_sim/maf/metrics/mo_metrics.py +1496 -0
  158. rubin_sim/maf/metrics/mo_summary_metrics.py +464 -0
  159. rubin_sim/maf/metrics/night_pointing_metric.py +70 -0
  160. rubin_sim/maf/metrics/optimal_m5_metric.py +94 -0
  161. rubin_sim/maf/metrics/pair_metric.py +69 -0
  162. rubin_sim/maf/metrics/periodic_detect_metric.py +133 -0
  163. rubin_sim/maf/metrics/phase_gap_metric.py +172 -0
  164. rubin_sim/maf/metrics/qso_number_counts_metric.py +138 -0
  165. rubin_sim/maf/metrics/scaling_metrics.py +148 -0
  166. rubin_sim/maf/metrics/schedview_metrics.py +39 -0
  167. rubin_sim/maf/metrics/season_metrics.py +344 -0
  168. rubin_sim/maf/metrics/simple_metrics.py +546 -0
  169. rubin_sim/maf/metrics/sky_sat_metric.py +18 -0
  170. rubin_sim/maf/metrics/sn_cadence_metric.py +104 -0
  171. rubin_sim/maf/metrics/sn_n_sn_metric.py +1364 -0
  172. rubin_sim/maf/metrics/sn_sl_metric.py +216 -0
  173. rubin_sim/maf/metrics/sn_snr_metric.py +715 -0
  174. rubin_sim/maf/metrics/snr_weight.py +24 -0
  175. rubin_sim/maf/metrics/star_density.py +77 -0
  176. rubin_sim/maf/metrics/string_count_metric.py +95 -0
  177. rubin_sim/maf/metrics/summary_metrics.py +201 -0
  178. rubin_sim/maf/metrics/surfb_metric.py +175 -0
  179. rubin_sim/maf/metrics/technical_metrics.py +271 -0
  180. rubin_sim/maf/metrics/tgaps.py +412 -0
  181. rubin_sim/maf/metrics/tomography_models.py +2034 -0
  182. rubin_sim/maf/metrics/transient_metrics.py +268 -0
  183. rubin_sim/maf/metrics/uniformity_metrics.py +418 -0
  184. rubin_sim/maf/metrics/use_metrics.py +55 -0
  185. rubin_sim/maf/metrics/vector_metrics.py +190 -0
  186. rubin_sim/maf/metrics/visit_groups_metric.py +341 -0
  187. rubin_sim/maf/metrics/weak_lensing_systematics_metric.py +210 -0
  188. rubin_sim/maf/plots/__init__.py +14 -0
  189. rubin_sim/maf/plots/hg_plotters.py +1117 -0
  190. rubin_sim/maf/plots/hourglass_plotters.py +120 -0
  191. rubin_sim/maf/plots/mo_plotters.py +358 -0
  192. rubin_sim/maf/plots/nd_plotters.py +220 -0
  193. rubin_sim/maf/plots/neo_distance_plotter.py +140 -0
  194. rubin_sim/maf/plots/night_pointing_plotter.py +96 -0
  195. rubin_sim/maf/plots/oned_plotters.py +114 -0
  196. rubin_sim/maf/plots/perceptual_rainbow.py +30 -0
  197. rubin_sim/maf/plots/plot_handler.py +766 -0
  198. rubin_sim/maf/plots/skyproj_plotters.py +540 -0
  199. rubin_sim/maf/plots/spatial_plotters.py +1029 -0
  200. rubin_sim/maf/plots/special_plotters.py +256 -0
  201. rubin_sim/maf/plots/two_d_plotters.py +177 -0
  202. rubin_sim/maf/plots/xyplotter.py +37 -0
  203. rubin_sim/maf/run_comparison/__init__.py +5 -0
  204. rubin_sim/maf/run_comparison/archive.py +584 -0
  205. rubin_sim/maf/run_comparison/gather_summaries.py +125 -0
  206. rubin_sim/maf/run_comparison/microlensing_compare.py +514 -0
  207. rubin_sim/maf/run_comparison/radar_plot.py +202 -0
  208. rubin_sim/maf/run_comparison/summary_plots.py +710 -0
  209. rubin_sim/maf/run_moving_calc.py +239 -0
  210. rubin_sim/maf/run_moving_fractions.py +128 -0
  211. rubin_sim/maf/run_moving_join.py +103 -0
  212. rubin_sim/maf/run_selfcal_metric.py +92 -0
  213. rubin_sim/maf/scimaf_dir.py +87 -0
  214. rubin_sim/maf/show_maf.py +227 -0
  215. rubin_sim/maf/slicers/__init__.py +13 -0
  216. rubin_sim/maf/slicers/base_slicer.py +513 -0
  217. rubin_sim/maf/slicers/base_spatial_slicer.py +202 -0
  218. rubin_sim/maf/slicers/healpix_sdss_slicer.py +118 -0
  219. rubin_sim/maf/slicers/healpix_slicer.py +189 -0
  220. rubin_sim/maf/slicers/healpix_subset_slicer.py +293 -0
  221. rubin_sim/maf/slicers/hourglass_slicer.py +37 -0
  222. rubin_sim/maf/slicers/mo_slicer.py +171 -0
  223. rubin_sim/maf/slicers/movie_slicer.py +288 -0
  224. rubin_sim/maf/slicers/nd_slicer.py +147 -0
  225. rubin_sim/maf/slicers/one_d_slicer.py +210 -0
  226. rubin_sim/maf/slicers/time_interval_slicers.py +283 -0
  227. rubin_sim/maf/slicers/uni_slicer.py +57 -0
  228. rubin_sim/maf/slicers/user_points_slicer.py +141 -0
  229. rubin_sim/maf/stackers/__init__.py +13 -0
  230. rubin_sim/maf/stackers/base_stacker.py +221 -0
  231. rubin_sim/maf/stackers/coord_stackers.py +224 -0
  232. rubin_sim/maf/stackers/date_stackers.py +192 -0
  233. rubin_sim/maf/stackers/general_stackers.py +683 -0
  234. rubin_sim/maf/stackers/get_col_info.py +104 -0
  235. rubin_sim/maf/stackers/label_stackers.py +114 -0
  236. rubin_sim/maf/stackers/m5_optimal_stacker.py +126 -0
  237. rubin_sim/maf/stackers/mo_phase.py +265 -0
  238. rubin_sim/maf/stackers/mo_stackers.py +486 -0
  239. rubin_sim/maf/stackers/n_follow_stacker.py +187 -0
  240. rubin_sim/maf/stackers/neo_dist_stacker.py +126 -0
  241. rubin_sim/maf/stackers/sdss_stackers.py +30 -0
  242. rubin_sim/maf/stackers/sn_stacker.py +152 -0
  243. rubin_sim/maf/stackers/teff_stacker.py +154 -0
  244. rubin_sim/maf/utils/__init__.py +6 -0
  245. rubin_sim/maf/utils/astrometry_utils.py +93 -0
  246. rubin_sim/maf/utils/generate_fov_map.py +58 -0
  247. rubin_sim/maf/utils/get_date_version.py +28 -0
  248. rubin_sim/maf/utils/maf_utils.py +212 -0
  249. rubin_sim/maf/utils/opsim_utils.py +259 -0
  250. rubin_sim/maf/utils/output_utils.py +34 -0
  251. rubin_sim/maf/utils/sn_n_sn_utils.py +894 -0
  252. rubin_sim/maf/utils/sn_utils.py +369 -0
  253. rubin_sim/maf/utils/stellar_mags.py +197 -0
  254. rubin_sim/maf/web/__init__.py +2 -0
  255. rubin_sim/maf/web/favicon.ico +0 -0
  256. rubin_sim/maf/web/maf_run_results.py +645 -0
  257. rubin_sim/maf/web/maf_tracking.py +139 -0
  258. rubin_sim/maf/web/sorttable.js +496 -0
  259. rubin_sim/maf/web/templates/allmetricresults.html +72 -0
  260. rubin_sim/maf/web/templates/configs.html +28 -0
  261. rubin_sim/maf/web/templates/macros.html +243 -0
  262. rubin_sim/maf/web/templates/master.html +294 -0
  263. rubin_sim/maf/web/templates/metricselect.html +91 -0
  264. rubin_sim/maf/web/templates/multicolor.html +147 -0
  265. rubin_sim/maf/web/templates/results.html +82 -0
  266. rubin_sim/maf/web/templates/runselect.html +58 -0
  267. rubin_sim/maf/web/templates/stats.html +50 -0
  268. rubin_sim/moving_objects/__init__.py +8 -0
  269. rubin_sim/moving_objects/base_obs.py +468 -0
  270. rubin_sim/moving_objects/cheby_fits.py +689 -0
  271. rubin_sim/moving_objects/cheby_values.py +231 -0
  272. rubin_sim/moving_objects/chebyshev_utils.py +365 -0
  273. rubin_sim/moving_objects/direct_obs.py +376 -0
  274. rubin_sim/moving_objects/make_lsst_obs.py +282 -0
  275. rubin_sim/moving_objects/ooephemerides.py +643 -0
  276. rubin_sim/moving_objects/orbits.py +507 -0
  277. rubin_sim/moving_objects/pre_generate.py +37 -0
  278. rubin_sim/moving_objects/utils.py +61 -0
  279. rubin_sim/phot_utils/__init__.py +7 -0
  280. rubin_sim/phot_utils/bandpass.py +425 -0
  281. rubin_sim/phot_utils/photometric_parameters.py +449 -0
  282. rubin_sim/phot_utils/physical_parameters.py +50 -0
  283. rubin_sim/phot_utils/predicted_zeropoints.py +245 -0
  284. rubin_sim/phot_utils/sed.py +1773 -0
  285. rubin_sim/phot_utils/sed_utils.py +52 -0
  286. rubin_sim/phot_utils/signaltonoise.py +695 -0
  287. rubin_sim/phot_utils/spectral_resampling.py +161 -0
  288. rubin_sim/satellite_constellations/__init__.py +3 -0
  289. rubin_sim/satellite_constellations/basis_function.py +40 -0
  290. rubin_sim/satellite_constellations/model_observatory.py +157 -0
  291. rubin_sim/satellite_constellations/sat_utils.py +488 -0
  292. rubin_sim/selfcal/__init__.py +4 -0
  293. rubin_sim/selfcal/generate_catalog.py +188 -0
  294. rubin_sim/selfcal/offsets.py +119 -0
  295. rubin_sim/selfcal/solver.py +143 -0
  296. rubin_sim/selfcal/star_tools.py +42 -0
  297. rubin_sim/sim_archive/__init__.py +14 -0
  298. rubin_sim/sim_archive/conda_packages.py +65 -0
  299. rubin_sim/sim_archive/future_vsarch.py +480 -0
  300. rubin_sim/sim_archive/make_snapshot.py +255 -0
  301. rubin_sim/sim_archive/prenight.py +216 -0
  302. rubin_sim/sim_archive/prenightindex.py +229 -0
  303. rubin_sim/sim_archive/prototype.py +1029 -0
  304. rubin_sim/sim_archive/sim_archive.py +680 -0
  305. rubin_sim/sim_archive/tempdb.py +56 -0
  306. rubin_sim/sim_archive/util.py +146 -0
  307. rubin_sim/sim_archive/vseqarchive.py +965 -0
  308. rubin_sim/sim_archive/vseqmetadata.py +1721 -0
  309. rubin_sim/skybrightness/__init__.py +5 -0
  310. rubin_sim/skybrightness/allsky_db.py +93 -0
  311. rubin_sim/skybrightness/data/ESO_Spectra/eso_tools.py +505 -0
  312. rubin_sim/skybrightness/data/solarSpec/package.py +22 -0
  313. rubin_sim/skybrightness/generate_hdf5.py +243 -0
  314. rubin_sim/skybrightness/interp_components.py +798 -0
  315. rubin_sim/skybrightness/sky_model.py +771 -0
  316. rubin_sim/skybrightness/twilight_func.py +83 -0
  317. rubin_sim/skybrightness/utils.py +91 -0
  318. rubin_sim-2.6.1.dev2.dist-info/METADATA +95 -0
  319. rubin_sim-2.6.1.dev2.dist-info/RECORD +387 -0
  320. rubin_sim-2.6.1.dev2.dist-info/WHEEL +5 -0
  321. rubin_sim-2.6.1.dev2.dist-info/entry_points.txt +24 -0
  322. rubin_sim-2.6.1.dev2.dist-info/licenses/LICENSE +674 -0
  323. rubin_sim-2.6.1.dev2.dist-info/top_level.txt +5 -0
  324. sql/make_vseqmeta.sql +251 -0
  325. tests/data/test_data.py +26 -0
  326. tests/data/test_ddf_grid.py +17 -0
  327. tests/maf/test_3x2fom.py +68 -0
  328. tests/maf/test_archive.py +162 -0
  329. tests/maf/test_basemetrics.py +99 -0
  330. tests/maf/test_batchcommon.py +36 -0
  331. tests/maf/test_batches.py +159 -0
  332. tests/maf/test_cadencemetrics.py +388 -0
  333. tests/maf/test_calibrationmetrics.py +242 -0
  334. tests/maf/test_color_slopes.py +71 -0
  335. tests/maf/test_cosmology_summaries.py +20 -0
  336. tests/maf/test_gathersummaries.py +48 -0
  337. tests/maf/test_healpixslicer.py +439 -0
  338. tests/maf/test_healpixsubsetslicer.py +273 -0
  339. tests/maf/test_hgplotters.py +145 -0
  340. tests/maf/test_hourglassmetric.py +33 -0
  341. tests/maf/test_io.py +187 -0
  342. tests/maf/test_json.py +169 -0
  343. tests/maf/test_maps.py +199 -0
  344. tests/maf/test_metricbundle.py +69 -0
  345. tests/maf/test_mometrics.py +422 -0
  346. tests/maf/test_movieslicer.py +216 -0
  347. tests/maf/test_ndslicer.py +240 -0
  348. tests/maf/test_neodistanceplotter.py +41 -0
  349. tests/maf/test_onedslicer.py +245 -0
  350. tests/maf/test_opsimutils.py +80 -0
  351. tests/maf/test_plotters.py +134 -0
  352. tests/maf/test_resultsdb.py +145 -0
  353. tests/maf/test_schedviewmetrics.py +14 -0
  354. tests/maf/test_simplemetrics.py +200 -0
  355. tests/maf/test_snmetrics.py +335 -0
  356. tests/maf/test_snmetrics_nsn.py +123 -0
  357. tests/maf/test_stackers.py +423 -0
  358. tests/maf/test_stellarmags.py +50 -0
  359. tests/maf/test_stringcount.py +26 -0
  360. tests/maf/test_summary_plots.py +197 -0
  361. tests/maf/test_summarymetrics.py +82 -0
  362. tests/maf/test_technicalmetrics.py +267 -0
  363. tests/maf/test_templatemetrics.py +86 -0
  364. tests/maf/test_timeintervalslicers.py +97 -0
  365. tests/maf/test_trackingdb.py +88 -0
  366. tests/maf/test_unislicer.py +116 -0
  367. tests/maf/test_vectormetrics.py +225 -0
  368. tests/maf/test_visitgroupsmetric.py +181 -0
  369. tests/moving_objects/test_camera.py +39 -0
  370. tests/moving_objects/test_chebyfits.py +188 -0
  371. tests/moving_objects/test_chebyshevutils.py +76 -0
  372. tests/moving_objects/test_chebyvalues.py +245 -0
  373. tests/moving_objects/test_ephemerides.py +219 -0
  374. tests/moving_objects/test_orbits.py +170 -0
  375. tests/moving_objects/test_sed_data.py +61 -0
  376. tests/phot_utils/test_approximatebandpasses.py +91 -0
  377. tests/phot_utils/test_photometricparameters.py +268 -0
  378. tests/phot_utils/test_photometry.py +61 -0
  379. tests/phot_utils/test_predicted_zeropoints.py +53 -0
  380. tests/phot_utils/test_read_bandpasses.py +29 -0
  381. tests/phot_utils/test_sed.py +368 -0
  382. tests/phot_utils/test_snr.py +370 -0
  383. tests/satellite_constellations/test_satellites.py +36 -0
  384. tests/sim_archive/test_make_snapshot.py +24 -0
  385. tests/sim_archive/test_prototype_sim_archive.py +204 -0
  386. tests/sim_archive/test_vseqarchive.py +947 -0
  387. tests/skybrightness/test_skymodel.py +359 -0
@@ -0,0 +1,1587 @@
1
+ __all__ = (
2
+ "ss_population_defaults",
3
+ "quick_discovery_batch",
4
+ "discovery_batch",
5
+ "run_completeness_summary",
6
+ "plot_completeness",
7
+ "characterization_inner_batch",
8
+ "characterization_outer_batch",
9
+ "run_fraction_summary",
10
+ "plot_fractions",
11
+ "plot_single",
12
+ "plot_activity",
13
+ "read_and_combine",
14
+ "combine_subsets",
15
+ )
16
+
17
+ import os
18
+ from copy import deepcopy
19
+
20
+ import matplotlib.pyplot as plt
21
+ import numpy as np
22
+ import numpy.ma as ma
23
+
24
+ import rubin_sim.maf.metric_bundles as mb
25
+ import rubin_sim.maf.metrics as metrics
26
+ import rubin_sim.maf.plots as plots
27
+ import rubin_sim.maf.stackers as stackers
28
+ from rubin_sim.maf.metric_bundles import MoMetricBundle
29
+
30
+ from .col_map_dict import col_map_dict
31
+ from .common import (
32
+ fraction_population_at_threshold,
33
+ summary_completeness_at_time,
34
+ summary_completeness_over_h,
35
+ )
36
+
37
+
38
+ def ss_population_defaults(objtype):
39
+ """Provide useful default ranges for H,
40
+ based on objtype of population type.
41
+ """
42
+ defaults = {}
43
+ defaults["Vatira"] = {
44
+ "h_range": [16, 28, 0.2],
45
+ "h_mark": 22,
46
+ "magtype": "asteroid",
47
+ "char": "inner",
48
+ }
49
+ defaults["PHA"] = {
50
+ "h_range": [16, 28, 0.2],
51
+ "h_mark": 22,
52
+ "magtype": "asteroid",
53
+ "char": "inner",
54
+ }
55
+ defaults["NEO"] = {
56
+ "h_range": [16, 28, 0.2],
57
+ "h_mark": 22,
58
+ "magtype": "asteroid",
59
+ "char": "inner",
60
+ }
61
+ defaults["MBA"] = {
62
+ "h_range": [16, 26, 0.2],
63
+ "h_mark": 20,
64
+ "magtype": "asteroid",
65
+ "char": "inner",
66
+ }
67
+ defaults["MBC"] = {
68
+ "h_range": [16, 26, 0.2],
69
+ "h_mark": 20,
70
+ "magtype": "asteroid",
71
+ "char": "inner",
72
+ }
73
+ defaults["Trojan"] = {
74
+ "h_range": [14, 22, 0.2],
75
+ "h_mark": 18,
76
+ "magtype": "asteroid",
77
+ "char": "inner",
78
+ }
79
+ defaults["TNO"] = {
80
+ "h_range": [4, 12, 0.2],
81
+ "h_mark": 8,
82
+ "magtype": "asteroid",
83
+ "char": "outer",
84
+ }
85
+ defaults["SDO"] = {
86
+ "h_range": [4, 12, 0.2],
87
+ "h_mark": 8,
88
+ "magtype": "asteroid",
89
+ "char": "outer",
90
+ }
91
+ defaults["LPC"] = {
92
+ "h_range": [6, 22, 0.5],
93
+ "h_mark": 13,
94
+ "magtype": "comet_oort",
95
+ "char": "outer",
96
+ }
97
+ defaults["SPC"] = {
98
+ "h_range": [4, 20, 0.5],
99
+ "h_mark": 8,
100
+ "magtype": "comet_short",
101
+ "char": "outer",
102
+ }
103
+ defaults["generic"] = {
104
+ "h_range": [4, 28, 0.5],
105
+ "h_mark": 10,
106
+ "magtype": "asteroid",
107
+ "char": "inner",
108
+ }
109
+ # Some objtypes may be provided by other names
110
+ if objtype.upper().startswith("GRANVIK"):
111
+ objtype = "NEO"
112
+ if objtype.upper().startswith("L7"):
113
+ objtype = "TNO"
114
+ if objtype.upper().startswith("OCC"):
115
+ objtype = "LPC"
116
+
117
+ if objtype not in defaults:
118
+ print(
119
+ f"## Could not find {objtype} in default keys ({defaults.keys()}). \n"
120
+ f"## Using generic default values instead."
121
+ )
122
+ objtype = "generic"
123
+
124
+ return defaults[objtype]
125
+
126
+
127
+ def quick_discovery_batch(
128
+ slicer,
129
+ colmap=None,
130
+ run_name="run_name",
131
+ detection_losses="detection",
132
+ objtype="",
133
+ albedo=None,
134
+ h_mark=None,
135
+ np_reduce=np.mean,
136
+ constraint_info_label="",
137
+ constraint=None,
138
+ magtype="asteroid",
139
+ ):
140
+ """A subset of discovery metrics, using only the default discovery
141
+ criteria of 3 pairs in 15 or 30 nights.
142
+ """
143
+ if colmap is None:
144
+ colmap = col_map_dict()
145
+ bundleList = []
146
+
147
+ basicPlotDict = {
148
+ "albedo": albedo,
149
+ "h_mark": h_mark,
150
+ "np_reduce": np_reduce,
151
+ "nxbins": 200,
152
+ "nybins": 200,
153
+ }
154
+ plot_funcs = [plots.MetricVsH()]
155
+ display_dict = {"group": f"{objtype}", "subgroup": "Discovery"}
156
+
157
+ if constraint_info_label == "" and constraint is not None:
158
+ constraint_info_label = constraint.replace("filter", "").replace("==", "").replace(" ", " ")
159
+ info_label = objtype + " " + constraint_info_label
160
+ info_label = info_label.rstrip(" ")
161
+
162
+ if detection_losses not in ("detection", "trailing"):
163
+ raise ValueError("Please choose detection or trailing as options for detection_losses.")
164
+ if detection_losses == "trailing":
165
+ magStacker = stackers.MoMagStacker(loss_col="dmag_trail", magtype=magtype)
166
+ detection_losses = " trailing loss"
167
+ else:
168
+ magStacker = stackers.MoMagStacker(loss_col="dmag_detect", magtype=magtype)
169
+ detection_losses = " detection loss"
170
+
171
+ # Set up a dictionary to pass to each metric for the column names.
172
+ colkwargs = {
173
+ "mjd_col": colmap["mjd"],
174
+ "seeing_col": colmap["seeingGeom"],
175
+ "exp_time_col": colmap["exptime"],
176
+ "m5_col": colmap["fiveSigmaDepth"],
177
+ "night_col": colmap["night"],
178
+ "filter_col": colmap["filter"],
179
+ }
180
+
181
+ def _setup_child_metrics(parentMetric):
182
+ childMetrics = {}
183
+ childMetrics["Time"] = metrics.DiscoveryTimeMetric(parentMetric, **colkwargs)
184
+ childMetrics["N_Chances"] = metrics.DiscoveryNChancesMetric(parentMetric, **colkwargs)
185
+ # Could expand to add N_chances per year, but not really necessary.
186
+ return childMetrics
187
+
188
+ def _configure_child_bundles(parentBundle):
189
+ dispDict = {
190
+ "group": f"{objtype}",
191
+ "subgroup": "Completeness Over Time",
192
+ "caption": "Time of discovery of objects",
193
+ "order": 0,
194
+ }
195
+ parentBundle.child_bundles["Time"].set_display_dict(dispDict)
196
+ dispDict = {
197
+ "group": f"{objtype}",
198
+ "subgroup": "N Chances",
199
+ "caption": "Number of chances for discovery of objects",
200
+ "order": 0,
201
+ }
202
+ parentBundle.child_bundles["N_Chances"].set_display_dict(dispDict)
203
+ return
204
+
205
+ t_min = 5.0 / 60.0 / 24.0
206
+ t_max = 90.0 / 60.0 / 24.0
207
+
208
+ # 3 pairs in 15
209
+ md = info_label + " 3 pairs in 15 nights" + detection_losses
210
+ # Set up plot dict.
211
+ plotDict = {"title": "%s: %s" % (run_name, md)}
212
+ plotDict.update(basicPlotDict)
213
+ metric = metrics.DiscoveryMetric(
214
+ n_obs_per_night=2,
215
+ t_min=t_min,
216
+ t_max=t_max,
217
+ n_nights_per_window=3,
218
+ t_window=15,
219
+ **colkwargs,
220
+ )
221
+ childMetrics = _setup_child_metrics(metric)
222
+ bundle = MoMetricBundle(
223
+ metric,
224
+ slicer,
225
+ constraint,
226
+ stacker_list=[magStacker],
227
+ run_name=run_name,
228
+ info_label=md,
229
+ child_metrics=childMetrics,
230
+ plot_dict=plotDict,
231
+ plot_funcs=plot_funcs,
232
+ display_dict=display_dict,
233
+ )
234
+ _configure_child_bundles(bundle)
235
+ bundleList.append(bundle)
236
+
237
+ # 3 pairs in 30
238
+ md = info_label + " 3 pairs in 30 nights" + detection_losses
239
+ plotDict = {"title": "%s: %s" % (run_name, md)}
240
+ plotDict.update(basicPlotDict)
241
+ metric = metrics.DiscoveryMetric(
242
+ n_obs_per_night=2,
243
+ t_min=t_min,
244
+ t_max=t_max,
245
+ n_nights_per_window=3,
246
+ t_window=30,
247
+ **colkwargs,
248
+ )
249
+ childMetrics = _setup_child_metrics(metric)
250
+ bundle = MoMetricBundle(
251
+ metric,
252
+ slicer,
253
+ constraint,
254
+ stacker_list=[magStacker],
255
+ run_name=run_name,
256
+ info_label=md,
257
+ child_metrics=childMetrics,
258
+ plot_dict=plotDict,
259
+ plot_funcs=plot_funcs,
260
+ display_dict=display_dict,
261
+ )
262
+ _configure_child_bundles(bundle)
263
+ bundleList.append(bundle)
264
+
265
+ # Set the run_name for all bundles and return the bundleDict.
266
+ for b in bundleList:
267
+ b.set_run_name(run_name)
268
+ return mb.make_bundles_dict_from_list(bundleList)
269
+
270
+
271
+ def discovery_batch(
272
+ slicer,
273
+ colmap=None,
274
+ run_name="run_name",
275
+ detection_losses="detection",
276
+ objtype="",
277
+ albedo=None,
278
+ h_mark=None,
279
+ np_reduce=np.mean,
280
+ constraint_info_label="",
281
+ constraint=None,
282
+ magtype="asteroid",
283
+ ):
284
+ """A comprehensive set of discovery metrics, using a wide range
285
+ of discovery criteria.
286
+ """
287
+ if colmap is None:
288
+ colmap = col_map_dict()
289
+ bundleList = []
290
+
291
+ basicPlotDict = {
292
+ "albedo": albedo,
293
+ "h_mark": h_mark,
294
+ "np_reduce": np_reduce,
295
+ "nxbins": 200,
296
+ "nybins": 200,
297
+ }
298
+ plot_funcs = [plots.MetricVsH()]
299
+ display_dict = {"group": f"{objtype}", "subgroup": "Discovery"}
300
+
301
+ if constraint_info_label == "" and constraint is not None:
302
+ constraint_info_label = constraint.replace("filter", "").replace("==", "").replace(" ", " ")
303
+ info_label = objtype + " " + constraint_info_label
304
+ info_label = info_label.rstrip(" ")
305
+
306
+ if detection_losses not in ("detection", "trailing"):
307
+ raise ValueError("Please choose detection or trailing as options for detection_losses.")
308
+ if detection_losses == "trailing":
309
+ # These are the SNR-losses only.
310
+ magStacker = stackers.MoMagStacker(loss_col="dmag_trail", magtype=magtype)
311
+ detection_losses = " trailing loss"
312
+ else:
313
+ # SNR losses, plus additional loss due to detecting with stellar PSF.
314
+ magStacker = stackers.MoMagStacker(loss_col="dmag_detect", magtype=magtype)
315
+ detection_losses = " detection loss"
316
+
317
+ # Set up a dictionary to pass to each metric for the column names.
318
+ colkwargs = {
319
+ "mjd_col": colmap["mjd"],
320
+ "seeing_col": colmap["seeingGeom"],
321
+ "exp_time_col": colmap["exptime"],
322
+ "m5_col": colmap["fiveSigmaDepth"],
323
+ "night_col": colmap["night"],
324
+ "filter_col": colmap["filter"],
325
+ }
326
+
327
+ def _setup_child_metrics(parentMetric):
328
+ childMetrics = {}
329
+ childMetrics["Time"] = metrics.DiscoveryTimeMetric(parentMetric, **colkwargs)
330
+ childMetrics["N_Chances"] = metrics.DiscoveryNChancesMetric(parentMetric, **colkwargs)
331
+ # Could expand to add N_chances per year, but not really necessary.
332
+ return childMetrics
333
+
334
+ def _configure_child_bundles(parentBundle):
335
+ dispDict = {
336
+ "group": f"{objtype}",
337
+ "subgroup": "Completeness Over Time",
338
+ "caption": "Time of discovery of objects",
339
+ "order": 0,
340
+ }
341
+ parentBundle.child_bundles["Time"].set_display_dict(dispDict)
342
+ dispDict = {
343
+ "group": f"{objtype}",
344
+ "subgroup": "N Chances",
345
+ "caption": "Number of chances for discovery of objects",
346
+ "order": 0,
347
+ }
348
+ parentBundle.child_bundles["N_Chances"].set_display_dict(dispDict)
349
+
350
+ t_min = 5.0 / 60.0 / 24.0
351
+ t_max = 90.0 / 60.0 / 24.0
352
+
353
+ # 3 pairs in 15 and 3 pairs in 30 done in 'quickDiscoveryBatch' (with vis).
354
+
355
+ # 4 pairs in 20
356
+ md = info_label + " 4 pairs in 20 nights" + detection_losses
357
+ plotDict = {"title": "%s: %s" % (run_name, md)}
358
+ plotDict.update(basicPlotDict)
359
+ metric = metrics.DiscoveryMetric(
360
+ n_obs_per_night=2,
361
+ t_min=t_min,
362
+ t_max=t_max,
363
+ n_nights_per_window=4,
364
+ t_window=20,
365
+ **colkwargs,
366
+ )
367
+ childMetrics = _setup_child_metrics(metric)
368
+ bundle = MoMetricBundle(
369
+ metric,
370
+ slicer,
371
+ constraint,
372
+ stacker_list=[magStacker],
373
+ run_name=run_name,
374
+ info_label=md,
375
+ child_metrics=childMetrics,
376
+ plot_dict=plotDict,
377
+ plot_funcs=plot_funcs,
378
+ display_dict=display_dict,
379
+ )
380
+ _configure_child_bundles(bundle)
381
+ bundleList.append(bundle)
382
+
383
+ # 3 triplets in 30
384
+ md = info_label + " 3 triplets in 30 nights" + detection_losses
385
+ plotDict = {"title": "%s: %s" % (run_name, md)}
386
+ plotDict.update(basicPlotDict)
387
+ metric = metrics.DiscoveryMetric(
388
+ n_obs_per_night=3,
389
+ t_min=t_min,
390
+ t_max=120.0 / 60.0 / 24.0,
391
+ n_nights_per_window=3,
392
+ t_window=30,
393
+ **colkwargs,
394
+ )
395
+ childMetrics = _setup_child_metrics(metric)
396
+ bundle = MoMetricBundle(
397
+ metric,
398
+ slicer,
399
+ constraint,
400
+ stacker_list=[magStacker],
401
+ run_name=run_name,
402
+ info_label=md,
403
+ child_metrics=childMetrics,
404
+ plot_dict=plotDict,
405
+ plot_funcs=plot_funcs,
406
+ display_dict=display_dict,
407
+ )
408
+ _configure_child_bundles(bundle)
409
+ bundleList.append(bundle)
410
+
411
+ # 1 quad
412
+ md = info_label + " 1 quad in 1 night" + detection_losses
413
+ plotDict = {"title": "%s: %s" % (run_name, md)}
414
+ plotDict.update(basicPlotDict)
415
+ metric = metrics.DiscoveryMetric(
416
+ n_obs_per_night=4,
417
+ t_min=t_min,
418
+ t_max=150.0 / 60.0 / 24.0,
419
+ n_nights_per_window=1,
420
+ t_window=2,
421
+ **colkwargs,
422
+ )
423
+ childMetrics = _setup_child_metrics(metric)
424
+ bundle = MoMetricBundle(
425
+ metric,
426
+ slicer,
427
+ constraint,
428
+ stacker_list=[magStacker],
429
+ run_name=run_name,
430
+ info_label=md,
431
+ child_metrics=childMetrics,
432
+ plot_dict=plotDict,
433
+ plot_funcs=plot_funcs,
434
+ display_dict=display_dict,
435
+ )
436
+ _configure_child_bundles(bundle)
437
+ bundleList.append(bundle)
438
+
439
+ # Play with SNR.
440
+ # First standard SNR / probabilistic visibility (SNR~5)
441
+ # 3 pairs in 15
442
+ md = info_label + " 3 pairs in 15 nights SNR=5" + detection_losses
443
+ # Set up plot dict.
444
+ plotDict = {"title": "%s: %s" % (run_name, md)}
445
+ plotDict.update(basicPlotDict)
446
+ metric = metrics.DiscoveryMetric(
447
+ n_obs_per_night=2,
448
+ t_min=t_min,
449
+ t_max=t_max,
450
+ n_nights_per_window=3,
451
+ t_window=15,
452
+ snr_limit=5,
453
+ **colkwargs,
454
+ )
455
+ childMetrics = _setup_child_metrics(metric)
456
+ bundle = MoMetricBundle(
457
+ metric,
458
+ slicer,
459
+ constraint,
460
+ stacker_list=[magStacker],
461
+ run_name=run_name,
462
+ info_label=md,
463
+ child_metrics=childMetrics,
464
+ plot_dict=plotDict,
465
+ plot_funcs=plot_funcs,
466
+ display_dict=display_dict,
467
+ )
468
+ _configure_child_bundles(bundle)
469
+ bundleList.append(bundle)
470
+
471
+ # 3 pairs in 15, SNR=4.
472
+ md = info_label + " 3 pairs in 15 nights SNR=4" + detection_losses
473
+ plotDict = {"title": "%s: %s" % (run_name, md)}
474
+ plotDict.update(basicPlotDict)
475
+ metric = metrics.DiscoveryMetric(
476
+ n_obs_per_night=2,
477
+ t_min=t_min,
478
+ t_max=t_max,
479
+ n_nights_per_window=3,
480
+ t_window=15,
481
+ snr_limit=4,
482
+ **colkwargs,
483
+ )
484
+ childMetrics = _setup_child_metrics(metric)
485
+ bundle = MoMetricBundle(
486
+ metric,
487
+ slicer,
488
+ constraint,
489
+ stacker_list=[magStacker],
490
+ run_name=run_name,
491
+ info_label=md,
492
+ child_metrics=childMetrics,
493
+ plot_dict=plotDict,
494
+ plot_funcs=plot_funcs,
495
+ display_dict=display_dict,
496
+ )
497
+ _configure_child_bundles(bundle)
498
+ bundleList.append(bundle)
499
+
500
+ # 3 pairs in 15, SNR=3
501
+ md = info_label + " 3 pairs in 15 nights SNR=3" + detection_losses
502
+ plotDict = {"title": "%s: %s" % (run_name, md)}
503
+ plotDict.update(basicPlotDict)
504
+ metric = metrics.DiscoveryMetric(
505
+ n_obs_per_night=2,
506
+ t_min=t_min,
507
+ t_max=t_max,
508
+ n_nights_per_window=3,
509
+ t_window=15,
510
+ snr_limit=3,
511
+ **colkwargs,
512
+ )
513
+ childMetrics = _setup_child_metrics(metric)
514
+ bundle = MoMetricBundle(
515
+ metric,
516
+ slicer,
517
+ constraint,
518
+ stacker_list=[magStacker],
519
+ run_name=run_name,
520
+ info_label=md,
521
+ child_metrics=childMetrics,
522
+ plot_dict=plotDict,
523
+ plot_funcs=plot_funcs,
524
+ display_dict=display_dict,
525
+ )
526
+ _configure_child_bundles(bundle)
527
+ bundleList.append(bundle)
528
+
529
+ # SNR = 0
530
+ # 3 pairs in 15, SNR=0
531
+ md = info_label + " 3 pairs in 15 nights SNR=0" + detection_losses
532
+ plotDict = {"title": "%s: %s" % (run_name, md)}
533
+ plotDict.update(basicPlotDict)
534
+ metric = metrics.DiscoveryMetric(
535
+ n_obs_per_night=2,
536
+ t_min=t_min,
537
+ t_max=t_max,
538
+ n_nights_per_window=3,
539
+ t_window=15,
540
+ snr_limit=0,
541
+ **colkwargs,
542
+ )
543
+ childMetrics = _setup_child_metrics(metric)
544
+ bundle = MoMetricBundle(
545
+ metric,
546
+ slicer,
547
+ constraint,
548
+ stacker_list=[magStacker],
549
+ run_name=run_name,
550
+ info_label=md,
551
+ child_metrics=childMetrics,
552
+ plot_dict=plotDict,
553
+ plot_funcs=plot_funcs,
554
+ display_dict=display_dict,
555
+ )
556
+ _configure_child_bundles(bundle)
557
+ bundleList.append(bundle)
558
+
559
+ # Play with weird strategies.
560
+ # Single detection.
561
+ md = info_label + " Single detection" + detection_losses
562
+ plotDict = {"title": "%s: %s" % (run_name, md)}
563
+ plotDict.update(basicPlotDict)
564
+ metric = metrics.DiscoveryMetric(
565
+ n_obs_per_night=1,
566
+ t_min=t_min,
567
+ t_max=t_max,
568
+ n_nights_per_window=1,
569
+ t_window=5,
570
+ **colkwargs,
571
+ )
572
+ childMetrics = _setup_child_metrics(metric)
573
+ bundle = MoMetricBundle(
574
+ metric,
575
+ slicer,
576
+ constraint,
577
+ stacker_list=[magStacker],
578
+ run_name=run_name,
579
+ info_label=md,
580
+ child_metrics=childMetrics,
581
+ plot_dict=plotDict,
582
+ plot_funcs=plot_funcs,
583
+ display_dict=display_dict,
584
+ )
585
+ _configure_child_bundles(bundle)
586
+ bundleList.append(bundle)
587
+
588
+ # Single pair of detections.
589
+ md = info_label + " Single pair" + detection_losses
590
+ plotDict = {"title": "%s: %s" % (run_name, md)}
591
+ plotDict.update(basicPlotDict)
592
+ metric = metrics.DiscoveryMetric(
593
+ n_obs_per_night=2,
594
+ t_min=t_min,
595
+ t_max=t_max,
596
+ n_nights_per_window=1,
597
+ t_window=5,
598
+ **colkwargs,
599
+ )
600
+ childMetrics = _setup_child_metrics(metric)
601
+ bundle = MoMetricBundle(
602
+ metric,
603
+ slicer,
604
+ constraint,
605
+ stacker_list=[magStacker],
606
+ run_name=run_name,
607
+ info_label=md,
608
+ child_metrics=childMetrics,
609
+ plot_dict=plotDict,
610
+ plot_funcs=plot_funcs,
611
+ display_dict=display_dict,
612
+ )
613
+ _configure_child_bundles(bundle)
614
+ bundleList.append(bundle)
615
+
616
+ # High velocity discovery.
617
+ md = info_label + " High velocity pair" + detection_losses
618
+ plotDict = {"title": "%s: %s" % (run_name, md)}
619
+ plotDict.update(basicPlotDict)
620
+ metric = metrics.HighVelocityNightsMetric(psf_factor=2.0, n_obs_per_night=2, **colkwargs)
621
+ bundle = MoMetricBundle(
622
+ metric,
623
+ slicer,
624
+ constraint,
625
+ stacker_list=[magStacker],
626
+ run_name=run_name,
627
+ info_label=md,
628
+ plot_dict=plotDict,
629
+ plot_funcs=plot_funcs,
630
+ display_dict=display_dict,
631
+ )
632
+ bundleList.append(bundle)
633
+
634
+ # "magic" detection - 6 in 60 days.
635
+ md = info_label + " 6 detections in 60 nights" + detection_losses
636
+ plotDict = {"title": "%s: %s" % (run_name, md)}
637
+ plotDict.update(basicPlotDict)
638
+ metric = metrics.MagicDiscoveryMetric(n_obs=6, t_window=60, **colkwargs)
639
+ bundle = MoMetricBundle(
640
+ metric,
641
+ slicer,
642
+ constraint,
643
+ stacker_list=[magStacker],
644
+ run_name=run_name,
645
+ info_label=md,
646
+ plot_dict=plotDict,
647
+ plot_funcs=plot_funcs,
648
+ display_dict=display_dict,
649
+ )
650
+ bundleList.append(bundle)
651
+
652
+ # Set the run_name for all bundles and return the bundleDict.
653
+ for b in bundleList:
654
+ b.set_run_name(run_name)
655
+ return mb.make_bundles_dict_from_list(bundleList)
656
+
657
+
658
+ def run_completeness_summary(bdict, h_mark, times, out_dir, results_db):
659
+ """Calculate completeness and create completeness bundles from all
660
+ N_Chances and Time (child) metrics of the (discovery) bundles in bdict,
661
+ and write completeness at h_mark to results_db, save bundle to disk.
662
+
663
+ This should be done after combining any sub-sets of the metric results.
664
+
665
+ Parameters
666
+ ----------
667
+ bdict : `dict` of `maf.MetricBundle`
668
+ Dict containing ~rubin_sim.maf.MoMetricBundles,
669
+ including bundles we're expecting to contain completeness.
670
+ h_mark : `float`
671
+ h_mark value to add to completeness plotting dict.
672
+ If not defined (None), then the h_mark from the plotdict from the
673
+ metric bundle will be used if available.
674
+ If None and h_mark not in plot_dict, then median of h_range values
675
+ will be used.
676
+ times : `np.ndarray`
677
+ The times at which to calculate completeness (over time).
678
+ out_dir : `str`
679
+ Output directory to save completeness bundles to disk.
680
+ results_db : `maf.ResultsDb`
681
+ Results database to save information about completeness bundle.
682
+
683
+ Returns
684
+ -------
685
+ metricDict : `dict` of `maf.MetricBundles`
686
+ A dictionary of the new completeness bundles. Keys match original keys,
687
+ with additions of "[Differential,Cumulative]Completeness@Time"
688
+ and "[Differential,Cumulative]Completeness" to distinguish new entries.
689
+ """
690
+ # Add completeness bundles and write completeness at h_mark to results_db.
691
+ completeness = {}
692
+
693
+ def _compbundles(b, bundle, h_mark, results_db):
694
+ # Find h_mark if not set (this may be different for different bundles).
695
+ if h_mark is None and "h_mark" in bundle.plot_dict:
696
+ h_mark = bundle.plot_dict["h_mark"]
697
+ if h_mark is None:
698
+ h_mark = np.median(bundle.slicer.slice_points["H"])
699
+ # Set up the summary metrics.
700
+ summaryTimeMetrics = summary_completeness_at_time(times, h_val=h_mark, h_index=0.33)
701
+ summaryTimeMetrics2 = summary_completeness_at_time(times, h_val=h_mark - 2, h_index=0.33)
702
+ summaryHMetrics = summary_completeness_over_h(requiredChances=1, Hindex=0.33)
703
+ comp = {}
704
+ # Bundle = single metric bundle.
705
+ # Add differential and cumulative completeness.
706
+ if "Time" in bundle.metric.name:
707
+ for metric in summaryTimeMetrics:
708
+ newkey = b + " " + metric.name
709
+ comp[newkey] = mb.make_completeness_bundle(bundle, metric, h_mark=None, results_db=results_db)
710
+ comp[newkey].plot_dict["times"] = times
711
+ comp[newkey].plot_dict["h_val"] = metric.hval
712
+ for metric in summaryTimeMetrics2:
713
+ newkey = b + " " + metric.name
714
+ comp[newkey] = mb.make_completeness_bundle(bundle, metric, h_mark=None, results_db=results_db)
715
+ comp[newkey].plot_dict["times"] = times
716
+ comp[newkey].plot_dict["h_val"] = metric.hval
717
+ elif "NChances" in bundle.metric.name or "N_Chances" in bundle.metric.name:
718
+ for metric in summaryHMetrics:
719
+ newkey = b + " " + metric.name
720
+ comp[newkey] = mb.make_completeness_bundle(
721
+ bundle, metric, h_mark=h_mark, results_db=results_db
722
+ )
723
+ elif "MagicDiscovery" in bundle.metric.name:
724
+ for metric in summaryHMetrics:
725
+ newkey = b + " " + metric.name
726
+ comp[newkey] = mb.make_completeness_bundle(
727
+ bundle, metric, h_mark=h_mark, results_db=results_db
728
+ )
729
+ elif "HighVelocity" in bundle.metric.name:
730
+ for metric in summaryHMetrics:
731
+ newkey = b + " " + metric.name
732
+ comp[newkey] = mb.make_completeness_bundle(
733
+ bundle, metric, h_mark=h_mark, results_db=results_db
734
+ )
735
+ return comp
736
+
737
+ # Generate the completeness bundles for the various discovery metrics.
738
+ for b, bundle in bdict.items():
739
+ if "Discovery" in bundle.metric.name:
740
+ completeness.update(_compbundles(b, bundle, h_mark, results_db))
741
+ if "MagicDiscovery" in bundle.metric.name:
742
+ completeness.update(_compbundles(b, bundle, h_mark, results_db))
743
+ if "HighVelocity" in bundle.metric.name:
744
+ completeness.update(_compbundles(b, bundle, h_mark, results_db))
745
+ # Write the completeness bundles to disk, so we can re-read them later.
746
+ # (also set the display dict properties, for the results_db output).
747
+ for b, bundle in completeness.items():
748
+ bundle.display_dict["subgroup"] = "Completeness"
749
+ bundle.write(out_dir=out_dir, results_db=results_db)
750
+
751
+ # Calculate total number of objects - currently for NEOs and PHAs only
752
+ for b, bundle in completeness.items():
753
+ if "DifferentialCompleteness" in b and "@Time" not in b:
754
+ if "NEO" in bundle.info_label:
755
+ nobj_metrics = [
756
+ metrics.TotalNumberSSO(h_mark=22, dndh_func=metrics.neo_dndh_granvik),
757
+ metrics.TotalNumberSSO(h_mark=25, dndh_func=metrics.neo_dndh_granvik),
758
+ ]
759
+ bundle.set_summary_metrics(nobj_metrics)
760
+ bundle.compute_summary_stats(results_db)
761
+ if "PHA" in bundle.info_label:
762
+ nobj_metrics = [metrics.TotalNumberSSO(h_mark=22, dndh_func=metrics.pha_dndh_granvik)]
763
+ bundle.set_summary_metrics(nobj_metrics)
764
+ bundle.compute_summary_stats(results_db)
765
+ return completeness
766
+
767
+
768
+ def plot_completeness(
769
+ bdictCompleteness,
770
+ figroot=None,
771
+ run_name=None,
772
+ results_db=None,
773
+ out_dir=".",
774
+ fig_format="pdf",
775
+ ):
776
+ """Plot a minor subset of the completeness results."""
777
+ # Separate some subsets to plot together -
778
+ # first just the simple 15 and 30 night detection loss metrics.
779
+ keys = [
780
+ "3_pairs_in_30_nights_detection_loss",
781
+ "3_pairs_in_15_nights_detection_loss",
782
+ ]
783
+ plotTimes = {}
784
+ plotComp = {}
785
+ plotDiff = {}
786
+ for k in bdictCompleteness:
787
+ for key in keys:
788
+ if key in k:
789
+ if "Time" in k:
790
+ if "Cumulative" in k:
791
+ plotTimes[k] = bdictCompleteness[k]
792
+ elif "Chances" in k:
793
+ if "Differential" in k:
794
+ plotDiff[k] = bdictCompleteness[k]
795
+ elif "Cumulative" in k:
796
+ plotComp[k] = bdictCompleteness[k]
797
+
798
+ # Add plot dictionaries to code 30 nights red, 15 nights blue,
799
+ # differentials dotted.
800
+ def _codePlot(key):
801
+ plotDict = {}
802
+ if "Differential" in k:
803
+ plotDict["linestyle"] = ":"
804
+ else:
805
+ plotDict["linestyle"] = "-"
806
+ if "30_nights" in k:
807
+ plotDict["color"] = "r"
808
+ if "15_nights" in k:
809
+ plotDict["color"] = "b"
810
+ return plotDict
811
+
812
+ # Apply color-coding.
813
+ for k, b in plotTimes.items():
814
+ b.set_plot_dict(_codePlot(k))
815
+ for k, b in plotDiff.items():
816
+ b.set_plot_dict(_codePlot(k))
817
+ for k, b in plotComp.items():
818
+ b.set_plot_dict(_codePlot(k))
819
+
820
+ first = bdictCompleteness[list(bdictCompleteness.keys())[0]]
821
+ if run_name is None:
822
+ run_name = first.run_name
823
+ if figroot is None:
824
+ figroot = run_name
825
+ display_dict = deepcopy(first.display_dict)
826
+
827
+ # Plot completeness as a function of time.
828
+ # Make custom plot, then save it with PlotHandler.
829
+ fig = plt.figure(figsize=(8, 6))
830
+ for k in plotTimes:
831
+ plt.plot(
832
+ plotTimes[k].plot_dict["times"],
833
+ plotTimes[k].metric_values[0, :],
834
+ label=plotTimes[k].plot_dict["label"] + " @H=%.2f" % plotTimes[k].plot_dict["h_val"],
835
+ )
836
+ plt.legend()
837
+ plt.xlabel("Time (MJD)")
838
+ plt.ylabel("Completeness")
839
+ plt.grid(True, alpha=0.3)
840
+ # Make a PlotHandler to deal with savings/results_db, etc.
841
+ ph = plots.PlotHandler(fig_format=fig_format, results_db=results_db, out_dir=out_dir)
842
+ display_dict["subgroup"] = "Completeness over time"
843
+ display_dict["caption"] = "Completeness over time, for H values indicated in legend."
844
+ ph.save_fig(
845
+ fig,
846
+ f"{figroot}_CompletenessOverTime",
847
+ "Combo",
848
+ "CompletenessOverTime",
849
+ "MoObjSlicer",
850
+ figroot,
851
+ None,
852
+ None,
853
+ display_dict=display_dict,
854
+ )
855
+
856
+ plt.savefig(
857
+ os.path.join(out_dir, f"{figroot}_CompletenessOverTime.{fig_format}"),
858
+ format=fig_format,
859
+ )
860
+
861
+ # Plot cumulative completeness.
862
+ ph = plots.PlotHandler(fig_format=fig_format, results_db=results_db, out_dir=out_dir)
863
+ ph.set_metric_bundles(plotComp)
864
+ plotDict = {"ylabel": "Completeness", "figsize": (8, 6), "albedo": 0.14}
865
+ ph.plot(
866
+ plot_func=plots.MetricVsH(),
867
+ plot_dicts=plotDict,
868
+ outfile_root=figroot + "_CumulativeCompleteness",
869
+ )
870
+
871
+ # Plot differential completeness.
872
+ ph = plots.PlotHandler(fig_format=fig_format, results_db=results_db, out_dir=out_dir)
873
+ ph.set_metric_bundles(plotDiff)
874
+ plotDict = {"ylabel": "Completeness", "figsize": (8, 6)}
875
+ ph.plot(
876
+ plot_func=plots.MetricVsH(),
877
+ plot_dicts=plotDict,
878
+ outfile_root=figroot + "_DifferentialCompleteness",
879
+ )
880
+
881
+ # And add the rest of the completeness calculations.
882
+ allComp = []
883
+ for k in bdictCompleteness:
884
+ if "DiscoveryNChances" in k:
885
+ if "Cumulative" in k:
886
+ allComp.append(bdictCompleteness[k])
887
+ if "Magic" in k:
888
+ if "Cumulative" in k:
889
+ allComp.append(bdictCompleteness[k])
890
+ ph = plots.PlotHandler(fig_format=fig_format, results_db=results_db, out_dir=out_dir)
891
+ ph.set_metric_bundles(allComp)
892
+ plotDict = {
893
+ "ylabel": "Completeness",
894
+ "figsize": (8, 6),
895
+ "legendloc": (1.01, 0.1),
896
+ "color": None,
897
+ }
898
+ display_dict["subgroup"] = "Completeness all criteria"
899
+ display_dict["caption"] = "Plotting all of the cumulative completeness curves together."
900
+ ph.plot(
901
+ plot_func=plots.MetricVsH(),
902
+ plot_dicts=plotDict,
903
+ display_dict=display_dict,
904
+ outfile_root=figroot + "_Many_CumulativeCompleteness",
905
+ )
906
+
907
+
908
+ def characterization_inner_batch(
909
+ slicer,
910
+ colmap=None,
911
+ run_name="run_name",
912
+ objtype="",
913
+ magtype="asteroid",
914
+ albedo=None,
915
+ h_mark=None,
916
+ constraint_info_label="",
917
+ constraint=None,
918
+ npReduce=np.mean,
919
+ windows=None,
920
+ bins=None,
921
+ ):
922
+ """Characterization metrics for inner solar system objects."""
923
+ if colmap is None:
924
+ colmap = col_map_dict()
925
+ bundleList = []
926
+
927
+ # Set up a dictionary to pass to each metric for the column names.
928
+ colkwargs = {
929
+ "mjd_col": colmap["mjd"],
930
+ "seeing_col": colmap["seeingGeom"],
931
+ "exp_time_col": colmap["exptime"],
932
+ "m5_col": colmap["fiveSigmaDepth"],
933
+ "night_col": colmap["night"],
934
+ "filter_col": colmap["filter"],
935
+ }
936
+
937
+ basicPlotDict = {
938
+ "albedo": albedo,
939
+ "h_mark": h_mark,
940
+ "np_reduce": npReduce,
941
+ "nxbins": 200,
942
+ "nybins": 200,
943
+ }
944
+ plot_funcs = [plots.MetricVsH()]
945
+
946
+ if constraint_info_label == "" and constraint is not None:
947
+ constraint_info_label = constraint.replace("filter", "").replace("==", "").replace(" ", " ")
948
+ info_label = objtype + " " + constraint_info_label
949
+ info_label = info_label.rstrip(" ")
950
+
951
+ display_dict = {"group": f"{objtype}"}
952
+
953
+ # Stackers
954
+ magStacker = stackers.MoMagStacker(loss_col="dmag_detect", magtype=magtype)
955
+ eclStacker = stackers.EclStacker()
956
+ stackerList = [magStacker, eclStacker]
957
+
958
+ # Windows are the different 'length of activity'
959
+ if windows is None:
960
+ windows = np.arange(10, 200, 30.0)
961
+ # Bins are the different 'anomaly variations' of activity
962
+ if bins is None:
963
+ bins = np.arange(5, 185, 20.0)
964
+
965
+ # Number of observations.
966
+ md = info_label
967
+ display_dict["subgroup"] = "N Obs"
968
+ plotDict = {
969
+ "ylabel": "Number of observations (#)",
970
+ "title": "%s: Number of observations %s" % (run_name, md),
971
+ }
972
+ plotDict.update(basicPlotDict)
973
+ metric = metrics.NObsMetric(**colkwargs)
974
+ bundle = MoMetricBundle(
975
+ metric,
976
+ slicer,
977
+ constraint,
978
+ stacker_list=stackerList,
979
+ run_name=run_name,
980
+ info_label=md,
981
+ plot_dict=plotDict,
982
+ plot_funcs=plot_funcs,
983
+ display_dict=display_dict,
984
+ )
985
+ bundleList.append(bundle)
986
+
987
+ # Observational arc.
988
+ md = info_label
989
+ display_dict["subgroup"] = "Obs Arc"
990
+ plotDict = {
991
+ "ylabel": "Observational Arc (days)",
992
+ "title": "%s: Observational Arc Length %s" % (run_name, md),
993
+ }
994
+ plotDict.update(basicPlotDict)
995
+ metric = metrics.ObsArcMetric(**colkwargs)
996
+ bundle = MoMetricBundle(
997
+ metric,
998
+ slicer,
999
+ constraint,
1000
+ stacker_list=stackerList,
1001
+ run_name=run_name,
1002
+ info_label=md,
1003
+ plot_dict=plotDict,
1004
+ plot_funcs=plot_funcs,
1005
+ display_dict=display_dict,
1006
+ )
1007
+ bundleList.append(bundle)
1008
+
1009
+ # Activity detection.
1010
+ display_dict["subgroup"] = "Activity"
1011
+ for w in windows:
1012
+ md = info_label + " activity lasting %.0f days" % w
1013
+ plotDict = {
1014
+ "title": "%s: Chances of detecting %s" % (run_name, md),
1015
+ "ylabel": "Probability of detection per %.0f day window" % w,
1016
+ }
1017
+ metric_name = "Chances of detecting activity lasting %.0f days" % w
1018
+ metric = metrics.ActivityOverTimeMetric(w, metric_name=metric_name, **colkwargs)
1019
+ bundle = MoMetricBundle(
1020
+ metric,
1021
+ slicer,
1022
+ constraint,
1023
+ stacker_list=stackerList,
1024
+ run_name=run_name,
1025
+ info_label=info_label,
1026
+ plot_dict=plotDict,
1027
+ plot_funcs=plot_funcs,
1028
+ display_dict=display_dict,
1029
+ )
1030
+ bundleList.append(bundle)
1031
+
1032
+ for b in bins:
1033
+ md = info_label + " activity covering %.0f deg" % (b)
1034
+ plotDict = {
1035
+ "title": "%s: Chances of detecting %s" % (run_name, md),
1036
+ "ylabel": "Probability of detection per %.0f deg window" % b,
1037
+ }
1038
+ metric_name = "Chances of detecting activity covering %.0f deg" % (b)
1039
+ metric = metrics.ActivityOverPeriodMetric(b, metric_name=metric_name, **colkwargs)
1040
+ bundle = MoMetricBundle(
1041
+ metric,
1042
+ slicer,
1043
+ constraint,
1044
+ stacker_list=stackerList,
1045
+ run_name=run_name,
1046
+ info_label=info_label,
1047
+ plot_dict=plotDict,
1048
+ plot_funcs=plot_funcs,
1049
+ display_dict=display_dict,
1050
+ )
1051
+ bundleList.append(bundle)
1052
+
1053
+ # Lightcurve inversion.
1054
+ md = info_label
1055
+ display_dict["subgroup"] = "Color/Inversion"
1056
+ plotDict = {
1057
+ "y_min": 0,
1058
+ "y_max": 1,
1059
+ "ylabel": "Fraction of objects",
1060
+ "title": "%s: Fraction with potential lightcurve inversion %s" % (run_name, md),
1061
+ }
1062
+ plotDict.update(basicPlotDict)
1063
+ metric = metrics.LightcurveInversionAsteroidMetric(**colkwargs)
1064
+ bundle = MoMetricBundle(
1065
+ metric,
1066
+ slicer,
1067
+ constraint,
1068
+ stacker_list=stackerList,
1069
+ run_name=run_name,
1070
+ info_label=md,
1071
+ plot_dict=plotDict,
1072
+ plot_funcs=plot_funcs,
1073
+ display_dict=display_dict,
1074
+ )
1075
+ bundleList.append(bundle)
1076
+
1077
+ # Color determination.
1078
+ md = info_label
1079
+ plotDict = {
1080
+ "y_min": 0,
1081
+ "y_max": 1,
1082
+ "ylabel": "Fraction of objects",
1083
+ "title": "%s: Fraction of population with colors in X filters %s" % (run_name, md),
1084
+ }
1085
+ plotDict.update(basicPlotDict)
1086
+ metric = metrics.ColorAsteroidMetric(**colkwargs)
1087
+ bundle = MoMetricBundle(
1088
+ metric,
1089
+ slicer,
1090
+ constraint,
1091
+ stacker_list=stackerList,
1092
+ run_name=run_name,
1093
+ info_label=md,
1094
+ plot_dict=plotDict,
1095
+ plot_funcs=plot_funcs,
1096
+ display_dict=display_dict,
1097
+ )
1098
+ bundleList.append(bundle)
1099
+
1100
+ # Set the run_name for all bundles and return the bundleDict.
1101
+ for b in bundleList:
1102
+ b.set_run_name(run_name)
1103
+ return mb.make_bundles_dict_from_list(bundleList)
1104
+
1105
+
1106
+ def characterization_outer_batch(
1107
+ slicer,
1108
+ colmap=None,
1109
+ run_name="run_name",
1110
+ objtype="",
1111
+ magtype="asteroid",
1112
+ albedo=None,
1113
+ h_mark=None,
1114
+ constraint_info_label="",
1115
+ constraint=None,
1116
+ npReduce=np.mean,
1117
+ windows=None,
1118
+ bins=None,
1119
+ ):
1120
+ """Characterization metrics for outer solar system objects."""
1121
+ if colmap is None:
1122
+ colmap = col_map_dict()
1123
+ bundleList = []
1124
+
1125
+ # Set up a dictionary to pass to each metric for the column names.
1126
+ colkwargs = {
1127
+ "mjd_col": colmap["mjd"],
1128
+ "seeing_col": colmap["seeingGeom"],
1129
+ "exp_time_col": colmap["exptime"],
1130
+ "m5_col": colmap["fiveSigmaDepth"],
1131
+ "night_col": colmap["night"],
1132
+ "filter_col": colmap["filter"],
1133
+ }
1134
+
1135
+ basicPlotDict = {
1136
+ "albedo": albedo,
1137
+ "h_mark": h_mark,
1138
+ "np_reduce": npReduce,
1139
+ "nxbins": 200,
1140
+ "nybins": 200,
1141
+ }
1142
+ plot_funcs = [plots.MetricVsH()]
1143
+
1144
+ if constraint_info_label == "" and constraint is not None:
1145
+ constraint_info_label = constraint.replace("filter", "").replace("==", "").replace(" ", " ")
1146
+ info_label = objtype + " " + constraint_info_label
1147
+ info_label = info_label.rstrip(" ")
1148
+
1149
+ display_dict = {"group": f"{objtype}"}
1150
+
1151
+ # Stackers
1152
+ magStacker = stackers.MoMagStacker(loss_col="dmag_detect", magtype=magtype)
1153
+ eclStacker = stackers.EclStacker()
1154
+ stackerList = [magStacker, eclStacker]
1155
+
1156
+ # Windows are the different 'length of activity'
1157
+ if windows is None:
1158
+ windows = np.arange(10, 200, 30.0)
1159
+ # Bins are the different 'anomaly variations' of activity
1160
+ if bins is None:
1161
+ bins = np.arange(5, 185, 20.0)
1162
+
1163
+ # Number of observations.
1164
+ md = info_label
1165
+ display_dict["subgroup"] = "N Obs"
1166
+ plotDict = {
1167
+ "ylabel": "Number of observations (#)",
1168
+ "title": "%s: Number of observations %s" % (run_name, md),
1169
+ }
1170
+ plotDict.update(basicPlotDict)
1171
+ metric = metrics.NObsMetric(**colkwargs)
1172
+ bundle = MoMetricBundle(
1173
+ metric,
1174
+ slicer,
1175
+ constraint,
1176
+ stacker_list=stackerList,
1177
+ run_name=run_name,
1178
+ info_label=md,
1179
+ plot_dict=plotDict,
1180
+ plot_funcs=plot_funcs,
1181
+ display_dict=display_dict,
1182
+ )
1183
+ bundleList.append(bundle)
1184
+
1185
+ # Observational arc.
1186
+ md = info_label
1187
+ display_dict["subgroup"] = "Obs Arc"
1188
+ plotDict = {
1189
+ "ylabel": "Observational Arc (days)",
1190
+ "title": "%s: Observational Arc Length %s" % (run_name, md),
1191
+ }
1192
+ plotDict.update(basicPlotDict)
1193
+ metric = metrics.ObsArcMetric(**colkwargs)
1194
+ bundle = MoMetricBundle(
1195
+ metric,
1196
+ slicer,
1197
+ constraint,
1198
+ stacker_list=stackerList,
1199
+ run_name=run_name,
1200
+ info_label=md,
1201
+ plot_dict=plotDict,
1202
+ plot_funcs=plot_funcs,
1203
+ display_dict=display_dict,
1204
+ )
1205
+ bundleList.append(bundle)
1206
+
1207
+ # Activity detection.
1208
+ display_dict["subgroup"] = "Activity"
1209
+ for w in windows:
1210
+ md = info_label + " activity lasting %.0f days" % w
1211
+ plotDict = {
1212
+ "title": "%s: Chances of detecting %s" % (run_name, md),
1213
+ "ylabel": "Probability of detection per %.0f day window" % w,
1214
+ }
1215
+ metric_name = "Chances of detecting activity lasting %.0f days" % w
1216
+ metric = metrics.ActivityOverTimeMetric(w, metric_name=metric_name, **colkwargs)
1217
+ bundle = MoMetricBundle(
1218
+ metric,
1219
+ slicer,
1220
+ constraint,
1221
+ stacker_list=stackerList,
1222
+ run_name=run_name,
1223
+ info_label=info_label,
1224
+ plot_dict=plotDict,
1225
+ plot_funcs=plot_funcs,
1226
+ display_dict=display_dict,
1227
+ )
1228
+ bundleList.append(bundle)
1229
+
1230
+ for b in bins:
1231
+ md = info_label + " activity covering %.0f deg" % (b)
1232
+ plotDict = {
1233
+ "title": "%s: Chances of detecting %s" % (run_name, md),
1234
+ "ylabel": "Probability of detection per %.2f deg window" % b,
1235
+ }
1236
+ metric_name = "Chances of detecting activity covering %.0f deg" % (b)
1237
+ metric = metrics.ActivityOverPeriodMetric(b, metric_name=metric_name, **colkwargs)
1238
+ bundle = MoMetricBundle(
1239
+ metric,
1240
+ slicer,
1241
+ constraint,
1242
+ stacker_list=stackerList,
1243
+ run_name=run_name,
1244
+ info_label=info_label,
1245
+ plot_dict=plotDict,
1246
+ plot_funcs=plot_funcs,
1247
+ display_dict=display_dict,
1248
+ )
1249
+ bundleList.append(bundle)
1250
+
1251
+ # Color determination.
1252
+ md = info_label
1253
+ display_dict["subgroup"] = "Color/Inversion"
1254
+ plotDict = {
1255
+ "y_min": 0,
1256
+ "y_max": 1,
1257
+ "ylabel": "Fraction of objects",
1258
+ "title": "%s: Fraction of population with colors in X filters %s" % (run_name, md),
1259
+ }
1260
+ plotDict.update(basicPlotDict)
1261
+ metric = metrics.LightcurveColorOuterMetric(**colkwargs)
1262
+ bundle = MoMetricBundle(
1263
+ metric,
1264
+ slicer,
1265
+ constraint,
1266
+ stacker_list=stackerList,
1267
+ run_name=run_name,
1268
+ info_label=md,
1269
+ plot_dict=plotDict,
1270
+ plot_funcs=plot_funcs,
1271
+ display_dict=display_dict,
1272
+ )
1273
+ bundleList.append(bundle)
1274
+
1275
+ # Set the run_name for all bundles and return the bundleDict.
1276
+ for b in bundleList:
1277
+ b.set_run_name(run_name)
1278
+ return mb.make_bundles_dict_from_list(bundleList)
1279
+
1280
+
1281
+ def run_fraction_summary(bdict, h_mark, out_dir, results_db):
1282
+ """
1283
+ Calculate fractional completeness of the population for
1284
+ color and lightcurve metrics.
1285
+
1286
+ This should be done after combining any sub-sets of the metric results.
1287
+
1288
+ Parameters
1289
+ ----------
1290
+ bdict : `dict` of `maf.MoMetricBundle`
1291
+ Dict containing bundles contianing lightcurve/color evaluations.
1292
+ h_mark : `float`
1293
+ h_mark value to add to completeness plotting dict.
1294
+ If defined, this value is used.
1295
+ If None, but h_mark in plot_dict for metric, then this value (-2) is
1296
+ used. If h_mark not in plotdict, then use the median h_range value-2.
1297
+ times : `np.ndarray`
1298
+ The times at which to calculate completeness (over time).
1299
+ out_dir : `str`
1300
+ Output directory to save completeness bundles to disk.
1301
+ results_db : `maf.ResultsDb`
1302
+ Results database to save information about completeness bundle.
1303
+
1304
+ Returns
1305
+ -------
1306
+ metricDict : `dict` of `maf.MetricBundle`
1307
+ Dictionary of the metric bundles for the fractional evaluation
1308
+ of the population.
1309
+ """
1310
+ fractions = {}
1311
+
1312
+ # Look for metrics from asteroid or outer solar system
1313
+ # color/lightcurve metrics.
1314
+ inversionSummary = fraction_population_at_threshold([1], ["Lightcurve Inversion"])
1315
+ asteroidColorSummary = fraction_population_at_threshold(
1316
+ [4, 3, 2, 1],
1317
+ ["6 of ugrizy", "5 of grizy", "4 of grizy", "2 of g, r or i, z or y"],
1318
+ )
1319
+ asteroidSummaryMetrics = {
1320
+ "LightcurveInversionAsteroid": inversionSummary,
1321
+ "LightcurveInversion_Asteroid": inversionSummary,
1322
+ "ColorAsteroid": asteroidColorSummary,
1323
+ "Color_Asteroid": asteroidColorSummary,
1324
+ }
1325
+
1326
+ outerColorSummary = fraction_population_at_threshold(
1327
+ [6, 5, 4, 3, 2, 1],
1328
+ ["6 filters", "5 filters", "4 filters", "3 filters", "2 filters", "1 filters"],
1329
+ )
1330
+ outerSummaryMetrics = {
1331
+ "LightcurveColorOuter": outerColorSummary,
1332
+ "lightcurveColor_Outer": outerColorSummary,
1333
+ }
1334
+
1335
+ for b, bundle in bdict.items():
1336
+ # Find h_mark if not set (this may be different for different bundles).
1337
+ if h_mark is None and "h_mark" in bundle.plot_dict:
1338
+ h_mark = bundle.plot_dict["h_mark"] - 2
1339
+ if h_mark is None:
1340
+ h_mark = np.median(bundle.slicer.slice_points["H"]) - 2
1341
+ # Make sure we didn't push h_mark outside the range of H values
1342
+ if h_mark < bundle.slicer.slice_points["H"].min():
1343
+ h_mark = bundle.slicer.slice_points["H"].min()
1344
+ for k in asteroidSummaryMetrics:
1345
+ if k in b:
1346
+ for summary_metric in asteroidSummaryMetrics[k]:
1347
+ newkey = b + " " + summary_metric.name
1348
+ fractions[newkey] = mb.make_completeness_bundle(
1349
+ bundle, summary_metric, h_mark=h_mark, results_db=results_db
1350
+ )
1351
+ for k in outerSummaryMetrics:
1352
+ if k in b:
1353
+ for summary_metric in outerSummaryMetrics[k]:
1354
+ newkey = b + " " + summary_metric.name
1355
+ fractions[newkey] = mb.make_completeness_bundle(
1356
+ bundle, summary_metric, h_mark=h_mark, results_db=results_db
1357
+ )
1358
+
1359
+ # Write fractional populations bundles to disk, so we can re-read later.
1360
+ for b, bundle in fractions.items():
1361
+ bundle.write(out_dir=out_dir, results_db=results_db)
1362
+ return fractions
1363
+
1364
+
1365
+ def plot_fractions(
1366
+ bdictFractions,
1367
+ figroot=None,
1368
+ run_name=None,
1369
+ results_db=None,
1370
+ out_dir=".",
1371
+ fig_format="pdf",
1372
+ ):
1373
+ # Set colors for the fractions.
1374
+ for b in bdictFractions.values():
1375
+ k = b.metric.name
1376
+ if "6" in k:
1377
+ b.plot_dict["color"] = "b"
1378
+ if "5" in k:
1379
+ b.plot_dict["color"] = "cyan"
1380
+ if "4" in k:
1381
+ b.plot_dict["color"] = "orange"
1382
+ if "2" in k:
1383
+ b.plot_dict["color"] = "r"
1384
+ if "1" in k:
1385
+ b.plot_dict["color"] = "magenta"
1386
+ if "Lightcurve Inversion" in k:
1387
+ b.plot_dict["color"] = "k"
1388
+ b.plot_dict["linestyle"] = ":"
1389
+ b.plot_dict["linewidth"] = 3
1390
+
1391
+ first = bdictFractions[list(bdictFractions.keys())[0]]
1392
+ if run_name is None:
1393
+ run_name = first.run_name
1394
+ if figroot is None:
1395
+ figroot = run_name
1396
+ display_dict = deepcopy(first.display_dict)
1397
+ display_dict["subgroup"] = "Characterization Fraction"
1398
+
1399
+ ph = plots.PlotHandler(fig_format=fig_format, results_db=results_db, out_dir=out_dir)
1400
+ ph.set_metric_bundles(bdictFractions)
1401
+ ph.joint_metric_names = "Fraction of population for colors or lightcurve inversion"
1402
+ plotDict = {"ylabel": "Fraction of population", "figsize": (8, 6)}
1403
+ ph.plot(
1404
+ plot_func=plots.MetricVsH(),
1405
+ plot_dicts=plotDict,
1406
+ display_dict=display_dict,
1407
+ outfile_root=figroot + "_characterization",
1408
+ )
1409
+
1410
+
1411
+ def plot_single(bundle, results_db=None, out_dir=".", fig_format="pdf"):
1412
+ """Plot 5%/25%/50%/75%/95% iles for a metric value."""
1413
+ pDict = {
1414
+ "95%ile": {
1415
+ "color": "k",
1416
+ "linestyle": "--",
1417
+ "label": "95th %ile",
1418
+ "np_reduce": lambda x, axis: np.percentile(x, 95, axis=axis),
1419
+ },
1420
+ "75%ile": {
1421
+ "color": "magenta",
1422
+ "linestyle": ":",
1423
+ "label": "75th %ile",
1424
+ "np_reduce": lambda x, axis: np.percentile(x, 75, axis=axis),
1425
+ },
1426
+ "Median": {
1427
+ "color": "b",
1428
+ "linestyle": "-",
1429
+ "label": "Median",
1430
+ "np_reduce": lambda x, axis: np.median(x, axis=axis),
1431
+ },
1432
+ "Mean": {
1433
+ "color": "g",
1434
+ "linestyle": "--",
1435
+ "label": "Mean",
1436
+ "np_reduce": np.mean,
1437
+ },
1438
+ "25%ile": {
1439
+ "color": "magenta",
1440
+ "linestyle": ":",
1441
+ "label": "25th %ile",
1442
+ "np_reduce": lambda x, axis: np.percentile(x, 25, axis=axis),
1443
+ },
1444
+ "5%ile": {
1445
+ "color": "k",
1446
+ "linestyle": "--",
1447
+ "label": "5th %ile",
1448
+ "np_reduce": lambda x, axis: np.percentile(x, 5, axis=axis),
1449
+ },
1450
+ }
1451
+ ph = plots.PlotHandler(fig_format=fig_format, results_db=results_db, out_dir=out_dir)
1452
+ plot_bundles = []
1453
+ plot_dicts = []
1454
+ for percentile in pDict:
1455
+ plot_bundles.append(bundle)
1456
+ plot_dicts.append(pDict[percentile])
1457
+ plot_dicts[0].update({"figsize": (8, 6), "legendloc": "upper right", "y_min": 0})
1458
+ # Remove the h_mark line because these plots get complicated already.
1459
+ for r in plot_dicts:
1460
+ r["h_mark"] = None
1461
+ ph.set_metric_bundles(plot_bundles)
1462
+ ph.plot(
1463
+ plot_func=plots.MetricVsH(),
1464
+ plot_dicts=plot_dicts,
1465
+ display_dict=bundle.display_dict,
1466
+ )
1467
+
1468
+
1469
+ def plot_not_found(nChances, h_mark):
1470
+ pass
1471
+
1472
+
1473
+ def plot_activity(bdict, figroot=None, results_db=None, out_dir=".", fig_format="pdf"):
1474
+ activity_deg = {}
1475
+ activity_days = {}
1476
+ for k in bdict:
1477
+ if "Chances_of_detecting_activity" in k:
1478
+ if "deg" in k:
1479
+ activity_deg[k] = bdict[k]
1480
+ if "days" in k:
1481
+ activity_days[k] = bdict[k]
1482
+
1483
+ first = bdict[list(bdict.keys())[0]]
1484
+ if figroot is None:
1485
+ figroot = first.run_name
1486
+ display_dict = deepcopy(first.display_dict)
1487
+
1488
+ if len(activity_days) > 0:
1489
+ # Plot (mean) likelihood of detection of activity over X days
1490
+ ph = plots.PlotHandler(fig_format=fig_format, results_db=results_db, out_dir=out_dir)
1491
+ ph.set_metric_bundles(activity_days)
1492
+ ph.joint_metric_names = "Chances of detecting activity lasting X days"
1493
+ plot_dict = {"ylabel": "Mean likelihood of detection", "figsize": (8, 6)}
1494
+ ph.plot(
1495
+ plot_func=plots.MetricVsH(),
1496
+ plot_dicts=plot_dict,
1497
+ display_dict=display_dict,
1498
+ outfile_root=figroot + "_activityDays",
1499
+ )
1500
+ if len(activity_deg) > 0:
1501
+ # Plot mean likelihood of detection of activity over X amount of orbit
1502
+ ph = plots.PlotHandler(fig_format=fig_format, results_db=results_db, out_dir=out_dir)
1503
+ ph.set_metric_bundles(activity_deg)
1504
+ ph.joint_metric_names = "Chances of detecting activity covering X deg"
1505
+ plot_dict = {"ylabel": "Mean likelihood of detection", "figsize": (8, 6)}
1506
+ ph.plot(
1507
+ plot_func=plots.MetricVsH(),
1508
+ plot_dicts=plot_dict,
1509
+ display_dict=display_dict,
1510
+ outfile_root=figroot + "_activityDeg",
1511
+ )
1512
+
1513
+
1514
+ def read_and_combine(orbitRoot, baseDir, splits, metricfile):
1515
+ """Read and combine the metric results from split locations,
1516
+ returning a single bundle.
1517
+
1518
+ This will read the files from
1519
+ baseDir/orbitRoot_[split]/metricfile
1520
+ where split = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], etc.
1521
+ (the subsets the original orbit file was split into).
1522
+
1523
+ Parameters
1524
+ ----------
1525
+ orbitRoot : `str`
1526
+ The root of the orbit file - l7_5k, mbas_5k, etc.
1527
+ baseDir: `str`
1528
+ The root directory containing the subset directories. (e.g. '.' often)
1529
+ splits:` np.ndarray` or `list` of `ints`
1530
+ The integers describing the split directories
1531
+ (e.g. [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
1532
+ metricfile: `str`
1533
+ The metric filename.
1534
+
1535
+ Returns
1536
+ -------
1537
+ metric_bundle : `~rubin_sim.maf.MoMetricBundle`
1538
+ A single metric bundle containing the combined data from the subsets.
1539
+
1540
+ Note that this won't work for particularly complex metric values,
1541
+ such as the parent Discovery metrics. However, you can read and combine
1542
+ their child metrics, as for these we can propagate the data masks.
1543
+ """
1544
+ subsets = {}
1545
+ for i in splits:
1546
+ subsets[i] = mb.create_empty_mo_metric_bundle()
1547
+ ddir = os.path.join(baseDir, f"{orbitRoot}_{i}")
1548
+ subsets[i].read(os.path.join(ddir, metricfile))
1549
+ bundle = combine_subsets(subsets)
1550
+ return bundle
1551
+
1552
+
1553
+ def combine_subsets(mbSubsets):
1554
+ # Combine the data from the subset metric bundles.
1555
+ # The first bundle will be used a template for the slicer.
1556
+ if isinstance(mbSubsets, dict):
1557
+ first = mbSubsets[list(mbSubsets.keys())[0]]
1558
+ else:
1559
+ first = mbSubsets[0]
1560
+ subsetdict = {}
1561
+ for i, b in enumerate(mbSubsets):
1562
+ subsetdict[i] = b
1563
+ mbSubsets = subsetdict
1564
+ joint = mb.create_empty_mo_metric_bundle()
1565
+ # Check if they're the same slicer.
1566
+ slicer = deepcopy(first.slicer)
1567
+ for i in mbSubsets:
1568
+ if np.any(slicer.slice_points["H"] != mbSubsets[i].slicer.slice_points["H"]):
1569
+ if np.any(slicer.slice_points["orbits"] != mbSubsets[i].slicer.slice_points["orbits"]):
1570
+ raise ValueError("Bundle %s has a different slicer than the first bundle" % (i))
1571
+ # Join metric values.
1572
+ joint.slicer = slicer
1573
+ joint.metric = first.metric
1574
+ # Don't just use the slicer shape to define the metric_values,
1575
+ # because of CompletenessBundles.
1576
+ metric_values = np.zeros(first.metric_values.shape, float)
1577
+ metric_values_mask = np.zeros(first.metric_values.shape, bool)
1578
+ for i in mbSubsets:
1579
+ metric_values += mbSubsets[i].metric_values.filled(0)
1580
+ metric_values_mask = np.where(metric_values_mask & mbSubsets[i].metric_values.mask, True, False)
1581
+ joint.metricValues = ma.MaskedArray(data=metric_values, mask=metric_values_mask, fill_value=0)
1582
+ joint.info_label = first.info_label
1583
+ joint.run_name = first.run_name
1584
+ joint.file_root = first.file_root.replace(".npz", "")
1585
+ joint.plotDict = first.plotDict
1586
+ joint.display_dict = first.display_dict
1587
+ return joint