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,1364 @@
|
|
|
1
|
+
__all__ = ("SNNSNMetric",)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import healpy as hp
|
|
5
|
+
import numpy as np
|
|
6
|
+
import numpy.lib.recfunctions as nlr
|
|
7
|
+
import pandas as pd
|
|
8
|
+
from scipy.interpolate import interp1d
|
|
9
|
+
|
|
10
|
+
from rubin_sim.maf.metrics import BaseMetric
|
|
11
|
+
from rubin_sim.maf.utils.sn_n_sn_utils import LcfastNew, SnRate, load_sne_cached
|
|
12
|
+
from rubin_sim.phot_utils import DustValues
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SNNSNMetric(BaseMetric):
|
|
16
|
+
"""
|
|
17
|
+
Measure zlim of type Ia supernovae.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
--------------
|
|
21
|
+
metricName : `str`, opt
|
|
22
|
+
metric name (default : SNSNRMetric)
|
|
23
|
+
mjd_col : `str`, opt
|
|
24
|
+
mjd column name (default : observationStartMJD)
|
|
25
|
+
filter_col : `str`, opt
|
|
26
|
+
filter column name (default: filter)
|
|
27
|
+
m5_col : `str`, opt
|
|
28
|
+
five-sigma depth column name (default : fiveSigmaDepth)
|
|
29
|
+
exptime_col : `str`, opt
|
|
30
|
+
exposure time column name (default : visitExposureTime)
|
|
31
|
+
night_col : `str`, opt
|
|
32
|
+
night column name (default : night)
|
|
33
|
+
obsid_col : `str`, opt
|
|
34
|
+
observation id column name (default : observationId)
|
|
35
|
+
nexp_col : `str`, opt
|
|
36
|
+
number of exposure column name (default : numExposures)
|
|
37
|
+
vistime_col : `str`, opt
|
|
38
|
+
visit time column name (default : visitTime)
|
|
39
|
+
seeing_col : `str`, opt
|
|
40
|
+
seeing column name (default: seeingFwhmEff)
|
|
41
|
+
note_col : `str`, opt
|
|
42
|
+
note column name (default: scheduler_note)
|
|
43
|
+
season : `list`, opt
|
|
44
|
+
list of seasons to process (float)(default: -1 = all seasons)
|
|
45
|
+
coadd : `bool`, opt
|
|
46
|
+
coaddition per night (and per band) (default : True)
|
|
47
|
+
zmin : `float`, opt
|
|
48
|
+
min redshift for the study (default: 0.0)
|
|
49
|
+
zmax : `float`, opt
|
|
50
|
+
max redshift for the study (default: 1.2)
|
|
51
|
+
verbose : `bool`, opt
|
|
52
|
+
verbose mode (default: False)
|
|
53
|
+
n_bef : `int`, opt
|
|
54
|
+
number of LC points LC before T0 (default:5)
|
|
55
|
+
n_aft : `int`, opt
|
|
56
|
+
number of LC points after T0 (default: 10)
|
|
57
|
+
snr_min : `float`, opt
|
|
58
|
+
minimal SNR of LC points (default: 5.0)
|
|
59
|
+
n_phase_min : `int`, opt
|
|
60
|
+
number of LC points with phase<= -5(default:1)
|
|
61
|
+
n_phase_max : `int`, opt
|
|
62
|
+
number of LC points with phase>= 20 (default: 1)
|
|
63
|
+
zlim_coeff: float, opt
|
|
64
|
+
corresponds to the zlim_coeff fraction of SN with z<zlim
|
|
65
|
+
bands : `str`, opt
|
|
66
|
+
bands to consider (default: grizy)
|
|
67
|
+
gammaName: `str`, opt
|
|
68
|
+
name of the gamma ref file to load (default: gamma_WFD.hdf5)
|
|
69
|
+
dust : `bool`, opt
|
|
70
|
+
Apply dust extinction to visit depth values (default False)
|
|
71
|
+
hard_dust_cut : `float`, opt
|
|
72
|
+
If set, cut any point on the sky that has an ebv extinction
|
|
73
|
+
higher than the hard_dust_cut value.
|
|
74
|
+
Default 0.25
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def __init__(
|
|
78
|
+
self,
|
|
79
|
+
metric_name="SNNSNMetric",
|
|
80
|
+
mjd_col="observationStartMJD",
|
|
81
|
+
filter_col="band",
|
|
82
|
+
m5_col="fiveSigmaDepth",
|
|
83
|
+
exptime_col="visitExposureTime",
|
|
84
|
+
night_col="night",
|
|
85
|
+
obsid_col="observationId",
|
|
86
|
+
nexp_col="numExposures",
|
|
87
|
+
vistime_col="visitTime",
|
|
88
|
+
seeing_col="seeingFwhmEff",
|
|
89
|
+
note_col="scheduler_note",
|
|
90
|
+
season=[-1],
|
|
91
|
+
coadd_night=True,
|
|
92
|
+
zmin=0.1,
|
|
93
|
+
zmax=0.5,
|
|
94
|
+
z_step=0.03,
|
|
95
|
+
daymax_step=3.0,
|
|
96
|
+
verbose=False,
|
|
97
|
+
ploteffi=False,
|
|
98
|
+
n_bef=3,
|
|
99
|
+
n_aft=8,
|
|
100
|
+
snr_min=1.0,
|
|
101
|
+
n_phase_min=1,
|
|
102
|
+
n_phase_max=1,
|
|
103
|
+
sigma_c=0.04,
|
|
104
|
+
zlim_coeff=0.95,
|
|
105
|
+
bands="grizy",
|
|
106
|
+
add_dust=False,
|
|
107
|
+
hard_dust_cut=0.25,
|
|
108
|
+
gamma_name="gamma_WFD.hdf5",
|
|
109
|
+
**kwargs,
|
|
110
|
+
):
|
|
111
|
+
# n_bef / n_aft = 3/8 for WFD, 4/10 for DDF
|
|
112
|
+
|
|
113
|
+
self.mjd_col = mjd_col
|
|
114
|
+
self.m5_col = m5_col
|
|
115
|
+
self.filter_col = filter_col
|
|
116
|
+
self.exptime_col = exptime_col
|
|
117
|
+
self.season_col = "season"
|
|
118
|
+
self.night_col = night_col
|
|
119
|
+
self.obsid_col = obsid_col
|
|
120
|
+
self.nexp_col = nexp_col
|
|
121
|
+
self.vistime_col = vistime_col
|
|
122
|
+
self.seeing_col = seeing_col
|
|
123
|
+
self.note_col = note_col
|
|
124
|
+
|
|
125
|
+
self.ploteffi = ploteffi
|
|
126
|
+
self.t0s = "all"
|
|
127
|
+
self.zlim_coeff = zlim_coeff
|
|
128
|
+
self.bands = bands
|
|
129
|
+
self.coadd_night = coadd_night
|
|
130
|
+
self.add_dust = add_dust
|
|
131
|
+
self.hard_dust_cut = hard_dust_cut
|
|
132
|
+
|
|
133
|
+
maps = ["DustMap"]
|
|
134
|
+
dust_properties = DustValues()
|
|
135
|
+
self.ax1 = dust_properties.ax1
|
|
136
|
+
|
|
137
|
+
cols = [
|
|
138
|
+
self.night_col,
|
|
139
|
+
self.m5_col,
|
|
140
|
+
self.filter_col,
|
|
141
|
+
self.mjd_col,
|
|
142
|
+
self.obsid_col,
|
|
143
|
+
self.nexp_col,
|
|
144
|
+
self.vistime_col,
|
|
145
|
+
self.exptime_col,
|
|
146
|
+
self.note_col,
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
super(SNNSNMetric, self).__init__(
|
|
150
|
+
col=cols,
|
|
151
|
+
metric_dtype="object",
|
|
152
|
+
metric_name=metric_name,
|
|
153
|
+
maps=maps,
|
|
154
|
+
**kwargs,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
self.season = season
|
|
158
|
+
|
|
159
|
+
# LC selection parameters
|
|
160
|
+
self.n_bef = n_bef # nb points before peak
|
|
161
|
+
self.n_aft = n_aft # nb points after peak
|
|
162
|
+
self.snr_min = snr_min # SNR cut for points before/after peak
|
|
163
|
+
self.n_phase_min = n_phase_min # nb of point with phase <=-5
|
|
164
|
+
self.n_phase_max = n_phase_max # nb of points with phase >=20
|
|
165
|
+
self.sigma_c = sigma_c
|
|
166
|
+
|
|
167
|
+
# loading reference LC files
|
|
168
|
+
lc_reference = load_sne_cached(gamma_name)
|
|
169
|
+
# loading reference LC files
|
|
170
|
+
|
|
171
|
+
self.lc_fast = {}
|
|
172
|
+
for key, vals in lc_reference.items():
|
|
173
|
+
self.lc_fast[key] = LcfastNew(
|
|
174
|
+
vals,
|
|
175
|
+
key[0],
|
|
176
|
+
key[1],
|
|
177
|
+
self.mjd_col,
|
|
178
|
+
self.filter_col,
|
|
179
|
+
self.exptime_col,
|
|
180
|
+
self.m5_col,
|
|
181
|
+
self.season_col,
|
|
182
|
+
self.nexp_col,
|
|
183
|
+
self.seeing_col,
|
|
184
|
+
self.snr_min,
|
|
185
|
+
light_output=False,
|
|
186
|
+
)
|
|
187
|
+
# loading parameters
|
|
188
|
+
self.zmin = zmin # zmin for the study
|
|
189
|
+
self.zmax = zmax # zmax for the study
|
|
190
|
+
self.zstep = z_step # zstep
|
|
191
|
+
# get redshift range for processing
|
|
192
|
+
zrange = list(np.arange(self.zmin, self.zmax, self.zstep))
|
|
193
|
+
if zrange[0] < 1.0e-6:
|
|
194
|
+
zrange[0] = 0.01
|
|
195
|
+
|
|
196
|
+
self.zrange = np.unique(zrange)
|
|
197
|
+
|
|
198
|
+
self.daymax_step = daymax_step # daymax step
|
|
199
|
+
self.min_rf_phase = -20.0 # min ref phase for LC points selection
|
|
200
|
+
self.max_rf_phase = 60.0 # max ref phase for LC points selection
|
|
201
|
+
|
|
202
|
+
self.min_rf_phase_qual = -15.0 # min ref phase for bounds effects
|
|
203
|
+
self.max_rf_phase_qual = 30.0 # max ref phase for bounds effects
|
|
204
|
+
|
|
205
|
+
# snrate
|
|
206
|
+
self.rate_sn = SnRate(
|
|
207
|
+
h0=70.0,
|
|
208
|
+
om0=0.3,
|
|
209
|
+
min_rf_phase=self.min_rf_phase_qual,
|
|
210
|
+
max_rf_phase=self.max_rf_phase_qual,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
# verbose mode - useful for debug and code performance estimation
|
|
214
|
+
self.verbose = verbose
|
|
215
|
+
|
|
216
|
+
# supernovae parameters for fisher estimation
|
|
217
|
+
self.params = ["x0", "x1", "daymax", "color"]
|
|
218
|
+
|
|
219
|
+
def run(self, data_slice, slice_point):
|
|
220
|
+
"""
|
|
221
|
+
Run method of the metric
|
|
222
|
+
|
|
223
|
+
Parameters
|
|
224
|
+
--------------
|
|
225
|
+
data_slice : `np.ndarray`
|
|
226
|
+
Observations to process (scheduler simulations)
|
|
227
|
+
slice_point : `bool`, opt
|
|
228
|
+
Information about the location on the sky from the slicer
|
|
229
|
+
|
|
230
|
+
Returns
|
|
231
|
+
-------
|
|
232
|
+
metricVal : `np.ndarray`
|
|
233
|
+
['n_sn', 'zlim'] at this point on the sky
|
|
234
|
+
"""
|
|
235
|
+
# Hard dust cut
|
|
236
|
+
if self.hard_dust_cut is not None:
|
|
237
|
+
ebvof_mw = slice_point["ebv"]
|
|
238
|
+
if ebvof_mw > self.hard_dust_cut:
|
|
239
|
+
return self.badval
|
|
240
|
+
|
|
241
|
+
# get area on-sky in this slice_point
|
|
242
|
+
if "nside" in slice_point:
|
|
243
|
+
self.pix_area = hp.nside2pixarea(slice_point["nside"], degrees=True)
|
|
244
|
+
else:
|
|
245
|
+
self.pix_area = 9.6
|
|
246
|
+
|
|
247
|
+
# If we want to apply dust extinction.
|
|
248
|
+
if self.add_dust:
|
|
249
|
+
new_m5 = data_slice[self.m5_col] * 0
|
|
250
|
+
for filtername in np.unique(data_slice[self.filter_col]):
|
|
251
|
+
in_filt = np.where(data_slice[self.filter_col] == filtername)[0]
|
|
252
|
+
a_x = self.ax1[filtername] * slice_point["ebv"]
|
|
253
|
+
new_m5[in_filt] = data_slice[self.m5_col][in_filt] - a_x
|
|
254
|
+
data_slice[self.m5_col] = new_m5
|
|
255
|
+
|
|
256
|
+
# select observations filter
|
|
257
|
+
good_filters = np.isin(data_slice[self.filter_col], list(self.bands))
|
|
258
|
+
data_slice = data_slice[good_filters]
|
|
259
|
+
|
|
260
|
+
# coaddition per night and per band (if requested by the user)
|
|
261
|
+
if self.coadd_night:
|
|
262
|
+
data_slice = self.coadd(data_slice)
|
|
263
|
+
|
|
264
|
+
# This seems unlikely, but is a possible bailout point
|
|
265
|
+
if len(data_slice) <= self.n_aft + self.n_bef:
|
|
266
|
+
return self.badval
|
|
267
|
+
|
|
268
|
+
# get season information (seasons calculated by gaps,
|
|
269
|
+
# not by place on sky)
|
|
270
|
+
data_slice = self.getseason(data_slice, mjd_col=self.mjd_col)
|
|
271
|
+
|
|
272
|
+
# get redshift values per season
|
|
273
|
+
zseason = self.z_season(self.season, data_slice)
|
|
274
|
+
zseason_allz = self.z_season_allz(zseason)
|
|
275
|
+
|
|
276
|
+
# estimate redshift completeness
|
|
277
|
+
metric_values = self.metric(data_slice, zseason_allz, x1=-2.0, color=0.2, zlim=-1, metric="zlim")
|
|
278
|
+
|
|
279
|
+
if metric_values is None:
|
|
280
|
+
return self.badval
|
|
281
|
+
|
|
282
|
+
if np.max(metric_values["zcomp"]) < 0:
|
|
283
|
+
return self.badval
|
|
284
|
+
|
|
285
|
+
# get redshift values per season up to zcomp
|
|
286
|
+
zseason = pd.DataFrame(metric_values[["season", "zcomp"]])
|
|
287
|
+
zseason.loc[:, "zmin"] = 0.01
|
|
288
|
+
zseason.loc[:, "zstep"] = self.zstep
|
|
289
|
+
zseason = zseason.rename(columns={"zcomp": "zmax"})
|
|
290
|
+
zseason["zmax"] += self.zstep
|
|
291
|
+
zseason_allz = self.z_season_allz(zseason)
|
|
292
|
+
|
|
293
|
+
# get the total number of well-sampled SN up to zcomp
|
|
294
|
+
nsn_zcomp = self.metric(
|
|
295
|
+
data_slice,
|
|
296
|
+
zseason_allz,
|
|
297
|
+
x1=0.0,
|
|
298
|
+
color=0.0,
|
|
299
|
+
zlim=metric_values[["season", "zcomp"]],
|
|
300
|
+
metric="nsn",
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
# final results
|
|
304
|
+
if nsn_zcomp is None:
|
|
305
|
+
return self.badval
|
|
306
|
+
metric_values = metric_values.merge(nsn_zcomp, left_on=["season"], right_on=["season"])
|
|
307
|
+
|
|
308
|
+
if self.verbose:
|
|
309
|
+
print("metric_values", metric_values[["season", "zcomp", "nsn"]])
|
|
310
|
+
|
|
311
|
+
idx = metric_values["zcomp"] > 0.0
|
|
312
|
+
selmet = metric_values[idx]
|
|
313
|
+
|
|
314
|
+
if len(selmet) > 0:
|
|
315
|
+
zcomp = selmet["zcomp"].median()
|
|
316
|
+
n_sn = selmet["nsn"].sum()
|
|
317
|
+
res = np.rec.fromrecords([(n_sn, zcomp)], names=["n_sn", "zlim"])
|
|
318
|
+
else:
|
|
319
|
+
res = self.badval
|
|
320
|
+
|
|
321
|
+
if self.verbose:
|
|
322
|
+
print("final result", res)
|
|
323
|
+
|
|
324
|
+
return res
|
|
325
|
+
|
|
326
|
+
def season_length(self, seasons, data_slice, zseason):
|
|
327
|
+
"""
|
|
328
|
+
Method to estimate season lengths vs z
|
|
329
|
+
|
|
330
|
+
Parameters
|
|
331
|
+
-----------
|
|
332
|
+
seasons : `list` [`int`]
|
|
333
|
+
list of seasons to process
|
|
334
|
+
data_slice : `np.ndarray`, (N,)`
|
|
335
|
+
array of observations
|
|
336
|
+
zseason : `pd.DataFrame`
|
|
337
|
+
redshift infos per season
|
|
338
|
+
|
|
339
|
+
Returns
|
|
340
|
+
--------
|
|
341
|
+
seasons : `list` [`int`]
|
|
342
|
+
list of seasons to process
|
|
343
|
+
dur_z : `pd.DataFrame`
|
|
344
|
+
season lengths vs z
|
|
345
|
+
"""
|
|
346
|
+
# if seasons = -1: process the seasons seen in data
|
|
347
|
+
if seasons == [-1]:
|
|
348
|
+
seasons = np.unique(data_slice[self.season_col])
|
|
349
|
+
|
|
350
|
+
# season infos
|
|
351
|
+
dfa = pd.DataFrame(np.copy(data_slice))
|
|
352
|
+
dfa = pd.DataFrame(dfa[dfa["season"].isin(seasons)])
|
|
353
|
+
|
|
354
|
+
season_info = self.get_season_info(dfa, zseason)
|
|
355
|
+
|
|
356
|
+
if self.verbose:
|
|
357
|
+
print("season_info", season_info)
|
|
358
|
+
|
|
359
|
+
if season_info.empty:
|
|
360
|
+
return [], pd.DataFrame()
|
|
361
|
+
|
|
362
|
+
season_info["season_copy"] = season_info["season"].values.copy()
|
|
363
|
+
dur_z = (
|
|
364
|
+
season_info.groupby("season_copy", group_keys=False)
|
|
365
|
+
.apply(lambda x: self.nsn_expected_z(x), include_groups=False)
|
|
366
|
+
.reset_index(drop=True)
|
|
367
|
+
)
|
|
368
|
+
return season_info["season"].to_list(), dur_z
|
|
369
|
+
|
|
370
|
+
def get_season_info(self, dfa, zseason, min_duration=60.0):
|
|
371
|
+
"""
|
|
372
|
+
method to get season infos vs z
|
|
373
|
+
|
|
374
|
+
Parameters
|
|
375
|
+
--------------
|
|
376
|
+
dfa : `pd.DataFrame`
|
|
377
|
+
data to process
|
|
378
|
+
zseason : `pd.DataFrame`
|
|
379
|
+
redshift infos per season
|
|
380
|
+
min_duration : `float`, opt
|
|
381
|
+
min season length to be accepted (default: 60 days)
|
|
382
|
+
|
|
383
|
+
Returns
|
|
384
|
+
--------
|
|
385
|
+
season_info : `pd.DataFrame` with season length infos
|
|
386
|
+
|
|
387
|
+
"""
|
|
388
|
+
dfa["season_copy"] = dfa["season"].values.copy()
|
|
389
|
+
season_info = (
|
|
390
|
+
dfa.groupby("season")
|
|
391
|
+
.apply(lambda x: self.season_info(x, min_duration=min_duration), include_groups=False)
|
|
392
|
+
.reset_index()
|
|
393
|
+
)
|
|
394
|
+
|
|
395
|
+
# season_info.index = season_info.index.droplevel()
|
|
396
|
+
season_info = season_info.drop(columns=["level_1"])
|
|
397
|
+
|
|
398
|
+
season_info = season_info.merge(zseason, left_on=["season"], right_on=["season"])
|
|
399
|
+
|
|
400
|
+
season_info["T0_min"] = season_info["MJD_min"] - (1.0 + season_info["z"]) * self.min_rf_phase_qual
|
|
401
|
+
season_info["T0_max"] = season_info["MJD_max"] - (1.0 + season_info["z"]) * self.max_rf_phase_qual
|
|
402
|
+
season_info["season_length"] = season_info["T0_max"] - season_info["T0_min"]
|
|
403
|
+
|
|
404
|
+
idx = season_info["season_length"] >= min_duration
|
|
405
|
+
|
|
406
|
+
return pd.DataFrame(season_info[idx])
|
|
407
|
+
|
|
408
|
+
def step_lc(self, obs, gen_par, x1=-2.0, color=0.2):
|
|
409
|
+
"""
|
|
410
|
+
Method to generate lc
|
|
411
|
+
|
|
412
|
+
Parameters
|
|
413
|
+
---------------
|
|
414
|
+
obs : array
|
|
415
|
+
observations
|
|
416
|
+
gen_par : array
|
|
417
|
+
simulation parameters
|
|
418
|
+
x1 : `float`, opt
|
|
419
|
+
stretch value (default: -2.0)
|
|
420
|
+
color : `float`, opt
|
|
421
|
+
color value (default: 0.2)
|
|
422
|
+
|
|
423
|
+
Returns
|
|
424
|
+
----------
|
|
425
|
+
SN light curves (astropy table)
|
|
426
|
+
|
|
427
|
+
"""
|
|
428
|
+
obs["season_copy"] = obs["season"].values.copy()
|
|
429
|
+
lc = obs.groupby(["season_copy"]).apply(
|
|
430
|
+
lambda x: self.gen_lc(x, gen_par, x1, color), include_groups=False
|
|
431
|
+
)
|
|
432
|
+
return lc
|
|
433
|
+
|
|
434
|
+
def step_efficiencies(self, lc):
|
|
435
|
+
"""
|
|
436
|
+
Method to estimate observing efficiencies
|
|
437
|
+
|
|
438
|
+
Parameter
|
|
439
|
+
-------------
|
|
440
|
+
lc: `pd.DataFrame`
|
|
441
|
+
light curves
|
|
442
|
+
|
|
443
|
+
Returns
|
|
444
|
+
-----------
|
|
445
|
+
`pd.DataFrame` with efficiencies
|
|
446
|
+
|
|
447
|
+
"""
|
|
448
|
+
cols = ["season", "z", "x1", "color", "sntype"]
|
|
449
|
+
for col in cols:
|
|
450
|
+
lc[col + "_copy"] = lc[col].values.copy()
|
|
451
|
+
|
|
452
|
+
sn_effis = lc.groupby(cols).apply(lambda x: self.sn_effi(x), include_groups=False).reset_index()
|
|
453
|
+
|
|
454
|
+
# estimate efficiencies
|
|
455
|
+
sn_effis["season"] = sn_effis["season"].astype(int)
|
|
456
|
+
sn_effis["effi"] = sn_effis["nsel"] / sn_effis["ntot"]
|
|
457
|
+
sn_effis["effi_err"] = np.sqrt(sn_effis["nsel"] * (1.0 - sn_effis["effi"])) / sn_effis["ntot"]
|
|
458
|
+
|
|
459
|
+
# prevent NaNs, set effi to 0 where there is 0 ntot
|
|
460
|
+
zero = np.where(sn_effis["ntot"] == 0)
|
|
461
|
+
sn_effis["effi"].values[zero] = 0
|
|
462
|
+
sn_effis["effi_err"].values[zero] = 0
|
|
463
|
+
|
|
464
|
+
if self.verbose:
|
|
465
|
+
for season in sn_effis["season"].unique():
|
|
466
|
+
idx = sn_effis["season"] == season
|
|
467
|
+
print("effis", sn_effis[idx])
|
|
468
|
+
|
|
469
|
+
if self.ploteffi:
|
|
470
|
+
from sn_metrics.sn_plot_live import plotNSN_effi
|
|
471
|
+
|
|
472
|
+
for season in sn_effis["season"].unique():
|
|
473
|
+
idx = sn_effis["season"] == season
|
|
474
|
+
print("effis", sn_effis[idx])
|
|
475
|
+
plotNSN_effi(sn_effis[idx], "effi", "effi_err", "Observing Efficiencies", ls="-")
|
|
476
|
+
|
|
477
|
+
return sn_effis
|
|
478
|
+
|
|
479
|
+
def step_nsn(self, sn_effis, dur_z):
|
|
480
|
+
"""
|
|
481
|
+
Method to estimate the number of supernovae from efficiencies
|
|
482
|
+
|
|
483
|
+
Parameters
|
|
484
|
+
----------
|
|
485
|
+
sn_effis : `pd.DataFrame`
|
|
486
|
+
data with efficiencies of observation
|
|
487
|
+
dur_z : array
|
|
488
|
+
array of season length
|
|
489
|
+
|
|
490
|
+
Returns
|
|
491
|
+
-------
|
|
492
|
+
initial sn_effis appended with a set of infos (duration, nsn)
|
|
493
|
+
|
|
494
|
+
"""
|
|
495
|
+
# add season length here
|
|
496
|
+
sn_effis = sn_effis.merge(dur_z, left_on=["season", "z"], right_on=["season", "z"])
|
|
497
|
+
|
|
498
|
+
# estimate the number of supernovae
|
|
499
|
+
sn_effis["nsn"] = sn_effis["effi"] * sn_effis["nsn_expected"]
|
|
500
|
+
|
|
501
|
+
return sn_effis
|
|
502
|
+
|
|
503
|
+
def season_info(self, grp, min_duration):
|
|
504
|
+
"""
|
|
505
|
+
Method to estimate seasonal info (cadence, season length, ...)
|
|
506
|
+
|
|
507
|
+
Parameters
|
|
508
|
+
--------------
|
|
509
|
+
grp : `pd.DataFrame` group
|
|
510
|
+
min_duration : `float`
|
|
511
|
+
minimal duration for a season to be considered
|
|
512
|
+
|
|
513
|
+
Returns
|
|
514
|
+
---------
|
|
515
|
+
`pd.DataFrame` with the following cols:
|
|
516
|
+
- Nvisits: number of visits for this group
|
|
517
|
+
- N_xx: number of visits in xx where xx is defined in self.bandstat
|
|
518
|
+
|
|
519
|
+
"""
|
|
520
|
+
df = pd.DataFrame([len(grp)], columns=["Nvisits"])
|
|
521
|
+
df["MJD_min"] = grp[self.mjd_col].min()
|
|
522
|
+
df["MJD_max"] = grp[self.mjd_col].max()
|
|
523
|
+
df["season_length"] = df["MJD_max"] - df["MJD_min"]
|
|
524
|
+
df["cadence"] = 0.0
|
|
525
|
+
|
|
526
|
+
if len(grp) > 5:
|
|
527
|
+
# to = grp.groupby(['night'])[self.mjd_col].median().sort_values()
|
|
528
|
+
# df['cadence'] = np.mean(to.diff())
|
|
529
|
+
nights = np.sort(grp["night"].unique())
|
|
530
|
+
diff = np.asarray(nights[1:] - nights[:-1])
|
|
531
|
+
df["cadence"] = np.median(diff).item()
|
|
532
|
+
|
|
533
|
+
# select seasons of at least 30 days
|
|
534
|
+
idx = df["season_length"] >= min_duration
|
|
535
|
+
|
|
536
|
+
return df[idx]
|
|
537
|
+
|
|
538
|
+
def duration_z(self, grp, min_duration=60.0):
|
|
539
|
+
"""
|
|
540
|
+
Method to estimate the season length vs redshift
|
|
541
|
+
This is necessary to take into account boundary effects
|
|
542
|
+
when estimating the number of SN that can be detected
|
|
543
|
+
|
|
544
|
+
daymin, daymax = min and max MJD of a season
|
|
545
|
+
T0_min(z) = daymin-(1+z)*min_rf_phase_qual
|
|
546
|
+
T0_max(z) = daymax-(1+z)*max_rf_phase_qual
|
|
547
|
+
season_length(z) = T0_max(z)-T0_min(z)
|
|
548
|
+
|
|
549
|
+
Parameters
|
|
550
|
+
--------------
|
|
551
|
+
grp : `pd.DataFrame` group
|
|
552
|
+
data to process: season infos
|
|
553
|
+
min_duration : `float`, opt
|
|
554
|
+
min season length for a season to be processed (deafult: 60 days)
|
|
555
|
+
|
|
556
|
+
Returns
|
|
557
|
+
----------
|
|
558
|
+
`pd.DataFrame` with season_length, z, T0_min and T0_max cols
|
|
559
|
+
|
|
560
|
+
"""
|
|
561
|
+
# IS THIS CALLED FROM ANYWHERE?
|
|
562
|
+
daymin = grp["MJD_min"].values
|
|
563
|
+
daymax = grp["MJD_max"].values
|
|
564
|
+
dur_z = pd.DataFrame(self.zrange, columns=["z"])
|
|
565
|
+
dur_z["T0_min"] = daymin - (1.0 + dur_z["z"]) * self.min_rf_phase_qual
|
|
566
|
+
dur_z["T0_max"] = daymax - (1.0 + dur_z["z"]) * self.max_rf_phase_qual
|
|
567
|
+
dur_z["season_length"] = dur_z["T0_max"] - dur_z["T0_min"]
|
|
568
|
+
# dur_z['season_length_orig'] = daymax-daymin
|
|
569
|
+
# dur_z['season_length_orig'] = [daymax-daymin]*len(self.zrange)
|
|
570
|
+
nsn = self.nsn_from_rate(dur_z)
|
|
571
|
+
if self.verbose:
|
|
572
|
+
print("dur_z", dur_z)
|
|
573
|
+
print("nsn expected", nsn)
|
|
574
|
+
dur_z = dur_z.merge(nsn, left_on=["z"], right_on=["z"])
|
|
575
|
+
|
|
576
|
+
idx = dur_z["season_length"] > min_duration
|
|
577
|
+
sel = dur_z[idx]
|
|
578
|
+
if len(sel) < 2:
|
|
579
|
+
return pd.DataFrame()
|
|
580
|
+
return dur_z
|
|
581
|
+
|
|
582
|
+
def calc_daymax(self, grp, daymax_step):
|
|
583
|
+
"""
|
|
584
|
+
Method to estimate T0 (daymax) values for simulation.
|
|
585
|
+
|
|
586
|
+
Parameters
|
|
587
|
+
--------------
|
|
588
|
+
grp: group (`pd.DataFrame` sense)
|
|
589
|
+
group of data to process with the following cols:
|
|
590
|
+
t0_min: T0 min value (per season)
|
|
591
|
+
t0_max: T0 max value (per season)
|
|
592
|
+
daymax_step: `float`
|
|
593
|
+
step for T0 simulation
|
|
594
|
+
|
|
595
|
+
Returns
|
|
596
|
+
----------
|
|
597
|
+
`pd.DataFrame` with daymax, min_rf_phase, max_rf_phase values
|
|
598
|
+
|
|
599
|
+
"""
|
|
600
|
+
|
|
601
|
+
if self.t0s == "all":
|
|
602
|
+
t0_max = grp["T0_max"].values
|
|
603
|
+
t0_min = grp["T0_min"].values
|
|
604
|
+
num = (t0_max - t0_min) / daymax_step
|
|
605
|
+
if t0_max - t0_min > 10:
|
|
606
|
+
df = pd.DataFrame(np.linspace(t0_min, t0_max, int(np.max(num))), columns=["daymax"])
|
|
607
|
+
else:
|
|
608
|
+
df = pd.DataFrame([-1], columns=["daymax"])
|
|
609
|
+
else:
|
|
610
|
+
df = pd.DataFrame([0.0], columns=["daymax"])
|
|
611
|
+
|
|
612
|
+
df["minRFphase"] = self.min_rf_phase
|
|
613
|
+
df["maxRFphase"] = self.max_rf_phase
|
|
614
|
+
|
|
615
|
+
return df
|
|
616
|
+
|
|
617
|
+
def gen_lc(self, grp, gen_par_orig, x1, color):
|
|
618
|
+
"""
|
|
619
|
+
Method to generate light curves from observations
|
|
620
|
+
|
|
621
|
+
Parameters
|
|
622
|
+
---------------
|
|
623
|
+
grp : pd group
|
|
624
|
+
observations to process
|
|
625
|
+
gen_par_orig : `pd.DataFrame`
|
|
626
|
+
simulation parameters
|
|
627
|
+
x1 : `float`
|
|
628
|
+
SN stretch
|
|
629
|
+
color : `float`
|
|
630
|
+
SN color
|
|
631
|
+
|
|
632
|
+
Returns
|
|
633
|
+
----------
|
|
634
|
+
light curves as `pd.DataFrame`
|
|
635
|
+
|
|
636
|
+
"""
|
|
637
|
+
season = grp.name
|
|
638
|
+
idx = gen_par_orig["season"] == season
|
|
639
|
+
gen_par = gen_par_orig[idx].to_records(index=False)
|
|
640
|
+
|
|
641
|
+
sntype = dict(zip([(-2.0, 0.2), (0.0, 0.0)], ["faint", "medium"]))
|
|
642
|
+
res = pd.DataFrame()
|
|
643
|
+
key = (np.round(x1, 1), np.round(color, 1))
|
|
644
|
+
vals = self.lc_fast[key]
|
|
645
|
+
|
|
646
|
+
gen_par_cp = gen_par.copy()
|
|
647
|
+
if key == (-2.0, 0.2):
|
|
648
|
+
idx = gen_par_cp["z"] < 0.9
|
|
649
|
+
gen_par_cp = gen_par_cp[idx]
|
|
650
|
+
lc = vals(grp.to_records(index=False), 0.0, gen_par_cp, bands="grizy")
|
|
651
|
+
lc["x1"] = key[0]
|
|
652
|
+
lc["color"] = key[1]
|
|
653
|
+
lc["sntype"] = sntype[key]
|
|
654
|
+
res = pd.concat((res, lc))
|
|
655
|
+
|
|
656
|
+
return res
|
|
657
|
+
|
|
658
|
+
def sn_effi(self, lc):
|
|
659
|
+
"""
|
|
660
|
+
Method to transform LCs to supernovae
|
|
661
|
+
|
|
662
|
+
Parameters
|
|
663
|
+
---------------
|
|
664
|
+
lc : pd grp
|
|
665
|
+
light curve
|
|
666
|
+
|
|
667
|
+
Returns
|
|
668
|
+
----------
|
|
669
|
+
`pd.DataFrame` of sn efficiencies vs z
|
|
670
|
+
"""
|
|
671
|
+
|
|
672
|
+
if self.verbose:
|
|
673
|
+
print("effi for", lc.name)
|
|
674
|
+
|
|
675
|
+
lcarr = lc.to_records(index=False)
|
|
676
|
+
|
|
677
|
+
idx = lcarr["snr_m5"] >= self.snr_min
|
|
678
|
+
|
|
679
|
+
lcarr = np.copy(lcarr[idx])
|
|
680
|
+
|
|
681
|
+
t0s = np.unique(lcarr["daymax"])
|
|
682
|
+
t0s.sort()
|
|
683
|
+
|
|
684
|
+
delta_t = lcarr["daymax"] - t0s[:, np.newaxis]
|
|
685
|
+
|
|
686
|
+
flag = np.abs(delta_t) < 1.0e-5
|
|
687
|
+
|
|
688
|
+
resdf = pd.DataFrame(t0s, columns=["daymax"])
|
|
689
|
+
|
|
690
|
+
# get n_phase_min, n_phase_max
|
|
691
|
+
for vv in [
|
|
692
|
+
"n_phmin",
|
|
693
|
+
"n_phmax",
|
|
694
|
+
"F_x0x0",
|
|
695
|
+
"F_x0x1",
|
|
696
|
+
"F_x0daymax",
|
|
697
|
+
"F_x0color",
|
|
698
|
+
"F_x1x1",
|
|
699
|
+
"F_x1daymax",
|
|
700
|
+
"F_x1color",
|
|
701
|
+
"F_daymaxdaymax",
|
|
702
|
+
"F_daymaxcolor",
|
|
703
|
+
"F_colorcolor",
|
|
704
|
+
]:
|
|
705
|
+
resdf[vv] = self.get_sum(lcarr, vv, len(delta_t), flag)
|
|
706
|
+
|
|
707
|
+
nights = np.tile(lcarr["night"], (len(delta_t), 1))
|
|
708
|
+
phases = np.tile(lcarr["phase"], (len(delta_t), 1))
|
|
709
|
+
|
|
710
|
+
flagph = phases >= 0.0
|
|
711
|
+
resdf["nepochs_aft"] = self.get_epochs(nights, flag, flagph)
|
|
712
|
+
flagph = phases <= 0.0
|
|
713
|
+
resdf["nepochs_bef"] = self.get_epochs(nights, flag, flagph)
|
|
714
|
+
|
|
715
|
+
# replace NaN by 0
|
|
716
|
+
# solution from: https://stackoverflow.com/
|
|
717
|
+
# questions/77900971/
|
|
718
|
+
# pandas-futurewarning-downcasting-
|
|
719
|
+
# object-dtype-arrays-on-fillna-ffill-bfill
|
|
720
|
+
with pd.option_context("future.no_silent_downcasting", True):
|
|
721
|
+
resdf = resdf.fillna(0).infer_objects(copy=False)
|
|
722
|
+
|
|
723
|
+
# get selection efficiencies
|
|
724
|
+
effis = self.efficiencies(resdf)
|
|
725
|
+
|
|
726
|
+
return effis
|
|
727
|
+
|
|
728
|
+
def get_sum(self, lcarr, varname, nvals, flag):
|
|
729
|
+
"""
|
|
730
|
+
Method to get the sum of variables using broadcasting
|
|
731
|
+
|
|
732
|
+
Parameters
|
|
733
|
+
--------------
|
|
734
|
+
lcarr : numpy array
|
|
735
|
+
data to process
|
|
736
|
+
varname : `str`
|
|
737
|
+
col to process in lcarr
|
|
738
|
+
nvals : `int`
|
|
739
|
+
dimension for tiling
|
|
740
|
+
flag : array(bool)
|
|
741
|
+
flag to apply
|
|
742
|
+
|
|
743
|
+
Returns
|
|
744
|
+
----------
|
|
745
|
+
array: the sum of the corresponding variable
|
|
746
|
+
|
|
747
|
+
"""
|
|
748
|
+
|
|
749
|
+
phmin = np.tile(lcarr[varname], (nvals, 1))
|
|
750
|
+
n_phmin = np.ma.array(phmin, mask=~flag)
|
|
751
|
+
n_phmin = n_phmin.sum(axis=1)
|
|
752
|
+
|
|
753
|
+
return n_phmin
|
|
754
|
+
|
|
755
|
+
def get_epochs(self, nights, flag, flagph):
|
|
756
|
+
"""
|
|
757
|
+
Method to get the number of epochs
|
|
758
|
+
|
|
759
|
+
Parameters
|
|
760
|
+
---------------
|
|
761
|
+
nights : array
|
|
762
|
+
night number array
|
|
763
|
+
flag : array(bool)
|
|
764
|
+
flag to apply
|
|
765
|
+
flagph : array(bool)
|
|
766
|
+
flag to apply
|
|
767
|
+
|
|
768
|
+
Returns
|
|
769
|
+
-----------
|
|
770
|
+
array with the number of epochs
|
|
771
|
+
|
|
772
|
+
"""
|
|
773
|
+
nights_cp = np.copy(nights)
|
|
774
|
+
B = np.ma.array(nights_cp, mask=~(flag & flagph))
|
|
775
|
+
B.sort(axis=1)
|
|
776
|
+
C = np.diff(B, axis=1) > 0
|
|
777
|
+
D = C.sum(axis=1) + 1
|
|
778
|
+
return D
|
|
779
|
+
|
|
780
|
+
def sigma_s_nparams(self, grp):
|
|
781
|
+
"""
|
|
782
|
+
Method to estimate variances of SN parameters
|
|
783
|
+
from inversion of the Fisher matrix
|
|
784
|
+
|
|
785
|
+
Parameters
|
|
786
|
+
---------------
|
|
787
|
+
grp: `pd.DataFrame` of flux derivatives wrt SN parameters
|
|
788
|
+
Returns
|
|
789
|
+
----------
|
|
790
|
+
Diagonal elements of the inverted matrix (as `pd.DataFrame`)
|
|
791
|
+
"""
|
|
792
|
+
|
|
793
|
+
# params = ['x0', 'x1', 'daymax', 'color']
|
|
794
|
+
parts = {}
|
|
795
|
+
for ia, vala in enumerate(self.params):
|
|
796
|
+
for jb, valb in enumerate(self.params):
|
|
797
|
+
if jb >= ia:
|
|
798
|
+
parts[ia, jb] = grp["F_" + vala + valb]
|
|
799
|
+
|
|
800
|
+
# print(parts)
|
|
801
|
+
size = len(grp)
|
|
802
|
+
npar = len(self.params)
|
|
803
|
+
fisher__big = np.zeros((npar * size, npar * size))
|
|
804
|
+
big__diag = np.zeros((npar * size, npar * size))
|
|
805
|
+
big__diag = []
|
|
806
|
+
|
|
807
|
+
for iv in range(size):
|
|
808
|
+
for ia, vala in enumerate(self.params):
|
|
809
|
+
for jb, valb in enumerate(self.params):
|
|
810
|
+
if jb >= ia:
|
|
811
|
+
fisher__big[ia + npar * iv][jb + npar * iv] = parts[ia, jb][iv]
|
|
812
|
+
|
|
813
|
+
# pprint.pprint(fisher__big)
|
|
814
|
+
|
|
815
|
+
fisher__big = fisher__big + np.triu(fisher__big, 1).T
|
|
816
|
+
big__diag = np.diag(np.linalg.inv(fisher__big))
|
|
817
|
+
|
|
818
|
+
res = pd.DataFrame()
|
|
819
|
+
for ia, vala in enumerate(self.params):
|
|
820
|
+
indices = range(ia, len(big__diag), npar)
|
|
821
|
+
res["Cov_{}{}".format(vala, vala)] = np.take(big__diag, indices)
|
|
822
|
+
|
|
823
|
+
return res
|
|
824
|
+
|
|
825
|
+
def efficiencies(self, dfo):
|
|
826
|
+
""" "
|
|
827
|
+
Method to estimate selection efficiencies
|
|
828
|
+
|
|
829
|
+
Parameters
|
|
830
|
+
---------------
|
|
831
|
+
df: `pd.DataFrame`
|
|
832
|
+
data to process
|
|
833
|
+
|
|
834
|
+
"""
|
|
835
|
+
|
|
836
|
+
if self.verbose:
|
|
837
|
+
print(
|
|
838
|
+
"selection params",
|
|
839
|
+
self.n_phase_min,
|
|
840
|
+
self.n_phase_max,
|
|
841
|
+
self.n_bef,
|
|
842
|
+
self.n_aft,
|
|
843
|
+
)
|
|
844
|
+
print(dfo)
|
|
845
|
+
df = pd.DataFrame(dfo)
|
|
846
|
+
df["select"] = df["n_phmin"] >= self.n_phase_min
|
|
847
|
+
df["select"] &= df["n_phmax"] >= self.n_phase_max
|
|
848
|
+
df["select"] &= df["nepochs_bef"] >= self.n_bef
|
|
849
|
+
df["select"] &= df["nepochs_aft"] >= self.n_aft
|
|
850
|
+
df["select"] = df["select"].astype(int)
|
|
851
|
+
df["Cov_colorcolor"] = 100.0
|
|
852
|
+
|
|
853
|
+
idx = df["select"] == 1
|
|
854
|
+
|
|
855
|
+
bad_sn = pd.DataFrame(df.loc[~idx])
|
|
856
|
+
good_sn = pd.DataFrame()
|
|
857
|
+
if len(df[idx]) > 0:
|
|
858
|
+
good_sn = pd.DataFrame(df.loc[idx].reset_index())
|
|
859
|
+
sigma__fisher = self.sigma_s_nparams(good_sn)
|
|
860
|
+
good_sn["Cov_colorcolor"] = sigma__fisher["Cov_colorcolor"]
|
|
861
|
+
|
|
862
|
+
all_sn = pd.concat((good_sn, bad_sn))
|
|
863
|
+
all_sn["select"] &= all_sn["Cov_colorcolor"] <= self.sigma_c**2
|
|
864
|
+
idx = all_sn["select"] == 1
|
|
865
|
+
|
|
866
|
+
if self.verbose:
|
|
867
|
+
if len(good_sn) > 0:
|
|
868
|
+
print("good SN", len(good_sn), good_sn[["daymax", "Cov_colorcolor"]])
|
|
869
|
+
else:
|
|
870
|
+
print("no good SN")
|
|
871
|
+
return pd.DataFrame({"ntot": [len(all_sn)], "nsel": [len(all_sn[idx])]})
|
|
872
|
+
|
|
873
|
+
def metric(self, data_slice, zseason, x1=-2.0, color=0.2, zlim=-1, metric="zlim"):
|
|
874
|
+
"""
|
|
875
|
+
Method to run the metric
|
|
876
|
+
|
|
877
|
+
Parameters
|
|
878
|
+
---------------
|
|
879
|
+
data_slice: array
|
|
880
|
+
observations to use for processing
|
|
881
|
+
zseason: array
|
|
882
|
+
season infos (season length vs z)
|
|
883
|
+
x1: float, opt
|
|
884
|
+
SN stretch (default: -2.0)
|
|
885
|
+
color: float, opt
|
|
886
|
+
SN color (default: -0.2)
|
|
887
|
+
zlim: float, opt
|
|
888
|
+
redshift limit used to estimate NSN (default: -1)
|
|
889
|
+
metric: str, opt
|
|
890
|
+
metric to estimate [zlim or nsn] (default: zlim)
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
"""
|
|
894
|
+
"""
|
|
895
|
+
snType = "medium"
|
|
896
|
+
if np.abs(x1 + 2.0) <= 1.0e-5:
|
|
897
|
+
snType = "faint"
|
|
898
|
+
"""
|
|
899
|
+
|
|
900
|
+
# get the season durations
|
|
901
|
+
seasons, dur_z = self.season_length(self.season, data_slice, zseason)
|
|
902
|
+
if not seasons or dur_z.empty:
|
|
903
|
+
return None
|
|
904
|
+
|
|
905
|
+
# chek the redshift range per season
|
|
906
|
+
dur_z = self.check_dur_z(dur_z)
|
|
907
|
+
if dur_z.empty:
|
|
908
|
+
return None
|
|
909
|
+
|
|
910
|
+
# Stick a season column on in case it got killed by a groupby
|
|
911
|
+
if "season" not in list(dur_z.columns):
|
|
912
|
+
dur_z["season"] = dur_z["index"] * 0 + np.unique(seasons)
|
|
913
|
+
|
|
914
|
+
# get simulation parameters
|
|
915
|
+
if np.size(np.unique(seasons)) > 1:
|
|
916
|
+
dur_z["z_copy"] = dur_z["z"].values.copy()
|
|
917
|
+
dur_z["season_copy"] = dur_z["season"].values.copy()
|
|
918
|
+
gen_par = (
|
|
919
|
+
dur_z.groupby(["z", "season"])
|
|
920
|
+
.apply(lambda x: self.calc_daymax(x, self.daymax_step), include_groups=False)
|
|
921
|
+
.reset_index()
|
|
922
|
+
)
|
|
923
|
+
else:
|
|
924
|
+
dur_z["z_copy"] = dur_z["z"].values.copy()
|
|
925
|
+
gen_par = (
|
|
926
|
+
dur_z.groupby(["z"])
|
|
927
|
+
.apply(lambda x: self.calc_daymax(x, self.daymax_step), include_groups=False)
|
|
928
|
+
.reset_index()
|
|
929
|
+
)
|
|
930
|
+
gen_par["season"] = gen_par["level_1"] * 0 + np.unique(seasons)
|
|
931
|
+
|
|
932
|
+
if gen_par.empty:
|
|
933
|
+
return None
|
|
934
|
+
|
|
935
|
+
# select observations corresponding to seasons
|
|
936
|
+
obs = pd.DataFrame(np.copy(data_slice))
|
|
937
|
+
obs = obs[obs["season"].isin(seasons)]
|
|
938
|
+
|
|
939
|
+
# metric values in a DataFrame
|
|
940
|
+
metric_values = pd.DataFrame()
|
|
941
|
+
|
|
942
|
+
# generate LC here
|
|
943
|
+
lc = self.step_lc(obs, gen_par, x1=x1, color=color)
|
|
944
|
+
|
|
945
|
+
if self.verbose:
|
|
946
|
+
print("daymax values", lc["daymax"].unique(), len(lc["daymax"].unique()))
|
|
947
|
+
print(
|
|
948
|
+
lc[
|
|
949
|
+
[
|
|
950
|
+
"daymax",
|
|
951
|
+
"z",
|
|
952
|
+
"flux",
|
|
953
|
+
"fluxerr_photo",
|
|
954
|
+
"flux_e_sec",
|
|
955
|
+
"flux_5",
|
|
956
|
+
self.m5_col,
|
|
957
|
+
]
|
|
958
|
+
]
|
|
959
|
+
)
|
|
960
|
+
|
|
961
|
+
if len(lc) == 0:
|
|
962
|
+
return None
|
|
963
|
+
|
|
964
|
+
# get observing efficiencies and build sn for metric
|
|
965
|
+
lc.index = lc.index.droplevel()
|
|
966
|
+
|
|
967
|
+
# estimate efficiencies
|
|
968
|
+
sn_effis = self.step_efficiencies(lc)
|
|
969
|
+
|
|
970
|
+
# estimate nsn
|
|
971
|
+
sn = self.step_nsn(sn_effis, dur_z)
|
|
972
|
+
|
|
973
|
+
# estimate redshift completeness
|
|
974
|
+
if metric == "zlim":
|
|
975
|
+
sn["season_copy"] = sn["season"].values.copy()
|
|
976
|
+
metric_values = (
|
|
977
|
+
sn.groupby(["season"]).apply(lambda x: self.zlim(x), include_groups=False).reset_index()
|
|
978
|
+
)
|
|
979
|
+
|
|
980
|
+
if metric == "nsn":
|
|
981
|
+
sn = sn.merge(zlim, left_on=["season"], right_on=["season"])
|
|
982
|
+
sn["season_copy"] = sn["season"].values.copy()
|
|
983
|
+
metric_values = (
|
|
984
|
+
sn.groupby(["season"]).apply(lambda x: self.nsn(x), include_groups=False).reset_index()
|
|
985
|
+
)
|
|
986
|
+
|
|
987
|
+
return metric_values
|
|
988
|
+
|
|
989
|
+
def z_season(self, seasons, data_slice):
|
|
990
|
+
"""
|
|
991
|
+
Fill the z values per season
|
|
992
|
+
|
|
993
|
+
Parameters
|
|
994
|
+
--------------
|
|
995
|
+
seasons: list
|
|
996
|
+
seasons to process
|
|
997
|
+
data_slice: array
|
|
998
|
+
data to process
|
|
999
|
+
|
|
1000
|
+
"""
|
|
1001
|
+
# if seasons = -1: process the seasons seen in data
|
|
1002
|
+
if seasons == [-1]:
|
|
1003
|
+
seasons = np.unique(data_slice[self.season_col])
|
|
1004
|
+
|
|
1005
|
+
# `pd.DataFrame` with zmin, zmax, zstep per season
|
|
1006
|
+
zseason = pd.DataFrame(seasons, columns=["season"])
|
|
1007
|
+
zseason["zmin"] = self.zmin
|
|
1008
|
+
zseason["zmax"] = self.zmax
|
|
1009
|
+
zseason["zstep"] = self.zstep
|
|
1010
|
+
|
|
1011
|
+
return zseason
|
|
1012
|
+
|
|
1013
|
+
def z_season_allz(self, zseason):
|
|
1014
|
+
|
|
1015
|
+
zseason["season_copy"] = zseason["season"].values.copy()
|
|
1016
|
+
zseason_allz = (
|
|
1017
|
+
zseason.groupby(["season"])
|
|
1018
|
+
.apply(
|
|
1019
|
+
lambda x: pd.DataFrame(
|
|
1020
|
+
{"z": list(np.arange(x["zmin"].mean(), x["zmax"].mean(), x["zstep"].mean()))}
|
|
1021
|
+
),
|
|
1022
|
+
include_groups=False,
|
|
1023
|
+
)
|
|
1024
|
+
.reset_index()
|
|
1025
|
+
)
|
|
1026
|
+
|
|
1027
|
+
return zseason_allz[["season", "z"]]
|
|
1028
|
+
|
|
1029
|
+
def nsn_from_rate(self, grp):
|
|
1030
|
+
"""
|
|
1031
|
+
Method to estimate the expected number of supernovae
|
|
1032
|
+
|
|
1033
|
+
Parameters
|
|
1034
|
+
---------------
|
|
1035
|
+
grp: `pd.DataFrame`
|
|
1036
|
+
data to process
|
|
1037
|
+
|
|
1038
|
+
Returns
|
|
1039
|
+
-----------
|
|
1040
|
+
`pd.DataFrame` with z and nsn_expected as cols
|
|
1041
|
+
|
|
1042
|
+
"""
|
|
1043
|
+
durinterp_z = interp1d(
|
|
1044
|
+
grp["z"],
|
|
1045
|
+
grp["season_length"],
|
|
1046
|
+
kind="linear",
|
|
1047
|
+
bounds_error=False,
|
|
1048
|
+
fill_value=0,
|
|
1049
|
+
)
|
|
1050
|
+
zz, rate, err_rate, nsn, err_nsn = self.rate_sn(
|
|
1051
|
+
zmin=self.zmin,
|
|
1052
|
+
zmax=self.zmax,
|
|
1053
|
+
dz=self.zstep,
|
|
1054
|
+
duration_z=durinterp_z,
|
|
1055
|
+
# duration=self.duration_ref,
|
|
1056
|
+
survey_area=self.pix_area,
|
|
1057
|
+
account_for_edges=False,
|
|
1058
|
+
)
|
|
1059
|
+
|
|
1060
|
+
nsn_expected = interp1d(zz, nsn, kind="linear", bounds_error=False, fill_value=0)
|
|
1061
|
+
nsn_res = nsn_expected(grp["z"])
|
|
1062
|
+
|
|
1063
|
+
return pd.DataFrame({"nsn_expected": nsn_res, "z": grp["z"].to_list()})
|
|
1064
|
+
|
|
1065
|
+
def coadd(self, obs):
|
|
1066
|
+
"""
|
|
1067
|
+
Method to coadd data per band and per night
|
|
1068
|
+
|
|
1069
|
+
Parameters
|
|
1070
|
+
------------
|
|
1071
|
+
data : `pd.DataFrame`
|
|
1072
|
+
`pd.DataFrame` of observations
|
|
1073
|
+
|
|
1074
|
+
Returns
|
|
1075
|
+
-------
|
|
1076
|
+
coadded data : `pd.DataFrame`
|
|
1077
|
+
|
|
1078
|
+
"""
|
|
1079
|
+
|
|
1080
|
+
data = pd.DataFrame(np.copy(obs))
|
|
1081
|
+
keygroup = [self.filter_col, self.night_col]
|
|
1082
|
+
|
|
1083
|
+
data.sort_values(by=keygroup, ascending=[True, True], inplace=True)
|
|
1084
|
+
|
|
1085
|
+
# get the median single exptime
|
|
1086
|
+
exptime_single = data[self.exptime_col].median()
|
|
1087
|
+
coadd_df = (
|
|
1088
|
+
data.groupby(keygroup)
|
|
1089
|
+
.agg(
|
|
1090
|
+
{
|
|
1091
|
+
self.nexp_col: ["sum"],
|
|
1092
|
+
self.vistime_col: ["sum"],
|
|
1093
|
+
self.exptime_col: ["sum"],
|
|
1094
|
+
self.mjd_col: ["mean"],
|
|
1095
|
+
self.m5_col: ["mean"],
|
|
1096
|
+
}
|
|
1097
|
+
)
|
|
1098
|
+
.reset_index()
|
|
1099
|
+
)
|
|
1100
|
+
|
|
1101
|
+
coadd_df.columns = [
|
|
1102
|
+
self.filter_col,
|
|
1103
|
+
self.night_col,
|
|
1104
|
+
self.nexp_col,
|
|
1105
|
+
self.vistime_col,
|
|
1106
|
+
self.exptime_col,
|
|
1107
|
+
self.mjd_col,
|
|
1108
|
+
self.m5_col,
|
|
1109
|
+
]
|
|
1110
|
+
|
|
1111
|
+
coadd_df = coadd_df.sort_values(by=self.mjd_col)
|
|
1112
|
+
coadd_df[self.m5_col] += 1.25 * np.log10(coadd_df[self.exptime_col] / exptime_single)
|
|
1113
|
+
|
|
1114
|
+
return coadd_df.to_records(index=False)
|
|
1115
|
+
|
|
1116
|
+
def getseason(self, obs, season_gap=80.0, mjd_col="observationStartMJD"):
|
|
1117
|
+
"""
|
|
1118
|
+
Method to estimate seasons
|
|
1119
|
+
|
|
1120
|
+
Parameters
|
|
1121
|
+
------------
|
|
1122
|
+
obs: `np.ndarray`
|
|
1123
|
+
array of observations
|
|
1124
|
+
season_gap: `float`, optional
|
|
1125
|
+
minimal gap required to define a season (default: 80 days)
|
|
1126
|
+
mjd_col: `str`, optional
|
|
1127
|
+
col name for MJD infos (default: observationStartMJD)
|
|
1128
|
+
|
|
1129
|
+
Returns
|
|
1130
|
+
---------
|
|
1131
|
+
obs : `np.ndarray`
|
|
1132
|
+
original numpy array with seasonnumber appended
|
|
1133
|
+
"""
|
|
1134
|
+
|
|
1135
|
+
# check whether season has already been estimated
|
|
1136
|
+
obs.sort(order=mjd_col)
|
|
1137
|
+
|
|
1138
|
+
seasoncalc = np.ones(obs.size, dtype=int)
|
|
1139
|
+
|
|
1140
|
+
if len(obs) > 1:
|
|
1141
|
+
diff = np.diff(obs[mjd_col])
|
|
1142
|
+
flag = np.where(diff > season_gap)[0]
|
|
1143
|
+
|
|
1144
|
+
if len(flag) > 0:
|
|
1145
|
+
for i, indx in enumerate(flag):
|
|
1146
|
+
seasoncalc[indx + 1 :] = i + 2
|
|
1147
|
+
|
|
1148
|
+
obs = nlr.append_fields(obs, "season", seasoncalc)
|
|
1149
|
+
|
|
1150
|
+
return obs
|
|
1151
|
+
|
|
1152
|
+
def reducen_sn(self, metric_val):
|
|
1153
|
+
# At each slice_point, return the sum nSN value.
|
|
1154
|
+
|
|
1155
|
+
return np.sum(metric_val["n_sn"])
|
|
1156
|
+
|
|
1157
|
+
def reducezlim(self, metric_val):
|
|
1158
|
+
# At each slice_point, return the median zlim
|
|
1159
|
+
result = np.median(metric_val["zlim"])
|
|
1160
|
+
if result < 0:
|
|
1161
|
+
result = self.badval
|
|
1162
|
+
|
|
1163
|
+
return result
|
|
1164
|
+
|
|
1165
|
+
def nsn_expected_z(self, grp):
|
|
1166
|
+
"""
|
|
1167
|
+
Method to estimate the expected nsn vs redshift
|
|
1168
|
+
|
|
1169
|
+
Parameters
|
|
1170
|
+
--------------
|
|
1171
|
+
grp: `pd.DataFrame` group
|
|
1172
|
+
data to process: season infos
|
|
1173
|
+
|
|
1174
|
+
Returns
|
|
1175
|
+
----------
|
|
1176
|
+
`pd.DataFrame` with season_length, z, nsn_expected cols
|
|
1177
|
+
|
|
1178
|
+
"""
|
|
1179
|
+
|
|
1180
|
+
if len(grp) < 2:
|
|
1181
|
+
nsn = pd.DataFrame(grp["z"].to_list(), columns=["z"])
|
|
1182
|
+
nsn.loc[:, "nsn_expected"] = 0
|
|
1183
|
+
else:
|
|
1184
|
+
nsn = self.nsn_from_rate(grp)
|
|
1185
|
+
|
|
1186
|
+
if self.verbose:
|
|
1187
|
+
print("dur_z", grp)
|
|
1188
|
+
print("nsn expected", nsn)
|
|
1189
|
+
|
|
1190
|
+
dur_z = pd.DataFrame(grp)
|
|
1191
|
+
dur_z = dur_z.merge(nsn, left_on=["z"], right_on=["z"])
|
|
1192
|
+
|
|
1193
|
+
# if "season" in dur_z.columns:
|
|
1194
|
+
# dur_z = dur_z.drop(columns=["season"])
|
|
1195
|
+
|
|
1196
|
+
return dur_z
|
|
1197
|
+
|
|
1198
|
+
def zlim_or_nsn(self, effi, sntype="faint", zlim=-1.0):
|
|
1199
|
+
"""
|
|
1200
|
+
Method to estimate the redshift limit or the number of sn
|
|
1201
|
+
|
|
1202
|
+
Parameters
|
|
1203
|
+
---------------
|
|
1204
|
+
effi : `pd.DataFrame`
|
|
1205
|
+
data to process
|
|
1206
|
+
sntype : `str`, opt
|
|
1207
|
+
type of SN to consider for estimation (default: faint)
|
|
1208
|
+
zlim : `float`, opt
|
|
1209
|
+
redshift limit
|
|
1210
|
+
|
|
1211
|
+
Returns
|
|
1212
|
+
-----------
|
|
1213
|
+
if zlim<0: returns the redshift limit
|
|
1214
|
+
if zlim>0: returns the number of sn up to zlim
|
|
1215
|
+
|
|
1216
|
+
|
|
1217
|
+
"""
|
|
1218
|
+
|
|
1219
|
+
seleffi = effi[effi["sntype"] == sntype]
|
|
1220
|
+
seleffi = seleffi.reset_index(drop=True)
|
|
1221
|
+
seleffi = seleffi.sort_values(by=["z"])
|
|
1222
|
+
nsn_cum = np.cumsum(seleffi["nsn"].to_list())
|
|
1223
|
+
|
|
1224
|
+
resa = -1.0
|
|
1225
|
+
if zlim < 0:
|
|
1226
|
+
df = pd.DataFrame(seleffi).reset_index(drop=True)
|
|
1227
|
+
df.loc[:, "nsn_cum"] = nsn_cum / nsn_cum[-1]
|
|
1228
|
+
index = df[df["nsn_cum"] < 1].index
|
|
1229
|
+
if len(index) == 0:
|
|
1230
|
+
return resa
|
|
1231
|
+
dfb = df[: index[-1] + 2]
|
|
1232
|
+
zlim = interp1d(
|
|
1233
|
+
dfb["nsn_cum"],
|
|
1234
|
+
dfb["z"],
|
|
1235
|
+
kind="linear",
|
|
1236
|
+
bounds_error=False,
|
|
1237
|
+
fill_value=0,
|
|
1238
|
+
)
|
|
1239
|
+
resa = zlim(self.zlim_coeff)
|
|
1240
|
+
else:
|
|
1241
|
+
effi = interp1d(
|
|
1242
|
+
seleffi["z"],
|
|
1243
|
+
seleffi["effi"],
|
|
1244
|
+
kind="linear",
|
|
1245
|
+
bounds_error=False,
|
|
1246
|
+
fill_value=0,
|
|
1247
|
+
)
|
|
1248
|
+
durinterp_z = interp1d(
|
|
1249
|
+
seleffi["z"],
|
|
1250
|
+
seleffi["season_length"],
|
|
1251
|
+
kind="linear",
|
|
1252
|
+
bounds_error=False,
|
|
1253
|
+
fill_value=0,
|
|
1254
|
+
)
|
|
1255
|
+
zmin, zstep = 0.1, 0.001
|
|
1256
|
+
resa = self.get_nsn(effi, durinterp_z, zmin, zlim, zstep)
|
|
1257
|
+
|
|
1258
|
+
return np.round(resa, 6)
|
|
1259
|
+
|
|
1260
|
+
def zlim(self, grp, sn_type="faint"):
|
|
1261
|
+
"""
|
|
1262
|
+
Method to estimate the metric zcomp
|
|
1263
|
+
|
|
1264
|
+
Parameters
|
|
1265
|
+
---------------
|
|
1266
|
+
grp: pd group
|
|
1267
|
+
sn_type: str, opt
|
|
1268
|
+
type of SN to estimate zlim (default: faint)
|
|
1269
|
+
|
|
1270
|
+
Returns
|
|
1271
|
+
------------
|
|
1272
|
+
zcomp : `pd.DataFrame` with the metric as cols
|
|
1273
|
+
"""
|
|
1274
|
+
zcomp = -1
|
|
1275
|
+
|
|
1276
|
+
if grp["effi"].mean() > 0.02 and len(grp["effi"]) >= 2:
|
|
1277
|
+
zcomp = self.zlim_or_nsn(grp, sn_type, -1)
|
|
1278
|
+
|
|
1279
|
+
return pd.DataFrame({"zcomp": [zcomp]})
|
|
1280
|
+
|
|
1281
|
+
def nsn(self, grp, sn_type="medium"):
|
|
1282
|
+
"""
|
|
1283
|
+
Method to estimate the metric nsn up to zlim
|
|
1284
|
+
|
|
1285
|
+
Parameters
|
|
1286
|
+
---------------
|
|
1287
|
+
grp: pd group
|
|
1288
|
+
sn_type: str, opt
|
|
1289
|
+
type of SN to estimate zlim (default: medium)
|
|
1290
|
+
|
|
1291
|
+
Returns
|
|
1292
|
+
------------
|
|
1293
|
+
nsn : `pd.DataFrame`
|
|
1294
|
+
Dataframe with the metric as cols
|
|
1295
|
+
"""
|
|
1296
|
+
nsn = -1
|
|
1297
|
+
|
|
1298
|
+
if grp["effi"].mean() > 0.02:
|
|
1299
|
+
nsn = self.zlim_or_nsn(grp, sn_type, grp["zcomp"].mean())
|
|
1300
|
+
|
|
1301
|
+
return pd.DataFrame({"nsn": [nsn]})
|
|
1302
|
+
|
|
1303
|
+
def get_nsn(self, effi, durinterp_z, zmin, zmax, zstep):
|
|
1304
|
+
"""
|
|
1305
|
+
Method to estimate to total number of SN: NSN = Sum(effi(z)*rate(z))
|
|
1306
|
+
|
|
1307
|
+
Parameters
|
|
1308
|
+
-----------
|
|
1309
|
+
effi : 1D interpolator
|
|
1310
|
+
efficiencies vs z
|
|
1311
|
+
durinterp_z : 1D interpolator
|
|
1312
|
+
duration vs z
|
|
1313
|
+
zmin : `float`
|
|
1314
|
+
redshift min
|
|
1315
|
+
zmax : `float`
|
|
1316
|
+
redshift max
|
|
1317
|
+
zstep : `float`
|
|
1318
|
+
redshift step
|
|
1319
|
+
|
|
1320
|
+
Returns
|
|
1321
|
+
----------
|
|
1322
|
+
tot_sn : `int`
|
|
1323
|
+
total number of SN up to zmax
|
|
1324
|
+
"""
|
|
1325
|
+
|
|
1326
|
+
zz, rate, err_rate, nsn, err_nsn = self.rate_sn(
|
|
1327
|
+
zmin=zmin,
|
|
1328
|
+
zmax=zmax + zstep,
|
|
1329
|
+
dz=zstep,
|
|
1330
|
+
duration_z=durinterp_z,
|
|
1331
|
+
# duration=180.,
|
|
1332
|
+
survey_area=self.pix_area,
|
|
1333
|
+
account_for_edges=False,
|
|
1334
|
+
)
|
|
1335
|
+
res = np.cumsum(effi(zz) * nsn)
|
|
1336
|
+
if np.size(res) > 0:
|
|
1337
|
+
return res[-1]
|
|
1338
|
+
else:
|
|
1339
|
+
return 0
|
|
1340
|
+
|
|
1341
|
+
def check_dur_z(self, dur_z, nmin=2):
|
|
1342
|
+
""" "
|
|
1343
|
+
Method to remove seasons with a poor redshift range due
|
|
1344
|
+
to too low season length
|
|
1345
|
+
|
|
1346
|
+
Parameters
|
|
1347
|
+
----------------
|
|
1348
|
+
dur_z: `pd.DataFrame`
|
|
1349
|
+
data to process
|
|
1350
|
+
nmin: int, opt
|
|
1351
|
+
minimal number of redshift points per season (default: 2)
|
|
1352
|
+
|
|
1353
|
+
Returns
|
|
1354
|
+
-----------
|
|
1355
|
+
dur_z_subset : `pd.DataFrame`
|
|
1356
|
+
dur_z but only with seasons having at least nmin points in redshift
|
|
1357
|
+
|
|
1358
|
+
"""
|
|
1359
|
+
|
|
1360
|
+
dur_z["size"] = dur_z.groupby(["season"])["z"].transform("size")
|
|
1361
|
+
|
|
1362
|
+
idx = dur_z["size"] >= nmin
|
|
1363
|
+
|
|
1364
|
+
return pd.DataFrame(dur_z[idx])
|