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,271 @@
1
+ __all__ = (
2
+ "NChangesMetric",
3
+ "MinTimeBetweenStatesMetric",
4
+ "NStateChangesFasterThanMetric",
5
+ "MaxStateChangesWithinMetric",
6
+ "OpenShutterFractionMetric",
7
+ "BruteOSFMetric",
8
+ )
9
+
10
+ import numpy as np
11
+
12
+ from .base_metric import BaseMetric
13
+
14
+
15
+ class NChangesMetric(BaseMetric):
16
+ """Compute the number of times a column value changes.
17
+ (useful for filter changes in particular).
18
+ """
19
+
20
+ def __init__(self, col="band", order_by="observationStartMJD", **kwargs):
21
+ self.col = col
22
+ self.order_by = order_by
23
+ super(NChangesMetric, self).__init__(col=[col, order_by], units="#", **kwargs)
24
+
25
+ def run(self, data_slice, slice_point=None):
26
+ idxs = np.argsort(data_slice[self.order_by])
27
+ diff = data_slice[self.col][idxs][1:] != data_slice[self.col][idxs][:-1]
28
+ return np.size(np.where(diff)[0])
29
+
30
+
31
+ class MinTimeBetweenStatesMetric(BaseMetric):
32
+ """Compute the minimum time between changes of state in a column value.
33
+ (useful for calculating fastest time between filter changes in particular).
34
+ Returns delta time in minutes!
35
+
36
+ Parameters
37
+ ----------
38
+ change_col : `str`
39
+ Column that we are tracking changes in.
40
+ time_col : str
41
+ Column with the time of each visit
42
+ """
43
+
44
+ def __init__(
45
+ self,
46
+ change_col="band",
47
+ time_col="observationStartMJD",
48
+ metric_name=None,
49
+ **kwargs,
50
+ ):
51
+ self.change_col = change_col
52
+ self.time_col = time_col
53
+ if metric_name is None:
54
+ metric_name = "Minimum time between %s changes (minutes)" % (change_col)
55
+ super(MinTimeBetweenStatesMetric, self).__init__(
56
+ col=[change_col, time_col], metric_name=metric_name, units="", **kwargs
57
+ )
58
+
59
+ def run(self, data_slice, slice_point=None):
60
+ # Sort on time, to be sure we've got changes in the right order.
61
+ idxs = np.argsort(data_slice[self.time_col])
62
+ changes = data_slice[self.change_col][idxs][1:] != data_slice[self.change_col][idxs][:-1]
63
+ condition = np.where(changes)[0]
64
+ changetimes = data_slice[self.time_col][idxs][1:][condition]
65
+ prevchangetime = np.concatenate(
66
+ (
67
+ np.array([data_slice[self.time_col][idxs][0]]),
68
+ data_slice[self.time_col][idxs][1:][condition][:-1],
69
+ )
70
+ )
71
+ dtimes = changetimes - prevchangetime
72
+ dtimes *= 24 * 60
73
+ if dtimes.size == 0:
74
+ return self.badval
75
+ return dtimes.min()
76
+
77
+
78
+ class NStateChangesFasterThanMetric(BaseMetric):
79
+ """
80
+ Compute the number of changes of state that happen faster than 'cutoff'.
81
+ (useful for calculating time between filter changes in particular).
82
+
83
+ Parameters
84
+ ----------
85
+ change_col : `str`
86
+ Column that we are tracking changes in.
87
+ time_col : str
88
+ Column with the time of each visit
89
+ cutoff : `float`
90
+ The cutoff value for the time between changes (in minutes).
91
+ """
92
+
93
+ def __init__(
94
+ self,
95
+ change_col="band",
96
+ time_col="observationStartMJD",
97
+ metric_name=None,
98
+ cutoff=20,
99
+ **kwargs,
100
+ ):
101
+ if metric_name is None:
102
+ metric_name = "Number of %s changes faster than <%.1f minutes" % (
103
+ change_col,
104
+ cutoff,
105
+ )
106
+ self.change_col = change_col
107
+ self.time_col = time_col
108
+ # Convert cutoff from minutes to days.
109
+ self.cutoff = cutoff / 24.0 / 60.0
110
+ super(NStateChangesFasterThanMetric, self).__init__(
111
+ col=[change_col, time_col], metric_name=metric_name, units="#", **kwargs
112
+ )
113
+
114
+ def run(self, data_slice, slice_point=None):
115
+ # Sort on time, to be sure we've got changes in the right order.
116
+ idxs = np.argsort(data_slice[self.time_col])
117
+ changes = data_slice[self.change_col][idxs][1:] != data_slice[self.change_col][idxs][:-1]
118
+ condition = np.where(changes)[0]
119
+ changetimes = data_slice[self.time_col][idxs][1:][condition]
120
+ prevchangetime = np.concatenate(
121
+ (
122
+ np.array([data_slice[self.time_col][idxs][0]]),
123
+ data_slice[self.time_col][idxs][1:][condition][:-1],
124
+ )
125
+ )
126
+ dtimes = changetimes - prevchangetime
127
+ return np.where(dtimes < self.cutoff)[0].size
128
+
129
+
130
+ class MaxStateChangesWithinMetric(BaseMetric):
131
+ """Compute the maximum number of changes of state that occur
132
+ within a given timespan.
133
+ (useful for calculating time between filter changes in particular).
134
+
135
+ Parameters
136
+ ----------
137
+ change_col : `str`
138
+ Column that we are tracking changes in.
139
+ time_col : str
140
+ Column with the time of each visit
141
+ timespan : `float`
142
+ The timespan to count the number of changes within (in minutes).
143
+ """
144
+
145
+ def __init__(
146
+ self,
147
+ change_col="band",
148
+ time_col="observationStartMJD",
149
+ metric_name=None,
150
+ timespan=20,
151
+ **kwargs,
152
+ ):
153
+ if metric_name is None:
154
+ metric_name = "Max number of %s changes within %.1f minutes" % (
155
+ change_col,
156
+ timespan,
157
+ )
158
+ self.change_col = change_col
159
+ self.time_col = time_col
160
+ self.timespan = timespan / 24.0 / 60.0 # Convert timespan from minutes to days.
161
+ super(MaxStateChangesWithinMetric, self).__init__(
162
+ col=[change_col, time_col], metric_name=metric_name, units="#", **kwargs
163
+ )
164
+
165
+ def run(self, data_slice, slice_point=None):
166
+ # This operates slightly differently from the metrics above;
167
+ # those calculate only successive times between changes, but here
168
+ # we must calculate the actual times of each change.
169
+ # Check if there was only one observation (and return 0 if so).
170
+ if data_slice[self.change_col].size == 1:
171
+ return 0
172
+ # Sort on time, to be sure we've got changes in the right order.
173
+ idxs = np.argsort(data_slice[self.time_col])
174
+ changes = data_slice[self.change_col][idxs][:-1] != data_slice[self.change_col][idxs][1:]
175
+ condition = np.where(changes)[0]
176
+ changetimes = data_slice[self.time_col][idxs][1:][condition]
177
+ # If there are 0 filter changes ...
178
+ if changetimes.size == 0:
179
+ return 0
180
+ # Otherwise ..
181
+ ct_plus = changetimes + self.timespan
182
+ indx2 = np.searchsorted(changetimes, ct_plus, side="right")
183
+ indx1 = np.arange(changetimes.size)
184
+ nchanges = indx2 - indx1
185
+ return nchanges.max()
186
+
187
+
188
+ class OpenShutterFractionMetric(BaseMetric):
189
+ """Compute the fraction of time the shutter is open
190
+ compared to the total time spent observing.
191
+ """
192
+
193
+ def __init__(
194
+ self,
195
+ metric_name="OpenShutterFraction",
196
+ slew_time_col="slewTime",
197
+ exp_time_col="visitExposureTime",
198
+ visit_time_col="visitTime",
199
+ **kwargs,
200
+ ):
201
+ self.exp_time_col = exp_time_col
202
+ self.visit_time_col = visit_time_col
203
+ self.slew_time_col = slew_time_col
204
+ super(OpenShutterFractionMetric, self).__init__(
205
+ col=[self.exp_time_col, self.visit_time_col, self.slew_time_col],
206
+ metric_name=metric_name,
207
+ units="OpenShutter/TotalTime",
208
+ **kwargs,
209
+ )
210
+ self.comment = "Open shutter time (%s total) divided by total visit time " "(%s) + slewtime (%s)." % (
211
+ self.exp_time_col,
212
+ self.visit_time_col,
213
+ self.slew_time_col,
214
+ )
215
+
216
+ def run(self, data_slice, slice_point=None):
217
+ result = np.sum(data_slice[self.exp_time_col]) / np.sum(
218
+ data_slice[self.slew_time_col] + data_slice[self.visit_time_col]
219
+ )
220
+ return result
221
+
222
+
223
+ class BruteOSFMetric(BaseMetric):
224
+ """Assume I can't trust the slewtime or visittime colums.
225
+ This computes the fraction of time the shutter is open,
226
+ with no penalty for the first exposure after a long gap
227
+ (e.g., 1st exposure of the night).
228
+ Presumably, the telescope will need to focus, so there's not much a
229
+ scheduler could do to optimize keeping the shutter open after a closure.
230
+
231
+ Parameters
232
+ ----------
233
+ maxgap : `float`
234
+ The maximum gap between observations, in minutes.
235
+ Assume anything longer the dome has closed.
236
+ fudge : `float`
237
+ Fudge factor if a constant has to be added to the exposure time values.
238
+ This time (in seconds) is added to the exposure time.
239
+ exp_time_col : `str`
240
+ The name of the exposure time column. Assumed to be in seconds.
241
+ mjd_col : `str`
242
+ The name of the start of the exposures. Assumed to be in units of days.
243
+ """
244
+
245
+ def __init__(
246
+ self,
247
+ metric_name="BruteOSFMetric",
248
+ exp_time_col="visitExposureTime",
249
+ mjd_col="observationStartMJD",
250
+ maxgap=10.0,
251
+ fudge=0.0,
252
+ **kwargs,
253
+ ):
254
+ self.exp_time_col = exp_time_col
255
+ self.maxgap = maxgap / 60.0 / 24.0 # convert from min to days
256
+ self.mjd_col = mjd_col
257
+ self.fudge = fudge
258
+ super(BruteOSFMetric, self).__init__(
259
+ col=[self.exp_time_col, mjd_col],
260
+ metric_name=metric_name,
261
+ units="OpenShutter/TotalTime",
262
+ **kwargs,
263
+ )
264
+
265
+ def run(self, data_slice, slice_point=None):
266
+ times = np.sort(data_slice[self.mjd_col])
267
+ diff = np.diff(times)
268
+ good = np.where(diff < self.maxgap)
269
+ open_time = np.sum(diff[good]) * 24.0 * 3600.0
270
+ result = np.sum(data_slice[self.exp_time_col] + self.fudge) / float(open_time)
271
+ return result
@@ -0,0 +1,412 @@
1
+ __all__ = (
2
+ "GapsMetric",
3
+ "TgapsMetric",
4
+ "TgapsPercentMetric",
5
+ "NightgapsMetric",
6
+ "NVisitsPerNightMetric",
7
+ "CoaddM5PerNightMetric",
8
+ "MaxGapMetric",
9
+ "NightTimespanMetric",
10
+ )
11
+
12
+ import numpy as np
13
+ from scipy.stats import binned_statistic
14
+
15
+ from ..utils import coadd_m5
16
+ from .base_metric import BaseMetric
17
+
18
+
19
+ class GapsMetric(BaseMetric):
20
+ """Compute the number of times a gaps of a specified timescale
21
+ (+/- 1/2 timescale) is sampled.
22
+
23
+ Parameters
24
+ ----------
25
+ times_col : `str`, optional
26
+ The column name for the exposure times. Values assumed to be in days.
27
+ Default is 'observationStartMJD'.
28
+ time_scale : `float`, optional
29
+ Time scale to see how well it is sampled (hours).
30
+ For example, the default of 2 hours means
31
+ observations spaced anywhere between 1 and 3 hours apart
32
+ will count as a sample. Default 2 hours.
33
+ units : `str`, optional
34
+ Default units to use for plots, etc. Default is "N" (for number).
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ times_col="observationStartMJD",
40
+ time_scale=2.0,
41
+ units="N",
42
+ **kwargs,
43
+ ):
44
+ self.times_col = times_col
45
+ # Convert to days and divide by two so we bin at the Nyquist frequency
46
+ self.bin_size = (time_scale / 24.0) / 2.0
47
+ super().__init__(col=[self.times_col], metric_dtype="float", units=units, **kwargs)
48
+
49
+ def run(self, data_slice, slice_point=None):
50
+ if data_slice.size < 2:
51
+ return self.badval
52
+ times = np.sort(data_slice[self.times_col])
53
+ bins = np.arange(times.min() - self.bin_size, times.max() + self.bin_size, self.bin_size)
54
+ vals, _be = np.histogram(times, bins)
55
+ # Bins are at 1/2 desired timescale, so compare bin 0 to bin 2 to see
56
+ # if the timescale has been sampled.
57
+ mult = vals[2:] * vals[0:-2]
58
+ result = np.size(np.where(mult > 0)[0])
59
+
60
+ return result
61
+
62
+
63
+ class TgapsMetric(BaseMetric):
64
+ """Histogram the times of the gaps between observations.
65
+
66
+
67
+ Measure the gaps between observations. By default, only gaps
68
+ between neighboring visits are computed. If all_gaps is set to true,
69
+ all gaps are computed (i.e., if there are observations at 10, 20, 30
70
+ and 40 the default will return a histogram of [10,10,10] while
71
+ all_gaps returns a histogram of [10,10,10,20,20,30])
72
+
73
+ Parameters
74
+ ----------
75
+ times_col : `str`, optional
76
+ The column name for the exposure times. Values assumed to be in days.
77
+ Default observationStartMJD.
78
+ all_gaps : `bool`, optional
79
+ Histogram the gaps between all observations (True) or just successive
80
+ observations (False)?
81
+ Default is False.
82
+ If all gaps are used, this metric can become significantly slower.
83
+ bins : `np.ndarray`, optional
84
+ The bins to use for the histogram of time gaps
85
+ (in days, or same units as times_col).
86
+ Default values are bins from 0 to 2 hours, in 5 minute intervals.
87
+
88
+ Returns
89
+ -------
90
+ histogram : `np.ndarray`
91
+ Returns a histogram of the tgaps at each slice point;
92
+ these histograms can be combined and plotted using the
93
+ 'SummaryHistogram plotter'.
94
+ """
95
+
96
+ def __init__(
97
+ self,
98
+ times_col="observationStartMJD",
99
+ all_gaps=False,
100
+ bins=np.arange(0, 120.0, 5.0) / 60.0 / 24.0,
101
+ units="days",
102
+ **kwargs,
103
+ ):
104
+ # Pass the same bins to the plotter.
105
+ self.bins = bins
106
+ self.times_col = times_col
107
+ super().__init__(col=[self.times_col], metric_dtype="object", units=units, **kwargs)
108
+ self.all_gaps = all_gaps
109
+
110
+ def run(self, data_slice, slice_point=None):
111
+ if data_slice.size < 2:
112
+ return self.badval
113
+ times = np.sort(data_slice[self.times_col])
114
+ if self.all_gaps:
115
+ all_diffs = []
116
+ for i in np.arange(1, times.size, 1):
117
+ all_diffs.append((times - np.roll(times, i))[i:])
118
+ dts = np.concatenate(all_diffs)
119
+ else:
120
+ dts = np.diff(times)
121
+ result, bins = np.histogram(dts, self.bins)
122
+ return result
123
+
124
+
125
+ class TgapsPercentMetric(BaseMetric):
126
+ """Compute the fraction of the time gaps between observations that occur
127
+ in a given time range.
128
+
129
+ Measure the gaps between observations. By default, only gaps
130
+ between neighboring visits are computed. If all_gaps is set to true,
131
+ all gaps are computed (i.e., if there are observations at 10, 20, 30 and
132
+ 40 the default will compute the percent of gaps between
133
+ specified endpoints.
134
+
135
+ This is different from the TgapsMetric in that this only looks at
136
+ what percent of intervals fall into the specified range, rather than
137
+ histogramming the entire set of tgaps.
138
+
139
+ This metric has drawbacks in that the result is tied to the overall
140
+ number of tgaps (i.e. a result of 100 could still be worse than
141
+ a different simulation with a result of 50, in terms of how often a
142
+ particular Tgap is sampled).
143
+
144
+ Parameters
145
+ ----------
146
+ times_col : `str`, opt
147
+ The column name for the exposure times. Values assumed to be in days.
148
+ Default observationStartMJD.
149
+ all_gaps : `bool`, opt
150
+ Histogram the gaps between all observations (True) or
151
+ just successive observations (False)?
152
+ Default is False. If all gaps are used, this metric
153
+ can become significantly slower.
154
+ min_time : `float`, opt
155
+ Minimum time of gaps to include (days). Default 2/24 (2 hours).
156
+ max_time : `float`, opt
157
+ Max time of gaps to include (days). Default 14/24 (14 hours).
158
+
159
+ Returns
160
+ -------
161
+ percent : `float`
162
+ Returns a float percent of the CDF between cdfMinTime and cdfMaxTime -
163
+ (# of tgaps within min_time/max_time / # of all tgaps).
164
+ """
165
+
166
+ def __init__(
167
+ self,
168
+ times_col="observationStartMJD",
169
+ all_gaps=False,
170
+ min_time=2.0 / 24,
171
+ max_time=14.0 / 24,
172
+ units="percent",
173
+ **kwargs,
174
+ ):
175
+ self.times_col = times_col
176
+ assert min_time <= max_time
177
+ self.min_time = min_time
178
+ self.max_time = max_time
179
+ super().__init__(col=[self.times_col], metric_dtype="float", units=units, **kwargs)
180
+ self.all_gaps = all_gaps
181
+
182
+ def run(self, data_slice, slice_point=None):
183
+ if data_slice.size < 2:
184
+ return self.badval
185
+ times = np.sort(data_slice[self.times_col])
186
+ if self.all_gaps:
187
+ all_diffs = []
188
+ for i in np.arange(1, times.size, 1):
189
+ all_diffs.append((times - np.roll(times, i))[i:])
190
+ dts = np.concatenate(all_diffs)
191
+ else:
192
+ dts = np.diff(times)
193
+ n_in_window = np.sum((dts >= self.min_time) & (dts <= self.max_time))
194
+ return n_in_window / len(dts) * 100.0
195
+
196
+
197
+ class NightgapsMetric(BaseMetric):
198
+ """Histogram the number of nights between observations.
199
+
200
+
201
+ Measure the gaps between observations. By default, only gaps
202
+ between neighboring visits are computed. If all_gaps is set to true,
203
+ all gaps are computed (i.e., if there are observations at 10, 20, 30 and
204
+ 40 the default will
205
+ histogram [10,10,10] while all_gaps histograms [10,10,10,20,20,30])
206
+
207
+ Parameters
208
+ ----------
209
+ night_col : `str`, optional
210
+ The column name for the night of each observation.
211
+ Default 'night'.
212
+ all_gaps : `bool`, optional
213
+ Histogram the gaps between all observations (True) or just successive
214
+ observations (False)?
215
+ Default is False. If all gaps are used, this metric can become
216
+ significantly slower.
217
+ bins : `np.ndarray`, optional
218
+ The bins to use for the histogram of time gaps (in days, or same
219
+ units as timesCol).
220
+ Default values are bins from 0 to 10 days, in 1 day intervals.
221
+
222
+ Returns
223
+ -------
224
+ histogram : `np.ndarray`
225
+ Returns a histogram of the deltaT between nights at each slice point;
226
+ these histograms can be combined and plotted using the
227
+ 'SummaryHistogram plotter'.
228
+ """
229
+
230
+ def __init__(
231
+ self,
232
+ night_col="night",
233
+ all_gaps=False,
234
+ bins=np.arange(0, 10, 1),
235
+ units="nights",
236
+ **kwargs,
237
+ ):
238
+ # Pass the same bins to the plotter.
239
+ self.bins = bins
240
+ self.night_col = night_col
241
+ super().__init__(col=[self.night_col], metric_dtype="object", units=units, **kwargs)
242
+ self.all_gaps = all_gaps
243
+
244
+ def run(self, data_slice, slice_point=None):
245
+ if data_slice.size < 2:
246
+ return self.badval
247
+ nights = np.sort(np.unique(data_slice[self.night_col]))
248
+ if self.all_gaps:
249
+ all_diffs = []
250
+ for i in np.arange(1, nights.size, 1):
251
+ all_diffs.append((nights - np.roll(nights, i))[i:])
252
+ dnights = np.concatenate(all_diffs)
253
+ else:
254
+ dnights = np.diff(nights)
255
+ result, bins = np.histogram(dnights, self.bins)
256
+ return result
257
+
258
+
259
+ class NVisitsPerNightMetric(BaseMetric):
260
+ """Histogram the number of visits in each night.
261
+
262
+ Splits the visits by night, then histograms how many visits occur
263
+ in each night.
264
+
265
+ Parameters
266
+ ----------
267
+ night_col : `str`, optional
268
+ The column name for the night of each observation.
269
+ Default 'night'.
270
+ bins : `np.ndarray`, optional
271
+ The bins to use for the histogram of time gaps (in days, or same
272
+ units as timesCol).
273
+ Default values are bins from 0 to 5 visits, in steps of 1.
274
+
275
+ Returns
276
+ -------
277
+ histogram : `np.ndarray`
278
+ Returns a histogram of the number of visits per night at each
279
+ slice point; these histograms can be combined and plotted using the
280
+ 'SummaryHistogram plotter'.
281
+ """
282
+
283
+ def __init__(self, night_col="night", bins=np.arange(0, 10, 1), units="#", **kwargs):
284
+ # Pass the same bins to the plotter.
285
+ self.bins = bins
286
+ self.night_col = night_col
287
+ super().__init__(col=[self.night_col], metric_dtype="object", units=units, **kwargs)
288
+
289
+ def run(self, data_slice, slice_point=None):
290
+ n, counts = np.unique(data_slice[self.night_col], return_counts=True)
291
+ result, bins = np.histogram(counts, self.bins)
292
+ return result
293
+
294
+
295
+ class CoaddM5PerNightMetric(BaseMetric):
296
+ """Histogram the coadded depth of visits in each night.
297
+
298
+ Splits the visits by night, then histograms the coadded depth.
299
+
300
+ Parameters
301
+ ----------
302
+ night_col : `str`, optional
303
+ The column name for the night of each observation.
304
+ Default 'night'.
305
+ m5_col : `str`, optional
306
+ The column name for the five sigma depth of each observation.
307
+ bins : `np.ndarray`, (N,) optional
308
+ The bins to use for the histogram of magnitude values.
309
+
310
+ Returns
311
+ -------
312
+ histogram : `np.ndarray`
313
+ Returns a histogram of the coadded depth per night at each slice point;
314
+ these histograms can be combined and plotted using the
315
+ 'SummaryHistogram plotter'.
316
+ """
317
+
318
+ def __init__(
319
+ self, night_col="night", m5_col="fiveSigmaDepth", bins=np.arange(20, 25, 0.05), units="mag", **kwargs
320
+ ):
321
+ # Pass the same bins to the plotter.
322
+ self.night_col = night_col
323
+ self.m5_col = m5_col
324
+ self.bins = bins
325
+ super().__init__(col=[self.night_col, self.m5_col], metric_dtype="object", units=units, **kwargs)
326
+
327
+ def run(self, data_slice, slice_point=None):
328
+ m5_per_night, be, bn = binned_statistic(
329
+ data_slice[self.night_col],
330
+ data_slice[self.m5_col],
331
+ statistic=coadd_m5,
332
+ bins=np.arange(0, 3653, 1),
333
+ )
334
+ # Drop the nights with no observations (-inf)
335
+ m5_per_night = m5_per_night[np.where(m5_per_night > 0)]
336
+ result, bins = np.histogram(m5_per_night, self.bins)
337
+ return result
338
+
339
+
340
+ class MaxGapMetric(BaseMetric):
341
+ """Find the maximum gap (in days) in between successive observations.
342
+
343
+ Useful for making sure there is an image within the last year that
344
+ would make a good template image.
345
+
346
+ Parameters
347
+ ----------
348
+ mjd_col : `str`, opt
349
+ The column name of the night of each observation.
350
+
351
+ Returns
352
+ -------
353
+ maxGap : `float`
354
+ The maximum gap (in days) between visits.
355
+ """
356
+
357
+ def __init__(self, mjd_col="observationStartMJD", **kwargs):
358
+ self.mjd_col = mjd_col
359
+ units = "Days"
360
+ super(MaxGapMetric, self).__init__(col=[self.mjd_col], units=units, **kwargs)
361
+
362
+ def run(self, data_slice, slice_point=None):
363
+ gaps = np.diff(np.sort(data_slice[self.mjd_col]))
364
+ if np.size(gaps) > 0:
365
+ result = np.max(gaps)
366
+ else:
367
+ result = self.badval
368
+ return result
369
+
370
+
371
+ class NightTimespanMetric(BaseMetric):
372
+ """Calculate the maximum time span covered in each night,
373
+ report the `percentile` value of all timespans.
374
+
375
+ Parameters
376
+ ----------
377
+ percentile : `float`, opt
378
+ Percentile value to report. Default 75th percentile.
379
+ night_col : `str`, opt
380
+ Name of the night column. Default 'night'.
381
+ mjd_col : `str`, opt
382
+ Name of the MJD visit column. Default 'observationStartMJD'.
383
+ """
384
+
385
+ def __init__(self, percentile=75, night_col="night", mjd_col="observationStartMJD", **kwargs):
386
+ self.percentile = percentile
387
+ self.night_col = night_col
388
+ self.mjd_col = mjd_col
389
+ if "metric_name" in kwargs:
390
+ metric_name = kwargs["metric_name"]
391
+ del kwargs["metric_name"]
392
+ else:
393
+ metric_name = f"{percentile}th Percentile Intranight Timespan"
394
+ super().__init__(
395
+ col=[self.night_col, self.mjd_col],
396
+ units="minutes",
397
+ metric_name=metric_name,
398
+ **kwargs,
399
+ )
400
+
401
+ def run(self, data_slice, slice_point=None):
402
+ data = np.sort(data_slice, order=self.mjd_col)
403
+ unights, counts = np.unique(data[self.night_col], return_counts=True)
404
+ unights = unights[np.where(counts > 1)]
405
+ if len(unights) == 0:
406
+ result = self.badval
407
+ else:
408
+ nstart = np.searchsorted(data[self.night_col], unights, side="left")
409
+ nend = np.searchsorted(data[self.night_col], unights, side="right") - 1
410
+ tspans = (data[self.mjd_col][nend] - data[self.mjd_col][nstart]) * 24.0 * 60.0
411
+ result = np.percentile(tspans, self.percentile)
412
+ return result