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,162 @@
1
+ __all__ = ("BDParallaxMetric", "VolumeSumMetric")
2
+
3
+ import healpy as hp
4
+ import numpy as np
5
+ from scipy import interpolate
6
+
7
+ import rubin_sim.maf.utils as mafUtils
8
+
9
+ from .base_metric import BaseMetric
10
+
11
+
12
+ def bd_colors(spec_type):
13
+ """Returns dictionary of potential Brown Dwarf colors
14
+
15
+ Parameters
16
+ ----------
17
+ spec_type : `str`
18
+ The desired spetral type of the Brown Dwarf.
19
+
20
+ """
21
+ result = {}
22
+ result["L0"] = {"i": 16.00, "z": 14.52, "y": 13.58}
23
+ result["L1"] = {"i": 16.41, "z": 14.93, "y": 13.97}
24
+ result["L2"] = {"i": 16.73, "z": 15.30, "y": 14.33}
25
+ result["L3"] = ({"i": 17.4, "z": 15.88, "y": 14.89},)
26
+ result["L4"] = {"i": 18.35, "z": 16.68, "y": 15.66}
27
+ result["L5"] = {"i": 18.71, "z": 16.94, "y": 15.87}
28
+ result["L6"] = {"i": 19.27, "z": 17.35, "y": 16.27}
29
+ result["L7"] = {"i": 20.09, "z": 18.18, "y": 17.13}
30
+ result["L8"] = {"i": 20.38, "z": 18.10, "y": 17.04}
31
+ result["L9"] = {"i": 20.09, "z": 17.69, "y": 16.57}
32
+ result["T0"] = {"i": 20.22, "z": 17.98, "y": 16.77}
33
+ result["T1"] = {"i": 21.10, "z": 18.84, "y": 17.45}
34
+ result["T2"] = {"i": 21.97, "z": 18.26, "y": 16.75}
35
+ result["T3"] = {"i": 22.50, "z": 18.08, "y": 16.50}
36
+ result["T4"] = {"i": 22.50, "z": 18.02, "y": 16.32}
37
+ result["T5"] = {"i": 22.69, "z": 19.20, "y": 17.43}
38
+ result["T6"] = {"i": 23.00, "z": 19.82, "y": 18.06}
39
+ result["T7"] = {"z": 21.17, "y": 19.34}
40
+ result["T8"] = {"z": 21.52, "y": 19.75}
41
+ result["T9"] = {"z": 21.82, "y": 20.37}
42
+ return result[spec_type]
43
+
44
+
45
+ class BDParallaxMetric(BaseMetric):
46
+ """Calculate the distance to which one could reach a parallax SNR for a
47
+ given object
48
+
49
+ Modification of ParallaxMetric, illustrated in
50
+ https://github.com/jgizis/
51
+ LSST-BD-Cadence/blob/main/bd_allLT_baseline_17.ipynb
52
+
53
+ Uses columns ra_pi_amp and dec_pi_amp,
54
+ calculated by the ParallaxFactorStacker.
55
+
56
+ Parameters
57
+ ----------
58
+ metricName : `str`, opt
59
+ Default 'parallax'.
60
+ m5_col : `str`, opt
61
+ The default column name for m5 information in the input data.
62
+ Default fiveSigmaDepth.
63
+ filter_col : `str`, opt
64
+ The column name for the filter information. Default filter.
65
+ seeing_col : `str`, opt
66
+ The column name for the seeing information.
67
+ Since the astrometry errors are based on the physical
68
+ size of the PSF, this should be the FWHM of the physical psf.
69
+ Default seeingFwhmGeom.
70
+ mags : `dict` or None
71
+ The absolute magnitude of the object in question.
72
+ Keys of filter name, values in mags.
73
+ Defaults to an L7 spectral type if None.
74
+ distances : `np.array`, (N,)
75
+ Distances to try putting the object at (pc).
76
+ atm_err : `float`, opt
77
+ The expected centroiding error due to the atmosphere, in arcseconds.
78
+ Default 0.01.
79
+ badval : `float`, opt
80
+ The value to return when the metric value cannot be calculated.
81
+ Default 0.
82
+ """
83
+
84
+ def __init__(
85
+ self,
86
+ metric_name="bdParallax",
87
+ m5_col="fiveSigmaDepth",
88
+ filter_col="band",
89
+ seeing_col="seeingFwhmGeom",
90
+ badval=0,
91
+ mags=None,
92
+ parallax_snr=10.0,
93
+ distances=np.arange(10, 200, 10),
94
+ atm_err=0.01,
95
+ normalize=False,
96
+ **kwargs,
97
+ ):
98
+ cols = [m5_col, filter_col, seeing_col, "ra_pi_amp", "dec_pi_amp"]
99
+
100
+ units = "pc"
101
+ super().__init__(cols, metric_name=metric_name, units=units, badval=badval, **kwargs)
102
+ # set return types
103
+ self.m5_col = m5_col
104
+ self.seeing_col = seeing_col
105
+ self.filter_col = filter_col
106
+ self.distances = distances
107
+ self.mags = {}
108
+ distance_mod = 5.0 * np.log10(distances) - 5.0
109
+ if mags is None:
110
+ mags = bd_colors("L7")
111
+ for key in mags:
112
+ self.mags[key] = mags[key] + distance_mod
113
+ self.parallax_snr_goal = parallax_snr
114
+ self.atm_err = atm_err
115
+ self.filters = list(self.mags.keys())
116
+ self.parallaxes = 1000.0 / distances # mas
117
+
118
+ def _final_sigma(self, position_errors, ra_pi_amp, dec_pi_amp):
119
+ """Assume parallax in RA and DEC are fit independently, then combined.
120
+ All inputs assumed to be arcsec.
121
+ """
122
+ sigma_a = position_errors / ra_pi_amp
123
+ sigma_b = position_errors / dec_pi_amp
124
+ sigma_ra = np.sqrt(1.0 / np.sum(1.0 / sigma_a**2, axis=1))
125
+ sigma_dec = np.sqrt(1.0 / np.sum(1.0 / sigma_b**2, axis=1))
126
+ # Combine RA and Dec uncertainties, convert to mas
127
+ sigma = np.sqrt(1.0 / (1.0 / sigma_ra**2 + 1.0 / sigma_dec**2)) * 1e3
128
+ return sigma
129
+
130
+ def run(self, data_slice, slice_point=None):
131
+ snr = np.zeros((np.size(self.mags[self.filters[0]]), len(data_slice)), dtype="float")
132
+ # compute SNR for all observations
133
+ for filt in self.filters:
134
+ good = np.where(data_slice[self.filter_col] == filt)[0]
135
+ if np.size(good) > 0:
136
+ snr[:, good] = mafUtils.m52snr(
137
+ self.mags[str(filt)][:, np.newaxis], data_slice[self.m5_col][good]
138
+ )
139
+
140
+ position_errors = mafUtils.astrom_precision(data_slice[self.seeing_col], snr, self.atm_err)
141
+ # uncertainty in the parallax in mas
142
+ sigma = self._final_sigma(position_errors, data_slice["ra_pi_amp"], data_slice["dec_pi_amp"])
143
+ fitted_parallax_snr = self.parallaxes / sigma
144
+ result = self.badval
145
+ # Let's interpolate to the distance where we would get our target SNR
146
+ if np.max(fitted_parallax_snr) >= self.parallax_snr_goal:
147
+ f = interpolate.interp1d(fitted_parallax_snr, self.distances, fill_value="extrapolate")
148
+ result = f(self.parallax_snr_goal)
149
+ return result
150
+
151
+
152
+ class VolumeSumMetric(BaseMetric):
153
+ """Compute the total volume assuming a metric has values of distance."""
154
+
155
+ def __init__(self, col=None, metric_name="VolumeSum", nside=None, **kwargs):
156
+ super(VolumeSumMetric, self).__init__(col=col, metric_name=metric_name, **kwargs)
157
+ self.pix_area = hp.nside2pixarea(nside)
158
+
159
+ def run(self, data_slice, slice_point=None):
160
+ # volume of sphere, times ratio of pixel area divided by area of sphere
161
+ vols = 1.0 / 3.0 * data_slice[self.colname] ** 3 * self.pix_area
162
+ return np.sum(vols)
@@ -0,0 +1,400 @@
1
+ __all__ = (
2
+ "TemplateExistsMetric",
3
+ "UniformityMetric",
4
+ "GeneralUniformityMetric",
5
+ "RapidRevisitUniformityMetric",
6
+ "RapidRevisitMetric",
7
+ "NRevisitsMetric",
8
+ "IntraNightGapsMetric",
9
+ "InterNightGapsMetric",
10
+ "VisitGapMetric",
11
+ )
12
+
13
+ import numpy as np
14
+
15
+ from .base_metric import BaseMetric
16
+
17
+
18
+ class FSMetric(BaseMetric):
19
+ """Calculate the fS value (Nvisit-weighted delta(M5-M5srd))."""
20
+
21
+ def __init__(self, filter_col="band", metric_name="fS", **kwargs):
22
+ self.filter_col = filter_col
23
+ cols = [self.filter_col]
24
+ super().__init__(cols=cols, metric_name=metric_name, units="fS", **kwargs)
25
+
26
+ def run(self, data_slice, slice_point=None):
27
+ # We could import this from the m5_flat_sed values,
28
+ # but it makes sense to calculate the m5
29
+ # directly from the throughputs. This is easy enough to do and
30
+ # will allow variation of
31
+ # the throughput curves and readnoise and visit length, etc.
32
+ pass
33
+
34
+
35
+ class TemplateExistsMetric(BaseMetric):
36
+ """Calculate the fraction of images with a previous template
37
+ image of desired quality."""
38
+
39
+ def __init__(
40
+ self,
41
+ seeing_col="seeingFwhmGeom",
42
+ observation_start_mjd_col="observationStartMJD",
43
+ metric_name="TemplateExistsMetric",
44
+ **kwargs,
45
+ ):
46
+ cols = [seeing_col, observation_start_mjd_col]
47
+ super(TemplateExistsMetric, self).__init__(
48
+ col=cols, metric_name=metric_name, units="fraction", **kwargs
49
+ )
50
+ self.seeing_col = seeing_col
51
+ self.observation_start_mjd_col = observation_start_mjd_col
52
+
53
+ def run(self, data_slice, slice_point=None):
54
+ # Check that data is sorted in observationStartMJD order
55
+ data_slice.sort(order=self.observation_start_mjd_col)
56
+ # Find the minimum seeing up to a given time
57
+ seeing_mins = np.minimum.accumulate(data_slice[self.seeing_col])
58
+ # Find the difference between the seeing and the minimum seeing
59
+ # at the previous visit
60
+ seeing_diff = data_slice[self.seeing_col] - np.roll(seeing_mins, 1)
61
+ # First image never has a template; check how many others do
62
+ good = np.where(seeing_diff[1:] >= 0.0)[0]
63
+ frac = (good.size) / float(data_slice[self.seeing_col].size)
64
+ return frac
65
+
66
+
67
+ class UniformityMetric(BaseMetric):
68
+ """Calculate how uniformly the observations are spaced in time.
69
+
70
+ This is based on how a KS-test works:
71
+ look at the cumulative distribution of observation dates,
72
+ and compare to a perfectly uniform cumulative distribution.
73
+ Perfectly uniform observations = 0, perfectly non-uniform = 1.
74
+
75
+ Parameters
76
+ ----------
77
+ mjd_col : `str`, optional
78
+ The column containing time for each observation.
79
+ Default "observationStartMJD".
80
+ survey_length : `float`, optional
81
+ The overall duration of the survey. Default 10.
82
+ """
83
+
84
+ def __init__(self, mjd_col="observationStartMJD", units="", survey_length=10.0, **kwargs):
85
+ """survey_length = time span of survey (years)"""
86
+ self.mjd_col = mjd_col
87
+ super(UniformityMetric, self).__init__(col=self.mjd_col, units=units, **kwargs)
88
+ self.survey_length = survey_length
89
+
90
+ def run(self, data_slice, slice_point=None):
91
+ # If only one observation, there is no uniformity
92
+ if data_slice[self.mjd_col].size == 1:
93
+ return 1
94
+ # Scale dates to lie between 0 and 1,
95
+ # where 0 is the first observation date and 1 is surveyLength
96
+ dates = (data_slice[self.mjd_col] - data_slice[self.mjd_col].min()) / (self.survey_length * 365.25)
97
+ dates.sort() # Just to be sure
98
+ n_cum = np.arange(1, dates.size + 1) / float(dates.size)
99
+ d_max = np.max(np.abs(n_cum - dates - dates[1]))
100
+ return d_max
101
+
102
+
103
+ class GeneralUniformityMetric(BaseMetric):
104
+ """Calculate how uniformly any values are distributed.
105
+
106
+ This is based on how a KS-test works:
107
+ look at the cumulative distribution of data,
108
+ and compare to a perfectly uniform cumulative distribution.
109
+ Perfectly uniform observations = 0, perfectly non-uniform = 1.
110
+ To be "perfectly uniform" here, the endpoints need to be included.
111
+
112
+ Parameters
113
+ ----------
114
+ col : `str`, optional
115
+ The column of data to use for the metric.
116
+ The default is "observationStartMJD" as this is most
117
+ typically used with time.
118
+ min_value : `float`, optional
119
+ The minimum value expected for the data.
120
+ Default None will calculate use the minimum value in this dataslice
121
+ (which may not cover the full range).
122
+ max_value : `float`, optional
123
+ The maximum value expected for the data.
124
+ Default None will calculate use the maximum value in this dataslice
125
+ (which may not cover the full range).
126
+ """
127
+
128
+ def __init__(self, col="observationStartMJD", units="", min_value=None, max_value=None, **kwargs):
129
+ self.col = col
130
+ super().__init__(col=self.col, units=units, **kwargs)
131
+ self.min_value = min_value
132
+ self.max_value = max_value
133
+
134
+ def run(self, data_slice, slice_point=None):
135
+ # If only one observation, there is no uniformity
136
+ if data_slice[self.col].size == 1:
137
+ return 1
138
+ # Scale values to lie between 0 and 1,
139
+ # where 0 is the min_value and 1 is max_value
140
+ if self.min_value is None:
141
+ min_value = data_slice[self.col].min()
142
+ else:
143
+ min_value = self.min_value
144
+ if self.max_value is None:
145
+ max_value = data_slice[self.col].max()
146
+ else:
147
+ max_value = self.max_value
148
+ scaled_values = (data_slice[self.col] - min_value) / max_value
149
+ scaled_values.sort() # Just to be sure
150
+ n_cum = np.arange(0, scaled_values.size) / float(scaled_values.size - 1)
151
+ d_max = np.max(np.abs(n_cum - scaled_values))
152
+ return d_max
153
+
154
+
155
+ class RapidRevisitUniformityMetric(BaseMetric):
156
+ """Calculate uniformity of time between consecutive visits on
157
+ short timescales (for RAV1).
158
+
159
+ Uses the same 'uniformity' calculation as the UniformityMetric,
160
+ based on the KS-test.
161
+ A value of 0 is perfectly uniform; a value of 1 is purely non-uniform.
162
+
163
+ Parameters
164
+ ----------
165
+ mjd_col : `str`, optional
166
+ The column containing the 'time' value. Default observationStartMJD.
167
+ min_nvisits : `int`, optional
168
+ The minimum number of visits required within the
169
+ time interval (d_tmin to d_tmax).
170
+ Default 100.
171
+ d_tmin : `float`, optional
172
+ The minimum dTime to consider (in days). Default 40 seconds.
173
+ d_tmax : `float`, optional
174
+ The maximum dTime to consider (in days). Default 30 minutes.
175
+ """
176
+
177
+ def __init__(
178
+ self,
179
+ mjd_col="observationStartMJD",
180
+ min_nvisits=100,
181
+ d_tmin=40.0 / 60.0 / 60.0 / 24.0,
182
+ d_tmax=30.0 / 60.0 / 24.0,
183
+ metric_name="RapidRevisitUniformity",
184
+ **kwargs,
185
+ ):
186
+ self.mjd_col = mjd_col
187
+ self.min_nvisits = min_nvisits
188
+ self.d_tmin = d_tmin
189
+ self.d_tmax = d_tmax
190
+ super().__init__(col=self.mjd_col, metric_name=metric_name, **kwargs)
191
+ # Update min_nvisits, as 0 visits will crash algorithm
192
+ # and 1 is nonuniform by definition.
193
+ if self.min_nvisits <= 1:
194
+ self.min_nvisits = 2
195
+
196
+ def run(self, data_slice, slice_point=None):
197
+ # Calculate consecutive visit time intervals
198
+ dtimes = np.diff(np.sort(data_slice[self.mjd_col]))
199
+ # Identify dtimes within interval from dTmin/dTmax.
200
+ good = np.where((dtimes >= self.d_tmin) & (dtimes <= self.d_tmax))[0]
201
+ # If there are not enough visits in this time range, return bad value.
202
+ if good.size < self.min_nvisits:
203
+ return self.badval
204
+ # Throw out dtimes outside desired range, and sort, then scale to 0-1.
205
+ dtimes = np.sort(dtimes[good])
206
+ dtimes = (dtimes - dtimes.min()) / float(self.d_tmax - self.d_tmin)
207
+ # Set up a uniform distribution between 0-1 (to match dtimes).
208
+ uniform_dtimes = np.arange(1, dtimes.size + 1, 1) / float(dtimes.size)
209
+ # Look at the differences between our times and the uniform times.
210
+ dmax = np.max(np.abs(uniform_dtimes - dtimes - dtimes[1]))
211
+ return dmax
212
+
213
+
214
+ class RapidRevisitMetric(BaseMetric):
215
+ def __init__(
216
+ self,
217
+ mjd_col="observationStartMJD",
218
+ metric_name="RapidRevisit",
219
+ d_tmin=40.0 / 60.0 / 60.0 / 24.0,
220
+ d_tpairs=20.0 / 60.0 / 24.0,
221
+ d_tmax=30.0 / 60.0 / 24.0,
222
+ min_n1=28,
223
+ min_n2=82,
224
+ **kwargs,
225
+ ):
226
+ self.mjd_col = mjd_col
227
+ self.d_tmin = d_tmin
228
+ self.d_tpairs = d_tpairs
229
+ self.d_tmax = d_tmax
230
+ self.min_n1 = min_n1
231
+ self.min_n2 = min_n2
232
+ super().__init__(col=self.mjd_col, metric_name=metric_name, **kwargs)
233
+
234
+ def run(self, data_slice, slice_point=None):
235
+ dtimes = np.diff(np.sort(data_slice[self.mjd_col]))
236
+ n1 = len(np.where((dtimes >= self.d_tmin) & (dtimes <= self.d_tpairs))[0])
237
+ n2 = len(np.where((dtimes >= self.d_tmin) & (dtimes <= self.d_tmax))[0])
238
+ if (n1 >= self.min_n1) and (n2 >= self.min_n2):
239
+ val = 1
240
+ else:
241
+ val = 0
242
+ return val
243
+
244
+
245
+ class NRevisitsMetric(BaseMetric):
246
+ """Calculate the number of consecutive visits with
247
+ time differences less than d_t.
248
+
249
+ Parameters
250
+ ----------
251
+ d_t : `float`, optional
252
+ The time interval to consider (in minutes). Default 30.
253
+ normed : `bool`, optional
254
+ Flag to indicate whether to return the total number of
255
+ consecutive visits with time differences less than d_t (False),
256
+ or the fraction of overall visits (True).
257
+ Note that we would expect (if all visits occur in pairs within d_t)
258
+ this fraction would be 0.5!
259
+ """
260
+
261
+ def __init__(self, mjd_col="observationStartMJD", d_t=30.0, normed=False, metric_name=None, **kwargs):
262
+ units = ""
263
+ if metric_name is None:
264
+ if normed:
265
+ metric_name = "Fraction of revisits faster than %.1f minutes" % (d_t)
266
+ else:
267
+ metric_name = "Number of revisits faster than %.1f minutes" % (d_t)
268
+ units = "#"
269
+ self.mjd_col = mjd_col
270
+ self.d_t = d_t / 60.0 / 24.0 # convert to days
271
+ self.normed = normed
272
+ super(NRevisitsMetric, self).__init__(
273
+ col=self.mjd_col, units=units, metric_name=metric_name, **kwargs
274
+ )
275
+
276
+ def run(self, data_slice, slice_point=None):
277
+ dtimes = np.diff(np.sort(data_slice[self.mjd_col]))
278
+ n_fast_revisits = np.size(np.where(dtimes <= self.d_t)[0])
279
+ if self.normed:
280
+ n_fast_revisits = n_fast_revisits / float(np.size(data_slice[self.mjd_col]))
281
+ return n_fast_revisits
282
+
283
+
284
+ class IntraNightGapsMetric(BaseMetric):
285
+ """
286
+ Calculate the (reduce_func) of the gap between consecutive
287
+ observations within a night, in hours.
288
+
289
+ Parameters
290
+ ----------
291
+ reduce_func : function, optional
292
+ Function that can operate on array-like structures.
293
+ Typically numpy function.
294
+ Default np.median.
295
+ """
296
+
297
+ def __init__(
298
+ self,
299
+ mjd_col="observationStartMJD",
300
+ night_col="night",
301
+ reduce_func=np.median,
302
+ metric_name="Median Intra-Night Gap",
303
+ **kwargs,
304
+ ):
305
+ units = "hours"
306
+ self.mjd_col = mjd_col
307
+ self.night_col = night_col
308
+ self.reduce_func = reduce_func
309
+ super(IntraNightGapsMetric, self).__init__(
310
+ col=[self.mjd_col, self.night_col], units=units, metric_name=metric_name, **kwargs
311
+ )
312
+
313
+ def run(self, data_slice, slice_point=None):
314
+ data_slice.sort(order=self.mjd_col)
315
+ dt = np.diff(data_slice[self.mjd_col])
316
+ dn = np.diff(data_slice[self.night_col])
317
+
318
+ good = np.where(dn == 0)
319
+ if np.size(good[0]) == 0:
320
+ result = self.badval
321
+ else:
322
+ result = self.reduce_func(dt[good]) * 24
323
+ return result
324
+
325
+
326
+ class InterNightGapsMetric(BaseMetric):
327
+ """Calculate the (reduce_func) of the gap between consecutive
328
+ observations in different nights, in days.
329
+
330
+ Parameters
331
+ ----------
332
+ reduce_func : function, optional
333
+ Function that can operate on array-like structures.
334
+ Typically numpy function.
335
+ Default np.median.
336
+ """
337
+
338
+ def __init__(
339
+ self,
340
+ mjd_col="observationStartMJD",
341
+ night_col="night",
342
+ reduce_func=np.median,
343
+ metric_name="Median Inter-Night Gap",
344
+ **kwargs,
345
+ ):
346
+ units = "days"
347
+ self.mjd_col = mjd_col
348
+ self.night_col = night_col
349
+ self.reduce_func = reduce_func
350
+ super().__init__(col=[self.mjd_col, self.night_col], units=units, metric_name=metric_name, **kwargs)
351
+
352
+ def run(self, data_slice, slice_point=None):
353
+ data_slice.sort(order=self.mjd_col)
354
+ unights = np.unique(data_slice[self.night_col])
355
+ if np.size(unights) < 2:
356
+ result = self.badval
357
+ else:
358
+ # Find the first and last observation of each night
359
+ first_of_night = np.searchsorted(data_slice[self.night_col], unights)
360
+ last_of_night = np.searchsorted(data_slice[self.night_col], unights, side="right") - 1
361
+ diff = data_slice[self.mjd_col][first_of_night[1:]] - data_slice[self.mjd_col][last_of_night[:-1]]
362
+ result = self.reduce_func(diff)
363
+ return result
364
+
365
+
366
+ class VisitGapMetric(BaseMetric):
367
+ """Calculate the (reduce_func) of the gap between any
368
+ consecutive observations, in hours, regardless of night boundaries.
369
+
370
+ Different from inter-night and intra-night gaps,
371
+ because this is really just counting all of the times between consecutive
372
+ observations (not time between nights or time within a night).
373
+
374
+ Parameters
375
+ ----------
376
+ reduce_func : function, optional
377
+ Function that can operate on array-like structures.
378
+ Typically numpy function.
379
+ Default np.median.
380
+ """
381
+
382
+ def __init__(
383
+ self,
384
+ mjd_col="observationStartMJD",
385
+ night_col="night",
386
+ reduce_func=np.median,
387
+ metric_name="VisitGap",
388
+ **kwargs,
389
+ ):
390
+ units = "hours"
391
+ self.mjd_col = mjd_col
392
+ self.night_col = night_col
393
+ self.reduce_func = reduce_func
394
+ super().__init__(col=[self.mjd_col, self.night_col], units=units, metric_name=metric_name, **kwargs)
395
+
396
+ def run(self, data_slice, slice_point=None):
397
+ data_slice.sort(order=self.mjd_col)
398
+ diff = np.diff(data_slice[self.mjd_col])
399
+ result = self.reduce_func(diff) * 24.0
400
+ return result