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