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,55 @@
|
|
|
1
|
+
__all__ = ("UseMetric",)
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from rubin_sim.maf.metrics.base_metric import BaseMetric
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class UseMetric(BaseMetric): # pylint: disable=too-few-public-methods
|
|
9
|
+
"""Metric to classify visits by type of visits"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, note_col="scheduler_note", **kwargs):
|
|
12
|
+
self.note_col = note_col
|
|
13
|
+
super().__init__(col=[note_col], metric_dtype="object", **kwargs)
|
|
14
|
+
|
|
15
|
+
def run(self, data_slice, slice_point=None): # pylint: disable=invalid-name
|
|
16
|
+
"""Run the metric.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
data_slice : `np.ndarray`, (N,)`
|
|
21
|
+
slice_point : `dict`
|
|
22
|
+
Dictionary of slice_point metadata passed to each metric.
|
|
23
|
+
E.g. the ra/dec of the healpix pixel.
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
use_name : `str`
|
|
28
|
+
use at each slice_point.
|
|
29
|
+
"""
|
|
30
|
+
use_name = None
|
|
31
|
+
visible_bands = ("u", "g", "r")
|
|
32
|
+
notes = data_slice[self.note_col]
|
|
33
|
+
if len(notes.shape) == 0:
|
|
34
|
+
note = notes
|
|
35
|
+
else:
|
|
36
|
+
note = notes[0]
|
|
37
|
+
assert np.all(notes == note)
|
|
38
|
+
|
|
39
|
+
note_elems = note.replace(":", ", ").split(", ")
|
|
40
|
+
# XXX--survey note strings should not be hard-coded here.
|
|
41
|
+
if note_elems[0] == "greedy":
|
|
42
|
+
use_name = note_elems[0]
|
|
43
|
+
if note_elems[0] == "DD":
|
|
44
|
+
use_name = note_elems[1]
|
|
45
|
+
if (note_elems[0] == "blob") | (note_elems[0] == "blob_twi"):
|
|
46
|
+
use_name = "wide with only IR"
|
|
47
|
+
for band in visible_bands:
|
|
48
|
+
if band in note_elems[1]:
|
|
49
|
+
use_name = "wide with u, g, or r"
|
|
50
|
+
|
|
51
|
+
assert use_name is not None, f"Unrecognized scheduler_note: {note}"
|
|
52
|
+
return use_name
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# internal functions & classes
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
__all__ = (
|
|
2
|
+
"HistogramMetric",
|
|
3
|
+
"AccumulateMetric",
|
|
4
|
+
"AccumulateCountMetric",
|
|
5
|
+
"HistogramM5Metric",
|
|
6
|
+
"AccumulateM5Metric",
|
|
7
|
+
"AccumulateUniformityMetric",
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
from scipy import stats
|
|
12
|
+
|
|
13
|
+
from .base_metric import BaseMetric
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class VectorMetric(BaseMetric):
|
|
17
|
+
"""
|
|
18
|
+
Base for metrics that return a vector
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, bins=None, bin_col="night", col="night", units=None, metric_dtype=float, **kwargs):
|
|
22
|
+
if isinstance(col, str):
|
|
23
|
+
cols = [col, bin_col]
|
|
24
|
+
else:
|
|
25
|
+
cols = list(col) + [bin_col]
|
|
26
|
+
|
|
27
|
+
super(VectorMetric, self).__init__(col=cols, units=units, metric_dtype=metric_dtype, **kwargs)
|
|
28
|
+
self.bins = bins
|
|
29
|
+
self.bin_col = bin_col
|
|
30
|
+
self.shape = np.size(bins) - 1
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class HistogramMetric(VectorMetric):
|
|
34
|
+
"""
|
|
35
|
+
A wrapper to stats.binned_statistic
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
bins=None,
|
|
41
|
+
bin_col="night",
|
|
42
|
+
col="night",
|
|
43
|
+
units="Count",
|
|
44
|
+
statistic="count",
|
|
45
|
+
metric_dtype=float,
|
|
46
|
+
**kwargs,
|
|
47
|
+
):
|
|
48
|
+
self.statistic = statistic
|
|
49
|
+
self.col = col
|
|
50
|
+
super(HistogramMetric, self).__init__(
|
|
51
|
+
col=col, bins=bins, bin_col=bin_col, units=units, metric_dtype=metric_dtype, **kwargs
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def run(self, data_slice, slice_point=None):
|
|
55
|
+
data_slice.sort(order=self.bin_col)
|
|
56
|
+
result, bin_edges, bin_number = stats.binned_statistic(
|
|
57
|
+
data_slice[self.bin_col],
|
|
58
|
+
data_slice[self.col],
|
|
59
|
+
bins=self.bins,
|
|
60
|
+
statistic=self.statistic,
|
|
61
|
+
)
|
|
62
|
+
return result
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class AccumulateMetric(VectorMetric):
|
|
66
|
+
"""
|
|
67
|
+
Calculate the accumulated stat
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def __init__(
|
|
71
|
+
self, col="night", bins=None, bin_col="night", function=np.add, metric_dtype=float, **kwargs
|
|
72
|
+
):
|
|
73
|
+
self.function = function
|
|
74
|
+
super(AccumulateMetric, self).__init__(
|
|
75
|
+
col=col, bin_col=bin_col, bins=bins, metric_dtype=metric_dtype, **kwargs
|
|
76
|
+
)
|
|
77
|
+
self.col = col
|
|
78
|
+
|
|
79
|
+
def run(self, data_slice, slice_point=None):
|
|
80
|
+
data_slice.sort(order=self.bin_col)
|
|
81
|
+
|
|
82
|
+
result = self.function.accumulate(data_slice[self.col])
|
|
83
|
+
indices = np.searchsorted(data_slice[self.bin_col], self.bins[1:], side="right")
|
|
84
|
+
indices[np.where(indices >= np.size(result))] = np.size(result) - 1
|
|
85
|
+
result = result[indices]
|
|
86
|
+
result[np.where(indices == 0)] = self.badval
|
|
87
|
+
return result
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class AccumulateCountMetric(AccumulateMetric):
|
|
91
|
+
def run(self, data_slice, slice_point=None):
|
|
92
|
+
data_slice.sort(order=self.bin_col)
|
|
93
|
+
to_count = np.ones(data_slice.size, dtype=int)
|
|
94
|
+
result = self.function.accumulate(to_count)
|
|
95
|
+
indices = np.searchsorted(data_slice[self.bin_col], self.bins[1:], side="right")
|
|
96
|
+
indices[np.where(indices >= np.size(result))] = np.size(result) - 1
|
|
97
|
+
result = result[indices]
|
|
98
|
+
result[np.where(indices == 0)] = self.badval
|
|
99
|
+
return result
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class HistogramM5Metric(HistogramMetric):
|
|
103
|
+
"""
|
|
104
|
+
Calculate the coadded depth for each bin (e.g., per night).
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
def __init__(
|
|
108
|
+
self,
|
|
109
|
+
bins=None,
|
|
110
|
+
bin_col="night",
|
|
111
|
+
m5_col="fiveSigmaDepth",
|
|
112
|
+
units="mag",
|
|
113
|
+
metric_name="HistogramM5Metric",
|
|
114
|
+
**kwargs,
|
|
115
|
+
):
|
|
116
|
+
super(HistogramM5Metric, self).__init__(
|
|
117
|
+
col=m5_col, bin_col=bin_col, bins=bins, metric_name=metric_name, units=units, **kwargs
|
|
118
|
+
)
|
|
119
|
+
self.m5_col = m5_col
|
|
120
|
+
|
|
121
|
+
def run(self, data_slice, slice_point=None):
|
|
122
|
+
data_slice.sort(order=self.bin_col)
|
|
123
|
+
flux = 10.0 ** (0.8 * data_slice[self.m5_col])
|
|
124
|
+
result, bin_edges, bin_number = stats.binned_statistic(
|
|
125
|
+
data_slice[self.bin_col], flux, bins=self.bins, statistic="sum"
|
|
126
|
+
)
|
|
127
|
+
no_flux = np.where(result == 0.0)
|
|
128
|
+
result = 1.25 * np.log10(result)
|
|
129
|
+
result[no_flux] = self.badval
|
|
130
|
+
return result
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class AccumulateM5Metric(AccumulateMetric):
|
|
134
|
+
def __init__(
|
|
135
|
+
self, bins=None, bin_col="night", m5_col="fiveSigmaDepth", metric_name="AccumulateM5Metric", **kwargs
|
|
136
|
+
):
|
|
137
|
+
self.m5_col = m5_col
|
|
138
|
+
super(AccumulateM5Metric, self).__init__(
|
|
139
|
+
bins=bins, bin_col=bin_col, col=m5_col, metric_name=metric_name, **kwargs
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
def run(self, data_slice, slice_point=None):
|
|
143
|
+
data_slice.sort(order=self.bin_col)
|
|
144
|
+
flux = 10.0 ** (0.8 * data_slice[self.m5_col])
|
|
145
|
+
|
|
146
|
+
result = np.add.accumulate(flux)
|
|
147
|
+
indices = np.searchsorted(data_slice[self.bin_col], self.bins[1:], side="right")
|
|
148
|
+
indices[np.where(indices >= np.size(result))] = np.size(result) - 1
|
|
149
|
+
result = result[indices]
|
|
150
|
+
result = 1.25 * np.log10(result)
|
|
151
|
+
result[np.where(indices == 0)] = self.badval
|
|
152
|
+
return result
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class AccumulateUniformityMetric(AccumulateMetric):
|
|
156
|
+
"""
|
|
157
|
+
Make a 2D version of UniformityMetric
|
|
158
|
+
"""
|
|
159
|
+
|
|
160
|
+
def __init__(
|
|
161
|
+
self,
|
|
162
|
+
bins=None,
|
|
163
|
+
bin_col="night",
|
|
164
|
+
exp_mjd_col="observationStartMJD",
|
|
165
|
+
metric_name="AccumulateUniformityMetric",
|
|
166
|
+
survey_length=10.0,
|
|
167
|
+
units="Fraction",
|
|
168
|
+
**kwargs,
|
|
169
|
+
):
|
|
170
|
+
self.exp_mjd_col = exp_mjd_col
|
|
171
|
+
if bins is None:
|
|
172
|
+
bins = np.arange(0, np.ceil(survey_length * 365.25)) - 0.5
|
|
173
|
+
super(AccumulateUniformityMetric, self).__init__(
|
|
174
|
+
bins=bins, bin_col=bin_col, col=exp_mjd_col, metric_name=metric_name, units=units, **kwargs
|
|
175
|
+
)
|
|
176
|
+
self.survey_length = survey_length
|
|
177
|
+
|
|
178
|
+
def run(self, data_slice, slice_point=None):
|
|
179
|
+
data_slice.sort(order=self.bin_col)
|
|
180
|
+
if data_slice.size == 1:
|
|
181
|
+
return np.ones(self.bins.size - 1, dtype=float)
|
|
182
|
+
|
|
183
|
+
visits_per_night, blah = np.histogram(data_slice[self.bin_col], bins=self.bins)
|
|
184
|
+
visits_per_night = np.add.accumulate(visits_per_night)
|
|
185
|
+
expected_per_night = np.arange(0.0, self.bins.size - 1) / (self.bins.size - 2) * data_slice.size
|
|
186
|
+
|
|
187
|
+
d_max = np.abs(visits_per_night - expected_per_night)
|
|
188
|
+
d_max = np.maximum.accumulate(d_max)
|
|
189
|
+
result = d_max / expected_per_night.max()
|
|
190
|
+
return result
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
__all__ = ("VisitGroupsMetric", "PairFractionMetric")
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from .base_metric import BaseMetric
|
|
7
|
+
|
|
8
|
+
# Example of more complex metric
|
|
9
|
+
# Takes multiple columns of data (although 'night' could be calculable
|
|
10
|
+
# from 'expmjd')
|
|
11
|
+
# Returns variable length array of data
|
|
12
|
+
# Uses multiple reduce functions
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class PairFractionMetric(BaseMetric):
|
|
16
|
+
"""What fraction of observations are part of a pair.
|
|
17
|
+
|
|
18
|
+
Note, an observation can be a member of more than one "pair". For example,
|
|
19
|
+
t=[0, 5, 30], all observations would be considered part of a pair because
|
|
20
|
+
they all have an observation within the given window to pair with (the
|
|
21
|
+
observation at t=30 pairs twice).
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
min_gap : float, optional
|
|
26
|
+
Minimum time to consider something part of a pair (minutes).
|
|
27
|
+
Default 15.
|
|
28
|
+
max_gap : float, optional
|
|
29
|
+
Maximum time to consider something part of a pair (minutes).
|
|
30
|
+
Default 90.
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self, mjd_col="observationStartMJD", metric_name="PairFraction", min_gap=15.0, max_gap=90.0, **kwargs
|
|
35
|
+
):
|
|
36
|
+
self.mjd_col = mjd_col
|
|
37
|
+
self.min_gap = min_gap / 60.0 / 24.0
|
|
38
|
+
self.max_gap = max_gap / 60.0 / 24.0
|
|
39
|
+
units = ""
|
|
40
|
+
super(PairFractionMetric, self).__init__(
|
|
41
|
+
col=[mjd_col], metric_name=metric_name, units=units, **kwargs
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
def run(self, data_slice, slice_point=None):
|
|
45
|
+
nobs = np.size(data_slice[self.mjd_col])
|
|
46
|
+
times = np.sort(data_slice[self.mjd_col])
|
|
47
|
+
|
|
48
|
+
# Check which ones have a forard match
|
|
49
|
+
t_plus = times + self.max_gap
|
|
50
|
+
t_minus = times + self.min_gap
|
|
51
|
+
ind1 = np.searchsorted(times, t_plus)
|
|
52
|
+
ind2 = np.searchsorted(times, t_minus)
|
|
53
|
+
# If ind1 and ind2 are the same, there is no pairable image for
|
|
54
|
+
# that exposure
|
|
55
|
+
diff1 = ind1 - ind2
|
|
56
|
+
|
|
57
|
+
# Check which have a back match
|
|
58
|
+
t_plus = times - self.max_gap
|
|
59
|
+
t_minus = times - self.min_gap
|
|
60
|
+
ind1 = np.searchsorted(times, t_plus)
|
|
61
|
+
ind2 = np.searchsorted(times, t_minus)
|
|
62
|
+
|
|
63
|
+
diff2 = ind1 - ind2
|
|
64
|
+
|
|
65
|
+
# The exposure has a pair ahead or behind
|
|
66
|
+
is_paired = np.where((diff1 != 0) | (diff2 != 0))[0]
|
|
67
|
+
result = np.size(is_paired) / float(nobs)
|
|
68
|
+
return result
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class VisitGroupsMetric(BaseMetric):
|
|
72
|
+
"""Count the number of visits per night within delta_t_min and delta_t_max.
|
|
73
|
+
|
|
74
|
+
Parameters
|
|
75
|
+
----------
|
|
76
|
+
time_col : str, optional
|
|
77
|
+
Column with the time of the visit.
|
|
78
|
+
Default: 'observationStartMJD'
|
|
79
|
+
nights_col : str, optional
|
|
80
|
+
Column with the night of the visit
|
|
81
|
+
Default: 'night'
|
|
82
|
+
delta_t_min : float, min
|
|
83
|
+
Minimum time of window: units are days
|
|
84
|
+
Default: 15.0 / 60.0 / 24.0 (15min in days)
|
|
85
|
+
delta_t_max : float, optional
|
|
86
|
+
Maximum time of window: units are days
|
|
87
|
+
Default: 90.0 / 60.0 / 24.0 (90min in days)
|
|
88
|
+
min_n_visits : int, optional
|
|
89
|
+
Minimum number of visits within a night (with spacing between
|
|
90
|
+
delta_t_min/max from any other visit) required
|
|
91
|
+
Default: 2
|
|
92
|
+
window : int, optional
|
|
93
|
+
Number of nights to consider within a window (for reduce methods)
|
|
94
|
+
Default: 30
|
|
95
|
+
min_n_nights : int, optional
|
|
96
|
+
minimum required number of nights within window to make a full 'group'
|
|
97
|
+
Default: 3
|
|
98
|
+
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def __init__(
|
|
102
|
+
self,
|
|
103
|
+
time_col="observationStartMJD",
|
|
104
|
+
nights_col="night",
|
|
105
|
+
metric_name="VisitGroups",
|
|
106
|
+
delta_t_min=15.0 / 60.0 / 24.0,
|
|
107
|
+
delta_t_max=90.0 / 60.0 / 24.0,
|
|
108
|
+
min_n_visits=2,
|
|
109
|
+
window=30,
|
|
110
|
+
min_n_nights=3,
|
|
111
|
+
**kwargs,
|
|
112
|
+
):
|
|
113
|
+
self.times = time_col
|
|
114
|
+
self.nights = nights_col
|
|
115
|
+
eps = 1e-10
|
|
116
|
+
self.delta_tmin = float(delta_t_min) - eps
|
|
117
|
+
self.delta_tmax = float(delta_t_max)
|
|
118
|
+
self.min_n_visits = int(min_n_visits)
|
|
119
|
+
self.window = int(window)
|
|
120
|
+
self.min_n_nights = int(min_n_nights)
|
|
121
|
+
super(VisitGroupsMetric, self).__init__(
|
|
122
|
+
col=[self.times, self.nights], metric_name=metric_name, **kwargs
|
|
123
|
+
)
|
|
124
|
+
self.reduce_order = {
|
|
125
|
+
"Median": 0,
|
|
126
|
+
"NNightsWithNVisits": 1,
|
|
127
|
+
"NVisitsInWindow": 2,
|
|
128
|
+
"NNightsInWindow": 3,
|
|
129
|
+
"NLunations": 4,
|
|
130
|
+
"MaxSeqLunations": 5,
|
|
131
|
+
}
|
|
132
|
+
self.comment = "Evaluation of the number of visits within a night, with separations between "
|
|
133
|
+
self.comment += "tMin %.1f and tMax %.1f minutes." % (
|
|
134
|
+
self.delta_tmin * 24.0 * 60.0,
|
|
135
|
+
self.delta_tmax * 24.0 * 60.0,
|
|
136
|
+
)
|
|
137
|
+
self.comment += "Groups of visits use a minimum number of visits per night of %d, " % (
|
|
138
|
+
self.min_n_visits
|
|
139
|
+
)
|
|
140
|
+
self.comment += "and minimum number of nights of %d." % (self.min_n_nights)
|
|
141
|
+
self.comment += "Two visits within this interval would count as 2. "
|
|
142
|
+
self.comment += "Visits closer than tMin, paired with visits that do fall within tMin/tMax, "
|
|
143
|
+
self.comment += "count as half visits. <br>"
|
|
144
|
+
self.comment += "VisitsGroups_Median calculates the median number of visits between tMin/tMax for "
|
|
145
|
+
self.comment += "all nights. <br>"
|
|
146
|
+
self.comment += "VisitGroups_NNightsWithNNights calculates the number of nights that have at "
|
|
147
|
+
self.comment += "least %d visits. <br>" % (self.min_n_visits)
|
|
148
|
+
self.comment += "VisitGroups_NVisitsInWindow calculates the max number of visits within a window of "
|
|
149
|
+
self.comment += "%d days. <br>" % (self.window)
|
|
150
|
+
self.comment += "VisitGroups_NNightsInWindow calculates the max number of nights that have more "
|
|
151
|
+
self.comment += "than %d visits within %d days. <br>" % (
|
|
152
|
+
self.min_n_visits,
|
|
153
|
+
self.window,
|
|
154
|
+
)
|
|
155
|
+
self.comment += "VisitGroups_NLunations calculates the number of lunations (30 days) that have "
|
|
156
|
+
self.comment += "at least one group of more than %d nights with more than %d visits, within " % (
|
|
157
|
+
self.min_n_nights,
|
|
158
|
+
self.min_n_visits,
|
|
159
|
+
)
|
|
160
|
+
self.comment += "%d days. <br>" % (self.window)
|
|
161
|
+
self.comment += "VisitGroups_MaxSeqLunations calculates the maximum sequential lunations that have "
|
|
162
|
+
self.comment += 'at least one "group". <br>'
|
|
163
|
+
|
|
164
|
+
def run(self, data_slice, slice_point=None):
|
|
165
|
+
"""
|
|
166
|
+
Return a dictionary of:
|
|
167
|
+
the number of visits within a night (within delta tmin/tmax of another
|
|
168
|
+
visit), and the nights with visits > minNVisits.
|
|
169
|
+
Count two visits which are within tmin of each other, but which have
|
|
170
|
+
another visit within tmin/tmax interval, as one and a half (instead of
|
|
171
|
+
two).
|
|
172
|
+
|
|
173
|
+
So for example: 4 visits, where 1, 2, 3 were all within deltaTMax of
|
|
174
|
+
each other, and 4 was later but within deltaTmax of visit 3 -- would
|
|
175
|
+
give you 4 visits. If visit 1 and 2 were closer together than
|
|
176
|
+
deltaTmin, the two would be counted as 1.5 visits together (if only 1
|
|
177
|
+
and 2 existed, then there would be 0 visits as none would be within the
|
|
178
|
+
qualifying time interval).
|
|
179
|
+
"""
|
|
180
|
+
uniquenights = np.unique(data_slice[self.nights])
|
|
181
|
+
nights = []
|
|
182
|
+
visit_num = []
|
|
183
|
+
# Find the nights with visits within deltaTmin/max of one another and
|
|
184
|
+
# count the number of visits
|
|
185
|
+
for n in uniquenights:
|
|
186
|
+
condition = data_slice[self.nights] == n
|
|
187
|
+
times = np.sort(data_slice[self.times][condition])
|
|
188
|
+
nvisits = 0
|
|
189
|
+
ntooclose = 0
|
|
190
|
+
# Calculate difference between each visit and time of previous
|
|
191
|
+
# visit (tnext- tnow)
|
|
192
|
+
timediff = np.diff(times)
|
|
193
|
+
timegood = np.where(
|
|
194
|
+
(timediff <= self.delta_tmax) & (timediff >= self.delta_tmin),
|
|
195
|
+
True,
|
|
196
|
+
False,
|
|
197
|
+
)
|
|
198
|
+
timetooclose = np.where(timediff < self.delta_tmin, True, False)
|
|
199
|
+
if len(timegood) > 1:
|
|
200
|
+
# Count visits for all but last index in timediff
|
|
201
|
+
for tg1, ttc1, tg2, ttc2 in zip(
|
|
202
|
+
timegood[:-1], timetooclose[:-1], timegood[1:], timetooclose[1:]
|
|
203
|
+
):
|
|
204
|
+
if tg1:
|
|
205
|
+
nvisits += 1
|
|
206
|
+
if not tg2:
|
|
207
|
+
nvisits += 1
|
|
208
|
+
if ttc1:
|
|
209
|
+
ntooclose += 1
|
|
210
|
+
if not tg2 and not ttc2:
|
|
211
|
+
ntooclose += 1
|
|
212
|
+
# Take care of last timediff
|
|
213
|
+
if timegood[-1]:
|
|
214
|
+
nvisits += 2 # close out visit sequence
|
|
215
|
+
if timetooclose[-1]:
|
|
216
|
+
ntooclose += 1
|
|
217
|
+
if not timegood[-2] and not timetooclose[-2]:
|
|
218
|
+
ntooclose += 1
|
|
219
|
+
else:
|
|
220
|
+
if timegood.size > 0:
|
|
221
|
+
nvisits += 2
|
|
222
|
+
# Count up all visits for night.
|
|
223
|
+
if nvisits > 0:
|
|
224
|
+
nvisits = nvisits + ntooclose / 2.0
|
|
225
|
+
visit_num.append(nvisits)
|
|
226
|
+
nights.append(n)
|
|
227
|
+
# Convert to numpy arrays.
|
|
228
|
+
visit_num = np.array(visit_num)
|
|
229
|
+
nights = np.array(nights)
|
|
230
|
+
metricval = {"visits": visit_num, "nights": nights}
|
|
231
|
+
if len(visit_num) == 0:
|
|
232
|
+
return self.badval
|
|
233
|
+
return metricval
|
|
234
|
+
|
|
235
|
+
def reduce_median(self, metricval):
|
|
236
|
+
"""Reduce to median number of visits per night."""
|
|
237
|
+
return np.median(metricval["visits"])
|
|
238
|
+
|
|
239
|
+
def reduce_n_nights_with_n_visits(self, metricval):
|
|
240
|
+
"""Reduce to total number of nights with more than 'minNVisits'
|
|
241
|
+
visits."""
|
|
242
|
+
condition = metricval["visits"] >= self.min_n_visits
|
|
243
|
+
return len(metricval["visits"][condition])
|
|
244
|
+
|
|
245
|
+
def _in_window(self, visits, nights, night, window, min_n_visits):
|
|
246
|
+
condition = (nights >= night) & (nights < night + window)
|
|
247
|
+
condition2 = visits[condition] >= min_n_visits
|
|
248
|
+
return visits[condition][condition2], nights[condition][condition2]
|
|
249
|
+
|
|
250
|
+
def reduce_n_visits_in_window(self, metricval):
|
|
251
|
+
"""Reduce to max number of total visits on all nights with more than
|
|
252
|
+
minNVisits, within any 'window' (default=30 nights)."""
|
|
253
|
+
maxnvisits = 0
|
|
254
|
+
for n in metricval["nights"]:
|
|
255
|
+
vw, nw = self._in_window(
|
|
256
|
+
metricval["visits"],
|
|
257
|
+
metricval["nights"],
|
|
258
|
+
n,
|
|
259
|
+
self.window,
|
|
260
|
+
self.min_n_visits,
|
|
261
|
+
)
|
|
262
|
+
maxnvisits = max((vw.sum(), maxnvisits))
|
|
263
|
+
return maxnvisits
|
|
264
|
+
|
|
265
|
+
def reduce_n_nights_in_window(self, metricval):
|
|
266
|
+
"""Reduce to max number of nights with more than minNVisits, within
|
|
267
|
+
'window' over all windows."""
|
|
268
|
+
maxnights = 0
|
|
269
|
+
for n in metricval["nights"]:
|
|
270
|
+
vw, nw = self._in_window(
|
|
271
|
+
metricval["visits"],
|
|
272
|
+
metricval["nights"],
|
|
273
|
+
n,
|
|
274
|
+
self.window,
|
|
275
|
+
self.min_n_visits,
|
|
276
|
+
)
|
|
277
|
+
maxnights = max(len(nw), maxnights)
|
|
278
|
+
return maxnights
|
|
279
|
+
|
|
280
|
+
def _in_lunation(self, visits, nights, lunation_start, lunation_length):
|
|
281
|
+
condition = (nights >= lunation_start) & (nights < lunation_start + lunation_length)
|
|
282
|
+
return visits[condition], nights[condition]
|
|
283
|
+
|
|
284
|
+
def reduce_n_lunations(self, metricval):
|
|
285
|
+
"""Reduce to number of lunations (unique 30 day windows) that contain
|
|
286
|
+
at least one 'group': a set of more than minNVisits per night, with
|
|
287
|
+
more than minNNights of visits within 'window' time period.
|
|
288
|
+
"""
|
|
289
|
+
lunation_length = 30
|
|
290
|
+
lunations = np.arange(
|
|
291
|
+
metricval["nights"][0],
|
|
292
|
+
metricval["nights"][-1] + lunation_length / 2.0,
|
|
293
|
+
lunation_length,
|
|
294
|
+
)
|
|
295
|
+
n_lunations = 0
|
|
296
|
+
for lunation in lunations:
|
|
297
|
+
# Find visits within lunation.
|
|
298
|
+
vl, nl = self._in_lunation(metricval["visits"], metricval["nights"], lunation, lunation_length)
|
|
299
|
+
for n in nl:
|
|
300
|
+
# Find visits which are in groups within the lunation.
|
|
301
|
+
vw, nw = self._in_window(vl, nl, n, self.window, self.min_n_visits)
|
|
302
|
+
if len(nw) >= self.min_n_nights:
|
|
303
|
+
n_lunations += 1
|
|
304
|
+
break
|
|
305
|
+
return n_lunations
|
|
306
|
+
|
|
307
|
+
def reduce_max_seq_lunations(self, metricval):
|
|
308
|
+
"""Count the max number of sequential lunations (unique 30 day windows
|
|
309
|
+
that contain at least one 'group': a set of more than minNVisits per
|
|
310
|
+
night, with more than minNNights of visits within 'window' time period.
|
|
311
|
+
"""
|
|
312
|
+
lunation_length = 30
|
|
313
|
+
lunations = np.arange(
|
|
314
|
+
metricval["nights"][0],
|
|
315
|
+
metricval["nights"][-1] + lunation_length / 2.0,
|
|
316
|
+
lunation_length,
|
|
317
|
+
)
|
|
318
|
+
max_sequence = 0
|
|
319
|
+
cur_sequence = 0
|
|
320
|
+
for lunation in lunations:
|
|
321
|
+
# Find visits within lunation.
|
|
322
|
+
vl, nl = self._in_lunation(metricval["visits"], metricval["nights"], lunation, lunation_length)
|
|
323
|
+
# If no visits this lunation:
|
|
324
|
+
if len(vl) == 0:
|
|
325
|
+
max_sequence = max(max_sequence, cur_sequence)
|
|
326
|
+
cur_sequence = 0
|
|
327
|
+
# Else, look to see if groups can be made from the visits.
|
|
328
|
+
for n in nl:
|
|
329
|
+
# Find visits which are in groups within the lunation.
|
|
330
|
+
vw, nw = self._in_window(vl, nl, n, self.window, self.min_n_visits)
|
|
331
|
+
# If there was a group within this lunation:
|
|
332
|
+
if len(nw) >= self.min_n_nights:
|
|
333
|
+
cur_sequence += 1
|
|
334
|
+
break
|
|
335
|
+
# Otherwise we're not in a sequence (anymore, or still).
|
|
336
|
+
else:
|
|
337
|
+
max_sequence = max(max_sequence, cur_sequence)
|
|
338
|
+
cur_sequence = 0
|
|
339
|
+
# Pick up last sequence if were in a sequence at last lunation.
|
|
340
|
+
max_sequence = max(max_sequence, cur_sequence)
|
|
341
|
+
return max_sequence
|