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,1074 @@
1
+ __all__ = (
2
+ "MetricRow",
3
+ "DisplayRow",
4
+ "PlotRow",
5
+ "SummaryStatRow",
6
+ "VersionRow",
7
+ "ResultsDb",
8
+ )
9
+
10
+ import datetime
11
+ import os
12
+ import time
13
+ import warnings
14
+ from sqlite3 import OperationalError
15
+
16
+ import numpy as np
17
+ from sqlalchemy import Column, Float, ForeignKey, Integer, String, create_engine
18
+ from sqlalchemy.engine import url
19
+ from sqlalchemy.exc import DatabaseError
20
+ from sqlalchemy.orm import backref, declarative_base, relationship, sessionmaker
21
+ from sqlalchemy.sql import text
22
+
23
+ from rubin_sim import __version__
24
+
25
+ rsVersion = __version__
26
+
27
+ Base = declarative_base()
28
+
29
+
30
+ class MetricRow(Base):
31
+ """
32
+ Define contents and format of metric list table.
33
+
34
+ (Table to list all metrics, their info_label, and their output data files).
35
+ """
36
+
37
+ __tablename__ = "metrics"
38
+ # Define columns in metric list table.
39
+ metric_id = Column(Integer, primary_key=True)
40
+ metric_name = Column(String)
41
+ slicer_name = Column(String)
42
+ run_name = Column(String)
43
+ sql_constraint = Column(String)
44
+ metric_info_label = Column(String)
45
+ metric_datafile = Column(String)
46
+
47
+ def __repr__(self):
48
+ return (
49
+ "<Metric(metric_id='%d', metric_name='%s', slicer_name='%s', "
50
+ "run_name='%s', sql_constraint='%s', metric_info_label='%s', metric_datafile='%s')>"
51
+ ) % (
52
+ self.metric_id,
53
+ self.metric_name,
54
+ self.slicer_name,
55
+ self.run_name,
56
+ self.sql_constraint,
57
+ self.metric_info_label,
58
+ self.metric_datafile,
59
+ )
60
+
61
+
62
+ class VersionRow(Base):
63
+ """"""
64
+
65
+ __tablename__ = "version"
66
+ version_id = Column(Integer, primary_key=True)
67
+ version = Column(String)
68
+ run_date = Column(String)
69
+
70
+ def __repr__(self):
71
+ return ("<Version(version='%s', run_date='%s')>") % (
72
+ self.version,
73
+ self.run_date,
74
+ )
75
+
76
+
77
+ class DisplayRow(Base):
78
+ """
79
+ Define contents and format of the displays table.
80
+
81
+ (Table to list the display properties for each metric.)
82
+ """
83
+
84
+ __tablename__ = "displays"
85
+ display_id = Column(Integer, primary_key=True)
86
+ metric_id = Column(Integer, ForeignKey("metrics.metric_id"))
87
+ # Group for displaying metric (in webpages).
88
+ display_group = Column(String)
89
+ # Subgroup for displaying metric.
90
+ display_subgroup = Column(String)
91
+ # Order to display metric (within subgroup).
92
+ display_order = Column(Float)
93
+ # The figure caption.
94
+ display_caption = Column(String)
95
+ metric = relationship("MetricRow", backref=backref("displays", order_by=display_id))
96
+
97
+ def __rep__(self):
98
+ return (
99
+ "<Display(display_group='%s', display_subgroup='%s', "
100
+ "display_order='%.1f', display_caption='%s')>"
101
+ % (
102
+ self.display_group,
103
+ self.display_subgroup,
104
+ self.display_order,
105
+ self.display_caption,
106
+ )
107
+ )
108
+
109
+
110
+ class PlotRow(Base):
111
+ """
112
+ Define contents and format of plot list table.
113
+
114
+ (Table to list all plots,
115
+ link them to relevant metrics in MetricList,
116
+ and provide info on filename).
117
+ """
118
+
119
+ __tablename__ = "plots"
120
+ # Define columns in plot list table.
121
+ plot_id = Column(Integer, primary_key=True)
122
+ # Matches metricID in MetricList table.
123
+ metric_id = Column(Integer, ForeignKey("metrics.metric_id"))
124
+ plot_type = Column(String)
125
+ plot_file = Column(String)
126
+ metric = relationship("MetricRow", backref=backref("plots", order_by=plot_id))
127
+
128
+ def __repr__(self):
129
+ return "<Plot(metric_id='%d', plot_type='%s', plot_file='%s')>" % (
130
+ self.metric_id,
131
+ self.plot_type,
132
+ self.plot_file,
133
+ )
134
+
135
+
136
+ class SummaryStatRow(Base):
137
+ """
138
+ Define contents and format of the summary statistics table.
139
+
140
+ (Table to list and link summary stats to relevant metrics in MetricList,
141
+ and provide summary stat name, value and potentially a comment).
142
+ """
143
+
144
+ __tablename__ = "summarystats"
145
+ # Define columns in summary table.
146
+ stat_id = Column(Integer, primary_key=True)
147
+ # Matches metricID in MetricList table.
148
+ metric_id = Column(Integer, ForeignKey("metrics.metric_id"))
149
+ summary_name = Column(String)
150
+ summary_value = Column(Float)
151
+ metric = relationship("MetricRow", backref=backref("summarystats", order_by=stat_id))
152
+
153
+ def __repr__(self):
154
+ return "<SummaryStat(metric_id='%d', summary_name='%s', summary_value='%f')>" % (
155
+ self.metric_id,
156
+ self.summary_name,
157
+ self.summary_value,
158
+ )
159
+
160
+
161
+ class ResultsDb:
162
+ """ResultsDb is a sqlite database containing information on the metrics
163
+ run via MAF, the plots created, the display information (such as captions),
164
+ and any summary statistics output.
165
+ """
166
+
167
+ def __init__(self, out_dir=None, database=None, verbose=False, timeout=180):
168
+ """
169
+ Set up the resultsDb database.
170
+ """
171
+ # We now require results_db to be a sqlite file (for simplicity).
172
+ # Leaving as attribute though.
173
+ self.driver = "sqlite"
174
+ # connecting to non-existent database creates it automatically
175
+ if database is None:
176
+ # Using default value for database name, should specify directory.
177
+ if out_dir is None:
178
+ out_dir = "."
179
+ # Check for output directory, make if needed.
180
+ if not os.path.isdir(out_dir):
181
+ try:
182
+ os.makedirs(out_dir)
183
+ except OSError as msg:
184
+ raise OSError(
185
+ msg,
186
+ "\n (If this was the database file (not out_dir), "
187
+ 'remember to use kwarg "database")',
188
+ )
189
+ self.database = os.path.join(out_dir, "resultsDb_sqlite.db")
190
+ else:
191
+ # Using non-default database, but may also specify directory root.
192
+ if out_dir is not None:
193
+ database = os.path.join(out_dir, database)
194
+ self.database = database
195
+ # If this is a new file, then we should record date and version later.
196
+ needs_version = not os.path.isfile(self.database)
197
+
198
+ # Connect to the specified file;
199
+ # this will create the database if it doesn't exist.
200
+ already_file = os.path.isfile(self.database)
201
+ db_address = url.URL.create(self.driver, database=self.database)
202
+
203
+ engine = create_engine(db_address, echo=verbose, connect_args={"timeout": timeout})
204
+ self.Session = sessionmaker(bind=engine)
205
+ self.open()
206
+ # Create the tables, if they don't already exist.
207
+ if not already_file:
208
+ try:
209
+ Base.metadata.create_all(engine)
210
+ except DatabaseError:
211
+ raise ValueError(
212
+ "Cannot create a %s database at %s. Check directory exists."
213
+ % (self.driver, self.database)
214
+ )
215
+ self.slen = 1024
216
+ # Check if we have a database matching this schema
217
+ # (with metric_info_label)
218
+ query = text("select * from metrics limit 1")
219
+ cols = self.session.execute(query)._metadata.keys
220
+ if "sql_constraint" not in cols:
221
+ self.update_database()
222
+
223
+ # record the version and date MAF was run with/on
224
+ if needs_version:
225
+ vers = rsVersion
226
+ run_date = datetime.datetime.now().strftime("%Y-%m-%d")
227
+ versioninfo = VersionRow(version=vers, run_date=run_date)
228
+ self.session.add(versioninfo)
229
+ self.session.commit()
230
+
231
+ self.close()
232
+
233
+ def update_database(self):
234
+ """Update the results_db from 'metricMetaData' to 'metric_info_label'
235
+ and now also changing the camel case to snake case
236
+ (metricId to metric_id, etc.).
237
+
238
+ This updates results_db to work with the current version of MAF,
239
+ including RunComparison and showMaf.
240
+ There is also a 'downgrade_database' to revert to the older style
241
+ with 'metricMetadata.
242
+ """
243
+ warnings.warn(
244
+ "Updating database to match new schema."
245
+ "Undo with self.downgrade_database if necessary (for older maf versions)."
246
+ )
247
+ query = text("select * from metrics limit 1")
248
+ cols = self.session.execute(query)._metadata.keys
249
+ if "metricMetadata" in cols:
250
+ # if it's very old
251
+ query = text("alter table metrics rename column metricMetadata to metric_info_label")
252
+ self.session.execute(query)
253
+ self.session.commit()
254
+ # Check for metricId vs. metric_id separately,
255
+ # as this change happened independently.
256
+ if "metricId" in cols:
257
+ for table in ["metrics", "summarystats", "plots", "displays"]:
258
+ query = text(f"alter table {table} rename column metricId to metric_id")
259
+ self.session.execute(query)
260
+ self.session.commit()
261
+ # Update to newest schema.
262
+ if "run_name" not in cols:
263
+ updates = {
264
+ "metricName": "metric_name",
265
+ "slicerName": "slicer_name",
266
+ "simDataName": "run_name",
267
+ "sqlConstraint": "sql_constraint",
268
+ "metricInfoLabel": "metric_info_label",
269
+ "metricDataFile": "metric_datafile",
270
+ }
271
+ for old, new in updates.items():
272
+ query = text(f"alter table metrics rename column {old} to {new}")
273
+ self.session.execute(query)
274
+ self.session.commit()
275
+ # update summarystat table
276
+ updates = {
277
+ "statId": "stat_id",
278
+ "summaryName": "summary_name",
279
+ "summaryValue": "summary_value",
280
+ }
281
+ for old, new in updates.items():
282
+ query = text(f"alter table summarystats rename column {old} to {new}")
283
+ self.session.execute(query)
284
+ self.session.commit()
285
+ # update plot table
286
+ updates = {
287
+ "plotId": "plot_id",
288
+ "plotType": "plot_type",
289
+ "plotFile": "plot_file",
290
+ }
291
+ for old, new in updates.items():
292
+ query = text(f"alter table plots rename column {old} to {new}")
293
+ self.session.execute(query)
294
+ self.session.commit()
295
+ # update display table
296
+ updates = {
297
+ "displayId": "display_id",
298
+ "displayGroup": "display_group",
299
+ "displaySubgroup": "display_subgroup",
300
+ "displayOrder": "display_order",
301
+ "displayCaption": "display_caption",
302
+ }
303
+ for old, new in updates.items():
304
+ query = text(f"alter table displays rename column {old} to {new}")
305
+ self.session.execute(query)
306
+ self.session.commit()
307
+ updates = {
308
+ "verId": "version_id",
309
+ "rundate": "run_date",
310
+ }
311
+ for old, new in updates.items():
312
+ query = text(f"alter table version rename column {old} to {new}")
313
+ self.session.execute(query)
314
+ self.session.commit()
315
+
316
+ def downgrade_database(self):
317
+ """
318
+ Downgrade resultsDb to work with v0.10<MAF< v1.0
319
+ There is also a 'upgradeDatabase' to update to the newer
320
+ style with 'metric_info_label.
321
+ """
322
+ self.open()
323
+ warnings.warn("Downgrading MAF resultsDb to run with MAF < v1.0")
324
+ updates = {
325
+ "metricId": "metric_id",
326
+ "metricName": "metric_name",
327
+ "slicerName": "slicer_name",
328
+ "simDataName": "run_name",
329
+ "sqlConstraint": "sql_constraint",
330
+ "metricInfoLabel": "metric_info_label",
331
+ "metricDataFile": "metric_datafile",
332
+ }
333
+ for old, new in updates.items():
334
+ query = text(f"alter table metrics rename column {new} to {old}")
335
+ self.session.execute(query)
336
+ self.session.commit()
337
+ # update summarystat table
338
+ updates = {
339
+ "statId": "stat_id",
340
+ "metricId": "metric_id",
341
+ "summaryName": "summary_name",
342
+ "summaryValue": "summary_value",
343
+ }
344
+ for old, new in updates.items():
345
+ query = text(f"alter table summarystats rename column {new} to {old}")
346
+ self.session.execute(query)
347
+ self.session.commit()
348
+ # update plot table
349
+ updates = {
350
+ "plotId": "plot_id",
351
+ "metricId": "metric_id",
352
+ "plotType": "plot_type",
353
+ "plotFile": "plot_file",
354
+ }
355
+ for old, new in updates.items():
356
+ query = text(f"alter table plots rename column {new} to {old}")
357
+ self.session.execute(query)
358
+ self.session.commit()
359
+ # update display table
360
+ updates = {
361
+ "displayId": "display_id",
362
+ "metricId": "metric_id",
363
+ "displayGroup": "display_group",
364
+ "displaySubgroup": "display_subgroup",
365
+ "displayOrder": "display_order",
366
+ "displayCaption": "display_caption",
367
+ }
368
+ for old, new in updates.items():
369
+ query = text(f"alter table displays rename column {new} to {old}")
370
+ self.session.execute(query)
371
+ self.session.commit()
372
+ updates = {
373
+ "verId": "version_id",
374
+ "rundate": "run_date",
375
+ }
376
+ for old, new in updates.items():
377
+ query = text(f"alter table version rename column {new} to {old}")
378
+ self.session.execute(query)
379
+ self.session.commit()
380
+ self.close()
381
+
382
+ def open(self):
383
+ """
384
+ Open connection to database
385
+ """
386
+ self.session = self.Session()
387
+ self.session.expire_on_commit = False
388
+
389
+ def close(self):
390
+ """
391
+ Close connection to database.
392
+ """
393
+ self.session.close()
394
+
395
+ def update_metric(
396
+ self,
397
+ metric_name,
398
+ slicer_name,
399
+ run_name,
400
+ sql_constraint,
401
+ metric_info_label,
402
+ metric_datafile,
403
+ ):
404
+ """
405
+ Add a row to or update a row in the metrics table.
406
+
407
+ Parameters
408
+ ----------
409
+ metric_name : `str`
410
+ Name of the Metric
411
+ slicer_name : `str`
412
+ Name of the Slicer
413
+ run_name : `str`
414
+ Name of the simulation (run_name, simName, run_name..)
415
+ sql_constraint : `str`
416
+ sql_constraint relevant for the metric bundle
417
+ metric_info_label : `str`
418
+ Information associated with the metric.
419
+ Could be derived from the sql_constraint or could
420
+ be a more descriptive version, specified by the user.
421
+ metric_datafile : `str`
422
+ The data file the metric bundle output is stored in.
423
+
424
+ Returns
425
+ -------
426
+ metric_id : `int`
427
+ The Id number of this metric in the metrics table.
428
+
429
+ If same metric (same metric_name, slicer_name, run_name,
430
+ sql_constraint, infoLabel) already exists, it does nothing.
431
+ """
432
+ self.open()
433
+ if run_name is None:
434
+ run_name = "NULL"
435
+ if sql_constraint is None:
436
+ sql_constraint = "NULL"
437
+ if metric_info_label is None:
438
+ metric_info_label = "NULL"
439
+ if metric_datafile is None:
440
+ metric_datafile = "NULL"
441
+ # Check if metric has already been added to database.
442
+ prev = (
443
+ self.session.query(MetricRow)
444
+ .filter_by(
445
+ metric_name=metric_name,
446
+ slicer_name=slicer_name,
447
+ run_name=run_name,
448
+ metric_info_label=metric_info_label,
449
+ sql_constraint=sql_constraint,
450
+ )
451
+ .all()
452
+ )
453
+ if len(prev) == 0:
454
+ metricinfo = MetricRow(
455
+ metric_name=metric_name,
456
+ slicer_name=slicer_name,
457
+ run_name=run_name,
458
+ sql_constraint=sql_constraint,
459
+ metric_info_label=metric_info_label,
460
+ metric_datafile=metric_datafile,
461
+ )
462
+ self.session.add(metricinfo)
463
+ self.session.commit()
464
+ else:
465
+ metricinfo = prev[0]
466
+ self.close()
467
+
468
+ return metricinfo.metric_id
469
+
470
+ def update_display(self, metric_id, display_dict, overwrite=True):
471
+ """
472
+ Add a row to or update a row in the displays table.
473
+
474
+ Parameters
475
+ ----------
476
+ metric_id : `int`
477
+ The metricID for this metric bundle in the metrics table
478
+ display_dict : `dict`
479
+ Dictionary containing the display info
480
+ (group/subgroup/order/caption)
481
+ overwrite : `bool`, opt
482
+ Replaces existing row with same metric_id if overwrite is True.
483
+ """
484
+ # Because we want to maintain 1-1 relationship between
485
+ # metric_id's and display_dict's: First check if a display line
486
+ # is present with this metricID.
487
+ self.open()
488
+ displayinfo = self.session.query(DisplayRow).filter_by(metric_id=metric_id).all()
489
+ if len(displayinfo) > 0:
490
+ if overwrite:
491
+ for d in displayinfo:
492
+ self.session.delete(d)
493
+ else:
494
+ return
495
+ # Then go ahead and add new display_dict.
496
+ for k in display_dict:
497
+ if display_dict[k] is None:
498
+ display_dict[k] = "NULL"
499
+ keys = ["group", "subgroup", "order", "caption"]
500
+ for k in keys:
501
+ if k not in display_dict:
502
+ display_dict[k] = "NULL"
503
+ if display_dict["order"] == "NULL":
504
+ display_dict["order"] = 0
505
+ display_group = display_dict["group"]
506
+ display_subgroup = display_dict["subgroup"]
507
+ display_order = display_dict["order"]
508
+ display_caption = display_dict["caption"]
509
+ if display_caption.endswith("(auto)"):
510
+ display_caption = display_caption.replace("(auto)", "", 1)
511
+ displayinfo = DisplayRow(
512
+ metric_id=metric_id,
513
+ display_group=display_group,
514
+ display_subgroup=display_subgroup,
515
+ display_order=display_order,
516
+ display_caption=display_caption,
517
+ )
518
+ self.session.add(displayinfo)
519
+ self.session.commit()
520
+ self.close()
521
+
522
+ def update_plot(self, metric_id, plot_type, plot_file, overwrite=False):
523
+ """
524
+ Add a row to or update a row in the plot table.
525
+
526
+ Parameters
527
+ ----------
528
+ metric_id : `int`
529
+ The metric Id of this metric bundle in the metrics table
530
+ plot_type : `str`
531
+ The type of this plot (oneDbinned data, healpix map, etc.)
532
+ plot_file : `str`
533
+ The filename for this plot
534
+ overwrite : `bool`
535
+ If True, replaces existing row.
536
+ If False, an additional plot is added to the output (e.g. with
537
+ a different range of color values, etc).
538
+ """
539
+ self.open()
540
+ plotinfo = self.session.query(PlotRow).filter_by(metric_id=metric_id, plot_type=plot_type).all()
541
+ if len(plotinfo) > 0 and overwrite:
542
+ for p in plotinfo:
543
+ self.session.delete(p)
544
+ plotinfo = PlotRow(metric_id=metric_id, plot_type=plot_type, plot_file=plot_file)
545
+ self.session.add(plotinfo)
546
+ self.session.commit()
547
+ self.close()
548
+
549
+ def update_summary_stat(self, metric_id, summary_name, summary_value, ntry=3, pause_time=100):
550
+ """
551
+ Add a row to or update a row in the summary statistic table.
552
+
553
+ Most summary statistics will be a simple name (string) + value (float)
554
+ pair. For special summary statistics which must return multiple values,
555
+ the base name can be provided as 'name', together with a np.ndarray as
556
+ 'value', where the array also has 'name' and 'value' columns
557
+ (and each name/value pair is then saved as a summary statistic
558
+ associated with this same metric_id).
559
+
560
+ Parameters
561
+ ----------
562
+ metric_id : `int`
563
+ The metric Id of this metric bundle
564
+ summary_name : `str`
565
+ The name of this summary statistic
566
+ summary_value: : `float` or `np.ndarray`
567
+ The value for this summary statistic.
568
+ If this is a np.ndarray, then it should also have 'name' and
569
+ 'value' columns to save each value to rows in the summary stats.
570
+ ntry : `int`, opt
571
+ The number of times to retry if database is locked.
572
+ pause_time : `int`, opt
573
+ Time to wait until trying again.
574
+ """
575
+ # Allow for special summary statistics which return data in a
576
+ # np.ndarray with 'name' and 'value' columns.
577
+ self.open()
578
+ tries = 0
579
+ if isinstance(summary_value, np.ndarray) and summary_value.dtype.names is not None:
580
+ if ("name" in summary_value.dtype.names) and ("value" in summary_value.dtype.names):
581
+ for value in summary_value:
582
+ sSuffix = value["name"]
583
+ if isinstance(sSuffix, bytes):
584
+ sSuffix = sSuffix.decode("utf-8")
585
+ else:
586
+ sSuffix = str(sSuffix)
587
+ summarystat = SummaryStatRow(
588
+ metric_id=metric_id,
589
+ summary_name=summary_name + " " + sSuffix,
590
+ summary_value=value["value"],
591
+ )
592
+ success = False
593
+ # This can hit a locked database if running in parallel
594
+ # have it try a few times before actually failing
595
+ # since nothing should be writing for a long time.
596
+ while (not success) & (tries < ntry):
597
+ try:
598
+ self.session.add(summarystat)
599
+ self.session.commit()
600
+ success = True
601
+ except OperationalError:
602
+ tries += 1
603
+ time.sleep(pause_time)
604
+ else:
605
+ warnings.warn("Warning! Cannot save non-conforming summary statistic.")
606
+ # Most summary statistics will be simple floats.
607
+ else:
608
+ if isinstance(summary_value, float) or isinstance(summary_value, int):
609
+ summarystat = SummaryStatRow(
610
+ metric_id=metric_id,
611
+ summary_name=summary_name,
612
+ summary_value=summary_value,
613
+ )
614
+ self.session.add(summarystat)
615
+ self.session.commit()
616
+ else:
617
+ warnings.warn("Warning! Cannot save summary statistic that is not a simple float or int")
618
+ self.close()
619
+
620
+ def get_metric_id(self, metric_name, slicer_name=None, metric_info_label=None, run_name=None):
621
+ """Find metric bundle Ids from the metric table.
622
+
623
+ Parameters
624
+ ----------
625
+ metric_name : `str`
626
+ Name of the Metric
627
+ slicer_name : `str`, opt
628
+ Name of the Slicer to match
629
+ metric_info_label : `str`, opt
630
+ Metadata value to match
631
+ run_name : `str`, opt
632
+ Name of the simulation (run_name) to match
633
+
634
+ Returns
635
+ -------
636
+ metric_id : `list` of `int`
637
+ List of matching metric_ids
638
+ """
639
+ self.open()
640
+ metric_id = []
641
+ query = self.session.query(
642
+ MetricRow.metric_id,
643
+ MetricRow.metric_name,
644
+ MetricRow.slicer_name,
645
+ MetricRow.metric_info_label,
646
+ MetricRow.run_name,
647
+ ).filter(MetricRow.metric_name == metric_name)
648
+ if slicer_name is not None:
649
+ query = query.filter(MetricRow.slicer_name == slicer_name)
650
+ if metric_info_label is not None:
651
+ query = query.filter(MetricRow.metric_info_label == metric_info_label)
652
+ if run_name is not None:
653
+ query = query.filter(MetricRow.run_name == run_name)
654
+ query = query.order_by(MetricRow.slicer_name, MetricRow.metric_info_label)
655
+ for m in query:
656
+ metric_id.append(m.metric_id)
657
+ self.close()
658
+ return metric_id
659
+
660
+ def get_metric_id_like(
661
+ self,
662
+ metric_name_like=None,
663
+ slicer_name_like=None,
664
+ metric_info_label_like=None,
665
+ run_name=None,
666
+ ):
667
+ """Find metric bundle Ids from the metric table,
668
+ but search for names 'like' the values.
669
+ (instead of a strict match from get_metric_id).
670
+
671
+ Parameters
672
+ ----------
673
+ metric_name : `str`
674
+ Partial name of the Metric
675
+ slicer_name : `str`, opt
676
+ Partial name of the Slicer to match
677
+ metric_info_label : `str`, opt
678
+ Partial info_label value to match
679
+ run_name : `str`, opt
680
+ Name of the simulation (run_name) to match (exact)
681
+
682
+ Returns
683
+ -------
684
+ metric_id : `list` of `int`
685
+ List of matching metric_ids
686
+ """
687
+ self.open()
688
+ metric_id = []
689
+ query = self.session.query(
690
+ MetricRow.metric_id,
691
+ MetricRow.metric_name,
692
+ MetricRow.slicer_name,
693
+ MetricRow.metric_info_label,
694
+ MetricRow.run_name,
695
+ )
696
+ if metric_name_like is not None:
697
+ query = query.filter(MetricRow.metric_name.like(f"%{str(metric_name_like)}%"))
698
+ if slicer_name_like is not None:
699
+ query = query.filter(MetricRow.slicer_name.like(f"%{str(slicer_name_like)}%"))
700
+ if metric_info_label_like is not None:
701
+ query = query.filter(MetricRow.metric_info_label.like(f"%{str(metric_info_label_like)}%"))
702
+ if run_name is not None:
703
+ query = query.filter(MetricRow.run_name == run_name)
704
+ for m in query:
705
+ metric_id.append(m.metric_id)
706
+ self.close()
707
+ return metric_id
708
+
709
+ def get_all_metric_ids(self):
710
+ """
711
+ Return a list of all metric_ids.
712
+ """
713
+ self.open()
714
+ metric_ids = []
715
+ for m in self.session.query(MetricRow.metric_id).all():
716
+ metric_ids.append(m.metric_id)
717
+ self.close()
718
+ return metric_ids
719
+
720
+ @staticmethod
721
+ def build_summary_name(metric_name, metric_info_label, slicer_name, summary_stat_name=None):
722
+ """Standardize a complete summary metric name,
723
+ combining the metric + slicer + summary + info_label."""
724
+ if metric_info_label is None:
725
+ metric_info_label = ""
726
+ if slicer_name is None:
727
+ slicer_name = ""
728
+ sName = summary_stat_name
729
+ if sName == "Identity" or sName == "Id" or sName == "Count" or sName is None:
730
+ sName = ""
731
+ slName = slicer_name
732
+ if slName == "UniSlicer":
733
+ slName = ""
734
+ name = " ".join([sName, metric_name, metric_info_label, slName]).rstrip(" ").lstrip(" ")
735
+ name.replace(",", "")
736
+ return name
737
+
738
+ def get_summary_stats(
739
+ self,
740
+ metric_id=None,
741
+ summary_name=None,
742
+ summary_name_like=None,
743
+ summary_name_notlike=None,
744
+ with_sim_name=False,
745
+ ):
746
+ """
747
+ Get the summary stats (optionally for metric_id list).
748
+ Optionally, also specify the summary metric name.
749
+ Returns a numpy array of the metric information +
750
+ summary statistic information.
751
+
752
+ Parameters
753
+ ----------
754
+ metric_id : `int` or `list` of `int`
755
+ Metric bundle Ids to match from the metric table
756
+ summary_name : `str`, opt
757
+ Match this summary statistic name exactly.
758
+ summary_name_like : `str`, opt
759
+ Partial match to this summary statistic name.
760
+ summary_name_notlike : `str`, opt
761
+ Exclude summary statistics with summary names like this.
762
+ with_sim_name : `bool`, opt
763
+ If True, add the run_name to the returned numpy recarray.
764
+
765
+ Returns
766
+ -------
767
+ summarystats : `np.recarray`
768
+ Numpy recarray containing the selected summary stat information.
769
+ """
770
+ if metric_id is not None:
771
+ if not hasattr(metric_id, "__iter__"):
772
+ metric_id = [
773
+ metric_id,
774
+ ]
775
+ summarystats = []
776
+ self.open()
777
+ # Join the metric table and the summarystat table,
778
+ # based on the metricID (the second filter)
779
+ query = self.session.query(MetricRow, SummaryStatRow).filter(
780
+ MetricRow.metric_id == SummaryStatRow.metric_id
781
+ )
782
+ if metric_id is not None:
783
+ query = query.filter(MetricRow.metric_id.in_(metric_id))
784
+ if summary_name is not None:
785
+ query = query.filter(SummaryStatRow.summary_name == str(summary_name))
786
+ if summary_name_like is not None:
787
+ query = query.filter(SummaryStatRow.summary_name.like(f"%{str(summary_name_like)}%"))
788
+ if summary_name_notlike is not None:
789
+ if isinstance(summary_name_notlike, list):
790
+ for s in summary_name_notlike:
791
+ query = query.filter(~SummaryStatRow.summary_name.like(f"%{str(s)}%"))
792
+ else:
793
+ query = query.filter(~SummaryStatRow.summary_name.like(f"%{str(summary_name_notlike)}%"))
794
+ for m, s in query:
795
+ long_name = self.build_summary_name(
796
+ m.metric_name, m.metric_info_label, m.slicer_name, s.summary_name
797
+ )
798
+ vals = (
799
+ m.metric_id,
800
+ long_name,
801
+ m.metric_name,
802
+ m.slicer_name,
803
+ m.metric_info_label,
804
+ s.summary_name,
805
+ s.summary_value,
806
+ )
807
+ if with_sim_name:
808
+ vals += (m.run_name,)
809
+ summarystats.append(vals)
810
+ # Convert to numpy array.
811
+ dtype_list = [
812
+ ("metric_id", int),
813
+ ("summary_name", str, self.slen),
814
+ ("metric_name", str, self.slen),
815
+ ("slicer_name", str, self.slen),
816
+ ("metric_info_label", str, self.slen),
817
+ ("summary_metric", str, self.slen),
818
+ ("summary_value", float),
819
+ ]
820
+ if with_sim_name:
821
+ dtype_list += [("run_name", str, self.slen)]
822
+ dtype = np.dtype(dtype_list)
823
+ summarystats = np.array(summarystats, dtype)
824
+ self.close()
825
+ return summarystats
826
+
827
+ def get_plot_files(self, metric_id=None, with_sim_name=False):
828
+ """
829
+ Find the metric_id, name, info_label, and all plot info
830
+ (optionally for metric_id list).
831
+
832
+ Parameters
833
+ ----------
834
+ metric_id : `int` `list`, or `None`
835
+ If None, plots for all metrics are returned. Otherwise, only plots
836
+ corresponding to the supplied metric ID or IDs are returned
837
+ with_sim_name : `bool`
838
+ If True, include the run name in the fields returned
839
+
840
+ Returns
841
+ -------
842
+ plotFiles : `numpy.recarray`
843
+ ``metric_id``
844
+ The metric ID
845
+ ``metric_name``
846
+ The metric name
847
+ ``metric_info_label``
848
+ info_label extracted from the sql constraint
849
+ (usually the filter)
850
+ ``plot_type``
851
+ The plot type
852
+ ``plot_file``
853
+ The full plot file (pdf by default)
854
+ ``thumb_file``
855
+ A plot thumbnail file name (png)
856
+ ``run_name``
857
+ The name of the run plotted (if `with_sim_name` was `True`)
858
+ """
859
+ if metric_id is None:
860
+ metric_id = self.get_all_metric_ids()
861
+ if not hasattr(metric_id, "__iter__"):
862
+ metric_id = [
863
+ metric_id,
864
+ ]
865
+ self.open()
866
+ plotfiles = []
867
+ for mid in metric_id:
868
+ # Join the metric table and the plot table based on the metricID
869
+ # (the second filter does the join)
870
+ query = (
871
+ self.session.query(MetricRow, PlotRow)
872
+ .filter(MetricRow.metric_id == mid)
873
+ .filter(MetricRow.metric_id == PlotRow.metric_id)
874
+ )
875
+ for m, p in query:
876
+ # The plot_file typically ends with .pdf
877
+ # (but the rest of name can have '.' or '_')
878
+ thumb_file = "thumb." + ".".join(p.plot_file.split(".")[:-1]) + ".png"
879
+ plot_file_fields = (
880
+ m.metric_id,
881
+ m.metric_name,
882
+ m.metric_info_label,
883
+ p.plot_type,
884
+ p.plot_file,
885
+ thumb_file,
886
+ )
887
+ if with_sim_name:
888
+ plot_file_fields += (m.run_name,)
889
+ plotfiles.append(plot_file_fields)
890
+
891
+ # Convert to numpy array.
892
+ dtype_list = [
893
+ ("metric_id", int),
894
+ ("metric_name", str, self.slen),
895
+ ("metric_info_label", str, self.slen),
896
+ ("plot_type", str, self.slen),
897
+ ("plot_file", str, self.slen),
898
+ ("thumb_file", str, self.slen),
899
+ ]
900
+
901
+ if with_sim_name:
902
+ dtype_list += [("run_name", str, self.slen)]
903
+ dtype = np.dtype(dtype_list)
904
+
905
+ plotfiles = np.array(plotfiles, dtype)
906
+ self.close()
907
+ return plotfiles
908
+
909
+ def get_metric_data_files(self, metric_id=None):
910
+ """
911
+ Get the metric data filenames for all or a single metric.
912
+ Returns a list.
913
+ """
914
+ if metric_id is None:
915
+ metric_id = self.get_all_metric_ids()
916
+ self.open()
917
+ if not hasattr(metric_id, "__iter__"):
918
+ metric_id = [
919
+ metric_id,
920
+ ]
921
+ datafiles = []
922
+ for mid in metric_id:
923
+ for m in self.session.query(MetricRow).filter(MetricRow.metric_id == mid).all():
924
+ datafiles.append(m.metric_datafile)
925
+ self.close()
926
+ return datafiles
927
+
928
+ def get_metric_info(self, metric_id=None, with_sim_name=False):
929
+ """Get the simple metric info, without display information.
930
+
931
+ Parameters
932
+ ----------
933
+ metric_id : `int` `list`, or `None`
934
+ If None, data for all metrics are returned. Otherwise, only data
935
+ corresponding to the supplied metric ID or IDs are returned
936
+ with_sim_name : `bool`
937
+ If True, include the run name in the fields returned
938
+
939
+ Returns
940
+ -------
941
+ plotFiles : `numpy.recarray`
942
+ ``metric_id``
943
+ The metric ID
944
+ ``metric_name``
945
+ The metric name
946
+ ``basemetric_names``
947
+ The base metric names
948
+ ``slicer_name``
949
+ The name of the slicer used in the bundleGroup
950
+ ``sql_constraint``
951
+ The full sql constraint used in the bundleGroup
952
+ ``metric_info_label``
953
+ Metadata extracted from the `sql_constraint`
954
+ (usually the filter)
955
+ ``metric_datafile``
956
+ The file name of the file with the metric data itself.
957
+ ``run_name``
958
+ The name of the run plotted (if `with_sim_name` was `True`)
959
+
960
+ """
961
+ if metric_id is None:
962
+ metric_id = self.get_all_metric_ids()
963
+ if not hasattr(metric_id, "__iter__"):
964
+ metric_id = [
965
+ metric_id,
966
+ ]
967
+ self.open()
968
+ metricInfo = []
969
+ for mId in metric_id:
970
+ # Query for all rows in metrics and displays that match metric_ids
971
+ query = self.session.query(MetricRow).filter(MetricRow.metric_id == mId)
972
+ for m in query:
973
+ base_metric_name = m.metric_name.split("_")[0]
974
+ mInfo = (
975
+ m.metric_id,
976
+ m.metric_name,
977
+ base_metric_name,
978
+ m.slicer_name,
979
+ m.sql_constraint,
980
+ m.metric_info_label,
981
+ m.metric_datafile,
982
+ )
983
+ if with_sim_name:
984
+ mInfo += (m.run_name,)
985
+
986
+ metricInfo.append(mInfo)
987
+ # Convert to numpy array.
988
+ dtype_list = [
989
+ ("metric_id", int),
990
+ ("metric_name", str, self.slen),
991
+ ("base_metric_names", str, self.slen),
992
+ ("slicer_name", str, self.slen),
993
+ ("sql_constraint", str, self.slen),
994
+ ("metric_info_label", str, self.slen),
995
+ ("metric_datafile", str, self.slen),
996
+ ]
997
+ if with_sim_name:
998
+ dtype_list += [("run_name", str, self.slen)]
999
+ dtype = np.dtype(dtype_list)
1000
+ metricInfo = np.array(metricInfo, dtype)
1001
+ self.close()
1002
+ return metricInfo
1003
+
1004
+ def get_metric_display_info(self, metric_id=None):
1005
+ """
1006
+ Get the contents of the metrics and displays table,
1007
+ together with the 'basemetric_name' (optionally, for metric_id list).
1008
+ Returns a numpy array of the metric information + display information.
1009
+
1010
+ An underlying assumption here is that all metrics have some
1011
+ display info. This may not always be the case.
1012
+ """
1013
+ if metric_id is None:
1014
+ metric_id = self.get_all_metric_ids()
1015
+ if not hasattr(metric_id, "__iter__"):
1016
+ metric_id = [
1017
+ metric_id,
1018
+ ]
1019
+ self.open()
1020
+ metricInfo = []
1021
+ for mId in metric_id:
1022
+ # Query for all rows in metrics and displays that match metric_ids.
1023
+ query = (
1024
+ self.session.query(MetricRow, DisplayRow)
1025
+ .filter(MetricRow.metric_id == mId)
1026
+ .filter(MetricRow.metric_id == DisplayRow.metric_id)
1027
+ )
1028
+ for m, d in query:
1029
+ base_metric_name = m.metric_name.split("_")[0]
1030
+ mInfo = (
1031
+ m.metric_id,
1032
+ m.metric_name,
1033
+ base_metric_name,
1034
+ m.slicer_name,
1035
+ m.sql_constraint,
1036
+ m.metric_info_label,
1037
+ m.metric_datafile,
1038
+ d.display_group,
1039
+ d.display_subgroup,
1040
+ d.display_order,
1041
+ d.display_caption,
1042
+ )
1043
+ metricInfo.append(mInfo)
1044
+ # Convert to numpy array.
1045
+ dtype = np.dtype(
1046
+ [
1047
+ ("metric_id", int),
1048
+ ("metric_name", np.str_, self.slen),
1049
+ ("base_metric_name", np.str_, self.slen),
1050
+ ("slicer_name", np.str_, self.slen),
1051
+ ("sql_constraint", np.str_, self.slen),
1052
+ ("metric_info_label", np.str_, self.slen),
1053
+ ("metric_datafile", np.str_, self.slen),
1054
+ ("display_group", np.str_, self.slen),
1055
+ ("display_subgroup", np.str_, self.slen),
1056
+ ("display_order", float),
1057
+ ("display_caption", np.str_, self.slen * 10),
1058
+ ]
1059
+ )
1060
+ metricInfo = np.array(metricInfo, dtype)
1061
+ self.close()
1062
+ return metricInfo
1063
+
1064
+ def get_run_name(self):
1065
+ """Return a list of the run_names for the metric bundles in
1066
+ the database.
1067
+ """
1068
+ self.open()
1069
+ query = self.session.query(MetricRow.run_name.distinct()).all()
1070
+ run_name = []
1071
+ for s in query:
1072
+ run_name.append(s[0])
1073
+ self.close()
1074
+ return run_name