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,423 @@
1
+ import os
2
+ import sys
3
+ import unittest
4
+ import warnings
5
+
6
+ import numpy as np
7
+ import pandas as pd
8
+ from astropy import units as u
9
+ from astropy.coordinates import SkyCoord
10
+ from astropy.time import Time
11
+ from rubin_scheduler.utils import Site, _alt_az_pa_from_ra_dec, calc_lmst
12
+
13
+ import rubin_sim.maf.stackers as stackers
14
+ from rubin_sim.data import get_data_dir
15
+ from rubin_sim.maf import get_sim_data
16
+
17
+ try:
18
+ import lsst.summit.utils.efdUtils
19
+ except ModuleNotFoundError:
20
+ pass
21
+
22
+
23
+ class TestStackerClasses(unittest.TestCase):
24
+ def setUp(self):
25
+ # get some of the test data
26
+ test_db = os.path.join(get_data_dir(), "sim_baseline", "baseline.db")
27
+ query = "select * from observations limit 1000"
28
+ self.test_data = get_sim_data(test_db, None, [], full_sql_query=query)
29
+
30
+ def test_stackers_run(self):
31
+ """Just run all of the stackers with our example data."""
32
+ for stacker_class in stackers.BaseStacker.registry.values():
33
+ stacker = stacker_class()
34
+ stacker_name = stacker.__class__.__name__.lower()
35
+ if stacker_name.startswith("sdss"):
36
+ continue
37
+ if isinstance(stacker, stackers.BaseMoStacker):
38
+ continue
39
+ try:
40
+ stacker.run(self.test_data)
41
+ except NotImplementedError:
42
+ pass
43
+ except:
44
+ print(f"Failed at stacker {stacker.__class__.__name__}")
45
+ raise
46
+
47
+ def test_add_cols(self):
48
+ """Test that we can add columns as expected."""
49
+ data = np.zeros(90, dtype=list(zip(["alt"], [float])))
50
+ data["alt"] = np.arange(0, 90)
51
+ stacker = stackers.ZenithDistStacker(alt_col="alt", degrees=True)
52
+ newcol = stacker.cols_added[0]
53
+ # First - are the columns added if they are not there.
54
+ data, cols_present = stacker._add_stacker_cols(data)
55
+ self.assertEqual(cols_present, False)
56
+ self.assertIn(newcol, data.dtype.names)
57
+ # Next - if they are present, is that information passed back?
58
+ with warnings.catch_warnings():
59
+ warnings.simplefilter("ignore")
60
+ data, cols_present = stacker._add_stacker_cols(data)
61
+ self.assertEqual(cols_present, True)
62
+
63
+ def test_eq(self):
64
+ """
65
+ Test that stackers can be compared
66
+ """
67
+ s1 = stackers.ParallaxFactorStacker()
68
+ s2 = stackers.ParallaxFactorStacker()
69
+ assert s1 == s2
70
+
71
+ # Test if they have numpy array atributes
72
+ s1.ack = np.arange(10)
73
+ s2.ack = np.arange(10)
74
+ assert s1 == s2
75
+
76
+ # Change the array and test
77
+ s1.ack += 1
78
+ assert s1 != s2
79
+
80
+ s2 = stackers.NormAirmassStacker()
81
+ assert s1 != s2
82
+
83
+ def test_norm_airmass(self):
84
+ """
85
+ Test the normalized airmass stacker.
86
+ """
87
+ rng = np.random.RandomState(232)
88
+ data = np.zeros(600, dtype=list(zip(["airmass", "fieldDec"], [float, float])))
89
+ data["airmass"] = rng.random_sample(600)
90
+ data["fieldDec"] = rng.random_sample(600) * np.pi - np.pi / 2.0
91
+ data["fieldDec"] = np.degrees(data["fieldDec"])
92
+ stacker = stackers.NormAirmassStacker(degrees=True)
93
+ data = stacker.run(data)
94
+ for i in np.arange(data.size):
95
+ self.assertLessEqual(data["normairmass"][i], data["airmass"][i])
96
+ self.assertLess(np.min(data["normairmass"] - data["airmass"]), 0)
97
+
98
+ def test_parallax_factor(self):
99
+ """
100
+ Test the parallax factor.
101
+ """
102
+
103
+ data = np.zeros(
104
+ 600,
105
+ dtype=list(
106
+ zip(
107
+ ["fieldRA", "fieldDec", "observationStartMJD"],
108
+ [float, float, float],
109
+ )
110
+ ),
111
+ )
112
+ data["fieldRA"] = data["fieldRA"] + 0.1
113
+ data["fieldDec"] = data["fieldDec"] - 0.1
114
+ data["observationStartMJD"] = np.arange(data.size) + 49000.0
115
+ stacker = stackers.ParallaxFactorStacker(degrees=True)
116
+ data = stacker.run(data)
117
+ self.assertLess(max(np.abs(data["ra_pi_amp"])), 1.1)
118
+ self.assertLess(max(np.abs(data["dec_pi_amp"])), 1.1)
119
+ self.assertLess(np.max(data["ra_pi_amp"] ** 2 + data["dec_pi_amp"] ** 2), 1.1)
120
+ self.assertGreater(min(np.abs(data["ra_pi_amp"])), 0.0)
121
+ self.assertGreater(min(np.abs(data["dec_pi_amp"])), 0.0)
122
+
123
+ def _t_dither_range(self, diffsra, diffsdec, ra, dec, max_dither):
124
+ self.assertLessEqual(np.abs(diffsra).max(), max_dither)
125
+ self.assertLessEqual(np.abs(diffsdec).max(), max_dither)
126
+ offsets = np.sqrt(diffsra**2 + diffsdec**2)
127
+ self.assertLessEqual(offsets.max(), max_dither)
128
+ self.assertGreater(diffsra.max(), 0)
129
+ self.assertGreater(diffsdec.max(), 0)
130
+ self.assertLess(diffsra.min(), 0)
131
+ self.assertLess(diffsdec.min(), 0)
132
+
133
+ def _t_dither_per_night(self, diffsra, diffsdec, ra, dec, nights):
134
+ n = np.unique(nights)
135
+ for ni in n:
136
+ match = np.where(nights == ni)[0]
137
+ dra_on_night = np.abs(np.diff(diffsra[match]))
138
+ ddec_on_night = np.abs(np.diff(diffsdec[match]))
139
+ if dra_on_night.max() > 0.0005:
140
+ print(ni)
141
+ m = np.where(dra_on_night > 0.0005)[0]
142
+ print(diffsra[match][m])
143
+ print(ra[match][m])
144
+ print(dec[match][m])
145
+ print(dra_on_night[m])
146
+ self.assertAlmostEqual(dra_on_night.max(), 0)
147
+ self.assertAlmostEqual(ddec_on_night.max(), 0)
148
+
149
+ def test_ha_stacker(self):
150
+ """Test the Hour Angle stacker"""
151
+ data = np.zeros(100, dtype=list(zip(["observationStartLST", "fieldRA"], [float, float])))
152
+ data["observationStartLST"] = np.arange(100) / 99.0 * np.pi * 2
153
+ stacker = stackers.HourAngleStacker(degrees=True)
154
+ data = stacker.run(data)
155
+ # Check that data is always wrapped
156
+ self.assertLess(np.max(data["HA"]), 12.0)
157
+ self.assertGreater(np.min(data["HA"]), -12.0)
158
+ # Check that HA is zero if lst == RA
159
+ data = np.zeros(1, dtype=list(zip(["observationStartLST", "fieldRA"], [float, float])))
160
+ data = stacker.run(data)
161
+ self.assertEqual(data["HA"], 0.0)
162
+ data = np.zeros(1, dtype=list(zip(["observationStartLST", "fieldRA"], [float, float])))
163
+ data["observationStartLST"] = 20.0
164
+ data["fieldRA"] = 20.0
165
+ data = stacker.run(data)
166
+ self.assertEqual(data["HA"], 0.0)
167
+ # Check a value
168
+ data = np.zeros(1, dtype=list(zip(["observationStartLST", "fieldRA"], [float, float])))
169
+ data["observationStartLST"] = 0.0
170
+ data["fieldRA"] = np.degrees(np.pi / 2.0)
171
+ data = stacker.run(data)
172
+ np.testing.assert_almost_equal(data["HA"], -6.0)
173
+
174
+ def test_pa_stacker(self):
175
+ """Test the parallacticAngleStacker"""
176
+ data = np.zeros(
177
+ 100,
178
+ dtype=list(
179
+ zip(
180
+ [
181
+ "observationStartMJD",
182
+ "fieldDec",
183
+ "fieldRA",
184
+ "observationStartLST",
185
+ ],
186
+ [float] * 4,
187
+ )
188
+ ),
189
+ )
190
+ data["observationStartMJD"] = np.arange(100) * 0.2 + 50000
191
+ site = Site(name="LSST")
192
+ data["observationStartLST"] = calc_lmst(data["observationStartMJD"], site.longitude_rad)
193
+ data["observationStartLST"] = data["observationStartLST"] * 180.0 / 12.0
194
+ stacker = stackers.ParallacticAngleStacker(degrees=True)
195
+ data = stacker.run(data)
196
+ # Check values are in good range
197
+ assert data["PA"].max() <= 180
198
+ assert data["PA"].min() >= -180
199
+
200
+ # Check compared to the util
201
+ check_pa = []
202
+ ras = np.radians(data["fieldRA"])
203
+ decs = np.radians(data["fieldDec"])
204
+ for ra, dec, mjd in zip(ras, decs, data["observationStartMJD"]):
205
+ alt, az, pa = _alt_az_pa_from_ra_dec(ra, dec, mjd, site.longitude_rad, site.latitude_rad)
206
+
207
+ check_pa.append(pa)
208
+ check_pa = np.degrees(check_pa)
209
+
210
+ np.testing.assert_array_almost_equal(data["PA"], check_pa, decimal=0)
211
+
212
+ def test_galactic_stacker(self):
213
+ """
214
+ Test the galactic coordinate stacker
215
+ """
216
+ ra, dec = np.degrees(
217
+ np.meshgrid(np.arange(0, 2.0 * np.pi, 0.1), np.arange(-np.pi / 2, np.pi / 2, 0.1))
218
+ )
219
+ ra = np.ravel(ra)
220
+ dec = np.ravel(dec)
221
+ data = np.zeros(ra.size, dtype=list(zip(["ra", "dec"], [float] * 2)))
222
+ data["ra"] += ra
223
+ data["dec"] += dec
224
+ s = stackers.GalacticStacker(ra_col="ra", dec_col="dec")
225
+ new_data = s.run(data)
226
+ c = SkyCoord(ra=ra * u.deg, dec=dec * u.deg).transform_to("galactic")
227
+ expected_l, expected_b = c.l.rad, c.b.rad
228
+ np.testing.assert_array_equal(new_data["gall"], expected_l)
229
+ np.testing.assert_array_equal(new_data["galb"], expected_b)
230
+
231
+ # Check that we have all the quadrants populated
232
+ q1 = np.where((new_data["gall"] < np.pi) & (new_data["galb"] < 0.0))[0]
233
+ q2 = np.where((new_data["gall"] < np.pi) & (new_data["galb"] > 0.0))[0]
234
+ q3 = np.where((new_data["gall"] > np.pi) & (new_data["galb"] < 0.0))[0]
235
+ q4 = np.where((new_data["gall"] > np.pi) & (new_data["galb"] > 0.0))[0]
236
+ assert q1.size > 0
237
+ assert q2.size > 0
238
+ assert q3.size > 0
239
+ assert q4.size > 0
240
+
241
+ def test_ecliptic_stacker(self):
242
+ ra, dec = np.degrees(
243
+ np.meshgrid(np.arange(0, 2.0 * np.pi, 0.1), np.arange(-np.pi / 2, np.pi / 2, 0.1))
244
+ )
245
+ ra = np.ravel(ra)
246
+ dec = np.ravel(dec)
247
+ data = np.zeros(ra.size, dtype=list(zip(["ra", "dec"], [float] * 2)))
248
+ data["ra"] += ra
249
+ data["dec"] += dec
250
+ s = stackers.EclipticStacker(ra_col="ra", dec_col="dec", degrees=True)
251
+ _ = s.run(data)
252
+
253
+ data = np.zeros(ra.size, dtype=list(zip(["ra", "dec"], [float] * 2)))
254
+ data["ra"] += ra
255
+ data["dec"] += dec
256
+ s = stackers.EclipticStacker(ra_col="ra", dec_col="dec", degrees=True, subtract_sun_lon=False)
257
+ _ = s.run(data)
258
+
259
+ def test_healpix_stacker(self):
260
+ ra, dec = np.degrees(
261
+ np.meshgrid(np.arange(0, 2.0 * np.pi, 0.1), np.arange(-np.pi / 2, np.pi / 2, 0.1))
262
+ )
263
+ ra = np.ravel(ra)
264
+ dec = np.ravel(dec)
265
+ data = np.zeros(ra.size, dtype=list(zip(["ra", "dec"], [float] * 2)))
266
+ data["ra"] += ra
267
+ data["dec"] += dec
268
+ s = stackers.HealpixStacker(ra_col="ra", dec_col="dec")
269
+ _ = s.run(data)
270
+
271
+ def test_teff_stacker(self):
272
+ rng = np.random.default_rng(seed=6563)
273
+ num_points = 5
274
+ data = np.zeros(
275
+ num_points,
276
+ dtype=list(zip(["fiveSigmaDepth", "band", "visitExposureTime"], [float, (np.str_, 1), float])),
277
+ )
278
+ data["fiveSigmaDepth"] = 23 + rng.random(num_points)
279
+ data["band"] = ["g"] * num_points
280
+ data["visitExposureTime"] = [30] * num_points
281
+
282
+ stacker = stackers.TeffStacker("fiveSigmaDepth", "band", "visitExposureTime")
283
+ value = stacker.run(data)
284
+ np.testing.assert_array_equal(value["fiveSigmaDepth"], value["fiveSigmaDepth"])
285
+ assert np.all(0.1 < value["t_eff"]) and np.all(value["t_eff"] < 10)
286
+
287
+ def test_observation_start_datetime64_stacker(self):
288
+ rng = np.random.default_rng(seed=6563)
289
+ num_points = 5
290
+ data = np.zeros(
291
+ num_points,
292
+ dtype=list(zip(["observationStartMJD"], [float])),
293
+ )
294
+ data["observationStartMJD"] = 61000 + 3000 * rng.random(num_points)
295
+
296
+ stacker = stackers.ObservationStartDatetime64Stacker("observationStartMJD")
297
+ value = stacker.run(data)
298
+ recovered_mjd = Time(value["observationStartDatetime64"], format="datetime64").mjd
299
+ assert np.allclose(recovered_mjd, data["observationStartMJD"])
300
+
301
+ def test_observation_start_timestamp_stacker(self):
302
+ rng = np.random.default_rng(seed=6563)
303
+ num_points = 5
304
+
305
+ data = pd.DataFrame(
306
+ {"id": np.arange(num_points), "observationStartMJD": 61000 + 3000 * rng.random(num_points)}
307
+ )
308
+
309
+ stacker = stackers.ObservationStartTimestampStacker("observationStartMJD")
310
+ value = stacker.run(data)
311
+ np.testing.assert_almost_equal(
312
+ data.observationStartMJD, Time(data.start_timestamp.dt.to_pydatetime()).mjd
313
+ )
314
+ assert value.start_timestamp.dtype == "datetime64[ns, UTC]"
315
+ assert isinstance(value.start_timestamp[0], pd.Timestamp)
316
+
317
+ data = pd.DataFrame(
318
+ {"id": np.arange(num_points), "observationStartMJD": 61000 + 3000 * rng.random(num_points)}
319
+ ).to_records(index=False)
320
+ stacker = stackers.ObservationStartTimestampStacker("observationStartMJD")
321
+ raw_value = stacker.run(data)
322
+ value = pd.DataFrame(raw_value)
323
+ np.testing.assert_almost_equal(
324
+ data["observationStartMJD"], Time(value.start_timestamp.dt.to_pydatetime()).mjd
325
+ )
326
+ assert value.start_timestamp.dtype == "datetime64[ns, UTC]"
327
+ assert isinstance(value.start_timestamp[0], pd.Timestamp)
328
+
329
+ data = {"id": np.arange(num_points), "observationStartMJD": 61000 + 3000 * rng.random(num_points)}
330
+ stacker = stackers.ObservationStartTimestampStacker("observationStartMJD")
331
+ raw_value = stacker.run(data)
332
+ value = pd.DataFrame(raw_value)
333
+ np.testing.assert_almost_equal(
334
+ data["observationStartMJD"], Time(value.start_timestamp.dt.to_pydatetime()).mjd
335
+ )
336
+ assert value.start_timestamp.dtype == "datetime64[ns, UTC]"
337
+ assert isinstance(value.start_timestamp[0], pd.Timestamp)
338
+
339
+ def test_day_obs_stackers(self):
340
+ rng = np.random.default_rng(seed=6563)
341
+ num_points = 5
342
+ obs_start_mjds = 61000 + 3000 * rng.random(num_points)
343
+
344
+ data = np.zeros(
345
+ num_points,
346
+ dtype=list(zip(["observationStartMJD"], [float])),
347
+ )
348
+ data["observationStartMJD"] = obs_start_mjds
349
+
350
+ try:
351
+ summit_get_day_obs = lsst.summit.utils.efdUtils.getDayObsForTime
352
+ except NameError:
353
+ summit_get_day_obs = None
354
+
355
+ day_obs_int_stacker = stackers.DayObsStacker("observationStartMJD")
356
+ day_obs_int = day_obs_int_stacker.run(data)
357
+ assert np.all(day_obs_int["dayObs"] > 20200000)
358
+ assert np.all(day_obs_int["dayObs"] < 20500000)
359
+ if summit_get_day_obs is not None:
360
+ summit_day_obs_int = np.array([summit_get_day_obs(Time(m, format="mjd")) for m in obs_start_mjds])
361
+ np.testing.assert_array_equal(day_obs_int["dayObs"], summit_day_obs_int)
362
+
363
+ day_obs_mjd_stacker = stackers.DayObsMJDStacker("observationStartMJD")
364
+ new_data = day_obs_mjd_stacker.run(data)
365
+ # If there were no offset, all values would be between 0 and 1.
366
+ # With the 0.5 day offset specified in SITCOMTN-32, this becomes
367
+ # 0.5 and 1.5.
368
+ assert np.all((obs_start_mjds - new_data["day_obs_mjd"]) <= 1.5)
369
+ assert np.all((obs_start_mjds - new_data["day_obs_mjd"]) >= 0.5)
370
+
371
+ day_obs_iso_stacker = stackers.DayObsISOStacker("observationStartMJD")
372
+ _ = day_obs_iso_stacker.run(data)
373
+
374
+ def test_overhead_stacker(self):
375
+ num_visits = 10
376
+ num_first_night_visits = 5
377
+
378
+ start_mjd = 61000.2
379
+ exptime = 30.0
380
+
381
+ exposure_times = np.full(num_visits, exptime, dtype=float)
382
+
383
+ rng = np.random.default_rng(seed=6563)
384
+ overheads = 2.0 + rng.random(num_visits)
385
+
386
+ visit_times = overheads + exposure_times
387
+ observation_end_mjds = start_mjd + np.cumsum(visit_times) / (24 * 60 * 60)
388
+ mjds = observation_end_mjds - visit_times / (24 * 60 * 60)
389
+ mjds[num_first_night_visits:] += 1
390
+ names = ["observationStartMJD", "visitExposureTime", "visitTime"]
391
+ types = [float] * 3
392
+ data = np.zeros(mjds.size, dtype=list(zip(names, types)))
393
+ data["observationStartMJD"] = mjds
394
+ data["visitExposureTime"] = exposure_times
395
+ data["visitTime"] = visit_times
396
+
397
+ overhead_stacker = stackers.OverheadStacker()
398
+ new_data = overhead_stacker.run(data)
399
+ measured_overhead = new_data["overhead"]
400
+
401
+ # There is no visit before the first, so the first overhead should be
402
+ # nan.
403
+ self.assertTrue(np.isnan(measured_overhead[0]))
404
+
405
+ # Test that the gap between nights is nan.
406
+ self.assertTrue(np.isnan(measured_overhead[num_first_night_visits]))
407
+
408
+ # Make sure there are no unexpected nans
409
+ self.assertEqual(np.count_nonzero(np.isnan(measured_overhead)), 2)
410
+
411
+ # Make sure all measured values are correct
412
+ these_gaps = ~np.isnan(measured_overhead)
413
+ self.assertTrue(np.allclose(measured_overhead[these_gaps], overheads[these_gaps]))
414
+
415
+ def testHelp(self):
416
+ # essentially, test that every stacker has cols_req and cols_added
417
+ with open(os.devnull, "w") as new_target:
418
+ sys.stdout = new_target
419
+ stackers.BaseStacker.help(doc=True)
420
+
421
+
422
+ if __name__ == "__main__":
423
+ unittest.main()
@@ -0,0 +1,50 @@
1
+ import unittest
2
+
3
+ import numpy as np
4
+
5
+ import rubin_sim.maf.utils as utils
6
+
7
+
8
+ class StellarMagsTest(unittest.TestCase):
9
+ """
10
+ Test the example stellar colors code
11
+ """
12
+
13
+ def test_sm(self):
14
+ keys = [
15
+ "O",
16
+ "B",
17
+ "A",
18
+ "F",
19
+ "G",
20
+ "K",
21
+ "M",
22
+ "HeWD_25200_80",
23
+ "WD_11000_85",
24
+ "WD_3000_85",
25
+ ]
26
+ filter_names = ["u", "g", "r", "i", "z", "y"]
27
+
28
+ # Check each type returns the correct format
29
+ for key in keys:
30
+ result = utils.stellar_mags(key)
31
+ for fn in filter_names:
32
+ self.assertIn(fn, result)
33
+ self.assertTrue(
34
+ (isinstance(result[fn], float)) | (isinstance(result[fn], np.float64)),
35
+ msg="result is neither a float nor a numpy float64",
36
+ )
37
+
38
+ # Check the exception gets raised
39
+ self.assertRaises(ValueError, utils.stellar_mags, "ack")
40
+
41
+ # Check the mags get fainter
42
+ for st in keys:
43
+ mags = utils.stellar_mags(st)
44
+ mags2 = utils.stellar_mags(st, rmag=20.0)
45
+ for key in mags:
46
+ self.assertLess(mags[key], mags2[key])
47
+
48
+
49
+ if __name__ == "__main__":
50
+ unittest.main()
@@ -0,0 +1,26 @@
1
+ import unittest
2
+
3
+ import numpy as np
4
+
5
+ import rubin_sim.maf.metrics as metrics
6
+
7
+
8
+ class TestStringCount(unittest.TestCase):
9
+ def testsc(self):
10
+ metric = metrics.StringCountMetric()
11
+ data = np.array(["a", "a", "b", "c", "", "", ""])
12
+ dt = np.dtype([("filter", np.str_, 1)])
13
+ data.dtype = dt
14
+ result = metric.run(data)
15
+ # Check that the metricValue is correct
16
+ expected_results = {"a": 2, "b": 1, "c": 1, "blank": 3}
17
+ for key in expected_results:
18
+ assert result[key] == expected_results[key]
19
+
20
+ # Check that the reduce functions got made and return expected result
21
+ for key in expected_results:
22
+ assert metric.reduce_funcs[key](result) == expected_results[key]
23
+
24
+
25
+ if __name__ == "__main__":
26
+ unittest.main()
@@ -0,0 +1,197 @@
1
+ # imports
2
+ import unittest
3
+
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+ import pandas as pd
7
+ from numpy.random import default_rng
8
+
9
+ from rubin_sim import maf
10
+
11
+ # constants
12
+
13
+ RANDOM_SEED = 6563
14
+
15
+ # exception classes
16
+
17
+ # interface functions
18
+
19
+ # classes
20
+
21
+
22
+ class TestSummaryPlots(unittest.TestCase):
23
+ num_runs = 11
24
+ num_metrics = 7
25
+
26
+ def setUp(self):
27
+ # Make tests reproducible
28
+ self.rng = default_rng(RANDOM_SEED)
29
+
30
+ self.runs = [f"run{i}" for i in range(self.num_runs)]
31
+ self.baseline = self.runs[0]
32
+
33
+ self.metrics = [f"metric{i}" for i in range(self.num_metrics)]
34
+ self.inverted_metrics = ["metric3", "metric5", "metric6"]
35
+ self.mag_metrics = ["metric1", "metric2", "metric6"]
36
+
37
+ self.metric_values = pd.DataFrame(
38
+ self.rng.normal(loc=3, scale=5, size=(self.num_runs, self.num_metrics)),
39
+ columns=self.metrics,
40
+ index=self.runs,
41
+ )
42
+ self.metric_values.columns.name = "metric"
43
+ self.metric_values.index.name = "run"
44
+
45
+ styles = ["-" for i in range(self.num_metrics)]
46
+
47
+ self.metric_subset = pd.DataFrame(
48
+ {"mag": False, "invert": False, "metric": self.metrics, "style": styles}
49
+ ).set_index("metric", drop=False)
50
+ self.metric_subset.loc[self.mag_metrics, "mag"] = True
51
+ self.metric_subset.loc[self.inverted_metrics, "invert"] = True
52
+ self.metric_subset.loc["metric3", "style"] = "b--"
53
+
54
+ def test_normalize_metric_summaries(self):
55
+ # Test standard normalization with one run
56
+ norm_values = maf.normalize_metric_summaries(self.baseline, self.metric_values, self.metric_subset)
57
+
58
+ ref_norm_values = _run_infos_norm_df(
59
+ self.metric_values,
60
+ self.baseline,
61
+ invert_cols=self.inverted_metrics,
62
+ mag_cols=self.mag_metrics,
63
+ )
64
+ np.testing.assert_allclose(norm_values.values, ref_norm_values.values)
65
+
66
+ # test normalizing against one run, as a list
67
+ norm_values = maf.normalize_metric_summaries([self.baseline], self.metric_values, self.metric_subset)
68
+ np.testing.assert_allclose(norm_values.values, ref_norm_values.values)
69
+
70
+ # test similar but pretend that self.baseline is two runs
71
+ norm_values = maf.normalize_metric_summaries(
72
+ [self.baseline, self.baseline], self.metric_values, self.metric_subset
73
+ )
74
+ np.testing.assert_allclose(norm_values.values, ref_norm_values.values)
75
+
76
+ # test similar but different runs
77
+ norm_values = maf.normalize_metric_summaries(
78
+ [self.runs[0], self.runs[1]], self.metric_values, self.metric_subset
79
+ )
80
+
81
+ def test_plot_run_metric(self):
82
+ fig, ax = maf.plot_run_metric(self.metric_values)
83
+
84
+ fig, ax = maf.plot_run_metric(
85
+ self.metric_values,
86
+ baseline_run=self.baseline,
87
+ metric_subset=self.metric_subset,
88
+ )
89
+
90
+ fig, ax = maf.plot_run_metric(
91
+ self.metric_values,
92
+ vertical_quantity="value",
93
+ horizontal_quantity="run",
94
+ )
95
+
96
+ fig, ax = maf.plot_run_metric(
97
+ self.metric_values,
98
+ vertical_quantity="value",
99
+ horizontal_quantity="metric",
100
+ )
101
+
102
+ run_label_map = {r: r + "foo" for r in self.runs}
103
+ fig, ax = maf.plot_run_metric(self.metric_values, run_label_map=run_label_map)
104
+
105
+ metric_label_map = {r: r + "foo" for r in self.metrics}
106
+ fig, ax = maf.plot_run_metric(self.metric_values, metric_label_map=metric_label_map)
107
+
108
+ fig, ax = maf.plot_run_metric(self.metric_values, cmap=plt.get_cmap("Set2"))
109
+
110
+ fig, ax = maf.plot_run_metric(self.metric_values, linestyles=["-", "--", ":"])
111
+
112
+ fig, ax = maf.plot_run_metric(self.metric_values, markers=["o", "v", "^", "<", ">", "8", "s"])
113
+
114
+ fig, ax = plt.subplots()
115
+ maf.plot_run_metric(self.metric_values, ax=ax)
116
+
117
+ def test_plot_run_metric_mesh(self):
118
+ fig, ax = maf.plot_run_metric_mesh(self.metric_values)
119
+
120
+ fig, ax = maf.plot_run_metric_mesh(
121
+ self.metric_values,
122
+ baseline_run=self.baseline,
123
+ metric_subset=self.metric_subset,
124
+ )
125
+
126
+ fig, ax = maf.plot_run_metric_mesh(
127
+ self.metric_values,
128
+ baseline_run=self.baseline,
129
+ )
130
+
131
+ fig, ax = maf.plot_run_metric_mesh(self.metric_values, color_range=12)
132
+
133
+ run_label_map = {r: r + "foo" for r in self.runs}
134
+ fig, ax = maf.plot_run_metric_mesh(self.metric_values, run_label_map=run_label_map)
135
+
136
+ metric_label_map = {r: r + "foo" for r in self.metrics}
137
+ fig, ax = maf.plot_run_metric_mesh(self.metric_values, metric_label_map=metric_label_map)
138
+
139
+ fig, ax = maf.plot_run_metric_mesh(self.metric_values, cmap=plt.get_cmap("Spectral"))
140
+
141
+ fig, ax = plt.subplots()
142
+ maf.plot_run_metric_mesh(self.metric_values, ax=ax)
143
+
144
+
145
+ # internal functions & classes
146
+
147
+
148
+ def _run_infos_norm_df(df, norm_run, invert_cols=None, mag_cols=None):
149
+ """
150
+ Normalize values in a DataFrame, based on the values in a given run.
151
+ Can normalize some columns (metric values) differently
152
+ (invert_cols, reverse_cols, mag_cols)
153
+ if those columns are specified; this lets the final normalized dataframe
154
+ 'look' the same way
155
+ in a plot (i.e. "up" is better (reverse_cols), they center on 1 (mag_cols),
156
+ and the magnitude scales as expected (invert_cols)).
157
+
158
+ Parameters
159
+ ----------
160
+ df : pd.DataFrame
161
+ The data frame containing the metric values to compare
162
+ norm_run: str
163
+ The name of the simulation to normalize to (typically family_baseline)
164
+ invert_cols: list
165
+ Columns (metric values) to convert to 1 / value
166
+ mag_cols: list
167
+ Columns (metrics values) to treat as magnitudes
168
+ (1 + (difference from norm_run))
169
+
170
+ Returns
171
+ -------
172
+ pd.DataFrame
173
+ Normalized data frame
174
+ """
175
+
176
+ # Copy the dataframe but drop the columns containing only strings
177
+ out_df = df.copy()
178
+ if invert_cols is None:
179
+ invert_cols = []
180
+ if mag_cols is None:
181
+ mag_cols = []
182
+ both_cols = [c for c in invert_cols if c in mag_cols]
183
+ invert_cols = [c for c in invert_cols if c not in both_cols]
184
+ mag_cols = [c for c in mag_cols if c not in both_cols]
185
+ out_df[mag_cols] = 1 + out_df[mag_cols] - out_df[mag_cols].loc[norm_run]
186
+ out_df[invert_cols] = 1 / out_df[invert_cols]
187
+ out_df[both_cols] = 1 - out_df[both_cols] + out_df[both_cols].loc[norm_run]
188
+ # which columns are strings?
189
+ string_cols = [c for c, t in zip(df.columns, df.dtypes) if t == "object"]
190
+ cols = [c for c in out_df.columns.values if not (c in mag_cols or c in string_cols)]
191
+ out_df[cols] = 1 + (out_df[cols] - out_df[cols].loc[norm_run]) / out_df[cols].loc[norm_run]
192
+ return out_df
193
+
194
+
195
+ run_tests_now = __name__ == "__main__"
196
+ if run_tests_now:
197
+ unittest.main()