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,652 @@
1
+ # Transient metric with input ascii SED.
2
+ # Builds upon and uses a significant amount of common code from the
3
+ # transientAsciiMetric by: fbb@nyu.edu, svalenti@lcogt.net
4
+ # Apart from the inherent differences between metrics, the code has changed in
5
+ # that many of the variable names have been changed for clarity, at the expense
6
+ # of brevity.
7
+ #
8
+ # Contact for this code:
9
+ # christian.setzer@fysik.su.se
10
+
11
+ __all__ = ("TransientAsciiSEDMetric",)
12
+
13
+ import os
14
+ from copy import deepcopy
15
+
16
+ import numpy as np
17
+
18
+ try:
19
+ from sncosmo import Model, TimeSeriesSource, read_griddata_ascii
20
+ except ImportError:
21
+ pass
22
+ from astropy.cosmology import Planck15 as cosmo # noqa N813
23
+
24
+ from rubin_sim.maf.metrics import BaseMetric
25
+ from rubin_sim.maf.utils import m52snr
26
+
27
+
28
+ class TransientAsciiSEDMetric(BaseMetric):
29
+ """
30
+ Based on the transientMetric and transientAsciiMetric, uses an ascii
31
+ input file and provides option to write out the light curves. Calculates
32
+ what fraction of the transients would be detected. A spatial slicer is the
33
+ preferred choice. The input SED should have the 3-column format
34
+ (phase, wave, flux), and be scaled to a distance of 10pc from the observer.
35
+
36
+ Parameters
37
+ -----------
38
+ ascii_file : `str`
39
+ The ascii file containing the inputs for the SED. The file must
40
+ contain three columns - ['phase', 'wave', 'flux'] -
41
+ of phase/epoch (in days), wavelength (Angstroms), and
42
+ flux (ergs/s/Angstrom).
43
+ metric_name : `str`, optional
44
+ Name of the metric, can be overwritten by user or child metric.
45
+ survey_duration : `float`, optional
46
+ Length of survey (years).
47
+ Default 10 or maximum of timespan of observations.
48
+ survey_start : `float`, optional
49
+ MJD for the survey start date.
50
+ Default None (uses the time of the first observation at each pointing).
51
+ detect_snr : `dict`, optional
52
+ An observation will be counted toward the discovery criteria if the
53
+ light curve SNR is higher than detect_snr (specified per bandpass).
54
+ Values must be provided for each filter which should be considered
55
+ in the lightcurve.
56
+ Default is {'u': 5, 'g': 5, 'r': 5, 'i': 5, 'z': 5, 'y': 5}
57
+ z : `float`, optional
58
+ Cosmological redshift at which to consider observations of the
59
+ tranisent SED.
60
+ num_pre_time : `int`, optional
61
+ Number of observations (in any filter(s)) to demand before pre_time,
62
+ before saying a transient has been detected.
63
+ Default 0.
64
+ pre_time : `float`, optional
65
+ The time by which num_pre_time detections are required (in days).
66
+ Default 5.0.
67
+ num_filters : `int`, optional
68
+ Number of filters that need to be observed for an object to be
69
+ counted as detected. Default 1. (if num_per_lightcurve is 0, then
70
+ this will be reset to 0).
71
+ filter_time : `float`, optional
72
+ The time within which observations in at least num_filters are
73
+ required (in days). Default None (no time constraint).
74
+ num_per_lightcurve : `int`, optional
75
+ Number of sections of the light curve that must be sampled above
76
+ the detect_snr theshold for the light curve to be counted.
77
+ For example, num_per_lightcurve = 2 means a light curve is only
78
+ considered detected if there is at least 1 observation in the first
79
+ half of the LC, and at least one in the second half of the LC.
80
+ num_per_lightcurve = 4 means each quarter of the light curve must
81
+ be detected to count. Default 1.
82
+ num_phases_to_run : `int`, optional
83
+ Sets the number of phases that should be checked.
84
+ One can imagine pathological cadences where many objects pass the
85
+ detection criteria, but would not if the observations were offset
86
+ by a phase-shift. Default 1.
87
+ output_data : `bool`, optional
88
+ If True, metric returns full lightcurve at each point. Note that
89
+ this will potentially create a very large metric output data file.
90
+ If False, metric returns the number of transients detected.
91
+ """
92
+
93
+ def __init__(
94
+ self,
95
+ ascii_file,
96
+ metric_name="TransientAsciiSEDMetric",
97
+ mjd_col="expMJD",
98
+ m5_col="fiveSigmaDepth",
99
+ filter_col="filter",
100
+ survey_duration=10.0,
101
+ survey_start=None,
102
+ detect_snr={"u": 5, "g": 5, "r": 5, "i": 5, "z": 5, "y": 5},
103
+ z=0.075,
104
+ num_pre_time=2,
105
+ pre_time=25.0,
106
+ num_filters=2,
107
+ filter_time=None,
108
+ num_per_lightcurve=1,
109
+ num_phases_to_run=5,
110
+ output_data=False,
111
+ **kwargs,
112
+ ):
113
+ # Set all initial attributes of the metric.
114
+ self.mjd_col = mjd_col
115
+ self.m5_col = m5_col
116
+ self.filter_col = filter_col
117
+ self.output_data = output_data
118
+ self.z = z
119
+
120
+ # If it is specified that the lightcurves should be returned rather
121
+ # than the summary statistics, this changes the output of the metric,
122
+ # and thus needs an alternate definition of the output type and units
123
+ # when calling the init of the base class.
124
+ if self.output_data:
125
+ super_dict = {"units": "", "metricDtype": "object"}
126
+ else:
127
+ super_dict = {"units": "Number Detected"}
128
+
129
+ super(TransientAsciiSEDMetric, self).__init__(
130
+ col=[self.mjd_col, self.m5_col, self.filter_col],
131
+ metric_name=metric_name,
132
+ **super_dict,
133
+ **kwargs,
134
+ )
135
+ # Continue setting the initial attributes.
136
+ self.survey_duration = survey_duration
137
+ self.survey_start = survey_start
138
+ self.detect_snr = detect_snr
139
+ self.num_pre_time = num_pre_time
140
+ self.pre_time = pre_time
141
+ self.num_filters = num_filters
142
+ self.filter_time = filter_time
143
+ self.num_per_lightcurve = num_per_lightcurve
144
+ if self.num_per_lightcurve == 0:
145
+ self.num_filters = 0
146
+ self.num_phases_to_run = num_phases_to_run
147
+ # Read ascii lightcurve template here.
148
+ # It doesn't change per slice_point.
149
+ self.read_sed(ascii_file)
150
+
151
+ def read_sed(self, ascii_file):
152
+ """
153
+ Reads in an ascii file detailing the time evolution of an SED. Must be
154
+ in the following format, 3 columns: phase, wavelength, flux.
155
+
156
+ This will also set the source model and redshift the model according to
157
+ initialization parameters.
158
+
159
+ Parameters
160
+ -----------
161
+ ascii_file : `str`
162
+ string containing the path to the ascii file containing the
163
+ SED evolution.
164
+
165
+ """
166
+ # Sanity to check to make sure the provided string indeed points to a
167
+ # file.
168
+ if not os.path.isfile(ascii_file):
169
+ raise IOError("Could not find SED ascii file %s" % (ascii_file))
170
+ # Read in the SED text file with sncosmo for use with it's Model API.
171
+ self.sed_phase, self.sed_wave, self.sed_flux = read_griddata_ascii(ascii_file)
172
+ # Make the source model and set the transient Model to be used for
173
+ # light curve generation and observation.
174
+ self.make_model()
175
+ # Given the redshifted SED set the transient duration.
176
+ self.transient_duration = self.redshifted_model.maxtime() - self.redshifted_model.mintime()
177
+
178
+ def make_model(self):
179
+ """
180
+ Wrapper function to take the phase, wave, and flux information from the
181
+ provided ascii file and create an sncosmo Model object,
182
+ and consistently redshift that model given initialization Parameters.
183
+ This sets the transient model in rest frame, and transient model in
184
+ observer frame,
185
+ i.e., it is cosmologically redshifted.
186
+ """
187
+ # Set the source model with sncosmo API.
188
+ source = TimeSeriesSource(self.sed_phase, self.sed_wave, self.sed_flux)
189
+ # Create transient model from sncosmo API
190
+ # Use deepcopy to make ensure full class is saved as attribute of new
191
+ # class.
192
+ self.transient_model = deepcopy(Model(source=source))
193
+ # With the Model set, apply the cosmological redshift specified at
194
+ # initialization.
195
+ self.set_redshift()
196
+
197
+ def set_redshift(self):
198
+ """
199
+ Function which takes the input desired observation redshift and
200
+ cosmologically redshifts the source SED. This sets the redshifted_model
201
+ which is what is needed for making observations.
202
+ """
203
+
204
+ z = self.z
205
+ # Deepcopy the model to local variable to get proper behavior of model
206
+ # object methods.
207
+ redshifted_model = deepcopy(self.transient_model)
208
+ # Compute the luminosity distance using Planck15 cosmological
209
+ # parameters, by which to decrease the amplitude of the SED
210
+ lumdist = cosmo.luminosity_distance(z).value * 1e6 # in pc
211
+ # SED is assumed to be at 10pc so scale accordingly.
212
+ amp = pow(np.divide(10.0, lumdist), 2)
213
+ # Set the redshift of the SED, this stretches the wavelength
214
+ # distribution.
215
+ redshifted_model.set(z=z)
216
+ # Separately set the amplitude, this rescales the flux at each
217
+ # wavelength.
218
+ redshifted_model.set(amplitude=amp)
219
+ self.redshifted_model = redshifted_model
220
+
221
+ def make_lightcurve(self, time, filters):
222
+ """
223
+ Compute light curve magnitudes from the source Model for the specified
224
+ light curve phases, and filters.
225
+
226
+ Parameters
227
+ ----------
228
+ time : `np.ndarray`, (N,)
229
+ The times of the observations.
230
+ filters : `list` [`str`]
231
+ The filters of the observations. ['u','g','r',...] format.
232
+
233
+ Returns
234
+ -------
235
+ light_curve_mags : `np.ndarray`, (N,)
236
+ The magnitudes of the object at the times and in the filters of
237
+ the observations.
238
+ """
239
+ # Use the redshifted source model.
240
+ redshifted_model = deepcopy(self.redshifted_model)
241
+ # initialize the light curve magnitudes array.
242
+ light_curve_mags = np.zeros(time.size, dtype=float)
243
+
244
+ # Iterate over the filters that are observed.
245
+ for flt in list(set(filters)):
246
+ # Find the phases of obesrvations in the current filter.
247
+ flt_times = list(time[np.where(filters == flt)[0]])
248
+ # Initialize the band magnitude list.
249
+ filter_mag = []
250
+ # Get all band magnitudes. Currently must be in loop, method fails
251
+ # in the scipy interpolation if attempting to vectorize according
252
+ # to sncosmo documentation.
253
+ for obs_time in flt_times:
254
+ filter_mag.append(redshifted_model.bandmag("lsst" + flt, "ab", obs_time))
255
+ # Set light_curve_mags for array indices corresponding to
256
+ # observations of the current filter.
257
+ light_curve_mags[np.where(filters == flt)[0]] = np.array(filter_mag)
258
+ self.light_curve_mags = light_curve_mags
259
+
260
+ def evaluate_all_detection_criteria(self, data_slice):
261
+ """
262
+ Wrapper function to setup loop for each transient light curve and
263
+ evaluate all detection criteria.
264
+
265
+ Parameters
266
+ -----------
267
+ data_slice : `np.array`
268
+ Numpy structured array containing the data related to the visits
269
+ provided by the slicer.
270
+
271
+ Returns
272
+ --------
273
+ transient_detected : `np.array`, (`bool`,)
274
+ Array containing `bool` tracking variable whether transient is
275
+ detected by passing all criteria.
276
+ num_detected : `int`
277
+ Scalar value of the number of transients that were detected in
278
+ total between all phase shifts considered.
279
+
280
+ """
281
+ # Track whether each individual light curve was detected.
282
+ # Start with the assumption that it is True, and if it fails
283
+ # criteria then becomes False.
284
+ self.transient_detected = np.ones(len(np.unique(self.transient_id)), dtype=bool)
285
+
286
+ # Loop through each lightcurve and check if it meets requirements.
287
+ for i, (start_ind, end_ind) in enumerate(zip(self.transient_start_index, self.transient_end_index)):
288
+ t_id = i
289
+ # If there were no observations at all for this lightcurve:
290
+ if start_ind == end_ind:
291
+ self.transient_detected[t_id] = False
292
+ continue
293
+
294
+ self.observation_epoch_above_thresh = self.observation_epoch[start_ind:end_ind][
295
+ np.where(self.obs_above_snr_threshold[start_ind:end_ind])
296
+ ]
297
+
298
+ self.evaluate_pre_time_detection_criteria(t_id)
299
+ # Check if previous condition passed.
300
+ # If not, move to next transient.
301
+ if not self.transient_detected[t_id]:
302
+ continue
303
+
304
+ self.evaluate_phase_section_detection_criteria(t_id)
305
+ # Check if previous condition passed.
306
+ # If not, move to next transient.
307
+ if not self.transient_detected[t_id]:
308
+ continue
309
+
310
+ self.evaluate_number_filters_detection_criteria(data_slice, start_ind, end_ind, t_id)
311
+ # Check if previous condition passed.
312
+ # If not, move to next transient.
313
+ if not self.transient_detected[t_id]:
314
+ continue
315
+
316
+ self.evaluate_filter_in_time_detection_criteria(t_id)
317
+ # Check if previous condition passed.
318
+ # If not, move to next transient.
319
+ # Note: this last if block is technically unnecessary but if
320
+ # further criteria are added then the if block should be copied
321
+ # afterwards.
322
+ if not self.transient_detected[t_id]:
323
+ continue
324
+ # Finished with current set of conditions
325
+
326
+ # Find the unique number of light curves that passed the required
327
+ # number of conditions
328
+ self.num_detected += len(np.where(self.transient_detected)[0])
329
+
330
+ def evaluate_pre_time_detection_criteria(self, t_id):
331
+ """
332
+ Function evaluate if the specfied number of observations of the current
333
+ transient take place before the user speficied light curve phase by
334
+ which these must be achieved.
335
+
336
+ Parameters
337
+ -----------
338
+ t_id : `int`
339
+ The transient id of the currently evaluated transient.
340
+ """
341
+ # If we did not get enough detections before pre_time, set
342
+ # transient_detected to False.
343
+ indices_pre_time = np.where(self.observation_epoch_above_thresh < self.pre_time)[0]
344
+ if len(indices_pre_time) < self.num_pre_time:
345
+ self.transient_detected[t_id] = False
346
+
347
+ def evaluate_phase_section_detection_criteria(self, t_id):
348
+ """
349
+ Function to evaluate if the specified number of equal length sections
350
+ of the current transient are detected given the user criteria.
351
+
352
+ Parameters
353
+ -----------
354
+ t_id : `int`
355
+ The transient id of the currently evaluated transient.
356
+ """
357
+ # If we did not get detections over enough sections of the
358
+ # lightcurve, set tranisent_detected to False.
359
+ detected_light_curve_sections = np.unique(
360
+ np.floor(self.observation_epoch_above_thresh / self.transient_duration * self.num_per_lightcurve)
361
+ )
362
+ if len(detected_light_curve_sections) < self.num_per_lightcurve:
363
+ self.transient_detected[t_id] = False
364
+
365
+ def evaluate_number_filters_detection_criteria(self, data_slice, start_ind, end_ind, t_id):
366
+ """
367
+ Function to evaluate if the current transient passes the required
368
+ number of detections in different filters.
369
+
370
+ Parameters
371
+ -----------
372
+ data_slice : `np.array`, (N,)
373
+ Numpy structured array containing the data related to the visits
374
+ provided by the slicer.
375
+ start_ind : `int`
376
+ Starting index for observations of the specific transient being
377
+ evaluated.
378
+ end_ind : `int`
379
+ Ending index for observations of the specific transient being
380
+ evaluated.
381
+ t_id : `int`
382
+ The transient id of the currently evaluated transient.
383
+ """
384
+ # If we did not get detections in enough filters, set transient
385
+ # detected to False.
386
+ self.detected_filters = data_slice[start_ind:end_ind][
387
+ np.where(self.obs_above_snr_threshold[start_ind:end_ind])
388
+ ][self.filter_col]
389
+ if len(np.unique(self.detected_filters)) < self.num_filters:
390
+ self.transient_detected[t_id] = False
391
+
392
+ def evaluate_filter_in_time_detection_criteria(self, t_id):
393
+ """
394
+ Function to evaluate whether the required detections in different
395
+ filters take place within the specified time span for them to count
396
+ towards detection of the transient.
397
+
398
+ Parameters
399
+ -----------
400
+ t_id : `int`
401
+ The transient id of the currently evaluted transient.
402
+ """
403
+ # If we did not get detections in enough filters within required
404
+ # time, set transient_detected to False.
405
+ if (self.filter_time is not None) and (self.num_filters > 1):
406
+ final_filter_detection_ind = np.searchsorted(
407
+ self.observation_epoch_above_thresh,
408
+ self.observation_epoch_above_thresh + self.filter_time,
409
+ "right",
410
+ )
411
+ final_filter_detection_ind = np.where(
412
+ final_filter_detection_ind < len(self.observation_epoch_above_thresh) - 1,
413
+ final_filter_detection_ind,
414
+ len(self.observation_epoch_above_thresh) - 1,
415
+ )
416
+ is_detected = False
417
+ for i, filt_end_ind in enumerate(final_filter_detection_ind):
418
+ if len(np.unique(self.detected_filters[i:filt_end_ind])) >= self.num_filters:
419
+ is_detected = True
420
+ break
421
+ if not is_detected:
422
+ self.transient_detected[t_id] = False
423
+
424
+ def setup_phase_shift_dependent_variables(self, time_shift, data_slice):
425
+ """
426
+ Wrapper function to initialize variables that will change for each
427
+ phase shift that is considered.
428
+
429
+ Parameters
430
+ -----------
431
+ time_shift : `float`
432
+ The offset given the currently considered phase shift by which
433
+ to cyclically shift the SED evolution.
434
+ data_slice : `np.array`, (N,)
435
+ Numpy structured array containing the data related to the visits
436
+ provided by the slicer.
437
+
438
+ Returns
439
+ ----------
440
+ max_num_transients : `int`
441
+ Updated number of the total simulated transients.
442
+ observation_epoch : `np.array`, (N,)
443
+ Array of transient light curve phases of observations of
444
+ transients within this phase shift cycle.
445
+ transient_id : `np.array`, (N,)
446
+ Array of all the transient ids within this phase shift cycle,
447
+ regardless of whether it is observed. dtype int.
448
+ transient_id_start : `int`
449
+ Updated starting id for next phase shift loop.
450
+ transient_start_index : `np.array`, (N,)
451
+ Array of the indicies for each transient that are the start of
452
+ their observations in the observation array. dtype int.
453
+ transient_end_index: `np.array`, (N,)
454
+ Array of the indicies for each transient that are the end of
455
+ their observations in the observation array. dtype int.
456
+ """
457
+ # Update the maximum possible transients that could have been
458
+ # observed during survey_duration.
459
+ self.max_num_transients += np.ceil(self.survey_duration / (self.transient_duration / 365.25))
460
+ # Calculate the observation epoch for each transient lightcurve.
461
+ self.observation_epoch = (
462
+ data_slice[self.mjd_col] - self.survey_start + time_shift
463
+ ) % self.transient_duration
464
+ # Identify the observations which belong to each distinct transient.
465
+ self.transient_id = (
466
+ np.floor((data_slice[self.mjd_col] - self.survey_start) / self.transient_duration)
467
+ + self.transient_id_start
468
+ )
469
+ # Set the starting id number for the next phase shift
470
+ self.transient_id_start = self.transient_id.max()
471
+ # Find the set of uniquely observed transients
472
+ unique_transient_id = np.unique(self.transient_id)
473
+ # Find the starting index for each transient_id.
474
+ self.transient_start_index = np.searchsorted(self.transient_id, unique_transient_id, side="left")
475
+ # Find the ending index of each transient_id.
476
+ self.transient_end_index = np.searchsorted(self.transient_id, unique_transient_id, side="right")
477
+
478
+ def setup_run_metric_variables(self, data_slice):
479
+ """
480
+ Wrapper function to handle basic initialization of variables used
481
+ to run this metric.
482
+
483
+ Parameters
484
+ -----------
485
+ data_slice : `np.array`, (N,)
486
+ Numpy structured array containing the data related to the visits
487
+ provided by the slicer.
488
+
489
+ Returns
490
+ ---------
491
+ data_slice : `np.array`, (N,)
492
+ Now sorted in time.
493
+ survey_duration : `float`
494
+ Defaults to the maximum between the chosen slicer and the user
495
+ specified duration given to the metric.
496
+ survey_start : `float`
497
+ Defaults to user specified, or metric default, however if it is
498
+ not defined sets to the earliest time in the given slicer.
499
+ """
500
+ # Sort the entire data_slice in order of time.
501
+ data_slice.sort(order=self.mjd_col)
502
+
503
+ # Check that survey_duration is not larger than the time of
504
+ # observations we obtained. If it is, then the max_num_transients will
505
+ # not be accurate.
506
+ data_slice_time_span = (data_slice[self.mjd_col].max() - data_slice[self.mjd_col].min()) / 365.25
507
+ # Take the maximum time delta, either specified or from the slicer, to
508
+ # be the survey duration.
509
+ self.survey_duration = np.max([data_slice_time_span, self.survey_duration])
510
+
511
+ # Set the survey start based on the slicer unless otherwise specified.
512
+ if self.survey_start is None:
513
+ self.survey_start = data_slice[self.mjd_col].min()
514
+ return data_slice
515
+
516
+ def initialize_phase_loop_variables(self, data_slice):
517
+ """
518
+ Wrapper function to initialize variables needed for checking all
519
+ transietnts and phase shifts for detected transients.
520
+
521
+ Parameters
522
+ -----------
523
+ data_slice : `np.array`, (N,)
524
+ Numpy structured array containing the data related to the visits
525
+ provided by the slicer.
526
+
527
+ Returns
528
+ ---------
529
+ time_phase_shifts : `np.array`, (N,)
530
+ The phase offsets over which to iterate detections given the
531
+ specfied number of phases to run.
532
+ num_detected : `int`
533
+ Initialized variable for the number detected, set to zero.
534
+ max_num_transients : `int`
535
+ Initialized variable for the total transients that are simulated
536
+ counting the multiplicity due to phase shifts.
537
+ transient_id_start : `int`
538
+ The starting id for simulated transients that are observed. This
539
+ accounts for if the requested length of the data_slice and the
540
+ number of simulated transient observations mismatch the number
541
+ of transients that fit in the specified survey duration given
542
+ the user specified survey start.
543
+ """
544
+ # Depending on the number of phase shifts to apply and check the
545
+ # detectability, compute the necessary time shifts corresponding to
546
+ # phase division of the lightcurves.
547
+ self.time_phase_shifts = (
548
+ np.arange(self.num_phases_to_run) * self.transient_duration / float(self.num_phases_to_run)
549
+ )
550
+ # Total number of transient which have reached detection thresholds.
551
+ self.num_detected = 0
552
+ # Total number of transients which could possibly be detected,
553
+ # given survey duration and transient duration.
554
+ self.max_num_transients = 0
555
+ # Set this, in case survey_start was set to be much earlier than this
556
+ # data (so we start counting at 0).
557
+ self.transient_id_start = -1 * np.floor(
558
+ (data_slice[self.mjd_col].min() - self.survey_start) / self.transient_duration
559
+ )
560
+
561
+ def evaluate_snr_thresholds(self, data_slice):
562
+ """
563
+ Take the given data_slice and the set SNR thresholds for observations
564
+ to be considered in further detections and compute which observations
565
+ pass.
566
+
567
+ Parameters
568
+ -----------
569
+ data_slice : `np.array`, (N,)
570
+ Numpy structured array containing the data related to the visits
571
+ provided by the slicer.
572
+
573
+ Returns
574
+ --------
575
+ obs_above_SNR_threshold: `np.array`, (N,)
576
+ `bool` array corresponding to all observations and whether or
577
+ not, given their filter specified SNR threshold, they pass this
578
+ thresholding cut.
579
+ """
580
+ # Initilize array for observations below or above SNR threshold
581
+ self.obs_above_snr_threshold = np.zeros(len(self.light_curve_SNRs), dtype=bool)
582
+ # Identify which detections rise above the required SNR threshold
583
+ # in each filter.
584
+ for filt in np.unique(data_slice[self.filter_col]):
585
+ # Find the indices for observations in current filter.
586
+ filter_match = np.where(data_slice[self.filter_col] == filt)[0]
587
+ # Find the subset of the above indices which are above SNR
588
+ # threshold condition, otherwise set threshold bool to False.
589
+ self.obs_above_snr_threshold[filter_match] = np.where(
590
+ self.light_curve_SNRs[filter_match] >= self.detect_snr[filt],
591
+ True,
592
+ False,
593
+ )
594
+
595
+ def run(self, data_slice, slice_point=None):
596
+ """
597
+ Calculate the detectability of a transient with the specified SED.
598
+
599
+ If self.output_data is True, then returns the full lightcurve for each
600
+ object instead of the total number of transients that are detected.
601
+
602
+ Parameters
603
+ ----------
604
+ data_slice : `np.array`, (N,)
605
+ Numpy structured array containing the data related to the visits
606
+ provided by the slicer.
607
+ slice_point : `dict`, optional
608
+ Dictionary containing information about the slice_point currently
609
+ active in the slicer.
610
+
611
+ Returns
612
+ -------
613
+ result : `float` or `dict`
614
+ The fraction of transients that could be detected.
615
+ (if output_data is False) Otherwise, a dictionary
616
+ with arrays of 'transient_id', 'lcMag', 'detected', 'expMJD',
617
+ 'SNR', 'filter', 'epoch'
618
+ """
619
+
620
+ data_slice = self.setup_run_metric_variables(data_slice)
621
+ self.initialize_phase_loop_variables(data_slice)
622
+
623
+ # Consider each different 'phase shift' separately.
624
+ # We then just have a series of lightcurves, taking place back-to-back.
625
+ for time_shift in self.time_phase_shifts:
626
+ self.setup_phase_shift_dependent_variables(time_shift, data_slice)
627
+
628
+ # Generate the actual light curve magnitudes and SNR
629
+ self.make_lightcurve(self.observation_epoch, data_slice[self.filter_col])
630
+ self.light_curve_SNRs = m52snr(self.light_curve_mags, data_slice[self.m5_col])
631
+
632
+ # Check observations above the defined threshold for detection.
633
+ self.evaluate_snr_thresholds(data_slice)
634
+ # With useable observations computed,
635
+ # evaluate all detection criteria
636
+ self.evaluate_all_detection_criteria(data_slice)
637
+
638
+ if self.output_data:
639
+ # Output all the light curves, regardless of detection threshold,
640
+ # but indicate which were 'detected'.
641
+ # Only returns for one phase shift, not all.
642
+ return {
643
+ "transient_id": self.transient_id,
644
+ "expMJD": data_slice[self.mjd_col],
645
+ "epoch": self.observation_epoch,
646
+ "filter": data_slice[self.filter_col],
647
+ "lcMag": self.light_curve_mags,
648
+ "SNR": self.light_curve_SNRs,
649
+ "detected": self.transient_detected,
650
+ }
651
+ else:
652
+ return float(self.num_detected)