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,584 @@
1
+ """Tools for use of project-generated opsim simulations and analysis."""
2
+
3
+ __all__ = (
4
+ "get_metric_subsets",
5
+ "create_metric_subset",
6
+ "write_metric_subsets",
7
+ "get_metric_summaries",
8
+ "get_runs",
9
+ "get_family_runs",
10
+ "download_runs",
11
+ "get_family_descriptions",
12
+ "describe_families",
13
+ )
14
+
15
+
16
+ import copy
17
+ import os
18
+ import sys
19
+ import urllib
20
+ import warnings
21
+
22
+ import numpy as np
23
+ import pandas as pd
24
+
25
+ try:
26
+ import IPython
27
+ except ModuleNotFoundError:
28
+ pass
29
+
30
+ from rubin_sim.data import get_data_dir
31
+
32
+ from .summary_plots import plot_run_metric
33
+
34
+ FAMILY_SOURCE = os.environ.get(
35
+ "RUBIN_SIM_FAMILY_SOURCE",
36
+ "https://raw.githubusercontent.com/lsst-pst/survey_strategy/main/fbs_2.0/runs_v2.2.json",
37
+ )
38
+
39
+ SUMMARY_SOURCE = os.environ.get(
40
+ "RUBIN_SIM_SUMMARY_SOURCE",
41
+ "https://s3df.slac.stanford.edu/data/rubin/sim-data/sims_featureScheduler_runs3.4/maf/summary.h5",
42
+ )
43
+
44
+ if os.uname().nodename.endswith(".datalab.noao.edu"):
45
+ DEFAULT_OPSIM_DB_DIR = "/sims_maf"
46
+ else:
47
+ DEFAULT_OPSIM_DB_DIR = os.getcwd()
48
+ OPSIM_DB_DIR = os.environ.get("OPSIM_DB_DIR", DEFAULT_OPSIM_DB_DIR)
49
+
50
+ BY_RUN_COLS = ["run", "brief", "filepath", "url"]
51
+
52
+
53
+ def get_metric_subsets(metric_subset_source=None):
54
+ """Get metadata on named subsets of related metrics.
55
+
56
+ Parameters
57
+ ----------
58
+ metric_subset_source : `str` or None
59
+ File name or URL for the json file from which to load the data.
60
+ If it is set to `None`, the data is loaded from `metric_subsets.json`
61
+ in the $rubin_sim_data.maf directory.
62
+
63
+ Returns
64
+ -------
65
+ metric_subsets : `pandas.DataFrame`
66
+ ``metric_subset``
67
+ The 1st level of the index is the name of a subset of metrics
68
+ (`str`).
69
+ ``metric``
70
+ The 2nd level of the index is the full name of the metric
71
+ (`str`).
72
+ ``metric``
73
+ The full name of the metric (`str`).
74
+ ``short_name``
75
+ An abbreviated name for the metric (`str`)..
76
+ ``style``
77
+ The ``matplotlib`` linestyle suggested for plots of the
78
+ metric (`str`).
79
+ ``invert``
80
+ When normalizing, invert the metric value first? (`bool`)
81
+ ``mag``
82
+ Is the value an (astronomical) magnitude? (`bool`)
83
+ """
84
+ if metric_subset_source is None:
85
+ metric_subset_source = os.path.join(get_data_dir(), "maf", "metric_subsets.json")
86
+ if isinstance(metric_subset_source, pd.DataFrame):
87
+ metric_subsets = metric_subset_source
88
+ else:
89
+ metric_subsets = (
90
+ pd.read_json(metric_subset_source)
91
+ .set_index("metric subset")
92
+ .set_index("metric", append=True, drop=False)
93
+ )
94
+ return metric_subsets
95
+
96
+
97
+ def create_metric_subset(
98
+ metric_subset_name,
99
+ metrics,
100
+ short_name=None,
101
+ style="-",
102
+ invert=False,
103
+ mag=False,
104
+ ):
105
+ """Create a DataFrame that defines a metric subset.
106
+
107
+ Parameters
108
+ ----------
109
+ metric_subset_name : `str`
110
+ The name of the new metric subset.
111
+ metrics : `list` [`str`]
112
+ A list of metric names in the subset.
113
+ short_name : `list` [`str`], optional
114
+ A list of shorter metric names, by default None
115
+ style : `list` [`str`], optional
116
+ The matplotlib line style symbol for lines representing the metric,
117
+ by default "-"
118
+ invert : `list` [`bool`], optional
119
+ Are smaller values of the metric better, such as for errors?,
120
+ by default False
121
+ mag : `list` [`bool`], optional
122
+ Is the metric an astronomical magnitude?, by default False
123
+
124
+ Returns
125
+ -------
126
+ metric_subset : `pandas.DataFrame`
127
+ A table of metrics and normalization and plotting flags defining the
128
+ content of a metric subset.
129
+ """
130
+ if short_name is None:
131
+ short_name = metrics
132
+
133
+ metric_subset = (
134
+ pd.DataFrame(
135
+ {
136
+ "metric subset": metric_subset_name,
137
+ "metric": metrics,
138
+ "short_name": short_name,
139
+ "style": style,
140
+ "invert": invert,
141
+ "mag": mag,
142
+ }
143
+ )
144
+ .set_index("metric subset")
145
+ .set_index("metric", append=True, drop=False)
146
+ )
147
+
148
+ return metric_subset
149
+
150
+
151
+ def write_metric_subsets(metric_subset_file, metric_subsets):
152
+ """Write an updated metric_subset dataframe to disk.
153
+
154
+ Parameters
155
+ ----------
156
+ metric_subset_file : `str`
157
+ Output file name.
158
+ metric_subsets : `pandas.DataFrame`
159
+ Metric_subset dataframe, as defined in get_metric_subsets
160
+ """
161
+ tmp = metric_subsets.reset_index("metric subset")
162
+ tmp.to_json(metric_subset_file, orient="records", indent=2)
163
+
164
+
165
+ def get_metric_summaries(
166
+ run_families=tuple(),
167
+ metric_subsets=tuple(),
168
+ runs=tuple(),
169
+ metrics=tuple(),
170
+ summary_source=None,
171
+ runs_source=None,
172
+ metric_subset_source=None,
173
+ run_order="family",
174
+ metric_order="summary",
175
+ ):
176
+ """Get summary metric values for a set of runs and metrics.
177
+
178
+ Parameters
179
+ ----------
180
+ run_families : iterable [`str`]
181
+ Families of runs to include in the summary.
182
+ metric_subsets : iterable [`str`]
183
+ subsets of metrics to include in the summary.
184
+ runs : iterable [`str`]
185
+ Runs to include in the summary (in addition to any that are part
186
+ of families included in ``run_families``).
187
+ metrics : iterable [`str`]
188
+ Metrics to include in the summary (in addition to any that are
189
+ part of subsets included in ``metric_subsets``).
190
+ summary_source : `str` or `pandas.DataFrame`
191
+ File name or URL for the file from which to load the data.
192
+ If the supplied value is a `pandas.DataFrame`, it the table
193
+ returned will be a subset of this supplied table.
194
+ run_source : `pandas.DataFrame` or `str`
195
+ Either a `pandas.DataFrame` of runs metadata (as returned by
196
+ `archive.get_runs`), or a file name or URL for the json file
197
+ from which to load the run metadata.
198
+ If it is set to `None`, the data is loaded from the URL specified
199
+ by the `archive.RUNS_SOURCE` constant.
200
+ metric_subset_source : `pandas.DataFrame` or `str`
201
+ Either a `pandas.DataFrame` of metric subset specifications
202
+ (as returned by `archive.get_metric_subsets`) or a
203
+ file name for the json file from which to load the data.
204
+ run_order : `str`
205
+ Sort runs according to family definition ("family") or summary file
206
+ ("summary") order.
207
+ metric_order : `str`
208
+ Sort metrics according to subset definition ("subset") or summary file
209
+ ("summary") order.
210
+
211
+ Returns
212
+ -------
213
+ summaries : `pandas.DataFrame`
214
+ Metric summary values are returned in a `pandas.DataFrame`, with
215
+ each column providing the metrics for one run, and each row the
216
+ values for one metric. The metric names constitute the index, and
217
+ the column names are the canonical run names.
218
+
219
+ Note
220
+ ----
221
+ The entire summary statistic values for all of the runs and metrics can
222
+ be downloaded from the default sources first, by simply calling
223
+
224
+ .. code-block:: python
225
+
226
+ summary = get_metric_summaries()
227
+
228
+ Then, you can use `get_metric_summaries` to get a subset without
229
+ redownloading the whole set by passing `summary_source=summary`. If you are
230
+ selecting multiple subsets of the summary, this avoids needing
231
+ to download the summary data multiple times.
232
+ """
233
+ summary_source = SUMMARY_SOURCE if summary_source is None else summary_source
234
+
235
+ runs = list(runs)
236
+ metrics = list(metrics)
237
+
238
+ if isinstance(run_families, str):
239
+ run_families = [run_families]
240
+
241
+ if isinstance(metric_subsets, str):
242
+ metric_subsets = [metric_subsets]
243
+
244
+ if isinstance(summary_source, pd.DataFrame):
245
+ all_summaries = summary_source
246
+ else:
247
+ try:
248
+ all_summaries = pd.read_csv(summary_source, index_col=0, low_memory=False)
249
+ except UnicodeDecodeError:
250
+ # then this was probably the h5 file instead
251
+ all_summaries = pd.read_hdf(summary_source)
252
+ all_summaries.index.name = "OpsimRun"
253
+
254
+ if len(run_families) > 0:
255
+ families = get_family_runs(runs_source)
256
+ for run_family in run_families:
257
+ runs.extend(pd.Series(families.loc[run_family, "run"]).tolist())
258
+
259
+ if len(metric_subsets) > 0:
260
+ metric_subset_df = get_metric_subsets(metric_subset_source)
261
+ for metric_subset in metric_subsets:
262
+ metrics.extend(list(metric_subset_df.loc[metric_subset, "metric"]))
263
+
264
+ if len(runs) == 0:
265
+ runs = slice(None)
266
+ else:
267
+ if run_order == "summary":
268
+ runs = [r for r in all_summaries.index if r in runs]
269
+
270
+ if len(metrics) == 0:
271
+ metrics = slice(None)
272
+ else:
273
+ requested_metrics = copy.copy(metrics)
274
+ for metric in requested_metrics:
275
+ if metric not in all_summaries.columns:
276
+ warnings.warn(f'Metric "{metric}" not in summary, skipping')
277
+ metrics.remove(metric)
278
+
279
+ if metric_order == "summary":
280
+ metrics = [m for m in all_summaries.columns if m in metrics]
281
+
282
+ summaries = all_summaries.loc[runs, metrics]
283
+ summaries.columns.name = "metric"
284
+ summaries.index.name = "run"
285
+ return summaries
286
+
287
+
288
+ def get_family_runs(run_source=None):
289
+ """Load a data frame that supplies run names for each run family
290
+
291
+ Parameters
292
+ ----------
293
+ run_source : `None` or `str`
294
+ File name or URL for the json file from which to load the metadata.
295
+ If it is set to `None`, the data is loaded from the URL specified
296
+ by the `archive.RUNS_SOURCE` constant.
297
+
298
+ Returns
299
+ -------
300
+ families : `pandas.DataFrame`
301
+ ``families``
302
+ The index is the run family. (`str`)
303
+ ``run``
304
+ the project-standard name for the run (`str`)
305
+ ``OpsimGroup``
306
+ The name for the group to which the runs belong (`str`)
307
+ ``OpsimComment``
308
+ Short description of the run (`str`)
309
+ ``OpsimVersion``
310
+ Opsim version name (`str`)
311
+ ``OpsimDate``
312
+ Date for the version of opsim (TODO: ?)
313
+ ``brief``
314
+ A list of descriptions for the run. Runs may have a
315
+ different description for each family it belongs to, so it
316
+ a list of the same length as the families column (`list`
317
+ [`str`])
318
+ ``url``
319
+ The URL from which the opsim output database for this run can be
320
+ downloaded.
321
+
322
+ Notes
323
+ -----
324
+ Because runs can be members of multiple families, more than one row may
325
+ provide metadata on the same run.
326
+
327
+ The same content (in a different form) can be obtained using
328
+ ``get_runs``. ``get_runs`` is more convenient when indexing by
329
+ run; ``get_family_runs`` when indexing by family.
330
+
331
+ """
332
+
333
+ run_source = FAMILY_SOURCE if run_source is None else run_source
334
+ if isinstance(run_source, pd.DataFrame):
335
+ runs = run_source
336
+ else:
337
+ families = pd.read_json(run_source, orient="index")
338
+ families.index.name = "family"
339
+ runs = families.explode(BY_RUN_COLS)
340
+
341
+ return runs
342
+
343
+
344
+ def get_runs(run_source=None):
345
+ """Load metadata on opsim runs into a `pandas.DataFrame`.
346
+
347
+ Parameters
348
+ ----------
349
+ run_source : `None` or `str`
350
+ File name or URL for the json file from which to load the metadata.
351
+ If it is set to `None`, the data is loaded from the URL specified
352
+ by the `archive.RUNS_SOURCE` constant.
353
+
354
+ Returns
355
+ -------
356
+ runs : `pandas.DataFrame`
357
+ ``run``
358
+ The index of the DataFrame is the project-standard name for the run
359
+ (`str`)
360
+ ``family``
361
+ A list of run families to which this run belongs (`list` [`str`])
362
+ ``version``
363
+ The simulation version
364
+ ``brief``
365
+ A list of descriptions for the run. Runs may have a
366
+ different description for each family it belongs to, so it
367
+ a list of the same length as the families column (`list`
368
+ [`str`])
369
+ ``filepath``
370
+ The file path, relative to a base opsim output directory.
371
+ ``url``
372
+ The URL from which the opsim output database for this run can be
373
+ downloaded.
374
+
375
+ Notes
376
+ -----
377
+ The same content (in a different form) can be obtained using
378
+ ``get_family_runs``. ``get_runs`` is more convenient when indexing by
379
+ run; ``get_family_runs`` when indexing by family.
380
+
381
+ """
382
+
383
+ family_runs = get_family_runs(run_source)
384
+
385
+ runs = (
386
+ family_runs.reset_index()
387
+ .groupby(BY_RUN_COLS)
388
+ .agg({c: list for c in family_runs.reset_index().columns if c not in BY_RUN_COLS})
389
+ .reset_index()
390
+ .set_index("run")
391
+ .loc[:, ["family", "version", "brief", "filepath", "url"]]
392
+ )
393
+
394
+ return runs
395
+
396
+
397
+ def download_runs(runs, dest_dir=None, runs_source=None, clobber=False):
398
+ """Download opsim visit databases for specified runs to a local directory.
399
+
400
+ Parameters
401
+ ----------
402
+ runs : `pandas.DataFrame` or iterable [`str`]
403
+ If a `pandas.DataFrame` is provided, the `OpsimRun` column will be used
404
+ to get run names, and data will be read from the url specified in the
405
+ `url` column.
406
+ If a collection of `str` is provided, these will be interpreted as
407
+ run names supplied by data originating in the run metadata provided
408
+ by the ``runs_source`` parameter.
409
+ dest_dir : `str`
410
+ The local directory into which to write downloaded visit databases.
411
+ runs_source : `str`
412
+ File name or URL for the json file from which to load the metadata.
413
+ If it is set to `None`, the data is loaded from the URL specified
414
+ by the `archive.RUNS_SOURCE` constant. This parameter is ignored
415
+ if the ``runs`` parameter is set to a `pandas.DataFrame`.
416
+ clobber : `bool`
417
+ If ``False``, runs that would clobber an existing file will be skipped.
418
+ If ``True``, existing files will be overwritten.
419
+
420
+
421
+ Returns
422
+ -------
423
+ runs : `pandas.DataFrame`
424
+ Metadata on runs downloaded (in the same structure as the return of
425
+ ``archive.get_runs``).
426
+ """
427
+
428
+ if isinstance(runs, str):
429
+ runs = [runs]
430
+
431
+ if not isinstance(runs, pd.DataFrame):
432
+ all_runs = get_runs(runs_source)
433
+ runs = all_runs.loc[runs, :]
434
+
435
+ if dest_dir is None:
436
+ dest_dir = OPSIM_DB_DIR
437
+
438
+ if not os.path.exists(dest_dir):
439
+ raise FileNotFoundError(dest_dir)
440
+
441
+ dest_fnames = pd.Series(name="fname", index=pd.Index([], name="OpsimRun"), dtype=object)
442
+
443
+ for run_name, run in runs.iterrows():
444
+ dest_fnames[run_name] = os.path.join(dest_dir, run.filepath)
445
+
446
+ # Create the directory if it does not exist
447
+ os.makedirs(os.path.dirname(dest_fnames[run_name]), exist_ok=True)
448
+
449
+ if clobber or not os.path.exists(dest_fnames[run_name]):
450
+ urllib.request.urlretrieve(run.url, dest_fnames[run_name])
451
+ else:
452
+ warnings.warn(f"{dest_fnames[run_name]} already exists; not downloading")
453
+
454
+ return dest_fnames
455
+
456
+
457
+ def get_family_descriptions(family_source=None):
458
+ """Get description of families or funs.
459
+
460
+ Parameters
461
+ ----------
462
+ family_source : `str
463
+ File name or URL for the json file from which to load the
464
+ family descriptinos. If it is set to `None`, the data is
465
+ loaded from the URL specified by the
466
+ `archive.FAMILY_SOURCE` constant.
467
+
468
+
469
+ Returns
470
+ -------
471
+ families : `pandas.DataFrame`
472
+ Family descriptions, with comments.
473
+
474
+ """
475
+ family_source = FAMILY_SOURCE if family_source is None else family_source
476
+ if isinstance(family_source, pd.DataFrame):
477
+ families = family_source
478
+ else:
479
+ families = pd.read_json(family_source, orient="index")
480
+ families.index.name = "family"
481
+ by_family_cols = [c for c in families.columns if c not in BY_RUN_COLS]
482
+ families = families.loc[:, by_family_cols + BY_RUN_COLS]
483
+ return families
484
+
485
+
486
+ def describe_families(
487
+ families,
488
+ summary=None,
489
+ table_metric_subset=None,
490
+ plot_metric_subset=None,
491
+ baseline_run=None,
492
+ round_table=2,
493
+ ):
494
+ """Display (in a jupyter on IPython notebook) family descirptions
495
+
496
+ Parameters
497
+ ----------
498
+ families : `pandas.DataFrame`
499
+ Data family descriptions as returned by get_family_descriptions.
500
+ summary : `pandas.DataFrame`
501
+ Summary metrics for each run, as returned by get_metric_summaries.
502
+ table_metric_subset : `pandas.DataFrame`
503
+ Metadata on metrics to be included in the table, with columns and
504
+ index as returned by get_metric_subsets. None if no metrics should be
505
+ included in the table.
506
+ plot_metric_subset : `pandas.DataFrame`
507
+ Metadata on metrics to be included in the plot, with columns and
508
+ index as returned by get_metric_subsets. None if no plot should be
509
+ made.
510
+ baseline_run : `str`
511
+ The name of the run to use to normalize metrics in the plot.
512
+ None if normalization should be skipped.
513
+ round_table : `int`, opt
514
+ Decimal places to which to round the table_metrics. Default 2.
515
+
516
+ Returns
517
+ -------
518
+ fig : `matplotlib.figure.Figure`
519
+ The plot figure.
520
+ ax : `matplotilb.axes.Axes`
521
+ The plot axes.
522
+ """
523
+
524
+ family_runs = families.explode(["run", "brief", "filepath"]).loc[:, ["run", "brief", "filepath"]]
525
+
526
+ # If there is just one run in the family, we might
527
+ # get a pd.Series back rather than a pd.DataFrame.
528
+ # Make sure we have a DataFrame
529
+ if isinstance(family_runs, pd.Series):
530
+ family_runs = pd.DataFrame([family_runs])
531
+
532
+ for family_name, family in families.iterrows():
533
+ # Use awkward appending of each line to string rather
534
+ # than a tripple quote to keep flake8 from complaining
535
+ # about blanks at the end of lines, which are
536
+ # meaningful in markdown (and desired here).
537
+ description = "---\n"
538
+ description += f"{family.description} \n"
539
+ description += f"**version**: {family.version} \n"
540
+ description += "**runs**: \n"
541
+
542
+ these_runs = family_runs.loc[[family_name], :]
543
+ if summary is not None:
544
+ if table_metric_subset is not None:
545
+ table_metric_summary = summary.loc[these_runs["run"], table_metric_subset["metric"]]
546
+ table_metric_summary.rename(table_metric_subset["short_name"], axis=1, inplace=True)
547
+ if round_table is not None:
548
+ table_metric_summary = table_metric_summary.round(round_table)
549
+ else:
550
+ table_metric_summary = summary.loc[these_runs["run"]]
551
+
552
+ these_runs = these_runs.join(table_metric_summary, on="run", how="left")
553
+
554
+ num_columns = len(these_runs.columns)
555
+ if num_columns > 5 and "filepath" in these_runs.columns:
556
+ these_runs = these_runs.drop(columns=["filepath"])
557
+
558
+ with pd.option_context("display.max_colwidth", 0):
559
+ if "IPython" in sys.modules:
560
+ IPython.display.display_markdown(description, raw=True)
561
+ IPython.display.display(
562
+ IPython.display.HTML(these_runs.set_index("run").to_html().replace("\\n", "<br>"))
563
+ )
564
+ else:
565
+ print(description)
566
+ print(these_runs.set_index("run"))
567
+
568
+ if plot_metric_subset is not None:
569
+ these_runs = family_runs["run"].values
570
+ if baseline_run is not None and baseline_run not in these_runs:
571
+ these_runs = np.concatenate([[baseline_run], these_runs])
572
+ these_metrics = [m for m in plot_metric_subset["metric"] if m in summary.columns]
573
+ fig, ax = plot_run_metric( # pylint: disable=invalid-name
574
+ summary.loc[these_runs, these_metrics],
575
+ metric_subset=plot_metric_subset,
576
+ metric_label_map=plot_metric_subset["short_name"],
577
+ baseline_run=baseline_run,
578
+ vertical_quantity="value",
579
+ horizontal_quantity="run",
580
+ )
581
+ else:
582
+ fig, ax = None, None # pylint: disable=invalid-name
583
+
584
+ return fig, ax
@@ -0,0 +1,125 @@
1
+ __all__ = ("combine_result_dbs", "gather_summaries")
2
+
3
+ import argparse
4
+ import glob
5
+ import logging
6
+ import os
7
+ import sqlite3
8
+
9
+ import pandas as pd
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def combine_result_dbs(run_dirs, dbfilename="resultsDb_sqlite.db"):
15
+ """Helper function for gather_summaries
16
+
17
+ Parameters
18
+ ----------
19
+ run_dirs : `list` [`str`]
20
+ A list of directories to search for MAF result databases.
21
+ dbfilename : `str`
22
+ The database filename to look for (default: resultsDb_sqlite.db).
23
+ """
24
+
25
+ # query to grab all the summary stats
26
+ sql_q = "SELECT summarystats.summary_value, "
27
+ sql_q += "metrics.metric_name, metrics.metric_info_label, "
28
+ sql_q += "metrics.slicer_name, summarystats.summary_name, metrics.run_name "
29
+ sql_q += "FROM summarystats INNER JOIN metrics ON metrics.metric_id=summarystats.metric_id"
30
+
31
+ all_summaries = []
32
+ for rdir in run_dirs:
33
+ fname = os.path.join(rdir, dbfilename)
34
+ if not os.path.isfile(fname):
35
+ logger.warning(f"No resultsDb database in {rdir}")
36
+
37
+ con = sqlite3.connect(fname)
38
+ temp_df = pd.read_sql(sql_q, con)
39
+ con.close()
40
+
41
+ # Make column names
42
+ def make_summary_name(x):
43
+ summary_name = " ".join(
44
+ [
45
+ x.summary_name.strip(),
46
+ x.metric_name.strip(),
47
+ x.metric_info_label.strip(),
48
+ x.slicer_name.strip(),
49
+ ]
50
+ )
51
+ summary_name = summary_name.replace(" ", " ")
52
+ return summary_name
53
+
54
+ temp_df["summary_names"] = temp_df.apply(make_summary_name, axis=1)
55
+ all_summaries.append(temp_df[["summary_names", "summary_value", "run_name"]])
56
+
57
+ # Make one big dataframe
58
+ all_summaries = pd.concat(all_summaries)
59
+ # Group by run names and drop duplicates
60
+ g = all_summaries.groupby(["run_name", "summary_names"]).agg({"summary_value": "last"})
61
+ # Convert to one row with all summary stats per run
62
+ result_df = g.reset_index("summary_names").pivot(columns="summary_names")
63
+ # That ended up as a MultiIndex which we didn't need, so fix and rename
64
+ result_df.columns = result_df.columns.droplevel(0).rename("metric")
65
+ return result_df
66
+
67
+
68
+ def gather_summaries():
69
+ """Find resultsDbs in a series of directories and gather up their summary
70
+ stats into a single CSV or hdf5 file. Outputs one row per unique run name.
71
+ """
72
+
73
+ parser = argparse.ArgumentParser(
74
+ description="Find resultsDbs in a series of directories and "
75
+ "gather up their summary stats into a single CSV or hdf5 file. "
76
+ "Intended to run on a set of metrics run on multiple "
77
+ "simulations, so that each results_db has similar summary"
78
+ "statistics."
79
+ )
80
+ parser.add_argument(
81
+ "--base_dir",
82
+ type=str,
83
+ default=".",
84
+ help="Root directory from where to search for MAF (sub)directories.",
85
+ )
86
+ parser.add_argument(
87
+ "--outfile",
88
+ type=str,
89
+ default="summary",
90
+ help="Output file name. Default (summary)",
91
+ )
92
+ parser.add_argument(
93
+ "--to_csv",
94
+ dest="to_csv",
95
+ action="store_true",
96
+ help="Create a .csv file, instead of the default hdf file.",
97
+ )
98
+ parser.add_argument("--to_hdf", dest="to_hdf", action="store_true")
99
+ parser.add_argument(
100
+ "--dirs",
101
+ type=str,
102
+ default=None,
103
+ help="comma separated list of directories to use, default None",
104
+ )
105
+
106
+ args = parser.parse_args()
107
+ if args.dirs is None:
108
+ run_dirs = glob.glob(args.base_dir + "/*/")
109
+ else:
110
+ run_dirs = args.dirs.split(",")
111
+
112
+ # Create output file name if needed
113
+ if args.to_csv:
114
+ outfile = args.outfile + ".csv"
115
+ else:
116
+ outfile = args.outfile + ".h5"
117
+
118
+ result_df = combine_result_dbs(run_dirs)
119
+
120
+ # Save summary statistics
121
+ if args.to_csv:
122
+ result_df.to_csv(outfile)
123
+ else:
124
+ # Create a CSV file
125
+ result_df.to_hdf(outfile, key="stats")