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,488 @@
1
+ __all__ = (
2
+ "create_constellation",
3
+ "starlink_tles_v1",
4
+ "starlink_tles_v2",
5
+ "oneweb_tles",
6
+ "Constellation",
7
+ "sun_alt_limits",
8
+ )
9
+
10
+ import numpy as np
11
+ from astropy import constants as const
12
+ from astropy import units as u
13
+ from rubin_scheduler.utils import SURVEY_START_MJD, Site, gnomonic_project_toxy, point_to_line_distance
14
+ from shapely.geometry import LineString, Point
15
+ from skyfield.api import EarthSatellite, load, wgs84
16
+
17
+ MJDOFFSET = 2400000.5
18
+ mjd0 = SURVEY_START_MJD
19
+
20
+
21
+ def sun_alt_limits():
22
+ """Return sun altitude limits (degrees) at which zero illuminated
23
+ satellites above 20 degrees altitude result.
24
+
25
+ Different constellations have different limits at which zero illumination
26
+ above 20 degrees occurs.
27
+
28
+ Returns
29
+ -------
30
+ sun_alt_limits : `dict` [`str`: `float`]
31
+ Dict with satellite constellation name keys,
32
+ altitude limits values (degrees).
33
+ """
34
+ # Estimated in sun_alts_limits.ipynb
35
+ result = {"slv1": -36.0, "slv2": -36.0, "oneweb": -53.0}
36
+ return result
37
+
38
+
39
+ def satellite_mean_motion(altitude, mu=const.GM_earth, r_earth=const.R_earth):
40
+ """Calculate mean motion of satellites at a given altitude in Earth's
41
+ gravitational field.
42
+ See https://en.wikipedia.org/wiki/Mean_motion#Formulae
43
+
44
+ Parameters
45
+ ----------
46
+ altitude : `float`
47
+ Altitude of the satellite.
48
+ Should be a float with astropy units attached.
49
+
50
+ Returns
51
+ -------
52
+ mean_motion : `float`
53
+ """
54
+ no = np.sqrt(4.0 * np.pi**2 * (altitude + r_earth) ** 3 / mu).to(u.day)
55
+ return 1 / no
56
+
57
+
58
+ def tle_from_orbital_parameters(sat_name, sat_nr, epoch, inclination, raan, mean_anomaly, mean_motion):
59
+ """Generate TLE strings from orbital parameters.
60
+
61
+ Parameters
62
+ ----------
63
+ sat_name : `str`
64
+ Satellite name
65
+ sat_nr : `float`
66
+ Satellite nr
67
+ epoch : `float`
68
+ Epoch
69
+ inclination : `float`
70
+ Inclination, probably with astropy units attached
71
+ raan : `float`
72
+ RA of the ascending node. Assumes astropy units.
73
+ mean_anomaly : `float`
74
+ Mean anomaly.
75
+ mean_motion : `float`
76
+ Mean motion.
77
+
78
+ Returns
79
+ -------
80
+ tle : `str`
81
+
82
+ Notes
83
+ -----
84
+ epoch has the format: first two digits are the year,
85
+ next three digits are the day from beginning of year,
86
+ then fraction of a day is given, e.g.
87
+ 20180.25 would be 2020, day 180, 6 hours (UT?)
88
+ """
89
+
90
+ # Note: RAAN = right ascention (or longitude) of ascending node
91
+ # I suspect this is filling in 0 eccentricity everywhere.
92
+
93
+ def checksum(line):
94
+ s = 0
95
+ for c in line[:-1]:
96
+ if c.isdigit():
97
+ s += int(c)
98
+ if c == "-":
99
+ s += 1
100
+ return "{:s}{:1d}".format(line[:-1], s % 10)
101
+
102
+ tle0 = sat_name
103
+ tle1 = checksum(
104
+ "1 {:05d}U 20001A {:14.8f} .00000000 00000-0 50000-4 " "0 0X".format(sat_nr, epoch)
105
+ )
106
+ tle2 = checksum(
107
+ "2 {:05d} {:8.4f} {:8.4f} 0001000 0.0000 {:8.4f} "
108
+ "{:11.8f} 0X".format(
109
+ sat_nr,
110
+ inclination.to_value(u.deg),
111
+ raan.to_value(u.deg),
112
+ mean_anomaly.to_value(u.deg),
113
+ mean_motion.to_value(1 / u.day),
114
+ )
115
+ )
116
+
117
+ return "\n".join([tle0, tle1, tle2])
118
+
119
+
120
+ def create_constellation(
121
+ altitudes,
122
+ inclinations,
123
+ nplanes,
124
+ sats_per_plane,
125
+ epoch=23274.0,
126
+ name="Test",
127
+ seed=42,
128
+ ):
129
+ """Create a set of orbital elements for a satellite constellation then
130
+ convert them to TLEs.
131
+
132
+ Parameters
133
+ ----------
134
+ altitudes : `np.ndarray`, (N,)
135
+ Altitudes (degrees).
136
+ inclinations : `np.ndarray`, (N,)
137
+ Inclinations (degrees).
138
+ nplanes : `np.ndarray`, (N,)
139
+ Number of satellite planes.
140
+ sats_per_plane : `np.ndarray`, (N,)
141
+ Number of satellites per orbital plane.
142
+ epoch : `float`
143
+ Epoch.
144
+ name : `str`
145
+ Satellite name.
146
+ seed : `float`
147
+ Random number seed.
148
+
149
+ Returns
150
+ -------
151
+ my_sat_tles : `list` of `str`
152
+ """
153
+
154
+ rng = np.random.default_rng(seed)
155
+
156
+ my_sat_tles = []
157
+ sat_nr = 8000
158
+ for alt, inc, n, s in zip(altitudes, inclinations, nplanes, sats_per_plane):
159
+ if s == 1:
160
+ # random placement for lower orbits
161
+ mas = rng.uniform(0, 360, n) * u.deg
162
+ raans = rng.uniform(0, 360, n) * u.deg
163
+ else:
164
+ mas = np.linspace(0.0, 360.0, s, endpoint=False) * u.deg
165
+ mas += rng.uniform(0, 360, 1) * u.deg
166
+ raans = np.linspace(0.0, 360.0, n, endpoint=False) * u.deg
167
+ mas, raans = np.meshgrid(mas, raans)
168
+ mas, raans = mas.flatten(), raans.flatten()
169
+
170
+ mm = satellite_mean_motion(alt)
171
+ for ma, raan in zip(mas, raans):
172
+ my_sat_tles.append(
173
+ tle_from_orbital_parameters(name + " {:d}".format(sat_nr), sat_nr, epoch, inc, raan, ma, mm)
174
+ )
175
+ sat_nr += 1
176
+
177
+ return my_sat_tles
178
+
179
+
180
+ def starlink_tles_v1():
181
+ """Create a list of satellite TLE's, appropriate for
182
+ Starlink v1 (as of July 2022). Should create 4,408 orbits
183
+
184
+ Returns
185
+ -------
186
+ my_sat_tles : `list` [`str`]
187
+ """
188
+ altitudes = np.array([550, 540, 570, 560, 560]) * u.km
189
+ inclinations = np.array([53, 53.2, 70, 97.6, 97.6]) * u.deg
190
+ nplanes = np.array([72, 72, 36, 6, 4])
191
+ sats_per_plane = np.array([22, 22, 20, 58, 43])
192
+
193
+ my_sat_tles = create_constellation(altitudes, inclinations, nplanes, sats_per_plane, name="starV1")
194
+
195
+ return my_sat_tles
196
+
197
+
198
+ def starlink_tles_v2():
199
+ """Create a list of satellite TLE's appropriate for
200
+ Starlink v2 (as of July 2022). Should create 29,988 orbits
201
+
202
+ Returns
203
+ -------
204
+ my_sat_tles : `list` [`str`]
205
+ """
206
+ altitudes = np.array([340, 345, 350, 360, 525, 530, 535, 604, 614]) * u.km
207
+ inclinations = np.array([53, 46, 38, 96.9, 53, 43, 33, 148, 115.7]) * u.deg
208
+ nplanes = np.array([48, 48, 48, 30, 28, 28, 28, 12, 18])
209
+ sats_per_plane = np.array([110, 110, 110, 120, 120, 120, 120, 12, 18])
210
+
211
+ my_sat_tles = create_constellation(altitudes, inclinations, nplanes, sats_per_plane, name="starV2")
212
+
213
+ return my_sat_tles
214
+
215
+
216
+ def oneweb_tles():
217
+ """Create a list of satellite TLE's appropriate
218
+ for OneWeb plans (as of July 2022). Should create 6,372 orbits
219
+
220
+ Returns
221
+ -------
222
+ my_sat_tles : `list` [`str`]
223
+ """
224
+ altitudes = np.array([1200, 1200, 1200]) * u.km
225
+ inclinations = np.array([87.9, 40, 55]) * u.deg
226
+ nplanes = np.array([49, 72, 72])
227
+ sats_per_plane = np.array([36, 32, 32])
228
+
229
+ my_sat_tles = create_constellation(altitudes, inclinations, nplanes, sats_per_plane, name="oneWe")
230
+
231
+ return my_sat_tles
232
+
233
+
234
+ class Constellation:
235
+ """Holds the constellation TLEs and calculates their appearance
236
+ in a series of observations.
237
+
238
+ Parameters
239
+ ----------
240
+ sat_tle_list : `list` [`str`]
241
+ A list of satellite TLEs to be used
242
+ alt_limit : `float`
243
+ Altitude limit below which satellites can be ignored (degrees)
244
+ fov : `float`
245
+ The field of view diameter (degrees)
246
+ """
247
+
248
+ def __init__(self, sat_tle_list, alt_limit=20.0, fov=3.5):
249
+ self.alt_limit_rad = np.radians(alt_limit)
250
+ self.fov_radius_rad = np.radians(fov / 2.0)
251
+
252
+ # Load ephemeris for sun position
253
+ self.eph = load("de421.bsp")
254
+
255
+ self.sat_list = []
256
+ self.ts = load.timescale()
257
+ for tle in sat_tle_list:
258
+ name, line1, line2 = tle.split("\n")
259
+ self.sat_list.append(EarthSatellite(line1, line2, name, self.ts))
260
+
261
+ self._make_location()
262
+
263
+ def _make_location(self):
264
+ telescope = Site(name="LSST")
265
+
266
+ self.observatory_site = wgs84.latlon(telescope.latitude, telescope.longitude, telescope.height)
267
+
268
+ def update_mjd(self, mjd):
269
+ """Calculate and record the alt/az position and illumination status
270
+ for all the satellites at a given time.
271
+
272
+ Parameters
273
+ ----------
274
+ mjd : `float`
275
+ New MJD.
276
+ """
277
+ jd = mjd + MJDOFFSET
278
+ t = self.ts.ut1_jd(jd)
279
+
280
+ self.altitudes_rad = []
281
+ self.azimuth_rad = []
282
+ self.illum = []
283
+ for sat in self.sat_list:
284
+ current_sat = sat.at(t)
285
+ illum = current_sat.is_sunlit(self.eph)
286
+ self.illum.append(illum.copy())
287
+ if illum:
288
+ topo = current_sat - self.observatory_site.at(t)
289
+ # this returns an Angle object
290
+ alt, az, dist = topo.altaz()
291
+ self.altitudes_rad.append(alt.radians + 0)
292
+ self.azimuth_rad.append(az.radians + 0)
293
+ else:
294
+ self.altitudes_rad.append(np.nan)
295
+ self.azimuth_rad.append(np.nan)
296
+
297
+ self.altitudes_rad = np.array(self.altitudes_rad)
298
+ self.azimuth_rad = np.array(self.azimuth_rad)
299
+ self.illum = np.array(self.illum)
300
+ # Keep track of the ones that are up and illuminated
301
+ self.visible = np.where((self.altitudes_rad >= self.alt_limit_rad) & self.illum)[0]
302
+
303
+ def paths_array(self, mjds):
304
+ """Calculate and return the RA/Dec/Alt and illumination status
305
+ for all the satellites at an array of times.
306
+
307
+ Parameters
308
+ ----------
309
+ mjds : `np.ndarray`, (N,)
310
+ Modified Julian Dates.
311
+
312
+ Returns
313
+ -------
314
+ ras : `np.ndarray`, (N,)
315
+ RAs at each MJD
316
+ decs : `np.ndarray`, (N,)
317
+ Decs at each MJD
318
+ alts : `np.ndarray`, (N,)
319
+ Altitudes at each MJD
320
+ illums : `np.ndarray`, (N,)
321
+ Array of bools for if satellite is illuminated
322
+ """
323
+
324
+ jd = mjds + MJDOFFSET
325
+ t = self.ts.ut1_jd(jd)
326
+
327
+ ras = []
328
+ decs = []
329
+ alts = []
330
+ illums = []
331
+ for sat in self.sat_list:
332
+ current_sat = sat.at(t)
333
+ illum = current_sat.is_sunlit(self.eph)
334
+ illums.append(illum.copy())
335
+ topo = current_sat - self.observatory_site.at(t)
336
+ ra, dec, distance = topo.radec()
337
+ alt, az, dist = topo.altaz()
338
+ ras.append(ra.radians)
339
+ decs.append(dec.radians)
340
+ alts.append(alt.radians)
341
+ return np.vstack(ras), np.vstack(decs), np.vstack(alts), np.vstack(illums)
342
+
343
+ def check_pointings(
344
+ self,
345
+ pointing_ras,
346
+ pointing_decs,
347
+ mjds,
348
+ visit_time,
349
+ fov_radius=1.75,
350
+ test_radius=10.0,
351
+ dt=2.0,
352
+ ):
353
+ """Calculate streak length and number of streaks in a set of visits.
354
+
355
+ Parameters
356
+ ----------
357
+ pointing_ras : `np.ndarray`, (N,)
358
+ The RA for each pointing (degrees).
359
+ pointing_decs : `np.ndarray`, (N,)
360
+ The dec for each pointing (degrees).
361
+ mjds : `np.ndarray`, (N,)
362
+ The MJD for the (start) of each pointing (days).
363
+ visit_time : `np.ndarray`, (N,)
364
+ The start to end time for a visit (seconds).
365
+ fov_radius : `float`
366
+ The radius of the science field of view (degrees)
367
+ test_radius : `float`
368
+ The radius to use to see if a streak gets close (degrees).
369
+ Should be large, because satellites can be moving at ~1 deg/s.
370
+ dt : `float`
371
+ The timestep to use for high resolution checking
372
+ if a satellite crossed (seconds).
373
+
374
+ Returns
375
+ -------
376
+ streak length : `float`
377
+ The total length of satellite streaks in the FoV (degrees)
378
+ n_streak : `int`
379
+ The number of streaks that were in the FoV.
380
+ """
381
+ test_radius_rad = np.radians(test_radius)
382
+ dt = dt / 3600 / 24 # to days
383
+ visit_time = visit_time / 3600.0 / 24.0
384
+
385
+ # Arrays to hold results
386
+ lengths_rad = np.zeros(pointing_ras.size, dtype=float)
387
+ n_streaks = np.zeros(pointing_ras.size, dtype=int)
388
+
389
+ input_id_indx_oned = np.arange(pointing_ras.size, dtype=int)
390
+
391
+ # Convert everything to radians for internal computations
392
+ pointing_ras_rad = np.radians(pointing_ras)
393
+ pointing_decs_rad = np.radians(pointing_decs)
394
+ fov_radius_rad = np.radians(fov_radius)
395
+
396
+ # Note self.paths_array should return an array that is
397
+ # N_sats x N_mjds in shape
398
+ # And all angles in radians.
399
+ sat_ra_1, sat_dec_1, sat_alt_1, sat_illum_1 = self.paths_array(mjds)
400
+ mjd_end = mjds + visit_time
401
+ sat_ra_2, sat_dec_2, sat_alt_2, sat_illum_2 = self.paths_array(mjd_end)
402
+
403
+ # broadcast the pointings to be the same shape as the satellite arrays.
404
+ pointing_ras_rad = np.broadcast_to(pointing_ras_rad, sat_ra_1.shape)
405
+ pointing_decs_rad = np.broadcast_to(pointing_decs_rad, sat_ra_1.shape)
406
+ input_id_indx = np.broadcast_to(input_id_indx_oned, sat_ra_1.shape)
407
+
408
+ # Which satellites are above the altitude limit and illuminated
409
+ # np.where confuses me when used on a 2d array.
410
+ above_illum_indx = np.where(
411
+ ((sat_alt_1 > self.alt_limit_rad) | (sat_alt_2 > self.alt_limit_rad))
412
+ & (sat_illum_1 | sat_illum_2)
413
+ )
414
+
415
+ # point_to_line_distance can take arrays,
416
+ # but they all need to be the same shape,
417
+ # thus why we broadcast pointing ra and dec above.
418
+ distances = point_to_line_distance(
419
+ sat_ra_1[above_illum_indx],
420
+ sat_dec_1[above_illum_indx],
421
+ sat_ra_2[above_illum_indx],
422
+ sat_dec_2[above_illum_indx],
423
+ pointing_ras_rad[above_illum_indx],
424
+ pointing_decs_rad[above_illum_indx],
425
+ )
426
+
427
+ close = np.where(distances < test_radius_rad)[0]
428
+
429
+ # Numpy broadcasting is such a dark art
430
+ sat_indx = np.arange(len(self.sat_list), dtype=int)[np.newaxis]
431
+ sat_indx = np.broadcast_to(sat_indx.T, sat_ra_1.shape)
432
+
433
+ mjd_broad = np.broadcast_to(mjds, sat_ra_1.shape)[above_illum_indx][close]
434
+ visit_broad = np.broadcast_to(visit_time, sat_ra_1.shape)[above_illum_indx][close]
435
+
436
+ # ok, this is pretty ugly, but should get the job done
437
+ # Loop over all the potential collisions we have found
438
+ for p_ra, p_dec, ob_indx, mjd, vt, sat_in in zip(
439
+ pointing_ras_rad[above_illum_indx][close],
440
+ pointing_decs_rad[above_illum_indx][close],
441
+ input_id_indx[above_illum_indx][close],
442
+ mjd_broad,
443
+ visit_broad,
444
+ sat_indx[above_illum_indx][close],
445
+ ):
446
+ mjd = np.linspace(mjd, mjd + vt, num=np.round(vt / dt).astype(int))
447
+ jd = mjd + MJDOFFSET
448
+ t = self.ts.ut1_jd(jd)
449
+ sat = self.sat_list[sat_in]
450
+ current_sat = sat.at(t)
451
+ topo = current_sat - self.observatory_site.at(t)
452
+ sat_ra, sat_dec, _distance = topo.radec()
453
+
454
+ length = _streak_length(sat_ra.radians, sat_dec.radians, p_ra, p_dec, fov_radius_rad)
455
+ if length > 0:
456
+ lengths_rad[ob_indx] += length
457
+ n_streaks[ob_indx] += 1
458
+ return np.degrees(lengths_rad), n_streaks
459
+
460
+
461
+ def _streak_length(sat_ras, sat_decs, pointing_ra, pointing_dec, radius):
462
+ """Calculate streak lengths for satellites in a given (circular) pointing.
463
+
464
+ Parameters
465
+ ----------
466
+ sat_ras : `np.ndarray`, (N,)
467
+ RA for each satellite (radians).
468
+ sat_decs : `np.ndarray`, (N,)
469
+ Decs for the satelltes (radians).
470
+ pointing_ra : `float`
471
+ RA of the pointing (radians).
472
+ pointing_dec : `float`
473
+ Dec of the pointing (radians).
474
+ radius : `float`
475
+ Radius of the field of view (radians).
476
+
477
+ Returns
478
+ -------
479
+ length : `float`
480
+ The length of the streak in radians
481
+ """
482
+ # Hopefully this broadcasts properly
483
+ x, y = gnomonic_project_toxy(sat_ras, sat_decs, pointing_ra, pointing_dec)
484
+ ls = LineString(zip(x, y))
485
+ p = Point(0, 0)
486
+ circle_buffer = p.buffer(radius)
487
+ length = circle_buffer.intersection(ls).length
488
+ return length
@@ -0,0 +1,4 @@
1
+ from .generate_catalog import *
2
+ from .offsets import *
3
+ from .solver import *
4
+ from .star_tools import *
@@ -0,0 +1,188 @@
1
+ __all__ = ("generate_catalog",)
2
+
3
+ import sys
4
+ import warnings
5
+
6
+ import numpy as np
7
+ import numpy.lib.recfunctions as rfn
8
+ from scipy.spatial import cKDTree as kdtree # noqa: N813
9
+
10
+ from .offsets import OffsetSNR
11
+ from .star_tools import assign_patches, stars_project
12
+
13
+
14
+ def wrap_ra(ra):
15
+ """Wraps RA into 0-360 degrees."""
16
+ ra = ra % 360.0
17
+ return ra
18
+
19
+
20
+ def cap_dec(dec):
21
+ """Terminates declination at +/- 90 degrees."""
22
+ dec = np.where(dec > 90, 90, dec)
23
+ dec = np.where(dec < -90, -90, dec)
24
+ return dec
25
+
26
+
27
+ def treexyz(ra, dec):
28
+ """Calculate x/y/z values for ra/dec points, ra/dec in radians."""
29
+ # Note ra/dec can be arrays.
30
+ x = np.cos(dec) * np.cos(ra)
31
+ y = np.cos(dec) * np.sin(ra)
32
+ z = np.sin(dec)
33
+ return x, y, z
34
+
35
+
36
+ def build_tree(ra, dec, leafsize=100):
37
+ """Build KD tree on RA/dec and set radius (via setRad) for matching.
38
+
39
+ Parameters
40
+ ----------
41
+ ra : `nd.ndarray`, (N,)
42
+ RA values of the tree (in radians)
43
+ dec : `nd.ndarray`, (N,)
44
+ Dec values of the tree (in radians).
45
+ leafsize : `float`, opt
46
+ The number of RA/Dec pointings in each leafnode.
47
+ Default 100.
48
+ """
49
+ if np.any(np.abs(ra) > np.pi * 2.0) or np.any(np.abs(dec) > np.pi * 2.0):
50
+ raise ValueError("Expecting RA and Dec values to be in radians.")
51
+ x, y, z = treexyz(ra, dec)
52
+ data = list(zip(x, y, z))
53
+ if np.size(data) > 0:
54
+ star_tree = kdtree(data, leafsize=leafsize)
55
+ else:
56
+ raise ValueError("ra and dec should have length greater than 0.")
57
+ return star_tree
58
+
59
+
60
+ def generate_catalog(
61
+ visits,
62
+ stars_array,
63
+ offsets=None,
64
+ lsst_filter="r",
65
+ n_patches=16,
66
+ radius_fov=1.8,
67
+ seed=42,
68
+ uncert_floor=0.005,
69
+ verbose=True,
70
+ ):
71
+ """
72
+ Generate a catalog of observed stellar magnitudes.
73
+
74
+ Parameters
75
+ ----------
76
+ visits : `np.array`, (N,)
77
+ A numpy array with the properties of the visits.
78
+ Expected columns of fiveSigmaDepth, ra, dec, rotSkyPos (all degrees)
79
+ offsets : `list` of rubin_sim.selfcal.Offset classes
80
+ A list of instatiated classes that will apply offsets to the stars
81
+ lsst_filter : `str`
82
+ Which filter to use for the observed stars.
83
+ n_patches : `int`
84
+ Number of patches to divide the FoV into. Must be an integer squared
85
+ radius_fov : `float`
86
+ Radius of the telescope field of view in degrees
87
+ seed : `float`
88
+ Random number seed
89
+ uncert_floor : `float`
90
+ Value to add in quadrature to magnitude uncertainties (mags)
91
+ verbose : `bool`
92
+ Should we be verbose
93
+ """
94
+
95
+ if offsets is None:
96
+ # Maybe change this to just run with a default SNR offset
97
+ warnings.warn("Warning, no offsets set, returning without running")
98
+ return
99
+
100
+ # For computing what the 'expected' uncertainty on the observation will be
101
+ mag_uncert = OffsetSNR(lsst_filter=lsst_filter)
102
+
103
+ # set the radius for the kdtree
104
+ x0, y0, z0 = (1, 0, 0)
105
+ x1, y1, z1 = treexyz(np.radians(radius_fov), 0)
106
+ tree_radius = np.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2 + (z1 - z0) ** 2)
107
+
108
+ newcols = [
109
+ "x",
110
+ "y",
111
+ "radius",
112
+ "patch_id",
113
+ "sub_patch",
114
+ "observed_mag",
115
+ "mag_uncert",
116
+ ]
117
+ newtypes = [float, float, float, int, int, float, float]
118
+ stars_new = np.zeros(stars_array.size, dtype=list(zip(newcols, newtypes)))
119
+
120
+ # only need to output these columns (saving rmag+ for now for convienence)
121
+ output_cols = [
122
+ "id",
123
+ "patch_id",
124
+ "observed_mag",
125
+ "mag_uncert",
126
+ "%smag" % lsst_filter,
127
+ "ra",
128
+ "decl",
129
+ ]
130
+ output_dtypes = [int, int, float, float, float, float, float]
131
+
132
+ stars = rfn.merge_arrays([stars_array, stars_new], flatten=True)
133
+
134
+ # Build a KDTree for the stars
135
+ star_tree = build_tree(np.radians(stars["ra"]), np.radians(stars["decl"]))
136
+
137
+ # XXX--maybe update the way seeding is going on
138
+ np.random.seed(seed)
139
+
140
+ list_of_observed_arrays = []
141
+
142
+ n_visits = np.size(visits)
143
+
144
+ for i, visit in enumerate(visits):
145
+ dmags = {}
146
+ # Calc x,y, radius for each star, crop off stars outside the FoV
147
+ # could replace with code to see where each star falls and get chipID.
148
+ vx, vy, vz = treexyz(np.radians(visit["ra"]), np.radians(visit["dec"]))
149
+ indices = star_tree.query_ball_point((vx, vy, vz), tree_radius)
150
+ stars_in = stars[indices]
151
+ stars_in = stars_project(stars_in, visit)
152
+
153
+ # Assign patchIDs
154
+ stars_in = assign_patches(stars_in, visit, n_patches=n_patches)
155
+
156
+ # Apply the offsets that have been configured
157
+ for offset in offsets:
158
+ dmags[offset.newkey] = offset(stars_in, visit, dmags=dmags)
159
+
160
+ # Total up all the dmag's to make the observed magnitude
161
+ keys = list(dmags.keys())
162
+ obs_mag = stars_in["%smag" % lsst_filter].copy()
163
+ for key in keys:
164
+ obs_mag += dmags[key]
165
+
166
+ # Calculate the uncertainty in the observed mag:
167
+ mag_err = (
168
+ mag_uncert.calc_mag_errors(obs_mag, err_only=True, m5=visit["fiveSigmaDepth"]) ** 2
169
+ + uncert_floor**2
170
+ ) ** 0.5
171
+
172
+ # put values into the right columns
173
+ stars_in["observed_mag"] = obs_mag
174
+ stars_in["mag_uncert"] = mag_err
175
+ # Should shrink this down so we only return the needed columns
176
+ # observed_mag, mag_uncert, patchid, star_id
177
+ sub_cols = np.empty(stars_in.size, dtype=list(zip(output_cols, output_dtypes)))
178
+ for key in output_cols:
179
+ sub_cols[key] = stars_in[key]
180
+ list_of_observed_arrays.append(sub_cols)
181
+ if verbose:
182
+ progress = i / n_visits * 100
183
+ text = "\rprogress = %.2f%%" % progress
184
+ sys.stdout.write(text)
185
+ sys.stdout.flush()
186
+
187
+ result = np.concatenate(list_of_observed_arrays)
188
+ return result