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.
- batch/compile_prenight_metadata_cache.sh +34 -0
- batch/run_auxtel_prenight_sims.sh +163 -0
- batch/run_prenight_sims.sh +239 -0
- docs/.gitignore +3 -0
- docs/Makefile +32 -0
- docs/api.rst +25 -0
- docs/conf.py +8 -0
- docs/data-api.rst +12 -0
- docs/data-download.rst +70 -0
- docs/developer.rst +14 -0
- docs/documenteer.toml +11 -0
- docs/index.rst +22 -0
- docs/installation.rst +76 -0
- docs/introduction.rst +37 -0
- docs/maf-api-batches.rst +12 -0
- docs/maf-api-db.rst +12 -0
- docs/maf-api-maf-contrib.rst +12 -0
- docs/maf-api-maps.rst +12 -0
- docs/maf-api-metricbundles.rst +12 -0
- docs/maf-api-metrics.rst +12 -0
- docs/maf-api-plots.rst +12 -0
- docs/maf-api-run-comparison.rst +12 -0
- docs/maf-api-slicers.rst +12 -0
- docs/maf-api-stackers.rst +12 -0
- docs/maf-api-utils.rst +12 -0
- docs/maf-api.rst +22 -0
- docs/maf.rst +60 -0
- docs/metric_list.py +49 -0
- docs/moving-objects-api.rst +12 -0
- docs/moving-objects.rst +22 -0
- docs/phot-utils-api.rst +12 -0
- docs/phot-utils.rst +11 -0
- docs/prenight.rst +117 -0
- docs/protoarchive.rst +276 -0
- docs/satellite-constellations-api.rst +12 -0
- docs/satellite-constellations.rst +13 -0
- docs/selfcal-api.rst +12 -0
- docs/selfcal.rst +15 -0
- docs/sim-archive-api.rst +12 -0
- docs/skybrightness-api.rst +12 -0
- docs/skybrightness.rst +23 -0
- docs/user-guide.rst +28 -0
- docs/vseqarchive-architecture.rst +438 -0
- docs/vseqarchive-setup.rst +238 -0
- docs/vseqarchive.rst +225 -0
- rubin_sim/__init__.py +7 -0
- rubin_sim/data/__init__.py +1 -0
- rubin_sim/data/rs_download_data.py +155 -0
- rubin_sim/maf/__init__.py +34 -0
- rubin_sim/maf/batches/__init__.py +18 -0
- rubin_sim/maf/batches/altaz_batch.py +161 -0
- rubin_sim/maf/batches/col_map_dict.py +274 -0
- rubin_sim/maf/batches/common.py +388 -0
- rubin_sim/maf/batches/ddf_batch.py +728 -0
- rubin_sim/maf/batches/filterchange_batch.py +182 -0
- rubin_sim/maf/batches/glance_batch.py +591 -0
- rubin_sim/maf/batches/hourglass_batch.py +79 -0
- rubin_sim/maf/batches/info_batch.py +114 -0
- rubin_sim/maf/batches/metadata_batch.py +558 -0
- rubin_sim/maf/batches/moving_objects_batch.py +1587 -0
- rubin_sim/maf/batches/openshutter_batch.py +100 -0
- rubin_sim/maf/batches/radar_limited.py +1100 -0
- rubin_sim/maf/batches/science_radar_batch.py +1910 -0
- rubin_sim/maf/batches/skycoverage.py +155 -0
- rubin_sim/maf/batches/slew_batch.py +146 -0
- rubin_sim/maf/batches/srd_batch.py +637 -0
- rubin_sim/maf/batches/time_batch.py +757 -0
- rubin_sim/maf/batches/time_sci_batch.py +105 -0
- rubin_sim/maf/batches/visitdepth_batch.py +485 -0
- rubin_sim/maf/db/__init__.py +2 -0
- rubin_sim/maf/db/add_run.py +34 -0
- rubin_sim/maf/db/results_db.py +1074 -0
- rubin_sim/maf/db/tracking_db.py +332 -0
- rubin_sim/maf/ddf_dir.py +53 -0
- rubin_sim/maf/generate_ss.py +218 -0
- rubin_sim/maf/glance_dir.py +58 -0
- rubin_sim/maf/maf_contrib/__init__.py +25 -0
- rubin_sim/maf/maf_contrib/calculate_lsst_field_visibility_astropy.py +170 -0
- rubin_sim/maf/maf_contrib/depth_limited_num_gal_metric.py +109 -0
- rubin_sim/maf/maf_contrib/example_new_metrics.py +40 -0
- rubin_sim/maf/maf_contrib/filter_pair_t_gaps_metric.py +208 -0
- rubin_sim/maf/maf_contrib/grb_transient_metric.py +249 -0
- rubin_sim/maf/maf_contrib/gw170817_det_metric.py +72 -0
- rubin_sim/maf/maf_contrib/intervals_between_obs_metric.py +68 -0
- rubin_sim/maf/maf_contrib/kne_metrics.py +473 -0
- rubin_sim/maf/maf_contrib/lss_metrics.py +45 -0
- rubin_sim/maf/maf_contrib/lss_obs_strategy/__init__.py +3 -0
- rubin_sim/maf/maf_contrib/lss_obs_strategy/constants_for_pipeline.py +73 -0
- rubin_sim/maf/maf_contrib/lss_obs_strategy/galaxy_counts_metric_extended.py +205 -0
- rubin_sim/maf/maf_contrib/lss_obs_strategy/galaxy_counts_with_pixel_calibration.py +171 -0
- rubin_sim/maf/maf_contrib/lv_dwarfs/__init__.py +1 -0
- rubin_sim/maf/maf_contrib/lv_dwarfs/lv_dwarfs_metrics.py +388 -0
- rubin_sim/maf/maf_contrib/microlensing_metric.py +593 -0
- rubin_sim/maf/maf_contrib/num_obs_in_survey_time_overlap_metric.py +43 -0
- rubin_sim/maf/maf_contrib/periodic_metric.py +51 -0
- rubin_sim/maf/maf_contrib/periodic_star_metric.py +186 -0
- rubin_sim/maf/maf_contrib/periodic_star_modulation_metric.py +236 -0
- rubin_sim/maf/maf_contrib/presto_color_kne_pop_metric.py +441 -0
- rubin_sim/maf/maf_contrib/selfcal_uniformity_metric.py +171 -0
- rubin_sim/maf/maf_contrib/star_count_mass_metric.py +64 -0
- rubin_sim/maf/maf_contrib/star_count_metric.py +56 -0
- rubin_sim/maf/maf_contrib/star_counts/__init__.py +8 -0
- rubin_sim/maf/maf_contrib/star_counts/abs_mag.py +324 -0
- rubin_sim/maf/maf_contrib/star_counts/coords.py +99 -0
- rubin_sim/maf/maf_contrib/star_counts/readme.txt +1 -0
- rubin_sim/maf/maf_contrib/star_counts/spec_type.py +91 -0
- rubin_sim/maf/maf_contrib/star_counts/starcount.py +30 -0
- rubin_sim/maf/maf_contrib/star_counts/starcount_bymass.py +93 -0
- rubin_sim/maf/maf_contrib/star_counts/stellardensity.py +59 -0
- rubin_sim/maf/maf_contrib/static_probes_fom_summary_metric.py +386 -0
- rubin_sim/maf/maf_contrib/tdes_pop_metric.py +362 -0
- rubin_sim/maf/maf_contrib/transient_ascii_sed_metric.py +652 -0
- rubin_sim/maf/maf_contrib/triplet_metric.py +156 -0
- rubin_sim/maf/maf_contrib/var_depth_metric.py +157 -0
- rubin_sim/maf/maf_contrib/xrb_metrics.py +523 -0
- rubin_sim/maf/maf_contrib/young_stellar_objects_metric.py +200 -0
- rubin_sim/maf/maf_night_report.py +200 -0
- rubin_sim/maf/make_fbs_tracking_db.py +90 -0
- rubin_sim/maf/maps/__init__.py +8 -0
- rubin_sim/maf/maps/base_map.py +72 -0
- rubin_sim/maf/maps/create_gaia_density_map.py +158 -0
- rubin_sim/maf/maps/dust_map.py +66 -0
- rubin_sim/maf/maps/dust_map_3d.py +190 -0
- rubin_sim/maf/maps/ebv_3d_hp.py +170 -0
- rubin_sim/maf/maps/ebv_hp.py +64 -0
- rubin_sim/maf/maps/gal_coords_map.py +22 -0
- rubin_sim/maf/maps/galactic_plane_priority_maps.py +210 -0
- rubin_sim/maf/maps/stellar_density_map.py +73 -0
- rubin_sim/maf/maps/trilegal_map.py +82 -0
- rubin_sim/maf/metadata_dir.py +90 -0
- rubin_sim/maf/metric_bundles/__init__.py +3 -0
- rubin_sim/maf/metric_bundles/metric_bundle.py +816 -0
- rubin_sim/maf/metric_bundles/metric_bundle_group.py +834 -0
- rubin_sim/maf/metric_bundles/mo_metric_bundle.py +646 -0
- rubin_sim/maf/metrics/__init__.py +52 -0
- rubin_sim/maf/metrics/agn_time_lag_metric.py +118 -0
- rubin_sim/maf/metrics/agnstructure.py +141 -0
- rubin_sim/maf/metrics/area_summary_metrics.py +120 -0
- rubin_sim/maf/metrics/base_metric.py +215 -0
- rubin_sim/maf/metrics/brown_dwarf_metric.py +162 -0
- rubin_sim/maf/metrics/cadence_metrics.py +400 -0
- rubin_sim/maf/metrics/calibration_metrics.py +618 -0
- rubin_sim/maf/metrics/chip_vendor_metric.py +43 -0
- rubin_sim/maf/metrics/color_slope_metrics.py +189 -0
- rubin_sim/maf/metrics/cosmology_summary_metrics.py +1212 -0
- rubin_sim/maf/metrics/coverage_metric.py +48 -0
- rubin_sim/maf/metrics/crowding_metric.py +255 -0
- rubin_sim/maf/metrics/cumulative_metric.py +46 -0
- rubin_sim/maf/metrics/dcr_metric.py +93 -0
- rubin_sim/maf/metrics/exgal_m5.py +57 -0
- rubin_sim/maf/metrics/fft_metric.py +27 -0
- rubin_sim/maf/metrics/galactic_plane_metrics.py +375 -0
- rubin_sim/maf/metrics/galplane_time_sampling_metrics.py +236 -0
- rubin_sim/maf/metrics/hourglass_metric.py +130 -0
- rubin_sim/maf/metrics/incremental_template_metric.py +255 -0
- rubin_sim/maf/metrics/kuiper_metrics.py +26 -0
- rubin_sim/maf/metrics/mo_metrics.py +1496 -0
- rubin_sim/maf/metrics/mo_summary_metrics.py +464 -0
- rubin_sim/maf/metrics/night_pointing_metric.py +70 -0
- rubin_sim/maf/metrics/optimal_m5_metric.py +94 -0
- rubin_sim/maf/metrics/pair_metric.py +69 -0
- rubin_sim/maf/metrics/periodic_detect_metric.py +133 -0
- rubin_sim/maf/metrics/phase_gap_metric.py +172 -0
- rubin_sim/maf/metrics/qso_number_counts_metric.py +138 -0
- rubin_sim/maf/metrics/scaling_metrics.py +148 -0
- rubin_sim/maf/metrics/schedview_metrics.py +39 -0
- rubin_sim/maf/metrics/season_metrics.py +344 -0
- rubin_sim/maf/metrics/simple_metrics.py +546 -0
- rubin_sim/maf/metrics/sky_sat_metric.py +18 -0
- rubin_sim/maf/metrics/sn_cadence_metric.py +104 -0
- rubin_sim/maf/metrics/sn_n_sn_metric.py +1364 -0
- rubin_sim/maf/metrics/sn_sl_metric.py +216 -0
- rubin_sim/maf/metrics/sn_snr_metric.py +715 -0
- rubin_sim/maf/metrics/snr_weight.py +24 -0
- rubin_sim/maf/metrics/star_density.py +77 -0
- rubin_sim/maf/metrics/string_count_metric.py +95 -0
- rubin_sim/maf/metrics/summary_metrics.py +201 -0
- rubin_sim/maf/metrics/surfb_metric.py +175 -0
- rubin_sim/maf/metrics/technical_metrics.py +271 -0
- rubin_sim/maf/metrics/tgaps.py +412 -0
- rubin_sim/maf/metrics/tomography_models.py +2034 -0
- rubin_sim/maf/metrics/transient_metrics.py +268 -0
- rubin_sim/maf/metrics/uniformity_metrics.py +418 -0
- rubin_sim/maf/metrics/use_metrics.py +55 -0
- rubin_sim/maf/metrics/vector_metrics.py +190 -0
- rubin_sim/maf/metrics/visit_groups_metric.py +341 -0
- rubin_sim/maf/metrics/weak_lensing_systematics_metric.py +210 -0
- rubin_sim/maf/plots/__init__.py +14 -0
- rubin_sim/maf/plots/hg_plotters.py +1117 -0
- rubin_sim/maf/plots/hourglass_plotters.py +120 -0
- rubin_sim/maf/plots/mo_plotters.py +358 -0
- rubin_sim/maf/plots/nd_plotters.py +220 -0
- rubin_sim/maf/plots/neo_distance_plotter.py +140 -0
- rubin_sim/maf/plots/night_pointing_plotter.py +96 -0
- rubin_sim/maf/plots/oned_plotters.py +114 -0
- rubin_sim/maf/plots/perceptual_rainbow.py +30 -0
- rubin_sim/maf/plots/plot_handler.py +766 -0
- rubin_sim/maf/plots/skyproj_plotters.py +540 -0
- rubin_sim/maf/plots/spatial_plotters.py +1029 -0
- rubin_sim/maf/plots/special_plotters.py +256 -0
- rubin_sim/maf/plots/two_d_plotters.py +177 -0
- rubin_sim/maf/plots/xyplotter.py +37 -0
- rubin_sim/maf/run_comparison/__init__.py +5 -0
- rubin_sim/maf/run_comparison/archive.py +584 -0
- rubin_sim/maf/run_comparison/gather_summaries.py +125 -0
- rubin_sim/maf/run_comparison/microlensing_compare.py +514 -0
- rubin_sim/maf/run_comparison/radar_plot.py +202 -0
- rubin_sim/maf/run_comparison/summary_plots.py +710 -0
- rubin_sim/maf/run_moving_calc.py +239 -0
- rubin_sim/maf/run_moving_fractions.py +128 -0
- rubin_sim/maf/run_moving_join.py +103 -0
- rubin_sim/maf/run_selfcal_metric.py +92 -0
- rubin_sim/maf/scimaf_dir.py +87 -0
- rubin_sim/maf/show_maf.py +227 -0
- rubin_sim/maf/slicers/__init__.py +13 -0
- rubin_sim/maf/slicers/base_slicer.py +513 -0
- rubin_sim/maf/slicers/base_spatial_slicer.py +202 -0
- rubin_sim/maf/slicers/healpix_sdss_slicer.py +118 -0
- rubin_sim/maf/slicers/healpix_slicer.py +189 -0
- rubin_sim/maf/slicers/healpix_subset_slicer.py +293 -0
- rubin_sim/maf/slicers/hourglass_slicer.py +37 -0
- rubin_sim/maf/slicers/mo_slicer.py +171 -0
- rubin_sim/maf/slicers/movie_slicer.py +288 -0
- rubin_sim/maf/slicers/nd_slicer.py +147 -0
- rubin_sim/maf/slicers/one_d_slicer.py +210 -0
- rubin_sim/maf/slicers/time_interval_slicers.py +283 -0
- rubin_sim/maf/slicers/uni_slicer.py +57 -0
- rubin_sim/maf/slicers/user_points_slicer.py +141 -0
- rubin_sim/maf/stackers/__init__.py +13 -0
- rubin_sim/maf/stackers/base_stacker.py +221 -0
- rubin_sim/maf/stackers/coord_stackers.py +224 -0
- rubin_sim/maf/stackers/date_stackers.py +192 -0
- rubin_sim/maf/stackers/general_stackers.py +683 -0
- rubin_sim/maf/stackers/get_col_info.py +104 -0
- rubin_sim/maf/stackers/label_stackers.py +114 -0
- rubin_sim/maf/stackers/m5_optimal_stacker.py +126 -0
- rubin_sim/maf/stackers/mo_phase.py +265 -0
- rubin_sim/maf/stackers/mo_stackers.py +486 -0
- rubin_sim/maf/stackers/n_follow_stacker.py +187 -0
- rubin_sim/maf/stackers/neo_dist_stacker.py +126 -0
- rubin_sim/maf/stackers/sdss_stackers.py +30 -0
- rubin_sim/maf/stackers/sn_stacker.py +152 -0
- rubin_sim/maf/stackers/teff_stacker.py +154 -0
- rubin_sim/maf/utils/__init__.py +6 -0
- rubin_sim/maf/utils/astrometry_utils.py +93 -0
- rubin_sim/maf/utils/generate_fov_map.py +58 -0
- rubin_sim/maf/utils/get_date_version.py +28 -0
- rubin_sim/maf/utils/maf_utils.py +212 -0
- rubin_sim/maf/utils/opsim_utils.py +259 -0
- rubin_sim/maf/utils/output_utils.py +34 -0
- rubin_sim/maf/utils/sn_n_sn_utils.py +894 -0
- rubin_sim/maf/utils/sn_utils.py +369 -0
- rubin_sim/maf/utils/stellar_mags.py +197 -0
- rubin_sim/maf/web/__init__.py +2 -0
- rubin_sim/maf/web/favicon.ico +0 -0
- rubin_sim/maf/web/maf_run_results.py +645 -0
- rubin_sim/maf/web/maf_tracking.py +139 -0
- rubin_sim/maf/web/sorttable.js +496 -0
- rubin_sim/maf/web/templates/allmetricresults.html +72 -0
- rubin_sim/maf/web/templates/configs.html +28 -0
- rubin_sim/maf/web/templates/macros.html +243 -0
- rubin_sim/maf/web/templates/master.html +294 -0
- rubin_sim/maf/web/templates/metricselect.html +91 -0
- rubin_sim/maf/web/templates/multicolor.html +147 -0
- rubin_sim/maf/web/templates/results.html +82 -0
- rubin_sim/maf/web/templates/runselect.html +58 -0
- rubin_sim/maf/web/templates/stats.html +50 -0
- rubin_sim/moving_objects/__init__.py +8 -0
- rubin_sim/moving_objects/base_obs.py +468 -0
- rubin_sim/moving_objects/cheby_fits.py +689 -0
- rubin_sim/moving_objects/cheby_values.py +231 -0
- rubin_sim/moving_objects/chebyshev_utils.py +365 -0
- rubin_sim/moving_objects/direct_obs.py +376 -0
- rubin_sim/moving_objects/make_lsst_obs.py +282 -0
- rubin_sim/moving_objects/ooephemerides.py +643 -0
- rubin_sim/moving_objects/orbits.py +507 -0
- rubin_sim/moving_objects/pre_generate.py +37 -0
- rubin_sim/moving_objects/utils.py +61 -0
- rubin_sim/phot_utils/__init__.py +7 -0
- rubin_sim/phot_utils/bandpass.py +425 -0
- rubin_sim/phot_utils/photometric_parameters.py +449 -0
- rubin_sim/phot_utils/physical_parameters.py +50 -0
- rubin_sim/phot_utils/predicted_zeropoints.py +245 -0
- rubin_sim/phot_utils/sed.py +1773 -0
- rubin_sim/phot_utils/sed_utils.py +52 -0
- rubin_sim/phot_utils/signaltonoise.py +695 -0
- rubin_sim/phot_utils/spectral_resampling.py +161 -0
- rubin_sim/satellite_constellations/__init__.py +3 -0
- rubin_sim/satellite_constellations/basis_function.py +40 -0
- rubin_sim/satellite_constellations/model_observatory.py +157 -0
- rubin_sim/satellite_constellations/sat_utils.py +488 -0
- rubin_sim/selfcal/__init__.py +4 -0
- rubin_sim/selfcal/generate_catalog.py +188 -0
- rubin_sim/selfcal/offsets.py +119 -0
- rubin_sim/selfcal/solver.py +143 -0
- rubin_sim/selfcal/star_tools.py +42 -0
- rubin_sim/sim_archive/__init__.py +14 -0
- rubin_sim/sim_archive/conda_packages.py +65 -0
- rubin_sim/sim_archive/future_vsarch.py +480 -0
- rubin_sim/sim_archive/make_snapshot.py +255 -0
- rubin_sim/sim_archive/prenight.py +216 -0
- rubin_sim/sim_archive/prenightindex.py +229 -0
- rubin_sim/sim_archive/prototype.py +1029 -0
- rubin_sim/sim_archive/sim_archive.py +680 -0
- rubin_sim/sim_archive/tempdb.py +56 -0
- rubin_sim/sim_archive/util.py +146 -0
- rubin_sim/sim_archive/vseqarchive.py +965 -0
- rubin_sim/sim_archive/vseqmetadata.py +1721 -0
- rubin_sim/skybrightness/__init__.py +5 -0
- rubin_sim/skybrightness/allsky_db.py +93 -0
- rubin_sim/skybrightness/data/ESO_Spectra/eso_tools.py +505 -0
- rubin_sim/skybrightness/data/solarSpec/package.py +22 -0
- rubin_sim/skybrightness/generate_hdf5.py +243 -0
- rubin_sim/skybrightness/interp_components.py +798 -0
- rubin_sim/skybrightness/sky_model.py +771 -0
- rubin_sim/skybrightness/twilight_func.py +83 -0
- rubin_sim/skybrightness/utils.py +91 -0
- rubin_sim-2.6.1.dev2.dist-info/METADATA +95 -0
- rubin_sim-2.6.1.dev2.dist-info/RECORD +387 -0
- rubin_sim-2.6.1.dev2.dist-info/WHEEL +5 -0
- rubin_sim-2.6.1.dev2.dist-info/entry_points.txt +24 -0
- rubin_sim-2.6.1.dev2.dist-info/licenses/LICENSE +674 -0
- rubin_sim-2.6.1.dev2.dist-info/top_level.txt +5 -0
- sql/make_vseqmeta.sql +251 -0
- tests/data/test_data.py +26 -0
- tests/data/test_ddf_grid.py +17 -0
- tests/maf/test_3x2fom.py +68 -0
- tests/maf/test_archive.py +162 -0
- tests/maf/test_basemetrics.py +99 -0
- tests/maf/test_batchcommon.py +36 -0
- tests/maf/test_batches.py +159 -0
- tests/maf/test_cadencemetrics.py +388 -0
- tests/maf/test_calibrationmetrics.py +242 -0
- tests/maf/test_color_slopes.py +71 -0
- tests/maf/test_cosmology_summaries.py +20 -0
- tests/maf/test_gathersummaries.py +48 -0
- tests/maf/test_healpixslicer.py +439 -0
- tests/maf/test_healpixsubsetslicer.py +273 -0
- tests/maf/test_hgplotters.py +145 -0
- tests/maf/test_hourglassmetric.py +33 -0
- tests/maf/test_io.py +187 -0
- tests/maf/test_json.py +169 -0
- tests/maf/test_maps.py +199 -0
- tests/maf/test_metricbundle.py +69 -0
- tests/maf/test_mometrics.py +422 -0
- tests/maf/test_movieslicer.py +216 -0
- tests/maf/test_ndslicer.py +240 -0
- tests/maf/test_neodistanceplotter.py +41 -0
- tests/maf/test_onedslicer.py +245 -0
- tests/maf/test_opsimutils.py +80 -0
- tests/maf/test_plotters.py +134 -0
- tests/maf/test_resultsdb.py +145 -0
- tests/maf/test_schedviewmetrics.py +14 -0
- tests/maf/test_simplemetrics.py +200 -0
- tests/maf/test_snmetrics.py +335 -0
- tests/maf/test_snmetrics_nsn.py +123 -0
- tests/maf/test_stackers.py +423 -0
- tests/maf/test_stellarmags.py +50 -0
- tests/maf/test_stringcount.py +26 -0
- tests/maf/test_summary_plots.py +197 -0
- tests/maf/test_summarymetrics.py +82 -0
- tests/maf/test_technicalmetrics.py +267 -0
- tests/maf/test_templatemetrics.py +86 -0
- tests/maf/test_timeintervalslicers.py +97 -0
- tests/maf/test_trackingdb.py +88 -0
- tests/maf/test_unislicer.py +116 -0
- tests/maf/test_vectormetrics.py +225 -0
- tests/maf/test_visitgroupsmetric.py +181 -0
- tests/moving_objects/test_camera.py +39 -0
- tests/moving_objects/test_chebyfits.py +188 -0
- tests/moving_objects/test_chebyshevutils.py +76 -0
- tests/moving_objects/test_chebyvalues.py +245 -0
- tests/moving_objects/test_ephemerides.py +219 -0
- tests/moving_objects/test_orbits.py +170 -0
- tests/moving_objects/test_sed_data.py +61 -0
- tests/phot_utils/test_approximatebandpasses.py +91 -0
- tests/phot_utils/test_photometricparameters.py +268 -0
- tests/phot_utils/test_photometry.py +61 -0
- tests/phot_utils/test_predicted_zeropoints.py +53 -0
- tests/phot_utils/test_read_bandpasses.py +29 -0
- tests/phot_utils/test_sed.py +368 -0
- tests/phot_utils/test_snr.py +370 -0
- tests/satellite_constellations/test_satellites.py +36 -0
- tests/sim_archive/test_make_snapshot.py +24 -0
- tests/sim_archive/test_prototype_sim_archive.py +204 -0
- tests/sim_archive/test_vseqarchive.py +947 -0
- tests/skybrightness/test_skymodel.py +359 -0
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
__all__ = (
|
|
2
|
+
"NormAirmassStacker",
|
|
3
|
+
"ParallaxFactorStacker",
|
|
4
|
+
"HourAngleStacker",
|
|
5
|
+
"ZenithDistStacker",
|
|
6
|
+
"ParallacticAngleStacker",
|
|
7
|
+
"DcrStacker",
|
|
8
|
+
"FiveSigmaStacker",
|
|
9
|
+
"SaturationStacker",
|
|
10
|
+
"OverheadStacker",
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
import warnings
|
|
14
|
+
|
|
15
|
+
import astropy.units as u
|
|
16
|
+
import numpy as np
|
|
17
|
+
from astropy.coordinates import GCRS, SkyCoord
|
|
18
|
+
from astropy.time import Time
|
|
19
|
+
from rubin_scheduler.utils import Site, m5_flat_sed
|
|
20
|
+
|
|
21
|
+
from rubin_sim.maf.utils import load_inst_zeropoints
|
|
22
|
+
|
|
23
|
+
from .base_stacker import BaseStacker
|
|
24
|
+
from .date_stackers import DayObsMJDStacker
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class SaturationStacker(BaseStacker):
|
|
28
|
+
"""Adds a calculated point-source saturation limit for each visit.
|
|
29
|
+
|
|
30
|
+
Assumes Gaussian PSF.
|
|
31
|
+
|
|
32
|
+
Parameters
|
|
33
|
+
----------
|
|
34
|
+
pixscale : `float`, optional
|
|
35
|
+
Arcsec per pixel.
|
|
36
|
+
saturation_e : `float`, optional
|
|
37
|
+
The saturation level in electrons.
|
|
38
|
+
zeropoints : dict-like, optional
|
|
39
|
+
The zeropoints for the telescope.
|
|
40
|
+
Keys should be str with filter names, values in mags.
|
|
41
|
+
Default of None, will use Rubin calculated zeropoints.
|
|
42
|
+
km : dict-like, optional
|
|
43
|
+
Atmospheric extinction values.
|
|
44
|
+
Keys should be str with filter names.
|
|
45
|
+
If None, will use Rubin calculated atmospheric extinction values.
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
cols_added = ["saturation_mag"]
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
seeing_col="seeingFwhmEff",
|
|
53
|
+
skybrightness_col="skyBrightness",
|
|
54
|
+
exptime_col="visitExposureTime",
|
|
55
|
+
nexp_col="numExposures",
|
|
56
|
+
filter_col="band",
|
|
57
|
+
airmass_col="airmass",
|
|
58
|
+
saturation_e=150e3,
|
|
59
|
+
zeropoints=None,
|
|
60
|
+
km=None,
|
|
61
|
+
pixscale=0.2,
|
|
62
|
+
):
|
|
63
|
+
self.units = ["mag"]
|
|
64
|
+
self.cols_req = [
|
|
65
|
+
seeing_col,
|
|
66
|
+
skybrightness_col,
|
|
67
|
+
exptime_col,
|
|
68
|
+
nexp_col,
|
|
69
|
+
filter_col,
|
|
70
|
+
airmass_col,
|
|
71
|
+
]
|
|
72
|
+
self.seeing_col = seeing_col
|
|
73
|
+
self.skybrightness_col = skybrightness_col
|
|
74
|
+
self.exptime_col = exptime_col
|
|
75
|
+
self.nexp_col = nexp_col
|
|
76
|
+
self.filter_col = filter_col
|
|
77
|
+
self.airmass_col = airmass_col
|
|
78
|
+
self.saturation_e = saturation_e
|
|
79
|
+
self.pixscale = pixscale
|
|
80
|
+
self.zeropoints = zeropoints
|
|
81
|
+
self.km = km
|
|
82
|
+
|
|
83
|
+
def _run(self, sim_data, cols_present=False):
|
|
84
|
+
if self.zeropoints is None:
|
|
85
|
+
zp_inst, k_atm = load_inst_zeropoints()
|
|
86
|
+
self.zeropoints = zp_inst
|
|
87
|
+
if self.km is None:
|
|
88
|
+
self.km = k_atm
|
|
89
|
+
for filtername in np.unique(sim_data[self.filter_col]):
|
|
90
|
+
in_filt = np.where(sim_data[self.filter_col] == filtername)[0]
|
|
91
|
+
# Calculate the length of the on-sky time per EXPOSURE
|
|
92
|
+
exptime = sim_data[self.exptime_col][in_filt] / sim_data[self.nexp_col][in_filt]
|
|
93
|
+
# Calculate sky counts per pixel per second
|
|
94
|
+
# from skybrightness + zeropoint (e/1s)
|
|
95
|
+
sky_counts = (
|
|
96
|
+
10.0 ** (0.4 * (self.zeropoints[filtername] - sim_data[self.skybrightness_col][in_filt]))
|
|
97
|
+
* self.pixscale**2
|
|
98
|
+
)
|
|
99
|
+
# Total sky counts in each exposure
|
|
100
|
+
sky_counts = sky_counts * exptime
|
|
101
|
+
# The counts available to the source (at peak) in each exposure is
|
|
102
|
+
# the difference between saturation and sky
|
|
103
|
+
remaining_counts_peak = self.saturation_e - sky_counts
|
|
104
|
+
# Now to figure out how many counts there would be total, if there
|
|
105
|
+
# are that many in the peak
|
|
106
|
+
sigma = sim_data[self.seeing_col][in_filt] / 2.354
|
|
107
|
+
source_counts = remaining_counts_peak * 2.0 * np.pi * (sigma / self.pixscale) ** 2
|
|
108
|
+
# source counts = counts per exposure (expTimeCol / nexp)
|
|
109
|
+
# Translate to counts per second, to apply zeropoint
|
|
110
|
+
count_rate = source_counts / exptime
|
|
111
|
+
sim_data["saturation_mag"][in_filt] = -2.5 * np.log10(count_rate) + self.zeropoints[filtername]
|
|
112
|
+
# Airmass correction
|
|
113
|
+
sim_data["saturation_mag"][in_filt] -= self.km[filtername] * (
|
|
114
|
+
sim_data[self.airmass_col][in_filt] - 1.0
|
|
115
|
+
)
|
|
116
|
+
# Explicitly make sure if sky has saturated we return NaN
|
|
117
|
+
sim_data["saturation_mag"][np.where(remaining_counts_peak < 0)] = np.nan
|
|
118
|
+
|
|
119
|
+
return sim_data
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class NoteRootStacker(BaseStacker):
|
|
123
|
+
"""Strip off things after a comma in the scheduler_note"""
|
|
124
|
+
|
|
125
|
+
cols_added = ["scheduler_note_root"]
|
|
126
|
+
|
|
127
|
+
def __init__(self, note_col="scheduler_note"):
|
|
128
|
+
self.units = ["mag"]
|
|
129
|
+
self.cols_req = [note_col]
|
|
130
|
+
self.note_col = note_col
|
|
131
|
+
self.cols_added_dtypes = ["<U50"]
|
|
132
|
+
|
|
133
|
+
def _run(self, sim_data, cols_present=False):
|
|
134
|
+
if cols_present:
|
|
135
|
+
# Column already present in data; assume it is fine.
|
|
136
|
+
return sim_data
|
|
137
|
+
new_note = [note.split(",")[0] for note in sim_data[self.note_col]]
|
|
138
|
+
sim_data["scheduler_note_root"] = new_note
|
|
139
|
+
return sim_data
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class FiveSigmaStacker(BaseStacker):
|
|
143
|
+
"""Calculate the 5-sigma limiting depth for a point source in the given
|
|
144
|
+
conditions.
|
|
145
|
+
|
|
146
|
+
This is generally not needed, unless the m5 parameters have been updated
|
|
147
|
+
or m5 was not previously calculated.
|
|
148
|
+
|
|
149
|
+
Parameters
|
|
150
|
+
----------
|
|
151
|
+
airmass_col : `str`, optional
|
|
152
|
+
Name of the airmass column in the data.
|
|
153
|
+
seeing_col : `str`, optional
|
|
154
|
+
Name of the seeing column in the data.
|
|
155
|
+
(FWHM of the single-Gaussian PSF)
|
|
156
|
+
skybrightness_col : `str`, optional
|
|
157
|
+
Name of the skybrightness column in the data.
|
|
158
|
+
filter_col : `str`, optional
|
|
159
|
+
Name of the filter bandpass column in the data.
|
|
160
|
+
exptime_col : `str`, optional
|
|
161
|
+
Name of the on-sky exposure time column in the data.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
cols_added = ["m5_simsUtils"]
|
|
165
|
+
|
|
166
|
+
def __init__(
|
|
167
|
+
self,
|
|
168
|
+
airmass_col="airmass",
|
|
169
|
+
seeing_col="seeingFwhmEff",
|
|
170
|
+
skybrightness_col="skyBrightness",
|
|
171
|
+
filter_col="band",
|
|
172
|
+
exptime_col="visitExposureTime",
|
|
173
|
+
):
|
|
174
|
+
self.units = ["mag"]
|
|
175
|
+
self.cols_req = [
|
|
176
|
+
airmass_col,
|
|
177
|
+
seeing_col,
|
|
178
|
+
skybrightness_col,
|
|
179
|
+
filter_col,
|
|
180
|
+
exptime_col,
|
|
181
|
+
]
|
|
182
|
+
self.airmass_col = airmass_col
|
|
183
|
+
self.seeing_col = seeing_col
|
|
184
|
+
self.skybrightness_col = skybrightness_col
|
|
185
|
+
self.filter_col = filter_col
|
|
186
|
+
self.exptime_col = exptime_col
|
|
187
|
+
|
|
188
|
+
def _run(self, sim_data, cols_present=False):
|
|
189
|
+
if cols_present:
|
|
190
|
+
# Column already present in data; assume it is fine.
|
|
191
|
+
return sim_data
|
|
192
|
+
filts = np.unique(sim_data[self.filter_col])
|
|
193
|
+
for filtername in filts:
|
|
194
|
+
infilt = np.where(sim_data[self.filter_col] == filtername)
|
|
195
|
+
sim_data["m5_simsUtils"][infilt] = m5_flat_sed(
|
|
196
|
+
filtername,
|
|
197
|
+
sim_data[infilt][self.skybrightness_col],
|
|
198
|
+
sim_data[infilt][self.seeing_col],
|
|
199
|
+
sim_data[infilt][self.exptime_col],
|
|
200
|
+
sim_data[infilt][self.airmass_col],
|
|
201
|
+
)
|
|
202
|
+
return sim_data
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class NormAirmassStacker(BaseStacker):
|
|
206
|
+
"""Adds a calculated normairmass for each pointing.
|
|
207
|
+
|
|
208
|
+
The normalized airmass is the airmass divided by the minimum airmass
|
|
209
|
+
achievable at each pointing (which is defined by the declination of
|
|
210
|
+
the field).
|
|
211
|
+
|
|
212
|
+
Parameters
|
|
213
|
+
----------
|
|
214
|
+
airmass_col : `str`, optional
|
|
215
|
+
The name of the airmass column in the data.
|
|
216
|
+
dec_col : `str`, optional
|
|
217
|
+
The name of the declination column in the data.
|
|
218
|
+
degrees : `bool`, optional
|
|
219
|
+
If True, angle columns are assumed to be in degrees and returned in
|
|
220
|
+
degrees. If False, uses and calculates radians.
|
|
221
|
+
telescope_lat : `float`, optional
|
|
222
|
+
The latitude of the telescope, in degrees.
|
|
223
|
+
"""
|
|
224
|
+
|
|
225
|
+
cols_added = ["normairmass"]
|
|
226
|
+
|
|
227
|
+
def __init__(
|
|
228
|
+
self,
|
|
229
|
+
airmass_col="airmass",
|
|
230
|
+
dec_col="fieldDec",
|
|
231
|
+
degrees=True,
|
|
232
|
+
telescope_lat=-30.2446388,
|
|
233
|
+
):
|
|
234
|
+
self.units = ["X / Xmin"]
|
|
235
|
+
self.cols_req = [airmass_col, dec_col]
|
|
236
|
+
self.airmass_col = airmass_col
|
|
237
|
+
self.dec_col = dec_col
|
|
238
|
+
self.telescope_lat = telescope_lat
|
|
239
|
+
self.degrees = degrees
|
|
240
|
+
|
|
241
|
+
def _run(self, sim_data, cols_present=False):
|
|
242
|
+
# Run method is required to calculate column.
|
|
243
|
+
# Driver runs getColInfo to know what columns are needed from db &
|
|
244
|
+
# which are calculated, then gets data from db and then calculates
|
|
245
|
+
# additional columns (via run methods here).
|
|
246
|
+
if cols_present:
|
|
247
|
+
# Column already present in data; assume it is correct
|
|
248
|
+
# and does not need recalculating.
|
|
249
|
+
return sim_data
|
|
250
|
+
dec = sim_data[self.dec_col]
|
|
251
|
+
if self.degrees:
|
|
252
|
+
dec = np.radians(dec)
|
|
253
|
+
min_z_possible = np.abs(dec - np.radians(self.telescope_lat))
|
|
254
|
+
min_airmass_possible = 1.0 / np.cos(min_z_possible)
|
|
255
|
+
sim_data["normairmass"] = sim_data[self.airmass_col] / min_airmass_possible
|
|
256
|
+
return sim_data
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class ZenithDistStacker(BaseStacker):
|
|
260
|
+
"""Adds a calculated zenithDistance value for each pointing.
|
|
261
|
+
|
|
262
|
+
Parameters
|
|
263
|
+
----------
|
|
264
|
+
alt_col : `str`, optional
|
|
265
|
+
The name of the altitude column in the data.
|
|
266
|
+
degrees : `bool`, optional
|
|
267
|
+
If True, data in alt_col is in degrees, and values for zenithDistance
|
|
268
|
+
will be in degrees. (Default).
|
|
269
|
+
If False, data in alt_col is in radians and zenithDistance values
|
|
270
|
+
will be in radians.
|
|
271
|
+
"""
|
|
272
|
+
|
|
273
|
+
cols_added = ["zenithDistance"]
|
|
274
|
+
|
|
275
|
+
def __init__(self, alt_col="altitude", degrees=True):
|
|
276
|
+
self.alt_col = alt_col
|
|
277
|
+
self.degrees = degrees
|
|
278
|
+
if self.degrees:
|
|
279
|
+
self.units = ["degrees"]
|
|
280
|
+
else:
|
|
281
|
+
self.unit = ["radians"]
|
|
282
|
+
self.cols_req = [self.alt_col]
|
|
283
|
+
|
|
284
|
+
def _run(self, sim_data, cols_present=False):
|
|
285
|
+
"""Calculate new column for zenith distance."""
|
|
286
|
+
if cols_present:
|
|
287
|
+
# Column already present in data; assume it is correct and does not
|
|
288
|
+
# need recalculating.
|
|
289
|
+
return sim_data
|
|
290
|
+
if self.degrees:
|
|
291
|
+
sim_data["zenithDistance"] = 90.0 - sim_data[self.alt_col]
|
|
292
|
+
else:
|
|
293
|
+
sim_data["zenithDistance"] = np.pi / 2.0 - sim_data[self.alt_col]
|
|
294
|
+
return sim_data
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
class ParallaxFactorStacker(BaseStacker):
|
|
298
|
+
"""Add a parallax factor (in arcseconds) column for each visit.
|
|
299
|
+
|
|
300
|
+
Parameters
|
|
301
|
+
----------
|
|
302
|
+
ra_col : `str`, optional
|
|
303
|
+
Name of the RA column in the data.
|
|
304
|
+
dec_col : `str`, optional
|
|
305
|
+
Name of the declination column in the data.
|
|
306
|
+
date_col : `str`, optional
|
|
307
|
+
Name of the exposure start time column in the data.
|
|
308
|
+
Date should be in units of MJD.
|
|
309
|
+
degrees : `bool`, optional
|
|
310
|
+
If true, assumes angles are in degrees. If False, radians.
|
|
311
|
+
"""
|
|
312
|
+
|
|
313
|
+
cols_added = ["ra_pi_amp", "dec_pi_amp"]
|
|
314
|
+
|
|
315
|
+
def __init__(
|
|
316
|
+
self,
|
|
317
|
+
ra_col="fieldRA",
|
|
318
|
+
dec_col="fieldDec",
|
|
319
|
+
date_col="observationStartMJD",
|
|
320
|
+
degrees=True,
|
|
321
|
+
):
|
|
322
|
+
self.ra_col = ra_col
|
|
323
|
+
self.dec_col = dec_col
|
|
324
|
+
self.date_col = date_col
|
|
325
|
+
self.units = ["arcsec", "arcsec"]
|
|
326
|
+
self.cols_req = [ra_col, dec_col, date_col]
|
|
327
|
+
self.degrees = degrees
|
|
328
|
+
|
|
329
|
+
def _gnomonic_project_toxy(self, ra1, dec1, r_acen, deccen):
|
|
330
|
+
# ra, dec values in RADIANS
|
|
331
|
+
# also used in Global Telescope Network website
|
|
332
|
+
cosc = np.sin(deccen) * np.sin(dec1) + np.cos(deccen) * np.cos(dec1) * np.cos(ra1 - r_acen)
|
|
333
|
+
x = np.cos(dec1) * np.sin(ra1 - r_acen) / cosc
|
|
334
|
+
y = (np.cos(deccen) * np.sin(dec1) - np.sin(deccen) * np.cos(dec1) * np.cos(ra1 - r_acen)) / cosc
|
|
335
|
+
return x, y
|
|
336
|
+
|
|
337
|
+
def _run(self, sim_data, cols_present=False):
|
|
338
|
+
if cols_present:
|
|
339
|
+
# Column already present in data; assume it is correct
|
|
340
|
+
# and does not need recalculating.
|
|
341
|
+
return sim_data
|
|
342
|
+
ra_pi_amp = np.zeros(np.size(sim_data), dtype=[("ra_pi_amp", "float")])
|
|
343
|
+
dec_pi_amp = np.zeros(np.size(sim_data), dtype=[("dec_pi_amp", "float")])
|
|
344
|
+
ra = sim_data[self.ra_col]
|
|
345
|
+
dec = sim_data[self.dec_col]
|
|
346
|
+
if self.degrees:
|
|
347
|
+
ra = np.radians(ra)
|
|
348
|
+
dec = np.radians(dec)
|
|
349
|
+
|
|
350
|
+
times = Time(sim_data[self.date_col], format="mjd")
|
|
351
|
+
c = SkyCoord(ra * u.rad, dec * u.rad, obstime=times)
|
|
352
|
+
geo_far = c.transform_to(GCRS)
|
|
353
|
+
c_near = SkyCoord(ra * u.rad, dec * u.rad, distance=1 * u.pc, obstime=times)
|
|
354
|
+
geo_near = c_near.transform_to(GCRS)
|
|
355
|
+
|
|
356
|
+
x_geo1, y_geo1 = self._gnomonic_project_toxy(geo_near.ra.rad, geo_near.dec.rad, ra, dec)
|
|
357
|
+
x_geo, y_geo = self._gnomonic_project_toxy(geo_far.ra.rad, geo_far.dec.rad, ra, dec)
|
|
358
|
+
|
|
359
|
+
# Return ra_pi_amp and dec_pi_amp in arcseconds.
|
|
360
|
+
ra_pi_amp[:] = np.degrees(x_geo1 - x_geo) * 3600.0
|
|
361
|
+
dec_pi_amp[:] = np.degrees(y_geo1 - y_geo) * 3600.0
|
|
362
|
+
sim_data["ra_pi_amp"] = ra_pi_amp
|
|
363
|
+
sim_data["dec_pi_amp"] = dec_pi_amp
|
|
364
|
+
return sim_data
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
class DcrStacker(BaseStacker):
|
|
368
|
+
"""Add columns representing the expected RA/Dec offsets expected for
|
|
369
|
+
an object due to differential chromatic refraction, per visit.
|
|
370
|
+
|
|
371
|
+
For DCR calculation, we also need zenithDistance, HA, and PA -- but these
|
|
372
|
+
will be explicitly handled within this stacker so that setup is consistent
|
|
373
|
+
and they run in order. If those values have already been calculated
|
|
374
|
+
elsewhere, they will not be overwritten.
|
|
375
|
+
|
|
376
|
+
Parameters
|
|
377
|
+
----------
|
|
378
|
+
filter_col : `str`, optional
|
|
379
|
+
The name of the column with filter names. Default 'filter'.
|
|
380
|
+
altCol : `str`, optional
|
|
381
|
+
Name of the column with altitude info. Default 'altitude'.
|
|
382
|
+
ra_col : `str`, optional
|
|
383
|
+
Name of the column with RA. Default 'fieldRA'.
|
|
384
|
+
dec_col : `str`, optional
|
|
385
|
+
Name of the column with Dec. Default 'fieldDec'.
|
|
386
|
+
lstCol : `str`, optional
|
|
387
|
+
Name of the column with local sidereal time. Default
|
|
388
|
+
'observationStartLST'.
|
|
389
|
+
site : `str` or `rubin_scheduler.utils.Site`, optional
|
|
390
|
+
Name of the observory or a rubin_scheduler.utils.Site object.
|
|
391
|
+
Default 'LSST'.
|
|
392
|
+
mjdCol : `str`, optional
|
|
393
|
+
Name of column with modified julian date.
|
|
394
|
+
Default 'observationStartMJD'
|
|
395
|
+
dcr_magnitudes : dict
|
|
396
|
+
Magnitude of the DCR offset for each filter at an
|
|
397
|
+
altitude/zenith distance of 45 degrees.
|
|
398
|
+
Defaults u=0.07, g=0.07, r=0.50, i=0.045, z=0.042, y=0.04
|
|
399
|
+
(all values should be in arcseconds).
|
|
400
|
+
|
|
401
|
+
Returns
|
|
402
|
+
-------
|
|
403
|
+
data : `numpy.array`
|
|
404
|
+
Returns array with additional columns 'ra_dcr_amp' and 'dec_dcr_amp'
|
|
405
|
+
with the DCR offsets for each observation. Also runs ZenithDistStacker
|
|
406
|
+
and ParallacticAngleStacker.
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
cols_added = ["ra_dcr_amp", "dec_dcr_amp"] # zenithDist, HA, PA
|
|
410
|
+
|
|
411
|
+
def __init__(
|
|
412
|
+
self,
|
|
413
|
+
filter_col="band",
|
|
414
|
+
alt_col="altitude",
|
|
415
|
+
degrees=True,
|
|
416
|
+
ra_col="fieldRA",
|
|
417
|
+
dec_col="fieldDec",
|
|
418
|
+
lst_col="observationStartLST",
|
|
419
|
+
site="LSST",
|
|
420
|
+
mjd_col="observationStartMJD",
|
|
421
|
+
dcr_magnitudes=None,
|
|
422
|
+
):
|
|
423
|
+
self.units = ["arcsec", "arcsec"]
|
|
424
|
+
if dcr_magnitudes is None:
|
|
425
|
+
# DCR amplitudes are in arcseconds.
|
|
426
|
+
self.dcr_magnitudes = {
|
|
427
|
+
"u": 0.07,
|
|
428
|
+
"g": 0.07,
|
|
429
|
+
"r": 0.050,
|
|
430
|
+
"i": 0.045,
|
|
431
|
+
"z": 0.042,
|
|
432
|
+
"y": 0.04,
|
|
433
|
+
}
|
|
434
|
+
else:
|
|
435
|
+
self.dcr_magnitudes = dcr_magnitudes
|
|
436
|
+
self.zd_col = "zenithDistance"
|
|
437
|
+
self.pa_col = "PA"
|
|
438
|
+
self.filter_col = filter_col
|
|
439
|
+
self.ra_col = ra_col
|
|
440
|
+
self.dec_col = dec_col
|
|
441
|
+
self.degrees = degrees
|
|
442
|
+
self.cols_req = [filter_col, ra_col, dec_col, alt_col, lst_col]
|
|
443
|
+
# 'zenithDist', 'PA', 'HA' are additional columns required, coming
|
|
444
|
+
# from other stackers which must also be configured -- so we handle
|
|
445
|
+
# this explicitly here.
|
|
446
|
+
self.zstacker = ZenithDistStacker(alt_col=alt_col, degrees=self.degrees)
|
|
447
|
+
self.pastacker = ParallacticAngleStacker(
|
|
448
|
+
ra_col=ra_col,
|
|
449
|
+
dec_col=dec_col,
|
|
450
|
+
mjd_col=mjd_col,
|
|
451
|
+
degrees=self.degrees,
|
|
452
|
+
lst_col=lst_col,
|
|
453
|
+
site=site,
|
|
454
|
+
)
|
|
455
|
+
# Note that RA/Dec could be coming from a dither stacker!
|
|
456
|
+
# But we will assume that coord stackers will be handled separately.
|
|
457
|
+
|
|
458
|
+
def _run(self, sim_data, cols_present=False):
|
|
459
|
+
if cols_present:
|
|
460
|
+
# Column already present in data; assume it is correct and does not
|
|
461
|
+
# need recalculating.
|
|
462
|
+
return sim_data
|
|
463
|
+
# Need to make sure the Zenith stacker gets run first Call _run method
|
|
464
|
+
# because already added these columns due to 'colsAdded' line.
|
|
465
|
+
sim_data = self.zstacker.run(sim_data)
|
|
466
|
+
sim_data = self.pastacker.run(sim_data)
|
|
467
|
+
if self.degrees:
|
|
468
|
+
zenith_tan = np.tan(np.radians(sim_data[self.zd_col]))
|
|
469
|
+
parallactic_angle = np.radians(sim_data[self.pa_col])
|
|
470
|
+
else:
|
|
471
|
+
zenith_tan = np.tan(sim_data[self.zd_col])
|
|
472
|
+
parallactic_angle = sim_data[self.pa_col]
|
|
473
|
+
dcr_in_ra = zenith_tan * np.sin(parallactic_angle)
|
|
474
|
+
dcr_in_dec = zenith_tan * np.cos(parallactic_angle)
|
|
475
|
+
for filtername in np.unique(sim_data[self.filter_col]):
|
|
476
|
+
fmatch = np.where(sim_data[self.filter_col] == filtername)
|
|
477
|
+
dcr_in_ra[fmatch] = self.dcr_magnitudes[filtername] * dcr_in_ra[fmatch]
|
|
478
|
+
dcr_in_dec[fmatch] = self.dcr_magnitudes[filtername] * dcr_in_dec[fmatch]
|
|
479
|
+
sim_data["ra_dcr_amp"] = dcr_in_ra
|
|
480
|
+
sim_data["dec_dcr_amp"] = dcr_in_dec
|
|
481
|
+
return sim_data
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
class HourAngleStacker(BaseStacker):
|
|
485
|
+
"""Add the Hour Angle (in decimal hours) for each observation.
|
|
486
|
+
|
|
487
|
+
Parameters
|
|
488
|
+
----------
|
|
489
|
+
lst_col : `str`, optional
|
|
490
|
+
Name of the LST column in the data.
|
|
491
|
+
ra_col : `str`, optional
|
|
492
|
+
Name of the RA column in the data.
|
|
493
|
+
degrees : `bool`, optional
|
|
494
|
+
If True, assumes angles (RA and LST) are in degrees.
|
|
495
|
+
If False, assumes radians.
|
|
496
|
+
"""
|
|
497
|
+
|
|
498
|
+
cols_added = ["HA"]
|
|
499
|
+
|
|
500
|
+
def __init__(self, lst_col="observationStartLST", ra_col="fieldRA", degrees=True):
|
|
501
|
+
self.units = ["Hours"]
|
|
502
|
+
self.cols_req = [lst_col, ra_col]
|
|
503
|
+
self.lst_col = lst_col
|
|
504
|
+
self.ra_col = ra_col
|
|
505
|
+
self.degrees = degrees
|
|
506
|
+
|
|
507
|
+
def _run(self, sim_data, cols_present=False):
|
|
508
|
+
"""HA = LST - RA"""
|
|
509
|
+
if cols_present:
|
|
510
|
+
# Column already present in data; assume it is correct and does not
|
|
511
|
+
# need recalculating.
|
|
512
|
+
return sim_data
|
|
513
|
+
if len(sim_data) == 0:
|
|
514
|
+
return sim_data
|
|
515
|
+
if self.degrees:
|
|
516
|
+
ra = np.radians(sim_data[self.ra_col])
|
|
517
|
+
lst = np.radians(sim_data[self.lst_col])
|
|
518
|
+
else:
|
|
519
|
+
ra = sim_data[self.ra_col]
|
|
520
|
+
lst = sim_data[self.lst_col]
|
|
521
|
+
# Check that LST is reasonable
|
|
522
|
+
if (np.min(lst) < 0) | (np.max(lst) > 2.0 * np.pi):
|
|
523
|
+
warnings.warn("LST values are not between 0 and 2 pi")
|
|
524
|
+
# Check that RA is reasonable
|
|
525
|
+
if (np.min(ra) < 0) | (np.max(ra) > 2.0 * np.pi):
|
|
526
|
+
warnings.warn("RA values are not between 0 and 2 pi")
|
|
527
|
+
ha = lst - ra
|
|
528
|
+
# Wrap the results so HA between -pi and pi
|
|
529
|
+
ha = np.where(ha < -np.pi, ha + 2.0 * np.pi, ha)
|
|
530
|
+
ha = np.where(ha > np.pi, ha - 2.0 * np.pi, ha)
|
|
531
|
+
# Convert radians to hours
|
|
532
|
+
sim_data["HA"] = ha * 12 / np.pi
|
|
533
|
+
return sim_data
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
class ParallacticAngleStacker(BaseStacker):
|
|
537
|
+
"""Add the calculated parallactic angle to each visit.
|
|
538
|
+
|
|
539
|
+
Parameters
|
|
540
|
+
----------
|
|
541
|
+
ra_col : `str`, optional
|
|
542
|
+
Name of the RA column in the data.
|
|
543
|
+
dec_col : `str`, optional
|
|
544
|
+
Name of the declination column in the data.
|
|
545
|
+
degrees : `bool`, optional
|
|
546
|
+
If True, assumes ra and dec in degrees and returns Parallactic Angle
|
|
547
|
+
in degrees. If False, assumes and returns radians.
|
|
548
|
+
mjd_col : `str`, optional
|
|
549
|
+
Name of the observation MJD column in the data.
|
|
550
|
+
lst_col : `str`, optional
|
|
551
|
+
Name of the LST column in the data.
|
|
552
|
+
site : `str` or `rubin_scheduler.utils.Site`, optional
|
|
553
|
+
Name of the observory or a rubin_scheduler.utils.Site object.
|
|
554
|
+
Default 'LSST'.
|
|
555
|
+
"""
|
|
556
|
+
|
|
557
|
+
cols_added = ["PA"]
|
|
558
|
+
|
|
559
|
+
def __init__(
|
|
560
|
+
self,
|
|
561
|
+
ra_col="fieldRA",
|
|
562
|
+
dec_col="fieldDec",
|
|
563
|
+
degrees=True,
|
|
564
|
+
mjd_col="observationStartMJD",
|
|
565
|
+
lst_col="observationStartLST",
|
|
566
|
+
site="LSST",
|
|
567
|
+
):
|
|
568
|
+
self.lst_col = lst_col
|
|
569
|
+
self.ra_col = ra_col
|
|
570
|
+
self.dec_col = dec_col
|
|
571
|
+
self.degrees = degrees
|
|
572
|
+
self.mjd_col = mjd_col
|
|
573
|
+
self.site = Site(name=site)
|
|
574
|
+
self.units = ["radians"]
|
|
575
|
+
self.cols_req = [self.ra_col, self.dec_col, self.mjd_col, self.lst_col]
|
|
576
|
+
self.ha_stacker = HourAngleStacker(lst_col=lst_col, ra_col=ra_col, degrees=self.degrees)
|
|
577
|
+
|
|
578
|
+
def _run(self, sim_data, cols_present=False):
|
|
579
|
+
# Equation from:
|
|
580
|
+
# http://www.gb.nrao.edu/~rcreager/GBTMetrology/140ft/l0058/gbtmemo52/memo52.html
|
|
581
|
+
# or
|
|
582
|
+
# http://www.gb.nrao.edu/GBT/DA/gbtidl/release2pt9/contrib/contrib/parangle.pro
|
|
583
|
+
if cols_present:
|
|
584
|
+
# Column already present in data; assume it is correct and does not
|
|
585
|
+
# need recalculating.
|
|
586
|
+
return sim_data
|
|
587
|
+
# Using the run method (not _run) means that if HA is present, it will
|
|
588
|
+
# not be recalculated.
|
|
589
|
+
sim_data = self.ha_stacker.run(sim_data)
|
|
590
|
+
if self.degrees:
|
|
591
|
+
dec = np.radians(sim_data[self.dec_col])
|
|
592
|
+
else:
|
|
593
|
+
dec = sim_data[self.dec_col]
|
|
594
|
+
sim_data["PA"] = np.arctan2(
|
|
595
|
+
np.sin(sim_data["HA"] * np.pi / 12.0),
|
|
596
|
+
(
|
|
597
|
+
np.cos(dec) * np.tan(self.site.latitude_rad)
|
|
598
|
+
- np.sin(dec) * np.cos(sim_data["HA"] * np.pi / 12.0)
|
|
599
|
+
),
|
|
600
|
+
)
|
|
601
|
+
if self.degrees:
|
|
602
|
+
sim_data["PA"] = np.degrees(sim_data["PA"])
|
|
603
|
+
return sim_data
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
class OverheadStacker(BaseStacker):
|
|
607
|
+
"""Add time between visits in seconds.
|
|
608
|
+
|
|
609
|
+
Parameters
|
|
610
|
+
----------
|
|
611
|
+
max_gap : `float`, optional
|
|
612
|
+
The maximum gap between observations, in minutes.
|
|
613
|
+
Assume anything longer the dome has closed.
|
|
614
|
+
Defaults to infinity.
|
|
615
|
+
mjd_col : `str`, optional
|
|
616
|
+
The name of the column with the observation start MJD.
|
|
617
|
+
Defaults to "observationStartMJD".
|
|
618
|
+
visit_time_col : `str`, optional
|
|
619
|
+
The name of the column with the total visit time (on-sky plus
|
|
620
|
+
shutter and other overheads).
|
|
621
|
+
Defaults to "visitTime".
|
|
622
|
+
exposure_time_col : `str`, optional
|
|
623
|
+
The name of the column with the visit on-sky exposure time.
|
|
624
|
+
Defaults to "visitExposureTime."
|
|
625
|
+
"""
|
|
626
|
+
|
|
627
|
+
cols_added = ["overhead"]
|
|
628
|
+
|
|
629
|
+
def __init__(
|
|
630
|
+
self,
|
|
631
|
+
max_gap=np.inf,
|
|
632
|
+
mjd_col="observationStartMJD",
|
|
633
|
+
visit_time_col="visitTime",
|
|
634
|
+
exposure_time_col="visitExposureTime",
|
|
635
|
+
):
|
|
636
|
+
# Set max_gap in minutes to match API of existing BruteOSFMetric
|
|
637
|
+
self.max_gap = max_gap
|
|
638
|
+
self.mjd_col = mjd_col
|
|
639
|
+
self.visit_time_col = visit_time_col
|
|
640
|
+
self.exposure_time_col = exposure_time_col
|
|
641
|
+
self.units = ["seconds"]
|
|
642
|
+
self.day_obs_mjd_stacker = DayObsMJDStacker(self.mjd_col)
|
|
643
|
+
self.cols_req = [self.mjd_col, self.visit_time_col, self.exposure_time_col]
|
|
644
|
+
self.cols_req.extend(self.day_obs_mjd_stacker.cols_req)
|
|
645
|
+
self.cols_req = list(set(self.cols_req))
|
|
646
|
+
|
|
647
|
+
def _run(self, sim_data, cols_present=False):
|
|
648
|
+
if cols_present:
|
|
649
|
+
# Column already present in data; assume it is correct and does not
|
|
650
|
+
# need recalculating.
|
|
651
|
+
return sim_data
|
|
652
|
+
|
|
653
|
+
# Count overhead as any time from the shutter close of the previous
|
|
654
|
+
# visit, to the shutter close of the current visit, minus the
|
|
655
|
+
# current on-sky exposure time.
|
|
656
|
+
# This is all non-exposure time required for this visit --
|
|
657
|
+
# includes slew time to this target, any shutter overheads for this
|
|
658
|
+
# visit, and any readouts not absorbed in slewtime for this visit.
|
|
659
|
+
observation_end_mjd = sim_data[self.mjd_col] + sim_data[self.visit_time_col] / (24 * 60 * 60)
|
|
660
|
+
overhead = (
|
|
661
|
+
np.diff(observation_end_mjd, prepend=np.nan) * 24 * 60 * 60 - sim_data[self.exposure_time_col]
|
|
662
|
+
)
|
|
663
|
+
|
|
664
|
+
# Rough heuristic not to count downtime due to weather or instrument
|
|
665
|
+
# problems as overhead. A more reliable way to do this would be to
|
|
666
|
+
# use other sources of weather data or problem reporting to identify
|
|
667
|
+
# these gaps.
|
|
668
|
+
# We might also explicitly want to look at the gaps that arise from
|
|
669
|
+
# these problems in order to measure time lost to these causes.
|
|
670
|
+
overhead[overhead > self.max_gap * 60] = np.nan
|
|
671
|
+
|
|
672
|
+
# If the gap includes a change of night, it isn't really overhead. For
|
|
673
|
+
# most reasonable finite values of self.max_gap, this is never
|
|
674
|
+
# relevant, but it's sometimes useful to set max_gap to inifinity to
|
|
675
|
+
# catch all delays in the night. (The comment above.) But, in
|
|
676
|
+
# even in this case, we would still not want to include gaps between
|
|
677
|
+
# nights.
|
|
678
|
+
day_obs_mjd = self.day_obs_mjd_stacker.run(sim_data)["day_obs_mjd"]
|
|
679
|
+
different_night = np.diff(day_obs_mjd, prepend=np.nan) != 0
|
|
680
|
+
overhead[different_night] = np.nan
|
|
681
|
+
|
|
682
|
+
sim_data[self.cols_added[0]] = overhead
|
|
683
|
+
return sim_data
|