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,370 @@
1
+ import os
2
+ import unittest
3
+
4
+ import numpy as np
5
+ from rubin_scheduler.data import get_data_dir
6
+
7
+ import rubin_sim.phot_utils.signaltonoise as snr
8
+ from rubin_sim.phot_utils import Bandpass, PhotometricParameters, Sed, scale_sky_m5
9
+
10
+
11
+ class TestSNRmethods(unittest.TestCase):
12
+ def setUp(self):
13
+ star_name = os.path.join(get_data_dir(), "tests", "cartoonSedTestData", "starSed")
14
+ star_name = os.path.join(star_name, "kurucz", "km20_5750.fits_g40_5790.gz")
15
+ self.star_sed = Sed()
16
+ self.star_sed.read_sed_flambda(star_name)
17
+ imsimband = Bandpass()
18
+ imsimband.imsim_bandpass()
19
+ f_norm = self.star_sed.calc_flux_norm(22.0, imsimband)
20
+ self.star_sed.multiply_flux_norm(f_norm)
21
+
22
+ hardware_dir = os.path.join(get_data_dir(), "throughputs", "baseline")
23
+ component_list = [
24
+ "detector.dat",
25
+ "m1.dat",
26
+ "m2.dat",
27
+ "m3.dat",
28
+ "lens1.dat",
29
+ "lens2.dat",
30
+ "lens3.dat",
31
+ ]
32
+ self.sky_sed = Sed()
33
+ self.sky_sed.read_sed_flambda(os.path.join(hardware_dir, "darksky.dat"))
34
+
35
+ total_name_list = [
36
+ "total_u.dat",
37
+ "total_g.dat",
38
+ "total_r.dat",
39
+ "total_i.dat",
40
+ "total_z.dat",
41
+ "total_y.dat",
42
+ ]
43
+
44
+ self.bp_list = []
45
+ self.hardware_list = []
46
+ for name in total_name_list:
47
+ dummy = Bandpass()
48
+ dummy.read_throughput(os.path.join(hardware_dir, name))
49
+ self.bp_list.append(dummy)
50
+
51
+ dummy = Bandpass()
52
+ hardware_name_list = [os.path.join(hardware_dir, name)]
53
+ for component in component_list:
54
+ hardware_name_list.append(os.path.join(hardware_dir, component))
55
+ dummy.read_throughput_list(hardware_name_list)
56
+ self.hardware_list.append(dummy)
57
+
58
+ self.filter_name_list = ["u", "g", "r", "i", "z", "y"]
59
+
60
+ self.seeing_defaults = {
61
+ "u": 0.92,
62
+ "g": 0.87,
63
+ "r": 0.83,
64
+ "i": 0.80,
65
+ "z": 0.78,
66
+ "y": 0.76,
67
+ }
68
+
69
+ def test_mag_error(self):
70
+ """
71
+ Make sure that calc_mag_error_sed and calc_mag_error_m5
72
+ agree to within 0.001
73
+ """
74
+ phot_params = PhotometricParameters()
75
+
76
+ # create a cartoon spectrum to test on
77
+ spectrum = Sed()
78
+ spectrum.set_flat_sed()
79
+ spectrum.multiply_flux_norm(1.0e-9)
80
+
81
+ # find the magnitudes of that spectrum in our bandpasses
82
+ mag_list = []
83
+ for total in self.bp_list:
84
+ mag_list.append(spectrum.calc_mag(total))
85
+ mag_list = np.array(mag_list)
86
+
87
+ # try for different normalizations of the skySED
88
+ for f_norm in np.arange(1.0, 5.0, 1.0):
89
+ self.sky_sed.multiply_flux_norm(f_norm)
90
+
91
+ for total, hardware, filterName, mm in zip(
92
+ self.bp_list, self.hardware_list, self.filter_name_list, mag_list
93
+ ):
94
+ fwhm_eff = self.seeing_defaults[filterName]
95
+
96
+ m5 = snr.calc_m5(self.sky_sed, total, hardware, phot_params, fwhm_eff=fwhm_eff)
97
+
98
+ sigma_sed = snr.calc_mag_error_sed(
99
+ spectrum,
100
+ total,
101
+ self.sky_sed,
102
+ hardware,
103
+ phot_params,
104
+ fwhm_eff=fwhm_eff,
105
+ )
106
+
107
+ sigma_m5, gamma = snr.calc_mag_error_m5(mm, total, m5, phot_params)
108
+
109
+ self.assertAlmostEqual(sigma_m5, sigma_sed, 3)
110
+
111
+ def test_verbose_snr(self):
112
+ """
113
+ Make sure that calc_snr_sed has everything
114
+ it needs to run in verbose mode
115
+ """
116
+ phot_params = PhotometricParameters()
117
+
118
+ # create a cartoon spectrum to test on
119
+ spectrum = Sed()
120
+ spectrum.set_flat_sed()
121
+ spectrum.multiply_flux_norm(1.0e-9)
122
+
123
+ snr.calc_snr_sed(
124
+ spectrum,
125
+ self.bp_list[0],
126
+ self.sky_sed,
127
+ self.hardware_list[0],
128
+ phot_params,
129
+ fwhm_eff=0.7,
130
+ verbose=True,
131
+ )
132
+
133
+ def test_signal_to_noise(self):
134
+ """
135
+ Test that calc_snr_m5 and calc_snr_sed give similar results
136
+ """
137
+ phot_params = PhotometricParameters()
138
+
139
+ m5 = []
140
+ for i in range(len(self.hardware_list)):
141
+ m5.append(
142
+ snr.calc_m5(
143
+ self.sky_sed,
144
+ self.bp_list[i],
145
+ self.hardware_list[i],
146
+ phot_params,
147
+ fwhm_eff=self.seeing_defaults[self.filter_name_list[i]],
148
+ )
149
+ )
150
+
151
+ sed_dir = os.path.join(get_data_dir(), "tests", "cartoonSedTestData/starSed/")
152
+ sed_dir = os.path.join(sed_dir, "kurucz")
153
+ file_name_list = os.listdir(sed_dir)
154
+
155
+ rng = np.random.RandomState(42)
156
+ offset = rng.random_sample(len(file_name_list)) * 2.0
157
+
158
+ for ix, name in enumerate(file_name_list):
159
+ if ix > 100:
160
+ break
161
+ spectrum = Sed()
162
+ spectrum.read_sed_flambda(os.path.join(sed_dir, name))
163
+ ff = spectrum.calc_flux_norm(m5[2] - offset[ix], self.bp_list[2])
164
+ spectrum.multiply_flux_norm(ff)
165
+ for i in range(len(self.bp_list)):
166
+ control_snr = snr.calc_snr_sed(
167
+ spectrum,
168
+ self.bp_list[i],
169
+ self.sky_sed,
170
+ self.hardware_list[i],
171
+ phot_params,
172
+ self.seeing_defaults[self.filter_name_list[i]],
173
+ )
174
+
175
+ mag = spectrum.calc_mag(self.bp_list[i])
176
+
177
+ test_snr, gamma = snr.calc_snr_m5(mag, self.bp_list[i], m5[i], phot_params)
178
+ self.assertLess((test_snr - control_snr) / control_snr, 0.001)
179
+
180
+ def test_systematic_uncertainty(self):
181
+ """
182
+ Test that systematic uncertainty is added correctly.
183
+ """
184
+ sigma_sys = 0.002
185
+ m5_list = [23.5, 24.3, 22.1, 20.0, 19.5, 21.7]
186
+ phot_params = PhotometricParameters(sigma_sys=sigma_sys)
187
+
188
+ magnitude_list = []
189
+ for bp in self.bp_list:
190
+ mag = self.star_sed.calc_mag(bp)
191
+ magnitude_list.append(mag)
192
+
193
+ for bp, hardware, filterName, mm, m5 in zip(
194
+ self.bp_list,
195
+ self.hardware_list,
196
+ self.filter_name_list,
197
+ magnitude_list,
198
+ m5_list,
199
+ ):
200
+ sky_dummy = Sed()
201
+ sky_dummy.read_sed_flambda(os.path.join(get_data_dir(), "throughputs", "baseline", "darksky.dat"))
202
+
203
+ normalized_sky_dummy = scale_sky_m5(
204
+ m5,
205
+ sky_dummy,
206
+ bp,
207
+ hardware,
208
+ fwhm_eff=self.seeing_defaults[filterName],
209
+ phot_params=phot_params,
210
+ )
211
+
212
+ sigma, gamma = snr.calc_mag_error_m5(mm, bp, m5, phot_params)
213
+
214
+ snrat = snr.calc_snr_sed(
215
+ self.star_sed,
216
+ bp,
217
+ normalized_sky_dummy,
218
+ hardware,
219
+ fwhm_eff=self.seeing_defaults[filterName],
220
+ phot_params=PhotometricParameters(),
221
+ )
222
+
223
+ test_snr, gamma = snr.calc_snr_m5(mm, bp, m5, phot_params=PhotometricParameters(sigma_sys=0.0))
224
+
225
+ self.assertAlmostEqual(
226
+ snrat,
227
+ test_snr,
228
+ 10,
229
+ msg="failed on calc_snr_m5 test %e != %e " % (snrat, test_snr),
230
+ )
231
+
232
+ control = np.sqrt(np.power(snr.mag_error_from_snr(test_snr), 2) + np.power(sigma_sys, 2))
233
+
234
+ msg = "%e is not %e; failed" % (sigma, control)
235
+
236
+ self.assertAlmostEqual(sigma, control, 10, msg=msg)
237
+
238
+ def test_no_systematic_uncertainty(self):
239
+ """
240
+ Test that systematic uncertainty is handled correctly
241
+ when set to None.
242
+ """
243
+ m5_list = [23.5, 24.3, 22.1, 20.0, 19.5, 21.7]
244
+ phot_params = PhotometricParameters(sigma_sys=0.0)
245
+
246
+ magnitude_list = []
247
+ for bp in self.bp_list:
248
+ mag = self.star_sed.calc_mag(bp)
249
+ magnitude_list.append(mag)
250
+
251
+ for bp, hardware, filterName, mm, m5 in zip(
252
+ self.bp_list,
253
+ self.hardware_list,
254
+ self.filter_name_list,
255
+ magnitude_list,
256
+ m5_list,
257
+ ):
258
+ sky_dummy = Sed()
259
+ sky_dummy.read_sed_flambda(os.path.join(get_data_dir(), "throughputs", "baseline", "darksky.dat"))
260
+
261
+ normalized_sky_dummy = scale_sky_m5(
262
+ m5,
263
+ sky_dummy,
264
+ bp,
265
+ hardware,
266
+ fwhm_eff=self.seeing_defaults[filterName],
267
+ phot_params=phot_params,
268
+ )
269
+
270
+ sigma, gamma = snr.calc_mag_error_m5(mm, bp, m5, phot_params)
271
+
272
+ snrat = snr.calc_snr_sed(
273
+ self.star_sed,
274
+ bp,
275
+ normalized_sky_dummy,
276
+ hardware,
277
+ fwhm_eff=self.seeing_defaults[filterName],
278
+ phot_params=PhotometricParameters(),
279
+ )
280
+
281
+ test_snr, gamma = snr.calc_snr_m5(mm, bp, m5, phot_params=PhotometricParameters(sigma_sys=0.0))
282
+
283
+ self.assertAlmostEqual(
284
+ snrat,
285
+ test_snr,
286
+ 10,
287
+ msg="failed on calc_snr_m5 test %e != %e " % (snrat, test_snr),
288
+ )
289
+
290
+ control = snr.mag_error_from_snr(test_snr)
291
+
292
+ msg = "%e is not %e; failed" % (sigma, control)
293
+
294
+ self.assertAlmostEqual(sigma, control, 10, msg=msg)
295
+
296
+ def test_fwh_mconversions(self):
297
+ fwhm_eff = 0.8
298
+ fwh_mgeom = snr.fwhm_eff2_fwhm_geom(fwhm_eff)
299
+ self.assertEqual(fwh_mgeom, (0.822 * fwhm_eff + 0.052))
300
+ fwh_mgeom = 0.8
301
+ fwhm_eff = snr.fwhm_geom2_fwhm_eff(fwh_mgeom)
302
+ self.assertEqual(fwhm_eff, (fwh_mgeom - 0.052) / 0.822)
303
+
304
+ def test_astrometric_error(self):
305
+ fwhm_geom = 0.7
306
+ m5 = 24.5
307
+ # For bright objects, error should be systematic floor
308
+ mag = 10
309
+ astrometric_err = snr.calc_astrometric_error(
310
+ mag, m5, fwhm_geom=fwhm_geom, nvisit=1, systematic_floor=10
311
+ )
312
+ self.assertAlmostEqual(astrometric_err, 10, 3)
313
+ # Even if you increase the number of visits,
314
+ # the systemic floor doesn't change
315
+ astrometric_err = snr.calc_astrometric_error(mag, m5, fwhm_geom=fwhm_geom, nvisit=100)
316
+ self.assertAlmostEqual(astrometric_err, 10, 3)
317
+ # For a single visit, fainter source, larger error and nvisits matters
318
+ mag = 24.5
319
+ astrometric_err1 = snr.calc_astrometric_error(
320
+ mag, m5, fwhm_geom=fwhm_geom, nvisit=1, systematic_floor=10
321
+ )
322
+ astrometric_err100 = snr.calc_astrometric_error(
323
+ mag, m5, fwhm_geom=fwhm_geom, nvisit=100, systematic_floor=10
324
+ )
325
+ self.assertGreater(astrometric_err1, astrometric_err100)
326
+ self.assertAlmostEqual(astrometric_err1, 140.357, 3)
327
+
328
+ def test_snr_arr(self):
329
+ """
330
+ Test that calc_snr_m5 works on numpy arrays of magnitudes
331
+ """
332
+ rng = np.random.RandomState(17)
333
+ mag_list = rng.random_sample(100) * 5.0 + 15.0
334
+
335
+ phot_params = PhotometricParameters()
336
+ bp = self.bp_list[0]
337
+ m5 = 24.0
338
+ control_list = []
339
+ for mm in mag_list:
340
+ ratio, gamma = snr.calc_snr_m5(mm, bp, m5, phot_params)
341
+ control_list.append(ratio)
342
+ control_list = np.array(control_list)
343
+
344
+ test_list, gamma = snr.calc_snr_m5(mag_list, bp, m5, phot_params)
345
+
346
+ np.testing.assert_array_equal(control_list, test_list)
347
+
348
+ def test_error_arr(self):
349
+ """
350
+ Test that calc_mag_error_m5 works on numpy arrays of magnitudes
351
+ """
352
+ rng = np.random.RandomState(17)
353
+ mag_list = rng.random_sample(100) * 5.0 + 15.0
354
+
355
+ phot_params = PhotometricParameters()
356
+ bp = self.bp_list[0]
357
+ m5 = 24.0
358
+ control_list = []
359
+ for mm in mag_list:
360
+ sig, gamma = snr.calc_mag_error_m5(mm, bp, m5, phot_params)
361
+ control_list.append(sig)
362
+ control_list = np.array(control_list)
363
+
364
+ test_list, gamma = snr.calc_mag_error_m5(mag_list, bp, m5, phot_params)
365
+
366
+ np.testing.assert_array_equal(control_list, test_list)
367
+
368
+
369
+ if __name__ == "__main__":
370
+ unittest.main()
@@ -0,0 +1,36 @@
1
+ import unittest
2
+
3
+ import numpy as np
4
+ from rubin_scheduler.utils import SURVEY_START_MJD
5
+
6
+ from rubin_sim.satellite_constellations import Constellation, oneweb_tles, starlink_tles_v1, starlink_tles_v2
7
+
8
+
9
+ class TestSatellites(unittest.TestCase):
10
+ def test_constellations(self):
11
+ """Test stellite constellations"""
12
+
13
+ mjd0 = SURVEY_START_MJD
14
+ sv1 = starlink_tles_v1()
15
+ sv2 = starlink_tles_v2()
16
+ onw = oneweb_tles()
17
+
18
+ assert sv1 is not None
19
+ assert sv2 is not None
20
+ assert onw is not None
21
+
22
+ const = Constellation(sv1)
23
+
24
+ lengths, n_s = const.check_pointings(
25
+ np.array([85.0, 82.0]),
26
+ np.array([0.0, 0.0]),
27
+ np.arange(2) + mjd0 + 1.5,
28
+ 30.0,
29
+ )
30
+
31
+ assert np.size(lengths) == 2
32
+ assert np.size(n_s) == 2
33
+
34
+
35
+ if __name__ == "__main__":
36
+ unittest.main()
@@ -0,0 +1,24 @@
1
+ import importlib.util
2
+ import unittest
3
+
4
+ from rubin_scheduler.scheduler.schedulers.core_scheduler import CoreScheduler
5
+
6
+ if importlib.util.find_spec("lsst"):
7
+ HAVE_TS = importlib.util.find_spec("lsst.ts")
8
+ else:
9
+ HAVE_TS = False
10
+
11
+ if HAVE_TS:
12
+ from rubin_sim.sim_archive import get_scheduler_instance_from_repo
13
+
14
+
15
+ class TestMakeSnapshot(unittest.TestCase):
16
+ @unittest.skip("Skipping because test depends on external repo.")
17
+ @unittest.skipIf(not HAVE_TS, "No lsst.ts")
18
+ def test_get_scheduler_instance_photcal(self):
19
+ scheduler = get_scheduler_instance_from_repo(
20
+ config_repo="https://github.com/lsst-ts/ts_config_ocs.git",
21
+ config_script="Scheduler/feature_scheduler/auxtel/fbs_config_image_photocal_survey.py",
22
+ config_branch="main",
23
+ )
24
+ self.assertIsInstance(scheduler, CoreScheduler)
@@ -0,0 +1,204 @@
1
+ import importlib
2
+ import lzma
3
+ import os
4
+ import pickle
5
+ import unittest
6
+ import urllib
7
+ from pathlib import Path
8
+ from tempfile import TemporaryDirectory
9
+
10
+ import numpy as np
11
+ import pandas as pd
12
+ from astropy.time import Time
13
+ from rubin_scheduler.scheduler import sim_runner
14
+ from rubin_scheduler.scheduler.example import example_scheduler
15
+ from rubin_scheduler.scheduler.model_observatory import ModelObservatory
16
+ from rubin_scheduler.utils import SURVEY_START_MJD
17
+
18
+ HAVE_LSST_RESOURCES = importlib.util.find_spec("lsst") and importlib.util.find_spec("lsst.resources")
19
+ HAVE_AWS_CREDENTIALS = "AWS_SHARED_CREDENTIALS_FILE" in os.environ and os.path.isfile(
20
+ os.environ["AWS_SHARED_CREDENTIALS_FILE"]
21
+ )
22
+
23
+ if HAVE_LSST_RESOURCES:
24
+ from lsst.resources import ResourcePath
25
+
26
+ from rubin_sim.sim_archive.prototype import (
27
+ check_opsim_archive_resource,
28
+ compile_sim_metadata,
29
+ fetch_obsloctap_visits,
30
+ fetch_sim_for_nights,
31
+ fetch_sim_stats_for_night,
32
+ find_latest_prenight_sim_for_nights,
33
+ make_sim_archive_cli,
34
+ make_sim_archive_dir,
35
+ read_archived_sim_metadata,
36
+ read_sim_metadata_from_hdf,
37
+ transfer_archive_dir,
38
+ verify_compiled_sim_metadata,
39
+ )
40
+
41
+
42
+ class TestPrototypeSimArchive(unittest.TestCase):
43
+ def setUp(self) -> None:
44
+ self.start_environ: dict = {}
45
+ self.start_environ.update(os.environ)
46
+ os.environ["LSST_DISABLE_BUCKET_VALIDATION"] = "1"
47
+
48
+ def tearDown(self) -> None:
49
+ for key in os.environ:
50
+ if key not in self.start_environ:
51
+ del os.environ[key]
52
+ else:
53
+ if os.environ[key] != self.start_environ[key]:
54
+ os.environ[key] = self.start_environ[key]
55
+
56
+ @unittest.skipIf(not HAVE_LSST_RESOURCES, "No lsst.resources")
57
+ def test_sim_archive(self) -> None:
58
+ # Begin by running a short simulation
59
+ sim_start_mjd = SURVEY_START_MJD
60
+ sim_duration = 1 # days
61
+ scheduler = example_scheduler(mjd_start=sim_start_mjd)
62
+ scheduler.keep_rewards = True
63
+ observatory = ModelObservatory(mjd_start=sim_start_mjd)
64
+
65
+ # Record the state of the scheduler at the start of the sim.
66
+ data_dir = TemporaryDirectory()
67
+ data_path = Path(data_dir.name)
68
+
69
+ scheduler_fname = data_path.joinpath("scheduler.pickle.xz")
70
+ with lzma.open(scheduler_fname, "wb", format=lzma.FORMAT_XZ) as pio:
71
+ pickle.dump(scheduler, pio)
72
+
73
+ files_to_archive = {"scheduler": scheduler_fname}
74
+
75
+ # Run the simulation
76
+ sim_runner_kwargs = {
77
+ "sim_start_mjd": sim_start_mjd,
78
+ "sim_duration": sim_duration,
79
+ "record_rewards": True,
80
+ }
81
+
82
+ observatory, scheduler, observations, reward_df, obs_rewards = sim_runner(
83
+ observatory, scheduler, **sim_runner_kwargs
84
+ )
85
+
86
+ # Make the scratch sim archive
87
+ make_sim_archive_dir(
88
+ observations,
89
+ reward_df=reward_df,
90
+ obs_rewards=obs_rewards,
91
+ in_files=files_to_archive,
92
+ sim_runner_kwargs=sim_runner_kwargs,
93
+ tags=["test"],
94
+ label="test",
95
+ data_path=data_path,
96
+ )
97
+
98
+ # Move the scratch sim archive to a test resource
99
+ test_resource_dir = TemporaryDirectory()
100
+ test_resource_uri = "file://" + test_resource_dir.name
101
+ sim_archive_uri = transfer_archive_dir(data_dir.name, test_resource_uri)
102
+
103
+ # Check the saved archive
104
+ archive_check = check_opsim_archive_resource(sim_archive_uri)
105
+ for value in archive_check.values():
106
+ self.assertTrue(value)
107
+
108
+ # Read back the metadata
109
+ archive_metadata = read_archived_sim_metadata(test_resource_uri)
110
+ base = sim_archive_uri.dirname().geturl().removeprefix(test_resource_uri).rstrip("/").lstrip("/")
111
+ expected_label = f"{base} test"
112
+ self.assertEqual(archive_metadata[sim_archive_uri.geturl()]["label"], expected_label)
113
+
114
+ # Cache the metadata
115
+ test_compiled_metadata_uri = test_resource_uri + "/compiled_metadata_cache.h5"
116
+
117
+ # Test reading from cached metadata
118
+ compile_sim_metadata(test_resource_uri, test_compiled_metadata_uri)
119
+ read_sim_metadata_from_hdf(test_compiled_metadata_uri)
120
+ read_archived_sim_metadata(test_resource_uri, compilation_resource=test_compiled_metadata_uri)
121
+ verify_compiled_sim_metadata(test_resource_uri, test_compiled_metadata_uri)
122
+
123
+ @unittest.skipIf(not HAVE_LSST_RESOURCES, "No lsst.resources")
124
+ @unittest.skipIf(importlib.util.find_spec("schedview") is None, "No schedview")
125
+ def test_cli(self) -> None:
126
+ test_resource_path = ResourcePath("resource://schedview/data/")
127
+ with test_resource_path.join("sample_opsim.db").as_local() as local_rp:
128
+ opsim = urllib.parse.urlparse(local_rp.geturl()).path
129
+
130
+ with test_resource_path.join("sample_rewards.h5").as_local() as local_rp:
131
+ rewards = urllib.parse.urlparse(local_rp.geturl()).path
132
+
133
+ with test_resource_path.join("sample_scheduler.pickle.xz").as_local() as local_rp:
134
+ scheduler = urllib.parse.urlparse(local_rp.geturl()).path
135
+
136
+ with TemporaryDirectory() as test_archive_dir:
137
+ test_archive_uri = f"file://{test_archive_dir}/"
138
+ make_sim_archive_cli(
139
+ "Test",
140
+ opsim,
141
+ "--rewards",
142
+ rewards,
143
+ "--scheduler",
144
+ scheduler,
145
+ "--archive_base_uri",
146
+ test_archive_uri,
147
+ )
148
+
149
+ @unittest.skipIf(not HAVE_LSST_RESOURCES, "No lsst.resources")
150
+ @unittest.skipIf(not HAVE_AWS_CREDENTIALS, "No credentials")
151
+ def test_find_latest_prenight_sim_for_night(self) -> None:
152
+ day_obs = "2025-09-25"
153
+ max_simulation_age = int(np.ceil(Time.now().mjd - Time(day_obs).mjd)) + 1
154
+ sim_metadata = find_latest_prenight_sim_for_nights(day_obs, max_simulation_age=max_simulation_age)
155
+ assert sim_metadata["simulated_dates"]["first"] <= day_obs <= sim_metadata["simulated_dates"]["last"]
156
+
157
+ @unittest.skipIf(not HAVE_LSST_RESOURCES, "No lsst.resources")
158
+ @unittest.skipIf(not HAVE_AWS_CREDENTIALS, "No credentials")
159
+ def test_fetch_sim_for_nights(self) -> None:
160
+ day_obs = "2025-09-25"
161
+ max_simulation_age = int(np.ceil(Time.now().mjd - Time(day_obs).mjd)) + 1
162
+ visits = fetch_sim_for_nights(day_obs, which_sim={"max_simulation_age": max_simulation_age})
163
+ assert len(visits) > 0
164
+
165
+ @unittest.skipIf(not HAVE_LSST_RESOURCES, "No lsst.resources")
166
+ @unittest.skipIf(not HAVE_AWS_CREDENTIALS, "No credentials")
167
+ def test_fetch_obsloctap_visits(self) -> None:
168
+ day_obs = "2025-09-25"
169
+ num_nights = 2
170
+ visits = pd.DataFrame(fetch_obsloctap_visits(day_obs, nights=num_nights))
171
+ assert 500 < len(visits) / num_nights < 1500
172
+
173
+ assert np.all(np.isfinite(visits["observationStartMJD"]))
174
+ assert np.floor(visits["observationStartMJD"].min() - 0.5) == Time(day_obs).mjd
175
+ assert np.floor(visits["observationStartMJD"].max() - 0.5) == Time(day_obs).mjd + num_nights - 1
176
+
177
+ assert np.all(np.isfinite(visits["fieldDec"]))
178
+ assert visits["fieldDec"].min() >= -90.0
179
+ assert visits["fieldDec"].max() <= 90.0
180
+
181
+ assert np.all(np.isfinite(visits["rotSkyPos"]))
182
+ assert visits["rotSkyPos"].min() >= -720.0
183
+ assert visits["rotSkyPos"].max() <= 720.0
184
+
185
+ assert np.all(np.isfinite(visits["visitExposureTime"]))
186
+ assert visits["visitExposureTime"].min() >= -720.0
187
+ assert visits["visitExposureTime"].max() <= 720.0
188
+
189
+ assert "band" in visits.columns
190
+ assert "target_name" in visits.columns
191
+
192
+ @unittest.skipIf(not HAVE_LSST_RESOURCES, "No lsst.resources")
193
+ @unittest.skipIf(not HAVE_AWS_CREDENTIALS, "No credentials")
194
+ def test_fetch_sim_stats_for_night(self) -> None:
195
+ day_obs = "2025-09-12"
196
+ num_visits = fetch_sim_stats_for_night(day_obs)["nominal_visits"]
197
+ assert num_visits > 0
198
+
199
+ # Make sure it runs with a default day_obs
200
+ fetch_sim_stats_for_night()
201
+
202
+
203
+ if __name__ == "__main__":
204
+ unittest.main()