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,618 @@
1
+ __all__ = (
2
+ "ParallaxMetric",
3
+ "ProperMotionMetric",
4
+ "RadiusObsMetric",
5
+ "ParallaxCoverageMetric",
6
+ "ParallaxDcrDegenMetric",
7
+ )
8
+
9
+ import numpy as np
10
+ import rubin_scheduler.utils as utils
11
+ from scipy.optimize import curve_fit
12
+
13
+ import rubin_sim.maf.utils as mafUtils
14
+
15
+ from .base_metric import BaseMetric
16
+
17
+
18
+ class ParallaxMetric(BaseMetric):
19
+ """Calculate the uncertainty in a parallax measurement
20
+ given a series of observations.
21
+
22
+ Uses columns ra_pi_amp and dec_pi_amp,
23
+ calculated by the ParallaxFactorStacker.
24
+
25
+ Parameters
26
+ ----------
27
+ m5_col : `str`, optional
28
+ The default column name for m5 information in the input data.
29
+ filter_col : `str`, optional
30
+ The column name for the filter information.
31
+ seeing_col : `str`, optional
32
+ The column name for the seeing information.
33
+ Since the astrometry errors are based on the physical size of the PSF,
34
+ this should be the FWHM of the physical psf, e.g. seeingFwhmGeom.
35
+ rmag : `float`, optional
36
+ The r magnitude of the fiducial star in r band.
37
+ Other filters are scaled using sedTemplate keyword.
38
+ SedTemplate : `str`, optional
39
+ The template to use. This can be 'flat' or 'O','B','A','F','G','K','M'.
40
+ atm_err : `float`, optional
41
+ The expected centroiding error due to the atmosphere, in arcseconds.
42
+ Default 0.01.
43
+ normalize : `bool`, optional
44
+ Compare the astrometric uncertainty to the uncertainty
45
+ that would result if half the observations were taken at the start
46
+ and half at the end.
47
+ A perfect survey will have a value close to 1, while
48
+ a poorly scheduled survey will be close to 0.
49
+ badval : `float`, optional
50
+ The value to return when the metric value cannot be calculated.
51
+ """
52
+
53
+ def __init__(
54
+ self,
55
+ m5_col="fiveSigmaDepth",
56
+ filter_col="band",
57
+ seeing_col="seeingFwhmGeom",
58
+ rmag=20.0,
59
+ sed_template="flat",
60
+ badval=-666,
61
+ atm_err=0.01,
62
+ normalize=False,
63
+ **kwargs,
64
+ ):
65
+ cols = [m5_col, filter_col, seeing_col, "ra_pi_amp", "dec_pi_amp"]
66
+ if normalize:
67
+ units = "ratio"
68
+ else:
69
+ units = "mas"
70
+ super().__init__(cols, units=units, badval=badval, **kwargs)
71
+ # set return type
72
+ self.m5_col = m5_col
73
+ self.seeing_col = seeing_col
74
+ self.filter_col = filter_col
75
+ filters = ["u", "g", "r", "i", "z", "y"]
76
+ self.mags = {}
77
+ if sed_template == "flat":
78
+ for f in filters:
79
+ self.mags[f] = rmag
80
+ else:
81
+ self.mags = utils.stellarMags(sed_template, rmag=rmag)
82
+ self.atm_err = atm_err
83
+ self.normalize = normalize
84
+ self.comment = (
85
+ "Estimated uncertainty in parallax measurement "
86
+ "(assuming no proper motion or that proper motion "
87
+ )
88
+ self.comment += (
89
+ "is well fit). Uses measurements in all bandpasses, "
90
+ "and estimates astrometric error based on SNR "
91
+ )
92
+ self.comment += "in each visit. "
93
+ if sed_template == "flat":
94
+ self.comment += "Assumes a flat SED. "
95
+ if self.normalize:
96
+ self.comment += (
97
+ "This normalized version of the metric displays the "
98
+ "estimated uncertainty in the parallax measurement, "
99
+ )
100
+ self.comment += "divided by the minimum parallax uncertainty possible "
101
+ self.comment += "(if all visits were six months apart). "
102
+ self.comment += "Values closer to 1 indicate more optimal " "scheduling for parallax measurement."
103
+
104
+ def _final_sigma(self, position_errors, ra_pi_amp, dec_pi_amp):
105
+ """Assume parallax in RA and DEC are fit independently, then combined.
106
+ All inputs assumed to be arcsec"""
107
+ with np.errstate(divide="ignore", invalid="ignore"):
108
+ sigma_a = position_errors / ra_pi_amp
109
+ sigma_b = position_errors / dec_pi_amp
110
+ sigma_ra = np.sqrt(1.0 / np.sum(1.0 / sigma_a**2))
111
+ sigma_dec = np.sqrt(1.0 / np.sum(1.0 / sigma_b**2))
112
+ # Combine RA and Dec uncertainties, convert to mas
113
+ sigma = np.sqrt(1.0 / (1.0 / sigma_ra**2 + 1.0 / sigma_dec**2)) * 1e3
114
+ return sigma
115
+
116
+ def run(self, data_slice, slice_point=None):
117
+ filters = np.unique(data_slice[self.filter_col])
118
+ if hasattr(filters[0], "decode"):
119
+ filters = [str(f.decode("utf-8")) for f in filters]
120
+ snr = np.zeros(len(data_slice), dtype="float")
121
+ # compute SNR for all observations
122
+ for filt in filters:
123
+ good = np.where(data_slice[self.filter_col] == filt)
124
+ snr[good] = mafUtils.m52snr(self.mags[str(filt)], data_slice[self.m5_col][good])
125
+ position_errors = mafUtils.astrom_precision(data_slice[self.seeing_col], snr, self.atm_err)
126
+ sigma = self._final_sigma(position_errors, data_slice["ra_pi_amp"], data_slice["dec_pi_amp"])
127
+ if self.normalize:
128
+ # Leave the dec parallax as zero since one can't have
129
+ # ra and dec maximized at the same time.
130
+ sigma = (
131
+ self._final_sigma(
132
+ position_errors,
133
+ data_slice["ra_pi_amp"] * 0 + 1.0,
134
+ data_slice["dec_pi_amp"] * 0,
135
+ )
136
+ / sigma
137
+ )
138
+ return sigma
139
+
140
+
141
+ class ProperMotionMetric(BaseMetric):
142
+ """Calculate the uncertainty in the returned proper motion.
143
+
144
+ This metric assumes gaussian errors in the astrometry measurements.
145
+
146
+ Parameters
147
+ ----------
148
+ metricName : `str`, optional
149
+ Default 'properMotion'.
150
+ m5_col : `str`, optional
151
+ The default column name for m5 information in the input data.
152
+ Default fiveSigmaDepth.
153
+ mjd_col : `str`, optional
154
+ The column name for the exposure time. Default observationStartMJD.
155
+ filterCol : `str`, optional
156
+ The column name for the filter information. Default filter.
157
+ seeing_col : `str`, optional
158
+ The column name for the seeing information.
159
+ Since the astrometry errors are based on the physical
160
+ size of the PSF, this should be the FWHM of the physical psf.
161
+ Default seeingFwhmGeom.
162
+ rmag : `float`, optional
163
+ The r magnitude of the fiducial star in r band.
164
+ Other filters are sclaed using sedTemplate keyword.
165
+ Default 20.0
166
+ SedTemplate : `str`, optional
167
+ The template to use. This can be 'flat' or 'O','B','A','F','G','K','M'.
168
+ Default flat.
169
+ atm_err : `float`, optional
170
+ The expected centroiding error due to the atmosphere, in arcseconds.
171
+ Default 0.01.
172
+ normalize : `bool`, optional
173
+ Compare the astrometric uncertainty to the uncertainty that would
174
+ result if half the observations were taken at the start and half
175
+ at the end. A perfect survey will have a value close to 1, while
176
+ a poorly scheduled survey will be close to 0. Default False.
177
+ baseline : `float`, optional
178
+ The length of the survey used for the normalization, in years.
179
+ Default 10.
180
+ badval : `float`, optional
181
+ The value to return when the metric value cannot be calculated.
182
+ Default -666.
183
+ """
184
+
185
+ def __init__(
186
+ self,
187
+ metric_name="properMotion",
188
+ m5_col="fiveSigmaDepth",
189
+ mjd_col="observationStartMJD",
190
+ filter_col="band",
191
+ seeing_col="seeingFwhmGeom",
192
+ rmag=20.0,
193
+ sed_template="flat",
194
+ badval=-666,
195
+ atm_err=0.01,
196
+ normalize=False,
197
+ baseline=10.0,
198
+ **kwargs,
199
+ ):
200
+ cols = [m5_col, mjd_col, filter_col, seeing_col]
201
+ if normalize:
202
+ units = "ratio"
203
+ else:
204
+ units = "mas/yr"
205
+ super(ProperMotionMetric, self).__init__(
206
+ col=cols, metric_name=metric_name, units=units, badval=badval, **kwargs
207
+ )
208
+ # set return type
209
+ self.mjd_col = mjd_col
210
+ self.seeing_col = seeing_col
211
+ self.m5_col = m5_col
212
+ self.filter_col = filter_col
213
+ filters = ["u", "g", "r", "i", "z", "y"]
214
+ self.mags = {}
215
+ if sed_template == "flat":
216
+ for f in filters:
217
+ self.mags[f] = rmag
218
+ else:
219
+ self.mags = utils.stellarMags(sed_template, rmag=rmag)
220
+ self.atm_err = atm_err
221
+ self.normalize = normalize
222
+ self.baseline = baseline
223
+ self.comment = (
224
+ "Estimated uncertainty of the proper motion fit "
225
+ "(assuming no parallax or that parallax is well fit). "
226
+ )
227
+ self.comment += (
228
+ "Uses visits in all bands, and generates approximate "
229
+ "astrometric errors using the SNR in each visit. "
230
+ )
231
+ if sed_template == "flat":
232
+ self.comment += "Assumes a flat SED. "
233
+ if self.normalize:
234
+ self.comment += (
235
+ "This normalized version of the metric represents " "the estimated uncertainty in the proper "
236
+ )
237
+ self.comment += "motion divided by the minimum uncertainty possible "
238
+ self.comment += "(if all visits were obtained on the first and last days of the survey). "
239
+ self.comment += "Values closer to 1 indicate more optimal scheduling."
240
+
241
+ def run(self, data_slice, slice_point=None):
242
+ filters = np.unique(data_slice[self.filter_col])
243
+ filters = [str(f) for f in filters]
244
+ precis = np.zeros(data_slice.size, dtype="float")
245
+ for f in filters:
246
+ observations = np.where(data_slice[self.filter_col] == f)
247
+ if np.size(observations[0]) < 2:
248
+ precis[observations] = self.badval
249
+ else:
250
+ snr = mafUtils.m52snr(self.mags[f], data_slice[self.m5_col][observations])
251
+ precis[observations] = mafUtils.astrom_precision(
252
+ data_slice[self.seeing_col][observations], snr, self.atm_err
253
+ )
254
+ good = np.where(precis != self.badval)
255
+ result = mafUtils.sigma_slope(data_slice[self.mjd_col][good], precis[good])
256
+ result = result * 365.25 * 1e3 # Convert to mas/yr
257
+ if (self.normalize) & (good[0].size > 0):
258
+ new_dates = data_slice[self.mjd_col][good] * 0
259
+ n_dates = new_dates.size
260
+ new_dates[n_dates // 2 :] = self.baseline * 365.25
261
+ result = (mafUtils.sigma_slope(new_dates, precis[good]) * 365.25 * 1e3) / result
262
+ # Observations that are very close together can still fail
263
+ if np.isnan(result):
264
+ result = self.badval
265
+ return result
266
+
267
+
268
+ class ParallaxCoverageMetric(BaseMetric):
269
+ """Check how well the parallax factor is distributed.
270
+
271
+ Subtracts the weighted mean position of the
272
+ parallax offsets, then computes the weighted mean radius of the points.
273
+ If points are well distributed, the mean radius will be near 1.
274
+ If phase coverage is bad, radius will be close to zero.
275
+
276
+ For points on the Ecliptic, uniform sampling should result in a
277
+ metric value of ~0.5.
278
+ At the poles, uniform sampling would result in a metric value of ~1.
279
+ Conceptually, it is helpful to remember that the parallax motion of a
280
+ star at the pole is a (nearly circular) ellipse while the motion of a
281
+ star on the ecliptic is a straight line. Thus, any pair of observations
282
+ separated by 6 months will give the full parallax range for a star on
283
+ the pole but only observations on very specific dates will give the
284
+ full range for a star on the ecliptic.
285
+
286
+ Optionally also demand that there are observations above the snr_limit
287
+ kwarg spanning theta_range radians.
288
+
289
+ Parameters
290
+ ----------
291
+ m5_col : `str`, optional
292
+ Column name for individual visit m5. Default fiveSigmaDepth.
293
+ mjd_col : `str`, optional
294
+ Column name for exposure time dates. Default observationStartMJD.
295
+ filter_col : `str`, optional
296
+ Column name for filter. Default filter.
297
+ seeing_col : `str`, optional
298
+ Column name for seeing (assumed FWHM). Default seeingFwhmGeom.
299
+ rmag : `float`, optional
300
+ Magnitude of fiducial star in r filter.
301
+ Other filters are scaled using sedTemplate keyword.
302
+ Default 20.0
303
+ sedTemplate : `str`, optional
304
+ Template to use (can be 'flat' or 'O','B','A','F','G','K','M').
305
+ Default 'flat'.
306
+ atm_err : `float`, optional
307
+ Centroiding error due to atmosphere in arcsec.
308
+ Default 0.01 (arcseconds).
309
+ theta_range : `float`, optional
310
+ Range of parallax offset angles to demand (in radians).
311
+ Default=0 (means no range requirement).
312
+ snr_limit : `float`, optional
313
+ Only include points above the snr_limit when computing theta_range.
314
+ Default 5.
315
+
316
+ Returns
317
+ --------
318
+ metricValu e: `float`
319
+ Returns a weighted mean of the length of the parallax factor vectors.
320
+ Values near 1 imply that the points are well distributed.
321
+ Values near 0 imply that the parallax phase coverage is bad.
322
+ Near the ecliptic, uniform sampling results in metric values
323
+ of about 0.5.
324
+
325
+ Notes
326
+ -----
327
+ Uses the ParallaxFactor stacker to calculate ra_pi_amp and dec_pi_amp.
328
+ """
329
+
330
+ def __init__(
331
+ self,
332
+ metric_name="ParallaxCoverageMetric",
333
+ m5_col="fiveSigmaDepth",
334
+ mjd_col="observationStartMJD",
335
+ filter_col="band",
336
+ seeing_col="seeingFwhmGeom",
337
+ rmag=20.0,
338
+ sed_template="flat",
339
+ atm_err=0.01,
340
+ theta_range=0.0,
341
+ snr_limit=5,
342
+ **kwargs,
343
+ ):
344
+ cols = ["ra_pi_amp", "dec_pi_amp", m5_col, mjd_col, filter_col, seeing_col]
345
+ units = "ratio"
346
+ super(ParallaxCoverageMetric, self).__init__(cols, metric_name=metric_name, units=units, **kwargs)
347
+ self.m5_col = m5_col
348
+ self.seeing_col = seeing_col
349
+ self.filter_col = filter_col
350
+ self.mjd_col = mjd_col
351
+
352
+ # Demand the range of theta values
353
+ self.theta_range = theta_range
354
+ self.snr_limit = snr_limit
355
+
356
+ filters = ["u", "g", "r", "i", "z", "y"]
357
+ self.mags = {}
358
+ if sed_template == "flat":
359
+ for f in filters:
360
+ self.mags[f] = rmag
361
+ else:
362
+ self.mags = utils.stellarMags(sed_template, rmag=rmag)
363
+ self.atm_err = atm_err
364
+ caption = "Parallax factor coverage for an r=%.2f star (0 is bad, 0.5-1 is good). " % (rmag)
365
+ caption += "One expects the parallax factor coverage to vary because stars on the ecliptic "
366
+ caption += "can be observed when they have no parallax offset while stars at the pole are always "
367
+ caption += "offset by the full parallax offset." ""
368
+ self.comment = caption
369
+
370
+ def _theta_check(self, ra_pi_amp, dec_pi_amp, snr):
371
+ good = np.where(snr >= self.snr_limit)
372
+ theta = np.arctan2(dec_pi_amp[good], ra_pi_amp[good])
373
+ # Make values between 0 and 2pi
374
+ theta = theta - np.min(theta)
375
+ result = 0.0
376
+ if np.max(theta) >= self.theta_range:
377
+ # Check that things are in different quadrants
378
+ theta = (theta + np.pi) % 2.0 * np.pi
379
+ theta = theta - np.min(theta)
380
+ if np.max(theta) >= self.theta_range:
381
+ result = 1
382
+ return result
383
+
384
+ def _compute_weights(self, data_slice, snr):
385
+ # Compute centroid uncertainty in each visit
386
+ position_errors = mafUtils.astrom_precision(data_slice[self.seeing_col], snr, self.atm_err)
387
+ weights = 1.0 / position_errors**2
388
+ return weights
389
+
390
+ def _weighted_r(self, dec_pi_amp, ra_pi_amp, weights):
391
+ ycoord = dec_pi_amp - np.average(dec_pi_amp, weights=weights)
392
+ xcoord = ra_pi_amp - np.average(ra_pi_amp, weights=weights)
393
+ radius = np.sqrt(xcoord**2 + ycoord**2)
394
+ ave_rad = np.average(radius, weights=weights)
395
+ return ave_rad
396
+
397
+ def run(self, data_slice, slice_point=None):
398
+ if np.size(data_slice) < 2:
399
+ return self.badval
400
+
401
+ filters = np.unique(data_slice[self.filter_col])
402
+ filters = [str(f) for f in filters]
403
+ snr = np.zeros(len(data_slice), dtype="float")
404
+ # compute SNR for all observations
405
+ for filt in filters:
406
+ in_filt = np.where(data_slice[self.filter_col] == filt)
407
+ snr[in_filt] = mafUtils.m52snr(self.mags[str(filt)], data_slice[self.m5_col][in_filt])
408
+
409
+ weights = self._compute_weights(data_slice, snr)
410
+ ave_r = self._weighted_r(data_slice["ra_pi_amp"], data_slice["dec_pi_amp"], weights)
411
+ if self.theta_range > 0:
412
+ theta_check = self._theta_check(data_slice["ra_pi_amp"], data_slice["dec_pi_amp"], snr)
413
+ else:
414
+ theta_check = 1.0
415
+ result = ave_r * theta_check
416
+ return result
417
+
418
+
419
+ class ParallaxDcrDegenMetric(BaseMetric):
420
+ """Use the full parallax and DCR displacement vectors to find if they
421
+ are degenerate.
422
+
423
+ Parameters
424
+ ----------
425
+ metricName : `str`, optional
426
+ Default 'ParallaxDcrDegenMetric'.
427
+ seeing_col : `str`, optional
428
+ Default 'FWHMgeom'
429
+ m5_col : `str`, optional
430
+ Default 'fiveSigmaDepth'
431
+ filter_col : `str`
432
+ Default 'filter'
433
+ atm_err : `float`
434
+ Minimum error in photometry centroids introduced by the atmosphere
435
+ (arcseconds). Default 0.01.
436
+ rmag : `float`
437
+ r-band magnitude of the fiducual star that is being used (mag).
438
+ SedTemplate : `str`
439
+ The SED template to use for fiducia star colors,
440
+ passed to rubin_scheduler.utils.stellarMags.
441
+ Default 'flat'
442
+ tol : `float`
443
+ Tolerance for how well curve_fit needs to work before
444
+ believing the covariance result.
445
+ Default 0.05.
446
+
447
+ Returns
448
+ -------
449
+ metricValue : `float`
450
+ Returns the correlation coefficient between the best-fit parallax
451
+ amplitude and DCR amplitude.
452
+ The RA and Dec offsets are fit simultaneously.
453
+ Values close to zero are good, values close to +/- 1 are bad.
454
+ Experience with fitting Monte Carlo simulations suggests the
455
+ astrometric fits start becoming poor around a correlation of 0.7.
456
+ """
457
+
458
+ def __init__(
459
+ self,
460
+ metric_name="ParallaxDcrDegenMetric",
461
+ seeing_col="seeingFwhmGeom",
462
+ m5_col="fiveSigmaDepth",
463
+ atm_err=0.01,
464
+ rmag=20.0,
465
+ sed_template="flat",
466
+ filter_col="band",
467
+ tol=0.05,
468
+ **kwargs,
469
+ ):
470
+ self.m5_col = m5_col
471
+ self.seeing_col = seeing_col
472
+ self.filter_col = filter_col
473
+ self.tol = tol
474
+ units = "Correlation"
475
+ # just put all the columns that all the stackers will need here?
476
+ cols = [
477
+ "ra_pi_amp",
478
+ "dec_pi_amp",
479
+ "ra_dcr_amp",
480
+ "dec_dcr_amp",
481
+ seeing_col,
482
+ m5_col,
483
+ ]
484
+ super(ParallaxDcrDegenMetric, self).__init__(cols, metric_name=metric_name, units=units, **kwargs)
485
+ self.mags = {}
486
+ if sed_template == "flat":
487
+ for f in ["u", "g", "r", "i", "z", "y"]:
488
+ self.mags[f] = rmag
489
+ else:
490
+ self.mags = utils.stellarMags(sed_template, rmag=rmag)
491
+ self.atm_err = atm_err
492
+
493
+ def _positions(self, x, a, b):
494
+ """Function to find parallax and dcr amplitudes
495
+
496
+ x should be a vector with [[parallax_x1, parallax_x2...,
497
+ parallax_y1, parallax_y2...],
498
+ [dcr_x1, dcr_x2..., dcr_y1, dcr_y2...]]
499
+ """
500
+ result = a * x[0, :] + b * x[1, :]
501
+ return result
502
+
503
+ def run(self, data_slice, slice_point=None):
504
+ # The idea here is that we calculate position errors (in RA and Dec)
505
+ # for all observations. Then we generate arrays of the parallax
506
+ # offsets (delta RA parallax = ra_pi_amp, etc) and the DCR offsets
507
+ # (delta RA DCR = ra_dcr_amp, etc), and just add them together into one
508
+ # RA (and Dec) offset. Then, we try to fit for how we combined these
509
+ # offsets, but while considering the astrometric noise. If we can
510
+ # figure out that we just added them together
511
+ # (i.e. the curve_fit result is [a=1, b=1] for the function
512
+ # _positions above) then we should be able to disentangle the
513
+ # parallax and DCR offsets when fitting 'for real'.
514
+ # compute SNR for all observations
515
+ snr = np.zeros(len(data_slice), dtype="float")
516
+ for filt in np.unique(data_slice[self.filter_col]):
517
+ in_filt = np.where(data_slice[self.filter_col] == filt)
518
+ snr[in_filt] = mafUtils.m52snr(self.mags[filt], data_slice[self.m5_col][in_filt])
519
+ # Compute the centroiding uncertainties
520
+ # Note that these centroiding uncertainties depend on the physical
521
+ # size of the PSF, thus we are using seeingFwhmGeom for these metrics,
522
+ # not seeingFwhmEff.
523
+ position_errors = mafUtils.astrom_precision(data_slice[self.seeing_col], snr, self.atm_err)
524
+ # Construct the vectors of RA/Dec offsets. xdata is the "input data".
525
+ # ydata is the "output".
526
+ xdata = np.empty((2, data_slice.size * 2), dtype=float)
527
+ xdata[0, :] = np.concatenate((data_slice["ra_pi_amp"], data_slice["dec_pi_amp"]))
528
+ xdata[1, :] = np.concatenate((data_slice["ra_dcr_amp"], data_slice["dec_dcr_amp"]))
529
+ ydata = np.sum(xdata, axis=0)
530
+ # Use curve_fit to compute covariance between parallax
531
+ # and dcr amplitudes
532
+ # Set the initial guess slightly off from the correct [1,1] to
533
+ # make sure it iterates.
534
+ popt, pcov = curve_fit(
535
+ self._positions,
536
+ xdata,
537
+ ydata,
538
+ p0=[1.1, 0.9],
539
+ sigma=np.concatenate((position_errors, position_errors)),
540
+ absolute_sigma=True,
541
+ )
542
+ # Catch if the fit failed to converge on the correct solution.
543
+ if np.max(np.abs(popt - np.array([1.0, 1.0]))) > self.tol:
544
+ return self.badval
545
+ # Covariance between best fit parallax amplitude and DCR amplitude.
546
+ cov = pcov[1, 0]
547
+ # Convert covariance between parallax and DCR amplitudes to normalized
548
+ # correlation
549
+ perr = np.sqrt(np.diag(pcov))
550
+ correlation = cov / (perr[0] * perr[1])
551
+ result = correlation
552
+ # This can throw infs.
553
+ if np.isinf(result):
554
+ result = self.badval
555
+ return result
556
+
557
+
558
+ def calc_dist_cosines(ra1, dec1, ra2, dec2):
559
+ """Calculates distance on a sphere using spherical law of cosines.
560
+
561
+ Note: floats can be replaced by numpy arrays of RA/Dec.
562
+ For very small distances, rounding errors may cause distance errors.
563
+
564
+ Parameters
565
+ ----------
566
+ ra1, dec1 : `float`, `float`
567
+ RA and Dec of one point. (radians)
568
+ ra2, dec2 : `float`, `float`
569
+ RA and Dec of another point. (radians)
570
+
571
+ Returns
572
+ -------
573
+ distance : `float`
574
+ Angular distance between the points in radians.
575
+ """
576
+ # This formula can have rounding errors for case where distances are small.
577
+ # Oh, the joys of wikipedia -
578
+ # http://en.wikipedia.org/wiki/Great-circle_distance
579
+ # For the purposes of these calculations, this is probably accurate enough.
580
+ D = np.sin(dec2) * np.sin(dec1) + np.cos(dec1) * np.cos(dec2) * np.cos(ra2 - ra1)
581
+ D = np.arccos(D)
582
+ return D
583
+
584
+
585
+ class RadiusObsMetric(BaseMetric):
586
+ """Evaluate slice point radial position in the focal plane of each visit,
587
+ reducing to the mean, rms and full range of these radial distances.
588
+ """
589
+
590
+ def __init__(
591
+ self, metric_name="radiusObs", ra_col="fieldRA", dec_col="fieldDec", units="radians", **kwargs
592
+ ):
593
+ self.ra_col = ra_col
594
+ self.dec_col = dec_col
595
+ super(RadiusObsMetric, self).__init__(
596
+ col=[self.ra_col, self.dec_col], metric_name=metric_name, units=units, **kwargs
597
+ )
598
+
599
+ def run(self, data_slice, slice_point):
600
+ ra = slice_point["ra"]
601
+ dec = slice_point["dec"]
602
+ distances = calc_dist_cosines(
603
+ ra,
604
+ dec,
605
+ np.radians(data_slice[self.ra_col]),
606
+ np.radians(data_slice[self.dec_col]),
607
+ )
608
+ distances = np.degrees(distances)
609
+ return distances
610
+
611
+ def reduce_mean(self, distances):
612
+ return np.mean(distances)
613
+
614
+ def reduce_rms(self, distances):
615
+ return np.std(distances)
616
+
617
+ def reduce_full_range(self, distances):
618
+ return np.max(distances) - np.min(distances)
@@ -0,0 +1,43 @@
1
+ __all__ = ("ChipVendorMetric",)
2
+
3
+ import numpy as np
4
+
5
+ from .base_metric import BaseMetric
6
+
7
+
8
+ class ChipVendorMetric(BaseMetric):
9
+ """
10
+ See what happens if we have chips from different vendors
11
+ """
12
+
13
+ def __init__(self, cols=None, **kwargs):
14
+ if cols is None:
15
+ cols = []
16
+ super(ChipVendorMetric, self).__init__(
17
+ col=cols, metric_dtype=float, units="1,2,3:v1,v2,both", **kwargs
18
+ )
19
+
20
+ def _chip_names2vendor_id(self, chip_name):
21
+ """
22
+ given a list of chipnames, convert to 1 or 2, representing
23
+ different vendors
24
+ """
25
+ vendors = []
26
+ for chip in chip_name:
27
+ # Parse the chip_name string.
28
+ if int(chip[2]) % 2 == 0:
29
+ vendors.append(1)
30
+ else:
31
+ vendors.append(2)
32
+ return vendors
33
+
34
+ def run(self, data_slice, slice_point=None):
35
+ if "chipNames" not in list(slice_point.keys()):
36
+ raise ValueError("No chipname info, need to set use_camera=True with a spatial slicer.")
37
+
38
+ uvendor_i_ds = np.unique(self._chip_names2vendor_id(slice_point["chipNames"]))
39
+ if np.size(uvendor_i_ds) == 1:
40
+ result = uvendor_i_ds
41
+ else:
42
+ result = 3
43
+ return result